开发者

How to detect stream_copy_to_stream errors?

I've got a bit of code which, simplified, looks something like:

$fout = fsockopen($host, 80);
stream_set_timeout($fout, 10*3600); // 10 hours
$fin = fopen($file, 'rb'); // not really a file stream, but good enough proxy here
$readbytes = stream_copy_to_stream($fin, $fout);
if(!$readbytes) die('copy failed');

However, I'm sometimes getting the following type of error:

Notice: stream_copy_to_stream(): send of 952 bytes failed with errno=104 Connection reset by peer in ...
Notice: stream_copy_to_stream(): send of 952 bytes failed with errno=32 Broken pipe in ...

And the check on $readbytes there won't pick up the error. I'm aware that it may be possible to check the total length of the file with the number of bytes copied, but this only works if the total length of the stream can be determined in advance.

As this happens randomly, I presume that the connection is just being dropped for some weird开发者_开发百科 reason (but if anyone has any suggestions to reduce the likeliness of this happening, I'm all ears). But it'd be nice to be able to know whether the transfer fully succeeded or not. Is there anyway to detect a problem without:

  • having to know the length of the stream in advance
  • hook into the PHP error handler to pick up the error

...or perhaps using a buffered fread/fwrite loop, checking the length of bytes written, the best solution here?

Thanks.


Okay, so here's my stream copy function, which tries to detect errors, but it seems to fail still (and I thought fwrite was meant to return the correct number of bytes)

function stream_copy($in, $out, $limit=null, $offset=null) {
    $bufsize = 32*1024;
    if(isset($offset)) fseek($in, $offset, SEEK_CUR);
    while(!feof($in)) {
        if(isset($limit)) {
            if(!$limit) break;
            $data = fread($in, min($limit,$bufsize));
        } else
            $data = fread($in, $bufsize);
        $datalen = strlen($data);
        $written = fwrite($out, $data);
        if($written != $datalen) {
            return false; // write failed
        }
        if(isset($limit)) $limit -= $datalen;
    }
    return true;
}

In above function, I'm still getting a 'true' returned even when an error is displayed.

So I'm just going to try hooking into PHP's error handler. Haven't tested the following, but my guess is that it should work

function stream_copy_to_stream_testerr($source, $dest) {
    $args = func_get_args();

    global $__stream_copy_to_stream_fine;
    $__stream_copy_to_stream_fine = true;

    set_error_handler('__stream_copy_to_stream_testerr');
    call_user_func_array('stream_copy_to_stream', $args);
    restore_error_handler();

    return $__stream_copy_to_stream_fine;
}
function __stream_copy_to_stream_testerr() {
    $GLOBALS['__stream_copy_to_stream_fine'] = false;
    return true;
}

Ugly, but the only solution I can see.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜