Home > Mobile >  Ci4 / Image Upload and Manipulate Error / finfo_file(/tmp/phpSrVWUZ): failed to open stream: No such
Ci4 / Image Upload and Manipulate Error / finfo_file(/tmp/phpSrVWUZ): failed to open stream: No such

Time:02-02

I am trying to (1) upload a image file (2) resize it and center it and (3) change the file name and (4) move it into /public dir.

Here is a part of my code;

$path = $this->request->getFile('dh_site_logo')->store();
            
$temp_file_path = WRITEPATH.'uploads/' . $path;

service('image')
    ->withFile($temp_file_path)  // must include full path
    ->fit(250,150,'center')
    ->save($temp_file_path);
            
$public_file_path = ROOTPATH.'public';
$file_to_upload = 'site_logo.'.$update_post->guessExtension();;
$overwrite = true;      
        
$update_post->move($public_file_path, $file_to_upload, $overwrite);

I assume I would have to do the image manipulation in the writable/uploads directory prior to moving to /public

I cant seem to lock on to the file that has been uploaded with a new random name, manipulate and then move.

Tried this, too

            // example of return $path = "20220130/1643544458_5a528551d1fe83c88e02.gif"
            $path = $this->request->getFile('dh_site_logo')->store('site_logo', 'site_logo.gif');
            
            $temp_file_path = WRITEPATH.'uploads/' . $path;

             service('image')
                ->withFile($temp_file_path)  // must include full path
                ->fit(250,150,'center')
                ->save($temp_file_path);
            
            $public_file_path = ROOTPATH.'public';
            $new_file_name = 'site_logo.gif';
            $overwrite = true;      
        
            $update_post->move($public_file_path, $new_file_name, $overwrite);

The above give me an error, The uploaded file has already been moved

CodePudding user response:

Ci4 / Image Upload and Manipulate Error / finfo_file(/tmp/phpSrVWUZ): failed to open stream: No such file or directory

Problem 1:

You're receiving the above error because of the line of code below:

$file_to_upload = 'site_logo.'.$update_post->guessExtension();;

Explanation 1:

On your first line of code below:

$path = $this->request->getFile('dh_site_logo')->store();

You're calling the CodeIgniter\HTTP\Files\UploadedFile::store(?string $folderName = null, ?string $fileName = null) method which saves the uploaded file (/tmp/phpSrVWUZ) to a new location.

I.e: The store(...) method moves the uploaded file from the server's default temporary directory (/tmp) to the project's upload directory (WRITEPATH . 'uploads/').

You then try calling $update_post->guessExtension() forgetting that the UploadedFile instance $update_post still refers to the old non-existent path (/tmp/phpSrVWUZ), hence the error.

To be more specific, the method CodeIgniter\HTTP\Files\UploadedFile::guessExtension() calls another method CodeIgniter\Files\File::getMimeType(). The method getMimeType(...) tries to retrieve the mime type using the code snippet below on a non-existent file resulting in the error:

finfo_file(finfo_open(FILEINFO_MIME_TYPE), "/tmp/phpSrVWUZ");

// PHP Warning:  finfo_file(/tmp/phpSrVWUZ): Failed to open stream: No such file or directory in ...

=========

Problem 2:

Tried this, too

...

The above give me an error, The uploaded file has already been moved

Explanation 2:

You normally receive this error because you're trying to move the uploaded file to a new location more than once.

This happens when you call the CodeIgniter\HTTP\Files\UploadedFile::store(...) or CodeIgniter\HTTP\Files\UploadedFile::move(...) method more than once.

Excerpt from CI 4.x source code.

/**
 * Move the uploaded file to a new location.
 * ...
 * If this method is called more than once, any subsequent calls MUST raise
 * an exception.
 * ...
 */
public function move(...): bool {
// ...
        if ($this->hasMoved) {
            throw HTTPException::forAlreadyMoved();
        }
// ...

}

To be more specific, every UploadedFile instance has a property called protected $hasMoved = false; which gets updated to true once the uploaded file has been moved successfully from the server's default temporary directory:

Excerpt from CI 4.x source code.

    /**
     * Returns whether the file has been moved or not. If it has,
     * the move() method will not work and certain properties, like
     * the tempName, will no longer be available.
     */
    public function hasMoved(): bool;

Solution A:

This applies if you don't care about the original uploaded file and you're only interested in the final transformed/resized file residing in the 'public' path.


public function createThumbnail(\CodeIgniter\HTTP\Files\UploadedFile $uploadedFile, ?string $newThumbnailFileName = null, int $width = 250, int $height = 150, string $position = "center"): ?\CodeIgniter\Files\File
{
    if (!$uploadedFile->isValid()) {
        return null;
    }

    $newThumbnailFileName = $newThumbnailFileName
        ? ((($point = strrpos($newThumbnailFileName, ".")) === false) ? $newThumbnailFileName : substr($newThumbnailFileName, 0, $point)) . $uploadedFile->guessExtension()
        : $uploadedFile->getRandomName();

    $targetPath = ROOTPATH . 'public' . DIRECTORY_SEPARATOR . $newThumbnailFileName;

    \Config\Services::image()
        ->withFile($uploadedFile->getRealPath() ?: $uploadedFile->__toString())
        ->fit($width, $height, $position)
        ->save($targetPath);

    return new \CodeIgniter\Files\File($targetPath, true);
}

The function above basically leaves the original uploaded file in the server's default temporary directory untouched and processes a new image which gets saved in the project's 'public' path.

Usage For Solution A:

The function above returns a CodeIgniter\Files\File instance representing the newly transformed image. I.e:

$requestFileName = "dh_site_logo";
$uploadedFile = $this->request->getFile($requestFileName);

// Generates a thumbnail in the 'public' path with a uniquely generated filename.
$thumbnail = $this->createThumbnail(
    uploadedFile: $uploadedFile
);

// OR

// Generates a thumbnail in the 'public' path with a custom filename ('site_logo').
$thumbnail = $this->createThumbnail(
    uploadedFile: $uploadedFile,
    newThumbnailFileName: "site_logo"
);

// OR

// You can modify the default parameters as well.
$thumbnail = $this->createThumbnail(
    uploadedFile: $uploadedFile,
    width: 100,
    height: 150,
    position: "left"
);

Solution B:

This applies if for some reason you want to transform/resize and save the modified image in the 'public' path similar to Solution A and still persist/keep or move the original uploaded file from the server's temporary directory to your project's writable/uploads folder for future reference or purposes.

TIP: The file will be deleted from the temporary directory at the end of the request if it has not been moved away or renamed. - Excerpt From PHP Doc: Example #2 Validating file uploads

Steps:

  1. Generate as many thumbnails (transformed files) as you need.
  2. Lastly, move the uploaded file from the server's default temporary directory to the project's writable/uploads folder.

$requestFileName = "dh_site_logo";
$uploadedFile = $this->request->getFile($requestFileName);

// 1. Generate as many thumbnails (transformed files) as you need.

// Generates a thumbnail in the 'public' path with
// a uniquely generated filename.
$thumbnail = $this->createThumbnail(
    uploadedFile: $uploadedFile
);

// 2. Lastly, move the uploaded file from the server's default temporary
// directory to the project's 'writable/uploads' folder (I.e: $uploadedFile->store()).

if (!$uploadedFile->hasMoved()) {
    // The moved uploaded file.
    $file = new \CodeIgniter\Files\File(WRITEPATH . 'uploads/' . $uploadedFile->store(), true);
}

  •  Tags:  
  • Related