php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #76268 stream_get_contents fail to seek on streams modified by curl_exec
Submitted: 2018-04-25 14:35 UTC Modified: 2020-06-17 16:25 UTC
From: divinity76 at gmail dot com Assigned:
Status: Analyzed Package: cURL related
PHP Version: 7.1.16 OS: linux, debian 10 x64 k4.15.11-1
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: divinity76 at gmail dot com
New email:
PHP Version: OS:

 

 [2018-04-25 14:35 UTC] divinity76 at gmail dot com
Description:
------------
stream_get_contents fail to seek on streams exclusively modified by curl_exec, the optional third parameter of stream_get_contents is "Seek to the specified offset", and is effectively ignored when the stream has only been modified by curl_exec. 

my best guess is that libcurl calls fwrite directly, and doesn't update php's own stream->position, and stream_get_contents in turn doesn't call fseek if it's not necessary (presumably to save up on syscalls), and determines if it's necessary by checking stream->positioun instead of ftell (presumably to save up on syscalls), then it calls fread() until EOF, which is where libcurl left it, and thus returns an empty string.

Test script:
---------------
<?php
$ch = curl_init ( "http://gstatic.com/generate_204" );
$h = tmpfile ();
curl_setopt_array ( $ch, array (
		CURLOPT_VERBOSE => 1,
		CURLOPT_STDERR => $h 
) );
curl_exec ( $ch );
$verbose1 = stream_get_contents ( $h, - 1, 0 ); // empty string 
fseek ( $h, 0, SEEK_SET ); // a manual fseek fixes it
$verbose2 = stream_get_contents ( $h, - 1, 0 ); // the actual CURLOPT_VERBOSE log
var_dump ( $verbose1 === $verbose2 );


Expected result:
----------------
bool(true)

Actual result:
--------------
bool(false)

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2019-03-26 15:35 UTC] mike@php.net
-Status: Open +Status: Verified
 [2019-03-26 15:54 UTC] divinity76 at gmail dot com
for the record, i have several times written code like

$stderrh=tmpfile();
curl_setopt($ch,CURLOPT_STDERR,$stderrh);
curl_exec($ch);
rewind($stderrh); // https://bugs.php.net/bug.php?id=76268
$stderr=stream_get_contents($stderrh);
fclose($stderrh);

because of this bug. real examples: https://stackoverflow.com/questions/53128631/curl-php-cannot-display-amazon and https://stackoverflow.com/questions/50051940/very-long-loadtime-php-curl and https://github.com/divinity76/autoit_php/blob/master/src/autoit.class.php#L97 and http://qaru.site/questions/15745219/set-a-global-php-curl-upload-download-speed-limit
 [2019-03-26 16:25 UTC] mike@php.net
-Status: Verified +Status: Analyzed
 [2019-03-26 16:25 UTC] mike@php.net
stream->position is still zero when curl returns.

For all other streams this might be fixable by upgrading ext/curl to streams instead of stdio, looks like streams came a few years later.
 [2020-06-17 16:25 UTC] cmb@php.net
> stream->position is still zero when curl returns.

Yes, but at least after the stream has been flushed[1], the
file-position indicator has been moved, but the PHP stream doesn't
notice.  It appears that the stream layer does not have an API to
synchronize the position with the file-position indicator;
otherwise this bug could easily be fixed.

[1] <https://github.com/php/php-src/blob/php-7.3.18/ext/curl/interface.c#L3186>
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sun Nov 24 00:01:27 2024 UTC