传输统计信息由 TransferStats 类提供,但是Guzzle documentation 没有描述统计信息的返回键和值。
阅读TransferStats cmets 提供了一些线索。
TransferStats 在三个类中创建:
CurlFactory
private static function invokeStats(EasyHandle $easy): void
{
$curlStats = \curl_getinfo($easy->handle);
$curlStats['appconnect_time'] = \curl_getinfo($easy->handle, \CURLINFO_APPCONNECT_TIME);
$stats = new TransferStats(
$easy->request,
$easy->response,
$curlStats['total_time'],
$easy->errno,
$curlStats
);
($easy->options['on_stats'])($stats);
}
MockHandler
private function invokeStats(
RequestInterface $request,
array $options,
ResponseInterface $response = null,
$reason = null
): void {
if (isset($options['on_stats'])) {
$transferTime = $options['transfer_time'] ?? 0;
$stats = new TransferStats($request, $response, $transferTime, $reason);
($options['on_stats'])($stats);
}
}
StreamHandler
private function invokeStats(
array $options,
RequestInterface $request,
?float $startTime,
ResponseInterface $response = null,
\Throwable $error = null
): void {
if (isset($options['on_stats'])) {
$stats = new TransferStats($request, $response, Utils::currentTime() - $startTime, $error, []);
($options['on_stats'])($stats);
}
}
Note 来自文档状态:
Guzzle 不再需要 cURL 来发送 HTTP 请求。
如果 cURL,Guzzle 将使用 PHP 流包装器发送 HTTP 请求
没有安装。或者,您可以提供自己的 HTTP 处理程序
用于发送请求。请记住,cURL 仍然是必需的
发送并发请求。
因此,您从 stats 收到的键和值很可能取决于 Guzzle 是否使用 cURL。您还可以在创建 TransferStats 的示例中看到它因不同的类(CurlFactory/MockHandler/StramHandler)而异。这可能是缺少统计信息文档的原因。
请注意,您可能从 stats 收到的键和值也取决于您使用的 cURL 版本,甚至是您使用的 PHP 版本。 PHP 的 curl_getinfo 的变更日志指出:
Version Description
7.3.0 Introduced CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, CURLINFO_CONTENT_LENGTH_UPLOAD_T (...)
所以低于 7.3.0 的 PHP 版本不应该有任何像 CURLINFO_CONTENT_LENGTH_DOWNLOAD_T 和许多其他的统计信息。
注意您可能会收到任何特定的键是个好主意,因此我始终建议将array_key_exists 与传输的状态数组一起使用。
假设 Guzzle 使用 cURL 进行请求,则统计信息由 PHP 的原生函数 curl_getinfo 获取,该函数描述了许多统计信息:
CURLINFO_EFFECTIVE_URL - Last effective URL
CURLINFO_HTTP_CODE - The last response code. As of PHP 5.5.0 and cURL 7.10.8, this is a legacy alias of CURLINFO_RESPONSE_CODE
(...)
和可能的数组键:
"url"
"content_type"
"http_code"
(...)
但是您可能会注意到 PHP 的预定义常量提供的排序描述不一致:
CURLINFO_HTTP_CODE - The last response code. As of PHP 5.5.0 and cURL 7.10.8, this is a legacy alias of CURLINFO_RESPONSE_CODE
和键列表:
"content_type"
CURLINFO_HTTP_CODE 在常量列表中排名第二,与返回键列表中的第二个键 content_type 不匹配。
此外,一些预定义的常量如:APPCONNECT_TIME_T 在返回的数组键列表中没有它们各自的名称。假设APPCONNECT_TIME_T 具有数组键appconnect_time_t 是错误的,因为它实际上是appconnect_time_us。
PHP 的curl_getinfo 文档不广泛也不一致。
要获取 PHP 的预定义常量和相应的数组键名,最好查看 PHP 7.4 source of ext/curl/interface.c 代码,您可能会在其中看到对本机 cURL 函数的调用:
if (curl_easy_getinfo(ch->cp, CURLINFO_HTTP_CODE, &l_code) == CURLE_OK) {
CAAL("http_code", l_code);
}
您可以轻松地将CURLINFO_HTTP_CODE(即curl_easy_getinfo 的第二个参数)与http_code(即CAAL 的第一个参数)匹配。
这样您就可以从最可靠的来源构建您自己的匹配列表,例如
[CURLINFO_HTTP_CODE => 'http_code', <PHPConstant> => <array-key>]
,因为来自 PHP 本身的来源。
因为 PHP 使用 cURL 的 curl_easy_getinfo 然后查看以下文档:
curl_easy_getinfo - 从 curl 中提取信息
将为您带来更多细节,特别有趣的是关于TIMES的这些:
An overview of the six time values available from curl_easy_getinfo()
curl_easy_perform()
|
|--NAMELOOKUP
|--|--CONNECT
|--|--|--APPCONNECT
|--|--|--|--PRETRANSFER
|--|--|--|--|--STARTTRANSFER
|--|--|--|--|--|--TOTAL
|--|--|--|--|--|--REDIRECT
例如:
CURLINFO_APPCONNECT_TIME_T
从开始到 SSL/SSH 握手完成的时间。看
CURLINFO_APPCONNECT_TIME_T
点击该链接,您可以获得更详细的解释:
(...) 这个时间通常非常接近
CURLINFO_PRETRANSFER_TIME_T时间,HTTP等情况除外
由于等待,预传输时间可能会延迟的流水线
管道线等。
当遵循重定向时,会添加每个请求的时间
一起。 (...)
我希望整个知识结合起来回答你的问题,并且你喜欢我揭示的整个挖掘过程,而不是在没有任何证据的情况下说 X 是 Y。
现在让我们玩得开心:)
运行此代码:
<?php
error_reporting(E_ALL);
header("Content-Type: text/plain");
$urlPhpSource = 'https://raw.githubusercontent.com/php/php-src/5caaf40b43303887a38d738a9c2a2f4cf6dc9b1a/ext/curl/interface.c';
$phpSourceArr = explode(\PHP_EOL, file_get_contents($urlPhpSource));
$option = '';
$optionNameArr = [];
foreach ($phpSourceArr as $line) {
$line = trim($line);
if (preg_match('/curl_easy_getinfo.+(CURLINFO_[A-Z_]+)/', $line, $matches)) {
$option = $matches[1];
}
if (!empty($option) && preg_match('/^CAA.+\"(.+)\"/', $line, $matches)) {
$optionNameArr[$option] = $matches[1];
$option = '';
}
}
$urlDescriptions = 'https://curl.se/libcurl/c/easy_getinfo_options.html';
$descriptionsArr = explode(\PHP_EOL, file_get_contents($urlDescriptions));
$descriptionResultArr = [];
foreach ($descriptionsArr as $line) {
$pattern = '/(CURLINFO_[A-Z_]+).*';
$pattern .= '<\/td><td>(.*)<\/td><\/tr>/';
if (preg_match($pattern, $line, $matches)) {
$descriptionResultArr[trim($matches[1])] = ucfirst(trim($matches[2]));
}
}
$resultCombinedArr = [];
foreach($optionNameArr as $option => $name) {
if (!key_exists($option, $descriptionResultArr)) {
$desciption = '<not found>';
} else {
$desciption = $descriptionResultArr[$option];
}
$tmpArr = [];
$tmpArr['name'] = $name;
$tmpArr['option'] = $option;
if (defined($option)) {
$tmpArr['optionValue'] = constant('\\' . $option);
}
$tmpArr['desciption'] = $desciption;
$resultCombinedArr[$name] = $tmpArr;
}
echo str_repeat("-", 80) . \PHP_EOL . \PHP_EOL;
echo "All Options:\n";
print_r($resultCombinedArr);
echo str_repeat("-", 80) . \PHP_EOL . \PHP_EOL;
echo "Available Options:\n";
print_r(array_filter($resultCombinedArr, function($data) {
return key_exists('optionValue', $data);
}));
echo str_repeat("-", 80) . \PHP_EOL . \PHP_EOL;
echo "Not available Options:\n";
print_r(array_filter($resultCombinedArr, function($data) {
return !key_exists('optionValue', $data);
}));
将给出所有可能的列表
- 预定义常量(选项)
- 选项的 int 值 (optionValue)
- 选项各自的数组键(名称)
- 选项的描述(描述)
这样:
All Options:
Array
(
[url] => Array
(
[name] => url
[option] => CURLINFO_EFFECTIVE_URL
[optionValue] => 1048577
[desciption] => Get the last used URL
)
[content_type] => Array
(
[name] => content_type
[option] => CURLINFO_CONTENT_TYPE
[optionValue] => 1048594
[desciption] => Get Content-Type
)
[http_code] => Array
(
[name] => http_code
[option] => CURLINFO_HTTP_CODE
[optionValue] => 2097154
[desciption] => <not found>
)
(...)
受您的 PHP 选项支持:
Available Options:
Array
(
[url] => Array
(
[name] => url
[option] => CURLINFO_EFFECTIVE_URL
[optionValue] => 1048577
[desciption] => Get the last used URL
)
[content_type] => Array
(
[name] => content_type
[option] => CURLINFO_CONTENT_TYPE
[optionValue] => 1048594
[desciption] => Get Content-Type
)
[http_code] => Array
(
[name] => http_code
[option] => CURLINFO_HTTP_CODE
[optionValue] => 2097154
[desciption] => <not found>
)
(...)
不支持:
Not available Options:
Array
(
[appconnect_time_us] => Array
(
[name] => appconnect_time_us
[option] => CURLINFO_APPCONNECT_TIME_T
[desciption] => Get the time until the SSL/SSH handshake is completed
)
[connect_time_us] => Array
(
[name] => connect_time_us
[option] => CURLINFO_CONNECT_TIME_T
[desciption] => Get the time until connect
)
[namelookup_time_us] => Array
(
[name] => namelookup_time_us
[option] => CURLINFO_NAMELOOKUP_TIME_T
[desciption] => Get the name lookup time in microseconds
)
(...)
请注意,如果未在 PHP 中定义像 CURLINFO_APPCONNECT_TIME_T 这样的预定义常量,则认为不支持选项 CURLINFO_APPCONNECT_TIME_T 但这并不一定意味着您将获得没有相应密钥 appconnect_time_us 或密钥的传输统计信息appconnect_time_us 会有一些未定义的值。
另一个奇怪的事情是我为 PHP 版本运行了这个 scipt:
PHP 7.3.27-9+ubuntu18.04.1+deb.sury.org+1 (cli)(构建时间:2021 年 2 月 23 日
15:10:08) (NTS)
我没有定义这些常量:
Array
(
[0] => CURLINFO_APPCONNECT_TIME_T
[1] => CURLINFO_CONNECT_TIME_T
[2] => CURLINFO_NAMELOOKUP_TIME_T
[3] => CURLINFO_PRETRANSFER_TIME_T
[4] => CURLINFO_REDIRECT_TIME_T
[5] => CURLINFO_STARTTRANSFER_TIME_T
[6] => CURLINFO_TOTAL_TIME_T
)
这与 curl_getinfo 文档中的声明互斥,该声明在 Changelog 部分下声明所有这些声明都应该已经在 PHP 7.3.0 及更高版本中引入。要么我做错了什么,要么curl_getinfo 的文档再次被证明是不准确的。
不过以我自己的官方形象为准
PHP 7.3.8 (cli)(构建时间:2019 年 8 月 2 日 05:16:32)(NTS)
Docker 镜像每个选项都可用。
这里是生成的参数的非官方文档,您可以复制并粘贴到您的项目中:
<?php
array (
'url' =>
array (
'name' => 'url',
'option' => 'CURLINFO_EFFECTIVE_URL',
'optionValue' => 1048577,
'desciption' => 'Get the last used URL',
),
'content_type' =>
array (
'name' => 'content_type',
'option' => 'CURLINFO_CONTENT_TYPE',
'optionValue' => 1048594,
'desciption' => 'Get Content-Type',
),
'http_code' =>
array (
'name' => 'http_code',
'option' => 'CURLINFO_HTTP_CODE',
'optionValue' => 2097154,
'desciption' => '<not found>',
),
'header_size' =>
array (
'name' => 'header_size',
'option' => 'CURLINFO_HEADER_SIZE',
'optionValue' => 2097163,
'desciption' => 'Get size of retrieved headers',
),
'request_size' =>
array (
'name' => 'request_size',
'option' => 'CURLINFO_REQUEST_SIZE',
'optionValue' => 2097164,
'desciption' => 'Get size of sent request',
),
'filetime' =>
array (
'name' => 'filetime',
'option' => 'CURLINFO_FILETIME',
'optionValue' => 2097166,
'desciption' => 'Get the remote time of the retrieved document',
),
'ssl_verify_result' =>
array (
'name' => 'ssl_verify_result',
'option' => 'CURLINFO_SSL_VERIFYRESULT',
'optionValue' => 2097165,
'desciption' => 'Get the result of the certificate verification',
),
'redirect_count' =>
array (
'name' => 'redirect_count',
'option' => 'CURLINFO_REDIRECT_COUNT',
'optionValue' => 2097172,
'desciption' => 'Get the number of redirects',
),
'total_time' =>
array (
'name' => 'total_time',
'option' => 'CURLINFO_TOTAL_TIME',
'optionValue' => 3145731,
'desciption' => 'Get total time of previous transfer',
),
'namelookup_time' =>
array (
'name' => 'namelookup_time',
'option' => 'CURLINFO_NAMELOOKUP_TIME',
'optionValue' => 3145732,
'desciption' => 'Get the name lookup time',
),
'connect_time' =>
array (
'name' => 'connect_time',
'option' => 'CURLINFO_CONNECT_TIME',
'optionValue' => 3145733,
'desciption' => 'Get the time until connect',
),
'pretransfer_time' =>
array (
'name' => 'pretransfer_time',
'option' => 'CURLINFO_PRETRANSFER_TIME',
'optionValue' => 3145734,
'desciption' => 'Get the time until the file transfer start',
),
'size_upload' =>
array (
'name' => 'size_upload',
'option' => 'CURLINFO_SIZE_UPLOAD',
'optionValue' => 3145735,
'desciption' => 'Get the number of uploaded bytes',
),
'size_download' =>
array (
'name' => 'size_download',
'option' => 'CURLINFO_SIZE_DOWNLOAD',
'optionValue' => 3145736,
'desciption' => 'Get the number of downloaded bytes',
),
'speed_download' =>
array (
'name' => 'speed_download',
'option' => 'CURLINFO_SPEED_DOWNLOAD',
'optionValue' => 3145737,
'desciption' => 'Get download speed',
),
'speed_upload' =>
array (
'name' => 'speed_upload',
'option' => 'CURLINFO_SPEED_UPLOAD',
'optionValue' => 3145738,
'desciption' => 'Get upload speed',
),
'download_content_length' =>
array (
'name' => 'download_content_length',
'option' => 'CURLINFO_CONTENT_LENGTH_DOWNLOAD',
'optionValue' => 3145743,
'desciption' => 'Get content-length of download',
),
'upload_content_length' =>
array (
'name' => 'upload_content_length',
'option' => 'CURLINFO_CONTENT_LENGTH_UPLOAD',
'optionValue' => 3145744,
'desciption' => 'Get the specified size of the upload',
),
'starttransfer_time' =>
array (
'name' => 'starttransfer_time',
'option' => 'CURLINFO_STARTTRANSFER_TIME',
'optionValue' => 3145745,
'desciption' => 'Get the time until the first byte is received',
),
'redirect_time' =>
array (
'name' => 'redirect_time',
'option' => 'CURLINFO_REDIRECT_TIME',
'optionValue' => 3145747,
'desciption' => 'Get the time for all redirection steps',
),
'redirect_url' =>
array (
'name' => 'redirect_url',
'option' => 'CURLINFO_REDIRECT_URL',
'optionValue' => 1048607,
'desciption' => 'Get the URL a redirect would go to',
),
'primary_ip' =>
array (
'name' => 'primary_ip',
'option' => 'CURLINFO_PRIMARY_IP',
'optionValue' => 1048608,
'desciption' => 'Get IP address of last connection',
),
'certinfo' =>
array (
'name' => 'certinfo',
'option' => 'CURLINFO_CERTINFO',
'optionValue' => 4194338,
'desciption' => 'Get the TLS certificate chain',
),
'primary_port' =>
array (
'name' => 'primary_port',
'option' => 'CURLINFO_PRIMARY_PORT',
'optionValue' => 2097192,
'desciption' => 'Get the latest destination port number',
),
'local_ip' =>
array (
'name' => 'local_ip',
'option' => 'CURLINFO_LOCAL_IP',
'optionValue' => 1048617,
'desciption' => 'Get local IP address of last connection',
),
'local_port' =>
array (
'name' => 'local_port',
'option' => 'CURLINFO_LOCAL_PORT',
'optionValue' => 2097194,
'desciption' => 'Get the latest local port number',
),
'http_version' =>
array (
'name' => 'http_version',
'option' => 'CURLINFO_HTTP_VERSION',
'optionValue' => 2097198,
'desciption' => 'Get the http version used in the connection',
),
'protocol' =>
array (
'name' => 'protocol',
'option' => 'CURLINFO_PROTOCOL',
'optionValue' => 2097200,
'desciption' => 'Get the protocol used in the connection',
),
'ssl_verifyresult' =>
array (
'name' => 'ssl_verifyresult',
'option' => 'CURLINFO_PROXY_SSL_VERIFYRESULT',
'optionValue' => 2097199,
'desciption' => 'Get the result of the proxy certificate verification',
),
'scheme' =>
array (
'name' => 'scheme',
'option' => 'CURLINFO_SCHEME',
'optionValue' => 1048625,
'desciption' => 'Get the URL scheme (sometimes called protocol) used in the connection',
),
'appconnect_time_us' =>
array (
'name' => 'appconnect_time_us',
'option' => 'CURLINFO_APPCONNECT_TIME_T',
'optionValue' => 6291512,
'desciption' => 'Get the time until the SSL/SSH handshake is completed',
),
'connect_time_us' =>
array (
'name' => 'connect_time_us',
'option' => 'CURLINFO_CONNECT_TIME_T',
'optionValue' => 6291508,
'desciption' => 'Get the time until connect',
),
'namelookup_time_us' =>
array (
'name' => 'namelookup_time_us',
'option' => 'CURLINFO_NAMELOOKUP_TIME_T',
'optionValue' => 6291507,
'desciption' => 'Get the name lookup time in microseconds',
),
'pretransfer_time_us' =>
array (
'name' => 'pretransfer_time_us',
'option' => 'CURLINFO_PRETRANSFER_TIME_T',
'optionValue' => 6291509,
'desciption' => 'Get the time until the file transfer start',
),
'redirect_time_us' =>
array (
'name' => 'redirect_time_us',
'option' => 'CURLINFO_REDIRECT_TIME_T',
'optionValue' => 6291511,
'desciption' => 'Get the time for all redirection steps',
),
'starttransfer_time_us' =>
array (
'name' => 'starttransfer_time_us',
'option' => 'CURLINFO_STARTTRANSFER_TIME_T',
'optionValue' => 6291510,
'desciption' => 'Get the time until the first byte is received',
),
'total_time_us' =>
array (
'name' => 'total_time_us',
'option' => 'CURLINFO_TOTAL_TIME_T',
'optionValue' => 6291506,
'desciption' => 'Get total time of previous transfer in microseconds',
),
)