stream_copy_to_stream() treats $offset of 0 as "current position"
Documentation does not mention that $offset of 0 keeps $from's position rather than copying from 0th offset.
<?php
$a = fopen('php://memory', 'r+');
$b = fopen('php://memory', 'r+');
fwrite($a, '0123456789');
fseek($a, 3);
stream_copy_to_stream($a, $b, 2, 0);
rewind($b);
echo stream_get_contents($b);
This code outputs 34 and not 01 as suggested by the documentation.
To me, this looks more like an implementation issue because $offset may depend on external factors such as user's input, and code most often doesn't expect the function's seeking behaviour to change if the input is zero or non-zero.
Related code (note the pos > 0 condition):
https://github.com/php/php-src/blob/11b612af6dbe9fdd60edb58d37e441c97bff79e0/ext/standard/streamsfuncs.c#L481-L509
PHP_FUNCTION(stream_copy_to_stream)
{
// ...
if (pos > 0 && php_stream_seek(src, pos, SEEK_SET) < 0) {
To me, this looks more like an implementation issue because
$offsetmay depend on external factors such as user's input, and code most often doesn't expect the function's seeking behaviour to change if the input is zero or non-zero.
I think it is "just" an unfortunate API design. The default value of $offset would have better been -1, and the respective condition pos >= 0. Given that it is implemented that way since the optional parameter has been introduced (PHP 5.1.0), I don't think we can change that now. So we're left with fixing the docs.