conversions of filename entries.
Normal path conversions will simply use this converter,
Certain other protocols (such as http) which specify a
required character set (utf8), may override the conversion
by defining a path_encode() and/or path_decode() wrapper ops method.
STD_ZEND_INI_ENTRY("unicode.runtime_encoding", NULL, ZEND_INI_ALL, OnUpdateEncoding, runtime_encoding_conv, zend_unicode_globals, unicode_globals)
STD_ZEND_INI_ENTRY("unicode.script_encoding", NULL, ZEND_INI_ALL, OnUpdateEncoding, script_encoding_conv, zend_unicode_globals, unicode_globals)
STD_ZEND_INI_ENTRY("unicode.http_input_encoding", NULL, ZEND_INI_ALL, OnUpdateEncoding, http_input_encoding_conv, zend_unicode_globals, unicode_globals)
+ STD_ZEND_INI_ENTRY("unicode.filesystem_encoding", NULL, ZEND_INI_ALL, OnUpdateEncoding, filesystem_encoding_conv, zend_unicode_globals, unicode_globals)
ZEND_INI_END()
UConverter *output_encoding_conv; /* output layer converter */
UConverter *script_encoding_conv; /* default script encoding converter */
UConverter *http_input_encoding_conv;/* http input encoding converter */
+ UConverter *filesystem_encoding_conv;/* default filesystem converter (entries, not contents) */
UConverter *utf8_conv; /* all-purpose UTF-8 converter */
uint16_t from_error_mode;
}
/* }}} */
-/* {{{ proto resource fopen(string filename, string mode [, bool use_include_path [, resource context]])
+/* {{{ proto resource fopen(string filename, string mode [, bool use_include_path [, resource context]]) U
Open a file or a URL and return a file pointer */
PHP_NAMED_FUNCTION(php_if_fopen)
{
char *filename, *mode;
int filename_len, mode_len;
+ zend_uchar filename_type;
zend_bool use_include_path = 0;
zval *zcontext = NULL;
php_stream *stream;
php_stream_context *context = NULL;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|br", &filename, &filename_len,
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ts|br", &filename, &filename_len, &filename_type,
&mode, &mode_len, &use_include_path, &zcontext) == FAILURE) {
RETURN_FALSE;
}
context = php_stream_context_from_zval(zcontext, 0);
-
+
+ if (filename_type == IS_UNICODE) {
+ if (php_stream_path_encode(NULL, &filename, &filename_len, filename, filename_len, REPORT_ERRORS, context) == FAILURE) {
+ RETURN_FALSE;
+ }
+ }
stream = php_stream_open_wrapper_ex(filename, mode, (use_include_path ? USE_PATH : 0) | REPORT_ERRORS, NULL, context);
+ if (filename_type == IS_UNICODE) {
+ efree(filename);
+ }
if (stream == NULL) {
RETURN_FALSE;
}
/* Create/Remove directory */
int (*stream_mkdir)(php_stream_wrapper *wrapper, char *url, int mode, int options, php_stream_context *context TSRMLS_DC);
int (*stream_rmdir)(php_stream_wrapper *wrapper, char *url, int options, php_stream_context *context TSRMLS_DC);
+
+ /* Unicode path manipulation -- Leave NULL to use UG(filesystem_encoding_conv) for conversion */
+ int (*path_encode)(php_stream_wrapper *wrapper, char **encpath, int *encpath_len, UChar *path, int path_len,
+ int options, php_stream_context *context TSRMLS_DC);
+ int (*path_decode)(php_stream_wrapper *wrapper, UChar **decpath, int *decpath_len, char *path, int path_len,
+ int options, php_stream_context *context TSRMLS_DC);
} php_stream_wrapper_ops;
struct _php_stream_wrapper {
#define php_stream_set_chunk_size(stream, size) _php_stream_set_option((stream), PHP_STREAM_OPTION_SET_CHUNK_SIZE, (size), NULL TSRMLS_CC)
+PHPAPI int _php_stream_path_encode(php_stream_wrapper *wrapper,
+ char **pathenc, int *pathenc_len, UChar *path, int path_len,
+ int options, php_stream_context *context TSRMLS_DC);
+#define php_stream_path_encode(wrapper, pathenc, pathenc_len, path, path_len, options, context) \
+ _php_stream_path_encode((wrapper), (pathenc), (pathenc_len), (path), (path_len), (options), (context) TSRMLS_CC)
+
+PHPAPI int _php_stream_path_decode(php_stream_wrapper *wrapper,
+ char **pathdec, int *pathdec_len, UChar *path, int path_len,
+ int options, php_stream_context *context TSRMLS_DC);
+#define php_stream_path_decode(wrapper, pathdec, pathdec_len, path, path_len, options, context) \
+ _php_stream_path_decode((wrapper), (pathdec), (pathdec_len), (path), (path_len), (options), (context) TSRMLS_CC)
+
END_EXTERN_C()
}
/* }}} */
+/* {{{ php_stream_path_encode
+Encode a filepath to the appropriate characterset.
+If the wrapper supports its own encoding rules it will be dispatched to wrapper->wops->path_encode()
+Otherwise the INI defined filesystem_encoding converter will be used
+If wrapper == NULL, the path will be explored to locate the correct wrapper
+*/
+PHPAPI int _php_stream_path_encode(php_stream_wrapper *wrapper,
+ char **pathenc, int *pathenc_len, UChar *path, int path_len,
+ int options, php_stream_context *context TSRMLS_DC)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ int num_conv;
+
+ if (!wrapper) {
+ UChar *p;
+ U_STRING_DECL(delim, "://", 3);
+ int delim_len = 3;
+
+ U_STRING_INIT(delim, "://", 3);
+
+ p = u_strFindFirst(path, path_len, delim, delim_len);
+ if (p) {
+ char *scheme = NULL;
+ int scheme_len = 0;
+
+ /* Convert just the scheme using utf8 in order to look it up in the registry */
+ num_conv = zend_convert_from_unicode(UG(utf8_conv), &scheme, &scheme_len, path, (p - path) + delim_len, &status);
+ if (U_FAILURE(status)) {
+ if (options & REPORT_ERRORS) {
+ zend_raise_conversion_error_ex("Unable to convert filepath", UG(utf8_conv), ZEND_FROM_UNICODE,
+ num_conv, (UG(from_error_mode) & ZEND_CONV_ERROR_EXCEPTION) TSRMLS_CC);
+ }
+ *pathenc = NULL;
+ *pathenc_len = 0;
+
+ return FAILURE;
+ }
+ wrapper = php_stream_locate_url_wrapper(scheme, NULL, options TSRMLS_CC);
+ efree(scheme);
+ if (!wrapper) {
+ *pathenc = NULL;
+ *pathenc_len = 0;
+
+ return FAILURE;
+ }
+ } else {
+ wrapper = &php_plain_files_wrapper;
+ }
+ }
+
+ if (wrapper->wops->path_encode) {
+ if (wrapper->wops->path_encode(wrapper, pathenc, pathenc_len, path, path_len, options, context TSRMLS_CC) == FAILURE) {
+ *pathenc = NULL;
+ *pathenc_len = 0;
+
+ return FAILURE;
+ }
+
+ return SUCCESS;
+ }
+
+ /* Otherwise, fallback on filesystem_encoding */
+ status = U_ZERO_ERROR;
+
+ num_conv = zend_convert_from_unicode(ZEND_U_CONVERTER(UG(filesystem_encoding_conv)),
+ pathenc, pathenc_len, path, path_len, &status);
+ if (U_FAILURE(status)) {
+ if (options & REPORT_ERRORS) {
+ zend_raise_conversion_error_ex("Unable to convert filepath", ZEND_U_CONVERTER(UG(filesystem_encoding_conv)),
+ ZEND_FROM_UNICODE, num_conv, (UG(from_error_mode) & ZEND_CONV_ERROR_EXCEPTION) TSRMLS_CC);
+ }
+
+ *pathenc = NULL;
+ *pathenc_len = 0;
+
+ return FAILURE;
+ }
+
+ return SUCCESS;
+}
+/* }}} */
+
+
+/* {{{ php_stream_path_decode
+Decode a filepath from its character set to unicode
+If the wrapper supports its own decoding rules it will be dispatched to wrapper->wops->path_encode()
+Otherwise (or if wrapper == NULL) the INI defined filesystem_encoding converter will be used.
+*/
+PHPAPI int _php_stream_path_decode(php_stream_wrapper *wrapper,
+ char **pathdec, int *pathdec_len, UChar *path, int path_len,
+ int options, php_stream_context *context TSRMLS_DC)
+{
+ int num_conv;
+ UErrorCode status = U_ZERO_ERROR;
+
+ if (wrapper && wrapper->wops->path_decode) {
+ if (wrapper->wops->path_decode(wrapper, pathdec, pathdec_len, path, path_len, options, context TSRMLS_CC) == FAILURE) {
+ *pathdec = NULL;
+ *pathdec_len = 0;
+
+ return FAILURE;
+ }
+ return SUCCESS;
+ }
+
+ /* Otherwise fallback on filesystem_encoding */
+ num_conv = zend_convert_to_unicode(ZEND_U_CONVERTER(UG(filesystem_encoding_conv)),
+ pathdec, pathdec_len, path, path_len, &status);
+ if (U_FAILURE(status)) {
+ if (options & REPORT_ERRORS) {
+ zend_raise_conversion_error_ex("Unable to convert filepath", ZEND_U_CONVERTER(UG(filesystem_encoding_conv)),
+ ZEND_TO_UNICODE, num_conv, (UG(to_error_mode) & ZEND_CONV_ERROR_EXCEPTION) TSRMLS_CC);
+ }
+
+ *pathdec = NULL;
+ *pathdec_len = 0;
+
+ return FAILURE;
+ }
+
+ return SUCCESS;
+
+}
+/* }}} */
+
/*
* Local variables:
* tab-width: 4