diff options
-rw-r--r-- | index.php | 24 | ||||
-rw-r--r-- | src/lib/Controller.class.php | 61 | ||||
-rw-r--r-- | src/lib/Mime.class.php | 10 | ||||
-rw-r--r-- | src/lib/Router.class.php | 4 | ||||
-rw-r--r-- | src/lib/View.class.php | 127 |
5 files changed, 157 insertions, 69 deletions
@@ -7,28 +7,34 @@ define('LIBPATH', BASEPATH.'/src/lib'.PATH_SEPARATOR.BASEPATH.'/src/ext') define('MODELPATH', BASEPATH.'/src/models'); define('VIEWPATH', BASEPATH.'/src/views');// views are not objects define('CONTROLLERPATH', BASEPATH.'/src/controllers'); +define('PLUGINPATH', BASEPATH.'/src/plugins'); // Modify our include path to catch our class files. set_include_path(get_include_path() .PATH_SEPARATOR.LIBPATH .PATH_SEPARATOR.MODELPATH .PATH_SEPARATOR.CONTROLLERPATH + .PATH_SEPARATOR.PLUGINPATH ); // Figure what page is trying to be loaded. Don't worry if we're // looking for a real file, if the requested page exists as a real // file, .htaccess won't even let us load this file. @$PAGE_RAW = $_GET['p']; -preg_match('@(.*)(\.([^./]))?@', $PAGE_RAW, $matches); -@$PAGE = $matches[1]; -@$EXT = $matches[3]; -@$ACCEPT = $_SERVER['HTTP_ACCEPT']; -if ($PAGE=='') - $PAGE = 'index'; -if ($EXT!='') - $ACCEPT = "$EXT, $ACCEPT"; +$PAGE_PARTS = explode('/', $PAGE_RAW); +$FILE = array_pop($PAGE_PARTS); +$regex = '@([^.]*)\\.(.*)@'; +if (preg_match($regex, $FILE, $matches)) { + @$FILE = $matches[1]; + @$EXT = $matches[2]; + array_push($PAGE_PARTS, $FILE); + $PAGE = implode('/', $PAGE_PARTS); +} else { + $PAGE = $PAGE_RAW; +} +if ($PAGE=='') $PAGE = 'index'; define('PAGE', $PAGE); unset($PAGE); -define('ACCEPT', $ACCEPT); unset($ACCEPT); +define('PAGE_EXT', $EXT); unset($EXT); // Get ready require_once('Model.class.php'); diff --git a/src/lib/Controller.class.php b/src/lib/Controller.class.php index 592ea2c..f9ed59d 100644 --- a/src/lib/Controller.class.php +++ b/src/lib/Controller.class.php @@ -1,65 +1,20 @@ <?php -class Controller { - /** - * Find the best view file to include based on file extension and HTTP - * 'Accept' headers. - */ - private function _resolveView($view) { - require_once('Mime.class.php'); - require_once('HTTP_Accept.class.php'); - - // Make a list of candidate views - $glob_string = VIEWPATH.'/pages/'.$view.'.*.php'; - $files = glob($glob_string); - - // Return false if there were no candidate views. - if (count($files) < 1) return false; +require_once('View.class.php'); - // $prefs is a associative array where the key is the file - // extension, and the value is how much we like that extension. - // Higher numbers are better. - $prefs = array(); - - // $accept will tell us how much we like a given mime type, - // based on the ACCEPT constant. - $accept = new HTTP_Accept(ACCEPT); - - // Loop through the candidate views, and record how much we - // like each. - foreach ($files as $file) { - $ext = preg_replace('@[^.]*\.(.*)\.php$@','$1', $file); - $mimes = Mime::ext2mime($ext); - foreach ($mimes as $mime) { - $quality = $accept->getQuality($mime); - if (isset($final[$ext])) { - $quality = max($final[$ext], $quality); - } - $prefs[$ext] = $quality; - } - } - - // Sort $prefs such that the entry with the highest value will - // appear first. - arsort($prefs); - - // Return the first entry in $prefs. - foreach ($prefs as $ext => $quality) { - return VIEWPATH."/pages/$view.$ext.php"; - } - } - +class Controller { /** * Show a $view, in the most appropriate format (according to file * extension and HTTP Accept header). Pass the array $vars to the view. */ protected function showView($view, $vars=null) { - global $VARS, $mm; + global $mm; + if ($vars===null) { $vars = array(); } - $VARS = $vars; - $VARS['template'] = $mm->template(); - include($this->_resolveView($view)); - unset($VARS); + $vars['template'] = $mm->template(); + + $obj = new View($view); + $obj->show($vars); } // Here be default handlers //////////////////////////////////////////// diff --git a/src/lib/Mime.class.php b/src/lib/Mime.class.php index 40562b4..f37c1eb 100644 --- a/src/lib/Mime.class.php +++ b/src/lib/Mime.class.php @@ -2,13 +2,14 @@ class Mime { public static $mimes = array( - 'csv' => array('text/x-comma-separated-values', + 'csv' => array( + 'text/csv', 'text/x-csv', + 'text/x-comma-separated-values', 'text/comma-separated-values', - 'application/octet-stream', - 'application/vnd.ms-excel', - 'text/x-csv', 'text/csv', 'application/csv', + 'application/csv', 'application/excel', 'application/vnd.msexcel'), 'xhtml' => array('text/html', 'application/xhtml+xml'), + 'html' => array('text/html', 'application/xhtml+xml'), 'bmp' => 'image/bmp', 'gif' => 'image/gif', 'jpeg' => array('image/jpeg', 'image/pjpeg'), @@ -18,7 +19,6 @@ class Mime { 'tiff' => 'image/tiff', 'tif' => 'image/tiff', 'css' => 'text/css', - 'html' => 'text/html', 'htm' => 'text/html', 'txt' => 'text/plain', 'json' => array('application/json', 'text/json') diff --git a/src/lib/Router.class.php b/src/lib/Router.class.php index 459034d..238e3f8 100644 --- a/src/lib/Router.class.php +++ b/src/lib/Router.class.php @@ -27,8 +27,8 @@ class Router { $dirs = explode(PATH_SEPARATOR, $controllerpath); foreach ($dirs as $dir) { // Find all files in $dir with the ext `.class.php' - $controllerfiles = glob($dir.'/*.class.php'); - foreach ($controllerfiles as $file) { + $files = glob($dir.'/*.class.php'); + foreach ($files as $file) { // and include them require_once($file); } diff --git a/src/lib/View.class.php b/src/lib/View.class.php new file mode 100644 index 0000000..ea5ad60 --- /dev/null +++ b/src/lib/View.class.php @@ -0,0 +1,127 @@ +<?php + +require_once('Mime.class.php'); +require_once('HTTP_Accept.class.php'); + +/** + * A class to handle loading and evaluating the appropriateness of different + * views. + * + * Depends on the state of the following variables/constants: + * PAGE_EXT + * VIEWPATH + * $_SERVER['HTTP_ACCEPT'] + */ +class View { + private $extensions = array(); + private $ext = ''; + private $view = ''; + + /** + * Return the filename of the view file with extension $ext + */ + private static function filename($view, $ext) { + return VIEWPATH."/pages/$view.$ext.php"; + } + + /** + * Choose between $extensions, which all have equal quality. + */ + private function chooseBetweenEquals($extensions) { + if (count($extensions)<1) return false; + return $extensions[0]; // XXX: Worst. Solution. Ever. + } + + /** + * Find the best available extension to use, based on file extension and + * HTTP 'Accept' headers. + */ + private function chooseExtension($view) { + // Make a list of candidate extensions for this view. + $files = glob(self::filename($view, '*')); + $this->extensions = array(); + foreach ($files as $file) { + $ext = preg_replace('@[^.]*\.(.*)\.php$@','$1', $file); + $this->extensions[] = $ext; + } + if (count($this->extensions)<1) return false; + + if (PAGE_EXT != '') { + // First, do a check if we can just return requested + // file extension: + if (in_array(PAGE_EXT, $this->extensions)) { + return PAGE_EXT; + } + + // Check for other extensions with the same mime type as + // the requested: + $accept_str = implode(', ', Mime::ext2mime(PAGE_EXT)); + $extensions = $this->parseAccept($view, $accept_str); + if ($ext = $this->chooseBetweenEquals($extensions)) return $ext; + } + + // Check for other extensions based on HTTP 'Accept' headers: + $accept_str = $_SERVER['HTTP_ACCEPT']; + $extensions = $this->parseAccept($view, $accept_str); + if ($ext = $this->chooseBetweenEquals($extensions)) return $ext; + + // Well, all the good options failed, so let's see what we've + // got left: + $extensions = $this->extensions; + return $this->chooseBetweenEquals($extensions); + + } + + private function parseAccept($view, $accept_str) { + // $prefs is a associative array where the key is the file + // extension, and the value is how much we like that extension. + // Higher numbers are better. + $prefs = array(); + + $accept = new HTTP_Accept($accept_str); + + // Loop through the candidate views, and record how much we + // like each. + foreach ($this->extensions as $ext) { + $mimes = Mime::ext2mime($ext); + foreach ($mimes as $mime) { + $quality = $accept->getQuality($mime); + if (isset($prefs[$ext])) { + $quality = max($prefs[$ext], $quality); + } + $prefs[$ext] = $quality; + } + } + + // Create an array of all extensions tied for the top quality. + $ret = array(); + $top_quality = 0.001;// minimum acceptable according to RFC 2616 + foreach ($prefs as $ext => $quality) { + if ($quality > $top_quality) { + $top_quality = $quality; + $ret = array(); + } + if ($quality == $top_quality) { + $ret[] = $ext; + } + } + return $ret; + } + + public function __construct($view) { + $this->ext = $this->chooseExtension($view); + $this->view = $view; + } + + public function show($vars) { + $file = self::filename($this->view, $this->ext); + $mimes = Mime::ext2mime($this->ext); + + header('Content-type: '.$mimes[0]); + + global $VARS; + $VARS = $vars; + include($file); + unset($VARS); + } +} |