Php 在通过HTTP加载数据之前确定文件大小

Php 在通过HTTP加载数据之前确定文件大小,php,http,curl,Php,Http,Curl,这可能吗?我目前正在使用cURL库用PHP编写代码,但这相当于整个HTTP 最明显的方法听起来像是向数据URL抛出HEAD请求并读取其内容长度头,但问题是,包括apache 2.0在内的一些服务器不针对HEAD请求发送内容长度,而且由于它不是强制性的,即使在GET请求时,也不能保证所有服务器都会回复此类信息 我让服务器下载用户输入指定的网页,并将其存储在服务器上,但我不想让它下载任何请求,结果发现文件太大,在下载所有内容后无法丢弃,从而阻塞恶意请求的带宽。 因此,我想在数据实际传输之前,可靠地了

这可能吗?我目前正在使用cURL库用PHP编写代码,但这相当于整个HTTP

最明显的方法听起来像是向数据URL抛出HEAD请求并读取其内容长度头,但问题是,包括apache 2.0在内的一些服务器不针对HEAD请求发送内容长度,而且由于它不是强制性的,即使在GET请求时,也不能保证所有服务器都会回复此类信息

我让服务器下载用户输入指定的网页,并将其存储在服务器上,但我不想让它下载任何请求,结果发现文件太大,在下载所有内容后无法丢弃,从而阻塞恶意请求的带宽。 因此,我想在数据实际传输之前,可靠地了解内容的大小

恶意web服务器发送错误内容长度的案例和那些小的奇怪情况与我无关,如果它适用于所有其他一般情况的话

到目前为止,我心目中最糟糕的想法是,实际上只需使用GET请求下载内容,如果连接超过传输过程中指定的大小限制,则只需断开连接,但在HTTP这样的通用协议上,这听起来像是一个非常丑陋的解决方案


有人有更好的想法吗?

没有,服务器不必告诉您他们将为您提供的资源的大小,因为他们自己可能不具备这些知识。因此,没有通用的方法,但是,是的,无论何时提供
内容长度
标题,您都可以尝试查找它。

我偶然发现了您的问题,正在寻找相同的答案。由于还没有真正的答案,我已经为自己设计了一个实现。当然,所有提到的注意事项仍然适用,是的,它确实使用了你的“丑陋”变体——但如果信息存在,这是实际获取数据的唯一方法

/**
 * Returns the size reported by the server, for the given URL, in bytes.
 *
 * Note this information may not be accurate, or may even be plain wrong.
 *
 * Also note, the return value is explicitly NOT converted to an integer, as
 * the remote file might be bigger than 2^31, which may mess up the number if
 * you are on a 32bit machine.
 *
 * @throws        InvalidArgumentException on unknown URL scheme
 * @throws        Exception when unable to connect
 * @param         string $url
 * @returns       int
 */
function getURLDownloadSize($url) {
    $parts = parse_url($url);

    if(isset($parts['port'])) {
        $port = $parts['port'];
    }
    else {
        $port = 80;
    }
    if($parts['scheme'] != 'http') {
        throw new \InvalidArgumentException('Scheme not supported');
    }

    $sock = fsockopen($parts['host'], $port, $errno, $errstr, 3);
    if(!$sock) {
        throw new \Exception(
            sprintf(
                'Unable to connect to host: %s',
                $errstr
            )
        );
    }
    stream_set_timeout($sock, 5);

    fwrite($sock, sprintf("GET %s HTTP/1.1\r\n", $parts['path']));
    fwrite($sock, sprintf("Host: %s\r\n",        $parts['host']));
    fwrite($sock,         "Connection: close\r\n"              );
    fwrite($sock,         "\r\n"                               );

    $data = fread($sock, 1024*20);
    fclose($sock);

    $matchresult = array();
    if (preg_match('/Content-Length:\s+(\d+)/', $data, $matchresult)) {
        return $matchresult[1];
    }
    return 0;
}

这不是一个可靠的方法。似乎一旦连接超过给定的大小,就切断连接是唯一的方法。是的,不是,这就是为什么每当它被提供的时候。事实上,是的,即使提供了它,它也可能只对估计有帮助,因为没有什么可以阻止服务器发布10字节的内容,并向客户端提供
/dev/uradom
的全部内容。