REST Handler
See also:
- Documentation:
RESTHandlerInfo
works with:
- Wikka 1.1.6.4 & 1.1.6.5
NOT included in any Wikka versionLast edited by
DomBonj:
1.1.6.5 compatibility Mon, 30 Jun 2008 17:15 EDT [
diff]
This is the development page for the REST handler.
Installation
- Save the first code block below as
handlers/page/rest.php
- Give it the same file permissions as the other php files in that directory
- Modify
wikka.php as shown on the second code block below
- Modify
libs/Wakka.class.php as shown on the third code block below
Code
1. New
handlers/page/rest.php file
<?php
#
# Selects and returns the requested XML chunk(s) of the page
#
# @package Handlers
# @name REST
#
# @authors DomBonj
#
# @version 0.94
#
# @input Parameters in URL : [tag][/attr[/value]]
# if attr = index, value must be an integer
#
# @output returns a XML document formatted as a UTF-8 string
#
# @uses Wakka::HasAccess()
# @uses Wakka::Format()
# @uses Wakka::Href()
#
if (!
defined('REST_ERROR_NOT_SUPPORTED')) define('REST_ERROR_NOT_SUPPORTED',
'MethodUnsupported');
if (!
defined('REST_ERROR_SYNTAX')) define('REST_ERROR_SYNTAX',
'SyntaxError');
if (!
defined('REST_ERROR_BAD_PARAMETERS')) define('REST_ERROR_BAD_PARAMETERS',
'IllegalParameters');
if (!
defined('REST_ERROR_XPATH_FAILURE')) define('REST_ERROR_XPATH_FAILURE',
'XPathFailure');
if (!
defined('REST_FORMAT_ERROR_MSG')) define('REST_FORMAT_ERROR_MSG',
'<Error><Code>%s</Code><Message>%s</Message><Resource>%s %s</Resource></Error>');
$REST_RETURN_CODES_ARRAY =
array(
'MethodUnsupported' =>
array('Method not supported',
'HTTP/1.1 501 Not Implemented'),
'SyntaxError' =>
array('Could not parse request string',
'HTTP/1.1 400 Bad Request'),
'IllegalParameters' =>
array('Illegal parameter(s) value',
'HTTP/1.1 400 Bad Request'),
'XPathFailure' =>
array('Could not process query',
'HTTP/1.1 500 Server Error')
);
function numeric_html_entities
($string)
{
$trans_tbl1 =
get_html_translation_table(HTML_ENTITIES
);
foreach ($trans_tbl1 as $ascii =>
$html_entity)
{
$trans_tbl2[$html_entity] =
'&#'.
ord($ascii) .
';';
$trans_tbl3[$ascii] =
'&#'.
ord($ascii) .
';';
}
// keep XML entities
unset($trans_tbl3['<']);
unset($trans_tbl3['>']);
unset($trans_tbl3['"']);
unset($trans_tbl3['\'']);
unset($trans_tbl3['&']);
$ret =
strtr (strtr ($string,
$trans_tbl2),
$trans_tbl3);
// translate '&' character if not part of a numeric entity
$ret =
preg_replace('/&(?!#[x]?[0-9a-f]+;)/i',
'&',
$ret);
return($ret);
}
function uri_suffix_to_xpath_request
(array $params)
{ // empty return value means parameter error
$tag =
isset($params[1]) ?
($params[1]!=
'*' ?
$params[1] :
'') :
'';
$attr =
isset($params[3]) ?
($params[3]!=
'*' ?
$params[3] :
'') :
'';
$val =
isset($params[5]) ?
($params[5]!=
'*' ?
$params[5] :
'') :
'';
$rank =
isset($params[7]) ?
$params[7] :
'';
if ((($val !=
'') &&
($attr ==
''))
||
(!
preg_match('/^([1-9][0-9]*)?$/',
$rank))
||
(($tag ==
'') &&
($attr ==
'') &&
($rank !==
'')) )
{ // semantically incorrect request
$xpath =
'';
$error_code = REST_ERROR_BAD_PARAMETERS;
}
else
{ // correct request
$xpath =
$tag ?
('//'.
$tag) :
((!
$attr && !
$val) ?
'/*' :
'//*');
$xpath .=
$attr ?
(($val ?
'[contains(concat(concat(" ", @'.
$attr.
'), " "), concat(concat(" ", \''.
$val .
'\'), " "))]' :
'[@'.
$attr .
']')) :
'';
$error_code =
'';
}
return(array($xpath,
$rank,
$error_code));
}
if ($this->
HasAccess('read') &&
$this->
page)
{
if ($_SERVER['REQUEST_METHOD'] !=
'GET')
{ // not supported
$xpath_req =
'';
$error_code = REST_ERROR_NOT_SUPPORTED;
}
elseif (preg_match('/^([a-zA-Z_\*][A-Za-z0-9:_\-\.]*)?(\/([a-zA-Z_*][A-Za-z0-9:_\-\.]*)?(\/([^\/]*))?(\/([^\/]*))?)?/',
$this->
RESTreq,
$matches))
{ // well-formed request
list
($xpath_req,
$rank,
$error_code) = uri_suffix_to_xpath_request
($matches);
}
else
{ // syntactically incorrect request
$xpath_req =
'';
$error_code = REST_ERROR_SYNTAX;
}
if (!
$error_code)
{ // build (x)html page. This code block is supposed to output the same html as the 'show' handler (bar transcoding)
$my_page =
'<div class="page">'.
"\n";
$my_page .=
$this->
Format($this->
page['body'],
'wakka');
$my_page .=
'<div style="clear: both"></div>'.
"\n";
// Footnote action
if (function_exists('FNprint'))
{
$my_page .=
(FNprint
($this,
'list',
'',
$this->
Href()));
}
$my_page .=
'</div>'.
"\n";
$my_page =
utf8_encode(numeric_html_entities
($my_page));
$output =
'';
try
{ // suppress WARNING messages
$xml =
new SimpleXMLElement
($my_page, LIBXML_NOERROR
);
}
catch
(Exception
$e)
{ // $xml is NULL
$error_code = REST_ERROR_XPATH_FAILURE;
}
if ($xml)
{
$cnt_obj =
1;
foreach ($xml->
xpath($xpath_req) as $xml_obj)
{
if ($rank ===
'')
{ // false if $rank=0
$output .=
$xml_obj->
asXML() .
"\n";
}
elseif ($cnt_obj++ ==
(int
)$rank)
{ // only keep object #rank
$output =
$xml_obj->
asXML() .
"\n";
}
}
// if a '< ?xml version="1.0"? >' first line has been added, remove it
$output =
preg_replace('/^\<\?xml[^\>]*?\>/i',
'',
$output);
}
}
if ($error_code)
{ // send 'Status' HTTP Header
header($REST_RETURN_CODES_ARRAY[$error_code][1]);
$output =
sprintf(REST_FORMAT_ERROR_MSG,
$error_code,
$REST_RETURN_CODES_ARRAY[$error_code][0],
$_SERVER['REQUEST_METHOD'], numeric_html_entities
($this->
RESTreq));
}
else
{
$output =
'<wikkapage>'.
$output .
'</wikkapage>';
}
// the 'Content-Type' HTTP Header is sent in libs/Wakka.class.php
print ('<?xml version="1.0" encoding="utf-8" ?>'.
"\n".
$output);
}
?>
2. In
wikka.php, go to line 378 [version 1.1.6.4 only] or to line 385 [version 1.1.6.5 only] and replace the following code block:
if (!
preg_match("/(xml|raw|mm|grabcode)$/",
$method))
{
with the following code block:
if ((!
preg_match("/(xml|raw|mm|grabcode)$/",
$method)) &&
(!
preg_match("/^rest(\W|$)/",
$method)))
{
3. In
libs/Wakka.class.php, go to line 1743 and replace the following code block:
// raw page handler
elseif ($this->
method ==
"raw")
{
header("Content-type: text/plain");
print($this->
Method($this->
method));
}
// grabcode page handler
with the following code block:
// raw page handler
elseif ($this->
method ==
"raw")
{
header("Content-type: text/plain");
print($this->
Method($this->
method));
}
// REST handler
elseif (preg_match('/^rest(\W|$)/',
$this->
method))
{
preg_match('/^rest(\/(.*))?/',
$this->
method,
$matches);
header("Content-Type: text/xml; charset=utf-8");
$this->
RESTreq =
$matches[2];
$output =
(version_compare(PHP_VERSION,
'5.0.0',
'<')) ?
'<Error>Unsupported: requires PHP version 5.0.0 or higher</Error>' :
$this->
Method('rest');
print ($output);
}
// grabcode page handler