diff options
Diffstat (limited to 'README.STREAMS')
-rw-r--r-- | README.STREAMS | 243 |
1 files changed, 0 insertions, 243 deletions
diff --git a/README.STREAMS b/README.STREAMS deleted file mode 100644 index 2ae89b7a51..0000000000 --- a/README.STREAMS +++ /dev/null @@ -1,243 +0,0 @@ -An Overview of the PHP Streams abstraction -========================================== -$Id$ - -Please send comments to: Wez Furlong <wez@thebrainroom.com> - -Note: this doc is preliminary and is intended to give the reader an idea of -how streams work and should be used. - -Why Streams? -============ -You may have noticed a shed-load of issock parameters flying around the PHP -code; we don't want them - they are ugly and cumbersome and force you to -special case sockets and files everytime you need to work with a "user-level" -PHP file pointer. -Streams take care of that and present the PHP extension coder with an ANSI -stdio-alike API that looks much nicer and can be extended to support non file -based data sources. - -Using Streams -============= -Streams use a php_stream* parameter just as ANSI stdio (fread etc.) use a -FILE* parameter. - -The main functions are: - -PHPAPI size_t php_stream_read(php_stream * stream, char * buf, size_t count); -PHPAPI size_t php_stream_write(php_stream * stream, const char * buf, size_t - count); -PHPAPI int php_stream_eof(php_stream * stream); -PHPAPI int php_stream_getc(php_stream * stream); -PHPAPI char *php_stream_gets(php_stream * stream, char *buf, size_t maxlen); -PHPAPI int php_stream_close(php_stream * stream); -PHPAPI int php_stream_flush(php_stream * stream); -PHPAPI int php_stream_seek(php_stream * stream, off_t offset, int whence); -PHPAPI off_t php_stream_tell(php_stream * stream); - -These (should) behave in the same way as the ANSI stdio functions with similar -names: fread, fwrite, feof, fgetc, fgets, fclose, fflush, fseek, ftell. - -Opening Streams -=============== -Ultimately, I aim to implement an fopen_wrapper-like call to do this with -minimum fuss. -Currently, mostly for testing purposes, you can use php_stream_fopen to open a -stream on a regular file. - -PHPAPI php_stream * php_stream_fopen(const char * filename, const char * - mode); - -This call behaves just like fopen(), except it returns a stream instead of a -FILE * - -Casting Streams -=============== -What if your extension needs to access the FILE* of a user level file pointer? -You need to "cast" the stream into a FILE*, and this is how you do it: - -FILE * fp; -php_stream * stream; /* already opened */ - -if (php_stream_cast(stream, PHP_STREAM_AS_STDIO, &fp, 1) == FAILURE) { - RETURN_FALSE; -} - -The prototype is: - -PHPAPI int php_stream_cast(php_stream * stream, int castas, void ** ret, int - show_err); - -The show_err parameter, if non-zero, will cause the function to display an -appropriate error message of type E_WARNING if the cast fails. - -castas can be one of the following values: -PHP_STREAM_AS_STDIO - a stdio FILE* -PHP_STREAM_AS_FD - a generic file descriptor -PHP_STREAM_AS_SOCKETD - a socket descriptor - -If you ask a socket stream for a FILE*, the abstraction will use fdopen to -create it for you. Be warned that doing so may cause buffered data to be lost -if you mix ANSI stdio calls on the FILE* with php stream calls on the stream. - -If your system has the fopencookie function, php streams can synthesize a -FILE* on top of any stream, which is useful for SSL sockets, memory based -streams, data base streams etc. etc. -NOTE: There might be situations where this is not desireable, and we need to -provide a flag to inform the casting routine of this. - -You can use: - -PHPAPI int php_stream_can_cast(php_stream * stream, int castas) - -to find out if a stream can be cast, without actually performing the cast, so -to check if a stream is a socket you might use: - -if (php_stream_can_cast(stream, PHP_STREAM_AS_SOCKETD) == SUCCESS) { - /* it's a socket */ -} - - -Stream Internals -================ - -There are two main structures associated with a stream - the php_stream -itself, which holds some state information (and possibly a buffer) and a -php_stream_ops structure, which holds the "virtual method table" for the -underlying implementation. - -The php_streams ops struct consists of pointers to methods that implement -read, write, close, flush, seek, gets and cast operations. Of these, an -implementation need only implement write, read, close and flush. The gets -method is intended to be used for non-buffered streams if there is an -underlying method that can efficiently behave as fgets. The ops struct also -contains a label for the implementation that will be used when printing error -messages - the stdio implementation has a label of "STDIO" for example. - -The idea is that a stream implementation defines a php_stream_ops struct, and -associates it with a php_stream using php_stream_alloc. - -As an example, the php_stream_fopen() function looks like this: - -PHPAPI php_stream * php_stream_fopen(const char * filename, const char * mode) -{ - FILE * fp = fopen(filename, mode); - php_stream * ret; - - if (fp) { - ret = php_stream_alloc(&php_stream_stdio_ops, fp, 0, 0, mode); - if (ret) - return ret; - - fclose(fp); - } - return NULL; -} - -php_stream_stdio_ops is a php_stream_ops structure that can be used to handle -FILE* based streams. - -A socket based stream would use code similar to that above to create a stream -to be passed back to fopen_wrapper (or it's yet to be implemented successor). - -The prototype for php_stream_alloc is this: - -PHPAPI php_stream * php_stream_alloc(php_stream_ops * ops, void * abstract, - size_t bufsize, int persistent, const char * mode) - -ops is a pointer to the implementation, -abstract holds implementation specific data that is relevant to this instance -of the stream, -bufsize is the size of the buffer to use - if 0, then buffering at the stream -level will be disabled (recommended for underlying sources that implement -their own buffering - such a FILE*), -persistent controls how the memory is to be allocated - persistently so that -it lasts across requests, or non-persistently so that it is freed at the end -of a request (it uses pemalloc), -mode is the stdio-like mode of operation - php streams places no real meaning -in the mode parameter, except that it checks for a 'w' in the string when -attempting to write (this may change). - -The mode parameter is passed on to fdopen/fopencookie when the stream is cast -into a FILE*, so it should be compatible with the mode parameter of fopen(). - -Writing your own stream implementation -====================================== - -First, you need to figure out what data you need to associate with the -php_stream. For example, you might need a pointer to some memory for memory -based streams, or if you were making a stream to read data from an RDBMS like -mysql, you might want to store the connection and rowset handles. - -The stream has a field called abstract that you can use to hold this data. -If you need to store more than a single field of data, define a structure to -hold it, allocate it (use pemalloc with the persistent flag set -appropriately), and use the abstract pointer to refer to it. - -For structured state you might have this: - -struct my_state { - MYSQL conn; - MYSQL_RES * result; -}; - -struct my_state * state = pemalloc(sizeof(struct my_state), persistent); - -/* initialize the connection, and run a query, using the fields in state to - * hold the results */ - -state->result = mysql_use_result(&state->conn); - -/* now allocate the stream itself */ -stream = php_stream_alloc(&my_ops, state, 0, persistent, "r"); - -/* now stream->abstract == state */ - -Once you have that part figured out, you can write your implementation and -define the your own php_stream_ops struct (we called it my_ops in the above -example). - -For example, for reading from this wierd mysql stream: - -static size_t php_mysqlop_read(php_stream * stream, char * buf, size_t count) -{ - struct my_state * state = (struct my_state*)stream->abstract; - - if (buf == NULL && count == 0) { - /* in this special case, php_streams is asking if we have reached the - * end of file */ - if (... at end of file ...) - return EOF; - else - return 0; - } - - /* pull out some data from the stream and put it in buf */ - ... mysql_fetch_row(state->result) ... - /* we could do something strange, like format the data as XML here, - and place that in the buf, but that brings in some complexities, - such as coping with a buffer size too small to hold the data, - so I won't even go in to how to do that here */ -} - -Implement the other operations - remember that write, read, close and flush -are all mandatory. The rest are optional. Declare your stream ops struct: - -php_stream_ops my_ops = { - php_mysqlop_write, php_mysqlop_read, php_mysqlop_close, - php_mysqlop_flush, NULL, NULL, NULL, - "Strange mySQL example" -} - -Thats it! - -Take a look at the STDIO implementation in streams.c for more information -about how these operations work. -The main thing to remember is that in your close operation you need to release -and free the resources you allocated for the abstract field. In the case of -the example above, you need to use mysql_free_result on the rowset, close the -connection and then use pefree to dispose of the struct you allocated. -You may read the stream->persistent field to determine if your struct was -allocated in persistent mode or not. - -vim:tw=78 |