diff options
41 files changed, 2356 insertions, 2148 deletions
diff --git a/configure.in b/configure.in index f0cb00d082..a507735cf2 100644 --- a/configure.in +++ b/configure.in @@ -730,15 +730,6 @@ if test "$PHP_DMALLOC" = "yes"; then ]) fi -# temporary until streams are better integrated -PHP_ARG_ENABLE(php-streams,whether to enable php streams, -[ --enable-php-streams Include experimental php streams. - Do not use unless you are testing the code!]) - -if test "$PHP_PHP_STREAMS" = "yes"; then - AC_DEFINE(HAVE_PHP_STREAM, 1, [Whether to use php streams]) -fi - AC_CHECK_LIB(crypt, crypt, [ PHP_ADD_LIBRARY(crypt) PHP_ADD_LIBRARY(crypt, 1) diff --git a/ext/curl/curl.c b/ext/curl/curl.c index 41f71b0a3a..2413d8b4e7 100644 --- a/ext/curl/curl.c +++ b/ext/curl/curl.c @@ -699,7 +699,14 @@ PHP_FUNCTION(curl_setopt) 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, 1, php_file_le_stream()); + ZEND_VERIFY_RESOURCE(what); + + if (!php_stream_cast((php_stream*)what, PHP_STREAM_AS_STDIO, (void*)&fp, REPORT_ERRORS)) + RETURN_FALSE; if (!fp) { RETURN_FALSE; } diff --git a/ext/exif/exif.c b/ext/exif/exif.c index bce7512862..0b10231bea 100644 --- a/ext/exif/exif.c +++ b/ext/exif/exif.c @@ -3220,8 +3220,8 @@ PHP_FUNCTION(exif_thumbnail) PHP_FUNCTION(exif_imagetype) { zval **arg1; - FILE *fp; - int issock=0, socketd=0, rsrc_id; + php_stream * stream; + int rsrc_id; int itype = 0; if (ZEND_NUM_ARGS() != 1) @@ -3230,27 +3230,15 @@ PHP_FUNCTION(exif_imagetype) if (zend_get_parameters_ex(1, &arg1) == FAILURE) WRONG_PARAM_COUNT; - fp = php_fopen_wrapper(Z_STRVAL_PP(arg1), "rb", IGNORE_PATH|ENFORCE_SAFE_MODE, &issock, &socketd, NULL TSRMLS_CC); + stream = php_stream_open_wrapper(Z_STRVAL_PP(arg1), "rb", IGNORE_PATH|ENFORCE_SAFE_MODE|REPORT_ERRORS, NULL TSRMLS_CC); - if (!fp && !socketd) { - if (issock != BAD_URL) { - char *tmp = estrndup(Z_STRVAL_PP(arg1), Z_STRLEN_PP(arg1)); - php_strip_url_passwd(tmp); - php_error(E_WARNING, "getimagetype: Unable to open '%s' for reading.", tmp); - efree(tmp); - } + if (stream == NULL) { RETURN_FALSE; } - if (issock) { - int *sock=emalloc(sizeof(int)); - *sock = socketd; - rsrc_id = ZEND_REGISTER_RESOURCE(NULL, sock, php_file_le_socket()); - } else { - rsrc_id = ZEND_REGISTER_RESOURCE(NULL, fp, php_file_le_fopen()); - } + rsrc_id = ZEND_REGISTER_RESOURCE(NULL, stream, php_file_le_stream()); - itype = itype = php_getimagetype(socketd, fp, issock, NULL); + itype = itype = php_getimagetype(stream, NULL); zend_list_delete(rsrc_id); @@ -3272,4 +3260,4 @@ PHP_FUNCTION(exif_imagetype) * vim600: sw=4 ts=4 tw=78 fdm=marker * vim<600: sw=4 ts=4 tw=78 */ -
\ No newline at end of file + diff --git a/ext/ftp/ftp.c b/ext/ftp/ftp.c index 3350e86642..4121e8dbf3 100644 --- a/ext/ftp/ftp.c +++ b/ext/ftp/ftp.c @@ -55,12 +55,6 @@ #include "ftp.h" #include "ext/standard/fsock.h" -/* define closesocket macro for portability */ -#ifndef PHP_WIN32 -#undef closesocket -#define closesocket close -#endif - /* sends an ftp command, returns true on success, false on error. * it sends the string "cmd args\r\n" if args is non-null, or * "cmd\r\n" if args is null @@ -547,7 +541,7 @@ ftp_pasv(ftpbuf_t *ftp, int pasv) /* {{{ ftp_get */ int -ftp_get(ftpbuf_t *ftp, FILE *outfp, const char *path, ftptype_t type) +ftp_get(ftpbuf_t *ftp, php_stream *outstream, const char *path, ftptype_t type) { databuf_t *data = NULL; char *ptr; @@ -585,23 +579,23 @@ ftp_get(ftpbuf_t *ftp, FILE *outfp, const char *path, ftptype_t type) if (type == FTPTYPE_ASCII) { for (ptr = data->buf; rcvd; rcvd--, ptr++) { if (lastch == '\r' && *ptr != '\n') - putc('\r', outfp); + php_stream_putc(outstream, '\r'); if (*ptr != '\r') - putc(*ptr, outfp); + php_stream_putc(outstream, *ptr); lastch = *ptr; } } else { - fwrite(data->buf, rcvd, 1, outfp); + php_stream_write(outstream, data->buf, rcvd); } } if (type == FTPTYPE_ASCII && lastch == '\r') - putc('\r', outfp); + php_stream_putc(outstream, '\r'); data = data_close(data); - if (ferror(outfp)) { + if (php_stream_error(outstream)) { goto bail; } @@ -619,7 +613,7 @@ bail: /* {{{ ftp_put */ int -ftp_put(ftpbuf_t *ftp, const char *path, FILE *infp, int insocket, int issock, ftptype_t type) +ftp_put(ftpbuf_t *ftp, const char *path, php_stream * instream, ftptype_t type) { databuf_t *data = NULL; int size; @@ -645,7 +639,7 @@ ftp_put(ftpbuf_t *ftp, const char *path, FILE *infp, int insocket, int issock, f size = 0; ptr = data->buf; - while ((ch = FP_FGETC(insocket, infp, issock))!=EOF && !FP_FEOF(insocket, infp, issock)) { + while ((ch = php_stream_getc(instream))!=EOF && !php_stream_eof(instream)) { /* flush if necessary */ if (FTP_BUFSIZE - size < 2) { if (my_send(ftp, data->fd, data->buf, size) != size) @@ -666,7 +660,7 @@ ftp_put(ftpbuf_t *ftp, const char *path, FILE *infp, int insocket, int issock, f if (size && my_send(ftp, data->fd, data->buf, size) != size) goto bail; - if (!issock && ferror(infp)) + if (php_stream_error(instream)) goto bail; data = data_close(data); diff --git a/ext/ftp/ftp.h b/ext/ftp/ftp.h index a44c463461..38b75b1f73 100644 --- a/ext/ftp/ftp.h +++ b/ext/ftp/ftp.h @@ -130,14 +130,13 @@ int ftp_pasv(ftpbuf_t *ftp, int pasv); /* retrieves a file and saves its contents to outfp * returns true on success, false on error */ -int ftp_get(ftpbuf_t *ftp, FILE *outfp, const char *path, +int ftp_get(ftpbuf_t *ftp, php_stream * outstream, const char *path, ftptype_t type); /* stores the data from a file, socket, or process as a file on the remote server * returns true on success, false on error */ -int ftp_put(ftpbuf_t *ftp, const char *path, FILE *infp, - int insocket, int issock, ftptype_t type); +int ftp_put(ftpbuf_t *ftp, const char *path, php_stream * instream, ftptype_t type); /* returns the size of the given file, or -1 on error */ int ftp_size(ftpbuf_t *ftp, const char *path); diff --git a/ext/ftp/php_ftp.c b/ext/ftp/php_ftp.c index eb2f8bc4d5..9d2673360a 100644 --- a/ext/ftp/php_ftp.c +++ b/ext/ftp/php_ftp.c @@ -114,7 +114,6 @@ PHP_MINFO_FUNCTION(ftp) xtype = mode; \ } -#define FILEP(fp, pval) ZEND_FETCH_RESOURCE(fp, FILE *, &pval, -1, "File-Handle", php_file_le_fopen()); /* {{{ proto resource ftp_connect(string host [, int port [, int timeout)]]) Opens a FTP stream */ @@ -401,7 +400,7 @@ PHP_FUNCTION(ftp_fget) zval *z_ftp, *z_file; ftpbuf_t *ftp; ftptype_t xtype; - FILE *fp; + php_stream *stream; char *file; int file_len, mode; @@ -410,15 +409,15 @@ PHP_FUNCTION(ftp_fget) } ZEND_FETCH_RESOURCE(ftp, ftpbuf_t*, &z_ftp, -1, le_ftpbuf_name, le_ftpbuf); - FILEP(fp, z_file); + ZEND_FETCH_RESOURCE(stream, php_stream*, &z_file, -1, "File-Handle", php_file_le_stream()); XTYPE(xtype, mode); - if (!ftp_get(ftp, fp, file, xtype) || ferror(fp)) { + if (!ftp_get(ftp, stream, file, xtype) || php_stream_error(stream)) { php_error(E_WARNING, "%s(): %s", get_active_function_name(TSRMLS_C), ftp->inbuf); RETURN_FALSE; } - if (ferror(fp)) { + if (php_stream_error(stream)) { php_error(E_WARNING, "%s(): error writing %s", get_active_function_name(TSRMLS_C), Z_STRVAL_P(z_file)); RETURN_FALSE; } @@ -456,8 +455,7 @@ PHP_FUNCTION(ftp_get) zval *z_ftp; ftpbuf_t *ftp; ftptype_t xtype; - FILE *outfp, *tmpfp; - int ch; + php_stream * tmpstream, *outstream; char *local, *remote; int local_len, remote_len, mode; @@ -471,42 +469,35 @@ PHP_FUNCTION(ftp_get) /* get to temporary file, so if there is an error, no existing * file gets clobbered */ - if ((tmpfp = tmpfile()) == NULL) { - php_error(E_WARNING, "%s(): error opening tmpfile", get_active_function_name(TSRMLS_C)); + tmpstream = php_stream_fopen_tmpfile(); + if (tmpstream == NULL) { RETURN_FALSE; } - if (!ftp_get(ftp, tmpfp, remote, xtype) || ferror(tmpfp)) { - fclose(tmpfp); + if (!ftp_get(ftp, tmpstream, remote, xtype) || php_stream_error(tmpstream)) { + php_stream_close(tmpstream); php_error(E_WARNING, "ftp_get: %s", ftp->inbuf); RETURN_FALSE; } -#ifdef PHP_WIN32 - if ((outfp = VCWD_FOPEN(local, "wb")) == NULL) { -#else - if ((outfp = VCWD_FOPEN(local, "w")) == NULL) { -#endif - fclose(tmpfp); + outstream = php_stream_fopen(local, "wb", NULL TSRMLS_C); + + if (outstream == NULL) { + php_stream_close(tmpstream); php_error(E_WARNING, "%s(): error opening %s", get_active_function_name(TSRMLS_C), local); RETURN_FALSE; } - rewind(tmpfp); - while ((ch = getc(tmpfp)) != EOF) - putc(ch, outfp); - - if (ferror(tmpfp) || ferror(outfp)) { - fclose(tmpfp); - fclose(outfp); + php_stream_rewind(tmpstream); + if (php_stream_copy_to_stream(tmpstream, outstream, 0) == 0) { php_error(E_WARNING, "%s(): error writing %s", get_active_function_name(TSRMLS_C), local); - RETURN_FALSE; + RETVAL_FALSE; } + else + RETVAL_TRUE; - fclose(tmpfp); - fclose(outfp); - - RETURN_TRUE; + php_stream_close(tmpstream); + php_stream_close(outstream); } /* }}} */ @@ -517,8 +508,8 @@ PHP_FUNCTION(ftp_fput) zval *z_ftp, *z_file; ftpbuf_t *ftp; ftptype_t xtype; - int type, mode, remote_len; - void *rsrc; + int mode, remote_len; + php_stream *stream; char *remote; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsrl", &z_ftp, &remote, &remote_len, &z_file, &mode) == FAILURE) { @@ -526,11 +517,10 @@ PHP_FUNCTION(ftp_fput) } ZEND_FETCH_RESOURCE(ftp, ftpbuf_t*, &z_ftp, -1, le_ftpbuf_name, le_ftpbuf); - rsrc = zend_fetch_resource(&z_file TSRMLS_CC, -1, "File-Handle", &type, 3, php_file_le_fopen(), php_file_le_popen(), php_file_le_socket()); - ZEND_VERIFY_RESOURCE(rsrc); + ZEND_FETCH_RESOURCE(stream, php_stream*, &z_file, -1, "File-Handle", php_file_le_stream()); XTYPE(xtype, mode); - if (!ftp_put(ftp, remote, (FILE*)rsrc, *(int*) rsrc, (type==php_file_le_socket()), xtype)) { + if (!ftp_put(ftp, remote, stream, xtype)) { php_error(E_WARNING, "%s(): %s", get_active_function_name(TSRMLS_C), ftp->inbuf); RETURN_FALSE; } @@ -546,9 +536,9 @@ PHP_FUNCTION(ftp_put) zval *z_ftp; ftpbuf_t *ftp; ftptype_t xtype; - FILE *infp; char *remote, *local; int remote_len, local_len, mode; + php_stream * instream; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rssl", &z_ftp, &remote, &remote_len, &local, &local_len, &mode) == FAILURE) { return; @@ -557,20 +547,18 @@ PHP_FUNCTION(ftp_put) ZEND_FETCH_RESOURCE(ftp, ftpbuf_t*, &z_ftp, -1, le_ftpbuf_name, le_ftpbuf); XTYPE(xtype, mode); -#ifdef PHP_WIN32 - if ((infp = VCWD_FOPEN(local, "rb")) == NULL) { -#else - if ((infp = VCWD_FOPEN(local, "r")) == NULL) { -#endif - php_error(E_WARNING, "%s(): error opening %s", get_active_function_name(TSRMLS_C), local); + instream = php_stream_fopen(local, "rb", NULL TSRMLS_C); + + if (instream == NULL) { RETURN_FALSE; } - if (!ftp_put(ftp, remote, infp, 0, 0, xtype) || ferror(infp)) { - fclose(infp); + + if (!ftp_put(ftp, remote, instream, xtype) || php_stream_error(instream)) { + php_stream_close(instream); php_error(E_WARNING, "%s(): %s", get_active_function_name(TSRMLS_C), ftp->inbuf); RETURN_FALSE; } - fclose(infp); + php_stream_close(instream); RETURN_TRUE; } diff --git a/ext/gd/gd.c b/ext/gd/gd.c index 1709c68ade..2bdeb0b6d4 100644 --- a/ext/gd/gd.c +++ b/ext/gd/gd.c @@ -441,8 +441,7 @@ PHP_FUNCTION(imageloadfont) int hdr_size = sizeof(gdFont) - sizeof(char *); int ind, body_size, n=0, b, i, body_size_check; gdFontPtr font; - FILE *fp; - int issock=0, socketd=0; + php_stream * stream; if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &file) == FAILURE) { ZEND_WRONG_PARAM_COUNT(); @@ -450,13 +449,8 @@ PHP_FUNCTION(imageloadfont) convert_to_string_ex(file); -#ifdef PHP_WIN32 - fp = VCWD_FOPEN(Z_STRVAL_PP(file), "rb"); -#else - fp = php_fopen_wrapper(Z_STRVAL_PP(file), "r", IGNORE_PATH|IGNORE_URL_WIN, &issock, &socketd, NULL TSRMLS_CC); -#endif - if (fp == NULL) { - php_error(E_WARNING, "ImageFontLoad: unable to open file"); + stream = php_stream_open_wrapper(Z_STRVAL_PP(file), "rb", IGNORE_PATH|IGNORE_URL_WIN|REPORT_ERRORS, NULL TSRMLS_CC); + if (stream == NULL) { RETURN_FALSE; } @@ -474,22 +468,22 @@ PHP_FUNCTION(imageloadfont) */ font = (gdFontPtr)emalloc(sizeof(gdFont)); b = 0; - while (b < hdr_size && (n = fread(&font[b], 1, hdr_size - b, fp))) + while (b < hdr_size && (n = php_stream_read(stream, (char*)&font[b], hdr_size - b))) b += n; if (!n) { - fclose(fp); + php_stream_close(stream); efree(font); - if (feof(fp)) { + if (php_stream_eof(stream)) { php_error(E_WARNING, "ImageFontLoad: end of file while reading header"); } else { php_error(E_WARNING, "ImageFontLoad: error while reading header"); } RETURN_FALSE; } - i = ftell(fp); - fseek(fp, 0, SEEK_END); - body_size_check = ftell(fp) - hdr_size; - fseek(fp, i, SEEK_SET); + i = php_stream_tell(stream); + php_stream_seek(stream, 0, SEEK_END); + body_size_check = php_stream_tell(stream) - hdr_size; + php_stream_seek(stream, i, SEEK_SET); body_size = font->w * font->h * font->nchars; if (body_size != body_size_check) { font->w = FLIPWORD(font->w); @@ -505,20 +499,20 @@ PHP_FUNCTION(imageloadfont) font->data = emalloc(body_size); b = 0; - while (b < body_size && (n = fread(&font->data[b], 1, body_size - b, fp))) + while (b < body_size && (n = php_stream_read(stream, &font->data[b], body_size - b))) b += n; if (!n) { - fclose(fp); + php_stream_close(stream); efree(font->data); efree(font); - if (feof(fp)) { + if (php_stream_eof(stream)) { php_error(E_WARNING, "ImageFontLoad: end of file while reading body"); } else { php_error(E_WARNING, "ImageFontLoad: error while reading body"); } RETURN_FALSE; } - fclose(fp); + php_stream_close(stream); /* Adding 5 to the font index so we will never have font indices * that overlap with the old fonts (with indices 1-5). The first @@ -1132,17 +1126,15 @@ PHP_FUNCTION(imagecreatefromstring) } /* }}} */ -size_t php_fread_all(char **buf, int socket, FILE *fp, int issock); - /* {{{ _php_image_create_from */ static void _php_image_create_from(INTERNAL_FUNCTION_PARAMETERS, int image_type, char *tn, gdImagePtr (*func_p)(), gdImagePtr (*ioctx_func_p)()) { zval **file, **srcx, **srcy, **width, **height; - gdImagePtr im; + gdImagePtr im = NULL; char *fn=NULL; - FILE *fp; - int issock=0, socketd=0; + php_stream * stream; + FILE * fp = NULL; int argc=ZEND_NUM_ARGS(); if ((image_type == PHP_GDIMG_TYPE_GD2PART && argc != 4) || @@ -1158,14 +1150,8 @@ static void _php_image_create_from(INTERNAL_FUNCTION_PARAMETERS, int image_type, fn = Z_STRVAL_PP(file); -#ifdef PHP_WIN32 - fp = VCWD_FOPEN(fn, "rb"); -#else - fp = php_fopen_wrapper(fn, "r", IGNORE_PATH|IGNORE_URL_WIN, &issock, &socketd, NULL TSRMLS_CC); -#endif - if (!fp && !socketd) { - php_strip_url_passwd(fn); - php_error(E_WARNING, "%s: Unable to open '%s' for reading", get_active_function_name(TSRMLS_C), fn); + stream = php_stream_open_wrapper(fn, "rb", REPORT_ERRORS|IGNORE_PATH|IGNORE_URL_WIN, NULL TSRMLS_CC); + if (stream == NULL) { RETURN_FALSE; } @@ -1173,32 +1159,29 @@ static void _php_image_create_from(INTERNAL_FUNCTION_PARAMETERS, int image_type, ioctx_func_p = NULL; /* don't allow sockets without IOCtx */ #endif - if(issock && !ioctx_func_p) { - php_error(E_WARNING, "%s: Sockets are not supported for image type '%s'", get_active_function_name(TSRMLS_C), tn); - RETURN_FALSE; + /* try and avoid allocating a FILE* if the stream is not naturally a FILE* */ + if (php_stream_is(stream, PHP_STREAM_IS_STDIO)) { + php_stream_cast(stream, PHP_STREAM_AS_STDIO, (void**)&fp, REPORT_ERRORS); } - - if(issock && socketd) { + else if (ioctx_func_p) { #ifdef USE_GD_IOCTX + /* we can create an io context */ gdIOCtx* io_ctx; size_t buff_size; - char *buff, *buff_em; + char *buff; - buff_size = php_fread_all(&buff_em, socketd, fp, issock); + /* needs to be malloc (persistent) - GD will free() it later */ + buff_size = php_stream_read_all(stream, &buff, 1); if(!buff_size) { php_error(E_WARNING,"%s: Cannot read image data", get_active_function_name(TSRMLS_C)); - RETURN_FALSE; + goto out_err; } - buff = malloc(buff_size); /* Should be malloc! GD uses free */ - memcpy(buff, buff_em, buff_size); - efree(buff_em); - io_ctx = gdNewDynamicCtx(buff_size, buff); if(!io_ctx) { php_error(E_WARNING,"%s: Cannot allocate GD IO context", get_active_function_name(TSRMLS_C)); - RETURN_FALSE; + goto out_err; } if (image_type == PHP_GDIMG_TYPE_GD2PART) { im = (*ioctx_func_p)(io_ctx, Z_LVAL_PP(srcx), Z_LVAL_PP(srcy), Z_LVAL_PP(width), Z_LVAL_PP(height)); @@ -1206,8 +1189,15 @@ static void _php_image_create_from(INTERNAL_FUNCTION_PARAMETERS, int image_type, im = (*ioctx_func_p)(io_ctx); } io_ctx->free(io_ctx); -#endif - } else { +#endif + } + else { + /* try and force the stream to be FILE* */ + if (FAILURE == php_stream_cast(stream, PHP_STREAM_AS_STDIO | PHP_STREAM_CAST_TRY_HARD, (void**)&fp, REPORT_ERRORS)) + goto out_err; + } + + if (!im && fp) { if (image_type == PHP_GDIMG_TYPE_GD2PART) { im = (*func_p)(fp, Z_LVAL_PP(srcx), Z_LVAL_PP(srcy), Z_LVAL_PP(width), Z_LVAL_PP(height)); } else { @@ -1215,15 +1205,18 @@ static void _php_image_create_from(INTERNAL_FUNCTION_PARAMETERS, int image_type, } fflush(fp); - fclose(fp); } - if (!im) { - php_error(E_WARNING,"%s: '%s' is not a valid %s file", get_active_function_name(TSRMLS_C), fn, tn); - RETURN_FALSE; + if (im) { + ZEND_REGISTER_RESOURCE(return_value, im, le_gd); + return; } - ZEND_REGISTER_RESOURCE(return_value, im, le_gd); + php_error(E_WARNING,"%s: '%s' is not a valid %s file", get_active_function_name(TSRMLS_C), fn, tn); +out_err: + php_stream_close(stream); + RETURN_FALSE; + } /* }}} */ diff --git a/ext/hyperwave/hw.c b/ext/hyperwave/hw.c index 4720763893..cc2991dab8 100644 --- a/ext/hyperwave/hw.c +++ b/ext/hyperwave/hw.c @@ -38,9 +38,6 @@ #else #include "build-defs.h" #endif -#ifdef HAVE_MMAP -#include <sys/mman.h> -#endif #if HYPERWAVE @@ -2861,7 +2858,6 @@ PHP_FUNCTION(hw_new_document) } /* }}} */ -#define BUFSIZE 8192 /* {{{ proto hwdoc hw_new_document_from_file(string objrec, string filename) Create a new document from a file */ PHP_FUNCTION(hw_new_document_from_file) @@ -2872,6 +2868,7 @@ PHP_FUNCTION(hw_new_document_from_file) int issock=0; int socketd=0; FILE *fp; + php_stream * stream; int ready=0; int bcount=0; int use_include_path=0; @@ -2884,14 +2881,10 @@ PHP_FUNCTION(hw_new_document_from_file) convert_to_string_ex(arg1); convert_to_string_ex(arg2); - fp = php_fopen_wrapper(Z_STRVAL_PP(arg2), "r", use_include_path|ENFORCE_SAFE_MODE, &issock, &socketd, NULL TSRMLS_CC); - if (!fp && !socketd){ - if (issock != BAD_URL) { - char *tmp = estrndup(Z_STRVAL_PP(arg2), Z_STRLEN_PP(arg2)); - php_strip_url_passwd(tmp); - php_error(E_WARNING, "hw_new_document_from_file(\"%s\") - %s", tmp, strerror(errno)); - efree(tmp); - } + stream = php_stream_open_wrapper(Z_STRVAL_PP(arg2), "r", use_include_path|ENFORCE_SAFE_MODE|REPORT_ERRORS, + NULL TSRMLS_CC); + + if (stream == NULL) { RETURN_FALSE; } @@ -2899,60 +2892,10 @@ PHP_FUNCTION(hw_new_document_from_file) if(NULL == doc) RETURN_FALSE; -#ifdef HAVE_MMAP - if(!issock) { - int fd; - struct stat sbuf; - off_t off; - void *p; - size_t len; - - fd = fileno(fp); - fstat(fd, &sbuf); - - if (sbuf.st_size > BUFSIZE) { - off = ftell(fp); - len = sbuf.st_size - off; - p = mmap(0, len, PROT_READ, MAP_SHARED, fd, off); - if (p != (void *) MAP_FAILED) { - doc->data = malloc(len); - if(NULL == doc->data) { - munmap(p, len); - free(doc); - RETURN_FALSE; - } - memcpy(doc->data, p, len); - munmap(p, len); - bcount = len; - doc->size = len; - ready = 1; - } - } - } -#endif - - if(!ready) { - int b; - - doc->data = malloc(BUFSIZE); - if(NULL == doc->data) { - free(doc); - RETURN_FALSE; - } - ptr = doc->data; - while ((b = FP_FREAD(&ptr[bcount], BUFSIZE, socketd, fp, issock)) > 0) { - bcount += b; - doc->data = realloc(doc->data, bcount+BUFSIZE); - ptr = doc->data; - } - } - - if (issock) { - SOCK_FCLOSE(socketd); - } else { - fclose(fp); - } + doc->size = php_stream_read_all(stream, &doc->data, 1); + php_stream_close(stream); + doc->data = realloc(doc->data, bcount+1); ptr = doc->data; ptr[bcount] = '\0'; @@ -2963,7 +2906,6 @@ PHP_FUNCTION(hw_new_document_from_file) Z_TYPE_P(return_value) = IS_LONG; } /* }}} */ -#undef BUFSIZE /* {{{ proto void hw_free_document(hwdoc doc) Frees memory of document */ diff --git a/ext/interbase/interbase.c b/ext/interbase/interbase.c index 86dce7501f..22b2baf7ba 100644 --- a/ext/interbase/interbase.c +++ b/ext/interbase/interbase.c @@ -2867,13 +2867,12 @@ PHP_FUNCTION(ibase_blob_import) zval **link_arg, **file_arg; int trans_n = 0, link_id = 0, trans_id = 0, size; unsigned short b; - int issock=0, socketd=0; ibase_blob_handle ib_blob; ibase_db_link *ib_link; char bl_data[IBASE_BLOB_SEG]; /* FIXME? blob_seg_size parameter? */ - FILE *fp; void * what; int type; + php_stream * stream; RESET_ERRMSG; @@ -2901,11 +2900,8 @@ PHP_FUNCTION(ibase_blob_import) RETURN_FALSE; } - what = zend_fetch_resource(file_arg TSRMLS_CC, -1, "File-Handle", &type, 2, php_file_le_fopen(), php_file_le_stream()); - ZEND_VERIFY_RESOURCE(what); - - if (type == php_file_le_fopen()) - fp = (FILE*)what; + stream = (php_stream*)zend_fetch_resource(file_arg TSRMLS_CC, -1, "File-Handle", &type, 1, php_file_le_stream()); + ZEND_VERIFY_RESOURCE(stream); ib_blob.link = ib_link->link; ib_blob.trans_handle = ib_link->trans[trans_n]; @@ -2920,32 +2916,15 @@ PHP_FUNCTION(ibase_blob_import) size = 0; -#if HAVE_PHP_STREAM - if (type == php_file_le_stream()) { - while(b = php_stream_read((php_stream*)what, bl_data, 1, sizeof(bl_data)) > 0) { - if (isc_put_segment(IB_STATUS, &ib_blob.bl_handle, b, bl_data)) { - _php_ibase_error(); - RETURN_FALSE; - } - size += b; - - } - } - else { -#endif - /* Can't see much use for the issock stuff here, it should be nuked --Wez */ - while (issock?(b=SOCK_FREAD(bl_data, sizeof(bl_data), socketd)):(b = fread(bl_data, 1, sizeof(bl_data), fp)) > 0) { + while(b = php_stream_read((php_stream*)what, bl_data, 1, sizeof(bl_data)) > 0) { if (isc_put_segment(IB_STATUS, &ib_blob.bl_handle, b, bl_data)) { _php_ibase_error(); RETURN_FALSE; } size += b; + } -#if HAVE_PHP_STREAM - } -#endif - if (isc_close_blob(IB_STATUS, &ib_blob.bl_handle)) { _php_ibase_error(); RETURN_FALSE; diff --git a/ext/mailparse/mailparse.c b/ext/mailparse/mailparse.c index 6fed12f1de..d3cb046951 100755 --- a/ext/mailparse/mailparse.c +++ b/ext/mailparse/mailparse.c @@ -149,12 +149,12 @@ static void mailparse_rfc822t_errfunc(const char * msg, int num) } #define UUDEC(c) (char)(((c)-' ')&077) -#define UU_NEXT(v) v = fgetc(infp); if (v == EOF) break; v = UUDEC(v) -static void mailparse_do_uudecode(FILE * infp, FILE * outfp) +#define UU_NEXT(v) v = php_stream_getc(instream); if (v == EOF) break; v = UUDEC(v) +static void mailparse_do_uudecode(php_stream * instream, php_stream * outstream) { int A, B, C, D, n; - while(!feof(infp)) { + while(!php_stream_eof(instream)) { UU_NEXT(n); while(n != 0) { @@ -164,14 +164,14 @@ static void mailparse_do_uudecode(FILE * infp, FILE * outfp) UU_NEXT(D); if (n-- > 0) - fputc( (A << 2) | (B >> 4), outfp); + php_stream_putc(outstream, (A << 2) | (B >> 4)); if (n-- > 0) - fputc( (B << 4) | (C >> 2), outfp); + php_stream_putc(outstream, (B << 4) | (C >> 2)); if (n-- > 0) - fputc( (C << 6) | D, outfp); + php_stream_putc(outstream, (C << 6) | D); } /* skip newline */ - fgetc(infp); + php_stream_getc(instream); } } @@ -181,28 +181,28 @@ static void mailparse_do_uudecode(FILE * infp, FILE * outfp) PHP_FUNCTION(mailparse_uudecode_all) { zval * file, * item; - FILE *infp, *outfp=NULL, *partfp=NULL; int type; char * buffer = NULL; char * outpath = NULL; int nparts = 0; + php_stream * instream, *outstream = NULL, *partstream = NULL; 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()); - ZEND_VERIFY_RESOURCE(infp); + instream = (php_stream*)zend_fetch_resource(&file TSRMLS_CC, -1, "File-Handle", &type, 1, php_file_le_stream()); + ZEND_VERIFY_RESOURCE(instream); - outfp = php_open_temporary_file(NULL, "mailparse", &outpath TSRMLS_CC); - if (outfp == NULL) { + outstream = php_stream_fopen_temporary_file(NULL, "mailparse", &outpath TSRMLS_CC); + if (outstream == NULL) { zend_error(E_WARNING, "%s(): unable to open temp file", get_active_function_name(TSRMLS_C)); RETURN_FALSE; } - rewind(infp); + php_stream_rewind(instream); buffer = emalloc(4096); - while(fgets(buffer, 4096, infp)) { + while(php_stream_gets(instream, buffer, 4096)) { /* Look for the "begin " sequence that identifies a uuencoded file */ if (strncmp(buffer, "begin ", 6) == 0) { char * origfilename; @@ -232,24 +232,24 @@ PHP_FUNCTION(mailparse_uudecode_all) add_assoc_string(item, "origfilename", origfilename, 1); /* create a temp file for the data */ - partfp = php_open_temporary_file(NULL, "mailparse", &outpath TSRMLS_CC); - if (partfp) { + partstream = php_stream_fopen_temporary_file(NULL, "mailparse", &outpath TSRMLS_CC); + if (partstream) { nparts++; add_assoc_string(item, "filename", outpath, 0); add_next_index_zval(return_value, item); /* decode it */ - mailparse_do_uudecode(infp, partfp); - fclose(partfp); + mailparse_do_uudecode(instream, partstream); + php_stream_close(partstream); } } else { /* write to the output file */ - fputs(buffer, outfp); + php_stream_puts(outstream, buffer); } } - fclose(outfp); - rewind(infp); + php_stream_close(outstream); + php_stream_rewind(instream); efree(buffer); if (nparts == 0) { @@ -317,7 +317,6 @@ PHP_FUNCTION(mailparse_rfc822_parse_addresses) PHP_FUNCTION(mailparse_determine_best_xfer_encoding) { zval ** file; - FILE * fp; int longline = 0; int linelen = 0; int c; @@ -330,10 +329,9 @@ PHP_FUNCTION(mailparse_determine_best_xfer_encoding) WRONG_PARAM_COUNT; } - what = zend_fetch_resource(file TSRMLS_CC, -1, "File-Handle", &type, 2, php_file_le_fopen(), php_file_le_stream()); + what = zend_fetch_resource(file TSRMLS_CC, -1, "File-Handle", &type, 1, php_file_le_stream()); ZEND_VERIFY_RESOURCE(what); -#if HAVE_PHP_STREAM if (type == php_file_le_stream()) { php_stream * stream = (php_stream*)what; @@ -358,33 +356,6 @@ PHP_FUNCTION(mailparse_determine_best_xfer_encoding) bestenc = mbfl_no_encoding_qprint; php_stream_rewind(stream); } - else { -#endif - fp = (FILE*)what; - - rewind(fp); - while(!feof(fp)) { - c = fgetc(fp); - 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; - } - if (longline) - bestenc = mbfl_no_encoding_qprint; - rewind(fp); -#if HAVE_PHP_STREAM - } -#endif name = (char *)mbfl_no2preferred_mime_name(bestenc); if (name) @@ -401,25 +372,28 @@ PHP_FUNCTION(mailparse_determine_best_xfer_encoding) /* {{{ proto boolean mailparse_stream_encode(resource sourcefp, resource destfp, string encoding) Streams data from source file pointer, apply encoding and write to destfp */ -static int mailparse_fp_output(int c, void * fp) +static int mailparse_stream_output(int c, void * stream) { - return fputc(c, (FILE*)fp); + char buf = c; + return php_stream_write((php_stream*)stream, &buf, 1); } -static int mailparse_fp_flush(void * fp) +static int mailparse_stream_flush(void * stream) { - return fflush((FILE*)fp); + return php_stream_flush((php_stream*)stream); } PHP_FUNCTION(mailparse_stream_encode) { zval ** srcfile, ** destfile, ** encod; - FILE * srcfp, * destfp; + void * what; + int type; + php_stream * srcstream, * deststream; char * buf; size_t len; size_t bufsize = 2048; enum mbfl_no_encoding enc; mbfl_convert_filter * conv = NULL; - + if (ZEND_NUM_ARGS() != 3 || zend_get_parameters_ex(3, &srcfile, &destfile, &encod) == FAILURE) { WRONG_PARAM_COUNT; } @@ -427,12 +401,18 @@ PHP_FUNCTION(mailparse_stream_encode) 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, 1, php_file_le_stream()); + ZEND_VERIFY_RESOURCE(what); + + srcstream = (php_stream*)what; + + what = zend_fetch_resource(destfile TSRMLS_CC, -1, "File-Handle", &type, 1, php_file_le_stream()); + ZEND_VERIFY_RESOURCE(what); + deststream = (php_stream*)what; convert_to_string_ex(encod); enc = mbfl_name2no_encoding(Z_STRVAL_PP(encod)); @@ -449,12 +429,13 @@ PHP_FUNCTION(mailparse_stream_encode) conv = mbfl_convert_filter_new(mbfl_no_encoding_8bit, enc, - mailparse_fp_output, - mailparse_fp_flush, - destfp + mailparse_stream_output, + mailparse_stream_flush, + deststream ); - while(!feof(srcfp)) { - len = fread(buf, sizeof(char), bufsize, srcfp); + + while(!php_stream_eof(srcstream)) { + len = php_stream_read(srcstream, buf, bufsize); if (len > 0) { int i; @@ -462,7 +443,7 @@ PHP_FUNCTION(mailparse_stream_encode) mbfl_convert_filter_feed(buf[i], conv); } } - + mbfl_convert_filter_flush(conv); mbfl_convert_filter_delete(conv); efree(buf); diff --git a/ext/ming/ming.c b/ext/ming/ming.c index 69bcb57c3a..46d0168c46 100644 --- a/ext/ming/ming.c +++ b/ext/ming/ming.c @@ -28,6 +28,7 @@ #include "ext/standard/info.h" #include "ext/standard/file.h" #include "ext/standard/fsock.h" +#include "php_streams.h" #if HAVE_MING @@ -229,18 +230,18 @@ static SWFInput newSWFInput_sock(int socket) static SWFInput getInput(zval **zfile TSRMLS_DC) { FILE *file; + void * what; int type; SWFInput input; - file = (FILE *) zend_fetch_resource(zfile TSRMLS_CC, -1, "File-Handle", &type, 3, php_file_le_fopen(), php_file_le_popen(), php_file_le_socket()); + what = zend_fetch_resource(zfile TSRMLS_CC, -1, "File-Handle", &type, 1, php_file_le_stream()); - if(type == php_file_le_socket()) - input = newSWFInput_sock(*(int *)file); - else - { - input = newSWFInput_file(file); - zend_list_addref(Z_LVAL_PP(zfile)); + if (!php_stream_cast((php_stream*)what, PHP_STREAM_AS_STDIO_FILE, (void*)&file, REPORT_ERRORS)) { + return NULL; } + + input = newSWFInput_file(file); + zend_list_addref(Z_LVAL_PP(zfile)); zend_list_addref(zend_list_insert(input, le_swfinputp)); @@ -1577,22 +1578,22 @@ PHP_FUNCTION(swfmovie_output) /* }}} */ /* {{{ swfmovie_saveToFile */ -void phpFileOutputMethod(byte b, void *data) +void phpStreamOutputMethod(byte b, void * data) { - fwrite(&b, 1, 1, (FILE *)data); + php_stream_write((php_stream*)data, &b, 1); } PHP_FUNCTION(swfmovie_saveToFile) { zval **x; SWFMovie movie = getMovie(getThis() TSRMLS_CC); - void *what; + php_stream *what; if((ZEND_NUM_ARGS() != 1) || zend_get_parameters_ex(1, &x) == FAILURE) WRONG_PARAM_COUNT; - ZEND_FETCH_RESOURCE(what, FILE *, x, -1,"File-Handle",php_file_le_fopen()); - RETURN_LONG(SWFMovie_output(movie, &phpFileOutputMethod, what)); + ZEND_FETCH_RESOURCE(what, php_stream *, x, -1,"File-Handle",php_file_le_stream()); + RETURN_LONG(SWFMovie_output(movie, &phpStreamOutputMethod, what)); } @@ -1602,29 +1603,29 @@ PHP_FUNCTION(swfmovie_saveToFile) PHP_FUNCTION(swfmovie_save) { zval **x; - FILE *file; long retval; + php_stream * stream; if((ZEND_NUM_ARGS() != 1) || zend_get_parameters_ex(1, &x) == FAILURE) WRONG_PARAM_COUNT; if(Z_TYPE_PP(x) == IS_RESOURCE) { - ZEND_FETCH_RESOURCE(file, FILE *, x, -1,"File-Handle",php_file_le_fopen()); + ZEND_FETCH_RESOURCE(stream, php_stream *, x, -1,"File-Handle",php_file_le_stream()); RETURN_LONG(SWFMovie_output(getMovie(getThis() TSRMLS_CC), - &phpFileOutputMethod, file)); + &phpStreamOutputMethod, stream)); } convert_to_string_ex(x); - file = VCWD_FOPEN(Z_STRVAL_PP(x), "wb"); + stream = php_stream_open_wrapper(Z_STRVAL_PP(x), "wb", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL, TSRMLS_CC); - if(file == NULL) - php_error(E_ERROR, "couldn't open file %s for writing", Z_STRVAL_PP(x)); + if (stream == NULL) + RETURN_FALSE; retval = SWFMovie_output(getMovie(getThis() TSRMLS_CC), - &phpFileOutputMethod, (void *)file); + &phpStreamOutputMethod, (void *)stream); fclose(file); diff --git a/ext/pdf/pdf.c b/ext/pdf/pdf.c index 5aa6d4394c..f283f0ce87 100644 --- a/ext/pdf/pdf.c +++ b/ext/pdf/pdf.c @@ -36,6 +36,7 @@ #include "ext/standard/head.h" #include "ext/standard/info.h" #include "ext/standard/file.h" +#include "php_streams.h" #if HAVE_LIBGD13 #include "ext/gd/php_gd.h" @@ -464,7 +465,9 @@ PHP_FUNCTION(pdf_set_info_keywords) PHP_FUNCTION(pdf_open) { zval **file; - FILE *fp; + void * what; + int type; + FILE *fp = NULL; PDF *pdf; int argc = ZEND_NUM_ARGS(); @@ -473,7 +476,12 @@ PHP_FUNCTION(pdf_open) if (argc != 1 || zend_get_parameters_ex(1, &file) == FAILURE) { fp = NULL; } else { - ZEND_FETCH_RESOURCE(fp, FILE *, file, -1, "File-Handle", php_file_le_fopen()); + what = zend_fetch_resource(file TSRMLS_CC, -1, "File-Handle", &type, 1, php_file_le_stream()); + ZEND_VERIFY_RESOURCE(what); + + if (!php_stream_cast((php_stream*)what, PHP_STREAM_AS_STDIO, (void*)&fp, 1) == FAILURE) { + RETURN_FALSE; + } /* XXX should do a zend_list_addref for <fp> here! */ } diff --git a/ext/pgsql/pgsql.c b/ext/pgsql/pgsql.c index fa96dd254c..35d31bcae5 100644 --- a/ext/pgsql/pgsql.c +++ b/ext/pgsql/pgsql.c @@ -1434,9 +1434,8 @@ PHP_FUNCTION(pg_trace) int id = -1; PGconn *pgsql; char *mode = "w"; - int issock, socketd; FILE *fp; - + php_stream * stream; id = PGG(default_link); switch (ZEND_NUM_ARGS()) { @@ -1469,15 +1468,18 @@ PHP_FUNCTION(pg_trace) ZEND_FETCH_RESOURCE2(pgsql, PGconn *, z_pgsql_link, id, "PostgreSQL link", le_link, le_plink); convert_to_string_ex(z_filename); - fp = php_fopen_wrapper(Z_STRVAL_PP(z_filename), mode, ENFORCE_SAFE_MODE, &issock, &socketd, NULL TSRMLS_CC); + stream = php_stream_open_wrapper(Z_STRVAL_PP(z_filename), mode, ENFORCE_SAFE_MODE|REPORT_ERRORS, NULL TSRMLS_CC); - if (!fp) { - php_error(E_WARNING, "Unable to open %s for logging", Z_STRVAL_PP(z_filename)); + if (!stream) { RETURN_FALSE; } - + + if (!php_stream_cast(stream, PHP_STREAM_AS_STDIO, (void**)fp, REPORT_ERRORS)) { + php_stream_close(stream); + RETURN_FALSE; + } + ZEND_REGISTER_RESOURCE(NULL, stream, php_file_le_stream()); PQtrace(pgsql, fp); - ZEND_REGISTER_RESOURCE(NULL, fp, php_file_le_fopen()); RETURN_TRUE; } /* }}} */ diff --git a/ext/recode/recode.c b/ext/recode/recode.c index fa1dcd46b8..488e3b3cfd 100644 --- a/ext/recode/recode.c +++ b/ext/recode/recode.c @@ -26,6 +26,7 @@ #include "php.h" #include "php_recode.h" +#include "php_streams.h" #if HAVE_LIBRECODE #include "ext/standard/info.h" @@ -162,28 +163,38 @@ PHP_FUNCTION(recode_file) int success; pval **req; pval **input, **output; + php_stream * instream, *outstream; FILE *in_fp, *out_fp; int in_type, out_type; + if (ZEND_NUM_ARGS() != 3 || zend_get_parameters_ex(3, &req, &input, &output) == FAILURE) { WRONG_PARAM_COUNT; } - in_fp = zend_fetch_resource(input TSRMLS_CC,-1, "File-Handle", &in_type, - 2, php_file_le_fopen(), php_file_le_popen()); - if (!in_fp) { + instream = zend_fetch_resource(input TSRMLS_CC,-1, "File-Handle", &in_type, + 1, php_file_le_stream()); + + if (!instream) { php_error(E_WARNING,"Unable to find input file identifier"); RETURN_FALSE; } - out_fp = zend_fetch_resource(output TSRMLS_CC,-1, "File-Handle", &out_type, - 2, php_file_le_fopen(), php_file_le_popen()); - if (!out_fp) { + if (!php_stream_cast(instream, PHP_STREAM_AS_STDIO, (void**)&in_fp, REPORT_ERRORS)) { + RETURN_FALSE; + } + + outstream = zend_fetch_resource(output TSRMLS_CC,-1, "File-Handle", &out_type, + 1, php_file_le_stream()); + if (!outstream) { php_error(E_WARNING,"Unable to find output file identifier"); RETURN_FALSE; } - + if (!php_stream_cast(outstream, PHP_STREAM_AS_STDIO, (void**)&out_fp, REPORT_ERRORS)) { + RETURN_FALSE; + } + convert_to_string_ex(req); request = recode_new_request(ReSG(outer)); diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index 8033e577b8..89e354891a 100644 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -20,6 +20,7 @@ /* $Id$ */ #include "php.h" +#include "php_streams.h" #include "php_main.h" #include "php_globals.h" #include "php_ini.h" @@ -274,6 +275,7 @@ function_entry basic_functions[] = { PHP_FE(wordwrap, NULL) PHP_FE(htmlspecialchars, NULL) PHP_FE(htmlentities, NULL) + PHP_FE(html_entity_decode, NULL) PHP_FE(get_html_translation_table, NULL) PHP_NAMED_FE(md5,php_if_md5, NULL) PHP_NAMED_FE(md5_file,php_if_md5_file, NULL) @@ -621,9 +623,7 @@ function_entry basic_functions[] = { PHP_FE(socket_set_blocking, NULL) #if HAVE_PHP_STREAM - PHP_FE(fopenstream, NULL) -#else - PHP_FALIAS(fopenstream, warn_not_available, NULL) + PHP_FE(fgetwrapperdata, NULL) #endif #if HAVE_SYS_TIME_H @@ -1004,15 +1004,16 @@ PHP_MINIT_FUNCTION(basic) if (PG(allow_url_fopen)) { - if (FAILURE == php_register_url_wrapper("http", php_fopen_url_wrap_http TSRMLS_CC)) { + if (FAILURE == php_register_url_stream_wrapper("http", &php_stream_http_wrapper TSRMLS_CC)) return FAILURE; - } - if (FAILURE == php_register_url_wrapper("ftp", php_fopen_url_wrap_ftp TSRMLS_CC)) { + if (FAILURE == php_register_url_stream_wrapper("php", &php_stream_php_wrapper TSRMLS_CC)) return FAILURE; - } - if (FAILURE == php_register_url_wrapper("php", php_fopen_url_wrap_php TSRMLS_CC)) { + if (FAILURE == php_register_url_stream_wrapper("ftp", &php_stream_ftp_wrapper TSRMLS_CC)) return FAILURE; - } +# if HAVE_OPENSSL_EXT + if (FAILURE == php_register_url_stream_wrapper("https", &php_stream_http_wrapper TSRMLS_CC)) + return FAILURE; +# endif } return SUCCESS; @@ -1028,9 +1029,13 @@ PHP_MSHUTDOWN_FUNCTION(basic) #endif if (PG(allow_url_fopen)) { - php_unregister_url_wrapper("http" TSRMLS_CC); - php_unregister_url_wrapper("ftp" TSRMLS_CC); - php_unregister_url_wrapper("php" TSRMLS_CC); + php_unregister_url_stream_wrapper("http" TSRMLS_CC); + php_unregister_url_stream_wrapper("ftp" TSRMLS_CC); + php_unregister_url_stream_wrapper("php" TSRMLS_CC); +# if HAVE_OPENSSL_EXT + php_unregister_url_stream_wrapper("https" TSRMLS_CC); +# endif + } UNREGISTER_INI_ENTRIES(); @@ -1503,8 +1508,7 @@ PHP_FUNCTION(error_log) PHPAPI int _php_error_log(int opt_err, char *message, char *opt, char *headers TSRMLS_DC) { - FILE *logfile; - int issock = 0, socketd = 0;; + php_stream * stream = NULL; switch (opt_err) { @@ -1528,13 +1532,11 @@ PHPAPI int _php_error_log(int opt_err, char *message, char *opt, char *headers T break; case 3: /*save to a file */ - logfile = php_fopen_wrapper(opt, "a", (IGNORE_URL | ENFORCE_SAFE_MODE), &issock, &socketd, NULL TSRMLS_CC); - if (!logfile) { - php_error(E_WARNING, "error_log: Unable to write to %s", opt); + stream = php_stream_open_wrapper(opt, "a", IGNORE_URL | ENFORCE_SAFE_MODE | REPORT_ERRORS, NULL TSRMLS_CC); + if (!stream) return FAILURE; - } - fwrite(message, strlen(message), 1, logfile); - fclose(logfile); + php_stream_write(stream, message, strlen(message)); + php_stream_close(stream); break; default: diff --git a/ext/standard/exec.c b/ext/standard/exec.c index 321a6d94d5..34a4cfbaf8 100644 --- a/ext/standard/exec.c +++ b/ext/standard/exec.c @@ -51,6 +51,7 @@ int php_Exec(int type, char *cmd, pval *array, pval *return_value TSRMLS_DC) int overflow_limit, lcmd, ldir; int rsrc_id; char *b, *c, *d=NULL; + php_stream * stream = NULL; #if PHP_SIGCHILD void (*sig_handler)(); #endif @@ -141,7 +142,9 @@ int php_Exec(int type, char *cmd, pval *array, pval *return_value TSRMLS_DC) * fd gets pclosed */ - rsrc_id = ZEND_REGISTER_RESOURCE(NULL, fp, php_file_le_popen()); + stream = php_stream_fopen_from_pipe(fp, "rb"); + if (stream) + rsrc_id = ZEND_REGISTER_RESOURCE(NULL, stream, php_file_le_stream()); if (type != 3) { l=0; diff --git a/ext/standard/file.c b/ext/standard/file.c index 6e918eb5b1..30cbf8346d 100644 --- a/ext/standard/file.c +++ b/ext/standard/file.c @@ -16,8 +16,8 @@ | Stig Bakken <ssb@fast.no> | | Andi Gutmans <andi@zend.com> | | Zeev Suraski <zeev@zend.com> | - | PHP 4.0 patches by Thies C. Arntzen <thies@thieso.net> | - | PHP 4.1 streams by Wez Furlong (wez@thebrainroom.com) | + | PHP 4.0 patches by Thies C. Arntzen (thies@thieso.net) | + | 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 @@ -103,79 +104,26 @@ php_file_globals file_globals; /* {{{ ZTS-stuff / Globals / Prototypes */ /* sharing globals is *evil* */ -static int le_fopen, le_popen, le_socket; -/* sorry folks; including this even if you haven't enabled streams - saves a zillion ifdefs */ static int le_stream = FAILURE; - /* }}} */ /* {{{ Module-Stuff */ -static void _file_popen_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC) -{ - FILE *pipe = (FILE *)rsrc->ptr; - - FG(pclose_ret) = pclose(pipe); -} - - -static void _file_socket_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC) -{ - int *sock = (int *)rsrc->ptr; - - SOCK_FCLOSE(*sock); -#if HAVE_SHUTDOWN - shutdown(*sock, 0); -#endif - efree(sock); -} - -#if HAVE_PHP_STREAM static void _file_stream_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC) { php_stream *stream = (php_stream*)rsrc->ptr; - - php_stream_close(stream); + /* the stream might be a pipe, so set the return value for pclose */ + FG(pclose_ret) = php_stream_close(stream); } -#endif PHPAPI int php_file_le_stream(void) { return le_stream; } -static void _file_fopen_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC) -{ - FILE *fp = (FILE *)rsrc->ptr; - - fclose(fp); -} - - -PHPAPI int php_file_le_fopen(void) /* XXX doe we really want this???? */ -{ - return le_fopen; -} - -PHPAPI int php_file_le_popen(void) /* XXX you may not like this, but I need it. -- KK */ -{ - return le_popen; -} - - -PHPAPI int php_file_le_socket(void) /* XXX doe we really want this???? */ -{ - return le_socket; -} - - static void file_globals_ctor(php_file_globals *file_globals_p TSRMLS_DC) { - zend_hash_init(&FG(ht_fsock_keys), 0, NULL, NULL, 1); - zend_hash_init(&FG(ht_fsock_socks), 0, NULL, (void (*)(void *))php_msock_destroy, 1); - FG(def_chunk_size) = PHP_FSOCK_CHUNK_SIZE; - FG(phpsockbuf) = NULL; + zend_hash_init(&FG(ht_persistent_socks), 0, NULL, NULL, 1); FG(fgetss_state) = 0; FG(pclose_ret) = 0; } @@ -183,21 +131,13 @@ static void file_globals_ctor(php_file_globals *file_globals_p TSRMLS_DC) static void file_globals_dtor(php_file_globals *file_globals_p TSRMLS_DC) { - zend_hash_destroy(&FG(ht_fsock_socks)); - zend_hash_destroy(&FG(ht_fsock_keys)); - php_cleanup_sockbuf(1 TSRMLS_CC); + zend_hash_destroy(&FG(ht_persistent_socks)); } PHP_MINIT_FUNCTION(file) { - le_fopen = zend_register_list_destructors_ex(_file_fopen_dtor, NULL, "file", module_number); - le_popen = zend_register_list_destructors_ex(_file_popen_dtor, NULL, "pipe", module_number); - le_socket = zend_register_list_destructors_ex(_file_socket_dtor, NULL, "socket", module_number); - -#if HAVE_PHP_STREAM le_stream = zend_register_list_destructors_ex(_file_stream_dtor, NULL, "stream", module_number); -#endif #ifdef ZTS ts_allocate_id(&file_globals_id, sizeof(php_file_globals), (ts_allocate_ctor) file_globals_ctor, (ts_allocate_dtor) file_globals_dtor); @@ -243,23 +183,14 @@ PHP_FUNCTION(flock) WRONG_PARAM_COUNT; } - what = zend_fetch_resource(arg1 TSRMLS_CC, -1, "File-Handle", &type, 4, le_fopen, le_popen, le_socket, le_stream); + what = zend_fetch_resource(arg1 TSRMLS_CC, -1, "File-Handle", &type, 1, le_stream); ZEND_VERIFY_RESOURCE(what); -#if HAVE_PHP_STREAM - if (type == le_stream) { - if (php_stream_cast((php_stream*)what, PHP_STREAM_AS_FD, (void*)&fd, 1) == FAILURE) { - RETURN_FALSE; - } - } else -#endif - if (type == le_socket) { - fd = *(int *) what; - } else { - fd = fileno((FILE*) what); + if (php_stream_cast((php_stream*)what, PHP_STREAM_AS_FD, (void*)&fd, 1) == FAILURE) { + RETURN_FALSE; } - convert_to_long_ex(arg2); + convert_to_long_ex(arg2); act = Z_LVAL_PP(arg2) & 3; if (act < 1 || act > 3) { @@ -307,15 +238,11 @@ PHP_FUNCTION(get_meta_tags) return; } - md.fp = php_fopen_wrapper(filename, "rb", - use_include_path | ENFORCE_SAFE_MODE, &md.issock, &md.socketd, NULL TSRMLS_CC); - if (!md.fp && !md.socketd) { - if (md.issock != BAD_URL) { - char *tmp = estrndup(filename, filename_len); - php_strip_url_passwd(tmp); - php_error(E_WARNING, "get_meta_tags(\"%s\") - %s", tmp, strerror(errno)); - efree(tmp); - } + md.stream = php_stream_open_wrapper(filename, "rb", + use_include_path | ENFORCE_SAFE_MODE | REPORT_ERRORS, + NULL TSRMLS_CC); + + if (!md.stream) { RETURN_FALSE; } @@ -434,11 +361,7 @@ PHP_FUNCTION(get_meta_tags) md.token_data = NULL; } - if (md.issock) { - SOCK_FCLOSE(md.socketd); - } else { - fclose(md.fp); - } + php_stream_close(md.stream); } /* }}} */ @@ -451,13 +374,12 @@ PHP_FUNCTION(file) { char *filename; int filename_len; - FILE *fp; char *slashed, *target_buf; register int i = 0; - int issock = 0, socketd = 0; int target_len, len; zend_bool use_include_path = 0; zend_bool reached_eof = 0; + php_stream * stream; /* Parse arguments */ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", @@ -465,15 +387,10 @@ PHP_FUNCTION(file) return; } - fp = php_fopen_wrapper(filename, "rb", - use_include_path | ENFORCE_SAFE_MODE, &issock, &socketd, NULL TSRMLS_CC); - if (!fp && !socketd) { - if (issock != BAD_URL) { - char *tmp = estrndup(filename, filename_len); - php_strip_url_passwd(tmp); - php_error(E_WARNING, "file(\"%s\") - %s", tmp, strerror(errno)); - efree(tmp); - } + stream = php_stream_open_wrapper(filename, "rb", + use_include_path | ENFORCE_SAFE_MODE | REPORT_ERRORS, + NULL TSRMLS_CC); + if (!stream) { RETURN_FALSE; } @@ -491,7 +408,7 @@ PHP_FUNCTION(file) target_buf = (char *) erealloc(target_buf, target_len+PHP_FILE_BUF_SIZE+1); target_buf[target_len+PHP_FILE_BUF_SIZE] = 0; /* avoid overflows */ } - if (FP_FGETS(target_buf+target_len, PHP_FILE_BUF_SIZE, socketd, fp, issock)==NULL) { + if (php_stream_gets(stream, target_buf+target_len, PHP_FILE_BUF_SIZE)==NULL) { if (target_len==0) { efree(target_buf); break; @@ -518,11 +435,7 @@ PHP_FUNCTION(file) target_buf = NULL; target_len = 0; } - if (issock) { - SOCK_FCLOSE(socketd); - } else { - fclose(fp); - } + php_stream_close(stream); } /* }}} */ @@ -558,56 +471,54 @@ PHP_FUNCTION(tempnam) Create a temporary file that will be deleted automatically after use */ PHP_NAMED_FUNCTION(php_if_tmpfile) { - FILE *fp; + php_stream * stream; + if (ZEND_NUM_ARGS() != 0) { WRONG_PARAM_COUNT; } - fp = tmpfile(); - if (fp == NULL) { - php_error(E_WARNING, "tmpfile(): %s", strerror(errno)); + stream = php_stream_fopen_tmpfile(); + + if (stream) { + ZEND_REGISTER_RESOURCE(return_value, stream, le_stream); + } + else { RETURN_FALSE; } - ZEND_REGISTER_RESOURCE(return_value, fp, le_fopen); } /* }}} */ -#if HAVE_PHP_STREAM -/* {{{ proto resource fopenstream(string filename, string mode) +/* {{{ proto resource fgetwrapperdata(resource fp) */ -PHP_FUNCTION(fopenstream) +PHP_FUNCTION(fgetwrapperdata) { - zval ** zfilename, ** zmode; + zval **arg1; php_stream * stream; - if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &zfilename, &zmode) == FAILURE) { + if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &arg1) == FAILURE) { WRONG_PARAM_COUNT; } - 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*)zend_fetch_resource(arg1 TSRMLS_CC, -1, "File-Handle", NULL, 1, le_stream); + ZEND_VERIFY_RESOURCE(stream); - 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)); - RETURN_FALSE; + if (stream->wrapperdata) { + *return_value = *(stream->wrapperdata); + zval_copy_ctor(return_value); } - ZEND_REGISTER_RESOURCE(return_value, stream, le_stream); + else + RETURN_FALSE; + } /* }}} */ -#endif /* {{{ proto resource fopen(string filename, string mode [, bool use_include_path]) Open a file or a URL and return a file pointer */ PHP_NAMED_FUNCTION(php_if_fopen) { zval **arg1, **arg2, **arg3; - FILE *fp; - char *p; - int *sock; int use_include_path = 0; - int issock=0, socketd=0; - + php_stream * stream; + switch(ZEND_NUM_ARGS()) { case 2: if (zend_get_parameters_ex(2, &arg1, &arg2) == FAILURE) { @@ -626,35 +537,16 @@ PHP_NAMED_FUNCTION(php_if_fopen) } convert_to_string_ex(arg1); convert_to_string_ex(arg2); - p = estrndup(Z_STRVAL_PP(arg2), Z_STRLEN_PP(arg2)); - /* - * We need a better way of returning error messages from - * php_fopen_wrapper(). - */ - fp = php_fopen_wrapper(Z_STRVAL_PP(arg1), p, - use_include_path | ENFORCE_SAFE_MODE, &issock, &socketd, NULL TSRMLS_CC); - if (!fp && !socketd) { - if (issock != BAD_URL) { - char *tmp = estrndup(Z_STRVAL_PP(arg1), Z_STRLEN_PP(arg1)); - php_strip_url_passwd(tmp); - php_error(E_WARNING, "fopen(\"%s\", \"%s\") - %s", tmp, p, strerror(errno)); - efree(tmp); - } - efree(p); + stream = php_stream_open_wrapper(Z_STRVAL_PP(arg1), Z_STRVAL_PP(arg2), + use_include_path | ENFORCE_SAFE_MODE | REPORT_ERRORS, + NULL TSRMLS_CC); + if (stream == NULL) { RETURN_FALSE; } - - efree(p); FG(fgetss_state) = 0; - - if (issock) { - sock = emalloc(sizeof(int)); - *sock = socketd; - ZEND_REGISTER_RESOURCE(return_value, sock, le_socket); - } else { - ZEND_REGISTER_RESOURCE(return_value, fp, le_fopen); - } + ZEND_REGISTER_RESOURCE(return_value, stream, le_stream); + return; } /* }}} */ @@ -670,7 +562,7 @@ PHP_FUNCTION(fclose) WRONG_PARAM_COUNT; } - what = zend_fetch_resource(arg1 TSRMLS_CC, -1, "File-Handle", &type, 3, le_fopen, le_socket, le_stream); + what = zend_fetch_resource(arg1 TSRMLS_CC, -1, "File-Handle", &type, 1, le_stream); ZEND_VERIFY_RESOURCE(what); zend_list_delete(Z_LVAL_PP(arg1)); @@ -687,7 +579,8 @@ PHP_FUNCTION(popen) FILE *fp; char *p, *tmp = NULL; char *b, buf[1024]; - + php_stream * stream; + if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &arg1, &arg2) == FAILURE) { WRONG_PARAM_COUNT; } @@ -730,9 +623,16 @@ PHP_FUNCTION(popen) RETURN_FALSE; } } - efree(p); + stream = php_stream_fopen_from_pipe(fp, p); + + if (stream == NULL) { + zend_error(E_WARNING, "popen(\"%s\", \"%s\"): %s", Z_STRVAL_PP(arg1), p, strerror(errno)); + RETVAL_FALSE; + } + else + ZEND_REGISTER_RESOURCE(return_value, stream, le_stream); - ZEND_REGISTER_RESOURCE(return_value, fp, le_popen); + efree(p); } /* }}} */ @@ -742,12 +642,13 @@ PHP_FUNCTION(pclose) { zval **arg1; void *what; - + int type; + if (ARG_COUNT(ht) != 1 || zend_get_parameters_ex(1, &arg1) == FAILURE) { WRONG_PARAM_COUNT; } - what = zend_fetch_resource(arg1 TSRMLS_CC,-1, "File-Handle", NULL, 1, le_popen); + what = zend_fetch_resource(arg1 TSRMLS_CC,-1, "File-Handle", &type, 1, le_stream); ZEND_VERIFY_RESOURCE(what); zend_list_delete(Z_LVAL_PP(arg1)); @@ -761,41 +662,25 @@ PHP_FUNCTION(feof) { zval **arg1; int type; - int issock=0; - int socketd=0; void *what; if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &arg1) == FAILURE) { WRONG_PARAM_COUNT; } - what = zend_fetch_resource(arg1 TSRMLS_CC, -1, "File-Handle", &type, 4, le_fopen, le_popen, le_socket, le_stream); + what = zend_fetch_resource(arg1 TSRMLS_CC, -1, "File-Handle", &type, 1, le_stream); ZEND_VERIFY_RESOURCE(what); - if (type == le_socket) { - issock = 1; - socketd = *(int *) what; - } - -#if HAVE_PHP_STREAM if (type == le_stream) { if (php_stream_eof((php_stream *) what)) { RETURN_TRUE; } RETURN_FALSE; } - else -#endif - { - if (FP_FEOF(socketd, (FILE *) what, issock)) { - RETURN_TRUE; - } else { - RETURN_FALSE; - } - } + RETURN_FALSE; } /* }}} */ - +/* TODO: move to main/network.c */ PHPAPI int php_set_sock_blocking(int socketd, int block) { int ret = SUCCESS; @@ -839,28 +724,24 @@ PHP_FUNCTION(socket_set_blocking) WRONG_PARAM_COUNT; } - what = zend_fetch_resource(arg1 TSRMLS_CC, -1, "File-Handle", &type, 2, le_socket, le_stream); + what = zend_fetch_resource(arg1 TSRMLS_CC, -1, "File-Handle", &type, 1, le_stream); ZEND_VERIFY_RESOURCE(what); convert_to_long_ex(arg2); block = Z_LVAL_PP(arg2); - 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 - if (php_set_sock_blocking(socketd, block) == FAILURE) - RETURN_FALSE; + if (php_stream_is((php_stream*)what, PHP_STREAM_IS_SOCKET)) { + /* TODO: check if the blocking mode is changed elsewhere, and see if we + * can integrate these calls into php_stream_sock_set_blocking */ + php_stream_cast((php_stream *) what, PHP_STREAM_AS_SOCKETD, (void *) &socketd, REPORT_ERRORS); - php_sockset_blocking(socketd, block == 0 ? 0 : 1); + if (php_set_sock_blocking(socketd, block) == FAILURE) + RETURN_FALSE; - RETURN_TRUE; + php_stream_sock_set_blocking((php_stream*)what, block == 0 ? 0 : 1); + RETURN_TRUE; + } + RETURN_FALSE; } /* }}} */ @@ -882,17 +763,15 @@ PHP_FUNCTION(socket_set_timeout) zval **socket, **seconds, **microseconds; int type; void *what; - int socketd = 0; struct timeval t; if (ZEND_NUM_ARGS() < 2 || ZEND_NUM_ARGS() > 3 || 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, 1, le_stream); ZEND_VERIFY_RESOURCE(what); - socketd = *(int *) what; convert_to_long_ex(seconds); t.tv_sec = Z_LVAL_PP(seconds); @@ -905,8 +784,12 @@ PHP_FUNCTION(socket_set_timeout) else t.tv_usec = 0; - php_sockset_timeout(socketd, &t); - RETURN_TRUE; + if (php_stream_is((php_stream*)what, PHP_STREAM_IS_SOCKET)) { + php_stream_sock_set_timeout((php_stream*)what, &t); + RETURN_TRUE; + } + + RETURN_FALSE; #endif /* HAVE_SYS_TIME_H */ } @@ -920,25 +803,30 @@ PHP_FUNCTION(socket_get_status) zval **socket; int type; void *what; - int socketd = 0; - struct php_sockbuf *sock; 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, 1, le_stream); ZEND_VERIFY_RESOURCE(what); - socketd = *(int *) what; - sock = php_get_socket(socketd); array_init(return_value); - add_assoc_bool(return_value, "timed_out", sock->timeout_event); - add_assoc_bool(return_value, "blocked", sock->is_blocked); - add_assoc_bool(return_value, "eof", sock->eof); - add_assoc_long(return_value, "unread_bytes", sock->writepos - sock->readpos); + if (php_stream_is((php_stream*)what, PHP_STREAM_IS_SOCKET)) { + + php_netstream_data_t * sock = PHP_NETSTREAM_DATA_FROM_STREAM((php_stream*)what); + + add_assoc_bool(return_value, "timed_out", sock->timeout_event); + add_assoc_bool(return_value, "blocked", sock->is_blocked); + add_assoc_bool(return_value, "eof", sock->eof); + add_assoc_long(return_value, "unread_bytes", sock->writepos - sock->readpos); + + } + else { + RETURN_FALSE; + } + } /* }}} */ @@ -950,8 +838,6 @@ PHP_FUNCTION(fgets) zval **arg1, **arg2; int len = 1024, type; char *buf; - int issock=0; - int socketd=0; void *what; int argc = ZEND_NUM_ARGS(); @@ -959,7 +845,7 @@ PHP_FUNCTION(fgets) WRONG_PARAM_COUNT; } - what = zend_fetch_resource(arg1 TSRMLS_CC, -1, "File-Handle", &type, 4, le_fopen, le_popen, le_socket, le_stream); + what = zend_fetch_resource(arg1 TSRMLS_CC, -1, "File-Handle", &type, 1, le_stream); ZEND_VERIFY_RESOURCE(what); if (argc>1) { @@ -972,35 +858,12 @@ PHP_FUNCTION(fgets) RETURN_FALSE; } - if (type == le_socket) { - issock = 1; - socketd = *(int *) what; - } - buf = emalloc(sizeof(char) * (len + 1)); /* needed because recv doesnt put a null at the end*/ memset(buf, 0, len+1); -#if HAVE_PHP_STREAM - if (type == le_stream) { - if (php_stream_gets((php_stream *) what, buf, len) == NULL) - goto exit_failed; - } - else -#endif - { - if (type == le_socket) { - issock = 1; - socketd = *(int *) what; - } -#ifdef HAVE_FLUSHIO - if (type == le_fopen) { - fseek((FILE *) what, 0, SEEK_CUR); - } -#endif - if (FP_FGETS(buf, len, socketd, (FILE *) what, issock) == NULL) - goto exit_failed; - } + if (php_stream_gets((php_stream *) what, buf, len) == NULL) + goto exit_failed; if (PG(magic_quotes_runtime)) { Z_STRVAL_P(return_value) = php_addslashes(buf, 0, &Z_STRLEN_P(return_value), 1 TSRMLS_CC); @@ -1027,8 +890,6 @@ PHP_FUNCTION(fgetc) zval **arg1; int type; char *buf; - int issock=0; - int socketd=0; void *what; int result; @@ -1036,28 +897,12 @@ PHP_FUNCTION(fgetc) WRONG_PARAM_COUNT; } - what = zend_fetch_resource(arg1 TSRMLS_CC, -1, "File-Handle", &type, 4, le_fopen, le_popen, le_socket, le_stream); + what = zend_fetch_resource(arg1 TSRMLS_CC, -1, "File-Handle", &type, 1, le_stream); ZEND_VERIFY_RESOURCE(what); - if (type == le_socket) { - issock = 1; - socketd = *(int *) what; - } - -#ifdef HAVE_FLUSHIO - if (type == le_fopen) { - fseek((FILE *) what, 0, SEEK_CUR); - } -#endif - buf = emalloc(sizeof(int)); + buf = emalloc(2 * sizeof(char)); -#if HAVE_PHP_STREAM - if (type == le_stream) { - result = php_stream_getc((php_stream*)what); - } - else -#endif - result = FP_FGETC(socketd, (FILE *) what, issock); + result = php_stream_getc((php_stream*)what); if (result == EOF) { efree(buf); @@ -1078,8 +923,6 @@ PHP_FUNCTION(fgetss) zval **fd, **bytes, **allow=NULL; int len, type; char *buf; - int issock=0; - int socketd=0; void *what; char *allowed_tags=NULL; int allowed_tags_len=0; @@ -1104,14 +947,9 @@ PHP_FUNCTION(fgetss) break; } - what = zend_fetch_resource(fd TSRMLS_CC, -1, "File-Handle", &type, 4, le_fopen, le_popen, le_socket, le_stream); + what = zend_fetch_resource(fd TSRMLS_CC, -1, "File-Handle", &type, 1, le_stream); ZEND_VERIFY_RESOURCE(what); - if (type == le_socket) { - issock = 1; - socketd = *(int *) what; - } - convert_to_long_ex(bytes); len = Z_LVAL_PP(bytes); if (len < 0) { @@ -1123,16 +961,7 @@ PHP_FUNCTION(fgetss) /*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((php_stream *) what, buf, len) == NULL) { - efree(buf); - RETURN_FALSE; - } - } - else -#endif - if (FP_FGETS(buf, len, socketd, (FILE *) what, issock) == NULL) { + if (php_stream_gets((php_stream *) what, buf, len) == NULL) { efree(buf); RETURN_FALSE; } @@ -1152,8 +981,6 @@ PHP_FUNCTION(fscanf) zval **file_handle, **format_string; int len, type; char *buf; - int issock=0; - int socketd=0; void *what; zval ***args; @@ -1172,7 +999,7 @@ PHP_FUNCTION(fscanf) file_handle = args[0]; format_string = args[1]; - what = zend_fetch_resource(file_handle TSRMLS_CC, -1, "File-Handle", &type, 4, le_fopen, le_popen, le_socket, le_stream); + what = zend_fetch_resource(file_handle TSRMLS_CC, -1, "File-Handle", &type, 1, le_stream); /* * we can't do a ZEND_VERIFY_RESOURCE(what), otherwise we end up @@ -1186,28 +1013,14 @@ PHP_FUNCTION(fscanf) len = SCAN_MAX_FSCANF_BUFSIZE; - if (type == le_socket) { - issock = 1; - socketd = *(int *) what; - } buf = emalloc(len + 1); /* needed because recv doesnt put a null at the end*/ memset(buf, 0, len+1); -#if HAVE_PHP_STREAM - if (type == le_stream) { - if (php_stream_gets((php_stream *) what, buf, len) == NULL) { - efree(buf); - RETURN_FALSE; - } - } - else -#endif - - if (FP_FGETS(buf, len, socketd, (FILE *) what, issock) == NULL) { + if (php_stream_gets((php_stream *) what, buf, len) == NULL) { efree(buf); RETURN_FALSE; - } + } convert_to_string_ex(format_string); result = php_sscanf_internal(buf, Z_STRVAL_PP(format_string), @@ -1229,8 +1042,6 @@ PHP_FUNCTION(fwrite) zval **arg1, **arg2, **arg3=NULL; int ret, type; int num_bytes; - int issock=0; - int socketd=0; void *what; switch (ZEND_NUM_ARGS()) { @@ -1255,37 +1066,16 @@ PHP_FUNCTION(fwrite) break; } - what = zend_fetch_resource(arg1 TSRMLS_CC, -1, "File-Handle", &type, 4, le_fopen, - le_popen, le_socket, le_stream); + what = zend_fetch_resource(arg1 TSRMLS_CC, -1, "File-Handle", &type, 1, le_stream); ZEND_VERIFY_RESOURCE(what); - if (type == le_socket) { - issock =1; - socketd = *(int *) what; - } - if (!arg3 && PG(magic_quotes_runtime)) { zval_copy_ctor(*arg2); php_stripslashes(Z_STRVAL_PP(arg2), &num_bytes TSRMLS_CC); } -#if HAVE_PHP_STREAM - if (type == le_stream) { - ret = php_stream_write((php_stream *) what, Z_STRVAL_PP(arg2), num_bytes); - } - else -#endif - - if (issock){ - ret = SOCK_WRITEL(Z_STRVAL_PP(arg2), num_bytes, socketd); - } else { -#ifdef HAVE_FLUSHIO - if (type == le_fopen) { - fseek((FILE *) what, 0, SEEK_CUR); - } -#endif - ret = fwrite(Z_STRVAL_PP(arg2), 1, num_bytes, (FILE *) what); - } + ret = php_stream_write((php_stream *) what, Z_STRVAL_PP(arg2), num_bytes); + RETURN_LONG(ret); } /* }}} */ @@ -1296,43 +1086,20 @@ PHP_FUNCTION(fflush) { zval **arg1; int ret, type; - int issock=0; - int socketd=0; void *what; if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &arg1) == FAILURE) { WRONG_PARAM_COUNT; } - what = zend_fetch_resource(arg1 TSRMLS_CC,-1, "File-Handle", &type, 4, le_fopen, le_popen, le_socket, le_stream); + what = zend_fetch_resource(arg1 TSRMLS_CC,-1, "File-Handle", &type, 1, le_stream); ZEND_VERIFY_RESOURCE(what); -#if HAVE_PHP_STREAM - if (type == le_stream) { - ret = php_stream_flush((php_stream *) what); - if (ret) { - RETURN_FALSE; - } - RETURN_TRUE; - } -#endif - - if (type == le_socket) { - issock =1; - socketd = *(int *) what; - } - - if (issock){ - ret = fsync(socketd); - } else { - ret = fflush((FILE *) what); - } - + ret = php_stream_flush((php_stream *) what); if (ret) { RETURN_FALSE; - } else { - RETURN_TRUE; } + RETURN_TRUE; } /* }}} */ @@ -1342,7 +1109,8 @@ PHP_FUNCTION(set_file_buffer) { zval **arg1, **arg2; int ret, type, buff; - void *what; + php_stream * stream; + FILE * fp; switch (ZEND_NUM_ARGS()) { case 2: @@ -1356,19 +1124,20 @@ PHP_FUNCTION(set_file_buffer) break; } - /* XXX: add stream support --Wez. */ - - what = zend_fetch_resource(arg1 TSRMLS_CC,-1, "File-Handle", &type, 2, le_fopen, le_popen); - ZEND_VERIFY_RESOURCE(what); - + stream = (php_stream*)zend_fetch_resource(arg1 TSRMLS_CC,-1, "File-Handle", &type, 1, le_stream); + ZEND_VERIFY_RESOURCE(stream); + if (!php_stream_is(stream, PHP_STREAM_IS_STDIO) || !php_stream_cast(stream, PHP_STREAM_AS_STDIO, (void**)&fp, REPORT_ERRORS)) { + RETURN_FALSE; + } + convert_to_long_ex(arg2); buff = Z_LVAL_PP(arg2); /* if buff is 0 then set to non-buffered */ if (buff == 0){ - ret = setvbuf((FILE *) what, NULL, _IONBF, 0); + ret = setvbuf(fp, NULL, _IONBF, 0); } else { - ret = setvbuf((FILE *) what, NULL, _IOFBF, buff); + ret = setvbuf(fp, NULL, _IOFBF, buff); } RETURN_LONG(ret); @@ -1381,16 +1150,18 @@ PHP_FUNCTION(rewind) { 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, 1, le_stream); ZEND_VERIFY_RESOURCE(what); - rewind((FILE *) what); + if (-1 == php_stream_rewind((php_stream*)what)) { + RETURN_FALSE; + } RETURN_TRUE; } /* }}} */ @@ -1402,20 +1173,19 @@ PHP_FUNCTION(ftell) 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, 1, le_stream); ZEND_VERIFY_RESOURCE(what); - ret = ftell((FILE *) what); - if (ret == -1) { + ret = php_stream_tell((php_stream*)what); + if (ret == -1) { RETURN_FALSE; } - RETURN_LONG(ret); } /* }}} */ @@ -1427,14 +1197,14 @@ PHP_FUNCTION(fseek) 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, 1, le_stream); ZEND_VERIFY_RESOURCE(what); convert_to_long_ex(arg2); @@ -1443,7 +1213,7 @@ PHP_FUNCTION(fseek) whence = Z_LVAL_PP(arg3); } - RETURN_LONG(fseek((FILE *) what, Z_LVAL_PP(arg2), whence)); + RETURN_LONG(php_stream_seek((php_stream*)what, Z_LVAL_PP(arg2), whence)); } /* }}} */ @@ -1508,27 +1278,27 @@ PHP_FUNCTION(rmdir) } /* }}} */ -/* {{{ php_passthru_fd */ -static size_t php_passthru_fd(int socketd, FILE *fp, int issock TSRMLS_DC) +/* {{{ php_passthru_stream */ +static size_t php_passthru_stream(php_stream * stream TSRMLS_DC) { size_t bcount = 0; int ready = 0; char buf[8192]; - /* XXX: add stream support --Wez. */ + int fd; #ifdef HAVE_MMAP - if (!issock) { - int fd; + 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; - fd = fileno(fp); fstat(fd, &sbuf); if (sbuf.st_size > sizeof(buf)) { - off = ftell(fp); + 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) { @@ -1543,16 +1313,14 @@ static size_t php_passthru_fd(int socketd, FILE *fp, int issock TSRMLS_DC) } } #endif - if(!ready) { int b; - while ((b = FP_FREAD(buf, sizeof(buf), socketd, fp, issock)) > 0) { + while ((b = php_stream_read(stream, buf, sizeof(buf))) > 0) { PHPWRITE(buf, b); bcount += b; } } - return bcount; } /* }}} */ @@ -1562,12 +1330,10 @@ static size_t php_passthru_fd(int socketd, FILE *fp, int issock TSRMLS_DC) PHP_FUNCTION(readfile) { zval **arg1, **arg2; - FILE *fp; int size=0; int use_include_path=0; - int issock=0, socketd=0; - int rsrc_id; - + php_stream * stream; + /* check args */ switch (ZEND_NUM_ARGS()) { case 1: @@ -1587,35 +1353,15 @@ PHP_FUNCTION(readfile) } convert_to_string_ex(arg1); - /* - * We need a better way of returning error messages from - * php_fopen_wrapper(). - */ - fp = php_fopen_wrapper(Z_STRVAL_PP(arg1), "rb", - use_include_path | ENFORCE_SAFE_MODE, &issock, &socketd, NULL TSRMLS_CC); - if (!fp && !socketd) { - if (issock != BAD_URL) { - char *tmp = estrndup(Z_STRVAL_PP(arg1), Z_STRLEN_PP(arg1)); - php_strip_url_passwd(tmp); - php_error(E_WARNING, "readfile(\"%s\") - %s", tmp, strerror(errno)); - efree(tmp); - } - RETURN_FALSE; + 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); } - - if (issock) { - int *sock = emalloc(sizeof(int)); - *sock = socketd; - rsrc_id = ZEND_REGISTER_RESOURCE(NULL, sock, php_file_le_socket()); - } else { - rsrc_id = ZEND_REGISTER_RESOURCE(NULL, fp, php_file_le_fopen()); - } - - size = php_passthru_fd(socketd, fp, issock TSRMLS_CC); - - zend_list_delete(rsrc_id); - - RETURN_LONG(size); + RETURN_FALSE; } /* }}} */ @@ -1655,27 +1401,16 @@ PHP_FUNCTION(fpassthru) { zval **arg1; int size, type; - int issock=0; - int socketd=0; void *what; 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", &type, 3, le_fopen, le_popen, le_socket); + what = zend_fetch_resource(arg1 TSRMLS_CC,-1, "File-Handle", &type, 1, le_stream); ZEND_VERIFY_RESOURCE(what); - if (type == le_socket) { - issock = 1; - socketd = *(int *) what; - } - - size = php_passthru_fd(socketd, (FILE *) what, issock TSRMLS_CC); - - zend_list_delete(Z_LVAL_PP(arg1)); - + size = php_passthru_stream((php_stream*)what TSRMLS_CC); RETURN_LONG(size); } /* }}} */ @@ -1756,24 +1491,26 @@ PHP_NAMED_FUNCTION(php_if_ftruncate) short int ret; int type; void *what; + int fd; 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, 1, le_stream); ZEND_VERIFY_RESOURCE(what); - if (type == le_socket) { + convert_to_long_ex(size); + + if (php_stream_is((php_stream*)what, PHP_STREAM_IS_SOCKET)) { php_error(E_WARNING, "can't truncate sockets!"); RETURN_FALSE; } - - convert_to_long_ex(size); - - ret = ftruncate(fileno((FILE *) what), Z_LVAL_PP(size)); - RETURN_LONG(ret + 1); + 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; } /* }}} */ @@ -1787,6 +1524,7 @@ PHP_NAMED_FUNCTION(php_if_fstat) 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 +1532,15 @@ PHP_NAMED_FUNCTION(php_if_fstat) 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, 1, le_stream); ZEND_VERIFY_RESOURCE(what); - if (fstat(fileno((FILE *) what), &stat_sb)) { + if (!php_stream_cast((php_stream*)what, PHP_STREAM_AS_FD, (void*)&fd, 1)) { + RETURN_FALSE; + } + + if (fstat(fd, &stat_sb)) { RETURN_FALSE; } @@ -1903,57 +1644,25 @@ PHP_FUNCTION(copy) */ PHPAPI int php_copy_file(char *src, char *dest TSRMLS_DC) { - char buffer[8192]; - int fd_s, fd_t, read_bytes; + php_stream * srcstream = NULL, * deststream = NULL; int ret = FAILURE; -#ifdef PHP_WIN32 - if ((fd_s=VCWD_OPEN(src, O_RDONLY|_O_BINARY))==-1) { -#else - if ((fd_s=VCWD_OPEN(src, O_RDONLY))==-1) { -#endif - php_error(E_WARNING, "Unable to open '%s' for reading: %s", src, strerror(errno)); - return FAILURE; - } -#ifdef PHP_WIN32 - if ((fd_t=VCWD_OPEN_MODE(dest, _O_WRONLY|_O_CREAT|_O_TRUNC|_O_BINARY, _S_IREAD|_S_IWRITE))==-1) { -#else - if ((fd_t=VCWD_CREAT(dest, 0777))==-1) { -#endif - php_error(E_WARNING, "Unable to create '%s': %s", dest, strerror(errno)); - close(fd_s); - return FAILURE; - } + srcstream = php_stream_open_wrapper(src, "rb", + ENFORCE_SAFE_MODE | REPORT_ERRORS, + NULL TSRMLS_CC); -#ifdef HAVE_MMAP - { - void *srcfile; - struct stat sbuf; + deststream = php_stream_open_wrapper(dest, "wb", + ENFORCE_SAFE_MODE | REPORT_ERRORS, + NULL TSRMLS_CC); - if (fstat(fd_s, &sbuf)) { - goto cleanup; - } - srcfile = mmap(NULL, sbuf.st_size, PROT_READ, MAP_SHARED, fd_s, 0); - if (srcfile != (void *) MAP_FAILED) { - if (write(fd_t, srcfile, sbuf.st_size) == sbuf.st_size) - ret = SUCCESS; - munmap(srcfile, sbuf.st_size); - goto cleanup; - } - } -#endif + if (srcstream && deststream) + ret = php_stream_copy_to_stream(srcstream, deststream, 0) == 0 ? FAILURE : SUCCESS; - while ((read_bytes=read(fd_s, buffer, 8192))!=-1 && read_bytes!=0) { - if (write(fd_t, buffer, read_bytes)==-1) { - php_error(E_WARNING, "Unable to write to '%s': %s", dest, strerror(errno)); - goto cleanup; - } - } - ret = SUCCESS; + if (srcstream) + php_stream_close(srcstream); + if (deststream) + php_stream_close(deststream); -cleanup: - close(fd_s); - close(fd_t); return ret; } /* }}} */ @@ -1964,22 +1673,14 @@ PHP_FUNCTION(fread) { zval **arg1, **arg2; int len, type; - int issock=0; - int socketd=0; - void *what; + php_stream * stream; 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); - ZEND_VERIFY_RESOURCE(what); - if (type == le_socket) { - issock = 1; - socketd = *(int *) what; - } + stream = (php_stream*)zend_fetch_resource(arg1 TSRMLS_CC,-1, "File-Handle", &type, 1, le_stream); + ZEND_VERIFY_RESOURCE(stream); convert_to_long_ex(arg2); len = Z_LVAL_PP(arg2); @@ -1989,19 +1690,11 @@ PHP_FUNCTION(fread) } Z_STRVAL_P(return_value) = emalloc(len + 1); - /* needed because recv doesnt put a null at the end*/ + Z_STRLEN_P(return_value) = php_stream_read(stream, Z_STRVAL_P(return_value), len); - if (!issock) { -#ifdef HAVE_FLUSHIO - if (type == le_fopen) { - fseek((FILE *) what, 0, SEEK_CUR); - } -#endif - Z_STRLEN_P(return_value) = fread(Z_STRVAL_P(return_value), 1, len, (FILE *) what); - } else { - Z_STRLEN_P(return_value) = SOCK_FREAD(Z_STRVAL_P(return_value), len, socketd); - } + /* needed because recv/read/gzread doesnt put a null at the end*/ Z_STRVAL_P(return_value)[Z_STRLEN_P(return_value)] = 0; + if (PG(magic_quotes_runtime)) { Z_STRVAL_P(return_value) = php_addslashes(Z_STRVAL_P(return_value), Z_STRLEN_P(return_value), &Z_STRLEN_P(return_value), 1 TSRMLS_CC); @@ -2022,9 +1715,7 @@ PHP_FUNCTION(fgetcsv) zval **fd, **bytes, **p_delim; int len, type; char *buf; - int issock=0; - int socketd=0; - void *what; + php_stream * stream; switch(ZEND_NUM_ARGS()) { case 2: @@ -2051,15 +1742,9 @@ PHP_FUNCTION(fgetcsv) /* 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); - ZEND_VERIFY_RESOURCE(what); - - if (type == le_socket) { - issock = 1; - socketd = *(int *) what; - } + stream = (php_stream*)zend_fetch_resource(fd TSRMLS_CC,-1, "File-Handle", &type, 1, le_stream); + ZEND_VERIFY_RESOURCE(stream); convert_to_long_ex(bytes); len = Z_LVAL_PP(bytes); @@ -2069,9 +1754,10 @@ PHP_FUNCTION(fgetcsv) } buf = emalloc(len + 1); - /*needed because recv doesnt set null char at end*/ + /*needed because recv/read/gzread doesnt set null char at end*/ memset(buf, 0, len + 1); - if (FP_FGETS(buf, len, socketd, (FILE *) what, issock) == NULL) { + + if (php_stream_gets(stream, buf, len) == NULL) { efree(buf); RETURN_FALSE; } @@ -2132,7 +1818,8 @@ PHP_FUNCTION(fgetcsv) /* read a new line from input, as at start of routine */ memset(buf, 0, len+1); - if (FP_FGETS(buf, len, socketd, (FILE *) what, issock) == NULL) { + + if (php_stream_gets(stream, buf, len) == NULL) { efree(lineEnd); efree(temp); efree(buf); @@ -2206,40 +1893,6 @@ PHP_FUNCTION(realpath) /* }}} */ #endif - -/* {{{ php_fread_all - Function reads all data from file or socket and puts it into the buffer */ -size_t php_fread_all(char **buf, int socket, FILE *fp, int issock) { - size_t ret; - char *ptr; - size_t len = 0, max_len; - int step = PHP_FSOCK_CHUNK_SIZE; - int min_room = PHP_FSOCK_CHUNK_SIZE / 4; - - 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; - if(len + min_room >= max_len) { - *buf = erealloc(*buf, max_len + step); - max_len += step; - ptr = *buf + len; - } - } - - if(len) { - *buf = erealloc(*buf, len); - } else { - efree(*buf); - *buf = NULL; - } - - return len; -} -/* }}} */ - /* See http://www.w3.org/TR/html4/intro/sgmltut.html#h-3.2.2 */ #define PHP_META_HTML401_CHARS "-_.:" @@ -2252,8 +1905,8 @@ php_meta_tags_token php_next_meta_token(php_meta_tags_data *md) memset((void *)buff, 0, META_DEF_BUFSIZE + 1); - while (md->ulc || (!FP_FEOF(md->socketd, md->fp, md->issock) && (ch = FP_FGETC(md->socketd, md->fp, md->issock)))) { - if(FP_FEOF(md->socketd, md->fp, md->issock)) + while (md->ulc || (!php_stream_eof(md->stream) && (ch = php_stream_getc(md->stream)))) { + if(php_stream_eof(md->stream)) break; if (md->ulc) { @@ -2278,8 +1931,8 @@ php_meta_tags_token php_next_meta_token(php_meta_tags_data *md) case '"': compliment = ch; md->token_len = 0; - while (!FP_FEOF(md->socketd, md->fp, md->issock) && - (ch = FP_FGETC(md->socketd, md->fp, md->issock)) && + while (!php_stream_eof(md->stream) && + (ch = php_stream_getc(md->stream)) && ch != compliment && ch != '<' && ch != '>') { buff[(md->token_len)++] = ch; @@ -2313,8 +1966,8 @@ php_meta_tags_token php_next_meta_token(php_meta_tags_data *md) if (isalnum(ch)) { md->token_len = 0; buff[(md->token_len)++] = ch; - while (!FP_FEOF(md->socketd, md->fp, md->issock) && - (ch = FP_FGETC(md->socketd, md->fp, md->issock)) && + while (!php_stream_eof(md->stream) && + (ch = php_stream_getc(md->stream)) && (isalnum(ch) || strchr(PHP_META_HTML401_CHARS, ch))) { buff[(md->token_len)++] = ch; diff --git a/ext/standard/file.h b/ext/standard/file.h index 070eec4a5e..eee46a9de9 100644 --- a/ext/standard/file.h +++ b/ext/standard/file.h @@ -69,14 +69,10 @@ PHP_FUNCTION(realpath); PHP_NAMED_FUNCTION(php_if_ftruncate); PHP_NAMED_FUNCTION(php_if_fstat); -/* temporary function for testing streams */ -PHP_FUNCTION(fopenstream); +PHP_FUNCTION(fgetwrapperdata); PHPAPI int php_set_sock_blocking(int socketd, int block); -PHPAPI int php_file_le_fopen(void); PHPAPI int php_file_le_stream(void); -PHPAPI int php_file_le_popen(void); -PHPAPI int php_file_le_socket(void); PHPAPI int php_copy_file(char *src, char *dest TSRMLS_DC); #define META_DEF_BUFSIZE 8192 @@ -94,9 +90,7 @@ typedef enum _php_meta_tags_token { } php_meta_tags_token; typedef struct _php_meta_tags_data { - FILE *fp; - int socketd; - int issock; + php_stream * stream; int ulc; int lc; char *input_buffer; @@ -110,10 +104,7 @@ php_meta_tags_token php_next_meta_token(php_meta_tags_data *); typedef struct { int fgetss_state; int pclose_ret; - HashTable ht_fsock_keys; - HashTable ht_fsock_socks; - struct php_sockbuf *phpsockbuf; - size_t def_chunk_size; + HashTable ht_persistent_socks; } php_file_globals; #ifdef ZTS diff --git a/ext/standard/fsock.c b/ext/standard/fsock.c index b1e1314800..b672e0087c 100644 --- a/ext/standard/fsock.c +++ b/ext/standard/fsock.c @@ -20,6 +20,8 @@ /* $Id$ */ +/* converted to PHP Streams and moved much code to main/network.c [wez] */ + /* Synced with php 3.0 revision 1.121 1999-06-18 [ssb] */ /* Synced with php 3.0 revision 1.133 1999-07-21 [sas] */ @@ -86,29 +88,6 @@ static int fsock_globals_id; extern int le_fp; #endif -#define CLOSE_SOCK(free_sock) \ - if(socketd >= 0) { \ - close(socketd); \ - } \ - if (free_sock) { \ - efree(sock); \ - } \ - if (key) { \ - efree(key); \ - } - -#define SEARCHCR() do { \ - if (TOREAD(sock)) { \ - for (p = READPTR(sock), pe = p + MIN(TOREAD(sock), maxlen); \ - *p != '\n'; ) \ - if (++p >= pe) { \ - p = NULL; \ - break; \ - } \ - } else \ - p = NULL; \ -} while (0) - #ifdef PHP_WIN32 #define EWOULDBLOCK WSAEWOULDBLOCK #else @@ -136,628 +115,150 @@ PHPAPI int php_lookup_hostname(const char *addr, struct in_addr *in) return 0; } /* }}} */ -/* {{{ php_is_persistent_sock */ -PHPAPI int php_is_persistent_sock(int sock) -{ - char *key; - TSRMLS_FETCH(); - - if (zend_hash_find(&FG(ht_fsock_socks), (char *) &sock, sizeof(sock), - (void **) &key) == SUCCESS) { - return 1; - } - return 0; -} -/* }}} */ /* {{{ php_fsockopen() */ -/* - This function takes an optional third argument which should be - passed by reference. The error code from the connect call is written - to this variable. -*/ -static void php_fsockopen(INTERNAL_FUNCTION_PARAMETERS, int persistent) { - pval **args[5]; - int *sock=emalloc(sizeof(int)); - int *sockp; - int arg_count=ZEND_NUM_ARGS(); - int socketd = -1; - unsigned char udp = 0; - struct timeval timeout = { 60, 0 }; - unsigned short portno; +static void php_fsockopen_stream(INTERNAL_FUNCTION_PARAMETERS, int persistent) +{ + char * host; + int host_len; + int port = -1; + zval * zerrno = NULL, * zerrstr = NULL; + double timeout = 60; unsigned long conv; - char *key = NULL; - - if (arg_count > 5 || arg_count < 2 || zend_get_parameters_array_ex(arg_count, args)==FAILURE) { - CLOSE_SOCK(1); - WRONG_PARAM_COUNT; + struct timeval tv; + char * hashkey = NULL; + php_stream * stream = NULL; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|lzzd", &host, &host_len, &port, &zerrno, &zerrstr, &timeout) == FAILURE) { + RETURN_FALSE; } - switch(arg_count) { - case 5: - convert_to_double_ex(args[4]); - conv = (unsigned long) (Z_DVAL_PP(args[4]) * 1000000.0); - timeout.tv_sec = conv / 1000000; - timeout.tv_usec = conv % 1000000; - /* fall-through */ - case 4: - zval_dtor(*args[3]); - ZVAL_STRING(*args[3], "", 1); - /* fall-through */ - case 3: - zval_dtor(*args[2]); - ZVAL_LONG(*args[2], 0); - break; - } - convert_to_string_ex(args[0]); - convert_to_long_ex(args[1]); - portno = (unsigned short) Z_LVAL_PP(args[1]); - - key = emalloc(Z_STRLEN_PP(args[0]) + 10); - sprintf(key, "%s:%d", Z_STRVAL_PP(args[0]), portno); - - if (persistent && zend_hash_find(&FG(ht_fsock_keys), key, strlen(key) + 1, - (void *) &sockp) == SUCCESS) { - CLOSE_SOCK(0); - *sock = *sockp; - ZEND_REGISTER_RESOURCE(return_value, sock, php_file_le_socket()); + + hashkey = emalloc(host_len + 10); + sprintf(hashkey, "%s:%d", host, port); + + if (persistent && zend_hash_find(&FG(ht_persistent_socks), hashkey, strlen(hashkey) + 1, + (void *) &stream) == SUCCESS) + { + efree(hashkey); + ZEND_REGISTER_RESOURCE(return_value, stream, php_file_le_stream()); return; } - if (portno) { - struct sockaddr_in server; + /* prepare the timeout value for use */ + conv = (unsigned long) (timeout * 1000000.0); + tv.tv_sec = conv / 1000000; + tv.tv_usec = conv % 1000000; - memset(&server, 0, sizeof(server)); - if(Z_STRLEN_PP(args[0]) >= 6 && !memcmp(Z_STRVAL_PP(args[0]), "udp://", sizeof("udp://")-1)) { - udp = 1; - } + if (zerrno) { + zval_dtor(zerrno); + ZVAL_LONG(zerrno, 0); + } + if (zerrstr) { + zval_dtor(zerrstr); + ZVAL_STRING(zerrno, "", 1); + } - socketd = socket(PF_INET, udp ? SOCK_DGRAM : SOCK_STREAM, 0); - if (socketd == SOCK_ERR) { - CLOSE_SOCK(1); - RETURN_FALSE; + if (port != -1) { /* connect to a host */ + enum php_sslflags_t { php_ssl_none, php_ssl_v23, php_ssl_tls }; + enum php_sslflags_t ssl_flags; + struct { + char * proto; + int protolen; + int socktype; + enum php_sslflags_t ssl_flags; + /* more flags to be added here */ + } sockmodes[] = { + { "udp://", 6, SOCK_DGRAM, php_ssl_none }, + { "tcp://", 6, SOCK_STREAM, php_ssl_none }, + { "ssl://", 6, SOCK_STREAM, php_ssl_v23 }, + { "tls://", 6, SOCK_STREAM, php_ssl_tls }, + /* more modes to be added here */ + { NULL, 0, 0 } + }; + int socktype = SOCK_STREAM; + int i; + + for (i = 0; sockmodes[i].proto != NULL; i++) { + if (strncmp(host, sockmodes[i].proto, sockmodes[i].protolen) == 0) { + ssl_flags = sockmodes[i].ssl_flags; + socktype = sockmodes[i].socktype; + host += sockmodes[i].protolen; + break; + } } - - server.sin_family = AF_INET; - - if(php_lookup_hostname(udp ? &Z_STRVAL_PP(args[0])[6] : Z_STRVAL_PP(args[0]), &server.sin_addr)) { - CLOSE_SOCK(1); - RETURN_FALSE; +#if !HAVE_OPENSSL_EXT + if (ssl_flags != php_ssl_none) { + zend_error(E_WARNING, "%s(): no SSL support in this build", get_active_function_name(TSRMLS_C)); } - - server.sin_port = htons(portno); - - if (php_connect_nonb(socketd, (struct sockaddr *) &server, sizeof(server), &timeout) == SOCK_CONN_ERR) { - CLOSE_SOCK(1); - - if (arg_count>2) { - zval_dtor(*args[2]); - ZVAL_LONG(*args[2], errno); - } - if (arg_count>3) { - zval_dtor(*args[3]); - ZVAL_STRING(*args[3], strerror(errno), 1); + else +#endif + stream = php_stream_sock_open_host(host, port, socktype, timeout, persistent); + +#if HAVE_OPENSSL_EXT + if (stream) { + int ssl_ret = FAILURE; + switch(ssl_flags) { + case php_ssl_v23: + ssl_ret = php_stream_sock_ssl_activate_with_method(stream, 1, SSLv23_client_method()); + break; + case php_ssl_tls: + ssl_ret = php_stream_sock_ssl_activate_with_method(stream, 1, TLSv1_client_method()); + break; + default: + /* unknown ?? */ } - RETURN_FALSE; - } -#if defined(AF_UNIX) - } else { - /* Unix domain socket. s->strval is socket name. */ - struct sockaddr_un unix_addr; - socketd = socket(PF_UNIX, SOCK_STREAM, 0); - if (socketd == SOCK_ERR) { - CLOSE_SOCK(1); - RETURN_FALSE; + if (ssl_ret == FAILURE) + zend_error(E_WARNING, "%s(): failed to activate SSL mode %d", get_active_function_name(TSRMLS_C), ssl_flags); } +#endif + + } else + stream = php_stream_sock_open_unix(host, persistent, &tv); - memset(&unix_addr, 0, sizeof(unix_addr)); - unix_addr.sun_family = AF_UNIX; - strlcpy(unix_addr.sun_path, Z_STRVAL_PP(args[0]), sizeof(unix_addr.sun_path)); + if (stream && persistent) { + zend_hash_update(&FG(ht_persistent_socks), hashkey, strlen(hashkey) + 1, + &stream, sizeof(stream), NULL); + } - if (php_connect_nonb(socketd, (struct sockaddr *) &unix_addr, sizeof(unix_addr), &timeout) == SOCK_CONN_ERR) { - CLOSE_SOCK(1); - if (arg_count>2) { - zval_dtor(*args[2]); - ZVAL_LONG(*args[2], errno); - } - if (arg_count>3) { - zval_dtor(*args[3]); - ZVAL_STRING(*args[3], strerror(errno), 1); - } - RETURN_FALSE; + efree(hashkey); + + if (stream == NULL) { + if (zerrno) { + zval_dtor(zerrno); + ZVAL_LONG(zerrno, errno); + } + if (zerrstr) { + zval_dtor(zerrstr); + ZVAL_STRING(zerrno, strerror(errno), 1); } -#endif /* AF_UNIX */ - } - *sock = socketd; - if (persistent) { - zend_hash_update(&FG(ht_fsock_keys), key, strlen(key) + 1, - sock, sizeof(*sock), NULL); - zend_hash_update(&FG(ht_fsock_socks), (char *) sock, sizeof(*sock), - key, strlen(key) + 1, NULL); + RETURN_FALSE; } - - if (key) - efree(key); - - ZEND_REGISTER_RESOURCE(return_value, sock, php_file_le_socket()); + + ZEND_REGISTER_RESOURCE(return_value, stream, php_file_le_stream()); } + /* }}} */ /* {{{ proto int fsockopen(string hostname, int port [, int errno [, string errstr [, float timeout]]]) Open Internet or Unix domain socket connection */ PHP_FUNCTION(fsockopen) { - php_fsockopen(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); + php_fsockopen_stream(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); } /* }}} */ /* {{{ proto int pfsockopen(string hostname, int port [, int errno [, string errstr [, float timeout]]]) Open persistent Internet or Unix domain socket connection */ PHP_FUNCTION(pfsockopen) { - php_fsockopen(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); -} -/* }}} */ - -#define SOCK_DESTROY(sock) \ - if(sock->readbuf) pefree(sock->readbuf, sock->persistent); \ - if(sock->prev) sock->prev->next = sock->next; \ - if(sock->next) sock->next->prev = sock->prev; \ - if(sock == FG(phpsockbuf)) \ - FG(phpsockbuf) = sock->next; \ - pefree(sock, sock->persistent) - -PHPAPI void php_cleanup_sockbuf(int persistent TSRMLS_DC) -{ - php_sockbuf *now, *next; - - for(now = FG(phpsockbuf); now; now = next) { - next = now->next; - if(now->persistent == persistent) { - SOCK_DESTROY(now); - } - } -} - -#define TOREAD(sock) ((sock)->writepos - (sock)->readpos) -#define READPTR(sock) ((sock)->readbuf + (sock)->readpos) -#define WRITEPTR(sock) ((sock)->readbuf + (sock)->writepos) -#define SOCK_FIND(sock, socket) \ - php_sockbuf *sock; \ - TSRMLS_FETCH(); \ - sock = php_sockfind(socket TSRMLS_CC); \ - if(!sock) sock = php_sockcreate(socket TSRMLS_CC) - -static php_sockbuf *php_sockfind(int socket TSRMLS_DC) -{ - php_sockbuf *buf = NULL, *tmp; - - for(tmp = FG(phpsockbuf); tmp; tmp = tmp->next) - if(tmp->socket == socket) { - buf = tmp; - break; - } - - return buf; -} - -static php_sockbuf *php_sockcreate(int socket TSRMLS_DC) -{ - php_sockbuf *sock; - int persistent = php_is_persistent_sock(socket); - - sock = pecalloc(sizeof(*sock), 1, persistent); - sock->socket = socket; - if((sock->next = FG(phpsockbuf))) - FG(phpsockbuf)->prev = sock; - sock->persistent = persistent; - sock->is_blocked = 1; - sock->chunk_size = FG(def_chunk_size); - sock->timeout.tv_sec = -1; - FG(phpsockbuf) = sock; - - return sock; -} - -PHPAPI php_sockbuf *php_get_socket(int socket) -{ - SOCK_FIND(sock, socket); - return sock; -} - -PHPAPI size_t php_sock_set_def_chunk_size(size_t size) -{ - size_t old; - TSRMLS_FETCH(); - - old = FG(def_chunk_size); - - if(size <= PHP_FSOCK_CHUNK_SIZE || size > 0) - FG(def_chunk_size) = size; - - return old; -} - -PHPAPI int php_sockdestroy(int socket) -{ - int ret = 0; - php_sockbuf *sock; - TSRMLS_FETCH(); - - sock = php_sockfind(socket TSRMLS_CC); - if(sock) { - ret = 1; - SOCK_DESTROY(sock); - } - - return ret; -} - -#if !defined(PHP_WIN32) -#undef closesocket -#define closesocket close -#endif - -#ifndef HAVE_SHUTDOWN -#undef shutdown -#define shutdown -#endif - -#define SOCK_CLOSE(s) shutdown(s, 0); closesocket(s) - -PHPAPI int php_sock_close(int socket) -{ - int ret = 0; - php_sockbuf *sock; - TSRMLS_FETCH(); - - sock = php_sockfind(socket TSRMLS_CC); - if(sock) { - if(!sock->persistent) { - SOCK_CLOSE(sock->socket); - SOCK_DESTROY(sock); - } - } else { - SOCK_CLOSE(socket); - } - - return ret; -} - -#define MAX_CHUNKS_PER_READ 10 - -static void php_sockwait_for_data(php_sockbuf *sock) -{ - fd_set fdr, tfdr; - int retval; - struct timeval timeout, *ptimeout; - - FD_ZERO(&fdr); - FD_SET(sock->socket, &fdr); - sock->timeout_event = 0; - - if (sock->timeout.tv_sec == -1) - ptimeout = NULL; - else - ptimeout = &timeout; - - while(1) { - tfdr = fdr; - timeout = sock->timeout; - - retval = select(sock->socket + 1, &tfdr, NULL, NULL, ptimeout); - - if (retval == 0) - sock->timeout_event = 1; - - if (retval >= 0) - break; - } -} - -static size_t php_sockread_internal(php_sockbuf *sock) -{ - char buf[PHP_FSOCK_CHUNK_SIZE]; - int nr_bytes; - size_t nr_read = 0; - - /* For blocking sockets, we wait until there is some - data to read (real data or EOF) - - Otherwise, recv() may time out and return 0 and - therefore sock->eof would be set errornously. - */ - - - if(sock->is_blocked) { - php_sockwait_for_data(sock); - if (sock->timeout_event) - return 0; - } - - /* read at a maximum sock->chunk_size */ - nr_bytes = recv(sock->socket, buf, sock->chunk_size, 0); - if(nr_bytes > 0) { - if(sock->writepos + nr_bytes > sock->readbuflen) { - sock->readbuflen += sock->chunk_size; - sock->readbuf = perealloc(sock->readbuf, sock->readbuflen, - sock->persistent); - } - memcpy(WRITEPTR(sock), buf, nr_bytes); - sock->writepos += nr_bytes; - nr_read = nr_bytes; - } else if(nr_bytes == 0 || (nr_bytes < 0 && errno != EWOULDBLOCK)) { - sock->eof = 1; - } - - return nr_read; -} - -static void php_sockread_total(php_sockbuf *sock, size_t maxread) -{ - while(!sock->eof && TOREAD(sock) < maxread && !sock->timeout_event) { - php_sockread_internal(sock); - } -} - -static size_t php_sockread(php_sockbuf *sock) -{ - size_t nr_bytes; - size_t nr_read = 0; - int i; - - for(i = 0; !sock->eof && i < MAX_CHUNKS_PER_READ; i++) { - nr_bytes = php_sockread_internal(sock); - if(nr_bytes == 0) break; - nr_read += nr_bytes; - } - - return nr_read; -} - -PHPAPI int php_sockset_blocking(int socket, int mode) -{ - int old; - SOCK_FIND(sock, socket); - - old = sock->is_blocked; - - sock->is_blocked = mode; - - return old; -} - -PHPAPI void php_sockset_timeout(int socket, struct timeval *timeout) -{ - SOCK_FIND(sock, socket); - - sock->timeout = *timeout; - sock->timeout_event = 0; -} - -#define SOCK_FIND_AND_READ_MAX(max) \ - SOCK_FIND(sock, socket); \ - if(sock->is_blocked) php_sockread_total(sock, max); else php_sockread(sock) - -/* {{{ php_sock_fgets() */ -/* - * FIXME: fgets depends on '\n' as line delimiter - */ -static char * php_sock_fgets_internal(char * buf, size_t maxlen, php_sockbuf * sock) -{ - char *p = NULL, *pe; - char *ret = NULL; - size_t amount = 0; - - if (maxlen==0) { - buf[0] = 0; - return buf; - } - - SEARCHCR(); - - if(!p) { - if(sock->is_blocked) { - while(!p && !sock->eof && !sock->timeout_event && TOREAD(sock) < maxlen) { - php_sockread_internal(sock); - SEARCHCR(); - } - } else { - php_sockread(sock); - SEARCHCR(); - } - } - - - if(p) { - amount = (ptrdiff_t) p - (ptrdiff_t) READPTR(sock) + 1; - } else { - amount = TOREAD(sock); - } - - amount = MIN(amount, maxlen); - - if(amount > 0) { - memcpy(buf, READPTR(sock), amount); - sock->readpos += amount; - } - buf[amount] = '\0'; - - /* signal error only, if we don't return data from this call and - if there is no data to read and if the eof flag is set */ - if(amount || TOREAD(sock) || !sock->eof) { - ret = buf; - } - - return ret; -} -PHPAPI char *php_sock_fgets(char *buf, size_t maxlen, int socket) -{ - SOCK_FIND(sock, socket); - return php_sock_fgets_internal(buf, maxlen, sock); -} - - -/* }}} */ - -/* - * FIXME: fgetc returns EOF, if no data is available on a nonblocking socket. - * I don't have any documentation on the semantics of fgetc in this case. - * - * ss@2ns.de 19990528 - */ - -PHPAPI int php_sock_fgetc(int socket) -{ - int ret = EOF; - SOCK_FIND_AND_READ_MAX(1); - - if(TOREAD(sock) > 0) { - ret = *READPTR(sock); - sock->readpos++; - } - - return ret; -} - -PHPAPI int php_sock_feof(int socket) -{ - int ret = 0; - SOCK_FIND(sock, socket); - - if(!sock->is_blocked) - php_sockread(sock); - - if(!TOREAD(sock) && sock->eof) - ret = 1; - - return ret; -} - -/* {{{ stream abstraction */ -#if HAVE_PHP_STREAM -static size_t php_sockop_write(php_stream * stream, const char * buf, size_t count) -{ - php_sockbuf * sock = (php_sockbuf*)stream->abstract; - return send(sock->socket, buf, count, 0); + php_fsockopen_stream(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); } - -static size_t php_sockop_read(php_stream * stream, char * buf, size_t count) -{ - php_sockbuf * sock = (php_sockbuf*)stream->abstract; - size_t ret = 0; - - if (sock->is_blocked) - php_sockread_total(sock, count); - else - php_sockread(sock); - - if(count < 0) - return ret; - - ret = MIN(TOREAD(sock), count); - if (ret) { - memcpy(buf, READPTR(sock), ret); - sock->readpos += ret; - } - - return ret; -} - -static int php_sockop_close(php_stream * stream) -{ - php_sockbuf * sock = (php_sockbuf*)stream->abstract; - - SOCK_CLOSE(sock->socket); - SOCK_DESTROY(sock); - - return 0; -} - -static int php_sockop_flush(php_stream * stream) -{ - php_sockbuf * sock = (php_sockbuf*)stream->abstract; - return fsync(sock->socket); -} - -static int php_sockop_cast(php_stream * stream, int castas, void ** ret) -{ - php_sockbuf * sock = (php_sockbuf*)stream->abstract; - TSRMLS_FETCH(); - - switch(castas) { - case PHP_STREAM_AS_STDIO: - if (ret) { - /* DANGER!: data buffered in stream->readbuf will be forgotten! */ - if (TOREAD(sock) > 0) - zend_error(E_WARNING, "%s(): buffered data lost during conversion to FILE*!", get_active_function_name(TSRMLS_C)); - *ret = fdopen(sock->socket, stream->mode); - if (*ret) - return SUCCESS; - return FAILURE; - } - return SUCCESS; - case PHP_STREAM_AS_FD: - case PHP_STREAM_AS_SOCKETD: - if (ret) - *ret = (void*)sock->socket; - return SUCCESS; - default: - return FAILURE; - } -} - -static char * php_sockop_gets(php_stream * stream, char *buf, size_t size) -{ - php_sockbuf * sock = (php_sockbuf*)stream->abstract; - return php_sock_fgets_internal(buf, size, sock); -} - -php_stream_ops php_stream_socket_ops = { - php_sockop_write, php_sockop_read, - php_sockop_close, php_sockop_flush, - NULL, php_sockop_gets, - php_sockop_cast, - "socket" -}; -#endif -/* }}} */ - -/* {{{ php_sock_fread() */ - -PHPAPI size_t php_sock_fread(char *ptr, size_t size, int socket) -{ - size_t ret = 0; - SOCK_FIND_AND_READ_MAX(size); - - if(size < 0) - return ret; - - ret = MIN(TOREAD(sock), size); - if(ret) { - memcpy(ptr, READPTR(sock), ret); - sock->readpos += ret; - } - - return ret; -} - /* }}} */ -/* {{{ module start/shutdown functions */ - - /* {{{ php_msock_destroy */ -PHPAPI void php_msock_destroy(int *data) -{ - close(*data); -} -/* }}} */ - - - +/* {{{ RSHUTDOWN_FUNCTION(fsock) */ PHP_RSHUTDOWN_FUNCTION(fsock) { - php_cleanup_sockbuf(0 TSRMLS_CC); return SUCCESS; } /* }}} */ diff --git a/ext/standard/fsock.h b/ext/standard/fsock.h index 13e5c5f196..fb134e97bc 100644 --- a/ext/standard/fsock.h +++ b/ext/standard/fsock.h @@ -27,54 +27,12 @@ #include "file.h" -#define PHP_FSOCK_CHUNK_SIZE 8192 - #include "php_network.h" -#if HAVE_PHP_STREAM -extern php_stream_ops php_stream_socket_ops; -#endif - -/* stream->abstract points to an instance of this */ -struct php_sockbuf { - int socket; - unsigned char *readbuf; - size_t readbuflen; - size_t readpos; - size_t writepos; - struct php_sockbuf *next; - struct php_sockbuf *prev; - char eof; - char persistent; - char is_blocked; - size_t chunk_size; - struct timeval timeout; - char timeout_event; -#if HAVE_PHP_STREAM - php_stream * stream; -#endif -}; - -typedef struct php_sockbuf php_sockbuf; - PHP_FUNCTION(fsockopen); PHP_FUNCTION(pfsockopen); PHPAPI int php_lookup_hostname(const char *addr, struct in_addr *in); -PHPAPI char *php_sock_fgets(char *buf, size_t maxlen, int socket); -PHPAPI size_t php_sock_fread(char *buf, size_t maxlen, int socket); -PHPAPI int php_sock_feof(int socket); -PHPAPI int php_sock_fgetc(int socket); -PHPAPI int php_is_persistent_sock(int); -PHPAPI int php_sockset_blocking(int socket, int mode); -PHPAPI void php_sockset_timeout(int socket, struct timeval *timeout); -PHPAPI int php_sockdestroy(int socket); -PHPAPI int php_sock_close(int socket); -PHPAPI size_t php_sock_set_def_chunk_size(size_t size); -PHPAPI void php_msock_destroy(int *data); -PHPAPI void php_cleanup_sockbuf(int persistent TSRMLS_DC); - -PHPAPI struct php_sockbuf *php_get_socket(int socket); PHP_RSHUTDOWN_FUNCTION(fsock); diff --git a/ext/standard/ftp_fopen_wrapper.c b/ext/standard/ftp_fopen_wrapper.c index 98552e1143..4c4b0543b1 100644 --- a/ext/standard/ftp_fopen_wrapper.c +++ b/ext/standard/ftp_fopen_wrapper.c @@ -66,22 +66,28 @@ #include "php_fopen_wrappers.h" -static int php_get_ftp_result(int socketd) +static int php_get_ftp_result(php_stream * stream) { char tmp_line[513]; - while (SOCK_FGETS(tmp_line, sizeof(tmp_line)-1, socketd) && + while (php_stream_gets(stream, tmp_line, sizeof(tmp_line)-1) && !(isdigit((int) tmp_line[0]) && isdigit((int) tmp_line[1]) && isdigit((int) tmp_line[2]) && tmp_line[3] == ' ')); return strtol(tmp_line, NULL, 10); } +php_stream_wrapper php_stream_ftp_wrapper = { + php_stream_url_wrap_ftp, + NULL +}; + + /* {{{ php_fopen_url_wrap_ftp */ -FILE *php_fopen_url_wrap_ftp(const char *path, char *mode, int options, int *issock, int *socketd, char **opened_path TSRMLS_DC) +php_stream * php_stream_url_wrap_ftp(char * path, char * mode, int options, char ** opened_path TSRMLS_DC) { - FILE *fp=NULL; + php_stream *stream=NULL; php_url *resource=NULL; char tmp_line[512]; unsigned short portno; @@ -91,126 +97,98 @@ FILE *php_fopen_url_wrap_ftp(const char *path, char *mode, int options, int *iss char *tpath, *ttpath; resource = php_url_parse((char *) path); - if (resource == NULL) { - php_error(E_WARNING, "Invalid URL specified, %s", path); - *issock = BAD_URL; + if (resource == NULL || resource->path == NULL) return NULL; - } else if (resource->path == NULL) { - php_error(E_WARNING, "No file-path specified"); - php_url_free(resource); - *issock = BAD_URL; - return NULL; - } + /* use port 21 if one wasn't specified */ if (resource->port == 0) resource->port = 21; - - *socketd = php_hostconnect(resource->host, resource->port, SOCK_STREAM, 0); - if (*socketd == -1) - goto errexit; -#if 0 - if ((fpc = fdopen(*socketd, "r+")) == NULL) { - php_url_free(resource); - return NULL; - } -#ifdef HAVE_SETVBUF - if ((setvbuf(fpc, NULL, _IONBF, 0)) != 0) { - php_url_free(resource); - fclose(fpc); - return NULL; - } -#endif -#endif + stream = php_stream_sock_open_host(resource->host, resource->port, SOCK_STREAM, 0, 0); + if (stream == NULL) + goto errexit; + /* Start talking to ftp server */ - result = php_get_ftp_result(*socketd); + result = php_get_ftp_result(stream); if (result > 299 || result < 200) goto errexit; /* send the user name */ - SOCK_WRITE("USER ", *socketd); + php_stream_write_string(stream, "USER "); if (resource->user != NULL) { php_raw_url_decode(resource->user, strlen(resource->user)); - SOCK_WRITE(resource->user, *socketd); + php_stream_write_string(stream, resource->user); } else { - SOCK_WRITE("anonymous", *socketd); + php_stream_write_string(stream, "anonymous"); } - SOCK_WRITE("\r\n", *socketd); + php_stream_write_string(stream, "\r\n"); /* get the response */ - result = php_get_ftp_result(*socketd); + result = php_get_ftp_result(stream); /* if a password is required, send it */ if (result >= 300 && result <= 399) { - SOCK_WRITE("PASS ", *socketd); + php_stream_write_string(stream, "PASS "); if (resource->pass != NULL) { php_raw_url_decode(resource->pass, strlen(resource->pass)); - SOCK_WRITE(resource->pass, *socketd); + php_stream_write_string(stream, resource->pass); } else { /* if the user has configured who they are, send that as the password */ if (cfg_get_string("from", &scratch) == SUCCESS) { - SOCK_WRITE(scratch, *socketd); + php_stream_write_string(stream, scratch); } else { - SOCK_WRITE("anonymous", *socketd); + php_stream_write_string(stream, "anonymous"); } } - SOCK_WRITE("\r\n", *socketd); + php_stream_write_string(stream, "\r\n"); /* read the response */ - result = php_get_ftp_result(*socketd); + result = php_get_ftp_result(stream); } if (result > 299 || result < 200) goto errexit; /* set the connection to be binary */ - SOCK_WRITE("TYPE I\r\n", *socketd); - result = php_get_ftp_result(*socketd); + php_stream_write_string(stream, "TYPE I\r\n"); + result = php_get_ftp_result(stream); if (result > 299 || result < 200) goto errexit; /* find out the size of the file (verifying it exists) */ - SOCK_WRITE("SIZE ", *socketd); - SOCK_WRITE(resource->path, *socketd); - SOCK_WRITE("\r\n", *socketd); + php_stream_write_string(stream, "SIZE "); + php_stream_write_string(stream, resource->path); + php_stream_write_string(stream, "\r\n"); /* read the response */ - result = php_get_ftp_result(*socketd); + result = php_get_ftp_result(stream); if (mode[0] == 'r') { /* when reading file, it must exist */ if (result > 299 || result < 200) { - php_error(E_WARNING, "File not found"); - php_url_free(resource); - SOCK_FCLOSE(*socketd); - *socketd = 0; errno = ENOENT; - return NULL; + goto errexit; } } else { /* when writing file, it must NOT exist */ if (result <= 299 && result >= 200) { - php_error(E_WARNING, "File already exists"); - php_url_free(resource); - SOCK_FCLOSE(*socketd); - *socketd = 0; errno = EEXIST; - return NULL; + goto errexit; } } /* set up the passive connection */ /* We try EPSV first, needed for IPv6 and works on some IPv4 servers */ - SOCK_WRITE("EPSV\r\n", *socketd); - while (SOCK_FGETS(tmp_line, sizeof(tmp_line)-1, *socketd) && + php_stream_write_string(stream, "EPSV\r\n"); + while (php_stream_gets(stream, tmp_line, sizeof(tmp_line)-1) && !(isdigit((int) tmp_line[0]) && isdigit((int) tmp_line[1]) && isdigit((int) tmp_line[2]) && tmp_line[3] == ' ')); /* check if we got a 229 response */ if (strncmp(tmp_line, "229", 3)) { /* EPSV failed, let's try PASV */ - SOCK_WRITE("PASV\r\n", *socketd); - while (SOCK_FGETS(tmp_line, sizeof(tmp_line)-1, *socketd) && + php_stream_write_string(stream, "PASV\r\n"); + while (php_stream_gets(stream, tmp_line, sizeof(tmp_line)-1) && !(isdigit((int) tmp_line[0]) && isdigit((int) tmp_line[1]) && isdigit((int) tmp_line[2]) && tmp_line[3] == ' ')); /* make sure we got a 227 response */ @@ -263,53 +241,33 @@ FILE *php_fopen_url_wrap_ftp(const char *path, char *mode, int options, int *iss if (mode[0] == 'r') { /* retrieve file */ - SOCK_WRITE("RETR ", *socketd); + php_stream_write_string(stream, "RETR "); } else { /* store file */ - SOCK_WRITE("STOR ", *socketd); + php_stream_write_string(stream, "STOR "); } if (resource->path != NULL) { - SOCK_WRITE(resource->path, *socketd); + php_stream_write_string(stream, resource->path); } else { - SOCK_WRITE("/", *socketd); + php_stream_write_string(stream, "/"); } /* close control connection */ - SOCK_WRITE("\r\nQUIT\r\n", *socketd); - SOCK_FCLOSE(*socketd); + php_stream_write_string(stream, "\r\nQUIT\r\n"); + php_stream_close(stream); /* open the data channel */ - *socketd = php_hostconnect(resource->host, portno, SOCK_STREAM, 0); - if (*socketd == -1) + stream = php_stream_sock_open_host(resource->host, portno, SOCK_STREAM, 0, 0); + if (stream == NULL) goto errexit; -#if 0 - if (mode[0] == 'r') { - if ((fp = fdopen(*socketd, "r+")) == NULL) { - php_url_free(resource); - return NULL; - } - } else { - if ((fp = fdopen(*socketd, "w+")) == NULL) { - php_url_free(resource); - return NULL; - } - } -#ifdef HAVE_SETVBUF - if ((setvbuf(fp, NULL, _IONBF, 0)) != 0) { - php_url_free(resource); - fclose(fp); - return NULL; - } -#endif -#endif + php_url_free(resource); - *issock = 1; - return (fp); + return stream; errexit: php_url_free(resource); - SOCK_FCLOSE(*socketd); - *socketd = 0; + if (stream) + php_stream_close(stream); return NULL; } /* }}} */ diff --git a/ext/standard/html.c b/ext/standard/html.c index cc2999ace1..7cf5a25de3 100644 --- a/ext/standard/html.c +++ b/ext/standard/html.c @@ -23,7 +23,7 @@ #include "php.h" #include "reg.h" #include "html.h" - +#include "php_string.h" #if HAVE_LOCALE_H #include <locale.h> #endif @@ -123,6 +123,21 @@ static const struct { { NULL } }; +static const struct { + unsigned short charcode; + char * entity; + int entitylen; + int flags; +} basic_entities[] = { + { '&', "&", 5, 0 }, + { '"', """, 6, ENT_HTML_QUOTE_DOUBLE }, + { '\'', "'", 6, ENT_HTML_QUOTE_SINGLE }, + { '<', "<", 4, 0 }, + { '>', ">", 4, 0 }, + { 0, NULL, 0, 0 } +}; + + /* {{{ get_next_char */ inline static unsigned short get_next_char(enum entity_charset charset, @@ -389,19 +404,88 @@ static enum entity_charset determine_charset(char * charset_hint) } /* }}} */ +/* {{{ php_unescape_html_entities + */ +PHPAPI char *php_unescape_html_entities(unsigned char *old, int oldlen, int *newlen, int all, int quote_style, char *hint_charset) +{ + int i, maxlen, len, retlen; + int j, k; + char *replaced, *ret; + enum entity_charset charset = determine_charset(hint_charset); + int matches_map; + unsigned char replacement[15]; + + ret = estrdup(old); + retlen = oldlen; + + if (all) { + /* look for a match in the maps for this charset */ + for (j=0; entity_map[j].charset != cs_terminator; j++) { + if (entity_map[j].charset != charset) + continue; + + for (k = entity_map[j].basechar; k <= entity_map[j].endchar; k++) { + unsigned char entity[32]; + int entity_length = 0; + + if (entity_map[j].table[k - entity_map[j].basechar] == NULL) + continue; + + + entity[0] = '&'; + entity_length = strlen(entity_map[j].table[k - entity_map[j].basechar]); + strncpy(&entity[1], entity_map[j].table[k - entity_map[j].basechar], sizeof(entity) - 2); + entity[entity_length+1] = ';'; + entity[entity_length+2] = '\0'; + entity_length += 2; + + /* When we have MBCS entities in the tables above, this will need to handle it */ + if (k > 0xff) + zend_error(E_WARNING, "cannot yet handle MBCS in html_entity_decode()!"); + replacement[0] = k; + replacement[1] = '\0'; + + replaced = php_str_to_str(ret, retlen, entity, entity_length, replacement, 1, &retlen); + efree(ret); + ret = replaced; + } + } + } + + for (j = 0; basic_entities[j].charcode != 0; j++) { + + if (basic_entities[j].flags && (quote_style & basic_entities[j].flags) == 0) + continue; + + replacement[0] = basic_entities[j].charcode; + replacement[1] = '\0'; + + replaced = php_str_to_str(ret, retlen, basic_entities[j].entity, basic_entities[j].entitylen, replacement, 1, &retlen); + efree(ret); + ret = replaced; + } + + *newlen = retlen; + return ret; +} +/* }}} */ + + + + /* {{{ php_escape_html_entities */ PHPAPI char *php_escape_html_entities(unsigned char *old, int oldlen, int *newlen, int all, int quote_style, char *hint_charset) { - int i, maxlen, len; - char *new; + int i, j, maxlen, len; + char *replaced; enum entity_charset charset = determine_charset(hint_charset); int matches_map; maxlen = 2 * oldlen; if (maxlen < 128) maxlen = 128; - new = emalloc (maxlen); + replaced = emalloc (maxlen); len = 0; i = 0; @@ -409,17 +493,16 @@ PHPAPI char *php_escape_html_entities(unsigned char *old, int oldlen, int *newle int mbseqlen; unsigned char mbsequence[16]; /* allow up to 15 characters in a multibyte sequence */ unsigned short this_char = get_next_char(charset, old, &i, mbsequence, &mbseqlen); - + matches_map = 0; - + if (len + 9 > maxlen) - new = erealloc (new, maxlen += 128); - + replaced = erealloc (replaced, maxlen += 128); + if (all) { /* look for a match in the maps for this charset */ - int j; unsigned char * rep; - + for (j=0; entity_map[j].charset != cs_terminator; j++) { if (entity_map[j].charset == charset @@ -432,48 +515,49 @@ PHPAPI char *php_escape_html_entities(unsigned char *old, int oldlen, int *newle * just output the character itself */ break; } - + matches_map = 1; break; } } if (matches_map) { - new[len++] = '&'; - strcpy(new + len, rep); + replaced[len++] = '&'; + strcpy(replaced + len, rep); len += strlen(rep); - new[len++] = ';'; + replaced[len++] = ';'; } } if (!matches_map) { - if (38 == this_char) { - memcpy (new + len, "&", 5); - len += 5; - } else if (34 == this_char && !(quote_style&ENT_NOQUOTES)) { - memcpy (new + len, """, 6); - len += 6; - } else if (39 == this_char && (quote_style&ENT_QUOTES)) { - memcpy (new + len, "'", 6); - len += 6; - } else if (60 == this_char) { - memcpy (new + len, "<", 4); - len += 4; - } else if (62 == this_char) { - memcpy (new + len, ">", 4); - len += 4; - } else if (this_char > 0xff) { - /* a wide char without a named entity; pass through the original sequence */ - memcpy(new + len, mbsequence, mbseqlen); - len += mbseqlen; - } else { - new [len++] = (unsigned char)this_char; + int is_basic = 0; + + for (j = 0; basic_entities[j].charcode != 0; j++) { + if ((basic_entities[j].charcode != this_char) || + (basic_entities[j].flags && (quote_style & basic_entities[j].flags) == 0)) + continue; + + memcpy(replaced + len, basic_entities[j].entity, basic_entities[j].entitylen); + len += basic_entities[j].entitylen; + + is_basic = 1; + break; + + } + if (!is_basic) { + if (this_char > 0xff) { + /* a wide char without a named entity; pass through the original sequence */ + memcpy(replaced + len, mbsequence, mbseqlen); + len += mbseqlen; + + } else + replaced [len++] = (unsigned char)this_char; } } } - new [len] = '\0'; + replaced [len] = '\0'; *newlen = len; - return new; + return replaced; } @@ -485,15 +569,15 @@ static void php_html_entities(INTERNAL_FUNCTION_PARAMETERS, int all) { char *str, *hint_charset = NULL; int str_len, hint_charset_len, len, quote_style = ENT_COMPAT; - char *new; + char *replaced; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ls", &str, &str_len, "e_style, &hint_charset, &hint_charset_len) == FAILURE) { return; } - new = php_escape_html_entities(str, str_len, &len, all, quote_style, hint_charset); - RETVAL_STRINGL(new, len, 0); + replaced = php_escape_html_entities(str, str_len, &len, all, quote_style, hint_charset); + RETVAL_STRINGL(replaced, len, 0); } /* }}} */ @@ -520,6 +604,25 @@ PHP_FUNCTION(htmlspecialchars) } /* }}} */ +/* {{{ proto string html_entity_decode(string string [, int quote_style][, string charset]) + Convert all applicable characters to HTML entities */ +PHP_FUNCTION(html_entity_decode) +{ + char *str, *hint_charset = NULL; + int str_len, hint_charset_len, len, quote_style = ENT_COMPAT; + char *replaced; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ls", &str, &str_len, + "e_style, &hint_charset, &hint_charset_len) == FAILURE) { + return; + } + + replaced = php_unescape_html_entities(str, str_len, &len, 1, quote_style, hint_charset); + RETVAL_STRINGL(replaced, len, 0); +} +/* }}} */ + + /* {{{ proto string htmlentities(string string [, int quote_style][, string charset]) Convert all applicable characters to HTML entities */ PHP_FUNCTION(htmlentities) @@ -566,15 +669,14 @@ PHP_FUNCTION(get_html_translation_table) /* break thru */ case HTML_SPECIALCHARS: - ind[0]=38; add_assoc_string(return_value, ind, "&", 1); - if(quote_style&ENT_QUOTES) { - ind[0]=39; add_assoc_string(return_value, ind, "'", 1); - } - if(!(quote_style&ENT_NOQUOTES)) { - ind[0]=34; add_assoc_string(return_value, ind, """, 1); + for (j = 0; basic_entities[j].charcode != 0; j++) { + + if (basic_entities[j].flags && (quote_style & basic_entities[j].flags) == 0) + continue; + + ind[0] = basic_entities[j].charcode; + add_assoc_string(return_value, ind, basic_entities[j].entity, 1); } - ind[0]=60; add_assoc_string(return_value, ind, "<", 1); - ind[0]=62; add_assoc_string(return_value, ind, ">", 1); break; } } diff --git a/ext/standard/html.h b/ext/standard/html.h index ac11acb0f1..5f122cbc6e 100644 --- a/ext/standard/html.h +++ b/ext/standard/html.h @@ -21,14 +21,19 @@ #ifndef HTML_H #define HTML_H -#define ENT_COMPAT 1 -#define ENT_QUOTES 2 -#define ENT_NOQUOTES 4 +#define ENT_HTML_QUOTE_NONE 0 +#define ENT_HTML_QUOTE_SINGLE 1 +#define ENT_HTML_QUOTE_DOUBLE 2 + +#define ENT_COMPAT ENT_HTML_QUOTE_DOUBLE +#define ENT_QUOTES (ENT_HTML_QUOTE_DOUBLE | ENT_HTML_QUOTE_SINGLE) +#define ENT_NOQUOTES ENT_HTML_QUOTE_NONE void register_html_constants(INIT_FUNC_ARGS); PHP_FUNCTION(htmlspecialchars); PHP_FUNCTION(htmlentities); +PHP_FUNCTION(html_entity_decode); PHP_FUNCTION(get_html_translation_table); PHPAPI char *php_escape_html_entities(unsigned char *old, int oldlen, int *newlen, int all, int quote_style, char * hint_charset); diff --git a/ext/standard/http_fopen_wrapper.c b/ext/standard/http_fopen_wrapper.c index 24e546bb60..41ee9d7d54 100644 --- a/ext/standard/http_fopen_wrapper.c +++ b/ext/standard/http_fopen_wrapper.c @@ -15,12 +15,14 @@ | Authors: Rasmus Lerdorf <rasmus@php.net> | | Jim Winstead <jimw@php.net> | | Hartmut Holzgraefe <hholzgra@php.net> | + | Wez Furlong <wez@thebrainroom.com> | +----------------------------------------------------------------------+ */ /* $Id$ */ #include "php.h" #include "php_globals.h" +#include "php_streams.h" #include "php_network.h" #include <stdio.h> @@ -66,7 +68,256 @@ #include "php_fopen_wrappers.h" -#define HTTP_HEADER_BLOCK_SIZE 128 +#define HTTP_HEADER_BLOCK_SIZE 1024 + +#if HAVE_PHP_STREAM + +php_stream * php_stream_url_wrap_http(char * path, char * mode, int options, char ** opened_path TSRMLS_DC) +{ + php_stream * stream = NULL; + php_url * resource = NULL; + int use_ssl; + char * scratch = NULL; + char * tmp = NULL; + int scratch_len = 0; + int body = 0; + char location[HTTP_HEADER_BLOCK_SIZE]; + zval * response_header = NULL; + int reqok = 0; + char * http_header_line = NULL; + char tmp_line[128]; + + resource = php_url_parse(path); + if (resource == NULL) + return NULL; + + use_ssl = resource->scheme && resource->scheme[4] == 's'; + + /* choose default ports */ + if (use_ssl && resource->port == 0) + resource->port = 443; + else if (resource->port == 0) + resource->port = 80; + + stream = php_stream_sock_open_host(resource->host, resource->port, SOCK_STREAM, 0, 0); + if (stream == NULL) + goto out; + +#if HAVE_OPENSSL_EXT + if (use_ssl) { + if (php_stream_sock_ssl_activate(stream, 1) == FAILURE) { + if (options & REPORT_ERRORS) { + zend_error(E_WARNING, "Unable to activate SSL mode"); + } + php_stream_close(stream); + stream = NULL; + goto out; + } + } +#endif + + scratch_len = strlen(path) + 32; + scratch = emalloc(scratch_len); + + strcpy(scratch, "GET "); + + /* file */ + if (resource->path && *resource->path) + strlcat(scratch, resource->path, scratch_len); + else + strlcat(scratch, "/", scratch_len); + + /* query string */ + if (resource->query) { + strlcat(scratch, "?", scratch_len); + strlcat(scratch, resource->query, scratch_len); + } + + /* protocol version we are speaking */ + strlcat(scratch, " HTTP/1.0\r\n", scratch_len); + + /* send it */ + php_stream_write(stream, scratch, strlen(scratch)); + + /* authz header if it was specified */ + if (resource->user && resource->pass) { + /* scratch is large enough, since it was made large enough for the whole URL */ + strcpy(scratch, resource->user); + strcat(scratch, ":"); + strcat(scratch, resource->pass); + + tmp = php_base64_encode((unsigned char*)scratch, strlen(scratch), NULL); + + if (snprintf(scratch, scratch_len, "Authorization: Basic %s\r\n", tmp) > 0) + php_stream_write(stream, scratch, strlen(scratch)); + + efree(tmp); + tmp = NULL; + } + + /* if the user has configured who they are, send a From: line */ + if (cfg_get_string("from", &tmp) == SUCCESS) { + if (snprintf(scratch, scratch_len, "From: %s\r\n", tmp) > 0) + php_stream_write(stream, scratch, strlen(scratch)); + } + + /* Send Host: header so name-based virtual hosts work */ + if ((use_ssl && resource->port != 443) || (!use_ssl && resource->port != 80)) { + if (snprintf(scratch, scratch_len, "Host: %s:%i\r\n", resource->host, resource->port) > 0) + php_stream_write(stream, scratch, strlen(scratch)); + } + else if (snprintf(scratch, scratch_len, "Host: %s\r\n", resource->host) > 0) + php_stream_write(stream, scratch, strlen(scratch)); + + php_stream_write_string(stream, "User-Agent: PHP/" PHP_VERSION "\r\n\r\n"); + + location[0] = '\0'; + + MAKE_STD_ZVAL(response_header); + array_init(response_header); + + if (!php_stream_eof(stream)) { + /* get response header */ + + if (php_stream_gets(stream, tmp_line, sizeof(tmp_line)-1) != NULL) { + zval * http_response; + + MAKE_STD_ZVAL(http_response); + if (strncmp(tmp_line + 8, " 200 ", 5) == 0) + reqok = 1; + Z_STRLEN_P(http_response) = strlen(tmp_line); + Z_STRVAL_P(http_response) = estrndup(tmp_line, Z_STRLEN_P(http_response)); + if (Z_STRVAL_P(http_response)[Z_STRLEN_P(http_response)-1]=='\n') { + Z_STRVAL_P(http_response)[Z_STRLEN_P(http_response)-1]=0; + Z_STRLEN_P(http_response)--; + if (Z_STRVAL_P(http_response)[Z_STRLEN_P(http_response)-1]=='\r') { + Z_STRVAL_P(http_response)[Z_STRLEN_P(http_response)-1]=0; + Z_STRLEN_P(http_response)--; + } + } + Z_TYPE_P(http_response) = IS_STRING; + zend_hash_next_index_insert(Z_ARRVAL_P(response_header), &http_response, sizeof(zval *), NULL); + } + } + + /* read past HTTP headers */ + + http_header_line = emalloc(HTTP_HEADER_BLOCK_SIZE); + + while (!body && !php_stream_eof(stream)) { + + if (php_stream_gets(stream, http_header_line, HTTP_HEADER_BLOCK_SIZE-1) != NULL) { + char * p; + int found_eol = 0; + int http_header_line_length; + + http_header_line[HTTP_HEADER_BLOCK_SIZE-1] = '\0'; + p = http_header_line; + while(*p) { + while(*p == '\n' || *p == '\r') { + *p = '\0'; + p--; + found_eol = 1; + } + if (found_eol) + break; + p++; + } + http_header_line_length = p-http_header_line+1; + + if (!strncasecmp(http_header_line, "Location: ", 10)) + strlcpy(location, http_header_line + 10, sizeof(location)); + + if (http_header_line[0] == '\0') + body = 1; + else { + zval * http_header; + + MAKE_STD_ZVAL(http_header); + + ZVAL_STRINGL(http_header, http_header_line, http_header_line_length, 1); + + zend_hash_next_index_insert(Z_ARRVAL_P(response_header), &http_header, sizeof(zval *), NULL); + } + } + else + break; + } + + if (!reqok) { + php_stream_close(stream); + stream = NULL; + + if (location[0] != '\0') { + + zval *entry, **entryp; + char new_path[HTTP_HEADER_BLOCK_SIZE]; + + *new_path='\0'; + if (strlen(location)<8 || (strncasecmp(location, "http://", 7) && strncasecmp(location, "https://", 8))) { + strcpy(new_path, resource->scheme); + strlcat(new_path, resource->host, sizeof(new_path)); + if ((use_ssl && resource->port != 443) || (!use_ssl && resource->port != 80)) { + snprintf(new_path+strlen(new_path), sizeof(new_path)-strlen(new_path)-1, ":%d", resource->port); + } + if (*location != '/') { + php_dirname(resource->path, strlen(resource->path)); + snprintf (new_path+strlen(new_path), sizeof(new_path)-strlen(new_path)-1, "%s/", resource->path); + } + strlcat(new_path, location, sizeof(new_path)); + } + else { + strlcpy(new_path, location, sizeof(new_path)); + } + stream = php_stream_url_wrap_http(new_path, mode, options, opened_path TSRMLS_CC); + if (stream->wrapperdata) { + entryp = &entry; + MAKE_STD_ZVAL(entry); + ZVAL_EMPTY_STRING(entry); + zend_hash_next_index_insert(Z_ARRVAL_P(response_header), entryp, sizeof(zval *), NULL); + zend_hash_internal_pointer_reset(Z_ARRVAL_P(stream->wrapperdata)); + while (zend_hash_get_current_data(Z_ARRVAL_P(stream->wrapperdata), (void **)&entryp) == SUCCESS) { + zval_add_ref(entryp); + zend_hash_next_index_insert(Z_ARRVAL_P(response_header), entryp, sizeof(zval *), NULL); + zend_hash_move_forward(Z_ARRVAL_P(stream->wrapperdata)); + } + zval_dtor(stream->wrapperdata); + FREE_ZVAL(stream->wrapperdata); + } + } + else if (options & REPORT_ERRORS) + zend_error(E_WARNING, "HTTP request failed! %s", tmp_line); + } +out: + if (http_header_line) + efree(http_header_line); + if (scratch) + efree(scratch); + php_url_free(resource); + + if (stream) + stream->wrapperdata = response_header; + + if (response_header) { + zval * sym; + MAKE_STD_ZVAL(sym); + *sym = *response_header; + zval_copy_ctor(sym); + ZEND_SET_SYMBOL(EG(active_symbol_table), "http_response_header", sym); + } + + + return stream; +} + +php_stream_wrapper php_stream_http_wrapper = { + php_stream_url_wrap_http, + NULL +}; + +#else + + /* {{{ php_fopen_url_wrap_http */ @@ -322,6 +573,8 @@ FILE *php_fopen_url_wrap_http(const char *path, char *mode, int options, int *is } /* }}} */ +#endif + /* * Local variables: * tab-width: 4 diff --git a/ext/standard/image.c b/ext/standard/image.c index e0a93f4a97..8505078dfc 100644 --- a/ext/standard/image.c +++ b/ext/standard/image.c @@ -73,7 +73,7 @@ struct gfxinfo { /* {{{ php_handle_gif * routine to handle GIF files. If only everything were that easy... ;} */ -static struct gfxinfo *php_handle_gif (int socketd, FILE *fp, int issock) +static struct gfxinfo *php_handle_gif (php_stream * stream) { struct gfxinfo *result = NULL; unsigned char a[2]; @@ -81,12 +81,12 @@ static struct gfxinfo *php_handle_gif (int socketd, FILE *fp, int issock) result = (struct gfxinfo *) ecalloc(1, sizeof(struct gfxinfo)); - FP_FREAD(temp, 3, socketd, fp, issock); /* fseek(fp, 6L, SEEK_SET); */ + php_stream_read(stream, temp, sizeof(temp)); /* fseek(fp, 6L, SEEK_SET); */ - FP_FREAD(a, sizeof(a), socketd, fp, issock); /* fread(a, sizeof(a), 1, fp); */ + php_stream_read(stream, a, sizeof(a)); /* fread(a, sizeof(a), 1, fp); */ result->width = (unsigned short)a[0] | (((unsigned short)a[1])<<8); - FP_FREAD(a, sizeof(a), socketd, fp, issock); /* fread(a, sizeof(a), 1, fp); */ + php_stream_read(stream, a, sizeof(a)); /* fread(a, sizeof(a), 1, fp); */ result->height = (unsigned short)a[0] | (((unsigned short)a[1])<<8); return result; @@ -95,7 +95,7 @@ static struct gfxinfo *php_handle_gif (int socketd, FILE *fp, int issock) /* {{{ php_handle_psd */ -static struct gfxinfo *php_handle_psd (int socketd, FILE *fp, int issock) +static struct gfxinfo *php_handle_psd (php_stream * stream) { struct gfxinfo *result = NULL; unsigned char a[8]; @@ -103,9 +103,9 @@ static struct gfxinfo *php_handle_psd (int socketd, FILE *fp, int issock) unsigned long in_width, in_height; result = (struct gfxinfo *) ecalloc(1, sizeof(struct gfxinfo)); - FP_FREAD(temp, sizeof(temp), socketd, fp, issock); + php_stream_read(stream, temp, sizeof(temp)); - if((FP_FREAD(a, sizeof(a), socketd, fp, issock)) <= 0) { + if((php_stream_read(stream, a, sizeof(a))) <= 0) { in_height = 0; in_width = 0; } else { @@ -122,7 +122,7 @@ static struct gfxinfo *php_handle_psd (int socketd, FILE *fp, int issock) /* {{{ php_handle_bmp */ -static struct gfxinfo *php_handle_bmp (int socketd, FILE *fp, int issock) +static struct gfxinfo *php_handle_bmp (php_stream * stream) { struct gfxinfo *result = NULL; char temp[15]; @@ -133,8 +133,8 @@ static struct gfxinfo *php_handle_bmp (int socketd, FILE *fp, int issock) result = (struct gfxinfo *) ecalloc (1, sizeof(struct gfxinfo)); - FP_FREAD(temp, sizeof(temp), socketd, fp, issock); - FP_FREAD((char*) &dim, sizeof(dim), socketd, fp, issock); + php_stream_read(stream, temp, sizeof(temp)); + php_stream_read(stream, (char*) &dim, sizeof(dim)); result->width = dim.in_width; result->height = dim.in_height; @@ -160,7 +160,7 @@ static unsigned long int php_swf_get_bits (unsigned char* buffer, unsigned int p /* {{{ php_handle_swf */ -static struct gfxinfo *php_handle_swf (int socketd, FILE *fp, int issock) +static struct gfxinfo *php_handle_swf (php_stream * stream) { struct gfxinfo *result = NULL; long bits; @@ -168,9 +168,9 @@ static struct gfxinfo *php_handle_swf (int socketd, FILE *fp, int issock) char temp[5]; result = (struct gfxinfo *) ecalloc (1, sizeof (struct gfxinfo)); - FP_FREAD(temp, 5, socketd, fp, issock); /* fseek(fp, 8L, SEEK_SET); */ + php_stream_read(stream, temp, 5); /* fseek(fp, 8L, SEEK_SET); */ - FP_FREAD(a, sizeof(a), socketd, fp, issock); /* fread(a, sizeof(a), 1, fp); */ + php_stream_read(stream, a, sizeof(a)); /* fread(a, sizeof(a), 1, fp); */ bits = php_swf_get_bits (a, 0, 5); result->width = (php_swf_get_bits (a, 5 + bits, bits) - php_swf_get_bits (a, 5, bits)) / 20; @@ -182,7 +182,7 @@ static struct gfxinfo *php_handle_swf (int socketd, FILE *fp, int issock) /* {{{ php_handle_png * routine to handle PNG files */ -static struct gfxinfo *php_handle_png (int socketd, FILE *fp, int issock) +static struct gfxinfo *php_handle_png (php_stream * stream) { struct gfxinfo *result = NULL; unsigned long in_width, in_height; @@ -191,9 +191,9 @@ static struct gfxinfo *php_handle_png (int socketd, FILE *fp, int issock) result = (struct gfxinfo *) ecalloc(1, sizeof(struct gfxinfo)); - FP_FREAD(temp, sizeof(temp), socketd, fp, issock); /* fseek(fp, 16L, SEEK_SET); */ + php_stream_read(stream, temp, sizeof(temp)); /* fseek(fp, 16L, SEEK_SET); */ - if((FP_FREAD(a, sizeof(a), socketd, fp, issock)) <= 0) { + if((php_stream_read(stream, a, sizeof(a))) <= 0) { in_width = 0; in_height = 0; } else { @@ -248,12 +248,12 @@ static struct gfxinfo *php_handle_png (int socketd, FILE *fp, int issock) /* {{{ php_read2 */ -static unsigned short php_read2(int socketd, FILE *fp, int issock) +static unsigned short php_read2(php_stream * stream) { unsigned char a[2]; /* just return 0 if we hit the end-of-file */ - if((FP_FREAD(a, sizeof(a), socketd, fp, issock)) <= 0) return 0; + if((php_stream_read(stream, a, sizeof(a))) <= 0) return 0; return (((unsigned short) a[ 0 ]) << 8) + ((unsigned short) a[ 1 ]); } @@ -261,7 +261,7 @@ static unsigned short php_read2(int socketd, FILE *fp, int issock) /* {{{ php_next_marker * get next marker byte from file */ -static unsigned int php_next_marker(int socketd, FILE *fp, int issock, int last_marker, int comment_correction, int ff_read) +static unsigned int php_next_marker(php_stream * stream, int last_marker, int comment_correction, int ff_read) { int a=0, marker; @@ -279,7 +279,7 @@ static unsigned int php_next_marker(int socketd, FILE *fp, int issock, int last_ a = 1; /* already read 0xff in filetype detection */ } do { - if ((marker = FP_FGETC(socketd, fp, issock)) == EOF) + if ((marker = php_stream_getc(stream)) == EOF) { return M_EOI;/* we hit EOF */ } @@ -312,52 +312,31 @@ static unsigned int php_next_marker(int socketd, FILE *fp, int issock, int last_ } /* }}} */ -/* {{{ php_skip_over - * skip over a block of specified length */ -#ifndef FP_FSKIP - -#define FP_FSKIP(l,socketd,fp,issock) php_skip_over(socketd,fp,issock,l) - -static void php_skip_over(int socketd, FILE *fp, int issock, size_t length) -{ - static char tmp[1024]; - - while(length>=sizeof(tmp)) { - FP_FREAD(tmp, sizeof(tmp), socketd, fp, issock); - length -= sizeof(tmp); - } - if(length) { - FP_FREAD(tmp, length, socketd, fp, issock); - } -} -#endif -/* }}} */ - /* {{{ php_skip_variable * skip over a variable-length block; assumes proper length marker */ -static void php_skip_variable(int socketd, FILE *fp, int issock) +static void php_skip_variable(php_stream * stream) { - size_t length = php_read2(socketd, fp, issock); - FP_FSKIP( length-2, socketd, fp, issock); + size_t length = php_read2(stream); + php_stream_seek(stream, SEEK_CUR, length-2); } /* }}} */ /* {{{ php_read_APP */ -static void php_read_APP(int socketd, FILE *fp, int issock, unsigned int marker, zval *info) +static void php_read_APP(php_stream * stream, unsigned int marker, zval *info) { unsigned short length; unsigned char *buffer; unsigned char markername[ 16 ]; zval *tmp; - length = php_read2(socketd, fp, issock); + length = php_read2(stream); length -= 2; /* length includes itself */ buffer = emalloc(length); if ( !buffer) return; - if (FP_FREAD(buffer, (long) length, socketd, fp, issock) <= 0) { + if (php_stream_read(stream, buffer, (long) length) <= 0) { efree(buffer); return; } @@ -375,14 +354,14 @@ static void php_read_APP(int socketd, FILE *fp, int issock, unsigned int marker, /* {{{ php_handle_jpeg main loop to parse JPEG structure */ -static struct gfxinfo *php_handle_jpeg (int socketd, FILE *fp, int issock, pval *info) +static struct gfxinfo *php_handle_jpeg (php_stream * stream, pval *info) { struct gfxinfo *result = NULL; unsigned int marker = M_PSEUDO; unsigned short length, ff_read=1; for (;;) { - marker = php_next_marker(socketd, fp, issock, marker, 1, ff_read); + marker = php_next_marker(stream, marker, 1, ff_read); ff_read = 0; switch (marker) { case M_SOF0: @@ -403,16 +382,16 @@ static struct gfxinfo *php_handle_jpeg (int socketd, FILE *fp, int issock, pval result = (struct gfxinfo *) ecalloc(1, sizeof(struct gfxinfo)); if ( !result) return NULL; - length = php_read2(socketd, fp, issock); - result->bits = FP_FGETC(socketd, fp, issock); - result->height = php_read2(socketd, fp, issock); - result->width = php_read2(socketd, fp, issock); - result->channels = FP_FGETC(socketd, fp, issock); + length = php_read2(stream); + result->bits = php_stream_getc(stream); + result->height = php_read2(stream); + result->width = php_read2(stream); + result->channels = php_stream_getc(stream); if (!info || length<8) /* if we don't want an extanded info -> return */ return result; - FP_FSKIP( length-8, socketd, fp, issock); + php_stream_seek(stream, SEEK_CUR, length-8); } else { - php_skip_variable(socketd, fp, issock); + php_skip_variable(stream); } break; @@ -433,9 +412,9 @@ static struct gfxinfo *php_handle_jpeg (int socketd, FILE *fp, int issock, pval case M_APP14: case M_APP15: if (info) { - php_read_APP(socketd, fp, issock, marker, info); /* read all the app markes... */ + php_read_APP(stream, marker, info); /* read all the app markes... */ } else { - php_skip_variable(socketd, fp, issock); + php_skip_variable(stream); } break; @@ -445,7 +424,7 @@ static struct gfxinfo *php_handle_jpeg (int socketd, FILE *fp, int issock, pval break; default: - php_skip_variable(socketd, fp, issock); /* anything else isn't interesting */ + php_skip_variable(stream); /* anything else isn't interesting */ break; } } @@ -462,12 +441,12 @@ static struct gfxinfo *php_handle_jpeg (int socketd, FILE *fp, int issock, pval /* {{{ php_read4 */ -static unsigned int php_read4(int socketd, FILE *fp, int issock) +static unsigned int php_read4(php_stream * stream) { unsigned char a[4]; /* just return 0 if we hit the end-of-file */ - if((FP_FREAD(a, sizeof(a), socketd, fp, issock)) <= 0) return 0; + if((php_stream_read(stream, a, sizeof(a))) <= 0) return 0; return (((unsigned int)a[0]) << 24) + (((unsigned int)a[1]) << 16) @@ -478,32 +457,32 @@ static unsigned int php_read4(int socketd, FILE *fp, int issock) /* {{{ php_handle_tiff main loop to parse TIFF structure */ -static struct gfxinfo *php_handle_jpc(int socketd, FILE *fp, int issock) +static struct gfxinfo *php_handle_jpc(php_stream * stream) { struct gfxinfo *result = NULL; unsigned int marker, dummy; unsigned short length, ff_read = 1; - marker = php_next_marker(socketd, fp, issock, 0, 0, ff_read); + marker = php_next_marker(stream, 0, 0, ff_read); ff_read = 0; if ( marker == JC_SIZ) { - length = php_read2(socketd, fp, issock); /* Lsiz: length of segment */ + length = php_read2(stream); /* Lsiz: length of segment */ if ( length<42 || length>49191) /* read the spec */ return NULL; result = (struct gfxinfo *) ecalloc(1, sizeof(struct gfxinfo)); if ( !result) return NULL; - dummy = php_read2(socketd, fp, issock); /* Rsiz: capabilities */ - result->height = php_read4(socketd, fp, issock); /* Xsiz */ - result->width = php_read4(socketd, fp, issock); /* Ysiz */ - dummy = php_read4(socketd, fp, issock); /* X0siz */ - dummy = php_read4(socketd, fp, issock); /* Y0siz */ - dummy = php_read4(socketd, fp, issock); /* XTsiz */ - dummy = php_read4(socketd, fp, issock); /* YTsiz */ - dummy = php_read4(socketd, fp, issock); /* XT0siz */ - dummy = php_read4(socketd, fp, issock); /* YT0siz */ - result->bits = php_read2(socketd, fp, issock); /* Csiz: precision in bitss */ + dummy = php_read2(stream); /* Rsiz: capabilities */ + result->height = php_read4(stream); /* Xsiz */ + result->width = php_read4(stream); /* Ysiz */ + dummy = php_read4(stream); /* X0siz */ + dummy = php_read4(stream); /* Y0siz */ + dummy = php_read4(stream); /* XTsiz */ + dummy = php_read4(stream); /* YTsiz */ + dummy = php_read4(stream); /* XT0siz */ + dummy = php_read4(stream); /* YT0siz */ + result->bits = php_read2(stream); /* Csiz: precision in bitss */ result->channels = 0; /* don't know yet */ return result; } @@ -582,7 +561,7 @@ static unsigned php_ifd_get32u(void *Long, int motorola_intel) /* {{{ php_handle_tiff main loop to parse TIFF structure */ -static struct gfxinfo *php_handle_tiff (int socketd, FILE *fp, int issock, pval *info, int motorola_intel) +static struct gfxinfo *php_handle_tiff (php_stream * stream, pval *info, int motorola_intel) { struct gfxinfo *result = NULL; int i, num_entries; @@ -591,17 +570,17 @@ static struct gfxinfo *php_handle_tiff (int socketd, FILE *fp, int issock, pval int entry_tag , entry_type; char *ifd_data, ifd_ptr[4]; - FP_FREAD(ifd_ptr, 4, socketd, fp, issock); + php_stream_read(stream, ifd_ptr, 4); ifd_addr = php_ifd_get32u(ifd_ptr, motorola_intel); - FP_FSKIP(ifd_addr-8, socketd, fp, issock); + php_stream_seek(stream, SEEK_CUR, ifd_addr-8); ifd_size = 2; ifd_data = emalloc(ifd_size); - FP_FREAD(ifd_data, 2, socketd, fp, issock); + php_stream_read(stream, ifd_data, 2); num_entries = php_ifd_get16u(ifd_data, motorola_intel); dir_size = 2/*num dir entries*/ +12/*length of entry*/*num_entries +4/* offset to next ifd (points to thumbnail or NULL)*/; ifd_size = dir_size; ifd_data = erealloc(ifd_data,ifd_size); - FP_FREAD(ifd_data+2, dir_size-2, socketd, fp, issock); + php_stream_read(stream, ifd_data+2, dir_size-2); /* now we have the directory we can look how long it should be */ ifd_size = dir_size; for(i=0;i<num_entries;i++) { @@ -654,12 +633,12 @@ static struct gfxinfo *php_handle_tiff (int socketd, FILE *fp, int issock, pval /* {{{ php_imagetype detect filetype from first bytes */ -int php_getimagetype(int socketd, FILE *fp, int issock, char *filetype) +int php_getimagetype(php_stream * stream, char *filetype) { char tmp[8]; if ( !filetype) filetype = tmp; - if((FP_FREAD(filetype, 3, socketd, fp, issock)) <= 0) { + if((php_stream_read(stream, filetype, 3)) <= 0) { php_error(E_WARNING, "getimagesize: Read error!"); return IMAGE_FILETYPE_UNKNOWN; } @@ -669,7 +648,7 @@ int php_getimagetype(int socketd, FILE *fp, int issock, char *filetype) } else if (!memcmp(filetype, php_sig_jpg, 3)) { return IMAGE_FILETYPE_JPEG; } else if (!memcmp(filetype, php_sig_png, 3)) { - FP_FREAD(filetype+3, 5, socketd, fp, issock); + php_stream_read(stream, filetype+3, 5); if (!memcmp(filetype, php_sig_png, 8)) { return IMAGE_FILETYPE_PNG; } else { @@ -685,7 +664,7 @@ int php_getimagetype(int socketd, FILE *fp, int issock, char *filetype) } else if (!memcmp(filetype, php_sig_jpc, 3)) { return IMAGE_FILETYPE_JPC; } else { - FP_FREAD(filetype+3, 1, socketd, fp, issock); + php_stream_read(stream, filetype+3, 1); if (!memcmp(filetype, php_sig_tif_ii, 4)) { return IMAGE_FILETYPE_TIFF_II; } else @@ -703,11 +682,11 @@ int php_getimagetype(int socketd, FILE *fp, int issock, char *filetype) PHP_FUNCTION(getimagesize) { zval **arg1, **info = NULL; - FILE *fp; - int issock=0, socketd=0, rsrc_id; + int rsrc_id; int itype = 0; char temp[64]; struct gfxinfo *result = NULL; + php_stream * stream = NULL; switch(ZEND_NUM_ARGS()) { @@ -736,58 +715,46 @@ PHP_FUNCTION(getimagesize) break; } - fp = php_fopen_wrapper(Z_STRVAL_PP(arg1), "rb", IGNORE_PATH|ENFORCE_SAFE_MODE, &issock, &socketd, NULL TSRMLS_CC); + stream = php_stream_open_wrapper(Z_STRVAL_PP(arg1), "rb", REPORT_ERRORS|IGNORE_PATH|ENFORCE_SAFE_MODE, NULL TSRMLS_CC); - if (!fp && !socketd) { - if (issock != BAD_URL) { - char *tmp = estrndup(Z_STRVAL_PP(arg1), Z_STRLEN_PP(arg1)); - php_strip_url_passwd(tmp); - php_error(E_WARNING, "getimagesize: Unable to open '%s' for reading.", tmp); - efree(tmp); - } + if (!stream) { RETURN_FALSE; } - if (issock) { - int *sock=emalloc(sizeof(int)); - *sock = socketd; - rsrc_id = ZEND_REGISTER_RESOURCE(NULL, sock, php_file_le_socket()); - } else { - rsrc_id = ZEND_REGISTER_RESOURCE(NULL, fp, php_file_le_fopen()); - } + rsrc_id = ZEND_REGISTER_RESOURCE(NULL, stream, php_file_le_stream()); - itype = php_getimagetype(socketd, fp, issock, NULL); + itype = php_getimagetype(stream, NULL); switch( itype) { case IMAGE_FILETYPE_GIF: - result = php_handle_gif (socketd, fp, issock); + result = php_handle_gif (stream); break; case IMAGE_FILETYPE_JPEG: if (info) { - result = php_handle_jpeg(socketd, fp, issock, *info); + result = php_handle_jpeg(stream, *info); } else { - result = php_handle_jpeg(socketd, fp, issock, NULL); + result = php_handle_jpeg(stream, NULL); } break; case IMAGE_FILETYPE_PNG: - result = php_handle_png(socketd, fp, issock); + result = php_handle_png(stream); break; case IMAGE_FILETYPE_SWF: - result = php_handle_swf(socketd, fp, issock); + result = php_handle_swf(stream); break; case IMAGE_FILETYPE_PSD: - result = php_handle_psd(socketd, fp, issock); + result = php_handle_psd(stream); break; case IMAGE_FILETYPE_BMP: - result = php_handle_bmp(socketd, fp, issock); + result = php_handle_bmp(stream); break; case IMAGE_FILETYPE_TIFF_II: - result = php_handle_tiff(socketd, fp, issock, NULL, 0); + result = php_handle_tiff(stream, NULL, 0); break; case IMAGE_FILETYPE_TIFF_MM: - result = php_handle_tiff(socketd, fp, issock, NULL, 1); + result = php_handle_tiff(stream, NULL, 1); break; case IMAGE_FILETYPE_JPC: - result = php_handle_jpc(socketd, fp, issock); + result = php_handle_jpc(stream); break; default: case IMAGE_FILETYPE_UNKNOWN: diff --git a/ext/standard/info.c b/ext/standard/info.c index 026e00db87..ac0d5560e6 100644 --- a/ext/standard/info.c +++ b/ext/standard/info.c @@ -211,9 +211,7 @@ PHPAPI void php_print_info(int flag TSRMLS_DC) php_info_print_table_row(2, "Thread Safety", "disabled" ); #endif -#if HAVE_PHP_STREAM - php_info_print_table_row(2, "Experimental PHP Streams", "enabled"); -#endif + php_info_print_table_row(2, "PHP Streams", "enabled"); php_info_print_table_end(); diff --git a/ext/standard/php_fopen_wrapper.c b/ext/standard/php_fopen_wrapper.c index 26c9ec2a9e..37b3b2b90f 100644 --- a/ext/standard/php_fopen_wrapper.c +++ b/ext/standard/php_fopen_wrapper.c @@ -30,26 +30,33 @@ #include "php_standard.h" #include "php_fopen_wrappers.h" - -/* {{{ php_fopen_url_wrap_php - */ -FILE *php_fopen_url_wrap_php(const char *path, char *mode, int options, int *issock, int *socketd, char **opened_path TSRMLS_DC) +php_stream * php_stream_url_wrap_php(char * path, char * mode, int options, char ** opened_path TSRMLS_DC) { - const char *res = path + 6; - - *issock = 0; + FILE * fp = NULL; + php_stream * stream = NULL; - if (!strcasecmp(res, "stdin")) { - return fdopen(dup(STDIN_FILENO), mode); - } else if (!strcasecmp(res, "stdout")) { - return fdopen(dup(STDOUT_FILENO), mode); - } else if (!strcasecmp(res, "stderr")) { - return fdopen(dup(STDERR_FILENO), mode); + if (!strcasecmp(path, "stdin")) { + fp = fdopen(dup(STDIN_FILENO), mode); + } else if (!strcasecmp(path, "stdout")) { + fp = fdopen(dup(STDOUT_FILENO), mode); + } else if (!strcasecmp(path, "stderr")) { + fp = fdopen(dup(STDERR_FILENO), mode); } - - return NULL; + /* TODO: implement php://output as a stream to write to the current output buffer ? */ + + if (fp) { + stream = php_stream_fopen_from_file(fp, mode); + if (stream == NULL) + fclose(fp); + } + return stream; } -/* }}} */ + +php_stream_wrapper php_stream_php_wrapper = { + php_stream_url_wrap_php, + NULL +}; + /* * Local variables: diff --git a/ext/standard/php_fopen_wrappers.h b/ext/standard/php_fopen_wrappers.h index 0cab1fe73e..1cad9777c9 100644 --- a/ext/standard/php_fopen_wrappers.h +++ b/ext/standard/php_fopen_wrappers.h @@ -23,8 +23,10 @@ #ifndef PHP_FOPEN_WRAPPERS_H #define PHP_FOPEN_WRAPPERS_H -FILE *php_fopen_url_wrap_http(const char *, char *, int, int *, int *, char ** TSRMLS_DC); -FILE *php_fopen_url_wrap_ftp(const char *, char *, int, int *, int *, char ** TSRMLS_DC); -FILE *php_fopen_url_wrap_php(const char *, char *, int, int *, int *, char ** TSRMLS_DC); +php_stream * php_stream_url_wrap_http(char * path, char * mode, int options, char ** opened_path TSRMLS_DC); +php_stream * php_stream_url_wrap_ftp(char * path, char * mode, int options, char ** opened_path TSRMLS_DC); +php_stream_wrapper php_stream_http_wrapper; +php_stream_wrapper php_stream_ftp_wrapper; +php_stream_wrapper php_stream_php_wrapper; #endif diff --git a/ext/standard/php_image.h b/ext/standard/php_image.h index 1837bab6a2..3046c8cd62 100644 --- a/ext/standard/php_image.h +++ b/ext/standard/php_image.h @@ -45,6 +45,6 @@ typedef enum } image_filetype; /* }}} */ -extern int php_getimagetype(int socketd, FILE *fp, int issock, char *filetype); +extern int php_getimagetype(php_stream * stream, char *filetype); #endif /* PHP_IMAGE_H */ diff --git a/ext/zlib/php_zlib.h b/ext/zlib/php_zlib.h index 7a9b0de247..bedc65c587 100644 --- a/ext/zlib/php_zlib.h +++ b/ext/zlib/php_zlib.h @@ -67,6 +67,9 @@ PHP_FUNCTION(ob_gzhandler); FILE *zlib_fopen_wrapper(const char *path, char *mode, int options, int *issock, int *socketd, char **opened_path TSRMLS_DC); int php_enable_output_compression(int buffer_size TSRMLS_DC); +php_stream * php_stream_gzopen(char * path, char * mode, int options, char ** opened_path TSRMLS_DC); +extern php_stream_ops php_stream_gzio_ops; +extern php_stream_wrapper php_stream_gzip_wrapper; #ifdef ZTS #define ZLIBG(v) TSRMG(zlib_globals_id, zend_zlib_globals *, v) diff --git a/ext/zlib/zlib.c b/ext/zlib/zlib.c index fdb54ca76e..1b39fb0399 100644 --- a/ext/zlib/zlib.c +++ b/ext/zlib/zlib.c @@ -187,12 +187,9 @@ PHP_MINIT_FUNCTION(zlib) #endif le_zp = zend_register_list_destructors_ex(phpi_destructor_gzclose, NULL, "zlib", module_number); -#if HAVE_FOPENCOOKIE - if(PG(allow_url_fopen)) { - php_register_url_wrapper("zlib", zlib_fopen_wrapper TSRMLS_CC); + php_register_url_stream_wrapper("zlib", &php_stream_gzip_wrapper TSRMLS_CC); } -#endif REGISTER_LONG_CONSTANT("FORCE_GZIP", CODING_GZIP, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("FORCE_DEFLATE", CODING_DEFLATE, CONST_CS | CONST_PERSISTENT); @@ -225,11 +222,8 @@ PHP_RINIT_FUNCTION(zlib) */ PHP_MSHUTDOWN_FUNCTION(zlib) { -#if HAVE_FOPENCOOKIE - if(PG(allow_url_fopen)) { - php_unregister_url_wrapper("zlib" TSRMLS_CC); - } -#endif + if (PG(allow_url_fopen)) + php_unregister_url_stream_wrapper("zlib" TSRMLS_CC); UNREGISTER_INI_ENTRIES(); @@ -258,15 +252,23 @@ PHP_MINFO_FUNCTION(zlib) */ static gzFile php_gzopen_wrapper(char *path, char *mode, int options TSRMLS_DC) { - FILE *f; - int issock=0, socketd=0; - - f = php_fopen_wrapper(path, mode, options, &issock, &socketd, NULL TSRMLS_CC); - - if (!f) { - return NULL; + php_stream * stream = NULL; + int fd; + + stream = php_stream_open_wrapper(path, mode, options | REPORT_ERRORS, NULL TSRMLS_CC); + if (stream) { + if (SUCCESS == php_stream_cast(stream, PHP_STREAM_AS_FD | PHP_STREAM_CAST_TRY_HARD, (void**)&fd, 1)) + { + gzFile ret = gzdopen(fd, mode); + if (ret) { + /* arrange to clean up the actual stream */ + ZEND_REGISTER_RESOURCE(NULL, stream, php_file_le_stream()); + return ret; + } + } + php_stream_close(stream); } - return gzdopen(fileno(f), mode); + return NULL; } /* }}} */ @@ -275,10 +277,10 @@ static gzFile php_gzopen_wrapper(char *path, char *mode, int options TSRMLS_DC) PHP_FUNCTION(gzfile) { pval **filename, **arg2; - gzFile zp; char *slashed, buf[8192]; register int i=0; int use_include_path = 0; + php_stream * stream; /* check args */ switch (ZEND_NUM_ARGS()) { @@ -299,8 +301,9 @@ PHP_FUNCTION(gzfile) } convert_to_string_ex(filename); - zp = php_gzopen_wrapper(Z_STRVAL_PP(filename),"r", use_include_path|ENFORCE_SAFE_MODE TSRMLS_CC); - if (!zp) { + /* using a stream here is a bit more efficient (resource wise) than php_gzopen_wrapper */ + stream = php_stream_gzopen(Z_STRVAL_PP(filename), "r", use_include_path|ENFORCE_SAFE_MODE, NULL TSRMLS_CC); + if (!stream) { php_error(E_WARNING,"gzFile(\"%s\") - %s",Z_STRVAL_PP(filename),strerror(errno)); RETURN_FALSE; } @@ -311,8 +314,8 @@ PHP_FUNCTION(gzfile) } /* Now loop through the file and do the magic quotes thing if needed */ - memset(buf,0,8191); - while(gzgets(zp, buf, 8191) != NULL) { + memset(buf,0,sizeof(buf)); + while(php_stream_gets(stream, buf, sizeof(buf)-1) != NULL) { if (PG(magic_quotes_runtime)) { int len; @@ -322,7 +325,7 @@ PHP_FUNCTION(gzfile) add_index_string(return_value, i++, buf, 1); } } - gzclose(zp); + php_stream_close(stream); } /* }}} */ diff --git a/ext/zlib/zlib_fopen_wrapper.c b/ext/zlib/zlib_fopen_wrapper.c index 2ca7aa77f1..5a59d023ab 100644 --- a/ext/zlib/zlib_fopen_wrapper.c +++ b/ext/zlib/zlib_fopen_wrapper.c @@ -23,78 +23,104 @@ #include "php_zlib.h" #include "fopen_wrappers.h" -#if HAVE_FOPENCOOKIE - - -struct gz_cookie { +struct php_gz_stream_data_t { gzFile gz_file; + php_stream * stream; }; -static ssize_t gz_reader(void *cookie, char *buffer, size_t size) +static size_t php_gziop_read(php_stream * stream, char * buf, size_t count) { - return gzread(((struct gz_cookie *)cookie)->gz_file,buffer,size); + struct php_gz_stream_data_t * self = (struct php_gz_stream_data_t *)stream->abstract; + + if (buf == NULL && count == 0) { + if (gzeof(self->gz_file)) + return EOF; + return 0; + } + + return gzread(self->gz_file, buf, count); } -static ssize_t gz_writer(void *cookie, const char *buffer, size_t size) { - return gzwrite(((struct gz_cookie *)cookie)->gz_file,(char *)buffer,size); +static char * php_gziop_gets(php_stream * stream, char * buf, size_t size) +{ + struct php_gz_stream_data_t * self = (struct php_gz_stream_data_t *)stream->abstract; + return gzgets(self->gz_file, buf, size); } -static int gz_seeker(void *cookie,off_t position, int whence) { - return gzseek(((struct gz_cookie *)cookie)->gz_file,(z_off_t)position,whence); + +static size_t php_gziop_write(php_stream * stream, const char * buf, size_t count) +{ + struct php_gz_stream_data_t * self = (struct php_gz_stream_data_t *)stream->abstract; + return gzwrite(self->gz_file, (char*)buf, count); } -static int gz_closer(void *cookie) { - int ret=gzclose(((struct gz_cookie *)cookie)->gz_file); - free(cookie); - cookie=NULL; - return ret; +static int php_gziop_seek(php_stream * stream, off_t offset, int whence) +{ + struct php_gz_stream_data_t * self = (struct php_gz_stream_data_t *)stream->abstract; + return gzseek(self->gz_file, offset, whence); } +static int php_gziop_close(php_stream * stream) +{ + struct php_gz_stream_data_t * self = (struct php_gz_stream_data_t *)stream->abstract; + int ret; + + ret = gzclose(self->gz_file); + php_stream_close(self->stream); + efree(self); + return ret; +} -static COOKIE_IO_FUNCTIONS_T gz_cookie_functions = -{ gz_reader -, gz_writer -, gz_seeker -, gz_closer +php_stream_ops php_stream_gzio_ops = { + php_gziop_write, php_gziop_read, + php_gziop_close, NULL, + php_gziop_seek, php_gziop_gets, + NULL, "ZLIB" }; -FILE *zlib_fopen_wrapper(const char *path, char *mode, int options, int *issock, int *socketd, char **opened_path TSRMLS_DC) +php_stream * php_stream_gzopen(char * path, char * mode, int options, char ** opened_path TSRMLS_DC) { - struct gz_cookie *gc = NULL; - FILE *fp; - int fissock=0, fsocketd=0; - - gc = (struct gz_cookie *)malloc(sizeof(struct gz_cookie)); - - if(gc) { - *issock = 0; - - while(*path!=':') - path++; - + struct php_gz_stream_data_t * self; + php_stream * stream = NULL; + + self = emalloc(sizeof(*self)); + + while(*path != ':') path++; - - fp = php_fopen_wrapper((char *) path, mode, options|IGNORE_URL, &fissock, &fsocketd, NULL TSRMLS_CC); - - if (!fp) { - free(gc); - return NULL; - } - - gc->gz_file = gzdopen(fileno(fp), mode); - - if(gc->gz_file) { - return fopencookie(gc,mode,gz_cookie_functions); - } else { - free(gc); - return NULL; + path++; + + self->stream = php_stream_open_wrapper(path, mode, options, opened_path TSRMLS_CC); + + if (self->stream) { + int fd; + if (SUCCESS == php_stream_cast(self->stream, PHP_STREAM_AS_FD, (void**)&fd, REPORT_ERRORS)) { + self->gz_file = gzdopen(fd, mode); + if (self->gz_file) { + stream = php_stream_alloc(&php_stream_gzio_ops, self, 0, mode); + if (stream) + return stream; + gzclose(self->gz_file); + } } } - errno = ENOENT; + if (stream) + php_stream_close(stream); + if (self && self->stream) + php_stream_close(self->stream); + if (self) + efree(self); + return NULL; } -#endif + +php_stream_wrapper php_stream_gzip_wrapper = { + php_stream_gzopen, + NULL +}; + + + /* * Local variables: diff --git a/main/fopen_wrappers.c b/main/fopen_wrappers.c index 7cf55651d4..9bbd126571 100644 --- a/main/fopen_wrappers.c +++ b/main/fopen_wrappers.c @@ -82,55 +82,6 @@ #endif /* }}} */ -static FILE *php_fopen_url_wrapper(const char *, char *, int, int *, int *, char ** TSRMLS_DC); -static HashTable fopen_url_wrappers_hash; - -/* {{{ php_register_url_wrapper - */ -PHPAPI int php_register_url_wrapper(const char *protocol, php_fopen_url_wrapper_t wrapper TSRMLS_DC) -{ - if(PG(allow_url_fopen)) { - return zend_hash_add(&fopen_url_wrappers_hash, (char *) protocol, strlen(protocol), &wrapper, sizeof(wrapper), NULL); - } else { - return FAILURE; - } -} -/* }}} */ - -/* {{{ php_unregister_url_wrapper - */ -PHPAPI int php_unregister_url_wrapper(char *protocol TSRMLS_DC) -{ - if(PG(allow_url_fopen)) { - return zend_hash_del(&fopen_url_wrappers_hash, protocol, strlen(protocol)); - } else { - return SUCCESS; - } -} -/* }}} */ - -/* {{{ php_init_fopen_wrappers - */ -int php_init_fopen_wrappers(TSRMLS_D) -{ - if(PG(allow_url_fopen)) { - return zend_hash_init(&fopen_url_wrappers_hash, 0, NULL, NULL, 1); - } - return SUCCESS; -} -/* }}} */ - -/* {{{ php_shutdown_fopen_wrappers - */ -int php_shutdown_fopen_wrappers(TSRMLS_D) -{ - if(PG(allow_url_fopen)) { - zend_hash_destroy(&fopen_url_wrappers_hash); - } - return SUCCESS; -} -/* }}} */ - /* {{{ php_check_specific_open_basedir When open_basedir is not NULL, check if the given filename is located in open_basedir. Returns -1 if error or not in the open_basedir, else 0 @@ -289,36 +240,6 @@ static FILE *php_fopen_and_set_opened_path(const char *path, char *mode, char ** } /* }}} */ -/* {{{ php_fopen_wrapper - */ -PHPAPI FILE *php_fopen_wrapper(char *path, char *mode, int options, int *issock, int *socketd, char **opened_path TSRMLS_DC) -{ - if (opened_path) { - *opened_path = NULL; - } - - if(!path || !*path) { - return NULL; - } - - - if(PG(allow_url_fopen)) { - if (!(options & IGNORE_URL)) { - return php_fopen_url_wrapper(path, mode, options, issock, socketd, opened_path TSRMLS_CC); - } - } - - if (options & USE_PATH && PG(include_path) != NULL) { - return php_fopen_with_path(path, mode, PG(include_path), opened_path TSRMLS_CC); - } else { - if (options & ENFORCE_SAFE_MODE && PG(safe_mode) && (!php_checkuid(path, mode, CHECKUID_CHECK_MODE_PARAM))) { - return NULL; - } - return php_fopen_and_set_opened_path(path, mode, opened_path TSRMLS_CC); - } -} -/* }}} */ - /* {{{ php_fopen_primary_script */ PHPAPI int php_fopen_primary_script(zend_file_handle *file_handle TSRMLS_DC) @@ -535,64 +456,6 @@ PHPAPI FILE *php_fopen_with_path(char *filename, char *mode, char *path, char ** } /* }}} */ -/* {{{ php_fopen_url_wrapper - */ -static FILE *php_fopen_url_wrapper(const char *path, char *mode, int options, int *issock, int *socketd, char **opened_path TSRMLS_DC) -{ - FILE *fp = NULL; - const char *p; - const char *protocol=NULL; - int n=0; - - for (p=path; isalnum((int)*p); p++) { - n++; - } - if ((*p==':')&&(n>1)) { - protocol=path; - } - - if (protocol) { - php_fopen_url_wrapper_t *wrapper=NULL; - - if (FAILURE==zend_hash_find(&fopen_url_wrappers_hash, (char *) protocol, n, (void **)&wrapper)) { - wrapper=NULL; - protocol=NULL; - } - if (wrapper) { - return (*wrapper)(path, mode, options, issock, socketd, opened_path TSRMLS_CC); - } - } - - if (!protocol || !strncasecmp(protocol, "file", n)){ - *issock = 0; - - if(protocol) { - if(path[n+1]=='/') { - if(path[n+2]=='/') { - php_error(E_WARNING, "remote host file access not supported, %s", path); - return NULL; - } - } - path+= n+1; - } - - if (options & USE_PATH) { - fp = php_fopen_with_path((char *) path, mode, PG(include_path), opened_path TSRMLS_CC); - } else { - if (options & ENFORCE_SAFE_MODE && PG(safe_mode) && (!php_checkuid(path, mode, CHECKUID_CHECK_MODE_PARAM))) { - fp = NULL; - } else { - fp = php_fopen_and_set_opened_path(path, mode, opened_path TSRMLS_CC); - } - } - return (fp); - } - - php_error(E_WARNING, "Invalid URL specified, %s", path); - return NULL; -} -/* }}} */ - /* {{{ php_strip_url_passwd */ PHPAPI char *php_strip_url_passwd(char *url) diff --git a/main/fopen_wrappers.h b/main/fopen_wrappers.h index dc28af9f47..24e60dcc00 100644 --- a/main/fopen_wrappers.h +++ b/main/fopen_wrappers.h @@ -27,12 +27,14 @@ #define IGNORE_URL 2 /* There's no USE_URL. */ #ifdef PHP_WIN32 -# define IGNORE_URL_WIN 2 +# define IGNORE_URL_WIN IGNORE_URL #else # define IGNORE_URL_WIN 0 #endif #define ENFORCE_SAFE_MODE 4 +#define REPORT_ERRORS 8 + #ifdef PHP_WIN32 # define SOCK_ERR INVALID_SOCKET # define SOCK_CONN_ERR SOCKET_ERROR @@ -42,22 +44,6 @@ # define SOCK_CONN_ERR -1 # define SOCK_RECV_ERR -1 #endif -#define SOCK_WRITE(d, s) send(s, d, strlen(d), 0) -#define SOCK_WRITEL(d, l, s) send(s, d, l, 0) -#define SOCK_FGETC(s) php_sock_fgetc((s)) -#define SOCK_FGETS(b, l, s) php_sock_fgets((b), (l), (s)) -#define SOCK_FEOF(sock) php_sock_feof((sock)) -#define SOCK_FREAD(ptr, size, sock) php_sock_fread((ptr), (size), (sock)) -#define SOCK_FCLOSE(s) php_sock_close(s) - -#define FP_FGETS(buf, len, sock, fp, issock) \ - ((issock)?SOCK_FGETS(buf, len, sock):fgets(buf, len, fp)) -#define FP_FREAD(buf, len, sock, fp, issock) \ - ((issock)?SOCK_FREAD(buf, len, sock):fread(buf, 1, len, fp)) -#define FP_FEOF(sock, fp, issock) \ - ((issock)?SOCK_FEOF(sock):feof(fp)) -#define FP_FGETC(sock, fp, issock) \ - ((issock)?SOCK_FGETC(sock):fgetc(fp)) /* values for issock */ #define IS_NOT_SOCKET 0 diff --git a/main/internal_functions.c.in b/main/internal_functions.c.in index f8d840d755..4903d6c4bb 100644 --- a/main/internal_functions.c.in +++ b/main/internal_functions.c.in @@ -29,6 +29,12 @@ #include <stdlib.h> #include <stdio.h> +#if HAVE_OPENSSL_EXT +/* zlib typedefs free_func which causes problems if the SSL includes happen + * after zlib.h is included */ +# include <openssl/ssl.h> +#endif + @EXT_INCLUDE_CODE@ zend_module_entry *php_builtin_extensions[] = { diff --git a/main/main.c b/main/main.c index 4d7d0b7cf3..e6d968dedb 100644 --- a/main/main.c +++ b/main/main.c @@ -73,6 +73,7 @@ #include "php_content_types.h" #include "php_ticks.h" #include "php_logos.h" +#include "php_streams.h" #include "SAPI.h" /* }}} */ @@ -562,17 +563,24 @@ PHP_FUNCTION(set_time_limit) */ static FILE *php_fopen_wrapper_for_zend(const char *filename, char **opened_path) { - int issock=0, socketd=0; - int old_chunk_size; - FILE *retval; + FILE *retval = NULL; + php_stream * stream; TSRMLS_FETCH(); - - old_chunk_size = php_sock_set_def_chunk_size(1); - retval=php_fopen_wrapper((char *) filename, "rb", USE_PATH|IGNORE_URL_WIN, &issock, &socketd, opened_path TSRMLS_CC); - php_sock_set_def_chunk_size(old_chunk_size); - - if (issock) { - retval = fdopen(socketd, "rb"); + + stream = php_stream_open_wrapper((char *)filename, "rb", USE_PATH|IGNORE_URL_WIN|REPORT_ERRORS, opened_path TSRMLS_CC); + if (stream) { + /* no need for us to check the stream type here */ + php_stream_sock_set_chunk_size(stream, 1); + + if (php_stream_cast(stream, PHP_STREAM_AS_STDIO | PHP_STREAM_CAST_TRY_HARD, (void**)&retval, 1) == SUCCESS) { + ZEND_REGISTER_RESOURCE(NULL, stream, php_file_le_stream()); + } + else { + php_stream_close(stream); + if (opened_path && *opened_path) + efree(*opened_path); + retval = NULL; + } } return retval; } @@ -941,14 +949,14 @@ int php_module_startup(sapi_module_struct *sf) REGISTER_INI_ENTRIES(); - /* initialize fopen wrappers registry - (this uses configuration parameters from php.ini) + /* initialize stream wrappers registry + * (this uses configuration parameters from php.ini) */ - if (php_init_fopen_wrappers(TSRMLS_C) == FAILURE) { - php_printf("PHP: Unable to initialize fopen url wrappers.\n"); + if (php_init_stream_wrappers(TSRMLS_C) == FAILURE) { + php_printf("PHP: Unable to initialize stream url wrappers.\n"); return FAILURE; } - + /* initialize registry for images to be used in phpinfo() (this uses configuration parameters from php.ini) */ @@ -1048,7 +1056,9 @@ void php_module_shutdown(TSRMLS_D) sapi_flush(TSRMLS_C); zend_shutdown(TSRMLS_C); - php_shutdown_fopen_wrappers(TSRMLS_C); + + php_shutdown_stream_wrappers(TSRMLS_C); + php_shutdown_info_logos(); UNREGISTER_INI_ENTRIES(); diff --git a/main/network.c b/main/network.c index 6be650875a..1aedbe416a 100644 --- a/main/network.c +++ b/main/network.c @@ -17,6 +17,9 @@ */ /* $Id$ */ +#define PHP_SOCK_CHUNK_SIZE 8192 +#define MAX_CHUNKS_PER_READ 10 + #include "php.h" #ifdef PHP_WIN32 @@ -408,6 +411,406 @@ int php_sockaddr_size(php_sockaddr_storage *addr) } /* }}} */ +PHPAPI php_stream * php_stream_sock_open_from_socket(int socket, int persistent) +{ + php_stream * stream; + php_netstream_data_t * sock; + + sock = pemalloc(sizeof(php_netstream_data_t), persistent); + memset(sock, 0, sizeof(php_netstream_data_t)); + + sock->is_blocked = 1; + sock->chunk_size = PHP_SOCK_CHUNK_SIZE; + sock->timeout.tv_sec = -1; + sock->socket = socket; + + stream = php_stream_alloc(&php_stream_socket_ops, sock, persistent, "r+"); + + if (stream == NULL) + pefree(sock, persistent); + + return stream; +} + +PHPAPI php_stream * php_stream_sock_open_host(const char * host, unsigned short port, + int socktype, int timeout, int persistent) +{ + int socket; + + socket = php_hostconnect(host, port, socktype, timeout); + + if (socket == -1) + return NULL; + + return php_stream_sock_open_from_socket(socket, persistent); +} + +PHPAPI php_stream * php_stream_sock_open_unix(const char * path, int persistent, struct timeval * timeout) +{ +#if defined(AF_UNIX) + int socketd; + struct sockaddr_un unix_addr; + + socketd = socket(PF_UNIX, SOCK_STREAM, 0); + if (socketd == SOCK_ERR) + return NULL; + + memset(&unix_addr, 0, sizeof(unix_addr)); + unix_addr.sun_family = AF_UNIX; + strlcpy(unix_addr.sun_path, path, sizeof(unix_addr.sun_path)); + + if (php_connect_nonb(socketd, (struct sockaddr *) &unix_addr, sizeof(unix_addr), timeout) == SOCK_CONN_ERR) + return NULL; + + return php_stream_sock_open_from_socket(socketd, persistent); +#else + return NULL; +#endif +} + +#if HAVE_OPENSSL_EXT +PHPAPI int php_stream_sock_ssl_activate_with_method(php_stream * stream, int activate, SSL_METHOD * method) +{ + php_netstream_data_t * sock = (php_netstream_data_t*)stream->abstract; + SSL_CTX * ctx = NULL; + + if (!php_stream_is(stream, PHP_STREAM_IS_SOCKET)) + return FAILURE; + + if (activate == sock->ssl_active) + return SUCCESS; /* already in desired mode */ + + if (activate && sock->ssl_handle == NULL) { + ctx = SSL_CTX_new(method); + if (ctx == NULL) + return FAILURE; + + sock->ssl_handle = SSL_new(ctx); + if (sock->ssl_handle == NULL) { + SSL_CTX_free(ctx); + return FAILURE; + } + + SSL_set_fd(sock->ssl_handle, sock->socket); + } + + if (activate) { + if (SSL_connect(sock->ssl_handle) <= 0) { + SSL_shutdown(sock->ssl_handle); + return FAILURE; + } + sock->ssl_active = activate; + } + else { + SSL_shutdown(sock->ssl_handle); + sock->ssl_active = 0; + } + return SUCCESS; +} +#endif + +PHPAPI void php_stream_sock_set_timeout(php_stream * stream, struct timeval *timeout) +{ + php_netstream_data_t * sock = (php_netstream_data_t*)stream->abstract; + + if (!php_stream_is(stream, PHP_STREAM_IS_SOCKET)) + return; + + sock->timeout = *timeout; + sock->timeout_event = 0; +} + +PHPAPI int php_stream_sock_set_blocking(php_stream * stream, int mode) +{ + int oldmode; + php_netstream_data_t * sock = (php_netstream_data_t*)stream->abstract; + + if (!php_stream_is(stream, PHP_STREAM_IS_SOCKET)) + return 0; + + oldmode = sock->is_blocked; + sock->is_blocked = mode; + + return oldmode; +} + +PHPAPI size_t php_stream_sock_set_chunk_size(php_stream * stream, size_t size) +{ + size_t oldsize; + php_netstream_data_t * sock = (php_netstream_data_t*)stream->abstract; + + if (!php_stream_is(stream, PHP_STREAM_IS_SOCKET)) + return 0; + + oldsize = sock->chunk_size; + sock->chunk_size = size; + + return oldsize; +} + +#define TOREAD(sock) ((sock)->writepos - (sock)->readpos) +#define READPTR(sock) ((sock)->readbuf + (sock)->readpos) +#define WRITEPTR(sock) ((sock)->readbuf + (sock)->writepos) + +static size_t php_sockop_write(php_stream * stream, const char * buf, size_t count) +{ + php_netstream_data_t * sock = (php_netstream_data_t*)stream->abstract; +#if HAVE_OPENSSL_EXT + if (sock->ssl_active) + return SSL_write(sock->ssl_handle, buf, count); +#endif + return send(sock->socket, buf, count, 0); +} +static void php_sock_stream_wait_for_data(php_stream * stream, php_netstream_data_t * sock) +{ + fd_set fdr, tfdr; + int retval; + struct timeval timeout, *ptimeout; + + FD_ZERO(&fdr); + FD_SET(sock->socket, &fdr); + sock->timeout_event = 0; + + if (sock->timeout.tv_sec == -1) + ptimeout = NULL; + else + ptimeout = &timeout; + + while(1) { + tfdr = fdr; + timeout = sock->timeout; + + retval = select(sock->socket + 1, &tfdr, NULL, NULL, ptimeout); + + if (retval == 0) + sock->timeout_event = 1; + + if (retval >= 0) + break; + } +} + +static size_t php_sock_stream_read_internal(php_stream * stream, php_netstream_data_t * sock) +{ + char buf[PHP_SOCK_CHUNK_SIZE]; + int nr_bytes; + size_t nr_read = 0; + + /* For blocking sockets, we wait until there is some + data to read (real data or EOF) + + Otherwise, recv() may time out and return 0 and + therefore sock->eof would be set errornously. + */ + + + if(sock->is_blocked) { + php_sock_stream_wait_for_data(stream, sock); + if (sock->timeout_event) + return 0; + } + + /* read at a maximum sock->chunk_size */ +#if HAVE_OPENSSL_EXT + if (sock->ssl_active) + nr_bytes = SSL_read(sock->ssl_handle, buf, sock->chunk_size); + else +#endif + nr_bytes = recv(sock->socket, buf, sock->chunk_size, 0); + if(nr_bytes > 0) { + if(sock->writepos + nr_bytes > sock->readbuflen) { + sock->readbuflen += sock->chunk_size; + sock->readbuf = perealloc(sock->readbuf, sock->readbuflen, + php_stream_is_persistent(stream)); + } + memcpy(WRITEPTR(sock), buf, nr_bytes); + sock->writepos += nr_bytes; + nr_read = nr_bytes; + } else if(nr_bytes == 0 || (nr_bytes < 0 && errno != EWOULDBLOCK)) { + sock->eof = 1; + } + + return nr_read; + +} + +static size_t php_sock_stream_read(php_stream * stream, php_netstream_data_t * sock) +{ + size_t nr_bytes; + size_t nr_read = 0; + int i; + + for(i = 0; !sock->eof && i < MAX_CHUNKS_PER_READ; i++) { + nr_bytes = php_sock_stream_read_internal(stream, sock); + if(nr_bytes == 0) break; + nr_read += nr_bytes; + } + + return nr_read; +} + +static size_t php_sockop_read(php_stream * stream, char * buf, size_t count) +{ + php_netstream_data_t * sock = (php_netstream_data_t*)stream->abstract; + size_t ret = 0; + + if (sock->is_blocked) { + while(!sock->eof && TOREAD(sock) < count && !sock->timeout_event) + php_sock_stream_read_internal(stream, sock); + } + else + php_sock_stream_read(stream, sock); + + if(count < 0) + return ret; + + ret = MIN(TOREAD(sock), count); + if (ret) { + memcpy(buf, READPTR(sock), ret); + sock->readpos += ret; + } + + return ret; +} + +static int php_sockop_close(php_stream * stream) +{ + php_netstream_data_t * sock = (php_netstream_data_t*)stream->abstract; + +#if HAVE_OPENSSL_EXT + if (sock->ssl_active) { + SSL_shutdown(sock->ssl_handle); + sock->ssl_active = 0; + SSL_free(sock->ssl_handle); + sock->ssl_handle = NULL; + } +#endif + + shutdown(sock->socket, 0); + closesocket(sock->socket); + + if (sock->readbuf) + pefree(sock->readbuf, php_stream_is_persistent(stream)); + + pefree(sock, php_stream_is_persistent(stream)); + + return 0; +} + +static int php_sockop_flush(php_stream * stream) +{ + php_netstream_data_t * sock = (php_netstream_data_t*)stream->abstract; + return fsync(sock->socket); +} + +static int php_sockop_cast(php_stream * stream, int castas, void ** ret) +{ + php_netstream_data_t * sock = (php_netstream_data_t*)stream->abstract; + TSRMLS_FETCH(); + + switch(castas) { + case PHP_STREAM_AS_STDIO: +#if HAVE_OPENSSL_EXT + if (sock->ssl_active) + return FAILURE; +#endif + if (ret) { + /* DANGER!: data buffered in stream->readbuf will be forgotten! */ + if (TOREAD(sock) > 0) + zend_error(E_WARNING, "%s(): buffered data lost during conversion to FILE*!", get_active_function_name(TSRMLS_C)); + *ret = fdopen(sock->socket, stream->mode); + if (*ret) + return SUCCESS; + return FAILURE; + } + return SUCCESS; + case PHP_STREAM_AS_FD: + case PHP_STREAM_AS_SOCKETD: +#if HAVE_OPENSSL_EXT + if (sock->ssl_active) + return FAILURE; +#endif + if (ret) + *ret = (void*)sock->socket; + return SUCCESS; + default: + return FAILURE; + } +} + +#define SEARCHCR() do { \ + if (TOREAD(sock)) { \ + for (p = READPTR(sock), pe = p + MIN(TOREAD(sock), maxlen); \ + *p != '\n'; ) \ + if (++p >= pe) { \ + p = NULL; \ + break; \ + } \ + } else \ + p = NULL; \ +} while (0) + + +static char * php_sockop_gets(php_stream * stream, char *buf, size_t maxlen) +{ + php_netstream_data_t * sock = (php_netstream_data_t*)stream->abstract; + char *p = NULL, *pe; + char *ret = NULL; + size_t amount = 0; + + if (maxlen==0) { + buf[0] = 0; + return buf; + } + + SEARCHCR(); + + if(!p) { + if(sock->is_blocked) { + while(!p && !sock->eof && !sock->timeout_event && TOREAD(sock) < maxlen) { + php_sock_stream_read_internal(stream, sock); + SEARCHCR(); + } + } else { + php_sock_stream_read(stream, sock); + SEARCHCR(); + } + } + + if(p) { + amount = (ptrdiff_t) p - (ptrdiff_t) READPTR(sock) + 1; + } else { + amount = TOREAD(sock); + } + + amount = MIN(amount, maxlen); + + if(amount > 0) { + memcpy(buf, READPTR(sock), amount); + sock->readpos += amount; + } + buf[amount] = '\0'; + + /* signal error only, if we don't return data from this call and + if there is no data to read and if the eof flag is set */ + if(amount || TOREAD(sock) || !sock->eof) { + ret = buf; + } + + return ret; +} + +php_stream_ops php_stream_socket_ops = { + php_sockop_write, php_sockop_read, + php_sockop_close, php_sockop_flush, + NULL, php_sockop_gets, + php_sockop_cast, + "socket" +}; + + + + /* * Local variables: * tab-width: 8 diff --git a/main/php_network.h b/main/php_network.h index b71737265f..b87e709fff 100644 --- a/main/php_network.h +++ b/main/php_network.h @@ -27,8 +27,17 @@ # undef FD_SETSIZE # include "arpa/inet.h" # define socklen_t unsigned int +#else +# undef closesocket +# define closesocket close +#endif + +#ifndef HAVE_SHUTDOWN +#undef shutdown +#define shutdown(s,n) /* nothing */ #endif + #ifdef HAVE_NETINET_IN_H # include <netinet/in.h> #endif @@ -41,6 +50,10 @@ #include <sys/time.h> #endif +#if HAVE_OPENSSL_EXT +#include <openssl/ssl.h> +#endif + #ifdef HAVE_SOCKADDR_STORAGE typedef struct sockaddr_storage php_sockaddr_storage; #else @@ -56,6 +69,47 @@ PHPAPI int php_connect_nonb(int sockfd, const struct sockaddr *addr, socklen_t a void php_any_addr(int family, php_sockaddr_storage *addr, unsigned short port); int php_sockaddr_size(php_sockaddr_storage *addr); +struct _php_netstream_data_t { + int socket; + unsigned char *readbuf; + size_t readbuflen; + size_t readpos; + size_t writepos; + char eof; + char is_blocked; + size_t chunk_size; + struct timeval timeout; + char timeout_event; +#if HAVE_OPENSSL_EXT + /* openssl specific bits here */ + SSL * ssl_handle; + int ssl_active; +#endif +}; +typedef struct _php_netstream_data_t php_netstream_data_t; + +#define PHP_NETSTREAM_DATA_FROM_STREAM(stream) (php_netstream_data_t*)(stream)->abstract + +extern php_stream_ops php_stream_socket_ops; +#define PHP_STREAM_IS_SOCKET (&php_stream_socket_ops) + +PHPAPI php_stream * php_stream_sock_open_from_socket(int socket, int persistent); +/* open a connection to a host using php_hostconnect and return a stream */ +PHPAPI php_stream * php_stream_sock_open_host(const char * host, unsigned short port, + int socktype, int timeout, int persistent); +PHPAPI php_stream * php_stream_sock_open_unix(const char * path, int persistent, struct timeval * timeout); + +PHPAPI void php_stream_sock_set_timeout(php_stream * stream, struct timeval *timeout); +PHPAPI int php_stream_sock_set_blocking(php_stream * stream, int mode); +/* set the chunk size for the stream; return the old chunk size */ +PHPAPI size_t php_stream_sock_set_chunk_size(php_stream * stream, size_t size); + +#if HAVE_OPENSSL_EXT +PHPAPI int php_stream_sock_ssl_activate_with_method(php_stream * stream, int activate, SSL_METHOD * method); +#define php_stream_sock_ssl_activate(stream, activate) php_stream_sock_ssl_activate_with_method((stream), (activate), SSLv23_client_method()) + +#endif + #endif /* _PHP_NETWORK_H */ /* diff --git a/main/php_streams.h b/main/php_streams.h index 6acaafb3fc..39b8e70a46 100755 --- a/main/php_streams.h +++ b/main/php_streams.h @@ -19,8 +19,6 @@ #ifndef PHP_STREAMS_H #define PHP_STREAMS_H -#if HAVE_PHP_STREAM - #ifdef HAVE_SYS_TIME_H #include <sys/time.h> #endif @@ -42,9 +40,23 @@ typedef struct _php_stream_ops { const char * label; /* label for this ops structure */ } php_stream_ops; +/* 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 void (*php_stream_wrapper_dtor_func_t)(php_stream * stream); + +typedef struct _php_stream_wrapper { + php_stream_factory_func_t create; + php_stream_wrapper_dtor_func_t destroy; +} php_stream_wrapper; + struct _php_stream { php_stream_ops * ops; void * abstract; /* convenience pointer for abstraction */ + + php_stream_wrapper * wrapper; /* which wrapper was used to open the stream */ + void * wrapperthis; /* convenience pointer for a instance of a wrapper */ + zval * wrapperdata; /* fgetwrapperdata retrieves this */ + int is_persistent; char mode[16]; /* "rwb" etc. ala stdio */ /* so we know how to clean it up correctly. This should be set to @@ -68,15 +80,34 @@ PHPAPI int php_stream_seek(php_stream * stream, off_t offset, int whence); PHPAPI off_t php_stream_tell(php_stream * stream); PHPAPI size_t php_stream_read(php_stream * stream, char * buf, size_t count); PHPAPI size_t php_stream_write(php_stream * stream, const char * buf, size_t count); +#define php_stream_write_string(stream, str) php_stream_write(stream, str, strlen(str)) PHPAPI int php_stream_eof(php_stream * stream); PHPAPI int php_stream_getc(php_stream * stream); +PHPAPI int php_stream_putc(php_stream * stream, int c); PHPAPI int php_stream_flush(php_stream * stream); PHPAPI char *php_stream_gets(php_stream * stream, char *buf, size_t maxlen); +PHPAPI int php_stream_puts(php_stream * stream, char * buf); -/* operations for a stdio FILE; the FILE * must be placed in stream->abstract */ +/* copy up to maxlen bytes from src to dest. If maxlen is 0, copy until eof(src). + * Uses mmap if the src is a plain file and at offset 0 */ +PHPAPI size_t php_stream_copy_to_stream(php_stream * src, php_stream * dest, size_t maxlen); +/* read all data from stream and put into a buffer. Caller must free buffer when done, + * according to allocopts. + * The copy will use mmap if available. */ +PHPAPI size_t php_stream_read_all(php_stream * src, char ** buf, int persistent); + +/* maybe implement someday */ +#define php_stream_error(stream) (0) + +/* operations for a stdio FILE; use the php_stream_fopen_XXX funcs below */ 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); +PHPAPI php_stream * php_stream_fopen_from_file(FILE * file, const char * mode); +PHPAPI php_stream * php_stream_fopen_from_pipe(FILE * file, const char * mode); +PHPAPI php_stream * php_stream_fopen_tmpfile(void); +PHPAPI php_stream * php_stream_fopen_temporary_file(const char * dir, const char * pfx, char **opened_path TSRMLS_DC); /* coerce the stream into some other form */ /* cast as a stdio FILE * */ @@ -86,15 +117,27 @@ PHPAPI php_stream * php_stream_fopen(const char * filename, const char * mode); /* cast as a socketd */ #define PHP_STREAM_AS_SOCKETD 2 +/* try really, really hard to make sure the cast happens (socketpair) */ +#define PHP_STREAM_CAST_TRY_HARD 0x80000000 + PHPAPI int php_stream_cast(php_stream * stream, int castas, void ** ret, int show_err); /* use this to check if a stream can be cast into another form */ #define php_stream_can_cast(stream, as) php_stream_cast(stream, as, NULL, 0) /* 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 + +#define php_stream_is_persistent(stream) (stream)->is_persistent + +/* Wrappers support */ +int php_init_stream_wrappers(TSRMLS_D); +int php_shutdown_stream_wrappers(TSRMLS_D); +PHPAPI int php_register_url_stream_wrapper(char * protocol, php_stream_wrapper * wrapper TSRMLS_DC); +PHPAPI int php_unregister_url_stream_wrapper(char * protocol TSRMLS_DC); -#endif /* HAVE_PHP_STREAM */ +PHPAPI php_stream * php_stream_open_wrapper(char * path, char * mode, int options, char ** opened_path TSRMLS_DC); #endif diff --git a/main/streams.c b/main/streams.c index b79d04a6d4..58e6ba44bb 100755 --- a/main/streams.c +++ b/main/streams.c @@ -12,14 +12,28 @@ | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ - | Author: Wez Furlong (wez@thebrainroom.com) | + | Authors: | + | Wez Furlong (wez@thebrainroom.com) | + | Borrowed code from: | + | Rasmus Lerdorf <rasmus@lerdorf.on.ca> | + | Jim Winstead <jimw@php.net> | +----------------------------------------------------------------------+ */ #define _GNU_SOURCE #include "php.h" +#include "php_globals.h" +#include "php_network.h" +#include "php_open_temporary_file.h" + +#ifdef HAVE_SYS_MMAN_H +#include <sys/mman.h> +#endif + +#ifndef MAP_FAILED +#define MAP_FAILED ((void *) -1) +#endif -#if HAVE_PHP_STREAM #ifdef PHP_WIN32 #define EWOULDBLOCK WSAEWOULDBLOCK @@ -27,18 +41,10 @@ #include "build-defs.h" #endif -#define MAX_CHUNK_SIZE 8192 - -#define TOREAD(stream) ((stream)->readbuf.writepos - (stream)->readbuf.readpos) -#define TOWRITE(stream) ((stream)->readbuf.writepos - (stream)->readbuf.readpos) - -#define READPTR(stream) ((stream)->readbuf.buffer + (stream)->readbuf.readpos) -#define WRITEPTR(stream) ((stream)->readbuf.buffer + (stream)->readbuf.writepos) - -#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; @@ -54,11 +60,18 @@ PHPAPI php_stream * php_stream_alloc(php_stream_ops * ops, void * abstract, int 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; + php_stream_flush(stream); + + if (stream->wrapper && stream->wrapper->destroy) { + stream->wrapper->destroy(stream); + } + if (call_dtor) { if (stream->fclose_stdiocast == PHP_STREAM_FCLOSE_FOPENCOOKIE) { @@ -82,11 +95,17 @@ PHPAPI int php_stream_free(php_stream * stream, int call_dtor) stream->stdiocast = NULL; } } + + if (stream->wrapperdata) { + FREE_ZVAL(stream->wrapperdata); + } pefree(stream, stream->is_persistent); 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); @@ -100,6 +119,14 @@ PHPAPI int php_stream_eof(php_stream * stream) return stream->ops->read(stream, NULL, 0) == EOF ? 1 : 0; } +PHPAPI int php_stream_putc(php_stream * stream, int c) +{ + unsigned char buf = c; + if (php_stream_write(stream, &buf, 1) > 0) + return 1; + return EOF; +} + PHPAPI int php_stream_getc(php_stream * stream) { char buf; @@ -109,6 +136,17 @@ PHPAPI int php_stream_getc(php_stream * stream) return EOF; } +PHPAPI int php_stream_puts(php_stream * stream, char * buf) +{ + int len; + char newline[2] = "\n"; /* is this OK for Win? */ + len = strlen(buf); + + if (len > 0 && php_stream_write(stream, buf, len) && php_stream_write(stream, newline, 1)) + return 1; + return 0; +} + PHPAPI char *php_stream_gets(php_stream * stream, char *buf, size_t maxlen) { @@ -142,18 +180,13 @@ PHPAPI char *php_stream_gets(php_stream * stream, char *buf, size_t maxlen) PHPAPI int php_stream_flush(php_stream * stream) { - return stream->ops->flush(stream); + if (stream->ops->flush) + return stream->ops->flush(stream); + return 0; } PHPAPI size_t php_stream_write(php_stream * stream, const char * buf, size_t count) { - if (strchr(stream->mode, 'w') == NULL) { - TSRMLS_FETCH(); - - zend_error(E_WARNING, "%s(): stream was not opened for writing", get_active_function_name(TSRMLS_C)); - return 0; - } - return stream->ops->write(stream, buf, count); } @@ -171,60 +204,310 @@ PHPAPI int php_stream_seek(php_stream * stream, off_t offset, int whence) if (stream->ops->seek) return stream->ops->seek(stream, offset, whence); + /* emulate forward moving seeks with reads */ + if (whence == SEEK_CUR && offset > 0) { + while(offset-- > 0) + if (php_stream_getc(stream) == EOF) + return -1; + return 0; + } + zend_error(E_WARNING, "streams of type %s do not support seeking", stream->ops->label); return -1; } -/*------- STDIO stream implementation -------*/ +#define CHUNK_SIZE 8192 + +PHPAPI size_t php_stream_read_all(php_stream * src, char ** buf, int persistent) +{ + size_t ret = 0; + char * ptr; + size_t len = 0, max_len; + int step = CHUNK_SIZE; + int min_room = CHUNK_SIZE / 4; +#if HAVE_MMAP + int srcfd; +#endif + +#if HAVE_MMAP + /* try and optimize the case where we are copying from the start of a plain file. + * We could probably make this work in more situations, but I don't trust the stdio + * buffering layer. + * */ + if ( php_stream_is(src, PHP_STREAM_IS_STDIO) && + php_stream_tell(src) == 0 && + SUCCESS == php_stream_cast(src, PHP_STREAM_AS_FD, (void**)&srcfd, 0)) + { + struct stat sbuf; + + if (fstat(srcfd, &sbuf) == 0) { + void * srcfile; + + srcfile = mmap(NULL, sbuf.st_size, PROT_READ, MAP_SHARED, srcfd, 0); + if (srcfile != (void*)MAP_FAILED) { + + *buf = pemalloc(persistent, sbuf.st_size); + + if (*buf) { + memcpy(*buf, srcfile, sbuf.st_size); + ret = sbuf.st_size; + } + + munmap(srcfile, sbuf.st_size); + return ret; + } + } + /* fall through - we might be able to copy in smaller chunks */ + } +#endif + + ptr = *buf = pemalloc(persistent, step); + max_len = step; + + while((ret = php_stream_read(src, ptr, max_len - len))) { + len += ret; + if (len + min_room >= max_len) { + *buf = perealloc(*buf, max_len + step, persistent); + max_len += step; + ptr = *buf + len; + } + } + if (len) { + *buf = perealloc(*buf, len, persistent); + } + else { + pefree(*buf, persistent); + *buf = NULL; + } + return len; +} + +PHPAPI size_t php_stream_copy_to_stream(php_stream * src, php_stream * dest, size_t maxlen) +{ + char buf[CHUNK_SIZE]; + size_t readchunk; + size_t haveread = 0; + size_t didread; +#if HAVE_MMAP + int srcfd; +#endif + +#if HAVE_MMAP + /* try and optimize the case where we are copying from the start of a plain file. + * We could probably make this work in more situations, but I don't trust the stdio + * buffering layer. + * */ + if ( php_stream_is(src, PHP_STREAM_IS_STDIO) && + php_stream_tell(src) == 0 && + SUCCESS == php_stream_cast(src, PHP_STREAM_AS_FD, (void**)&srcfd, 0)) + { + struct stat sbuf; + + if (fstat(srcfd, &sbuf) == 0) { + void * srcfile; + + srcfile = mmap(NULL, sbuf.st_size, PROT_READ, MAP_SHARED, srcfd, 0); + if (srcfile != (void*)MAP_FAILED) { + haveread = php_stream_write(dest, srcfile, sbuf.st_size); + munmap(srcfile, sbuf.st_size); + return haveread; + } + } + /* fall through - we might be able to copy in smaller chunks */ + } +#endif + + while(1) { + readchunk = sizeof(buf); + + if (maxlen && (maxlen - haveread) < readchunk) + readchunk = maxlen - haveread; + + didread = php_stream_read(src, buf, readchunk); + if (didread) { + /* extra paranoid */ + size_t didwrite, towrite; + char * writeptr; + + towrite = didread; + writeptr = buf; + haveread += didread; + + while(towrite) { + didwrite = php_stream_write(dest, writeptr, towrite); + + if (didwrite == 0) + return 0; /* error */ + + towrite -= didwrite; + writeptr += didwrite; + } + } + else + return 0; /* error */ + + if (maxlen - haveread == 0) + break; + } + + return haveread; + +} +/* }}} */ + + + +/* {{{ ------- STDIO stream implementation -------*/ + +typedef struct { + FILE * file; + int is_pipe; /* use pclose */ +#if HAVE_FLUSHIO + char last_op; +#endif +} php_stdio_stream_data; + +PHPAPI php_stream * php_stream_fopen_temporary_file(const char * dir, const char * pfx, char **opened_path TSRMLS_DC) +{ + FILE * fp = php_open_temporary_file(dir, pfx, opened_path); + + if (fp) { + php_stream * stream = php_stream_fopen_from_file(fp, "wb"); + if (stream) + return stream; + fclose(fp); + + zend_error(E_WARNING, "%s(): unable to allocate stream", get_active_function_name(TSRMLS_C)); + + return NULL; + } + return NULL; +} + +PHPAPI php_stream * php_stream_fopen_tmpfile(void) +{ + FILE * fp; + php_stream * stream; + + fp = tmpfile(); + if (fp == NULL) { + zend_error(E_WARNING, "tmpfile(): %s", strerror(errno)); + return NULL; + } + stream = php_stream_fopen_from_file(fp, "r+"); + if (stream == NULL) { + zend_error(E_WARNING, "tmpfile(): %s", strerror(errno)); + fclose(fp); + return NULL; + } + return stream; +} + + +PHPAPI php_stream * php_stream_fopen_from_file(FILE * file, const char * mode) +{ + php_stdio_stream_data * self; + + self = emalloc(sizeof(*self)); + self->file = file; + self->is_pipe = 0; + return php_stream_alloc(&php_stream_stdio_ops, self, 0, mode); +} + +PHPAPI php_stream * php_stream_fopen_from_pipe(FILE * file, const char * mode) +{ + php_stdio_stream_data * self; + + self = emalloc(sizeof(*self)); + self->file = file; + self->is_pipe = 1; + return php_stream_alloc(&php_stream_stdio_ops, self, 0, mode); +} static size_t php_stdiop_write(php_stream * stream, const char * buf, size_t count) { - return fwrite(buf, 1, count, (FILE*)stream->abstract); + php_stdio_stream_data * data = (php_stdio_stream_data*)stream->abstract; + +#if HAVE_FLUSHIO + if (data->last_op == 'r') + fseek(data->file, 0, SEEK_CUR); + data->last_op = 'w'; +#endif + + return fwrite(buf, 1, count, data->file); } static size_t php_stdiop_read(php_stream * stream, char * buf, size_t count) { + php_stdio_stream_data * data = (php_stdio_stream_data*)stream->abstract; + if (buf == NULL && count == 0) { /* check for EOF condition */ - if (feof((FILE*)stream->abstract)) { + if (feof(data->file)) { return EOF; } return 0; } - return fread(buf, 1, count, (FILE*)stream->abstract); + +#if HAVE_FLUSHIO + if (data->last_op == 'w') + fseek(data->file, 0, SEEK_CUR); + data->last_op = 'r'; +#endif + + return fread(buf, 1, count, data->file); } static int php_stdiop_close(php_stream * stream) { - return fclose((FILE*)stream->abstract); + int ret; + php_stdio_stream_data * data = (php_stdio_stream_data*)stream->abstract; + + if (data->is_pipe) + ret = pclose(data->file); + else + ret = fclose(data->file); + + efree(data); + + return ret; } static int php_stdiop_flush(php_stream * stream) { - return fflush((FILE*)stream->abstract); + return fflush(((php_stdio_stream_data*)stream->abstract)->file); } static int php_stdiop_seek(php_stream * stream, off_t offset, int whence) { - return fseek((FILE*)stream->abstract, offset, whence); + return fseek(((php_stdio_stream_data*)stream->abstract)->file, offset, whence); } static char * php_stdiop_gets(php_stream * stream, char * buf, size_t size) { - return fgets(buf, size, (FILE*)stream->abstract); + php_stdio_stream_data * data = (php_stdio_stream_data*)stream->abstract; + +#if HAVE_FLUSHIO + if (data->last_op == 'w') + fseek(data->file, 0, SEEK_CUR); + data->last_op = 'r'; +#endif + + return fgets(buf, size, data->file); } static int php_stdiop_cast(php_stream * stream, int castas, void ** ret) { int fd; + php_stdio_stream_data * data = (php_stdio_stream_data*)stream->abstract; switch (castas) { case PHP_STREAM_AS_STDIO: if (ret) - *ret = stream->abstract; + *ret = data->file; return SUCCESS; case PHP_STREAM_AS_FD: - fd = fileno((FILE*)stream->abstract); + fd = fileno(data->file); if (fd < 0) return FAILURE; if (ret) @@ -242,21 +525,153 @@ php_stream_ops php_stream_stdio_ops = { "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) /* {{{ */ +{ + /* 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 = fopen(filename, mode); + 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); + php_stream * ret = php_stream_fopen_from_file(fp, mode); + + if (ret) { + if (opened_path) { + *opened_path = realpath; + realpath = NULL; + } + if (realpath) + efree(realpath); - if (ret) 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) { @@ -286,9 +701,14 @@ static COOKIE_IO_FUNCTIONS_T stream_cookie_functions = #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) /* {{{ */ { + + /* trying hard is not yet implemented */ + castas &= ~PHP_STREAM_CAST_TRY_HARD; + if (castas == PHP_STREAM_AS_STDIO) { if (stream->stdiocast) { if (ret) @@ -354,9 +774,110 @@ exit_success: 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; } -#endif +PHPAPI int php_register_url_stream_wrapper(char * protocol, php_stream_wrapper * wrapper TSRMLS_DC) +{ + if (PG(allow_url_fopen)) + return zend_hash_add(&url_stream_wrappers_hash, protocol, strlen(protocol), wrapper, sizeof(wrapper), NULL); + return FAILURE; +} +PHPAPI int php_unregister_url_stream_wrapper(char * protocol TSRMLS_DC) +{ + if (PG(allow_url_fopen)) + return zend_hash_del(&url_stream_wrappers_hash, protocol, strlen(protocol)); + return SUCCESS; +} + +static php_stream * php_stream_open_url(char * path, char * mode, int options, char ** opened_path TSRMLS_DC) +{ + php_stream_wrapper * 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) { + if (FAILURE == zend_hash_find(&url_stream_wrappers_hash, (char*)protocol, n, (void**)&wrapper)) { + wrapper = NULL; + protocol = NULL; + } + if (wrapper) { + php_stream * stream = wrapper->create(path, mode, options, opened_path TSRMLS_CC); + if (stream) + stream->wrapper = wrapper; + return stream; + } + } + + 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; +} + + /* * Local variables: * tab-width: 4 diff --git a/tests/strings/003.phpt b/tests/strings/003.phpt index f7d754988b..97e3aaa38f 100644 --- a/tests/strings/003.phpt +++ b/tests/strings/003.phpt @@ -5,9 +5,15 @@ HTML entities --FILE-- <?php setlocale (LC_CTYPE, "C"); -echo htmlspecialchars ("<>\"&εΔ\n"); -echo htmlentities ("<>\"&εΔ\n"); +$sc_encoded = htmlspecialchars ("<>\"&εΔ\n"); +echo $sc_encoded; +$ent_encoded = htmlentities ("<>\"&εΔ\n"); +echo $ent_encoded; +echo html_entity_decode($sc_encoded); +echo html_entity_decode($ent_encoded); ?> --EXPECT-- <>"&εΔ <>"&åÄ +<>"&εΔ +<>"&εΔ |