I want to wrtite a simple code that lets me download a file depending on the ID specified in the URL. For doing that, it connects to the database and tries to get the information of the file associated to the ID. Then, it sends the headers with the extracted info and the file.
But for reasons that I don't know, it outputs a blank page. There aren't any logfiles anywhere, just it suddenly stops.
Please, a bit of help would be really appreciated. Thanks you for spending your time
<?php
//We include the variables needed to do the connection to the db
include '../php/vars.php';
$id=$_GET['id'];
//We connect to the database
$con = mysql_connect("$dbsv","$dbuser","$dbpass");
if (!$con)
{
die('Could not connect: ' . mysql_error());
}
mysql_select_db("$dbname", $con);
// We do the query
if ($query === false) {echo mysql_error();}
$query = "SELECT name,filetype FROM links WHERE id=$id";
$result = mysql_query($query);
// Check result. This shows the actual query sent to MySQL, and the error. Useful for debugging.
if (!$result) {
$message = 'Invalid query: ' . mysql_error() . "\n";
$message .= 'Whole query: ' . $query;
die($message);
}
while ($row = mysql_fetch_assoc($result))
{
// Assign variables
$filename = $row['name'];
$type = $row['filetype'];
}
//We download the file
if (file_exists($filename)) {
header('Content-Description: File Transfer');
header( "Content-type: $type");
header('Content-Disposition: attachment; filename='.basename($filename));
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($filename));
fopen("$filename", "r");;
exit;
}
?>
I'm not native English. Expect gramatical, syntax and ortographical errors. If you detect them, please, notify me.
As I see you want to pass the file right?
fopen("$filename", "r");
replace this with
readfile($filename);
fopen just opens a file pointer and does absolutly nothing with the file itself, you have to use fread, write and fclose to do stuff with the file, there are more operations but basicly fopen just gives you a file pointer
There are a lot of logical errors, you need to fix:
if ($query === false) {echo mysql_error();}
$query is not set at this point. so it's never false. (You are saying basically if (null === false))
while ($row = mysql_fetch_assoc($result))
{
// Assign variables
$filename = $row['name'];
$type = $row['filetype'];
}
//We download the file
if (file_exists($filename)) {
Depending on your result count you are overriding $filename multiple times - and then only perform an operation on the LAST value.
Either move the logic into the while loop.
Or don't use a while-loop if you are expecting a single result.
Then:
fopen("$filename", "r");
You are opening a file - and then? doing nothing at all. Continue with fread() until EOF is reached and then use fclose($handle) bevor outputting the result.
(This is the reason for simply seeing nothing)
You would use readfile() instead. readfile() reads a file and writes it to the output buffer.
Here is manual link http://php.net/manual/en/function.readfile.php
if (file_exists($filename)) {
header('Content-Description: File Transfer');
header( "Content-type: $type");
header('Content-Disposition: attachment; filename='.basename($filename));
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($filename));
readfile($filename);
exit;
}
Related
download.php:
<?php require_once('Connections/connection_psfriend.php'); ?>
<?php
$idreceived = addslashes($_REQUEST['sendid']);
$filepathquery = "SELECT bd_brushfilepath FROM tbl_brushdescription WHERE bd_brushid = $idreceived";
$Recordset = mysql_query($filepathquery,$connection_psfriend) or die(mysql_error());
$filepath = mysql_fetch_assoc($Recordset);
$receivedfilerequest = $filepath['bd_brushfilepath'];
$file_path = $_SERVER['DOCUMENT_ROOT'].'/'.'ps-friend'.'/' . $receivedfilerequest;
$updatedownlaodquery = "UPDATE tbl_brushdescription SET bd_brushdownloads = bd_brushdownloads + 1 WHERE bd_brushid = $idreceived";
$Recordset = mysql_query($updatedownlaodquery,$connection_psfriend) or die(mysql_error());
if(file_exists( $file_path)){
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($file_path));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file_path));
ob_clean();
flush();
readfile($file_path);
exit;
}
My problem:
The code works fine with google Chrome for all 143 entries made in the database. It works fine fine with Firefox too except for 5 out of those 143.
for firefox it shows:( for those 5 entries):
In the database, I am using filepaths to store the files. All the files are either in zip format or rar format. Those files are not downloaded in rar/zip format. With google chrome, there is no problem at all. Is there something wrong with the script?
First of all, please stop using MYSQL_ function, see why-shouldnt-i-use-mysql-functions-in-php.
Secondly you are using $idreceived = addslashes($_REQUEST['sendid']); as a nice way to prevent SQL injection. Unfortunately you are calling the query like WHERE bd_brushid = $idreceived, so without quotes.
In other words, you are still vulnerable, as long as I dont use any quotes. Consider me sending sendid=1 OR 1=1. All your rows would be updated in the second query.
Change it to WHERE bd_brushid = '$idreceived', or even better: check how-to-prevent-sql-injection-in-php
Now to your problem. I think you should change one line to the following to include quotes
header('Content-Disposition: attachment; filename="'.basename($file_path).'"');
If it still does not work, send the right content type in the header.
<?php
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$type = finfo_file($finfo, $file_path);
header('Content-Type: '.$type)
?>
The following has always worked for me
$file=$_POST['file'];
header( "Content-Disposition: attachment; filename=$file" );
readfile("$_POST[file]");
without any of the content type headers.However my file extension is .zip.Your file does not seem to have an extension.
I have created a PHP page that allows users to download a file when they click the this link:
Download File
I have also created the download page that the link directs to:
<?php
if(isset($_GET['file'])) {
$fileID = $_GET['pubid'];
$filename= ($_GET['file']);
$path = "admin/pubfiles/";
$fullPath = $path . $filename;
mysql_select_db($database_connDioceseofife, $connDioceseofife);
$sql = "SELECT file FROM publications WHERE pubID = $fileID";
$result = mysql_query($sql) or die(mysql_error());
$row = mysql_fetch_assoc($result);
if($filename == NULL) {
die('No file exists or the name is invalid!');
}
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header("Content-Disposition: attachment; filename=\"$filename\"");
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
readfile($fullPath);
}
?>
Now my problem is, when the download popup window come up, it reads that the file is of 0 bytes. And when downloaded, it can't open. i get the message that it is not a supported file type or its been damaged or corrupted.
Please any help would be much appreciated.
You're not doing anything with the query result in $row.
Use $row['file'] to get the actual file itself.
Thank you all for assisting me. I have been able to solve the problem after further reading. I have updated the initial script i wrote. what is above is now the working script.
What i did was to include $fullpath = $path . $filename then changed the header("Content-Disposition: attachment; filename=\"$filename\""); and then the readfile function from readfile($path) to readfile($fullpath).
Thanks again #nlsbshtr and everybody else for your help.
I am using php script to provide download from my website after a requisite javascript timer this php script is included which causes the download. But the downloaded file is corrupt no matter whatever I try. Can anyone help me point out where am I going wrong.
This is my code
<?php
include "db.php";
$id = htmlspecialchars($_GET['id']);
$error = false;
$conn = mysql_connect(DB_HOST,DB_USER,DB_PASSWORD);
if(!($conn)) echo "Failed To Connect To The Database!";
else{
if(mysql_select_db(DB_NAME,$conn)){
$qry = "SELECT Link FROM downloads WHERE ID=$id";
try{
$result = mysql_query($qry);
if(mysql_num_rows($result)==1){
while($rows = mysql_fetch_array($result)){
$f=$rows['Link'];
}
//pathinfo returns an array of information
$path = pathinfo($f);
//basename say the filename+extension
$n = $path['basename'];
//NOW comes the action, this statement would say that WHATEVER output given by the script is given in form of an octet-stream, or else to make it easy an application or downloadable
header('Content-type: application/octet-stream');
header('Content-Length: ' . filesize($f));
//This would be the one to rename the file
header('Content-Disposition: attachment; filename='.$n.'');
//Finally it reads the file and prepare the output
readfile($f);
exit();
}else $error = true;
}catch(Exception $e){
$error = true;
}
if($error)
{
header("Status: 404 Not Found");
}
}
}
?>
This helped me in case of more output buffers was opened.
//NOW comes the action, this statement would say that WHATEVER output given by the script is given in form of an octet-stream, or else to make it easy an application or downloadable
header('Content-type: application/octet-stream');
header('Content-Length: ' . filesize($f));
//This would be the one to rename the file
header('Content-Disposition: attachment; filename='.$n.'');
//clean all levels of output buffering
while (ob_get_level()) {
ob_end_clean();
}
readfile($f);
exit();
First of all, as some people pointed out on the comments, remove all spaces before the opening PHP tag (<?php) on the first line and that should do the trick (unless this file is included or required by some other file).
When you print anything on the screen, even a single space, your server will send the headers along with the content to be printed (in the case, your blank spaces). To prevent this from happening, you can:
a) not print anything before you're done writing the headers;
b) run an ob_start() as the first thing in your script, write stuff, edit your headers and then ob_flush() and ob_clean() whenever you want your content to be sent to the user's browser.
In b), even if you successfully write your headers without getting an error, the spaces will corrupt your binary file. You should only be writing your binary content, not a few spaces with the binary content.
The ob_ prefix stands for Output Buffer. When calling ob_start(), you tell your application that everything you output (echo, printf, etc) should be held in memory until you explicitly tell it to 'go' (ob_flush()) to the client. That way, you hold the output along with the headers, and when you are done writing them, they will be sent just fine along with the content.
ob_start();//add this to the beginning of your code
if (file_exists($filepath) && is_readable($filepath) ) {
header('Content-Description: File Transfer');
header("Content-Type: application/octet-stream");
header("Content-Disposition: attachment; filename=$files");
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header("content-length=".filesize($filepath));
header("Content-Transfer-Encoding: binary");
/*add while (ob_get_level()) {
ob_end_clean();
} before readfile()*/
while (ob_get_level()) {
ob_end_clean();
}
flush();
readfile($filepath);
How can I check if something was print in the browser? I've tried headers_sent but it's for headers...
If nothing was printed i want to download a file:
public function download() {
$file = null;
$line = null;
if(headers_sent($file, $line)) {
/* generic exception... change that... */
throw new Exception('Headers was sent before in file ' . $file . ', line #' . $line);
}
header('Content-Description: File Transfer');
header('Content-Type: ' . $this->mime);
header('Content-Disposition: attachment; filename=' . $this->name);
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Length: ' . $this->size);
readfile($this->path);
Thank you.
You can use PHP Output control functions to check if there was any output to the browser.
Example:
<?php
ob_start();
echo 'something';
$output = ob_get_contents();
if (!empty($output))
{
die('something was printed');
}
else
{
readfile();
}
The short answer is you can't. After you have sent data to the client, you have no chance of finding out what gets done with that data.
This question has some workaround ideas, but none of them is anywhere near fail-safe.
I don't know of any way of detecting if output is already started. I suppose headers_sent is a way to detect that, since PHP will send the headers when it runs into the first output in the executing script.
If you need to control when the output is started, you should probably look into output buffering control.
How do I put a download button on a site to get a CSV of a table Query?
Currently I am using SELECT * INTO OUTFILE to make the CSV file on the server HD and is fine except...
I want to create the CSV like I am now, but I want the "OUTFILE" to be saved on the clients computer when they click Download.
<?php
// Create new file name for file to be created
$csvfilename = "/dropbox/consolodated-" . date("Y-M-d_H-i-s") . ".csv";
mysql_query ("SELECT * INTO OUTFILE '$csvfilename' FIELDS TERMINATED BY ',' FROM people ");
?>
<H2>Done - File created - Now download it from FTP site.</H2>
The solution to this can be that:
First you save the csv file on to server.
then get it's path
and finally create an anchor tag with its path for download eg:
_
Download
Here are a couple of similar posts:
Generating CSV file and then forcing the file to download.
PHP code to convert a MySQL query to CSV
Add a POST form at the end which includes a hidden field containing the filename (but NOT the path!) of the file to download. Then have the page it POSTs to read the variable and offer the file for download. Don't forget to enable output buffering and to occasionally flush so that the form is not visible until the query has completed.
Simple, here is a sample snippet:
$csv_filename = "/dropbox/consolodated-" . date("Y-M-d_H-i-s") . ".csv";
Download($csv_filename);
And here is the download function:
function Download($path, $speed = null)
{
if (is_file($path) === true)
{
set_time_limit(0);
while (ob_get_level() > 0)
{
ob_end_clean();
}
$size = sprintf('%u', filesize($path));
$speed = (is_null($speed) === true) ? $size : intval($speed) * 1024;
header('Expires: 0');
header('Pragma: public');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Content-Type: application/octet-stream');
header('Content-Length: ' . $size);
header('Content-Disposition: attachment; filename="' . basename($path) . '"');
header('Content-Transfer-Encoding: binary');
for ($i = 0; $i <= $size; $i = $i + $speed)
{
echo file_get_contents($path, false, null, $i, $speed);
flush();
sleep(1);
}
exit();
}
return false;
}
Merry Xmas to you too! =)