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>
7 * This file is part of PhpWiki.
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.
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.
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
23 * LIBRARY USED - POSSIBLE PROBLEMS
24 * ================================
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
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.
36 * INTERFACE SPECIFICTION
37 * ======================
39 * The interface specification is that discussed at
40 * http://www.ecyrd.com/JSPWiki/Wiki.jsp?page=WikiRPCInterface
42 * See also http://www.usemod.com/cgi-bin/mb.pl?XmlRpc
44 * NB: All XMLRPC methods should be prefixed with "wiki."
50 // Remove all warnings from xmlrpc.inc
51 // Return list of external links in listLinks
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")
59 die('This is the address of the XML-RPC interface.' .
60 ' You must use XML-RPC calls to access information here');
63 // Include the php XML-RPC library
64 include("lib/XMLRPC/xmlrpc.inc");
65 include("lib/XMLRPC/xmlrpcs.inc");
67 // Constant defined to indicate to phpwiki that it is being accessed via XML-RPC
68 define ("WIKI_XMLRPC", "true");
70 define ("WIKI_XMLRPC_VERSION", 1);
71 // Start up the main code
72 include_once("index.php");
73 include_once("lib/main.php");
76 * Helper function: Looks up a page revision (most recent by default) in the wiki database
78 * @param xmlrpcmsg $params : string pagename [int version]
79 * @return WikiDB _PageRevision object, or false if no such page
82 function _getPageRevision ($params)
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);
94 $revision = $page->getCurrentRevision();
96 $revision = $page->getRevision($version);
104 * Helper functions for encoding/decoding strings.
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.
114 * Convert a short string (page name, author) to xmlrpcval.
116 function short_string ($str) {
117 return new xmlrpcval(rawurlencode(utf8_encode($str)), 'string');
121 * Convert a large string (page content) to xmlrpcval.
123 function long_string ($str) {
124 return new xmlrpcval(utf8_encode($str), 'base64');
128 * Decode a short string (e.g. page name)
130 function short_string_decode ($str) {
131 return utf8_decode(urldecode($str));
135 * Get an xmlrpc "No such page" error message
137 function NoSuchPage ()
139 global $xmlrpcerruser;
140 return new xmlrpcresp(0, $xmlrpcerruser + 1, "No such page");
144 // ****************************************************************************
145 // Main API functions follow
146 // ****************************************************************************
150 * int getRPCVersionSupported(): Returns 1 for this version of the API
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';
161 // The function must be a function in the global scope which services the XML-RPC
163 function getRPCVersionSupported($params)
165 return new xmlrpcresp(new xmlrpcval(WIKI_XMLRPC_VERSION, "int"));
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
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.
179 $getRecentChanges_sig = array(array($xmlrpcArray, $xmlrpcDateTime));
180 $getRecentChanges_doc = 'Get a list of changed pages since [timestamp]';
182 function getRecentChanges($params)
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();
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');
199 // Build an array of xmlrpc structs
200 $pages[] = new xmlrpcval(array('name'=>$name,
201 'lastModified'=>$lastmodified,
203 'version'=>$version),
206 return new xmlrpcresp(new xmlrpcval($pages, "array"));
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.
216 $getPage_sig = array(array($xmlrpcBase64, $xmlrpcString));
217 $getPage_doc = 'Get the raw Wiki text of the current version of a page';
219 function getPage($params)
221 $revision = _getPageRevision($params);
226 return new xmlrpcresp(long_string($revision->getPackedContent()));
231 * base64 getPageVersion( String pagename, int version ): Get the raw Wiki text of page.
232 * Returns UTF-8, expects UTF-8 with URL encoding.
235 $getPageVersion_sig = array(array($xmlrpcBase64, $xmlrpcString, $xmlrpcInt));
236 $getPageVersion_doc = 'Get the raw Wiki text of a page version';
238 function getPageVersion($params)
240 // error checking is done in getPage
241 return getPage($params);
245 * base64 getPageHTML( String pagename ): Return page in rendered HTML.
246 * Returns UTF-8, expects UTF-8 with URL encoding.
249 $getPageHTML_sig = array(array($xmlrpcBase64, $xmlrpcString));
250 $getPageHTML_doc = 'Get the current version of a page rendered in HTML';
252 function getPageHTML($params)
254 $revision = _getPageRevision($params);
258 include_once('lib/PageType.php');
259 $content = array(PageType($revision));
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')
265 $content = $content[0]->getContent();
268 return new xmlrpcresp(long_string(AsXML($content)));
272 * base64 getPageHTMLVersion( String pagename, int version ): Return page in rendered HTML, UTF-8.
275 $getPageHTMLVersion_sig = array(array($xmlrpcBase64, $xmlrpcString, $xmlrpcInt));
276 $getPageHTMLVersion_doc = 'Get a version of a page rendered in HTML';
278 function getPageHTMLVersion($params)
280 return getPageHTML($params);
284 * getAllPages(): Returns a list of all pages. The result is an array of strings.
287 $getAllPages_sig = array(array($xmlrpcArray));
288 $getAllPages_doc = 'Returns a list of all pages as an array of strings';
290 function getAllPages($params)
293 $dbh = $request->getDbh();
294 $iterator = $dbh->getAllPages();
296 while ($page = $iterator->next()) {
297 $pages[] = short_string($page->getName());
299 return new xmlrpcresp(new xmlrpcval($pages, "array"));
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
310 $getPageInfo_sig = array(array($xmlrpcStruct, $xmlrpcString));
311 $getPageInfo_doc = 'Gets info about the current version of a page';
313 function getPageInfo($params)
315 $revision = _getPageRevision($params);
319 $name = short_string($revision->getPageName());
320 $version = new xmlrpcval ($revision->getVersion(), "int");
321 $lastmodified = new xmlrpcval(iso8601_encode($revision->get('mtime'), 0),
323 $author = short_string($revision->get('author'));
325 return new xmlrpcresp(new xmlrpcval(array('name' => $name,
326 'lastModified' => $lastmodified,
327 'version' => $version,
328 'author' => $author),
333 * struct getPageInfoVersion( string pagename, int version ) : returns
334 * a struct just like plain getPageInfo(), but this time for a
338 $getPageInfoVersion_sig = array(array($xmlrpcStruct, $xmlrpcString, $xmlrpcInt));
339 $getPageInfoVersion_doc = 'Gets info about a page version';
341 function getPageInfoVersion($params)
343 return getPageInfo($params);
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).
353 $listLinks_sig = array(array($xmlrpcArray, $xmlrpcString));
354 $listLinks_doc = 'Lists all links for a given page';
356 function listLinks($params)
360 $ParamPageName = $params->getParam(0);
361 $pagename = short_string_decode($ParamPageName->scalarval());
362 $dbh = $request->getDbh();
363 if (! $dbh->isWikiPage($pagename))
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');
376 // Compute URL to page
378 $currentrev = $currentpage->getCurrentRevision();
379 if ($currentrev->hasDefaultContents())
380 $args['action'] = 'edit';
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));
389 $linkstruct[] = new xmlrpcval(array('name'=> $name,
394 return new xmlrpcresp(new xmlrpcval ($linkstruct, "array"));
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),
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),
436 array("function" => "listLinks",
437 "signature" => $listLinks_sig,
438 "docstring" => $listLinks_doc)
441 // (c-file-style: "gnu")
446 // c-hanging-comment-ender-p: nil
447 // indent-tabs-mode: nil