From: Wez Furlong Date: Tue, 2 Apr 2002 16:46:33 +0000 (+0000) Subject: main/streams.c X-Git-Tag: php-4.3.0dev-ZendEngine2-Preview1~906 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=a0f165a5cb615d49834d5e68ab7ab543e45d493e;p=php main/streams.c --- diff --git a/ext/mailparse/mailparse.c b/ext/mailparse/mailparse.c index ed8672c886..37095e478a 100755 --- a/ext/mailparse/mailparse.c +++ b/ext/mailparse/mailparse.c @@ -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); } /* }}} */ diff --git a/ext/mailparse/php_mailparse.h b/ext/mailparse/php_mailparse.h index 1f3c8bdb31..8ae3d34875 100755 --- a/ext/mailparse/php_mailparse.h +++ b/ext/mailparse/php_mailparse.h @@ -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); diff --git a/ext/mailparse/try.php b/ext/mailparse/try.php index ac2a32f1d8..0cb175b73a 100755 --- a/ext/mailparse/try.php +++ b/ext/mailparse/try.php @@ -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); diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index edc7817c91..7fcdba87cc 100644 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -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)) { diff --git a/ext/standard/exec.c b/ext/standard/exec.c index 4b6b75c768..48a3d02b59 100644 --- a/ext/standard/exec.c +++ b/ext/standard/exec.c @@ -35,6 +35,16 @@ #include #endif +#if HAVE_SYS_TYPES_H +#include +#endif +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_FCNTL_H +#include +#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 diff --git a/ext/standard/exec.h b/ext/standard/exec.h index 4cf325ae61..e315a5c83c 100644 --- a/ext/standard/exec.h +++ b/ext/standard/exec.h @@ -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 *); diff --git a/main/memory_streams.c b/main/memory_streams.c index fdd074903f..eae29e4acf 100644 --- a/main/memory_streams.c +++ b/main/memory_streams.c @@ -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; } diff --git a/main/streams.c b/main/streams.c index 52431cd1da..a4c4d7e67b 100755 --- a/main/streams.c +++ b/main/streams.c @@ -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;