Rename PHP error on file upload from contact form

Hi,

This is almost definitely an issue with my hosting setup, but if anyone has any guidance on what I need to tell them to do that would be hugely appreciated!

I have a contact form, which includes a file upload field. The setup for this is heavily based on this cookbook: Forms with attachments | Kirby CMS.

All works perfectly on my local setup, but I am getting an error on the live site when a file is uploaded. This is my controller (I have included it all in case there is something I have done wrong):

<?php

use Uniform\Form;

return function ($kirby, $page)
{
    $form = new Form([
        'name' => [
          'rules' => ['required'],
          'message' => 'Please enter your name'
        ],
        'organisation' => [],
        'email' => [
            'rules' => ['required', 'email'],
            'message' => 'Please enter a valid email address',
        ],
        'phone' => [],
        'enquiry' => [
          'rules' => ['required'],
          'message' => 'Please choose an option',
        ],
        'message' => [
          'rules' => ['required'],
          'message' => 'Please enter a message',
        ], 
        'files' => [],
    ]);

    $data = [
      'name'          => get('name'),
      'organisation'  => get('organisation'),
      'phone'         => get('phone'),
      'email'         => get('email'),
      'enquiry'       => get('enquiry'),
      'message'       => get('message')
    ];

    // Attachments

    $attachments = [];
    $alerts      = null;

    $uploads = $kirby->request()->files()->get('files');

    if (!empty($uploads) && count($uploads) > 3) {
      $alerts[] = 'You may only upload up to 3 files.';
    }

    // loop through uploads and check if they are valid
    if(!empty($uploads) && count($uploads) > 0):
    foreach ($uploads as $upload) {

      if($upload['size'] > 0): //Seem to have an empty element thing happening so do this check
      // make sure the user uploads at least one file
      if ($upload['error'] !== 0) {
          $alerts[] = 'The file could not be uploaded';
      // make sure the file is not larger than 2MB…    
      } elseif ($upload['size'] > 5000000)  {
          $alerts[] = $upload['name'] . ' is larger than 5 MB';
      // …and the file is a PDF
      } else {
          $name     = $upload['tmp_name'];
          $tmpName  = pathinfo($name);
          // sanitize the original filename
          $filename = $tmpName['dirname']. '/'. F::safeName($upload['name']);

          if (rename($upload['tmp_name'], $filename)) {
              $name = $filename;
          }
          // add the files to the attachments array
          $attachments[] = $name;
      }  
    endif;

    }
    endif;

    // Get the enquiry type rather than the destination email

    if(empty($alerts)):

    if ($kirby->request()->is('POST')) {

      // Get email to send to

      if($row = $page->selectOptions()->toStructure()->findBy("option", $form->data('enquiry'))):
        $enquiryEmail = $row->email();
      endif;

      try {
        # Attach file & send email
        $form->honeypotGuard()->honeytimeGuard([
          'key' => c::get('uniform.honeytime.key'),
          'seconds' => 3,
        ])->emailAction([
            'to' => $enquiryEmail . '@website.com',
            'from' => 'website@website.com',
            'template' => 'simple',
            'subject' => 'Website form submission regarding ' . $form->data('enquiry'),
            'attachments' => $attachments
        ])->done();
    }

    catch (Exception $e) {
        $form->fail('file', $e->getMessage());
    }

    }

    endif;

    return compact('form','alerts','data','uploads');
};

The error I am getting is:

rename(/tmp/php4uBjD7,/tmp/blank2.pdf): Operation not permitted

Which is caused by this line:

if (rename($upload['tmp_name'], $filename)) {
            $name = $filename;
        }

So the issue is with the rename function. Is there anything unusual about this function, why it would not be permitted on my hosting? Could it be to do with my permissions? The site is hosted by Fasthosts on their shared hosting, running on PHP 8.2

What is the upload_tmp_dir? I guess this is a directory where you don’t have write rights.

Check if you can change this directory to something else under your control in cPanel or whatever your control panel is.

Thanks for the reply

This is on phpinfo:

Directive        local value      master value
upload_tmp_dir   /tmp/            /tmp/

I’m not sure if I can change this, it is pretty restrictive shared hosting the client is on, I don’t have cPanel access. Is there a way of modifying the code to avoid this issue? I don’t need the filenames to be retained, the files can be attached to the email with their temporary names.

Then just skip the renaming part

Cool, that sounds like a plan!

So this is what I have currently:

$name     = $upload['tmp_name'];
$tmpName  = pathinfo($name);
// sanitize the original filename
$filename = $tmpName['dirname']. '/'. F::safeName($upload['name']);

if (rename($upload['tmp_name'], $filename)) {
  $name = $filename;
          }
// add the files to the attachments array
$attachments[] = $name;

Would it just be this instead?

// add the files to the attachments array
$attachments[] = $upload['tmp_name'];

?

Yes, I think so

Thanks for your help so far.

This nearly works - the file is attached but doesn’t have an extension. So if I upload example.pdf the attached file is phpWaMi4z without the extension.

So I ended up going down the route of uploading the files to Kirby, and then sending them as attachments. Not ideal as the files will now sit on the server, but I think the smoothest route.

This was really helpful in getting this set up : Uploading files from frontend | Kirby CMS

You could delete them again after sending