3 * NB: do not let your IDE fool you. The correct encoding for this file is NOT UTF8.
5 include_once __DIR__ . '/../lib/xmlrpc.inc';
6 include_once __DIR__ . '/../lib/xmlrpcs.inc';
8 class ParsingBugsTests extends PHPUnit_Framework_TestCase
10 public $args = array();
12 public function setUp()
14 $this->args = argParser::getArgs();
17 protected function newMsg($methodName, $params = array())
19 $msg = new xmlrpcmsg($methodName, $params);
20 if ($this->args['DEBUG']) {
21 $msg->setDebug($this->args['DEBUG']);
26 public function testMinusOneString()
28 $v = new xmlrpcval('-1');
29 $u = new xmlrpcval('-1', 'string');
30 $t = new xmlrpcval(-1, 'string');
31 $this->assertEquals($u->scalarval(), $v->scalarval());
32 $this->assertEquals($t->scalarval(), $v->scalarval());
36 * This looks funny, and we might call it a bug. But we strive for 100 backwards compat...
38 public function testMinusOneInt()
40 $v = new xmlrpcval(-1);
42 $this->assertEquals($u->scalarval(), $v->scalarval());
45 public function testUnicodeInMemberName()
47 $str = "G" . chr(252) . "nter, El" . chr(232) . "ne";
48 $v = array($str => new xmlrpcval(1));
49 $r = new xmlrpcresp(new xmlrpcval($v, 'struct'));
51 $m = $this->newMsg('dummy');
52 $r = $m->parseResponse($r);
54 $this->assertEquals($v->structmemexists($str), true);
57 public function testUnicodeInErrorString()
59 $response = utf8_encode(
60 '<?xml version="1.0"?>
62 <!-- found by G. giunta, covers what happens when lib receives
63 UTF8 chars in response text and comments -->
64 <!-- ' . chr(224) . chr(252) . chr(232) . 'àüè -->
70 <name>faultCode</name>
71 <value><int>888</int></value>
74 <name>faultString</name>
75 <value><string>' . chr(224) . chr(252) . chr(232) . 'àüè</string></value>
81 $m = $this->newMsg('dummy');
82 $r = $m->parseResponse($response);
83 $v = $r->faultString();
84 $this->assertEquals(chr(224) . chr(252) . chr(232) . chr(224) . chr(252) . chr(232), $v);
87 public function testValidNumbers()
89 $m = $this->newMsg('dummy');
91 '<?xml version="1.0"?>
99 <value><int>01</int></value>
103 <value><double>01.10</double></value>
106 <name>integer2</name>
107 <value><int>+1</int></value>
111 <value><double>+1.10</double></value>
115 <value><double>-1.10e2</double></value>
122 $r = $m->parseResponse($fp);
124 $s = $v->structmem('integer1');
125 $t = $v->structmem('float1');
126 $u = $v->structmem('integer2');
127 $w = $v->structmem('float2');
128 $x = $v->structmem('float3');
129 $this->assertEquals(1, $s->scalarval());
130 $this->assertEquals(1.1, $t->scalarval());
131 $this->assertEquals(1, $u->scalarval());
132 $this->assertEquals(1.1, $w->scalarval());
133 $this->assertEquals(-110.0, $x->scalarval());
136 public function testAddScalarToStruct()
138 $v = new xmlrpcval(array('a' => 'b'), 'struct');
139 // use @ operator in case error_log gets on screen
140 $r = @$v->addscalar('c');
141 $this->assertEquals(0, $r);
144 public function testAddStructToStruct()
146 $v = new xmlrpcval(array('a' => new xmlrpcval('b')), 'struct');
147 $r = $v->addstruct(array('b' => new xmlrpcval('c')));
148 $this->assertEquals(2, $v->structsize());
149 $this->assertEquals(1, $r);
150 $r = $v->addstruct(array('b' => new xmlrpcval('b')));
151 $this->assertEquals(2, $v->structsize());
154 public function testAddArrayToArray()
156 $v = new xmlrpcval(array(new xmlrpcval('a'), new xmlrpcval('b')), 'array');
157 $r = $v->addarray(array(new xmlrpcval('b'), new xmlrpcval('c')));
158 $this->assertEquals(4, $v->arraysize());
159 $this->assertEquals(1, $r);
162 public function testEncodeArray()
165 $v = php_xmlrpc_encode($r);
166 $this->assertEquals('array', $v->kindof());
169 public function testEncodeRecursive()
171 $v = php_xmlrpc_encode(php_xmlrpc_encode('a simple string'));
172 $this->assertEquals('scalar', $v->kindof());
175 public function testBrokenRequests()
177 $s = new xmlrpc_server();
178 // omitting the 'params' tag: not tolerated by the lib anymore
179 $f = '<?xml version="1.0"?>
181 <methodName>system.methodHelp</methodName>
183 <value><string>system.methodHelp</string></value>
186 $r = $s->parserequest($f);
187 $this->assertEquals(15, $r->faultCode());
188 // omitting a 'param' tag
189 $f = '<?xml version="1.0"?>
191 <methodName>system.methodHelp</methodName>
193 <value><string>system.methodHelp</string></value>
196 $r = $s->parserequest($f);
197 $this->assertEquals(15, $r->faultCode());
198 // omitting a 'value' tag
199 $f = '<?xml version="1.0"?>
201 <methodName>system.methodHelp</methodName>
203 <param><string>system.methodHelp</string></param>
206 $r = $s->parserequest($f);
207 $this->assertEquals(15, $r->faultCode());
210 public function testBrokenResponses()
212 $m = $this->newMsg('dummy');
213 // omitting the 'params' tag: no more tolerated by the lib...
214 $f = '<?xml version="1.0"?>
217 <value><string>system.methodHelp</string></value>
220 $r = $m->parseResponse($f);
221 $this->assertEquals(2, $r->faultCode());
222 // omitting the 'param' tag: no more tolerated by the lib...
223 $f = '<?xml version="1.0"?>
226 <value><string>system.methodHelp</string></value>
229 $r = $m->parseResponse($f);
230 $this->assertEquals(2, $r->faultCode());
231 // omitting a 'value' tag: KO
232 $f = '<?xml version="1.0"?>
235 <param><string>system.methodHelp</string></param>
238 $r = $m->parseResponse($f);
239 $this->assertEquals(2, $r->faultCode());
242 public function testBuggyHttp()
244 $s = $this->newMsg('dummy');
245 $f = 'HTTP/1.1 100 Welcome to the jungle
248 X-Content-Marx-Brothers: Harpo
250 Content-Length: who knows?
254 <?xml version="1.0"?>
255 <!-- First of all, let\'s check out if the lib properly handles a commented </methodResponse> tag... -->
256 <methodResponse><params><param><value><struct><member><name>userid</name><value>311127</value></member>
257 <member><name>dateCreated</name><value><dateTime.iso8601>20011126T09:17:52</dateTime.iso8601></value></member><member><name>content</name><value>hello world. 2 newlines follow
260 and there they were.</value></member><member><name>postid</name><value>7414222</value></member></struct></value></param></params></methodResponse>
261 <script type="text\javascript">document.write(\'Hello, my name is added nag, I\\\'m happy to serve your content for free\');</script>
263 $r = $s->parseResponse($f);
265 $s = $v->structmem('content');
266 $this->assertEquals("hello world. 2 newlines follow\n\n\nand there they were.", $s->scalarval());
269 public function testStringBug()
271 $s = $this->newMsg('dummy');
272 $f = '<?xml version="1.0"?>
274 <!-- found by 2z69xks7bpy001@sneakemail.com, amongst others
275 covers what happens when there\'s character data after </string>
276 and before </value> -->
289 <name>sessionID</name>
291 <string>S300510007I</string>
299 $r = $s->parseResponse($f);
301 $s = $v->structmem('sessionID');
302 $this->assertEquals('S300510007I', $s->scalarval());
305 public function testWhiteSpace()
307 $s = $this->newMsg('dummy');
308 $f = '<?xml version="1.0"?><methodResponse><params><param><value><struct><member><name>userid</name><value>311127</value></member>
309 <member><name>dateCreated</name><value><dateTime.iso8601>20011126T09:17:52</dateTime.iso8601></value></member><member><name>content</name><value>hello world. 2 newlines follow
312 and there they were.</value></member><member><name>postid</name><value>7414222</value></member></struct></value></param></params></methodResponse>
314 $r = $s->parseResponse($f);
316 $s = $v->structmem('content');
317 $this->assertEquals("hello world. 2 newlines follow\n\n\nand there they were.", $s->scalarval());
320 public function testDoubleDataInArrayTag()
322 $s = $this->newMsg('dummy');
323 $f = '<?xml version="1.0"?><methodResponse><params><param><value><array>
326 </array></value></param></params></methodResponse>
328 $r = $s->parseResponse($f);
329 $v = $r->faultCode();
330 $this->assertEquals(2, $v);
331 $f = '<?xml version="1.0"?><methodResponse><params><param><value><array>
332 <data><value>Hello world</value></data>
334 </array></value></param></params></methodResponse>
336 $r = $s->parseResponse($f);
337 $v = $r->faultCode();
338 $this->assertEquals(2, $v);
341 public function testDoubleStuffInValueTag()
343 $s = $this->newMsg('dummy');
344 $f = '<?xml version="1.0"?><methodResponse><params><param><value>
345 <string>hello world</string>
346 <array><data></data></array>
347 </value></param></params></methodResponse>
349 $r = $s->parseResponse($f);
350 $v = $r->faultCode();
351 $this->assertEquals(2, $v);
352 $f = '<?xml version="1.0"?><methodResponse><params><param><value>
353 <string>hello</string>
354 <string>world</string>
355 </value></param></params></methodResponse>
357 $r = $s->parseResponse($f);
358 $v = $r->faultCode();
359 $this->assertEquals(2, $v);
360 $f = '<?xml version="1.0"?><methodResponse><params><param><value>
361 <string>hello</string>
362 <struct><member><name>hello><value>world</value></member></struct>
363 </value></param></params></methodResponse>
365 $r = $s->parseResponse($f);
366 $v = $r->faultCode();
367 $this->assertEquals(2, $v);
370 public function testAutodecodeResponse()
372 $s = $this->newMsg('dummy');
373 $f = '<?xml version="1.0"?><methodResponse><params><param><value><struct><member><name>userid</name><value>311127</value></member>
374 <member><name>dateCreated</name><value><dateTime.iso8601>20011126T09:17:52</dateTime.iso8601></value></member><member><name>content</name><value>hello world. 2 newlines follow
377 and there they were.</value></member><member><name>postid</name><value>7414222</value></member></struct></value></param></params></methodResponse>
379 $r = $s->parseResponse($f, true, 'phpvals');
382 $this->assertEquals("hello world. 2 newlines follow\n\n\nand there they were.", $s);
385 public function testNoDecodeResponse()
387 $s = $this->newMsg('dummy');
388 $f = '<?xml version="1.0"?><methodResponse><params><param><value><struct><member><name>userid</name><value>311127</value></member>
389 <member><name>dateCreated</name><value><dateTime.iso8601>20011126T09:17:52</dateTime.iso8601></value></member><member><name>content</name><value>hello world. 2 newlines follow
392 and there they were.</value></member><member><name>postid</name><value>7414222</value></member></struct></value></param></params></methodResponse>';
393 $r = $s->parseResponse($f, true, 'xml');
395 $this->assertEquals($f, $v);
398 public function testAutoCoDec()
400 $data1 = array(1, 1.0, 'hello world', true, '20051021T23:43:00', -1, 11.0, '~!@#$%^&*()_+|', false, '20051021T23:43:00');
401 $data2 = array('zero' => $data1, 'one' => $data1, 'two' => $data1, 'three' => $data1, 'four' => $data1, 'five' => $data1, 'six' => $data1, 'seven' => $data1, 'eight' => $data1, 'nine' => $data1);
402 $data = array($data2, $data2, $data2, $data2, $data2, $data2, $data2, $data2, $data2, $data2);
403 //$keys = array('zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine');
404 $v1 = php_xmlrpc_encode($data, array('auto_dates'));
405 $v2 = php_xmlrpc_decode_xml($v1->serialize());
406 $this->assertEquals($v1, $v2);
407 $r1 = new PhpXmlRpc\Response($v1);
408 $r2 = php_xmlrpc_decode_xml($r1->serialize());
409 $r2->serialize(); // needed to set internal member payload
410 $this->assertEquals($r1, $r2);
411 $m1 = new PhpXmlRpc\Request('hello dolly', array($v1));
412 $m2 = php_xmlrpc_decode_xml($m1->serialize());
413 $m2->serialize(); // needed to set internal member payload
414 $this->assertEquals($m1, $m2);
417 public function testUTF8Request()
419 $sendstring = 'κόσμε'; // Greek word 'kosme'. NB: NOT a valid ISO8859 string!
420 $GLOBALS['xmlrpc_internalencoding'] = 'UTF-8';
421 \PhpXmlRpc\PhpXmlRpc::importGlobals();
422 $f = new xmlrpcval($sendstring, 'string');
423 $v = $f->serialize();
424 $this->assertEquals("<value><string>κόσμε</string></value>\n", $v);
425 $GLOBALS['xmlrpc_internalencoding'] = 'ISO-8859-1';
426 \PhpXmlRpc\PhpXmlRpc::importGlobals();
429 public function testUTF8Response()
431 $string = chr(224) . chr(252) . chr(232);
433 $s = $this->newMsg('dummy');
434 $f = "HTTP/1.1 200 OK\r\nContent-type: text/xml; charset=UTF-8\r\n\r\n" . '<?xml version="1.0"?><methodResponse><params><param><value><struct><member><name>userid</name><value>311127</value></member>
435 <member><name>dateCreated</name><value><dateTime.iso8601>20011126T09:17:52</dateTime.iso8601></value></member><member><name>content</name><value>' . utf8_encode($string) . '</value></member><member><name>postid</name><value>7414222</value></member></struct></value></param></params></methodResponse>
437 $r = $s->parseResponse($f, false, 'phpvals');
440 $this->assertEquals($string, $v);
442 $f = '<?xml version="1.0" encoding="utf-8"?><methodResponse><params><param><value><struct><member><name>userid</name><value>311127</value></member>
443 <member><name>dateCreated</name><value><dateTime.iso8601>20011126T09:17:52</dateTime.iso8601></value></member><member><name>content</name><value>' . utf8_encode($string) . '</value></member><member><name>postid</name><value>7414222</value></member></struct></value></param></params></methodResponse>
445 $r = $s->parseResponse($f, false, 'phpvals');
448 $this->assertEquals($string, $v);
450 $r = php_xmlrpc_decode_xml($f);
452 $v = $v->structmem('content')->scalarval();
453 $this->assertEquals($string, $v);
456 public function testLatin1Response()
458 $string = chr(224) . chr(252) . chr(232);
460 $s = $this->newMsg('dummy');
461 $f = "HTTP/1.1 200 OK\r\nContent-type: text/xml; charset=ISO-8859-1\r\n\r\n" . '<?xml version="1.0"?><methodResponse><params><param><value><struct><member><name>userid</name><value>311127</value></member>
462 <member><name>dateCreated</name><value><dateTime.iso8601>20011126T09:17:52</dateTime.iso8601></value></member><member><name>content</name><value>' . $string . '</value></member><member><name>postid</name><value>7414222</value></member></struct></value></param></params></methodResponse>
464 $r = $s->parseResponse($f, false, 'phpvals');
467 $this->assertEquals($string, $v);
469 $f = '<?xml version="1.0" encoding="iso-8859-1"?><methodResponse><params><param><value><struct><member><name>userid</name><value>311127</value></member>
470 <member><name>dateCreated</name><value><dateTime.iso8601>20011126T09:17:52</dateTime.iso8601></value></member><member><name>content</name><value>' . $string . '</value></member><member><name>postid</name><value>7414222</value></member></struct></value></param></params></methodResponse>
472 $r = $s->parseResponse($f, false, 'phpvals');
475 $this->assertEquals($string, $v);
477 $r = php_xmlrpc_decode_xml($f);
479 $v = $v->structmem('content')->scalarval();
480 $this->assertEquals($string, $v);
483 public function testUTF8IntString()
485 $v = new xmlrpcval(100, 'int');
486 $s = $v->serialize('UTF-8');
487 $this->assertequals("<value><int>100</int></value>\n", $s);
490 public function testStringInt()
492 $v = new xmlrpcval('hello world', 'int');
493 $s = $v->serialize();
494 $this->assertequals("<value><int>0</int></value>\n", $s);
497 public function testStructMemExists()
499 $v = php_xmlrpc_encode(array('hello' => 'world'));
500 $b = $v->structmemexists('hello');
501 $this->assertequals(true, $b);
502 $b = $v->structmemexists('world');
503 $this->assertequals(false, $b);
506 public function testNilvalue()
508 // default case: we do not accept nil values received
509 $v = new xmlrpcval('hello', 'null');
510 $r = new xmlrpcresp($v);
511 $s = $r->serialize();
512 $m = $this->newMsg('dummy');
513 $r = $m->parseresponse($s);
514 $this->assertequals(2, $r->faultCode());
515 // enable reception of nil values
516 $GLOBALS['xmlrpc_null_extension'] = true;
517 \PhpXmlRpc\PhpXmlRpc::importGlobals();
518 $r = $m->parseresponse($s);
520 $this->assertequals('null', $v->scalartyp());
521 // test with the apache version: EX:NIL
522 $GLOBALS['xmlrpc_null_apache_encoding'] = true;
523 \PhpXmlRpc\PhpXmlRpc::importGlobals();
525 $v = new xmlrpcval('hello', 'null');
526 $s = $v->serialize();
527 $this->assertequals(1, preg_match('#<value><ex:nil/></value>#', $s));
529 $r = new xmlrpcresp($v);
530 $s = $r->serialize();
531 $r = $m->parseresponse($s);
533 $this->assertequals('null', $v->scalartyp());
534 $GLOBALS['xmlrpc_null_extension'] = false;
535 \PhpXmlRpc\PhpXmlRpc::importGlobals();
536 $r = $m->parseresponse($s);
537 $this->assertequals(2, $r->faultCode());
540 public function TestLocale()
542 $locale = setlocale(LC_NUMERIC, 0);
543 /// @todo on php 5.3/win setting locale to german does not seem to set decimal separator to comma...
544 if (setlocale(LC_NUMERIC, 'deu', 'de_DE@euro', 'de_DE', 'de', 'ge') !== false) {
545 $v = new xmlrpcval(1.1, 'double');
546 if (strpos($v->scalarval(), ',') == 1) {
547 $r = $v->serialize();
548 $this->assertequals(false, strpos($r, ','));
549 setlocale(LC_NUMERIC, $locale);
551 setlocale(LC_NUMERIC, $locale);
552 $this->markTestSkipped('did not find a locale which sets decimal separator to comma');
555 $this->markTestSkipped('did not find a locale which sets decimal separator to comma');