phpscreenshothikvision

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


When accessing this URL in my PC browser, I see a screenshot from a stream recorded by my HikVision NVR

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

but when I try to access the same url from an php file executed by Apache server on a RaspberryPi board I have in the same network, get the 401 Unauthorized error, I tried 3 different ways of accessing the url, and none worked

<?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; 
?>

And the errors are those :

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

When accessing the URL in browser with correct password, the image shows correctly, the headers are as follows:

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

I also tried accessing the image directly from RaspberryPi command line, using wget command, the image saved correctly, so it must be something on the PHP side.

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]


Any help is appreciated.


Solution

  • Changing my comment to an answer:

    Did you actually try v3 by itself and not part of the combined script? You will definitely not get a file_get_contents error if you're using cURL, which makes me suspect cURL might actually be working (but possibly not returning the data you're expecting). Add a check to see if cURL's $data === false, and if so, check the output of curl_error($ch).

    One other thing I noticed is, based on the wget code, it looks like that succeeded using HTTP Digest auth (CURLAUTH_DIGEST), rather than Basic auth.

    So, overall, I'd recommend this as a next step:

    $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);