/** * Default Q/dir handler. * Just displays a simple directory listing, * and prevents further processing by returning true. */ function Q_dir() { $filename = Q_Request::filename(); // TODO: show directory listing echo Q::view('Q/dir.php', compact('filename')); return true; }
function Q_file($params) { $filename = Q::ifset($params, 'filename', Q_Request::filename()); $parts = explode('.', $filename); $ext = end($parts); $intercept = true; switch ($ext) { case 'png': case 'jpeg': case 'gif': header("Content-type: image/{$ext}"); break; case 'jpg': header("Content-type: image/jpeg"); break; case 'pdf': header("Content-type: application/{$ext}"); break; case 'js': header("Content-type: application/javascript"); break; case 'ogg': case 'mp3': header("Content-type: audio/{$ext}"); break; case 'css': header("Content-type: text/css"); break; case 'cur': header("Content-type: image/vnd.microsoft.icon .cur .ico"); break; default: break; } header("HTTP/1.0 404 Not Found"); readfile($filename); return true; }
/** * Dispatches a URI for internal processing. * Usually called by a front controller. * @method dispatch * @static * @param {mixed} [$uri=null] You can pass a custom URI to dispatch. Otherwise, Qbix will attempt * to route the requested URL, if any. * @param {array} [$check=array('accessible')] Pass array() to skip checking whether the URI can be obtained * as a result of routing some URL. * @return {boolean} * @throws {Q_Exception_MethodNotSupported} * @throws {Q_Exception_Recursion} * @throws {Q_Exception_DispatcherErrors} * @throws {Q_Exception_DispatcherForward} */ static function dispatch($uri = null, $check = array('accessible')) { if (!is_array($check)) { $check = array('accessible'); } if (isset($uri)) { if (in_array('accessible', $check)) { if (!Q_Uri::url($uri)) { // We shouldn't dispatch to this URI $uri = Q_Uri::from(array()); } } self::$uri = Q_Uri::from($uri); } else { $request_uri = Q_Request::uri(); self::$uri = clone $request_uri; } // if file or dir is requested, try to serve it $served = false; $skip = Q_Config::get('Q', 'dispatcherSkipFilename', false); $filename = $skip ? false : Q_Request::filename(); if ($filename) { if (is_dir($filename)) { /** * @event Q/dir * @param {string} filename * @param {string} routed_uri * @return {boolean} */ $served = Q::event("Q/dir", compact('filename', 'routed_uri')); $dir_was_served = true; } else { /** * @event Q/file * @param {string} filename * @param {string} routed_uri * @return {boolean} */ $served = Q::event("Q/file", compact('filename', 'routed_uri')); $dir_was_served = false; } } // if response was served, then return if ($served) { self::result($dir_was_served ? "Dir served" : "File served"); return true; } // This loop is for forwarding $max_forwards = Q_Config::get('Q', 'maxForwards', 10); for ($try = 0; $try < $max_forwards; ++$try) { // Make an array from the routed URI $routed_uri_array = array(); if (self::$uri instanceof Q_Uri) { $routed_uri_array = self::$uri->toArray(); } // If no module was found, then respond with noModule and return if (!isset(self::$uri->module)) { /** * @event Q/noModule * @param {array} $routed_uri_array */ Q::event("Q/noModule", $routed_uri_array); // should echo things self::result("No module"); return false; } $module = self::$uri->module; try { // Implement restricting of modules we are allowed to access $routed_modules = Q_Config::get('Q', 'routedModules', null); if (isset($routed_modules)) { if (!in_array($module, $routed_modules)) { /** * @event Q/notFound * @param {array} $routed_uri_array */ Q::event('Q/notFound', $routed_uri_array); // should echo things self::result("Unknown module"); return false; } } else { if (!Q::realPath("handlers/{$module}")) { Q::event('Q/notFound', $routed_uri_array); // should echo things self::result("Unknown module"); return false; } } // Implement notFound if action was not found if (empty(self::$uri->action)) { Q::event('Q/notFound', $routed_uri_array); // should echo things self::result("Unknown action"); return false; } // Fire a pure event, for aggregation etc if (!isset(self::$skip['Q/prepare'])) { /** * @event Q/prepare * @param {array} $routed_uri_array */ Q::event('Q/prepare', $routed_uri_array, true); } // Perform validation if (!isset(self::$skip['Q/validate'])) { /** * @event Q/validate * @param {array} $routed_uri_array */ Q::event('Q/validate', $routed_uri_array); if (!isset(self::$skip['Q/errors'])) { // Check if any errors accumulated if (Q_Response::getErrors()) { // There were validation errors -- render a response self::result('Validation errors'); self::errors(null, $module, null); return false; } } } // Time to instantiate some app objects from the request if (!isset(self::$skip['Q/objects'])) { /** * @event Q/objects * @param {array} $routed_uri_array */ Q::event('Q/objects', $routed_uri_array, true); } // We might want to reroute the request if (!isset(self::$skip['Q/reroute'])) { /** * @event Q/reroute * @param {array} $routed_uri_array * @return {boolean} whether to stop the dispatch */ $stop_dispatch = Q::event('Q/reroute', $routed_uri_array, true); if ($stop_dispatch) { self::result("Stopped dispatch"); return false; } } // Make some changes to server state, possibly $method = Q_Request::method(); if ($method != 'GET') { $methods = Q_Config::get('Q', 'methods', array('POST', 'PUT', 'DELETE', 'OPTIONS', 'HEAD')); if (!in_array($method, $methods)) { throw new Q_Exception_MethodNotSupported(compact('method')); } $method_event = 'Q/' . strtolower($method); if (!isset(self::$skip['Q/method']) and !isset(self::$skip[$method_event])) { if (!Q::canHandle($method_event)) { throw new Q_Exception_MethodNotSupported(compact('method')); } Q::event($method_event); } } // You can calculate some analytics here, and store them somewhere if (!isset(self::$skip['Q/analytics'])) { /** * @event Q/analytics * @param {array} $routed_uri_array */ Q::event('Q/analytics', $routed_uri_array, true); } if (!isset(self::$skip['Q/errors'])) { // Check if any errors accumulated if (Q_Response::getErrors()) { // There were processing errors -- render a response self::result('Processing errors'); self::errors(null, $module, null); return false; } } // When handling all further events, you should probably // refrain from changing server state, and only do reading. // That is because GET in HTTP is not supposed to have side effects // for which the client is responsible. // Start buffering the response, unless otherwise requested $handler = Q_Response::isBuffered(); if ($handler !== false) { $ob = new Q_OutputBuffer($handler); } // Generate and render a response /** * @event Q/response * @param {array} $routed_uri_array */ self::$response_started = true; Q::event("Q/response", $routed_uri_array); if (!empty($ob)) { $ob->endFlush(); } self::result("Served response"); return true; } catch (Q_Exception_DispatcherForward $e) { if (!empty($ob)) { $ob->getClean(); } self::handleForwardException($e); } catch (Q_Exception_DispatcherErrors $e) { if (!empty($ob)) { $partial_response = $ob->getClean(); } else { $partial_response = null; } self::errors(null, $module, $partial_response); self::result("Rendered errors"); return true; } catch (Exception $exception) { if (!empty($ob)) { $partial_response = $ob->getClean(); } else { $partial_response = null; } $message = $exception->getMessage(); $file = $exception->getFile(); $line = $exception->getLine(); if (is_callable(array($exception, 'getTraceAsStringEx'))) { $trace_string = $exception->getTraceAsStringEx(); } else { $trace_string = $exception->getTraceAsString(); } $colored = Q_Exception::coloredString($message, $file, $line, $trace_string); self::result("Exception occurred:\n\n{$colored}"); try { self::errors($exception, $module, $partial_response); } catch (Exception $e) { if (!empty($forwarding_to_error_action)) { // Looks like there were errors in the error action // So show the default one with the original exception throw $exception; } if (get_class($e) === 'Q_Exception_DispatcherForward') { $forwarding_to_error_action = true; self::handleForwardException($e); continue; } else { throw $e; } } return false; } } // If we are here, we have done forwarding too much throw new Q_Exception_Recursion(array('function_name' => 'Dispatcher::forward()')); }