<?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); } }