파일 을 다운로드하지 않고 http : //my_url/my_file.txt 원격 파일의 크기를 얻을 수있는 방법이 있습니까?
파일 을 다운로드하지 않고 http : //my_url/my_file.txt 원격 파일의 크기를 얻을 수있는 방법이 있습니까?
답변:
여기 에 대해 뭔가를 찾았습니다 .
원격 파일의 크기를 가져 오는 가장 좋은 방법은 다음과 같습니다. HEAD 요청은 요청의 실제 본문을 가져 오지 않고 헤더 만 검색합니다. 따라서 100MB의 리소스에 대한 HEAD 요청을 만드는 것은 1KB의 리소스에 대한 HEAD 요청과 동일한 시간이 걸립니다.
<?php
/**
* Returns the size of a file without downloading it, or -1 if the file
* size could not be determined.
*
* @param $url - The location of the remote file to download. Cannot
* be null or empty.
*
* @return The size of the file referenced by $url, or -1 if the size
* could not be determined.
*/
function curl_get_file_size( $url ) {
// Assume failure.
$result = -1;
$curl = curl_init( $url );
// Issue a HEAD request and follow any redirects.
curl_setopt( $curl, CURLOPT_NOBODY, true );
curl_setopt( $curl, CURLOPT_HEADER, true );
curl_setopt( $curl, CURLOPT_RETURNTRANSFER, true );
curl_setopt( $curl, CURLOPT_FOLLOWLOCATION, true );
curl_setopt( $curl, CURLOPT_USERAGENT, get_user_agent_string() );
$data = curl_exec( $curl );
curl_close( $curl );
if( $data ) {
$content_length = "unknown";
$status = "unknown";
if( preg_match( "/^HTTP\/1\.[01] (\d\d\d)/", $data, $matches ) ) {
$status = (int)$matches[1];
}
if( preg_match( "/Content-Length: (\d+)/", $data, $matches ) ) {
$content_length = (int)$matches[1];
}
// http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
if( $status == 200 || ($status > 300 && $status <= 308) ) {
$result = $content_length;
}
}
return $result;
}
?>
용법:
$file_size = curl_get_file_size( "http://stackoverflow.com/questions/2602612/php-remote-file-size-without-downloading-file" );
curl_getinfo
@macki가 제안한 것처럼 사용하는 것이 더 낫지 않습니까?
get_user_agent_string()
정의되지 않은 것처럼 나를 위해 작동하지 않았습니다 . 전체 라인을 제거하면 모든 것이 작동했습니다.
http://www.dailymotion.com/rss/user/dialhainaut/
SO : stackoverflow.com/questions/36761377/…
이 코드 시도
function retrieve_remote_file_size($url){
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_HEADER, TRUE);
curl_setopt($ch, CURLOPT_NOBODY, TRUE);
$data = curl_exec($ch);
$size = curl_getinfo($ch, CURLINFO_CONTENT_LENGTH_DOWNLOAD);
curl_close($ch);
return $size;
}
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
.
CURLOPT_FOLLOWLOCATION
사실로 설정했습니다.
몇 번 언급했듯이 이동 방법 은 응답 헤더의 Content-Length
필드 에서 정보를 검색하는 것 입니다 .
그러나
fopen
PHP가있는 경우 get_headers()
(기억 : KISS ) or alike를 사용하거나 심지어 curl 라이브러리를 호출 하기 위해 수동으로 HEAD 요청 (다시 말하지만 지원되지 않을 수도 있음)을 만들 필요가 없습니다 .의 사용은 get_headers()
다음 KISS 원칙 및 프로빙하고있는 서버가 HEAD 요청을 지원하지 않는 경우에도 작동합니다.
그래서, 여기 내 버전이 있습니다 (gimmick : 사람이 읽을 수있는 형식의 크기를 반환합니다 ;-)) :
요점 : https://gist.github.com/eyecatchup/f26300ffd7e50a92bc4d(curl 및 get_headers 버전)
get_headers ()-버전 :
<?php
/**
* Get the file size of any remote resource (using get_headers()),
* either in bytes or - default - as human-readable formatted string.
*
* @author Stephan Schmitz <eyecatchup@gmail.com>
* @license MIT <http://eyecatchup.mit-license.org/>
* @url <https://gist.github.com/eyecatchup/f26300ffd7e50a92bc4d>
*
* @param string $url Takes the remote object's URL.
* @param boolean $formatSize Whether to return size in bytes or formatted.
* @param boolean $useHead Whether to use HEAD requests. If false, uses GET.
* @return string Returns human-readable formatted size
* or size in bytes (default: formatted).
*/
function getRemoteFilesize($url, $formatSize = true, $useHead = true)
{
if (false !== $useHead) {
stream_context_set_default(array('http' => array('method' => 'HEAD')));
}
$head = array_change_key_case(get_headers($url, 1));
// content-length of download (in bytes), read from Content-Length: field
$clen = isset($head['content-length']) ? $head['content-length'] : 0;
// cannot retrieve file size, return "-1"
if (!$clen) {
return -1;
}
if (!$formatSize) {
return $clen; // return size in bytes
}
$size = $clen;
switch ($clen) {
case $clen < 1024:
$size = $clen .' B'; break;
case $clen < 1048576:
$size = round($clen / 1024, 2) .' KiB'; break;
case $clen < 1073741824:
$size = round($clen / 1048576, 2) . ' MiB'; break;
case $clen < 1099511627776:
$size = round($clen / 1073741824, 2) . ' GiB'; break;
}
return $size; // return formatted size
}
용법:
$url = 'http://download.tuxfamily.org/notepadplus/6.6.9/npp.6.6.9.Installer.exe';
echo getRemoteFilesize($url); // echoes "7.51 MiB"
추가 참고 사항 : Content-Length 헤더는 선택 사항입니다. 따라서 일반적인 솔루션으로 방탄이 아닙니다 !
Content-Length
선택 사항이지만, 그것을 다운로드하지 않고 파일 크기를 얻을 수있는 유일한 방법입니다 - 그리고 get_headers
얻을 수있는 가장 좋은 방법입니다 content-length
.
stream_context_create
에 대한 호출에 사용하는 별도의 컨텍스트를 만드는 get_headers
(7.1 이상).
PHP 함수는 get_headers()
수표의 나를 위해 작동 내용 길이를 로
$headers = get_headers('http://example.com/image.jpg', 1);
$filesize = $headers['Content-Length'];
자세한 내용은 PHP 함수 get_headers ()
잘 모르겠지만 get_headers 함수를 사용할 수 없습니까?
$url = 'http://example.com/dir/file.txt';
$headers = get_headers($url, true);
if ( isset($headers['Content-Length']) ) {
$size = 'file size:' . $headers['Content-Length'];
}
else {
$size = 'file size: unknown';
}
echo $size;
한 줄 최고의 솔루션 :
echo array_change_key_case(get_headers("http://.../file.txt",1))['content-length'];
PHP는 너무 섬세합니다
function urlsize($url):int{
return array_change_key_case(get_headers($url,1))['content-length'];
}
echo urlsize("http://.../file.txt");
가장 간단하고 효율적인 구현 :
function remote_filesize($url, $fallback_to_download = false)
{
static $regex = '/^Content-Length: *+\K\d++$/im';
if (!$fp = @fopen($url, 'rb')) {
return false;
}
if (isset($http_response_header) && preg_match($regex, implode("\n", $http_response_header), $matches)) {
return (int)$matches[0];
}
if (!$fallback_to_download) {
return false;
}
return strlen(stream_get_contents($fp));
}
Content-Length
헤더 가 포함 된 경우 . 그리고 명시적인 $fp
종료는 필요하지 않습니다. 만료시 자동으로 해제됩니다. php.net/manual/en/language.types.resource.php
nc -l localhost 8080
*close
최신 PHP 에서는 대부분의 기능이 필요하지 않습니다. 두 가지 역사적 이유, 즉 구현 제한과 C 언어 모방 때문입니다.
원격 파일 크기를 얻으려면 아래 기능을 시도하십시오.
function remote_file_size($url){
$head = "";
$url_p = parse_url($url);
$host = $url_p["host"];
if(!preg_match("/[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*/",$host)){
$ip=gethostbyname($host);
if(!preg_match("/[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*/",$ip)){
return -1;
}
}
if(isset($url_p["port"]))
$port = intval($url_p["port"]);
else
$port = 80;
if(!$port) $port=80;
$path = $url_p["path"];
$fp = fsockopen($host, $port, $errno, $errstr, 20);
if(!$fp) {
return false;
} else {
fputs($fp, "HEAD " . $url . " HTTP/1.1\r\n");
fputs($fp, "HOST: " . $host . "\r\n");
fputs($fp, "User-Agent: http://www.example.com/my_application\r\n");
fputs($fp, "Connection: close\r\n\r\n");
$headers = "";
while (!feof($fp)) {
$headers .= fgets ($fp, 128);
}
}
fclose ($fp);
$return = -2;
$arr_headers = explode("\n", $headers);
foreach($arr_headers as $header) {
$s1 = "HTTP/1.1";
$s2 = "Content-Length: ";
$s3 = "Location: ";
if(substr(strtolower ($header), 0, strlen($s1)) == strtolower($s1)) $status = substr($header, strlen($s1));
if(substr(strtolower ($header), 0, strlen($s2)) == strtolower($s2)) $size = substr($header, strlen($s2));
if(substr(strtolower ($header), 0, strlen($s3)) == strtolower($s3)) $newurl = substr($header, strlen($s3));
}
if(intval($size) > 0) {
$return=intval($size);
} else {
$return=$status;
}
if (intval($status)==302 && strlen($newurl) > 0) {
$return = remote_file_size($newurl);
}
return $return;
}
다음은 HEAD
요청을 지원하지 않는 서버에서 작동하는 또 다른 접근 방식입니다 .
cURL을 사용하여 파일의 첫 번째 바이트를 요청하는 HTTP 범위 헤더가있는 콘텐츠를 요청합니다.
서버가 범위 요청을 지원하는 경우 (대부분의 미디어 서버에서 지원) 리소스 크기에 대한 응답을받습니다.
서버가 바이트 범위로 응답하지 않으면 콘텐츠 길이 헤더를 찾아 길이를 결정합니다.
범위 또는 콘텐츠 길이 헤더에서 크기가 발견되면 전송이 중단됩니다. 크기를 찾을 수없고 함수가 응답 본문 읽기를 시작하면 전송이 중단됩니다.
HEAD
요청으로 인해 405
메서드가 지원되지 않는 응답이 발생하는 경우 이는 추가 접근 방식이 될 수 있습니다 .
/**
* Try to determine the size of a remote file by making an HTTP request for
* a byte range, or look for the content-length header in the response.
* The function aborts the transfer as soon as the size is found, or if no
* length headers are returned, it aborts the transfer.
*
* @return int|null null if size could not be determined, or length of content
*/
function getRemoteFileSize($url)
{
$ch = curl_init($url);
$headers = array(
'Range: bytes=0-1',
'Connection: close',
);
$in_headers = true;
$size = null;
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2450.0 Iron/46.0.2450.0');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_VERBOSE, 0); // set to 1 to debug
curl_setopt($ch, CURLOPT_STDERR, fopen('php://output', 'r'));
curl_setopt($ch, CURLOPT_HEADERFUNCTION, function($curl, $line) use (&$in_headers, &$size) {
$length = strlen($line);
if (trim($line) == '') {
$in_headers = false;
}
list($header, $content) = explode(':', $line, 2);
$header = strtolower(trim($header));
if ($header == 'content-range') {
// found a content-range header
list($rng, $s) = explode('/', $content, 2);
$size = (int)$s;
return 0; // aborts transfer
} else if ($header == 'content-length' && 206 != curl_getinfo($curl, CURLINFO_HTTP_CODE)) {
// found content-length header and this is not a 206 Partial Content response (range response)
$size = (int)$content;
return 0;
} else {
// continue
return $length;
}
});
curl_setopt($ch, CURLOPT_WRITEFUNCTION, function($curl, $data) use ($in_headers) {
if (!$in_headers) {
// shouldn't be here unless we couldn't determine file size
// abort transfer
return 0;
}
// write function is also called when reading headers
return strlen($data);
});
$result = curl_exec($ch);
$info = curl_getinfo($ch);
return $size;
}
용법:
$size = getRemoteFileSize('http://example.com/video.mp4');
if ($size === null) {
echo "Could not determine file size from headers.";
} else {
echo "File size is {$size} bytes.";
}
Content-Length
사용할 수없는 경우에도 .
여기에서 대부분의 답변은 CURL을 사용하거나 헤더 읽기를 기반으로합니다. 그러나 일부 특정 상황에서는 더 쉬운 솔루션을 사용할 수 있습니다. filesize()
PHP.net의 문서를 참고하십시오 . " PHP 5.0.0부터이 함수는 일부 URL 래퍼와 함께 사용할 수도 있습니다. stat () 기능 군을 지원하는 래퍼를 확인 하려면 지원되는 프로토콜 및 래퍼 를 참조하세요. "라는 팁 이 있습니다 .
따라서 서버와 PHP 파서가 올바르게 구성되어 있으면 filesize()
함수 를 사용 하고 전체 URL을 제공하고 원하는 크기의 원격 파일을 가리키고 PHP가 모든 마법을 수행하도록 할 수 있습니다.
이것을 시도하십시오 : 나는 그것을 사용하고 좋은 결과를 얻었습니다.
function getRemoteFilesize($url)
{
$file_headers = @get_headers($url, 1);
if($size =getSize($file_headers)){
return $size;
} elseif($file_headers[0] == "HTTP/1.1 302 Found"){
if (isset($file_headers["Location"])) {
$url = $file_headers["Location"][0];
if (strpos($url, "/_as/") !== false) {
$url = substr($url, 0, strpos($url, "/_as/"));
}
$file_headers = @get_headers($url, 1);
return getSize($file_headers);
}
}
return false;
}
function getSize($file_headers){
if (!$file_headers || $file_headers[0] == "HTTP/1.1 404 Not Found" || $file_headers[0] == "HTTP/1.0 404 Not Found") {
return false;
} elseif ($file_headers[0] == "HTTP/1.0 200 OK" || $file_headers[0] == "HTTP/1.1 200 OK") {
$clen=(isset($file_headers['Content-Length']))?$file_headers['Content-Length']:false;
$size = $clen;
if($clen) {
switch ($clen) {
case $clen < 1024:
$size = $clen . ' B';
break;
case $clen < 1048576:
$size = round($clen / 1024, 2) . ' KiB';
break;
case $clen < 1073741824:
$size = round($clen / 1048576, 2) . ' MiB';
break;
case $clen < 1099511627776:
$size = round($clen / 1073741824, 2) . ' GiB';
break;
}
}
return $size;
}
return false;
}
이제 다음과 같이 테스트하십시오.
echo getRemoteFilesize('http://mandasoy.com/wp-content/themes/spacious/images/plain.png').PHP_EOL;
echo getRemoteFilesize('http://bookfi.net/dl/201893/e96818').PHP_EOL;
echo getRemoteFilesize('/programming/14679268/downloading-files-as-attachment-filesize-incorrect').PHP_EOL;
결과 :
24.82KiB
912KiB
101.85 KiB
HTTP / 2 요청을 처리하려면 https://stackoverflow.com/a/2602624/2380767에 제공된 기능을 약간 변경해야합니다.
<?php
/**
* Returns the size of a file without downloading it, or -1 if the file
* size could not be determined.
*
* @param $url - The location of the remote file to download. Cannot
* be null or empty.
*
* @return The size of the file referenced by $url, or -1 if the size
* could not be determined.
*/
function curl_get_file_size( $url ) {
// Assume failure.
$result = -1;
$curl = curl_init( $url );
// Issue a HEAD request and follow any redirects.
curl_setopt( $curl, CURLOPT_NOBODY, true );
curl_setopt( $curl, CURLOPT_HEADER, true );
curl_setopt( $curl, CURLOPT_RETURNTRANSFER, true );
curl_setopt( $curl, CURLOPT_FOLLOWLOCATION, true );
curl_setopt( $curl, CURLOPT_USERAGENT, get_user_agent_string() );
$data = curl_exec( $curl );
curl_close( $curl );
if( $data ) {
$content_length = "unknown";
$status = "unknown";
if( preg_match( "/^HTTP\/1\.[01] (\d\d\d)/", $data, $matches ) ) {
$status = (int)$matches[1];
} elseif( preg_match( "/^HTTP\/2 (\d\d\d)/", $data, $matches ) ) {
$status = (int)$matches[1];
}
if( preg_match( "/Content-Length: (\d+)/", $data, $matches ) ) {
$content_length = (int)$matches[1];
} elseif( preg_match( "/content-length: (\d+)/", $data, $matches ) ) {
$content_length = (int)$matches[1];
}
// http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
if( $status == 200 || ($status > 300 && $status <= 308) ) {
$result = $content_length;
}
}
return $result;
}
?>