diff --git a/system/libraries/Xmlrpc.php b/system/libraries/Xmlrpc.php
index 8587015e877..5238c056f9a 100644
--- a/system/libraries/Xmlrpc.php
+++ b/system/libraries/Xmlrpc.php
@@ -1151,8 +1151,7 @@ public function parseResponse($fp)
//-------------------------------------
$parser = xml_parser_create($this->xmlrpc_defencoding);
- $pname = (string) $parser;
- $this->xh[$pname] = array(
+ $this->xh = array(
'isf' => 0,
'ac' => '',
'headers' => array(),
@@ -1175,7 +1174,7 @@ public function parseResponse($fp)
{
break;
}
- $this->xh[$pname]['headers'][] = $line;
+ $this->xh['headers'][] = $line;
}
$data = implode("\r\n", $lines);
@@ -1193,18 +1192,18 @@ public function parseResponse($fp)
xml_parser_free($parser);
// Got ourselves some badness, it seems
- if ($this->xh[$pname]['isf'] > 1)
+ if ($this->xh['isf'] > 1)
{
if ($this->debug === TRUE)
{
- echo "---Invalid Return---\n".$this->xh[$pname]['isf_reason']."---Invalid Return---\n\n";
+ echo "---Invalid Return---\n".$this->xh['isf_reason']."---Invalid Return---\n\n";
}
- return new XML_RPC_Response(0, $this->xmlrpcerr['invalid_return'], $this->xmlrpcstr['invalid_return'].' '.$this->xh[$pname]['isf_reason']);
+ return new XML_RPC_Response(0, $this->xmlrpcerr['invalid_return'], $this->xmlrpcstr['invalid_return'].' '.$this->xh['isf_reason']);
}
- elseif ( ! is_object($this->xh[$pname]['value']))
+ elseif ( ! is_object($this->xh['value']))
{
- return new XML_RPC_Response(0, $this->xmlrpcerr['invalid_return'], $this->xmlrpcstr['invalid_return'].' '.$this->xh[$pname]['isf_reason']);
+ return new XML_RPC_Response(0, $this->xmlrpcerr['invalid_return'], $this->xmlrpcstr['invalid_return'].' '.$this->xh['isf_reason']);
}
// Display XML content for debugging
@@ -1212,10 +1211,10 @@ public function parseResponse($fp)
{
echo '
';
- if (count($this->xh[$pname]['headers']) > 0)
+ if (count($this->xh['headers']) > 0)
{
echo "---HEADERS---\n";
- foreach ($this->xh[$pname]['headers'] as $header)
+ foreach ($this->xh['headers'] as $header)
{
echo $header."\n";
}
@@ -1223,13 +1222,13 @@ public function parseResponse($fp)
}
echo "---DATA---\n".htmlspecialchars($data)."\n---END DATA---\n\n---PARSED---\n";
- var_dump($this->xh[$pname]['value']);
+ var_dump($this->xh['value']);
echo "\n---END PARSED---";
}
// Send response
- $v = $this->xh[$pname]['value'];
- if ($this->xh[$pname]['isf'])
+ $v = $this->xh['value'];
+ if ($this->xh['isf'])
{
$errno_v = $v->me['struct']['faultCode'];
$errstr_v = $v->me['struct']['faultString'];
@@ -1248,7 +1247,7 @@ public function parseResponse($fp)
$r = new XML_RPC_Response($v);
}
- $r->headers = $this->xh[$pname]['headers'];
+ $r->headers = $this->xh['headers'];
return $r;
}
@@ -1279,26 +1278,24 @@ public function parseResponse($fp)
*/
public function open_tag($the_parser, $name)
{
- $the_parser = (string) $the_parser;
-
// If invalid nesting, then return
- if ($this->xh[$the_parser]['isf'] > 1) return;
+ if ($this->xh['isf'] > 1) return;
// Evaluate and check for correct nesting of XML elements
- if (count($this->xh[$the_parser]['stack']) === 0)
+ if (count($this->xh['stack']) === 0)
{
if ($name !== 'METHODRESPONSE' && $name !== 'METHODCALL')
{
- $this->xh[$the_parser]['isf'] = 2;
- $this->xh[$the_parser]['isf_reason'] = 'Top level XML-RPC element is missing';
+ $this->xh['isf'] = 2;
+ $this->xh['isf_reason'] = 'Top level XML-RPC element is missing';
return;
}
}
// not top level element: see if parent is OK
- elseif ( ! in_array($this->xh[$the_parser]['stack'][0], $this->valid_parents[$name], TRUE))
+ elseif ( ! in_array($this->xh['stack'][0], $this->valid_parents[$name], TRUE))
{
- $this->xh[$the_parser]['isf'] = 2;
- $this->xh[$the_parser]['isf_reason'] = 'XML-RPC element '.$name.' cannot be child of '.$this->xh[$the_parser]['stack'][0];
+ $this->xh['isf'] = 2;
+ $this->xh['isf_reason'] = 'XML-RPC element '.$name.' cannot be child of '.$this->xh['stack'][0];
return;
}
@@ -1308,22 +1305,22 @@ public function open_tag($the_parser, $name)
case 'ARRAY':
// Creates array for child elements
$cur_val = array('value' => array(), 'type' => $name);
- array_unshift($this->xh[$the_parser]['valuestack'], $cur_val);
+ array_unshift($this->xh['valuestack'], $cur_val);
break;
case 'METHODNAME':
case 'NAME':
- $this->xh[$the_parser]['ac'] = '';
+ $this->xh['ac'] = '';
break;
case 'FAULT':
- $this->xh[$the_parser]['isf'] = 1;
+ $this->xh['isf'] = 1;
break;
case 'PARAM':
- $this->xh[$the_parser]['value'] = NULL;
+ $this->xh['value'] = NULL;
break;
case 'VALUE':
- $this->xh[$the_parser]['vt'] = 'value';
- $this->xh[$the_parser]['ac'] = '';
- $this->xh[$the_parser]['lv'] = 1;
+ $this->xh['vt'] = 'value';
+ $this->xh['ac'] = '';
+ $this->xh['lv'] = 1;
break;
case 'I4':
case 'INT':
@@ -1332,23 +1329,23 @@ public function open_tag($the_parser, $name)
case 'DOUBLE':
case 'DATETIME.ISO8601':
case 'BASE64':
- if ($this->xh[$the_parser]['vt'] !== 'value')
+ if ($this->xh['vt'] !== 'value')
{
//two data elements inside a value: an error occurred!
- $this->xh[$the_parser]['isf'] = 2;
- $this->xh[$the_parser]['isf_reason'] = 'There is a '.$name.' element following a '
- .$this->xh[$the_parser]['vt'].' element inside a single value';
+ $this->xh['isf'] = 2;
+ $this->xh['isf_reason'] = 'There is a '.$name.' element following a '
+ .$this->xh['vt'].' element inside a single value';
return;
}
- $this->xh[$the_parser]['ac'] = '';
+ $this->xh['ac'] = '';
break;
case 'MEMBER':
// Set name of to nothing to prevent errors later if no is found
- $this->xh[$the_parser]['valuestack'][0]['name'] = '';
+ $this->xh['valuestack'][0]['name'] = '';
// Set NULL value to check to see if value passed for this param/member
- $this->xh[$the_parser]['value'] = NULL;
+ $this->xh['value'] = NULL;
break;
case 'DATA':
case 'METHODCALL':
@@ -1358,15 +1355,15 @@ public function open_tag($the_parser, $name)
break;
default:
/// An Invalid Element is Found, so we have trouble
- $this->xh[$the_parser]['isf'] = 2;
- $this->xh[$the_parser]['isf_reason'] = 'Invalid XML-RPC element found: '.$name;
+ $this->xh['isf'] = 2;
+ $this->xh['isf_reason'] = 'Invalid XML-RPC element found: '.$name;
break;
}
// Add current element name to stack, to allow validation of nesting
- array_unshift($this->xh[$the_parser]['stack'], $name);
+ array_unshift($this->xh['stack'], $name);
- $name === 'VALUE' OR $this->xh[$the_parser]['lv'] = 0;
+ $name === 'VALUE' OR $this->xh['lv'] = 0;
}
// --------------------------------------------------------------------
@@ -1380,27 +1377,25 @@ public function open_tag($the_parser, $name)
*/
public function closing_tag($the_parser, $name)
{
- $the_parser = (string) $the_parser;
-
- if ($this->xh[$the_parser]['isf'] > 1) return;
+ if ($this->xh['isf'] > 1) return;
// Remove current element from stack and set variable
// NOTE: If the XML validates, then we do not have to worry about
// the opening and closing of elements. Nesting is checked on the opening
// tag so we be safe there as well.
- $curr_elem = array_shift($this->xh[$the_parser]['stack']);
+ $curr_elem = array_shift($this->xh['stack']);
switch ($name)
{
case 'STRUCT':
case 'ARRAY':
- $cur_val = array_shift($this->xh[$the_parser]['valuestack']);
- $this->xh[$the_parser]['value'] = isset($cur_val['values']) ? $cur_val['values'] : array();
- $this->xh[$the_parser]['vt'] = strtolower($name);
+ $cur_val = array_shift($this->xh['valuestack']);
+ $this->xh['value'] = isset($cur_val['values']) ? $cur_val['values'] : array();
+ $this->xh['vt'] = strtolower($name);
break;
case 'NAME':
- $this->xh[$the_parser]['valuestack'][0]['name'] = $this->xh[$the_parser]['ac'];
+ $this->xh['valuestack'][0]['name'] = $this->xh['ac'];
break;
case 'BOOLEAN':
case 'I4':
@@ -1409,87 +1404,87 @@ public function closing_tag($the_parser, $name)
case 'DOUBLE':
case 'DATETIME.ISO8601':
case 'BASE64':
- $this->xh[$the_parser]['vt'] = strtolower($name);
+ $this->xh['vt'] = strtolower($name);
if ($name === 'STRING')
{
- $this->xh[$the_parser]['value'] = $this->xh[$the_parser]['ac'];
+ $this->xh['value'] = $this->xh['ac'];
}
elseif ($name === 'DATETIME.ISO8601')
{
- $this->xh[$the_parser]['vt'] = $this->xmlrpcDateTime;
- $this->xh[$the_parser]['value'] = $this->xh[$the_parser]['ac'];
+ $this->xh['vt'] = $this->xmlrpcDateTime;
+ $this->xh['value'] = $this->xh['ac'];
}
elseif ($name === 'BASE64')
{
- $this->xh[$the_parser]['value'] = base64_decode($this->xh[$the_parser]['ac']);
+ $this->xh['value'] = base64_decode($this->xh['ac']);
}
elseif ($name === 'BOOLEAN')
{
// Translated BOOLEAN values to TRUE AND FALSE
- $this->xh[$the_parser]['value'] = (bool) $this->xh[$the_parser]['ac'];
+ $this->xh['value'] = (bool) $this->xh['ac'];
}
elseif ($name=='DOUBLE')
{
// we have a DOUBLE
// we must check that only 0123456789-. are characters here
- $this->xh[$the_parser]['value'] = preg_match('/^[+-]?[eE0-9\t \.]+$/', $this->xh[$the_parser]['ac'])
- ? (float) $this->xh[$the_parser]['ac']
+ $this->xh['value'] = preg_match('/^[+-]?[eE0-9\t \.]+$/', $this->xh['ac'])
+ ? (float) $this->xh['ac']
: 'ERROR_NON_NUMERIC_FOUND';
}
else
{
// we have an I4/INT
// we must check that only 0123456789- are characters here
- $this->xh[$the_parser]['value'] = preg_match('/^[+-]?[0-9\t ]+$/', $this->xh[$the_parser]['ac'])
- ? (int) $this->xh[$the_parser]['ac']
+ $this->xh['value'] = preg_match('/^[+-]?[0-9\t ]+$/', $this->xh['ac'])
+ ? (int) $this->xh['ac']
: 'ERROR_NON_NUMERIC_FOUND';
}
- $this->xh[$the_parser]['ac'] = '';
- $this->xh[$the_parser]['lv'] = 3; // indicate we've found a value
+ $this->xh['ac'] = '';
+ $this->xh['lv'] = 3; // indicate we've found a value
break;
case 'VALUE':
// This if() detects if no scalar was inside
- if ($this->xh[$the_parser]['vt'] == 'value')
+ if ($this->xh['vt'] == 'value')
{
- $this->xh[$the_parser]['value'] = $this->xh[$the_parser]['ac'];
- $this->xh[$the_parser]['vt'] = $this->xmlrpcString;
+ $this->xh['value'] = $this->xh['ac'];
+ $this->xh['vt'] = $this->xmlrpcString;
}
// build the XML-RPC value out of the data received, and substitute it
- $temp = new XML_RPC_Values($this->xh[$the_parser]['value'], $this->xh[$the_parser]['vt']);
+ $temp = new XML_RPC_Values($this->xh['value'], $this->xh['vt']);
- if (count($this->xh[$the_parser]['valuestack']) && $this->xh[$the_parser]['valuestack'][0]['type'] === 'ARRAY')
+ if (count($this->xh['valuestack']) && $this->xh['valuestack'][0]['type'] === 'ARRAY')
{
// Array
- $this->xh[$the_parser]['valuestack'][0]['values'][] = $temp;
+ $this->xh['valuestack'][0]['values'][] = $temp;
}
else
{
// Struct
- $this->xh[$the_parser]['value'] = $temp;
+ $this->xh['value'] = $temp;
}
break;
case 'MEMBER':
- $this->xh[$the_parser]['ac'] = '';
+ $this->xh['ac'] = '';
// If value add to array in the stack for the last element built
- if ($this->xh[$the_parser]['value'])
+ if ($this->xh['value'])
{
- $this->xh[$the_parser]['valuestack'][0]['values'][$this->xh[$the_parser]['valuestack'][0]['name']] = $this->xh[$the_parser]['value'];
+ $this->xh['valuestack'][0]['values'][$this->xh['valuestack'][0]['name']] = $this->xh['value'];
}
break;
case 'DATA':
- $this->xh[$the_parser]['ac'] = '';
+ $this->xh['ac'] = '';
break;
case 'PARAM':
- if ($this->xh[$the_parser]['value'])
+ if ($this->xh['value'])
{
- $this->xh[$the_parser]['params'][] = $this->xh[$the_parser]['value'];
+ $this->xh['params'][] = $this->xh['value'];
}
break;
case 'METHODNAME':
- $this->xh[$the_parser]['method'] = ltrim($this->xh[$the_parser]['ac']);
+ $this->xh['method'] = ltrim($this->xh['ac']);
break;
case 'PARAMS':
case 'FAULT':
@@ -1514,24 +1509,22 @@ public function closing_tag($the_parser, $name)
*/
public function character_data($the_parser, $data)
{
- $the_parser = (string) $the_parser;
-
- if ($this->xh[$the_parser]['isf'] > 1) return; // XML Fault found already
+ if ($this->xh['isf'] > 1) return; // XML Fault found already
// If a value has not been found
- if ($this->xh[$the_parser]['lv'] !== 3)
+ if ($this->xh['lv'] !== 3)
{
- if ($this->xh[$the_parser]['lv'] === 1)
+ if ($this->xh['lv'] === 1)
{
- $this->xh[$the_parser]['lv'] = 2; // Found a value
+ $this->xh['lv'] = 2; // Found a value
}
- if ( ! isset($this->xh[$the_parser]['ac']))
+ if ( ! isset($this->xh['ac']))
{
- $this->xh[$the_parser]['ac'] = '';
+ $this->xh['ac'] = '';
}
- $this->xh[$the_parser]['ac'] .= $data;
+ $this->xh['ac'] .= $data;
}
}
diff --git a/system/libraries/Xmlrpcs.php b/system/libraries/Xmlrpcs.php
index eb5a24c4917..481938b3400 100644
--- a/system/libraries/Xmlrpcs.php
+++ b/system/libraries/Xmlrpcs.php
@@ -234,9 +234,8 @@ public function parseRequest($data = '')
$parser = xml_parser_create($this->xmlrpc_defencoding);
$parser_object = new XML_RPC_Message('filler');
- $pname = (string) $parser;
- $parser_object->xh[$pname] = array(
+ $parser_object->xh = array(
'isf' => 0,
'isf_reason' => '',
'params' => array(),
@@ -265,7 +264,7 @@ public function parseRequest($data = '')
xml_get_current_line_number($parser)));
xml_parser_free($parser);
}
- elseif ($parser_object->xh[$pname]['isf'])
+ elseif ($parser_object->xh['isf'])
{
return new XML_RPC_Response(0, $this->xmlrpcerr['invalid_return'], $this->xmlrpcstr['invalid_return']);
}
@@ -273,17 +272,17 @@ public function parseRequest($data = '')
{
xml_parser_free($parser);
- $m = new XML_RPC_Message($parser_object->xh[$pname]['method']);
+ $m = new XML_RPC_Message($parser_object->xh['method']);
$plist = '';
- for ($i = 0, $c = count($parser_object->xh[$pname]['params']); $i < $c; $i++)
+ for ($i = 0, $c = count($parser_object->xh['params']); $i < $c; $i++)
{
if ($this->debug === TRUE)
{
- $plist .= $i.' - '.print_r(get_object_vars($parser_object->xh[$pname]['params'][$i]), TRUE).";\n";
+ $plist .= $i.' - '.print_r(get_object_vars($parser_object->xh['params'][$i]), TRUE).";\n";
}
- $m->addParam($parser_object->xh[$pname]['params'][$i]);
+ $m->addParam($parser_object->xh['params'][$i]);
}
if ($this->debug === TRUE)
diff --git a/tests/codeigniter/libraries/Xmlrpc_test.php b/tests/codeigniter/libraries/Xmlrpc_test.php
new file mode 100644
index 00000000000..46d73bf6e3e
--- /dev/null
+++ b/tests/codeigniter/libraries/Xmlrpc_test.php
@@ -0,0 +1,130 @@
+input = new CI_Input($security);
+
+ $this->input_lib_raw_stream = new ReflectionProperty($this->input, '_raw_input_stream');
+ $this->input_lib_raw_stream->setAccessible(TRUE);
+
+ $this->ci_instance_var('input', $this->input);
+ $this->ci_instance_var('security', $security);
+ }
+
+ // --------------------------------------------------------------------
+
+ public function test_xmlrpc_client()
+ {
+ $xmlrpc = new Mock_Libraries_Xmlrpc();
+ $xmlrpc->server('http://rpc.test/');
+ $xmlrpc->method('testcontroller.test');
+
+ $request = array('My Blog', 'http://www.myrpc.com/test/');
+ $message = 'test'.time();
+ $xml_response = $this->xml_response($message);
+ $xmlrpc->client->mock_response = "HTTP/1.1 200 OK\r\nContent-Type: text/xml\r\nContent-Length: ".strlen($xml_response)."\r\n\r\n$xml_response";
+
+ // Perform in the same request multiple calls
+ for ($attempt = 1; $attempt <= 2; $attempt++)
+ {
+ $xmlrpc->request($request);
+
+ $this->assertTrue($xmlrpc->send_request());
+
+ $response = $xmlrpc->display_response();
+
+ $this->assertEquals('theuser', $response['name']);
+ $this->assertEquals(123435, $response['member_id']);
+ $this->assertEquals($message, $response['request']);
+ }
+ }
+
+ // --------------------------------------------------------------------
+
+ public function test_xmlrpc_server()
+ {
+ $xmlrpcs = new Mock_Libraries_Xmlrpcs();
+
+ $config['functions']['Testmethod'] = array('function' => __CLASS__.'.mock_method_new_entry');
+ $config['object'] = $this;
+
+ $xmlrpcs->initialize($config);
+
+ $_SERVER['REQUEST_METHOD'] = 'POST';
+ $this->input_lib_raw_stream->setValue($this->input, $this->xml_request());
+
+ $xmlrpcs->serve();
+
+ $this->assertEquals('Test', $this->method_param);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * @param XML_RPC_Message $param
+ */
+ public function mock_method_new_entry($param)
+ {
+ $this->method_param = $param->params[0]->scalarval();
+
+ return new XML_RPC_Response(new XML_RPC_Values(true, 'boolean'));
+ }
+
+ // --------------------------------------------------------------------
+
+ private function xml_response($message)
+ {
+ return '
+
+
+
+
+
+
+name
+
+theuser
+
+
+
+member_id
+
+123435
+
+
+
+request
+
+'.$message.'
+
+
+
+
+
+';
+ }
+
+ // --------------------------------------------------------------------
+
+ public function xml_request()
+ {
+ return '
+
+Testmethod
+
+
+
+Test
+
+
+
+';
+ }
+}
diff --git a/tests/mocks/autoloader.php b/tests/mocks/autoloader.php
index 4dd53d4af31..ce3454dc9ed 100644
--- a/tests/mocks/autoloader.php
+++ b/tests/mocks/autoloader.php
@@ -52,6 +52,7 @@ function autoload($class)
'Upload',
'User_agent',
'Xmlrpc',
+ 'Xmlrpcs',
'Zip'
);
diff --git a/tests/mocks/libraries/xmlrpc.php b/tests/mocks/libraries/xmlrpc.php
new file mode 100644
index 00000000000..32f5f3765d5
--- /dev/null
+++ b/tests/mocks/libraries/xmlrpc.php
@@ -0,0 +1,33 @@
+client = new Mock_Libraries_XML_RPC_Client('/', $url, $port, $proxy, $proxy_port);
+ }
+}
+
+class Mock_Libraries_XML_RPC_Client extends XML_RPC_Client {
+ public $mock_response = '';
+
+ /**
+ * @param XML_RPC_Message $msg
+ */
+ public function sendPayload($msg)
+ {
+ if (empty($msg->payload))
+ {
+ $msg->createPayload();
+ }
+
+ $fp = fopen('php://memory', 'rw+');
+ fwrite($fp, $this->mock_response);
+ fseek($fp, 0);
+
+ $parsed = $msg->parseResponse($fp);
+ fclose($fp);
+
+ return $parsed;
+ }
+}
+
diff --git a/tests/mocks/libraries/xmlrpcs.php b/tests/mocks/libraries/xmlrpcs.php
new file mode 100644
index 00000000000..d93396c0189
--- /dev/null
+++ b/tests/mocks/libraries/xmlrpcs.php
@@ -0,0 +1,23 @@
+parseRequest();
+
+ $payload = 'xmlrpc_defencoding.'"?'.'>'."\n".$this->debug_msg.$r->prepare_response();
+
+ $this->mock_payload = "HTTP/1.1 200 OK\r\n";
+ $this->mock_payload .= "Content-Type: text/xml\r\n";
+ $this->mock_payload .= 'Content-Length: '.strlen($payload)."\r\n";
+
+ $this->mock_payload .= "\r\n";
+
+ $this->mock_payload .= $payload;
+ }
+}