![]() ![]() | ![]() |
1.1 misho 1: --TEST--
2: User-space streams
3: --FILE--
4: <?php
5: # vim600:syn=php:
6:
7: /* This is a fairly aggressive test that looks at
8: * user streams and also gives the seek/gets/buffer
9: * layer of streams a thorough testing */
10:
11: $lyrics = <<<EOD
12: ...and the road becomes my bride
13: I have stripped of all but pride
14: so in her I do confide
15: and she keeps me satisfied
16: gives me all I need
17: ...and with dust in throat I crave
18: to the game you stay a slave
19: rover wanderer
20: nomad vagabond
21: call me what you will
22: But Ill take my time anywhere
23: Free to speak my mind anywhere
24: and Ill redefine anywhere
25: Anywhere I roam
26: Where I lay my head is home
27: ...and the earth becomes my throne
28: I adapt to the unknown
29: under wandering stars Ive grown
30: by myself but not alone
31: I ask no one
32: ...and my ties are severed clean
33: the less I have the more I gain
34: off the beaten path I reign
35: rover wanderer
36: nomad vagabond
37: call me what you will
38: But Ill take my time anywhere
39: Free to speak my mind anywhere
40: and Ill never mind anywhere
41: Anywhere I roam
42: Where I lay my head is home
43: But Ill take my time anywhere
44: Free to speak my mind anywhere
45: and Ill take my find anywhere
46: Anywhere I roam
47: Where I lay my head is home
48: carved upon my stone
49: my body lie but still I roam
50: Wherever I may roam.
51:
52: Wherever I May Roam
53:
54: EOD;
55:
56: /* repeat the data a few times so that it grows larger than
57: * the default cache chunk size and that we have something
58: * to seek around... */
59: $DATA = "";
60: for ($i = 0; $i < 30; $i++) {
61: if ($i % 2 == 0)
62: $DATA .= str_rot13($lyrics);
63: else
64: $DATA .= $lyrics;
65: }
66:
67: /* store the data in a regular file so that we can compare
68: * the results */
69: $tf = tmpfile();
70: fwrite($tf, (binary)$DATA);
71: $n = ftell($tf);
72: rewind($tf) or die("failed to rewind tmp file!");
73: if (ftell($tf) != 0)
74: die("tmpfile is not at start!");
75: $DATALEN = strlen($DATA);
76: if ($n != $DATALEN)
77: die("tmpfile stored $n bytes; should be $DATALEN!");
78:
79: class uselessstream
80: {
81: }
82:
83: class mystream
84: {
85: public $path;
86: public $mode;
87: public $options;
88:
89: public $position;
90: public $varname;
91:
92: function stream_open($path, $mode, $options, &$opened_path)
93: {
94: $this->path = $path;
95: $this->mode = $mode;
96: $this->options = $options;
97:
98: $split = parse_url($path);
99: $this->varname = $split["host"];
100:
101: if (strchr($mode, 'a'))
102: $this->position = strlen($GLOBALS[$this->varname]);
103: else
104: $this->position = 0;
105:
106: return true;
107: }
108:
109: function stream_read($count)
110: {
111: $ret = substr($GLOBALS[$this->varname], $this->position, $count);
112: $this->position += strlen($ret);
113: return $ret;
114: }
115:
116: function stream_tell()
117: {
118: return $this->position;
119: }
120:
121: function stream_eof()
122: {
123: return $this->position >= strlen($GLOBALS[$this->varname]);
124: }
125:
126: function stream_seek($offset, $whence)
127: {
128: switch($whence) {
129: case SEEK_SET:
130: if ($offset < strlen($GLOBALS[$this->varname]) && $offset >= 0) {
131: $this->position = $offset;
132: return true;
133: } else {
134: return false;
135: }
136: break;
137: case SEEK_CUR:
138: if ($offset >= 0) {
139: $this->position += $offset;
140: return true;
141: } else {
142: return false;
143: }
144: break;
145: case SEEK_END:
146: if (strlen($GLOBALS[$this->varname]) + $offset >= 0) {
147: $this->position = strlen($GLOBALS[$this->varname]) + $offset;
148: return true;
149: } else {
150: return false;
151: }
152: break;
153: default:
154: return false;
155: }
156: }
157:
158: }
159:
160: if (@stream_wrapper_register("bogus", "class_not_exist")) {
1.1.1.2 ! misho 161: die("Registered a non-existent class!!!???");
1.1 misho 162: }
163: echo "Not Registered\n";
164:
165: if (!stream_wrapper_register("test", "mystream")) {
166: die("test wrapper registration failed");
167: }
168: echo "Registered\n";
169:
170: if (!stream_wrapper_register("bogon", "uselessstream")) {
171: die("bogon wrapper registration failed");
172: }
173: echo "Registered\n";
174:
175: $b = @fopen("bogon://url", "rb");
176: if (is_resource($b)) {
177: die("Opened a bogon??");
178: }
179:
180: $fp = fopen("test://DATA", "rb");
181: if (!$fp || !is_resource($fp)) {
182: die("Failed to open resource");
183: }
184:
185: /* some default seeks that will cause buffer/cache misses */
186: $seeks = array(
187: array(SEEK_SET, 0, 0),
188: array(SEEK_CUR, 8450, 8450),
189: array(SEEK_CUR, -7904, 546),
190: array(SEEK_CUR, 12456, 13002),
191:
192: /* end up at BOF so that randomly generated seek offsets
193: * below will know where they are supposed to be */
194: array(SEEK_SET, 0, 0)
195: );
196:
197: $whence_map = array(
198: SEEK_CUR,
199: SEEK_SET,
200: SEEK_END
201: );
202: $whence_names = array(
203: SEEK_CUR => "SEEK_CUR",
204: SEEK_SET => "SEEK_SET",
205: SEEK_END => "SEEK_END"
206: );
207:
208: /* generate some random seek offsets */
209: $position = 0;
210: for ($i = 0; $i < 256; $i++) {
211: $whence = $whence_map[array_rand($whence_map, 1)];
212: switch($whence) {
213: case SEEK_SET:
214: $offset = rand(0, $DATALEN - 1);
215: $position = $offset;
216: break;
217: case SEEK_END:
218: $offset = -rand(0, $DATALEN - 1);
219: $position = $DATALEN + $offset;
220: break;
221: case SEEK_CUR:
222: $offset = rand(0, $DATALEN - 1);
223: $offset -= $position;
224: $position += $offset;
225: break;
226: }
227:
228: $seeks[] = array($whence, $offset, $position);
229: }
230:
231: /* we compare the results of fgets using differing line lengths to
232: * test the fgets layer also */
233: $line_lengths = array(1024, 256, 64, 16);
234: $fail_count = 0;
235:
236: ob_start();
237: foreach($line_lengths as $line_length) {
238: /* now compare the real stream with the user stream */
239: $j = 0;
240: rewind($tf);
241: rewind($fp);
242: foreach($seeks as $seekdata) {
243: list($whence, $offset, $position) = $seekdata;
244:
245: $rpb = ftell($tf);
246: $rr = (int)fseek($tf, $offset, $whence);
247: $rpa = ftell($tf);
248: $rline = fgets($tf, $line_length);
249: (int)fseek($tf, - strlen($rline), SEEK_CUR);
250:
251: $upb = ftell($fp);
252: $ur = (int)fseek($fp, $offset, $whence);
253: $upa = ftell($fp);
254: $uline = fgets($fp, $line_length);
255: (int)fseek($fp, - strlen($uline), SEEK_CUR);
256:
257: printf("\n--[%d] whence=%s offset=%d line_length=%d position_should_be=%d --\n",
258: $j, $whence_names[$whence], $offset, $line_length, $position);
259: printf("REAL: pos=(%d,%d,%d) ret=%d line[%d]=`%s'\n", $rpb, $rpa, ftell($tf), $rr, strlen($rline), $rline);
260: printf("USER: pos=(%d,%d,%d) ret=%d line[%d]=`%s'\n", $upb, $upa, ftell($fp), $ur, strlen($uline), $uline);
261:
262: if ($rr != $ur || $rline != $uline || $rpa != $position || $upa != $position) {
263: $fail_count++;
264: echo "###################################### FAIL!\n";
265: $dat = stream_get_meta_data($fp);
266: var_dump($dat);
267: break;
268: }
269:
270: $j++;
271: }
272: if ($fail_count)
273: break;
274: }
275:
276: if ($fail_count == 0) {
277: ob_end_clean();
278: echo "SEEK: OK\n";
279: } else {
280: echo "SEEK: FAIL\n";
281: ob_end_flush();
282: }
283:
284: $fail_count = 0;
285:
286: fseek($fp, $DATALEN / 2, SEEK_SET);
287: fseek($tf, $DATALEN / 2, SEEK_SET);
288:
289: if (ftell($fp) != ftell($tf)) {
290: echo "SEEK: positions do not match!\n";
291: }
292:
293: $n = 0;
294: while(!feof($fp)) {
295: $uline = fgets($fp, 1024);
296: $rline = fgets($tf, 1024);
297:
298: if ($uline != $rline) {
299: echo "FGETS: FAIL\niter=$n user=$uline [pos=" . ftell($fp) . "]\nreal=$rline [pos=" . ftell($tf) . "]\n";
300: $fail_count++;
301: break;
302: }
303: }
304:
305: if ($fail_count == 0) {
306: echo "FGETS: OK\n";
307: }
308:
309: /* One final test to see if the position is respected when opened for append */
310: $fp = fopen("test://lyrics", "a+");
311: rewind($fp);
312: var_dump(ftell($fp));
313: $data = fgets($fp);
314: fclose($fp);
315: echo $data . "\n";
316:
317: ?>
318: --EXPECT--
319: Not Registered
320: Registered
321: Registered
322: SEEK: OK
323: FGETS: OK
324: int(0)
325: ...and the road becomes my bride