php download save file - php

$filename = "members.csv";
if($_POST['SaveFileButton'] != ""){
header ("Content-Type: application/download");
header ("Content-Disposition: attachment; filename=$filename");
header ("Content-Length: " . filesize("$filename"));
$fp = fopen("$filename", "r");
fpassthru($fp);}
Sometimes this works perfectly and downloads the file.
Sometimes it displays the entire file contents at the top of the webpage, as though I had used echo, followed by the normal webpage underneath it.
I can't figure out why it's printing it to the screen.
The only unusual thing I've changed in this php file lately was adding an OnUpdate event to my Select ListBox.
<script type="text/javascript">
function listbox_update(){
var fullname = document.getElementById("listboxid").value;
var editcode = document.getElementById("codeid").value;
var filter = document.getElementById("filterid").value;
document.location.href="/php/members.php?fullname="+fullname+"&filter="+filter+"&editcode="+editcode;}
</script>

Related

writing not required html to a text file

I am writing my output to the text file and then downloading it using php but issue is that it is saving the output but it is also saving the whole structure of HTML into the textfile also. I don't know why its happening tried to solve it but did'nt figure out how.
I want to save output from fwrite($fh, $formatted_url."\n");
Below is my code:
function get_m3u8_video_segment($url,$portnum=80,$from,$to)
{
$file_name="urlscan.txt";
$fh = fopen($file_name, 'w') or die("Unable to open file!");
for ($x = $from; $x <= $to; $x++)
{
$formatted_url="{$url}:{$portnum}/s-{$x}.m3u8";
//echo "URL is: $formatted_url <br>";
//$contents = file_get_contents($formatted_url);
$contents = get_web_page( $formatted_url );
if ((strpos($contents, 'not found') !== false)||(strpos($contents, 'EXTM3U') !== false))
{
echo" $formatted_url<br>";
fwrite($fh, $formatted_url."\n");
}
}
//header download
header("Content-Disposition: attachment; filename=\"" . $file_name . "\"");
header("Content-Type: application/force-download");
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header("Content-Type: text/plain");
}
get_m3u8_video_segment($url,$portnum,$from,$to);
}
If there is other HTML content elsewhere in your PHP script then this will also be outputted as it normally is, except in this case it will become part of the downloaded file. If you don't want that to happen then you have to stop your script with an exit(); command after you have output the content you actually want. In your script, it looks like you can probably do this just after the call to the function. (But if you have already output some HTML before this, you'll need to alter your script more substantially.)
N.B. I'm surprised you aren't getting a warning about headers being already sent? That normally happens if you try to set headers after you've already echoed some content. Check your log files. Normally you are supposed to output the headers first.
Also, unless you are wanting to keep it for some other purpose, there is no use in saving anything to urlscan.txt - it is not playing any part in your download process. And it would get overwritten every time this script is executed anyway. The headers will cause the browser to treat the output contents (i.e. anything which the PHP script sends to the regular output) as a text file - but this is not the same file as the text file on your server's disk, and its contents can be different.
You happen to be outputting similar content (via echo" $formatted_url<br>";) as you are adding to the urlscan file (via fwrite($fh, $formatted_url."\n");) and I think this may be confusing you into thinking that you're outputting the contents of urlscan.txt, but you aren't - your PHP headers are telling the browser to treat the output of your script (which would normally just go onto the browser window as a HTML page) as a file - but it's a) a new file, and b) actually isn't a file at all until it reaches the browser, it's just a response to a HTTP request. The browser turns it into a file on the client machine because of how it interprets the headers.
Another thing: the content you output needs to be in text format, not HTML, so you need to change the <br> in your echo to a \n.
Lastly, you're outputting the content-type header twice, which is nonsense. A HTTP request or response can only have one content type. In this case, text/plain is the valid MIME type, the other one is not real.
Taking into account all of the above, your code would probably be better written as:
function get_m3u8_video_segment($url, $portnum=80, $from, $to)
{
//header download
$file_name="urlscan.txt";
header("Content-Disposition: attachment; filename=\"" . $file_name . "\"");
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header("Content-Type: text/plain");
for ($x = $from; $x <= $to; $x++)
{
$formatted_url="{$url}:{$portnum}/s-{$x}.m3u8";
$contents = get_web_page( $formatted_url );
if ((strpos($contents, 'not found') !== false)||(strpos($contents, 'EXTM3U') !== false))
{
echo" $formatted_url\n";
}
}
}
get_m3u8_video_segment($url, $portnum, $from, $to);
exit();

Convert database query results to excel and allow download from ajax call

I have looked through a few similar questions but can't quite find what I am looking for (please don't mark this as duplicate as I did try to find an answer without posting a question)
When the user clicks on a button, an ajax request is sent to the controller where I am getting data back from the model. I am then converting it to a csv format and on success of the ajax call I want the file to download. I have everything working except the download part. I have seen some examples where you just redirect but that doesn't download anything, it shows a new page with the results.
$( '.spExcel' ).on('click', function() {
$.ajax({
url: url + '/Widgets/exportSpExcel',
type: 'POST',
})
.done(function (data) {
window.location.assign(data);
})
});
PHP:
if($_SERVER['REQUEST_METHOD'] === 'POST') {
$results = $this->DashboardModel->listPeople();
$filename = 'People_' . date('dmY') . '.csv';
header("Content-Description: File Transfer");
header("Content-Type: application/csv");
header("Content-Disposition: attachment; filename=$filename");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
$handle = fopen('php://output', 'w');
$header = array("Name", "Contact Number");
fputcsv($handle, $header);
foreach ($results as $result):
fputcsv($handle, $result);
endforeach;
fclose($handle);
}
Ajax isn't capable of writing a downloaded file - the browser has to do that itself. You could use window.open() but that would open the file in a new tab or window, which would then close immediately. That can look messy - it works but isn't ideal.
The simplest way to deal with this is to make the link download the response directly, without trying to use Ajax. Change the link to suit your needs, but it would be something like this...
<a href="/Widgets/exportSpExcel" class="spExcel" download>click to download</a>
Just add the download attribute to a link. It really is that simple :)

PHP: How to hide URL

I have the following download.php script to download a file, which works great:
<?php
header("Content-Type: application/octet-stream");
$file = $_GET["file"];
header("Content-Disposition: attachment; filename=" . urlencode($file));
header("Content-Type: application/force-download");
header("Content-Type: application/octet-stream");
header("Content-Type: application/download");
header("Content-Description: File Transfer");
header("Content-Length: " . filesize($file));
flush();
$fp = fopen($file, "r");
while (!feof($fp))
{
echo fread($fp, 65536);
flush();
}
fclose($fp);
?>
What I want to achieve is to hide the URL where this file is located, so that when the user clicks a link such as <a target="_blank" href="http://domain.com/files/download.php?file=filename.pdf">Download file</a>, a new tab opens up with no URL and starts downloding the file. What is actually happening is the new tab opens and the file download starts but the URL bar is displaying http://domain.com/files/download.php?file=filename.pdf.
If this cannot be done with php, how can I achieve this? I have seen several downloads where the URL is not shown, so I know this is somehow possible.
EDIT: Here is the reason I want to do this: We will send a html mailing with a link to the file download, and the website where this file download is hosted is not the website from the company which sends the mail.
As always, thank you very much.
A typical way doing this, is to place the files you want to provide for download outside your docroot.
Your download script should know about this place and has to process the requested filename considering this.
For example:
path/in/your/system/docroot/download.php
and
path/in/your/system/files/filename.pdf
If someone is requesting download.php?file=filename.pdf your script has to look up in path/in/your/system/files/ for this file and has to handle it.
You can create a new window with iframe content to that URL.
var win = window.open("", "Title", "toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=yes, resizable=yes, width=780, height=200, top="+(screen.height-400)+", left="+(screen.width-840));
win.document.body.innerHTML = "<iframe src='YOUR URL'></iframe>";
If you remove the target="_blank" no new tab will be opened and the file will just be downloaded.
In the end, it's not possible because the user can open Google Inspector and check the Network tab.
Edit: If that's the case, you would use JavaScript:
Edit 2: In case the popup is blocked by the browser or addon, use a fallback:
Edit 3: In case JS is disabled:
<head><meta http-equiv="refresh" content="5;http://domain.com/files/download.php?file=filename.pdf">
<script>
var win = window.open("http://domain.com/files/download.php?file=filename.pdf");
if (!win) {
window.location = "http://domain.com/files/download.php?file=filename.pdf";
}
</script>
</head>
Edit 4: If you don't want the user to see the domain of the user site at all, get your PHP script to download the file and then output that to the user:
header("Content-Type: application/octet-stream");
$file = $_GET["file"];
$file = 'http://otherdomain.com/location/' . $file; // This line should suffice for all that you're trying to do
header("Content-Disposition: attachment; filename=" . urlencode($file));
header("Content-Type: application/force-download");
header("Content-Type: application/octet-stream");
header("Content-Type: application/download");
header("Content-Description: File Transfer");
header("Content-Length: " . filesize($file));
flush();
$fp = fopen($file, "r");
while (!feof($fp))
{
echo fread($fp, 65536);
flush();
}
fclose($fp);
Submit the form as POST and use $_REQUEST to get the file:
$file = $_REQUEST["file"];

Display message before creating excel in jquery and PHP

I am creating a web app in my company. The user can click on a button and an csv is created with MySQL data.
So far so god.
In jquery, when the user clicks the button it redirect to:
document.location.href = '/SDR/SDRJSON.php?type=' + id;
On PHP the csv file is created:
I connect to the database and create a the csv file:
while($row = $stmt->fetch(PDO::FETCH_NUM))
{
array_push($csv, $row);
}
$fp = fopen('file.csv', 'w');
foreach ($csv as $row) {
fputcsv($fp, $row, ';');
}
$FileName = 'PEW_'.$CountryCode;
fclose($fp);
header('Content-Encoding: UTF-8');
header('Content-type: text/csv; charset=UTF-8');
header("Content-Disposition: attachment; filename='".$FileName."'.csv");
header("Pragma: public");
header("Expires: 0");
echo "\xEF\xBB\xBF"; // UTF-8 BOM
readfile('file.csv');
On the page where the button is, the user clicks there and the page starts waiting for the server and then the csv file starts downloading.
For small files is ok, because it is instantaneous. But for larger files it takes like 10 / 15 seconds. Is it possible to show a message while the page waits for the server?
I don't Think PHP can echo while the csv is being made ... What you could do is split the "Document Formation" and "Document Download" into two parts.
Let Ajax Make a query for the CSV to be made . And when that has been completed the PHP (Document Formation) will echo the Path of the File.
Then After that You can use document.location.href to Newly Created File.
I ll give the code
ajax-code
$('#sample-button').click(function(){
$.ajax({
url : '/SDR/SDRJSON.php?type=' + id,
success : function(data){
if(data.url)
{
var urlToDownload = data.url;
alert("File is ready for download");
document.location.href = "http://www.domain.com/file/path/"+data.url;
// Make sure data.url has the full path or append the data.url
// with some strings to make sure the full path is reflected
// into document.location.href ...
}
else
{
alert("Something went wrong");
}
}
});
alert("CSV is being prepared Please wait... ");
});
documentFormation.php
while($row = $stmt->fetch(PDO::FETCH_NUM))
{
array_push($csv, $row);
}
$FileName = 'PEW_'.$CountryCode;
$fp = fopen($FileName, 'w');
foreach ($csv as $row) {
fputcsv($fp, $row, ';');
}
fclose($fp);
$response = array();
$response['url'] = $FileName;
echo json_encode($response); // You can handle rest of the cases where to display errors (if you have any)
// Your DocumentFormation PHP Ends here. No need for header() or readFile.
If you dont want the file to stay on server , Edit the document href to This PHP passing 'path' as the parameter
document.location.href = "documentDownload.php?path="+data.url;
documentDownload.php
$path = $_GET['path'];
$filename = end(explode("/" , $path));
header('Content-Encoding: UTF-8');
header('Content-type: text/csv; charset=UTF-8');
//Assuming $filename is like 'xyz.csv'
header("Content-Disposition: attachment; filename='".$filename);
header("Pragma: public");
header("Expires: 0");
echo "\xEF\xBB\xBF"; // UTF-8 BOM
// Reading file contents
readfile('Relative Path to File'.$path);
// Deleting after Read
unlink('Relative Path to File'.$path); // To Delete right after reading

javascript : send file to php script for user to download

In the website I'm building, I'm trying to provide users the ability to export and download data in KML format. I've built a PHP script to generate a kml file from a string. It works reasonably well, until requests get too long and then I get 414 errors.
The thing is, I'm pretty sure I'm going at this the wrong way (I'm new to php). Rather than sending my data as a string, which can get to multiple tens of thousands of characters long, I should be sending a file generated by javascript to the php script which would send it back to the user or something like this. Is it possible?
If not, what other options do I have?
Here's my php script :
if($_SERVER['REQUEST_METHOD']=='POST') {
$text = $_POST['text'];
$text = str_replace('\r\n', PHP_EOL, $text);
$text = str_replace('\n', PHP_EOL, $text);
$text = str_replace('\t', "\t", $text);
$text = str_replace('_HASH_', "#", $text);
$filename = $_POST['filename'];
$tmpName = tempnam(sys_get_temp_dir(), $filename);
$file = fopen($tmpName, 'w');
fwrite($file, $text);
fclose($file);
header('Content-Description: File Transfer');
header("Content-Type: application/octet-stream");
//header('Content-Type: text/plain');
header('Content-Disposition: attachment; filename=' . $filename . '.kml');
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($tmpName));
ob_clean();
flush();
readfile($tmpName);
unlink($tmpName);
exit;
}
* EDIT *
Ok, I changed the php script to use POST instead of GET which should clear up the length issue. But this has shown me another problem.
I'm using dojo to write my website. I'm doing an xhr request with POST method. This request comes back successfully. In the success handler, I'm navigating to the same url I passed to the request by setting the src of a hidden iFrame (so as to avoid reloading the page). The results in a GET request which doesn't work with my script (POST).Furthermore, I believe this means I'm running the php script twice which makes no sense.
Should I just navigate directly to the url of the php script with required parameters? In this case, how do I navigate to a url using a POST request?
I'm a bit confused about all of this, it probably shows too!
Thanks,
* SOLUTION *
mguimard sent me on the right track to solve my issue. Here's the bit of code I used to send my POST request while avoiding to realod the page:
download: function(text) {
var ifr = document.createElement('iframe');
ifr.setAttribute('name', "target");
ifr.style.display = 'none';
document.body.appendChild(ifr);
var f = document.createElement('form');
f.setAttribute('method',"post");
f.setAttribute('action',"saveFileAs.php");
f.setAttribute('target',"target");
addField(f, "filename", "myFileName");
addField(f, "text", text);
f.submit();
ifr.onload = cleanUp;
function cleanUp(){
document.body.removeChild(ifr);
ifr = null;
}
function addField(form, name, value) {
var i = document.createElement("input");
i.setAttribute('name',name);
i.setAttribute('type','text');
i.value = value;
form.appendChild(i);
}
}
Ggilmann

Categories