From 87bd7d57c64cf35456aa4b10316f353896904be2 Mon Sep 17 00:00:00 2001 From: Shane Caraveo Date: Sun, 5 Oct 2003 20:45:27 +0000 Subject: [PATCH] Add schema and relaxNG validation support domdocument->schemaValidate(string filename) domdocument->schemaValidateSource(string xml) domdocument->relaxNGValidate(string filename) domdocument->relaxNGValidateSource(string xml) also fix domelement->setAttributeNS --- ext/dom/document.c | 283 ++++++++++++++++++++++++++++------ ext/dom/dom_fe.h | 7 + ext/dom/element.c | 13 +- ext/dom/examples/relaxNG.php | 11 ++ ext/dom/examples/relaxNG.rng | 11 ++ ext/dom/examples/relaxNG.xml | 1 + ext/dom/examples/relaxNG2.rng | 23 +++ ext/dom/examples/relaxNG3.rng | 8 + ext/dom/examples/shipping.php | 11 ++ ext/dom/examples/shipping.xml | 21 +++ ext/dom/examples/shipping.xsd | 36 +++++ 11 files changed, 373 insertions(+), 52 deletions(-) create mode 100644 ext/dom/examples/relaxNG.php create mode 100644 ext/dom/examples/relaxNG.rng create mode 100644 ext/dom/examples/relaxNG.xml create mode 100644 ext/dom/examples/relaxNG2.rng create mode 100644 ext/dom/examples/relaxNG3.rng create mode 100644 ext/dom/examples/shipping.php create mode 100644 ext/dom/examples/shipping.xml create mode 100644 ext/dom/examples/shipping.xsd diff --git a/ext/dom/document.c b/ext/dom/document.c index 5b59dba232..e9e08a85db 100644 --- a/ext/dom/document.c +++ b/ext/dom/document.c @@ -27,6 +27,10 @@ #if HAVE_LIBXML && HAVE_DOM #include "php_dom.h" #include +#ifdef LIBXML_SCHEMAS_ENABLED +#include +#include +#endif typedef struct _idsIterator idsIterator; struct _idsIterator { @@ -83,6 +87,12 @@ zend_function_entry php_dom_document_class_functions[] = { PHP_FALIAS(saveHTML, dom_document_save_html, NULL) PHP_FALIAS(saveHTMLFile, dom_document_save_html_file, NULL) #endif /* defined(LIBXML_HTML_ENABLED) */ +#if defined(LIBXML_SCHEMAS_ENABLED) + PHP_FALIAS(schemaValidate, dom_document_schema_validate_file, NULL) + PHP_FALIAS(schemaValidateSource, dom_document_schema_validate_xml, NULL) + PHP_FALIAS(relaxNGValidate, dom_document_relaxNG_validate_file, NULL) + PHP_FALIAS(relaxNGValidateSource, dom_document_relaxNG_validate_xml, NULL) +#endif {NULL, NULL, NULL} }; @@ -1204,6 +1214,56 @@ PHP_FUNCTION(dom_document_document) } /* }}} end dom_document_document */ +char *_dom_get_valid_file_path(char *source, char *resolved_path, int resolved_path_len TSRMLS_DC) { + xmlURI *uri; + xmlChar *escsource; + char *file_dest; + int isFileUri = 0; + + uri = xmlCreateURI(); + escsource = xmlURIEscapeStr(source, ":"); + xmlParseURIReference(uri, escsource); + xmlFree(escsource); + + if (uri->scheme != NULL) { + /* absolute file uris - libxml only supports localhost or empty host */ + if (strncasecmp(source, "file:///",8) == 0) { + isFileUri = 1; +#ifdef PHP_WIN32 + source += 8; +#else + source += 7; +#endif + } else if (strncasecmp(source, "file://localhost/",17) == 0) { + isFileUri = 1; +#ifdef PHP_WIN32 + source += 17; +#else + source += 16; +#endif + } + } + + file_dest = source; + + if ((uri->scheme == NULL || isFileUri)) { + /* XXX possible buffer overflow if VCWD_REALPATH does not know size of resolved_path */ + if (! VCWD_REALPATH(source, resolved_path)) { + expand_filepath(source, resolved_path TSRMLS_CC); + } + file_dest = resolved_path; + } + + xmlFreeURI(uri); + + if ((PG(safe_mode) && (!php_checkuid(file_dest, NULL, CHECKUID_CHECK_FILE_AND_DIR))) || php_check_open_basedir(file_dest TSRMLS_CC)) { + return NULL; + } else { + return file_dest; + } +} + + /* {{{ */ static xmlDocPtr dom_document_parser(zval *id, int mode, char *source TSRMLS_DC) { xmlDocPtr ret; @@ -1235,50 +1295,8 @@ static xmlDocPtr dom_document_parser(zval *id, int mode, char *source TSRMLS_DC) keep_blanks = xmlKeepBlanksDefault(keep_blanks); if (mode == DOM_LOAD_FILE) { - - xmlURI *uri; - xmlChar *escsource; - char *file_dest; - int isFileUri = 0; - - uri = xmlCreateURI(); - escsource = xmlURIEscapeStr(source, ":"); - xmlParseURIReference(uri, escsource); - xmlFree(escsource); - - if (uri->scheme != NULL) { - /* absolute file uris - libxml only supports localhost or empty host */ - if (strncasecmp(source, "file:///",8) == 0) { - isFileUri = 1; -#ifdef PHP_WIN32 - source += 8; -#else - source += 7; -#endif - } else if (strncasecmp(source, "file://localhost/",17) == 0) { - isFileUri = 1; -#ifdef PHP_WIN32 - source += 17; -#else - source += 16; -#endif - } - } - - file_dest = source; - - if ((uri->scheme == NULL || isFileUri)) { - if (! VCWD_REALPATH(source, resolved_path)) { - expand_filepath(source, resolved_path TSRMLS_CC); - } - file_dest = resolved_path; - } - - xmlFreeURI(uri); - - if ((PG(safe_mode) && (!php_checkuid(file_dest, NULL, CHECKUID_CHECK_FILE_AND_DIR))) || php_check_open_basedir(file_dest TSRMLS_CC)) { - ctxt = NULL; - } else { + char *file_dest = _dom_get_valid_file_path(source, resolved_path, MAXPATHLEN TSRMLS_CC); + if (file_dest) { ctxt = xmlCreateFileParserCtxt(file_dest); } } else { @@ -1293,11 +1311,11 @@ static xmlDocPtr dom_document_parser(zval *id, int mode, char *source TSRMLS_DC) /* If loading from memory, we need to set the base directory for the document */ if (mode != DOM_LOAD_FILE) { - #if HAVE_GETCWD - directory = VCWD_GETCWD(resolved_path, MAXPATHLEN); - #elif HAVE_GETWD - directory = VCWD_GETWD(resolved_path); - #endif +#if HAVE_GETCWD + directory = VCWD_GETCWD(resolved_path, MAXPATHLEN); +#elif HAVE_GETWD + directory = VCWD_GETWD(resolved_path); +#endif if (directory) { if(ctxt->directory != NULL) { xmlFree((char *) ctxt->directory); @@ -1531,6 +1549,173 @@ PHP_FUNCTION(dom_document_validate) } /* }}} end dom_document_validate */ +#if defined(LIBXML_SCHEMAS_ENABLED) +static void +_dom_document_schema_validate(INTERNAL_FUNCTION_PARAMETERS, int type) +{ + zval *id; + xmlDoc *docp; + dom_object *intern; + char *source = NULL, *valid_file = NULL, *directory = NULL; + int source_len = 0; + xmlSchemaParserCtxtPtr parser; + xmlSchemaPtr sptr; + xmlSchemaValidCtxtPtr vptr; + int is_valid; + char resolved_path[MAXPATHLEN + 1]; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &source, &source_len) == FAILURE) { + return; + } + + DOM_GET_THIS_OBJ(docp, id, xmlDocPtr, intern); + + switch (type) { + case DOM_LOAD_FILE: + valid_file = _dom_get_valid_file_path(source, resolved_path, MAXPATHLEN TSRMLS_CC); + if (!valid_file) { + php_error(E_WARNING, "Invalid Schema file source"); + RETURN_FALSE; + } + parser = xmlSchemaNewParserCtxt(valid_file); + break; + case DOM_LOAD_STRING: + parser = xmlSchemaNewMemParserCtxt(source, source_len); + /* If loading from memory, we need to set the base directory for the document + but it is not apparent how to do that for schema's */ + break; + } + + xmlSchemaSetParserErrors(parser, + (xmlSchemaValidityErrorFunc) php_dom_validate_error, + (xmlSchemaValidityWarningFunc) php_dom_validate_error, + parser); + sptr = xmlSchemaParse(parser); + xmlSchemaFreeParserCtxt(parser); + if (!sptr) { + php_error(E_WARNING, "Invalid Schema"); + RETURN_FALSE; + } + + docp = (xmlDocPtr) dom_object_get_node(intern); + + vptr = xmlSchemaNewValidCtxt(sptr); + if (!vptr) { + xmlSchemaFree(sptr); + php_error(E_ERROR, "Invalid Schema Validation Context"); + RETURN_FALSE; + } + + xmlSchemaSetValidErrors(vptr, php_dom_validate_error, php_dom_validate_error, vptr); + is_valid = xmlSchemaValidateDoc(vptr, docp); + xmlSchemaFree(sptr); + xmlSchemaFreeValidCtxt(vptr); + + if (is_valid == 0) { + RETURN_TRUE; + } else { + RETURN_FALSE; + } +} + +/* {{{ proto boolean domnode _dom_document_schema_validate(string filename); */ +PHP_FUNCTION(dom_document_schema_validate_file) +{ + _dom_document_schema_validate(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_FILE); +} +/* }}} end _dom_document_schema_validate */ + +/* {{{ proto boolean domnode _dom_document_schema_validate(string source); */ +PHP_FUNCTION(dom_document_schema_validate_xml) +{ + _dom_document_schema_validate(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_STRING); +} +/* }}} end _dom_document_schema_validate */ + + +static void +_dom_document_relaxNG_validate(INTERNAL_FUNCTION_PARAMETERS, int type) +{ + zval *id; + xmlDoc *docp; + dom_object *intern; + char *source = NULL, *valid_file = NULL, *directory = NULL; + int source_len = 0; + xmlRelaxNGParserCtxtPtr parser; + xmlRelaxNGPtr sptr; + xmlRelaxNGValidCtxtPtr vptr; + int is_valid; + char resolved_path[MAXPATHLEN + 1]; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &source, &source_len) == FAILURE) { + return; + } + + DOM_GET_THIS_OBJ(docp, id, xmlDocPtr, intern); + + switch (type) { + case DOM_LOAD_FILE: + valid_file = _dom_get_valid_file_path(source, resolved_path, MAXPATHLEN TSRMLS_CC); + if (!valid_file) { + php_error(E_WARNING, "Invalid RelaxNG file source"); + RETURN_FALSE; + } + parser = xmlRelaxNGNewParserCtxt(valid_file); + break; + case DOM_LOAD_STRING: + parser = xmlRelaxNGNewMemParserCtxt(source, source_len); + /* If loading from memory, we need to set the base directory for the document + but it is not apparent how to do that for schema's */ + break; + } + + xmlRelaxNGSetParserErrors(parser, + (xmlRelaxNGValidityErrorFunc) php_dom_validate_error, + (xmlRelaxNGValidityWarningFunc) php_dom_validate_error, + parser); + sptr = xmlRelaxNGParse(parser); + xmlRelaxNGFreeParserCtxt(parser); + if (!sptr) { + php_error(E_WARNING, "Invalid RelaxNG"); + RETURN_FALSE; + } + + docp = (xmlDocPtr) dom_object_get_node(intern); + + vptr = xmlRelaxNGNewValidCtxt(sptr); + if (!vptr) { + xmlRelaxNGFree(sptr); + php_error(E_ERROR, "Invalid RelaxNG Validation Context"); + RETURN_FALSE; + } + + xmlRelaxNGSetValidErrors(vptr, php_dom_validate_error, php_dom_validate_error, vptr); + is_valid = xmlRelaxNGValidateDoc(vptr, docp); + xmlRelaxNGFree(sptr); + xmlRelaxNGFreeValidCtxt(vptr); + + if (is_valid == 0) { + RETURN_TRUE; + } else { + RETURN_FALSE; + } +} + +/* {{{ proto boolean domnode dom_document_relaxNG_validate_file(string filename); */ +PHP_FUNCTION(dom_document_relaxNG_validate_file) +{ + _dom_document_relaxNG_validate(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_FILE); +} +/* }}} end dom_document_relaxNG_validate_file */ + +/* {{{ proto boolean domnode dom_document_relaxNG_validate_xml(string source); */ +PHP_FUNCTION(dom_document_relaxNG_validate_xml) +{ + _dom_document_relaxNG_validate(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_STRING); +} +/* }}} end dom_document_relaxNG_validate_xml */ + +#endif #if defined(LIBXML_HTML_ENABLED) diff --git a/ext/dom/dom_fe.h b/ext/dom/dom_fe.h index b8406bee98..c5a8b450c3 100644 --- a/ext/dom/dom_fe.h +++ b/ext/dom/dom_fe.h @@ -134,6 +134,13 @@ PHP_FUNCTION(dom_document_save_html); PHP_FUNCTION(dom_document_save_html_file); #endif /* defined(LIBXML_HTML_ENABLED) */ +#if defined(LIBXML_SCHEMAS_ENABLED) +PHP_FUNCTION(dom_document_schema_validate_file); +PHP_FUNCTION(dom_document_schema_validate_xml); +PHP_FUNCTION(dom_document_relaxNG_validate_file); +PHP_FUNCTION(dom_document_relaxNG_validate_xml); +#endif + /* domnode methods */ PHP_FUNCTION(dom_node_insert_before); PHP_FUNCTION(dom_node_replace_child); diff --git a/ext/dom/element.c b/ext/dom/element.c index ceffc972f2..063b24e6d5 100644 --- a/ext/dom/element.c +++ b/ext/dom/element.c @@ -497,15 +497,16 @@ PHP_FUNCTION(dom_element_set_attribute_ns) zval *id, *rv = NULL; xmlNodePtr elemp, nodep = NULL; xmlNsPtr nsptr; - int ret, uri_len = 0, name_len = 0; - char *uri, *name; + xmlAttr *attr; + int ret, uri_len = 0, name_len = 0, value_len = 0; + char *uri, *name, *value; char *localname = NULL, *prefix = NULL; dom_object *intern; int errorcode = 0, stricterror; DOM_GET_THIS_OBJ(elemp, id, xmlNodePtr, intern); - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &uri, &uri_len, &name, &name_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sss", &uri, &uri_len, &name, &name_len, &value, &value_len) == FAILURE) { return; } @@ -538,6 +539,12 @@ PHP_FUNCTION(dom_element_set_attribute_ns) if (errorcode == 0) { nodep = (xmlNodePtr) xmlSetNsProp(elemp, nsptr, localname, NULL); } + + attr = xmlSetProp(nodep, localname, value); + if (!attr) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "No such attribute '%s'", localname); + RETURN_FALSE; + } } xmlFree(localname); diff --git a/ext/dom/examples/relaxNG.php b/ext/dom/examples/relaxNG.php new file mode 100644 index 0000000000..d265fd988e --- /dev/null +++ b/ext/dom/examples/relaxNG.php @@ -0,0 +1,11 @@ +load('relaxNG.xml'); +if (!$dom->relaxNGValidate('relaxNG.rng')) { + print "Document is not valid"; +} else { + print "Document is valid"; +} + +?> \ No newline at end of file diff --git a/ext/dom/examples/relaxNG.rng b/ext/dom/examples/relaxNG.rng new file mode 100644 index 0000000000..f4357e04ef --- /dev/null +++ b/ext/dom/examples/relaxNG.rng @@ -0,0 +1,11 @@ + + + + + + + + + + diff --git a/ext/dom/examples/relaxNG.xml b/ext/dom/examples/relaxNG.xml new file mode 100644 index 0000000000..6b0cac1225 --- /dev/null +++ b/ext/dom/examples/relaxNG.xml @@ -0,0 +1 @@ +hello \ No newline at end of file diff --git a/ext/dom/examples/relaxNG2.rng b/ext/dom/examples/relaxNG2.rng new file mode 100644 index 0000000000..4adae7b151 --- /dev/null +++ b/ext/dom/examples/relaxNG2.rng @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ext/dom/examples/relaxNG3.rng b/ext/dom/examples/relaxNG3.rng new file mode 100644 index 0000000000..73e1eb6165 --- /dev/null +++ b/ext/dom/examples/relaxNG3.rng @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/ext/dom/examples/shipping.php b/ext/dom/examples/shipping.php new file mode 100644 index 0000000000..5205fd2014 --- /dev/null +++ b/ext/dom/examples/shipping.php @@ -0,0 +1,11 @@ +load('shipping.xml'); +if (!$dom->schemaValidate('shipping.xsd')) { + print "Document is not valid"; +} else { + print "Document is valid"; +} + +?> \ No newline at end of file diff --git a/ext/dom/examples/shipping.xml b/ext/dom/examples/shipping.xml new file mode 100644 index 0000000000..dc8a09e301 --- /dev/null +++ b/ext/dom/examples/shipping.xml @@ -0,0 +1,21 @@ + + + + Tove Svendson + Ragnhildvei 2 +
4000 Stavanger
+ Norway +
+ + + Empire Burlesque + 1 + 10.90 + + + Hide your heart + 1 + 9.90 + + +
\ No newline at end of file diff --git a/ext/dom/examples/shipping.xsd b/ext/dom/examples/shipping.xsd new file mode 100644 index 0000000000..8b16b7c03a --- /dev/null +++ b/ext/dom/examples/shipping.xsd @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file -- 2.50.1