README.STREAMS 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. An Overview of the PHP Streams abstraction
  2. ==========================================
  3. WARNING: some prototypes in this file are out of date.
  4. The information contained here is being integrated into
  5. the PHP manual - stay tuned...
  6. Please send comments to: Wez Furlong <wez@thebrainroom.com>
  7. Why Streams?
  8. ============
  9. You may have noticed a shed-load of issock parameters flying around the PHP
  10. code; we don't want them - they are ugly and cumbersome and force you to
  11. special case sockets and files every time you need to work with a "user-level"
  12. PHP file pointer.
  13. Streams take care of that and present the PHP extension coder with an ANSI
  14. stdio-alike API that looks much nicer and can be extended to support non file
  15. based data sources.
  16. Using Streams
  17. =============
  18. Streams use a php_stream* parameter just as ANSI stdio (fread etc.) use a
  19. FILE* parameter.
  20. The main functions are:
  21. PHPAPI size_t php_stream_read(php_stream * stream, char * buf, size_t count);
  22. PHPAPI size_t php_stream_write(php_stream * stream, const char * buf, size_t
  23. count);
  24. PHPAPI size_t php_stream_printf(php_stream * stream,
  25. const char * fmt, ...);
  26. PHPAPI int php_stream_eof(php_stream * stream);
  27. PHPAPI int php_stream_getc(php_stream * stream);
  28. PHPAPI char *php_stream_gets(php_stream * stream, char *buf, size_t maxlen);
  29. PHPAPI int php_stream_close(php_stream * stream);
  30. PHPAPI int php_stream_flush(php_stream * stream);
  31. PHPAPI int php_stream_seek(php_stream * stream, off_t offset, int whence);
  32. PHPAPI off_t php_stream_tell(php_stream * stream);
  33. PHPAPI int php_stream_lock(php_stream * stream, int mode);
  34. These (should) behave in the same way as the ANSI stdio functions with similar
  35. names: fread, fwrite, fprintf, feof, fgetc, fgets, fclose, fflush, fseek, ftell, flock.
  36. Opening Streams
  37. ===============
  38. In most cases, you should use this API:
  39. PHPAPI php_stream *php_stream_open_wrapper(const char *path, const char *mode,
  40. int options, char **opened_path);
  41. Where:
  42. path is the file or resource to open.
  43. mode is the stdio compatible mode eg: "wb", "rb" etc.
  44. options is a combination of the following values:
  45. IGNORE_PATH (default) - don't use include path to search for the file
  46. USE_PATH - use include path to search for the file
  47. IGNORE_URL - do not use plugin wrappers
  48. REPORT_ERRORS - show errors in a standard format if something
  49. goes wrong.
  50. STREAM_MUST_SEEK - If you really need to be able to seek the stream
  51. and don't need to be able to write to the original
  52. file/URL, use this option to arrange for the stream
  53. to be copied (if needed) into a stream that can
  54. be seek()ed.
  55. opened_path is used to return the path of the actual file opened,
  56. but if you used STREAM_MUST_SEEK, may not be valid. You are
  57. responsible for efree()ing opened_path. opened_path may be (and usually
  58. is) NULL.
  59. If you need to open a specific stream, or convert standard resources into
  60. streams there are a range of functions to do this defined in php_streams.h.
  61. A brief list of the most commonly used functions:
  62. PHPAPI php_stream *php_stream_fopen_from_file(FILE *file, const char *mode);
  63. Convert a FILE * into a stream.
  64. PHPAPI php_stream *php_stream_fopen_tmpfile(void);
  65. Open a FILE * with tmpfile() and convert into a stream.
  66. PHPAPI php_stream *php_stream_fopen_temporary_file(const char *dir,
  67. const char *pfx, char **opened_path);
  68. Generate a temporary file name and open it.
  69. There are some network enabled relatives in php_network.h:
  70. PHPAPI php_stream *php_stream_sock_open_from_socket(int socket, int persistent);
  71. Convert a socket into a stream.
  72. PHPAPI php_stream *php_stream_sock_open_host(const char *host, unsigned short port,
  73. int socktype, int timeout, int persistent);
  74. Open a connection to a host and return a stream.
  75. PHPAPI php_stream *php_stream_sock_open_unix(const char *path, int persistent,
  76. struct timeval *timeout);
  77. Open a UNIX domain socket.
  78. Stream Utilities
  79. ================
  80. If you need to copy some data from one stream to another, you will be please
  81. to know that the streams API provides a standard way to do this:
  82. PHPAPI size_t php_stream_copy_to_stream(php_stream *src,
  83. php_stream *dest, size_t maxlen);
  84. If you want to copy all remaining data from the src stream, pass
  85. PHP_STREAM_COPY_ALL as the maxlen parameter, otherwise maxlen indicates the
  86. number of bytes to copy.
  87. This function will try to use mmap where available to make the copying more
  88. efficient.
  89. If you want to read the contents of a stream into an allocated memory buffer,
  90. you should use:
  91. PHPAPI size_t php_stream_copy_to_mem(php_stream *src, char **buf,
  92. size_t maxlen, int persistent);
  93. This function will set buf to the address of the buffer that it allocated,
  94. which will be maxlen bytes in length, or will be the entire length of the
  95. data remaining on the stream if you set maxlen to PHP_STREAM_COPY_ALL.
  96. The buffer is allocated using pemalloc(); you need to call pefree() to
  97. release the memory when you are done.
  98. As with copy_to_stream, this function will try use mmap where it can.
  99. If you have an existing stream and need to be able to seek() it, you
  100. can use this function to copy the contents into a new stream that can
  101. be seek()ed:
  102. PHPAPI int php_stream_make_seekable(php_stream *origstream, php_stream **newstream);
  103. It returns one of the following values:
  104. #define PHP_STREAM_UNCHANGED 0 /* orig stream was seekable anyway */
  105. #define PHP_STREAM_RELEASED 1 /* newstream should be used; origstream is no longer valid */
  106. #define PHP_STREAM_FAILED 2 /* an error occurred while attempting conversion */
  107. #define PHP_STREAM_CRITICAL 3 /* an error occurred; origstream is in an unknown state; you should close origstream */
  108. make_seekable will always set newstream to be the stream that is valid
  109. if the function succeeds.
  110. When you have finished, remember to close the stream.
  111. NOTE: If you only need to seek forward, there is no need to call this
  112. function, as the php_stream_seek can emulate forward seeking when the
  113. whence parameter is SEEK_CUR.
  114. NOTE: Writing to the stream may not affect the original source, so it
  115. only makes sense to use this for read-only use.
  116. NOTE: If the origstream is network based, this function will block
  117. until the whole contents have been downloaded.
  118. NOTE: Never call this function with an origstream that is referenced
  119. as a resource! It will close the origstream on success, and this
  120. can lead to a crash when the resource is later used/released.
  121. NOTE: If you are opening a stream and need it to be seekable, use the
  122. STREAM_MUST_SEEK option to php_stream_open_wrapper();
  123. PHPAPI int php_stream_supports_lock(php_stream * stream);
  124. This function will return either 1 (success) or 0 (failure) indicating whether or
  125. not a lock can be set on this stream. Typically you can only set locks on stdio streams.
  126. Casting Streams
  127. ===============
  128. What if your extension needs to access the FILE* of a user level file pointer?
  129. You need to "cast" the stream into a FILE*, and this is how you do it:
  130. FILE * fp;
  131. php_stream * stream; /* already opened */
  132. if (php_stream_cast(stream, PHP_STREAM_AS_STDIO, (void*)&fp, REPORT_ERRORS) == FAILURE) {
  133. RETURN_FALSE;
  134. }
  135. The prototype is:
  136. PHPAPI int php_stream_cast(php_stream * stream, int castas, void ** ret, int
  137. show_err);
  138. The show_err parameter, if non-zero, will cause the function to display an
  139. appropriate error message of type E_WARNING if the cast fails.
  140. castas can be one of the following values:
  141. PHP_STREAM_AS_STDIO - a stdio FILE*
  142. PHP_STREAM_AS_FD - a generic file descriptor
  143. PHP_STREAM_AS_SOCKETD - a socket descriptor
  144. If you ask a socket stream for a FILE*, the abstraction will use fdopen to
  145. create it for you. Be warned that doing so may cause buffered data to be lost
  146. if you mix ANSI stdio calls on the FILE* with php stream calls on the stream.
  147. If your system has the fopencookie function, php streams can synthesize a
  148. FILE* on top of any stream, which is useful for SSL sockets, memory based
  149. streams, data base streams etc. etc.
  150. In situations where this is not desirable, you should query the stream
  151. to see if it naturally supports FILE *. You can use this code snippet
  152. for this purpose:
  153. if (php_stream_is(stream, PHP_STREAM_IS_STDIO)) {
  154. /* can safely cast to FILE* with no adverse side effects */
  155. }
  156. You can use:
  157. PHPAPI int php_stream_can_cast(php_stream * stream, int castas)
  158. to find out if a stream can be cast, without actually performing the cast, so
  159. to check if a stream is a socket you might use:
  160. if (php_stream_can_cast(stream, PHP_STREAM_AS_SOCKETD) == SUCCESS) {
  161. /* it can be a socket */
  162. }
  163. Please note the difference between php_stream_is and php_stream_can_cast;
  164. stream_is tells you if the stream is a particular type of stream, whereas
  165. can_cast tells you if the stream can be forced into the form you request.
  166. The former doesn't change anything, while the later *might* change some
  167. state in the stream.
  168. Stream Internals
  169. ================
  170. There are two main structures associated with a stream - the php_stream
  171. itself, which holds some state information (and possibly a buffer) and a
  172. php_stream_ops structure, which holds the "virtual method table" for the
  173. underlying implementation.
  174. The php_streams ops struct consists of pointers to methods that implement
  175. read, write, close, flush, seek, gets and cast operations. Of these, an
  176. implementation need only implement write, read, close and flush. The gets
  177. method is intended to be used for streams if there is an underlying method
  178. that can efficiently behave as fgets. The ops struct also contains a label
  179. for the implementation that will be used when printing error messages - the
  180. stdio implementation has a label of "STDIO" for example.
  181. The idea is that a stream implementation defines a php_stream_ops struct, and
  182. associates it with a php_stream using php_stream_alloc.
  183. As an example, the php_stream_fopen() function looks like this:
  184. PHPAPI php_stream * php_stream_fopen(const char * filename, const char * mode)
  185. {
  186. FILE * fp = fopen(filename, mode);
  187. php_stream * ret;
  188. if (fp) {
  189. ret = php_stream_alloc(&php_stream_stdio_ops, fp, 0, 0, mode);
  190. if (ret)
  191. return ret;
  192. fclose(fp);
  193. }
  194. return NULL;
  195. }
  196. php_stream_stdio_ops is a php_stream_ops structure that can be used to handle
  197. FILE* based streams.
  198. A socket based stream would use code similar to that above to create a stream
  199. to be passed back to fopen_wrapper (or it's yet to be implemented successor).
  200. The prototype for php_stream_alloc is this:
  201. PHPAPI php_stream * php_stream_alloc(php_stream_ops * ops, void * abstract,
  202. size_t bufsize, int persistent, const char * mode)
  203. ops is a pointer to the implementation,
  204. abstract holds implementation specific data that is relevant to this instance
  205. of the stream,
  206. bufsize is the size of the buffer to use - if 0, then buffering at the stream
  207. level will be disabled (recommended for underlying sources that implement
  208. their own buffering - such a FILE*),
  209. persistent controls how the memory is to be allocated - persistently so that
  210. it lasts across requests, or non-persistently so that it is freed at the end
  211. of a request (it uses pemalloc),
  212. mode is the stdio-like mode of operation - php streams places no real meaning
  213. in the mode parameter, except that it checks for a 'w' in the string when
  214. attempting to write (this may change).
  215. The mode parameter is passed on to fdopen/fopencookie when the stream is cast
  216. into a FILE*, so it should be compatible with the mode parameter of fopen().
  217. Writing your own stream implementation
  218. ======================================
  219. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  220. RULE #1: when writing your own streams: make sure you have configured PHP with
  221. --enable-debug.
  222. I've taken some great pains to hook into the Zend memory manager to help track
  223. down allocation problems. It will also help you spot incorrect use of the
  224. STREAMS_DC, STREAMS_CC and the semi-private STREAMS_REL_CC macros for function
  225. definitions.
  226. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  227. RULE #2: Please use the stdio stream as a reference; it will help you
  228. understand the semantics of the stream operations, and it will always
  229. be more up to date than these docs :-)
  230. First, you need to figure out what data you need to associate with the
  231. php_stream. For example, you might need a pointer to some memory for memory
  232. based streams, or if you were making a stream to read data from an RDBMS like
  233. MySQL, you might want to store the connection and rowset handles.
  234. The stream has a field called abstract that you can use to hold this data.
  235. If you need to store more than a single field of data, define a structure to
  236. hold it, allocate it (use pemalloc with the persistent flag set
  237. appropriately), and use the abstract pointer to refer to it.
  238. For structured state you might have this:
  239. struct my_state {
  240. MYSQL conn;
  241. MYSQL_RES * result;
  242. };
  243. struct my_state * state = pemalloc(sizeof(struct my_state), persistent);
  244. /* initialize the connection, and run a query, using the fields in state to
  245. * hold the results */
  246. state->result = mysql_use_result(&state->conn);
  247. /* now allocate the stream itself */
  248. stream = php_stream_alloc(&my_ops, state, 0, persistent, "r");
  249. /* now stream->abstract == state */
  250. Once you have that part figured out, you can write your implementation and
  251. define the your own php_stream_ops struct (we called it my_ops in the above
  252. example).
  253. For example, for reading from this weird MySQL stream:
  254. static size_t php_mysqlop_read(php_stream * stream, char * buf, size_t count)
  255. {
  256. struct my_state * state = (struct my_state*)stream->abstract;
  257. if (buf == NULL && count == 0) {
  258. /* in this special case, php_streams is asking if we have reached the
  259. * end of file */
  260. if (... at end of file ...)
  261. return EOF;
  262. else
  263. return 0;
  264. }
  265. /* pull out some data from the stream and put it in buf */
  266. ... mysql_fetch_row(state->result) ...
  267. /* we could do something strange, like format the data as XML here,
  268. and place that in the buf, but that brings in some complexities,
  269. such as coping with a buffer size too small to hold the data,
  270. so I won't even go in to how to do that here */
  271. }
  272. Implement the other operations - remember that write, read, close and flush
  273. are all mandatory. The rest are optional. Declare your stream ops struct:
  274. php_stream_ops my_ops = {
  275. php_mysqlop_write, php_mysqlop_read, php_mysqlop_close,
  276. php_mysqlop_flush, NULL, NULL, NULL,
  277. "Strange MySQL example"
  278. }
  279. Thats it!
  280. Take a look at the STDIO implementation in streams.c for more information
  281. about how these operations work.
  282. The main thing to remember is that in your close operation you need to release
  283. and free the resources you allocated for the abstract field. In the case of
  284. the example above, you need to use mysql_free_result on the rowset, close the
  285. connection and then use pefree to dispose of the struct you allocated.
  286. You may read the stream->persistent field to determine if your struct was
  287. allocated in persistent mode or not.
  288. vim:tw=78:et