Annotation of embedaddon/php/README.STREAMS, revision 1.1.1.2
1.1 misho 1: An Overview of the PHP Streams abstraction
2: ==========================================
1.1.1.2 ! misho 3: $Id$
1.1 misho 4:
5: WARNING: some prototypes in this file are out of date.
6: The information contained here is being integrated into
7: the PHP manual - stay tuned...
8:
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
15: special case sockets and files every time you need to work with a "user-level"
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
30: count);
31: PHPAPI size_t php_stream_printf(php_stream * stream TSRMLS_DC,
32: const char * fmt, ...);
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);
40: PHPAPI int php_stream_lock(php_stream * stream, int mode);
41:
42: These (should) behave in the same way as the ANSI stdio functions with similar
43: names: fread, fwrite, fprintf, feof, fgetc, fgets, fclose, fflush, fseek, ftell, flock.
44:
45: Opening Streams
46: ===============
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.
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.
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.
78:
79: PHPAPI php_stream *php_stream_fopen_tmpfile(void);
80: Open a FILE * with tmpfile() and convert into a stream.
81:
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.
127:
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:
144: NOTE: If you only need to seek forward, there is no need to call this
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:
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:
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:
174: if (php_stream_cast(stream, PHP_STREAM_AS_STDIO, (void*)&fp, REPORT_ERRORS) == FAILURE) {
175: RETURN_FALSE;
176: }
177:
178: The prototype is:
179:
180: PHPAPI int php_stream_cast(php_stream * stream, int castas, void ** ret, int
181: show_err);
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.
198:
199: In situations where this is not desirable, you should query the stream
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: }
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:
214: if (php_stream_can_cast(stream, PHP_STREAM_AS_SOCKETD) == SUCCESS) {
215: /* it can be a socket */
216: }
217:
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.
221: The former doesn't change anything, while the later *might* change some
222: state in the stream.
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
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.
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: {
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;
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,
269: size_t bufsize, int persistent, const char * mode)
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:
290: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
291: RULE #1: when writing your own streams: make sure you have configured PHP with
292: --enable-debug.
293: I've taken some great pains to hook into the Zend memory manager to help track
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.
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:
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
306: MySQL, you might want to store the connection and rowset handles.
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:
315: struct my_state {
316: MYSQL conn;
317: MYSQL_RES * result;
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:
336: For example, for reading from this weird MySQL stream:
337:
338: static size_t php_mysqlop_read(php_stream * stream, char * buf, size_t count)
339: {
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 */
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 = {
363: php_mysqlop_write, php_mysqlop_read, php_mysqlop_close,
364: php_mysqlop_flush, NULL, NULL, NULL,
365: "Strange MySQL example"
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:
379: vim:tw=78:et
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>