In my website, I want to allow the user to upload files (they will be stored in a database) and then allow them to download the uploaded files after that. The uploading process is done without errors and they are saved in binary.
The downloading process also works but the downloaded files are corrupted !
Any idea why?
The uploading code:
<?php require_once('Connections/databasestudents.php'); ?>
<?php
$fileName = $_FILES['file']['name'];
$tmpName = $_FILES['file']['tmp_name'];
$fileSize = $_FILES['file']['size'];
$fileType = $_FILES['file']['type'];
$fp = fopen($tmpName, 'r');
$content = fread($fp, filesize($tmpName));
$content = addslashes($content);
$studentId = $_POST['studentId'];
fclose($fp);
$query = "INSERT INTO file (studentId, fileName, fileType, fileContent ) ".
"VALUES ('$studentId', '$fileName', '$fileType', '$content')";
mysql_select_db($database_databasestudents, $databasestudents);
mysql_query($query) or die('Error, query failed');
header("Location: students.php");
die();
?>
The download code:
<?php require_once('Connections/databasestudents.php'); ?>
<?php
mysql_select_db($database_databasestudents, $databasestudents);
$query = 'SELECT fileName, fileContent, fileType, LENGTH(fileContent) as fileSize from file WHERE id="'. $_GET ['id'].'";';
$Recordset1 = mysql_query($query, $databasestudents) or die(mysql_error());
$row_Recordset1 = mysql_fetch_assoc($Recordset1);
$result = mysql_query($query);
$row = mysql_fetch_array($result, MYSQL_BOTH);
$size = $row['fileSize'];
$type = $row['fileType'];
$name =$row['fileName'];
$fileContent = $row['fileContent'];
echo $size . "". $type . " ". $name;
header("Content-length: $size");
header("Content-type: $type");
header("Content-Disposition: attachment; filename=$name");
echo $fileContent;
mysql_close();
?>
Use PDOs and prepared statements. This may fix the issue, and it will fix the SQL injection vulnerability in the download code (which currently allows people to hack your database).
PDO has "large objects" (LOBs) support meant for exactly what you are doing. It will be much more efficient than what you are currently doing. The documentation provides excellent example code which does more or less exactly what you want.
I've figured it out .. jus removing this line from the download code:
echo $size . "". $type . " ". $name;
Related
I have successfully uploaded pdf files to the database but now when I am trying to read the files I'm getting issue "Failed to load PDF" when I click on the link. I have checked my browser plugins there is no issue with it.
<?php
$con=mysqli_connect("localhost","root","");
// Check connection
if (mysqli_connect_errno())
{
echo "Failed to connect to MySQL: " . mysqli_connect_error();
}
mysqli_select_db($con,"mahmood_faridi");
$query = "SELECT id, name FROM upload";
$result = mysqli_query($con,$query) or die('Error, query failed');
if(mysqli_num_rows($result)==0){
echo "Database is empty <br>";
}
else{
while(list($id, $name) = mysqli_fetch_array($result)){
echo "$name<br>";
}
}
if(isset($_GET['id'])){
$id = $_GET['id'];
$query = "SELECT content FROM upload WHERE id = '$id'";
$result = mysqli_query($con,$query) or die('Error, query failed');
$row = mysqli_fetch_row($result);
$content=$row['content'];
header('Content-type: application/pdf');
header('Content-Disposition: inline; filename="' . $content . '"');
header('Content-Transfer-Encoding: binary');
header('Accept-Ranges: bytes');
ob_clean();
ob_flush ();
#readfile($content);
}
mysqli_close($con);
?>
This is the “save file” code:
<?php
$con=mysqli_connect("localhost","root","");
// Check connection
if (mysqli_connect_errno())
{
echo "Failed to connect to MySQL: " . mysqli_connect_error();
}
if(isset($_POST['upload']) && $_FILES['userfile']['size'] > 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 = mysqli_real_escape_string($con,$content);
fclose($fp);
if(!get_magic_quotes_gpc())
{
$fileName = mysqli_real_escape_string($con,$fileName);
}
mysqli_select_db($con,"mahmood_faridi");
$query = "INSERT INTO upload (name, size, type, content ) ".
"VALUES ('$fileName', '$fileSize', '$fileType', '$content')";
mysqli_query($con,$query) or die('Error, query failed');
mysqli_close($con);
echo "<br>File $fileName uploaded<br>";
}
else
echo "File not uploaded"
?>
I was going to post this as a comment, but it got a bit too long.
When saving the file to the database, try base64_encoding the content, and then base64_decoding it when reading it out. PDFs look odd when viewed in text, and the collation of the database can affect the way it saves, or even what is saved. If one single character changes, you'll have a corrupt PDF.
Also make sure that error reporting is turned off, and that you have no spaces being output alongside the PDF which will also show as the file being corrupt.
I'd also consider splitting the functionality you have out into different files. It looks like everything is in one file there, which can lead to output happening when you don't fully expect it, again corrupting a download.
As an alternative, can you not save the PDF to disk and store the location in the database. You can then read the file as needed and output it, and then there's no issue of the PDF content being corrupted within the database. If you go down this route, make sure you give them unique names as two files could be uploaded with the same name and you might accidentally overwrite one.
Oooooops!
We all concentrated about encoding and database storing, but the problem is another!
When you output your PDF, you get the content from database, but you send this content to the user through:
#readfile($content);
readfile($content) outputs the contents of the file with filepath $content, but in $content there is not any filepath!
You simply change this line of code in
echo $content;
and your script will works.
(Read more about readfile)
I am running a website, and part of the site is allowing users to upload files to a SQL database, and then download them. The download itself works, but the file is getting corrupted. Image files cannot be opened, doc files are showing up as blank. I will attach below my uploading script and my downloading script.
$classid = $_POST['uploadclass'];
$userid = $_SESSION['id'];
$view = $_POST['view'];
$filename = $_FILES['uploadfile']['name'];
$tmpname = $_FILES['uploadfile']['tmpname'];
$filesize = $_FILES['uploadfile']['size'];
$filetype = $_FILES['uploadfile']['type'];
$fp = fopen($tmpname, 'r');
$content = fread($fp, filesize($tmpname));
$content = addslashes($content);
fclose($fp);
if (!get_magic_quotes_gpc()){
$filename = addslashes($filename);
}
$query = "INSERT INTO uploads VALUES('','$filename', '$filetype', '$filesize', '$content', '$userid', '$classid', '$view', 'no')";
$run = mysqli_query($connect, $query);
mysqli_close($connect);
header('location: files.php');
Below is the code for my download page.
$query = "SELECT * FROM uploads WHERE id=$id";
$run = mysqli_query($connect, $query);
while ($row = mysqli_fetch_assoc($run)){
$name = $row['name'];
$type = $row['type'];
$size = $row['size'];
$content = $row['content'];
}
header("Content-length: $size");
header("Content-type: $type");
header("Content-Disposition: attachment; filename=$name");
echo $content;
?>
You are incorrectly handling the files and everything else when inserting them into the database. All files that are already there are damaged and probably destroyed.
addslashes() is no escaping function for a database. Always use the escaping function that comes with the DB extension you are using. If you are using mysqli, then the correct function must be mysqli_real_escape_string().
You should however have a look at prepared statements. These will use an different way of transferring the data that does not need escaping. Do pay attention however to the setting of magic quotes. The preferred setting is OFF, and the recent PHP versions starting with 5.4 have this feature removed already. So you have to deal with escaping the data you insert into the database anyway.
I can't seem to download my files online which I'm uploading into a MySQL database I only get plain text, vague signs mostly. In localhost though downloading is no problem. I checked my database online and locally both are uploaded good in the upload table. I'll show you Upload.php(It's not called that in real, and this is also not the entire script, It's a big script) first:
if (isset($_POST['verstuur'])) {
$id = NULL;
if($_FILES['userfile']['size'] > 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);
fclose($fp);
if(!get_magic_quotes_gpc())
{
$fileName = addslashes($fileName);
}
$query = "INSERT INTO upload (name, size, type, content ) ".
"VALUES ('$fileName', '$fileSize', '$fileType', '$content')";
mysql_query($query) or die('Fout, query mislukt');
$query = "SELECT LAST_INSERT_ID() ID";
$result = mysql_query($query);
while($row = mysql_fetch_array($result)){
$id = $row['ID'];
}
}
Okay so I have another script where I create the download link:
$query = "SELECT U_ID, name FROM upload WHERE U_ID = '$opvraag[U_ID]'";
$result = mysql_query($query) or die('Error, query failed');
if(mysql_num_rows($result) == 0)
{
echo "<td>Geen Bijlage</td>";
}
else
{
while(list($id, $name) = mysql_fetch_array($result))
{
echo '<td>'.$name.'</td>';
}
}
And Last I have download.php
if(isset($_GET['id']))
{
$id = $_GET['id'];
$query = "SELECT name, type, size, content " .
"FROM upload WHERE U_ID = '$id'";
$result = mysql_query($query) or die('Fout, query mislukt');
list($name, $type, $size, $content) = mysql_fetch_array($result);
header("Content-length: $size");
header("Content-type: $type");
header("Content-Disposition: attachment; filename=$name");
echo stripslashes($content);
exit;
}
The Database Table:
Name: Type:
U_ID int(8) AUTO_INCREMENT
name varchar(255)
size int(8)
type text
content blob
Can you try replacing your 3 calls to headers() in your download.php with this:
header("Accept-Ranges: bytes");
header("Keep-Alive: timeout=15, max=100");
header("Content-Disposition: attachment; filename=$name");
header("Content-type: $type");
header("Content-Transfer-Encoding: binary");
header( "Content-Description: File Transfer");
I'm able to upload a file to mysql but when i download it, the content changes.. example i have test.txt with
"hello"
on it.. when i download it, the test.txt becomes
< pre class='xdebug-var-dump' dir='ltr'>string 'sfasfsafasfsaf' (length=14)
sfasfsafasfsaf
not sure, what's wrong..
this is my code for downloading the file:
<?php include("class_lib.php");
$db = new database();
$db->connect();
if(isset($_GET["file_id"])){
$file_id = $_GET["file_id"];
$query = "SELECT filename, filetype, filesize, bin_data " .
"FROM file_tbl WHERE id = '$file_id'";
$result = mysql_query($query) or die('Error, query failed' . mysql_error());
list($filename, $filetype, $filesize, $bin_data) = mysql_fetch_array($result);
var_dump($bin_data);
header("Content-length: $filesize");
header("Content-type: $filetype");
header("Content-Disposition: attachment; filename=$filename");
echo $bin_data;
}
?>
for images also, it downloads but there's no image anymore.. it only shows "no preview available".. is this with my download script above?
or maybe this upload script i have:
$fileid = (string) ($lastemp_id + 1);
$fileName = basename($_FILES['binFile']['name']);
$extension = pathinfo($fileName, PATHINFO_EXTENSION);
$fileName .= "_fileid_" . $fileid;
$fileName = $fileName.".".$extension;
$tmpName = $_FILES['binFile']['tmp_name'];
$fileSize = $_FILES['binFile']['size'];
$fileType = $_FILES['binFile']['type'];
$fileDesc = $_POST["txtDescription"];
$fp = fopen($tmpName, 'r');
$content = fread($fp, filesize($tmpName));
$content = addslashes($content);
fclose($fp);
if(!get_magic_quotes_gpc()){ $fileName = addslashes($fileName); }
if (isset($fileName)) {
$sql = "INSERT INTO file_tbl ";
$sql .= "(file_desc, bin_data, filename, filesize, filetype) ";
$sql .= "VALUES ('$fileDesc', '$content', ";
$sql .= "'$fileName', '$fileSize', '$fileType')";
mysql_query($sql, $db->connection) or die('Error: query failed' . mysql_error());
$message = "File uploaded.<br>"; var_dump($content);
}
else $message = "No file uploaded. (opt)";
what is wrong here exactly??
You're recklessly jamming binary data into your database without even a whiff of proper SQL escaping. What did you expect to happen? This short sample of code is so full of severe SQL injection bugs I hope for your sake it isn't deployed on the public internet.
For your own safety you should immediately stop using the creaky, old, deprecated mysql_query interface and spend the small amount of time necessary to switch your queries to PDO.
You would not have problems like this if you were using placeholders.
What you're seeing is probably the result of your spurious var_dump statement before you output your proper content.
Please try this, if upload file is flawless.
You can encode your binary data to 64 format when insert into database and also decode before download it.
<?php
ob_start();
include("class_lib.php");
$db = new database();
$db->connect();
if(isset($_GET["file_id"])){
$file_id = $_GET["file_id"];
$query = "SELECT filename, filetype, filesize, bin_data " .
"FROM file_tbl WHERE id = '$file_id'";
$result = mysql_query($query) or die('Error, query failed' . mysql_error());
list($filename, $filetype, $filesize, $bin_data) = mysql_fetch_array($result);
var_dump($bin_data);
ob_end_clean();
header("Content-length: $filesize");
header("Content-type: $filetype");
header("Content-Disposition: attachment; filename=$filename");
echo $bin_data;
exit;
}
?>
I have a classifieds website where users must fill in a form in order to put a ad. The form consists of name, password, category, specifications etc etc.
Now, I need to add a image upload function into this form, which must have the following:
1- Upload up to 5 images.
2- A 'remove image link' beneath each image if the user wants another image instead.
How would you do this?
Thanks
Best would be if there was a plugin or something to Jquery which is easy to modify...
jQuery Multiple File Upload
You can limit the number of uploads using the max option or passing a number as the only parameter. More info on the Examples tab.
If you want to upload it as a file to an SQL database, have something like this in the form (in php echo format):
echo "<input type=\"hidden\" name=\"MAX_FILE_SIZE\" value=\"2000000\">
<input name=\"userfile\" type=\"file\" id=\"userfile\">";
Then in your form's receiving php page put something like this:
if ($_FILES['userfile']['size'] > 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);
fclose($fp);
if(!get_magic_quotes_gpc())
{
$fileName = addslashes($fileName);
}
$query = "INSERT INTO files (name, size, type, content ) VALUES ('$fileName', '$fileSize', '$fileType', '$content')";
mysql_query($query) or die('Error, query failed');
$thisq = mysql_query("SELECT * FROM `files` WHERE 1 ORDER BY `id` DESC LIMIT 1");
$fileidnumber= mysql_fetch_array($thisq);
}
That will store the file to a database and then return the key for you to save or use however you'd like. You can then create a page to download the files like this:
<?php
import_request_variables(gp);
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 `files` 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;
exit;
}
?>