Subversion-Projekte lars-tiefland.php_share

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 1
<?php
2
 
3
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
4
 
5
// LICENSE AGREEMENT. If folded, press za here to unfold and read license {{{
6
 
7
/**
8
* +-----------------------------------------------------------------------------+
9
* | Copyright (c) 2004-2006 Sergio Gonalves Carvalho                                |
10
* +-----------------------------------------------------------------------------+
11
* | This file is part of XML_RPC2.                                              |
12
* |                                                                             |
13
* | XML_RPC2 is free software; you can redistribute it and/or modify            |
14
* | it under the terms of the GNU Lesser General Public License as published by |
15
* | the Free Software Foundation; either version 2.1 of the License, or         |
16
* | (at your option) any later version.                                         |
17
* |                                                                             |
18
* | XML_RPC2 is distributed in the hope that it will be useful,                 |
19
* | but WITHOUT ANY WARRANTY; without even the implied warranty of              |
20
* | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               |
21
* | GNU Lesser General Public License for more details.                         |
22
* |                                                                             |
23
* | You should have received a copy of the GNU Lesser General Public License    |
24
* | along with XML_RPC2; if not, write to the Free Software                     |
25
* | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA                    |
26
* | 02111-1307 USA                                                              |
27
* +-----------------------------------------------------------------------------+
28
* | Author: Sergio Carvalho <sergio.carvalho@portugalmail.com>                  |
29
* +-----------------------------------------------------------------------------+
30
*
31
* @category   XML
32
* @package    XML_RPC2
33
* @author     Sergio Carvalho <sergio.carvalho@portugalmail.com>
34
* @copyright  2004-2006 Sergio Carvalho
35
* @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
36
* @version    CVS: $Id: Server.php 308639 2011-02-24 20:34:19Z sergiosgc $
37
* @link       http://pear.php.net/package/XML_RPC2
38
*/
39
 
40
// }}}
41
 
42
// dependencies {{{
43
require_once 'XML/RPC2/Exception.php';
44
require_once 'XML/RPC2/Backend.php';
45
require_once 'XML/RPC2/Server/Input.php';
46
// }}}
47
 
48
 
49
/**
50
 * XML_RPC2_Server is the frontend class for exposing PHP functions via XML-RPC.
51
 *
52
 * Exporting a programatic interface via XML-RPC using XML_RPC2 is exceedingly easy:
53
 *
54
 * The first step is to assemble all methods you wish to export into a class. You may either
55
 * create a (abstract) class with exportable methods as static, or use an existing instance
56
 * of an object.
57
 *
58
 * You'll then need to document the methods using PHPDocumentor tags. XML_RPC2 will use the
59
 * documentation for server introspection. You'll get something like this:
60
 *
61
 * <code>
62
 * class ExampleServer {
63
 *     /**
64
 *      * hello says hello
65
 *      *
66
 *      * @param string  Name
67
 *      * @return string Greetings
68
 *      {@*}
69
 *     public static function hello($name)
70
    {
71
 *         return "Hello $name";
72
 *     }
73
 * }
74
 * </code>
75
 *
76
 * Now, instantiate the server, using the Factory method to select a backend and a call handler for you:
77
 * <code>
78
 * require_once 'XML/RPC2/Server.php';
79
 * $server = XML_RPC2_Server::create('ExampleServer');
80
 * $server->handleCall();
81
 * </code>
82
 *
83
 * This will create a server exporting all of the 'ExampleServer' class' methods. If you wish to export
84
 * instance methods as well, pass an object instance to the factory instead:
85
 * <code>
86
 * require_once 'XML/RPC2/Server.php';
87
 * $server = XML_RPC2_Server::create(new ExampleServer());
88
 * $server->handleCall();
89
 * </code>
90
 *
91
 * @category   XML
92
 * @package    XML_RPC2
93
 * @author     Sergio Carvalho <sergio.carvalho@portugalmail.com>
94
 * @copyright  2004-2006 Sergio Carvalho
95
 * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
96
 * @link       http://pear.php.net/package/XML_RPC2
97
 */
98
abstract class XML_RPC2_Server
99
{
100
 
101
    // {{{ properties
102
 
103
    /**
104
     * callHandler field
105
     *
106
     * The call handler is responsible for executing the server exported methods
107
     *
108
     * @var mixed
109
     */
110
    protected $callHandler = null;
111
 
112
    /**
113
     * prefix field
114
     *
115
     * @var string
116
     */
117
    protected $prefix = '';
118
 
119
    /**
120
     * encoding field
121
     *
122
     * TODO : work on encoding for this backend
123
     *
124
     * @var string
125
     */
126
    protected $encoding = 'utf-8';
127
 
128
    /**
129
     * display html documentation of xmlrpc exported methods when there is no post datas
130
     *
131
     * @var boolean
132
     */
133
    protected $autoDocument = true;
134
 
135
    /**
136
     * display external links at the end of autodocumented page
137
     *
138
     * @var boolean
139
     */
140
    protected $autoDocumentExternalLinks = true;
141
 
142
    /**
143
     * signature checking flag
144
     *
145
     * if set to true, the server will check the method signature before
146
     * calling the corresponding php method
147
     *
148
     * @var boolean
149
     */
150
    protected $signatureChecking = true;
151
 
152
    /**
153
     * input handler
154
     *
155
     * Implementation of XML_RPC2_Server_Input that feeds this server with input
156
     *
157
     * @var XML_RPC2_Server_Input
158
    */
159
    protected $input;
160
 
161
    // }}}
162
    // {{{ constructor
163
 
164
    /**
165
     * Create a new XML-RPC Server.
166
     *
167
     * @param object $callHandler the call handler will receive a method call for each remote call received.
168
     * @param array associative array of options
169
     */
170
    protected function __construct($callHandler, $options = array())
171
    {
172
        $this->callHandler = $callHandler;
173
        if ((isset($options['prefix'])) && (is_string($options['prefix']))) {
174
            $this->prefix = $options['prefix'];
175
        }
176
        if ((isset($options['encoding'])) && (is_string($options['encoding']))) {
177
            $this->encoding = $options['encoding'];
178
        }
179
        if ((isset($options['autoDocument'])) && (is_bool($options['autoDocument']))) {
180
            $this->autoDocument = $options['autoDocument'];
181
        }
182
        if ((isset($options['autoDocumentExternalLinks'])) && (is_bool($options['autoDocumentExternalLinks']))) {
183
            $this->autoDocumentExternalLinks = $options['autoDocumentExternalLinks'];
184
        }
185
        if ((isset($options['signatureChecking'])) && (is_bool($options['signatureChecking']))) {
186
            $this->signatureChecking = $options['signatureChecking'];
187
        }
188
        if (!isset($options['input'])) $options['input'] = 'XML_RPC2_Server_Input_RawPostData';
189
        if (is_string($options['input'])) {
190
            $inputDir = strtr($options['input'], array('_' => DIRECTORY_SEPARATOR)) . '.php';
191
            require_once($inputDir);
192
            $inputClass = $options['input'];
193
 
194
            $options['input'] = new $inputClass();
195
        }
196
        if ($options['input'] instanceof XML_RPC2_Server_Input) {
197
            $this->input = $options['input'];
198
        } else {
199
            throw new XML_RPC2_ConfigException('Invalid value for "input" option. It must be either a XML_RPC2_Server_Input subclass name or XML_RPC2_Server_Input subclass instance');
200
        }
201
    }
202
 
203
    // }}}
204
    // {{{ create()
205
 
206
    /**
207
     * Factory method to select a backend and return a new XML_RPC2_Server based on the backend
208
     *
209
     * @param mixed $callTarget either a class name or an object instance.
210
     * @param array associative array of options
211
     * @return object a server class instance
212
     */
213
    public static function create($callTarget, $options = array())
214
    {
215
        if (isset($options['backend'])) {
216
            XML_RPC2_Backend::setBackend($options['backend']);
217
        }
218
        if (isset($options['prefix'])) {
219
            $prefix = $options['prefix'];
220
        } else {
221
            $prefix = '';
222
        }
223
        $backend = XML_RPC2_Backend::getServerClassname();
224
        // Find callHandler class
225
        if (!isset($options['callHandler'])) {
226
            if (is_object($callTarget)) { // Delegate calls to instance methods
227
                require_once 'XML/RPC2/Server/CallHandler/Instance.php';
228
                $callHandler = new XML_RPC2_Server_CallHandler_Instance($callTarget, $prefix);
229
            } else { // Delegate calls to static class methods
230
                require_once 'XML/RPC2/Server/CallHandler/Class.php';
231
                $callHandler = new XML_RPC2_Server_CallHandler_Class($callTarget, $prefix);
232
            }
233
        } else {
234
            $callHandler = $options['callHandler'];
235
        }
236
        return new $backend($callHandler, $options);
237
    }
238
 
239
    // }}}
240
    // {{{ handleCall()
241
 
242
    /**
243
     * Receive the XML-RPC request, decode the HTTP payload, delegate execution to the call handler, and output the encoded call handler response.
244
     *
245
     */
246
    public abstract function handleCall();
247
 
248
    // }}}
249
    // {{{ errorToException()
250
 
251
    /**
252
     * Transform an error into an exception
253
     *
254
     * @param int $errno error number
255
     * @param string $errstr error string
256
     * @param string $errfile error file
257
     * @param int $errline error line
258
     */
259
    public static function errorToException($errno, $errstr, $errfile, $errline)
260
    {
261
        switch ($errno) {
262
            case E_WARNING:
263
            case E_NOTICE:
264
            case E_USER_WARNING:
265
            case E_USER_NOTICE:
266
            case E_STRICT:
267
                // Silence warnings
268
                // TODO Logging should occur here
269
                break;
270
            default:
271
                throw new Exception('Classic error reported "' . $errstr . '" on ' . $errfile . ':' . $errline);
272
        }
273
    }
274
 
275
    // }}}
276
    // {{{ autoDocument()
277
    /*     autoDocument {{{ */
278
    /**
279
     *     autoDocument. Produce an HTML page from the result of server introspection
280
     *
281
     * @return string HTML document describing this server
282
     */
283
    public function autoDocument()
284
    /* }}} */
285
    {
286
        print "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n";
287
        print "<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"en\" xml:lang=\"en\">\n";
288
        print "  <head>\n";
289
        print "    <meta http-equiv=\"Content-Type\" content=\"text/HTML; charset=" . $this->encoding . "\"  />\n";
290
        print "    <title>Available XMLRPC methods for this server</title>\n";
291
        print "    <style type=\"text/css\">\n";
292
        print "      li,p { font-size: 10pt; font-family: Arial,Helvetia,sans-serif; }\n";
293
        print "      a:link { background-color: white; color: blue; text-decoration: underline; font-weight: bold; }\n";
294
        print "      a:visited { background-color: white; color: blue; text-decoration: underline; font-weight: bold; }\n";
295
        print "      table { border-collapse:collapse; width: 100% }\n";
296
        print "      table,td { padding: 5px; border: 1px solid black; }\n";
297
        print "      div.bloc { border: 1px dashed gray; padding: 10px; margin-bottom: 20px; }\n";
298
        print "      div.description { border: 1px solid black; padding: 10px; }\n";
299
        print "      span.type { background-color: white; color: gray; font-weight: normal; }\n";
300
        print "      span.paratype { background-color: white; color: gray; font-weight: normal; }\n";
301
        print "      span.name { background-color: white; color: #660000; }\n";
302
        print "      span.paraname { background-color: white; color: #336600; }\n";
303
        print "      img { border: 0px; }\n";
304
        print "      li { font-size: 12pt; }\n";
305
        print "    </style>\n";
306
        print "  </head>\n";
307
        print "  <body>\n";
308
        print "    <h1>Available XMLRPC methods for this server</h1>\n";
309
        print "    <h2><a name=\"index\">Index</a></h2>\n";
310
        print "    <ul>\n";
311
        foreach ($this->callHandler->getMethods() as $method) {
312
            $name = $method->getName();
313
            $id = md5($name);
314
            $signature = $method->getHTMLSignature();
315
            print "      <li><a href=\"#$id\">$name()</a></li>\n";
316
        }
317
        print "    </ul>\n";
318
        print "    <h2>Details</h2>\n";
319
        foreach ($this->callHandler->getMethods() as $method) {
320
            print "    <div class=\"bloc\">\n";
321
            $method->autoDocument();
322
            print "      <p>(return to <a href=\"#index\">index</a>)</p>\n";
323
            print "    </div>\n";
324
        }
325
        if (!($this->autoDocumentExternalLinks)) {
326
            print '    <p><a href="http://pear.php.net/packages/XML_RPC2"><img src="http://pear.php.net/gifs/pear-power.png" alt="Powered by PEAR/XML_RPC2" height="31" width="88" /></a> &nbsp; &nbsp; &nbsp; <a href="http://validator.w3.org/check?uri=referer"><img src="http://www.w3.org/Icons/valid-xhtml10" alt="Valid XHTML 1.0 Strict" height="31" width="88" /></a> &nbsp; &nbsp; &nbsp; <a href="http://jigsaw.w3.org/css-validator/"><img style="border:0;width:88px;height:31px" src="http://jigsaw.w3.org/css-validator/images/vcss" alt="Valid CSS!" /></a></p>' . "\n";
327
        }
328
        print "  </body>\n";
329
        print "</html>\n";
330
    }
331
    // }}}
332
    // {{{ getContentLength()
333
 
334
    /**
335
     * Gets the content legth of a serialized XML-RPC message in bytes
336
     *
337
     * @param string $content the serialized XML-RPC message.
338
     *
339
     * @return integer the content length in bytes.
340
     */
341
    protected function getContentLength($content)
342
    {
343
        if (extension_loaded('mbstring') && (ini_get('mbstring.func_overload') & 2) == 2) {
344
            $length = mb_strlen($content, '8bit');
345
        } else {
346
            $length = strlen((binary)$content);
347
        }
348
 
349
        return $length;
350
    }
351
 
352
    // }}}
353
}
354
 
355
?>