Let's say i want to generate a download link and put it into <a> tag.
my php script:
function download_link(){
$this_id = "d"; //this is the name of file from server
$original_filename = 'xample.pdf'; //This come from database
$ext = pathinfo($original_filename, PATHINFO_EXTENSION);
$file = '../uploads/'.$this_id.'.'.$ext;
if (file_exists($file)) {
header('Content-Description: File Transfer');
header('Content-Type: application/'.$ext);
header('Content-Disposition: attachment; filename='.$original_filename);//Rename the file with its original filename
header('Content-Transfer-Encoding: binary');
header('Content-Length: ' . filesize($file));
ob_clean();
flush();
return readfile($file);//Here where i want to return the generated url
}
return '#'; //Or return nothing if file doesn't exist
echo ''; //And put it here, the generated url
now, my directory location is ../uploads/.
i am expecting a result like: so when the user click this tag the file will be downloaded. but instead, when i reload the page it is automatically downloading without clicking the download button which is the <a> tag.
note: i am trying to rename the filename when botton download is clicked.
i know there is a problem in my logic. maybe this can be done with JQUERY? or AJAX? im searching for solution but did not find the answer.
here's what i did with JQUERY AJAX:
HTML tag
<a id="server_name_file_name">download</a>
JQUERY AJAX:
$('a').click(function(e) {
e.preventDefault();
var id = $(this).attr('id');
$.ajax({
type: 'POST',
url: 'download.php',
data: { server_file_name: id,},
success: function(response) {
if(response == 1){
alert("Unable to download, Maybe the file is corrupted. Please try to reload the page.");
}else{
window.location.href = response;
return false;
}
}})
});
download.php
$this_id = $_POST['server_file_name'];
$original_filename = 'xample.pdf'; //This come from database
$ext = pathinfo($original_filename, PATHINFO_EXTENSION);
$file = '../uploads/'.$this_id.'.'.$ext;
if (file_exists($file)) {
header('Content-Description: File Transfer');
header('Content-Type: application/'.$ext);
header('Content-Disposition: attachment; filename='.$original_filename);//Rename the file with its original filename
header('Content-Transfer-Encoding: binary');
header('Content-Length: ' . filesize($file));
ob_clean();
flush();
echo readfile($file);//Here where i want to return the generated url
exit();
} die('1');
but doesnt work.
anyone can help me here? Thank you!!!!
You're returning the actual contents of the file with readfile.
Thats why browser starts to download the file you return.
What you need to do is to generate the string which will point to the file.
If your "uploads" dir is accessible by url, then your downloads.php should look like this:
$this_id = $_POST['server_file_name'];
$original_filename = 'xample.pdf'; //This come from database
$ext = pathinfo($original_filename, PATHINFO_EXTENSION);
$file = '../uploads/' . $this_id . '.' . $ext;
if (file_exists($file)) {
echo 'www.myserver.com/uploads/' . $this_id . '.' . $ext;
exit();
}
die('1');
If your uploads dir is not accessible from outside, then you need to copy the file into the public directory first.
At a first glance, i can identify a couple of problems.
Your download function does not return the link of the file but rather it outputs the file itself, so it is logical that when refreshing the page, the file is downloading.
Plus, I can see that you are calling your function useing function download_link() whereas it should be directly download_link().
The proper way this should be done is having the download link to a file executing the download_link function (ex: http://yoursite.com/download_file.php?file=filename)
Of course it is advisable to have an id instead of filename in the URL and apply all the security you need etc...
Inside download_file.php file, you can call download_link($filename) or better download_link($id) and get the file name from the database or wherever you are storing it and then output the file as you are doing now.
Related
I am trying to implement download functionality in PHP. A user can download single or multiple files. If user try to download single file, the file gets downloaded normally. If user tries to download multiple files, all the files will be converted to zip and get downloaded.
But my problem is how to pass the gruop of filenames along with their paths. For a single file I passed it using
window.location = directories_path + "?action=download&files="+download;
download can be an array where I can pass files. But I am unable to pass them. My url appeared alike
localhost/proj/Base?action=download&files=[object Object]
I even tried with AJAX passing file names in json format. But it didn't work.
My JS code for the download process
$("input:checked").each(function(){
if($(this).siblings('a').length > 0)
{
download.push({
name: $(this).siblings('a').text(),
path: $(this).siblings('a').attr('href'),
});
}
});
if( checked == 0 ) {
alert("Please select any file to download");
} else {
window.location = directories_path + "?action=download&files="+download;
}
My php code for downloading single file is
header('Content-Type: application/octet-stream');
header('Content-Length: '.filesize($file));
header('Content-Disposition: attachment; filename='.$file);
header('Content-Transfer-Encoding: binary');
readfile($file);
My question is Is there any way so that I can pass an array of objects(filename and filepath) in url so that I can download the files correspondingly. Thanks
Thanks #ADyson and remaining all others for help. Finally this is how I implemented it. I am posting it so that it might be useful to someone.
I made an AJAX post request and returned the link. And finally changed the window.location to that specific link for multiple files. But for single file downloads, It may not be possible sometimes. For Eg: If you change the location to PNG image. The browser opens the PNG image instead of downloading it. So, I preferred HTML anchor download tag for single file downloads.
This is my JQuery code:
$(".uploaded_files").on('click', '#download', function(event){
download = [];
$("input:checked").each(function(){
if($(this).siblings('a').length > 0)
{
download.push({
name: $(this).siblings('a').text(),
path: $(this).siblings('a').attr('href'),
});
}
});
if( checked == 0 ) {
alert("Please select any file to download");
} else if( checked == 1) {
$("body").append($(''));
console.log(download);
document.getElementById('download_single').click();
$("a#download_single").remove();
} else {
alert("The download begins in few seconds");
$.post('Base.php', {
action: 'download',
files: download //array of objects of files
}, function(link) {
window.location = link;
});
}
});
This is my PHP code for downloading multiple files
$zip = new ZipArchive();
$zip_file = 'tmp/'.md5("download".rand(1,1000000)."zipfile").".zip";
if( $zip->open($zip_file, ZipArchive::CREATE))
{
foreach($files as $file)
{
$file['path'] = explode('uploads/', $file['path'])[1];
$file['path'] = 'uploads/'.$file['path'];
$zip->addFile($file['path'], $file['name'] );
}
$zip->close();
header('Content-disposition: attachment; filename='.$zip_file.'');
header('Content-type: application/zip');
echo "http://localhost/".$zip_file;
die();
So this is my whole setup :
I'm on a HTML page and i'm opening a POST request using JS inside the same HTML page and i'm opening it in a new window like this :
<script>
function Download() {
form = document.createElement('form');
form.setAttribute('method', 'POST');
form.setAttribute('action', 'test.php?App=AppNameHere');
form.setAttribute('target', 'NewWindow');
myvar = document.createElement('input');
myvar.setAttribute('name', 'terms');
myvar.setAttribute('value', '');
form.appendChild(myvar);
document.body.appendChild(form);
window.open('test.html', 'NewWindow', 'scrollbars=no,menubar=no,height=100,width=500,resizable=no,toolbar=no,status=no');
form.submit();
}
</script>
Now inside test.php i'm downloading an app referring to the GET request for the App var in the URL, also the POST request works just fine, but after start downloading the file i need to close the window, so i used :
echo "<script type='text/javascript'>window.close();</script>";
Now i tested it and it worked closing the window just fine, but now here is my problem... inside the test.php file i'm also using sessions (session_start();) and when i do use that line (session_start();) the java script code for closing the window does not work any more!!, i'v tried commenting all the code but keeping session_start(); and i really found out that it's what preventing the window from closing, which is very weird, they are not related at all, or this is what i think at least, here is my test.php file :
<?php
session_start();
if($_SESSION["TEMP"] == "Yes"){
if(isset($_GET['App'])){
$fileName = $_GET['App'] . " - Setup.exe";
if(basename($_GET['App']) == $_GET['App']){
$path = 'download_directory/' . $fileName;
$size = filesize($path);
header('Content-Type: application/octet-stream');
header('Content-Length: ' . $size);
header('Content-Disposition: attachment; filename=' . $fileName);
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
ob_clean();
$file = # fopen($path, 'rb');
if($file){
fpassthru($file);
$_SESSION["TEMP"] = "No";
}
}
}
}
echo "<script type='text/javascript'>window.close();</script>";
?>
Downloading the file also worked!
Can someone please explain to me what's happening and help me go around this because i really need to use sessions?!
In public/templates/calendar.html I have
<a href="" id="secret_download_button" style="display:none" download="">
In the same file I have a button (download qr), i make an ajax call from javascript, the qr gets created in /public/uploads/thumbs/qrcodes/'filename'
the ajax calls is finished and the following function is called which is in
public/javascript/some.js
function (data) {
$('#secret_download_button').attr('href',data.content);
$('#secret_download_button').attr('download','somename');
$('#secret_download_button').click();
});
data.content = public/upload/thumbs/qrcodes/someqr.png (example)
I need to use relative paths, not absolute paths. What am I doing wrong ? I am guessing that I am setting the href path wrong.
Also from what I read online this solution is not supported by IE. Is there another, simpler, more elegant way of doing this ( I need to be able to specify the name of the file which will be downloaded )
Edit
Solved it server-side in the end. thanks. For anyone else having the same problem I used this:
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.basename($activity_name . '.png').'"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($root . $path . $file_name));
readfile($root . $path . $file_name);
exit;
You're right, the download attribute is not supported by IE nor Edge (supported in Edge 13+) : http://caniuse.com/#feat=download
To have a cross-browser solution, you will have to open the url in the current window :
function (data) {
window.location.href = data.content;
});
or a new window :
function (data) {
window.open(data.content);
});
Two limitations:
you can't set the filename client-side, you have to set it server side
the browser will not download the file if it can read it (like images, pdf...), you will have to use the "save as"
I have a page with some forms and input fields, which the user fills in and then they are sent to a php page via Ajax and $_POST.
And then the php File writes the output to a txt file. - that works just fine. My problem is I am trying to force the user to download it on that same page that creates the file, after the file is created and I can't seem to get it to work, nothing happens besides the file being created:
Here the code where the .txt File is created (this works nice):
$myfile = fopen("test.txt", "w") or die("Unable to open file!");
foreach ($URLsArray as &$url) {
$row=$SomeArray[$keys[$index]]."\t".$SomeArray[$keys[$index]]."\t".$SomeArray[$keys[$index]]."\t".$SomeArray[$keys[$index]]."\t".$url."\n";
fwrite($myfile, $zeile);
$index = $index + 1;
}
fclose($myfile);
And here the code, where I try to force the download: (after the fclose)
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename('test.txt'));
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize('test.txt'));
readfile('test.txt');
exit;
And when I try this I get the error: "Unexpected token A". "A" is the first letter in the test.txt, which is created.
And I know that there are a lot of similar questions, but not one solution worked for me.
I hope someone can help me :)
Instead of doing this backend with PHP you could try to do this on the frontend part. The easiest solution is to write some JavaScript code which adds an iframe to your webpage. The iframe should then have a href to the file you want the user to download.
Okay here my solution: #CBroe thanks for the hint with the background request, I would have tried for ages to get the download work in the php file. So what I did:
In PHP: I echo the filename after the .txt file is created:
echo json_encode(array('filename' => "your_Data".time().".txt"));
Than in JavaScript I read the filename in the success method and put the link in an <a> element. Later that will be a button which is set active.
success : function(data) {
$("#button_get_file_download").attr("href", "urlToFolder"+data.filename);
},
I have built a PHP script that sends *.MP3 files form outside the public_html directory,
it works OK and sends the file. The problem is that I have a JavaScript script which should change the current time of the audio file (audioFile.currentTime = 25;).
When I do this(Get the file from inside the public_html directory), it works:
// JavaScript:
var audioFile = new Audio("https://www.website.com/files/audioFile.mp3");
audioFile.play();
audioFile.currentTime = 15;
But, when I try to get the file from the following PHP script it sends the file OK. But, I can't change the "currentTime" using JavaScript
<?php
// This PHP file is public www.website.com/getAudioFile.php/
$fileLocation = "../audioFiles/audioFile.mp3";
if (file_exists($fileLocation))
{
header('Content-type: audio/mpeg');
header('Content-Disposition: inline; filename="' . $filename . '"');
header('Content-Transfer-Encoding: binary');
header('Content-Length: ' . filesize($file));
readfile($file);
}
?>
This is the JavaScript within which I tried to change the audio file currentTime:
<script>
var audioFile = new Audio("www.website.com/getAudioFile.php");
audioFile.play();
audioFile.currentTime = 15;
</script>
Each time I use object.currentTime = 15, the audio files plays from the start.
If anyone knows what headers I should send or anything else I should do, please let me know how to solve my problem.
Maybe You should bind canplay event from Audio component and in this callback set currentTime property.
http://www.w3schools.com/tags/av_event_canplay.asp
Shortly after I have posted this question, I found the solution to the problem.
In order to make the script work you will need to add the header('Accept-Ranges: bytes');
Like this:
<?php
// This PHP file is public www.website.com/getAudioFile.php/
$fileLocation = "../audioFiles/audioFile.mp3";
if (file_exists($fileLocation))
{
header('Content-type: audio/mpeg');
header('Content-Disposition: inline; filename="' . $filename . '"');
header('Content-Transfer-Encoding: binary');
header('Accept-Ranges: bytes');
header('Content-Length: ' . filesize($file));
readfile($file);
}
?>