While downloading a zip file from server my PHP website get stucked - php

I have made a script which zips certain files on server and downloads but issue is while zip is downloading i can't navigate any where on the site. it get stucked until download is not finished or cancelled. i am using below code for making a zip and downloading it
<?php
$files = $_SESSION['cart']['all'];
function createZip($files, $zip_file) {
$zip = new ZipArchive;
if ($zip->open($zip_file, ZipArchive::OVERWRITE) === TRUE) {
foreach ($files as $file) {
if ($file->songType == "1") {
$zip->addFile('assets/songs/' . $file->filePath, $file->filePath);
} else if ($file->songType == "2") {
$zip->addFile('assets/videos/' . $file->filePath, $file->filePath);
}
}
$zip->close();
$_SESSION['cart'] = array();
$_SESSION['cart']['temp'] = array();
$_SESSION['cart']['all'] = array();
return true;
}
else
return false;
}
$temp = 'file.zip';
$pp111 = $temp;
if (createZip($files, $pp111)) {
// header('Content-Type: application/octet-stream');
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); // Date in the past
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); //Update modified time to current time.
header("Content-Length: " . filesize($pp111)); //file size
header("Content-Disposition: attachment; filename=\"" . stripslashes($pp111) . "\""); //give the file a name.
ob_clean();
flush();
readfile($pp111); // now start reading the file on your server to start downloading to user's desktop */
// unlink($pp111);
ob_end_flush();
ob_end_clean();
exit();
} else {
exit();
}
?>

If you don't close the session, the session file remains locked for all other requests from the same user. If download takes 60 seconds, user has to wait 60 seconds.
You should grab all the data you need on top of the script and then close the session to release the file.

Related

error using readfile php function

I have this function which outputs an image to the browser. However i get an error image cannot be displayed because it contains errors.
I've done the file_exists check and the image headers are all applied correctly.
function sendImage(string $file, int $browser_cache = 2592000) {
if (file_exists($file)) {
header("Content-Type: ". mime_content_type($file));
header("Cache-Control: private, max-age=".$browser_cache);
header('Expires: '.gmdate('D, d M Y H:i:s', time()+$browser_cache).' GMT');
header('Content-Length: '.filesize($file));
readfile($file);
exit;
} else {
echo 'file does not exist';
}
}
Call the function
$file = $_SERVER['DOCUMENT_ROOT'] . '/images/image.png';
sendImage($file);
The image opens in my browser just fine. But displays an error with this function.
What I can tell from experience is that readfile does not work with large files.
And sometimes, even when you got the PHP part right there are other points of failures.
I suggest using the X-Sendfile header instead of manually outputting the file:
function sendImage(string $file, int $browser_cache = 2592000) {
$path = realpath($file);
if ($path !== false) {
header("Content-Type: ". mime_content_type($file));
header("Cache-Control: private, max-age=".$browser_cache);
header('Expires: '.gmdate('D, d M Y H:i:s', time()+$browser_cache).' GMT');
header('Content-Length: '.filesize($file));
header('X-Sendfile: '.$path);
exit;
} else {
echo 'file does not exist';
}
}
Of course you have to enable it in your webserver configuration for it to work.

How to echo date in php

this code is doing Zip & Download perfect but i want to change a time to date how can i do this
when i save a folder its save with time i want to save with date how can i do this
this is time script how can i change in to date when i change Y-m-d but this is not working its showing this error Parse error: syntax error, unexpected T_STRING in downloadlist.php on line 26
please help me to fix this issue
thanks
$filename = Y-m-d " Backup.zip"; (not working)
$filename = time() ." Backup.zip"; ( working code)
downloadlist.php
<?php
// function download($file) downloads file provided in $file
function download($file) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($file));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
ob_clean();
flush();
readfile($file);
exit;
}
$files = $_POST['file'];
if(empty($files))
{
echo("You haven't selected any file to download.");
}
else
{
$zip = new ZipArchive();
$filename = time() ." Backup.zip"; //adds timestamp to zip archive so every file has unique filename
if ($zip->open($filename, ZIPARCHIVE::CREATE)!==TRUE) { // creates new zip archive
exit("Cannot open <$filename>\n");
}
$N = count($files);
for($i=0; $i < $N; $i++)
{
$zip->addFile($files[$i], $files[$i]); //add files to archive
}
$numFiles = $zip->numFiles;
$zip->close();
$time = 8; //how long in seconds do we wait for files to be archived.
$found = false;
for($i=0; $i<$time; $i++){
if($numFiles == $N){ // check if number of files in zip archive equals number of checked files
download($filename);
$found = true;
break;
}
sleep(1); // if not found wait one second before continue looping
}
if($found) { }
else echo "Sorry, this is taking too long";
}
?>
list.php
<?php
function listDir($dirName)
{
$forbidden_files=array('.htaccess','.htpasswd');
$allow_ext=array('.pdf','.doc','.docx','.xls','.xlsx','.txt');
?><form name="filelist" action="downloadList.php" method="POST"><?php echo "\n";
if ($handle = opendir($dirName)) {
while (false !== ($file = readdir($handle)) ) {
$allowed=(strpos($file,'.')!==false && in_array(substr($file,strpos($file,'.')) ,$allow_ext ));
if ($file != "." && $file != ".." && $allowed ) { ?> <input type=checkbox name="file[]" value="<?php echo "$file";?>"><?php echo "$file"; ?><br><?php echo "\n";
}
}
closedir($handle);
}
?><br><input type="submit" name="formSubmit" value="Zip and download" /></form><?php
}
listDir('.'); ?>
$filename = Y-m-d " Backup.zip"; (not working)
because you are not using date() here. Also, you are not concatenating strings using ..
$filename = date('Y-m-d')."Backup.zip";
The above code will work for you.

php returning file corrupt on mp4 readfile access to folder outside root directory

Am trying to load the mp4 file on page but i get a corrupt file message.
Am using this as my php file to load from private folder outside root directory and open it directly from browser to see if video plays directly to firefox browser:
if(!empty($_GET['video']))
{
if (strpos($_GET['video'], "\0") !== FALSE) die('');
$video = $_REQUEST['video'];
$path_parts = pathinfo($video);
$file_name = $path_parts['basename'];
require_once("config.php");
if(isUserLoggedIn())
{
//Construct an Order object
$IsPaid = new Order($reference=$loggedInUser -> user_id,$pesapal_tracking_id=NULL,$orderstatus = NULL);
//Check if he is paid
if($IsPaid->isPaid())
{
//Private folder
$file = $_SERVER['DOCUMENT_ROOT'].'/../privatelogged/'. $file_name;
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
header("Cache-Control: no-store, must-revalidate");
header("Content-Type: video/mp4");
header('Content-Length: ' . filesize($file));
set_time_limit(0);
$resource = #fopen($file,"rb");
while(!feof($resource))
{
print(#fread($resource, 1024*8));
ob_flush();
flush();
}
//readfile($file);
}
}
}

Form downloads same ZIP over and over

Thanks to the users community on this forum, I wrote a very simple web form that allows my user to view text files from within their Internet browser.
I have now two functions whereby the text files returned by the search are compressed into a ZIP. Here's my code
function getFilesFromSite() {
$result = null;
$ZIPresult = null;
if (empty($_POST['DBSite'])) { return null; }
$mydir = MYDIR;
$dir = opendir($mydir);
$DBSite = $_POST['DBSite'];
$getfilename = mysql_query("select filename from search_table where site='" . $DBSite . "'") or die(mysql_error());
while ($row = mysql_fetch_array($getfilename)) {
$filename = $row['filename'];
$result .= '<tr><td>' . $filename . '</td></tr>';
$ZIPresult .= basename($mydir) . '/' . $filename.' ';
}
if ($result) {
$result = "<table><tbody><tr><td>Search Results.</td></tr> $result</table>";
shell_exec("/bin/rm -f SearchResult.zip;/usr/bin/zip -9 SearchResult.zip ". $ZIPresult ." > /dev/null ");
//header for forced download
header("Pragma: public");
header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1
header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Date in the past
$fileName = 'SearchResult.zip';
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-Transfer-Encoding: binary");
header('Content-type: application/zip');
header("Content-length: " . filesize($fileName));
header('Content-Disposition: attachment; filename="' . $fileName . '"');
ob_start(); // Starts output buffering.
readfile($fileName); // "Outputs" the file.
$content = ob_get_flush(); // Grabs the output and assigns it to a variable.
print base64_encode($content);
}
function getFilesFromError() {
//Just a copy paste from above with different input parameter...
}
The problem is that the ZIP file with the contents from whatever search was done first gets downloaded over and over again. For instance, the results from getFilesFromSite() will always get downloaded even though I did a search with getFilesFromError() afterwards.
I suspect my headers are incorrectly set but I am not sure where.
PS: The new ZipArchive() library/class is not available on our production environment so I chose to use the Unix utility ZIP instead.
Using Base64 was actually not working for reasons well stated here. Instead, I turned zlib compression off and reverted back to using binary as output format. Finally, I set Content-Type to application/octet-stream in my header. Everything is working fine now ; here's my code:
function getFiles() {
ini_set('zlib.output_compression', 'Off');
$result = null;
$ZIPresult = null;
$cleanup = null;
$output = null;
$fileName = null;
//remove old zip if any
$cleanup = shell_exec("/bin/rm -f SearchResult.zip");
error_log("SHELL OUTPUT=>" . $cleanup, 0);
//test
if (empty($_POST['DBRIDs'])) { return null; }
$mydir = MYDIR; // set from the CONSTANT
$dir = opendir($mydir);
$DBRIDs = $_POST['DBRIDs'];
$getfilename = mysql_query("select /*! SQL_CACHE */ filename from automation where rid in (" . $DBRIDs . ")") or die(mysql_error());
while ($row = mysql_fetch_array($getfilename)) {
$filename = $row['filename'];
$result .= '<tr><td>' . $filename . '</td></tr>';
$ZIPresult .= basename($mydir) . '/' . $filename.' ';
}
if ($result) {
$result = "<table><tbody><tr><td>Search Results.</td></tr> $result</table>";
$output = shell_exec("/usr/bin/zip SearchResult.zip ". $ZIPresult ." ");
error_log("SHELL OUTPUT=>" . $output, 0);
$fileName = 'SearchResult.zip';
error_log("ZIP FILENAME=>" . $fileName, 0);
if (file_exists($fileName)) {
//header for forced download
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($fileName));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($fileName));
ob_clean();
flush();
readfile($fileName);
exit;
}
}
return $result;
}
Thanks to all for taking the time!!

How to download existing file in PHP

I have a pdf file on my server. I want to create such link that, user can click on it and download that pdf file. I am using Zend frame work with Php.
place this code inside a php file and call it f.e. "download.php":
<?php
$fullPath = "path/to/your/file.ext";
if ($fd = fopen ($fullPath, "r")) {
$fsize = filesize($fullPath);
$path_parts = pathinfo($fullPath);
$ext = strtolower($path_parts["extension"]);
header("Content-type: application/pdf");
header("Content-Disposition: attachment; filename=\"".$path_parts["basename"]."\"");
header("Content-length: $fsize");
header("Cache-control: private");
while(!feof($fd)) {
$buffer = fread($fd, 2048);
echo $buffer;
}
}
fclose ($fd);
exit;
?>
Example: place this kind of link into the document where the file download is offered:
Download here
More Detail:
http://www.finalwebsites.com/forums/topic/php-file-download
I assume there is a reason you can't just link to the pdf directly, such as the need to authenticate the user. In that case, you will need to set the correct headers, and, as others have noted, you can use get_file_contents to serve the pdf. However, using get_file_contents requires that you read the file into memory before you send the response. If the file is large, or if you receive many requests at once, you can easily run out of memory. A great solution if you're using Apache or Lighttpd is to use XSendFile. With XSendFile you set the X-Sendfile response header to the file's path, and your web server serves the file directly from disk - without revealing the file's location on disk.
The problem with this solution is that the module must be installed on Apache, and it must be configured to work with Lighttpd.
Once XSendFile is installed, your Zend Framework action code would look something like the following:
// user auth or other code here -- there has to be a reason you're not
// just pointing to the pdf file directly
$this->_helper->layout->disableLayout();
$this->_helper->viewRenderer->setNoRender();
$this->getResponse()->setHeader('Content-type', 'application/pdf')
->setHeader('X-Sendfile', 'path-to-file')
->sendResponse();
header("Content-type: application/pdf");
header("Content-Disposition: attachment; filename=filename.pdf");
$pdfiledata = file_get_contents($filename);
echo $pdfiledata;
I have been using this reusable action helper for sending files to users. It works well and is better than messing around with headers yourself.
I don't know if Zend provides a class for this. In general this is achieved by using the header function. have a look at the PHP site:
http://php.net/manual/en/function.header.php
There are some examples of downloading files.
Good luck!
I've always used the become_file_download function from the open source BalPHP library which you can plug and play (stick) into your project right away. It allows for:
Instant download of the file
Easily specify params like content-type, cache life, buffer size.
Supports multi-part transactions allowing for faster downloads which won't kill your server for big file transfers.
Supports pause/resume functionality.
And etags for caching:
You can find the latest version here:
http://github.com/balupton/balphp/blob/master/trunk/lib/core/functions/_files.funcs.php#L75
And here it is copy and pasted as of 27 August, 2010:
/**
* Become a file download, should be the last script that runs in your program
*
* http://tools.ietf.org/id/draft-ietf-http-range-retrieval-00.txt
*
* #version 3, July 18, 2009 (Added suport for data)
* #since 2, August 11, 2007
*
* #author Benjamin "balupton" Lupton <contact#balupton.com> - {#link http://www.balupton.com/}
*
* #param string $file_path
* #param string $content_type
* #param int $buffer_size
* #param string $file_name
* #param timestamp $file_time
*
* #return boolean true on success, false on error
*/
function become_file_download ( $file_path_or_data, $content_type = NULL, $buffer_size = null, $file_name = null, $file_time = null, $expires = null ) {
// Prepare
if ( empty($buffer_size) )
$buffer_size = 4096;
if ( empty($content_type) )
$content_type = 'application/force-download';
// Check if we are data
$file_descriptor = null;
if ( file_exists($file_path_or_data) && $file_descriptor = fopen($file_path_or_data, 'rb') ) {
// We could be a file
// Set some variables
$file_data = null;
$file_path = $file_path_or_data;
$file_name = $file_name ? $file_name : basename($file_path);
$file_size = filesize($file_path);
$file_time = filemtime($file_path);
$etag = md5($file_time . $file_name);
} elseif ( $file_name !== null ) {
// We are just data
$file_data = $file_path_or_data;
$file_path = null;
$file_size = strlen($file_data);
$etag = md5($file_data);
if ( $file_time === null )
$file_time = time();
else
$file_time = ensure_timestamp($file_time);
} else {
// We couldn't find the file
header('HTTP/1.1 404 Not Found');
return false;
}
// Prepare timestamps
$expires = ensure_timestamp($expires);
// Set some variables
$date = gmdate('D, d M Y H:i:s') . ' GMT';
$expires = gmdate('D, d M Y H:i:s', $expires) . ' GMT';
$last_modified = gmdate('D, d M Y H:i:s', $file_time) . ' GMT';
// Say we can go on forever
set_time_limit(0);
// Check relevance
$etag_relevant = !empty($_SERVER['HTTP_IF_NONE_MATCH']) && trim(stripslashes($_SERVER['HTTP_IF_NONE_MATCH']), '\'"') === $etag;
$date_relevant = !empty($_SERVER['HTTP_IF_MODIFIED_SINCE']) && strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) >= $file_time;
// Handle download
if ( $etag_relevant || $date_relevant ) {
// Not modified
header('HTTP/1.0 304 Not Modified');
header('Status: 304 Not Modified');
header('Pragma: public');
header('Cache-Control: private');
header('ETag: "' . $etag . '"');
header('Date: ' . $date);
header('Expires: ' . $expires);
header('Last-modified: ' . $last_modified);
return true;
} elseif ( !empty($_SERVER['HTTP_RANGE']) ) {
// Partial download
/*
* bytes=0-99,500-1499,4000-
*/
// Explode RANGE
list($size_unit,$ranges) = explode($_SERVER['HTTP_RANGE'], '=', 2);
// Explode RANGES
$ranges = explode(',', $ranges);
// Cycle through ranges
foreach ( $ranges as $range ) {
// We have a range
/*
* All bytes until the end of document, except for the first 500 bytes:
* Content-Range: bytes 500-1233/1234
*/
// Set range start
$range_start = null;
if ( !empty($range[0]) && is_numeric($range[0]) ) {
// The range has a start
$range_start = intval($range[0]);
} else {
$range_start = 0;
}
// Set range end
if ( !empty($range[1]) && is_numeric($range[1]) ) {
// The range has an end
$range_end = intval($range[1]);
} else {
$range_end = $file_size - 1;
}
// Set the range size
$range_size = $range_end - $range_start + 1;
// Set the headers
header('HTTP/1.1 206 Partial Content');
header('Pragma: public');
header('Cache-Control: private');
header('ETag: "' . $etag . '"');
header('Date: ' . $date);
header('Expires: ' . $expires);
header('Last-modified: ' . $last_modified);
header('Content-Transfer-Encoding: binary');
header('Accept-Ranges: bytes');
header('Content-Range: bytes ' . $range_start . '-' . $range_end . '/' . $file_size);
header('Content-Length: ' . $range_size);
header('Content-Type: ' . $content_type);
if ( $content_type === 'application/force-download' )
header('Content-Disposition: attachment; filename=' . urlencode($file_name));
// Handle our data transfer
if ( !$file_path ) {
// We are using file_data
echo substr($file_data, $range_start, $range_end - $range_start);
} else {
// Seek to our location
fseek($file_descriptor, $range_start);
// Read the file
$remaining = $range_size;
while ( $remaining > 0 ) {
// 0-6 | buffer = 3 | remaining = 7
// 0,1,2 | buffer = 3 | remaining = 4
// 3,4,5 | buffer = 3 | remaining = 1
// 6 | buffer = 1 | remaining = 0
// Set buffer size
$buffer_size = min($buffer_size, $remaining);
// Output file contents
echo fread($file_descriptor, $buffer_size);
flush();
ob_flush();
// Update remaining
$remaining -= $buffer_size;
}
}
}
} else {
// Usual download
// header('Pragma: public');
// header('Cache-control: must-revalidate, post-check=0, pre-check=0');
// header('Expires: '. gmdate('D, d M Y H:i:s').' GMT');
// Set headers
header('HTTP/1.1 200 OK');
header('Pragma: public');
header('Cache-Control: private');
header('ETag: "' . $etag . '"');
header('Date: ' . $date);
header('Expires: ' . $expires);
header('Last-modified: ' . $last_modified);
header('Content-Transfer-Encoding: binary');
header('Accept-Ranges: bytes');
header('Content-Length: ' . $file_size);
header('Content-Type: ' . $content_type);
if ( $content_type === 'application/force-download' )
header('Content-Disposition: attachment; filename=' . urlencode($file_name));
// Handle our data transfer
if ( !$file_path ) {
// We are using file_data
echo $file_data;
} else {
// Seek to our location
// Read the file
$file_descriptor = fopen($file_path, 'r');
while ( !feof($file_descriptor) ) {
// Output file contents
echo fread($file_descriptor, $buffer_size);
flush();
ob_flush();
}
}
}
// Close the file
if ( $file_descriptor )
fclose($file_descriptor);
// Done
return true;
}
It also depends on another plug and play function called ensure_timestamp which you can find here:
http://github.com/balupton/balphp/blob/master/trunk/lib/core/functions/_datetime.funcs.php#L31
/**
* Gets the days between two timestamps
* #version 1, January 28, 2010
* #param mixed $value
* #return timestamp
*/
function ensure_timestamp ( $value = null ) {
$result = null;
if ( $value === null ) $result = time();
elseif ( is_numeric($value) ) $result = $value;
elseif ( is_string($value) ) $result = strtotime($value);
else throw new Exception('Unknown timestamp type.');
return $result;
}

Categories