Posted by Dan Sosedoff
on October 02, 2009
Some time ago i wrote a simple regex patterns to determine whether my client crawler bot, mobile client or just regular one. Easy to expand and to use.
function is_mobile($agent) {
$pattern = '/(blackberry|motorokr|motorola|sony|windows ce|240x320|176x220|palm|mobile|iphone|ipod|symbian|nokia|samsung|midp)/i';
return (bool)preg_match($pattern, $agent);
}
function is_crawler($agent) {
pattern = '/(google|yahoo|baidu|bot|webalta|ia_archiver)/';
return (bool)preg_match($pattern, $agent);
}
Posted by Dan Sosedoff
on September 20, 2009
My previous version of php url router was not good enough, so i`ve done some core modification to the class. Its more flexible now. The whole idea is very similar to Rails` and Merb`s url router (merb is a rails-fork). In fact, previous version doesn`t even support GET variables in the request uri. New version just merges variables from request string into the same parameters array where other variables are stored. Also there is a command “default_routes” that maps default routes like this “/:controller/:action/:id”. So, basically you have two options – use defaults & custom routes or use only custom, which means that all other requests will be ignored. Function default_routes must be declared last.
Here is the sources:
define('ROUTER_DEFAULT_CONTROLLER', 'home');
define('ROUTER_DEFAULT_ACTION', 'index');
class Router {
public $request_uri;
public $routes;
public $controller, $controller_name;
public $action, $id;
public $params;
public $route_found = false;
public function __construct() {
$request = $_SERVER['REQUEST_URI'];
$pos = strpos($request, '?');
if ($pos) $request = substr($request, 0, $pos);
$this->request_uri = $request;
$this->routes = array();
}
public function map($rule, $target=array(), $conditions=array()) {
$this->routes[$rule] = new Route($rule, $this->request_uri, $target, $conditions);
}
public function default_routes() {
$this->map('/:controller');
$this->map('/:controller/:action');
$this->map('/:controller/:action/:id');
}
private function set_route($route) {
$this->route_found = true;
$params = $route->params;
$this->controller = $params['controller']; unset($params['controller']);
$this->action = $params['action']; unset($params['action']);
$this->id = $params['id'];
$this->params = array_merge($params, $_GET);
if (empty($this->controller)) $this->controller = ROUTER_DEFAULT_CONTROLLER;
if (empty($this->action)) $this->action = ROUTER_DEFAULT_ACTION;
if (empty($this->id)) $this->id = null;
$w = explode('_', $this->controller);
foreach($w as $k => $v) $w[$k] = ucfirst($v);
$this->controller_name = implode('', $w);
}
public function execute() {
foreach($this->routes as $route) {
if ($route->is_matched) {
$this->set_route($route);
break;
}
}
}
}
class Route {
public $is_matched = false;
public $params;
public $url;
private $conditions;
function __construct($url, $request_uri, $target, $conditions) {
$this->url = $url;
$this->params = array();
$this->conditions = $conditions;
$p_names = array(); $p_values = array();
preg_match_all('@:([\w]+)@', $url, $p_names, PREG_PATTERN_ORDER);
$p_names = $p_names[0];
$url_regex = preg_replace_callback('@:[\w]+@', array($this, 'regex_url'), $url);
$url_regex .= '/?';
if (preg_match('@^' . $url_regex . '$@', $request_uri, $p_values)) {
array_shift($p_values);
foreach($p_names as $index => $value) $this->params[substr($value,1)] = urldecode($p_values[$index]);
foreach($target as $key => $value) $this->params[$key] = $value;
$this->is_matched = true;
}
unset($p_names); unset($p_values);
}
function regex_url($matches) {
$key = str_replace(':', '', $matches[0]);
if (array_key_exists($key, $this->conditions)) {
return '('.$this->conditions[$key].')';
}
else {
return '([a-zA-Z0-9_\+\-%]+)';
}
}
}
Setup example:
$r = new Router(); // create router instance
$r->map('/', array('controller' => 'home')); // main page will call controller "Home" with method "index()"
$r->map('/login', array('controller' => 'auth', 'action' => 'login'));
$r->map('/logout', array('controller' => 'auth', 'action' => 'logout'));
$r->map('/signup', array('controller' => 'auth', 'action' => 'signup'));
$r->map('/profile/:action', array('controller' => 'profile')); // will call controller "Profile" with dynamic method ":action()"
$r->map('/users/:id', array('controller' => 'users'), array('id' => '[\d]{1,8}')); // define filters for the url parameters
$r->default_routes();
$r->execute();
Usage example:
$router = new Router();
// ... some configs ...
$controller = $router->controller; // will return name as it appears in url, ex: 'user_images'
$controller = $router->controller_name; // will return processed name of controller
// for example, if class name in url is 'user_images', then 'controller_name' var will be UserImages
$router->action;
$router->id; // if parameter :id presents
$router->params; // array(...)
$router->route_matched; // true - if route found, false - if not
Small and useful class.
Posted by Dan Sosedoff
on July 04, 2009
!!! CONSIDER THIS AS AN UPDATE:Rails-like PHP Url Router
Here is simple url parser, that produces output parameters lile: controller, action, parameters. Also, it support simple virtual key rules, “rails” style.
For example, url like “http://foo.bar/book/view/12″ will produce parameters: controller = book, action = view, id = 12.
Here is php code:
<?
/* ------------------------------------------------------------- */
/* URL Router class */
/* ------------------------------------------------------------- */
class Router {
static protected $instance;
static protected $controller;
static protected $action;
static protected $params;
static protected $rules;
public static function getInstance() {
if (isset(self::$instance) and (self::$instance instanceof self)) {
return self::$instance;
} else {
self::$instance = new self();
return self::$instance;
}
}
private static function arrayClean($array) {
foreach($array as $key => $value) {
if (strlen($value) == 0) unset($array[$key]);
}
}
private static function ruleMatch($rule, $data) {
$ruleItems = explode('/',$rule); self::arrayClean(&$ruleItems);
$dataItems = explode('/',$data); self::arrayClean(&$dataItems);
if (count($ruleItems) == count($dataItems)) {
$result = array();
foreach($ruleItems as $ruleKey => $ruleValue) {
if (preg_match('/^:[\w]{1,}$/',$ruleValue)) {
$ruleValue = substr($ruleValue,1);
$result[$ruleValue] = $dataItems[$ruleKey];
}
else {
if (strcmp($ruleValue,$dataItems[$ruleKey]) != 0) {
return false;
}
}
}
if (count($result) > 0) return $result;
unset($result);
}
return false;
}
private static function defaultRoutes($url) {
// process default routes
$items = explode('/',$url);
// remove empty blocks
foreach($items as $key => $value) {
if (strlen($value) == 0) unset($items[$key]);
}
// extract data
if (count($items)) {
self::$controller = array_shift($items);
self::$action = array_shift($items);
self::$params = $items;
}
}
protected function __construct() {
self::$rules = array();
}
public static function init() {
$url = $_SERVER['REQUEST_URI'];
$isCustom = false;
if (count(self::$rules)) {
foreach(self::$rules as $ruleKey => $ruleData) {
$params = self::ruleMatch($ruleKey,$url);
if ($params) {
self::$controller = $ruleData['controller'];
self::$action = $ruleData['action'];
self::$params = $params;
$isCustom = true;
break;
}
}
}
if (!$isCustom) self::defaultRoutes($url);
if (!strlen(self::$controller)) self::$controller = 'home';
if (!strlen(self::$action)) self::$action = 'index';
}
public static function addRule($rule, $target) {
self::$rules[$rule] = $target;
}
public static function getController() { return self::$controller; }
public static function getAction() { return self::$action; }
public static function getParams() { return self::$params; }
public static function getParam($id) { return self::$params[$id]; }
}
?>
Basic usage:
$router = Router::getInstance(); // init router
$router->addRule('/books/:id/:keyname',array('controller' => 'books', 'action' => 'view')); // add simple rule
// add some more rules
$router->init(); // execute router
So, as you can see, the router class can be accessible from anywhere in your code. Just because the class has beed designed as one-instance object, you cannot call for new instance. To get instance of router you need to call Router::getInstance() instead.
We have added simple rule for url`s like this ‘/books/12345/this-is-a-book-keyname’. Default routing system will identify this url incorrectly (controller => books, action => 12345). So the action 12345 not exists. That`s why we need to add custom rule. It will parse this url correctly: controller => books, action => view. And the rest of parameters will be automatically added to parameteres array. To access this array you need to call $router->getParams(); If you need to get just one parameter, call directly: $var = $router->getParam(0).
This router is really simple and can be used in small web sites that not require complete framework. Also it is fast.
Download file Router.php
View paste
Posted by Dan Sosedoff
on March 20, 2009
Here is php version of ruby class that i made a long time ago. The same functionality and results.
<?
class ImageScale {
private function changeGeometry($sz,$value) {
if ($sz['width'] > $sz['height']) { // horizontal image
$newsz['width'] = $value;
$newsz['height'] = ceil(($newsz['width'] * $sz['height']) / $sz['width']);
}
else { // vertical image
$newsz['height'] = $value;
$newsz['width'] = ceil(($newsz['height'] * $sz['width']) / $sz['height']);
}
return $newsz;
}
private function changeGeometry2($sz,$value) {
$newsz['width'] = $value;
$newsz['height'] = ceil(($newsz['width'] * $sz['height']) / $sz['width']);
return $newsz;
}
/**
* Make thumbnail of specified maximum side size
*/
public function processThumb($source_path, $dest_path, $sidesize, $quality=85, $scale_method=1) {
if (file_exists($source_path) && is_readable($source_path)) {
$image = new Imagick($source_path);
$geometry = $image->getImageGeometry(); // ['width', 'height']
if ($geometry['width'] > $sidesize) {
if ($scale_method == 1) $geometry = $this->changeGeometry($geometry,$sidesize);
if ($scale_method == 2) $geometry = $this->changeGeometry2($geometry,$sidesize);
}
$image->cropThumbnailImage($geometry['width'],$geometry['height']);
$image->setCompression(Imagick::COMPRESSION_JPEG);
$image->setCompressionQuality($quality);
return $image->writeImage($dest_path);
}
return false;
}
/**
* Make square thumbnail
*/
public function processRectThumb($source_path, $dest_path, $size=150, $quality=85) {
if (file_exists($source_path) && is_readable($source_path)) {
$image = new Imagick($source_path);
if ($image) {
$image->cropThumbnailImage($size,$size);
$image->setCompression(Imagick::COMPRESSION_JPEG);
$image->setCompressionQuality($quality);
return $image->writeImage($dest_path);
}
}
return false;
}
}
?>
Download file – http://files.sosedoff.com/1167c8db/