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:
- Generate as many thumbnails (transformed files) as you need.
- 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);
}