Issues (320)

demo/server/methodProviders/functions.php (1 issue)

1
<?php
2
/**
3
 * Defines functions and signatures which can be registered as methods exposed by an XML-RPC Server
4
 *
5
 * To use this, use something akin to:
6
 * $signatures = include('functions.php');
7
 *
8
 * Demoes a simple possible way to implement webservices without cluttering the global scope: create xml-rpc-aware static
9
 * methods in a class, and use them for the Server's dispatch map without the need to instantiate an object of that class.
10
 *
11
 * Alternative implementation strategies are possible as well:
12
 * 1. same as above, but use non-static class methods and an object instance
13
 * 2. define functions in the global scope to be used as xml-rpc method handlers: see interop.php
14
 * 3. define xml-rpc method handlers as anonymous functions directly within the dispatch map: see validator1.php
15
 * 4. use php methods or functions which are not aware of xml-rpc and let the Server do all the necessary type conversion:
16
 *    see discuss.php
17
 * 5. use the PhpXmlRpc\Wrapper class to achieve the same as in point 4, with no need to manually write the dispatch map
18
 *    configuration (but taking instead a performance hit)
19 559
 * 6. use the PhpXmlRpc\Wrapper class to generate php code in offline mode, achieving the same as in point 5 with no
20
 *    performance hit at runtime: see codegen.php
21
 */
22
23
use PhpXmlRpc\Encoder;
24
use PhpXmlRpc\PhpXmlRpc;
25
use PhpXmlRpc\Response;
26
use PhpXmlRpc\Server;
27
use PhpXmlRpc\Value;
28
29
class exampleMethods
30
{
31 559
    public static $stateNames = array(
32
        "Alabama", "Alaska", "Arizona", "Arkansas", "California",
33 559
        "Colorado", "Columbia", "Connecticut", "Delaware", "Florida",
34
        "Georgia", "Hawaii", "Idaho", "Illinois", "Indiana", "Iowa", "Kansas",
35
        "Kentucky", "Louisiana", "Maine", "Maryland", "Massachusetts", "Michigan",
36 22
        "Minnesota", "Mississippi", "Missouri", "Montana", "Nebraska", "Nevada",
37
        "New Hampshire", "New Jersey", "New Mexico", "New York", "North Carolina",
38 22
        "North Dakota", "Ohio", "Oklahoma", "Oregon", "Pennsylvania", "Rhode Island",
39
        "South Carolina", "South Dakota", "Tennessee", "Texas", "Utah", "Vermont",
40
        "Virginia", "Washington", "West Virginia", "Wisconsin", "Wyoming",
41
    );
42
43 22
    public static $findstate_sig = array(array('string', 'int'));
44
    public static $findstate_doc = 'When passed an integer between 1 and 51 returns the name of a US state, where the integer is the index of that state name in an alphabetic order.';
45 22
    public static function findState($req)
46 22
    {
47
        $err = '';
48
49
        // get the first param
50
        // param must be there and of the correct type: server object does the validation for us
51
        $sno = $req->getParam(0);
52
53 22
        // extract the value of the state number
54
        $snv = $sno->scalarVal();
55
56
        // look it up in our array (zero-based)
57 22
        if (isset(self::$stateNames[$snv - 1])) {
58
            $stateName = self::$stateNames[$snv - 1];
59
        } else {
60
            // not there, so complain
61
            $err = "I don't have a state for the index '" . $snv . "'";
62
        }
63
64
        if ($err != '') {
65
            // if we generated an error, create an error return response
66
            return new Response(0, PhpXmlRpc::$xmlrpcerruser, $err);
67
        } else {
68
            // otherwise, we create the right response with the state name
69
            return new Response(new Value($stateName));
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $stateName does not seem to be defined for all execution paths leading up to this point.
Loading history...
70
        }
71
    }
72
73
    public static $agesorter_sig = array(array('array', 'array'));
74
    public static $agesorter_doc = 'Send this method an array of [string, int] structs, eg:
75
<pre>
76
 Dave   35
77
 Edd    45
78
 Fred   23
79
 Barney 37
80
</pre>
81
And the array will be returned with the entries sorted by their numbers.';
82
    public static function ageSorter($req)
83
    {
84
        Server::xmlrpc_debugmsg("Entering 'agesorter'");
85
86
        // error string for [if|when] things go wrong
87
        $err = '';
88 559
89 559
        // get the parameter, turn it into an easy-to-manipulate php array
90
        $enc = new Encoder();
91
        $v = $enc->decode($req->getParam(0));
92
93
        $max = count($v);
94
        Server::xmlrpc_debugmsg("Found $max array elements");
95
96
        // extract name and age from struct. The values nested inside it were not type-checked, so we do it
97
        $agar = array();
98
        foreach ($v as $i => $rec) {
99
            if (!is_array($rec)) {
100
                $err = "Found non-struct in array at element $i";
101
                break;
102
            }
103
            if (!isset($rec['name']) || !isset($rec['age'])) {
104
                Server::xmlrpc_debugmsg("Invalid array element $i: miss name or age");
105
                continue;
106
            }
107
            $agar[$rec["name"]] = $rec["age"];
108
        }
109
110
        if ($err != '') {
111
            Server::xmlrpc_debugmsg("Aborting 'agesorter'");
112
            return new Response(0, PhpXmlRpc::$xmlrpcerruser, $err);
113
        }
114
115
        asort($agar);
116
117
        // create the output value
118
        $o = array();
119
        foreach ($agar as $name => $age) {
120
            $o[] = array("name" => $name, "age" => $age);
121
        }
122
123
        Server::xmlrpc_debugmsg("Leaving 'agesorter'");
124
125
        return new Response($enc->encode($o));
126
    }
127
128
    public static $addtwo_sig = array(array('int', 'int', 'int'));
129
    public static $addtwo_doc = 'Add two integers together and return the result';
130
    public static function addTwo($req)
131
    {
132
        $s = $req->getParam(0);
133
        $t = $req->getParam(1);
134
135
        return new Response(new Value($s->scalarVal() + $t->scalarVal(), Value::$xmlrpcInt));
136
    }
137
138
    public static $addtwodouble_sig = array(array('double', 'double', 'double'));
139
    public static $addtwodouble_doc = 'Add two doubles together and return the result';
140
    public static function addTwoDouble($req)
141
    {
142
        $s = $req->getParam(0);
143
        $t = $req->getParam(1);
144
145
        return new Response(new Value($s->scalarVal() + $t->scalarVal(), Value::$xmlrpcDouble));
146
    }
147
148
    public static $stringecho_sig = array(array('string', 'string'));
149 559
    public static $stringecho_doc = 'Accepts a string parameter, returns the string.';
150 559
    public static function stringEcho($req)
151
    {
152
        // just sends back a string
153 43
        return new Response(new Value($req->getParam(0)->scalarVal()));
154 43
    }
155
156 43
    public static $echoback_sig = array(array('string', 'string'));
157
    public static $echoback_doc = 'Accepts a string parameter, returns the entire incoming payload';
158
    public static function echoBack($req)
159 559
    {
160 559
        // just sends back a string with what I got sent to me, that's all
161
162
        /// @todo file_get_contents does not take into account either receiving compressed requests, or requests with
163 22
        ///       data which is not in UTF-8. Otoh using req->serialize means that what we are sending back is not
164 22
        ///       byte-for-byte identical to what we received, and that <, >, ', " and & will be double-encoded.
165
        ///       In fact, we miss some API (or extra data) in the Request...
166 22
        //$payload = file_get_contents('php://input');
167
        $payload = $req->serialize(PhpXmlRpc::$xmlrpc_internalencoding);
168
        $s = "I got the following message:\n" . $payload;
169 559
170 559
        return new Response(new Value($s));
171
    }
172
173
    public static $echosixtyfour_sig = array(array('string', 'base64'));
174 72
    public static $echosixtyfour_doc = 'Accepts a base64 parameter and returns it decoded as a string';
175
    public static function echoSixtyFour($req)
176
    {
177 559
        // Accepts an encoded value, but sends it back as a normal string.
178 559
        // This is to test that base64 encoding is working as expected
179
        $incoming = $req->getParam(0);
180
181
        return new Response(new Value($incoming->scalarVal(), Value::$xmlrpcString));
182
    }
183
184
    public static $bitflipper_sig = array(array('array', 'array'));
185
    public static $bitflipper_doc = 'Accepts an array of booleans, and returns them inverted';
186
    public static function bitFlipper($req)
187 559
    {
188 559
        $v = $req->getParam(0);
189
        $rv = new Value(array(), Value::$xmlrpcArray);
190
191
        foreach ($v as $b) {
192
            if ($b->scalarVal()) {
193 22
                $rv[] = new Value(false, Value::$xmlrpcBoolean);
194
            } else {
195 22
                $rv[] = new Value(true, Value::$xmlrpcBoolean);
196
            }
197
        }
198 559
199 559
        return new Response($rv);
200
    }
201
202 22
    public static $mailsend_sig = array(array(
203 22
        'boolean', 'string', 'string',
204
        'string', 'string', 'string',
205 22
        'string', 'string',
206 22
    ));
207 22
    public static $mailsend_doc = 'mail.send(recipient, subject, text, sender, cc, bcc, mimetype)<br/>
208
recipient, cc, and bcc are strings, comma-separated lists of email addresses, as described above.<br/>
209 22
subject is a string, the subject of the message.<br/>
210
sender is a string, it\'s the email address of the person sending the message. This string can not be
211
a comma-separated list, it must contain a single email address only.<br/>
212
text is a string, it contains the body of the message.<br/>
213 22
mimetype, a string, is a standard MIME type, for example, text/plain.';
214
    /**
215
     * WARNING: this functionality depends on the sendmail -t option, it may not work with Windows machines properly;
216 559
     * particularly the Bcc option.
217 559
     * Sneak on your friends at your own risk!
218
     */
219
    public static function mailSend($req)
220
    {
221
        $err = "";
222
223
        $mTo = $req->getParam(0);
224
        $mSub = $req->getParam(1);
225
        $mBody = $req->getParam(2);
226
        $mFrom = $req->getParam(3);
227
        $mCc = $req->getParam(4);
228
        $mBcc = $req->getParam(5);
229
        $mMime = $req->getParam(6);
230
231
        if ($mTo->scalarVal() == "") {
232
            $err = "Error, no 'To' field specified";
233
        }
234
235
        if ($mFrom->scalarVal() == "") {
236
            $err = "Error, no 'From' field specified";
237
        }
238 559
239 559
        /// @todo in real life, we should check for presence of return characters to avoid header injection!
240
241
        $msgHdr = "From: " . $mFrom->scalarVal() . "\n";
242 22
        $msgHdr .= "To: " . $mTo->scalarVal() . "\n";
243 22
244 22
        if ($mCc->scalarVal() != "") {
245 22
            $msgHdr .= "Cc: " . $mCc->scalarVal() . "\n";
246 22
        }
247
        if ($mBcc->scalarVal() != "") {
248
            $msgHdr .= "Bcc: " . $mBcc->scalarVal() . "\n";
249 22
        }
250
        if ($mMime->scalarVal() != "") {
251
            $msgHdr .= "Content-type: " . $mMime->scalarVal() . "\n";
252 559
        }
253 559
        $msgHdr .= "X-Mailer: XML-RPC for PHP mailer 1.0";
254
255
        if ($err == "") {
256 1
            if (!mail("", $mSub->scalarVal(), $mBody->scalarVal(), $msgHdr)) {
257 1
                $err = "Error, could not send the mail.";
258
            }
259
        }
260
261 559
        if ($err) {
262 559
            return new Response(0, PhpXmlRpc::$xmlrpcerruser, $err);
263 559
        } else {
264
            return new Response(new Value(true, Value::$xmlrpcBoolean));
265 559
        }
266
    }
267
268
}
269
270
return array(
271
    "examples.getStateName" => array(
272
        "function" => array("exampleMethods", "findState"),
273
        "signature" => exampleMethods::$findstate_sig,
274
        "docstring" => exampleMethods::$findstate_doc,
275
    ),
276
    "examples.sortByAge" => array(
277
        "function" => array("exampleMethods", "ageSorter"),
278
        "signature" => exampleMethods::$agesorter_sig,
279
        "docstring" => exampleMethods::$agesorter_doc,
280
    ),
281
    "examples.addtwo" => array(
282
        "function" => array("exampleMethods", "addTwo"),
283
        "signature" => exampleMethods::$addtwo_sig,
284
        "docstring" => exampleMethods::$addtwo_doc,
285
    ),
286
    "examples.addtwodouble" => array(
287
        "function" => array("exampleMethods", "addTwoDouble"),
288
        "signature" => exampleMethods::$addtwodouble_sig,
289
        "docstring" => exampleMethods::$addtwodouble_doc,
290
    ),
291
    "examples.stringecho" => array(
292
        "function" => array("exampleMethods", "stringEcho"),
293
        "signature" => exampleMethods::$stringecho_sig,
294
        "docstring" => exampleMethods::$stringecho_doc,
295
    ),
296
    "examples.echo" => array(
297
        "function" => array("exampleMethods", "echoBack"),
298
        "signature" => exampleMethods::$echoback_sig,
299
        "docstring" => exampleMethods::$echoback_doc,
300
    ),
301
    "examples.decode64" => array(
302
        "function" => array("exampleMethods", "echoSixtyFour"),
303
        "signature" => exampleMethods::$echosixtyfour_sig,
304
        "docstring" => exampleMethods::$echosixtyfour_doc,
305
    ),
306
    "examples.invertBooleans" => array(
307
        "function" => array("exampleMethods", "bitFlipper"),
308
        "signature" => exampleMethods::$bitflipper_sig,
309
        "docstring" => exampleMethods::$bitflipper_doc,
310
    ),
311
312
    // same as examples_getStateName, but with no dot - so that it is easier to map this into a method call
313
    // by clients which map f.e. xmlrpc method names into php object method names
314
    "examples_getStateName" => array(
315
        "function" => array("exampleMethods", "findState"),
316
        "signature" => exampleMethods::$findstate_sig,
317
        "docstring" => exampleMethods::$findstate_doc,
318
    ),
319
320
    // left in as an example, but disabled by default, to avoid this being abused if left on an open server
321
    /*"mail.send" => array(
322
        "function" => array("exampleMethods", "mailSend"),
323
        "signature" => exampleMethods::$mailsend_sig,
324
        "docstring" => exampleMethods::$mailsend_doc,
325
    ),*/
326
);
327