From: Sara Golemon Date: Wed, 29 Mar 2006 22:52:24 +0000 (+0000) Subject: Update php_stream_passthru() to handle unicode data. X-Git-Tag: RELEASE_1_3~198 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=1c97a0d78c437a74977da362e874603e6d43a826;p=php Update php_stream_passthru() to handle unicode data. This updates userspace functions fpassthru() and readfile() UG(output_encoding) is used by php_stream_passthru() to translate unicode stream contents back to an outputable character set. Note: readfile()'s second parameter (use_include_path) has been changed to be a bitmask "flags" parameter instead. For the most commonly used values (TRUE, 1) this will continue functioning as expected since the value of FILE_USE_INCLUDE_PATH is (coincidentally) 1. The impact to other values should be noted in the migration6 guide. This change makes it possible to allow readfile() to output binary file contents (default) or unicode transcoded contents (using FILE_TEXT flag). --- diff --git a/ext/standard/file.c b/ext/standard/file.c index 048f23aa9f..bd1750bf55 100644 --- a/ext/standard/file.c +++ b/ext/standard/file.c @@ -547,7 +547,7 @@ PHP_FUNCTION(file_get_contents) } /* }}} */ -/* {{{ proto int file_put_contents(string file, mixed data [, int flags [, resource context]]) +/* {{{ proto int file_put_contents(string file, mixed data [, int flags [, resource context]]) U Write/Create a file with contents data and return the number of bytes written */ PHP_FUNCTION(file_put_contents) { @@ -991,7 +991,7 @@ PHPAPI PHP_FUNCTION(feof) } /* }}} */ -/* {{{ proto string fgets(resource fp[, int length]) +/* {{{ proto string fgets(resource fp[, int length]) U Get a line from file pointer */ PHPAPI PHP_FUNCTION(fgets) { @@ -1021,7 +1021,7 @@ PHPAPI PHP_FUNCTION(fgets) } /* }}} */ -/* {{{ proto string fgetc(resource fp) +/* {{{ proto string fgetc(resource fp) U Get a character from file pointer */ PHPAPI PHP_FUNCTION(fgetc) { @@ -1052,7 +1052,7 @@ PHPAPI PHP_FUNCTION(fgetc) } /* }}} */ -/* {{{ proto string fgetss(resource fp [, int length, string allowable_tags]) +/* {{{ proto string fgetss(resource fp [, int length, string allowable_tags]) U Get a line from file pointer and strip HTML tags */ PHPAPI PHP_FUNCTION(fgetss) { @@ -1168,7 +1168,7 @@ PHP_FUNCTION(fscanf) } /* }}} */ -/* {{{ proto int fwrite(resource fp, string str [, int length]) +/* {{{ proto int fwrite(resource fp, string str [, int length]) U Binary-safe file write */ PHPAPI PHP_FUNCTION(fwrite) { @@ -1371,26 +1371,30 @@ PHP_FUNCTION(rmdir) } /* }}} */ -/* {{{ proto int readfile(string filename [, bool use_include_path[, resource context]]) +/* {{{ proto int readfile(string filename [, int flags[, resource context]]) U Output a file or a URL */ -/* UTODO: Accept unicode contents */ PHP_FUNCTION(readfile) { char *filename; int size = 0; int filename_len; - zend_bool use_include_path = 0; + long flags = 0; zval *zcontext = NULL; php_stream *stream; php_stream_context *context = NULL; + char *mode = "rb"; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|br!", &filename, &filename_len, &use_include_path, &zcontext) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|lr!", &filename, &filename_len, &flags, &zcontext) == FAILURE) { RETURN_FALSE; } context = php_stream_context_from_zval(zcontext, 0); - stream = php_stream_open_wrapper_ex(filename, "rb", (use_include_path ? USE_PATH : 0) | REPORT_ERRORS, NULL, context); + if (flags & PHP_FILE_TEXT) { + mode = "rt"; + } + + stream = php_stream_open_wrapper_ex(filename, mode, ((flags & PHP_FILE_USE_INCLUDE_PATH) ? USE_PATH : 0) | REPORT_ERRORS, NULL, context); if (stream) { size = php_stream_passthru(stream); php_stream_close(stream); @@ -1429,9 +1433,8 @@ PHP_FUNCTION(umask) /* }}} */ -/* {{{ proto int fpassthru(resource fp) +/* {{{ proto int fpassthru(resource fp) U Output all remaining data from a file pointer */ -/* UTODO: Accept unicode contents */ PHPAPI PHP_FUNCTION(fpassthru) { zval **arg1; @@ -1733,7 +1736,7 @@ safe_to_copy: } /* }}} */ -/* {{{ proto string fread(resource fp, int length) +/* {{{ proto string fread(resource fp, int length) U Binary-safe file read */ PHPAPI PHP_FUNCTION(fread) { diff --git a/main/streams/streams.c b/main/streams/streams.c index 4c25c53f2e..f9dbb88136 100755 --- a/main/streams/streams.c +++ b/main/streams/streams.c @@ -1507,11 +1507,10 @@ PHPAPI int _php_stream_truncate_set_size(php_stream *stream, size_t newsize TSRM PHPAPI size_t _php_stream_passthru(php_stream * stream STREAMS_DC TSRMLS_DC) { - size_t bcount = 0; - char buf[8192]; - int b; + size_t count = 0; if (php_stream_mmap_possible(stream)) { + /* mmap_possible == non-filtered stream == binary stream */ char *p; size_t mapped; @@ -1526,12 +1525,46 @@ PHPAPI size_t _php_stream_passthru(php_stream * stream STREAMS_DC TSRMLS_DC) } } - while ((b = php_stream_read(stream, buf, sizeof(buf))) > 0) { - PHPWRITE(buf, b); - bcount += b; + if (stream->readbuf_type == IS_UNICODE) { + UChar inbuf_start[8192]; + UConverter *conv = ZEND_U_CONVERTER(UG(output_encoding_conv)); + int outbuflen = UCNV_GET_MAX_BYTES_FOR_STRING(8192, ucnv_getMaxCharSize(conv)); + char *outbuf_start = emalloc(outbuflen + 1); + int b; + + ucnv_resetFromUnicode(conv); + + while ((b = php_stream_read_unicode(stream, inbuf_start, sizeof(inbuf_start))) > 0) { + char *outbuf = outbuf_start; + UChar *inbuf = inbuf_start; + UErrorCode status = U_ZERO_ERROR; + int len; + + ucnv_fromUnicode(conv, &outbuf, outbuf + outbuflen, &inbuf, inbuf + b, NULL, TRUE, &status); + len = u_countChar32(inbuf_start, inbuf - inbuf_start); + if (U_FAILURE(status)) { + /* Memory overflow isn't a problem becuase MAX_BYTES_FOR_STRING was allocated, + anything else is a more serious problem */ + zend_raise_conversion_error_ex("Unable to convert unicode character using output_encoding, at least one character was lost", + conv, ZEND_FROM_UNICODE, len, (UG(from_error_mode) & ZEND_CONV_ERROR_EXCEPTION) TSRMLS_CC); + } + if (outbuf > outbuf_start) { + PHPWRITE(outbuf_start, outbuf - outbuf_start); + count += len; + } + } + efree(outbuf_start); + } else { + char buf[8192]; + int b; + + while ((b = php_stream_read(stream, buf, sizeof(buf))) > 0) { + PHPWRITE(buf, b); + count += b; + } } - return bcount; + return count; }