]> granicus.if.org Git - php/commitdiff
Tweak the API to be more consistent.
authorWez Furlong <wez@php.net>
Sat, 16 Mar 2002 13:48:57 +0000 (13:48 +0000)
committerWez Furlong <wez@php.net>
Sat, 16 Mar 2002 13:48:57 +0000 (13:48 +0000)
Update docs.

README.STREAMS
TODO
ext/gd/gd.c
ext/hyperwave/hw.c
main/php_streams.h
main/streams.c

index 2ae89b7a51d8a3f6113ff56588bc53df9036cf17..e5a3cca35a185eecd590b8c64e073a1a71ee7f0c 100644 (file)
@@ -4,9 +4,6 @@ $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
@@ -26,7 +23,7 @@ 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);
+        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);
@@ -40,16 +37,77 @@ 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.
+In most cases, you should use this API:
+
+PHPAPI php_stream *php_stream_open_wrapper(char *path, char *mode,
+    int options, char **opened_path TSRMLS_DC);
+
+Where:
+    path is the file or resource to open.
+    mode is the stdio compatible mode eg: "wb", "rb" etc.
+    options is a combination of the following values:
+        IGNORE_PATH  (default) - don't use include path to search for the file
+        USE_PATH        - use include path to search for the file
+        IGNORE_URL      - do not use plugin wrappers
+        REPORT_ERRORS   - show errors in a standard format if something
+                          goes wrong.
+    opened_path is used to return the path of the actual file opened.
+
+If you need to open a specific stream, or convert standard resources into
+streams there are a range of functions to do this defined in php_streams.h.
+A brief list of the most commonly used functions:
+
+PHPAPI php_stream *php_stream_fopen_from_file(FILE *file, const char *mode);
+    Convert a FILE * into a stream.
 
-PHPAPI php_stream * php_stream_fopen(const char * filename, const char *
-               mode);
+PHPAPI php_stream *php_stream_fopen_tmpfile(void);
+    Open a FILE * with tmpfile() and convert into a stream.
 
-This call behaves just like fopen(), except it returns a stream instead of a
-FILE *
+PHPAPI php_stream *php_stream_fopen_temporary_file(const char *dir,
+    const char *pfx, char **opened_path TSRMLS_DC);
+    Generate a temporary file name and open it.
+
+There are some network enabled relatives in php_network.h:
+
+PHPAPI php_stream *php_stream_sock_open_from_socket(int socket, int persistent);
+    Convert a socket into a stream.
+
+PHPAPI php_stream *php_stream_sock_open_host(const char *host, unsigned short port,
+               int socktype, int timeout, int persistent);
+    Open a connection to a host and return a stream.
+
+PHPAPI php_stream *php_stream_sock_open_unix(const char *path, int persistent,
+    struct timeval *timeout);
+    Open a UNIX domain socket.
+   
+
+Stream Utilities
+================
+
+If you need to copy some data from one stream to another, you will be please
+to know that the streams API provides a standard way to do this:
+
+PHPAPI size_t php_stream_copy_to_stream(php_stream *src,
+    php_stream *dest, size_t maxlen);
+
+If you want to copy all remaining data from the src stream, pass
+PHP_STREAM_COPY_ALL as the maxlen parameter, otherwise maxlen indicates the
+number of bytes to copy.
+This function will try to use mmap where available to make the copying more
+efficient.
+
+If you want to read the contents of a stream into an allocated memory buffer,
+you should use:
+
+PHPAPI size_t php_stream_copy_to_mem(php_stream *src, char **buf,
+    size_t maxlen, int persistent);
+
+This function will set buf to the address of the buffer that it allocated,
+which will be maxlen bytes in length, or will be the entire length of the
+data remaining on the stream if you set maxlen to PHP_STREAM_COPY_ALL.
+The buffer is allocated using pemalloc(); you need to call pefree() to
+release the memory when you are done.
+As with copy_to_stream, this function will try use mmap where it can.
 
 Casting Streams
 ===============
@@ -59,14 +117,14 @@ 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;
+if (php_stream_cast(stream, PHP_STREAM_AS_STDIO, (void*)&fp, REPORT_ERRORS) == FAILURE)    {
+    RETURN_FALSE;
 }
 
 The prototype is:
 
 PHPAPI int php_stream_cast(php_stream * stream, int castas, void ** ret, int
-               show_err);
+        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.
@@ -83,8 +141,14 @@ 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.
+
+In situations where this is not desireable, you should query the stream
+to see if it naturally supports FILE *.  You can use this code snippet
+for this purpose:
+
+    if (php_stream_is(stream, PHP_STREAM_IS_STDIO)) {
+        /* can safely cast to FILE* with no adverse side effects */
+    }
 
 You can use:
 
@@ -93,10 +157,15 @@ 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 */
+if (php_stream_can_cast(stream, PHP_STREAM_AS_SOCKETD) == SUCCESS)  {
+    /* it can be a socket */
 }
 
+Please note the difference between php_stream_is and php_stream_can_cast;
+stream_is tells you if the stream is a particular type of stream, whereas
+can_cast tells you if the stream can be forced into the form you request.
+The format doesn't change anything, while the later *might* change some
+state in the stream.
 
 Stream Internals
 ================
@@ -121,17 +190,17 @@ 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;
+    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
@@ -143,7 +212,7 @@ 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)
+        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
@@ -176,9 +245,9 @@ 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 {
+    MYSQL conn;
+    MYSQL_RES * result;
 };
 
 struct my_state * state = pemalloc(sizeof(struct my_state), persistent);
@@ -201,32 +270,32 @@ 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 */
+    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"
+    php_mysqlop_write, php_mysqlop_read, php_mysqlop_close,
+    php_mysqlop_flush, NULL, NULL, NULL,
+    "Strange mySQL example"
 }
 
 Thats it!
@@ -240,4 +309,4 @@ 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
+vim:tw=78:et
diff --git a/TODO b/TODO
index 6d7c1a35767ed9950fcbbcf15634d40a1f4837f3..97a654cf632e2b61070a1241f243554f0ea99fee 100644 (file)
--- a/TODO
+++ b/TODO
@@ -43,10 +43,6 @@ global
     * on some platforms unimplemented function will just do nothing 
       (e.g. symlink) they should print a warning or not even be defined!
       (DONE ?)
-    * Finish PHP streams abstraction, nuke all that issock stuff, implement SSL
-      socket support. (wez)
-        - ext/ftp/ -> all FILEs to streams
-        - ext/bz2/ -> convert to stream impl.
     * Use arg_separator.input to implode args in the CGI sapi extension
       and arg_separator.input to explode in php_build_argv(). (DONE?)
     * Change the odbc_fetch_into() function to require ALWAYS the first two
index c839bfe2674351a16ac686be03aa739d9b146981..30ed56779245105a4777d444c3a3d4426c40d49d 100644 (file)
@@ -1171,7 +1171,7 @@ static void _php_image_create_from(INTERNAL_FUNCTION_PARAMETERS, int image_type,
                char *buff;
 
                /* needs to be malloc (persistent) - GD will free() it later */
-               buff_size = php_stream_read_all(stream, &buff, 1);
+               buff_size = php_stream_copy_to_mem(stream, &buff, PHP_STREAM_COPY_ALL, 1);
 
                if(!buff_size) {
                        php_error(E_WARNING,"%s: Cannot read image data", get_active_function_name(TSRMLS_C));
index 006a8f2209aa9e9344b38da49d724486dea52fe6..978a1915c0f31ceac7eb791c10ec69f567a67f25 100644 (file)
@@ -2892,7 +2892,7 @@ PHP_FUNCTION(hw_new_document_from_file)
        if(NULL == doc)
                RETURN_FALSE;
 
-       doc->size = php_stream_read_all(stream, &doc->data, 1);
+       doc->size = php_stream_copy_to_mem(stream, &doc->data, PHP_STREAM_COPY_ALL, 1);
 
        php_stream_close(stream);
        
index 289ae46b63ff0e9cec35b1dad92ea3c92c0ac235..7ec7f6f6f7caaa2a3fdea39ccabd5e76ce41f628 100755 (executable)
@@ -107,7 +107,7 @@ PHPAPI int php_stream_puts(php_stream *stream, char *buf);
 PHPAPI size_t php_stream_copy_to_stream(php_stream *src, php_stream *dest, size_t maxlen);
 /* read all data from stream and put into a buffer. Caller must free buffer when done.
  * The copy will use mmap if available. */
-PHPAPI size_t php_stream_read_all(php_stream *src, char **buf, int persistent);
+PHPAPI size_t php_stream_copy_to_mem(php_stream *src, char **buf, size_t maxlen, int persistent);
 
 /* maybe implement someday */
 #define php_stream_error(stream)       (0)
index 5a7ff97c504803a7fb76be843eae01f91a4908d7..eb0c942f277636dbbdabf1be97cfac30912136e5 100755 (executable)
@@ -227,7 +227,7 @@ PHPAPI int php_stream_seek(php_stream *stream, off_t offset, int whence)
        return -1;
 }
 
-PHPAPI size_t php_stream_read_all(php_stream *src, char **buf, int persistent)
+PHPAPI size_t php_stream_copy_to_mem(php_stream *src, char **buf, size_t maxlen, int persistent)
 {
        size_t ret = 0;
        char *ptr;
@@ -238,6 +238,15 @@ PHPAPI size_t php_stream_read_all(php_stream *src, char **buf, int persistent)
        int srcfd;
 #endif
 
+       if (buf)
+               *buf = NULL;
+       
+       if (maxlen == 0)
+               return 0;
+
+       if (maxlen == PHP_STREAM_COPY_ALL)
+               maxlen = 0;
+
 #if HAVE_MMAP
        /* try and optimize the case where we are copying from the start of a plain file.
         * We could probably make this work in more situations, but I don't trust the stdio
@@ -251,18 +260,21 @@ PHPAPI size_t php_stream_read_all(php_stream *src, char **buf, int persistent)
 
                if (fstat(srcfd, &sbuf) == 0) {
                        void *srcfile;
-                       
-                       srcfile = mmap(NULL, sbuf.st_size, PROT_READ, MAP_SHARED, srcfd, 0);
+
+                       if (maxlen > sbuf.st_size || maxlen == 0)
+                               maxlen = sbuf.st_size;
+                               
+                       srcfile = mmap(NULL, maxlen, PROT_READ, MAP_SHARED, srcfd, 0);
                        if (srcfile != (void*)MAP_FAILED) {
 
-                               *buf = pemalloc(persistent, sbuf.st_size);
+                               *buf = pemalloc(persistent, maxlen);
 
                                if (*buf)       {
-                                       memcpy(*buf, srcfile, sbuf.st_size);
-                                       ret = sbuf.st_size;
+                                       memcpy(*buf, srcfile, maxlen);
+                                       ret = maxlen;
                                }
                                
-                               munmap(srcfile, sbuf.st_size);
+                               munmap(srcfile, maxlen);
                                return ret;
                        }
                }