RouterHostnameRule.class.php

Go to the documentation of this file.
00001 <?php
00002 /***************************************************************************
00003  *   Copyright (C) 2008 by Sergey S. Sergeev                               *
00004  *                                                                         *
00005  *   This program is free software; you can redistribute it and/or modify  *
00006  *   it under the terms of the GNU Lesser General Public License as        *
00007  *   published by the Free Software Foundation; either version 3 of the    *
00008  *   License, or (at your option) any later version.                       *
00009  *                                                                         *
00010  ***************************************************************************/
00011 
00012     final class RouterHostnameRule extends RouterBaseRule
00013     {
00014         const SCHEME_HTTP           = 'http';
00015         const SCHEME_HTTPS          = 'https';
00016         
00017         protected $hostVariable     = ':';
00018         protected $regexDelimiter   = '#';
00019         
00020         protected $scheme           = null;
00021         protected $defaultRegex     = null;
00022         protected $route            = null;
00023         protected $routeProcessed   = false;
00024         protected $variables        = array();
00025         protected $parts            = array();
00026         protected $requirements     = array();
00027         protected $values           = array();
00028         
00029         protected $staticCount      = 0;
00030         
00034         public static function create($route)
00035         {
00036             return new self($route);
00037         }
00038         
00039         public function __construct($route)
00040         {
00041             $this->route = trim($route, '.');
00042             $this->scheme = self::SCHEME_HTTP;
00043         }
00044         
00048         public function setRequirements(array $reqirements)
00049         {
00050             $this->requirements = $reqirements;
00051             
00052             return $this;
00053         }
00054         
00055         public function getRequirements()
00056         {
00057             return $this->requirements;
00058         }
00059         
00063         public function setSecure()
00064         {
00065             $this->scheme = self::SCHEME_HTTPS;
00066             
00067             return $this;
00068         }
00069         
00070         public function isSecure()
00071         {
00072             return $this->scheme == self::SCHEME_HTTPS;
00073         }
00074         
00078         public function setScheme($schema)
00079         {
00080             $this->scheme = $schema;
00081             
00082             return $this;
00083         }
00084         
00085         public function getScheme()
00086         {
00087             return $this->scheme;
00088         }
00089         
00090         public function match(HttpRequest $request)
00091         {
00092             $this->processRoute();
00093             
00094             if (
00095                 $this->isSecureRequest($request)
00096                 && !$this->isSecure()
00097             )
00098                 return array();
00099             
00100             if ($request->hasServerVar('HTTP_HOST'))
00101                 $host = $request->getServerVar('HTTP_HOST');
00102             else
00103                 throw new RouterException('Can not find host');
00104             
00105             $result = array();
00106             
00107             if (preg_match('#:\d+$#', $host, $result) === 1)
00108                 $host = substr($host, 0, -strlen($result[0]));
00109             
00110             $hostStaticCount = 0;
00111             $values = array();
00112             
00113             $host = trim($host, '.');
00114             
00115             // FIXME: strpos('.', ...), probably?
00116             if ($host) {
00117                 $host = explode('.', $host);
00118                 
00119                 foreach ($host as $pos => $hostPart) {
00120                     if (!array_key_exists($pos, $this->parts)) {
00121                         return array();
00122                     }
00123                     
00124                     $name =
00125                         isset($this->variables[$pos])
00126                             ? $this->variables[$pos]
00127                             : null;
00128                     
00129                     $hostPart = urldecode($hostPart);
00130                     
00131                     if (
00132                         ($name === null)
00133                         && ($this->parts[$pos] != $hostPart)
00134                     ) {
00135                         return array();
00136                     }
00137                     
00138                     if (
00139                         ($this->parts[$pos] !== null)
00140                         && !preg_match(
00141                             $this->regexDelimiter
00142                             .'^'.$this->parts[$pos].'$'
00143                             .$this->regexDelimiter.'iu',
00144                             
00145                             $hostPart
00146                         )
00147                     ) {
00148                         return array();
00149                     }
00150                     
00151                     if ($name !== null) {
00152                         $values[$name] = $hostPart;
00153                     } else {
00154                         ++$hostStaticCount;
00155                     }
00156                 }
00157             }
00158             
00159             if ($this->staticCount != $hostStaticCount)
00160                 return array();
00161             
00162             $return = $values + $this->defaults;
00163             
00164             foreach ($this->variables as $var) {
00165                 if (!array_key_exists($var, $return))
00166                     return array();
00167             }
00168             
00169             $this->values = $values;
00170             
00171             return $return;
00172         }
00173         
00174         public function assembly(
00175             array $data = array(),
00176             $reset = false,
00177             $encode = false
00178         )
00179         {
00180             $this->processRoute();
00181             
00182             $host = array();
00183             $flag = false;
00184             
00185             foreach ($this->parts as $key => $part) {
00186                 $name =
00187                     isset($this->variables[$key])
00188                         ? $this->variables[$key]
00189                         : null;
00190                 
00191                 $useDefault = false;
00192                 
00193                 if (
00194                     isset($name)
00195                     && array_key_exists($name, $data)
00196                     && ($data[$name] === null)
00197                 ) {
00198                     $useDefault = true;
00199                 }
00200                 
00201                 if ($name) {
00202                     if (isset($data[$name]) && !$useDefault) {
00203                         $host[$key] = $data[$name];
00204                         unset($data[$name]);
00205                     } elseif (
00206                         !$reset
00207                         && !$useDefault
00208                         && isset($this->values[$name])
00209                     ) {
00210                         $host[$key] = $this->values[$name];
00211                     } elseif (isset($this->defaults[$name])) {
00212                         $host[$key] = $this->defaults[$name];
00213                     } else {
00214                         // FIXME: bogus message
00215                         throw new RouterException($name . ' is not specified');
00216                     }
00217                 } else {
00218                     $host[$key] = $part;
00219                 }
00220             }
00221             
00222             $return = null;
00223             
00224             foreach (array_reverse($host, true) as $key => $value) {
00225                 if (
00226                     $flag
00227                     || !isset($this->variables[$key])
00228                     || ($value !== $this->getDefault($this->variables[$key]))
00229                 ) {
00230                     if ($encode)
00231                         $value = urlencode($value);
00232                     
00233                     $return = '.'.$value.$return;
00234                     $flag = true;
00235                 }
00236             }
00237             
00238             // FIXME: rtrim, probably?
00239             $host = trim($return, '.');
00240             
00241             return $this->resolveSchema() . '://' . $host . $this->resolvePath();
00242             
00243         }
00244         
00248         protected function processRoute()
00249         {
00250             if ($this->routeProcessed)
00251                 return $this;
00252             
00253             // FIXME: if (strpos('.', ...), probably?
00254             if ($this->route) {
00255                 foreach (explode('.', $this->route) as $pos => $part) {
00256                     if (substr($part, 0, 1) == $this->hostVariable) {
00257                         $name = substr($part, 1);
00258                         
00259                         $this->parts[$pos] = (
00260                             isset($this->requirements[$name])
00261                                 ? $this->requirements[$name]
00262                                 : $this->defaultRegex
00263                             );
00264                         
00265                         $this->variables[$pos] = $name;
00266                     } else {
00267                         $this->parts[$pos] = $part;
00268                         ++$this->staticCount;
00269                     }
00270                 }
00271             }
00272             
00273             $this->routeProcessed = true;
00274             
00275             return $this;
00276         }
00277         
00278         protected function isSecureRequest(HttpRequest $request)
00279         {
00280             return (
00281                 $request->hasServerVar('HTTPS')
00282                 && $request->getServerVar('HTTPS') == 'on'
00283             ) || (
00284                 $request->hasServerVar('SERVER_PORT')
00285                 && (int) $request->getServerVar('SERVER_PORT') === 443
00286             );
00287         }
00288         
00289         protected function resolveSchema()
00290         {
00291             $base = RouterRewrite::me()->getBaseUrl();
00292             
00293             if ($this->scheme) {
00294                 return $this->scheme;
00295             } elseif (
00296                 ($base instanceof HttpUrl)
00297                 && $base->getScheme()
00298             ) {
00299                 return $base->getScheme();
00300             } else {
00301                 throw new RouterException('Cannot resolve scheme');
00302             }
00303         }
00304         
00305         protected function resolvePath()
00306         {
00307             if (
00308                 ($base = RouterRewrite::me()->getBaseUrl())
00309                 && ($this->scheme == $base->getScheme())
00310             ) {
00311                 return rtrim($base->getPath(), '/');
00312             } else {
00313                 return '';
00314             }
00315         }
00316     }
00317 ?>