2002-09-18 10:15:40 +00:00
|
|
|
--TEST--
|
|
|
|
User-space streams
|
|
|
|
--FILE--
|
|
|
|
<?php
|
|
|
|
# vim600:syn=php:
|
|
|
|
|
2002-10-29 14:36:49 +00:00
|
|
|
/* This is a fairly aggressive test that looks at
|
|
|
|
* user streams and also gives the seek/gets/buffer
|
|
|
|
* layer of streams a thorough testing */
|
2002-09-23 13:22:10 +00:00
|
|
|
|
|
|
|
$lyrics = <<<EOD
|
|
|
|
...and the road becomes my bride
|
|
|
|
I have stripped of all but pride
|
|
|
|
so in her I do confide
|
|
|
|
and she keeps me satisfied
|
|
|
|
gives me all I need
|
|
|
|
...and with dust in throat I crave
|
|
|
|
to the game you stay a slave
|
|
|
|
rover wanderer
|
|
|
|
nomad vagabond
|
|
|
|
call me what you will
|
|
|
|
But Ill take my time anywhere
|
|
|
|
Free to speak my mind anywhere
|
|
|
|
and Ill redefine anywhere
|
|
|
|
Anywhere I roam
|
|
|
|
Where I lay my head is home
|
|
|
|
...and the earth becomes my throne
|
|
|
|
I adapt to the unknown
|
|
|
|
under wandering stars Ive grown
|
|
|
|
by myself but not alone
|
|
|
|
I ask no one
|
|
|
|
...and my ties are severed clean
|
|
|
|
the less I have the more I gain
|
|
|
|
off the beaten path I reign
|
|
|
|
rover wanderer
|
|
|
|
nomad vagabond
|
|
|
|
call me what you will
|
|
|
|
But Ill take my time anywhere
|
|
|
|
Free to speak my mind anywhere
|
|
|
|
and Ill never mind anywhere
|
|
|
|
Anywhere I roam
|
|
|
|
Where I lay my head is home
|
|
|
|
But Ill take my time anywhere
|
|
|
|
Free to speak my mind anywhere
|
|
|
|
and Ill take my find anywhere
|
|
|
|
Anywhere I roam
|
|
|
|
Where I lay my head is home
|
|
|
|
carved upon my stone
|
|
|
|
my body lie but still I roam
|
|
|
|
Wherever I may roam.
|
|
|
|
|
|
|
|
Wherever I May Roam
|
|
|
|
|
|
|
|
EOD;
|
|
|
|
|
2002-10-29 14:36:49 +00:00
|
|
|
/* repeat the data a few times so that it grows larger than
|
|
|
|
* the default cache chunk size and that we have something
|
|
|
|
* to seek around... */
|
2002-09-23 13:22:10 +00:00
|
|
|
$DATA = "";
|
|
|
|
for ($i = 0; $i < 30; $i++) {
|
|
|
|
if ($i % 2 == 0)
|
|
|
|
$DATA .= str_rot13($lyrics);
|
|
|
|
else
|
|
|
|
$DATA .= $lyrics;
|
2002-09-18 10:15:40 +00:00
|
|
|
}
|
|
|
|
|
2002-10-29 14:36:49 +00:00
|
|
|
/* store the data in a regular file so that we can compare
|
|
|
|
* the results */
|
2002-09-23 13:22:10 +00:00
|
|
|
$tf = tmpfile();
|
2007-11-05 17:43:21 +00:00
|
|
|
fwrite($tf, (binary)$DATA);
|
2002-09-23 13:22:10 +00:00
|
|
|
$n = ftell($tf);
|
|
|
|
rewind($tf) or die("failed to rewind tmp file!");
|
|
|
|
if (ftell($tf) != 0)
|
|
|
|
die("tmpfile is not at start!");
|
|
|
|
$DATALEN = strlen($DATA);
|
|
|
|
if ($n != $DATALEN)
|
|
|
|
die("tmpfile stored $n bytes; should be $DATALEN!");
|
2002-09-18 10:15:40 +00:00
|
|
|
|
2002-10-29 14:05:55 +00:00
|
|
|
class uselessstream
|
|
|
|
{
|
2002-09-23 13:22:10 +00:00
|
|
|
}
|
2002-09-18 10:15:40 +00:00
|
|
|
|
2002-10-29 14:05:55 +00:00
|
|
|
class mystream
|
|
|
|
{
|
2003-11-30 13:57:20 +00:00
|
|
|
public $path;
|
|
|
|
public $mode;
|
|
|
|
public $options;
|
2002-09-18 10:15:40 +00:00
|
|
|
|
2003-11-30 13:57:20 +00:00
|
|
|
public $position;
|
|
|
|
public $varname;
|
2002-09-23 13:22:10 +00:00
|
|
|
|
2002-09-18 10:15:40 +00:00
|
|
|
function stream_open($path, $mode, $options, &$opened_path)
|
|
|
|
{
|
|
|
|
$this->path = $path;
|
|
|
|
$this->mode = $mode;
|
|
|
|
$this->options = $options;
|
2002-09-23 13:22:10 +00:00
|
|
|
|
|
|
|
$split = parse_url($path);
|
|
|
|
$this->varname = $split["host"];
|
2002-12-22 18:05:36 +00:00
|
|
|
|
|
|
|
if (strchr($mode, 'a'))
|
|
|
|
$this->position = strlen($GLOBALS[$this->varname]);
|
|
|
|
else
|
|
|
|
$this->position = 0;
|
2002-09-23 13:22:10 +00:00
|
|
|
|
2002-09-18 10:15:40 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2002-09-23 13:22:10 +00:00
|
|
|
function stream_read($count)
|
|
|
|
{
|
|
|
|
$ret = substr($GLOBALS[$this->varname], $this->position, $count);
|
|
|
|
$this->position += strlen($ret);
|
|
|
|
return $ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
function stream_tell()
|
|
|
|
{
|
|
|
|
return $this->position;
|
|
|
|
}
|
|
|
|
|
|
|
|
function stream_eof()
|
|
|
|
{
|
|
|
|
return $this->position >= strlen($GLOBALS[$this->varname]);
|
|
|
|
}
|
|
|
|
|
|
|
|
function stream_seek($offset, $whence)
|
|
|
|
{
|
|
|
|
switch($whence) {
|
|
|
|
case SEEK_SET:
|
|
|
|
if ($offset < strlen($GLOBALS[$this->varname]) && $offset >= 0) {
|
|
|
|
$this->position = $offset;
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SEEK_CUR:
|
|
|
|
if ($offset >= 0) {
|
|
|
|
$this->position += $offset;
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SEEK_END:
|
|
|
|
if (strlen($GLOBALS[$this->varname]) + $offset >= 0) {
|
|
|
|
$this->position = strlen($GLOBALS[$this->varname]) + $offset;
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-09-18 10:15:40 +00:00
|
|
|
}
|
|
|
|
|
2003-05-19 15:35:06 +00:00
|
|
|
if (@stream_wrapper_register("bogus", "class_not_exist")) {
|
2002-09-18 10:15:40 +00:00
|
|
|
die("Registered a non-existant class!!!???");
|
2002-10-29 14:05:55 +00:00
|
|
|
}
|
|
|
|
echo "Not Registered\n";
|
2002-09-18 10:15:40 +00:00
|
|
|
|
2003-05-19 15:35:06 +00:00
|
|
|
if (!stream_wrapper_register("test", "mystream")) {
|
2002-09-18 10:15:40 +00:00
|
|
|
die("test wrapper registration failed");
|
2002-10-29 14:05:55 +00:00
|
|
|
}
|
|
|
|
echo "Registered\n";
|
2002-09-18 10:15:40 +00:00
|
|
|
|
2003-05-19 15:35:06 +00:00
|
|
|
if (!stream_wrapper_register("bogon", "uselessstream")) {
|
2002-10-29 14:05:55 +00:00
|
|
|
die("bogon wrapper registration failed");
|
|
|
|
}
|
2002-09-18 10:15:40 +00:00
|
|
|
echo "Registered\n";
|
|
|
|
|
|
|
|
$b = @fopen("bogon://url", "rb");
|
2002-10-29 14:05:55 +00:00
|
|
|
if (is_resource($b)) {
|
2002-09-18 10:15:40 +00:00
|
|
|
die("Opened a bogon??");
|
2002-10-29 14:05:55 +00:00
|
|
|
}
|
2002-09-18 10:15:40 +00:00
|
|
|
|
2002-09-23 13:22:10 +00:00
|
|
|
$fp = fopen("test://DATA", "rb");
|
2002-10-29 14:05:55 +00:00
|
|
|
if (!$fp || !is_resource($fp)) {
|
2002-09-18 10:15:40 +00:00
|
|
|
die("Failed to open resource");
|
2002-10-29 14:05:55 +00:00
|
|
|
}
|
2002-09-18 10:15:40 +00:00
|
|
|
|
2002-10-29 14:36:49 +00:00
|
|
|
/* some default seeks that will cause buffer/cache misses */
|
2002-09-23 13:22:10 +00:00
|
|
|
$seeks = array(
|
|
|
|
array(SEEK_SET, 0, 0),
|
|
|
|
array(SEEK_CUR, 8450, 8450),
|
|
|
|
array(SEEK_CUR, -7904, 546),
|
|
|
|
array(SEEK_CUR, 12456, 13002),
|
|
|
|
|
2002-10-29 14:36:49 +00:00
|
|
|
/* end up at BOF so that randomly generated seek offsets
|
|
|
|
* below will know where they are supposed to be */
|
2002-09-23 13:22:10 +00:00
|
|
|
array(SEEK_SET, 0, 0)
|
|
|
|
);
|
|
|
|
|
|
|
|
$whence_map = array(
|
|
|
|
SEEK_CUR,
|
|
|
|
SEEK_SET,
|
|
|
|
SEEK_END
|
|
|
|
);
|
|
|
|
$whence_names = array(
|
|
|
|
SEEK_CUR => "SEEK_CUR",
|
|
|
|
SEEK_SET => "SEEK_SET",
|
|
|
|
SEEK_END => "SEEK_END"
|
|
|
|
);
|
|
|
|
|
2002-10-29 14:36:49 +00:00
|
|
|
/* generate some random seek offsets */
|
2002-09-23 13:22:10 +00:00
|
|
|
$position = 0;
|
|
|
|
for ($i = 0; $i < 256; $i++) {
|
|
|
|
$whence = $whence_map[array_rand($whence_map, 1)];
|
|
|
|
switch($whence) {
|
|
|
|
case SEEK_SET:
|
2006-03-20 22:09:11 +00:00
|
|
|
$offset = rand(0, $DATALEN - 1);
|
2002-09-23 13:22:10 +00:00
|
|
|
$position = $offset;
|
|
|
|
break;
|
|
|
|
case SEEK_END:
|
2006-03-20 22:09:11 +00:00
|
|
|
$offset = -rand(0, $DATALEN - 1);
|
2002-09-23 13:22:10 +00:00
|
|
|
$position = $DATALEN + $offset;
|
|
|
|
break;
|
|
|
|
case SEEK_CUR:
|
2006-03-20 22:09:11 +00:00
|
|
|
$offset = rand(0, $DATALEN - 1);
|
2002-09-23 13:22:10 +00:00
|
|
|
$offset -= $position;
|
|
|
|
$position += $offset;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
$seeks[] = array($whence, $offset, $position);
|
|
|
|
}
|
|
|
|
|
2002-10-29 14:36:49 +00:00
|
|
|
/* we compare the results of fgets using differing line lengths to
|
|
|
|
* test the fgets layer also */
|
2002-09-23 13:22:10 +00:00
|
|
|
$line_lengths = array(1024, 256, 64, 16);
|
|
|
|
$fail_count = 0;
|
|
|
|
|
|
|
|
ob_start();
|
|
|
|
foreach($line_lengths as $line_length) {
|
2002-10-29 14:36:49 +00:00
|
|
|
/* now compare the real stream with the user stream */
|
2002-09-23 13:22:10 +00:00
|
|
|
$j = 0;
|
|
|
|
rewind($tf);
|
|
|
|
rewind($fp);
|
|
|
|
foreach($seeks as $seekdata) {
|
|
|
|
list($whence, $offset, $position) = $seekdata;
|
|
|
|
|
|
|
|
$rpb = ftell($tf);
|
|
|
|
$rr = (int)fseek($tf, $offset, $whence);
|
|
|
|
$rpa = ftell($tf);
|
|
|
|
$rline = fgets($tf, $line_length);
|
|
|
|
(int)fseek($tf, - strlen($rline), SEEK_CUR);
|
|
|
|
|
|
|
|
$upb = ftell($fp);
|
|
|
|
$ur = (int)fseek($fp, $offset, $whence);
|
|
|
|
$upa = ftell($fp);
|
|
|
|
$uline = fgets($fp, $line_length);
|
|
|
|
(int)fseek($fp, - strlen($uline), SEEK_CUR);
|
|
|
|
|
|
|
|
printf("\n--[%d] whence=%s offset=%d line_length=%d position_should_be=%d --\n",
|
|
|
|
$j, $whence_names[$whence], $offset, $line_length, $position);
|
2002-10-05 10:35:13 +00:00
|
|
|
printf("REAL: pos=(%d,%d,%d) ret=%d line[%d]=`%s'\n", $rpb, $rpa, ftell($tf), $rr, strlen($rline), $rline);
|
|
|
|
printf("USER: pos=(%d,%d,%d) ret=%d line[%d]=`%s'\n", $upb, $upa, ftell($fp), $ur, strlen($uline), $uline);
|
2002-09-23 13:22:10 +00:00
|
|
|
|
|
|
|
if ($rr != $ur || $rline != $uline || $rpa != $position || $upa != $position) {
|
|
|
|
$fail_count++;
|
2002-10-05 10:35:13 +00:00
|
|
|
echo "###################################### FAIL!\n";
|
2002-09-28 22:14:21 +00:00
|
|
|
$dat = stream_get_meta_data($fp);
|
2002-09-23 13:22:10 +00:00
|
|
|
var_dump($dat);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
$j++;
|
|
|
|
}
|
|
|
|
if ($fail_count)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($fail_count == 0) {
|
|
|
|
ob_end_clean();
|
|
|
|
echo "SEEK: OK\n";
|
|
|
|
} else {
|
|
|
|
echo "SEEK: FAIL\n";
|
|
|
|
ob_end_flush();
|
|
|
|
}
|
|
|
|
|
|
|
|
$fail_count = 0;
|
2002-10-14 02:25:51 +00:00
|
|
|
|
2002-09-23 13:22:10 +00:00
|
|
|
fseek($fp, $DATALEN / 2, SEEK_SET);
|
|
|
|
fseek($tf, $DATALEN / 2, SEEK_SET);
|
|
|
|
|
2002-10-14 02:25:51 +00:00
|
|
|
if (ftell($fp) != ftell($tf)) {
|
|
|
|
echo "SEEK: positions do not match!\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
$n = 0;
|
2002-09-23 13:22:10 +00:00
|
|
|
while(!feof($fp)) {
|
|
|
|
$uline = fgets($fp, 1024);
|
2002-10-05 10:35:13 +00:00
|
|
|
$rline = fgets($tf, 1024);
|
2002-09-23 13:22:10 +00:00
|
|
|
|
|
|
|
if ($uline != $rline) {
|
2002-10-14 02:25:51 +00:00
|
|
|
echo "FGETS: FAIL\niter=$n user=$uline [pos=" . ftell($fp) . "]\nreal=$rline [pos=" . ftell($tf) . "]\n";
|
2002-09-23 13:22:10 +00:00
|
|
|
$fail_count++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-10-29 14:05:55 +00:00
|
|
|
if ($fail_count == 0) {
|
2002-09-23 13:22:10 +00:00
|
|
|
echo "FGETS: OK\n";
|
2002-10-29 14:05:55 +00:00
|
|
|
}
|
2002-12-22 18:05:36 +00:00
|
|
|
|
|
|
|
/* One final test to see if the position is respected when opened for append */
|
|
|
|
$fp = fopen("test://lyrics", "a+");
|
|
|
|
rewind($fp);
|
|
|
|
var_dump(ftell($fp));
|
|
|
|
$data = fgets($fp);
|
|
|
|
fclose($fp);
|
|
|
|
echo $data . "\n";
|
|
|
|
|
2002-09-18 10:15:40 +00:00
|
|
|
?>
|
|
|
|
--EXPECT--
|
2002-10-29 14:05:55 +00:00
|
|
|
Not Registered
|
|
|
|
Registered
|
2002-09-18 10:15:40 +00:00
|
|
|
Registered
|
2002-09-23 13:22:10 +00:00
|
|
|
SEEK: OK
|
|
|
|
FGETS: OK
|
2002-12-22 18:05:36 +00:00
|
|
|
int(0)
|
|
|
|
...and the road becomes my bride
|