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