Загрузить удаленный файл прямо на клиента?

Мне нужно загрузить удаленный файл прямо к клиенту. После некоторого поиска в Google я нашел этот скрипт в руководстве по php, но его возможности возобновления не работают. Этот скрипт использует Http_Range для создания возобновляемой ссылки для скачивания. Есть ли другой способ сделать это? Конечно, это будет с помощью cUrl но мне нужно загрузить удаленный файл прямо к клиенту. Как я могу решить эту проблему?

 <?php $url="http://dl.remote-domain.com/files/file.mp4"; dl_file_resumable($url); function dl_file_resumable($file, $is_resume=TRUE) { //Gather relevent info about file $size = remotefilesize($file); $fileinfo = pathinfo($file); //workaround for IE filename bug with multiple periods / multiple dots in filename //that adds square brackets to filename - eg. setup.abc.exe becomes setup[1].abc.exe $filename = (strstr($_SERVER['HTTP_USER_AGENT'], 'MSIE')) ? preg_replace('/\./', '%2e', $fileinfo['basename'], substr_count($fileinfo ['basename'], '.') - 1) : $fileinfo['basename']; $file_extension = strtolower($path_info['extension']); //This will set the Content-Type to the appropriate setting for the file switch($file_extension) { case 'exe': $ctype='application/octet-stream'; break; case 'zip': $ctype='application/zip'; break; case 'mp3': $ctype='audio/mpeg'; break; case 'mpg': $ctype='video/mpeg'; break; case 'avi': $ctype='video/x-msvideo'; break; default: $ctype='application/force-download'; } //check if http_range is sent by browser (or download manager) if($is_resume && 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 = ''; } } 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)) ? ($size - 1) : min(abs(intval($seek_end)),($size - 1)); $seek_start = (empty($seek_start) || $seek_end < abs(intval($seek_start))) ? 0 : max(abs (intval($seek_start)),0); //add headers if resumable if ($is_resume) { //Only send partial content header if downloading a piece of the file (IE workaround) if ($seek_start > 0 || $seek_end < ($size - 1)) { header('HTTP/1.1 206 Partial Content'); } header('Accept-Ranges: bytes'); header('Content-Range: bytes '.$seek_start.'-'.$seek_end.'/'.$size); } //headers for IE Bugs (is this necessary?) //header("Cache-Control: cache, must-revalidate"); //header("Pragma: public"); header('Content-Type: ' . $ctype); header('Content-Disposition: attachment; filename="' . $filename . '"'); header('Content-Length: '.($seek_end - $seek_start + 1)); //open the file $fp = fopen($file, 'rb'); //seek to start of missing part fseek($fp, $seek_start); //start buffered download while(!feof($fp)) { //reset time limit for big files set_time_limit(0); print(fread($fp, 1024*8)); flush(); ob_flush(); } fclose($fp); exit; } function remotefilesize($url, $user = "", $pw = "") { ob_start(); $ch = curl_init($url); curl_setopt($ch, CURLOPT_HEADER, 1); curl_setopt($ch, CURLOPT_NOBODY, 1); if(!empty($user) && !empty($pw)) { $headers = array('Authorization: Basic ' . base64_encode("$user:$pw")); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); } $ok = curl_exec($ch); curl_close($ch); $head = ob_get_contents(); ob_end_clean(); $regex = '/Content-Length:\s([0-9].+?)\s/'; $count = preg_match($regex, $head, $matches); return isset($matches[1]) ? $matches[1] : "unknown"; } ?> в <?php $url="http://dl.remote-domain.com/files/file.mp4"; dl_file_resumable($url); function dl_file_resumable($file, $is_resume=TRUE) { //Gather relevent info about file $size = remotefilesize($file); $fileinfo = pathinfo($file); //workaround for IE filename bug with multiple periods / multiple dots in filename //that adds square brackets to filename - eg. setup.abc.exe becomes setup[1].abc.exe $filename = (strstr($_SERVER['HTTP_USER_AGENT'], 'MSIE')) ? preg_replace('/\./', '%2e', $fileinfo['basename'], substr_count($fileinfo ['basename'], '.') - 1) : $fileinfo['basename']; $file_extension = strtolower($path_info['extension']); //This will set the Content-Type to the appropriate setting for the file switch($file_extension) { case 'exe': $ctype='application/octet-stream'; break; case 'zip': $ctype='application/zip'; break; case 'mp3': $ctype='audio/mpeg'; break; case 'mpg': $ctype='video/mpeg'; break; case 'avi': $ctype='video/x-msvideo'; break; default: $ctype='application/force-download'; } //check if http_range is sent by browser (or download manager) if($is_resume && 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 = ''; } } 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)) ? ($size - 1) : min(abs(intval($seek_end)),($size - 1)); $seek_start = (empty($seek_start) || $seek_end < abs(intval($seek_start))) ? 0 : max(abs (intval($seek_start)),0); //add headers if resumable if ($is_resume) { //Only send partial content header if downloading a piece of the file (IE workaround) if ($seek_start > 0 || $seek_end < ($size - 1)) { header('HTTP/1.1 206 Partial Content'); } header('Accept-Ranges: bytes'); header('Content-Range: bytes '.$seek_start.'-'.$seek_end.'/'.$size); } //headers for IE Bugs (is this necessary?) //header("Cache-Control: cache, must-revalidate"); //header("Pragma: public"); header('Content-Type: ' . $ctype); header('Content-Disposition: attachment; filename="' . $filename . '"'); header('Content-Length: '.($seek_end - $seek_start + 1)); //open the file $fp = fopen($file, 'rb'); //seek to start of missing part fseek($fp, $seek_start); //start buffered download while(!feof($fp)) { //reset time limit for big files set_time_limit(0); print(fread($fp, 1024*8)); flush(); ob_flush(); } fclose($fp); exit; } function remotefilesize($url, $user = "", $pw = "") { ob_start(); $ch = curl_init($url); curl_setopt($ch, CURLOPT_HEADER, 1); curl_setopt($ch, CURLOPT_NOBODY, 1); if(!empty($user) && !empty($pw)) { $headers = array('Authorization: Basic ' . base64_encode("$user:$pw")); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); } $ok = curl_exec($ch); curl_close($ch); $head = ob_get_contents(); ob_end_clean(); $regex = '/Content-Length:\s([0-9].+?)\s/'; $count = preg_match($regex, $head, $matches); return isset($matches[1]) ? $matches[1] : "unknown"; } ?> 

Если вы хотите просто нажать файл для пользователя, выполните следующие действия:

  1. Начать буферизацию вывода.
  2. Прочитайте содержимое файла как есть для буфера.
  3. Установите ответный заголовок на mime-тип (как в коде, который вы опубликовали).
  4. Сбросьте выходной буфер.

Пользователю будет предложено сохранить файл, если тип mime не отображается в соответствии со стандартами браузера.