=====REST Handler===== >>==See also:== - Documentation: RESTHandlerInfo ==works with:== - Wikka 1.1.6.4 & 1.1.6.5 >>//NOT included in any Wikka version//{{lastedit show="3"}} 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)%s%s%s %s'); $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 = '
'. "\n"; $my_page .= $this->Format($this->page['body'], 'wakka'); $my_page .= '
'. "\n"; // Footnote action if (function_exists('FNprint')) { $my_page .= (FNprint($this, 'list', '', $this->Href())); } $my_page .= '
'."\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 = ''. $output .''; } // the 'Content-Type' HTTP Header is sent in libs/Wakka.class.php print (''. "\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: %%(php) if (!preg_match("/(xml|raw|mm|grabcode)$/", $method)) { %% with the following code block: %%(php) 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: %%(php) // 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: %%(php) // 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', '<')) ? 'Unsupported: requires PHP version 5.0.0 or higher' : $this->Method('rest'); print ($output); } // grabcode page handler %%