如何从外部服务器上的文件中推送Headers进行下载?

时间:2023-02-05 23:05:03

The following script is what I usually use to push headers to the browser so that the dialog box appears for users to download a file.

以下脚本是我通常用于将标头推送到浏览器的脚本,以便出现供用户下载文件的对话框。

However, in this case the file resides on a different server. I though this should make no difference but it does as when I execute this script with the URL of an externam MP3 file it gives me a "ERROR: File not found". However, this file exists, and I can get to it using the same URL I pass to this script.

但是,在这种情况下,该文件驻留在不同的服务器上。我虽然这应该没什么区别,但是当我用externam MP3文件的URL执行这个脚本时它会给我一个“错误:找不到文件”。但是,此文件存在,我可以使用我传递给此脚本的相同URL来访问它。

Any ideas why? I would appreciate any help.

有什么想法吗?我将不胜感激任何帮助。

<?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 个解决方案

#1


3  

Single-quotes strings are not parsed for variables, so $_SESSION['$serverURL'] is probably not going to work as you expect. I suspect you mean $_SESSION[$serverURL] or $_SESSION['serverURL'].

不会为变量解析单引号字符串,因此$ _SESSION ['$ serverURL']可能无法按预期工作。我怀疑你的意思是$ _SESSION [$ serverURL]或$ _SESSION ['serverURL']。

Also calling filesize() and then readfile() will probably result in your script making two HTTP requests to fetch the file from the other server (unless this gets cached somehow). You could do it in one HTTP request using cURL, which may be a better option. Here is a brief example, you should be able to adapt it to do what you want. You might also want to consider forwarding other headers such as the Content-Type header from the other server (if reliable) rather than re-generating them yourself.

另外调用filesize()然后调用readfile()可能会导致你的脚本发出两个HTTP请求来从另一个服务器获取文件(除非以某种方式缓存)。您可以使用cURL在一个HTTP请求中执行此操作,这可能是更好的选择。这是一个简短的例子,您应该能够根据自己的需要进行调整。您可能还需要考虑从其他服务器转发其他标头(如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;
}

#1


3  

Single-quotes strings are not parsed for variables, so $_SESSION['$serverURL'] is probably not going to work as you expect. I suspect you mean $_SESSION[$serverURL] or $_SESSION['serverURL'].

不会为变量解析单引号字符串,因此$ _SESSION ['$ serverURL']可能无法按预期工作。我怀疑你的意思是$ _SESSION [$ serverURL]或$ _SESSION ['serverURL']。

Also calling filesize() and then readfile() will probably result in your script making two HTTP requests to fetch the file from the other server (unless this gets cached somehow). You could do it in one HTTP request using cURL, which may be a better option. Here is a brief example, you should be able to adapt it to do what you want. You might also want to consider forwarding other headers such as the Content-Type header from the other server (if reliable) rather than re-generating them yourself.

另外调用filesize()然后调用readfile()可能会导致你的脚本发出两个HTTP请求来从另一个服务器获取文件(除非以某种方式缓存)。您可以使用cURL在一个HTTP请求中执行此操作,这可能是更好的选择。这是一个简短的例子,您应该能够根据自己的需要进行调整。您可能还需要考虑从其他服务器转发其他标头(如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;
}