PHP: imagemagick creates empty image with convert - php

I have a script that is supposed to take an image and convert it to a .jpg. This is the code that makes it happen:
$uploadDir = $_SERVER['DOCUMENT_ROOT'] . "/blogimages/";
$tempFile = ereg_replace("'", "_", basename($_FILES['newsImg']['name']));
$uploadFile = $uploadDir . $tempFile;
move_uploaded_file($_FILES['newsImg']['tmp_name'], $uploadFile);
$newPic = $uploadDir . $blogID . ".jpg";
if(file_exists($newPic)){
unlink($newPic);
}
$convertString = "$IM -strip $uploadFile $newPic";
echo "<!-- $convertString -->";
exec($convertString);
as can be seen I put the final string in an HTML comment so I can see what is being executed. What happens is that the converted image is created, but it is a 0 byte image. So no data is actually written to the file. Just to make sure convert is actually working like it normally should I copy and pasted the convert string from the html comment to a command line and it works just fine. It only seems to be having problems within the PHP exec. Any thoughts on why this might be?

I'm thinking perhaps the upload file handle isn't yet closed when you try to execute the command? That way Imagemagick would see an incomplete file.
Looking at the code I don't see how it could happen, especially since the file is moved around, but it would explain the behavior.

Start by doing some error checking on the $_FILES['newsImg']['name'] and follow it up by making sure the move_uploaded_file(...) succeeded.

Related

Laravel File Exception "Could not move the file"

So I'm working on a basic file upload system that for the most part seems to be working. Most files go through perfectly and upload without a hitch, but for some reason, other files do not and I get the following error:
This isn't a permissions error as it does work for some files - I don't believe it to be a filesize or filetype issue either.
My upload method is as follows:
$file = Input::file('photo');
$destinationPath = 'user_img/';
$extension = $file->getClientOriginalExtension();
$rand = str_random(12);
$filename = 'usr_'. Auth::user()->id . '_str=' . $rand . '_file='. Crypt::encrypt($file->getClientOriginalName()) .'.'. $extension;
$upload_success = $file->move($destinationPath, $filename);
I'm not finding any solution on the web, and I can't figure out why it's throwing this exception. Any ideas?
I don't want to count all characters in the filename in the screenshot, but there could be an issue with the length of your file name. Wikipedia Filename - Length Restrictions
In my case, this was the issue: using reserved characters in a file name.
This is how i was getting the file name:
$photo_name = "User_".md5($user->id).'_'.date('Y-m-d H:i:s').".$ext";
This would mean that the eventual file name would have characters like -,: and _. On reading this Wikipedia article https://en.wikipedia.org/wiki/Filename#Reserved_characters_and_words , i realised that the : (colon) is a reserved character and once i got rid of it (by amending the timestamp section to date('Ymd_His'), the error was gone and the upload was successful.
Ah damn, it seems as my filelengths were over 255 characters and thus the filesystem wasn't liking it. I've changed from Crypt to MD5 and the issue is now resolved.
Something similar happened to me, the context was this: through the view I was loading a file through an input. When I tried to save the file to a folder, I got this error. I use laravel 9 with livewire.
In the end I just had to use the methods provided by liveware:
$filename = time() . $this->documento->getClientOriginalName();
$this->documento->storeAs('documents', $filename, 'public');
Fuentes: https://laravel-livewire.com/docs/2.x/file-uploads

Sometimes my PHP function doesn't work well

I wrote a php function to copy an internet image to local folder, sometimes it works well, but sometimes it just generate an invalid file with size of 1257B.
function copyImageToLocal($url, $id)
{
$ext=strrchr($url, ".");
$filename = 'images/' . $id . $ext;
ob_start();
readfile($url);
$img = ob_get_contents();
ob_end_clean();
$fp=#fopen($filename, "a");
fwrite($fp, $img);
fclose($fp);
}
Note: The $url passed in is valid, sometimes this function fails at first time, but may successful for the second or third time. It's really strange...
Does this require some special PHP settings?
Please help me!
I have found the real reason: the test image url is not allowed for program accessing, though it can be opened in browser.
I tried some other image url, the function works well.
So, it seems I need find a way to process this kind of cases.
Thanks guys!
Why don't you just open the file and write it to the disk like so:
file_put_contents($filename, fopen($url, 'r'));
This will even do buffering for you so you shouldn't run into memory problems (since you are storing the whole image in memory before writing it to a file)

Passing uploaded files from php to Perl script

I have a perl script which takes input as a file and return results in text files. I want to use file as input, which is uploaded by user through php page. For that what should I do? I have PHP 5.3.14 and ActivePerl 5.14.x.
In PHP, when a file is uploaded, it is first placed in a temporary location. You can move it to another location using move_uploaded_file():
http://php.net/manual/en/function.move-uploaded-file.php
Then, you can call your Perl script in a variety of ways, which are outlined here:
How can I call a Perl script from PHP?
So, let's say you are using the low-level method of using the exec() function, and the file is uploaded in a file upload field with name "userfile", you might use something like this:
$perlCommand = // ... something, e.g. from config ...
$workingPath = // ... something, e.g. from config ...
$filename = $workingPath . $_FILES['userfile']['name']
if (move_uploaded_file($_FILES['userfile']['tmp_name'], $filename)) {
$output = array();
$return = 0;
exec($perlCommand . ' ' . $filename, $output, $return);
// Do something with $output and / or $return values
}
Note that this assumes that the Perl script takes the name of the file as an argument. It might be that it reads the file from standard input, it wasn't clear from the question. Obviously if it is the latter then it will be a bit different, again depending on the method you use to call Perl.
Thanks #leftclickben
I've solved the problem. I used a form to get file from user and then saved the filename to an argument $file.
Then I passed $file to Perl script using
$result = shell_exec("path\to\perl.pl" $file);
echo $result;
$file passed to perl.pl as an array named $ARGV[0]
#!usr/bin/perl
$filename = $ARGV[0];
open(HDL, $filename) or die "file not available, restart program\n";

How can I improve this PHP code?

I have the php code below which help me get a photo's thumbnail image path in a script
It will take a supplied value like this from a mysql DB '2/34/12/thepicture.jpg'
It will then turn it into this '2/34/12/thepicture_thumb1.jpg'
I am sure there is a better performance way of doing this and I am open to any help please
Also on a page with 50 user's this would run 50 times to get 50 different photos
// the photo has it is pulled from the DB, it has the folders and filename as 1
$photo_url = '2/34/12/thepicture_thumb1.jpg';
//build the full photo filepath
$file = $site_path. 'images/userphoto/' . $photo_url;
// make sure file name is not empty and the file exist
if ($photo_url != '' && file_exists($file)) {
//get file info
$fil_ext1 = pathinfo($file);
$fil_ext = $fil_ext1['extension'];
$fil_explode = '.' . $fil_ext;
$arr = explode($fil_explode, $photo_url);
// add "_thumb" or else "_thumb1" inbetween
// the file name and the file extension 2/45/12/photo.jpg becomes 2/45/12/photo_thumb1.jpg
$pic1 = $arr[0] . "_thumb" . $fil_explode;
//make sure the thumbnail image exist
if (file_exists("images/userphoto/" . $pic1)) {
//retunr the thumbnail image url
$img_name = $pic1;
}
}
1 thing I am curious about is how it uses pathinfo() to get the files extension, since the extension will always be 3 digits, would other methods of getting this value better performance?
Is there a performance problem with this code, or are you just optimizing prematurely? Unless the performance is bad enough to be a usability issue and the profiler tells you that this code is to blame, there are much more pressing issues with this code.
To answer the question: "How can I improve this PHP code?" Add whitespace.
Performance-wise, if you're calling built-in PHP functions the performance is excellent because you're running compiled code behind the scenes.
Of course, calling all these functions when you don't need to isn't a good idea. In your case, the pathinfo function returns the various paths you need. You call the explode function on the original name when you can build the file name like this (note, the 'filename' is only available since PHP 5.2):
$fInfo = pathinfo($file);
$thumb_name = $fInfo['dirname'] . '/' . $fInfo['filename'] . '_thumb' . $fInfo['extension'];
If you don't have PHP 5.2, then the simplest way is to ignore that function and use strrpos and substr:
// gets the position of the last dot
$lastDot = strrpos($file, '.');
// first bit gets everything before the dot,
// second gets everything from the dot onwards
$thumbName = substr($file, 0, $lastDot) . '_thumb1' . substr($file, $lastDot);
The best optimization for this code is to increase it's readability:
// make sure file name is not empty and the file exist
if ( $photo_url != '' && file_exists($file) ) {
// Get information about the file path
$path_info = pathinfo($file);
// determine the thumbnail name
// add "_thumb" or else "_thumb1" inbetween
// the file name and the file extension 2/45/12/photo.jpg
// becomes 2/45/12/photo_thumb.jpg
$pic1 = "{$path_info['dirname']}/{$path_info['basename']}_thumb.{$fil_ext}";
// if this calculated thumbnail file exists, use it in place of
// the image name
if ( file_exists( "images/userphoto/" . $pic1 ) ) {
$img_name = $pic1;
}
}
I have broken up the components of the function using line breaks, and used the information returned from pathinfo() to simplify the process of determining the thumbnail name.
Updated to incorporate feedback from #DisgruntledGoat
Why are you even concerned about the performance of this function? Assuming you call it only once (say, when the "main" filename is generated) and store the result, its runtime should be essentially zero compared to DB and filesystem access. If you're calling it on every access to re-compute the thumbnail path, well, that's wasteful but it's still not going to be significantly impacting your runtime.
Now, if you want it to look nicer and be more maintainable, that's a worthwhile goal.
The easiest way to fix this is to thumbnail all user profile pics before hand and keep it around so you don't keep resizing.
$img_name = preg_replace('/^(.*)(\..*?)$/', '\1_thumb\2', $file);
Edit: bbcode disappeared with \.

Remove spaces in file names apache

1.Hi, I have a internal use only file upload script that uploads the files to a directory. When I upload something from my computer with a spcace in the name i.e example 1.zip it uploads with a space in the name thus killing the link in a email. Is it possible to make apache remove the space when its uploaded or make it a underscore?
The second problem I am having is how would I parse this to make the link an email link with the url of the file as the body of the email amd the email addy anything?
if (move_uploaded_file($_FILES['file']['tmp_name'], $uploaddir . $_FILES['file']['name'])) {
// uploaded file was moved and renamed succesfuly. Display a message.
echo "Link: " . "http://example.org/" . $_FILES["file"]["name"];
You just need to urlencode() your file name and everything is fine:
echo "Link: http://example.org/" . urlencode($_FILES["file"]["name"]);
But if you want to remove the spaces for another reason, you can use str_replace():
$replaced_name = str_replace(' ', '_', $_FILES["file"]["name"]);
rename($uploaddir . '/' . $_FILES['file']['name'], $uploaddir . '/' . $replaced_name);
# You should urlencode() it nonetheless:
echo "Link: http://example.org/" . urlencode($replaced_name);
Try:
$filename = $_FILES['file']['name'];
$filename = preg_replace("/[^a-zA-Z0-9]/", "", $filename);
//then
if (move_uploaded_file($_FILES['file']['tmp_name'], $uploaddir . $filename)) {
// uploaded file was moved and renamed succesfuly. Display a message.
echo "Link: " . "http://example.org/" . $filename;
As a side note : with the code you are using, what is happening if two files with the same name are uploaded ? If you don't do a check (like "is there a file that already has that name in $uploaddir ?") the second file will replace the first one.
That might not be something you want... is it ?
If not, to solve that (potential) problem, one solution is to always rename uploaded files, with names you control. (A simple counter would probably to the trick)
Another thing is : $_FILES["file"]["name"] is sent by the client, and, as such, can probably be forged to contains whatever someone would want. If it contains something like "../../index.php" (or something like this - you get the idea), this could allow someone to put any file they want on your server.
To prevent this from happening, you shoud be sure the file name/path used as destination of move_uploaded_file does not contain anything "dangerous". A solution could be to use basename. (see, for instance, example #2 on POST method uploads)
You might also want to check the mimetype of the uploaded file, so you don't get executables, for instance -- and you should make sure files uploaded are not executable by the webserver.

Categories