I'm in the process of developing a PHP webpage that constructs a .SVG file from a SQL database on the fly, embeds it in the page, and enables a user to interact with it. These temporary files take on the form SVG[RandomNumber].svg and the unlink function successfully deletes the files with no error messages.
Here's the problem: I assumed that if I invoked the unlink function after the SVG file had loaded for the user, the webpage would be unaffected since the user's browser would have cached the file or whatnot. Everything works perfectly when no unlink command is present in the code; however, 'unlinking' anywhere -- even at the end of the webpage, causes no object to show at all. In Firefox there's no trace of the object, and in IE I receive the error "The webpage cannot be found."
So have I deleted the file before the browser uploads it? What's the best way to deal with the general situation?
Thank you.
It might be useful to change workflow and don't create temporaries. When image is used only once or it's generation is not a big deal you can try to generate it on-the-fly in following fashion
<?php
// We'll be outputting a SVG
header('Content-type: Content-Type: image/svg+xml');
// It will be called image.svg
header('Content-Disposition: attachment; filename="image.svg"');
// Don't cache
header("Cache-Control: no-cache, must-revalidate");
header("Expires: " . date("D, j M Y H:i:s"));
// The PDF source is in original.pdf
generate_svg_from_db('image.svg');
?>
Related
We have had a site for many years, PHP on Ubuntu where clients can download forms/letters as pdfs, then upload them when completed.
Now when re-downloading client's uploaded multi-page pdf, the first (cover) page is blank and Adobe acrobat says "error exists on page...". When we ftp the document, the file is fine with no errors, so the problem has to be in the file download / readfile() process.
This error occurs in both Chrome & Firefox (all updated). If you just view the pdf in the browser, the cover page appears to be fine and readable, however, if you download it you get the same adobe error and blank first page. I am at a loss for how to diagnose this.
Below is the PHP code we use to pull the file.
Please note, for security reasons we do not allow linking directly to any files. The link is to a php page that validates an encoded file request for permission to read a file, then pulls the correct file info from the database for that user, then reads the file and serves it back to the client. I have not included the validation or database related code, just the relevant readfile code:
header("Content-Length: " . filesize('/filestore/' . $doc['filename']));
header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Date in the past
header('Content-type: application/pdf');
header('Content-Disposition: attachment; filename="' . $docname . '.' . strtolower(end(explode('.', $doc['filename']))) . '"');
header("Pragma: private");
readfile('/filestore/' . $doc['filename']);
Additional info based on questions in comments:
To prevent direct linking and brute force scraping of documents, the file store is not in a public folder (so no direct linking).
User links look something like this My File with the id encoded with the file info and CSRF token plus session token checks as part of the validation. The download.php file validates the user and file to make sure they have permission to the document then calls the code above to obtain and "serve" the file to the browser.
$docname is the client's original filename for the file stored in the database. We save files with our own generated file name to prevent naming conflicts when clients use the same file name, this is stored in the DB as $doc['filename']. We restore the client's filename when downloading.
First post. I'm working on a project for a client where they have pdf files uploaded to a file structure (LAMP Stack) but the files have no extensions on them. Under the assumption that those files have to be PDF how would I get the browsers to understand that, and open them accordingly? Obviously with adding the file extensions this would suddenly work but I can't change the way their system works, it would result in too many changes and they are on a tight deadline. As for saving a temporary copy somewhere, I could do that, but I was hoping for a better solution. Is there a way to suggest to the browsers that they open a file a certain way?
Any thoughts guys/gals?
You just set the application type and file name in the headers, like so:
// This points to the file in question, note that it doesn't
// care whether it has an extension on the name or not.
$filePathOnDisk = '/path/to/your/pdffile';
// You can make this whatever you like, it doesn't have to
// be the same as the file name on the disk! This is the name of the file your end
// user will see when they are asked if they want to save. open, etc in the browser.
$fileName = 'file.pdf';
$data = file_get_contents($filePathOnDisk);
header("Content-type: application/pdf");
header("Content-disposition: attachment;filename=$fileName");
echo $data;
See PHP: stream remote pdf to client browser and Proper MIME media type for PDF files for reference as well.
Tested
You can use the following which will prompt the user to save the (PDF) file on their computer.
Notice the different file names.
One is the file that will be uploaded/prompted to the user download_example.pdf, while the other is the file without an extension as set in readfile('example');
<?php
header('Content-type: application/pdf');
header('Content-Disposition: attachment; filename="download_example.pdf"');
readfile('example');
?>
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;
well I'm just wondering how I can get an mp3 download to start instantly, as oppose to it simply starting to play in the browser when you directly go to it.
Preferably using php headers.
So essentially when you click the file, I want a download box to appear saving save etc. Right now it just opens and starts playing in the browser.
Thanks
You'll need to create a PHP file that "redirects" to the MP3 file, and point your links to that PHP file.
Code as below:
<?php
header('Content-type: audio/mpeg');
header('Content-Disposition: attachment; filename="fileName.mp3"');
readfile('originalFile.mp3');
?>
Note: The line that sets the Content-Disposition header is the critical one.
THE EXAMPLE
1) User enters in a playlist in a <textarea>
C:/music/foo.mp3
C:/music/bar.mp3
C:/music/hello.mp3
2) They click a save button. I send the user's playlist to the server with AJAX.
3) The server formats the text with PHP in this fashion:
<playlist>
<item>C:/music/foo.mp3</item>
<item>C:/music/bar.mp3</item>
<item>C:/music/hello.mp3</item>
</playlist>
4) A file save dialog pops up asking the user to save this formatted text as playlist.m3u on their own harddrive.
QUESTIONS
A) Is it possible to not write a file to the harddrive on the server when generating this m3u file? I don't want millions of files clogging up my server. I suppose PHP can echo out the formatted text and set headers to masquerade as a file.
B) How do I get the file save dialog to pop up for this on-the-fly file? If it were a real file, I would just have the PHP respond back with the location of the file. Then I would have JS insert a new iFrame with that location. But I don't want to write a file on the server, so I can't do this.
new Ajax.Request(
'generateM3u.php',
onSuccess: function(transport) {
$$('body').first().appendChild(
new Element(
'iframe', {
src: transport.responseText
}
)
);
}
);
You should take a look at http://php.net/manual/en/function.header.php from the PHP manual. There are a lot of user contributions at the bottom of the page regarding forcing the browser to show a download prompt rather than printing to screen.
Here is one from that page (By phpnet at holodyn dot com 31-Jan-2011 09:01) which I have edited slightly. I think it answers both questions A and B. Just send the textbox's contents to the PHP file through an iframe, allow it to format the text appropriately and send it back to the browser with the following headers.
$contents = '<playlist>etc....</playlist>';
header("Pragma: public"); // required
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: private", false); // required for certain browsers
header("Content-Type: audio/x-mpegurl");
header("Content-Disposition: attachment; filename=\"playlist.m3u\";" );
header("Content-Transfer-Encoding: binary");
header("Content-Length: " . strlen($contents));
ob_clean();
flush();
echo $contents;
Edit: If what you want is an all Javascript solution, then I personally don't know, and after a little google-ing, it looks like others don't either. Most seem to solve this with an invisible iframe that directs to a server-side file.
Edit 2: I've changed the content type so that it matches the m3u file type.
How about creating a form on your parent DOM, and post it to the IFRAME/pop-up that you created?
The POST action URL will be your generateMu3.php
To answer your questions,
A & B) I assume so... as long as generateM3u.php sets the correct MIMEType for the .m3u file...
I'm not familiar with syntax in PHP, but in both Java & .NET, you can set the response's MIMEType in the header to, say, a Word document, and the browser will read the header, and if it's a file that is "Save-able", it'll prompt the client to save the page as a file.
If I read this correctly there's a machine creating the .m3u files. In that case, perhaps just write the files to a temporary directory, /tmp on unix machines andC:\Windows\Temp on Windows machines. Those files are cleared on boot, which should allow you to handle B) without all the A).