Blame view
sources/3rdparty/sabre/dav/lib/Sabre/DAV/XMLUtil.php
6.69 KB
|
03e52840d
|
1 |
<?php |
|
6d9380f96
|
2 |
namespace Sabre\DAV; |
|
03e52840d
|
3 4 5 |
/** * XML utilities for WebDAV * |
|
6d9380f96
|
6 7 8 |
* @copyright Copyright (C) 2007-2014 fruux GmbH (https://fruux.com/). * @author Evert Pot (http://evertpot.com/) * @license http://sabre.io/license/ Modified BSD License |
|
03e52840d
|
9 |
*/ |
|
6d9380f96
|
10 |
class XMLUtil {
|
|
03e52840d
|
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
/**
* Returns the 'clark notation' for an element.
*
* For example, and element encoded as:
* <b:myelem xmlns:b="http://www.example.org/" />
* will be returned as:
* {http://www.example.org}myelem
*
* This format is used throughout the SabreDAV sourcecode.
* Elements encoded with the urn:DAV namespace will
* be returned as if they were in the DAV: namespace. This is to avoid
* compatibility problems.
*
* This function will return null if a nodetype other than an Element is passed.
*
|
|
6d9380f96
|
27 |
* @param \DOMNode $dom |
|
03e52840d
|
28 29 |
* @return string
*/
|
|
6d9380f96
|
30 |
static function toClarkNotation(\DOMNode $dom) {
|
|
03e52840d
|
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
if ($dom->nodeType !== XML_ELEMENT_NODE) return null;
// Mapping back to the real namespace, in case it was dav
if ($dom->namespaceURI=='urn:DAV') $ns = 'DAV:'; else $ns = $dom->namespaceURI;
// Mapping to clark notation
return '{' . $ns . '}' . $dom->localName;
}
/**
* Parses a clark-notation string, and returns the namespace and element
* name components.
*
* If the string was invalid, it will throw an InvalidArgumentException.
*
* @param string $str
* @throws InvalidArgumentException
* @return array
*/
static function parseClarkNotation($str) {
if (!preg_match('/^{([^}]*)}(.*)$/',$str,$matches)) {
|
|
6d9380f96
|
55 |
throw new \InvalidArgumentException('\'' . $str . '\' is not a valid clark-notation formatted string');
|
|
03e52840d
|
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
}
return array(
$matches[1],
$matches[2]
);
}
/**
* This method takes an XML document (as string) and converts all instances of the
* DAV: namespace to urn:DAV
*
* This is unfortunately needed, because the DAV: namespace violates the xml namespaces
* spec, and causes the DOM to throw errors
*
* @param string $xmlDocument
* @return array|string|null
*/
static function convertDAVNamespace($xmlDocument) {
// This is used to map the DAV: namespace to urn:DAV. This is needed, because the DAV:
// namespace is actually a violation of the XML namespaces specification, and will cause errors
return preg_replace("/xmlns(:[A-Za-z0-9_]*)?=(\"|\')DAV:(\\2)/","xmlns\\1=\\2urn:DAV\\2",$xmlDocument);
}
/**
* This method provides a generic way to load a DOMDocument for WebDAV use.
*
|
|
6d9380f96
|
86 |
* This method throws a Sabre\DAV\Exception\BadRequest exception for any xml errors. |
|
03e52840d
|
87 88 89 |
* It does not preserve whitespace, and it converts the DAV: namespace to urn:DAV.
*
* @param string $xml
|
|
6d9380f96
|
90 |
* @throws Sabre\DAV\Exception\BadRequest |
|
03e52840d
|
91 92 93 94 95 |
* @return DOMDocument
*/
static function loadDOMDocument($xml) {
if (empty($xml))
|
|
6d9380f96
|
96 |
throw new Exception\BadRequest('Empty XML document sent');
|
|
03e52840d
|
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
// The BitKinex client sends xml documents as UTF-16. PHP 5.3.1 (and presumably lower)
// does not support this, so we must intercept this and convert to UTF-8.
if (substr($xml,0,12) === "\x3c\x00\x3f\x00\x78\x00\x6d\x00\x6c\x00\x20\x00") {
// Note: the preceeding byte sequence is "<?xml" encoded as UTF_16, without the BOM.
$xml = iconv('UTF-16LE','UTF-8',$xml);
// Because the xml header might specify the encoding, we must also change this.
// This regex looks for the string encoding="UTF-16" and replaces it with
// encoding="UTF-8".
$xml = preg_replace('|<\?xml([^>]*)encoding="UTF-16"([^>]*)>|u','<?xml\1encoding="UTF-8"\2>',$xml);
}
// Retaining old error setting
$oldErrorSetting = libxml_use_internal_errors(true);
|
|
6d9380f96
|
114 115 116 |
// Fixes an XXE vulnerability on PHP versions older than 5.3.23 or
// 5.4.13.
$oldEntityLoaderSetting = libxml_disable_entity_loader(true);
|
|
03e52840d
|
117 118 119 |
// Clearing any previous errors
libxml_clear_errors();
|
|
6d9380f96
|
120 |
$dom = new \DOMDocument(); |
|
03e52840d
|
121 122 123 |
// We don't generally care about any whitespace
$dom->preserveWhiteSpace = false;
|
|
6d9380f96
|
124 125 |
$dom->loadXML(self::convertDAVNamespace($xml),LIBXML_NOWARNING | LIBXML_NOERROR);
|
|
03e52840d
|
126 127 128 |
if ($error = libxml_get_last_error()) {
libxml_clear_errors();
|
|
6d9380f96
|
129 |
throw new Exception\BadRequest('The request body had an invalid XML body. (message: ' . $error->message . ', errorcode: ' . $error->code . ', line: ' . $error->line . ')');
|
|
03e52840d
|
130 131 132 133 |
}
// Restoring old mechanism for error handling
if ($oldErrorSetting===false) libxml_use_internal_errors(false);
|
|
6d9380f96
|
134 |
if ($oldEntityLoaderSetting===false) libxml_disable_entity_loader(false); |
|
03e52840d
|
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
return $dom;
}
/**
* Parses all WebDAV properties out of a DOM Element
*
* Generally WebDAV properties are enclosed in {DAV:}prop elements. This
* method helps by going through all these and pulling out the actual
* propertynames, making them array keys and making the property values,
* well.. the array values.
*
* If no value was given (self-closing element) null will be used as the
* value. This is used in for example PROPFIND requests.
*
* Complex values are supported through the propertyMap argument. The
* propertyMap should have the clark-notation properties as it's keys, and
* classnames as values.
*
* When any of these properties are found, the unserialize() method will be
* (statically) called. The result of this method is used as the value.
*
|
|
6d9380f96
|
158 |
* @param \DOMElement $parentNode |
|
03e52840d
|
159 160 161 |
* @param array $propertyMap
* @return array
*/
|
|
6d9380f96
|
162 |
static function parseProperties(\DOMElement $parentNode, array $propertyMap = array()) {
|
|
03e52840d
|
163 164 165 |
$propList = array();
foreach($parentNode->childNodes as $propNode) {
|
|
6d9380f96
|
166 |
if (self::toClarkNotation($propNode)!=='{DAV:}prop') continue;
|
|
03e52840d
|
167 168 169 170 171 |
foreach($propNode->childNodes as $propNodeData) {
/* If there are no elements in here, we actually get 1 text node, this special case is dedicated to netdrive */
if ($propNodeData->nodeType != XML_ELEMENT_NODE) continue;
|
|
6d9380f96
|
172 |
$propertyName = self::toClarkNotation($propNodeData); |
|
03e52840d
|
173 174 175 176 177 178 179 180 181 182 183 184 185 186 |
if (isset($propertyMap[$propertyName])) {
$propList[$propertyName] = call_user_func(array($propertyMap[$propertyName],'unserialize'),$propNodeData);
} else {
$propList[$propertyName] = $propNodeData->textContent;
}
}
}
return $propList;
}
}
|