当在 php 代码中发出请求时,在 URL 中使用用户名和密码的 http 请求失败,但在任何浏览器中都有效

http request with user and password in URL fails when request is made in php code, but works in any browser

在我的 PC 浏览器中访问此 URL 时,我看到了我的 HikVision NVR 录制的流的屏幕截图

http://admin:441e3!@192.168.1.90/ISAPI/Streaming/channels/201/picture?videoResolutionWidth=1920&videoResolutionHeight=1080

但是当我尝试从 Apache 服务器在同一网络中的 RaspberryPi 板上执行的 php 文件访问相同的 url 时,出现 401 Unauthorized 错误,我尝试了 3访问 url 和 none 的不同方式有效

<?php

/* v1 */
$data = file_get_contents("http://admin:441e3!@192.168.1.90/ISAPI/Streaming/channels/201/picture?videoResolutionWidth=1920&videoResolutionHeight=1080");
header('Content-type: image/jpeg');
echo $data;

/* v2 */

$username = 'admin';
$password = '441e3!';
$url = 'http://192.168.1.90/ISAPI/Streaming/channels/201/picture?videoResolutionWidth=1920&videoResolutionHeight=1080';



$context = stream_context_create(array(
    'http' => array(
        'header'  => "Authorization: Basic " . base64_encode("$username:$password")
    )
));
$data = file_get_contents($url, false, $context);

header('Content-type: image/jpeg');
echo $data;

/* v3 */

$login = 'admin';
$password = '441e3!';

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_setopt($ch, CURLOPT_USERPWD, "$login:$password");
$data = curl_exec($ch);
curl_close($ch);

header('Content-type: image/jpeg');
echo $data; 
?>

错误是:

v1:

[Tue Nov 02 21:31:17.529527 2021] [:error] [pid 30366] [client 192.168.1.29:65434] PHP Warning:  file_get_contents(http://...@192.168.1.90/ISAPI/Streaming/channels/201/picture?videoResolutionWidth=1920&amp;videoResolutionHeight=1080): failed to open stream: HTTP request failed! HTTP/1.0 401 Unauthorized\r\n in /var/www/html/security                                                                   _cam3.php on line 30

v2 & v3 error:

[Tue Nov 02 21:55:07.643803 2021] [:error] [pid 26933] [client 192.168.1.29:60984] PHP Warning:  file_get_contents(http://192.168.1.90/ISAPI/Streaming/channels/201/picture?videoResolutionWidth=1920&amp;videoResolutionHeight=1080)     : failed to open stream: HTTP request failed! HTTP/1.0 401 Unauthorized\r\n in /var/www/html/security_cam3.php on line 24

用正确的密码在浏览器中访问URL时,图像正确显示,headers如下:

GENERAL

Request URL: http://admin:441e3!@192.168.1.90/ISAPI/Streaming/channels/201/picture?videoResolutionWidth=1920&videoResolutionHeight=1080
Request Method: GET
Status Code: 200 OK
Remote Address: 192.168.1.90:80
Referrer Policy: strict-origin-when-cross-origin

RESPONSE HEADERS

HTTP/1.1 200 OK
Connection: close
Pragma: no-cache
Cache-Control: no-cache
Content-Type: image/jpeg
Content-Length: 123814

REQUEST HEADERS

GET /ISAPI/Streaming/channels/201/picture?videoResolutionWidth=1920&videoResolutionHeight=1080 HTTP/1.1
Host: 192.168.1.90
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9

QUERY STRING PARAMETERS

videoResolutionWidth: 1920
videoResolutionHeight: 1080

我也试过直接从 RaspberryPi 命令行访问图像,使用 wget 命令,图像保存正确,所以它一定是 PHP 那边的东西。

root@bananapi:~# wget 'http://admin:441e3!-@192.168.1.90/ISAPI/Streaming/channels/201/picture?videoResolutionWidth=1920&videoResolutionHeight=1080'
--2021-11-02 22:57:50--  http://admin:*password*@192.168.1.90/ISAPI/Streaming/channels/201/picture?videoResolutionWidth=1920&videoResolutionHeight=1080
Connecting to 192.168.1.90:80... connected.
HTTP request sent, awaiting response... 401 Unauthorized
Authentication selected: Digest realm="da9ea0f8f352408658c64b0a", domain="::", qop="auth", nonce="e1f5166b2054a18a2a17595a4bbfaf23:1635894137125", opaque="", algorithm="MD5", stale="FALSE"
Reusing existing connection to 192.168.1.90:80.
HTTP request sent, awaiting response... 200 OK
Length: 125170 (122K) [image/jpeg]
Saving to: ‘picture?videoResolutionWidth=1920&videoResolutionHeight=1080’

picture?videoResolutionWidth=1920&videoResolutionHeight=10 100%[======================================================================================================================================>] 122.24K  --.-KB/s    in 0.003s

2021-11-02 22:57:50 (39.7 MB/s) - ‘picture?videoResolutionWidth=1920&videoResolutionHeight=1080’ saved [125170/125170]


感谢任何帮助。

将我的评论更改为答案:

您真的单独尝试过 v3 而不是组合脚本的一部分吗?如果您使用的是 cURL,您肯定 not 会收到 file_get_contents 错误,这让我怀疑 cURL 可能实际上正在工作(但可能不会返回您期望的数据) .添加检查以查看 cURL 是否为 $data === false,如果是,则检查 curl_error($ch).

的输出

我注意到的另一件事是,根据 wget 代码,看起来使用 HTTP 摘要身份验证 (CURLAUTH_DIGEST) 而不是基本身份验证成功。

所以,总的来说,我建议下一步这样做:

$login = 'admin';
$password = '441e3!';

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
curl_setopt($ch, CURLOPT_USERPWD, "$login:$password");
$data = curl_exec($ch);

if ($data === false) {
    echo 'ERROR: ' . curl_error($ch);
}
else {
    header('Content-type: image/jpeg');
    echo $data; 
}

curl_close($ch);