summaryrefslogtreecommitdiff
path: root/ext/xmlreader/php_xmlreader.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/xmlreader/php_xmlreader.c')
-rw-r--r--ext/xmlreader/php_xmlreader.c180
1 files changed, 178 insertions, 2 deletions
diff --git a/ext/xmlreader/php_xmlreader.c b/ext/xmlreader/php_xmlreader.c
index 351da49..f4b3e32 100644
--- a/ext/xmlreader/php_xmlreader.c
+++ b/ext/xmlreader/php_xmlreader.c
@@ -47,6 +47,9 @@ typedef struct _xmlreader_prop_handler {
int type;
} xmlreader_prop_handler;
+#define XMLREADER_LOAD_STRING 0
+#define XMLREADER_LOAD_FILE 1
+
static void xmlreader_register_prop_handler(HashTable *prop_handler, char *name, xmlreader_read_int_t read_int_func, xmlreader_read_char_t read_char_func, int rettype TSRMLS_DC)
{
xmlreader_prop_handler hnd;
@@ -178,6 +181,97 @@ void xmlreader_write_property(zval *object, zval *member, zval *value TSRMLS_DC)
}
/* }}} */
+/* _xmlreader_get_valid_file_path and _xmlreader_get_relaxNG should be made a
+ common function in libxml extension as code is common to a few xml extensions */
+char *_xmlreader_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);
+
+ return file_dest;
+}
+
+#ifdef LIBXML_SCHEMAS_ENABLED
+static xmlRelaxNGPtr _xmlreader_get_relaxNG(char *source, int source_len, int type,
+ xmlRelaxNGValidityErrorFunc error_func,
+ xmlRelaxNGValidityWarningFunc warn_func TSRMLS_DC)
+{
+ char *valid_file = NULL;
+ xmlRelaxNGParserCtxtPtr parser = NULL;
+ xmlRelaxNGPtr sptr;
+ char resolved_path[MAXPATHLEN + 1];
+
+ switch (type) {
+ case XMLREADER_LOAD_FILE:
+ valid_file = _xmlreader_get_valid_file_path(source, resolved_path, MAXPATHLEN TSRMLS_CC);
+ if (!valid_file) {
+ return NULL;
+ }
+ parser = xmlRelaxNGNewParserCtxt(valid_file);
+ break;
+ case XMLREADER_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;
+ default:
+ return NULL;
+ }
+
+ if (parser == NULL) {
+ return NULL;
+ }
+
+ if (error_func || warn_func) {
+ xmlRelaxNGSetParserErrors(parser,
+ (xmlRelaxNGValidityErrorFunc) error_func,
+ (xmlRelaxNGValidityWarningFunc) warn_func,
+ parser);
+ }
+ sptr = xmlRelaxNGParse(parser);
+ xmlRelaxNGFreeParserCtxt(parser);
+
+ return sptr;
+}
+#endif
+
/* {{{ xmlreader_module_entry
*/
zend_module_entry xmlreader_module_entry = {
@@ -216,6 +310,12 @@ static void xmlreader_free_resources(xmlreader_object *intern) {
xmlFreeTextReader(intern->ptr);
intern->ptr = NULL;
}
+#ifdef LIBXML_SCHEMAS_ENABLED
+ if (intern->schema) {
+ xmlRelaxNGFree((xmlRelaxNGPtr) intern->schema);
+ intern->schema = NULL;
+ }
+#endif
}
}
@@ -246,6 +346,7 @@ zend_object_value xmlreader_objects_new(zend_class_entry *class_type TSRMLS_DC)
intern->std.in_set = 0;
intern->ptr = NULL;
intern->input = NULL;
+ intern->schema = NULL;
intern->prop_handler = &xmlreader_prop_handlers;
ALLOC_HASHTABLE(intern->std.properties);
@@ -329,6 +430,58 @@ static void php_xmlreader_no_arg_string(INTERNAL_FUNCTION_PARAMETERS, xmlreader_
}
*/
+static void php_xmlreader_set_relaxng_schema(INTERNAL_FUNCTION_PARAMETERS, int type) {
+#ifdef LIBXML_SCHEMAS_ENABLED
+ zval *id;
+ int source_len = 0, retval = -1;
+ xmlreader_object *intern;
+ xmlRelaxNGPtr schema = NULL;
+ char *source;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s!", &source, &source_len) == FAILURE) {
+ return;
+ }
+
+ if (source != NULL && !source_len) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Schema data source is requried");
+ RETURN_FALSE;
+ }
+
+ id = getThis();
+
+ intern = (xmlreader_object *)zend_object_store_get_object(id TSRMLS_CC);
+ if (intern && intern->ptr) {
+ if (source) {
+ schema = _xmlreader_get_relaxNG(source, source_len, type, NULL, NULL TSRMLS_CC);
+ if (schema) {
+ retval = xmlTextReaderRelaxNGSetSchema(intern->ptr, schema);
+ }
+ } else {
+ /* unset the associated relaxNG context and schema if one exists */
+ retval = xmlTextReaderRelaxNGSetSchema(intern->ptr, NULL);
+ }
+
+ if (retval == 0) {
+ if (intern->schema) {
+ xmlRelaxNGFree((xmlRelaxNGPtr) intern->schema);
+ }
+
+ intern->schema = schema;
+
+ RETURN_TRUE;
+ }
+ }
+
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to set schema. This must be set prior to reading or schema contains errors.");
+
+ RETURN_FALSE;
+#else
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "No Schema support built into libxml.");
+
+ RETURN_FALSE;
+#endif
+}
+
/* {{{ proto boolean close()
Closes xmlreader - current frees resources until xmlTextReaderClose is fixed in libxml */
PHP_METHOD(xmlreader, close)
@@ -610,7 +763,8 @@ PHP_METHOD(xmlreader, open)
zval *id;
int source_len = 0;
xmlreader_object *intern;
- char *source;
+ char *source, *valid_file = NULL;
+ char resolved_path[MAXPATHLEN + 1];
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &source, &source_len) == FAILURE) {
return;
@@ -627,7 +781,11 @@ PHP_METHOD(xmlreader, open)
xmlreader_free_resources(intern);
- intern->ptr = xmlNewTextReaderFilename(source);
+ valid_file = _xmlreader_get_valid_file_path(source, resolved_path, MAXPATHLEN TSRMLS_CC);
+
+ if (valid_file) {
+ intern->ptr = xmlNewTextReaderFilename(valid_file);
+ }
if (intern->ptr == NULL) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to open source data");
@@ -689,6 +847,22 @@ PHP_METHOD(xmlreader, setParserProperty)
}
/* }}} */
+/* {{{ proto boolean setRelaxNGSchemaSource(string filename)
+Sets the string that the the XMLReader will parse. */
+PHP_METHOD(xmlreader, setRelaxNGSchema)
+{
+ php_xmlreader_set_relaxng_schema(INTERNAL_FUNCTION_PARAM_PASSTHRU, XMLREADER_LOAD_FILE);
+}
+/* }}} */
+
+/* {{{ proto boolean setRelaxNGSchemaSource(string source)
+Sets the string that the the XMLReader will parse. */
+PHP_METHOD(xmlreader, setRelaxNGSchemaSource)
+{
+ php_xmlreader_set_relaxng_schema(INTERNAL_FUNCTION_PARAM_PASSTHRU, XMLREADER_LOAD_STRING);
+}
+/* }}} */
+
/* {{{ proto boolean XML(string source)
Sets the string that the the XMLReader will parse. */
PHP_METHOD(xmlreader, XML)
@@ -770,6 +944,8 @@ static zend_function_entry xmlreader_functions[] = {
PHP_ME(xmlreader, resetState, NULL, ZEND_ACC_PUBLIC)
*/
PHP_ME(xmlreader, setParserProperty, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(xmlreader, setRelaxNGSchema, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(xmlreader, setRelaxNGSchemaSource, NULL, ZEND_ACC_PUBLIC)
PHP_ME(xmlreader, XML, NULL, ZEND_ACC_PUBLIC)
{NULL, NULL, NULL}
};