Allow user to download file created via ajax - php

I'm using PHPWord to generate MS word documents in php. It works fine and i can create a file and store it on my server via an ajax request, but after its created i need to allow the user to download it.
There has to be someway i can serialize the file and pass it back in the ajax response then queue it for download in javascript? I could use any advice on how to do this with a file
after the file is created, i tried in php:
$wordFile = file_get_contents('helloWorld2018.docx');
and then tried returning that, but ofcourse i got an error as i tried to convert it as a JSON variable. Is there someway i could serialize this, pass it via json, then queue it for download? I'm using Jquery and Codeigniter btw
thanks

Well this is what I found. Juan had the correct response but gets a massive downvote for not explaining how that is done, or explaining that window.location won't actually redirect the user if its pointing to a file, it just queues the download, which is perfect
I use Codeigniter, so after the file is created, i have this controller called 'Download'
header("Cache-Control: no-cache");
header("Content-Description: File Transfer");
header("Content-Disposition: attachment; filename=hellowWorld2018.docx");
header("Content-Transfer-Encoding: binary");
readfile("helloWorld2018.docx");
Then in the ajax success function i just say window.location = 'download' and it downloads the file.
Still havent figured out how i'm going to set the headers and readfile command dynamically yet but that should be relatively easy. thanks, G

Related

Trigger an action when a certain file URL is downloaded

I would like to trigger an action when Apache detects that a certain file URL has been started for download (or: successfully downloaded).
Example: when https://example.com/download/token_A6FZ523/myfile.zip is downloaded by a client, execute the following query to a SQLite database:
INSERT INTO downloads(date, tokenID) VALUES(CURRENT_TIMESTAMP, "A6FZ523");
Usage: then, in a PHP Dashboard, I can check who has downloaded the delivered files.
I could do this by:
running a script every minute on the server,
parsing the Apache logs /var/log/apache2/other_vhosts_access.log in search for a pattern download/token_.*/myfile.zip
execute the INSERT INTO query in this case
This seems rather complex and the fact of having to run the script every minute is not a nice solution.
What is a good solution to ask Apache to save to a SQLite database the information "The file associated to download token A6FZ523 has been downloaded by the client."?
Or maybe should PHP be used instead?
I think your problem lies in that you are directly fetching a file that is stored on the server, as opposed to using PHP to "serve" this file programatically. This isn't the first problem you will encounter with this method, you also can't check for security or get the file from external file storage (generally speaking, you don't store files directly on the web server these days!).
But, simple to do once you know how :)
Firstly, lets change the URL you download your file from to something like https://example.com/download.php?token=A6FZ523
So, we are sending a GET variable to a php script named "download.php". In that script you will have something like the following:
<?php
$token = $_GET['token'];
// Get the information about the file from the DB, something like:
// SELECT filename, size, path FROM files WHERE token = $token;
// Giving you $filename, $size and $path
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename=' . $filename);
header('Content-Transfer-Encoding: binary');
header('Connection: Keep-Alive');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Length: ' . $size);
echo file_get_contents($path);
// This will be on a completed download
// INSERT INTO downloads(date, tokenID) VALUES(CURRENT_TIMESTAMP, $token);
?>
When the download.php file is called, the token is taken and matched to a file's info in the DB. You then set headers which basically tells the browser "this is a file", your browser responds accordingly by implementing a file download as normal. You then read the contents of the file to the user. Once this has been completed, you can log the download via another DB call.
A big thing to say is that this script (obviously with the DB calls written in) should do the very basics for you, but there is a lot more to add depending on your usage scenario. Think security, input validation, where you store your files and sending a MIME type header.
Hopefully that should point you in the right direction though :)
If you have access to server and authority to install thins you could add mod_log_sql and have the apache save the log directly into a database table (it even parse the info for you) them in your dashboard you can just do simple queries. The "thing" here it seams that you are in need to get the name of the downloader, therefore you should add that "tokenID" to your URL and set the Apache to deny the url if tokenID is not present. You would need to parse the tokenID from url in the log thought.

PHP save file without save as dialog

I'm creating MS Office Word document with PHP as following:
header("Content-type: application/vnd.ms-word");
header("Content-Disposition: attachment;Filename=filename.doc");
header("Content-Transfer-Encoding: binary");
But I need to save file to the server without save as dialog to be able to do something with the created *.doc file and give it to user only after the modification.
So how can I acheive this?
The code you use is for sending as download to the browser user.
To save on the server, use the this in PHP :
file_put_contents('path/to/ms/word/document.doc', $theData);
Then after you use your code to sent the saved file.

Make temporary Files downloadable from Website

On a webservice I'm developing, a user should be able to download his data in a HTML file. This file contains everything (including images as base64).
Now to make the user download this, I would have to create the file and save it on my webserver. Afterwards, I'd have to delete it using a cronjob, because I can't figure out when the download is complete.
Is there another way? Would it be possible to download a file to the user which does not physically exist on my webserver, but gets somehow created temporarily?
Thank you for your help!
As far as the WWW is concerned, there is no such thing as a file. There are just HTTP resources.
The server might get the data from a file, it might not.
Just output the data for the file from your PHP program. (i.e. by putting it outside <?php and ?> or using echo or any other technique that causes PHP to output something).
You need to make sure you use the right Content-Type header, but since you are using HTML, that is text/html which is the default.
You can add a Content-Disposition header if you want the user to be prompted to save their download somewhere instead of rendering the downloaded HTML in the browser window.
header("Content-Disposition: attachment; filename='foo.html'");
<?php
// We'll be outputting a PDF
header('Content-type: application/pdf');
// It will be called downloaded.pdf
header('Content-Disposition: attachment; filename="downloaded.pdf"');
// The PDF source is in original.pdf
readfile('original.pdf');
?>
From: http://php.net/manual/en/function.header.php

PHP force File downloads without applying headers

Is there a way to force any given file specified without giving the headers for it? What I have is a handful of different docs and other file types that a client wishes to offer up as download upon request, however they want to obscure the file path best they can. Unfortunately I don't know what file types most of these are and they want a somewhat dynamic ability. I'm not getting paid for this piece. So I am looking for quick and dirty if at all possible. Something that doesnt force me to come up with a logic for every file type possible just so I can have the headers built right for the file type in question so it downloads proper..
Is there a way to achieve this?
Well, if I undertand your problem, you want an easy way to download any type of file using a php script.
First of, you have a couple of ways to do it...
The most insecure one:
- You have a directory (lets say 'files/') where all files are stored. You create a script that receive a param (filename) and you look for the file in that directory. This is insecure because anyone can try to download any file there is, and also access subdirectories just passing "../" as param. You must need to do some parse there.
Other option is to use a DB, you store the filenames and associates them to an unique ID, later you have you script like: download.php?id=1 and it downloads the file which DB id is 1. This is the best I think.
Anyway, you can choose whatever you think is best, the code to force a download dialog should be something like:
$file = "my_file.zip"; // this is what you will get from a param (i.e. ?file=my_file.zip) or from DB query
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-Disposition: attachment; filename=$file"); // this is totally needed
header("Content-Length: ".filesize($file));
header("Content-Type: application/force-download");
header("Content-Transfer-Encoding: binary");
readfile($file);
That should do the trick.
Good luck!

PHP generated XML not downloadable in IE

I have an XML feed generated by a PHP script with mod_rewrite running. IE opens the feed OK but I cannot get it to save the file to disk or import to Excel.
The file I am trying to access in the url is similar to:
http://domain.com/download/export.xml
This gets written to a download PHP script and is not actually an XML file.
After setting the headers as below, it is still not possible to get IE to save the file. Also, as it is not capable of displaying the plain source, copy & paste into notepad will not work because of various styling changes IE makes to the XML.
<?php
header("Content-type: text/xml");
header('Content-Disposition: attachment; filename="QuoteExport_'.$quoteDate.'_'.$quoteSlot.'.xml"');
Does anyone know the solution? Thanks.
Edit:
Thanks for the help so far. I have tried a combination of these headers and still not getting the results I want. No matter what I set, IE always displays it in-line in the browser with no option to download. The save functionality also still does not work either. Any other ideas how to force IE to save the XML as a file by using headers?
Edit2: The state now is that IE gives the option to open/save but whilst trying to save, there is a popup saying that it is "Unable to open this internet site.". Yet at the same time, the open option displays the content with no issues.
To force ie and other browsers to download you have to specify specific headers like in this example :
header("Content-disposition: attachment; filename=\"".$fileName . ".csv\"");
header("Content-Type: application/force-download");
header("Content-Transfer-Encoding: binary");
header("Pragma: no-cache");
header("Expires: 0");
Other wise if you use text/xml, ie thinks he knows how to display it and does so.
You need to set a session parameter for some versions of IE. Assuming you have $my_file_name and $my_file_contents set, here's how it would look:
if(strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE')) {
session_cache_limiter("public");
}
session_start();
header('Content-type: application/octet-stream');
header('Content-Disposition: attachment; filename=".' $my_file_name '. "');
print($my_file_contents);
(Adapted from this article)
Try setting the content-type to application/xml or application/force-download
After spending much time changing the headers, I went for a slightly different approach. No matter what I was setting them to, it just would not work for me.
Anyway the solution implemented was:
When a client lands on the URL (http~://my-domain.com/downloads/export.xml), the PHP script generates a real XML file in the same location as the request-URI and saves it on the server, schedules it for a delete job in the future and then effectively refreshes the browser. Then, the mod-rewrite rules on the second request serve the actual file and then IE can use the file correctly. A future request then causes the cycle to run again.
Slightly round about way of doing things, but it was the fastest method. Also, I had the ability to schedule file operations from another part of the application making life much easier for clean-up!
Anyway thanks for the help and I did learn a thing-or-two about header options.

Categories