Index: ext/bz2/bz2.c =================================================================== RCS file: /repository/php4/ext/bz2/bz2.c,v retrieving revision 1.34 diff -u -w -B -b -r1.34 bz2.c --- ext/bz2/bz2.c 27 Jan 2002 17:24:31 -0000 1.34 +++ ext/bz2/bz2.c 14 Feb 2002 00:37:25 -0000 @@ -128,8 +128,21 @@ } /* If it is a resource, than its a 'FILE *' resource */ else { - ZEND_FETCH_RESOURCE(fp, FILE *, file, -1, "File Handle", php_file_le_fopen()); - bz = BZ2_bzdopen(fileno(fp), Z_STRVAL_PP(mode)); + int type; + int fd; + + fp = (FILE*) zend_fetch_resource(file TSRMLS_CC, -1, "File-Handle", &type, 2, php_file_le_fopen(), php_file_le_stream()); + ZEND_VERIFY_RESOURCE(fp); +#if HAVE_PHP_STREAM + if (type == php_file_le_stream()) { + if (!php_stream_cast((php_stream*)fp, PHP_STREAM_AS_FD, (void*)&fd, REPORT_ERRORS)) + RETURN_FALSE; + } + else +#endif + fd = fileno(fp); + + bz = BZ2_bzdopen(fd, Z_STRVAL_PP(mode)); } if (bz == NULL) { Index: ext/curl/curl.c =================================================================== RCS file: /repository/php4/ext/curl/curl.c,v retrieving revision 1.105 diff -u -w -B -b -r1.105 curl.c --- ext/curl/curl.c 27 Jan 2002 06:11:50 -0000 1.105 +++ ext/curl/curl.c 14 Feb 2002 00:37:26 -0000 @@ -699,7 +699,18 @@ case CURLOPT_WRITEHEADER: case CURLOPT_STDERR: { FILE *fp = NULL; - ZEND_FETCH_RESOURCE(fp, FILE *, zvalue, -1, "File-Handle", php_file_le_fopen()); + int type; + void * what; + + what = zend_fetch_resource(zvalue TSRMLS_CC, -1, "File-Handle", &type, 2, php_file_le_fopen(), php_file_le_stream()); + ZEND_VERIFY_RESOURCE(what); + +#if HAVE_PHP_STREAM + if (type == php_file_le_stream()) { + if (!php_stream_cast((php_stream*)what, PHP_STREAM_AS_STDIO, (void*)&fp, REPORT_ERRORS)) + RETURN_FALSE; + } +#endif if (!fp) { RETURN_FALSE; } Index: ext/mailparse/mailparse.c =================================================================== RCS file: /repository/php4/ext/mailparse/mailparse.c,v retrieving revision 1.17 diff -u -w -B -b -r1.17 mailparse.c --- ext/mailparse/mailparse.c 4 Feb 2002 14:27:37 -0000 1.17 +++ ext/mailparse/mailparse.c 14 Feb 2002 00:37:27 -0000 @@ -183,6 +183,7 @@ zval * file, * item; FILE *infp, *outfp=NULL, *partfp=NULL; int type; + void * what; char * buffer = NULL; char * outpath = NULL; int nparts = 0; @@ -190,9 +191,20 @@ if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "r", &file)) return; - infp = (FILE*)zend_fetch_resource(&file TSRMLS_CC, -1, "File-Handle", &type, 1, php_file_le_fopen()); + what = zend_fetch_resource(&file TSRMLS_CC, -1, "File-Handle", &type, 2, php_file_le_fopen(), php_file_le_stream()); ZEND_VERIFY_RESOURCE(infp); +#if HAVE_PHP_STREAM + if (type == php_file_le_stream()) { + if (php_stream_cast((php_stream *) what, PHP_STREAM_AS_STDIO, (void *) &infp, 1) == FAILURE) { + RETURN_FALSE; + } + } + else +#endif + infp = (FILE*)what; + + outfp = php_open_temporary_file(NULL, "mailparse", &outpath TSRMLS_CC); if (outfp == NULL) { zend_error(E_WARNING, "%s(): unable to open temp file", get_active_function_name(TSRMLS_C)); @@ -401,6 +413,18 @@ /* {{{ proto boolean mailparse_stream_encode(resource sourcefp, resource destfp, string encoding) Streams data from source file pointer, apply encoding and write to destfp */ +#if HAVE_PHP_STREAM +static int mailparse_stream_output(int c, void * stream) +{ + char buf = c; + return php_stream_write((php_stream*)stream, &buf, 1); +} +static int mailparse_stream_flush(void * stream) +{ + return php_stream_flush((php_stream*)stream); +} +#endif + static int mailparse_fp_output(int c, void * fp) { return fputc(c, (FILE*)fp); @@ -414,6 +438,11 @@ { zval ** srcfile, ** destfile, ** encod; FILE * srcfp, * destfp; + void * what; + int type; +#if HAVE_PHP_STREAM + php_stream * srcstream, * deststream; +#endif char * buf; size_t len; size_t bufsize = 2048; @@ -427,12 +456,32 @@ if (Z_TYPE_PP(srcfile) == IS_RESOURCE && Z_LVAL_PP(srcfile) == 0) { RETURN_FALSE; } - ZEND_FETCH_RESOURCE(srcfp, FILE *, srcfile, -1, "File-Handle", php_file_le_fopen()); - if (Z_TYPE_PP(destfile) == IS_RESOURCE && Z_LVAL_PP(destfile) == 0) { RETURN_FALSE; } - ZEND_FETCH_RESOURCE(destfp, FILE *, destfile, -1, "File-Handle", php_file_le_fopen()); + + what = zend_fetch_resource(srcfile TSRMLS_CC, -1, "File-Handle", &type, 2, php_file_le_fopen(), php_file_le_stream()); + ZEND_VERIFY_RESOURCE(what); + +#if HAVE_PHP_STREAM + if (type == php_file_le_stream()) { + srcstream = (php_stream*)what; + } + else +#endif + srcfp = (FILE*)what; + + + what = zend_fetch_resource(destfile TSRMLS_CC, -1, "File-Handle", &type, 2, php_file_le_fopen(), php_file_le_stream()); + ZEND_VERIFY_RESOURCE(what); +#if HAVE_PHP_STREAM + if (type == php_file_le_stream()) { + deststream = (php_stream*)what; + } + else +#endif + destfp = (FILE*)what; + convert_to_string_ex(encod); enc = mbfl_name2no_encoding(Z_STRVAL_PP(encod)); @@ -447,6 +496,28 @@ buf = emalloc(bufsize); RETVAL_TRUE; +#if HAVE_PHP_STREAM + if (type == php_file_le_stream()) { + conv = mbfl_convert_filter_new(mbfl_no_encoding_8bit, + enc, + mailparse_stream_output, + mailparse_stream_flush, + deststream + ); + + while(!php_stream_eof(srcstream)) { + len = php_stream_read(srcstream, buf, bufsize); + if (len > 0) + { + int i; + for (i=0; i here! */ } Index: ext/recode/recode.c =================================================================== RCS file: /repository/php4/ext/recode/recode.c,v retrieving revision 1.20 diff -u -w -B -b -r1.20 recode.c --- ext/recode/recode.c 11 Dec 2001 15:30:18 -0000 1.20 +++ ext/recode/recode.c 14 Feb 2002 00:37:32 -0000 @@ -26,6 +26,7 @@ #include "php.h" #include "php_recode.h" +#include "php_streams.h" #if HAVE_LIBRECODE #include "ext/standard/info.h" @@ -171,18 +173,34 @@ } in_fp = zend_fetch_resource(input TSRMLS_CC,-1, "File-Handle", &in_type, - 2, php_file_le_fopen(), php_file_le_popen()); + 3, php_file_le_fopen(), php_file_le_popen(), php_file_le_stream()); + if (!in_fp) { php_error(E_WARNING,"Unable to find input file identifier"); RETURN_FALSE; } +#if HAVE_PHP_STREAM + if (in_type == php_file_le_stream()) { + if (!php_stream_cast((php_stream*)in_fp, PHP_STREAM_AS_STDIO, &in_fp, REPORT_ERRORS)) { + RETURN_FALSE; + } + } +#endif + out_fp = zend_fetch_resource(output TSRMLS_CC,-1, "File-Handle", &out_type, - 2, php_file_le_fopen(), php_file_le_popen()); + 3, php_file_le_fopen(), php_file_le_popen(), php_file_le_stream()); if (!out_fp) { php_error(E_WARNING,"Unable to find output file identifier"); RETURN_FALSE; } +#if HAVE_PHP_STREAM + if (out_type == php_file_le_stream()) { + if (!php_stream_cast((php_stream*)out_fp, PHP_STREAM_AS_STDIO, &out_fp, REPORT_ERRORS)) { + RETURN_FALSE; + } + } +#endif convert_to_string_ex(req); Index: ext/standard/file.c =================================================================== RCS file: /repository/php4/ext/standard/file.c,v retrieving revision 1.204 diff -u -w -B -b -r1.204 file.c --- ext/standard/file.c 11 Jan 2002 10:44:24 -0000 1.204 +++ ext/standard/file.c 14 Feb 2002 00:37:36 -0000 @@ -17,7 +17,7 @@ | Andi Gutmans | | Zeev Suraski | | PHP 4.0 patches by Thies C. Arntzen (thies@thieso.net) | - | PHP 4.1 streams by Wez Furlong (wez@thebrainroom.com) | + | PHP streams by Wez Furlong (wez@thebrainroom.com) | +----------------------------------------------------------------------+ */ @@ -72,6 +72,7 @@ #endif #include "fsock.h" #include "fopen_wrappers.h" +#include "php_streams.h" #include "php_globals.h" #ifdef HAVE_SYS_FILE_H @@ -586,7 +587,7 @@ convert_to_string_ex(zfilename); convert_to_string_ex(zmode); - stream = php_stream_fopen(Z_STRVAL_PP(zfilename), Z_STRVAL_PP(zmode)); + stream = php_stream_fopen(Z_STRVAL_PP(zfilename), Z_STRVAL_PP(zmode), NULL TSRMLS_C); if (stream == NULL) { zend_error(E_WARNING, "%s(): unable to open %s: %s", get_active_function_name(TSRMLS_C), Z_STRVAL_PP(zfilename), strerror(errno)); @@ -889,10 +890,20 @@ zend_get_parameters_ex(ZEND_NUM_ARGS(), &socket, &seconds, µseconds)==FAILURE) { WRONG_PARAM_COUNT; } - /* XXX: add stream support --Wez. */ - what = zend_fetch_resource(socket TSRMLS_CC, -1, "File-Handle", &type, 1, le_socket); + + what = zend_fetch_resource(socket TSRMLS_CC, -1, "File-Handle", &type, 2, le_socket, le_stream); ZEND_VERIFY_RESOURCE(what); + + if (type == le_socket) { socketd = *(int *) what; + } +#if HAVE_PHP_STREAM + else if (type == le_stream) { + if (php_stream_cast((php_stream *) what, PHP_STREAM_AS_SOCKETD, (void *) &socketd, 1) == FAILURE) { + RETURN_FALSE; + } + } +#endif convert_to_long_ex(seconds); t.tv_sec = Z_LVAL_PP(seconds); @@ -926,11 +937,20 @@ if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(ZEND_NUM_ARGS(), &socket) == FAILURE) { WRONG_PARAM_COUNT; } - /* XXX: add stream support --Wez. */ - what = zend_fetch_resource(socket TSRMLS_CC, -1, "File-Handle", &type, 1, le_socket); + what = zend_fetch_resource(socket TSRMLS_CC, -1, "File-Handle", &type, 2, le_socket, le_stream); ZEND_VERIFY_RESOURCE(what); + if (type == le_socket) { socketd = *(int *) what; + } +#if HAVE_PHP_STREAM + else if (type == le_stream) { + if (php_stream_cast((php_stream *) what, PHP_STREAM_AS_SOCKETD, (void *) &socketd, 1) == FAILURE) { + RETURN_FALSE; + } + } +#endif + sock = php_get_socket(socketd); array_init(return_value); @@ -1356,11 +1376,13 @@ break; } - /* XXX: add stream support --Wez. */ - - what = zend_fetch_resource(arg1 TSRMLS_CC,-1, "File-Handle", &type, 2, le_fopen, le_popen); + what = zend_fetch_resource(arg1 TSRMLS_CC,-1, "File-Handle", &type, 3, le_fopen, le_popen, le_stream); ZEND_VERIFY_RESOURCE(what); - +#if HAVE_PHP_STREAM + if (type == le_stream && !php_stream_is((php_stream*)what, PHP_STREAM_IS_STDIO)) { + RETURN_FALSE; + } +#endif convert_to_long_ex(arg2); buff = Z_LVAL_PP(arg2); @@ -1381,15 +1403,24 @@ { zval **arg1; void *what; + int type; if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &arg1) == FAILURE) { WRONG_PARAM_COUNT; } - /* XXX: add stream support --Wez. */ - what = zend_fetch_resource(arg1 TSRMLS_CC,-1, "File-Handle", NULL, 2, le_fopen, le_popen); + what = zend_fetch_resource(arg1 TSRMLS_CC,-1, "File-Handle", &type, 3, le_fopen, le_popen, le_stream); ZEND_VERIFY_RESOURCE(what); +#if HAVE_PHP_STREAM + if (type == le_stream) { + if (-1 == php_stream_rewind((php_stream*)what)) { + RETURN_FALSE; + } + RETURN_TRUE; + } +#endif + rewind((FILE *) what); RETURN_TRUE; } @@ -1402,15 +1433,25 @@ zval **arg1; void *what; long ret; + int type; if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &arg1) == FAILURE) { WRONG_PARAM_COUNT; } - /* XXX: add stream support --Wez. */ - what = zend_fetch_resource(arg1 TSRMLS_CC,-1, "File-Handle", NULL, 2, le_fopen, le_popen); + what = zend_fetch_resource(arg1 TSRMLS_CC,-1, "File-Handle", &type, 2, le_fopen, le_popen, le_stream); ZEND_VERIFY_RESOURCE(what); +#if HAVE_PHP_STREAM + if (type == le_stream) { + ret = php_stream_tell((php_stream*)what); + if (ret == -1) { + RETURN_FALSE; + } + RETURN_LONG(ret); + } +#endif + ret = ftell((FILE *) what); if (ret == -1) { RETURN_FALSE; @@ -1427,14 +1468,14 @@ zval **arg1, **arg2, **arg3; int argcount = ZEND_NUM_ARGS(), whence = SEEK_SET; void *what; + int type; if (argcount < 2 || argcount > 3 || zend_get_parameters_ex(argcount, &arg1, &arg2, &arg3) == FAILURE) { WRONG_PARAM_COUNT; } - /* XXX: add stream support --Wez. */ - what = zend_fetch_resource(arg1 TSRMLS_CC,-1, "File-Handle", NULL, 2, le_fopen, le_popen); + what = zend_fetch_resource(arg1 TSRMLS_CC,-1, "File-Handle", &type, 3, le_fopen, le_popen, le_stream); ZEND_VERIFY_RESOURCE(what); convert_to_long_ex(arg2); @@ -1443,6 +1484,13 @@ whence = Z_LVAL_PP(arg3); } +#if HAVE_PHP_STREAM + if (type == le_stream) { + RETURN_LONG(php_stream_seek((php_stream*)what, Z_LVAL_PP(arg2), whence)); + } +#endif + + RETURN_LONG(fseek((FILE *) what, Z_LVAL_PP(arg2), whence)); } @@ -1508,13 +1556,59 @@ } /* }}} */ +#if HAVE_PHP_STREAM +static size_t php_passthru_stream(php_stream * stream TSRMLS_DC) +{ + size_t bcount = 0; + int ready = 0; + char buf[8192]; + int fd; + +#ifdef HAVE_MMAP + if (!php_stream_is(stream, PHP_STREAM_IS_SOCKET) + && php_stream_cast(stream, PHP_STREAM_AS_FD, (void*)&fd, 0)) + { + struct stat sbuf; + off_t off; + void *p; + size_t len; + + fstat(fd, &sbuf); + + if (sbuf.st_size > sizeof(buf)) { + off = php_stream_tell(stream); + len = sbuf.st_size - off; + p = mmap(0, len, PROT_READ, MAP_SHARED, fd, off); + if (p != (void *) MAP_FAILED) { + BG(mmap_file) = p; + BG(mmap_len) = len; + PHPWRITE(p, len); + BG(mmap_file) = NULL; + munmap(p, len); + bcount += len; + ready = 1; + } + } + } +#endif + if(!ready) { + int b; + + while ((b = php_stream_read(stream, buf, sizeof(buf))) > 0) { + PHPWRITE(buf, b); + bcount += b; + } + } + return bcount; +} +#endif + /* {{{ php_passthru_fd */ static size_t php_passthru_fd(int socketd, FILE *fp, int issock TSRMLS_DC) { size_t bcount = 0; int ready = 0; char buf[8192]; - /* XXX: add stream support --Wez. */ #ifdef HAVE_MMAP if (!issock) { @@ -1567,6 +1661,9 @@ int use_include_path=0; int issock=0, socketd=0; int rsrc_id; +#if HAVE_PHP_STREAM + php_stream * stream; +#endif /* check args */ switch (ZEND_NUM_ARGS()) { @@ -1587,6 +1684,17 @@ } convert_to_string_ex(arg1); +#if HAVE_PHP_STREAM + stream = php_stream_open_wrapper(Z_STRVAL_PP(arg1), "rb", + use_include_path | ENFORCE_SAFE_MODE | REPORT_ERRORS, + NULL TSRMLS_CC); + if (stream) { + size = php_passthru_stream(stream TSRMLS_CC); + php_stream_close(stream); + } + RETURN_LONG(size); +#endif + /* * We need a better way of returning error messages from * php_fopen_wrapper(). @@ -1663,10 +1771,17 @@ WRONG_PARAM_COUNT; } - /* XXX: add stream support --Wez. */ - what = zend_fetch_resource(arg1 TSRMLS_CC,-1, "File-Handle", &type, 3, le_fopen, le_popen, le_socket); + what = zend_fetch_resource(arg1 TSRMLS_CC,-1, "File-Handle", &type, 4, le_fopen, le_popen, le_socket, le_stream); ZEND_VERIFY_RESOURCE(what); +#if HAVE_PHP_STREAM + if (type == le_stream) { + size = php_passthru_stream((php_stream*)what TSRMLS_CC); + RETURN_LONG(size); + } +#endif + + if (type == le_socket) { issock = 1; socketd = *(int *) what; @@ -1760,17 +1875,32 @@ if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &fp, &size) == FAILURE) { WRONG_PARAM_COUNT; } - /* XXX: add stream support --Wez. */ - what = zend_fetch_resource(fp TSRMLS_CC,-1, "File-Handle", &type, 3, le_fopen, le_popen, le_socket); + what = zend_fetch_resource(fp TSRMLS_CC,-1, "File-Handle", &type, 4, le_fopen, le_popen, le_socket, le_stream); ZEND_VERIFY_RESOURCE(what); - if (type == le_socket) { + convert_to_long_ex(size); + +#if HAVE_PHP_STREAM + if (type == le_stream) { + int fd; + + if (php_stream_is((php_stream*)what, PHP_STREAM_IS_SOCKET)) { php_error(E_WARNING, "can't truncate sockets!"); RETURN_FALSE; } + if (php_stream_cast((php_stream*)what, PHP_STREAM_AS_FD, (void*)&fd, 1)) { + ret = ftruncate(fd, Z_LVAL_PP(size)); + RETURN_LONG(ret + 1); + } + RETURN_FALSE; + } +#endif - convert_to_long_ex(size); + if (type == le_socket) { + php_error(E_WARNING, "can't truncate sockets!"); + RETURN_FALSE; + } ret = ftruncate(fileno((FILE *) what), Z_LVAL_PP(size)); RETURN_LONG(ret + 1); @@ -1787,6 +1917,7 @@ int type; void *what; struct stat stat_sb; + int fd; char *stat_sb_names[13]={"dev", "ino", "mode", "nlink", "uid", "gid", "rdev", "size", "atime", "mtime", "ctime", "blksize", "blocks"}; @@ -1794,12 +1925,25 @@ if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &fp) == FAILURE) { WRONG_PARAM_COUNT; } - /* XXX: add stream support --Wez. */ - what = zend_fetch_resource(fp TSRMLS_CC,-1, "File-Handle", &type, 3, le_fopen, le_popen, le_socket); + what = zend_fetch_resource(fp TSRMLS_CC,-1, "File-Handle", &type, 4, le_fopen, le_popen, le_socket, le_stream); ZEND_VERIFY_RESOURCE(what); - if (fstat(fileno((FILE *) what), &stat_sb)) { +#if HAVE_PHP_STREAM + if (type == le_stream) { + if (!php_stream_cast((php_stream*)what, PHP_STREAM_AS_FD, (void*)&fd, 1)) { + RETURN_FALSE; + } + } + else +#endif + if (type == le_socket) { + fd = *(int*)what; + } + else + fd = fileno((FILE*) what); + + if (fstat(fd, &stat_sb)) { RETURN_FALSE; } @@ -1971,16 +2115,10 @@ if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &arg1, &arg2) == FAILURE) { WRONG_PARAM_COUNT; } - /* XXX: add stream support --Wez. */ - what = zend_fetch_resource(arg1 TSRMLS_CC,-1, "File-Handle", &type, 3, le_fopen, le_popen, le_socket); + what = zend_fetch_resource(arg1 TSRMLS_CC,-1, "File-Handle", &type, 4, le_fopen, le_popen, le_socket, le_stream); ZEND_VERIFY_RESOURCE(what); - if (type == le_socket) { - issock = 1; - socketd = *(int *) what; - } - convert_to_long_ex(arg2); len = Z_LVAL_PP(arg2); if (len < 0) { @@ -1988,9 +2126,26 @@ RETURN_FALSE; } + if (type == le_socket) { + issock = 1; + socketd = *(int *) what; + } + Z_STRVAL_P(return_value) = emalloc(len + 1); /* needed because recv doesnt put a null at the end*/ +#if HAVE_PHP_STREAM + if (type == le_stream) { + php_stream * stream = (php_stream*)what; + +#ifdef HAVE_FLUSHIO + if (php_stream_is(stream, PHP_STREAM_IS_STDIO)) + php_stream_seek(stream, 0, SEEK_CUR); +#endif + Z_STRLEN_P(return_value) = php_stream_read(stream, Z_STRVAL_P(return_value), len); + } + else +#endif if (!issock) { #ifdef HAVE_FLUSHIO if (type == le_fopen) { @@ -2025,6 +2180,9 @@ int issock=0; int socketd=0; void *what; +#if HAVE_PHP_STREAM + php_stream * stream; +#endif switch(ZEND_NUM_ARGS()) { case 2: @@ -2051,15 +2209,19 @@ /* NOTREACHED */ break; } - /* XXX: add stream support --Wez. */ - what = zend_fetch_resource(fd TSRMLS_CC,-1, "File-Handle", &type, 3, le_fopen, le_popen, le_socket); + what = zend_fetch_resource(fd TSRMLS_CC,-1, "File-Handle", &type, 4, le_fopen, le_popen, le_socket, le_stream); ZEND_VERIFY_RESOURCE(what); if (type == le_socket) { issock = 1; socketd = *(int *) what; } +#if HAVE_PHP_STREAM + if (type == le_stream) { + stream = (php_stream*)what; + } +#endif convert_to_long_ex(bytes); len = Z_LVAL_PP(bytes); @@ -2071,6 +2233,17 @@ buf = emalloc(len + 1); /*needed because recv doesnt set null char at end*/ memset(buf, 0, len + 1); + +#if HAVE_PHP_STREAM + if (type == le_stream) { + if (php_stream_gets(stream, buf, len) == NULL) { + efree(buf); + RETURN_FALSE; + } + } + else +#endif + if (FP_FGETS(buf, len, socketd, (FILE *) what, issock) == NULL) { efree(buf); RETURN_FALSE; @@ -2132,6 +2305,19 @@ /* read a new line from input, as at start of routine */ memset(buf, 0, len+1); + +#if HAVE_PHP_STREAM + if (type == le_stream) { + if (php_stream_gets(stream, buf, len) == NULL) { + efree(lineEnd); + efree(temp); + efree(buf); + zval_ptr_dtor(&return_value); + RETURN_FALSE; + } + } + else +#endif if (FP_FGETS(buf, len, socketd, (FILE *) what, issock) == NULL) { efree(lineEnd); efree(temp); @@ -2218,7 +2404,6 @@ ptr = *buf = emalloc(step); max_len = step; - /* XXX: add stream support --Wez. */ while((ret = FP_FREAD(ptr, max_len - len, socket, fp, issock))) { len += ret; Index: ext/standard/fsock.h =================================================================== RCS file: /repository/php4/ext/standard/fsock.h,v retrieving revision 1.40 diff -u -w -B -b -r1.40 fsock.h --- ext/standard/fsock.h 11 Dec 2001 15:30:31 -0000 1.40 +++ ext/standard/fsock.h 14 Feb 2002 00:37:36 -0000 @@ -33,6 +33,7 @@ #if HAVE_PHP_STREAM extern php_stream_ops php_stream_socket_ops; +#define PHP_STREAM_IS_SOCKET (&php_stream_socket_ops) #endif /* stream->abstract points to an instance of this */ Index: main/fopen_wrappers.h =================================================================== RCS file: /repository/php4/main/fopen_wrappers.h,v retrieving revision 1.32 diff -u -w -B -b -r1.32 fopen_wrappers.h --- main/fopen_wrappers.h 1 Feb 2002 20:04:14 -0000 1.32 +++ main/fopen_wrappers.h 14 Feb 2002 00:37:37 -0000 @@ -33,6 +33,8 @@ #endif #define ENFORCE_SAFE_MODE 4 +#define REPORT_ERRORS 8 + #ifdef PHP_WIN32 # define SOCK_ERR INVALID_SOCKET # define SOCK_CONN_ERR SOCKET_ERROR Index: main/main.c =================================================================== RCS file: /repository/php4/main/main.c,v retrieving revision 1.421 diff -u -w -B -b -r1.421 main.c --- main/main.c 5 Feb 2002 06:31:53 -0000 1.421 +++ main/main.c 14 Feb 2002 00:37:39 -0000 @@ -73,6 +73,7 @@ #include "php_content_types.h" #include "php_ticks.h" #include "php_logos.h" +#include "php_streams.h" #include "SAPI.h" /* }}} */ @@ -900,6 +901,16 @@ return FAILURE; } +#if HAVE_PHP_STREAM + /* initialize stream wrappers registry + * (this uses configuration parameters from php.ini) + */ + if (php_init_stream_wrappers(TSRMLS_C) == FAILURE) { + php_printf("PHP: Unable to initialize stream url wrappers.\n"); + return FAILURE; + } +#endif + /* initialize registry for images to be used in phpinfo() (this uses configuration parameters from php.ini) */ @@ -998,6 +1009,11 @@ sapi_flush(TSRMLS_C); zend_shutdown(TSRMLS_C); + +#if HAVE_PHP_STREAM + php_shutdown_stream_wrappers(TSRMLS_C); +#endif + php_shutdown_fopen_wrappers(TSRMLS_C); php_shutdown_info_logos(); UNREGISTER_INI_ENTRIES(); Index: main/php_streams.h =================================================================== RCS file: /repository/php4/main/php_streams.h,v retrieving revision 1.5 diff -u -w -B -b -r1.5 php_streams.h --- main/php_streams.h 11 Dec 2001 15:31:05 -0000 1.5 +++ main/php_streams.h 14 Feb 2002 00:37:39 -0000 @@ -77,7 +77,8 @@ /* operations for a stdio FILE; the FILE * must be placed in stream->abstract */ extern php_stream_ops php_stream_stdio_ops; /* like fopen, but returns a stream */ -PHPAPI php_stream * php_stream_fopen(const char * filename, const char * mode); +PHPAPI php_stream * php_stream_fopen(const char * filename, const char * mode, char **opened_path TSRMLS_DC); +PHPAPI php_stream * php_stream_fopen_with_path(char * filename, char * mode, char * path, char **opened_path TSRMLS_DC); /* coerce the stream into some other form */ /* cast as a stdio FILE * */ @@ -93,7 +94,24 @@ /* use this to check if a stream is of a particular type: * PHPAPI int php_stream_is(php_stream * stream, php_stream_ops * ops); */ -#define php_stream_is(stream, anops) (stream->ops == anops) +#define php_stream_is(stream, anops) ((stream)->ops == anops) + +#define PHP_STREAM_IS_STDIO &php_stream_stdio_ops + +/* Wrappers support */ +/* options uses the IGNORE_URL family of defines from fopen_wrappers.h */ +typedef php_stream * (*php_stream_factory_func_t)(char * filename, char * mode, int options, char ** opened_path TSRMLS_DC); +typedef struct { + char * protocol; + php_stream_factory_func_t create; +} php_stream_wrapper_t; + +int php_init_stream_wrappers(TSRMLS_D); +int php_shutdown_stream_wrappers(TSRMLS_D); +PHPAPI int php_register_url_stream_wrapper(php_stream_wrapper_t * wrapper TSRMLS_DC); +PHPAPI int php_unregister_url_stream_wrapper(php_stream_wrapper_t * wrapper TSRMLS_DC); + +PHPAPI php_stream * php_stream_open_wrapper(char * path, char * mode, int options, char ** opened_path TSRMLS_DC); #endif /* HAVE_PHP_STREAM */ Index: main/streams.c =================================================================== RCS file: /repository/php4/main/streams.c,v retrieving revision 1.8 diff -u -w -B -b -r1.8 streams.c --- main/streams.c 11 Dec 2001 15:31:05 -0000 1.8 +++ main/streams.c 14 Feb 2002 00:37:40 -0000 @@ -14,11 +14,18 @@ +----------------------------------------------------------------------+ | Authors: | | Wez Furlong (wez@thebrainroom.com) | + | Borrowed code from: | + | Rasmus Lerdorf | + | Jim Winstead | +----------------------------------------------------------------------+ */ +/* define this to allow us to fallback on older fopen wrapper handlers */ +#define STREAMS_SUPPORT_FOPEN_WRAPPER 1 + #define _GNU_SOURCE #include "php.h" +#include "php_globals.h" #if HAVE_PHP_STREAM @@ -38,8 +45,10 @@ #define READ_MAX(stream, max) if (stream->is_blocked) stream_read_total(sock, max); else stream_readahead(sock) +static HashTable url_stream_wrappers_hash; + /* allocate a new stream for a particular ops */ -PHPAPI php_stream * php_stream_alloc(php_stream_ops * ops, void * abstract, int persistent, const char * mode) +PHPAPI php_stream * php_stream_alloc(php_stream_ops * ops, void * abstract, int persistent, const char * mode) /* {{{ */ { php_stream * ret; @@ -55,8 +64,9 @@ return ret; } +/* }}} */ -PHPAPI int php_stream_free(php_stream * stream, int call_dtor) +PHPAPI int php_stream_free(php_stream * stream, int call_dtor) /* {{{ */ { int ret = 1; @@ -87,7 +97,9 @@ return ret; } +/* }}} */ +/* {{{ generic stream operations */ PHPAPI size_t php_stream_read(php_stream * stream, char * buf, size_t size) { return stream->ops->read(stream, buf, size); @@ -175,8 +187,9 @@ zend_error(E_WARNING, "streams of type %s do not support seeking", stream->ops->label); return -1; } +/* }}} */ -/*------- STDIO stream implementation -------*/ +/* {{{ ------- STDIO stream implementation -------*/ static size_t php_stdiop_write(php_stream * stream, const char * buf, size_t count) { @@ -243,21 +256,149 @@ "STDIO" }; -PHPAPI php_stream * php_stream_fopen(const char * filename, const char * mode) +PHPAPI php_stream * php_stream_fopen_with_path(char * filename, char * mode, char * path, char **opened_path TSRMLS_DC) /* {{{ */ { - FILE * fp = fopen(filename, mode); + /* code ripped off from fopen_wrappers.c */ + char *pathbuf, *ptr, *end; + char *exec_fname; + char trypath[MAXPATHLEN]; + struct stat sb; + php_stream *stream; + int path_length; + int filename_length; + int exec_fname_length; + + if (opened_path) { + *opened_path = NULL; + } + + if(!filename) { + return NULL; + } + + filename_length = strlen(filename); + + /* Relative path open */ + if (*filename == '.') { + if (PG(safe_mode) && (!php_checkuid(filename, mode, CHECKUID_CHECK_MODE_PARAM))) { + return NULL; + } + return php_stream_fopen(filename, mode, opened_path TSRMLS_CC); + } + + /* + * files in safe_mode_include_dir (or subdir) are excluded from + * safe mode GID/UID checks + */ + + /* Absolute path open */ + if (IS_ABSOLUTE_PATH(filename, filename_length)) { + if ((php_check_safe_mode_include_dir(filename TSRMLS_CC)) == 0) + /* filename is in safe_mode_include_dir (or subdir) */ + return php_stream_fopen(filename, mode, opened_path TSRMLS_CC); + + if (PG(safe_mode) && (!php_checkuid(filename, mode, CHECKUID_CHECK_MODE_PARAM))) + return NULL; + + return php_stream_fopen(filename, mode, opened_path TSRMLS_CC); + } + + if (!path || (path && !*path)) { + if (PG(safe_mode) && (!php_checkuid(filename, mode, CHECKUID_CHECK_MODE_PARAM))) { + return NULL; + } + return php_stream_fopen(filename, mode, opened_path TSRMLS_CC); + } + + /* check in provided path */ + /* append the calling scripts' current working directory + * as a fall back case + */ + if (zend_is_executing(TSRMLS_C)) { + exec_fname = zend_get_executed_filename(TSRMLS_C); + exec_fname_length = strlen(exec_fname); + path_length = strlen(path); + + while ((--exec_fname_length >= 0) && !IS_SLASH(exec_fname[exec_fname_length])); + if ((exec_fname && exec_fname[0] == '[') + || exec_fname_length<=0) { + /* [no active file] or no path */ + pathbuf = estrdup(path); + } else { + pathbuf = (char *) emalloc(exec_fname_length + path_length +1 +1); + memcpy(pathbuf, path, path_length); + pathbuf[path_length] = DEFAULT_DIR_SEPARATOR; + memcpy(pathbuf+path_length+1, exec_fname, exec_fname_length); + pathbuf[path_length + exec_fname_length +1] = '\0'; + } + } else { + pathbuf = estrdup(path); + } + + ptr = pathbuf; + + while (ptr && *ptr) { + end = strchr(ptr, DEFAULT_DIR_SEPARATOR); + if (end != NULL) { + *end = '\0'; + end++; + } + snprintf(trypath, MAXPATHLEN, "%s/%s", ptr, filename); + if (PG(safe_mode)) { + if (VCWD_STAT(trypath, &sb) == 0) { + /* file exists ... check permission */ + if ((php_check_safe_mode_include_dir(trypath TSRMLS_CC) == 0) || + php_checkuid(trypath, mode, CHECKUID_CHECK_MODE_PARAM)) + /* UID ok, or trypath is in safe_mode_include_dir */ + stream = php_stream_fopen(trypath, mode, opened_path TSRMLS_CC); + else + stream = NULL; + + efree(pathbuf); + return stream; + } + } + stream = php_stream_fopen(trypath, mode, opened_path TSRMLS_CC); + if (stream) { + efree(pathbuf); + return stream; + } + ptr = end; + } /* end provided path */ + + efree(pathbuf); + return NULL; + +} +/* }}} */ + +PHPAPI php_stream * php_stream_fopen(const char * filename, const char * mode, char **opened_path TSRMLS_DC) +{ + FILE * fp; + char * realpath; + + realpath = expand_filepath(filename, NULL TSRMLS_C); + + fp = fopen(realpath, mode); if (fp) { php_stream * ret = php_stream_alloc(&php_stream_stdio_ops, fp, 0, mode); - if (ret) + if (ret) { + if (opened_path) + *opened_path = realpath; + return ret; + } fclose(fp); } + efree(realpath); return NULL; } +/* }}} */ +/* {{{ STDIO with fopencookie */ #if HAVE_FOPENCOOKIE static ssize_t stream_cookie_reader(void *cookie, char *buffer, size_t size) { @@ -287,8 +428,9 @@ #else /* TODO: use socketpair() to emulate fopencookie, as suggested by Hartmut ? */ #endif +/* }}} */ -PHPAPI int php_stream_cast(php_stream * stream, int castas, void ** ret, int show_err) +PHPAPI int php_stream_cast(php_stream * stream, int castas, void ** ret, int show_err) /* {{{ */ { if (castas == PHP_STREAM_AS_STDIO) { if (stream->stdiocast) { @@ -355,7 +497,124 @@ return SUCCESS; +} /* }}} */ + +int php_init_stream_wrappers(TSRMLS_D) +{ + if (PG(allow_url_fopen)) + return zend_hash_init(&url_stream_wrappers_hash, 0, NULL, NULL, 1); + return SUCCESS; } + +int php_shutdown_stream_wrappers(TSRMLS_D) +{ + if (PG(allow_url_fopen)) + zend_hash_destroy(&url_stream_wrappers_hash); + return SUCCESS; +} + +PHPAPI int php_register_url_stream_wrapper(php_stream_wrapper_t * wrapper TSRMLS_DC) +{ + if (PG(allow_url_fopen)) + return zend_hash_add(&url_stream_wrappers_hash, wrapper->protocol, strlen(wrapper->protocol), wrapper, sizeof(wrapper), NULL); + return FAILURE; +} +PHPAPI int php_unregister_url_stream_wrapper(php_stream_wrapper_t * wrapper TSRMLS_DC) +{ + if (PG(allow_url_fopen)) + return zend_hash_del(&url_stream_wrappers_hash, wrapper->protocol, strlen(wrapper->protocol)); + return SUCCESS; +} + +static php_stream * php_stream_open_url(char * path, char * mode, int options, char ** opened_path TSRMLS_DC) +{ + php_stream * stream; + php_stream_wrapper_t * wrapper; + const char * p, *protocol = NULL; + int n = 0; + + for (p = path; isalnum((int)*p); p++) + n++; + + if ((*p == ':') && (n > 1)) + protocol = path; + + if (protocol) { +#ifdef STREAMS_SUPPORT_FOPEN_WRAPPER + FILE * fallback; + int issock; + int socketd; +#endif + + if (FAILURE == zend_hash_find(&url_stream_wrappers_hash, (char*)protocol, n, (void**)&wrapper)) { + wrapper = NULL; + protocol = NULL; + } + if (wrapper) + return wrapper->create(path, mode, options, opened_path TSRMLS_CC); + + /* no luck there. We could try the regular fopen wrappers stuff here */ +#ifdef STREAMS_SUPPORT_FOPEN_WRAPPER + fallback = php_fopen_wrapper(path, mode, options, &issock, &socketd, opened_path TSRMLS_CC); + if (issock) { + /* TODO: create a socket stream. For now, fdopen it (yuk!) */ + fallback = fdopen(socketd, mode); + } + if (fallback) { + return php_stream_alloc(&php_stream_stdio_ops, fallback, 0, mode); + } +#endif + } + + if (!protocol || !strncasecmp(protocol, "file", n)) { + if (protocol && path[n+1] == '/' && path[n+2] == '/') { + zend_error(E_WARNING, "remote host file access not supported, %s", path); + return NULL; + } + if (protocol) + path += n + 1; + + /* fall back on regular file access */ + return php_stream_open_wrapper(path, mode, (options & ~REPORT_ERRORS) | IGNORE_URL, + opened_path TSRMLS_CC); + } + return NULL; +} + +PHPAPI php_stream * php_stream_open_wrapper(char * path, char * mode, int options, char ** opened_path TSRMLS_DC) +{ + php_stream * stream = NULL; + + if (opened_path) + *opened_path = NULL; + + if (!path || !*path) + return NULL; + + if (PG(allow_url_fopen) && !(options & IGNORE_URL)) { + stream = php_stream_open_url(path, mode, options, opened_path TSRMLS_CC); + goto out; + } + + if ((options & USE_PATH) && PG(include_path) != NULL) { + stream = php_stream_fopen_with_path(path, mode, PG(include_path), opened_path TSRMLS_CC); + goto out; + } + + if ((options & ENFORCE_SAFE_MODE) && PG(safe_mode) && (!php_checkuid(path, mode, CHECKUID_CHECK_MODE_PARAM))) + return NULL; + + stream = php_stream_fopen(path, mode, opened_path TSRMLS_CC); +out: + if (stream == NULL && (options & REPORT_ERRORS)) { + char * tmp = estrdup(path); + php_strip_url_passwd(tmp); + zend_error(E_WARNING, "%s(\"%s\") - %s", get_active_function_name(TSRMLS_CC), tmp, strerror(errno)); + efree(tmp); + } + return stream; +} + #endif /*