'Bad Request', 403 => 'Forbidden', 415 => 'Unsupported Media Type', 501 => 'Not Implemented' ); /** MainDriver($outline_store, $tpl): Construct the driver object, given an OutlineStore and a template processor. */ function MainDriver($config, $log, $routes, $store, $tpl) { $this->config = $config; $this->log = $log; $this->routes = $routes; $this->store = $store; $this->tpl = $tpl; } /** matchRoute($path): Match a URL path against configured routes to find a URL prefix and an action to call. */ function matchRoute($method, $path) { $url_match = "/"; $action_match = "default.action.php"; foreach ($this->routes as $req_spec => $action) { list($method_spec, $url) = explode(' ', $req_spec); if ( ('*'==$method_spec || $method==$method_spec) && startsWith($path, $url) ) { $url_match = $url; $action_match = $action; break; } } // Work out the extra path info not matched by the route. $path = substr($path, strlen($url_match)-1); return array('url'=>$url_match, 'action'=>$action_match, 'path'=>$path, 'method'=>$method); } /** main(): Main driver function, dispatches to method handlers. */ function main() { // Set up the error handler to throw exceptions set_error_handler(array("MainDriver", "handleError")); // Toss a reference to the driver into the template processor. $this->tpl->assign('driver', $this); // HACK: Use the base URL and query string to carve out path. $path = substr($_SERVER['REQUEST_URI'], strlen($this->config['BASE_URL'])); if (isset($_SERVER['QUERY_STRING']) && strlen($_SERVER['QUERY_STRING'])>0) $path = substr($path, 0, 0-1-strlen($_SERVER['QUERY_STRING'])); $path = urldecode($path); // HACK: Allow request method spoofing from URL parameter, for Safari etal. if ('POST' == $_SERVER['REQUEST_METHOD'] && isset($_GET['REQUEST_METHOD'])) $_SERVER['REQUEST_METHOD'] = $_GET['REQUEST_METHOD']; // Match the path up with available routes. $route = $this->matchRoute($_SERVER['REQUEST_METHOD'], $path); $this->log->debug("Route matched, method=".$route['method']." path=".$route['path']." url=".$route['url']." action=".$route['action']); // Fire up the action associated with the route. global $driver; $driver = $this; $this->route = $route; $this->path = $route['path']; include $this->config['ACTION_PATH'].'/'.$route['action']; return; } /** handleError: Convert old-style errors into modern exceptions. */ public static function handleError($errnum, $errmsg, $file, $lineno) { global $log; $msg = "Error #$errnum in $file @ line $lineno:\n\n$errmsg"; switch ($errnum) { case E_USER_ERROR: $log->err($msg); header("HTTP/1.1 500 Internal Server Error", 500); throw new Exception($msg); case E_USER_WARNING: $log->warn($msg); break; case E_USER_NOTICE: $log->info($msg); break; default: $log->debug($msg); break; } } /** getRequestBody(): Fetch the raw data from a request. */ function getRequestBody() { if (isset($HTTP_RAW_POST_DATA)) { $input = $HTTP_RAW_POST_DATA; } else { $input = file_get_contents('php://input'); } return $input; } /** showErrorTextResponse($code, $msg): */ function showErrorTextResponse($code, $msg) { $status_msg = $this->status_codes[$code]; header("HTTP/1.1 $code $status_msg", $code); header("Content-Type: text/plain"); echo $msg."\n"; } /** show400(): Display a page not found error TODO: Set these functions up more generically. */ function show400($msg) { header("HTTP/1.1 400 Bad Request", 400); echo $msg; // $this->tpl->display('400.tpl.php'); } /** show403(): Display a page not found error */ function show403($message) { header("HTTP/1.1 403 Forbidden", 403); $this->tpl->assign('message', $message); $this->tpl->display('403.tpl.php'); } /** show404(): Display a page not found error */ function show404() { header("HTTP/1.1 404 Not Found", 404); $this->tpl->display('404.tpl.php'); } /** echoJSON($data): Render and echo a data structure as a JSON format string. */ function echoJSON($data) { $json = new Services_JSON(); $out = $json->encode($data); if (isset($_GET['callback'])) { $out = $_GET['callback']."($out)"; } header("Content-Type: text/javascript; charset=utf8"); echo $out; } /** applyXSLT($xsl_fn, $data): Given an XSL filename and a string of XML data, apply the transformation. */ function applyXSLT($xsl_fn, $data, $vars=array()) { // Load up and parse the stylesheet. $xsl_fn = $this->config['XSL_PATH']."/".$xsl_fn; try { $xsl_data = file_get_contents($xsl_fn); $xsl_doc = new DOMDocument(); $xsl_doc->loadXML($xsl_data); $xsl = new XSLTProcessor(); $xsl->importStyleSheet($xsl_doc); } catch (Exception $e) { throw new Exception("Couldn't load XSL '$xsl_fn': ".$e->getMessage()); } // Dump some PHP request data into parameters. /* foreach ($_ENV as $k => $v) { $xsl->setParameter("", "ENV.$k", "$v"); } foreach ($_REQUEST as $k => $v) { $xsl->setParameter("", "REQUEST.$k", "$v"); } foreach ($_POST as $k => $v) { $xsl->setParameter("", "POST.$k", "$v"); } */ foreach ($_GET as $k => $v) { $xsl->setParameter("", "GET.$k", "$v"); } foreach ($_SERVER as $k => $v) { $xsl->setParameter("", "SERVER.$k", "$v"); } foreach ($this->config as $k => $v) { $xsl->setParameter("", "CONFIG.$k", "$v"); } foreach ($vars as $k => $v) { $xsl->setParameter("", "VARS.$k", "$v"); } try { if (is_string($data)) { // If the incoming document is in string form, parse it. $doc = new DOMDocument(); $doc->loadXML($data); } else { // Otherwise, use it directly and assume it's a doc. $doc = $data; } // Attempt to apply the XSL transformation to the given XML // $doc = $xsl->transformToDoc($doc); $rv = $xsl->transformToXML($doc); if (!$rv) throw new Exception("XSL transformation failed!"); return $rv; } catch(Exception $e) { throw new Exception("Couldn't apply XSL '$xsl_fn' to XML: ".$e->getMessage()); } } } ?>