diff options
author | Gustavo André dos Santos Lopes <cataphract@php.net> | 2011-08-29 05:00:26 +0000 |
---|---|---|
committer | Gustavo André dos Santos Lopes <cataphract@php.net> | 2011-08-29 05:00:26 +0000 |
commit | 0d7e6a73d6753a825cdde1abc508fad8ca456024 (patch) | |
tree | 94028ecd3613b179cfe307b95838731ef79051af /ext/libxml/libxml.c | |
parent | 402c8cb70e2859daaba24bbb49a1fff7bf43795d (diff) | |
download | php-git-0d7e6a73d6753a825cdde1abc508fad8ca456024.tar.gz |
- Added libxml_set_external_entity_loader().
Diffstat (limited to 'ext/libxml/libxml.c')
-rw-r--r-- | ext/libxml/libxml.c | 177 |
1 files changed, 174 insertions, 3 deletions
diff --git a/ext/libxml/libxml.c b/ext/libxml/libxml.c index 25988a6d60..9863043b5d 100644 --- a/ext/libxml/libxml.c +++ b/ext/libxml/libxml.c @@ -70,6 +70,7 @@ static PHP_FUNCTION(libxml_use_internal_errors); static PHP_FUNCTION(libxml_get_last_error); static PHP_FUNCTION(libxml_clear_errors); static PHP_FUNCTION(libxml_get_errors); +static PHP_FUNCTION(libxml_set_external_entity_loader); static PHP_FUNCTION(libxml_disable_entity_loader); static zend_class_entry *libxmlerror_class_entry; @@ -111,6 +112,9 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_libxml_disable_entity_loader, 0, 0, 0) ZEND_ARG_INFO(0, disable) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_INFO_EX(arginfo_libxml_set_external_entity_loader, 0, 0, 1) + ZEND_ARG_INFO(0, resolver_function) +ZEND_END_ARG_INFO() /* }}} */ /* {{{ extension definition structures */ @@ -121,6 +125,7 @@ static const zend_function_entry libxml_functions[] = { PHP_FE(libxml_clear_errors, arginfo_libxml_clear_errors) PHP_FE(libxml_get_errors, arginfo_libxml_get_errors) PHP_FE(libxml_disable_entity_loader, arginfo_libxml_disable_entity_loader) + PHP_FE(libxml_set_external_entity_loader, arginfo_libxml_set_external_entity_loader) PHP_FE_END }; @@ -263,6 +268,19 @@ static PHP_GINIT_FUNCTION(libxml) 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; +} + +static void _php_libxml_destroy_fci(zend_fcall_info *fci) +{ + if (fci->size > 0) { + zval_ptr_dtor(&fci->function_name); + if (fci->object_ptr != NULL) { + zval_ptr_dtor(&fci->object_ptr); + } + fci->size = 0; + } } /* Channel libxml file io layer through the PHP streams subsystem. @@ -280,8 +298,9 @@ static void *php_libxml_streams_IO_open_wrapper(const char *filename, const char TSRMLS_FETCH(); - uri = xmlParseURI((xmlChar *)filename); - if (uri && (uri->scheme == NULL || (xmlStrncmp(uri->scheme, "file", 4) == 0))) { + uri = xmlParseURI(filename); + if (uri && (uri->scheme == NULL || + (xmlStrncmp(BAD_CAST uri->scheme, BAD_CAST "file", 4) == 0))) { resolved_path = xmlURIUnescapeString(filename, 0, NULL); isescaped = 1; } else { @@ -669,7 +688,7 @@ static PHP_MINIT_FUNCTION(libxml) xmlParserInputBufferCreateFilenameDefault(php_libxml_input_buffer_create_filename); xmlOutputBufferCreateFilenameDefault(php_libxml_output_buffer_create_filename); } - + return SUCCESS; } @@ -723,6 +742,8 @@ static PHP_RSHUTDOWN_FUNCTION(libxml) LIBXML(error_list) = NULL; } xmlResetLastError(); + + _php_libxml_destroy_fci(&LIBXML(entity_loader).fci); return SUCCESS; } @@ -905,6 +926,156 @@ static PHP_FUNCTION(libxml_disable_entity_loader) } /* }}} */ +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; + TSRMLS_FETCH(); + zend_fcall_info *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) +{ + zend_fcall_info fci; + zend_fcall_info_cache fcc; + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "f!", &fci, &fcc) + == FAILURE) { + return; + } + + 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; +} +/* }}} */ + /* {{{ Common functions shared by extensions */ int php_libxml_xmlCheckUTF8(const unsigned char *s) { |