How to create a download link of files in databse - php

I have created a upload form and a php file which extract the name, size, type of the file and stores it in a database upload script, in table files. The file is also given a uniqid which is also stored in the same table.
Now I am trying to build up a download.php file where I want that when a specific link with the uniqid in is opened the script look in databse for the file searching for the uniqid and show the information against it.?
Here is my upload.php
<?php
include('config.php');
function bytesToSize1024($bytes, $precision = 300) {
$unit = array('B','KB','MB');
return #round($bytes / pow(1024, ($i = floor(log($bytes, 1024)))), $precision).' '.$unit[$i];
}
$FileName = $_FILES['filename']['name'];
$FileType = $_FILES['filename']['type'];
$FileSize = bytesToSize1024($_FILES['filename']['size'], 1);
$Fileid = uniqid(rand());
$tmp_name = $_FILES["filename"]["tmp_name"];
if ($_FILES["filename"]["error"] > 0)
{
echo "Apologies, an error has occurred.";
echo "Error Code: " . $_FILES["fileToUpload"]["error"];
}
else
{
move_uploaded_file($_FILES["filename"]["tmp_name"],
"C:\wamp\www\upload\upload" . $_FILES["filename"]["name"]);
}
$query2 = "INSERT INTO files (id, name, size, type) VALUES ('$Fileid', '$FileName', '$FileSize', '$FileType')";
$result2 = mysql_query($query2);
echo <<<EOF
<p>Your file: {$FileName} has been successfully received.</p>
<p>Type: {$FileType}</p>
<p>Size: {$FileSize}</p>
<p>Temp Foler: {$tmp_name}</p>
<p>Download Link: localhost/upload/download.php?=$Fileid
EOF;
?>
Please first tell me which kind of link I should create like. localhost/download.php?=uniqid
will the above example work and how to make it work. I am confused?
Here I have tried to create a download.php file but it is not good
<?php
include('config.php');
$query = "SELECT * FROM files";
$result = mysql_query($query);
$row = mysql_fetch_array($result);
?>
<?php
echo <<<EOF
File Name: <?php echo $row['name']; ?>
$row
EOF;
?>

This is the code you need. Consider storing byte count in the database for file size.
Of course it might need some changes to be exactly what you want.
<?php
include('config.php');
//get id from GET method and make sure that it's safe to be used in the query
$id=mysql_real_escape_string($_GET['id']);
$query = "SELECT * FROM `files` WHERE `id`='$id'";
$result = mysql_query($query);
$row = mysql_fetch_array($result);
if (count($row)!=1) //check if our unique record has been found
die('Sorry but we could not find this file!');
$row=$row[0];
//send download headers
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.$row['name']);
header('Content-Transfer-Encoding: binary');
header('Cache-Control: must-revalidate');
header('Pragma: no-cache');
header('Content-Length: ' .$row['size']);
readfile(upload" . $row['name']); //I recommend you to change the path and file name of your uploaded files!
?>
Link example: http://yourdomain.com/download.php?id=123

Related

php can't open pdf after downloading

in my project I need to upload pdf file and download it afterwards.
everything works fine , but after i download the pdf file its been currupted and i can't view it.
if i try to open it with Adobe Acrobat Reader i get this error that says the file been currupted and didn't encoded correctly.
can someone help me to resolve this? thanks!
php script for download and upload:
<?php
// connect to the database
require_once 'connectionoop.php';
require_once 'core/init.php';
$query1 = sprintf("SELECT files.id, files.name,files.size ,files.downloads , association.Aname ,projects.Pname,files.project
FROM files
INNER JOIN projects ON files.project = projects.id INNER JOIN association ON projects.Aid = association.id
");
$result1 = $mysqli->query($query1);
$files=array();
foreach ($result1 as $row) {
$files[] = $row;
}
// Uploads files
if (isset($_POST['save'])) { // if save button on the form is clicked
// name of the uploaded file
$filename = $_FILES['myfile']['name'];
$proj = $_POST['Aid'];
// destination of the file on the server
$destination = 'uploads/' . $filename;
// get the file extension
$extension = pathinfo($filename, PATHINFO_EXTENSION);
// the physical file on a temporary uploads directory on the server
$file = $_FILES['myfile']['tmp_name'];
$size = $_FILES['myfile']['size'];
if (!in_array($extension, ['zip', 'pdf', 'docx'])) {
echo "You file extension must be .zip, .pdf or .docx";
} elseif ($_FILES['myfile']['size'] > 1000000) { // file shouldn't be larger than 1Megabyte
echo "File too large!";
} else {
// move the uploaded (temporary) file to the specified destination
if (copy($file, $destination)) {
$query = sprintf("INSERT INTO files (name, size, downloads , project) VALUES ('$filename', $size, 0,$proj)");
//execute query
$result = $mysqli->query($query);
$sql = "INSERT INTO files (name, size, downloads) VALUES ('$filename', $size, 0)";
$pr=new Project($proj);
$pr->update(array(
'hasfile' =>1
));
Redirect::to('downloads.php');
} else {
echo "Failed to upload file.<br>".$destination;
}
}
}
if (isset($_GET['file_id'])) {
$id = $_GET['file_id'];
$query2 = sprintf("SELECT * FROM files WHERE id=$id");
// fetch file to download from database
$result2 = $mysqli->query($query2);
$data = array();
foreach ($result2 as $row) {
$data[] = $row;
}
$filepath = 'uploads/' .$data[0]['name'];
if (file_exists($filepath)) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename=' . basename($filepath));
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize('uploads/' . $data['name']));
readfile('uploads/' . $data['name']);
// Now update downloads count
$newCount = $data['downloads'] + 1;
$query3 = sprintf("UPDATE files SET downloads=$newCount WHERE id=$id");
// fetch file to download from database
$result3 = $mysqli->query($query3);
exit;
}
}
It should be header("Content-type:application/pdf");

How to make a download button for files taken from a database?

I need to print out all the files that I've saved in a database and then make it possible to download them. I am able to echo them, but I don't know how to make a download "button" to download them to the computer.
The datbase has two columns: ID and Ime.
I tried using a tag from HTML with no luck. I was able to echo buttons next to file names, but I couldn't download them (I tried using file_put_contents method)
This is the code that outputs file names (Ime = Name in my language).
<?php
$conn = mysqli_connect('localhost','root','usbw','down');
$query = "SELECT * FROM datoteka";
$result = mysqli_query($conn,$query);
$result_check = mysqli_num_rows($result);
if($result_check > 0){
while($row = mysqli_fetch_assoc($result)){
echo $row["Ime"]."<br>";
}
}
?>
The output looks like this:
datoteka2019-04-01-15-44.doc
datoteka2019-04-01-15-48.doc
datoteka2019-04-01-15-16.pdf
Files in database that I want to be able to download (3 for now, could be more)
There should be a download button (or something cliclkable) next to each file name on website that would enable me to download this file from the database (one file at time, not all at once).
I once made a similar script, what you have to do is set some headers and echo the data from database.
An example of that could be, assuming that the data is in $row['filedata'], the following
<?php
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-Disposition: attachment; filename=".$row['Ime']);
header("Content-Type: application/zip");
header("Content-Transfer-Encoding: binary");
echo $row['filedata'];
?>
Now you have to know what file to download first, and for that we can use a GET or POST parameter
<?php
$fileID = htmlentities($_GET['fileID']);
$conn = mysqli_connect('localhost','root','usbw','down');
$fileID = mysqli_real_escape_string($conn, $fileID); // ALWAYS ESCAPE USER INPUT
$query = "SELECT * FROM datoteka where `ID`=$fileID";
$result = mysqli_query($conn, $query);
$result_check = mysqli_num_rows($result);
if($result_check > 1 || $result_check < 1){ //If more then 1 result die
die('inavlid ID');
}
$row = mysqli_fetch_assoc($result);
//and here the above mentioned lines
?>
The easiest way to add a download button to the page would be by using the window.open() function in JavaScript like so:
echo $row['Ime']."<button onclick='window.open(\"download.php?fileID=".$row['ID']."\");'>Download</button><br>";
This will open a new window which will download the file
The total would look something like this
For download.php:
<?php
$fileID = htmlentities($_GET['fileID']);
$conn = mysqli_connect('localhost','root','usbw','down');
$fileID = mysqli_real_escape_string($conn, $fileID); // ALWAYS ESCAPE USER INPUT
$query = "SELECT * FROM datoteka where `ID`=$fileID";
$result = mysqli_query($conn, $query);
$result_check = mysqli_num_rows($result);
if($result_check > 1 || $result_check < 1){ //If more then 1 result die
die('inavlid ID');
}
$row = mysqli_fetch_assoc($result);
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-Disposition: attachment; filename=".$row['Ime']);
header("Content-Type: application/zip");
header("Content-Transfer-Encoding: binary");
echo $row['filedata'];
?>
and for index.php
<?php
$conn = mysqli_connect('localhost','root','usbw','down');
$query = "SELECT * FROM datoteka";
$result = mysqli_query($conn,$query);
$result_check = mysqli_num_rows($result);
if($result_check > 0){
while($row = mysqli_fetch_assoc($result)){
echo $row['Ime']."<button onclick='window.open(\"download.php?fileID=".$row['ID']."\");'>Download</button><br>";
}
}
?>
You can read here https://www.php.net/file_put_contents,
and you need to know where the path file is. ex:
/users/john/downloads/namefile.doc

Force download Zip file results corrupted

I'm trying to force a zip-file's download after some checks ( hash , expiration date, download's number ) .
The link of the page contains the id ( hash ) to validate the download.
For example:
www.example.com/download.php?id=505fbeabfd97c0ab15a016d68512d8df5acdedd6e6cc6
Everything works, but the file is corrupted.
If I try to eliminate all checks and the connection to the database, the zip downloaded is ok.
Here's the code:
<?php
$maxdownloads = "80";
// Set the key's viable duration in seconds (86400 seconds = 24 hours)
$maxtime = "2592000";
require ('connect.php');
if(get_magic_quotes_gpc()) {
$id = stripslashes($_GET['id']);
}else{
$id = $_GET['id'];
}
echo $id;
// Get the key, timestamp, and number of downloads from the database
$query = sprintf("SELECT * FROM digital_orders WHERE hash= '%s'",
mysqli_real_escape_string($conn,$id));
$result = $conn->query($query);
$row = $result->fetch_assoc();
if (!$row) {
echo "The download key you are using is invalid.";
}else{
$timecheck = date('U') - $row['date'];
echo $timecheck;
if ($timecheck >= $maxtime) {
echo "This key has expired (exceeded time allotted).<br />";
}else{
$downloads = $row['download'];
echo $downloads;
$downloads += 1;
if ($downloads > $maxdownloads) {
echo "This key has expired (exceeded allowed downloads<br/>";
}else{
$sql = sprintf("UPDATE digital_orders SET download .$downloads."' WHERE hash= '%s'",
mysqli_real_escape_string($conn,$id));
$incrementdownloads = $conn->query($sql);
$result->close();
// chiusura della connessione
$conn->close();
// Debug echo "Key validated.";
// Force the browser to start the download automatically
/*
Variables:
$file = real name of actual download file on the server
$filename = new name of local download file - this is what the visitor's file will actually be called when he/she saves it
*/
// Get parameters
$file = "dante.zip"; // Decode URL-encoded string
$filename = "foto.zip";
$filepath = "digital_orders/Dante/" . $file;
// Process download
if(file_exists($filepath)) {
ob_start();
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.$filename.'"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($filepath));
flush(); // Flush system output buffer
ob_end_clean();
readfile($filepath);
exit;
}
}
}
}
?>
If I try to open the zip file that works with note-pad there is :
PK
ûe‹L dante.txtPK
ûe‹L $ dante.txt
CdÔ‹‚ÑÓCdÔ‹‚ÑÓÆ‹‚ÑÓPK [
'
If I try to open the corrupted zip file there is:
505fbeabfd97c0ab15a016d68512d8df5acdedd6e6cc61226822PK
ûe‹L dante.txtPK
ûe‹L $ dante.txt
CdÔ‹‚ÑÓCdÔ‹‚ÑÓÆ‹‚ÑÓPK [
Any suggestion? '

PDF not downloading when file is called

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.

Header download file is corrupted

I'm trying to download files via headers from my database. I'm not sure why my downloaded files are all corrupted when I change my download code to one that uses OOP but are fine when my code is non-OOP.
This is where I get the file id and call the download function:(handleDownload.php)
if (isset($_GET['id'])) {
$id = $_GET['id'];
//pump id into function getDBFiles to pull file with matching id
$fileData = $Download->getDBFiles($id);
header('Content-Type:"' . $fileData[2]. '"');
header('Content-Disposition: attachment; filename="' . $fileData[1]. '"');
echo $fileData[0];
exit;
}
This is the function that pulls the file from the database (download.php)
public function getDBFiles($id) {
global $database;
$sql = "SELECT * FROM ".self::$table_name." WHERE resume_id ='" . $id . "'";
$result = $database->query($sql);
if ($row = $result->fetch_array(MYSQLI_ASSOC)) {
$name = $row['resume_title'];
$type = $row['file_type'];
$content = $row['resume_data']; //content of file
//$size = $row['file_size']; //file size
return array($content, $name, $type);
}
}
$Download = new Download();
$download =& $Download;
The code works fine if it's all in one page as shown below though:
if (isset($_GET['id'])) {
$id = $_GET['id'];
mysqli_select_db($con, "apples");
$query = "SELECT * FROM resume where resume_id ='" . $id . "'";
$result = mysqli_query($con, $query) or die('Error, query failed');
if ($row = $result->fetch_array(MYSQLI_ASSOC)) {
$name = $row['resume_title'];
$type = $row['file_type'];
$content = $row['resume_data']; //content of file
$size = $row['file_size']; //file size
header('Content-Type:"' . $type . '"');
//header('Content-length:"' . $size . '"');
header('Content-Disposition: attachment; filename="' . $name . '"');
//var_dump($row);
echo $content;
}
}
UPDATE:
I'm now getting a download file is corrupted instead of a blank file. This is how the same file is outputted by the different download codes. The one on top is from the OOP code while the other is from the working non-OOP version.
This is my download code in its entirety.
try {
//execute retrieval of files from database
$Download-> showDBFiles();
//pass results to output array
$output = $Download->getMessages();
//if id is set then get file from database
if (isset($_GET['id'])) {
$id = $_GET['id'];
//pump id into function getDBFiles to pull file with matching id
$fileData = $Download->getDBFiles($id);
header('Content-Type:"' . $fileData[2]. '"');
header('Content-Disposition: attachment; filename="' . $fileData[1]. '"');
echo $fileData[0];
die();
}
} catch (Exception $e) {
$result[] = $e->getMessages();
}
After calling the functions, I would then echo out the output (the download links) with a foreach loop
<h2>Output</h2>
<?php if ($output) { ?>
<ul class="result">
<?php
foreach ($output as $message) {
$id = $message['id'];
$name = $message['name'];
?>
<li><?php echo $name; ?></li>
<?php }
?>
</ul>
In your non-OOP solution check for leading whitespaces inside the php file.
The following code would produce a corrupted file because of a leading whitespace.
<?php
if (isset($_GET['id'])) {...
This also applies to whitespaces after the closing php tag (which you should not use).
Those chars will be submitted by your browser, included in the download stream and corrupt the whole file.

Categories