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? '
Related
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");
I have this code broken down into two parts:
The first one create me a zip file empty and download it.
The second one download me from my database a PDF file that I decoded in base64.
Both work well separately. I would like to be able to merge them and download in zip format two PDF files that are in my database.
I would like to use the addFromString function to not create a folder on my server but to download the zip file directly for the user.
Can you help me please?
Thanks for your help
<?php
include '../include/classe_PDO.php';
$suivi = $_POST['suivi'];
// //ZIP PART
//Name zip folder with date
$dirzip = date('Ymd His')."_andromeda";
// Zip creation
$nomzip = "C:/wamp64/www\Dylan/SAV/final/include/$dirzip.zip";
$zip = new ZipArchive;
if($zip -> open($nomzip, ZipArchive::CREATE ) === TRUE)
{
$dir = opendir($chemin);
while($fichier = readdir($dir))
{
if(is_file($chemin.$fichier))
{
$zip -> addFromString($file, $decoded);
}
}
$zip ->close();
}
//Zip download
header('Content-Type: application/zip');
header('Content-Disposition: attachment; filename="'.basename($nomzip).'"');
header('Content-Length: ' . filesize($nomzip));
flush();
readfile($nomzip);
//DOWNLOAD PART
try {
// Connect to db
$db = new db('mysql:dbname=jotform; host=localhost', 'root', '');
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// Set SQL
$sql = "SELECT * FROM `dhl` WHERE `submission_id` = :suivi";
// Prepare query
$query = $db->prepare($sql);
// Execute query
$query->execute(array(':suivi' => $suivi));
foreach ($query as $row) {
$filedata = $row['label_envoi']; //get base64 data from query result
$decoded = base64_decode($filedata); //decode base64 to binary
$filedata2 = $row['label_retour']; //Second column
$decoded2 = base64_decode($filedata2);
//set suitable HTTP response headers
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="label.pdf"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
//output the binary file data in the body of the response
echo $decoded;
}
} catch (PDOException $e) {
echo 'Error: ' . $e->getMessage();
}
?>
You need to loop through your database rows and add each piece of decoded file data to the zip file. Then download the zip at the end.
For example:
include '../include/classe_PDO.php';
$suivi = $_POST['suivi'];
// //ZIP PART
//Name zip folder with date
$dirzip = date('Ymd His')."_andromeda";
// Zip creation
$nomzip = "C:/wamp64/www/Dylan/SAV/final/include/$dirzip.zip";
$zip = new ZipArchive;
if ($zip->open($nomzip, ZipArchive::CREATE ) === TRUE)
{
try {
//connect to DB
$db = new db('mysql:dbname=jotform; host=localhost', 'root', '');
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
//prepare and execute query
$sql = "SELECT * FROM `dhl` WHERE `submission_id` = :suivi";
$query = $db->prepare($sql);
$query->execute(array(':suivi' => $suivi));
foreach ($query as $row) {
//decode base64 to binary
$decoded = base64_decode($row['label_envoi']);
$decoded2 = base64_decode($row['label_retour']);
//add to zip
//N.B. if there could be more than one row returned by the database, you'll need to ensure the PDFs have unique names instead of these hard-coded ones
$zip->addFromString("label1.pdf", $decoded);
$zip->addFromString("label2.pdf", $decoded2);
}
}
catch (PDOException $e) {
echo 'Error: ' . $e->getMessage();
}
$zip ->close();
//Zip download
header('Content-Type: application/zip');
header('Content-Disposition: attachment; filename="'.basename($nomzip).'"');
header('Content-Length: ' . filesize($nomzip));
flush();
readfile($nomzip);
}
else
{
echo "Error - Zip file could not be created";
}
I have a database table which stores the document file name and on the local pc i have a folder named as uploads which stores the actual files the user uploads.
The way i upload files are as follows,
$filename = $_FILES['attachment']['name'];
// 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['attachment']['tmp_name'];
$size = $_FILES['attachment']['size'];
if (!in_array($extension, ['zip', 'pdf', 'docx'])) {
echo "You file extension must be .zip, .pdf or .docx";
} elseif ($_FILES['attachment']['size'] > 1000000) { // file shouldn't be larger than 1Megabyte
echo "File too large!";
} else {
// move the uploaded (temporary) file to the specified destination
if (move_uploaded_file($file, $destination)) {
$sender_name = $_POST['sender_name'];
$contact = $_POST['contactnumber'];
$sender_mail = $_POST['sender_email'];
$description = $_POST['description'];
$applied = date('Y-m-d');
$jobapply = "INSERT INTO `job_submission`(`NAME`, `CONTACT`, `EMAIL`, `MESSAGE`,
`APPLIED_ON`, `CAREER_ID`,`CV`) VALUES
('$sender_name','$contact','$sender_mail','$description','$applied','$idc','$filename')";
if (mysqli_query($connect, $jobapply)) {
echo "You Application Was Submitted Successfully! We Wish You All The Best";
}
} else {
echo "Failed to upload file.";
}
}
The results of this code is the file name along with the other data are stored in the database and on the other hand the file is also stored in the uploads directory.
Now i want to download the file stored in the folder to the machine by using a button. for which I have written a code as follows,
if (isset($_GET['file_id'])) {
$id = $_GET['file_id'];
// fetch file to download from database
$sql = "SELECT * FROM job_submission WHERE JOB_ID='$id'";
$result = mysqli_query($connect, $sql);
$file = mysqli_fetch_assoc($result);
$filepath = 'uploads/' . $file['CV'];
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/' . $file['CV']));
readfile('uploads/' . $file['CV']);
exit;
}
}
The above code is called from a button inside a table,
<td>Download </td>
The file gets downloaded but it doesn't open and throws an error saying
Error Failed to load PDF document.
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
Here is a simple script I have written to limit downloads for users to one at a time (IE if they are downloading a file then they cannot download another one until they cancel the current download or it finishes).
ignore_user_abort(true);
$local_file = $_GET['filename'];
$download_file = explode("/", $local_file);
$download_file = $download_file[count($download_file) -1];
// set the download rate limit (value is in kilobytes per second
$download_rate = 100;
if(file_exists($local_file) && is_file($local_file)) {
$ip = visitor_ip();
if(!are_downloading($ip)) {
header('Cache-control: private');
header('Content-Type: application/octet-stream');
header('Content-Length: '.filesize($local_file));
header('Content-Disposition: filename='.$download_file);
flush();
$file = fopen($local_file, "r");
log_downloader($ip);
while(!feof($file)) {
if (!connection_aborted()) {
// send the current file part to the browser
print fread($file, round($download_rate * 1024));
// flush the content to the browser
flush();
// sleep one second
sleep(1);
} else {
break;
}
}
clear_downloader($ip);
fclose($file);
} else {
die('<span style="color:#DDDDDD">Due to server limitations you may only download one file at a time. Please cancel or wait for your current download to finish before trying again. Click here to return.</span>');
}
} else {
die('Error: The file '.$local_file.' does not exist!');
}
function visitor_ip() {
if(isset($_SERVER['HTTP_X_FORWARDED_FOR']))
$TheIp=$_SERVER['HTTP_X_FORWARDED_FOR'];
else $TheIp=$_SERVER['REMOTE_ADDR'];
return trim($TheIp);
}
function are_downloading($ip) {
$query = "select * from downloaders where ip_addr='$ip'";
$result = mysql_query($query);
$num_rows = mysql_num_rows($result);
return $num_rows > 0;
}
function log_downloader($ip) {
$query = "insert into downloaders (ip_addr) values ('$ip')";
$result = mysql_query($query);
}
function clear_downloader($ip) {
$query = "delete from downloaders where ip_addr='$ip'";
$result = mysql_query($query);
}
When I test it out, it works fine, but for a lot of people, their IP never gets cleared out of the database - even when they have finished downloading/cancelled a file. Why don't the IPs get deleted?
The problem was that with big downloads the MySQL connection went away, I simply had to reconnect in the clear_downloader function and now it works fine.