Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

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