]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - RPC2.php
General cleanup.
[SourceForge/phpwiki.git] / RPC2.php
1 <?php 
2 // $Id: RPC2.php,v 1.3 2002-09-04 20:35:15 dairiki Exp $
3 /* Copyright (C) 2002, Lawrence Akka <lakka@users.sourceforge.net>
4  *
5  * LICENCE
6  * =======
7  * This file is part of PhpWiki.
8  * 
9  * PhpWiki is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  * 
14  * PhpWiki is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  * 
19  * You should have received a copy of the GNU General Public License
20  * along with PhpWiki; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  *
23  * LIBRARY USED - POSSIBLE PROBLEMS
24  * ================================
25  * 
26  * This file provides an XML-RPC interface for PhpWiki.  It uses the XML-RPC 
27  * library for PHP by Edd Dumbill - see http://xmlrpc.usefulinc.com/php.html 
28  * for details.
29  *
30  * PHP >= 4.1.0 includes experimental support for the xmlrpc-epi c library 
31  * written by Dan Libby (see http://uk2.php.net/manual/en/ref.xmlrpc.php).  This
32  * is not compiled into PHP by default.  If it *is* compiled into your installation
33  * (ie you have --with-xmlrpc) there may well be namespace conflicts with the xml-rpc
34  * library used by this code, and you will get errors.
35  * 
36  * INTERFACE SPECIFICTION
37  * ======================
38  *  
39  * The interface specification is that discussed at 
40  * http://www.ecyrd.com/JSPWiki/Wiki.jsp?page=WikiRPCInterface
41  * 
42  * See also http://www.usemod.com/cgi-bin/mb.pl?XmlRpc
43  * 
44  * NB:  All XMLRPC methods should be prefixed with "wiki."
45  * eg  wiki.getAllPages
46  * 
47 */
48
49 // ToDo:  
50 //        Remove all warnings from xmlrpc.inc 
51 //        Return list of external links in listLinks
52  
53
54 // Intercept GET requests from confused users.  Only POST is allowed here!
55 // There is some indication that $HTTP_SERVER_VARS is deprecated in php > 4.1.0
56 // in favour of $_Server, but as far as I know, it still works.
57 if ($HTTP_SERVER_VARS['REQUEST_METHOD'] != "POST")  
58 {
59     die('This is the address of the XML-RPC interface.' .
60         '  You must use XML-RPC calls to access information here');
61 }
62
63 // Include the php XML-RPC library
64 include("lib/XMLRPC/xmlrpc.inc");
65 include("lib/XMLRPC/xmlrpcs.inc");
66
67 // Constant defined to indicate to phpwiki that it is being accessed via XML-RPC
68 define ("WIKI_XMLRPC", "true");
69 //  API version
70 define ("WIKI_XMLRPC_VERSION", 1);
71 // Start up the main code
72 include_once("index.php");
73 include_once("lib/main.php");
74
75 /**
76  * Helper function:  Looks up a page revision (most recent by default) in the wiki database
77  * 
78  * @param xmlrpcmsg $params :  string pagename [int version]
79  * @return WikiDB _PageRevision object, or false if no such page
80  */
81
82 function _getPageRevision ($params)
83 {
84     global $request;
85     $ParamPageName = $params->getParam(0);
86     $ParamVersion = $params->getParam(1);
87     $pagename = short_string_decode($ParamPageName->scalarval());
88     $version =  ($ParamVersion) ? ($ParamVersion->scalarval()):(0);
89     // FIXME:  test for version <=0 ??
90     $dbh = $request->getDbh();
91     if ($dbh->isWikiPage($pagename)) {
92         $page = $dbh->getPage($pagename);
93         if (!$version) {
94             $revision = $page->getCurrentRevision();
95         } else {
96             $revision = $page->getRevision($version);
97         } 
98         return $revision;
99     } 
100     return false;
101
102
103 /*
104  * Helper functions for encoding/decoding strings.
105  *
106  * According to WikiRPC spec, all returned strings take one of either
107  * two forms.  Short strings (page names, and authors) are converted to
108  * UTF-8, then rawurlencode()d, and returned as XML-RPC <code>strings</code>.
109  * Long strings (page content) are converted to UTF-8 then returned as
110  * XML-RPC <code>base64</code> binary objects.
111  */
112
113 /**
114  * Convert a short string (page name, author) to xmlrpcval.
115  */
116 function short_string ($str) {
117     return new xmlrpcval(rawurlencode(utf8_encode($str)), 'string');
118 }
119
120 /**
121  * Convert a large string (page content) to xmlrpcval.
122  */
123 function long_string ($str) {
124     return new xmlrpcval(utf8_encode($str), 'base64');
125 }
126
127 /**
128  * Decode a short string (e.g. page name)
129  */
130 function short_string_decode ($str) {
131     return utf8_decode(urldecode($str));
132 }
133
134 /**
135  * Get an xmlrpc "No such page" error message
136  */
137 function NoSuchPage () 
138 {
139     global $xmlrpcerruser;
140     return new xmlrpcresp(0, $xmlrpcerruser + 1, "No such page");
141 }
142
143
144 // ****************************************************************************
145 // Main API functions follow
146 // ****************************************************************************
147
148
149 /**
150  * int getRPCVersionSupported(): Returns 1 for this version of the API 
151  */
152
153 // Method signature:  An array of possible signatures.  Each signature is
154 // an array of types. The first entry is the return type.  The other 
155 // entries (if any) are the parameter types
156 $getRPCVersionSupported_sig = array(array($xmlrpcInt));
157 // Doc string:  A string containing documentation for the method. The 
158 // documentation may contain HTML markup
159 $getRPCVersionSupported_doc = 'Get the version of the wiki API';
160
161 // The function must be a function in the global scope which services the XML-RPC
162 // method.
163 function getRPCVersionSupported($params)
164 {
165     return new xmlrpcresp(new xmlrpcval(WIKI_XMLRPC_VERSION, "int"));
166 }
167
168 /**
169  * array getRecentChanges(Date timestamp) : Get list of changed pages since 
170  * timestamp, which should be in UTC. The result is an array, where each element
171  * is a struct: 
172  *     name (string) : Name of the page. The name is UTF-8 with URL encoding to make it ASCII. 
173  *     lastModified (date) : Date of last modification, in UTC. 
174  *     author (string) : Name of the author (if available). Again, name is UTF-8 with URL encoding. 
175  *         version (int) : Current version. 
176  * A page MAY be specified multiple times. A page MAY NOT be specified multiple 
177  * times with the same modification date.
178  */
179 $getRecentChanges_sig = array(array($xmlrpcArray, $xmlrpcDateTime));
180 $getRecentChanges_doc = 'Get a list of changed pages since [timestamp]';
181
182 function getRecentChanges($params)
183 {
184     global $request;
185     // Get the first parameter as an ISO 8601 date.  Assume UTC
186     $encoded_date = $params->getParam(0);
187     $datetime = iso8601_decode($encoded_date->scalarval(), 1);
188     $dbh = $request->getDbh();
189     $pages = array();
190     $iterator = $dbh->mostRecent(array('since' => $datetime));
191     while ($page = $iterator->next()) {
192         // $page contains a WikiDB_PageRevision object
193         // no need to url encode $name, because it is already stored in that format ???
194         $name = short_string($page->getPageName());
195         $lastmodified = new xmlrpcval(iso8601_encode($page->get('mtime')), "dateTime.iso8601");
196         $author = short_string($page->get('author'));
197         $version = new xmlrpcval($page->getVersion(), 'int');
198
199         // Build an array of xmlrpc structs
200         $pages[] = new xmlrpcval(array('name'=>$name, 
201                                        'lastModified'=>$lastmodified,
202                                        'author'=>$author,
203                                        'version'=>$version),
204                                  'struct');
205     } 
206     return new xmlrpcresp(new xmlrpcval($pages, "array"));
207
208
209
210 /**
211  * base64 getPage( String pagename ): Get the raw Wiki text of page, latest version. 
212  * Page name must be UTF-8, with URL encoding. Returned value is a binary object,
213  * with UTF-8 encoded page data.
214  */
215
216 $getPage_sig = array(array($xmlrpcBase64, $xmlrpcString));
217 $getPage_doc = 'Get the raw Wiki text of the current version of a page';
218
219 function getPage($params)
220 {
221     $revision = _getPageRevision($params);
222
223     if (! $revision)
224         return NoSuchPage();
225
226     return new xmlrpcresp(long_string($revision->getPackedContent()));
227 }
228  
229
230 /**
231  * base64 getPageVersion( String pagename, int version ): Get the raw Wiki text of page.
232  * Returns UTF-8, expects UTF-8 with URL encoding.
233  */
234
235 $getPageVersion_sig = array(array($xmlrpcBase64, $xmlrpcString, $xmlrpcInt));
236 $getPageVersion_doc = 'Get the raw Wiki text of a page version';
237
238 function getPageVersion($params)
239 {
240     // error checking is done in getPage
241     return getPage($params);
242
243
244 /**
245  * base64 getPageHTML( String pagename ): Return page in rendered HTML. 
246  * Returns UTF-8, expects UTF-8 with URL encoding.
247  */
248
249 $getPageHTML_sig = array(array($xmlrpcBase64, $xmlrpcString));
250 $getPageHTML_doc = 'Get the current version of a page rendered in HTML';
251
252 function getPageHTML($params)
253 {
254     $revision = _getPageRevision($params);
255     if (!$revision)
256         return NoSuchPage();
257     
258     include_once('lib/PageType.php');
259     $content = array(PageType($revision));
260
261     // Get rid of outer <div class="wikitext">
262     while (count($content) == 1 && isa($content[0], 'XmlContent')) {
263         if (isa($content[0], 'XmlElement') && $content[0]->getTag() != 'div')
264             break;
265         $content = $content[0]->getContent();
266     }
267
268     return new xmlrpcresp(long_string(AsXML($content)));
269
270
271 /**
272  * base64 getPageHTMLVersion( String pagename, int version ): Return page in rendered HTML, UTF-8.
273  */
274
275 $getPageHTMLVersion_sig = array(array($xmlrpcBase64, $xmlrpcString, $xmlrpcInt));
276 $getPageHTMLVersion_doc = 'Get a version of a page rendered in HTML';
277
278 function getPageHTMLVersion($params)
279 {
280     return getPageHTML($params);
281
282
283 /**
284  * getAllPages(): Returns a list of all pages. The result is an array of strings.
285  */
286
287 $getAllPages_sig = array(array($xmlrpcArray));
288 $getAllPages_doc = 'Returns a list of all pages as an array of strings'; 
289  
290 function getAllPages($params)
291 {
292     global $request;
293     $dbh = $request->getDbh();
294     $iterator = $dbh->getAllPages();
295     $pages = array();
296     while ($page = $iterator->next()) {
297         $pages[] = short_string($page->getName());
298     } 
299     return new xmlrpcresp(new xmlrpcval($pages, "array"));
300
301
302 /**
303  * struct getPageInfo( string pagename ) : returns a struct with elements: 
304  *   name (string): the canonical page name 
305  *   lastModified (date): Last modification date 
306  *   version (int): current version 
307  *       author (string): author name 
308  */
309
310 $getPageInfo_sig = array(array($xmlrpcStruct, $xmlrpcString));
311 $getPageInfo_doc = 'Gets info about the current version of a page';
312
313 function getPageInfo($params)
314 {
315     $revision = _getPageRevision($params);
316     if (!$revision)
317         return NoSuchPage();
318     
319     $name = short_string($revision->getPageName());
320     $version = new xmlrpcval ($revision->getVersion(), "int");
321     $lastmodified = new xmlrpcval(iso8601_encode($revision->get('mtime'), 0),
322                                   "dateTime.iso8601");
323     $author = short_string($revision->get('author'));
324         
325     return new xmlrpcresp(new xmlrpcval(array('name' => $name, 
326                                               'lastModified' => $lastmodified,
327                                               'version' => $version, 
328                                               'author' => $author), 
329                                         "struct"));
330
331
332 /**
333  * struct getPageInfoVersion( string pagename, int version ) : returns
334  * a struct just like plain getPageInfo(), but this time for a
335  * specific version.
336  */
337
338 $getPageInfoVersion_sig = array(array($xmlrpcStruct, $xmlrpcString, $xmlrpcInt));
339 $getPageInfoVersion_doc = 'Gets info about a page version';
340
341 function getPageInfoVersion($params)
342 {
343     return getPageInfo($params);
344 }
345
346  
347 /*  array listLinks( string pagename ): Lists all links for a given page. The
348  *  returned array contains structs, with the following elements: 
349  *       name (string) : The page name or URL the link is to. 
350  *       type (int) : The link type. Zero (0) for internal Wiki link,
351  *         one (1) for external link (URL - image link, whatever).
352  */
353 $listLinks_sig = array(array($xmlrpcArray, $xmlrpcString));
354 $listLinks_doc = 'Lists all links for a given page';
355
356 function listLinks($params)
357 {
358     global $request;
359     
360     $ParamPageName = $params->getParam(0);
361     $pagename = short_string_decode($ParamPageName->scalarval());
362     $dbh = $request->getDbh();
363     if (! $dbh->isWikiPage($pagename))
364         return NoSuchPage();
365     
366     $page = $dbh->getPage($pagename);
367     $linkiterator = $page->getLinks();
368     $linkstruct = array();
369     while ($currentpage = $linkiterator->next()) {
370         $currentname = $currentpage->getName();
371         $name = short_string($currentname);
372         // NB no clean way to extract a list of external links yet, so
373         // only internal links returned.  ie all type 'local'.
374         $type = new xmlrpcval('local');
375
376         // Compute URL to page
377         $args = array();
378         $currentrev = $currentpage->getCurrentRevision();
379         if ($currentrev->hasDefaultContents())
380             $args['action'] = 'edit';
381
382         // FIXME: Autodetected value of VIRTUAL_PATH wrong,
383         // this make absolute URLs contstructed by WikiURL wrong.
384         // Also, if USE_PATH_INFO is false, WikiURL is wrong
385         // due to its use of SCRIPT_NAME.
386         $use_abspath = USE_PATH_INFO && ! preg_match('/RPC2.php$/', VIRTUAL_PATH);
387         $href = new xmlrpcval(WikiURL($currentname, $args, $use_abspath));
388             
389         $linkstruct[] = new xmlrpcval(array('name'=> $name,
390                                             'type'=> $type,
391                                             'href' => $href),
392                                       "struct");
393     }
394     return new xmlrpcresp(new xmlrpcval ($linkstruct, "array"));
395
396  
397 // Construct the server instance, and set up the despatch map, which maps
398 // the XML-RPC methods onto the wiki functions
399 $s = new xmlrpc_server(array("wiki.getRPCVersionSupported" =>
400                              array("function" => "getRPCVersionSupported",
401                                    "signature" => $getRPCVersionSupported_sig,
402                                    "docstring" => $getRPCVersionSupported_doc),
403                              "wiki.getRecentChanges" =>
404                              array("function" => "getRecentChanges",
405                                    "signature" => $getRecentChanges_sig,
406                                    "docstring" => $getRecentChanges_doc),
407                              "wiki.getPage" =>
408                              array("function" => "getPage",
409                                    "signature" => $getPage_sig,
410                                    "docstring" => $getPage_doc),
411                              "wiki.getPageVersion" =>
412                              array("function" => "getPageVersion",
413                                    "signature" => $getPageVersion_sig,
414                                    "docstring" => $getPageVersion_doc),
415                              "wiki.getPageHTML" =>
416                              array("function" => "getPageHTML",
417                                    "signature" => $getPageHTML_sig,
418                                    "docstring" => $getPageHTML_doc),
419                              "wiki.getPageHTMLVersion" =>
420                              array("function" => "getPageHTMLVersion",
421                                    "signature" => $getPageHTMLVersion_sig,
422                                    "docstring" => $getPageHTMLVersion_doc),
423                              "wiki.getAllPages" =>
424                              array("function" => "getAllPages",
425                                    "signature" => $getAllPages_sig,
426                                    "docstring" => $getAllPages_doc),
427                              "wiki.getPageInfo" =>
428                              array("function" => "getPageInfo",
429                                    "signature" => $getPageInfo_sig,
430                                    "docstring" => $getPageInfo_doc),
431                              "wiki.getPageInfoVersion" =>
432                              array("function" => "getPageInfoVersion",
433                                    "signature" => $getPageInfoVersion_sig,
434                                    "docstring" => $getPageInfoVersion_doc),
435                              "wiki.listLinks" =>
436                              array("function" => "listLinks",
437                                    "signature" => $listLinks_sig,
438                                    "docstring" => $listLinks_doc)
439                              ));
440
441 // (c-file-style: "gnu")
442 // Local Variables:
443 // mode: php
444 // tab-width: 8
445 // c-basic-offset: 4
446 // c-hanging-comment-ender-p: nil
447 // indent-tabs-mode: nil
448 // End:   
449 ?>