2009-08-31 5 views
0

나는 주어진 폴더의 하위 폴더와 파일을 표시하는이 PHP 스크립트를 작성하고 있습니다. 파일을 다운로드해야합니다.PHP 파일 다운로드 : 이상한 http 헤더

가능한 한 적은 정보를 공개하기 위해 디렉토리의 각 항목은 html 마크 업을 포함하는 제출 버튼이있는 양식입니다. send 메소드는 POST입니다.

내가 디렉토리를 클릭하면 해당 디렉토리가 열리고 내용이 잘 표시됩니다. 파일을 클릭하면 다운로드 프롬프트가 표시되고 파일이 잘 다운로드됩니다.

0 65535 f 
0000000000 65535 f 
0000000000 65535 f 
0000000000 65535 f 
0000000000 65535 f 
0000000000 65535 f 
0000000000 65535 f 
0000000000 65535 f 
0000000000 65535 f 
0000000000 65535 f 
0000000000 65535 f 
0000000000 65535 f 
0000000000 65535 f 
0000000000 65535 f 
trailer 
<</Size 34>> 
startxref 
116 
%%EOF 
HTTP/1.1 200 OK 
Date: Mon, 31 Aug 2009 21:01:36 GMT 
Server: Apache 
X-Powered-By: PHP/5.2.5 
Expires: Thu, 19 Nov 1981 08:52:00 GMT 
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0 
Pragma: no-cache 
Keep-Alive: timeout=15, max=93 
Connection: Keep-Alive 
Transfer-Encoding: chunked 
Content-Type: text/html 

2822 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml"> 

디스플레이 페이지의 HTML 코드 소스의 나머지가 나열됩니다 는하지만 클릭 그 후, 나는 그런 일을 보게된다.

여기에 무슨 일이 일어나고 있습니까?

UPDATE : 내 "강제 다운로드"코드 :

function offerToDownloadFile($filename, $access_type='url') { 


// converting url to local path so Apache can find the file. 
// force download: 
// required for IE, otherwise Content-disposition is ignored 
    if (ini_get('zlib.output_compression')) 
     ini_set('zlib.output_compression', 'Off'); 

    if($access_type === 'url') { 
    // access type is via the file 's url 
     $parsed_url = parse_url($filename); 
     $fileinfo = pathinfo($filename); 
     $parsed_url['extension'] = $fileinfo['extension']; 
     $parsed_url['filename'] = $fileinfo['basename']; 

     $parsed_url['localpath'] = LOCALROOT . $parsed_url['path']; 
    } 
    else { 
    // access type is the local file path 
     $fileinfo = pathinfo($filename); 
     $parsed_url['localpath'] = $filename; 
     $parsed_url['filename'] = basename($filename); 
     $parsed_url['extension'] = $fileinfo['extension']; 
    } 


    // just in case there is a double slash created when joining document_root and path 
    $parsed_url['localpath'] = preg_replace('/\/\//', '/', $parsed_url['localpath']); 

    if (!file_exists($parsed_url['localpath'])) { 
     die('File not found: ' . $parsed_url['localpath']); 
    } 
    $allowed_ext = array('ics','pdf', 'png', 'jpg', 'jpeg', 'zip', 'doc', 'xls', 'gif', 'exe', 'ppt'); 
    if (!in_array($parsed_url['extension'], $allowed_ext)) { 
     die('This file type is forbidden.'); 
    } 

    switch ($parsed_url['extension']) { 
     case "ics": $ctype="text/calendar"; 
      break; 
     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"); 
    header("Content-Disposition: attachment; filename=\"" . $parsed_url['filename'] . "\";"); 
    header("Content-Transfer-Encoding: binary"); 
    header("Content-Length: " . filesize($parsed_url['localpath'])); 
    readfile($parsed_url['localpath']); 
    clearstatcache(); 
    exit(); 

} 

답변

2

파일 다운로드 스크립트가 잘못된 Content-Length를 설정했을 수 있으므로 파일의 마지막 몇 바이트가 다음 요청으로 넘쳐 흐트러짐을 초래할 수 있습니다.

사용중인 웹 서버와 OS는 무엇이며 PHP는 어떻게 호출합니까? Windows라면 PHP 설치가 어떻게 든 이진 스트림 대신 텍스트로 stdout에 쓸 수 있다는 의혹이 생기기 때문입니다. 이것은 각각의 \ n 바이트가 \ r \ n 시퀀스로 변환 될 것이기 때문에 대부분의 바이너리 파일을 읽을 수 없도록 만들고 응답 본문을 Content-Length 헤더보다 약간 길게 만듭니다.

$ parsed_url [ 'localpath'] = LOCALROOT. $ parsed_url [ 'path'];

오히려 위험합니다. 나는 $ filename이 그것의 무엇이든을 시도하기 전에 그것의 생활의 인치 내에서 검사되고 유효하게했다는 것을 희망 할 것입니다. (파일 이름 유효성 검사는 현혹 적으로 어렵습니다.)

+0

웹 서버 + OS : 서버 : Apache/2.0.63 (Unix) mod_ssl/2.0.63 OpenSSL/0.9.8e-fips-rhel5 mod_auth_passthrough/2.1 mod_bwlimited/1.4 FrontPage/5.0.2.2635 PHP/5.2.8 X-Powered -By : PHP/5.2.8 두 번째 발언에 대해서는 이전에 file_exist()가 있는지 확인합니다. 충분하지 않아? – pixeline

+0

... filesize()를 호출하는 줄을 주석 처리하는 것으로 문제가 해결됩니다. 그게 될 수 있을까? – pixeline

+0

Content-Length를 생략하면 아파치가 길이를 자동으로 처리하게됩니다 (대개 청크 응답으로 출력을 래핑함으로써). 그러면 자동으로 길이가 올바르게됩니다. 문제는 \ n -> \ r \ n 문제가 아니라면 (왜 유닉스 서버를 사용한다면 그렇게 될 수 없다), 길이 헤더가 틀린 이유이다. 어떤 이유로 filesize()가 FALSE를 반환 할 수 있습니까? – bobince

-1

나는 모든 쓰레기가 무엇을 말할 수 있지만, die() 전화를 통해 파일을 전송 한 후, 그것을 피할 수 있습니다.

+0

나는 이미 그것을 가지고 있습니다, 불행히도. – pixeline