나는 7M (7 - 30M)보다 큰 파일을 읽으려면 file_get_contents()
을 사용합니다. 그런 다음 클라이언트가 다운로드 할 수 있도록 표시합니다.PHP : 왜 내가 16 메가 바이트 (16624 바이트)의 파일을 다운로드 할 수 있습니까?
참고 : 이러한 파일을 다운로드하기위한 직접적인 링크는 없습니다. 그래서 나는 그것을 PHP로 읽고 다운로드 파일을 만들어야한다. 큰 파일을 메모리로 읽어들이는 것은 잘못된 아이디어입니다. 가장 좋은 방법은 파일을 다운로드 링크로 만드는 것입니다. 그러나 지금은 아닙니다 ... 파일이 다른 사람들에 의해 만들어지고 파일을 우리의 클라우드 파일 서버로 옮길 계획이 없다는 것을 명심하십시오. --- PHP로 처리해야합니다.
뭔가가 있습니다. 내 개인 PHP7 도커 컨테이너에서 잘 작동합니다 (설정 파일은 https://github.com/AarioAi/Conf입니다)
전체 파일 (아마도 7.8M)을 다운로드 할 수 있습니다.
하지만이 코드를 거의 동일한 PHP와 Nginx 구성을 가진 다른 서버 (PHP 5.5)로 푸시하면됩니다. 이 파일은 16KB (16624B) 만 다운로드 할 수 있습니다.
여기에 7.8M 바이너리 파일에 대한 디버그 정보는 다음과 같습니다 위해
"HTTP_RANGE": null,
"Content-Length:": 7490833,
"md5": "aaefc8249e2a96574fa7b83e7bc168f0",
"fileSize": 7490833
는 16킬로바이트 세그먼트가 원본 파일의 일부인지 여부를 확인합니다. 반복되는 문자열 인 "Hello, Aario"가있는 16M 파일을 채 웁니다. 쉘 스크립트로. 그런 다음 PHP 5.5 서버에서 다운로드 한 16KB 세그먼트를 엽니 다. 그들은 모두 "Hello, Aario. 안녕하세요, Aario. ....."입니다.
따라서 16KB는 확실히 원본 파일의 세그먼트입니다.
"HTTP_RANGE": null,
"Content-type": "application/force-download",
"Content-Length:": 16155228,
"md5": "5c919dd9d1049a59e7c2a8cb55a695a9",
"fileSize": 16155228
내가 ob_xxx에 아무것도 전송하지, 그래서 나는 output_buffering
설정 아무 문제가 없다 생각한다. "안녕하세요, Aario"
다음은 16M에 대한 디버그 정보입니다. PHP memory_limit
구성은 두 서버에서 동일합니다. 그리고 php-fpm.conf 파일 사이에는 큰 차이가 없음을 알았습니다.
시간이 초과되었을 수 있습니다. Nginx keepalive_timeout
을 다른 서버 (PHP 5.5)에서 확인하십시오.이 서버 (PHP 7)보다 긴 65
입니다.
팁을 주실 수 있습니까?
//---------------------------------------------------------------------
$length = (function_exists('mb_strlen') ? mb_strlen($content, '8bit') : strlen($content));
// it's just the sample to calculate Content-Length, actually,
// it needs be handled in the if (isset($_SERVER['HTTP_RANGE'])) {}
//----------------------------------------------------------------------
if (isset($_SERVER['HTTP_RANGE'])) {
header('Accept-Ranges: bytes');
//client sent us a multibyte range, can not hold this one for now
if (strpos($_SERVER['HTTP_RANGE'], ',') !== false) {
header("Content-Range: bytes $contentStart-$contentEnd/$fileSize");
....
....
}
if ($debug > 0) {
return [
'Content-type' => $contentType,
'Content-Length:' => $length,
'md5' => md5_file($file),
'fileSize' => $fileSize,
];
} else {
header('Pragma: public');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header("Content-Type: $contentType");
header('Content-Length: ' . $length);
header("Content-Disposition: attachment; filename=\"$fileName\"");
header('Content-Transfer-Encoding: binary');
$content = function_exists('mb_substr') ? mb_substr($content, $contentStart, $length) : substr($content, $contentStart, $length);
ob_start();
ob_end_clean();
echo $content;
exit(0);
}
위한 ob_start() ... 당신은 그것을 구글 수 있습니다
출력에 파일을 스트리밍 할 수있는 더 좋은 방법이있다.그리고 클라이언트가 HTTP_RANGE를 전송하도록 허용하려고합니다. – AarioAi
내 요점은 :'ob_start();','ob_end_clean();'바로 뒤에 오는 것은 아무 것도하지 않는다. 당신은 그것을 떠날 수 있고 결과는 동일 할 것입니다. 'HTTP_RANGE'에 대해서 : 내 코드는 간단한 예제이며, 어쨌든 원하는대로 확장 할 수 있습니다. –
전에 fopen을 시도했지만,'echo $ content'와 같았습니다. 큰 파일을 메모리로 읽어들이는 것은 잘못된 아이디어입니다. 가장 좋은 방법은 파일을 다운로드 링크로 만드는 것입니다. 그러나 지금은 아닙니다 ... 파일이 다른 사람들에 의해 만들어지고 파일을 우리의 클라우드 파일 서버로 옮길 계획이 없다는 것을 명심하십시오. --- PHP로 처리해야합니다. 나는 fpassthru를 시도했다. PHP 5.5에서 7.8M까지만 16KB 만 다운로드 할 수있다. – AarioAi