File downloaded from PHP script is different than file on server - php

I have a html file that allows a user to submit a file to post a file to my 'upload_file.php' PHP script.
index.html:
<html>
<body>
<form action="upload_file.php" method="post" enctype="multipart/form-data">
<label for="file">Filename:</label>
<input type="file" name="file" id="file"><br>
<input type="submit" name="submit" value="Submit">
</form>
</body>
</html>
upload_file.php referenced above takes in a file, does some work, and spits out a xlsx file (using PHPExcel). After creating the PHPExcel object, this is how I write it to the server and then force the user to download:
// Save Excel 2007 file
$objWriter = new PHPExcel_Writer_Excel2007($objPHPExcel);
$fileBase = explode(".",$_FILES['file']['name']);
$outFilename = $fileBase[0] . date('His') . ".xlsx";
$objWriter->save($outFilename);
$url = "http://localhost/QWDATA/$outFilename";
//Initiate user download of file
header("Content-Type: application/octet-stream");
header("Content-Transfer-Encoding: Binary");
header("Content-disposition: attachment; filename=\"$outFilename\"");
echo readfile($url);
When I do this, the download is initiated successfully... with one issue:
Opening the file that is downloaded results in an error in excel:
"We found a problem with some content in $filename. Do you want us to
try to recover as much as we can? If you trust the source of this
workbook, click Yes."
Clicking "yes" on the excel error results in a 'repaired' xlsx file opening and looking exactly as one would expect. Looking at a log of repairs that were done gives me this:
error129480_02.xmlErrors
were detected in file
'C:\XPATHX\$filename.xlsx'Excel
completed file level validation and repair. Some parts of this
workbook may have been repaired or
discarded.
... which is to say, nothing specific.
Tracking the issue back, opening the file directly from the server does NOT result in this error; telling me something additional is going on in the download code above.
My question is: What could be causing this and/or how can I solve the problem?

readfile echoes by itself. You don't need to call echo.
Actually, doing so, will echo the result of readfile (which is the size of the file as an integer), so that causes a couple of extra bytes at the end of the file. This will be easy for Excel to fix, and probably won't result in actual data loss, but still the file is invalid, so you get the error.

Looking at the file on the server and the file that downloads, I noticed a 5 byte difference.
Having already removed all other echo commands from the php file due to suggestions here (https://phpexcel.codeplex.com/discussions/42854) and here (PHPExcel File format or extension is not valid) I knew something had to be adding information.
I made the following changes to the above code -- taking out the escaped quotes in the filename (just a personal guess) in the header setting and changing echo to readfile (as suggested here: http://webdesign.about.com/od/php/ht/force_download.htm). Thus giving me:
// Save Excel 2007 file
$objWriter = new PHPExcel_Writer_Excel2007($objPHPExcel);
$fileBase = explode(".",$_FILES['file']['name']);
$outFilename = $fileBase[0] . date('His') . ".xlsx";
$objWriter->save($outFilename);
$url = "http://localhost/QWDATA/$outFilename";
//Initiate user download of file
header("Content-disposition: attachment; filename=$outFilename");
header("Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
header("Content-Transfer-Encoding: Binary");
readfile($outFilename);
This appears to directly download the file with no additions -- which means excel is happy and the problem is solved.
In short, it appears echo readfile($outFilename); needed to just be readfile($outFilename);

Related

Initiate download without button

I'm a PHP newbie ... and stuck!
I would like to realize this HTML/PHP project in a single file (as opposed to using .html and .php files separately).
Basically, 3 steps are necessary.
upload a PDF file.
process the PDF file. Output is a .txt file.
offer the user the processed .txt file without the standard download button.
(1.) and (2.) is already properly implemented and works fine. (3.) is my problem/question. The internet offers several solutions, but all with download buttons which the user has to press to trigger download from server to local machine. I would like to write (in PHP only) code which offers the user a Save Dialog Box, which permits saving the .txt file locally. Is this possible without any HTML code, hence solely by PHP?
Below the real code heavily simplified to the necessary.
<form action = "" method = "POST" enctype = "multipart/form-data">
Select PDF file to be uploaded.
<input type = "file" name="pdffile" />
<input type = "submit" name = "submit" value = "upload roster" />
</form>
<?php
if(isset($_FILES['pdffile'])) {
$errors = array();
$file_name = $_FILES['pdffile']['name'];
$file_size = $_FILES['pdffile']['size'];
$file_tmp = $_FILES['pdffile']['tmp_name'];
...
move_uploaded_file($file_tmp, "/home/user/pdf2txt/uploads/" . $file_name);
$cmd = "../../pdf2txt/pdf2txt ../../pdf2txt/uploads/" . $file_name;
...
// the stdout of pdf2txt is stored in /tmp/pdffile.txt
// initiate download to user - THAT'S MY PROBLEM/QUESTION
...
?>
EDIT
Maybe I was too short. The project should be realized inside a WordPress page. I use a PHP plugin which permits PHP code injection. Now ... using the code of #mrid, I get ...
Warning: Cannot modify header information – headers already sent by (output started at /home/geohei/mysite/WP_TEST/wp-content/themes/blackoot-pro/header.php:12) in /home/geohei/mysite/WP_TEST/wp-content/plugins/insert-php/insert_php.php(48) : eval()’d code on line 81
insert-php.php is the WordPress PHP plugin.
blackroot is the theme.
I understand that headers were already previously sent by the theme and I am not allowed to change them.
What can be done in such a situation?
Here's an example of
header('Content-Disposition: attachment; filename=' . basename($filename) . '"');
header("Content-type: text/plain");
header('Content-Length: ' . filesize($filename));
readfile($filename);

PDF Download gives corrupt PDF php

I am saving a pdf file, and then attempting to download it using php.
The script seemed to work fine, but all of the sudden not anymore.
Can anybody see what I am missing?
PS: the file I am downloading is only 4.3kb big, so I assume that would be because it is not downloading at all. The actual file size should be bigger than this.
$pdf->output(ROOTDIR.'/modules/addons/statement_generator/reports/statement.pdf');
if($action=='print'){
$file_name = 'statement.pdf';
$file_url = "http://".$_SERVER['SERVER_NAME']."/modules/addons/statement_generator/reports/" . $file_name;
header('Content-Type: application/pdf');
header("Content-Transfer-Encoding: Binary");
header("Content-disposition: attachment; filename=\"".$file_name."\"");
readfile($file_url);
exit;
}
The $pdf->output() call will already send the PDF to the client. The file will not be saved to your local folder (Didn't you checked at least this?) because you have to pass "F" as the snd parameter.
After that you try to read from an URL (!!!!) that does not exists and which maybe return a nicely styled 404 html response. Two issues here:
Why are you using http when you have the local path used some lines above? Use the local path only!
The content returned by the URL is append to the already send PDF which ends in a document mixed of PDF and HTML (the 404 response) -> corrupted PDF
Conclusion: Use "F" as the 2nd parameter and use the same path for both writing and reading and not a mix of local path and URL.

What does the "PK¿¿¿" response means in PHP

Hi I'm downloading a file to an app on iOS using the function readfile() on a PHP web service and I want to know if the file is downloaded correctly but I don't know how I can do that.
So what I'm trying is to do some echo to know if the file has been downloaded like this:
echo "before";
readfile($file);
echo "after";
But the response I get is this:
beforePK¿¿¿
Any one knows what does this mean or how can I know if the file is downloaded correctly?
UPDATE:
Yes it's a zip file, here are my headers
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-Disposition: attachment; filename=$ticket");
header("Content-Type: application/zip");
header("Content-Transfer-Encoding: binary");
You're trying to output the contents of a zip file aren't you?
readfile($file) works the same as echo file_get_contents($file). If you're trying to present someone a file to download, do not add any additional output else you risk breaking the file.
I would also recommend reading up on the header function. That way you can explicitly tell the browser that you're sending a file, not an HTML page that has file-like contents. (See the examples involving Content-Type)
PHP should be setting the correct headers prior to readfile() - this LITERALLY reads the file out to the browser/app... but the browser/app needs to know what to do with it...
Usually you just assume that once the connection has closed that the data is done being transferred. If you want to validate that the file has been transferred fully, and without corruption you'll need to use a data structure like XML or JSON which will:
Delimit the data fields and cause the XML/JSON parser to throw an error if one is omitted, aka the transfer was cut off before it finished.
Allow you to embed more than one piece of data with the response, eg. an MD5 hash of the file that can be re-calculated client-side to verify that the data is intact.
eg:
$file = 'myfile.zip';
$my_data = array(
'file' => base64_encode(file_get_contents($file)),
'hash' => md5_file($file)
)
//header calls
header(...)
echo json_encode($my_data);
exit;

PHP Download not working with path coming from DB

I have a simple form that, when posted back, calls a function to initiate a download. The path and file name are pulled from the database then I'm using headers to start the download. My code for the download is:
//START DOWNLOAD
header('Content-type: "application/octet-stream"');
header('Content-Disposition: attachment; filename="'.$FILE_PATH.$FILE_NAME.'"');
header("Content-Transfer-Encoding: binary");
header("Connection: close")
In the example above, the $FILE_PATH variable is /downloads/software/ and the $FILE_NAME variable is client-installer.exe. So, what I would expect is a file called client-installer.exe (approximately 70MB) to be downloaded to the client. Instead, I get a file called _downloads_software_client-installer.exe and approximately 10KB.
I thought maybe I needed to urlencode the file path/name but that didn't fix the issue either. So I'm left thinking perhaps I have something wrong with the header but can't seem to find it.
Thank you!
The filename header just denotes what the file should be called. It must contain only a filename, not a path. The internal path on the server's hard disk is irrelevant and of no interest to the client. Your server will have to output the actual file data in the response, the client can't take it from the server given the path.
See readfile.

Using php to force download a pdf

Im trying to get a website to have a button that forces a download of a pdf.
Heres the html of the button:
<a href=scripts/download.php>
<input type="image" src="images/download.gif" alt="Submit button"/>
</a>
And the php script so far:
<?php
header('Content-Type: application/pdf');
header('Content-disposition: attachment;filename=documents/ECM_IT_ResumeDownload.pdf');
readfile('documents/ECM_IT_ResumeDownload.pdf');
?>
This seems to download the file fine but when I go to open it i get this error:
"Adobe Reader could not open 'documents_ECM_IT_ResumeDownload.pdf' because it is either not a supported file type or because the file has been damaged (for example, it was sent as an email attachment and wasn't correctly decoded)."
Any help would be greatly appreciated.
EDIT
Opened the pdf in a text editor and got this message:
"
Warning: readfile(documents/ECM_IT_ResumeDownload.pdf) [function.readfile]: failed to open stream: No such file or directory in html/scripts/download.php on line 4
"
The document is definitely there though. in html/documents/ECM_IT_ResumeDownload.pdf
$file_url = www.example.com/pdffolder/$pdfname;
header('Content-Type: application/pdf');
header("Content-Transfer-Encoding: Binary");
header("Content-disposition: attachment; filename=".$pdfname);
readfile($file_url);
Try removing the path to the file and just leave the file name in the content:
header('Content-Type: application/pdf');
header('Content-disposition: attachment; filename=ECM_IT_ResumeDownload.pdf');
Have you tried getting rid of the closing PHP tag (the ?>) at the end? It will treat the page as a pure PHP page, removing any possible new lines that might accidentally get appended to the end of the output. This helped me when I was dynamically creating excel files for download, and they were downloading as corrupted. Check out this page for more information:
http://www.php.net/manual/en/language.basic-syntax.phptags.php
From your edited question, it seems like PHP is unable to find the file. Try using an absolute path to the file like so: "c:\blah\de\blah\bloo.pdf" or "c:/blah/de/blah/bloo.pdf". If one of those paths works and downloads correctly, your relative path is incorrect in some way.
I always use Gowon Patterson's download script, it also has hotlink protection:
http://by.gowondesigns.com/getfile/
By the way, a bit late, but to identify the problem properly here:
Your download script is at scripts/download.php and the file you want to download is at documents/[...].pdf.
Therefore, your readfile() function should be traversing to the parent directory (outside of scripts/), e.g. readfile('../documents/[...].pdf');.

Categories