I have a script that generates a PDF in Zend. I copied the script from converting image to pdf to another directory on the server. I now get the error:
Fatal error: Uncaught exception 'Zend_Pdf_Exception' with message 'Cannot create image resource.
File not found.' in /kalendarz/Zend/Pdf/Resource/ImageFactory.php:38
Stack trace:
#0 /kalendarz/Zend/Pdf/Image.php(124): Zend_Pdf_Resource_ImageFactory::factory('data/0116b4/cro...')
#1 /kalendarz/cms.php(56): Zend_Pdf_Image::imageWithPath('data/0116b4/cro...')
#2 {main} thrown in /kalendarz/Zend/Pdf/Resource/ImageFactory.php on line 38
Code of website, example link to image (http://tinyurl.com/8srbfza):
else if($_GET['action']=='generate') {
//1 punkt typograficzny postscriptowy (cyfrowy) = 1/72 cala = 0,3528 mm
function mm_to_pt($size_mm) {
return $size_mm/0.3528;
}
require_once("Zend/Pdf.php");
$pdf = new Zend_Pdf();
$page_w = mm_to_pt(100);
$page_h = mm_to_pt(90);
$page = $pdf->newPage($page_w.':'.$page_h.':');
$pdf->pages[] = $page;
$imagePath= 'data/'.$_GET['id'].'/crop_'.$_GET['id'].'.jpg'; //to nie jest miniaturka
$image = Zend_Pdf_Image::imageWithPath($imagePath);
$left = mm_to_pt(0);
$right = mm_to_pt(100);
$top = mm_to_pt(90);
$bottom = mm_to_pt(0);
$page->drawImage($image, $left, $bottom, $right, $top);
$pdfData = $pdf->render();
header("Content-Disposition: inline; filename=".$_GET['id'].".pdf");
header("Content-type: application/x-pdf");
echo $pdfData;
die();
}
Zend_Pdf_Image::imageWithPath expects a valid file and uses is_file function call to check the file existence.
First of all, use absolute path to the image, instead of using the relative one. You can specify the absolute path by referring to your APPLICATION_PATH. For example,
APPLICATION_PATH . '/../public/data
If APPLICATION_PATH is not already defined in your code, paste this code in your public/index.php
defined('APPLICATION_PATH')
|| define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../application'));
Then, check if 'data/'.$GET['id'].'/crop'.$_GET['id'].'.jpg' exists. Also, check if the file has proper permissions to be accessed by PHP.
Note : Use the Zend request object instead of the $_GET.
Use an absolute path:
$imagePath = '/kalendarz/data/'.$_GET['id'].'/crop_'.$_GET['id'].'.jpg';
or:
$imagePath = APPLICATION_PATH.'/../data/'.$_GET['id'].'/crop_'.$_GET['id'].'.jpg';
you might also want to put some validation on $_GET['id'].
Related
I need to create PDF's thumbnail every time it gets loaded via POST method.
Once I upload the file inside Controller, it runs getThumb function that uses Imagick to create thumbnail. The problem is that everytime I do that, this request breaks and shows this error - The "/tmp/phpY14gRo" file does not exist or is not readable..
Imagick is properly installed. I use php-7.2-apache docker image.
But if I run shell_excec script that does absolutely the same thing, it works! That eliminates all suspicions of the wrong dependency installation
Here's the function from my controller:
public function createThumb($source, $target, $size = 256, $page = 1)
{
if (file_exists($source) && !is_dir($source)): // source path must be available and not be a directory
if (mime_content_type($source) != 'application/pdf'):
return FALSE; // source is not a pdf file returns a failure
endif;
$sepa = '/'; // using '/' as file separation for nfs on linux.
$target = dirname($source) . $sepa . $target;
$size = intval($size); // only use as integer, default is 256
$page = intval($page); // only use as integer, default is 1
$page--; // default page 1, must be treated as 0 hereafter
if ($page < 0) {
$page = 0;
} // we cannot have negative values
//It breaks exactly right here
$img = new Imagick($source . "[$page]"); // [0] = first page, [1] = second page
$imH = $img->getImageHeight();
$imW = $img->getImageWidth();
if ($imH == 0) {
$imH = 1;
} // if the pdf page has no height use 1 instead
if ($imW == 0) {
$imW = 1;
} // if the pdf page has no width use 1 instead
$sizR = round($size * (min($imW, $imH) / max($imW, $imH))); // relative pixels of the shorter side
$img->setImageColorspace(255); // prevent image colors from inverting
$img->setImageBackgroundColor('white'); // set background color and flatten
$img = $img->flattenImages(); // prevents black zones on transparency in pdf
$img->setimageformat('jpeg');
if ($imH == $imW) {
$img->thumbnailimage($size, $size);
} // square page
if ($imH < $imW) {
$img->thumbnailimage($size, $sizR);
} // landscape page orientation
if ($imH > $imW) {
$img->thumbnailimage($sizR, $size);
} // portrait page orientation
if (!is_dir(dirname($target))) {
mkdir(dirname($target), 0777, true);
} // if not there make target directory
$img->writeimage($target);
$img->clear();
$img->destroy();
if (file_exists($target)) {
return $target;
} // return the path to the new file for further processing
endif;
return FALSE; // the source file was not available, or Imagick didn't create a file, so returns a failure
}
I thought that it was permission problems but found out that it's not.
Update:
If I initialize Imagick without parameters it won't throw errors and thus won't create thumbnail as it doesn't get file path. So, whenever I add file path and PHP starts searching for that file, and the error occurs. Inside the log, I noticed that the InvalidArgumentException exception was thrown by a Symfony framework.
Here's an image of the error:
After debugging I found out that Imagick was not imported into the project.
So, I just added use Imagick at the top of my Controller.
In my case i call $validator->fails() two times.
In my case, the first call $validator->fails() in my Controller action, after checking deleted the file. The second call could not find this file.
I'm using the storage facade to store an avatar which works fine, but I want to resize my image like I did in previous versions of Laravel.
How can I go about doing this?
Here is what I have so far (doesn't work)
$path = $request->file('createcommunityavatar');
$resize = Image::make($path)->fit(300);
$store = Storage::putFile('public/image', $resize);
$url = Storage::url($store);
Error Message:
Command (hashName) is not available for driver (Gd).
You're trying to pass into putFile wrong object. That method expects File object (not Image).
$path = $request->file('createcommunityavatar');
// returns \Intervention\Image\Image - OK
$resize = Image::make($path)->fit(300);
// expects 2nd arg - \Illuminate\Http\UploadedFile - ERROR, because Image does not have hashName method
$store = Storage::putFile('public/image', $resize);
$url = Storage::url($store);
Ok, now when we understand the main reason, let's fix the code
// returns Intervention\Image\Image
$resize = Image::make($path)->fit(300)->encode('jpg');
// calculate md5 hash of encoded image
$hash = md5($resize->__toString());
// use hash as a name
$path = "images/{$hash}.jpg";
// save it locally to ~/public/images/{$hash}.jpg
$resize->save(public_path($path));
// $url = "/images/{$hash}.jpg"
$url = "/" . $path;
Let's imagine that you want to use Storage facade:
// does not work - Storage::putFile('public/image', $resize);
// Storage::put($path, $contents, $visibility = null)
Storage::put('public/image/myUniqueFileNameHere.jpg', $resize->__toString());
The put method works with the Image intervention output.
The putFile method accepts either an Illuminate\Http\File or Illuminate\Http\UploadedFile instance.
$photo = Image::make($request->file('photo'))
->resize(400, null, function ($constraint) { $constraint->aspectRatio(); } )
->encode('jpg',80);
Storage::disk('public')->put( 'photo.jpg', $photo);
The above code resizes the uploaded file to 400px width while holding the aspect ratio. Then encodes to jpg at 80% quality.
The file is then stored to the public disc.
Note you must provide a filename, not just the directory.
Using Laravel 5.8
I had a similar issue when trying to read an image file with Image when this one was saved and loaded with Storage.
Beside all the answers I wasn't sure why it wasn't working.
Exception when Image was trying to read the file
Intervention\Image\Exception\NotReadableException : Unable to init from given binary data.
Short answer
Adding ->encode()solved the issue
http://image.intervention.io/api/encode
Scenario
Basically I had a test like this
Storage::fake();
$photo = factory(Photo::class)->create();
$file = \Image::make(
UploadedFile::fake()->image($photo->file_name, 300, 300)
);
Storage::disk($photo->disk)
->put(
$photo->fullPath(),
$file
);
And in the controller I had something like this
return \Image::make(
Storage::disk($photo->disk)
->get(
$photo->fullPath()
)
)->response();
Solution
After investigation I realized that any file created by Image and saved by the Storage had a size of 0 octets.
After looking at all the solutions from this post and few hours after, I noticed everyone was using encode() but no one did mention it was that. So I tried and it worked.
Investigating a bit more, Image does, in fact, encode under the hood before saving.
https://github.com/Intervention/image/blob/master/src/Intervention/Image/Image.php#L146
So, my solution was to simple doing this
$file = \Image::make(
\Illuminate\Http\UploadedFile::fake()->image('filename.jpg', 300, 300)
)->encode();
\Storage::put('photos/test.jpg', $file);
testable in Tinker, It will create a black image
The cleanest solution I could find—using the native Storage facade—is the following. I can confirm that this works in Laravel 5.7, using intervention/image version 2.4.2.
$file = $request->file('avatar');
$path = $file->hashName('public/avatars');
$image = Image::make($file)->fit(300);
Storage::put($path, (string) $image->encode());
$url = Storage::url($path);
I do it this way:
Resize and save image somewhere (such as in the public folder).
Create a new File and pass it to Laravel filesystem functions (such as putFileAs).
Delete temporary intervention file
Note: Of course you can modify it according to your needs.
$file = $request->file('portfolio_thumb_image');
$image = Image::make($file);
$image->resize(570, 326, function ($constraint) {
$constraint->aspectRatio();
});
$thumbnail_image_name = pathinfo($file->getClientOriginalName(), PATHINFO_FILENAME).'.'.$file->getClientOriginalExtension();
$image->save(public_path('images/'.$thumbnail_image_name));
$saved_image_uri = $image->dirname.'/'.$image->basename;
//Now use laravel filesystem.
$uploaded_thumbnail_image = Storage::putFileAs('public/thumbnails/'.$portfolio_returned->id, new File($saved_image_uri), $thumbnail_image_name);
//Now delete temporary intervention image as we have moved it to Storage folder with Laravel filesystem.
$image->destroy();
unlink($saved_image_uri);
Make sure to add use Illuminate\Http\File; to top of your file for this to work, and read through the documentation section Automatic Streaming.
This assumes you want all jpegs
$path = $request->file('createcommunityavatar');
$resize = Image::make($path)->fit(300)->encode('jpg');
$filePath = $resize->getRealPath() . '.jpg';
$resize->save($filePath);
$store = Storage::putFile('public/image', new File($resize));
$url = Storage::url($store);
This is how I am doing it in my application with comments to help
// Get the file from the request
$requestImage = request()->file('image');
// Get the filepath of the request file (.tmp) and append .jpg
$requestImagePath = $requestImage->getRealPath() . '.jpg';
// Modify the image using intervention
$interventionImage = Image::make($requestImage)->resize(125, 125)->encode('jpg');
// Save the intervention image over the request image
$interventionImage->save($requestImagePath);
// Send the image to file storage
$url = Storage::putFileAs('photos', new File($requestImagePath), 'thumbnail.jpg');
return response()->json(['url' => $url]);
I've done it with following way, its simple and without any path confusion :
//Get file
$path= $request->file('createcommunityavatar');
// Resize and encode to required type
$img = Image::make($file)->fit(300)->encode('jpg');
//Provide own name
$name = time() . '.jpg';
//Put file with own name
Storage::put($name, $img);
//Move file to your location
Storage::move($name, 'public/image/' . $name);
Try updating the GD extension for the current php version.
If that doesn't help, try saving the resized image on local disk and using Storage::putFile.
You may delete the file once it has been uploaded to your storage path.
The second parameter to your putFile method is an instance of the Image Intervention class. You need to pass this as the second parameter to the putFile method.
$resize->save($absolutePath . 'small/' . $imageName);
You can't store an \Intervention\Image\Image object directly with the Laravel 5 filesystem. What you can do is resize the image from your request, and save it under the same tmp path. Then just store the uploaded (overwritten) file to the filesystem.
Code:
$image = $request->file('createcommunityavatar');
//resize and save under same tmp path
$resize = Image::make($image)->fit(300)->save();
// store in the filesystem with a generated filename
$store = $image->store('image', 'public');
// get url from storage
$url = Storage::url($store);
In my case the error was caused by calling the hashName method on an image instance.
//initially
$image = Image::make(request('image')->getRealPath());
$filename = $image->hashName();
//to fix the error
$image = Image::make(request('image')->getRealPath());
$filename = request('image')->hashName();
I cannot google anywhere that one cannot use absolute path in copy() destination. However,
$baseUrl_master_MM = "http://mysite.öä/MM/";
$img_dir = 'img_1';
$img = '01.jpg';
$orig_online = $baseUrl_master_MM.$img_dir.'/'.$img;
$dest_online = '../../mm_img/'.$img_dir.'-online.jpg';
$copy = copy($orig_preview, $dest_preview);
works fine, but the same with absolute path
$baseUrl_master_MM = "http://mysite.öä/MM/";
$baseUrl_master_MM_online = "http://mysite.öä/mm_img/";
$img_dir = 'img_1';
$img = '01.jpg';
$orig_online = $baseUrl_master_MM.$img_dir.'/'.$img;
$dest_online = $baseUrl_master_MM_online.$img_dir.'-online.jpg';
$copy = copy($orig_preview, $dest_preview);
will give no errors and copies no files.
Destination directory exists, and rights are 777. Am I missing something?
You can't use the HTTP protocol to copy a file on a server. Taken from the PHP documentation on HTTP wrapper
Allows read-only access to files/resources via HTTP 1.0, using the HTTP GET method.
To copy to your local server, use an absolute path.
Please do the following :
if(!#copy($orig_preview, $dest_preview))
{
$errors= error_get_last();
echo "COPY ERROR: ".$errors['type'];
echo "<br />\n".$errors['message'];
} else {
echo "File copied from remote!";
}
Tell what the error's you see?
Also absolute path should look like :
$abs = $_SERVER['PHP_SELF'];
Sorry for post as answer , couldn't post as comment
I am having an issue with imagick php library.
I am doing a recursive search in my file system and look for any pdf files.
$it = new RecursiveDirectoryIterator("/test/project");
$display = Array ('pdf');
foreach(new RecursiveIteratorIterator($it) as $file){
if (in_array(strtolower(array_pop(explode('.', $file))), $display))
{
if(file_exists($file)){
echo $file; //this would echo /test/project/test1.pdf
$im = new Imagick($file);
$im->setImageFormat("jpg");
file_put_contents('test.txt', $im);
}
}
}
However, I am getting an error saying
Fatal error: Uncaught exception 'ImagickException' with message 'Can not process empty Imagick object' in /test.php:57
Stack trace:
#0 /test.php(57): Imagick->setimageformat('jpg')
#1 {main}
thrown in /test.php on line 57
line 57 is $im->setImageFormat("jpg");
However, if I replace my $im = new Imagick($file) with $im = new Imagick('/test/project/test1.pdf'), the error is gone.
I don't know why this is happening. Can someone give me a hint for this issue? Thanks so much
According to this, the .jpg files' format is JPEG.
Note 1:
Your $file variable is an object SplFileInfo, but you are using it always like a string. Use RecursiveDirectoryIterator::CURRENT_AS_PATHNAME flag in RecursiveDirectoryIterator's constructor, to be a real string.
Note 2:
You can filter the iterator entries with RegexIterator, f.ex.: new RegexIterator($recursiveIteratorIterator, '/\.pdf$/') (after Note 1). Or, you can use GlobIterator too for searching only pdf files.
As #pozs pointed out
Note 1: Your $file variable is an object SplFileInfo, but you are
using it always like a string.
Here's a code snippet which gets you the filename as string and has an optimized method to get the file extension:
<?php
$display = array ('pdf');
$directoryIterator = new RecursiveDirectoryIterator('./test/project');
// The key of the iterator is a string with the filename
foreach (new RecursiveIteratorIterator($directoryIterator) as $fileName => $file) {
// Optimized method to get the file extension
$fileExtension = pathinfo($fileName, PATHINFO_EXTENSION);
if (in_array(strtolower($fileExtension), $display)) {
if(file_exists($fileName)){
echo "{$fileName}\n";
// Just do what you want with Imagick here
}
}
Maybe try this approach from : PDF to JPG conversion using PHP
$fp_pdf = fopen($pdf, 'rb');
$img = new imagick();
$img->readImageFile($fp_pdf);
It also seems from reading other posts that GhostScript is faster?
i have just come across what i think i need for my front end multi uploader script in joomla.
Mootools fancy upload looks great! but i am having trouble when i uncomment the script that uploads the images inside the uploads folder?
All i have done is uncommented the default script inside the test file and created a folder called uploads which i set to 757 and also tried 777
But for some reason the uploader now returns some strange error about md 5 hash stuff?
eastern_beach_jetty.jpgAn error occured:
Warning: md5_file(/tmp/phpUjHol4) [function.md5-file]: failed to open stream: No such file or directory in /home/user/www.mydomain.com.au/test/server/script.php on line 133
{"status":"1","name":"eastern_beach_jetty.jpg","hash":false}
The fancy uploader website from where i got the script is here http://digitarald.de/project/fancyupload/
Any help on this would be so greatly apprecited,
thank you.
John
Coincidentally, I did the same mistake as you, the reason is that the first move tmp file to the destination folder, and then referring to the tmp file, which no longer exists, because it is in the target folder. I know that the late response, but it was as if someone had the same problem.
Not:
move_uploaded_file($_FILES['Filedata']['tmp_name'], '../uploads/' . $_FILES['Filedata']['name']);
$return['src'] = '/uploads/' . $_FILES['Filedata']['name'];
if ($error) {
(...)
} else {
(...)
// $return['hash'] = md5_file($_FILES['Filedata']['tmp_name']);
// ... and if available, we get image data
$info = #getimagesize($_FILES['Filedata']['tmp_name']);
if ($info) {
$return['width'] = $info[0];
$return['height'] = $info[1];
$return['mime'] = $info['mime'];
}
}
Yes:
if ($error) {
(...)
} else {
(...)
// $return['hash'] = md5_file($_FILES['Filedata']['tmp_name']);
// ... and if available, we get image data
$info = #getimagesize($_FILES['Filedata']['tmp_name']);
if ($info) {
$return['width'] = $info[0];
$return['height'] = $info[1];
$return['mime'] = $info['mime'];
}
}
move_uploaded_file($_FILES['Filedata']['tmp_name'], '../uploads/' . $_FILES['Filedata']['name']);
$return['src'] = '/uploads/' . $_FILES['Filedata']['name'];