/** * Check if a view file exists * @param array $context * @param bool $check_controller Check for the existence of a corresponding controller method * @return bool */ public static function exists($context, $check_controller = false) { $file = APP_DIR . 'sites/' . $context['site'] . '/' . $context['template'] . '/' . $context['controller'] . '.' . $context['view'] . '.php'; if (file_exists($file)) { return $file; } $file = APP_DIR . 'sites/' . $context['site'] . '/' . self::$CONTEXT_DEFAULTS['template'] . '/' . $context['controller'] . '.' . $context['view'] . '.php'; if (file_exists($file)) { return $file; } if ($check_controller && Controller::exists($context['site'], $context['controller']) && method_exists('controllers\\' . $context['site'] . '\\' . $context['controller'], $context['view'])) { return true; } else { return false; } }
/** * Main bootstrapping function. Initialize framework, perform routing, hand things off to template controller. * @return void */ public static function init() { self::trace('init'); // Load classes that will always be used; faster than autoloader include CONFIG_FILE; if (!defined('IS_PRODUCTION')) { throw new \Exception('IS_PRODUCTION not set! Please check ' . CONFIG_FILE . '.'); } include JMVC_DIR . 'view.php'; include JMVC_DIR . 'controller.php'; if (file_exists(APP_DIR . 'routes.php')) { include APP_DIR . 'routes.php'; } if (file_exists(APP_DIR . 'constants.php')) { include APP_DIR . 'constants.php'; } date_default_timezone_set('America/New_York'); // TODO: make this configurable spl_autoload_register(array('JMVC', 'autoloader')); // set error handling error_reporting(E_ERROR | E_WARNING | E_PARSE); set_exception_handler(array('JMVC', 'handle_exception')); set_error_handler(array('JMVC', 'handle_error'), E_ERROR | E_WARNING); register_shutdown_function(array('JMVC', 'fatal_error_checker')); if (defined('TRACE_THRESHOLD')) { register_shutdown_function(array('JMVC', 'check_trace')); } self::trace('bootstrap complete'); if (!isset($_SERVER['REQUEST_URI'])) { //don't do routing if we're not running as a web server process return; } // define some helper constants $uri = htmlspecialchars(urldecode($_SERVER['REQUEST_URI'])); // defend against XSS if ($qPos = strpos($uri, '?')) { define('CURRENT_URL', substr($uri, 0, $qPos)); define('QUERY_STRING', substr($uri, $qPos)); } else { define('CURRENT_URL', $uri); define('QUERY_STRING', ''); } define('IS_AJAX', isset($_SERVER['HTTP_X_REQUESTED_WITH'])); // check if we need to do a URL redirect (301) if (isset($REDIRECTS)) { foreach ($REDIRECTS as $in => $out) { $routed_url = preg_replace('%' . $in . '%', $out, CURRENT_URL, 1, $count); if ($count) { \jmvc\Controller::forward($routed_url . QUERY_STRING, true); break; } } } self::trace('redirects complete'); $app_url = CURRENT_URL; // Check for any internal URL mapping if (isset($ROUTES)) { foreach ($ROUTES as $in => $out) { $routed_url = preg_replace('%' . $in . '%', $out, $app_url, 1, $count); if ($count) { $routed_parts = explode('?', $routed_url); $app_url = $routed_parts[0]; if (isset($routed_parts[1]) && !empty($routed_parts[1])) { foreach (explode('&', $routed_parts[1]) as $pair) { list($key, $val) = explode('=', $pair); $_GET[$key] = $val; $_REQUEST[$key] = $val; } } break; } } } self::trace('routes complete'); // Set default context if (defined('DEFAULT_SITE')) { \jmvc\View::$CONTEXT_DEFAULTS['site'] = DEFAULT_SITE; } if (defined('DEFAULT_TEMPLATE')) { \jmvc\View::$CONTEXT_DEFAULTS['template'] = DEFAULT_TEMPLATE; } if (defined('DEFAULT_CONTROLLER')) { \jmvc\View::$CONTEXT_DEFAULTS['controller'] = DEFAULT_CONTROLLER; } if (defined('DEFAULT_VIEW')) { \jmvc\View::$CONTEXT_DEFAULTS['view'] = DEFAULT_VIEW; } // routing if ($app_url == '/') { $context = \jmvc\View::$CONTEXT_DEFAULTS; $url_parts = array(); } else { if (substr($app_url, 0, 5) == '/css/') { self::css(); } else { // Parse each segment of the URL, left to right $url_parts = explode('/', trim($app_url, '/')); // Set site if (Controller::exists($url_parts[0], 'template')) { $context['site'] = array_shift($url_parts); } if (isset($context['site'])) { if ($context['site'] == \jmvc\View::$CONTEXT_DEFAULTS['site']) { // block direct url for default site \jmvc::do404(); } } else { $context['site'] = \jmvc\View::$CONTEXT_DEFAULTS['site']; } // Do not allow access to base class methods if (method_exists('jmvc\\controller', $url_parts[0])) { \jmvc::do404(); } // Set template if (method_exists('controllers\\' . $context['site'] . '\\Template', $url_parts[0])) { $context['template'] = array_shift($url_parts); } if (isset($context['template'])) { if ($context['template'] == \jmvc\View::$CONTEXT_DEFAULTS['template']) { // block direct url for default template \jmvc::do404(); } } else { $context['template'] = \jmvc\View::$CONTEXT_DEFAULTS['template']; } // Get controller $possible_controller = str_replace('-', '_', $url_parts[0]); if ($possible_controller == \jmvc\View::$CONTEXT_DEFAULTS['controller'] || $possible_controller == 'template') { // block direct url for default controller \jmvc::do404(); } if (Controller::exists($context['site'], $possible_controller)) { $context['controller'] = $possible_controller; array_shift($url_parts); } if (!isset($context['controller'])) { $context['controller'] = \jmvc\View::$CONTEXT_DEFAULTS['controller']; } // Get view $possible_view = empty($url_parts) ? null : str_replace('-', '_', $url_parts[0]); if ($possible_view == \jmvc\View::$CONTEXT_DEFAULTS['view']) { // block direct url for default view \jmvc::do404(); } if (count($url_parts) && View::exists($context + array('view' => $possible_view), true)) { $context['view'] = $possible_view; array_shift($url_parts); } if (!isset($context['view'])) { $context['view'] = \jmvc\View::$CONTEXT_DEFAULTS['view']; } } } self::trace('routing complete'); self::hook('post_routing', $context); self::trace('post_routing hooks complete'); // Hand things off to the template controller ob_start(); echo \jmvc\View::render(array_merge($context, array('controller' => 'template', 'view' => $context['template'])), array_merge($url_parts, array('context' => $context))); self::hook('post_render', $context); }