userstreams.phpt 7.0 KB

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