shane Sun Oct 5 16:45:28 2003 EDT Added files: /php-src/ext/dom/examples relaxNG.php relaxNG.rng relaxNG.xml relaxNG2.rng relaxNG3.rng shipping.php shipping.xml shipping.xsd
Modified files: /php-src/ext/dom document.c dom_fe.h element.c Log: 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
Index: php-src/ext/dom/document.c diff -u php-src/ext/dom/document.c:1.28 php-src/ext/dom/document.c:1.29 --- php-src/ext/dom/document.c:1.28 Sun Oct 5 07:52:22 2003 +++ php-src/ext/dom/document.c Sun Oct 5 16:45:26 2003 @@ -17,7 +17,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: document.c,v 1.28 2003/10/05 11:52:22 rrichards Exp $ */ +/* $Id: document.c,v 1.29 2003/10/05 20:45:26 shane Exp $ */ #ifdef HAVE_CONFIG_H #include "config.h" @@ -27,6 +27,10 @@ #if HAVE_LIBXML && HAVE_DOM #include "php_dom.h" #include <libxml/SAX.h> +#ifdef LIBXML_SCHEMAS_ENABLED +#include <libxml/relaxng.h> +#include <libxml/xmlschemas.h> +#endif typedef struct _idsIterator idsIterator; struct _idsIterator { @@ -83,6 +87,12 @@ 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 @@ } /* }}} 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 @@ 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 @@ /* 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 @@ } /* }}} 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) Index: php-src/ext/dom/dom_fe.h diff -u php-src/ext/dom/dom_fe.h:1.5 php-src/ext/dom/dom_fe.h:1.6 --- php-src/ext/dom/dom_fe.h:1.5 Mon Sep 8 14:28:35 2003 +++ php-src/ext/dom/dom_fe.h Sun Oct 5 16:45:26 2003 @@ -17,7 +17,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: dom_fe.h,v 1.5 2003/09/08 18:28:35 rrichards Exp $ */ +/* $Id: dom_fe.h,v 1.6 2003/10/05 20:45:26 shane Exp $ */ #ifndef DOM_FE_H #define DOM_FE_H @@ -133,6 +133,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); Index: php-src/ext/dom/element.c diff -u php-src/ext/dom/element.c:1.14 php-src/ext/dom/element.c:1.15 --- php-src/ext/dom/element.c:1.14 Sun Oct 5 07:52:22 2003 +++ php-src/ext/dom/element.c Sun Oct 5 16:45:26 2003 @@ -17,7 +17,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: element.c,v 1.14 2003/10/05 11:52:22 rrichards Exp $ */ +/* $Id: element.c,v 1.15 2003/10/05 20:45:26 shane Exp $ */ #ifdef HAVE_CONFIG_H #include "config.h" @@ -497,15 +497,16 @@ 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; } @@ -537,6 +538,12 @@ 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; } } Index: php-src/ext/dom/examples/relaxNG.php +++ php-src/ext/dom/examples/relaxNG.php <?php $dom = new domDocument; $dom->load('relaxNG.xml'); if (!$dom->relaxNGValidate('relaxNG.rng')) { print "Document is not valid"; } else { print "Document is valid"; } ?> Index: php-src/ext/dom/examples/relaxNG.rng +++ php-src/ext/dom/examples/relaxNG.rng <?xml version="1.0" encoding="iso-8859-1"?> <grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"> <include href="relaxNG2.rng"> <define name="TEI.prose"><ref name="INCLUDE"/></define> </include> </grammar> Index: php-src/ext/dom/examples/relaxNG.xml +++ php-src/ext/dom/examples/relaxNG.xml <TEI.2>hello</TEI.2> Index: php-src/ext/dom/examples/relaxNG2.rng +++ php-src/ext/dom/examples/relaxNG2.rng <?xml version="1.0" encoding="utf-8"?> <grammar xmlns="http://relaxng.org/ns/structure/1.0" xmlns:t="http://www.thaiopensource.com/ns/annotations" xmlns:a="http://relaxng.org/ns/compatibility/annotations/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"> <start> <ref name="TEI.2"/> </start> <define name="IGNORE"> <notAllowed/> </define> <define name="INCLUDE"> <empty/> </define> <include href="relaxNG3.rng"/> <define name="TEI.2"> <element name="TEI.2"> <text/> </element> </define> </grammar> Index: php-src/ext/dom/examples/relaxNG3.rng +++ php-src/ext/dom/examples/relaxNG3.rng <?xml version="1.0" encoding="utf-8"?> <grammar xmlns="http://relaxng.org/ns/structure/1.0" xmlns:t="http://www.thaiopensource.com/ns/annotations" xmlns:a="http://relaxng.org/ns/compatibility/annotations/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"> <define name="TEI.prose" combine="interleave"> <ref name="IGNORE"/> </define> </grammar> Index: php-src/ext/dom/examples/shipping.php +++ php-src/ext/dom/examples/shipping.php <?php $dom = new domDocument; $dom->load('shipping.xml'); if (!$dom->schemaValidate('shipping.xsd')) { print "Document is not valid"; } else { print "Document is valid"; } ?> Index: php-src/ext/dom/examples/shipping.xml +++ php-src/ext/dom/examples/shipping.xml <?xml version="1.0"?> <shipOrder> <shipTo> <name>Tove Svendson</name> <street>Ragnhildvei 2</street> <address>4000 Stavanger</address> <country>Norway</country> </shipTo> <items> <item> <title>Empire Burlesque</title> <quantity>1</quantity> <price>10.90</price> </item> <item> <title>Hide your heart</title> <quantity>1</quantity> <price>9.90</price> </item> </items> </shipOrder> Index: php-src/ext/dom/examples/shipping.xsd +++ php-src/ext/dom/examples/shipping.xsd <?xml version="1.0"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:element name="shipOrder" type="order"/> <xsd:complexType name="order"> <xsd:all> <xsd:element name="shipTo" type="shipAddress"/> <xsd:element name="items" type="cdItems"/> </xsd:all> </xsd:complexType> <xsd:complexType name="shipAddress"> <xsd:all> <xsd:element name="name" type="xsd:string"/> <xsd:element name="street" type="xsd:string"/> <xsd:element name="address" type="xsd:string"/> <xsd:element name="country" type="xsd:string"/> </xsd:all> </xsd:complexType> <xsd:complexType name="cdItems"> <xsd:sequence> <xsd:element name="item" type="cdItem" maxOccurs="unbounded" minOccurs="1"/> </xsd:sequence> </xsd:complexType> <xsd:complexType name="cdItem"> <xsd:all> <xsd:element name="title" type="xsd:string"/> <xsd:element name="quantity" type="xsd:positiveInteger"/> <xsd:element name="price" type="xsd:decimal"/> </xsd:all> </xsd:complexType> </xsd:schema>
-- PHP CVS Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php