summaryrefslogtreecommitdiff
path: root/lpf/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lpf/lib')
-rw-r--r--lpf/lib/Controller.class.php30
-rw-r--r--lpf/lib/Mime.class.php45
-rw-r--r--lpf/lib/Model.class.php9
-rw-r--r--lpf/lib/Router.class.php110
-rw-r--r--lpf/lib/View.class.php135
5 files changed, 329 insertions, 0 deletions
diff --git a/lpf/lib/Controller.class.php b/lpf/lib/Controller.class.php
new file mode 100644
index 0000000..05736ee
--- /dev/null
+++ b/lpf/lib/Controller.class.php
@@ -0,0 +1,30 @@
+<?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) {
+ if ($vars===null) { $vars = array(); }
+
+ $obj = new View($view);
+ $obj->show($vars);
+ }
+
+ // Here be default handlers ////////////////////////////////////////////
+
+ public function index($routed, $remainder) {
+ header('Content-type: text/plain');
+ echo " == Generic Controller Index == \n\n";
+ $routed_str = implode('/', $routed);
+ $remainder_str = implode('/', $remainder);
+ echo "Full path: $routed_str/$remainder_str\n";
+ echo "Controller path: $routed_str\n";
+ echo "Remainder path: $remainder_str\n";
+ }
+ public function http404($routed, $remainder) {
+ $this->showView('http404', array('routed'=>$routed,
+ 'remainder'=>$remainder));
+ }
+}
diff --git a/lpf/lib/Mime.class.php b/lpf/lib/Mime.class.php
new file mode 100644
index 0000000..f37c1eb
--- /dev/null
+++ b/lpf/lib/Mime.class.php
@@ -0,0 +1,45 @@
+<?php
+
+class Mime {
+ public static $mimes = array(
+ 'csv' => array(
+ 'text/csv', 'text/x-csv',
+ 'text/x-comma-separated-values',
+ 'text/comma-separated-values',
+ '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'),
+ 'jpg' => array('image/jpeg', 'image/pjpeg'),
+ 'jpe' => array('image/jpeg', 'image/pjpeg'),
+ 'png' => array('image/png', 'image/x-png'),
+ 'tiff' => 'image/tiff',
+ 'tif' => 'image/tiff',
+ 'css' => 'text/css',
+ 'htm' => 'text/html',
+ 'txt' => 'text/plain',
+ 'json' => array('application/json', 'text/json')
+ );
+
+ public static function ext2mime($ext) {
+ $mimes = self::$mimes;
+ $mime = $mimes[$ext];
+ if (!is_array($mime)) $mime = array($mime);
+ return $mime;
+ }
+ public static function mime2ext($my_mime) {
+ $ret = array();
+ foreach (self::mimes as $ext => $mime) {
+ if (is_array($mime)) {
+ $match = in_array($my_mime, $mime);
+ } else {
+ $match = $my_mime==$mime;
+ }
+ if ($match) $ret[] = $ext;
+ }
+ return $ret;
+ }
+} \ No newline at end of file
diff --git a/lpf/lib/Model.class.php b/lpf/lib/Model.class.php
new file mode 100644
index 0000000..0cce525
--- /dev/null
+++ b/lpf/lib/Model.class.php
@@ -0,0 +1,9 @@
+<?php
+require_once('Database.class.php');
+
+abstract class Model {
+ protected $db;
+ public function __construct() {
+ $this->db = Database::getInstance();
+ }
+}
diff --git a/lpf/lib/Router.class.php b/lpf/lib/Router.class.php
new file mode 100644
index 0000000..238e3f8
--- /dev/null
+++ b/lpf/lib/Router.class.php
@@ -0,0 +1,110 @@
+<?php
+
+require_once('Controller.class.php');
+
+class Router {
+ /**
+ * Array mapping URIs to controllers.
+ * A controller may register itself either by using
+ * Router::register($URI, $controller[, $function]);
+ * or by adding itself to the $ROUTER global.
+ *
+ * The default here just gives us a 404 handler.
+ */
+ private $routes = array('/*' => 'Http404');
+
+ /**
+ * Instantiate a router that looks for controllers in $controllerpath.
+ */
+ public function Router($controllerpath) {
+ // create a $ROUTES global that can be used to set up our
+ // $this->routes.
+ global $ROUTES;
+ $ROUTES = $this->routes;
+
+ // Split $controllerpath into directories, and load the
+ // controllers in each.
+ $dirs = explode(PATH_SEPARATOR, $controllerpath);
+ foreach ($dirs as $dir) {
+ // Find all files in $dir with the ext `.class.php'
+ $files = glob($dir.'/*.class.php');
+ foreach ($files as $file) {
+ // and include them
+ require_once($file);
+ }
+ }
+
+ $this->routes = $ROUTES;
+ unset($ROUTES);
+ }
+
+ /**
+ * Route the page at the relative URL $page to the appropriate
+ * controller, and call the appropriate function.
+ */
+ public function route($page) {
+ $parts = explode('/', $page);
+ $length = count($parts); // the # of segments in $controllerpart
+
+ // if $page ends in "/", strip that off
+ if ($parts[$length-1]=='') {
+ array_pop($parts);
+ $length--;
+ }
+
+ $controllerpart = implode('/', $parts);
+
+ // Keep shortening $controllerpart until it matches something in
+ // $this->routes. The shortest it will ever become is '/*'.
+ // If no key exists for '/*', that's an infinite loop.
+ // Fortunately, the default value of $this->routes directs '/*'
+ // to the Http404 controller.
+ while(!isset($this->routes[$controllerpart])) {
+ $some_parts = array_slice($parts, 0, $length);
+ $controllerpart = implode('/', $some_parts).'/*';
+ $length--;
+ }
+ $length++;
+
+ // Figure what function to call on what controller
+ // Grammar Nazi Warning: `what' or `which'?
+ $controller = $this->routes[$controllerpart];
+ if (strpos($controller, '->')===false) {
+ // imply function
+ $function = $parts[$length];
+ } else {
+ preg_match('/(.*)->(.*)/', $controller, $matches);
+ $controller = $matches[1];
+ $function = $matches[2];
+ }
+
+ // Default to the `index' function, provided by all controllers
+ if ($function=='') {
+ $function = 'index';
+ }
+
+ // We will pass these arrays to the function.
+ $routed = array_slice($parts, 0, $length);
+ $remainder = array_slice($parts, $length);
+
+ // Finally, run the controller
+ $obj = new $controller();
+ if (in_array($function, get_class_methods($obj))) {
+ call_user_func(array($obj, $function),
+ $routed, $remainder);
+ } else {
+ $obj->http404($routed, $remainder);
+ }
+ }
+
+ /**
+ * This is to allow controllers to register themselves to the router.
+ * If $function=='', then the function will be determined by the segment
+ * to the right of the last segment in $path
+ */
+ public static function register($path, $controller, $function='') {
+ $str = $controller.(($function=='')?'':'->'.$function);
+ global $ROUTES;
+ $ROUTES[$path] = $str;
+ }
+} \ No newline at end of file
diff --git a/lpf/lib/View.class.php b/lpf/lib/View.class.php
new file mode 100644
index 0000000..d7a21d3
--- /dev/null
+++ b/lpf/lib/View.class.php
@@ -0,0 +1,135 @@
+<?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;
+ $pref = array('html');
+ foreach ($pref as $ext) {
+ if (in_array($ext, $extensions)) return $ext;
+ }
+ 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();
+ $regex = '@'.preg_quote(VIEWPATH,'@').'[^.]*\.(.*)\.php$@';
+ foreach ($files as $file) {
+ $ext = preg_replace($regex, '$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]);
+
+ require_once(VIEWPATH.'/Template.class.php');
+ $vars['template'] = new Template();
+
+ global $VARS;
+ $VARS = $vars;
+ include($file);
+ unset($VARS);
+ }
+}