cataphract Tue, 30 Aug 2011 01:08:22 +0000 Revision: http://svn.php.net/viewvc?view=revision&revision=315752
Log: - Turns out the external entity loader is not a per-thread global but a true global. Changed code accordingly; however, applications that embed PHP and also use libxml2 may be affected negatively. Changed paths: U php/php-src/branches/PHP_5_4/ext/libxml/libxml.c U php/php-src/branches/PHP_5_4/ext/libxml/php_libxml.h U php/php-src/trunk/ext/libxml/libxml.c U php/php-src/trunk/ext/libxml/php_libxml.h
Modified: php/php-src/branches/PHP_5_4/ext/libxml/libxml.c =================================================================== --- php/php-src/branches/PHP_5_4/ext/libxml/libxml.c 2011-08-30 00:53:28 UTC (rev 315751) +++ php/php-src/branches/PHP_5_4/ext/libxml/libxml.c 2011-08-30 01:08:22 UTC (rev 315752) @@ -55,6 +55,7 @@ /* a true global for initialization */ static int _php_libxml_initialized = 0; static int _php_libxml_per_request_initialization = 1; +static xmlExternalEntityLoader _php_libxml_default_entity_loader; typedef struct _php_libxml_func_handler { php_libxml_export_node export_func; @@ -268,7 +269,6 @@ libxml_globals->stream_context = NULL; libxml_globals->error_buffer.c = NULL; libxml_globals->error_list = NULL; - libxml_globals->defaultEntityLoader = NULL; libxml_globals->entity_loader.fci.size = 0; } @@ -549,6 +549,131 @@ } } +static xmlParserInputPtr _php_libxml_external_entity_loader(const char *URL, + const char *ID, xmlParserCtxtPtr context) +{ + xmlParserInputPtr ret = NULL; + const char *resource = NULL; + zval *public = NULL, + *system = NULL, + *ctxzv = NULL, + **params[] = {&public, &system, &ctxzv}, + *retval_ptr = NULL; + int retval; + zend_fcall_info *fci; + TSRMLS_FETCH(); + + fci = &LIBXML(entity_loader).fci; + + if (fci->size == 0) { + /* no custom user-land callback set up; delegate to original loader */ + return _php_libxml_default_entity_loader(URL, ID, context); + } + + ALLOC_INIT_ZVAL(public); + if (ID != NULL) { + ZVAL_STRING(public, ID, 1); + } + ALLOC_INIT_ZVAL(system); + if (URL != NULL) { + ZVAL_STRING(system, URL, 1); + } + MAKE_STD_ZVAL(ctxzv); + array_init_size(ctxzv, 4); + +#define ADD_NULL_OR_STRING_KEY(memb) \ + if (context->memb == NULL) { \ + add_assoc_null_ex(ctxzv, #memb, sizeof(#memb)); \ + } else { \ + add_assoc_string_ex(ctxzv, #memb, sizeof(#memb), \ + (char *)context->memb, 1); \ + } + + ADD_NULL_OR_STRING_KEY(directory) + ADD_NULL_OR_STRING_KEY(intSubName) + ADD_NULL_OR_STRING_KEY(extSubURI) + ADD_NULL_OR_STRING_KEY(extSubSystem) + +#undef ADD_NULL_OR_STRING_KEY + + fci->retval_ptr_ptr = &retval_ptr; + fci->params = params; + fci->param_count = sizeof(params)/sizeof(*params); + fci->no_separation = 1; + + retval = zend_call_function(fci, &LIBXML(entity_loader).fcc TSRMLS_CC); + if (retval != SUCCESS || fci->retval_ptr_ptr == NULL) { + php_libxml_ctx_error(context, + "Call to user entity loader callback '%s' has failed", + fci->function_name); + } else { + retval_ptr = *fci->retval_ptr_ptr; + if (retval_ptr == NULL) { + php_libxml_ctx_error(context, + "Call to user entity loader callback '%s' has failed; " + "probably it has thrown an exception", + fci->function_name); + } else if (Z_TYPE_P(retval_ptr) == IS_STRING) { +is_string: + resource = Z_STRVAL_P(retval_ptr); + } else if (Z_TYPE_P(retval_ptr) == IS_RESOURCE) { + php_stream *stream; + php_stream_from_zval_no_verify(stream, &retval_ptr); + if (stream == NULL) { + php_libxml_ctx_error(context, + "The user entity loader callback '%s' has returned a " + "resource, but it is not a stream", + fci->function_name); + } else { + /* TODO: allow storing the encoding in the stream context? */ + xmlCharEncoding enc = XML_CHAR_ENCODING_NONE; + xmlParserInputBufferPtr pib = xmlAllocParserInputBuffer(enc); + if (pib == NULL) { + php_libxml_ctx_error(context, "Could not allocate parser " + "input buffer"); + } else { + /* make stream not being closed when the zval is freed */ + zend_list_addref(stream->rsrc_id); + pib->context = stream; + pib->readcallback = php_libxml_streams_IO_read; + pib->closecallback = php_libxml_streams_IO_close; + + ret = xmlNewIOInputStream(context, pib, enc); + if (ret == NULL) { + xmlFreeParserInputBuffer(pib); + } + } + } + } else if (Z_TYPE_P(retval_ptr) != IS_NULL) { + /* retval not string nor resource nor null; convert to string */ + SEPARATE_ZVAL(&retval_ptr); + convert_to_string(retval_ptr); + goto is_string; + } /* else is null; don't try anything */ + } + + if (ret == NULL) { + if (resource == NULL) { + if (ID == NULL) { + ID = "NULL"; + } + php_libxml_ctx_error(context, + "Failed to load external entity \"%s\"\n", ID); + } else { + /* we got the resource in the form of a string; open it */ + ret = xmlNewInputFromFile(context, resource); + } + } + + zval_ptr_dtor(&public); + zval_ptr_dtor(&system); + zval_ptr_dtor(&ctxzv); + if (retval_ptr != NULL) { + zval_ptr_dtor(&retval_ptr); + } + return ret; +} + PHP_LIBXML_API void php_libxml_ctx_error(void *ctx, const char *msg, ...) { va_list args; @@ -586,6 +711,9 @@ if (!_php_libxml_initialized) { /* we should be the only one's to ever init!! */ xmlInitParser(); + + _php_libxml_default_entity_loader = xmlGetExternalEntityLoader(); + xmlSetExternalEntityLoader(_php_libxml_external_entity_loader); zend_hash_init(&php_libxml_exports, 0, NULL, NULL, 1); @@ -926,126 +1054,6 @@ } /* }}} */ -static xmlParserInputPtr _php_libxml_user_entity_loader(const char *URL, - const char *ID, xmlParserCtxtPtr context) -{ - xmlParserInputPtr ret = NULL; - const char *resource = NULL; - zval *public = NULL, - *system = NULL, - *ctxzv = NULL, - **params[] = {&public, &system, &ctxzv}, - *retval_ptr = NULL; - int retval; - zend_fcall_info *fci; - TSRMLS_FETCH(); - - fci = &LIBXML(entity_loader).fci; - - ALLOC_INIT_ZVAL(public); - if (ID != NULL) { - ZVAL_STRING(public, ID, 1); - } - ALLOC_INIT_ZVAL(system); - if (URL != NULL) { - ZVAL_STRING(system, URL, 1); - } - MAKE_STD_ZVAL(ctxzv); - array_init_size(ctxzv, 4); - -#define ADD_NULL_OR_STRING_KEY(memb) \ - if (context->memb == NULL) { \ - add_assoc_null_ex(ctxzv, #memb, sizeof(#memb)); \ - } else { \ - add_assoc_string_ex(ctxzv, #memb, sizeof(#memb), \ - (char *)context->memb, 1); \ - } - - ADD_NULL_OR_STRING_KEY(directory) - ADD_NULL_OR_STRING_KEY(intSubName) - ADD_NULL_OR_STRING_KEY(extSubURI) - ADD_NULL_OR_STRING_KEY(extSubSystem) - -#undef ADD_NULL_OR_STRING_KEY - - fci->retval_ptr_ptr = &retval_ptr; - fci->params = params; - fci->param_count = sizeof(params)/sizeof(*params); - fci->no_separation = 1; - - retval = zend_call_function(fci, &LIBXML(entity_loader).fcc TSRMLS_CC); - if (retval != SUCCESS || fci->retval_ptr_ptr == NULL) { - php_libxml_ctx_error(context, - "Call to user entity loader callback '%s' has failed", - fci->function_name); - } else { - retval_ptr = *fci->retval_ptr_ptr; - if (retval_ptr == NULL) { - php_libxml_ctx_error(context, - "Call to user entity loader callback '%s' has failed; " - "probably it has thrown an exception", - fci->function_name); - } else if (Z_TYPE_P(retval_ptr) == IS_STRING) { -is_string: - resource = Z_STRVAL_P(retval_ptr); - } else if (Z_TYPE_P(retval_ptr) == IS_RESOURCE) { - php_stream *stream; - php_stream_from_zval_no_verify(stream, &retval_ptr); - if (stream == NULL) { - php_libxml_ctx_error(context, - "The user entity loader callback '%s' has returned a " - "resource, but it is not a stream", - fci->function_name); - } else { - /* TODO: allow storing the encoding in the stream context? */ - xmlCharEncoding enc = XML_CHAR_ENCODING_NONE; - xmlParserInputBufferPtr pib = xmlAllocParserInputBuffer(enc); - if (pib == NULL) { - php_libxml_ctx_error(context, "Could not allocate parser " - "input buffer"); - } else { - /* make stream not being closed when the zval is freed */ - zend_list_addref(stream->rsrc_id); - pib->context = stream; - pib->readcallback = php_libxml_streams_IO_read; - pib->closecallback = php_libxml_streams_IO_close; - - ret = xmlNewIOInputStream(context, pib, enc); - if (ret == NULL) { - xmlFreeParserInputBuffer(pib); - } - } - } - } else if (Z_TYPE_P(retval_ptr) != IS_NULL) { - /* retval not string nor resource nor null; convert to string */ - SEPARATE_ZVAL(&retval_ptr); - convert_to_string(retval_ptr); - goto is_string; - } /* else is null; don't try anything */ - } - - if (ret == NULL) { - if (resource == NULL) { - if (ID == NULL) { - ID = "NULL"; - } - php_libxml_ctx_error(context, - "Failed to load external entity \"%s\"\n", ID); - } else { - /* we got the resource in the form of a string; open it */ - ret = xmlNewInputFromFile(context, resource); - } - } - - zval_ptr_dtor(&public); - zval_ptr_dtor(&system); - zval_ptr_dtor(&ctxzv); - if (retval_ptr != NULL) { - zval_ptr_dtor(&retval_ptr); - } - return ret; -} - /* {{{ proto void libxml_set_external_entity_loader(callback resolver_function) Changes the default external entity loader */ static PHP_FUNCTION(libxml_set_external_entity_loader) @@ -1057,21 +1065,15 @@ return; } + _php_libxml_destroy_fci(&LIBXML(entity_loader).fci); + if (fci.size > 0) { /* argument not null */ - /* save for later invocations with NULL */ - if (LIBXML(defaultEntityLoader) == NULL) { - LIBXML(defaultEntityLoader) = xmlGetExternalEntityLoader(); - } - _php_libxml_destroy_fci(&LIBXML(entity_loader).fci); LIBXML(entity_loader).fci = fci; Z_ADDREF_P(fci.function_name); if (fci.object_ptr != NULL) { Z_ADDREF_P(fci.object_ptr); } LIBXML(entity_loader).fcc = fcc; - xmlSetExternalEntityLoader(_php_libxml_user_entity_loader); - } else { - xmlSetExternalEntityLoader(LIBXML(defaultEntityLoader)); } RETURN_TRUE; Modified: php/php-src/branches/PHP_5_4/ext/libxml/php_libxml.h =================================================================== --- php/php-src/branches/PHP_5_4/ext/libxml/php_libxml.h 2011-08-30 00:53:28 UTC (rev 315751) +++ php/php-src/branches/PHP_5_4/ext/libxml/php_libxml.h 2011-08-30 01:08:22 UTC (rev 315752) @@ -43,7 +43,6 @@ zval *stream_context; smart_str error_buffer; zend_llist *error_list; - xmlExternalEntityLoader defaultEntityLoader; /* saved here to allow it restored */ struct _php_libxml_entity_resolver { zend_fcall_info fci; zend_fcall_info_cache fcc; Modified: php/php-src/trunk/ext/libxml/libxml.c =================================================================== --- php/php-src/trunk/ext/libxml/libxml.c 2011-08-30 00:53:28 UTC (rev 315751) +++ php/php-src/trunk/ext/libxml/libxml.c 2011-08-30 01:08:22 UTC (rev 315752) @@ -55,6 +55,7 @@ /* a true global for initialization */ static int _php_libxml_initialized = 0; static int _php_libxml_per_request_initialization = 1; +static xmlExternalEntityLoader _php_libxml_default_entity_loader; typedef struct _php_libxml_func_handler { php_libxml_export_node export_func; @@ -268,7 +269,6 @@ libxml_globals->stream_context = NULL; libxml_globals->error_buffer.c = NULL; libxml_globals->error_list = NULL; - libxml_globals->defaultEntityLoader = NULL; libxml_globals->entity_loader.fci.size = 0; } @@ -549,6 +549,131 @@ } } +static xmlParserInputPtr _php_libxml_external_entity_loader(const char *URL, + const char *ID, xmlParserCtxtPtr context) +{ + xmlParserInputPtr ret = NULL; + const char *resource = NULL; + zval *public = NULL, + *system = NULL, + *ctxzv = NULL, + **params[] = {&public, &system, &ctxzv}, + *retval_ptr = NULL; + int retval; + zend_fcall_info *fci; + TSRMLS_FETCH(); + + fci = &LIBXML(entity_loader).fci; + + if (fci->size == 0) { + /* no custom user-land callback set up; delegate to original loader */ + return _php_libxml_default_entity_loader(URL, ID, context); + } + + ALLOC_INIT_ZVAL(public); + if (ID != NULL) { + ZVAL_STRING(public, ID, 1); + } + ALLOC_INIT_ZVAL(system); + if (URL != NULL) { + ZVAL_STRING(system, URL, 1); + } + MAKE_STD_ZVAL(ctxzv); + array_init_size(ctxzv, 4); + +#define ADD_NULL_OR_STRING_KEY(memb) \ + if (context->memb == NULL) { \ + add_assoc_null_ex(ctxzv, #memb, sizeof(#memb)); \ + } else { \ + add_assoc_string_ex(ctxzv, #memb, sizeof(#memb), \ + (char *)context->memb, 1); \ + } + + ADD_NULL_OR_STRING_KEY(directory) + ADD_NULL_OR_STRING_KEY(intSubName) + ADD_NULL_OR_STRING_KEY(extSubURI) + ADD_NULL_OR_STRING_KEY(extSubSystem) + +#undef ADD_NULL_OR_STRING_KEY + + fci->retval_ptr_ptr = &retval_ptr; + fci->params = params; + fci->param_count = sizeof(params)/sizeof(*params); + fci->no_separation = 1; + + retval = zend_call_function(fci, &LIBXML(entity_loader).fcc TSRMLS_CC); + if (retval != SUCCESS || fci->retval_ptr_ptr == NULL) { + php_libxml_ctx_error(context, + "Call to user entity loader callback '%s' has failed", + fci->function_name); + } else { + retval_ptr = *fci->retval_ptr_ptr; + if (retval_ptr == NULL) { + php_libxml_ctx_error(context, + "Call to user entity loader callback '%s' has failed; " + "probably it has thrown an exception", + fci->function_name); + } else if (Z_TYPE_P(retval_ptr) == IS_STRING) { +is_string: + resource = Z_STRVAL_P(retval_ptr); + } else if (Z_TYPE_P(retval_ptr) == IS_RESOURCE) { + php_stream *stream; + php_stream_from_zval_no_verify(stream, &retval_ptr); + if (stream == NULL) { + php_libxml_ctx_error(context, + "The user entity loader callback '%s' has returned a " + "resource, but it is not a stream", + fci->function_name); + } else { + /* TODO: allow storing the encoding in the stream context? */ + xmlCharEncoding enc = XML_CHAR_ENCODING_NONE; + xmlParserInputBufferPtr pib = xmlAllocParserInputBuffer(enc); + if (pib == NULL) { + php_libxml_ctx_error(context, "Could not allocate parser " + "input buffer"); + } else { + /* make stream not being closed when the zval is freed */ + zend_list_addref(stream->rsrc_id); + pib->context = stream; + pib->readcallback = php_libxml_streams_IO_read; + pib->closecallback = php_libxml_streams_IO_close; + + ret = xmlNewIOInputStream(context, pib, enc); + if (ret == NULL) { + xmlFreeParserInputBuffer(pib); + } + } + } + } else if (Z_TYPE_P(retval_ptr) != IS_NULL) { + /* retval not string nor resource nor null; convert to string */ + SEPARATE_ZVAL(&retval_ptr); + convert_to_string(retval_ptr); + goto is_string; + } /* else is null; don't try anything */ + } + + if (ret == NULL) { + if (resource == NULL) { + if (ID == NULL) { + ID = "NULL"; + } + php_libxml_ctx_error(context, + "Failed to load external entity \"%s\"\n", ID); + } else { + /* we got the resource in the form of a string; open it */ + ret = xmlNewInputFromFile(context, resource); + } + } + + zval_ptr_dtor(&public); + zval_ptr_dtor(&system); + zval_ptr_dtor(&ctxzv); + if (retval_ptr != NULL) { + zval_ptr_dtor(&retval_ptr); + } + return ret; +} + PHP_LIBXML_API void php_libxml_ctx_error(void *ctx, const char *msg, ...) { va_list args; @@ -586,6 +711,9 @@ if (!_php_libxml_initialized) { /* we should be the only one's to ever init!! */ xmlInitParser(); + + _php_libxml_default_entity_loader = xmlGetExternalEntityLoader(); + xmlSetExternalEntityLoader(_php_libxml_external_entity_loader); zend_hash_init(&php_libxml_exports, 0, NULL, NULL, 1); @@ -926,126 +1054,6 @@ } /* }}} */ -static xmlParserInputPtr _php_libxml_user_entity_loader(const char *URL, - const char *ID, xmlParserCtxtPtr context) -{ - xmlParserInputPtr ret = NULL; - const char *resource = NULL; - zval *public = NULL, - *system = NULL, - *ctxzv = NULL, - **params[] = {&public, &system, &ctxzv}, - *retval_ptr = NULL; - int retval; - zend_fcall_info *fci; - TSRMLS_FETCH(); - - fci = &LIBXML(entity_loader).fci; - - ALLOC_INIT_ZVAL(public); - if (ID != NULL) { - ZVAL_STRING(public, ID, 1); - } - ALLOC_INIT_ZVAL(system); - if (URL != NULL) { - ZVAL_STRING(system, URL, 1); - } - MAKE_STD_ZVAL(ctxzv); - array_init_size(ctxzv, 4); - -#define ADD_NULL_OR_STRING_KEY(memb) \ - if (context->memb == NULL) { \ - add_assoc_null_ex(ctxzv, #memb, sizeof(#memb)); \ - } else { \ - add_assoc_string_ex(ctxzv, #memb, sizeof(#memb), \ - (char *)context->memb, 1); \ - } - - ADD_NULL_OR_STRING_KEY(directory) - ADD_NULL_OR_STRING_KEY(intSubName) - ADD_NULL_OR_STRING_KEY(extSubURI) - ADD_NULL_OR_STRING_KEY(extSubSystem) - -#undef ADD_NULL_OR_STRING_KEY - - fci->retval_ptr_ptr = &retval_ptr; - fci->params = params; - fci->param_count = sizeof(params)/sizeof(*params); - fci->no_separation = 1; - - retval = zend_call_function(fci, &LIBXML(entity_loader).fcc TSRMLS_CC); - if (retval != SUCCESS || fci->retval_ptr_ptr == NULL) { - php_libxml_ctx_error(context, - "Call to user entity loader callback '%s' has failed", - fci->function_name); - } else { - retval_ptr = *fci->retval_ptr_ptr; - if (retval_ptr == NULL) { - php_libxml_ctx_error(context, - "Call to user entity loader callback '%s' has failed; " - "probably it has thrown an exception", - fci->function_name); - } else if (Z_TYPE_P(retval_ptr) == IS_STRING) { -is_string: - resource = Z_STRVAL_P(retval_ptr); - } else if (Z_TYPE_P(retval_ptr) == IS_RESOURCE) { - php_stream *stream; - php_stream_from_zval_no_verify(stream, &retval_ptr); - if (stream == NULL) { - php_libxml_ctx_error(context, - "The user entity loader callback '%s' has returned a " - "resource, but it is not a stream", - fci->function_name); - } else { - /* TODO: allow storing the encoding in the stream context? */ - xmlCharEncoding enc = XML_CHAR_ENCODING_NONE; - xmlParserInputBufferPtr pib = xmlAllocParserInputBuffer(enc); - if (pib == NULL) { - php_libxml_ctx_error(context, "Could not allocate parser " - "input buffer"); - } else { - /* make stream not being closed when the zval is freed */ - zend_list_addref(stream->rsrc_id); - pib->context = stream; - pib->readcallback = php_libxml_streams_IO_read; - pib->closecallback = php_libxml_streams_IO_close; - - ret = xmlNewIOInputStream(context, pib, enc); - if (ret == NULL) { - xmlFreeParserInputBuffer(pib); - } - } - } - } else if (Z_TYPE_P(retval_ptr) != IS_NULL) { - /* retval not string nor resource nor null; convert to string */ - SEPARATE_ZVAL(&retval_ptr); - convert_to_string(retval_ptr); - goto is_string; - } /* else is null; don't try anything */ - } - - if (ret == NULL) { - if (resource == NULL) { - if (ID == NULL) { - ID = "NULL"; - } - php_libxml_ctx_error(context, - "Failed to load external entity \"%s\"\n", ID); - } else { - /* we got the resource in the form of a string; open it */ - ret = xmlNewInputFromFile(context, resource); - } - } - - zval_ptr_dtor(&public); - zval_ptr_dtor(&system); - zval_ptr_dtor(&ctxzv); - if (retval_ptr != NULL) { - zval_ptr_dtor(&retval_ptr); - } - return ret; -} - /* {{{ proto void libxml_set_external_entity_loader(callback resolver_function) Changes the default external entity loader */ static PHP_FUNCTION(libxml_set_external_entity_loader) @@ -1057,21 +1065,15 @@ return; } + _php_libxml_destroy_fci(&LIBXML(entity_loader).fci); + if (fci.size > 0) { /* argument not null */ - /* save for later invocations with NULL */ - if (LIBXML(defaultEntityLoader) == NULL) { - LIBXML(defaultEntityLoader) = xmlGetExternalEntityLoader(); - } - _php_libxml_destroy_fci(&LIBXML(entity_loader).fci); LIBXML(entity_loader).fci = fci; Z_ADDREF_P(fci.function_name); if (fci.object_ptr != NULL) { Z_ADDREF_P(fci.object_ptr); } LIBXML(entity_loader).fcc = fcc; - xmlSetExternalEntityLoader(_php_libxml_user_entity_loader); - } else { - xmlSetExternalEntityLoader(LIBXML(defaultEntityLoader)); } RETURN_TRUE; Modified: php/php-src/trunk/ext/libxml/php_libxml.h =================================================================== --- php/php-src/trunk/ext/libxml/php_libxml.h 2011-08-30 00:53:28 UTC (rev 315751) +++ php/php-src/trunk/ext/libxml/php_libxml.h 2011-08-30 01:08:22 UTC (rev 315752) @@ -43,7 +43,6 @@ zval *stream_context; smart_str error_buffer; zend_llist *error_list; - xmlExternalEntityLoader defaultEntityLoader; /* saved here to allow it restored */ struct _php_libxml_entity_resolver { zend_fcall_info fci; zend_fcall_info_cache fcc;
-- PHP CVS Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php