a tiny mvc framework for php using php-activerecord

reorganize things a bit by creating a Request object in the apache interface and passing that to the router. this will eventually let requests get routed properly that don't come from apache.

add a logging utility and log some information about each request like rails, such as the total processing time and the database time using the stuff just added to php-activerecord.

handle rescuing a bit better and move the big html page into its own .phtml file

+432 -265
+2 -2
interfaces/apache.php
··· 8 8 9 9 require_once(dirname(__FILE__) . "/../lib/halfmoon.php"); 10 10 11 - HalfMoon\Router::instance()->routeRequest($_SERVER["PATH_INFO"], 12 - $_SERVER["QUERY_STRING"], $_SERVER["HTTP_HOST"]); 11 + $req = new HalfMoon\Request($_SERVER["SCRIPT_URI"], $_GET, $_POST, $_SERVER); 12 + $req->process(); 13 13 14 14 ?>
+21 -6
lib/controller.php
··· 25 25 * forgery */ 26 26 static $protect_from_forgery = true; 27 27 28 + public $request = array(); 28 29 public $params = array(); 29 30 public $locals = array(); 30 31 31 32 private $did_render = false; 32 33 private $did_layout = false; 34 + 35 + public function __construct($request) { 36 + $this->request = $request; 37 + $this->params = &$request->params; 38 + } 33 39 34 40 /* turn local class variables into $variables when rendering views */ 35 41 public function __set($name, $value) { ··· 65 71 /* prevent any content from getting to the user */ 66 72 while (ob_end_clean()) 67 73 ; 74 + 75 + Log::info("Redirected to " . $link); 68 76 69 77 header("Location: " . $link); 70 78 ··· 147 155 /* export variables set in the controller to the view */ 148 156 foreach ($this->locals as $k => $v) { 149 157 if (in_array($k, $__special_vars)) { 150 - error_log("tried to redefine \$" . $k . " passed from " 158 + Log::warn("tried to redefine \$" . $k . " passed from " 151 159 . "controller"); 152 160 continue; 153 161 } ··· 158 166 /* and any passed as locals to the render() function */ 159 167 foreach ($__vars as $k => $v) { 160 168 if (in_array($k, $__special_vars)) { 161 - error_log("tried to redefine \$" . $k . " passed from " 162 - . "render() call"); 169 + Log::warn("tried to redefine \$" . $k . " passed " 170 + . "from render() call"); 163 171 continue; 164 172 } 165 173 ··· 169 177 /* define $controller where $this can't be used */ 170 178 $controller = $this; 171 179 180 + Log::info("Rendering " . $__file); 181 + 172 182 require($__file); 173 183 } 174 184 ··· 249 259 $this->did_layout = true; 250 260 251 261 if (file_exists(HALFMOON_ROOT . "/views/layouts/" . $layout . 252 - ".phtml")) 262 + ".phtml")) { 263 + Log::info("Rendering layout " . $layout); 253 264 require(HALFMOON_ROOT . "/views/layouts/" . $layout . ".phtml"); 254 - else 265 + } else 255 266 print $content_for_layout; 256 267 } 257 268 ··· 322 333 throw new RenderException("before_filter \"" . $filter[0] 323 334 . "\" function does not exist"); 324 335 325 - if (!call_user_func_array(array($this, $filter[0]), array())) 336 + if (!call_user_func_array(array($this, $filter[0]), array())) { 337 + Log::info("Filter chain halted as " . $filter[0] . " returned " 338 + . "false."); 339 + 326 340 return false; 341 + } 327 342 } 328 343 329 344 return true;
+3 -2
lib/halfmoon.php
··· 3 3 main entry point 4 4 */ 5 5 6 - if (floatval(phpversion()) < 5.3) { 6 + if (floatval(phpversion()) < 5.3) 7 7 die("PHP version of at least 5.3 is required and you are using " 8 8 . phpversion() . ")"); 9 - } 10 9 11 10 /* where our app lives (not just where halfmoon lives) */ 12 11 define("HALFMOON_ROOT", realpath(dirname(__FILE__) . "/../../")); ··· 22 21 if (!defined("HALFMOON_ENV")) 23 22 define("HALFMOON_ENV", "development"); 24 23 24 + require_once(HALFMOON_ROOT . "/halfmoon/lib/logging.php"); 25 25 require_once(HALFMOON_ROOT . "/halfmoon/lib/exceptions.php"); 26 26 require_once(HALFMOON_ROOT . "/halfmoon/lib/rescue.php"); 27 27 ··· 31 31 require_once(HALFMOON_ROOT . "/halfmoon/lib/form_helper.php"); 32 32 require_once(HALFMOON_ROOT . "/halfmoon/lib/helpers.php"); 33 33 require_once(HALFMOON_ROOT . "/halfmoon/lib/controller.php"); 34 + require_once(HALFMOON_ROOT . "/halfmoon/lib/request.php"); 34 35 require_once(HALFMOON_ROOT . "/halfmoon/lib/router.php"); 35 36 36 37 /* load site-specific boot settings */
+32
lib/logging.php
··· 1 + <?php 2 + /* 3 + logging utilities 4 + */ 5 + 6 + namespace HalfMoon; 7 + 8 + class Log { 9 + static function error($string) { 10 + error_log($string); 11 + } 12 + 13 + static function info($string) { 14 + error_log($string); 15 + } 16 + 17 + static function warn($string) { 18 + error_log($string); 19 + } 20 + 21 + /* print_r() to the error log */ 22 + static function error_log_r($param) { 23 + ob_start(); 24 + print_r($param); 25 + $lines = explode("\n", ob_get_clean()); 26 + 27 + foreach ($lines as $line) 28 + error_log($line); 29 + } 30 + } 31 + 32 + ?>
+241
lib/request.php
··· 1 + <?php 2 + /* 3 + an individual HTTP request 4 + */ 5 + 6 + namespace HalfMoon; 7 + 8 + class Request { 9 + const TRUSTED_PROXIES = '/^127\.0\.0\.1$|^(10|172\.(1[6-9]|2[0-9]|30|31)|192\.168)\./i'; 10 + 11 + private $start_time; 12 + 13 + public $url; 14 + public $scheme; 15 + public $host; 16 + public $port; 17 + public $path; 18 + public $query; 19 + 20 + public $get = array(); 21 + public $post = array(); 22 + public $params = array(); 23 + 24 + public $headers = array(); 25 + 26 + public function __construct($url, $get_vars, $post_vars, $headers) { 27 + $this->start_time = microtime(true); 28 + 29 + $url_parts = parse_url($url); 30 + 31 + $this->url = $url; 32 + $this->scheme = $url_parts["scheme"]; 33 + $this->host = $url_parts["host"]; 34 + $this->port = $url_parts["port"]; 35 + $this->path = $url_parts["path"]; 36 + $this->query = $url_parts["query"]; 37 + 38 + /* strip leading and trailing slashes, then again in case some were 39 + * hiding */ 40 + $this->path = trim(preg_replace("/^\/*/", "", preg_replace("/\/$/", "", 41 + trim($this->path)))); 42 + 43 + /* store get and post vars in $params first according to php's 44 + variables_order setting (EGPCS by default) */ 45 + foreach (str_split(ini_get("variables_order")) as $vtype) { 46 + $varray = null; 47 + 48 + switch (strtoupper($vtype)) { 49 + case "P": 50 + $varray = $post_vars; 51 + break; 52 + case "G": 53 + $varray = $get_vars; 54 + break; 55 + } 56 + 57 + if ($varray) 58 + foreach ($varray as $k => $v) 59 + $this->params[$k] = $v; 60 + } 61 + 62 + $this->get = $get_vars; 63 + $this->post = $post_vars; 64 + 65 + $this->headers = $headers; 66 + } 67 + 68 + /* pass ourself to the router and handle the url. if it fails, try to 69 + * handle it gracefully. */ 70 + public function process() { 71 + try { 72 + Router::instance()->routeRequest($this); 73 + 74 + $total_time = (float)(microtime(time) - $this->start_time); 75 + $db_time = (float)\ActiveRecord\ConnectionManager:: 76 + get_connection()->reset_database_time(); 77 + 78 + Log::info("Completed in " . sprintf("%0.5f", $total_time) 79 + . " | DB: " . sprintf("%0.5f", $db_time) 80 + . " (" . intval(($db_time / $total_time) * 100) . "%)" 81 + . " [" . $this->url . "]"); 82 + } 83 + 84 + catch (\Exception $e) { 85 + $this->rescue($e); 86 + } 87 + } 88 + 89 + /* determine originating IP address. REMOTE_ADDR is the standard but will 90 + * fail if the user is behind a proxy. HTTP_CLIENT_IP and/or 91 + * HTTP_X_FORWARDED_FOR are set by proxies so check for these if 92 + * REMOTE_ADDR is a proxy. HTTP_X_FORWARDED_FOR may be a comma- delimited 93 + * list in the case of multiple chained proxies; the last address which is 94 + * not trusted is the originating IP. */ 95 + private $_remote_ip; 96 + public function remote_ip() { 97 + if ($this->_remote_ip) 98 + return $this->_remote_ip; 99 + 100 + $remote_addr_list = array(); 101 + if ($this->headers["REMOTE_ADDR"]) 102 + $remote_addr_list = explode(",", $this->headers["REMOTE_ADDR"]); 103 + 104 + foreach ($remote_addr_list as $addr) 105 + if (!preg_match(Request::TRUSTED_PROXIES, $addr)) 106 + return ($this->_remote_ip = $addr); 107 + 108 + $forwarded_for = array(); 109 + 110 + if ($this->headers["HTTP_X_FORWARDED_FOR"]) 111 + $forwarded_for = explode(",", 112 + $this->headers["HTTP_X_FORWARDED_FOR"]); 113 + 114 + if ($this->headers["HTTP_CLIENT_IP"]) { 115 + if (!in_array($this->headers["HTTP_CLIENT_IP"], $forwarded_for)) 116 + throw new HalfMoonException("IP spoofing attack? " 117 + . "HTTP_CLIENT_IP=" 118 + . var_export($this->headers["HTTP_CLIENT_IP"], true) 119 + . ", HTTP_X_FORWARDED_FOR=" 120 + . var_export($this->headers["HTTP_X_FORWARDED_FOR"], true)); 121 + 122 + return ($this->_remote_ip = $this->headers["HTTP_CLIENT_IP"]); 123 + } 124 + 125 + if (count($forwarded_for)) { 126 + while (count($forwarded_for) > 1 && 127 + preg_match(Request::TRUSTED_PROXIES, trim(end($forwarded_for)))) 128 + array_pop($forwarded_for); 129 + 130 + return ($this->_remote_ip = trim(end($forwarded_for))); 131 + } 132 + 133 + return ($this->_remote_ip = $this->headers["REMOTE_ADDR"]); 134 + } 135 + 136 + /* "GET", "PUT", etc. */ 137 + public function request_method() { 138 + return strtoupper($this->headers["REQUEST_METHOD"]); 139 + } 140 + 141 + /* exception handler, log it and pass it off to rescue_in_public */ 142 + private function rescue($exception) { 143 + /* kill all buffered output */ 144 + while (ob_end_clean()) 145 + ; 146 + 147 + $str = get_class($exception); 148 + if ($exception->getMessage()) 149 + $str .= ": " . $exception->getMessage(); 150 + 151 + Log::error($str . ":"); 152 + 153 + foreach ($exception->getTrace() as $call) 154 + Log::error(" " . ($call["file"] ? $call["file"] 155 + : $call["class"]) . ":" . $call["line"] . " in " 156 + . $call["function"] . "()"); 157 + 158 + return $this->rescue_in_public($exception, $str); 159 + } 160 + 161 + /* return a friendly error page to the user (or a full one with debugging 162 + * if we're in development mode with display_errors turned on) */ 163 + private function rescue_in_public($exception, $title) { 164 + if (HALFMOON_ENV == "development" && ini_get("display_errors")) 165 + require_once(dirname(__FILE__) . "/rescue.phtml"); 166 + else { 167 + /* production mode, try to handle gracefully */ 168 + 169 + if ($exception instanceof HalfMoon\RoutingException) { 170 + header($_SERVER["SERVER_PROTOCOL"] . " 404 File Not Found"); 171 + 172 + if (file_exists($f = HALFMOON_ROOT . "/public/404.html")) { 173 + HalfMoon\Log::error("Rendering " . $f); 174 + require_once($f); 175 + } else { 176 + /* failsafe */ 177 + ?> 178 + <html> 179 + <head>File Not Found</head> 180 + <body> 181 + <h1>File Not Found</h1> 182 + The file you requested could not be found. An additional error 183 + occured while processing the error document. 184 + </body> 185 + </html> 186 + <? 187 + } 188 + } 189 + 190 + elseif ($exception instanceof HalfMoon\InvalidAuthenticityToken) { 191 + /* be like rails and give the odd 422 status */ 192 + header($_SERVER["SERVER_PROTOCOL"] . " 422 Unprocessable Entity"); 193 + 194 + if (file_exists($f = HALFMOON_ROOT . "/public/422.html")) { 195 + HalfMoon\Log::error("Rendering " . $f); 196 + require_once($f); 197 + } else { 198 + /* failsafe */ 199 + ?> 200 + <html> 201 + <head>Change Rejected</head> 202 + <body> 203 + <h1>Change Rejected</h1> 204 + The change you submitted was rejected due to a security 205 + problem. An additional error occured while processing the 206 + error document. 207 + </body> 208 + </html> 209 + <? 210 + } 211 + } 212 + 213 + else { 214 + header($_SERVER["SERVER_PROTOCOL"] . " 500 Server Error"); 215 + 216 + if (file_exists($f = HALFMOON_ROOT . "/public/500.html")) { 217 + HalfMoon\Log::error("Rendering " . $f); 218 + require_once($f); 219 + } else { 220 + /* failsafe */ 221 + ?> 222 + <html> 223 + <head>Application Error</head> 224 + <body> 225 + <h1>Application Error</h1> 226 + An internal application error occured while processing your 227 + request. Additionally, an error occured while processing the 228 + error document. 229 + </body> 230 + </html> 231 + <? 232 + } 233 + } 234 + } 235 + 236 + /* that's it, end of the line */ 237 + exit; 238 + } 239 + } 240 + 241 + ?>
-195
lib/rescue.php
··· 3 3 error and exception handling 4 4 */ 5 5 6 - function halfmoon_exception_handler($exception) { 7 - /* kill all buffered output */ 8 - while (ob_end_clean()) 9 - ; 10 - 11 - if (HALFMOON_ENV == "development" && ini_get("display_errors")) { 12 - $str = $exception->getMessage(); 13 - 14 - if ($str == "") 15 - $str = get_class($exception); 16 - 17 - ?> 18 - <html> 19 - <head> 20 - <title><?= h($str) ?></title> 21 - <style type="text/css"> 22 - h2, h3, h4 { 23 - margin: 0; 24 - } 25 - div.info { 26 - background-color: #eee; 27 - padding: 10px; 28 - font-family: monospace; 29 - } 30 - </style> 31 - </head> 32 - <body> 33 - <h2><?= h($str) ?></h2> 34 - <p> 35 - <tt>HALFMOON_ROOT: <?= h(HALFMOON_ROOT) ?></tt> 36 - </p> 37 - <p> 38 - <h3>Backtrace</h3> 39 - </p> 40 - <p> 41 - <div class="info"> 42 - <? 43 - 44 - $backtrace = $exception->getTrace(); 45 - 46 - foreach ($backtrace as $call) { 47 - if ($call["file"]) { 48 - $fileparts = explode("/", $call["file"]); 49 - 50 - for ($x = 0; $x < count($fileparts); $x++) { 51 - $fileparts[$x] = h($fileparts[$x]); 52 - 53 - if ($x == count($fileparts) - 1) 54 - $fileparts[$x] = "<strong>" . $fileparts[$x] 55 - . "</strong>"; 56 - } 57 - 58 - ?> 59 - <?= join("/", $fileparts); ?><? 60 - } else { 61 - ?><?= h($call["class"]) ?><? 62 - } 63 - 64 - ?>:<?= h($call["line"]) ?> 65 - in 66 - <strong><?= h($call["function"]) ?>()</strong> 67 - <br /> 68 - <? 69 - } 70 - 71 - ?> 72 - </div> 73 - </p> 74 - <p> 75 - <h3>Request</h3> 76 - </p> 77 - 78 - <p> 79 - <h4>GET Parameters</h4> 80 - </p> 81 - <p> 82 - <div class="info"> 83 - <? foreach ((array)$_GET as $k => $v) { ?> 84 - <strong><?= h(var_export($k, true)) ?></strong>: 85 - <?= h(var_export($v, true)) ?><br /> 86 - <? } ?> 87 - </div> 88 - </p> 89 - 90 - <p> 91 - <h4>POST Parameters</h4> 92 - </p> 93 - <p> 94 - <div class="info"> 95 - <? foreach ((array)$_POST as $k => $v) { ?> 96 - <strong><?= h(var_export($k, true)) ?></strong>: 97 - <?= h(var_export($v, true)) ?><br /> 98 - <? } ?> 99 - </div> 100 - </p> 101 - 102 - <p> 103 - <h4>Uploaded Files</h4> 104 - </p> 105 - <p> 106 - <div class="info"> 107 - <? foreach ((array)$_FILES as $k => $v) { ?> 108 - <strong><?= h(var_export($k, true)) ?></strong>: 109 - <?= h(var_export($v, true)) ?><br /> 110 - <? } ?> 111 - </div> 112 - </p> 113 - 114 - <p> 115 - <h3>Session</h3> 116 - </p> 117 - <p> 118 - <div class="info"> 119 - <? foreach ((array)$_SESSION as $k => $v) { ?> 120 - <?= h(var_export($k, true) . ": " . var_export($v, true)) ?><br /> 121 - <? } ?> 122 - </div> 123 - </p> 124 - </body> 125 - </html> 126 - <? 127 - } else { 128 - /* production mode, try to handle gracefully */ 129 - 130 - if ($exception instanceof HalfMoon\RoutingException) { 131 - header($_SERVER["SERVER_PROTOCOL"] . " 404 File Not Found"); 132 - 133 - if (file_exists(HALFMOON_ROOT . "/public/404.html")) 134 - require_once(HALFMOON_ROOT . "/public/404.html"); 135 - else { 136 - /* failsafe */ 137 - ?> 138 - <html> 139 - <head>File Not Found</head> 140 - <body> 141 - <h1>File Not Found</h1> 142 - The file you requested could not be found. An additional error 143 - occured while processing the error document. 144 - </body> 145 - </html> 146 - <? 147 - } 148 - } 149 - 150 - elseif ($exception instanceof HalfMoon\InvalidAuthenticityToken) { 151 - /* be like rails and give the odd 422 status */ 152 - header($_SERVER["SERVER_PROTOCOL"] . " 422 Unprocessable Entity"); 153 - 154 - if (file_exists(HALFMOON_ROOT . "/public/422.html")) 155 - require_once(HALFMOON_ROOT . "/public/422.html"); 156 - else { 157 - /* failsafe */ 158 - ?> 159 - <html> 160 - <head>Change Rejected</head> 161 - <body> 162 - <h1>Change Rejected</h1> 163 - The change you submitted was rejected due to a security 164 - problem. An additional error occured while processing the 165 - error document. 166 - </body> 167 - </html> 168 - <? 169 - } 170 - 171 - } else { 172 - header($_SERVER["SERVER_PROTOCOL"] . " 500 Server Error"); 173 - 174 - if (file_exists(HALFMOON_ROOT . "/public/500.html")) 175 - require_once(HALFMOON_ROOT . "/public/500.html"); 176 - else { 177 - /* failsafe */ 178 - ?> 179 - <html> 180 - <head>Application Error</head> 181 - <body> 182 - <h1>Application Error</h1> 183 - An internal application error occured while processing your 184 - request. Additionally, an error occured while processing the 185 - error document. 186 - </body> 187 - </html> 188 - <? 189 - } 190 - } 191 - 192 - error_log($str); 193 - 194 - exit; 195 - } 196 - } 197 - 198 6 function throw_exception_from_error($errno, $errstr, $errfile, $errline) { 199 7 $do_report = (bool)($errno & ini_get("error_reporting")); 200 8 ··· 208 16 /* make traditional errors throw exceptions so we can handle everything in one 209 17 * place */ 210 18 set_error_handler("throw_exception_from_error"); 211 - 212 - /* and handle our exceptions with a pretty html page */ 213 - set_exception_handler("halfmoon_exception_handler"); 214 19 215 20 ?>
+100
lib/rescue.phtml
··· 1 + <?php 2 + /* 3 + html file rendered in exception handler when in the development environment 4 + */ 5 + ?> 6 + <html> 7 + <head> 8 + <title><?= h($title) ?></title> 9 + <style type="text/css"> 10 + h2, h3, h4 { 11 + margin: 0; 12 + } 13 + div.info { 14 + background-color: #eee; 15 + padding: 10px; 16 + font-family: monospace; 17 + } 18 + </style> 19 + </head> 20 + <body> 21 + <h2><?= h($title) ?></h2> 22 + <p> 23 + <tt>HALFMOON_ROOT: <?= h(HALFMOON_ROOT) ?></tt> 24 + </p> 25 + <p> 26 + <h3>Backtrace</h3> 27 + </p> 28 + <p> 29 + <div class="info"> 30 + <? 31 + 32 + foreach ($exception->getTrace() as $call) { 33 + if ($call["file"]) { 34 + $fileparts = explode("/", $call["file"]); 35 + 36 + for ($x = 0; $x < count($fileparts); $x++) { 37 + $fileparts[$x] = h($fileparts[$x]); 38 + 39 + if ($x == count($fileparts) - 1) 40 + $fileparts[$x] = "<strong>" . $fileparts[$x] . "</strong>"; 41 + } 42 + 43 + ?> 44 + <?= join("/", $fileparts); ?><? 45 + } else { 46 + ?><?= h($call["class"]) ?><? 47 + } 48 + 49 + ?>:<?= h($call["line"]) ?> 50 + in 51 + <strong><?= h($call["function"]) ?>()</strong> 52 + <br /> 53 + <? 54 + } 55 + 56 + ?> 57 + </div> 58 + </p> 59 + <p> 60 + <h3>Request</h3> 61 + </p> 62 + 63 + <? foreach (array("get", "post") as $a) { ?> 64 + <p> 65 + <h4><?= strtoupper($a) ?> Parameters</h4> 66 + </p> 67 + <p> 68 + <div class="info"> 69 + <? foreach ((array)$this->$a as $k => $v) { ?> 70 + <strong><?= h(var_export($k, true)) ?></strong>: 71 + <?= h(var_export($v, true)) ?><br /> 72 + <? } ?> 73 + </div> 74 + </p> 75 + <? } ?> 76 + 77 + <p> 78 + <h4>Uploaded Files</h4> 79 + </p> 80 + <p> 81 + <div class="info"> 82 + <? foreach ((array)$_FILES as $k => $v) { ?> 83 + <strong><?= h(var_export($k, true)) ?></strong>: 84 + <?= h(var_export($v, true)) ?><br /> 85 + <? } ?> 86 + </div> 87 + </p> 88 + 89 + <p> 90 + <h3>Session</h3> 91 + </p> 92 + <p> 93 + <div class="info"> 94 + <? foreach ((array)$_SESSION as $k => $v) { ?> 95 + <?= h(var_export($k, true) . ": " . var_export($v, true)) ?><br /> 96 + <? } ?> 97 + </div> 98 + </p> 99 + </body> 100 + </html>
+31 -49
lib/router.php
··· 26 26 public function addRootRoute($route) { 27 27 if (!is_array($route)) 28 28 throw new HalfMoonException("invalid root route of " 29 - . var_export($route)); 29 + . var_export($route, true)); 30 30 31 31 /* only one root route can match a particular condition */ 32 32 foreach ($this->rootRoutes as $rr) 33 33 if (!array_diff_assoc((array)$rr, (array)$route["conditions"])) 34 34 throw new HalfMoonException("cannot add second root route " 35 - . "with no conditions: " . var_export($route)); 35 + . "with no conditions: " . var_export($route, true)); 36 36 37 37 array_push($this->rootRoutes, $route); 38 38 } 39 39 40 - public function routeRequest($url, $params, $hostname) { 41 - /* strip leading and trailing slashes, then again in case some were 42 - * hiding */ 43 - $url = trim(preg_replace("/^\/*/", "", preg_replace("/\/$/", "", 44 - trim($url)))); 45 - 46 - $url_pieces = explode("/", $url); 47 - 48 - /* store some special variables in $params */ 49 - $params["hostname"] = $hostname; 40 + public function routeRequest($request) { 41 + $path_pieces = explode("/", $request->path); 50 42 51 43 /* find and take the first matching route, storing route components in 52 44 * $params */ 53 - if ($url == "") { 45 + if ($request->path == "") { 54 46 if (!count($this->rootRoutes)) 55 47 throw new HalfMoonException("no root route defined"); 56 48 ··· 58 50 /* verify virtual host matches if there's a condition on it */ 59 51 if ($route["conditions"]["hostname"]) 60 52 if (!Utils::strcasecmp_or_preg_match( 61 - $route["conditions"]["hostname"], $hostname)) 53 + $route["conditions"]["hostname"], $request->hostname)) 62 54 continue; 63 55 64 - return $this->takeRoute($route, $url, $params); 56 + return $this->takeRoute($route, $request); 65 57 } 66 58 } else { 67 59 foreach ($this->routes as $route) { 68 60 /* verify virtual host matches if there's a condition on it */ 69 61 if ($route["conditions"]["hostname"]) 70 62 if (!Utils::strcasecmp_or_preg_match( 71 - $route["conditions"]["hostname"], $hostname)) 63 + $route["conditions"]["hostname"], $request->hostname)) 72 64 continue; 73 65 74 66 /* trim slashes from route definition and bust it up into ··· 85 77 86 78 if ($reg_or_string && 87 79 !Utils::strcasecmp_or_preg_match($reg_or_string, 88 - $url_pieces[$x])) 80 + $path_pieces[$x])) 89 81 $match = false; 90 82 else 91 83 /* store this named parameter (e.g. "/:blah" route 92 - * on a url of "/hi" defines $route["blah"] to be 84 + * on a path of "/hi" defines $route["blah"] to be 93 85 * "hi") */ 94 - $route[$m[1]] = $url_pieces[$x]; 86 + $route[$m[1]] = $path_pieces[$x]; 95 87 } 96 88 97 89 /* look for a glob condition */ 98 90 elseif (preg_match("/^\*(.+)$/", $route_pieces[$x], $m)) { 99 - /* concatenate the rest of the url as this one param */ 91 + /* concatenate the rest of the path as this one param */ 100 92 $u = ""; 101 - for ($j = $x; $j < count($url_pieces); $j++) 102 - $u .= ($u == "" ? "" : "/") . $url_pieces[$j]; 93 + for ($j = $x; $j < count($path_pieces); $j++) 94 + $u .= ($u == "" ? "" : "/") . $path_pieces[$j]; 103 95 104 96 $route[$m[1]] = $u; 105 97 ··· 107 99 } 108 100 109 101 /* else it must match exactly (case-insensitively) */ 110 - elseif (strcasecmp($route_pieces[$x], $url_pieces[$x]) != 0) 102 + elseif (strcasecmp($route_pieces[$x], $path_pieces[$x]) 103 + != 0) 111 104 $match = false; 112 105 113 106 if (!$match) ··· 124 117 * doesn't exist, that way at least the backtrace will show 125 118 * what controller we resolved it to */ 126 119 127 - return $this->takeRoute($route, $url, $params); 120 + return $this->takeRoute($route, $request); 128 121 } 129 122 } 130 123 } 131 124 132 125 /* still here, no routes matched */ 133 - throw new RoutingException("no route for url \"" . $url . "\""); 126 + throw new RoutingException("no route for url \"" . $request->path . "\""); 134 127 } 135 128 136 - public function takeRoute($route, $url, $params) { 129 + public function takeRoute($route, $request) { 137 130 /* we need at least a controller */ 138 131 if ($route["controller"] == "") 139 132 throw new HalfMoonException("no controller specified"); ··· 142 135 if ($route["action"] == "") 143 136 $route["action"] = "index"; 144 137 145 - /* store get and post vars in $params first according to php's 146 - * variables_order setting (EGPCS by default) */ 147 - foreach (str_split(ini_get("variables_order")) as $vtype) { 148 - $varray = null; 149 - 150 - switch (strtoupper($vtype)) { 151 - case "P": 152 - $varray = $_POST; 153 - break; 154 - case "G": 155 - $varray = $_GET; 156 - break; 157 - } 158 - 159 - if ($varray) 160 - foreach ($varray as $k => $v) 161 - $params[$k] = $v; 162 - } 163 - 164 - /* then store the parameters named in the route with data from the url, 138 + /* store the parameters named in the route with data from the url, 165 139 * overriding anything passed by the user as get/post */ 166 140 foreach ($route as $k => $v) 167 - $params[$k] = $v; 141 + $request->params[$k] = $v; 168 142 169 143 $c = ucfirst($route["controller"]) . "Controller"; 170 - $controller = new $c; 171 - $controller->params = $params; 144 + 145 + /* log some basic information */ 146 + Log::info("Processing " . $c . "::" . $route["action"] . " (for " 147 + . $request->remote_ip() . " at " . date("c") . ") [" 148 + . $request->request_method() . "]"); 149 + Log::info(" Parameters: " . json_encode($params)); 150 + 151 + $controller = new $c($request); 172 152 $controller->render_action($route["action"], array()); 173 153 } 174 154 } 155 + 156 + ?>
+1
lib/singleton.php
··· 75 75 return get_class($backtrace[2]['object']); 76 76 } 77 77 } 78 + 78 79 ?>
-10
lib/utilities.php
··· 35 35 return get_class(Utils::current_controller()); 36 36 } 37 37 38 - /* print_r() to the error log */ 39 - static function error_log_r($param) { 40 - ob_start(); 41 - print_r($param); 42 - $lines = explode("\n", ob_get_clean()); 43 - 44 - foreach ($lines as $line) 45 - error_log($line); 46 - } 47 - 48 38 /* return an array of public methods for a given class */ 49 39 static function get_public_class_methods($class) { 50 40 $methods = array();
+1 -1
skel/config/boot.php
··· 15 15 * queries to apache's error log */ 16 16 class LogLogLog { 17 17 public function log($sql) { 18 - error_log($sql); 18 + error_log(" " . $sql); 19 19 } 20 20 } 21 21