30 'valuestack' => array(),
40 'VALUE' => array(
'MEMBER',
'DATA',
'PARAM',
'FAULT'),
41 'BOOLEAN' => array(
'VALUE'),
42 'I4' => array(
'VALUE'),
43 'INT' => array(
'VALUE'),
44 'STRING' => array(
'VALUE'),
45 'DOUBLE' => array(
'VALUE'),
46 'DATETIME.ISO8601' => array(
'VALUE'),
47 'BASE64' => array(
'VALUE'),
48 'MEMBER' => array(
'STRUCT'),
49 'NAME' => array(
'MEMBER'),
50 'DATA' => array(
'ARRAY'),
51 'ARRAY' => array(
'VALUE'),
52 'STRUCT' => array(
'VALUE'),
53 'PARAM' => array(
'PARAMS'),
54 'METHODNAME' => array(
'METHODCALL'),
55 'PARAMS' => array(
'METHODCALL',
'METHODRESPONSE'),
56 'FAULT' => array(
'METHODRESPONSE'),
57 'NIL' => array(
'VALUE'),
58 'EX:NIL' => array(
'VALUE'),
64 public function xmlrpc_se($parser, $name, $attrs, $acceptSingleVals =
false)
67 if ($this->_xh[
'isf'] < 2) {
72 if (count($this->_xh[
'stack']) == 0) {
73 if ($name !=
'METHODRESPONSE' && $name !=
'METHODCALL' && (
74 $name !=
'VALUE' && !$acceptSingleVals)
76 $this->_xh[
'isf'] = 2;
77 $this->_xh[
'isf_reason'] =
'missing top level xmlrpc element';
81 $this->_xh[
'rt'] = strtolower($name);
85 $parent = end($this->_xh[
'stack']);
86 if (!array_key_exists($name, $this->xmlrpc_valid_parents) || !in_array($parent, $this->xmlrpc_valid_parents[$name])) {
87 $this->_xh[
'isf'] = 2;
88 $this->_xh[
'isf_reason'] =
"xmlrpc element $name cannot be child of $parent";
98 $this->_xh[
'vt'] =
'value';
99 $this->_xh[
'ac'] =
'';
100 $this->_xh[
'lv'] = 1;
101 $this->_xh[
'php_class'] =
null;
108 case 'DATETIME.ISO8601':
110 if ($this->_xh[
'vt'] !=
'value') {
112 $this->_xh[
'isf'] = 2;
113 $this->_xh[
'isf_reason'] =
"$name element following a {$this->_xh['vt']} element inside a single value";
117 $this->_xh[
'ac'] =
'';
121 if ($this->_xh[
'vt'] !=
'value') {
123 $this->_xh[
'isf'] = 2;
124 $this->_xh[
'isf_reason'] =
"$name element following a {$this->_xh['vt']} element inside a single value";
130 $curVal[
'values'] = array();
131 $curVal[
'type'] = $name;
134 if (@isset($attrs[
'PHP_CLASS'])) {
135 $curVal[
'php_class'] = $attrs[
'PHP_CLASS'];
137 $this->_xh[
'valuestack'][] = $curVal;
138 $this->_xh[
'vt'] =
'data';
141 if ($this->_xh[
'vt'] !=
'data') {
143 $this->_xh[
'isf'] = 2;
144 $this->_xh[
'isf_reason'] =
"found two data elements inside an array element";
149 case 'METHODRESPONSE':
156 $this->_xh[
'ac'] =
'';
159 $this->_xh[
'isf'] = 1;
162 $this->_xh[
'valuestack'][count($this->_xh[
'valuestack']) - 1][
'name'] =
'';
167 $this->_xh[
'vt'] =
null;
172 if ($this->_xh[
'vt'] !=
'value') {
174 $this->_xh[
'isf'] = 2;
175 $this->_xh[
'isf_reason'] =
"$name element following a {$this->_xh['vt']} element inside a single value";
179 $this->_xh[
'ac'] =
'';
186 $this->_xh[
'isf'] = 2;
187 $this->_xh[
'isf_reason'] =
"found not-xmlrpc xml element $name";
192 $this->_xh[
'stack'][] = $name;
195 if ($name !=
'VALUE') {
196 $this->_xh[
'lv'] = 0;
206 $this->
xmlrpc_se($parser, $name, $attrs,
true);
212 public function xmlrpc_ee($parser, $name, $rebuildXmlrpcvals =
true)
214 if ($this->_xh[
'isf'] < 2) {
219 $currElem = array_pop($this->_xh[
'stack']);
224 if ($this->_xh[
'vt'] ==
'value') {
225 $this->_xh[
'value'] = $this->_xh[
'ac'];
229 if ($rebuildXmlrpcvals) {
231 $temp =
new Value($this->_xh[
'value'], $this->_xh[
'vt']);
234 if (isset($this->_xh[
'php_class'])) {
235 $temp->_php_class = $this->_xh[
'php_class'];
239 $vscount = count($this->_xh[
'valuestack']);
240 if ($vscount && $this->_xh[
'valuestack'][$vscount - 1][
'type'] ==
'ARRAY') {
241 $this->_xh[
'valuestack'][$vscount - 1][
'values'][] = $temp;
243 $this->_xh[
'value'] = $temp;
249 if (isset($this->_xh[
'php_class'])) {
254 $vscount = count($this->_xh[
'valuestack']);
255 if ($vscount && $this->_xh[
'valuestack'][$vscount - 1][
'type'] ==
'ARRAY') {
256 $this->_xh[
'valuestack'][$vscount - 1][
'values'][] = $this->_xh[
'value'];
265 case 'DATETIME.ISO8601':
267 $this->_xh[
'vt'] = strtolower($name);
270 if ($name ==
'STRING') {
271 $this->_xh[
'value'] = $this->_xh[
'ac'];
272 } elseif ($name ==
'DATETIME.ISO8601') {
273 if (!preg_match(
'/^[0-9]{8}T[0-9]{2}:[0-9]{2}:[0-9]{2}$/', $this->_xh[
'ac'])) {
274 error_log(
'XML-RPC: ' . __METHOD__ .
': invalid value received in DATETIME: ' . $this->_xh[
'ac']);
277 $this->_xh[
'value'] = $this->_xh[
'ac'];
278 } elseif ($name ==
'BASE64') {
280 $this->_xh[
'value'] = base64_decode($this->_xh[
'ac']);
281 } elseif ($name ==
'BOOLEAN') {
288 if ($this->_xh[
'ac'] ==
'1' || strcasecmp($this->_xh[
'ac'],
'true') == 0) {
289 $this->_xh[
'value'] =
true;
292 if ($this->_xh[
'ac'] !=
'0' && strcasecmp($this->_xh[
'ac'],
'false') != 0) {
293 error_log(
'XML-RPC: ' . __METHOD__ .
': invalid value received in BOOLEAN: ' . $this->_xh[
'ac']);
295 $this->_xh[
'value'] =
false;
297 } elseif ($name ==
'DOUBLE') {
301 if (!preg_match(
'/^[+-eE0123456789 \t.]+$/', $this->_xh[
'ac'])) {
303 error_log(
'XML-RPC: ' . __METHOD__ .
': non numeric value received in DOUBLE: ' . $this->_xh[
'ac']);
304 $this->_xh[
'value'] =
'ERROR_NON_NUMERIC_FOUND';
307 $this->_xh[
'value'] = (double)$this->_xh[
'ac'];
312 if (!preg_match(
'/^[+-]?[0123456789 \t]+$/', $this->_xh[
'ac'])) {
314 error_log(
'XML-RPC: ' . __METHOD__ .
': non numeric value received in INT: ' . $this->_xh[
'ac']);
315 $this->_xh[
'value'] =
'ERROR_NON_NUMERIC_FOUND';
318 $this->_xh[
'value'] = (int)$this->_xh[
'ac'];
321 $this->_xh[
'lv'] = 3;
324 $this->_xh[
'valuestack'][count($this->_xh[
'valuestack']) - 1][
'name'] = $this->_xh[
'ac'];
329 if ($this->_xh[
'vt']) {
330 $vscount = count($this->_xh[
'valuestack']);
331 $this->_xh[
'valuestack'][$vscount - 1][
'values'][$this->_xh[
'valuestack'][$vscount - 1][
'name']] = $this->_xh[
'value'];
333 error_log(
'XML-RPC: ' . __METHOD__ .
': missing VALUE inside STRUCT in received xml');
337 $this->_xh[
'vt'] =
null;
342 $currVal = array_pop($this->_xh[
'valuestack']);
343 $this->_xh[
'value'] = $currVal[
'values'];
344 $this->_xh[
'vt'] = strtolower($name);
345 if (isset($currVal[
'php_class'])) {
346 $this->_xh[
'php_class'] = $currVal[
'php_class'];
352 if ($this->_xh[
'vt']) {
353 $this->_xh[
'params'][] = $this->_xh[
'value'];
354 $this->_xh[
'pt'][] = $this->_xh[
'vt'];
356 error_log(
'XML-RPC: ' . __METHOD__ .
': missing VALUE inside PARAM in received xml');
360 $this->_xh[
'method'] = preg_replace(
'/^[\n\r\t ]+/',
'', $this->_xh[
'ac']);
365 $this->_xh[
'vt'] =
'null';
366 $this->_xh[
'value'] =
null;
367 $this->_xh[
'lv'] = 3;
374 case 'METHORESPONSE':
398 if ($this->_xh[
'isf'] < 2) {
401 if ($this->_xh[
'lv'] != 3) {
402 $this->_xh[
'ac'] .= $data;
414 if ($this->_xh[
'isf'] < 2) {
415 if (substr($data, 0, 1) ==
'&' && substr($data, -1, 1) ==
';') {
416 $this->_xh[
'ac'] .= $data;
444 public static function guessEncoding($httpHeader =
'', $xmlChunk =
'', $encodingPrefs =
null)
462 if (preg_match(
'/;\s*charset\s*=([^;]+)/i', $httpHeader, $matches)) {
463 return strtoupper(trim($matches[1],
" \t\""));
473 if (preg_match(
'/^(\x00\x00\xFE\xFF|\xFF\xFE\x00\x00|\x00\x00\xFF\xFE|\xFE\xFF\x00\x00)/', $xmlChunk)) {
475 } elseif (preg_match(
'/^(\xFE\xFF|\xFF\xFE)/', $xmlChunk)) {
477 } elseif (preg_match(
'/^(\xEF\xBB\xBF)/', $xmlChunk)) {
485 if (preg_match(
'/^<\?xml\s+version\s*=\s*' .
"((?:\"[a-zA-Z0-9_.:-]+\")|(?:'[a-zA-Z0-9_.:-]+'))" .
486 '\s+encoding\s*=\s*' .
"((?:\"[A-Za-z][A-Za-z0-9._-]*\")|(?:'[A-Za-z][A-Za-z0-9._-]*'))/",
487 $xmlChunk, $matches)) {
488 return strtoupper(substr($matches[2], 1, -1));
492 if (extension_loaded(
'mbstring')) {
496 if ($encodingPrefs) {
497 $enc = mb_detect_encoding($xmlChunk, $encodingPrefs);
499 $enc = mb_detect_encoding($xmlChunk);
503 if ($enc ==
'ASCII') {
527 if (preg_match(
'/^(\x00\x00\xFE\xFF|\xFF\xFE\x00\x00|\x00\x00\xFF\xFE|\xFE\xFF\x00\x00)/', $xmlChunk)) {
529 } elseif (preg_match(
'/^(\xFE\xFF|\xFF\xFE)/', $xmlChunk)) {
531 } elseif (preg_match(
'/^(\xEF\xBB\xBF)/', $xmlChunk)) {
539 if (preg_match(
'/^<\?xml\s+version\s*=\s*' .
"((?:\"[a-zA-Z0-9_.:-]+\")|(?:'[a-zA-Z0-9_.:-]+'))" .
540 '\s+encoding\s*=\s*' .
"((?:\"[A-Za-z][A-Za-z0-9._-]*\")|(?:'[A-Za-z][A-Za-z0-9._-]*'))/",
541 $xmlChunk, $matches)) {