I think I have a header related problem, am kinda new to them; here we go:
On 'summary.php' I have links that when I click, ajax a value to another page called 'note.php'.
Note.php has a header which i use to produce an MS-Word document - this works fine BUT ONLY WHEN I RUN note.php DIRECTLY, the Word file gets downloaded easily.
But no Word file download when I use the click-button-to-download-document.
Where should I look?
session_start();
include('otc_toolbox.php');
//ob_flush();
/*
if(isset($_POST["month"]))
{
$month = $_POST["month"];
$member= $_POST["member"];
}
*/
$month = $_POST["month"];
$member= $_POST["member"];
//else exit();
//Get current date
$date = date('Y-m-d');
//Prepare document html
$dnoteHTML = '';
$dnoteHTML .= '<html><body><table style="width:100%;">';
......
//header("Content-type: application/vnd.ms-word");
//header("Content-Disposition: attachment;Filename=DebitNote.doc");
echo $dnoteHTML;
You can't trigger a file download from an AJAX request.
With the content disposition set to attachment, using
window.location.href = "note.php";
should trigger the download without actually navigating away from the original page.
If the document takes a long time to generate, you could split the generation and download into two separate parts - AJAX request to a "generate" page to create the document, then when that's done, aim the browser at the "download" page to download it.
Related
I have a copy of 350+ images on my sever, when a person tries to view one, if it is more than 5 minutes old, I want my sever to check with another website that I am mirroring data from(they insist on me mirroring instead of hotlinking) and get the newest copy. Any thoughts on how to do this?
I can do a cron script and get all of the images, but there are problems doing that.(My host limits me to once every 15 minutes, I would have to get a lot of images that my users may or may not actually view.)
I am thinking there should be a way to do this in PHP, but I have no idea where I would start.
You could serve the images via a php script that allows you to do the necessary checks before displaying the image.
<img src="/index.php/image-name.jpg">
Below is one option for the checks
// get the image name from the uri
$image = explode("/", $_SERVER['REQUEST_URI'])[2];
// check if the image exists
if (is_file($image)) {
// get the file age
$age = filemtime($image);
if ($age < time() - (60*5)) { // 5 mins old
// file too old so check for new one
// do your check and serve the appropriate image
}
else
{
// get the image and serve it to the user
$fp = fopen($image, 'rb');
// send the right headers
header("Content-Type: image/jpg");
header("Content-Length: " . filesize($image));
// dump the picture and stop the script
fpassthru($fp);
exit();
}
}
else
{
// handle error
}
You can apply ajax at your project.
call your server at every 5 minutes using ajax and refresh your content.
In short; AJAX is about loading data in the background and display it on the webpage, without reloading the whole page.
For an insurance company, I've created PDF forms of their various insurance applications. These will be available on their website (when it is done). Each form, being in PDF, looks exactly like the printed version of the application. The idea is that a user fills it out online, hits the (visible but unprintable) "Submit" button at the bottom of the form, and the entire completed PDF is sent to the company. That way they can print it out, and carry on with their current paper filing system.
I experimented with using a "mailto:..." URL for the Submit button, but that requires an external mail program. It also gives the attached PDF a random temp filename.
Therefore, I'd like to send the PDF to a php script, change the name, and email it to the company from there. I played with it a bit, and I can reach the destination script, but I have no idea what happens to the PDF. I expected it to show up in $_FILES, but nothing.
Saving to a database is not an option.
When preparing the PDF form, you can choose how you would like to submit: as an HTML form (as Sepodati said), as XML data, as FDF (which only sends data, and will open the original PDF when displaying the data), or as a completed PDF. For ease of use for the site owners, who are not computer savvy, I'm going to send them a completed PDF that they can print.
So, the same question remains: where does my PDF file go when I get to my destination script?
I'm submitting the PDF via a Submit button on the PDF itself. You'll have to be familiar with PDF forms to understand this. For the URL, I put the destination PHP script.
In my destination script, I tried the following
PHP Code:
reset ($_FILES);
while (list ($key, $val) = each ($_FILES)) {
echo "$key => $val<br />\n";
}
I did this for $_FILES, $_GET, $_POST, and $_REQUEST. Nothing came up, as though each array was empty. I might have done this wrong, though.
I put phpinfo() in the script, and these vars appear related to the PDF...
_SERVER["CONTENT_LENGTH"] = 37722
_SERVER["CONTENT_TYPE"] = application/pdf
_SERVER["HTTP_USER_AGENT"] = Mozilla/4.0 (compatible; Adobe Acrobat Control Version 5.00 for ActiveX)
_SERVER["REQUEST_METHOD"] = POST
The content length is approximately the size of the PDF.
Something else I didn't notice before is that upon submission, Internet Explorer displays this page (or a name like it):
C:\WINDOWS\TEMP\pa003773.html
This page contains all the output from my script.
It's very interesting that it's supposed to send the entire PDF. I would be interested in knowing how it does that because I've searched the Adobe site for information on how to submit an entire PDF file by clicking a button on the PDF form.
The only thing I found on their site was information about the FDF and XFDF formats. Both of these formats have to be parsed in some way by your form handler script and aren't included in $_FILES the way a file is uploaded when you select the file from the filesystem.
$fptr = fopen("temp.fdf", "w");
fputs($fptr, $HTTP_RAW_POST_DATA);
fclose($fptr);
This is a really old post so I'm sure you've gotten your answer by now but here's what worked for me in case anyone else stumbles across this in the future.
BTW- this only works for if you are submitting the entire PDF with the form fields completed.The address you would put on your submit button would be something like http://youserver.com/lib/php/formProcess.php?email=to#company.com&formName=Asset%20Inventory
<?php
ob_start();
$file = file_get_contents("php://input"); //Gets binary PDF Data
$time = microtime(true);
//Names pdf file based on the time to the microsecond so nothing gets overwritten. Obviously you can change this to whatever you want or do something like $_REQUEST['formName'] and just include the form name in your URL from your pdf submit button
$newfile = "forms/" . $time . ".pdf";
$worked = file_put_contents($newfile, $file); //Creates File
ob_end_clean();
//Upon completion you can either return XFDF to update a field on your form or display a PDF document. I chose the PDF route because it worked for our situation.
$successFile = 'success.pdf';
$errFileFile = 'error.pdf';
require 'PHPMailer/PHPMailerAutoload.php';
$mail = new PHPMailer;
$mail->isSendmail();
$mail->setFrom('From email address', 'from name');
$mail->addReplyTo('Reply to email', 'Reply to name');
$mail->addAddress($_REQUEST['email']); //get email from URL- alternately you can just hardcode in an address
$mail->addAttachment( $newfile );
$mail->isHTML(true);
$mail->Subject = 'New form submission';
$mail->Body = 'A new form has been submitted.';
if(!$mail->send()) {
header('Content-type: application/pdf');
readfile($errFile);
} else {
header('Content-type: application/pdf');
readfile($successFile);
//if you want to delete the file from the server after emailing: unlink($newfile);
}
?>
I've got a large form where the user is allowed to input many different fields, and when they're done I need to send the contents of the form to the server, process it, and then spit out a .txt file containing the results of the processing for them to download. Now, I'm all set except for the download part. Setting the headers on the response to the jQuery .post() doesn't seem to work. Is there any other way than doing some sort of iframe trick to make this work (a la JavaScript/jQuery to download file via POST with JSON data)?
Again, I'm sending data to the server, processing it, and then would like to just echo out the result with headers to prompt a download dialog. I don't want to write the result to disk, offer that for download, and then delete the file from the server.
Don't use AJAX. There is no cross-browser way to force the browser to show a save-as dialog in JavaScript for some arbitrary blob of data received from the server via AJAX. If you want the browser to interpret the results of a HTTP POST request (in this case, offering a download dialog) then don't issue the request via AJAX.
If you need to perform some kind of validation via AJAX, you'll have to do a two step process where your validation occurs via AJAX, and then the download is started by redirecting the browser to the URL where the .txt file can be found.
Found this thread while struggling with similar issue. Here's the workaround I ended up using:
$.post('genFile.php', {data : data}, function(url) {
$("body").append("<iframe src='download.php?url="+url+"' style='display: none;'></iframe>");
});
genFile.php creates the file in staging location using a randomly generated string for filename.
download.php reads the generated file, sets the MIME type and disposition (allowing to prompt using a predefined name instead of the random string in the actual filename), returns the file content and cleans up by deleting the source file.
[edit] might as well share the PHP code...
download.php:
<?php
$fname = "/tmp/".$_GET['url'];
header('Content-Type: text/xml');
header('Content-Disposition: attachment; filename="plan.xml"');
echo file_get_contents($fname);
unlink ($fname);
?>
genFile.php:
<?php
$length = 12;
$chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
$str = substr( str_shuffle( $chars ), 0, $length ).'.xml';
$fh = fopen(('tmp/'.$str), 'w') or die("can't open file");
fwrite($fh,$_POST["data"]);
fclose($fh);
echo $str;
?>
Rather than using jQuery's .post(), you should just do a normal POST by submitting the form, and have the server respond with appropriate Content-Encoding and MIME-type headers. You can't trigger a download through post() because jQuery encapsulates the returned data.
One thing I see in use rather frequently, though, is this:
$.post('generateFile.php', function(data) {
// generateFile builds data and stores it in a
// temporary location on the server, and returns
// the URL to the requester.
// For example, http://mysite.com/getFile.php?id=12345
// Open a new window to the returned URL which
// should prompt a download, assuming the server
// is sending the correct headers:
window.open(data);
});
I'm trying to accomplish a fairly simple task for my website, but I"m not sure exactly how to go about it. I want the user to be viewing a table, then click a button, at which point the user can save the contents of that table as a csv file. This request can sometimes be quite complicated so I generate a progress page to alert the user.
I have most things figured out except actually generating the csv file. (I use jQuery and PHP)
the jQuery code run on click:
hmis_query_csv_export: function(query_name) {
$.uiLock('<p>Query Loading.</p><img src="/images/loading.gif" />')
$.get({
url: '/php_scripts/utils/csv_export.php',
data: {query_name: query_name},
success: function(data) {
$.uiUnlock();
}
});}
the relevant PHP:
header("Content-type: text/x-csv");
header("Content-Disposition: attachment; filename=search_results.csv");
//
//Generate csv
//
echo $csvOutput
exit();
What this does is sends the text as the PHP file, but it's doesn't generate a download. What am I doing wrong?
If you are forcing a download, you can redirect the current page to the download link. Since the link will generate a download dialog, the current page (and its state) will be kept in place.
Basic approach:
$('a#query_name').click(function(){
$('#wait-animation').show();
document.location.href = '/php_scripts/utils/csv_export.php?query_name='+query_name;
$('#wait-animation').hide();
});
More complicated:
$('a#query_name').click(function(){
MyTimestamp = new Date().getTime(); // Meant to be global var
$('#wait-animation').show();
$.get('/php_scripts/utils/csv_export.php','timestamp='+MyTimestamp+'&query_name='query_name,function(){
document.location.href = '/php_scripts/utils/csv_export.php?timestamp='+MyTimestamp+'&query_name='+query_name;
$('#wait-animation').hide();
});
});
At PHP script:
#header("Last-Modified: " . #gmdate("D, d M Y H:i:s",$_GET['timestamp']) . " GMT");
#header("Content-type: text/x-csv");
// If the file is NOT requested via AJAX, force-download
if(!isset($_SERVER['HTTP_X_REQUESTED_WITH']) || strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) != 'xmlhttprequest') {
header("Content-Disposition: attachment; filename=search_results.csv");
}
//
//Generate csv
//
echo $csvOutput
exit();
The URL for both requests must be the same to trick the browser not to start a new download at document.location.href, but to save the copy at the cache. I'm not totally sure about it, but seems pretty promising.
EDIT I just tried this with a 10MB file and it seems that val() is too slow to insert the data. Hurrumph.
Okay, so I gave this one another go. This may or may not be completely insane! The idea is to make an AJAX request to create the data, then use the callback to insert the data into a hidden form on the current page which has an action of a third "download" page; after the insertion, the form is automatically submitted, the download page sends headers and echoes the POST, and et voila, download.
All the while, on the original page you've got an indication that the file is being prepared, and when it finishes the indicator is updated.
NOTE: this test code isn't tested extensively, and has no real security checks (or any at all) put in place. I tested it with a 1.5MB CSV file I had laying about and it was reasonably snappy.
Index.html
<a id="downloadlink" href="#">Click Me</a>
<div id="wait"></div>
<form id="hiddenform" method="POST" action="download.php">
<input type="hidden" id="filedata" name="data" value="">
</form>
test.js
$(document).ready(function(){
$("#downloadlink").click(function(){ // click the link to download
lock(); // start indicator
$.get("create.php",function(filedata){ // AJAX call returns with CSV file data
$("#filedata").val(filedata); // insert into the hidden form
unlock(); // update indicator
$("#hiddenform").submit(); // submit the form data to the download page
});
});
function lock(){
$("#wait").text("Creating File...");
}
function unlock(){
$("#wait").text("Done");
}
});
create.php
<?php
//create $data
print $data;
?>
download.php
<?php
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Content-Type: text/x-csv");
header("Content-Disposition: attachment;filename=\"search_results.csv\"");
if($_POST['data']){
print $_POST['data'];
}
?>
The best way to accomplish this is to use a Data URI as follows:
Make the AJAX call to the server as per normal
Generate the CSV on the server-side
Return the data (either bare or inside a JSON structure)
Create a Data URI in Javascript using the returned data
Set window.location.href to the Data URI
See this link for instructions (paragraph #3, specifically): http://en.wikipedia.org/wiki/Data_URI_scheme
This way, you don't need to save any files on the server, and you also don't need to use iframes or hidden form elements or any such hacks.
I don't think you can make the browser download using a AJAX/JS request. Try using a hidden iframe that navigates to the page which generates the CSV
Well the point of using AJAX is to avoid a visible reload of the page. If you want a download, you want the opposite,- a brand new request from the browser. I'd say, just create a simple button pointing to your php page.
To echo and expand on what others have said, you can't really send the file using AJAX. One of the reasons for this is (and someone correct me if I'm wrong on this, please) that the page you're currently on already has sent its content headers; you can't send them again to the same window, even with an AJAX request (which is what your PHP file is attempting to do).
What I've done before in projects is to simply provide a link (with target="_blank" or javascript redirect) to a separate download PHP page. If you're using Apache, check out mod_xsendfile as well.
I have a intranet site running PHP 5 that needs to list a folder containing only Excel files.
Ideally the user needs to be able to input some search criteria (ie date) and the files would be filtered into a list of hyperlinks. These hyperlinks could then be selected to download the excel file.
What I have so far is:
//get search parameters (from a form)
$s_Date = $_GET['s_Date'];
$s_Shift = $_GET['s_Shift'];
$s_Name = $_GET['s_Name'];
//search folder
foreach(glob("c:\folderA\folderB\*".$s_Date."*".$s_Shift."*".$s_Name."*.*") as $FileName)
{
echo basename($FileName);
echo"<a href=?myad=".basename($FileName)."/>Download</a>"."<br />";
}
This returns list of files but selecting hyperlinks doesn't prompt for download.
How do I get the hyperlink to force a content-type of msexcel?
Assuming you are using a PHP script to deliver the file conent, the script needs to set the Content-Type header:
<?
header('Content-Type: application/excel');
header('Content-Disposition: attachment;filename=myfile.xls');
// send file content
?>
Note you can also set the name to use for the file using the Content-Disposition header.
You might also want to consider a more well-formed <a> tag that points to your download script:
echo 'Download<br />';
In this example, you need to replace dl.php with your actual script.
Also append Content-Length header:
header('Content-Length : ' . filesize('myfile.xls'));
Client would like to know how big file is and how much of it has already been downloaded.