]> granicus.if.org Git - php/commitdiff
Update php_stream_passthru() to handle unicode data.
authorSara Golemon <pollita@php.net>
Wed, 29 Mar 2006 22:52:24 +0000 (22:52 +0000)
committerSara Golemon <pollita@php.net>
Wed, 29 Mar 2006 22:52:24 +0000 (22:52 +0000)
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).

ext/standard/file.c
main/streams/streams.c

index 048f23aa9f499b8884d8dcad5ca309feba7d9e31..bd1750bf55e78b684fa3c820f36a36f277a6a9ff 100644 (file)
@@ -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)
 {
index 4c25c53f2ef5d4b5fdeb87bfd20e3d7099efcd76..f9dbb8813645a024dccc52115c8ad8282bbe9459 100755 (executable)
@@ -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;
 }