PageRenderTime 45ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/fitzgerald.php

https://bitbucket.org/timcubb/mcms
PHP | 366 lines | 285 code | 72 blank | 9 comment | 33 complexity | fc56af3b23ed07559ceaf18badec63fb MD5 | raw file
  1. <?php
  2. // This is the only file you really need! The directory structure of this repo is a suggestion,
  3. // not a requirement. It's your app.
  4. /* Fitzgerald - a single file PHP framework
  5. * (c) 2010 Jim Benton and contributors, released under the MIT license
  6. * Version 0.5
  7. */
  8. class Url {
  9. private $url;
  10. private $method;
  11. private $conditions;
  12. public $params = array();
  13. public $match = false;
  14. public function __construct($httpMethod, $url, $conditions=array(), $mountPoint) {
  15. $requestMethod = $_SERVER['REQUEST_METHOD'];
  16. $requestUri = str_replace($mountPoint, '', preg_replace('/\?.+/', '', $_SERVER['REQUEST_URI']));
  17. $this->url = $url;
  18. $this->method = $httpMethod;
  19. $this->conditions = $conditions;
  20. if (strtoupper($httpMethod) == $requestMethod) {
  21. $paramNames = array();
  22. $paramValues = array();
  23. preg_match_all('@:([a-zA-Z_]+)@', $url, $paramNames, PREG_PATTERN_ORDER); // get param names
  24. $paramNames = $paramNames[1]; // we want the set of matches
  25. $regexedUrl = preg_replace_callback('@:[a-zA-Z_\-]+@', array($this, 'regexValue'), $url); // replace param with regex capture
  26. if (preg_match('@^' . $regexedUrl . '$@', $requestUri, $paramValues)){ // determine match and get param values
  27. array_shift($paramValues); // remove the complete text match
  28. for ($i=0; $i < count($paramNames); $i++) {
  29. $this->params[$paramNames[$i]] = $paramValues[$i];
  30. }
  31. $this->match = true;
  32. }
  33. }
  34. }
  35. private function regexValue($matches) {
  36. $key = str_replace(':', '', $matches[0]);
  37. if (array_key_exists($key, $this->conditions)) {
  38. return '(' . $this->conditions[$key] . ')';
  39. } else {
  40. return '([a-zA-Z0-9_\-]+)';
  41. }
  42. }
  43. }
  44. class ArrayWrapper {
  45. private $subject;
  46. public function __construct(&$subject) {
  47. $this->subject = $subject;
  48. }
  49. public function __get($key) {
  50. return isset($this->subject[$key]) ? $this->subject[$key] : null;
  51. }
  52. public function __set($key, $value) {
  53. $this->subject[$key] = $value;
  54. return $value;
  55. }
  56. public function __isset($key){
  57. return isset($this->subject[$key]) && ( is_array($this->subject[$key]) || strlen($this->subject[$key]) > 0 );
  58. }
  59. public function getCount(){
  60. return count($this->subject);
  61. }
  62. }
  63. class SessionWrapper {
  64. public function setFlash($msg, $status = 'none') {
  65. $_SESSION['flash_msg'] = $msg;
  66. $_SESSION['flash_status'] = $status;
  67. }
  68. public function getFlash() {
  69. $msg = '';
  70. if (isset($_SESSION['flash_msg'])) {
  71. $msg = $_SESSION['flash_msg'];
  72. unset($_SESSION['flash_msg']);
  73. unset($_SESSION['flash_status']);
  74. }
  75. return $msg;
  76. }
  77. public function hasFlash() {
  78. return isset($_SESSION['flash_msg']);
  79. }
  80. public function flashStatus() {
  81. $status = 'undefined';
  82. if (isset($_SESSION['flash_status'])) {
  83. $status = $_SESSION['flash_status'];
  84. // it's unset at getFlash as it's related to the flash itself
  85. }
  86. return $status;
  87. }
  88. public function __get($key) {
  89. return isset($_SESSION[$key]) ? $_SESSION[$key] : null;
  90. }
  91. public function __set($key, $value) {
  92. $_SESSION[$key] = $value;
  93. return $value;
  94. }
  95. public function __isset($key){
  96. return isset($_SESSION[$key]);
  97. }
  98. }
  99. class RequestWrapper {
  100. public function __get($key) {
  101. return isset($_REQUEST[$key]) ? $_REQUEST[$key] : null;
  102. }
  103. public function __set($key, $value) {
  104. $_REQUEST[$key] = $value;
  105. return $value;
  106. }
  107. public function __isset($key){
  108. return isset($_REQUEST[$key]);
  109. }
  110. public function getCount(){
  111. return count($_REQUEST);
  112. }
  113. }
  114. class Fitzgerald {
  115. private $mappings = array(), $before_filters = array(), $after_filters = array();
  116. protected $options;
  117. protected $session;
  118. protected $request;
  119. public function __construct($options=array()) {
  120. $this->options = new ArrayWrapper($options);
  121. session_name('fitzgerald_session');
  122. session_start();
  123. $this->session = new SessionWrapper;
  124. $this->request = new RequestWrapper;
  125. set_error_handler(array($this, 'handleError'), 2);
  126. }
  127. public function handleError($number, $message, $file, $line) {
  128. header("HTTP/1.0 500 Server Error");
  129. echo $this->render('500', compact('number', 'message', 'file', 'line'));
  130. die();
  131. }
  132. public function show404() {
  133. header("HTTP/1.0 404 Not Found");
  134. echo $this->render('404');
  135. die();
  136. }
  137. public function get($url, $methodName, $conditions = array()) {
  138. $this->event('get', $url, $methodName, $conditions);
  139. }
  140. public function post($url, $methodName, $conditions = array()) {
  141. $this->event('post', $url, $methodName, $conditions);
  142. }
  143. public function put($url, $methodName, $conditions = array()) {
  144. $this->event('put', $url, $methodName, $conditions);
  145. }
  146. public function delete($url, $methodName, $conditions = array()) {
  147. $this->event('delete', $url, $methodName, $conditions);
  148. }
  149. public function before($methodName, $filterName) {
  150. $this->push_filter($this->before_filters, $methodName, $filterName);
  151. }
  152. public function after($methodName, $filterName) {
  153. $this->push_filter($this->after_filters, $methodName, $filterName);
  154. }
  155. protected function push_filter(&$arr_filter, $methodName, $filterName) {
  156. if (!is_array($methodName)) {
  157. $methodName = explode('|', $methodName);
  158. }
  159. for ($i = 0; $i < count($methodName); $i++) {
  160. $method = $methodName[$i];
  161. if (!isset($arr_filter[$method])) {
  162. $arr_filter[$method] = array();
  163. }
  164. array_push($arr_filter[$method], $filterName);
  165. }
  166. }
  167. protected function run_filter($arr_filter, $methodName) {
  168. if(isset($arr_filter[$methodName])) {
  169. for ($i=0; $i < count($arr_filter[$methodName]); $i++) {
  170. $return = call_user_func(array($this, $arr_filter[$methodName][$i]));
  171. if(!is_null($return)) {
  172. return $return;
  173. }
  174. }
  175. }
  176. }
  177. public function run() {
  178. echo $this->processRequest();
  179. }
  180. protected function redirect($path) {
  181. $protocol = empty($_SERVER['HTTPS']) ? 'http' : 'https';
  182. $host = (preg_match('%^http://|https://%', $path) > 0) ? '' : "$protocol://" . $_SERVER['HTTP_HOST'];
  183. $uri = is_string($this->options->mountPoint) ? $this->options->mountPoint : '';
  184. if (!empty($this->error)) {
  185. $this->session->error = $this->error;
  186. }
  187. if (!empty($this->success)) {
  188. $this->session->success = $this->success;
  189. }
  190. header("Location: $host$uri$path");
  191. return false;
  192. }
  193. protected function render($fileName, $variableArray=array()) {
  194. $variableArray['options'] = $this->options;
  195. $variableArray['request'] = $this->request;
  196. $variableArray['session'] = $this->session;
  197. if(isset($this->error)) {
  198. $variableArray['error'] = $this->error;
  199. }
  200. if(isset($this->success)) {
  201. $variableArray['success'] = $this->success;
  202. }
  203. if (is_string($this->options->layout)) {
  204. //echo "huh: 1".$this->options->layout;
  205. $variableArray['content'] = $this->renderTemplate($fileName, $variableArray);
  206. return $this->renderTemplate($this->options->layout, $variableArray);
  207. } else {
  208. //echo "huh: 0";
  209. return $this->renderTemplate($fileName, $variableArray);
  210. }
  211. }
  212. protected function renderTemplate($fileName, $locals = array())
  213. {
  214. ob_start();
  215. extract($locals);
  216. include(realpath($this->root() . 'views/' . $fileName . '.php'));
  217. return ob_get_clean();
  218. }
  219. protected function renderPartial($fileName, $locals = array())
  220. {
  221. echo $this->renderTemplate($fileName, $locals);
  222. }
  223. protected function sendFile($filename, $contentType, $path) {
  224. header("Content-type: $contentType");
  225. header("Content-Disposition: attachment; filename=$filename");
  226. return readfile($path);
  227. }
  228. protected function sendDownload($filename, $path) {
  229. header("Content-Type: application/force-download");
  230. header("Content-Type: application/octet-stream");
  231. header("Content-Type: application/download");
  232. header("Content-Description: File Transfer");
  233. header("Content-Disposition: attachment; filename=$filename".";");
  234. header("Content-Transfer-Encoding: binary");
  235. return readfile($path);
  236. }
  237. protected function execute($methodName, $params) {
  238. $return = $this->run_filter($this->before_filters, $methodName);
  239. if (!is_null($return)) {
  240. return $return;
  241. }
  242. if ($this->session->error) {
  243. $this->error = $this->session->error;
  244. $this->session->error = null;
  245. }
  246. if ($this->session->success) {
  247. $this->success = $this->session->success;
  248. $this->session->success = null;
  249. }
  250. $reflection = new ReflectionMethod(get_class($this), $methodName);
  251. $args = array();
  252. foreach($reflection->getParameters() as $param) {
  253. if(isset($params[$param->name])) {
  254. $args[$param->name] = $params[$param->name];
  255. }
  256. else if($param->isDefaultValueAvailable()) {
  257. $args[$param->name] = $param->getDefaultValue();
  258. }
  259. }
  260. $response = $reflection->invokeArgs($this, $args);
  261. $return = $this->run_filter($this->after_filters, $methodName);
  262. if (!is_null($return)) {
  263. return $return;
  264. }
  265. return $response;
  266. }
  267. protected function event($httpMethod, $url, $methodName, $conditions=array()) {
  268. if (method_exists($this, $methodName)) {
  269. array_push($this->mappings, array($httpMethod, $url, $methodName, $conditions));
  270. }
  271. }
  272. protected function root() {
  273. if($root = $this->options->root)
  274. return $root;
  275. else
  276. return dirname(__FILE__) . '/../';
  277. }
  278. protected function path($path) {
  279. return $this->root() . $path;
  280. }
  281. protected function processRequest() {
  282. $charset = (is_string($this->options->charset)) ? ";charset={$this->options->charset}" : "";
  283. header("Content-type: text/html" . $charset);
  284. for($i = 0; $i < count($this->mappings); $i++) {
  285. $mapping = $this->mappings[$i];
  286. $mountPoint = is_string($this->options->mountPoint) ? $this->options->mountPoint : '';
  287. $url = new Url($mapping[0], $mapping[1], $mapping[3], $mountPoint);
  288. if($url->match) {
  289. return $this->execute($mapping[2], $url->params);
  290. }
  291. }
  292. return $this->show404();
  293. }
  294. }