PHP Upload/Download

I have a small form where my users are able to upload a a file into MySQL and then later it can be downloaded. It appears that my files are being uploaded successfully, but when I try to download them, I get the error “Cannot open file, it may be corrupt”. My upload script is:

$fileName = $_FILES['proposal']['name'];
					$tmpName  = $_FILES['proposal']['tmp_name'];
					$fileSize = $_FILES['proposal']['size'];
					$fileType = $_FILES['proposal']['type'];
					
					$fp      = fopen($tmpName, 'r');
					$content = fread($fp, filesize($tmpName));
					$content = addslashes($content);
					fclose($fp);



					if(!get_magic_quotes_gpc())
					{
    					$fileName = addslashes($fileName);

include './lib/configdb.php';
					include './lib/opendb.php';

					$query = "INSERT INTO appfiles (name, size, type, content ) ".
					"VALUES ('$fileName', '$fileSize', '$fileType', '$content')";

					mysql_query($query) or die('Error, query failed');
					include './lib/closedb.php';
					}

and the download script is as follows:

<html>
<head>
<title>Download File From MySQL</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
</head>

<?php
if(isset($_GET['id']))
{
// if id is set then get the file with the id from database

include './lib/configdb.php';
include './lib/opendb.php';

$id    = $_GET['id'];
$query = "SELECT name, type, size, content " .
         "FROM appfiles WHERE id = '$id'";

$result = mysql_query($query) or die('Error, query failed');
list($name, $type, $size, $content) = mysql_fetch_array($result);

header("Content-length: $size");
header("Content-type: $type");
header("Content-Disposition: attachment; filename=$name");
echo $content;

include './lib/closedb.php';
exit;
}

?>



<body>
<?php
include './lib/configdb.php';
include './lib/opendb.php';

$query = "SELECT id, name FROM appfiles";
$result = mysql_query($query) or die('Error, query failed');

if(mysql_num_rows($result) == 0)
{
echo "Database is empty <br>";
}
else
{
while(list($id, $name) = mysql_fetch_array($result))
{

echo " <a href=\\"download.php?id=$id \\"> $name </a> <br>";

echo "benchmark 1";
}
}
include './lib/closedb.php';
?>
</body>
</html>

Any assistance on why the files are becoming corrupted after being uploaded and how to remedy this would be helpful.

Is your database table cell type a BLOB where you are saving your picture? Or, are you just saving the picture info in the database, and the picture in a directory on your hard drive?

I’m saving the file in BLOB field in the database.

try without the addslashes($content); or run stripslashes($content); after you retrieve it.

Uh, no. Neither. Actually, I’d highly recommend replacing addslashes with mysql_real_escape_string, but you still MUST escape data being inserted into the DB, especially binary data like this!

Also, you do not need to unescape the data - the escaping is only relevant when running the query itself, the added slashes do not accompany your data into the database. The only time this would occur is if you are double-escaping your data (is magic_quotes_gpc turned on?).

Try var_dump()-ing your variables in the download script and see what’s going on with them.

Edit:

Just spotted the problem. Ditch the HTML in your download script. That’s what’s screwing you up. In fact, I’m surprised you’re not getting errors along the lines of “Cannot send headers: data already sent”. There should be nothing at all (not even whitespace) outside of <?php and ?>

I’ve removed the html that is in the download file and now it reads:



<?php
if(isset($_GET['id']))
{
// if id is set then get the file with the id from database

include './lib/configdb.php';
include './lib/opendb.php';

$id    = $_GET['id'];
$query = "SELECT name, type, size, content " .
         "FROM appfiles WHERE id = '$id'";

$result = mysql_query($query) or die('Error, query failed');
list($name, $type, $size, $content) = mysql_fetch_array($result);

header("Content-length: $size");
header("Content-type: $type");
header("Content-Disposition: attachment; filename=$name");
echo $content;

include './lib/closedb.php';
exit;
}


include './lib/configdb.php';
include './lib/opendb.php';

$query = "SELECT id, name FROM appfiles";
$result = mysql_query($query) or die('Error, query failed');

if(mysql_num_rows($result) == 0)
{
echo "Database is empty <br>";
}
else
{
while(list($id, $name) = mysql_fetch_array($result))
{

echo " <a href=\\"download.php?id=$id \\"> $name </a> <br>";

echo "benchmark 1";
}
}
include './lib/closedb.php';
?>

My output is still the same. I’m not sure if I made it clear, but the download page does list what is in the database and provides linkes for downloading individual files, its just when I click them to download I’m told that the file is corrupted.

upload.sql


CREATE TABLE `upload` (
  `id` int(11) NOT NULL auto_increment,
  `name` varchar(30) NOT NULL,
  `type` varchar(30) NOT NULL,
  `size` int(11) NOT NULL,
  `content` mediumblob NOT NULL,
  PRIMARY KEY  (`id`)
);

up.html


&lt;form action="up.php" method="post" enctype="multipart/form-data"&gt;
&lt;table width="350" border="0" cellpadding="1" cellspacing="1" class="box"&gt;
&lt;tr&gt;
&lt;td width="246"&gt;
&lt;input type="hidden" name="MAX_FILE_SIZE" value="2000000"&gt;
&lt;input name="userfile" type="file" id="userfile"&gt;
&lt;/td&gt;
&lt;td width="80"&gt;&lt;input name="upload" type="submit" class="box" id="upload" value=" Upload "&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/form&gt;

up.php


&lt;?php
mysql_connect("localhost","user","xyz") or die(mysql_error());
mysql_select_db("database") or die(mysql_error());

    if(isset($_POST['upload']) && $_FILES['userfile']['size'] &gt; 0)
    {
    $fileName = $_FILES['userfile']['name'];
    $tmpName  = $_FILES['userfile']['tmp_name'];
    $fileSize = $_FILES['userfile']['size'];
    $fileType = $_FILES['userfile']['type'];
    $fp = fopen($tmpName, 'r');
    $content = fread($fp, filesize($tmpName));
    $content = addslashes($content);
    $file_extension = strtolower(substr(strrchr($fileName,"."),1));
    switch($file_extension){
    case "gif": $ctype="image/gif"; break;
    case "png": $ctype="image/png"; break;
    case "jpeg":
    case "jpg": $ctype="image/jpg"; break;
    case "3gp": $ctype="video/3gpp"; break;
    case "pdf": $ctype="application/pdf"; break;
    default:
    die("File requested for encrypted display has no valid extension.");
    }
    fclose($fp);
    if(!get_magic_quotes_gpc()){
    $fileName = addslashes($fileName);
    }
    $query = "INSERT INTO upload (name, size, type, content )
    VALUES ('$fileName', '$fileSize', '$file_extension', '$content')";
    mysql_query($query) or die('Error, query failed');
    echo "&lt;br&gt;File $fileName uploaded&lt;br&gt;";
    }
?&gt;

download.php


&lt;?php
    mysql_connect("localhost","user","xyz") or die(mysql_error());
    mysql_select_db("database") or die(mysql_error());
    if(isset($_GET['id'])){
    $id=intval($_GET['id']);
    $query = "SELECT name, type, size, content FROM upload WHERE id=$id";
    $result = mysql_query($query) or die('Error, query failed');
    list($name, $type, $size, $content) = mysql_fetch_array($result);
    header("Content-Disposition: attachment; filename=$name");
    header("Content-length: $size");
    header("Content-type: $type");
    echo $content;
    exit;
    }
?&gt;
&lt;html&gt;
&lt;head&gt;
&lt;title&gt;Download File From MySQL&lt;/title&gt;
&lt;meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"&gt;
&lt;/head&gt;

&lt;body&gt;
&lt;?php
    $query  = "SELECT id, name FROM upload";
    $result = mysql_query($query) or die('Error, query failed');
    if(mysql_num_rows($result) == 0)
    {
    echo "Database is empty &lt;br&gt;";
    }else{
    while(list($id, $name) = mysql_fetch_array($result)){
?&gt;
    &lt;a href="download.php?id=&lt;?php echo $id ?&gt;"&gt;&lt;?php echo $name ?&gt;&lt;/a&gt; &lt;br/&gt;
&lt;?php
    }
    }
?&gt;
&lt;/body&gt;
&lt;/html&gt;

It works for me, if you have any question, just ask

Thanks you guys!
Ernie: your code works just fine and am able to run it. Now I’m trying to figure out the difference between what your code is and what my initial code was. The difference that jumps right out at me is that checked file extension before inserting the file into the database (i dont know why that would make a difference) but I’m in the process of comparing them right now.

what really makes a difference is this


//before uploading, make sure the file extension is correct
$file_extension = strtolower(substr(strrchr($fileName,"."),1));

I am trying to work with almost exactly the same code that Ernie posted that I found online.

My upload code is working fine. My download code outputs the download links with the file names, but I hit a snag when I actually click the link. When clicked, it prompts me to download my actual download.php page, rather than my intended file.

My code is as follows:


<?php
include("config.php") ;
if(isset($_GET['id']))
{
// if id is set then get the file with the id from database


$id    = $_GET['id'];
$query = "SELECT name, type, size, content " .
         "FROM incident_reports WHERE id = $id";

$file=odbc_exec($conn, $query);
list($name, $type, $size, $content) = odbc_fetch_array($file);

header("Content-Disposition: attachment; filename=$name");
header("Content-length: $size");
header("Content-type: $type");
echo $content;


exit;
}

?>

<?



$query = "SELECT id, name FROM incident_reports";
$result=odbc_exec($conn, $query);

if(odbc_num_rows($result) == 0)
{
echo "Database is empty <br>";
}
else
{
while(odbc_fetch_array($result))
{
  $id=odbc_result($result,"id");
  $name=odbc_result($result,"name");
?>
<a href="download.php?id=<? echo $id;?>"><? echo $name;?></a> <br>
<?php
}
}

?>

Any ideas what I’m doing incorrectly? The only difference I can see is I had to change the code to connect via odbc. Otherwise it should work as far as I know.

I would also like some suggestions on how I can modify the headers so the downloaded file launches in its intended program, rather than prompt for download.

Any help in this regard would be appreciated!

try this:


<?php
ini_set("display_errors",1);
error_reporting(E_ALL);
include("opendb.php") ;
if(isset($_GET['id']))
{
	// if id is set then get the file with the id from database
	
	$id    = (int) $_GET['id'];

	$query = "SELECT name
					,type
					,size
					,content
				FROM incident_reports
				 WHERE id = $id";

	$query = mysql_query($query) or die(mysql_error());

	list($name, $type, $size, $content) = mysql_fetch_array($query);
	header("Content-Disposition: attachment; filename=$name");
    header("Content-length: $size");
    header("Content-type: $type");
    echo $content;
    exit;
}
?>

<?php

$query = "SELECT id,name FROM incident_reports";
$result = mysql_query($query) or die(mysql_error());

if(mysql_num_rows($result) == 0)
{
	echo "Database is empty <br>";
}
else
{
	while($row = mysql_fetch_row($result))
	{
?>
<a href="download.php?id=<? echo $row[0]; ?>"><? echo $row[1]; ?></a><br>
<?php
	}
}
?>

Ernie –

Your code generates this for me:

<a href="download.php?id="></a><br>
<a href="download.php?id="></a><br>  

This is at least partially working as I have two entries in my database. Its not pulling the name or id for some reason…

change the connection and the queries to fit your needs