Jump to content

Files downloaded from database corrupt/not keeping file extension


mikeg542

Recommended Posts

As the title suggests, I am storing files in the database then having others download them. When the file downloads, firefox knows what the file type is (example txt, pdf, jpeg) but when it is installed on my computer it doesn't have the file extension nor can it be opened by the applicable viewing application. Here's my code:

 

upload file

$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);

fclose($fp);

 

 

$query = "INSERT INTO items (sizefile, typefile, content, linknum, sentstaffid, recievedstaffid, clientname) ".

"VALUES ('$fileSize', '$fileType', '$content', '$link', '', '', '')";

 

 

Downloading the file:

while(list($id) = mysql_fetch_array($result))

{

?>

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

<?php

}

}

}

 

 

download.php

include (databaseopen.php);

 

if(isset($_GET['id']))

{

$id = $_GET['id'];

$query = "SELECT linknum, typefile, sizefile, content FROM items WHERE linknum = '$id'";

 

$result = mysql_query($query) or die('Error, query failed' . mysql_error());

list($name, $type, $size, $content) = mysql_fetch_array($result);

$content = stripslashes($content);

 

header("Content-type: $type");

header("Content-length: $size");

header("Content-Disposition: attachment; filename=$name");

header("Content-Description: PHP Generated Data");

echo $content;

 

 

exit;

is this MySQL? change the following lines:

 

update file:

    $fileName = mysql_real_escape_string($_FILES['userfile']['name']);
    $tmpName  = mysql_real_escape_string($_FILES['userfile']['tmp_name']);
    $fileSize = mysql_real_escape_string($_FILES['userfile']['size']);
    $fileType = mysql_real_escape_string($_FILES['userfile']['type']);

    $fp      = fopen($tmpName, 'r');
    $content = fread($fp, filesize($tmpName));
    $content = mysql_real_escape_string($content);
    fclose($fp);


    $query = "INSERT INTO items (sizefile, typefile, content, linknum, sentstaffid, recievedstaffid, clientname) ".
    "VALUES ('$fileSize', '$fileType', '$content', '$link', '', '', '')";

 

download.php

include (databaseopen.php);

if(isset($_GET['id']))
{
$id = $_GET['id'];
$query = "SELECT linknum, typefile, sizefile, content FROM items WHERE linknum = '$id'";

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

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


exit;

If I do it with a .doc file for example, the file displays pages of failed to display characters instead of the 5 letters the document actually has. It does seem to be keeping the extension better however! Just another problem came out of that

hum...ok...try doing base64 encode/decode...

update file

    $fileName = mysql_real_escape_string($_FILES['userfile']['name']);
    $tmpName  = mysql_real_escape_string($_FILES['userfile']['tmp_name']);
    $fileSize = mysql_real_escape_string($_FILES['userfile']['size']);
    $fileType = mysql_real_escape_string($_FILES['userfile']['type']);

    $fp      = fopen($tmpName, 'r');
    $content = fread($fp, filesize($tmpName));
    $content = base64_encode($content);
    fclose($fp);

    $query = "INSERT INTO items (sizefile, typefile, content, linknum, sentstaffid, recievedstaffid, clientname) ".
    "VALUES ('$fileSize', '$fileType', '$content', '$link', '', '', '')";

 

download.php

include (databaseopen.php);

if(isset($_GET['id']))
{
$id = $_GET['id'];
$query = "SELECT linknum, typefile, sizefile, content FROM items WHERE linknum = '$id'";

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

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


exit;

 

to be honest...databases aren't really for storing files. you should keep the files in a folder somewhere. once you insert the record into the database (do everything the same, except don't put the content in), use mysql_insert_id() to get the ID of that row. Then, move the file to the folder and name it that ID.

 

same problem. The document gets filled with crap.

 

The purpose for this script is for authenticated users (these are going to be people who we trust to directly upload the files) will upload the files and this will create a linknum that can be entered in a field to download the file from the website with the same linknum. If this could be done without needing to store the files like this, That'd work perfectly well too. Thanks for your help thus far.

yeah, create a folder, let's call it 'uploads'. put this folder outside the webroot or use htaccess to block direct access to it. in your table, i assume you have a unique field? you mention linknum, so i will assume this field is unique:

 

    $fileName = mysql_real_escape_string($_FILES['userfile']['name']);
    $fileSize = mysql_real_escape_string($_FILES['userfile']['size']);
    $fileType = mysql_real_escape_string($_FILES['userfile']['type']);

    $query = "INSERT INTO items (sizefile, typefile, content, linknum, sentstaffid, recievedstaffid, clientname) ".
    "VALUES ('$fileSize', '$fileType', '', '$link', '', '', '')";

    $tmpName  = $_FILES['userfile']['tmp_name'];
    move_uploaded_file($tmpName,'uploads/'.$link);

that should move the file to the uploads folder (change the path to uploads accordingly). and the filename should be whatever the value of $link is (again, which i assume is unique)

 

then to download:

include (databaseopen.php);

if(isset($_GET['id']))
{
$id = mysql_real_escape_string($_GET['id']);
$query = "SELECT linknum, typefile, sizefile FROM items WHERE linknum = '$id'";

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

header("Content-type: $type");
header("Content-length: $size");
header("Content-Disposition: attachment; filename=$name");
header("Content-Description: PHP Generated Data");
readfile('uploads/'.$name);
exit;

Here's what I have now

 

upload

if (isset($_POST['upload']))

{

$linkchars = 'BCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz123456789';

$link = '';

for ($x=0; $x < 8; $x++)

{

$link .= $linkchars{rand(0, strlen($linkchars)-1)};

}

    $fileName = mysql_real_escape_string($_FILES['userfile']['name']);

    $fileSize = mysql_real_escape_string($_FILES['userfile']['size']);

    $fileType = mysql_real_escape_string($_FILES['userfile']['type']);

 

    $query = "INSERT INTO items (sizefile, typefile, content, linknum, sentstaffid, recievedstaffid, clientname) ".

    "VALUES ('$fileSize', '$fileType', '', '$link', '', '', '')";

 

    $tmpName  = $_FILES['userfile']['tmp_name'];

    move_uploaded_file($tmpName,'uploads/'.$link);

 

mysql_query($query) or die('Error, query failed:'. mysql_error());

 

 

download

 

if(isset($_GET['id']))

{

 

$id = mysql_real_escape_string($_GET['id']);

$query = "SELECT linknum, typefile, sizefile FROM items WHERE linknum = '$id'";

 

$result = mysql_query($query) or die('Error, query failed' . mysql_error());

list($name, $type, $size) = mysql_fetch_array($result);

 

header("Content-type: $type");

header("Content-length: $size");

header("Content-Disposition: attachment; filename=$name");

header("Content-Description: PHP Generated Data");

readfile('uploads/'.$name);

 

exit;

}

 

 

 

 

$link is used as a unique identifier that users can use to upload a certain file. While we trust all the users with uploading and downloading, we still only want those who are supposed to get the files to be able to open them (thus the lnik codes)

but the link is just a random 8 characters right? so there is a unique key for it? instead, you should have an auto_increment field in your table. you insert the row into the table, then use that to identify it. do you have an auto_incrementing primary key?

I do, but since the linknum can be fed into download.php?id=##. If it just uses an autoincrementer, each user would have access to their file as well as every single one before it in the increment.

 

Having the link my way gives : 51^8 possibilities which makes it HIGHly unlikely to have a non-unique code. As well, there will be a function that checks if the code is taken when it is created.

sorry, but that is the wrong way to do it. in download.php you should check to see if the user has access to the requested file. the way you have it now, you can easily have collisions with the $linknum and overwrite files

Not particularly, the chances are still 1 in hundreds of thousaunds that two are the same even with 10000 entries. But that's not the point, I was told to do it this way so I'm just doing the best I can with what I have (validation with the database to redo the $link = ... if there already is one with that name).

I just hope to figure out why the doc files are empty and the image files are not keeping their extensions. I appreciate any help you give

right, but we are past that...

 

when downloading, you want the filename to be the original filename when it was uploaded right?

 

-a user uploads sample.doc

-it generates a random linknum: abcdefgh

-the user goes to download.php?id=abcdefgh

-the file that downloads should be called sample.doc right?

 

if so, you need to store the filename "sample.doc" into a field in the DB

right...that is the internal path to the file...but i'm talking about the headers you send to the person downloading it:

 

header("Content-type: $type");
header("Content-length: $size");
header("Content-Disposition: attachment; filename=$name");
header("Content-Description: PHP Generated Data");

 

$name is whatever filename you want in the Save prompt the user gets. i assume that is what you meant by "not keeping their extensions". if i am wrong what do you mean by "not keeping their extensions"

assuming the new field is called 'namefile':

 

if (isset($_POST['upload']))
{
  $linkchars = 'BCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz1234567 89';
  $link = '';
  for ($x=0; $x < 8; $x++)
  {
    $link .= $linkchars{rand(0, strlen($linkchars)-1)};
  }

  //Move file
  $tmpName  = $_FILES['userfile']['tmp_name'];
  move_uploaded_file($tmpName,'uploads/'.$link);
  
  //Add to database     
  $fileName = mysql_real_escape_string($_FILES['userfile']['name']);
  $fileSize = mysql_real_escape_string($_FILES['userfile']['size']);
  $fileType = mysql_real_escape_string($_FILES['userfile']['type']);
  $query = "INSERT INTO items (sizefile, typefile, namefile, linknum, sentstaffid, recievedstaffid, clientname) VALUES ('$fileSize', '$fileType', '$fileName', '$link', '', '', '')";
  mysql_query($query) or die('Error, query failed:'. mysql_error());
}

 

if(isset($_GET['id']))
{
  $id = mysql_real_escape_string($_GET['id']);
  $query = "SELECT linknum, typefile, sizefile, namefile FROM items WHERE linknum = '$id'";
  $result = mysql_query($query) or die('Error, query failed' . mysql_error());
  list($file, $type, $size, $name) = mysql_fetch_array($result);

  header("Content-type: $type");
  header("Content-length: $size");
  header("Content-Disposition: attachment; filename=$name");
  header("Content-Description: PHP Generated Data");
  readfile('uploads/'.$file);
  exit;
}

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.