Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Initial import

  • Loading branch information...
commit f5b63be50aee8c129e479707916a16fee5cfa446 0 parents
@jim authored
19 LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2008 Jim Benton
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
5 README
@@ -0,0 +1,5 @@
+Fitzgerald is a tiny PHP framework that was inspired oh so heavily by the wondrous Sinatra of the Ruby world.
+
+See example.php for a look at how to use Fitzgerald, and read the blog post:
+
+Have fun!
15 app.php
@@ -0,0 +1,15 @@
+<?php
+ // See the accompanying README for how to use Fitzgerald!
+
+ include('lib/fitzgerald.php');
+
+ class Application extends Fitzgerald {
+ // Define your controller methods, remembering to return a value for the browser!
+ }
+
+ $app = new Application();
+
+ // Define your url mappings. TAke advantage of placeholders and regexes for safety.
+
+ $app->run();
+?>
79 example.php
@@ -0,0 +1,79 @@
+<?php
+
+ include('lib/fitzgerald.php');
+
+ class ApplicationWithLogin extends Fitzgerald {
+
+ // Redefine the constructor to setup the app
+ public function __construct($options=array()) {
+ session_set_cookie_params(3600);
+ parent::__construct($options);
+ }
+
+ // Basic get request
+ public function get_index() {
+ return $this->render('index');
+ }
+
+ // Login/logout
+ public function get_logout() {
+ $this->logout();
+ return $this->redirect('/login');
+ }
+
+ public function post_login() {
+ if ($this->login($this->request->username, $this->request->password)) {
+ return $this->redirect('/secret');
+ } else {
+ $this->error = 'Invalid username or password';
+ return $this->redirect('/login');
+ }
+ }
+
+ public function get_secret($page) {
+ if ($this->isLoggedIn()) {
+ return $this->redirect('/login');
+ }
+ $secretMessage = 'Psst!';
+ return $this->render($page, compact('secretMessage'));
+ }
+
+ // Helper methods
+
+ private function isLoggedIn() {
+ if (!is_null($this->session->user) && $this->isValidUser($this->session->user)) {
+ return true;
+ } else {
+ $this->logout();
+ return false;
+ }
+ }
+
+ private function isValidUser($username) {
+ return $username == 'frank';
+ }
+
+ private function login($username, $password) {
+ return $username == 'frank' && $password == 'sinatra';
+ }
+
+ private function logout() {
+ $this->session->user = null;
+ session_destroy();
+ }
+
+ }
+
+ // Layout is the only option right now, but you can add your own via subclassing
+ $app = new ApplicationWithLogin(array('layout' => 'login'));
+
+ // Basic mappings specify which function is called for a matching URL
+ $app->get('/', 'get_index');
+ $app->post('/login', 'post_login');
+
+ // You can use placeholders in the URL that will be mapped to the specified function's arguments
+ // The optional third argument can be an array of regexs that the url must match for each placeholder
+ $app->get('/secret/:page', 'get_secret', array('page' => 'one|two|three'));
+
+ $app->run();
+?>
222 lib/fitzgerald.php
@@ -0,0 +1,222 @@
+<?php
+
+ // This is the only file you really need! The directory structur of this repo is a suggestion,
+ // not a requirement! It's your app.
+
+ class Template {
+ private $fileName;
+ private $root;
+ public function __construct($root, $fileName) {
+ $this->fileName = $fileName;
+ $this->root = $root;
+ }
+ public function render($locals) {
+ foreach ($locals as $local => $value) {
+ $$local = $value;
+ }
+ ob_start();
+ include($this->root . 'views/' . $this->fileName . '.php');
+ return ob_get_clean();
+ }
+ }
+
+ class Url {
+ private $url;
+ private $method;
+ private $conditions;
+
+ public $params = array();
+ public $match = false;
+
+ public function __construct($httpMethod, $url, $conditions=array(), $mountPoint) {
+
+ $requestMethod = $_SERVER['REQUEST_METHOD'];
+ $requestUri = str_replace($mountPoint, '', $_SERVER['REQUEST_URI']);
+
+ $this->url = $url;
+ $this->method = $httpMethod;
+ $this->conditions = $conditions;
+
+ if (strtoupper($httpMethod) == $requestMethod) {
+
+ $paramNames = array();
+ $paramValues = array();
+
+ preg_match_all('@:([a-zA-Z]+)@', $url, $paramNames, PREG_PATTERN_ORDER); // get param names
+ $paramNames = $paramNames[1]; // we want the set of matches
+ $regexedUrl = preg_replace_callback('@:[a-zA-Z_]+@', array($this, 'regexValue'), $url); // replace param with regex capture
+ if (preg_match('@^' . $regexedUrl . '$@', $requestUri, $paramValues)){ // determine match and get param values
+ array_shift($paramValues); // remove the complete text match
+ for ($i=0; $i < count($paramNames); $i++) {
+ $this->params[$paramNames[$i]] = $paramValues[$i];
+ }
+ $this->match = true;
+ }
+ }
+ }
+
+ private function regexValue($matches) {
+ $key = str_replace(':', '', $matches[0]);
+ if (array_key_exists($key, $this->conditions)) {
+ return '(' . $this->conditions[$key] . ')';
+ } else {
+ return '([a-zA-Z0-9_]+)';
+ }
+ }
+
+ }
+
+ class ArrayWrapper {
+ private $subject;
+ public function __construct(&$subject) {
+ $this->subject = $subject;
+ }
+ public function __get($key) {
+ return isset($this->subject[$key]) ? $this->subject[$key] : null;
+ }
+
+ public function __set($key, $value) {
+ $this->subject = $value;
+ return $value;
+ }
+ }
+
+ class SessionWrapper {
+ public function __get($key) {
+ global $_SESSION;
+ return isset($_SESSION[$key]) ? $_SESSION[$key] : null;
+ }
+
+ public function __set($key, $value) {
+ global $_SESSION;
+ $_SESSION[$key] = $value;
+ return $value;
+ }
+ }
+
+ class RequestWrapper {
+ public function __get($key) {
+ global $_REQUEST;
+ return isset($_REQUEST[$key]) ? $_REQUEST[$key] : null;
+ }
+
+ public function __set($key, $value) {
+ global $_REQUEST;
+ $_REQUEST[$key] = $value;
+ return $value;
+ }
+ }
+
+ class Fitzgerald {
+
+ private $mappings = array();
+ private $options;
+ protected $session;
+ protected $request;
+
+ public function __construct($options=array()) {
+ $this->options = new ArrayWrapper($options);
+ session_name('fitzgerald_session');
+ session_start();
+ $this->session = new SessionWrapper;
+ $this->request = new RequestWrapper;
+ set_error_handler(array($this, 'handleError'), 2);
+ }
+
+ public function handleError($number, $message, $file, $line) {
+ echo $this->render('500');
+ die();
+ }
+
+ public function get($url, $methodName, $conditions=array()) {
+ $this->event('get', $url, $methodName, $conditions);
+ }
+
+ public function post($url, $methodName, $conditions=array()) {
+ $this->event('post', $url, $methodName, $conditions);
+ }
+
+ public function run() {
+ echo $this->processRequest();
+ }
+
+ protected function redirect($path) {
+ $host = $_SERVER['HTTP_HOST'];
+ if (is_string($this->options->mointPoint)) {
+ $uri = $this->options->mountPoint;
+ } else {
+ $uri = '';
+ }
+ $this->session->error = $this->error;
+ return header("Location: http://$host$uri$path");
+ }
+
+ protected function render($fileName, $variableArray=array()) {
+ $variableArray['session'] = $this->session;
+ $variableArray['request'] = $this->request;
+ if(isset($this->error)) {
+ $variableArray['error'] = $this->error;
+ }
+
+ if (is_string($this->options->layout)) {
+ $contentTemplate = new Template($this->root(), $fileName); // create content template
+ $variableArray['content'] = $contentTemplate->render($variableArray); // render and store contet
+ $layoutTemplate = new Template($this->root(), $this->options->layout); // create layout template
+ return $layoutTemplate->render($variableArray); // render layout template and return
+ } else {
+ $template = new Template($this->root(), $fileName); // create template
+ return $template->render($variableArray); // render template and return
+ }
+ }
+
+ protected function sendFile($filename, $contentType, $path) {
+ header("Content-type: $contentType");
+ header("Content-Disposition: attachment; filename=$filename");
+ return readfile($path);
+ }
+
+ private function execute($methodName, $params) {
+
+ if ($this->session->error) {
+ $this->error = $this->session->error;
+ $this->session->error = null;
+ }
+
+ $reflection = new ReflectionMethod('Application', $methodName);
+ $args = array();
+
+ foreach ($reflection->getParameters() as $i => $param) {
+ $args[$param->name] = $params[$param->name];
+ }
+ return call_user_func_array(array($this, $methodName), $args);
+ }
+
+ private function event($httpMethod, $url, $methodName, $conditions=array()) {
+ if (method_exists($this, $methodName)) {
+ array_push($this->mappings, array($httpMethod, $url, $methodName, $conditions));
+ }
+ }
+
+ protected function root() {
+ return dirname(__FILE__) . '/../';
+ }
+
+ protected function path($path) {
+ return $this->root() . $path;
+ }
+
+ private function processRequest() {
+ for ($i = 0; $i < count($this->mappings); $i++) {
+ $mapping = $this->mappings[$i];
+ $mountPoint = is_string($this->options->mountPoint) ? $this->options->mountPoint : '';
+ $url = new Url($mapping[0], $mapping[1], $mapping[3], $mountPoint);
+ if ($url->match) {
+ return $this->execute($mapping[2], $url->params);
+ }
+ }
+ $this->render('404');
+ }
+
+ }
+
+?>
5 public/.htaccess
@@ -0,0 +1,5 @@
+RewriteEngine On
+RewriteBase /
+RewriteCond %{REQUEST_FILENAME} !-f
+RewriteCond %{REQUEST_FILENAME} !-d
+RewriteRule . /index.php [L]
3  public/index.php
@@ -0,0 +1,3 @@
+<?php
+ include('../app.php');
+?>
1  views/404.php
@@ -0,0 +1 @@
+<p class="not_found">Sorry, that file was not found.</p>
1  views/500.php
@@ -0,0 +1 @@
+<p class="error">Sorry, an error occurred.</p>
Please sign in to comment.
Something went wrong with that request. Please try again.