diff --git a/plugins/spamx/SLVbase.class.php b/plugins/spamx/SLVbase.class.php index cb9d1f902..54d555f7e 100644 --- a/plugins/spamx/SLVbase.class.php +++ b/plugins/spamx/SLVbase.class.php @@ -79,7 +79,7 @@ public function CheckForSpam($post) $resp = $cli->send($msg, $_SPX_CONF['timeout']); if (!$resp) { - COM_errorLog('Error communicating with SLV: ' . $cli->errstr + COM_errorLog('Error communicating with SLV: ' . $cli->getErrorString() . '; Message was ' . $msg->serialize()); } else if ($resp->faultCode()) { COM_errorLog('Error communicating with SLV. Fault code: ' diff --git a/system/classes/Autoload.php b/system/classes/Autoload.php index 532fa6ef6..857adbf94 100644 --- a/system/classes/Autoload.php +++ b/system/classes/Autoload.php @@ -47,6 +47,12 @@ public static function load($className) /** @noinspection PhpIncludeInspection */ include $path; } + + if (stripos($className, 'XML_RPC_Server') === 0) { + include __DIR__ . DIRECTORY_SEPARATOR . 'XML/RPC/Server.php'; + } elseif (stripos($className, 'XML_RPC_') === 0) { + include __DIR__ . DIRECTORY_SEPARATOR . 'XML/RPC.php'; + } } } diff --git a/system/classes/XML/RPC.php b/system/classes/XML/RPC.php index 31aed890c..3a1a1b5d5 100644 --- a/system/classes/XML/RPC.php +++ b/system/classes/XML/RPC.php @@ -1,13 +1,9 @@ 1, @@ -132,7 +137,8 @@ /** * Error message numbers - * @global array $GLOBALS['XML_RPC_err'] + * + * @global array $GLOBALS ['XML_RPC_err'] */ $GLOBALS['XML_RPC_err'] = array( 'unknown_method' => 1, @@ -146,7 +152,8 @@ /** * Error message strings - * @global array $GLOBALS['XML_RPC_str'] + * + * @global array $GLOBALS ['XML_RPC_str'] */ $GLOBALS['XML_RPC_str'] = array( 'unknown_method' => 'Unknown method', @@ -161,26 +168,30 @@ /** * Default XML encoding (ISO-8859-1, UTF-8 or US-ASCII) - * @global string $GLOBALS['XML_RPC_defencoding'] + * + * @global string $GLOBALS ['XML_RPC_defencoding'] */ $GLOBALS['XML_RPC_defencoding'] = 'UTF-8'; /** * User error codes start at 800 - * @global int $GLOBALS['XML_RPC_erruser'] + * + * @global int $GLOBALS ['XML_RPC_erruser'] */ $GLOBALS['XML_RPC_erruser'] = 800; /** * XML parse error codes start at 100 - * @global int $GLOBALS['XML_RPC_errxml'] + * + * @global int $GLOBALS ['XML_RPC_errxml'] */ $GLOBALS['XML_RPC_errxml'] = 100; /** * Compose backslashes for escaping regexp - * @global string $GLOBALS['XML_RPC_backslash'] + * + * @global string $GLOBALS ['XML_RPC_backslash'] */ $GLOBALS['XML_RPC_backslash'] = chr(92) . chr(92); @@ -188,39 +199,40 @@ /** * Should we automatically base64 encode strings that contain characters * which can cause PHP's SAX-based XML parser to break? - * @global boolean $GLOBALS['XML_RPC_auto_base64'] + * + * @global boolean $GLOBALS ['XML_RPC_auto_base64'] */ $GLOBALS['XML_RPC_auto_base64'] = false; /** * Valid parents of XML elements - * @global array $GLOBALS['XML_RPC_valid_parents'] + * + * @global array $GLOBALS ['XML_RPC_valid_parents'] */ $GLOBALS['XML_RPC_valid_parents'] = array( - 'BOOLEAN' => array('VALUE'), - 'I4' => array('VALUE'), - 'INT' => array('VALUE'), - 'STRING' => array('VALUE'), - 'DOUBLE' => array('VALUE'), + 'BOOLEAN' => array('VALUE'), + 'I4' => array('VALUE'), + 'INT' => array('VALUE'), + 'STRING' => array('VALUE'), + 'DOUBLE' => array('VALUE'), 'DATETIME.ISO8601' => array('VALUE'), - 'BASE64' => array('VALUE'), - 'ARRAY' => array('VALUE'), - 'STRUCT' => array('VALUE'), - 'PARAM' => array('PARAMS'), - 'METHODNAME' => array('METHODCALL'), - 'PARAMS' => array('METHODCALL', 'METHODRESPONSE'), - 'MEMBER' => array('STRUCT'), - 'NAME' => array('MEMBER'), - 'DATA' => array('ARRAY'), - 'FAULT' => array('METHODRESPONSE'), - 'VALUE' => array('MEMBER', 'DATA', 'PARAM', 'FAULT'), + 'BASE64' => array('VALUE'), + 'ARRAY' => array('VALUE'), + 'STRUCT' => array('VALUE'), + 'PARAM' => array('PARAMS'), + 'METHODNAME' => array('METHODCALL'), + 'PARAMS' => array('METHODCALL', 'METHODRESPONSE'), + 'MEMBER' => array('STRUCT'), + 'NAME' => array('MEMBER'), + 'DATA' => array('ARRAY'), + 'FAULT' => array('METHODRESPONSE'), + 'VALUE' => array('MEMBER', 'DATA', 'PARAM', 'FAULT'), ); /** * Stores state during parsing - * * quick explanation of components: * + ac = accumulates values * + qt = decides if quotes are needed for evaluation @@ -231,306 +243,476 @@ * + params = stores parameters in method calls * + method = stores method name * - * @global array $GLOBALS['XML_RPC_xh'] + * @global array $GLOBALS ['XML_RPC_xh'] */ $GLOBALS['XML_RPC_xh'] = array(); -/** - * Start element handler for the XML parser - * - * @return void - */ -function XML_RPC_se($parser_resource, $name, $attrs) +class XML_RPC { - global $XML_RPC_xh, $XML_RPC_valid_parents; - - $parser = (int) $parser_resource; + /** + * Return an ISO8601 encoded string + * While timezones ought to be supported, the XML-RPC spec says: + * "Don't assume a timezone. It should be specified by the server in its + * documentation what assumptions it makes about timezones." + * This routine always assumes localtime unless $utc is set to 1, in which + * case UTC is assumed and an adjustment for locale is made when encoding. + * + * @return string the formatted date + */ + public static function XML_RPC_iso8601_encode($timet, $utc = 0) + { + if (!$utc) { + $t = strftime('%Y%m%dT%H:%M:%S', $timet); + } else { + if (function_exists('gmstrftime')) { + // gmstrftime doesn't exist in some versions of PHP + $t = gmstrftime('%Y%m%dT%H:%M:%S', $timet); + } else { + $t = strftime('%Y%m%dT%H:%M:%S', $timet - date('Z')); + } + } - // if invalid xmlrpc already detected, skip all processing - if ($XML_RPC_xh[$parser]['isf'] >= 2) { - return; + return $t; } - // check for correct element nesting - // top level element can only be of 2 types - if (count($XML_RPC_xh[$parser]['stack']) == 0) { - if ($name != 'METHODRESPONSE' && $name != 'METHODCALL') { - $XML_RPC_xh[$parser]['isf'] = 2; - $XML_RPC_xh[$parser]['isf_reason'] = 'missing top level xmlrpc element'; - return; - } - } else { - // not top level element: see if parent is OK - if (!in_array($XML_RPC_xh[$parser]['stack'][0], $XML_RPC_valid_parents[$name])) { - $name = preg_replace('@[^a-zA-Z0-9._-]@', '', $name); - $XML_RPC_xh[$parser]['isf'] = 2; - $XML_RPC_xh[$parser]['isf_reason'] = "xmlrpc element $name cannot be child of {$XML_RPC_xh[$parser]['stack'][0]}"; - return; + /** + * Convert a datetime string into a Unix timestamp + * While timezones ought to be supported, the XML-RPC spec says: + * "Don't assume a timezone. It should be specified by the server in its + * documentation what assumptions it makes about timezones." + * This routine always assumes localtime unless $utc is set to 1, in which + * case UTC is assumed and an adjustment for locale is made when encoding. + * + * @return int the unix timestamp of the date submitted + */ + public static function XML_RPC_iso8601_decode($idate, $utc = 0) + { + $t = 0; + if (preg_match('@([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})@', $idate, $regs)) { + if ($utc) { + $t = gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]); + } else { + $t = mktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]); + } } + + return $t; } - switch ($name) { - case 'STRUCT': - $XML_RPC_xh[$parser]['cm']++; + /** + * Converts an XML_RPC_Value object into native PHP types + * + * @param XML_RPC_Value $XML_RPC_val the object to decode + * @return mixed the PHP values + * @throws InvalidArgumentException + */ + public static function decode($XML_RPC_val) + { + $kind = $XML_RPC_val->kindOf(); + + if ($kind === 'scalar') { + return $XML_RPC_val->scalarValue(); + } elseif ($kind == 'array') { + $size = $XML_RPC_val->arraySize(); + $arr = array(); + for ($i = 0; $i < $size; $i++) { + $arr[] = self::decode($XML_RPC_val->arrayMem($i)); + } - // turn quoting off - $XML_RPC_xh[$parser]['qt'] = 0; + return $arr; + } elseif ($kind === 'struct') { + $XML_RPC_val->structReset(); + $arr = array(); + while (list($key, $value) = $XML_RPC_val->structEach()) { + $arr[$key] = self::decode($value); + } + + return $arr; + } - $cur_val = array(); - $cur_val['value'] = array(); - $cur_val['members'] = 1; - array_unshift($XML_RPC_xh[$parser]['valuestack'], $cur_val); - break; + throw new InvalidArgumentException(__METHOD__ . ': Unknown value type ' . $kind); + } - case 'ARRAY': - $XML_RPC_xh[$parser]['cm']++; + /** + * Converts native PHP types into an XML_RPC_Value object + * + * @param mixed $php_val the PHP value or variable you want encoded + * @return object the XML_RPC_Value object + */ + public static function encode($php_val) + { + $type = gettype($php_val); + $XML_RPC_val = new XML_RPC_Value; - // turn quoting off - $XML_RPC_xh[$parser]['qt'] = 0; + switch ($type) { + case 'array': + if (empty($php_val)) { + $XML_RPC_val->addArray($php_val); + break; + } + $tmp = array_diff(array_keys($php_val), range(0, count($php_val) - 1)); + if (empty($tmp)) { + $arr = array(); + foreach ($php_val as $k => $v) { + $arr[$k] = self::encode($v); + } + $XML_RPC_val->addArray($arr); + break; + } + // fall though if it's not an enumerated array - $cur_val = array(); - $cur_val['value'] = array(); - $cur_val['members'] = 0; - array_unshift($XML_RPC_xh[$parser]['valuestack'], $cur_val); - break; + case 'object': + $arr = array(); + foreach ($php_val as $k => $v) { + $arr[$k] = self::encode($v); + } + $XML_RPC_val->addStruct($arr); + break; - case 'NAME': - $XML_RPC_xh[$parser]['ac'] = ''; - break; + case 'integer': + $XML_RPC_val->addScalar($php_val, $GLOBALS['XML_RPC_Int']); + break; - case 'FAULT': - $XML_RPC_xh[$parser]['isf'] = 1; - break; + case 'double': + $XML_RPC_val->addScalar($php_val, $GLOBALS['XML_RPC_Double']); + break; - case 'PARAM': - $XML_RPC_xh[$parser]['valuestack'] = array(); - break; + case 'string': + case 'NULL': + if (preg_match('@^[0-9]{8}\T{1}[0-9]{2}\:[0-9]{2}\:[0-9]{2}$@', $php_val)) { + $XML_RPC_val->addScalar($php_val, $GLOBALS['XML_RPC_DateTime']); + } elseif ($GLOBALS['XML_RPC_auto_base64'] + && preg_match("@[^ -~\t\r\n]@", $php_val) + ) { + // Characters other than alpha-numeric, punctuation, SP, TAB, + // LF and CR break the XML parser, encode value via Base 64. + $XML_RPC_val->addScalar($php_val, $GLOBALS['XML_RPC_Base64']); + } else { + $XML_RPC_val->addScalar($php_val, $GLOBALS['XML_RPC_String']); + } + break; - case 'VALUE': - $XML_RPC_xh[$parser]['lv'] = 1; - $XML_RPC_xh[$parser]['vt'] = $GLOBALS['XML_RPC_String']; - $XML_RPC_xh[$parser]['ac'] = ''; - $XML_RPC_xh[$parser]['qt'] = 0; - // look for a value: if this is still 1 by the - // time we reach the first data segment then the type is string - // by implication and we need to add in a quote - break; - - case 'I4': - case 'INT': - case 'STRING': - case 'BOOLEAN': - case 'DOUBLE': - case 'DATETIME.ISO8601': - case 'BASE64': - $XML_RPC_xh[$parser]['ac'] = ''; // reset the accumulator - - if ($name == 'DATETIME.ISO8601' || $name == 'STRING') { - $XML_RPC_xh[$parser]['qt'] = 1; - - if ($name == 'DATETIME.ISO8601') { - $XML_RPC_xh[$parser]['vt'] = $GLOBALS['XML_RPC_DateTime']; - } + case 'boolean': + // Add support for encoding/decoding of booleans, since they + // are supported in PHP + // by + $XML_RPC_val->addScalar($php_val, $GLOBALS['XML_RPC_Boolean']); + break; - } elseif ($name == 'BASE64') { - $XML_RPC_xh[$parser]['qt'] = 2; - } else { - // No quoting is required here -- but - // at the end of the element we must check - // for data format errors. - $XML_RPC_xh[$parser]['qt'] = 0; + case 'unknown type': + default: + $XML_RPC_val = false; } - break; - case 'MEMBER': - $XML_RPC_xh[$parser]['ac'] = ''; - break; - - case 'DATA': - case 'METHODCALL': - case 'METHODNAME': - case 'METHODRESPONSE': - case 'PARAMS': - // valid elements that add little to processing - break; + return $XML_RPC_val; } + /** + * Start element handler for the XML parser + * + * @param resource $parser_resource + * @param string $name + * @param array $attrs + * @return void + */ + public static function startElement($parser_resource, $name, array $attrs) + { + global $XML_RPC_xh, $XML_RPC_valid_parents; - // Save current element to stack - array_unshift($XML_RPC_xh[$parser]['stack'], $name); - - if ($name != 'VALUE') { - $XML_RPC_xh[$parser]['lv'] = 0; - } -} - -/** - * End element handler for the XML parser - * - * @return void - */ -function XML_RPC_ee($parser_resource, $name) -{ - global $XML_RPC_xh; + $parser = (int) $parser_resource; - $parser = (int) $parser_resource; + // if invalid xmlrpc already detected, skip all processing + if ($XML_RPC_xh[$parser]['isf'] >= 2) { + return; + } - if ($XML_RPC_xh[$parser]['isf'] >= 2) { - return; - } + // check for correct element nesting + // top level element can only be of 2 types + if (count($XML_RPC_xh[$parser]['stack']) == 0) { + if ($name != 'METHODRESPONSE' && $name != 'METHODCALL') { + $XML_RPC_xh[$parser]['isf'] = 2; + $XML_RPC_xh[$parser]['isf_reason'] = 'missing top level xmlrpc element'; - // push this element from stack - // NB: if XML validates, correct opening/closing is guaranteed and - // we do not have to check for $name == $curr_elem. - // we also checked for proper nesting at start of elements... - $curr_elem = array_shift($XML_RPC_xh[$parser]['stack']); - - switch ($name) { - case 'STRUCT': - case 'ARRAY': - $cur_val = array_shift($XML_RPC_xh[$parser]['valuestack']); - $XML_RPC_xh[$parser]['value'] = $cur_val['value']; - $XML_RPC_xh[$parser]['vt'] = strtolower($name); - $XML_RPC_xh[$parser]['cm']--; - break; - - case 'NAME': - $XML_RPC_xh[$parser]['valuestack'][0]['name'] = $XML_RPC_xh[$parser]['ac']; - break; - - case 'BOOLEAN': - // special case here: we translate boolean 1 or 0 into PHP - // constants true or false - if ($XML_RPC_xh[$parser]['ac'] == '1') { - $XML_RPC_xh[$parser]['ac'] = 'true'; + return; + } } else { - $XML_RPC_xh[$parser]['ac'] = 'false'; - } + // not top level element: see if parent is OK + if (!in_array($XML_RPC_xh[$parser]['stack'][0], $XML_RPC_valid_parents[$name])) { + $name = preg_replace('@[^a-zA-Z0-9._-]@', '', $name); + $XML_RPC_xh[$parser]['isf'] = 2; + $XML_RPC_xh[$parser]['isf_reason'] = "xmlrpc element $name cannot be child of {$XML_RPC_xh[$parser]['stack'][0]}"; - $XML_RPC_xh[$parser]['vt'] = strtolower($name); - // Drop through intentionally. - - case 'I4': - case 'INT': - case 'STRING': - case 'DOUBLE': - case 'DATETIME.ISO8601': - case 'BASE64': - if ($XML_RPC_xh[$parser]['qt'] == 1) { - // we use double quotes rather than single so backslashification works OK - $XML_RPC_xh[$parser]['value'] = $XML_RPC_xh[$parser]['ac']; - } elseif ($XML_RPC_xh[$parser]['qt'] == 2) { - $XML_RPC_xh[$parser]['value'] = base64_decode($XML_RPC_xh[$parser]['ac']); - } elseif ($name == 'BOOLEAN') { - $XML_RPC_xh[$parser]['value'] = $XML_RPC_xh[$parser]['ac']; - } else { - // we have an I4, INT or a DOUBLE - // we must check that only 0123456789-. are characters here - if (!preg_match("@^[+-]?[0123456789 \t\.]+$@", $XML_RPC_xh[$parser]['ac'])) { - XML_RPC_Base::raiseError('Non-numeric value received in INT or DOUBLE', - XML_RPC_ERROR_NON_NUMERIC_FOUND); - $XML_RPC_xh[$parser]['value'] = XML_RPC_ERROR_NON_NUMERIC_FOUND; - } else { - // it's ok, add it on - $XML_RPC_xh[$parser]['value'] = $XML_RPC_xh[$parser]['ac']; + return; } } - $XML_RPC_xh[$parser]['ac'] = ''; - $XML_RPC_xh[$parser]['qt'] = 0; - $XML_RPC_xh[$parser]['lv'] = 3; // indicate we've found a value - break; - - case 'VALUE': - if ($XML_RPC_xh[$parser]['vt'] == $GLOBALS['XML_RPC_String']) { - if (strlen($XML_RPC_xh[$parser]['ac']) > 0) { - $XML_RPC_xh[$parser]['value'] = $XML_RPC_xh[$parser]['ac']; - } elseif ($XML_RPC_xh[$parser]['lv'] == 1) { - // The element was empty. - $XML_RPC_xh[$parser]['value'] = ''; - } + switch ($name) { + case 'STRUCT': + $XML_RPC_xh[$parser]['cm']++; + + // turn quoting off + $XML_RPC_xh[$parser]['qt'] = 0; + + $cur_val = array(); + $cur_val['value'] = array(); + $cur_val['members'] = 1; + array_unshift($XML_RPC_xh[$parser]['valuestack'], $cur_val); + break; + + case 'ARRAY': + $XML_RPC_xh[$parser]['cm']++; + + // turn quoting off + $XML_RPC_xh[$parser]['qt'] = 0; + + $cur_val = array(); + $cur_val['value'] = array(); + $cur_val['members'] = 0; + array_unshift($XML_RPC_xh[$parser]['valuestack'], $cur_val); + break; + + case 'NAME': + $XML_RPC_xh[$parser]['ac'] = ''; + break; + + case 'FAULT': + $XML_RPC_xh[$parser]['isf'] = 1; + break; + + case 'PARAM': + $XML_RPC_xh[$parser]['valuestack'] = array(); + break; + + case 'VALUE': + $XML_RPC_xh[$parser]['lv'] = 1; + $XML_RPC_xh[$parser]['vt'] = $GLOBALS['XML_RPC_String']; + $XML_RPC_xh[$parser]['ac'] = ''; + $XML_RPC_xh[$parser]['qt'] = 0; + // look for a value: if this is still 1 by the + // time we reach the first data segment then the type is string + // by implication and we need to add in a quote + break; + + case 'I4': + case 'INT': + case 'STRING': + case 'BOOLEAN': + case 'DOUBLE': + case 'DATETIME.ISO8601': + case 'BASE64': + $XML_RPC_xh[$parser]['ac'] = ''; // reset the accumulator + + if ($name == 'DATETIME.ISO8601' || $name == 'STRING') { + $XML_RPC_xh[$parser]['qt'] = 1; + + if ($name == 'DATETIME.ISO8601') { + $XML_RPC_xh[$parser]['vt'] = $GLOBALS['XML_RPC_DateTime']; + } + + } elseif ($name == 'BASE64') { + $XML_RPC_xh[$parser]['qt'] = 2; + } else { + // No quoting is required here -- but + // at the end of the element we must check + // for data format errors. + $XML_RPC_xh[$parser]['qt'] = 0; + } + break; + + case 'MEMBER': + $XML_RPC_xh[$parser]['ac'] = ''; + break; + + case 'DATA': + case 'METHODCALL': + case 'METHODNAME': + case 'METHODRESPONSE': + case 'PARAMS': + // valid elements that add little to processing + break; } - $temp = new XML_RPC_Value($XML_RPC_xh[$parser]['value'], $XML_RPC_xh[$parser]['vt']); - $cur_val = array_shift($XML_RPC_xh[$parser]['valuestack']); - if (is_array($cur_val)) { - if ($cur_val['members']==0) { - $cur_val['value'][] = $temp; - } else { - $XML_RPC_xh[$parser]['value'] = $temp; - } - array_unshift($XML_RPC_xh[$parser]['valuestack'], $cur_val); - } else { - $XML_RPC_xh[$parser]['value'] = $temp; + // Save current element to stack + array_unshift($XML_RPC_xh[$parser]['stack'], $name); + + if ($name != 'VALUE') { + $XML_RPC_xh[$parser]['lv'] = 0; } - break; + } - case 'MEMBER': - $XML_RPC_xh[$parser]['ac'] = ''; - $XML_RPC_xh[$parser]['qt'] = 0; + /** + * End element handler for the XML parser + * + * @param resource $parser_resource + * @param string $name + * @return void + */ + public static function endElement($parser_resource, $name) + { + global $XML_RPC_xh; - $cur_val = array_shift($XML_RPC_xh[$parser]['valuestack']); - if (is_array($cur_val)) { - if ($cur_val['members']==1) { - $cur_val['value'][$cur_val['name']] = $XML_RPC_xh[$parser]['value']; - } - array_unshift($XML_RPC_xh[$parser]['valuestack'], $cur_val); + $parser = (int) $parser_resource; + + if ($XML_RPC_xh[$parser]['isf'] >= 2) { + return; } - break; - case 'DATA': - $XML_RPC_xh[$parser]['ac'] = ''; - $XML_RPC_xh[$parser]['qt'] = 0; - break; - - case 'PARAM': - $XML_RPC_xh[$parser]['params'][] = $XML_RPC_xh[$parser]['value']; - break; - - case 'METHODNAME': - case 'RPCMETHODNAME': - $XML_RPC_xh[$parser]['method'] = preg_replace("@^[\n\r\t ]+@", '', - $XML_RPC_xh[$parser]['ac']); - break; - } + // push this element from stack + // NB: if XML validates, correct opening/closing is guaranteed and + // we do not have to check for $name == $curr_elem. + // we also checked for proper nesting at start of elements... + $curr_elem = array_shift($XML_RPC_xh[$parser]['stack']); - // if it's a valid type name, set the type - if (isset($GLOBALS['XML_RPC_Types'][strtolower($name)])) { - $XML_RPC_xh[$parser]['vt'] = strtolower($name); - } -} + switch ($name) { + case 'STRUCT': + case 'ARRAY': + $cur_val = array_shift($XML_RPC_xh[$parser]['valuestack']); + $XML_RPC_xh[$parser]['value'] = $cur_val['value']; + $XML_RPC_xh[$parser]['vt'] = strtolower($name); + $XML_RPC_xh[$parser]['cm']--; + break; -/** - * Character data handler for the XML parser - * - * @return void - */ -function XML_RPC_cd($parser_resource, $data) -{ - global $XML_RPC_xh, $XML_RPC_backslash; + case 'NAME': + $XML_RPC_xh[$parser]['valuestack'][0]['name'] = $XML_RPC_xh[$parser]['ac']; + break; + + case 'BOOLEAN': + // special case here: we translate boolean 1 or 0 into PHP + // constants true or false + if ($XML_RPC_xh[$parser]['ac'] == '1') { + $XML_RPC_xh[$parser]['ac'] = 'true'; + } else { + $XML_RPC_xh[$parser]['ac'] = 'false'; + } + + $XML_RPC_xh[$parser]['vt'] = strtolower($name); + // Drop through intentionally. + + case 'I4': + case 'INT': + case 'STRING': + case 'DOUBLE': + case 'DATETIME.ISO8601': + case 'BASE64': + if ($XML_RPC_xh[$parser]['qt'] == 1) { + // we use double quotes rather than single so backslashification works OK + $XML_RPC_xh[$parser]['value'] = $XML_RPC_xh[$parser]['ac']; + } elseif ($XML_RPC_xh[$parser]['qt'] == 2) { + $XML_RPC_xh[$parser]['value'] = base64_decode($XML_RPC_xh[$parser]['ac']); + } elseif ($name == 'BOOLEAN') { + $XML_RPC_xh[$parser]['value'] = $XML_RPC_xh[$parser]['ac']; + } else { + // we have an I4, INT or a DOUBLE + // we must check that only 0123456789-. are characters here + if (!preg_match("@^[+-]?[0123456789 \t\.]+$@", $XML_RPC_xh[$parser]['ac'])) { + XML_RPC_Base::raiseErrorStatic('Non-numeric value received in INT or DOUBLE', + XML_RPC_ERROR_NON_NUMERIC_FOUND); + $XML_RPC_xh[$parser]['value'] = XML_RPC_ERROR_NON_NUMERIC_FOUND; + } else { + // it's ok, add it on + $XML_RPC_xh[$parser]['value'] = $XML_RPC_xh[$parser]['ac']; + } + } + + $XML_RPC_xh[$parser]['ac'] = ''; + $XML_RPC_xh[$parser]['qt'] = 0; + $XML_RPC_xh[$parser]['lv'] = 3; // indicate we've found a value + break; + + case 'VALUE': + if ($XML_RPC_xh[$parser]['vt'] == $GLOBALS['XML_RPC_String']) { + if (strlen($XML_RPC_xh[$parser]['ac']) > 0) { + $XML_RPC_xh[$parser]['value'] = $XML_RPC_xh[$parser]['ac']; + } elseif ($XML_RPC_xh[$parser]['lv'] == 1) { + // The element was empty. + $XML_RPC_xh[$parser]['value'] = ''; + } + } + + $temp = new XML_RPC_Value($XML_RPC_xh[$parser]['value'], $XML_RPC_xh[$parser]['vt']); - $parser = (int) $parser_resource; + $cur_val = array_shift($XML_RPC_xh[$parser]['valuestack']); + if (is_array($cur_val)) { + if ($cur_val['members'] == 0) { + $cur_val['value'][] = $temp; + } else { + $XML_RPC_xh[$parser]['value'] = $temp; + } + array_unshift($XML_RPC_xh[$parser]['valuestack'], $cur_val); + } else { + $XML_RPC_xh[$parser]['value'] = $temp; + } + break; + + case 'MEMBER': + $XML_RPC_xh[$parser]['ac'] = ''; + $XML_RPC_xh[$parser]['qt'] = 0; + + $cur_val = array_shift($XML_RPC_xh[$parser]['valuestack']); + if (is_array($cur_val)) { + if ($cur_val['members'] == 1) { + $cur_val['value'][$cur_val['name']] = $XML_RPC_xh[$parser]['value']; + } + array_unshift($XML_RPC_xh[$parser]['valuestack'], $cur_val); + } + break; + + case 'DATA': + $XML_RPC_xh[$parser]['ac'] = ''; + $XML_RPC_xh[$parser]['qt'] = 0; + break; - if ($XML_RPC_xh[$parser]['lv'] != 3) { - // "lookforvalue==3" means that we've found an entire value - // and should discard any further character data + case 'PARAM': + $XML_RPC_xh[$parser]['params'][] = $XML_RPC_xh[$parser]['value']; + break; + + case 'METHODNAME': + case 'RPCMETHODNAME': + $XML_RPC_xh[$parser]['method'] = preg_replace("@^[\n\r\t ]+@", '', + $XML_RPC_xh[$parser]['ac']); + break; + } - if ($XML_RPC_xh[$parser]['lv'] == 1) { - // if we've found text and we're just in a then - // turn quoting on, as this will be a string - $XML_RPC_xh[$parser]['qt'] = 1; - // and say we've found a value - $XML_RPC_xh[$parser]['lv'] = 2; + // if it's a valid type name, set the type + if (isset($GLOBALS['XML_RPC_Types'][strtolower($name)])) { + $XML_RPC_xh[$parser]['vt'] = strtolower($name); } + } + + /** + * Character data handler for the XML parser + * + * @param resource $parser_resource + * @param mixed $data + * @return void + */ + public static function cd($parser_resource, $data) + { + global $XML_RPC_xh; + + $parser = (int) $parser_resource; + + if ($XML_RPC_xh[$parser]['lv'] != 3) { + // "lookforvalue==3" means that we've found an entire value + // and should discard any further character data - // replace characters that eval would - // do special things with - if (!isset($XML_RPC_xh[$parser]['ac'])) { - $XML_RPC_xh[$parser]['ac'] = ''; + if ($XML_RPC_xh[$parser]['lv'] == 1) { + // if we've found text and we're just in a then + // turn quoting on, as this will be a string + $XML_RPC_xh[$parser]['qt'] = 1; + // and say we've found a value + $XML_RPC_xh[$parser]['lv'] = 2; + } + + // replace characters that eval would + // do special things with + if (!isset($XML_RPC_xh[$parser]['ac'])) { + $XML_RPC_xh[$parser]['ac'] = ''; + } + $XML_RPC_xh[$parser]['ac'] .= $data; } - $XML_RPC_xh[$parser]['ac'] .= $data; } } @@ -548,33 +730,39 @@ function XML_RPC_cd($parser_resource, $data) * @version Release: @package_version@ * @link http://pear.php.net/package/XML_RPC */ -class XML_RPC_Base { +class XML_RPC_Base +{ + /** + * PEAR Error handling + * + * @param string $msg + * @param int $code + * @return PEAR_Error + */ + public function raiseError($msg, $code) + { + return PEAR::raiseError(get_class($this) . ': ' . $msg, $code); + } /** * PEAR Error handling * - * @return object PEAR_Error object + * @param string $msg + * @param int $code + * @return PEAR_Error */ - function raiseError($msg, $code) + public static function raiseErrorStatic($msg, $code) { - include_once 'PEAR.php'; - if (is_object(@$this)) { - return PEAR::raiseError(get_class($this) . ': ' . $msg, $code); - } else { - return PEAR::raiseError('XML_RPC: ' . $msg, $code); - } + return PEAR::raiseError('XML_RPC: ' . $msg, $code); } /** * Tell whether something is a PEAR_Error object * - * @param mixed $value the item to check - * + * @param mixed $value the item to check * @return bool whether $value is a PEAR_Error object or not - * - * @access public */ - function isError($value) + public function isError($value) { return is_object($value) && is_a($value, 'PEAR_Error'); } @@ -594,160 +782,167 @@ function isError($value) * @version Release: @package_version@ * @link http://pear.php.net/package/XML_RPC */ -class XML_RPC_Client extends XML_RPC_Base { - +class XML_RPC_Client extends XML_RPC_Base +{ /** * The path and name of the RPC server script you want the request to go to + * * @var string */ - var $path = ''; + private $path = ''; /** * The name of the remote server to connect to + * * @var string */ - var $server = ''; + private $server = ''; /** * The protocol to use in contacting the remote server + * * @var string */ - var $protocol = 'http://'; + private $protocol = 'http://'; /** * The port for connecting to the remote server - * * The default is 80 for http:// connections * and 443 for https:// and ssl:// connections. * * @var integer */ - var $port = 80; + private $port = 80; /** * A user name for accessing the RPC server + * * @var string * @see XML_RPC_Client::setCredentials() */ - var $username = ''; + private $userName = ''; /** * A password for accessing the RPC server + * * @var string * @see XML_RPC_Client::setCredentials() */ - var $password = ''; + private $password = ''; /** * The name of the proxy server to use, if any + * * @var string */ - var $proxy = ''; + private $proxy = ''; /** * The protocol to use in contacting the proxy server, if any + * * @var string */ - var $proxy_protocol = 'http://'; + private $proxyProtocol = 'http://'; /** * The port for connecting to the proxy server - * * The default is 8080 for http:// connections * and 443 for https:// and ssl:// connections. * * @var integer */ - var $proxy_port = 8080; + private $proxyPort = 8080; /** * A user name for accessing the proxy server + * * @var string */ - var $proxy_user = ''; + private $proxyUser = ''; /** * A password for accessing the proxy server + * * @var string */ - var $proxy_pass = ''; + private $proxyPass = ''; /** * The error number, if any + * * @var integer */ - var $errno = 0; + private $errNo = 0; /** * The error message, if any + * * @var string */ - var $errstr = ''; + private $errString = ''; /** * The current debug mode (1 = on, 0 = off) + * * @var integer */ - var $debug = 0; + private $debug = 0; /** * The HTTP headers for the current request. + * * @var string */ - var $headers = ''; - + private $headers = ''; /** * Sets the object's properties * - * @param string $path the path and name of the RPC server script + * @param string $path the path and name of the RPC server script * you want the request to go to - * @param string $server the URL of the remote server to connect to. + * @param string $server the URL of the remote server to connect to. * If this parameter doesn't specify a * protocol and $port is 443, ssl:// is * assumed. - * @param integer $port a port for connecting to the remote server. + * @param integer $port a port for connecting to the remote server. * Defaults to 80 for http:// connections and * 443 for https:// and ssl:// connections. - * @param string $proxy the URL of the proxy server to use, if any. + * @param string $proxy the URL of the proxy server to use, if any. * If this parameter doesn't specify a * protocol and $port is 443, ssl:// is * assumed. - * @param integer $proxy_port a port for connecting to the remote server. + * @param integer $proxyPort a port for connecting to the remote server. * Defaults to 8080 for http:// connections and * 443 for https:// and ssl:// connections. - * @param string $proxy_user a user name for accessing the proxy server - * @param string $proxy_pass a password for accessing the proxy server - * - * @return void + * @param string $proxyUser a user name for accessing the proxy server + * @param string $proxyPass a password for accessing the proxy server */ - function XML_RPC_Client($path, $server, $port = 0, - $proxy = '', $proxy_port = 0, - $proxy_user = '', $proxy_pass = '') + public function __construct($path, $server, $port = 0, $proxy = '', $proxyPort = 0, $proxyUser = '', $proxyPass = '') { - $this->path = $path; - $this->proxy_user = $proxy_user; - $this->proxy_pass = $proxy_pass; + $this->path = $path; + $this->proxyUser = $proxyUser; + $this->proxyPass = $proxyPass; preg_match('@^(http://|https://|ssl://)?(.*)$@', $server, $match); + if ($match[1] == '') { if ($port == 443) { - $this->server = $match[2]; + $this->server = $match[2]; $this->protocol = 'ssl://'; - $this->port = 443; + $this->port = 443; } else { $this->server = $match[2]; if ($port) { $this->port = $port; } } - } elseif ($match[1] == 'http://') { + } elseif ($match[1] === 'http://') { $this->server = $match[2]; if ($port) { $this->port = $port; } } else { - $this->server = $match[2]; + $this->server = $match[2]; $this->protocol = 'ssl://'; if ($port) { $this->port = $port; @@ -758,29 +953,30 @@ function XML_RPC_Client($path, $server, $port = 0, if ($proxy) { preg_match('@^(http://|https://|ssl://)?(.*)$@', $proxy, $match); + if ($match[1] == '') { - if ($proxy_port == 443) { - $this->proxy = $match[2]; - $this->proxy_protocol = 'ssl://'; - $this->proxy_port = 443; + if ($proxyPort == 443) { + $this->proxy = $match[2]; + $this->proxyProtocol = 'ssl://'; + $this->proxyPort = 443; } else { $this->proxy = $match[2]; - if ($proxy_port) { - $this->proxy_port = $proxy_port; + if ($proxyPort) { + $this->proxyPort = $proxyPort; } } - } elseif ($match[1] == 'http://') { + } elseif ($match[1] === 'http://') { $this->proxy = $match[2]; - if ($proxy_port) { - $this->proxy_port = $proxy_port; + if ($proxyPort) { + $this->proxyPort = $proxyPort; } } else { - $this->proxy = $match[2]; - $this->proxy_protocol = 'ssl://'; - if ($proxy_port) { - $this->proxy_port = $proxy_port; + $this->proxy = $match[2]; + $this->proxyProtocol = 'ssl://'; + if ($proxyPort) { + $this->proxyPort = $proxyPort; } else { - $this->proxy_port = 443; + $this->proxyPort = 443; } } } @@ -789,107 +985,95 @@ function XML_RPC_Client($path, $server, $port = 0, /** * Change the current debug mode * - * @param int $in where 1 = on, 0 = off - * + * @param int $in where 1 = on, 0 = off * @return void */ - function setDebug($in) + public function setDebug($in) { - if ($in) { - $this->debug = 1; - } else { - $this->debug = 0; - } + $this->debug = $in ? 1 : 0; + } + + /** + * @return string + */ + public function getErrorString() + { + return $this->errString; } /** * Sets whether strings that contain characters which may cause PHP's * SAX-based XML parser to break should be automatically base64 encoded - * * This is is a workaround for systems that don't have PHP's mbstring * extension available. * - * @param int $in where 1 = on, 0 = off - * + * @param int $in where 1 = on, 0 = off * @return void */ - function setAutoBase64($in) + public function setAutoBase64($in) { - if ($in) { - $GLOBALS['XML_RPC_auto_base64'] = true; - } else { - $GLOBALS['XML_RPC_auto_base64'] = false; - } + $GLOBALS['XML_RPC_auto_base64'] = $in ? true : false; } /** * Set username and password properties for connecting to the RPC server * - * @param string $u the user name - * @param string $p the password - * + * @param string $u the user name + * @param string $p the password * @return void - * - * @see XML_RPC_Client::$username, XML_RPC_Client::$password + * @see XML_RPC_Client::$userName, XML_RPC_Client::$password */ - function setCredentials($u, $p) + public function setCredentials($u, $p) { - $this->username = $u; + $this->userName = $u; $this->password = $p; } /** * Transmit the RPC request via HTTP 1.0 protocol * - * @param object $msg the XML_RPC_Message object - * @param int $timeout how many seconds to wait for the request - * - * @return object an XML_RPC_Response object. 0 is returned if any - * problems happen. - * + * @param XML_RPC_Message $msg the XML_RPC_Message object + * @param int $timeout how many seconds to wait for the request + * @return XML_RPC_Response|int 0 is returned if any problems happen. * @see XML_RPC_Message, XML_RPC_Client::XML_RPC_Client(), - * XML_RPC_Client::setCredentials() + * XML_RPC_Client::setCredentials() */ - function send($msg, $timeout = 0) + public function send($msg, $timeout = 0) { if (!is_object($msg) || !is_a($msg, 'XML_RPC_Message')) { - $this->errstr = 'send()\'s $msg parameter must be an' - . ' XML_RPC_Message object.'; - $this->raiseError($this->errstr, XML_RPC_ERROR_PROGRAMMING); + $this->errString = 'send()\'s $msg parameter must be an' . ' XML_RPC_Message object.'; + $this->raiseError($this->errString, XML_RPC_ERROR_PROGRAMMING); + return 0; } - $msg->debug = $this->debug; + + $msg->setDebug($this->debug); + return $this->sendPayloadHTTP10($msg, $this->server, $this->port, - $timeout, $this->username, - $this->password); + $timeout, $this->userName, + $this->password); } /** * Transmit the RPC request via HTTP 1.0 protocol - * * Requests should be sent using XML_RPC_Client send() rather than * calling this method directly. * - * @param object $msg the XML_RPC_Message object - * @param string $server the server to send the request to - * @param int $port the server port send the request to - * @param int $timeout how many seconds to wait for the request - * before giving up - * @param string $username a user name for accessing the RPC server - * @param string $password a password for accessing the RPC server - * - * @return object an XML_RPC_Response object. 0 is returned if any - * problems happen. - * - * @access protected + * @param XML_RPC_Message $msg the XML_RPC_Message object + * @param string $server the server to send the request to + * @param int $port the server port send the request to + * @param int $timeout how many seconds to wait for the request + * before giving up + * @param string $userName a user name for accessing the RPC server + * @param string $password a password for accessing the RPC server + * @return XML_RPC_Response|int 0 is returned if any problems happen. * @see XML_RPC_Client::send() */ - function sendPayloadHTTP10($msg, $server, $port, $timeout = 0, - $username = '', $password = '') + protected function sendPayloadHTTP10(XML_RPC_Message $msg, $server, $port, $timeout = 0, $userName = '', $password = '') { - // Pre-emptive BC hacks for fools calling sendPayloadHTTP10() directly - if ($username != $this->username) { - $this->setCredentials($username, $password); + // Preemptive BC hacks for fools calling sendPayloadHTTP10() directly + if ($userName != $this->userName) { + $this->setCredentials($userName, $password); } // Only create the payload if it was not created previously @@ -898,13 +1082,13 @@ function sendPayloadHTTP10($msg, $server, $port, $timeout = 0, } $this->createHeaders($msg); - $op = $this->headers . "\r\n\r\n"; + $op = $this->headers . "\r\n\r\n"; $op .= $msg->payload; if ($this->debug) { - print "\n
---SENT---\n";
-            print $op;
-            print "\n---END---
\n"; + echo "\n
---SENT---\n";
+            echo $op;
+            echo "\n---END---
\n"; } /* @@ -912,30 +1096,31 @@ function sendPayloadHTTP10($msg, $server, $port, $timeout = 0, * instead to the xml-rpc server */ if ($this->proxy) { - if ($this->proxy_protocol == 'http://') { + if ($this->proxyProtocol === 'http://') { $protocol = ''; } else { - $protocol = $this->proxy_protocol; + $protocol = $this->proxyProtocol; } if ($timeout > 0) { - $fp = @fsockopen($protocol . $this->proxy, $this->proxy_port, - $this->errno, $this->errstr, $timeout); + $fp = @fsockopen($protocol . $this->proxy, $this->proxyPort, + $this->errNo, $this->errString, $timeout); } else { - $fp = @fsockopen($protocol . $this->proxy, $this->proxy_port, - $this->errno, $this->errstr); + $fp = @fsockopen($protocol . $this->proxy, $this->proxyPort, + $this->errNo, $this->errString); } } else { - if ($this->protocol == 'http://') { + if ($this->protocol === 'http://') { $protocol = ''; } else { $protocol = $this->protocol; } + if ($timeout > 0) { $fp = @fsockopen($protocol . $server, $port, - $this->errno, $this->errstr, $timeout); + $this->errNo, $this->errString, $timeout); } else { $fp = @fsockopen($protocol . $server, $port, - $this->errno, $this->errstr); + $this->errNo, $this->errString); } } @@ -945,15 +1130,17 @@ function sendPayloadHTTP10($msg, $server, $port, $timeout = 0, */ if (!$fp && $this->proxy) { $this->raiseError('Connection to proxy server ' - . $this->proxy . ':' . $this->proxy_port - . ' failed. ' . $this->errstr, - XML_RPC_ERROR_CONNECTION_FAILED); + . $this->proxy . ':' . $this->proxyPort + . ' failed. ' . $this->errString, + XML_RPC_ERROR_CONNECTION_FAILED); + return 0; } elseif (!$fp) { $this->raiseError('Connection to RPC server ' - . $server . ':' . $port - . ' failed. ' . $this->errstr, - XML_RPC_ERROR_CONNECTION_FAILED); + . $server . ':' . $port + . ' failed. ' . $this->errString, + XML_RPC_ERROR_CONNECTION_FAILED); + return 0; } @@ -966,7 +1153,8 @@ function sendPayloadHTTP10($msg, $server, $port, $timeout = 0, } if (!fputs($fp, $op, strlen($op))) { - $this->errstr = 'Write error'; + $this->errString = 'Write error'; + return 0; } $resp = $msg->parseResponseFile($fp); @@ -974,57 +1162,56 @@ function sendPayloadHTTP10($msg, $server, $port, $timeout = 0, $meta = socket_get_status($fp); if ($meta['timed_out']) { fclose($fp); - $this->errstr = 'RPC server did not send response before timeout.'; - $this->raiseError($this->errstr, XML_RPC_ERROR_CONNECTION_FAILED); + $this->errString = 'RPC server did not send response before timeout.'; + $this->raiseError($this->errString, XML_RPC_ERROR_CONNECTION_FAILED); + return 0; } fclose($fp); + return $resp; } /** * Determines the HTTP headers and puts it in the $headers property * - * @param object $msg the XML_RPC_Message object - * + * @param object $msg the XML_RPC_Message object * @return boolean TRUE if okay, FALSE if the message payload isn't set. - * - * @access protected */ - function createHeaders($msg) + protected function createHeaders($msg) { if (empty($msg->payload)) { return false; } if ($this->proxy) { $this->headers = 'POST ' . $this->protocol . $this->server; - if ($this->proxy_port) { + if ($this->proxyPort) { $this->headers .= ':' . $this->port; } } else { - $this->headers = 'POST '; + $this->headers = 'POST '; } - $this->headers .= $this->path. " HTTP/1.0\r\n"; - + $this->headers .= $this->path . " HTTP/1.0\r\n"; $this->headers .= "User-Agent: PEAR XML_RPC\r\n"; $this->headers .= 'Host: ' . $this->server . "\r\n"; - if ($this->proxy && $this->proxy_user) { + if ($this->proxy && $this->proxyUser) { $this->headers .= 'Proxy-Authorization: Basic ' - . base64_encode("$this->proxy_user:$this->proxy_pass") - . "\r\n"; + . base64_encode("$this->proxyUser:$this->proxyPass") + . "\r\n"; } // thanks to Grant Rauscher for this - if ($this->username) { + if ($this->userName) { $this->headers .= 'Authorization: Basic ' - . base64_encode("$this->username:$this->password") - . "\r\n"; + . base64_encode("{$this->userName}:{$this->password}") + . "\r\n"; } $this->headers .= "Content-Type: text/xml\r\n"; $this->headers .= 'Content-Length: ' . strlen($msg->payload); + return true; } } @@ -1045,78 +1232,111 @@ function createHeaders($msg) */ class XML_RPC_Response extends XML_RPC_Base { - var $xv; - var $fn; - var $fs; - var $hdrs; + /** + * @var int|XML_RPC_Value + */ + private $value; /** - * @return void + * @var int + */ + private $faultCode; + + /** + * @var string + */ + private $faultString; + + /** + * @var array */ - function XML_RPC_Response($val, $fcode = 0, $fstr = '') + private $headers = array(); + + /** + * XML_RPC_Response constructor. + * + * @param XML_RPC_Value|int $value + * @param int $faultCode + * @param string $faultString + */ + public function __construct($value, $faultCode = 0, $faultString = '') { - if ($fcode != 0) { - $this->fn = $fcode; - $this->fs = htmlspecialchars($fstr); + if ($faultCode != 0) { + $this->faultCode = $faultCode; + $this->faultString = htmlspecialchars($faultString); } else { - $this->xv = $val; + $this->setValue($value); } } /** * @return int the error code */ - function faultCode() + public function faultCode() { - if (isset($this->fn)) { - return $this->fn; - } else { - return 0; - } + return isset($this->faultCode) ? $this->faultCode : 0; } /** * @return string the error string */ - function faultString() + public function faultString() { - return $this->fs; + return $this->faultString; } /** * @return mixed the value */ - function value() + public function value() + { + return $this->value; + } + + /** + * Setter function + * + * @param XML_RPC_Value|int $value + */ + public function setValue($value) + { + $this->value = $value; + } + + public function setHeaders(array $headers) { - return $this->xv; + $this->headers = $headers; } /** * @return string the error message in XML format */ - function serialize() + public function serialize() { $rs = "\n"; - if ($this->fn) { + + if ($this->faultCode) { $rs .= " faultCode - " . $this->fn . " + " . $this->faultCode . " faultString - " . $this->fs . " + " . $this->faultString . " "; } else { - $rs .= "\n\n" . $this->xv->serialize() . - "\n"; + $rs .= "\n\n" . $this->value->serialize() . + "\n"; } + $rs .= "\n"; + return $rs; } } @@ -1140,111 +1360,123 @@ class XML_RPC_Message extends XML_RPC_Base /** * Should the payload's content be passed through mb_convert_encoding()? * - * @see XML_RPC_Message::setConvertPayloadEncoding() + * @see XML_RPC_Message::setConvertPayloadEncoding() * @since Property available since Release 1.5.1 * @var boolean */ - var $convert_payload_encoding = false; + private $convert_payload_encoding = false; /** * The current debug mode (1 = on, 0 = off) + * * @var integer */ - var $debug = 0; + private $debug = 0; /** * The encoding to be used for outgoing messages - * * Defaults to the value of $GLOBALS['XML_RPC_defencoding'] * * @var string * @see XML_RPC_Message::setSendEncoding(), * $GLOBALS['XML_RPC_defencoding'], XML_RPC_Message::xml_header() */ - var $send_encoding = ''; + private $send_encoding = ''; /** * The method presently being evaluated + * * @var string */ - var $methodname = ''; + private $methodName = ''; /** * @var array */ - var $params = array(); + private $params = array(); /** * The XML message being generated + * * @var string */ - var $payload = ''; + public $payload = ''; /** * Should extra line breaks be removed from the payload? + * * @since Property available since Release 1.4.6 * @var boolean */ - var $remove_extra_lines = true; + private $remove_extra_lines = true; /** * The XML response from the remote server + * * @since Property available since Release 1.4.6 * @var string */ - var $response_payload = ''; - + private $response_payload = ''; /** - * @return void + * XML_RPC_Message constructor. + * + * @param string $method + * @param array $params */ - function XML_RPC_Message($meth, $pars = 0) + public function __construct($method, array $params = array()) { - $this->methodname = $meth; - if (is_array($pars) && sizeof($pars) > 0) { - for ($i = 0; $i < sizeof($pars); $i++) { - $this->addParam($pars[$i]); + $this->methodName = $method; + + if (count($params) > 0) { + foreach ($params as $param) { + $this->addParam($param); } } } + /** + * @param int $switch + */ + public function setDebug($switch) + { + $this->debug = $switch ? 1 : 0; + } + /** * Produces the XML declaration including the encoding attribute - * * The encoding is determined by this class' $send_encoding * property. If the $send_encoding property is not set, use * $GLOBALS['XML_RPC_defencoding']. * * @return string the XML declaration and element - * * @see XML_RPC_Message::setSendEncoding(), * XML_RPC_Message::$send_encoding, $GLOBALS['XML_RPC_defencoding'] */ - function xml_header() + private function xml_header() { global $XML_RPC_defencoding; if (!$this->send_encoding) { $this->send_encoding = $XML_RPC_defencoding; } + return 'send_encoding . '"?>' - . "\n\n"; + . "\n\n"; } /** * @return string the closing tag */ - function xml_footer() + private function xml_footer() { return "\n"; } /** * Fills the XML_RPC_Message::$payload property - * * Part of the process makes sure all line endings are in DOS format * (CRLF), which is probably required by specifications. - * * If XML_RPC_Message::setConvertPayloadEncoding() was set to true, * the payload gets passed through mb_convert_encoding() * to ensure the payload matches the encoding set in the @@ -1252,27 +1484,29 @@ function xml_footer() * XML_RPC_Message::setSendEncoding(). * * @return void - * * @uses XML_RPC_Message::xml_header(), XML_RPC_Message::xml_footer() - * @see XML_RPC_Message::setSendEncoding(), $GLOBALS['XML_RPC_defencoding'], + * @see XML_RPC_Message::setSendEncoding(), $GLOBALS['XML_RPC_defencoding'], * XML_RPC_Message::setConvertPayloadEncoding() */ - function createPayload() + public function createPayload() { - $this->payload = $this->xml_header(); - $this->payload .= '' . $this->methodname . "\n"; - $this->payload .= "\n"; - for ($i = 0; $i < sizeof($this->params); $i++) { - $p = $this->params[$i]; - $this->payload .= "\n" . $p->serialize() . "\n"; + $this->payload = $this->xml_header() + . '' . $this->methodName . "\n" + . "\n"; + + foreach ($this->params as $param) { + $this->payload .= "\n" . $param->serialize() . "\n"; } - $this->payload .= "\n"; - $this->payload .= $this->xml_footer(); + + $this->payload .= "\n" + . $this->xml_footer(); + if ($this->remove_extra_lines) { $this->payload = preg_replace("@[\r\n]+@", "\r\n", $this->payload); } else { $this->payload = preg_replace("@\r\n|\n|\r|\n\r@", "\r\n", $this->payload); } + if ($this->convert_payload_encoding) { $this->payload = mb_convert_encoding($this->payload, $this->send_encoding); } @@ -1281,42 +1515,43 @@ function createPayload() /** * @return string the name of the method */ - function method($meth = '') + public function method($method = '') { - if ($meth != '') { - $this->methodname = $meth; + if ($method != '') { + $this->methodName = $method; } - return $this->methodname; + + return $this->methodName; } /** * @return string the payload */ - function serialize() + public function serialize() { $this->createPayload(); + return $this->payload; } /** + * @param mixed $param * @return void */ - function addParam($par) + public function addParam($param) { - $this->params[] = $par; + $this->params[] = $param; } /** * Obtains an XML_RPC_Value object for the given parameter * - * @param int $i the index number of the parameter to obtain - * + * @param int $i the index number of the parameter to obtain * @return object the XML_RPC_Value object. * If the parameter doesn't exist, an XML_RPC_Response object. - * * @since Returns XML_RPC_Response object on error since Release 1.3.0 */ - function getParam($i) + public function getParam($i) { global $XML_RPC_err, $XML_RPC_str; @@ -1324,53 +1559,50 @@ function getParam($i) return $this->params[$i]; } else { $this->raiseError('The submitted request did not contain this parameter', - XML_RPC_ERROR_INCORRECT_PARAMS); + XML_RPC_ERROR_INCORRECT_PARAMS); + return new XML_RPC_Response(0, $XML_RPC_err['incorrect_params'], - $XML_RPC_str['incorrect_params']); + $XML_RPC_str['incorrect_params']); } } /** * @return int the number of parameters */ - function getNumParams() + public function getNumParams() { - return sizeof($this->params); + return count($this->params); } /** * Sets whether the payload's content gets passed through * mb_convert_encoding() - * * Returns PEAR_ERROR object if mb_convert_encoding() isn't available. * - * @param int $in where 1 = on, 0 = off - * - * @return void - * - * @see XML_RPC_Message::setSendEncoding() - * @since Method available since Release 1.5.1 + * @param int $in where 1 = on, 0 = off + * @return mixed + * @see XML_RPC_Message::setSendEncoding() + * @since Method available since Release 1.5.1 */ - function setConvertPayloadEncoding($in) + private function setConvertPayloadEncoding($in) { if ($in && !function_exists('mb_convert_encoding')) { return $this->raiseError('mb_convert_encoding() is not available', - XML_RPC_ERROR_PROGRAMMING); + XML_RPC_ERROR_PROGRAMMING); } + $this->convert_payload_encoding = $in; } /** * Sets the XML declaration's encoding attribute * - * @param string $type the encoding type (ISO-8859-1, UTF-8 or US-ASCII) - * + * @param string $type the encoding type (ISO-8859-1, UTF-8 or US-ASCII) * @return void - * - * @see XML_RPC_Message::setConvertPayloadEncoding(), XML_RPC_Message::xml_header() - * @since Method available since Release 1.2.0 + * @see XML_RPC_Message::setConvertPayloadEncoding(), XML_RPC_Message::xml_header() + * @since Method available since Release 1.2.0 */ - function setSendEncoding($type) + private function setSendEncoding($type) { $this->send_encoding = $type; } @@ -1378,25 +1610,22 @@ function setSendEncoding($type) /** * Determine the XML's encoding via the encoding attribute * in the XML declaration - * * If the encoding parameter is not set or is not ISO-8859-1, UTF-8 * or US-ASCII, $XML_RPC_defencoding will be returned. * - * @param string $data the XML that will be parsed - * + * @param string $data the XML that will be parsed * @return string the encoding to be used - * * @link http://php.net/xml_parser_create * @since Method available since Release 1.2.0 */ - function getEncoding($data) + public static function getEncoding($data) { global $XML_RPC_defencoding; if (preg_match('@<\?xml[^>]*\s*encoding\s*=\s*[\'"]([^"\']*)[\'"]@', - $data, $match)) - { + $data, $match)) { $match[1] = trim(strtoupper($match[1])); + switch ($match[1]) { case 'ISO-8859-1': case 'UTF-8': @@ -1413,25 +1642,29 @@ function getEncoding($data) } /** - * @return object a new XML_RPC_Response object + * @param resource $fp + * @return XML_RPC_Response */ - function parseResponseFile($fp) + public function parseResponseFile($fp) { $ipd = ''; + while ($data = @fread($fp, 8192)) { $ipd .= $data; } + return $this->parseResponse($ipd); } /** - * @return object a new XML_RPC_Response object + * @param string $data + * @return XML_RPC_Response */ - function parseResponse($data = '') + private function parseResponse($data = '') { - global $XML_RPC_xh, $XML_RPC_err, $XML_RPC_str, $XML_RPC_defencoding; + global $XML_RPC_xh, $XML_RPC_err, $XML_RPC_str; - $encoding = $this->getEncoding($data); + $encoding = self::getEncoding($data); $parser_resource = xml_parser_create($encoding); $parser = (int) $parser_resource; @@ -1446,33 +1679,35 @@ function parseResponse($data = '') $XML_RPC_xh[$parser]['valuestack'] = array(); xml_parser_set_option($parser_resource, XML_OPTION_CASE_FOLDING, true); - xml_set_element_handler($parser_resource, 'XML_RPC_se', 'XML_RPC_ee'); - xml_set_character_data_handler($parser_resource, 'XML_RPC_cd'); + xml_set_element_handler($parser_resource, 'XML_RPC::startElement', 'XML_RPC::endElement'); + xml_set_character_data_handler($parser_resource, 'XML_RPC::cd'); $hdrfnd = 0; if ($this->debug) { - print "\n
---GOT---\n";
-            print isset($_SERVER['SERVER_PROTOCOL']) ? htmlspecialchars($data) : $data;
-            print "\n---END---
\n"; + echo "\n
---GOT---\n";
+            echo isset($_SERVER['SERVER_PROTOCOL']) ? htmlspecialchars($data) : $data;
+            echo "\n---END---
\n"; } // See if response is a 200 or a 100 then a 200, else raise error. // But only do this if we're using the HTTP protocol. if (preg_match('@^HTTP@', $data) && !preg_match('@^HTTP/[0-9\.]+ 200 @', $data) && - !preg_match('@^HTTP/[0-9\.]+ 10[0-9]([A-Z ]+)?[\r\n]+HTTP/[0-9\.]+ 200@', $data)) - { - $errstr = substr($data, 0, strpos($data, "\n") - 1); - error_log('HTTP error, got response: ' . $errstr); - $r = new XML_RPC_Response(0, $XML_RPC_err['http_error'], - $XML_RPC_str['http_error'] . ' (' . - $errstr . ')'); - xml_parser_free($parser_resource); - return $r; + !preg_match('@^HTTP/[0-9\.]+ 10[0-9]([A-Z ]+)?[\r\n]+HTTP/[0-9\.]+ 200@', $data) + ) { + $errorString = substr($data, 0, strpos($data, "\n") - 1); + error_log('HTTP error, got response: ' . $errorString); + $r = new XML_RPC_Response(0, $XML_RPC_err['http_error'], + $XML_RPC_str['http_error'] . ' (' . + $errorString . ')' + ); + xml_parser_free($parser_resource); + + return $r; } // gotta get rid of headers here - if (!$hdrfnd && ($brpos = strpos($data,"\r\n\r\n"))) { + if (!$hdrfnd && ($brpos = strpos($data, "\r\n\r\n"))) { $XML_RPC_xh[$parser]['ha'] = substr($data, 0, $brpos); $data = substr($data, $brpos + 4); $hdrfnd = 1; @@ -1483,54 +1718,57 @@ function parseResponse($data = '') * (e.g. javascript automatically inserted by free hosts) * thanks to Luca Mariano */ - $data = substr($data, 0, strpos($data, "") + 17); + $data = substr($data, 0, strpos($data, '') + strlen('')); $this->response_payload = $data; if (!xml_parse($parser_resource, $data, sizeof($data))) { // thanks to Peter Kocks if (xml_get_current_line_number($parser_resource) == 1) { - $errstr = 'XML error at line 1, check URL'; + $errorString = 'XML error at line 1, check URL'; } else { - $errstr = sprintf('XML error: %s at line %d', - xml_error_string(xml_get_error_code($parser_resource)), - xml_get_current_line_number($parser_resource)); + $errorString = sprintf('XML error: %s at line %d', + xml_error_string(xml_get_error_code($parser_resource)), + xml_get_current_line_number($parser_resource)); } - error_log($errstr); + error_log($errorString); $r = new XML_RPC_Response(0, $XML_RPC_err['invalid_return'], - $XML_RPC_str['invalid_return']); + $XML_RPC_str['invalid_return']); xml_parser_free($parser_resource); + return $r; } xml_parser_free($parser_resource); if ($this->debug) { - print "\n
---PARSED---\n";
+            echo "\n
---PARSED---\n";
             var_dump($XML_RPC_xh[$parser]['value']);
-            print "---END---
\n"; + echo "---END---
\n"; } if ($XML_RPC_xh[$parser]['isf'] > 1) { $r = new XML_RPC_Response(0, $XML_RPC_err['invalid_return'], - $XML_RPC_str['invalid_return'].' '.$XML_RPC_xh[$parser]['isf_reason']); + $XML_RPC_str['invalid_return'] . ' ' . $XML_RPC_xh[$parser]['isf_reason']); } elseif (!is_object($XML_RPC_xh[$parser]['value'])) { // then something odd has happened // and it's time to generate a client side error // indicating something odd went on $r = new XML_RPC_Response(0, $XML_RPC_err['invalid_return'], - $XML_RPC_str['invalid_return']); + $XML_RPC_str['invalid_return']); } else { $v = $XML_RPC_xh[$parser]['value']; if ($XML_RPC_xh[$parser]['isf']) { - $f = $v->structmem('faultCode'); - $fs = $v->structmem('faultString'); - $r = new XML_RPC_Response($v, $f->scalarval(), - $fs->scalarval()); + $f = $v->structMem('faultCode'); + $fs = $v->structMem('faultString'); + $r = new XML_RPC_Response($v, $f->scalarValue(), + $fs->scalarValue()); } else { $r = new XML_RPC_Response($v); } } - $r->hdrs = preg_split("@\r?\n@", $XML_RPC_xh[$parser]['ha']); + + $r->setHeaders(preg_split("@\r?\n@", $XML_RPC_xh[$parser]['ha'])); + return $r; } } @@ -1551,18 +1789,22 @@ function parseResponse($data = '') */ class XML_RPC_Value extends XML_RPC_Base { - var $me = array(); - var $mytype = 0; + private $me = array(); + private $myType = 0; /** - * @return void + * XML_RPC_Value constructor. + * + * @param int $val + * @param string $type */ - function XML_RPC_Value($val = -1, $type = '') + public function __construct($val = -1, $type = '') { $this->me = array(); - $this->mytype = 0; + $this->myType = 0; + if ($val != -1 || $type != '') { - if ($type == '') { + if ($type === '') { $type = 'string'; } if (!array_key_exists($type, $GLOBALS['XML_RPC_Types'])) { @@ -1579,87 +1821,101 @@ function XML_RPC_Value($val = -1, $type = '') } /** + * @param mixed $value + * @param string $type * @return int returns 1 if successful or 0 if there are problems */ - function addScalar($val, $type = 'string') + public function addScalar($value, $type = 'string') { - if ($this->mytype == 1) { + if ($this->myType == 1) { $this->raiseError('Scalar can have only one value', - XML_RPC_ERROR_INVALID_TYPE); + XML_RPC_ERROR_INVALID_TYPE); + return 0; } $typeof = $GLOBALS['XML_RPC_Types'][$type]; if ($typeof != 1) { $this->raiseError("Not a scalar type (${typeof})", - XML_RPC_ERROR_INVALID_TYPE); + XML_RPC_ERROR_INVALID_TYPE); + return 0; } if ($type == $GLOBALS['XML_RPC_Boolean']) { - if (strcasecmp($val, 'true') == 0 - || $val == 1 - || ($val == true && strcasecmp($val, 'false'))) - { - $val = 1; + if ((strcasecmp($value, 'true') === 0) + || ($value == 1) + || ($value == true && strcasecmp($value, 'false')) + ) { + $value = 1; } else { - $val = 0; + $value = 0; } } - if ($this->mytype == 2) { + if ($this->myType == 2) { // we're adding to an array here $ar = $this->me['array']; - $ar[] = new XML_RPC_Value($val, $type); + $ar[] = new XML_RPC_Value($value, $type); $this->me['array'] = $ar; } else { // a scalar, so set the value and remember we're scalar - $this->me[$type] = $val; - $this->mytype = $typeof; + $this->me[$type] = $value; + $this->myType = $typeof; } + return 1; } /** + * @param mixed $values * @return int returns 1 if successful or 0 if there are problems */ - function addArray($vals) + public function addArray($values) { - if ($this->mytype != 0) { + if ($this->myType != 0) { $this->raiseError( - 'Already initialized as a [' . $this->kindOf() . ']', - XML_RPC_ERROR_ALREADY_INITIALIZED); + 'Already initialized as a [' . $this->kindOf() . ']', + XML_RPC_ERROR_ALREADY_INITIALIZED + ); + return 0; } - $this->mytype = $GLOBALS['XML_RPC_Types']['array']; - $this->me['array'] = $vals; + + $this->myType = $GLOBALS['XML_RPC_Types']['array']; + $this->me['array'] = $values; + return 1; } /** + * @param mixed $values * @return int returns 1 if successful or 0 if there are problems */ - function addStruct($vals) + public function addStruct($values) { - if ($this->mytype != 0) { + if ($this->myType != 0) { $this->raiseError( - 'Already initialized as a [' . $this->kindOf() . ']', - XML_RPC_ERROR_ALREADY_INITIALIZED); + 'Already initialized as a [' . $this->kindOf() . ']', + XML_RPC_ERROR_ALREADY_INITIALIZED); + return 0; } - $this->mytype = $GLOBALS['XML_RPC_Types']['struct']; - $this->me['struct'] = $vals; + + $this->myType = $GLOBALS['XML_RPC_Types']['struct']; + $this->me['struct'] = $values; + return 1; } /** + * @param array $array * @return void */ - function dump($ar) + public function dump($array) { - reset($ar); - foreach ($ar as $key => $val) { + foreach ($array as $key => $val) { echo "$key => $val
"; - if ($key == 'array') { + if ($key === 'array') { foreach ($val as $key2 => $val2) { echo "-- $key2 => $val2
"; } @@ -1670,100 +1926,110 @@ function dump($ar) /** * @return string the data type of the current value */ - function kindOf() + public function kindOf() { - switch ($this->mytype) { - case 3: - return 'struct'; + switch ($this->myType) { + case 3: + return 'struct'; - case 2: - return 'array'; + case 2: + return 'array'; - case 1: - return 'scalar'; + case 1: + return 'scalar'; - default: - return 'undef'; + default: + return 'undef'; } } /** + * @param string $type + * @param mixed $val * @return string the data in XML format */ - function serializedata($typ, $val) + private function serializeData($type, $val) { $rs = ''; - if (!array_key_exists($typ, $GLOBALS['XML_RPC_Types'])) { + if (!array_key_exists($type, $GLOBALS['XML_RPC_Types'])) { // XXX // need some way to report this error - return; + return null; } - switch ($GLOBALS['XML_RPC_Types'][$typ]) { - case 3: - // struct - $rs .= "\n"; - reset($val); - foreach ($val as $key2 => $val2) { - $rs .= "" . htmlspecialchars($key2) . "\n"; - $rs .= $this->serializeval($val2); - $rs .= "\n"; - } - $rs .= ''; - break; - - case 2: - // array - $rs .= "\n\n"; - foreach ($val as $value) { - $rs .= $this->serializeval($value); - } - $rs .= "\n"; - break; - case 1: - switch ($typ) { - case $GLOBALS['XML_RPC_Base64']: - $rs .= "<${typ}>" . base64_encode($val) . ""; - break; - case $GLOBALS['XML_RPC_Boolean']: - $rs .= "<${typ}>" . ($val ? '1' : '0') . ""; + switch ($GLOBALS['XML_RPC_Types'][$type]) { + case 3: + // struct + $rs .= "\n"; + + foreach ($val as $key2 => $val2) { + $rs .= "" . htmlspecialchars($key2) . "\n"; + $rs .= $this->serializeValue($val2); + $rs .= "\n"; + } + $rs .= ''; break; - case $GLOBALS['XML_RPC_String']: - $rs .= "<${typ}>" . htmlspecialchars($val). ""; + + case 2: + // array + $rs .= "\n\n"; + + foreach ($val as $value) { + $rs .= $this->serializeValue($value); + } + $rs .= "\n"; break; - default: - $rs .= "<${typ}>${val}"; - } + + case 1: + switch ($type) { + case $GLOBALS['XML_RPC_Base64']: + $rs .= "<${type}>" . base64_encode($val) . ""; + break; + + case $GLOBALS['XML_RPC_Boolean']: + $rs .= "<${type}>" . ($val ? '1' : '0') . ""; + break; + + case $GLOBALS['XML_RPC_String']: + $rs .= "<${type}>" . htmlspecialchars($val) . ""; + break; + + default: + $rs .= "<${type}>${val}"; + } } + return $rs; } /** * @return string the data in XML format */ - function serialize() + public function serialize() { - return $this->serializeval($this); + return $this->serializeValue($this); } /** * @return string the data in XML format */ - function serializeval($o) + private function serializeValue($o) { if (!is_object($o) || empty($o->me) || !is_array($o->me)) { return ''; } + $ar = $o->me; reset($ar); list($typ, $val) = each($ar); - return '' . $this->serializedata($typ, $val) . "\n"; + + return '' . $this->serializeData($typ, $val) . "\n"; } /** * @return mixed the contents of the element requested */ - function structmem($m) + public function structMem($m) { return $this->me['struct'][$m]; } @@ -1771,15 +2037,15 @@ function structmem($m) /** * @return void */ - function structreset() + public function structReset() { reset($this->me['struct']); } /** - * @return the key/value pair of the struct's current element + * @return array the key/value pair of the struct's current element */ - function structeach() + public function structEach() { return each($this->me['struct']); } @@ -1787,7 +2053,7 @@ function structeach() /** * @return mixed the current value */ - function getval() + public function getValue() { // UNSTABLE @@ -1808,9 +2074,11 @@ function getval() // add support for structures directly encoding php objects if (is_object($b)) { $t = get_object_vars($b); + foreach ($t as $id => $cont) { - $t[$id] = $cont->scalarval(); + $t[$id] = $cont->scalarValue(); } + foreach ($t as $id => $cont) { $b->$id = $cont; } @@ -1824,33 +2092,35 @@ function getval() * @return mixed the current element's scalar value. If the value is * not scalar, FALSE is returned. */ - function scalarval() + public function scalarValue() { reset($this->me); $v = current($this->me); if (!is_scalar($v)) { $v = false; } + return $v; } /** * @return string */ - function scalartyp() + public function scalarTyp() { reset($this->me); $a = key($this->me); if ($a == $GLOBALS['XML_RPC_I4']) { $a = $GLOBALS['XML_RPC_Int']; } + return $a; } /** * @return mixed the struct's current element */ - function arraymem($m) + public function arrayMem($m) { return $this->me['array'][$m]; } @@ -1858,196 +2128,24 @@ function arraymem($m) /** * @return int the number of elements in the array */ - function arraysize() + public function arraySize() { reset($this->me); - list($a, $b) = each($this->me); + list(, $b) = each($this->me); + return sizeof($b); } /** * Determines if the item submitted is an XML_RPC_Value object * - * @param mixed $val the variable to be evaluated - * + * @param mixed $val the variable to be evaluated * @return bool TRUE if the item is an XML_RPC_Value object - * * @static * @since Method available since Release 1.3.0 */ - function isValue($val) + public static function isValue($val) { - return (strtolower(get_class($val)) == 'xml_rpc_value'); + return (strtolower(get_class($val)) === 'xml_rpc_value'); } } - -/** - * Return an ISO8601 encoded string - * - * While timezones ought to be supported, the XML-RPC spec says: - * - * "Don't assume a timezone. It should be specified by the server in its - * documentation what assumptions it makes about timezones." - * - * This routine always assumes localtime unless $utc is set to 1, in which - * case UTC is assumed and an adjustment for locale is made when encoding. - * - * @return string the formatted date - */ -function XML_RPC_iso8601_encode($timet, $utc = 0) -{ - if (!$utc) { - $t = strftime('%Y%m%dT%H:%M:%S', $timet); - } else { - if (function_exists('gmstrftime')) { - // gmstrftime doesn't exist in some versions - // of PHP - $t = gmstrftime('%Y%m%dT%H:%M:%S', $timet); - } else { - $t = strftime('%Y%m%dT%H:%M:%S', $timet - date('Z')); - } - } - return $t; -} - -/** - * Convert a datetime string into a Unix timestamp - * - * While timezones ought to be supported, the XML-RPC spec says: - * - * "Don't assume a timezone. It should be specified by the server in its - * documentation what assumptions it makes about timezones." - * - * This routine always assumes localtime unless $utc is set to 1, in which - * case UTC is assumed and an adjustment for locale is made when encoding. - * - * @return int the unix timestamp of the date submitted - */ -function XML_RPC_iso8601_decode($idate, $utc = 0) -{ - $t = 0; - if (preg_match('@([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})@', $idate, $regs)) { - if ($utc) { - $t = gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]); - } else { - $t = mktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]); - } - } - return $t; -} - -/** - * Converts an XML_RPC_Value object into native PHP types - * - * @param object $XML_RPC_val the XML_RPC_Value object to decode - * - * @return mixed the PHP values - */ -function XML_RPC_decode($XML_RPC_val) -{ - $kind = $XML_RPC_val->kindOf(); - - if ($kind == 'scalar') { - return $XML_RPC_val->scalarval(); - - } elseif ($kind == 'array') { - $size = $XML_RPC_val->arraysize(); - $arr = array(); - for ($i = 0; $i < $size; $i++) { - $arr[] = XML_RPC_decode($XML_RPC_val->arraymem($i)); - } - return $arr; - - } elseif ($kind == 'struct') { - $XML_RPC_val->structreset(); - $arr = array(); - while (list($key, $value) = $XML_RPC_val->structeach()) { - $arr[$key] = XML_RPC_decode($value); - } - return $arr; - } -} - -/** - * Converts native PHP types into an XML_RPC_Value object - * - * @param mixed $php_val the PHP value or variable you want encoded - * - * @return object the XML_RPC_Value object - */ -function XML_RPC_encode($php_val) -{ - $type = gettype($php_val); - $XML_RPC_val = new XML_RPC_Value; - - switch ($type) { - case 'array': - if (empty($php_val)) { - $XML_RPC_val->addArray($php_val); - break; - } - $tmp = array_diff(array_keys($php_val), range(0, count($php_val)-1)); - if (empty($tmp)) { - $arr = array(); - foreach ($php_val as $k => $v) { - $arr[$k] = XML_RPC_encode($v); - } - $XML_RPC_val->addArray($arr); - break; - } - // fall though if it's not an enumerated array - - case 'object': - $arr = array(); - foreach ($php_val as $k => $v) { - $arr[$k] = XML_RPC_encode($v); - } - $XML_RPC_val->addStruct($arr); - break; - - case 'integer': - $XML_RPC_val->addScalar($php_val, $GLOBALS['XML_RPC_Int']); - break; - - case 'double': - $XML_RPC_val->addScalar($php_val, $GLOBALS['XML_RPC_Double']); - break; - - case 'string': - case 'NULL': - if (preg_match('@^[0-9]{8}\T{1}[0-9]{2}\:[0-9]{2}\:[0-9]{2}$@', $php_val)) { - $XML_RPC_val->addScalar($php_val, $GLOBALS['XML_RPC_DateTime']); - } elseif ($GLOBALS['XML_RPC_auto_base64'] - && preg_match("@[^ -~\t\r\n]@", $php_val)) - { - // Characters other than alpha-numeric, punctuation, SP, TAB, - // LF and CR break the XML parser, encode value via Base 64. - $XML_RPC_val->addScalar($php_val, $GLOBALS['XML_RPC_Base64']); - } else { - $XML_RPC_val->addScalar($php_val, $GLOBALS['XML_RPC_String']); - } - break; - - case 'boolean': - // Add support for encoding/decoding of booleans, since they - // are supported in PHP - // by - $XML_RPC_val->addScalar($php_val, $GLOBALS['XML_RPC_Boolean']); - break; - - case 'unknown type': - default: - $XML_RPC_val = false; - } - return $XML_RPC_val; -} - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * c-hanging-comment-ender-p: nil - * End: - */ - -?> diff --git a/system/classes/XML/RPC/Server.php b/system/classes/XML/RPC/Server.php index c7d264390..18d3eabbe 100644 --- a/system/classes/XML/RPC/Server.php +++ b/system/classes/XML/RPC/Server.php @@ -1,7 +1,5 @@ dmap as $key => $val) { + foreach ($server->dispatchMap as $key => $val) { $outAr[] = new XML_RPC_Value($key, 'string'); } foreach ($XML_RPC_Server_dmap as $key => $val) { @@ -142,15 +135,17 @@ function XML_RPC_Server_listMethods($server, $m) * If no signatures are known, returns a none-array * (test for type != array to detect missing signature) * + * @param mixed $server + * @param XML_RPC_Message $m * @return object a new XML_RPC_Response object */ function XML_RPC_Server_methodSignature($server, $m) { global $XML_RPC_err, $XML_RPC_str, $XML_RPC_Server_dmap; - $methName = $m->getParam(0); - $methName = $methName->scalarval(); - if (strpos($methName, 'system.') === 0) { + $method = $m->getParam(0); + $methodName = $method->scalarValue(); + if (strpos($methodName, 'system.') === 0) { $dmap = $XML_RPC_Server_dmap; $sysCall = 1; } else { @@ -158,10 +153,10 @@ function XML_RPC_Server_methodSignature($server, $m) $sysCall = 0; } // print "\n"; - if (isset($dmap[$methName])) { - if ($dmap[$methName]['signature']) { + if (isset($dmap[$methodName])) { + if ($dmap[$methodName]['signature']) { $sigs = array(); - $thesigs = $dmap[$methName]['signature']; + $thesigs = $dmap[$methodName]['signature']; for ($i = 0; $i < sizeof($thesigs); $i++) { $cursig = array(); $inSig = $thesigs[$i]; @@ -185,15 +180,17 @@ function XML_RPC_Server_methodSignature($server, $m) * Returns help text if defined for the method passed, otherwise returns * an empty string * + * @param mixed $server + * @param XML_RPC_Message $m * @return object a new XML_RPC_Response object */ function XML_RPC_Server_methodHelp($server, $m) { global $XML_RPC_err, $XML_RPC_str, $XML_RPC_Server_dmap; - $methName = $m->getParam(0); - $methName = $methName->scalarval(); - if (strpos($methName, 'system.') === 0) { + $method = $m->getParam(0); + $methodName = $method->scalarValue(); + if (strpos($methodName, 'system.') === 0) { $dmap = $XML_RPC_Server_dmap; $sysCall = 1; } else { @@ -201,9 +198,9 @@ function XML_RPC_Server_methodHelp($server, $m) $sysCall = 0; } - if (isset($dmap[$methName])) { - if ($dmap[$methName]['docstring']) { - $r = new XML_RPC_Response(new XML_RPC_Value($dmap[$methName]['docstring']), + if (isset($dmap[$methodName])) { + if ($dmap[$methodName]['docstring']) { + $r = new XML_RPC_Response(new XML_RPC_Value($dmap[$methodName]['docstring']), 'string'); } else { $r = new XML_RPC_Response(new XML_RPC_Value('', 'string')); @@ -221,6 +218,7 @@ function XML_RPC_Server_methodHelp($server, $m) function XML_RPC_Server_debugmsg($m) { global $XML_RPC_Server_debuginfo; + $XML_RPC_Server_debuginfo = $XML_RPC_Server_debuginfo . $m . "\n"; } @@ -260,7 +258,7 @@ function XML_RPC_Server_debugmsg($m) * @version Release: @package_version@ * @link http://pear.php.net/package/XML_RPC */ -class XML_RPC_Server +class XML_RPC_Server extends XML_RPC_Base { /** * Should the payload's content be passed through mb_convert_encoding()? @@ -269,44 +267,45 @@ class XML_RPC_Server * @since Property available since Release 1.5.1 * @var boolean */ - var $convert_payload_encoding = false; + private $convert_payload_encoding = false; /** * The dispatch map, listing the methods this server provides. * @var array */ - var $dmap = array(); + public $dispatchMap = array(); /** * The present response's encoding * @var string * @see XML_RPC_Message::getEncoding() */ - var $encoding = ''; + private $encoding = ''; /** * Debug mode (0 = off, 1 = on) * @var integer */ - var $debug = 0; + private $debug = 0; /** * The response's HTTP headers * @var string */ - var $server_headers = ''; + private $server_headers = ''; /** * The response's XML payload * @var string */ - var $server_payload = ''; + private $server_payload = ''; /** * Constructor for the XML_RPC_Server class + * - * @param array $dispMap the dispatch map. An associative array +*@param array $dispatchMap the dispatch map. An associative array * explaining each function. The keys of the main * array are the procedure names used by the * clients. The value is another associative array @@ -319,24 +318,15 @@ class XML_RPC_Server * parameters * + The 'docstring' element (optional) is a * string describing what the method does - * @param int $serviceNow should the HTTP response be sent now? + * @param int $serviceNow should the HTTP response be sent now? * (1 = yes, 0 = no) - * @param int $debug should debug output be displayed? + * @param int $debug should debug output be displayed? * (1 = yes, 0 = no) - * - * @return void */ - function XML_RPC_Server($dispMap, $serviceNow = 1, $debug = 0) + public function __construct($dispatchMap, $serviceNow = 1, $debug = 0) { - global $HTTP_RAW_POST_DATA; - - if ($debug) { - $this->debug = 1; - } else { - $this->debug = 0; - } - - $this->dmap = $dispMap; + $this->debug = $debug ? 1 : 0; + $this->dispatchMap = $dispatchMap; if ($serviceNow) { $this->service(); @@ -349,7 +339,7 @@ function XML_RPC_Server($dispMap, $serviceNow = 1, $debug = 0) /** * @return string the debug information if debug debug mode is on */ - function serializeDebug() + private function serializeDebug() { global $XML_RPC_Server_debuginfo, $HTTP_RAW_POST_DATA; @@ -376,7 +366,7 @@ function serializeDebug() * * @param int $in where 1 = on, 0 = off * - * @return void + * @return void|mixed * * @see XML_RPC_Message::getEncoding() * @since Method available since Release 1.5.1 @@ -479,28 +469,30 @@ function createServerHeaders() } /** + * @param XML_RPC_Message $in + * @param array $sig * @return array */ - function verifySignature($in, $sig) + function verifySignature($in, array $sig) { - for ($i = 0; $i < sizeof($sig); $i++) { + for ($i = 0; $i < count($sig); $i++) { // check each possible signature in turn - $cursig = $sig[$i]; - if (sizeof($cursig) == $in->getNumParams() + 1) { + $currentSig = $sig[$i]; + if (count($currentSig) == $in->getNumParams() + 1) { $itsOK = 1; for ($n = 0; $n < $in->getNumParams(); $n++) { $p = $in->getParam($n); // print "\n"; - if ($p->kindOf() == 'scalar') { + if ($p->kindOf() === 'scalar') { $pt = $p->scalartyp(); } else { $pt = $p->kindOf(); } // $n+1 as first type of sig is return type - if ($pt != $cursig[$n+1]) { + if ($pt != $currentSig[$n+1]) { $itsOK = 0; $pno = $n+1; - $wanted = $cursig[$n+1]; + $wanted = $currentSig[$n+1]; $got = $pt; break; } @@ -511,7 +503,7 @@ function verifySignature($in, $sig) } } if (isset($wanted)) { - return array(0, "Wanted ${wanted}, got ${got} at param ${pno}"); + return array(0, "Wanted {$wanted}, got {$got} at param {$pno}"); } else { $allowed = array(); foreach ($sig as $val) { @@ -539,7 +531,7 @@ function parseRequest($data = '') { global $XML_RPC_xh, $HTTP_RAW_POST_DATA, $XML_RPC_err, $XML_RPC_str, $XML_RPC_errxml, - $XML_RPC_defencoding, $XML_RPC_Server_dmap; + $XML_RPC_Server_dmap; if ($data == '') { $data = $HTTP_RAW_POST_DATA; @@ -560,10 +552,10 @@ function parseRequest($data = '') $plist = ''; // decompose incoming XML into request structure - xml_parser_set_option($parser_resource, XML_OPTION_CASE_FOLDING, true); - xml_set_element_handler($parser_resource, 'XML_RPC_se', 'XML_RPC_ee'); - xml_set_character_data_handler($parser_resource, 'XML_RPC_cd'); + xml_set_element_handler($parser_resource, 'XML_RPC::startElement', 'XML_RPC::endElement'); + xml_set_character_data_handler($parser_resource, 'XML_RPC::cd'); + if (!xml_parse($parser_resource, $data, 1)) { // return XML error as a faultCode $r = new XML_RPC_Response(0, @@ -599,7 +591,7 @@ function parseRequest($data = '') $dmap = $XML_RPC_Server_dmap; $sysCall = 1; } else { - $dmap = $this->dmap; + $dmap = $this->dispatchMap; $sysCall = 0; } @@ -651,22 +643,12 @@ function parseRequest($data = '') * * Useful for debugging. */ - function echoInput() + public function echoInput() { global $HTTP_RAW_POST_DATA; $r = new XML_RPC_Response(0); - $r->xv = new XML_RPC_Value("'Aha said I: '" . $HTTP_RAW_POST_DATA, 'string'); - print $r->serialize(); + $r->setValue(new XML_RPC_Value("'Aha said I: '" . $HTTP_RAW_POST_DATA, 'string')); + echo $r->serialize(); } } - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * c-hanging-comment-ender-p: nil - * End: - */ - -?> diff --git a/system/lib-pingback.php b/system/lib-pingback.php index cf449e7da..0a7e468ba 100644 --- a/system/lib-pingback.php +++ b/system/lib-pingback.php @@ -33,9 +33,6 @@ die('This file can not be used on its own!'); } -// PEAR class to handle XML-RPC -require_once 'XML/RPC.php'; - /** * Get the Pingback URL for a given URL * @@ -121,14 +118,14 @@ function PNB_sendPingback($sourceURI, $targetURI) $client = new XML_RPC_Client ($parts['path'], $parts['host'], $parts['port']); //$client->setDebug (1); - $msg = new XML_RPC_Message ('pingback.ping', - array(new XML_RPC_Value ($sourceURI, 'string'), - new XML_RPC_Value ($targetURI, 'string'))); + $msg = new XML_RPC_Message('pingback.ping', + array(new XML_RPC_Value($sourceURI, 'string'), + new XML_RPC_Value($targetURI, 'string'))); $response = $client->send($msg, 0, $parts['scheme']); if (!is_object($response) && ($response == 0)) { - $retval = $client->errstring; - } else if ($response->faultCode() != 0) { + $retval = $client->getErrorString(); + } elseif ($response->faultCode() != 0) { $retval = $response->faultString(); }