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.
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 have a database that is storing all my pdf files for a website. The table has columns for the library_item_id, filename(name of the file), mime_type, File size, file_item(the Blob) and I have a php file called download.php. This file is supposed to download the correct file from the database when they user clicks the link. But when the file is downloaded and clicked to open I get Adobe saying it cannot open the pdf. Saying its not decoded correctly. Here is my download.php file:
require_once("scripts/connection.php");
if(isset($_GET["id"])){
$fid = $_GET["id"];
}
else{
header("Location: literature.php");
}
$sql= "SELECT filename, mime_type, file_item FROM library_items WHERE library_item_id = ?";
$stmt = $conn->prepare($sql);
$stmt->bind_param('s', $fid);
$stmt->execute();
$stmt->bind_result($filename, $mime, $file_item);
while($stmt->fetch()){
$file_name = $filename;
$mime_type = $mime;
$file = $file_item;
}
header("Content-length: ".strlen($file));
header("Content-type: $mime_type");
header("Content-disposition: download; filename=$file_name");
echo $file;
mysqli_close($conn);
I have tried everything I could think of including add the obj_flush() commands and all that it still gives me the same error. What am I doing wrong on this?
Here is the edit for the code inserting the file into the database.
session_start();
$display = trim($_POST["file-display-name"]);
$company = trim($_POST["companies"]);
$lib_cat = trim($_POST["library-cats"]);
if(empty($display) || empty($company) || empty($lib_cat)){
$_SESSION["errormsg"] = "Required information is missing please fill out all required fields.";
header("Location: ../library.php");
}
else{
$file_name = $_FILES['library-file']['name'];
$tmp_name = $_FILES['library-file']['tmp_name'];
$file_size = $_FILES['library-file']['size'];
$file_type = $_FILES['library-file']['type'];
$fp = fopen($tmp_name, 'r');
$content = fread($fp, filesize($tmp_name));
$content = addslashes($content);
fclose($fp);
if(!get_magic_quotes_gpc()){
$file_name = addslashes($file_name);
}
if(empty($content)){
$_SESSION["errormsg"] = "Required information is missing please fill out all required fields.";
header("Location: ../library.php");
}
else{
require_once("connection.php");
// Insert the logo into the companies photo table
$sql = "INSERT INTO library_items(filename, mime_type, file_size, file_item, display_name, company_id, library_category_id) VALUES(?,?,?,?,?,?,?)";
$stmt = $conn->prepare($sql);
$stmt->bind_param('sssssss', $file_name, $file_type, $file_size, $content, $display, $company, $lib_cat);
if(!$stmt->execute()){
$_SESSION["errormsg"] = "Failed to add library item: ".mysqli_error();
header("Location: ../library.php");
}
}
unset($_SESSION["errormsg"]);
$_SESSION["successmsg"] = "Library Item successfully added into the database.";
header("Location: ../library.php");
}
UPDATE:
I now have the file downloading and attempting to display once the downloaded file is double clicked to open. It is telling me there is an invalid colorSpace. From what I can tell this is a problem when the file is uploaded into the database. From my upload file posted is there anything I am not doing correctly?
You need following changes. In the insert file
Instead of
$content = addslashes($content);
use
$content = base64_encode($content);
So while downloading, decode it.
$file = base64_decode($file_item);
Replace the following code
header("Content-type: '".$mime_type."'");
header("Content-Disposition: inline; filename='".$file_name."'");
header('Content-Transfer-Encoding: binary');
header('Accept-Ranges: bytes');
readfile($file);
with
header("Content-length: ".strlen($file));
header("Content-type: $mime_type");
header("Content-disposition: download; filename=$file_name");
echo $file;
check if size of downloaded file is correct (matches size of file in database). If it is, you should be debugging the part where the file is inserted into database. If not - check if anything gets printed out before sending file to browser - maybe scripts/connection.php prints something like empty line, error message or BOM?
If you can't find it, try turning output buffering on and call ob_clean() before sending file.
Sorry for my english, I hope it's understandable.
I am currently having problems with displaying image from mysql database. I am able to upload an image to mysql database, however if i want to retrieve it from the database, it is displayed in Gibberish text.
Here is upload.php
if (isset($_FILES['image']) && $_FILES['image']['size'] > 0) {
$filename = mysqli_real_escape_string($mysqli,$_FILES['image']['name']);
$tmpName = $_FILES['image']['tmp_name'];
$fp = fopen($tmpName, 'r');
$data = fread($fp, filesize($tmpName));
$data = addslashes($data);
fclose($fp);
$query = "INSERT INTO `TABLES` (`image`)
VALUES( NULL,'$data')";
$result = $mysqli->query($query);
}
View.php
$mysqlquery = "SELECT * FROM TABLE";
$results = $mysqli->query($mysqlquery);
if($results->num_rows > 0){
while ($row = $results ->fetch_assoc()){
echo '<div align = "center">';
echo "<b>".$row["image"]. "<br></b>";
header("Content-type: image/jpeg");
}
}
Try this and do not forget to give image path before source
echo "<img src='your image location directory/". $row['image'] .'" >";
Oooooh... I just wish I had the answer to this one...
Some thoughts, though.
First, from personal experience I urge against storing images in the database. For one thing, your database backups will quickly become ridiculous. A more common, and better, approach is to store the images in the file system and store only the location (e.g. /img/pic03.jpg ) of the image in the database.
Next, I see you are modifying the received binary data:
$tmpName = $_FILES['image']['tmp_name'];
$fp = fopen($tmpName, 'r');
$data = fread($fp, filesize($tmpName));
$data = addslashes($data);
fclose($fp);
Perhaps you know something that I don't (it's not difficult), but generally, if you gerfingerpoke with binary image data you get ... um... gibberish. Try disabling those lines and see what happens.
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;
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;
}
?>