xref: /PHP-5.5/README.STREAMS (revision 6efd9ea5)
1e85f4fd5SWez FurlongAn Overview of the PHP Streams abstraction
2e85f4fd5SWez Furlong==========================================
3e85f4fd5SWez Furlong$Id$
4e85f4fd5SWez Furlong
55a21ab42SWez FurlongWARNING: some prototypes in this file are out of date.
65a21ab42SWez FurlongThe information contained here is being integrated into
767f80413SJon Parisethe PHP manual - stay tuned...
85a21ab42SWez Furlong
9e85f4fd5SWez FurlongPlease send comments to: Wez Furlong <wez@thebrainroom.com>
10e85f4fd5SWez Furlong
11e85f4fd5SWez FurlongWhy Streams?
12e85f4fd5SWez Furlong============
13e85f4fd5SWez FurlongYou may have noticed a shed-load of issock parameters flying around the PHP
14e85f4fd5SWez Furlongcode; we don't want them - they are ugly and cumbersome and force you to
1567f80413SJon Parisespecial case sockets and files every time you need to work with a "user-level"
16e85f4fd5SWez FurlongPHP file pointer.
17e85f4fd5SWez FurlongStreams take care of that and present the PHP extension coder with an ANSI
18e85f4fd5SWez Furlongstdio-alike API that looks much nicer and can be extended to support non file
19e85f4fd5SWez Furlongbased data sources.
20e85f4fd5SWez Furlong
21e85f4fd5SWez FurlongUsing Streams
22e85f4fd5SWez Furlong=============
23e85f4fd5SWez FurlongStreams use a php_stream* parameter just as ANSI stdio (fread etc.) use a
24e85f4fd5SWez FurlongFILE* parameter.
25e85f4fd5SWez Furlong
26e85f4fd5SWez FurlongThe main functions are:
27e85f4fd5SWez Furlong
28e85f4fd5SWez FurlongPHPAPI size_t php_stream_read(php_stream * stream, char * buf, size_t count);
29e85f4fd5SWez FurlongPHPAPI size_t php_stream_write(php_stream * stream, const char * buf, size_t
3030647934SWez Furlong        count);
318135094bSMarcus BoergerPHPAPI size_t php_stream_printf(php_stream * stream TSRMLS_DC,
328135094bSMarcus Boerger        const char * fmt, ...);
33e85f4fd5SWez FurlongPHPAPI int php_stream_eof(php_stream * stream);
34e85f4fd5SWez FurlongPHPAPI int php_stream_getc(php_stream * stream);
35e85f4fd5SWez FurlongPHPAPI char *php_stream_gets(php_stream * stream, char *buf, size_t maxlen);
36e85f4fd5SWez FurlongPHPAPI int php_stream_close(php_stream * stream);
37e85f4fd5SWez FurlongPHPAPI int php_stream_flush(php_stream * stream);
38e85f4fd5SWez FurlongPHPAPI int php_stream_seek(php_stream * stream, off_t offset, int whence);
39e85f4fd5SWez FurlongPHPAPI off_t php_stream_tell(php_stream * stream);
40*6efd9ea5SIlia AlshanetskyPHPAPI int php_stream_lock(php_stream * stream, int mode);
41e85f4fd5SWez Furlong
42e85f4fd5SWez FurlongThese (should) behave in the same way as the ANSI stdio functions with similar
43*6efd9ea5SIlia Alshanetskynames: fread, fwrite, fprintf, feof, fgetc, fgets, fclose, fflush, fseek, ftell, flock.
44e85f4fd5SWez Furlong
45e85f4fd5SWez FurlongOpening Streams
46e85f4fd5SWez Furlong===============
4730647934SWez FurlongIn most cases, you should use this API:
4830647934SWez Furlong
4930647934SWez FurlongPHPAPI php_stream *php_stream_open_wrapper(char *path, char *mode,
5030647934SWez Furlong    int options, char **opened_path TSRMLS_DC);
5130647934SWez Furlong
5230647934SWez FurlongWhere:
5330647934SWez Furlong    path is the file or resource to open.
5430647934SWez Furlong    mode is the stdio compatible mode eg: "wb", "rb" etc.
5530647934SWez Furlong    options is a combination of the following values:
5630647934SWez Furlong        IGNORE_PATH  (default) - don't use include path to search for the file
5730647934SWez Furlong        USE_PATH        - use include path to search for the file
5830647934SWez Furlong        IGNORE_URL      - do not use plugin wrappers
5930647934SWez Furlong        REPORT_ERRORS   - show errors in a standard format if something
6030647934SWez Furlong                          goes wrong.
6112a00923SWez Furlong        STREAM_MUST_SEEK - If you really need to be able to seek the stream
6212a00923SWez Furlong                           and don't need to be able to write to the original
6312a00923SWez Furlong                           file/URL, use this option to arrange for the stream
6412a00923SWez Furlong                           to be copied (if needed) into a stream that can
6512a00923SWez Furlong                           be seek()ed.
6612a00923SWez Furlong
6712a00923SWez Furlong    opened_path is used to return the path of the actual file opened,
6812a00923SWez Furlong    but if you used STREAM_MUST_SEEK, may not be valid.  You are
6912a00923SWez Furlong    responsible for efree()ing opened_path.  opened_path may be (and usually
7012a00923SWez Furlong    is) NULL.
7130647934SWez Furlong
7230647934SWez FurlongIf you need to open a specific stream, or convert standard resources into
7330647934SWez Furlongstreams there are a range of functions to do this defined in php_streams.h.
7430647934SWez FurlongA brief list of the most commonly used functions:
7530647934SWez Furlong
7630647934SWez FurlongPHPAPI php_stream *php_stream_fopen_from_file(FILE *file, const char *mode);
7730647934SWez Furlong    Convert a FILE * into a stream.
78e85f4fd5SWez Furlong
7930647934SWez FurlongPHPAPI php_stream *php_stream_fopen_tmpfile(void);
8030647934SWez Furlong    Open a FILE * with tmpfile() and convert into a stream.
81e85f4fd5SWez Furlong
8230647934SWez FurlongPHPAPI php_stream *php_stream_fopen_temporary_file(const char *dir,
8330647934SWez Furlong    const char *pfx, char **opened_path TSRMLS_DC);
8430647934SWez Furlong    Generate a temporary file name and open it.
8530647934SWez Furlong
8630647934SWez FurlongThere are some network enabled relatives in php_network.h:
8730647934SWez Furlong
8830647934SWez FurlongPHPAPI php_stream *php_stream_sock_open_from_socket(int socket, int persistent);
8930647934SWez Furlong    Convert a socket into a stream.
9030647934SWez Furlong
9130647934SWez FurlongPHPAPI php_stream *php_stream_sock_open_host(const char *host, unsigned short port,
9230647934SWez Furlong		int socktype, int timeout, int persistent);
9330647934SWez Furlong    Open a connection to a host and return a stream.
9430647934SWez Furlong
9530647934SWez FurlongPHPAPI php_stream *php_stream_sock_open_unix(const char *path, int persistent,
9630647934SWez Furlong    struct timeval *timeout);
9730647934SWez Furlong    Open a UNIX domain socket.
9830647934SWez Furlong
9930647934SWez Furlong
10030647934SWez FurlongStream Utilities
10130647934SWez Furlong================
10230647934SWez Furlong
10330647934SWez FurlongIf you need to copy some data from one stream to another, you will be please
10430647934SWez Furlongto know that the streams API provides a standard way to do this:
10530647934SWez Furlong
10630647934SWez FurlongPHPAPI size_t php_stream_copy_to_stream(php_stream *src,
10730647934SWez Furlong    php_stream *dest, size_t maxlen);
10830647934SWez Furlong
10930647934SWez FurlongIf you want to copy all remaining data from the src stream, pass
11030647934SWez FurlongPHP_STREAM_COPY_ALL as the maxlen parameter, otherwise maxlen indicates the
11130647934SWez Furlongnumber of bytes to copy.
11230647934SWez FurlongThis function will try to use mmap where available to make the copying more
11330647934SWez Furlongefficient.
11430647934SWez Furlong
11530647934SWez FurlongIf you want to read the contents of a stream into an allocated memory buffer,
11630647934SWez Furlongyou should use:
11730647934SWez Furlong
11830647934SWez FurlongPHPAPI size_t php_stream_copy_to_mem(php_stream *src, char **buf,
11930647934SWez Furlong    size_t maxlen, int persistent);
12030647934SWez Furlong
12130647934SWez FurlongThis function will set buf to the address of the buffer that it allocated,
12230647934SWez Furlongwhich will be maxlen bytes in length, or will be the entire length of the
12330647934SWez Furlongdata remaining on the stream if you set maxlen to PHP_STREAM_COPY_ALL.
12430647934SWez FurlongThe buffer is allocated using pemalloc(); you need to call pefree() to
12530647934SWez Furlongrelease the memory when you are done.
12630647934SWez FurlongAs with copy_to_stream, this function will try use mmap where it can.
127e85f4fd5SWez Furlong
12812a00923SWez FurlongIf you have an existing stream and need to be able to seek() it, you
12912a00923SWez Furlongcan use this function to copy the contents into a new stream that can
13012a00923SWez Furlongbe seek()ed:
13112a00923SWez Furlong
13212a00923SWez FurlongPHPAPI int php_stream_make_seekable(php_stream *origstream, php_stream **newstream);
13312a00923SWez Furlong
13412a00923SWez FurlongIt returns one of the following values:
13512a00923SWez Furlong#define PHP_STREAM_UNCHANGED	0 /* orig stream was seekable anyway */
13612a00923SWez Furlong#define PHP_STREAM_RELEASED		1 /* newstream should be used; origstream is no longer valid */
13712a00923SWez Furlong#define PHP_STREAM_FAILED		2 /* an error occurred while attempting conversion */
13812a00923SWez Furlong#define PHP_STREAM_CRITICAL		3 /* an error occurred; origstream is in an unknown state; you should close origstream */
13912a00923SWez Furlong
14012a00923SWez Furlongmake_seekable will always set newstream to be the stream that is valid
14112a00923SWez Furlongif the function succeeds.
14212a00923SWez FurlongWhen you have finished, remember to close the stream.
14312a00923SWez Furlong
14467f80413SJon PariseNOTE: If you only need to seek forward, there is no need to call this
14512a00923SWez Furlongfunction, as the php_stream_seek can emulate forward seeking when the
14612a00923SWez Furlongwhence parameter is SEEK_CUR.
14712a00923SWez Furlong
14812a00923SWez FurlongNOTE: Writing to the stream may not affect the original source, so it
14912a00923SWez Furlongonly makes sense to use this for read-only use.
15012a00923SWez Furlong
15112a00923SWez FurlongNOTE: If the origstream is network based, this function will block
15212a00923SWez Furlonguntil the whole contents have been downloaded.
15312a00923SWez Furlong
15412a00923SWez FurlongNOTE: Never call this function with an origstream that is referenced
15512a00923SWez Furlongas a resource! It will close the origstream on success, and this
15612a00923SWez Furlongcan lead to a crash when the resource is later used/released.
15712a00923SWez Furlong
15812a00923SWez FurlongNOTE: If you are opening a stream and need it to be seekable, use the
15912a00923SWez FurlongSTREAM_MUST_SEEK option to php_stream_open_wrapper();
16012a00923SWez Furlong
161*6efd9ea5SIlia AlshanetskyPHPAPI int php_stream_supports_lock(php_stream * stream);
162*6efd9ea5SIlia Alshanetsky
163*6efd9ea5SIlia AlshanetskyThis function will return either 1 (success) or 0 (failure) indicating whether or
164*6efd9ea5SIlia Alshanetskynot a lock can be set on this stream. Typically you can only set locks on stdio streams.
165*6efd9ea5SIlia Alshanetsky
166e85f4fd5SWez FurlongCasting Streams
167e85f4fd5SWez Furlong===============
168e85f4fd5SWez FurlongWhat if your extension needs to access the FILE* of a user level file pointer?
169e85f4fd5SWez FurlongYou need to "cast" the stream into a FILE*, and this is how you do it:
170e85f4fd5SWez Furlong
171e85f4fd5SWez FurlongFILE * fp;
172e85f4fd5SWez Furlongphp_stream * stream; /* already opened */
173e85f4fd5SWez Furlong
17430647934SWez Furlongif (php_stream_cast(stream, PHP_STREAM_AS_STDIO, (void*)&fp, REPORT_ERRORS) == FAILURE)    {
17530647934SWez Furlong    RETURN_FALSE;
176e85f4fd5SWez Furlong}
177e85f4fd5SWez Furlong
178e85f4fd5SWez FurlongThe prototype is:
179e85f4fd5SWez Furlong
180e85f4fd5SWez FurlongPHPAPI int php_stream_cast(php_stream * stream, int castas, void ** ret, int
18130647934SWez Furlong        show_err);
182e85f4fd5SWez Furlong
183e85f4fd5SWez FurlongThe show_err parameter, if non-zero, will cause the function to display an
184e85f4fd5SWez Furlongappropriate error message of type E_WARNING if the cast fails.
185e85f4fd5SWez Furlong
186e85f4fd5SWez Furlongcastas can be one of the following values:
187e85f4fd5SWez FurlongPHP_STREAM_AS_STDIO - a stdio FILE*
188e85f4fd5SWez FurlongPHP_STREAM_AS_FD - a generic file descriptor
189e85f4fd5SWez FurlongPHP_STREAM_AS_SOCKETD - a socket descriptor
190e85f4fd5SWez Furlong
191e85f4fd5SWez FurlongIf you ask a socket stream for a FILE*, the abstraction will use fdopen to
192e85f4fd5SWez Furlongcreate it for you.  Be warned that doing so may cause buffered data to be lost
193e85f4fd5SWez Furlongif you mix ANSI stdio calls on the FILE* with php stream calls on the stream.
194e85f4fd5SWez Furlong
195e85f4fd5SWez FurlongIf your system has the fopencookie function, php streams can synthesize a
196e85f4fd5SWez FurlongFILE* on top of any stream, which is useful for SSL sockets, memory based
197e85f4fd5SWez Furlongstreams, data base streams etc. etc.
19830647934SWez Furlong
19967f80413SJon PariseIn situations where this is not desirable, you should query the stream
20030647934SWez Furlongto see if it naturally supports FILE *.  You can use this code snippet
20130647934SWez Furlongfor this purpose:
20230647934SWez Furlong
20330647934SWez Furlong    if (php_stream_is(stream, PHP_STREAM_IS_STDIO)) {
20430647934SWez Furlong        /* can safely cast to FILE* with no adverse side effects */
20530647934SWez Furlong    }
206e85f4fd5SWez Furlong
207e85f4fd5SWez FurlongYou can use:
208e85f4fd5SWez Furlong
209e85f4fd5SWez FurlongPHPAPI int php_stream_can_cast(php_stream * stream, int castas)
210e85f4fd5SWez Furlong
211e85f4fd5SWez Furlongto find out if a stream can be cast, without actually performing the cast, so
212e85f4fd5SWez Furlongto check if a stream is a socket you might use:
213e85f4fd5SWez Furlong
21430647934SWez Furlongif (php_stream_can_cast(stream, PHP_STREAM_AS_SOCKETD) == SUCCESS)  {
21530647934SWez Furlong    /* it can be a socket */
216e85f4fd5SWez Furlong}
217e85f4fd5SWez Furlong
21830647934SWez FurlongPlease note the difference between php_stream_is and php_stream_can_cast;
21930647934SWez Furlongstream_is tells you if the stream is a particular type of stream, whereas
22030647934SWez Furlongcan_cast tells you if the stream can be forced into the form you request.
2216abd7c6fSWez FurlongThe former doesn't change anything, while the later *might* change some
22230647934SWez Furlongstate in the stream.
223e85f4fd5SWez Furlong
224e85f4fd5SWez FurlongStream Internals
225e85f4fd5SWez Furlong================
226e85f4fd5SWez Furlong
227e85f4fd5SWez FurlongThere are two main structures associated with a stream - the php_stream
228e85f4fd5SWez Furlongitself, which holds some state information (and possibly a buffer) and a
229e85f4fd5SWez Furlongphp_stream_ops structure, which holds the "virtual method table" for the
230e85f4fd5SWez Furlongunderlying implementation.
231e85f4fd5SWez Furlong
232e85f4fd5SWez FurlongThe php_streams ops struct consists of pointers to methods that implement
233e85f4fd5SWez Furlongread, write, close, flush, seek, gets and cast operations.  Of these, an
234e85f4fd5SWez Furlongimplementation need only implement write, read, close and flush.  The gets
235afd2c566SWez Furlongmethod is intended to be used for streams if there is an underlying method
236afd2c566SWez Furlongthat can efficiently behave as fgets.  The ops struct also contains a label
237afd2c566SWez Furlongfor the implementation that will be used when printing error messages - the
238afd2c566SWez Furlongstdio implementation has a label of "STDIO" for example.
239e85f4fd5SWez Furlong
240e85f4fd5SWez FurlongThe idea is that a stream implementation defines a php_stream_ops struct, and
241e85f4fd5SWez Furlongassociates it with a php_stream using php_stream_alloc.
242e85f4fd5SWez Furlong
243e85f4fd5SWez FurlongAs an example, the php_stream_fopen() function looks like this:
244e85f4fd5SWez Furlong
245e85f4fd5SWez FurlongPHPAPI php_stream * php_stream_fopen(const char * filename, const char * mode)
246e85f4fd5SWez Furlong{
24730647934SWez Furlong    FILE * fp = fopen(filename, mode);
24830647934SWez Furlong    php_stream * ret;
24930647934SWez Furlong
25030647934SWez Furlong    if (fp) {
25130647934SWez Furlong        ret = php_stream_alloc(&php_stream_stdio_ops, fp, 0, 0, mode);
25230647934SWez Furlong        if (ret)
25330647934SWez Furlong            return ret;
25430647934SWez Furlong
25530647934SWez Furlong        fclose(fp);
25630647934SWez Furlong    }
25730647934SWez Furlong    return NULL;
258e85f4fd5SWez Furlong}
259e85f4fd5SWez Furlong
260e85f4fd5SWez Furlongphp_stream_stdio_ops is a php_stream_ops structure that can be used to handle
261e85f4fd5SWez FurlongFILE* based streams.
262e85f4fd5SWez Furlong
263e85f4fd5SWez FurlongA socket based stream would use code similar to that above to create a stream
264e85f4fd5SWez Furlongto be passed back to fopen_wrapper (or it's yet to be implemented successor).
265e85f4fd5SWez Furlong
266e85f4fd5SWez FurlongThe prototype for php_stream_alloc is this:
267e85f4fd5SWez Furlong
268e85f4fd5SWez FurlongPHPAPI php_stream * php_stream_alloc(php_stream_ops * ops, void * abstract,
26930647934SWez Furlong        size_t bufsize, int persistent, const char * mode)
270e85f4fd5SWez Furlong
271e85f4fd5SWez Furlongops is a pointer to the implementation,
272e85f4fd5SWez Furlongabstract holds implementation specific data that is relevant to this instance
273e85f4fd5SWez Furlongof the stream,
274e85f4fd5SWez Furlongbufsize is the size of the buffer to use - if 0, then buffering at the stream
275e85f4fd5SWez Furlonglevel will be disabled (recommended for underlying sources that implement
276e85f4fd5SWez Furlongtheir own buffering - such a FILE*),
277e85f4fd5SWez Furlongpersistent controls how the memory is to be allocated - persistently so that
278e85f4fd5SWez Furlongit lasts across requests, or non-persistently so that it is freed at the end
279e85f4fd5SWez Furlongof a request (it uses pemalloc),
280e85f4fd5SWez Furlongmode is the stdio-like mode of operation - php streams places no real meaning
281e85f4fd5SWez Furlongin the mode parameter, except that it checks for a 'w' in the string when
282e85f4fd5SWez Furlongattempting to write (this may change).
283e85f4fd5SWez Furlong
284e85f4fd5SWez FurlongThe mode parameter is passed on to fdopen/fopencookie when the stream is cast
285e85f4fd5SWez Furlonginto a FILE*, so it should be compatible with the mode parameter of fopen().
286e85f4fd5SWez Furlong
287e85f4fd5SWez FurlongWriting your own stream implementation
288e85f4fd5SWez Furlong======================================
289e85f4fd5SWez Furlong
290afd2c566SWez Furlong!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
291dc8593cbSWez FurlongRULE #1: when writing your own streams: make sure you have configured PHP with
292dc8593cbSWez Furlong--enable-debug.
29367f80413SJon PariseI've taken some great pains to hook into the Zend memory manager to help track
294dc8593cbSWez Furlongdown allocation problems.  It will also help you spot incorrect use of the
295dc8593cbSWez FurlongSTREAMS_DC, STREAMS_CC and the semi-private STREAMS_REL_CC macros for function
296dc8593cbSWez Furlongdefinitions.
297afd2c566SWez Furlong!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
298afd2c566SWez Furlong
299afd2c566SWez FurlongRULE #2: Please use the stdio stream as a reference; it will help you
300afd2c566SWez Furlongunderstand the semantics of the stream operations, and it will always
301afd2c566SWez Furlongbe more up to date than these docs :-)
302afd2c566SWez Furlong
303e85f4fd5SWez FurlongFirst, you need to figure out what data you need to associate with the
304e85f4fd5SWez Furlongphp_stream.  For example, you might need a pointer to some memory for memory
305e85f4fd5SWez Furlongbased streams, or if you were making a stream to read data from an RDBMS like
30667f80413SJon PariseMySQL, you might want to store the connection and rowset handles.
307e85f4fd5SWez Furlong
308e85f4fd5SWez FurlongThe stream has a field called abstract that you can use to hold this data.
309e85f4fd5SWez FurlongIf you need to store more than a single field of data, define a structure to
310e85f4fd5SWez Furlonghold it, allocate it (use pemalloc with the persistent flag set
311e85f4fd5SWez Furlongappropriately), and use the abstract pointer to refer to it.
312e85f4fd5SWez Furlong
313e85f4fd5SWez FurlongFor structured state you might have this:
314e85f4fd5SWez Furlong
31530647934SWez Furlongstruct my_state {
31630647934SWez Furlong    MYSQL conn;
31730647934SWez Furlong    MYSQL_RES * result;
318e85f4fd5SWez Furlong};
319e85f4fd5SWez Furlong
320e85f4fd5SWez Furlongstruct my_state * state = pemalloc(sizeof(struct my_state), persistent);
321e85f4fd5SWez Furlong
322e85f4fd5SWez Furlong/* initialize the connection, and run a query, using the fields in state to
323e85f4fd5SWez Furlong * hold the results */
324e85f4fd5SWez Furlong
325e85f4fd5SWez Furlongstate->result = mysql_use_result(&state->conn);
326e85f4fd5SWez Furlong
327e85f4fd5SWez Furlong/* now allocate the stream itself */
328e85f4fd5SWez Furlongstream = php_stream_alloc(&my_ops, state, 0, persistent, "r");
329e85f4fd5SWez Furlong
330e85f4fd5SWez Furlong/* now stream->abstract == state */
331e85f4fd5SWez Furlong
332e85f4fd5SWez FurlongOnce you have that part figured out, you can write your implementation and
333e85f4fd5SWez Furlongdefine the your own php_stream_ops struct (we called it my_ops in the above
334e85f4fd5SWez Furlongexample).
335e85f4fd5SWez Furlong
33667f80413SJon PariseFor example, for reading from this weird MySQL stream:
337e85f4fd5SWez Furlong
338e85f4fd5SWez Furlongstatic size_t php_mysqlop_read(php_stream * stream, char * buf, size_t count)
339e85f4fd5SWez Furlong{
34030647934SWez Furlong    struct my_state * state = (struct my_state*)stream->abstract;
34130647934SWez Furlong
34230647934SWez Furlong    if (buf == NULL && count == 0)  {
34330647934SWez Furlong        /* in this special case, php_streams is asking if we have reached the
34430647934SWez Furlong         * end of file */
34530647934SWez Furlong        if (... at end of file ...)
34630647934SWez Furlong            return EOF;
34730647934SWez Furlong        else
34830647934SWez Furlong            return 0;
34930647934SWez Furlong    }
35030647934SWez Furlong
35130647934SWez Furlong    /* pull out some data from the stream and put it in buf */
35230647934SWez Furlong    ... mysql_fetch_row(state->result) ...
35330647934SWez Furlong    /* we could do something strange, like format the data as XML here,
35430647934SWez Furlong        and place that in the buf, but that brings in some complexities,
35530647934SWez Furlong        such as coping with a buffer size too small to hold the data,
35630647934SWez Furlong        so I won't even go in to how to do that here */
357e85f4fd5SWez Furlong}
358e85f4fd5SWez Furlong
359e85f4fd5SWez FurlongImplement the other operations - remember that write, read, close and flush
360e85f4fd5SWez Furlongare all mandatory.  The rest are optional.  Declare your stream ops struct:
361e85f4fd5SWez Furlong
362e85f4fd5SWez Furlongphp_stream_ops my_ops = {
36330647934SWez Furlong    php_mysqlop_write, php_mysqlop_read, php_mysqlop_close,
36430647934SWez Furlong    php_mysqlop_flush, NULL, NULL, NULL,
36567f80413SJon Parise    "Strange MySQL example"
366e85f4fd5SWez Furlong}
367e85f4fd5SWez Furlong
368e85f4fd5SWez FurlongThats it!
369e85f4fd5SWez Furlong
370e85f4fd5SWez FurlongTake a look at the STDIO implementation in streams.c for more information
371e85f4fd5SWez Furlongabout how these operations work.
372e85f4fd5SWez FurlongThe main thing to remember is that in your close operation you need to release
373e85f4fd5SWez Furlongand free the resources you allocated for the abstract field.  In the case of
374e85f4fd5SWez Furlongthe example above, you need to use mysql_free_result on the rowset, close the
375e85f4fd5SWez Furlongconnection and then use pefree to dispose of the struct you allocated.
376e85f4fd5SWez FurlongYou may read the stream->persistent field to determine if your struct was
377e85f4fd5SWez Furlongallocated in persistent mode or not.
378e85f4fd5SWez Furlong
37930647934SWez Furlongvim:tw=78:et