improve code coverage for demo files
[plcapi.git] / demo / server / server.php
1 <?php
2 /**
3  * Demo server for xmlrpc library.
4  *
5  * Implements a lot of webservices, including a suite of services used for
6  * interoperability testing (validator1 methods), and some whose only purpose
7  * is to be used for unit-testing the library.
8  *
9  * Please do not copy this file verbatim into your production server.
10  **/
11
12 require_once __DIR__ . "/_prepend.php";
13
14 use PhpXmlRpc\Value;
15
16 /**
17  * Used to test usage of object methods in dispatch maps and in wrapper code.
18  */
19 class xmlrpcServerMethodsContainer
20 {
21     /**
22      * Method used to test logging of php warnings generated by user functions.
23      * @param PhpXmlRpc\Request $req
24      * @return PhpXmlRpc\Response
25      */
26     public function phpWarningGenerator($req)
27     {
28         $a = $undefinedVariable; // this triggers a warning in E_ALL mode, since $undefinedVariable is undefined
29         return new PhpXmlRpc\Response(new Value(1, Value::$xmlrpcBoolean));
30     }
31
32     /**
33      * Method used to test catching of exceptions in the server.
34      * @param PhpXmlRpc\Request $req
35      * @throws Exception
36      */
37     public function exceptionGenerator($req)
38     {
39         throw new Exception("it's just a test", 1);
40     }
41
42     /**
43      * @param string $msg
44      */
45     public function debugMessageGenerator($msg)
46     {
47         PhpXmlRpc\Server::xmlrpc_debugmsg($msg);
48     }
49
50     /**
51      * A PHP version of the state-number server. Send me an integer and i'll sell you a state.
52      * Used to test wrapping of PHP methods into xmlrpc methods.
53      *
54      * @param integer $num
55      * @return string
56      * @throws Exception
57      */
58     public static function findState($num)
59     {
60         return inner_findstate($num);
61     }
62
63     /**
64      * Returns an instance of stdClass.
65      * Used to test wrapping of PHP objects with class preservation
66      */
67     public function returnObject()
68     {
69         $obj = new stdClass();
70         $obj->hello = 'world';
71         return $obj;
72     }
73 }
74
75 // a PHP version of the state-number server
76 // send me an integer and i'll sell you a state
77
78 $stateNames = array(
79     "Alabama", "Alaska", "Arizona", "Arkansas", "California",
80     "Colorado", "Columbia", "Connecticut", "Delaware", "Florida",
81     "Georgia", "Hawaii", "Idaho", "Illinois", "Indiana", "Iowa", "Kansas",
82     "Kentucky", "Louisiana", "Maine", "Maryland", "Massachusetts", "Michigan",
83     "Minnesota", "Mississippi", "Missouri", "Montana", "Nebraska", "Nevada",
84     "New Hampshire", "New Jersey", "New Mexico", "New York", "North Carolina",
85     "North Dakota", "Ohio", "Oklahoma", "Oregon", "Pennsylvania", "Rhode Island",
86     "South Carolina", "South Dakota", "Tennessee", "Texas", "Utah", "Vermont",
87     "Virginia", "Washington", "West Virginia", "Wisconsin", "Wyoming",
88 );
89
90 $findstate_sig = array(array(Value::$xmlrpcString, Value::$xmlrpcInt));
91 $findstate_doc = 'When passed an integer between 1 and 51 returns the
92 name of a US state, where the integer is the index of that state name
93 in an alphabetic order.';
94
95 function findState($req)
96 {
97     global $stateNames;
98
99     $err = "";
100     // get the first param
101     $sno = $req->getParam(0);
102
103     // param must be there and of the correct type: server object does the validation for us
104
105     // extract the value of the state number
106     $snv = $sno->scalarval();
107     // look it up in our array (zero-based)
108     if (isset($stateNames[$snv - 1])) {
109         $stateName = $stateNames[$snv - 1];
110     } else {
111         // not there, so complain
112         $err = "I don't have a state for the index '" . $snv . "'";
113     }
114
115     // if we generated an error, create an error return response
116     if ($err) {
117         return new PhpXmlRpc\Response(0, PhpXmlRpc\PhpXmlRpc::$xmlrpcerruser, $err);
118     } else {
119         // otherwise, we create the right response with the state name
120         return new PhpXmlRpc\Response(new Value($stateName));
121     }
122 }
123
124 /**
125  * Inner code of the state-number server.
126  * Used to test wrapping of PHP functions into xmlrpc methods.
127  *
128  * @param integer $stateNo the state number
129  *
130  * @return string the name of the state (or error description)
131  *
132  * @throws Exception if state is not found
133  */
134 function inner_findstate($stateNo)
135 {
136     global $stateNames;
137
138     if (isset($stateNames[$stateNo - 1])) {
139         return $stateNames[$stateNo - 1];
140     } else {
141         // not, there so complain
142         throw new Exception("I don't have a state for the index '" . $stateNo . "'", PhpXmlRpc\PhpXmlRpc::$xmlrpcerruser);
143     }
144 }
145
146 $wrapper = new PhpXmlRpc\Wrapper();
147
148 $findstate2_sig = $wrapper->wrapPhpFunction('inner_findstate');
149
150 $findstate3_sig = $wrapper->wrapPhpFunction(array('xmlrpcServerMethodsContainer', 'findState'));
151
152 $obj = new xmlrpcServerMethodsContainer();
153 $findstate4_sig = $wrapper->wrapPhpFunction(array($obj, 'findstate'));
154
155 $findstate5_sig = $wrapper->wrapPhpFunction('xmlrpcServerMethodsContainer::findState', '', array('return_source' => true));
156 eval($findstate5_sig['source']);
157
158 $findstate6_sig = $wrapper->wrapPhpFunction('inner_findstate', '', array('return_source' => true));
159 eval($findstate6_sig['source']);
160
161 $findstate7_sig = $wrapper->wrapPhpFunction(array('xmlrpcServerMethodsContainer', 'findState'), '', array('return_source' => true));
162 eval($findstate7_sig['source']);
163
164 $obj = new xmlrpcServerMethodsContainer();
165 $findstate8_sig = $wrapper->wrapPhpFunction(array($obj, 'findstate'), '', array('return_source' => true));
166 eval($findstate8_sig['source']);
167
168 $findstate9_sig = $wrapper->wrapPhpFunction('xmlrpcServerMethodsContainer::findState', '', array('return_source' => true));
169 eval($findstate9_sig['source']);
170
171 $findstate10_sig = array(
172     "function" => function ($req) { return findState($req); },
173     "signature" => $findstate_sig,
174     "docstring" => $findstate_doc,
175 );
176
177 $findstate11_sig = $wrapper->wrapPhpFunction(function ($stateNo) { return inner_findstate($stateNo); });
178
179 $c = new xmlrpcServerMethodsContainer;
180 $moreSignatures = $wrapper->wrapPhpClass($c, array('prefix' => 'tests.', 'method_type' => 'all'));
181
182 $returnObj_sig =  $wrapper->wrapPhpFunction(array($c, 'returnObject'), '', array('encode_php_objs' => true));
183
184 // used to test signatures with NULL params
185 $findstate12_sig = array(
186     array(Value::$xmlrpcString, Value::$xmlrpcInt, Value::$xmlrpcNull),
187     array(Value::$xmlrpcString, Value::$xmlrpcNull, Value::$xmlrpcInt),
188 );
189
190 function findStateWithNulls($req)
191 {
192     $a = $req->getParam(0);
193     $b = $req->getParam(1);
194
195     if ($a->scalartyp() == Value::$xmlrpcNull)
196         return new PhpXmlRpc\Response(new Value(inner_findstate($b->scalarval())));
197     else
198         return new PhpXmlRpc\Response(new Value(inner_findstate($a->scalarval())));
199 }
200
201 $addtwo_sig = array(array(Value::$xmlrpcInt, Value::$xmlrpcInt, Value::$xmlrpcInt));
202 $addtwo_doc = 'Add two integers together and return the result';
203 function addTwo($req)
204 {
205     $s = $req->getParam(0);
206     $t = $req->getParam(1);
207
208     return new PhpXmlRpc\Response(new Value($s->scalarval() + $t->scalarval(), Value::$xmlrpcInt));
209 }
210
211 $addtwodouble_sig = array(array(Value::$xmlrpcDouble, Value::$xmlrpcDouble, Value::$xmlrpcDouble));
212 $addtwodouble_doc = 'Add two doubles together and return the result';
213 function addTwoDouble($req)
214 {
215     $s = $req->getParam(0);
216     $t = $req->getParam(1);
217
218     return new PhpXmlRpc\Response(new Value($s->scalarval() + $t->scalarval(), Value::$xmlrpcDouble));
219 }
220
221 $stringecho_sig = array(array(Value::$xmlrpcString, Value::$xmlrpcString));
222 $stringecho_doc = 'Accepts a string parameter, returns the string.';
223 function stringEcho($req)
224 {
225     // just sends back a string
226     return new PhpXmlRpc\Response(new Value($req->getParam(0)->scalarval()));
227 }
228
229 $echoback_sig = array(array(Value::$xmlrpcString, Value::$xmlrpcString));
230 $echoback_doc = 'Accepts a string parameter, returns the entire incoming payload';
231 function echoBack($req)
232 {
233     // just sends back a string with what i got sent to me, just escaped, that's all
234     $s = "I got the following message:\n" . $req->serialize();
235
236     return new PhpXmlRpc\Response(new Value($s));
237 }
238
239 $echosixtyfour_sig = array(array(Value::$xmlrpcString, Value::$xmlrpcBase64));
240 $echosixtyfour_doc = 'Accepts a base64 parameter and returns it decoded as a string';
241 function echoSixtyFour($req)
242 {
243     // Accepts an encoded value, but sends it back as a normal string.
244     // This is to test that base64 encoding is working as expected
245     $incoming = $req->getParam(0);
246
247     return new PhpXmlRpc\Response(new Value($incoming->scalarval(), Value::$xmlrpcString));
248 }
249
250 $bitflipper_sig = array(array(Value::$xmlrpcArray, Value::$xmlrpcArray));
251 $bitflipper_doc = 'Accepts an array of booleans, and returns them inverted';
252 function bitFlipper($req)
253 {
254     $v = $req->getParam(0);
255     $rv = new Value(array(), Value::$xmlrpcArray);
256
257     foreach ($v as $b) {
258         if ($b->scalarval()) {
259             $rv[] = new Value(false, Value::$xmlrpcBoolean);
260         } else {
261             $rv[] = new Value(true, Value::$xmlrpcBoolean);
262         }
263     }
264
265     return new PhpXmlRpc\Response($rv);
266 }
267
268 // Sorting demo
269 //
270 // send me an array of structs thus:
271 //
272 // Dave 35
273 // Edd  45
274 // Fred 23
275 // Barney 37
276 //
277 // and I'll return it to you in sorted order
278
279 function agesorter_compare($a, $b)
280 {
281     global $agesorter_arr;
282
283     // don't even ask me _why_ these come padded with hyphens, I couldn't tell you :p
284     $a = str_replace("-", "", $a);
285     $b = str_replace("-", "", $b);
286
287     if ($agesorter_arr[$a] == $agesorter_arr[$b]) {
288         return 0;
289     }
290
291     return ($agesorter_arr[$a] > $agesorter_arr[$b]) ? -1 : 1;
292 }
293
294 $agesorter_sig = array(array(Value::$xmlrpcArray, Value::$xmlrpcArray));
295 $agesorter_doc = 'Send this method an array of [string, int] structs, eg:
296 <pre>
297  Dave   35
298  Edd    45
299  Fred   23
300  Barney 37
301 </pre>
302 And the array will be returned with the entries sorted by their numbers.
303 ';
304 function ageSorter($req)
305 {
306     global $agesorter_arr, $s;
307
308     PhpXmlRpc\Server::xmlrpc_debugmsg("Entering 'agesorter'");
309     // get the parameter
310     $sno = $req->getParam(0);
311     // error string for [if|when] things go wrong
312     $err = "";
313     $agar = array();
314
315     $max = $sno->count();
316     PhpXmlRpc\Server::xmlrpc_debugmsg("Found $max array elements");
317     foreach ($sno as $i => $rec) {
318         if ($rec->kindOf() != "struct") {
319             $err = "Found non-struct in array at element $i";
320             break;
321         }
322         // extract name and age from struct
323         $n = $rec["name"];
324         $a = $rec["age"];
325         // $n and $a are xmlrpcvals,
326         // so get the scalarval from them
327         $agar[$n->scalarval()] = $a->scalarval();
328     }
329
330     // create the output value
331     $v = new Value(array(), Value::$xmlrpcArray);
332
333     $agesorter_arr = $agar;
334     // hack, must make global as uksort() won't
335     // allow us to pass any other auxiliary information
336     uksort($agesorter_arr, 'agesorter_compare');
337     foreach($agesorter_arr as $key => $val) {
338         // recreate each struct element
339         $v[] = new Value(
340             array(
341                 "name" => new Value($key),
342                 "age" => new Value($val, "int")
343             ),
344             Value::$xmlrpcStruct
345         );
346     }
347
348     if ($err) {
349         return new PhpXmlRpc\Response(0, PhpXmlRpc\PhpXmlRpc::$xmlrpcerruser, $err);
350     } else {
351         return new PhpXmlRpc\Response($v);
352     }
353 }
354
355 // signature and instructions, place these in the dispatch map
356 $mailsend_sig = array(array(
357     Value::$xmlrpcBoolean, Value::$xmlrpcString, Value::$xmlrpcString,
358     Value::$xmlrpcString, Value::$xmlrpcString, Value::$xmlrpcString,
359     Value::$xmlrpcString, Value::$xmlrpcString,
360 ));
361 $mailsend_doc = 'mail.send(recipient, subject, text, sender, cc, bcc, mimetype)<br/>
362 recipient, cc, and bcc are strings, comma-separated lists of email addresses, as described above.<br/>
363 subject is a string, the subject of the message.<br/>
364 sender is a string, it\'s the email address of the person sending the message. This string can not be
365 a comma-separated list, it must contain a single email address only.<br/>
366 text is a string, it contains the body of the message.<br/>
367 mimetype, a string, is a standard MIME type, for example, text/plain.
368 ';
369 // WARNING; this functionality depends on the sendmail -t option
370 // it may not work with Windows machines properly; particularly
371 // the Bcc option. Sneak on your friends at your own risk!
372 function mailSend($req)
373 {
374     $err = "";
375
376     $mTo = $req->getParam(0);
377     $mSub = $req->getParam(1);
378     $mBody = $req->getParam(2);
379     $mFrom = $req->getParam(3);
380     $mCc = $req->getParam(4);
381     $mBcc = $req->getParam(5);
382     $mMime = $req->getParam(6);
383
384     if ($mTo->scalarval() == "") {
385         $err = "Error, no 'To' field specified";
386     }
387
388     if ($mFrom->scalarval() == "") {
389         $err = "Error, no 'From' field specified";
390     }
391
392     $msgHdr = "From: " . $mFrom->scalarval() . "\n";
393     $msgHdr .= "To: " . $mTo->scalarval() . "\n";
394
395     if ($mCc->scalarval() != "") {
396         $msgHdr .= "Cc: " . $mCc->scalarval() . "\n";
397     }
398     if ($mBcc->scalarval() != "") {
399         $msgHdr .= "Bcc: " . $mBcc->scalarval() . "\n";
400     }
401     if ($mMime->scalarval() != "") {
402         $msgHdr .= "Content-type: " . $mMime->scalarval() . "\n";
403     }
404     $msgHdr .= "X-Mailer: XML-RPC for PHP mailer 1.0";
405
406     if ($err == "") {
407         if (!mail("",
408             $mSub->scalarval(),
409             $mBody->scalarval(),
410             $msgHdr)
411         ) {
412             $err = "Error, could not send the mail.";
413         }
414     }
415
416     if ($err) {
417         return new PhpXmlRpc\Response(0, PhpXmlRpc\PhpXmlRpc::$xmlrpcerruser, $err);
418     } else {
419         return new PhpXmlRpc\Response(new Value(true, Value::$xmlrpcBoolean));
420     }
421 }
422
423 $getallheaders_sig = array(array(Value::$xmlrpcStruct));
424 $getallheaders_doc = 'Returns a struct containing all the HTTP headers received with the request. Provides limited functionality with IIS';
425 function getAllHeaders_xmlrpc($req)
426 {
427     $encoder = new PhpXmlRpc\Encoder();
428
429     if (function_exists('getallheaders')) {
430         return new PhpXmlRpc\Response($encoder->encode(getallheaders()));
431     } else {
432         $headers = array();
433         // IIS: poor man's version of getallheaders
434         foreach ($_SERVER as $key => $val) {
435             if (strpos($key, 'HTTP_') === 0) {
436                 $key = ucfirst(str_replace('_', '-', strtolower(substr($key, 5))));
437                 $headers[$key] = $val;
438             }
439         }
440
441         return new PhpXmlRpc\Response($encoder->encode($headers));
442     }
443 }
444
445 $setcookies_sig = array(array(Value::$xmlrpcInt, Value::$xmlrpcStruct));
446 $setcookies_doc = 'Sends to client a response containing a single \'1\' digit, and sets to it http cookies as received in the request (array of structs describing a cookie)';
447 function setCookies($req)
448 {
449     $encoder = new PhpXmlRpc\Encoder();
450     $cookies = $req->getParam(0);
451     foreach ($cookies as $name => $value) {
452         $cookieDesc = $encoder->decode($value);
453         setcookie($name, @$cookieDesc['value'], @$cookieDesc['expires'], @$cookieDesc['path'], @$cookieDesc['domain'], @$cookieDesc['secure']);
454     }
455
456     return new PhpXmlRpc\Response(new Value(1, Value::$xmlrpcInt));
457 }
458
459 $getcookies_sig = array(array(Value::$xmlrpcStruct));
460 $getcookies_doc = 'Sends to client a response containing all http cookies as received in the request (as struct)';
461 function getCookies($req)
462 {
463     $encoder = new PhpXmlRpc\Encoder();
464     return new PhpXmlRpc\Response($encoder->encode($_COOKIE));
465 }
466
467 $v1_arrayOfStructs_sig = array(array(Value::$xmlrpcInt, Value::$xmlrpcArray));
468 $v1_arrayOfStructs_doc = 'This handler takes a single parameter, an array of structs, each of which contains at least three elements named moe, larry and curly, all <i4>s. Your handler must add all the struct elements named curly and return the result.';
469 function v1_arrayOfStructs($req)
470 {
471     $sno = $req->getParam(0);
472     $numCurly = 0;
473     foreach ($sno as $str) {
474         foreach ($str as $key => $val) {
475             if ($key == "curly") {
476                 $numCurly += $val->scalarval();
477             }
478         }
479     }
480
481     return new PhpXmlRpc\Response(new Value($numCurly, Value::$xmlrpcInt));
482 }
483
484 $v1_easyStruct_sig = array(array(Value::$xmlrpcInt, Value::$xmlrpcStruct));
485 $v1_easyStruct_doc = 'This handler takes a single parameter, a struct, containing at least three elements named moe, larry and curly, all &lt;i4&gt;s. Your handler must add the three numbers and return the result.';
486 function v1_easyStruct($req)
487 {
488     $sno = $req->getParam(0);
489     $moe = $sno["moe"];
490     $larry = $sno["larry"];
491     $curly = $sno["curly"];
492     $num = $moe->scalarval() + $larry->scalarval() + $curly->scalarval();
493
494     return new PhpXmlRpc\Response(new Value($num, Value::$xmlrpcInt));
495 }
496
497 $v1_echoStruct_sig = array(array(Value::$xmlrpcStruct, Value::$xmlrpcStruct));
498 $v1_echoStruct_doc = 'This handler takes a single parameter, a struct. Your handler must return the struct.';
499 function v1_echoStruct($req)
500 {
501     $sno = $req->getParam(0);
502
503     return new PhpXmlRpc\Response($sno);
504 }
505
506 $v1_manyTypes_sig = array(array(
507     Value::$xmlrpcArray, Value::$xmlrpcInt, Value::$xmlrpcBoolean,
508     Value::$xmlrpcString, Value::$xmlrpcDouble, Value::$xmlrpcDateTime,
509     Value::$xmlrpcBase64,
510 ));
511 $v1_manyTypes_doc = 'This handler takes six parameters, and returns an array containing all the parameters.';
512 function v1_manyTypes($req)
513 {
514     return new PhpXmlRpc\Response(new Value(
515         array(
516             $req->getParam(0),
517             $req->getParam(1),
518             $req->getParam(2),
519             $req->getParam(3),
520             $req->getParam(4),
521             $req->getParam(5)
522         ),
523         Value::$xmlrpcArray
524     ));
525 }
526
527 $v1_moderateSizeArrayCheck_sig = array(array(Value::$xmlrpcString, Value::$xmlrpcArray));
528 $v1_moderateSizeArrayCheck_doc = 'This handler takes a single parameter, which is an array containing between 100 and 200 elements. Each of the items is a string, your handler must return a string containing the concatenated text of the first and last elements.';
529 function v1_moderateSizeArrayCheck($req)
530 {
531     $ar = $req->getParam(0);
532     $sz = $ar->count();
533     $first = $ar[0];
534     $last = $ar[$sz - 1];
535
536     return new PhpXmlRpc\Response(new Value($first->scalarval() .
537         $last->scalarval(), Value::$xmlrpcString));
538 }
539
540 $v1_simpleStructReturn_sig = array(array(Value::$xmlrpcStruct, Value::$xmlrpcInt));
541 $v1_simpleStructReturn_doc = 'This handler takes one parameter, and returns a struct containing three elements, times10, times100 and times1000, the result of multiplying the number by 10, 100 and 1000.';
542 function v1_simpleStructReturn($req)
543 {
544     $sno = $req->getParam(0);
545     $v = $sno->scalarval();
546
547     return new PhpXmlRpc\Response(new Value(
548         array(
549             "times10" => new Value($v * 10, Value::$xmlrpcInt),
550             "times100" => new Value($v * 100, Value::$xmlrpcInt),
551             "times1000" => new Value($v * 1000, Value::$xmlrpcInt)
552         ),
553         Value::$xmlrpcStruct
554     ));
555 }
556
557 $v1_nestedStruct_sig = array(array(Value::$xmlrpcInt, Value::$xmlrpcStruct));
558 $v1_nestedStruct_doc = 'This handler takes a single parameter, a struct, that models a daily calendar. At the top level, there is one struct for each year. Each year is broken down into months, and months into days. Most of the days are empty in the struct you receive, but the entry for April 1, 2000 contains a least three elements named moe, larry and curly, all &lt;i4&gt;s. Your handler must add the three numbers and return the result.';
559 function v1_nestedStruct($req)
560 {
561     $sno = $req->getParam(0);
562
563     $twoK = $sno["2000"];
564     $april = $twoK["04"];
565     $fools = $april["01"];
566     $curly = $fools["curly"];
567     $larry = $fools["larry"];
568     $moe = $fools["moe"];
569
570     return new PhpXmlRpc\Response(new Value($curly->scalarval() + $larry->scalarval() + $moe->scalarval(), Value::$xmlrpcInt));
571 }
572
573 $v1_countTheEntities_sig = array(array(Value::$xmlrpcStruct, Value::$xmlrpcString));
574 $v1_countTheEntities_doc = 'This handler takes a single parameter, a string, that contains any number of predefined entities, namely &lt;, &gt;, &amp; \' and ".<BR>Your handler must return a struct that contains five fields, all numbers: ctLeftAngleBrackets, ctRightAngleBrackets, ctAmpersands, ctApostrophes, ctQuotes.';
575 function v1_countTheEntities($req)
576 {
577     $sno = $req->getParam(0);
578     $str = $sno->scalarval();
579     $gt = 0;
580     $lt = 0;
581     $ap = 0;
582     $qu = 0;
583     $amp = 0;
584     for ($i = 0; $i < strlen($str); $i++) {
585         $c = substr($str, $i, 1);
586         switch ($c) {
587             case ">":
588                 $gt++;
589                 break;
590             case "<":
591                 $lt++;
592                 break;
593             case "\"":
594                 $qu++;
595                 break;
596             case "'":
597                 $ap++;
598                 break;
599             case "&":
600                 $amp++;
601                 break;
602             default:
603                 break;
604         }
605     }
606
607     return new PhpXmlRpc\Response(new Value(
608         array(
609             "ctLeftAngleBrackets" => new Value($lt, Value::$xmlrpcInt),
610             "ctRightAngleBrackets" => new Value($gt, Value::$xmlrpcInt),
611             "ctAmpersands" => new Value($amp, Value::$xmlrpcInt),
612             "ctApostrophes" => new Value($ap, Value::$xmlrpcInt),
613             "ctQuotes" => new Value($qu, Value::$xmlrpcInt)
614         ),
615         Value::$xmlrpcStruct
616     ));
617 }
618
619 // trivial interop tests
620 // http://www.xmlrpc.com/stories/storyReader$1636
621
622 $i_echoString_sig = array(array(Value::$xmlrpcString, Value::$xmlrpcString));
623 $i_echoString_doc = "Echoes string.";
624
625 $i_echoStringArray_sig = array(array(Value::$xmlrpcArray, Value::$xmlrpcArray));
626 $i_echoStringArray_doc = "Echoes string array.";
627
628 $i_echoInteger_sig = array(array(Value::$xmlrpcInt, Value::$xmlrpcInt));
629 $i_echoInteger_doc = "Echoes integer.";
630
631 $i_echoIntegerArray_sig = array(array(Value::$xmlrpcArray, Value::$xmlrpcArray));
632 $i_echoIntegerArray_doc = "Echoes integer array.";
633
634 $i_echoFloat_sig = array(array(Value::$xmlrpcDouble, Value::$xmlrpcDouble));
635 $i_echoFloat_doc = "Echoes float.";
636
637 $i_echoFloatArray_sig = array(array(Value::$xmlrpcArray, Value::$xmlrpcArray));
638 $i_echoFloatArray_doc = "Echoes float array.";
639
640 $i_echoStruct_sig = array(array(Value::$xmlrpcStruct, Value::$xmlrpcStruct));
641 $i_echoStruct_doc = "Echoes struct.";
642
643 $i_echoStructArray_sig = array(array(Value::$xmlrpcArray, Value::$xmlrpcArray));
644 $i_echoStructArray_doc = "Echoes struct array.";
645
646 $i_echoValue_doc = "Echoes any value back.";
647 $i_echoValue_sig = array(array(Value::$xmlrpcValue, Value::$xmlrpcValue));
648
649 $i_echoBase64_sig = array(array(Value::$xmlrpcBase64, Value::$xmlrpcBase64));
650 $i_echoBase64_doc = "Echoes base64.";
651
652 $i_echoDate_sig = array(array(Value::$xmlrpcDateTime, Value::$xmlrpcDateTime));
653 $i_echoDate_doc = "Echoes dateTime.";
654
655 function i_echoParam($req)
656 {
657     $s = $req->getParam(0);
658
659     return new PhpXmlRpc\Response($s);
660 }
661
662 function i_echoString($req)
663 {
664     return i_echoParam($req);
665 }
666
667 function i_echoInteger($req)
668 {
669     return i_echoParam($req);
670 }
671
672 function i_echoFloat($req)
673 {
674     return i_echoParam($req);
675 }
676
677 function i_echoStruct($req)
678 {
679     return i_echoParam($req);
680 }
681
682 function i_echoStringArray($req)
683 {
684     return i_echoParam($req);
685 }
686
687 function i_echoIntegerArray($req)
688 {
689     return i_echoParam($req);
690 }
691
692 function i_echoFloatArray($req)
693 {
694     return i_echoParam($req);
695 }
696
697 function i_echoStructArray($req)
698 {
699     return i_echoParam($req);
700 }
701
702 function i_echoValue($req)
703 {
704     return i_echoParam($req);
705 }
706
707 function i_echoBase64($req)
708 {
709     return i_echoParam($req);
710 }
711
712 function i_echoDate($req)
713 {
714     return i_echoParam($req);
715 }
716
717 $i_whichToolkit_sig = array(array(Value::$xmlrpcStruct));
718 $i_whichToolkit_doc = "Returns a struct containing the following strings: toolkitDocsUrl, toolkitName, toolkitVersion, toolkitOperatingSystem.";
719
720 function i_whichToolkit($req)
721 {
722     global $SERVER_SOFTWARE;
723     $ret = array(
724         "toolkitDocsUrl" => "http://phpxmlrpc.sourceforge.net/",
725         "toolkitName" => PhpXmlRpc\PhpXmlRpc::$xmlrpcName,
726         "toolkitVersion" => PhpXmlRpc\PhpXmlRpc::$xmlrpcVersion,
727         "toolkitOperatingSystem" => isset($SERVER_SOFTWARE) ? $SERVER_SOFTWARE : $_SERVER['SERVER_SOFTWARE'],
728     );
729
730     $encoder = new PhpXmlRpc\Encoder();
731     return new PhpXmlRpc\Response($encoder->encode($ret));
732 }
733
734 $object = new xmlrpcServerMethodsContainer();
735 $signatures = array(
736     "examples.getStateName" => array(
737         "function" => "findState",
738         "signature" => $findstate_sig,
739         "docstring" => $findstate_doc,
740     ),
741     "examples.sortByAge" => array(
742         "function" => "ageSorter",
743         "signature" => $agesorter_sig,
744         "docstring" => $agesorter_doc,
745     ),
746     "examples.addtwo" => array(
747         "function" => "addTwo",
748         "signature" => $addtwo_sig,
749         "docstring" => $addtwo_doc,
750     ),
751     "examples.addtwodouble" => array(
752         "function" => "addTwoDouble",
753         "signature" => $addtwodouble_sig,
754         "docstring" => $addtwodouble_doc,
755     ),
756     "examples.stringecho" => array(
757         "function" => "stringEcho",
758         "signature" => $stringecho_sig,
759         "docstring" => $stringecho_doc,
760     ),
761     "examples.echo" => array(
762         "function" => "echoBack",
763         "signature" => $echoback_sig,
764         "docstring" => $echoback_doc,
765     ),
766     "examples.decode64" => array(
767         "function" => "echoSixtyFour",
768         "signature" => $echosixtyfour_sig,
769         "docstring" => $echosixtyfour_doc,
770     ),
771     "examples.invertBooleans" => array(
772         "function" => "bitFlipper",
773         "signature" => $bitflipper_sig,
774         "docstring" => $bitflipper_doc,
775     ),
776     // signature omitted on purpose
777     "tests.generatePHPWarning" => array(
778         "function" => array($object, "phpWarningGenerator"),
779     ),
780     // signature omitted on purpose
781     "tests.raiseException" => array(
782         "function" => array($object, "exceptionGenerator"),
783     ),
784     // Greek word 'kosme'. NB: NOT a valid ISO8859 string!
785     // NB: we can only register this when setting internal encoding to UTF-8, or it will break system.listMethods
786     "tests.utf8methodname." . 'κόσμε' => array(
787         "function" => "stringEcho",
788         "signature" => $stringecho_sig,
789         "docstring" => $stringecho_doc,
790     ),
791     /*"tests.iso88591methodname." . chr(224) . chr(252) . chr(232) => array(
792         "function" => "stringEcho",
793         "signature" => $stringecho_sig,
794         "docstring" => $stringecho_doc,
795     ),*/
796     "examples.getallheaders" => array(
797         "function" => 'getAllHeaders_xmlrpc',
798         "signature" => $getallheaders_sig,
799         "docstring" => $getallheaders_doc,
800     ),
801     "examples.setcookies" => array(
802         "function" => 'setCookies',
803         "signature" => $setcookies_sig,
804         "docstring" => $setcookies_doc,
805     ),
806     "examples.getcookies" => array(
807         "function" => 'getCookies',
808         "signature" => $getcookies_sig,
809         "docstring" => $getcookies_doc,
810     ),
811     "mail.send" => array(
812         "function" => "mailSend",
813         "signature" => $mailsend_sig,
814         "docstring" => $mailsend_doc,
815     ),
816     "validator1.arrayOfStructsTest" => array(
817         "function" => "v1_arrayOfStructs",
818         "signature" => $v1_arrayOfStructs_sig,
819         "docstring" => $v1_arrayOfStructs_doc,
820     ),
821     "validator1.easyStructTest" => array(
822         "function" => "v1_easyStruct",
823         "signature" => $v1_easyStruct_sig,
824         "docstring" => $v1_easyStruct_doc,
825     ),
826     "validator1.echoStructTest" => array(
827         "function" => "v1_echoStruct",
828         "signature" => $v1_echoStruct_sig,
829         "docstring" => $v1_echoStruct_doc,
830     ),
831     "validator1.manyTypesTest" => array(
832         "function" => "v1_manyTypes",
833         "signature" => $v1_manyTypes_sig,
834         "docstring" => $v1_manyTypes_doc,
835     ),
836     "validator1.moderateSizeArrayCheck" => array(
837         "function" => "v1_moderateSizeArrayCheck",
838         "signature" => $v1_moderateSizeArrayCheck_sig,
839         "docstring" => $v1_moderateSizeArrayCheck_doc,
840     ),
841     "validator1.simpleStructReturnTest" => array(
842         "function" => "v1_simpleStructReturn",
843         "signature" => $v1_simpleStructReturn_sig,
844         "docstring" => $v1_simpleStructReturn_doc,
845     ),
846     "validator1.nestedStructTest" => array(
847         "function" => "v1_nestedStruct",
848         "signature" => $v1_nestedStruct_sig,
849         "docstring" => $v1_nestedStruct_doc,
850     ),
851     "validator1.countTheEntities" => array(
852         "function" => "v1_countTheEntities",
853         "signature" => $v1_countTheEntities_sig,
854         "docstring" => $v1_countTheEntities_doc,
855     ),
856     "interopEchoTests.echoString" => array(
857         "function" => "i_echoString",
858         "signature" => $i_echoString_sig,
859         "docstring" => $i_echoString_doc,
860     ),
861     "interopEchoTests.echoStringArray" => array(
862         "function" => "i_echoStringArray",
863         "signature" => $i_echoStringArray_sig,
864         "docstring" => $i_echoStringArray_doc,
865     ),
866     "interopEchoTests.echoInteger" => array(
867         "function" => "i_echoInteger",
868         "signature" => $i_echoInteger_sig,
869         "docstring" => $i_echoInteger_doc,
870     ),
871     "interopEchoTests.echoIntegerArray" => array(
872         "function" => "i_echoIntegerArray",
873         "signature" => $i_echoIntegerArray_sig,
874         "docstring" => $i_echoIntegerArray_doc,
875     ),
876     "interopEchoTests.echoFloat" => array(
877         "function" => "i_echoFloat",
878         "signature" => $i_echoFloat_sig,
879         "docstring" => $i_echoFloat_doc,
880     ),
881     "interopEchoTests.echoFloatArray" => array(
882         "function" => "i_echoFloatArray",
883         "signature" => $i_echoFloatArray_sig,
884         "docstring" => $i_echoFloatArray_doc,
885     ),
886     "interopEchoTests.echoStruct" => array(
887         "function" => "i_echoStruct",
888         "signature" => $i_echoStruct_sig,
889         "docstring" => $i_echoStruct_doc,
890     ),
891     "interopEchoTests.echoStructArray" => array(
892         "function" => "i_echoStructArray",
893         "signature" => $i_echoStructArray_sig,
894         "docstring" => $i_echoStructArray_doc,
895     ),
896     "interopEchoTests.echoValue" => array(
897         "function" => "i_echoValue",
898         "signature" => $i_echoValue_sig,
899         "docstring" => $i_echoValue_doc,
900     ),
901     "interopEchoTests.echoBase64" => array(
902         "function" => "i_echoBase64",
903         "signature" => $i_echoBase64_sig,
904         "docstring" => $i_echoBase64_doc,
905     ),
906     "interopEchoTests.echoDate" => array(
907         "function" => "i_echoDate",
908         "signature" => $i_echoDate_sig,
909         "docstring" => $i_echoDate_doc,
910     ),
911     "interopEchoTests.whichToolkit" => array(
912         "function" => "i_whichToolkit",
913         "signature" => $i_whichToolkit_sig,
914         "docstring" => $i_whichToolkit_doc,
915     ),
916
917     'tests.getStateName.2' => $findstate2_sig,
918     'tests.getStateName.3' => $findstate3_sig,
919     'tests.getStateName.4' => $findstate4_sig,
920     'tests.getStateName.5' => $findstate5_sig,
921     'tests.getStateName.6' => $findstate6_sig,
922     'tests.getStateName.7' => $findstate7_sig,
923     'tests.getStateName.8' => $findstate8_sig,
924     'tests.getStateName.9' => $findstate9_sig,
925     'tests.getStateName.10' => $findstate10_sig,
926     'tests.getStateName.11' => $findstate11_sig,
927
928     'tests.getStateName.12' => array(
929         "function" => "findStateWithNulls",
930         "signature" => $findstate12_sig,
931         "docstring" => $findstate_doc,
932     ),
933
934     'tests.returnPhpObject' => $returnObj_sig,
935 );
936
937 $signatures = array_merge($signatures, $moreSignatures);
938
939 // Enable support for the NULL extension
940 PhpXmlRpc\PhpXmlRpc::$xmlrpc_null_extension = true;
941
942 $s = new PhpXmlRpc\Server($signatures, false);
943 $s->setdebug(3);
944 $s->compress_response = true;
945
946 // Out-of-band information: let the client manipulate the server operations.
947 // We do this to help the testsuite script: do not reproduce in production!
948 if (isset($_GET['RESPONSE_ENCODING'])) {
949     $s->response_charset_encoding = $_GET['RESPONSE_ENCODING'];
950 }
951 if (isset($_GET['DETECT_ENCODINGS'])) {
952     PhpXmlRpc\PhpXmlRpc::$xmlrpc_detectencodings = $_GET['DETECT_ENCODINGS'];
953 }
954 if (isset($_GET['EXCEPTION_HANDLING'])) {
955     $s->exception_handling = $_GET['EXCEPTION_HANDLING'];
956 }
957 if (isset($_GET['FORCE_AUTH'])) {
958     // We implement both  Basic and Digest auth in php to avoid having to set it up in a vhost.
959     // Code taken from php.net
960     // NB: we do NOT check for valid credentials!
961     if ($_GET['FORCE_AUTH'] == 'Basic') {
962         if (!isset($_SERVER['PHP_AUTH_USER']) && !isset($_SERVER['REMOTE_USER']) && !isset($_SERVER['REDIRECT_REMOTE_USER'])) {
963             header('HTTP/1.0 401 Unauthorized');
964             header('WWW-Authenticate: Basic realm="Phpxmlrpc Basic Realm"');
965             die('Text visible if user hits Cancel button');
966         }
967     } elseif ($_GET['FORCE_AUTH'] == 'Digest') {
968         if (empty($_SERVER['PHP_AUTH_DIGEST'])) {
969             header('HTTP/1.1 401 Unauthorized');
970             header('WWW-Authenticate: Digest realm="Phpxmlrpc Digest Realm",qop="auth",nonce="'.uniqid().'",opaque="'.md5('Phpxmlrpc Digest Realm').'"');
971             die('Text visible if user hits Cancel button');
972         }
973     }
974 }
975
976 $s->service();
977 // That should do all we need!
978
979 require_once __DIR__ . "/_append.php";