Why is php rename() corrupting my file? - php

I am using plupload to do an upload of multiple files to my server. Using this, there is a parameter 'url : 'upload.php'. upload.php catches the files as they are received, and might recombine them if they get chunked. Once the full file is received, it sends a response back to the original page, displaying a green checkbox icon.
I have added some code to this page, after all the main code to manipulate the photos I have uploaded. My plan is to create three copies of my full size image, lg, med, and small. I got this part working, but then decided to first rename the original file to match my naming scheme.
I now get a corrupted renamed file, and thus my three smaller images also get corrupted.
//get the original file info
$filepath = $_SERVER['DOCUMENT_ROOT'].'/uploads/';
$filepathinfo = pathinfo($filepath.$fileName);//fileName is used previously in the file
//rename original file to a unique name
$finding_id = 'xyz';
$file_name_new = uniqid($client_id . '-' . $finding_id . '-', true); //doesn't include extension
//rename($filepath.$fileName, $filepath.$file_name_new.'.'.$ext);
//copy($filepath.$fileName, $filepath.$file_name_new.'.'.$ext);
As is, I get my one file, or how ever many I uploaded, byte size matches original exactly, and name stays the same (except for removal of certain characters).
If I uncomment only the rename function, I actually get two files. The byte sizes total the original photo. The larger file displays with a section of gray at the bottom. The smaller file doesn't display at all.
If I uncomment only the copy function, I get an exact renamed copy of my original file, my original file, and another file, the same size and corruption as the larger file doing a rename.
Any ideas? Seems like it should be pretty straightforward.

if the file was currently uploaded by HTTP POST use move_uploaded_file
if you fopen() somewhere in this request the same file make sure to call fclose()

I forgot I had the chunking feature turned on. Must have turned it on to test something. For whatever reason, when the script was running the last chunk of the file hadn't been fully appended yet. Thanks for all the input anyway!

Are you writing to the file yourself? If so, the problem might be that you're missing a call to fflush or fclose. (The last chunk of the file not getting written and the file no longer being there when PHP gets round to writing it. This shouldn't happen if you're using Linux or some other Unix, but I could envisage it on Windows.)

Related

using PHP to remove the extension from a file and then downloading it

I recently had a asked a question very similar to this one, however after evaluating that I did not explain it in the best way I have come back once again explaining it in a greater manner.
So, I am creating a system that will gather data from a MySQL database and use a unique id to download a file, however depending on the value of a column within that database called type, this file could be anything from a png file to an xml file. What I am currently doing is trying to download these files WITHOUT any extension.
As an example to maybe make this easier to understand, a file named image.png would be converted to just image and then downloaded.
With this you could rename the file to image.png again on the local machine and view the image.
This may seem very inefficient to most reading this but for my current situation it's all that will work.
How could I remove a files extension and then download it? (in php)
Thank you in advance.
Just use headers to specify response type.
$filepath = '/wherever/the/file/is.png';
$filename = 'new-cool-name';
header('Content-Type: whatever/content-type-is');
header("Content-disposition: attachment;filename=$filename");
readfile($filepath);
This basically sends a response with specified content-type as an attachment and the body of the attachment contains the file contents. If you never sure what's the content type is, then just use application/octet-stream
Usually when you set out to push a file for downloading from a serverside script, you do so by utilizing http headers like https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition
The filename of the downloadable file is specified in that header
Okay so to remove an extention from a file you could do is
$withoutExtion = preg_replace('/\\.[^.\\s]{3,4}$/', '', $youfilename);
...followed by your file download code

Add a default mp3 extension to file name that already does not have mp3 extension

I have a website where users upload mp3 files and get a link. All the files are upload from a form to the database table. But the problem is that some of the files being uploaded do not contain .mp3 extensions I think this is because of the devices users have they save audio files with just name.
here is an example url to the file :
www.example.com/images/my_audio
As you can see .mp3 extension is missing.
And I want this link to appear like this (with a default .mp3 extension)
www.example.com/images/my_audio.mp3
How can I validate the image name during upload and add an extension if it is without extension?
I tried with str_replace()
str_replace(" ",",".mp3",$file);
But it does not seem to work.
Any idea?
You can use this:
if(preg_match('/mp3/',$file))
{
echo 'It has extension';
}
else
{
$file .= '.mp3';
}
If you want a one-liner you could always use
preg_replace("/(.+)(?<!\.mp3)$/i", "$1.mp3", $file_name);
First argument to preg_replace says
Grab any text (.+), as long as the
Text immediately before the end of the line (EOL = $) is not .mp3: (?<!\.mp3)
At this point there are two possibilities. Depending on if the user had an .mp3 extension at the end of the file name, either we've found something that matches the two criteria above, or we haven't:
If you do have something of the form of XYZ.mp3 it just gets returned as-is, which is the desired behaviour. This is because it failed criteria #2 and did not get grabbed.
Otherwise, the second argument to preg_replace says we take the text we grabbed ($1), and append .mp3.
The word on the street is true though. You really should verify that the file data is in fact an mp3.
You might want to look at the pathinfo() function, which can give you the various pieces of the filename.

base64 Pic Upload and Crop Situation PHP

I am trying to take a pic upload from a mobile device to a server. We are building with PhoneGap (Javascript), so we are having turn it into a string in order to send it to the server. I am having problems once I receive it, to turn it back into a readable image file.
Simply put, I need to take a string and a file name sent to me, decode it, convert it into a .png, then crop it into a circular image.
This is what I have going on currently
if (isset($_POST['file']))
{
//Result variable
$result = false;
$pic = base64_decode($_POST['file']);
$filename = $_POST['filename'];
if (strlen($pic) > 9 )
{
$fh = fopen("/var/www/pics/events/".$filename, 'w') or die("can't open file");
fwrite($fh, $pic);
fclose($fh);
}
}
I think I can get the rest of the code to work if I can figure out what I am doing wrong here that makes it not save properly as a image file? The file uploads correctly, but it stores with out an extension, and when I point to it in my browser, it comes up like it is supposed to be an image file, but never displays the image. That little broken picture icon with the colored shapes is what I get when I direct to it's location.
Do I need to be aware of what image type is being sent during this process at all? How is it knowing if it is a .gif, .jpg/jpeg, .png, etc...?
Thanks in advance for any help!
Nathan
For Security reasons you should sanitize the file name to prevent directory traversal.
On a brighter note, make sure the file is saved with the proper extension; if you are already saving with the correct extension you could have an encoding issue from the app.
If neither of the previous possibilities are the case make sure that your String Size does not exceed the maximum POST size limit in your php.ini; if that is the case increase the size limit.

Clean up after creating the pdf

I'm generating a pdf file with html2fpdf.
$pdf = new HTML2FPDF();
$pdf->HTML2FPDF("P","mm","A4");
$pdf->AddPage();
$pdf->WriteHTML($html);
$pdf->output('sample.pdf');
This sample works great. But:
How do I delete the pdf after the output? I just want to have links in my tool, the users can download the pdf and after that it shoud be deleted on the server.
How can I 'clean up' after generating the pdf?
You can use PHP's file deletion function called unlink()
Call this function with the full path to the generated PDF file (or any file for that matter) and PHP will delete that file.
http://php.net/manual/en/function.unlink.php
You don't necessarily have to delete the file immediately after the user has downloaded it. You can just as easily place all the generated files in one central folder and have a cron job execute a more general clean up script simply removing the older files.
One method could be -
Scan the contents of the folder using scandir().
Iterate over its files in a foreach loop..
Inspect the creation time of each file using filemtime().
If the creation time was over hour ago, delete the file using unlink().
Because you are generating the PDF file yourself within your PHP code, I didn't mention the permissions consideration. Here would be a good place to mention that your PHP must have the correct file system permissions in order to perform any action on the file system. You are creating a PDF file so it's safe to assume that you have the correct permissions to make changes to the file system but if you plan on using this unlink() function in other scripts make sure that the files you are dealing with have the correct permissions set.
If you don't add the 'F' flag to the output function there will be no pdf files stored on the server at all:
$pdf->output('sample.pdf', 'F'); //stores PDF on server
In your case the script itself behaves like an actual pdf file. So, creating a link to the script is just like a link to the pdf, except that the PDF is created every time the script is requested. To tell the browser it's a PDF the content-type response header must be set to application/pdf:
content-type: application/pdf
This way the broser knows that it's a pdf even if the URL is ending in a .php. You can use rewrite engine to make it end in pdf or whatever else.
Sending the headers is done by the fpdf/tcpdf. In short: you don't have to do any cleanup, because no pdf file is stored on the server.
If you wonder what the name is for than, try saving the pdf file. The recommanded name when saving will be sample.pdf.
Reference:
PHP header() function, at the examples there is one for sending pdf
FPDF::Output()
TCPDF::Output()

Remote uploading MULTIPLE images

Okay, I have a question guys. I want to remote upload (copy an image from a site to my server) MULTIPLE images by putting links into a TEXTAREA and hitting submit. I just don't know how to make this possible with multiple images.
I am able to make it with an single image using the copy(); function, but not for multiple entries in a TEXTAREA.
I also want to limit the remote uploading feature up to 30 remote links and one image should not exceed 10MB - But I don't know how to start. I heard cURL is able to make this and I also heard that file_get_contents(); with file_put_contents(); can make a similar thing, but I still cannot figure out how to do it myself.
Help anyone? :)
You can use the same procedure as you do now with a single image, but do it in a loop.
$lines = explode("\n", $_POST['textarea']);
if(count($lines) > 30) {
die('Too many files');
}
foreach($lines as $line) {
$srcfile = trim($line);
//copy $srcfile here
//check size of the file with filesize()
}
You need to parse the URLs out of the textarea. You could with this PHP side with a regular expression.
You could then examine the parsed URLs and array_slice() the first 30, or error if more than 30.
You'd then need to copy the files from the remote server. You could inspect the Content-Length header to ensure the file is under 10mb. You could get just the headers using HEAD instead of GET.
I am not familiar with PHP but I suggest the following:
Solving the multiple files upload issue:
splitting the content in the text area by the carriage return
then iterate them to get image
preserve the size of each file in a variable, but how to get the size?
you can do exec (system) call to know the file size (this requires a full image download but its the most convenient way ), or you can make use of Content-Length header value, if the content length is more than 10 MG then skip it and move to the next item.
How to download the image?
use the file put content but make sure to put the encoding as binary encoding to preserve the content type.

Categories