]> granicus.if.org Git - php/commitdiff
main/streams.c
authorWez Furlong <wez@php.net>
Tue, 2 Apr 2002 16:46:33 +0000 (16:46 +0000)
committerWez Furlong <wez@php.net>
Tue, 2 Apr 2002 16:46:33 +0000 (16:46 +0000)
ext/mailparse/mailparse.c
ext/mailparse/php_mailparse.h
ext/mailparse/try.php
ext/standard/basic_functions.c
ext/standard/exec.c
ext/standard/exec.h
main/memory_streams.c
main/streams.c

index ed8672c886a0ba297d41f301600e1d4a192a69ee..37095e478a13425ca6170923716ad77a18b2330a 100755 (executable)
@@ -52,6 +52,7 @@ function_entry mailparse_functions[] = {
        PHP_FE(mailparse_msg_get_part_data,                     NULL)
        PHP_FE(mailparse_msg_extract_part,                      NULL)
        PHP_FE(mailparse_msg_extract_part_file,         NULL)
+       PHP_FE(mailparse_msg_extract_whole_part_file,           NULL)
        
        PHP_FE(mailparse_msg_create,                            NULL)
        PHP_FE(mailparse_msg_free,                              NULL)
@@ -124,6 +125,7 @@ PHP_MINFO_FUNCTION(mailparse)
 {
        php_info_print_table_start();
        php_info_print_table_header(2, "mailparse support", "enabled");
+       php_info_print_table_row(2, "Revision", "$Revision$");
        php_info_print_table_end();
 
        DISPLAY_INI_ENTRIES();
@@ -313,7 +315,7 @@ PHP_FUNCTION(mailparse_rfc822_parse_addresses)
 }
 /* }}} */
 
-/* {{{ proto int mailparse_determine_best_xfer_encoding(resource fp)
+/* {{{ proto string mailparse_determine_best_xfer_encoding(resource fp)
    Figures out the best way of encoding the content read from the file pointer fp, which must be seek-able */
 PHP_FUNCTION(mailparse_determine_best_xfer_encoding)
 {
@@ -322,41 +324,36 @@ PHP_FUNCTION(mailparse_determine_best_xfer_encoding)
        int linelen = 0;
        int c;
        enum mbfl_no_encoding bestenc = mbfl_no_encoding_7bit;
-       void * what;
-       int type;
+       php_stream *stream;
        char * name;
 
        if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &file) == FAILURE)        {
                WRONG_PARAM_COUNT;
        }
 
-       what = zend_fetch_resource(file TSRMLS_CC, -1, "File-Handle", &type, 1, php_file_le_stream());
-       ZEND_VERIFY_RESOURCE(what);
-
-       if (type == php_file_le_stream())       {
-               php_stream *stream = (php_stream*)what;
+       stream = zend_fetch_resource(file TSRMLS_CC, -1, "File-Handle", NULL, 1, php_file_le_stream());
+       ZEND_VERIFY_RESOURCE(stream);
 
-               php_stream_rewind(stream);
-               while(!php_stream_eof(stream))  {
-                       c = php_stream_getc(stream);
-                       if (c == EOF)
-                               break;
-                       if (c > 0x80)
-                               bestenc = mbfl_no_encoding_8bit;
-                       else if (c == 0)        {
-                               bestenc = mbfl_no_encoding_base64;
-                               longline = 0;
-                               break;
-                       }
-                       if (c == '\n')
-                               linelen = 0;
-                       else if (++linelen > 200)
-                               longline = 1;
+       php_stream_rewind(stream);
+       while(!php_stream_eof(stream))  {
+               c = php_stream_getc(stream);
+               if (c == EOF)
+                       break;
+               if (c > 0x80)
+                       bestenc = mbfl_no_encoding_8bit;
+               else if (c == 0)        {
+                       bestenc = mbfl_no_encoding_base64;
+                       longline = 0;
+                       break;
                }
-               if (longline)
-                       bestenc = mbfl_no_encoding_qprint;
-               php_stream_rewind(stream);
+               if (c == '\n')
+                       linelen = 0;
+               else if (++linelen > 200)
+                       longline = 1;
        }
+       if (longline)
+               bestenc = mbfl_no_encoding_qprint;
+       php_stream_rewind(stream);
 
        name = (char *)mbfl_no2preferred_mime_name(bestenc);
        if (name)
@@ -510,7 +507,7 @@ PHP_FUNCTION(mailparse_msg_parse_file)
        zval **filename;
        struct rfc2045 *rfcbuf;
        char *filebuf;
-       FILE *fp;
+       php_stream *stream;
 
        if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &filename) == FAILURE)    {
                WRONG_PARAM_COUNT;
@@ -519,9 +516,8 @@ PHP_FUNCTION(mailparse_msg_parse_file)
        convert_to_string_ex(filename);
 
        /* open file and read it in */
-       fp = VCWD_FOPEN(Z_STRVAL_PP(filename), "r");
-       if (fp == NULL) {
-               zend_error(E_WARNING, "%s(): unable to open file %s", get_active_function_name(TSRMLS_C), Z_STRVAL_PP(filename));
+       stream = php_stream_open_wrapper(Z_STRVAL_PP(filename), "rb", ENFORCE_SAFE_MODE|REPORT_ERRORS, NULL);
+       if (stream == NULL)     {
                RETURN_FALSE;
        }
 
@@ -531,14 +527,14 @@ PHP_FUNCTION(mailparse_msg_parse_file)
        if (rfcbuf)     {
                ZEND_REGISTER_RESOURCE(return_value, rfcbuf, le_rfc2045);
 
-               while(!feof(fp))        {
-                       int got = fread(filebuf, sizeof(char), MAILPARSE_BUFSIZ, fp);
+               while(!php_stream_eof(stream))  {
+                       int got = php_stream_read(stream, filebuf, MAILPARSE_BUFSIZ);
                        if (got > 0)    {
                                rfc2045_parse(rfcbuf, filebuf, got);
                        }
                }
-               fclose(fp);
        }
+       php_stream_close(stream);
        efree(filebuf);
 }
 /* }}} */
@@ -661,140 +657,178 @@ static int extract_callback_stdout(const char *p, size_t n, void *ptr)
        return 0;
 }
 
-/* {{{ proto void mailparse_msg_extract_part(resource rfc2045, string msgbody[, string callbackfunc])
-   Extracts/decodes a message section.  If callbackfunc is not specified, the contents will be sent to "stdout" */
-PHP_FUNCTION(mailparse_msg_extract_part)
+/* callback for decoding to a stream */
+static int extract_callback_stream(const char *p, size_t n, void *ptr)
+{
+       TSRMLS_FETCH();
+       php_stream_write((php_stream*)ptr, p, n);
+       return 0;
+}
+
+
+#define MAILPARSE_DECODE_NONE  0               /* include headers and leave section untouched */
+#define MAILPARSE_DECODE_8BIT  1               /* decode body into 8-bit */
+#define MAILPARSE_DECODE_NOHEADERS     2       /* don't include the headers */
+static int extract_part(struct rfc2045 *rfcbuf, int decode, php_stream *src, void *callbackdata,
+               rfc2045_decode_user_func_t callback TSRMLS_DC)
 {
-       zval **arg, **bodystr, **cbfunc;
-       struct rfc2045 *rfcbuf;
        off_t start, end, body;
        off_t nlines;
        off_t nbodylines;
+       off_t start_pos;
+       char *filebuf = NULL;
+       int ret = FAILURE;
+       
+       /* figure out where the message part starts/ends */
+       rfc2045_mimepos(rfcbuf, &start, &end, &body, &nlines, &nbodylines);
 
-       switch(ZEND_NUM_ARGS()) {
-               case 3:
-                       if (zend_get_parameters_ex(3, &arg, &bodystr, &cbfunc) == FAILURE)      {
-                               WRONG_PARAM_COUNT;
-                       }
-                       if (Z_TYPE_PP(cbfunc) != IS_ARRAY)
-                               convert_to_string_ex(cbfunc);
-                       break;
-               case 2:
-                       if (zend_get_parameters_ex(2, &arg, &bodystr) == FAILURE)       {
-                               WRONG_PARAM_COUNT;
-                       }
-                       cbfunc = NULL;
-                       break;
-       }
-       convert_to_string_ex(bodystr);
+       start_pos = decode & MAILPARSE_DECODE_NOHEADERS ? body : start;
 
-       if (Z_TYPE_PP(arg) == IS_RESOURCE && Z_LVAL_PP(arg) == 0)       {
-               RETURN_FALSE;
+       if (decode & MAILPARSE_DECODE_8BIT)
+               rfc2045_cdecode_start(rfcbuf, callback, callbackdata);
+       
+       if (php_stream_seek(src, start_pos, SEEK_SET) == -1) {
+               zend_error(E_WARNING, "%s(): unable to seek to section start", get_active_function_name(TSRMLS_C));
+               goto cleanup;
        }
-       mailparse_fetch_rfc2045_resource(rfcbuf, arg);
-
-
-       rfc2045_mimepos(rfcbuf, &start, &end, &body, &nlines, &nbodylines);
+       
+       filebuf = emalloc(MAILPARSE_BUFSIZ);
+       
+       while (start_pos < end)
+       {
+               size_t n = MAILPARSE_BUFSIZ - 1;
 
-       if (cbfunc)
-               rfc2045_cdecode_start(rfcbuf, (rfc2045_decode_user_func_t)&extract_callback_user_func, *cbfunc);
-       else
-               rfc2045_cdecode_start(rfcbuf, &extract_callback_stdout, NULL);
+               if ((off_t)n > end - start_pos)
+                       n = end - start_pos;
+               
+               n = php_stream_read(src, filebuf, n);
+               
+               if (n == 0)
+               {
+                       zend_error(E_WARNING, "%s(): error reading from file at offset %d", get_active_function_name(TSRMLS_C), start_pos);
+                       goto cleanup;
+               }
 
-       if (Z_STRLEN_PP(bodystr) < end)
-               end = Z_STRLEN_PP(bodystr);
-       else
-               end = end-body;
+               filebuf[n] = '\0';
+               
+               if (decode & MAILPARSE_DECODE_8BIT)
+                       rfc2045_cdecode(rfcbuf, filebuf, n);
+               else
+                       callback(filebuf, n, callbackdata);
 
-       rfc2045_cdecode(rfcbuf, Z_STRVAL_PP(bodystr) + body, end);
-       rfc2045_cdecode_end(rfcbuf);
+               start_pos += n;
+       }
+       ret = SUCCESS;
 
-       RETURN_TRUE;
+cleanup:
+       if (decode & MAILPARSE_DECODE_8BIT)
+               rfc2045_cdecode_end(rfcbuf);
 
+       if (filebuf)
+               efree(filebuf);
+       
+       return ret;
 }
-/* }}} */
 
-/* {{{ proto string mailparse_msg_extract_part_file(resource rfc2045, string filename [, string callbackfunc])
-   Extracts/decodes a message section, decoding the transfer encoding */
-PHP_FUNCTION(mailparse_msg_extract_part_file)
+static void mailparse_do_extract(INTERNAL_FUNCTION_PARAMETERS, int decode, int isfile)
 {
-       zval **arg, **filename, **cbfunc;
+       zval *part, *filename, *callbackfunc = NULL;
        struct rfc2045 *rfcbuf;
-       char *filebuf = NULL;
-       FILE *fp = NULL;
-       off_t start, end, body;
-       off_t nlines;
-       off_t nbodylines;
+       php_stream *srcstream = NULL, *deststream = NULL;
+       rfc2045_decode_user_func_t cbfunc = NULL;
+       void *cbdata = NULL;
+       int close_src_stream = 0;
 
-       switch(ZEND_NUM_ARGS()) {
-               case 3:
-                       if (zend_get_parameters_ex(3, &arg, &filename, &cbfunc) == FAILURE)     {
-                               WRONG_PARAM_COUNT;
-                       }
-                       if (Z_TYPE_PP(cbfunc) != IS_ARRAY)
-                               convert_to_string_ex(cbfunc);
-                       break;
-               case 2:
-                       if (zend_get_parameters_ex(2, &arg, &filename) == FAILURE)      {
-                               WRONG_PARAM_COUNT;
-                       }
-                       cbfunc = NULL;
-                       break;
+       if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rz|z", &part, &filename, &callbackfunc)) {
+               RETURN_FALSE;
        }
-       convert_to_string_ex(filename);
 
-       if (Z_TYPE_PP(arg) == IS_RESOURCE && Z_LVAL_PP(arg) == 0)       {
+       if (Z_TYPE_P(part) == IS_RESOURCE && Z_LVAL_P(part) == 0)       {
                RETURN_FALSE;
        }
-       mailparse_fetch_rfc2045_resource(rfcbuf, arg);
-
-       /* figure out where the message part starts/ends */
-       rfc2045_mimepos(rfcbuf, &start, &end, &body, &nlines, &nbodylines);
+       mailparse_fetch_rfc2045_resource(rfcbuf, &part);
 
-       if (cbfunc)
-               rfc2045_cdecode_start(rfcbuf, (rfc2045_decode_user_func_t)&extract_callback_user_func, *cbfunc);
-       else
-               rfc2045_cdecode_start(rfcbuf, &extract_callback_stdout, NULL);
+       /* filename can be a filename or a stream */
+       if (Z_TYPE_P(filename) == IS_RESOURCE) {
+               srcstream = (php_stream*)zend_fetch_resource(&filename TSRMLS_CC, -1, "File-Handle", NULL, 1, php_file_le_stream());
+               ZEND_VERIFY_RESOURCE(srcstream);
+       } else if (isfile) {
+               convert_to_string_ex(&filename);
+               srcstream = php_stream_open_wrapper(Z_STRVAL_P(filename), "rb", ENFORCE_SAFE_MODE|REPORT_ERRORS, NULL);
+       } else {
+               /* filename is the actual data */
+               srcstream = php_stream_memory_open(TEMP_STREAM_READONLY, Z_STRVAL_P(filename), Z_STRLEN_P(filename));
+               close_src_stream = 1;
+       }
 
-       /* open file and read it in */
-       fp = VCWD_FOPEN(Z_STRVAL_PP(filename), "rb");
-       if (fp == NULL) {
-               zend_error(E_WARNING, "%s(): unable to open file %s", get_active_function_name(TSRMLS_C), Z_STRVAL_PP(filename));
+       if (srcstream == NULL) {
                RETURN_FALSE;
        }
-       if (fseek(fp, body, SEEK_SET) == -1)
-       {
-               zend_error(E_WARNING, "%s(): unable to seek to section start", get_active_function_name(TSRMLS_C));
-               RETVAL_FALSE;
-               goto cleanup;
+
+       if (callbackfunc != NULL) {
+               if (Z_TYPE_P(callbackfunc) == IS_NULL) {
+                       cbfunc = extract_callback_stream;
+                       cbdata = deststream = php_stream_memory_create(TEMP_STREAM_DEFAULT);
+               } else if (Z_TYPE_P(callbackfunc) == IS_RESOURCE) {
+                       deststream = (php_stream*)zend_fetch_resource(&callbackfunc TSRMLS_CC, -1, "File-Handle", NULL, 1, php_file_le_stream());
+                       ZEND_VERIFY_RESOURCE(deststream);
+                       cbfunc = extract_callback_stream;
+                       cbdata = deststream;
+                       deststream = NULL; /* don't free this one */
+               } else {
+                       if (Z_TYPE_P(callbackfunc) != IS_ARRAY)
+                               convert_to_string_ex(&callbackfunc);
+                       cbfunc = (rfc2045_decode_user_func_t)&extract_callback_user_func;
+                       cbdata = callbackfunc;
+               }
+       } else {
+               cbfunc = extract_callback_stdout;
+               cbdata = NULL;
        }
-       filebuf = emalloc(MAILPARSE_BUFSIZ);
 
+       RETVAL_FALSE;
+       
+       if (SUCCESS == extract_part(rfcbuf, decode, srcstream, cbdata, cbfunc TSRMLS_CC)) {
 
-       while (body < end)
-       {
-               size_t n = MAILPARSE_BUFSIZ;
+               if (deststream != NULL) {
+                       /* return it's contents as a string */
+                       char *membuf = NULL;
+                       size_t memlen = 0;
+                       membuf = php_stream_memory_get_buffer(deststream, &memlen);
+                       RETVAL_STRINGL(membuf, memlen, 1);
 
-               if ((off_t)n > end-body)
-                       n=end-body;
-               n = fread(filebuf, sizeof(char), n, fp);
-               if (n == 0)
-               {
-                       zend_error(E_WARNING, "%s(): error reading from file \"%s\", offset %d", get_active_function_name(TSRMLS_C), Z_STRVAL_PP(filename), body);
-                       RETVAL_FALSE;
-                       goto cleanup;
+               } else {
+                       RETVAL_TRUE;
                }
-               rfc2045_cdecode(rfcbuf, filebuf, n);
-               body += n;
        }
-       RETVAL_TRUE;
 
-cleanup:
-       rfc2045_cdecode_end(rfcbuf);
-       if (fp)
-               fclose(fp);
-       if (filebuf)
-               efree(filebuf);
+       if (deststream)
+               php_stream_close(deststream);
+       if (close_src_stream && srcstream)
+               php_stream_close(srcstream);
+}
+
+/* {{{ proto void mailparse_msg_extract_part(resource rfc2045, string msgbody[, string callbackfunc])
+   Extracts/decodes a message section.  If callbackfunc is not specified, the contents will be sent to "stdout" */
+PHP_FUNCTION(mailparse_msg_extract_part)
+{
+       mailparse_do_extract(INTERNAL_FUNCTION_PARAM_PASSTHRU, MAILPARSE_DECODE_8BIT | MAILPARSE_DECODE_NOHEADERS, 0);
+}
+/* }}} */
+
+/* {{{ proto string mailparse_msg_extract_whole_part_file(resource rfc2045, string filename [, string callbackfunc])
+   Extracts a message section including headers without decoding the transfer encoding */
+PHP_FUNCTION(mailparse_msg_extract_whole_part_file)
+{
+       mailparse_do_extract(INTERNAL_FUNCTION_PARAM_PASSTHRU, MAILPARSE_DECODE_NONE, 1);
+}
+/* }}} */
+
+/* {{{ proto string mailparse_msg_extract_part_file(resource rfc2045, string filename [, string callbackfunc])
+   Extracts/decodes a message section, decoding the transfer encoding */
+PHP_FUNCTION(mailparse_msg_extract_part_file)
+{
+       mailparse_do_extract(INTERNAL_FUNCTION_PARAM_PASSTHRU, MAILPARSE_DECODE_8BIT | MAILPARSE_DECODE_NOHEADERS, 1);
 }
 /* }}} */
 
index 1f3c8bdb31a14cd3419440c17ee5dfee24d2becc..8ae3d348756bbe6d38167f0f3d37ad16cd7f5214 100755 (executable)
@@ -43,6 +43,7 @@ PHP_FUNCTION(mailparse_msg_get_structure);
 PHP_FUNCTION(mailparse_msg_get_part_data);
 PHP_FUNCTION(mailparse_msg_extract_part);
 PHP_FUNCTION(mailparse_msg_extract_part_file);
+PHP_FUNCTION(mailparse_msg_extract_whole_part_file);
 
 PHP_FUNCTION(mailparse_msg_create);
 PHP_FUNCTION(mailparse_msg_free);
index ac2a32f1d80b84119eddeddef1fdc1fcc282a1fd..0cb175b73a79a503e54817fc2402dd75356ccd86 100755 (executable)
@@ -6,10 +6,7 @@
  * You will be able to choose a part to view.
  * */
 
-#$filename = "/home/CLIENTWEB/worlddo/mimetests/namib.rfc822";
-$filename = "/home/CLIENTWEB/worlddo/mimetests/uumsg";
-#$filename = "/home/CLIENTWEB/worlddo/mimetests/segblob.txt";
-#$filename = "yourmessage.txt";
+$filename = "yourmessage.txt";
 
 /* parse the message and return a mime message resource */
 $mime = mailparse_msg_parse_file($filename);
index edc7817c91a393969ba3dca1ae776f7c27181773..7fcdba87cc4dacf3d05703eaee3c72039772b0f3 100644 (file)
@@ -377,6 +377,7 @@ function_entry basic_functions[] = {
        PHP_FE(escapeshellarg,                                                                                                  NULL)
        PHP_FE(passthru,                                second_arg_force_ref)
        PHP_FE(shell_exec,                                                                                                              NULL)
+       PHP_FE(proc_open,                               third_arg_force_ref)
 
        PHP_FE(rand,                                                                                                                    NULL)
        PHP_FE(srand,                                                                                                                   NULL)
@@ -977,6 +978,7 @@ PHP_MINIT_FUNCTION(basic)
        PHP_MINIT(array) (INIT_FUNC_ARGS_PASSTHRU);
        PHP_MINIT(assert) (INIT_FUNC_ARGS_PASSTHRU);
        PHP_MINIT(url_scanner_ex) (INIT_FUNC_ARGS_PASSTHRU);
+       PHP_MINIT(proc_open) (INIT_FUNC_ARGS_PASSTHRU);
 
 
        if (PG(allow_url_fopen)) {
index 4b6b75c768dd864bd7db333e656efd90c5ed1d79..48a3d02b593510cd89d1db9c737554afb0f50ba5 100644 (file)
 #include <signal.h>
 #endif
 
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
 /* {{{ php_Exec
  * If type==0, only last line of output is returned (exec)
  * If type==1, all lines will be printed and last lined returned (system)
@@ -477,6 +487,352 @@ PHP_FUNCTION(shell_exec)
 }
 /* }}} */
 
+static int le_proc_open;
+
+static void proc_open_rsrc_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
+{
+#if HAVE_SYS_WAIT
+       int wstatus;
+       pid_t child, wait_pid;
+       
+       child = (pid_t)rsrc->ptr;
+
+       do {
+               wait_pid = waitpid(child, &wstatus, 0);
+       } while (wait_pid == -1 && errno = EINTR);
+       
+       if (wait_pid == -1)
+               FG(pclose_ret) = -1;
+       else
+               FG(pclose_ret) = wstatus;
+#else
+       FG(pclose_ret) = -1;
+#endif
+}
+
+PHP_MINIT_FUNCTION(proc_open)
+{
+       le_proc_open = zend_register_list_destructors_ex(proc_open_rsrc_dtor, NULL, "proc-opened-process", module_number);
+       return SUCCESS;
+}
+
+/* {{{ proto resource proc_open(string command, array descriptorspec, array &pipes)
+   Run a process with more control over it's file descriptors */
+PHP_FUNCTION(proc_open)
+{
+#define MAX_DESCRIPTORS        16
+#define DESC_PIPE              1
+#define DESC_FILE              2
+#define DESC_PARENT_MODE_WRITE 8
+#ifndef O_BINARY
+#define O_BINARY       0
+#endif
+
+#ifdef PHP_WIN32
+       /* NOINHERIT is actually required for pipes to work correctly when inherited;
+        * see the win32 specific dup call a little further down */
+#define pipe(handles)  _pipe((handles), 512, _O_BINARY | _O_NOINHERIT)
+#endif
+
+       char *command;
+       long command_len;
+       zval *descriptorspec;
+       zval *pipes;
+       struct {
+               int index; /* desired fd number in child process */
+               int parentend, childend; /* fds for pipes in parent/child */
+               int mode;
+       } descriptors[MAX_DESCRIPTORS];
+       int ndesc = 0;
+       int i;
+       zval **descitem = NULL;
+       HashPosition pos;
+#ifdef PHP_WIN32
+       PROCESS_INFORMATION pi;
+       STARTUPINFO si;
+       BOOL newprocok;
+       HANDLE child;
+#else
+       pid_t child;
+#endif
+
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "saz/", &command,
+                               &command_len, &descriptorspec, &pipes) == FAILURE) {
+               RETURN_FALSE;
+       }
+
+       memset(descriptors, 0, sizeof(descriptors));
+
+       /* walk the descriptor spec and set up files/pipes */
+       zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(descriptorspec), &pos);
+       while (zend_hash_get_current_data_ex(Z_ARRVAL_P(descriptorspec), (void **)&descitem, &pos) == SUCCESS) {
+               char *str_index;
+               ulong nindex;
+               zval **ztype;
+
+               str_index = NULL;
+               zend_hash_get_current_key_ex(Z_ARRVAL_P(descriptorspec), &str_index, NULL, &nindex, 0, &pos);
+
+               if (str_index) {
+                       zend_error(E_WARNING, "%s(): descriptor spec must be an integer indexed array",
+                                       get_active_function_name(TSRMLS_C));
+                       RETURN_FALSE;
+               }
+
+               descriptors[ndesc].index = nindex;
+
+               if (Z_TYPE_PP(descitem) == IS_RESOURCE) {
+                       /* should be a stream - try and dup the descriptor */
+                       php_stream *stream;
+                       int fd;
+
+                       ZEND_FETCH_RESOURCE(stream, php_stream *, descitem, -1, "File-Handle", php_file_le_stream());
+
+                       if (FAILURE == php_stream_cast(stream, PHP_STREAM_AS_FD, (void **)&fd, REPORT_ERRORS)) {
+                               RETURN_FALSE;
+                       }
+
+                       descriptors[ndesc].childend = dup(fd);
+                       if (descriptors[ndesc].childend < 0) {
+                               zend_error(E_WARNING, "%s(): unable to dup File-Handle for descriptor %d - %s",
+                                               get_active_function_name(TSRMLS_C), nindex, strerror(errno));
+                       }
+                       descriptors[ndesc].mode = DESC_FILE;
+
+               } else if (Z_TYPE_PP(descitem) != IS_ARRAY) {
+                       zend_error(E_WARNING, "%s(): descriptor item must be either an array or a File-Handle",
+                                       get_active_function_name(TSRMLS_C));
+                       RETURN_FALSE;
+               } else {
+
+                       zend_hash_index_find(Z_ARRVAL_PP(descitem), 0, (void **)&ztype);
+                       convert_to_string_ex(ztype);
+
+                       if (strcmp(Z_STRVAL_PP(ztype), "pipe") == 0) {
+                               int newpipe[2];
+                               zval **zmode;
+
+                               descriptors[ndesc].mode = DESC_PIPE;
+                               if (0 != pipe(newpipe)) {
+                                       zend_error(E_WARNING, "%s(): unable to create pipe %s",
+                                                       get_active_function_name(TSRMLS_C), strerror(errno));
+                                       RETURN_FALSE;
+                               }
+
+                               zend_hash_index_find(Z_ARRVAL_PP(descitem), 1, (void **)&zmode);
+                               convert_to_string_ex(zmode);
+
+                               if (strcmp(Z_STRVAL_PP(zmode), "w") != 0) {
+                                       descriptors[ndesc].parentend = newpipe[1];
+                                       descriptors[ndesc].childend = newpipe[0];
+                                       descriptors[ndesc].mode |= DESC_PARENT_MODE_WRITE;
+                               } else {
+                                       descriptors[ndesc].parentend = newpipe[0];
+                                       descriptors[ndesc].childend = newpipe[1];
+                               }
+
+#ifdef PHP_WIN32
+                               {       /* this magic is needed to ensure that pipes work
+                                        * correctly in the child */
+                                       int tmpfd = dup(descriptors[ndesc].childend);
+                                       close(descriptors[ndesc].childend);
+                                       descriptors[ndesc].childend = tmpfd;
+                               }
+#endif
+
+                       } else if (strcmp(Z_STRVAL_PP(ztype), "file") == 0) {
+                               zval **zfile, **zmode;
+                               int open_flags = 0;
+                               const struct {
+                                       char *modestring;
+                                       int flags;
+                               } modemap[] = {
+                                       { "r",          O_RDONLY },
+                                       { "rb",         O_RDONLY | O_BINARY },
+                                       { "r+",         O_RDWR },
+                                       { "rb+",        O_RDWR | O_BINARY },
+                                       { "w",          O_WRONLY | O_CREAT | O_TRUNC },
+                                       { "wb",         O_WRONLY | O_CREAT | O_TRUNC | O_BINARY},
+                                       { "w+",         O_RDWR | O_CREAT | O_TRUNC },
+                                       { "wb+",        O_RDWR | O_CREAT | O_TRUNC | O_BINARY},
+                                       { "a",          O_WRONLY | O_CREAT | O_APPEND },
+                                       { "ab",         O_WRONLY | O_CREAT | O_APPEND | O_BINARY },
+                                       { "a+",         O_RDWR | O_CREAT | O_APPEND },
+                                       { "ab+",        O_RDWR | O_CREAT | O_APPEND | O_BINARY},
+                                       { NULL, 0 }
+                               };
+
+                               descriptors[ndesc].mode = DESC_FILE;
+
+                               zend_hash_index_find(Z_ARRVAL_PP(descitem), 1, (void **)&zfile);
+                               convert_to_string_ex(zfile);
+
+                               zend_hash_index_find(Z_ARRVAL_PP(descitem), 2, (void **)&zmode);
+                               convert_to_string_ex(zmode);
+
+                               for (i = 0; modemap[i].modestring != NULL; i++) {
+                                       if (strcmp(modemap[i].modestring, Z_STRVAL_PP(zmode)) == 0) {
+                                               open_flags = modemap[i].flags;
+                                               break;
+                                       }
+                               }
+
+                               descriptors[ndesc].childend = VCWD_OPEN_MODE(Z_STRVAL_PP(zfile), open_flags, 0644);
+                               if (descriptors[ndesc].childend < 0) {
+
+                                       if (PG(allow_url_fopen)) {
+                                               /* try a wrapper */
+                                               int fd;
+                                               php_stream *stream;
+                                               size_t old_size = FG(def_chunk_size);
+
+                                               FG(def_chunk_size) = 1;
+                                               stream = php_stream_open_wrapper(Z_STRVAL_PP(zfile), Z_STRVAL_PP(zmode),
+                                                               ENFORCE_SAFE_MODE|REPORT_ERRORS, NULL);
+                                               FG(def_chunk_size) = old_size;
+
+                                               if (stream == NULL)
+                                                       RETURN_FALSE;
+
+                                               /* force into an fd */
+                                               if (FAILURE == php_stream_cast(stream, PHP_STREAM_CAST_RELEASE|PHP_STREAM_AS_FD, (void **)&fd, REPORT_ERRORS))
+                                                       RETURN_FALSE;
+
+                                               descriptors[ndesc].childend = fd;
+
+                                       } else {
+
+                                               zend_error(E_WARNING, "%s(): unable to open %s with mode %s",
+                                                               get_active_function_name(TSRMLS_C),
+                                                               Z_STRVAL_PP(zfile), Z_STRVAL_PP(zmode));
+                                               RETURN_FALSE;
+                                       }
+                               }
+                       } else {
+                               zend_error(E_WARNING, "%s(): %s is not a valid descriptor spec/mode",
+                                               get_active_function_name(TSRMLS_C), Z_STRVAL_PP(ztype));
+                               RETURN_FALSE;
+                       }
+               }
+
+               zend_hash_move_forward_ex(Z_ARRVAL_P(descriptorspec), &pos);
+               if (++ndesc == MAX_DESCRIPTORS)
+                       break;
+       }
+
+#ifdef PHP_WIN32
+       memset(&si, 0, sizeof(si));
+       si.cb = sizeof(si);
+       
+       /* redirect stdin/stdout/stderr if requested */
+       for (i = 0; i < ndesc; i++) {
+               switch(descriptors[i].index) {
+                       case 0:
+                               si.hStdInput = (HANDLE)_get_osfhandle(descriptors[i].childend);
+                               si.dwFlags |= STARTF_USESTDHANDLES;
+                               break;
+                       case 1:
+                               si.hStdOutput = (HANDLE)_get_osfhandle(descriptors[i].childend);
+                               si.dwFlags |= STARTF_USESTDHANDLES;
+                               break;
+                       case 2:
+                               si.hStdError = (HANDLE)_get_osfhandle(descriptors[i].childend);
+                               si.dwFlags |= STARTF_USESTDHANDLES;
+                               break;
+               }
+       }
+
+       memset(&pi, 0, sizeof(pi));
+       
+       newprocok = CreateProcess(NULL, command, NULL, NULL, TRUE, NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi);
+
+       if (FALSE == newprocok) {
+               zend_error(E_WARNING, "%s(): CreateProcess failed", get_active_function_name(TSRMLS_C));
+               RETURN_FALSE;
+       }
+
+       child = pi.hProcess;
+       
+#else
+       /* the unix way */
+
+       child = fork();
+
+       if (child == 0) {
+               /* this is the child process */
+
+               /* close those descriptors that we just opened for the parent stuff,
+                * dup new descriptors into required descriptors and close the original
+                * cruft */
+               for (i = 0; i < ndesc; i++) {
+                       switch (descriptors[i].mode & ~DESC_PARENT_MODE_WRITE) {
+                               case DESC_PIPE:
+                                       close(descriptors[i].parentend);
+                                       break;
+                       }
+                       if (dup2(descriptors[i].childend, descriptors[i].index) < 0)
+                               perror("dup2");
+                       if (descriptors[i].childend != descriptors[i].index)
+                               close(descriptors[i].childend);
+               }
+
+               execl("/bin/sh", "sh", "-c", command, NULL);
+               _exit(127);
+
+       } else if (child < 0) {
+               /* failed to fork() */
+
+               /* clean up all the descriptors */
+               for (i = 0; i < ndesc; i++) {
+                       close(descriptors[i].childend);
+                       close(descriptors[i].parentend);
+               }
+
+               zend_error(E_WARNING, "%s(): fork failed - %s",
+                               get_active_function_name(TSRMLS_C),
+                               strerror(errno)
+                               );
+
+               RETURN_FALSE;
+
+       }
+#endif
+       /* we forked/spawned and this is the parent */
+
+       array_init(pipes);
+
+       /* clean up all the child ends and then open streams on the parent
+        * ends, where appropriate */
+       for (i = 0; i < ndesc; i++) {
+               char *stdiomode;
+               FILE *fp;
+               php_stream *stream;
+
+               close(descriptors[i].childend);
+
+               switch (descriptors[i].mode & ~DESC_PARENT_MODE_WRITE) {
+                       case DESC_PIPE:
+                               stdiomode = descriptors[i].mode & DESC_PARENT_MODE_WRITE ? "w" : "r";
+                               fp = fdopen(descriptors[i].parentend, stdiomode);
+                               if (fp) {
+                                       stream = php_stream_fopen_from_file(fp, stdiomode);
+                                       if (stream) {
+                                               zval *retfp;
+
+                                               MAKE_STD_ZVAL(retfp);
+                                               php_stream_to_zval(stream, retfp);
+                                               add_index_zval(pipes, descriptors[i].index, retfp);
+                                       }
+                               }
+                               break;
+               }
+       }
+
+       ZEND_REGISTER_RESOURCE(return_value, child, le_proc_open);
+
+}
+/* }}} */
+
 /*
  * Local variables:
  * tab-width: 4
index 4cf325ae61fd5fa204fb4176e49663565fb69ad7..e315a5c83c6d9aa31cf9a8d263b3ca13bd73091b 100644 (file)
@@ -27,6 +27,8 @@ PHP_FUNCTION(escapeshellcmd);
 PHP_FUNCTION(escapeshellarg);
 PHP_FUNCTION(passthru);
 PHP_FUNCTION(shell_exec);
+PHP_FUNCTION(proc_open);
+PHP_MINIT_FUNCTION(proc_open);
 
 char *php_escape_shell_cmd(char *);
 char *php_escape_shell_arg(char *);
index fdd074903f5d228a636cc20a7d0c4f207c249920..eae29e4acf1c45b7172fd165909ba6443bae5649 100644 (file)
@@ -120,7 +120,7 @@ static int php_stream_memory_close(php_stream *stream, int close_handle TSRMLS_D
        ms = stream->abstract;
        assert(ms != NULL);
 
-       if (ms->data) {
+       if (ms->data && close_handle && ms->mode != TEMP_STREAM_READONLY) {
                efree(ms->data);
        }
        efree(ms);
@@ -262,13 +262,19 @@ PHPAPI php_stream *_php_stream_memory_open(int mode, char *buf, size_t length ST
 {      php_stream *stream;
        php_stream_memory_data *ms;
 
-       if ((stream = php_stream_memory_create_rel(TEMP_STREAM_DEFAULT)) != NULL) {
-               if (length) {
-                       assert(buf != NULL);
-                       php_stream_write(stream, buf, length);
-               }
+       if ((stream = php_stream_memory_create_rel(mode)) != NULL) {
                ms = stream->abstract;
-               ms->mode = mode;
+               
+               if (mode == TEMP_STREAM_READONLY) {
+                       /* use the buffer directly */
+                       ms->data = buf;
+                       ms->fsize = length;
+               } else {
+                       if (length) {
+                               assert(buf != NULL);
+                               php_stream_write(stream, buf, length);
+                       }
+               }
        }
        return stream;
 }
index 52431cd1dafb6f6352b49d88e5b37c0b65588fea..a4c4d7e67bcc1a277565da357c9a0fa7e47a0bb4 100755 (executable)
@@ -716,6 +716,7 @@ static int php_stdiop_cast(php_stream *stream, int castas, void **ret TSRMLS_DC)
                                return FAILURE;
                        }
                        if (ret) {
+                               fflush(data->file);
                                *ret = (void*)fd;
                        }
                        return SUCCESS;