Как вставить заголовки из файла на внешний сервер для загрузки? - PullRequest
2 голосов
/ 08 июня 2009

Следующий скрипт - это то, что я обычно использую для отправки заголовков в браузер, чтобы у пользователей появлялось диалоговое окно для загрузки файла.

Однако в этом случае файл находится на другом сервере. Я думаю, что это не должно иметь никакого значения, но это происходит потому, что когда я выполняю этот скрипт с URL-адресом файла MP3 externam, он дает мне «ОШИБКА: Файл не найден». Однако этот файл существует, и я могу получить к нему тот же URL-адрес, который передал этому сценарию.

Есть идеи, почему? Буду признателен за любую помощь.

<?php session_start();

//below variable contains full path to external site where file resides
$filename = $_SESSION['$serverURL'].'audio/'.$_SESSION['fileName'].'.mp3';
//below variable contains a chosen filename of the file to be downloaded
$properFilename = $_GET['properFilename'].'.mp3';

// required for IE, otherwise Content-disposition is ignored
if(ini_get('zlib.output_compression'))
  ini_set('zlib.output_compression', 'Off');

// addition by Jorg Weske
$file_extension = strtolower(substr(strrchr($filename,"."),1));

if( $filename == "" ) 
{
  //echo "download file NOT SPECIFIED";
  exit;
} elseif ( ! file_exists( $filename ) ) 
{
  //echo "ERROR: File not found";
  exit;
};
switch( $file_extension )
{
  case "pdf": $ctype="application/pdf"; break;
  case "exe": $ctype="application/octet-stream"; break;
  case "zip": $ctype="application/zip"; break;
  case "doc": $ctype="application/msword"; break;
  case "xls": $ctype="application/vnd.ms-excel"; break;
  case "ppt": $ctype="application/vnd.ms-powerpoint"; break;
  case "gif": $ctype="image/gif"; break;
  case "png": $ctype="image/png"; break;
  case "jpeg":
  case "jpg": $ctype="image/jpg"; break;
  default: $ctype="application/force-download";
}
header("Pragma: public"); // required
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: private",false); // required for certain browsers 
header("Content-Type: $ctype");
// change, added quotes to allow spaces in filenames, by Rajkumar Singh
header("Content-Disposition: attachment; filename=\"".basename($properFilename)."\";" );
header("Content-Transfer-Encoding: binary");
header("Content-Length: ".filesize($filename));
readfile("$filename");
exit();   

?>

1 Ответ

3 голосов
/ 08 июня 2009

Строки в одинарных кавычках не анализируются для переменных, поэтому $_SESSION['$serverURL'], вероятно, не будет работать так, как вы ожидаете. Я подозреваю, что вы имеете в виду $_SESSION[$serverURL] или $_SESSION['serverURL'].

Также вызов filesize(), а затем readfile(), вероятно, приведет к тому, что ваш скрипт выполнит два HTTP-запроса для извлечения файла с другого сервера (если это не будет каким-либо образом кэшировано). Вы можете сделать это в одном HTTP-запросе, используя cURL, что может быть лучшим вариантом. Вот краткий пример, вы должны иметь возможность адаптировать его, чтобы делать то, что вы хотите. Вы также можете рассмотреть возможность пересылки других заголовков, таких как заголовок Content-Type, с другого сервера (если они надежны), а не их повторную генерацию.

<?php

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, 'http://example.com');

//set callbacks to receive headers and content
curl_setopt($ch, CURLOPT_HEADERFUNCTION, 'on_receive_header');
curl_setopt($ch, CURLOPT_WRITEFUNCTION, 'on_receive_content');

//send your other custom headers somewhere like here

if (false === curl_exec($ch)) {
    //handle error better than this.
    die(curl_error($ch));   
}

function on_receive_header($ch, $string) {
    //You could here forward the other headers received from your other server if you wanted

    //for now we only want Content-Length
    if (stripos($string, 'Content-Length') !== false) {
        header($string);   
    }

    //curl requires you to return the amount of data received
    $length = strlen($string);
    return $length;
}

function on_receive_content($ch, $string) {
    echo $string;

    //again return amount written
    $length = strlen($string);
    return $length;
}
...