I am trying to download a large file from an external link using php, I don't have a big idea about this subject, I tried to use the code below, but it always giving me file does not exist!.
I changed the if(file_exists($filePath)) to if(true), but I end with a downloaded file of 0 byte size, where is the error in my code?
$filePath = "http://down.egyu.net/Movies/The.Gambler.2014.720p.BluRay.x264.EGFire.CoM.mp4"; // set your download file path here.
download($filePath); // calls download function
function download($filePath)
{
if(!empty($filePath))
{
$fileInfo = pathinfo($filePath);
$fileName = $fileInfo['basename'];
$fileExtnesion = $fileInfo['extension'];
$default_contentType = "application/octet-stream";
$content_types_list = mimeTypes();
// to find and use specific content type, check out this IANA page : http://www.iana.org/assignments/media-types/media-types.xhtml
if (array_key_exists($fileExtnesion, $content_types_list))
{
$contentType = $content_types_list[$fileExtnesion];
}
else
{
$contentType = $default_contentType;
}
if(file_exists($filePath))
{
$size = filesize($filePath);
$offset = 0;
$length = $size;
//HEADERS FOR PARTIAL DOWNLOAD FACILITY BEGINS
if(isset($_SERVER['HTTP_RANGE']))
{
preg_match('/bytes=(\d+)-(\d+)?/', $_SERVER['HTTP_RANGE'], $matches);
$offset = intval($matches[1]);
$length = intval($matches[2]) - $offset;
$fhandle = fopen($filePath, 'r');
fseek($fhandle, $offset); // seek to the requested offset, this is 0 if it's not a partial content request
$data = fread($fhandle, $length);
fclose($fhandle);
header('HTTP/1.1 206 Partial Content');
header('Content-Range: bytes ' . $offset . '-' . ($offset + $length) . '/' . $size);
}//HEADERS FOR PARTIAL DOWNLOAD FACILITY BEGINS
//USUAL HEADERS FOR DOWNLOAD
header("Content-Disposition: attachment;filename=".$fileName);
header('Content-Type: '.$contentType);
header("Accept-Ranges: bytes");
header("Pragma: public");
header("Expires: -1");
header("Cache-Control: no-cache");
header("Cache-Control: public, must-revalidate, post-check=0, pre-check=0");
header("Content-Length: ".filesize($filePath));
$chunksize = 8 * (1024 * 1024); //8MB (highest possible fread length)
if ($size > $chunksize)
{
$handle = fopen($_FILES["file"]["tmp_name"], 'rb');
$buffer = '';
while (!feof($handle) && (connection_status() === CONNECTION_NORMAL))
{
$buffer = fread($handle, $chunksize);
print $buffer;
ob_flush();
flush();
}
if(connection_status() !== CONNECTION_NORMAL)
{
echo "Connection aborted";
}
fclose($handle);
}
else
{
ob_clean();
flush();
readfile($filePath);
}
}
else
{
echo 'File does not exist!';
}
}
else
{
echo 'There is no file to download!';
}
}
I found the answer myself, I used a function to get the status of url if it exist and to get the file size:
/* You may need these ini settings too */
set_time_limit(0);
ini_set('memory_limit', '512M');
//THE DOWNLOAD SCRIPT
$filePath = "http://down.egyu.net/Movies/The.Gambler.2014.720p.BluRay.x264.EGFire.CoM.mp4"; // set your download file path here.
download($filePath); // calls download function
function download($filePath)
{
if(!empty($filePath))
{
$fileInfo = pathinfo($filePath);
$fileName = $fileInfo['basename'];
$fileExtnesion = $fileInfo['extension'];
$default_contentType = "application/octet-stream";
$content_types_list = mimeTypes();
// to find and use specific content type, check out this IANA page : http://www.iana.org/assignments/media-types/media-types.xhtml
if (array_key_exists($fileExtnesion, $content_types_list))
{
$contentType = $content_types_list[$fileExtnesion];
}
else
{
$contentType = $default_contentType;
}
$exist = is_url_exist($fileInfo['dirname']."/".$fileInfo['basename']);
if($exist['response'])
{
$size = $exist['size'];
$offset = 0;
$length = $size;
//HEADERS FOR PARTIAL DOWNLOAD FACILITY BEGINS
if(isset($_SERVER['HTTP_RANGE']))
{
preg_match('/bytes=(\d+)-(\d+)?/', $_SERVER['HTTP_RANGE'], $matches);
$offset = intval($matches[1]);
$length = intval($matches[2]) - $offset;
$fhandle = fopen($filePath, 'r');
fseek($fhandle, $offset); // seek to the requested offset, this is 0 if it's not a partial content request
$data = fread($fhandle, $length);
fclose($fhandle);
header('HTTP/1.1 206 Partial Content');
header('Content-Range: bytes ' . $offset . '-' . ($offset + $length) . '/' . $size);
}//HEADERS FOR PARTIAL DOWNLOAD FACILITY BEGINS
//USUAL HEADERS FOR DOWNLOAD
header("Content-Disposition: attachment;filename=".$fileName);
header('Content-Type: '.$contentType);
header("Accept-Ranges: bytes");
header("Pragma: public");
header("Expires: -1");
header("Cache-Control: no-cache");
header("Cache-Control: public, must-revalidate, post-check=0, pre-check=0");
header("Content-Length: ".$size);
$chunksize = 8 * (1024 * 1024); //8MB (highest possible fread length)
if ($size > $chunksize)
{
$handle = fopen($_FILES["file"]["tmp_name"], 'rb');
$buffer = '';
while (!feof($handle) && (connection_status() === CONNECTION_NORMAL))
{
$buffer = fread($handle, $chunksize);
print $buffer;
ob_flush();
flush();
}
if(connection_status() !== CONNECTION_NORMAL)
{
echo "Connection aborted";
}
fclose($handle);
}
else
{
ob_clean();
flush();
readfile($filePath);
}
}
else
{
echo 'File does not exist!';
}
}
else
{
echo 'There is no file to download!';
}
}
function is_url_exist($url){
$array = array();
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_NOBODY, true);
curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$size = curl_getinfo($ch, CURLINFO_CONTENT_LENGTH_DOWNLOAD);
if($code == 200){
$array['response'] = true;
}else{
$array['response'] = false;
}
$array['size'] = $size;
curl_close($ch);
return $array;
}
Related
I want to stream a video file of any length. But I struggle with creating my php script for this purpose.
I created one but when i seek the video it just breaks and the video goes back from beginning. Sometimes i get net::ERR_CONTENT_LENGTH_MISMATCH error. And cant figure out how to get things done. There is my code.
<?php
$filename = "song.mp4";
$file = fopen($filename, 'rb');
$filesize = filesize($filename);
$buffer = 5 * 1024;
header("Content-Type: video/mp4");
header("Cache-Control: no-cache");
header("Accept-Ranges: bytes");
if(isset($_SERVER['HTTP_RANGE'])){
$matches = array();
preg_match("/(\d+)/i", $_SERVER['HTTP_RANGE'], $matches);
$start = (int)$matches[1];
if(isset($matches[2])){
$end = $matches[2];
}else{
$end = $filesize - 1;
}
$length = $filesize - $start + 1;
fseek($file, $start);
header("Content-Length: " . $length);
header("Content-Range: bytes $start-$end/$filesize");
}else{
header("Content-Length: " . $filesize);
}
while(!feof($file)){
$data = fread($file, $buffer);
echo $data;
flush();
}
fclose($file);
fclose($log);
exit;
?>
I expect to get the full video streamed without any problems when i seek through.
Provides file downloads with PHP.
It works fine on the web, but it does not work properly in the app.
What is the reason why the header of the file is normally displayed but the file is not downloaded?
android webview download
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
request.setMimeType(mimetype);
request.addRequestHeader("User-Agent", userAgent);
request.setDescription("Downloading file");
request.setTitle(URLUtil.guessFileName(url,contentDisposition,mimetype));
request.allowScanningByMediaScanner();
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, URLUtil.guessFileName(url,contentDisposition,mimetype));
DownloadManager dm = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
headers
header('Content-Type: ' . $this->mimetype);
header('Content-Disposition: attachment; filename="' . $this->dl_filename . '"');
header("Content-Transfer-Encoding: binary");
header('Accept-Ranges: bytes');
/* The three lines below basically make the
download non-cacheable */
header("Cache-control: private");
header('Pragma: private');
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
// multipart-download and download resuming support
if(isset($_SERVER['HTTP_RANGE']) && !$this->force_single){
list($a, $range) = explode("=", $_SERVER['HTTP_RANGE'], 2);
list($range) = explode(",", $range, 2);
list($range, $range_end) = explode("-", $range);
$range = intval($range);
if(!$range_end){
$range_end = $size - 1;
}else{
$range_end = intval($range_end);
}
$new_length = $range_end - $range + 1;
header('HTTP/1.1 206 Partial Content');
header('Content-Length: ' . $new_length);
header('Content-Range: bytes ' . $range . '-' . $range_end . '/' . $size);
//set the offset range
$this->mt_range = $range;
}else{
$new_length = $size;
header("Content-Length: " . $size);
}
download file
if($file = fopen($filename, 'r')){
if(isset($_SERVER['HTTP_RANGE']) && !$this->force_single){
fseek($file, $this->mt_range);
}
//write the data out to the browser
while(!feof($file) && !connection_aborted() && $bytes_send < $block_size){
$buffer = fread($file, $chunksize);
echo $buffer;
flush();
$bytes_send += strlen($buffer);
}
fclose($file);
}
I am using the below code snippet to read mp4 files using PHP and play it in the video tag. This code works when I call the video as file(test.mp4) in the localhost allowing to move the seeker back and forth. But when I use Video Source as URL(http://techslides.com/demos/sample-videos/small.mp4) the video is playing but cannot move the seeker back and front.
$filename = 'http://techslides.com/demos/sample-videos/small.mp4';
$mimeType = 'video/mp4';
$ch = curl_init($filename);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_HEADER, TRUE);
curl_setopt($ch, CURLOPT_NOBODY, TRUE);
$data = curl_exec($ch);
$size = curl_getinfo($ch, CURLINFO_CONTENT_LENGTH_DOWNLOAD);
curl_close($ch);
// echo $size = filesize($filename);die;
$time = date('r', filemtime($filename));
$fm = #fopen($filename, 'rb');
if (!$fm)
{
header ("HTTP/1.1 505 Internal server error");
return;
}
$begin = 0;
$end = $size - 1;
if (isset($_SERVER['HTTP_RANGE']))
{
if (preg_match('/bytes=\h*(\d+)-(\d*)[\D.*]?/i', $_SERVER['HTTP_RANGE'], $matches))
{
$begin = intval($matches[1]);
if (!empty($matches[2]))
{
$end = intval($matches[2]);
}
}
}
if (isset($_SERVER['HTTP_RANGE']))
{
header('GET HTTP/1.1 206 Partial Content');
}
else
{
header('HTTP/1.1 200 OK');
}
header("Content-Type: video/mp4");
header('Accept-Ranges: bytes');
header("Content-Disposition: inline;");
header("Content-Range: bytes $begin-$end/$size");
header("Content-Transfer-Encoding: binary\n");
header('Cache-Control: public, must-revalidate, max-age=0');
header('Pragma: no-cache');
header('Content-Length:' . (($end - $begin) + 1));
if (isset($_SERVER['HTTP_RANGE']))
{
header("Content-Range: bytes $begin-$end/$size");
}
header('Connection: close');
$cur = $begin;
fseek($fm, $begin, 0);
while(!feof($fm) && $cur <= $end && (connection_status() == 0))
{
print fread($fm, min(1024 * 16, ($end - $cur) + 1));
$cur += 1024 * 16;
usleep(1000);
}
i have tried do that before ,
it's not working because fseek() do not support http,
the file must be 'seekable' that mean you must get file from path
check this answer https://stackoverflow.com/a/21722576/5380308
I have the following code to force download an IPA file (after codesigning it with a script). It works fine with smaller files but with larger files, my web server starts returning a 500 Internal Server Error. Would someone be able to help me tweak my existing code to overcome this issue?
$time = md5(time());
// Runs code signing script here
// And then attempts to initiate download
$path = "done/$time/";
$latest_ctime = 0;
$latest_filename = '';
$d = dir($path);
while (false !== ($entry = $d->read())) {
$filepath = "{$path}/{$entry}";
if (is_file($filepath) && filectime($filepath) > $latest_ctime) {
$latest_ctime = filectime($filepath);
$latest_filename = $entry;
}
}
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-Disposition: attachment; filename=$time.ipa");
header("Content-Type: application/ipa");
header("Content-Transfer-Encoding: binary");
// Read the file from disk
readfile("done/$time/".$latest_filename);
// header('location: dashboard.php');
} else {
// Throwback
die("Failed. Contact support. // <p>$sign</p>");
}
Here is an example:
$filepath = "done/{$time}/{$latest_filename}";
$size = filesize($filepath);
$mimetype = 'application/ipa';
// Turn off buffering
if (ob_get_level()) {
ob_end_clean();
}
$handle = fopen($filepath, 'rb');
if ($handle !== false && $size > 0) {
#flock($handle, LOCK_SH);
$filename = rawurldecode($filepath);
$old_max_execution_time = ini_get('max_execution_time');
$old_cache_limiter = session_cache_limiter();
ini_set('max_execution_time', 0);
session_cache_limiter(false);
header("Cache-Control: public");
header("Content-Description: File Transfer");
header('Content-Type: ' . $mimetype);
header('Content-Transfer-Encoding: binary');
header('Content-disposition: attachment; filename="'. $filename .'"');
// or your variant
// header("Content-Disposition: attachment; filename=" . md5(time()));
header("Content-Length: $size");
$start = 0;
$end = $size - 1;
$chunk = 8 * 1024;
$requested = (float)$end - (float)$start + 1;
while (! $error) {
if ($chunk >= $requested) {
$chunk = (integer)$requested;
}
set_time_limit(0);
while (! feof($handle) && (connection_status() === 0)) {
if (! $buffer = #fread($handle, $chunk)) {
$error = true;
break 2;
}
print($buffer);
flush();
}
#flock($handle, LOCK_UN);
#fclose($handle);
ini_set('max_execution_time', $old_max_execution_time);
session_cache_limiter($old_cache_limiter);
break;
}
if ($error) {
// 500 - Internal server error
exit;
}
} else {
// Can't open file
exit;
}
Maybe problem in script time execution.
Try to set ini_set('max_execution_time', 0);
Also try to read and send file by chunks.
PHP $_SERVER does not return HTTP_range key and without that key how can I perform a "resume download" or download in chunks?
if (isset($_SERVER['HTTP_RANGE'])) {
echo "find";
} else{
echo "not find";
}
i can't get $_SERVER['HTTP_RANGE'] from server .......
There is no key HTTP_RANGE when i print $_SERVER
===================================================
<?php
// get the file request, throw error if nothing supplied
// hide notices
#ini_set('error_reporting', E_ALL & ~ E_NOTICE);
//- turn off compression on the server
#apache_setenv('no-gzip', 1);
#ini_set('zlib.output_compression', 'Off');
if(!isset($_REQUEST['file']) || empty($_REQUEST['file']))
{
header("HTTP/1.0 400 Bad Request");
exit;
}
// sanitize the file request, keep just the name and extension
// also, replaces the file location with a preset one ('./myfiles/' in this example)
$file_path = $_REQUEST['file'];
$path_parts = pathinfo($file_path);
$file_name = $path_parts['basename'];
$file_ext = $path_parts['extension'];
$file_path = './myfiles/' . $file_name;
// allow a file to be streamed instead of sent as an attachment
$is_attachment = isset($_REQUEST['stream']) ? false : true;
// make sure the file exists
if (is_file($file_path))
{
$file_size = filesize($file_path);
$file = #fopen($file_path,"rb");
if ($file)
{
// set the headers, prevent caching
header("Pragma: public");
header("Expires: -1");
header("Cache-Control: public, must-revalidate, post-check=0, pre-check=0");
header("Content-Disposition: attachment; filename=\"$file_name\"");
// set appropriate headers for attachment or streamed file
if ($is_attachment) {
header("Content-Disposition: attachment; filename=\"$file_name\"");
}
else {
header('Content-Disposition: inline;');
header('Content-Transfer-Encoding: binary');
}
// set the mime type based on extension, add yours if needed.
$ctype_default = "application/octet-stream";
$content_types = array(
"exe" => "application/octet-stream",
"zip" => "application/zip",
"mp3" => "audio/mpeg",
"mpg" => "video/mpeg",
"avi" => "video/x-msvideo",
);
$ctype = isset($content_types[$file_ext]) ? $content_types[$file_ext] : $ctype_default;
header("Content-Type: " . $ctype);
//check if http_range is sent by browser (or download manager)
if(isset($_SERVER['HTTP_RANGE']))
{
list($size_unit, $range_orig) = explode('=', $_SERVER['HTTP_RANGE'], 2);
if ($size_unit == 'bytes')
{
//multiple ranges could be specified at the same time, but for simplicity only serve the first range
//http://tools.ietf.org/id/draft-ietf-http-range-retrieval-00.txt
list($range, $extra_ranges) = explode(',', $range_orig, 2);
}
else
{
$range = '';
header('HTTP/1.1 416 Requested Range Not Satisfiable');
exit;
}
}
else
{
$range = '';
}
//figure out download piece from range (if set)
list($seek_start, $seek_end) = explode('-', $range, 2);
//set start and end based on range (if set), else set defaults
//also check for invalid ranges.
$seek_end = (empty($seek_end)) ? ($file_size - 1) : min(abs(intval($seek_end)),($file_size - 1));
$seek_start = (empty($seek_start) || $seek_end < abs(intval($seek_start))) ? 0 : max(abs(intval($seek_start)),0);
//Only send partial content header if downloading a piece of the file (IE workaround)
if ($seek_start > 0 || $seek_end < ($file_size - 1))
{
header('HTTP/1.1 206 Partial Content');
header('Content-Range: bytes '.$seek_start.'-'.$seek_end.'/'.$file_size);
header('Content-Length: '.($seek_end - $seek_start + 1));
}
else
header("Content-Length: $file_size");
header('Accept-Ranges: bytes');
set_time_limit(0);
fseek($file, $seek_start);
while(!feof($file))
{
print(#fread($file, 1024*8));
ob_flush();
flush();
if (connection_status()!=0)
{
#fclose($file);
exit;
}
}
// file save was a success
#fclose($file);
exit;
}
else
{
// file couldn't be opened
header("HTTP/1.0 500 Internal Server Error");
exit;
}
}
else
{
// file does not exist
header("HTTP/1.0 404 Not Found");
exit;
}
?>