CrossPHP
  • Namespace
  • Class
  • Download

Namespaces

  • Cross
    • Auth
    • Cache
      • Driver
      • Request
    • Core
    • DB
      • Connecter
      • Drivers
      • SQLAssembler
    • Exception
    • Http
    • I
    • Lib
      • Document
    • Module
    • MVC
    • Runtime
  • None

Classes

  • Cross\Auth\CookieAuth
  • Cross\Auth\SessionAuth
  • Cross\Cache\Driver\FileCacheDriver
  • Cross\Cache\Driver\MemcacheDriver
  • Cross\Cache\Driver\RedisDriver
  • Cross\Cache\Request\FileCache
  • Cross\Cache\Request\Memcache
  • Cross\Cache\Request\RedisCache
  • Cross\Cache\RequestCache
  • Cross\Core\Annotate
  • Cross\Core\Application
  • Cross\Core\ArrayMap
  • Cross\Core\Config
  • Cross\Core\CrossArray
  • Cross\Core\Delegate
  • Cross\Core\FrameBase
  • Cross\Core\Helper
  • Cross\Core\HttpAuth
  • Cross\Core\Loader
  • Cross\Core\Rest
  • Cross\Core\Router
  • Cross\DB\Connecter\BaseConnecter
  • Cross\DB\Connecter\MySQLConnecter
  • Cross\DB\Connecter\PgSQLConnecter
  • Cross\DB\Connecter\SQLiteConnecter
  • Cross\DB\DBFactory
  • Cross\DB\Drivers\CouchDriver
  • Cross\DB\Drivers\MongoDriver
  • Cross\DB\Drivers\PDOSqlDriver
  • Cross\DB\SQLAssembler\MySQLAssembler
  • Cross\DB\SQLAssembler\PgSQLAssembler
  • Cross\DB\SQLAssembler\SQLAssembler
  • Cross\DB\SQLAssembler\SQLiteAssembler
  • Cross\Http\Request
  • Cross\Http\Response
  • Cross\Lib\Array2XML
  • Cross\Lib\Document\CallTree
  • Cross\Lib\Document\CallTreeToHTML
  • Cross\Lib\Document\HTML
  • Cross\Lib\StringToPHPStream
  • Cross\Module\SQLModule
  • Cross\MVC\Controller
  • Cross\MVC\Module
  • Cross\MVC\View
  • Cross\Runtime\ClosureContainer

Interfaces

  • Cross\I\CacheInterface
  • Cross\I\HttpAuthInterface
  • Cross\I\PDOConnecter
  • Cross\I\RequestCacheInterface
  • Cross\I\RouterInterface
  • Cross\I\SqlInterface

Exceptions

  • Cross\Exception\CacheException
  • Cross\Exception\CoreException
  • Cross\Exception\CrossException
  • Cross\Exception\FrontException

Functions

  • ascLogo
  • line
  • tBody
  • th
  • tHead
  1 <?php
  2 /**
  3  * Cross - a micro PHP 5 framework
  4  *
  5  * @link        http://www.crossphp.com
  6  * @license     MIT License
  7  */
  8 
  9 namespace Cross\Core;
 10 
 11 use Cross\Exception\CoreException;
 12 use Cross\Http\Request;
 13 use ReflectionFunction;
 14 use Closure;
 15 
 16 /**
 17  * @author wonli <wonli@live.com>
 18  * Class Rest
 19  * @package Cross\Core
 20  */
 21 class Rest
 22 {
 23     /**
 24      * @var array
 25      */
 26     protected $rules;
 27 
 28     /**
 29      * @var Request
 30      */
 31     protected $request;
 32 
 33     /**
 34      * @var Delegate
 35      */
 36     protected $delegate;
 37 
 38     /**
 39      * @var string
 40      */
 41     protected $request_type;
 42 
 43     /**
 44      * @var string
 45      */
 46     protected $request_string;
 47 
 48     /**
 49      * @var array
 50      */
 51     protected $custom_router_config = array();
 52 
 53     /**
 54      * @var Rest
 55      */
 56     private static $instance;
 57 
 58     /**
 59      * 初始化request
 60      *
 61      * @param Delegate $delegate
 62      * @throws CoreException
 63      */
 64     private function __construct(Delegate &$delegate)
 65     {
 66         $this->delegate = $delegate;
 67         $this->request = $delegate->getRequest();
 68         $this->request_type = strtoupper($this->request->getRequestType());
 69         $this->request_string = $delegate->getRouter()->getUriRequest('/', $useless, false, false);
 70     }
 71 
 72     /**
 73      * 创建rest实例
 74      *
 75      * @param Delegate $delegate
 76      * @return Rest
 77      * @throws CoreException
 78      */
 79     static function getInstance(Delegate &$delegate)
 80     {
 81         if (!self::$instance) {
 82             self::$instance = new Rest($delegate);
 83         }
 84 
 85         return self::$instance;
 86     }
 87 
 88     /**
 89      * GET
 90      *
 91      * @param string $custom_router
 92      * @param callable|Closure $process_closure
 93      */
 94     function get($custom_router, Closure $process_closure)
 95     {
 96         $this->addCustomRouter('GET', $custom_router, $process_closure);
 97     }
 98 
 99     /**
100      * POST
101      *
102      * @param string $custom_router
103      * @param callable|Closure $process_closure
104      */
105     function post($custom_router, Closure $process_closure)
106     {
107         $this->addCustomRouter('POST', $custom_router, $process_closure);
108     }
109 
110     /**
111      * PUT
112      *
113      * @param string $custom_router
114      * @param callable|Closure $process_closure
115      */
116     function put($custom_router, Closure $process_closure)
117     {
118         $this->addCustomRouter('PUT', $custom_router, $process_closure);
119     }
120 
121     /**
122      * PATCH
123      *
124      * @param string $custom_router
125      * @param Closure $process_closure
126      */
127     function patch($custom_router, Closure $process_closure)
128     {
129         $this->addCustomRouter('PATCH', $custom_router, $process_closure);
130     }
131 
132     /**
133      * OPTIONS
134      *
135      * @param string $custom_router
136      * @param Closure $process_closure
137      */
138     function options($custom_router, Closure $process_closure)
139     {
140         $this->addCustomRouter('OPTIONS', $custom_router, $process_closure);
141     }
142 
143     /**
144      * DELETE
145      *
146      * @param string $custom_router
147      * @param callable|Closure $process_closure
148      */
149     function delete($custom_router, Closure $process_closure)
150     {
151         $this->addCustomRouter('DELETE', $custom_router, $process_closure);
152     }
153 
154     /**
155      * HEAD
156      *
157      * @param string $custom_router
158      * @param Closure $process_closure
159      */
160     function head($custom_router, Closure $process_closure)
161     {
162         $this->addCustomRouter('HEAD', $custom_router, $process_closure);
163     }
164 
165     /**
166      * Any
167      *
168      * @param string $custom_router
169      * @param callable|Closure $process_closure
170      */
171     function any($custom_router, Closure $process_closure)
172     {
173         $this->addCustomRouter($this->request_type, $custom_router, $process_closure);
174     }
175 
176     /**
177      * @see Delegate::on()
178      *
179      * @param string $name
180      * @param Closure $f
181      */
182     function on($name, Closure $f)
183     {
184         $this->delegate->on($name, $f);
185     }
186 
187     /**
188      * 参数正则验证规则
189      *
190      * @param array $rules
191      */
192     function rules(array $rules)
193     {
194         $this->rules = $rules;
195     }
196 
197     /**
198      * 处理请求
199      *
200      * @throws CoreException
201      */
202     function run()
203     {
204         $match = false;
205         $params = array();
206         $process_closure = null;
207         if (!empty($this->custom_router_config[$this->request_type])) {
208             $custom_routers = $this->custom_router_config[$this->request_type];
209             if (!empty($custom_routers['high']) && isset($custom_routers['high'][$this->request_string])) {
210                 $match = true;
211                 $process_closure = $custom_routers['high'][$this->request_string];
212             } elseif (!empty($custom_routers['current'])) {
213                 $match = $this->matchProcess($custom_routers['current'], $process_closure, $params);
214             } elseif (!empty($custom_routers['global'])) {
215                 $match = $this->matchProcess($custom_routers['global'], $process_closure, $params);
216             }
217         }
218 
219         if ($match && $process_closure !== null) {
220             $this->response($process_closure, $params);
221         } else {
222             $closure_container = $this->delegate->getClosureContainer();
223             if ($closure_container->has('mismatching')) {
224                 $closure_container->run('mismatching');
225             } else {
226                 throw new CoreException('Not match uri');
227             }
228         }
229     }
230 
231     /**
232      * 循环匹配(参数多的优先)
233      *
234      * @param array $routers
235      * @param $process_closure
236      * @param array $params
237      * @return bool
238      */
239     private function matchProcess(array $routers, & $process_closure, & $params)
240     {
241         uasort($routers, function ($a, $b) {
242             return $a['params_count'] < $b['params_count'];
243         });
244 
245         foreach ($routers as $router => $router_config) {
246             $params = array();
247             if (true === $this->matchCustomRouter($router, $router_config['params_key'], $params)) {
248                 $process_closure = $router_config['process_closure'];
249                 return true;
250             }
251         }
252 
253         return false;
254     }
255 
256     /**
257      * 匹配uri和自定义路由
258      *
259      * @param string $custom_router
260      * @param array $params_keys
261      * @param array $params
262      * @return bool
263      */
264     private function matchCustomRouter($custom_router, array $params_keys = array(), array & $params = array())
265     {
266         $request_uri_string = $this->request_string;
267         $custom_router_params_token = preg_replace("/\{:(.*?)\}/", '{PARAMS}', $custom_router);
268         while (strlen($custom_router_params_token) > 0) {
269             $defined_params_pos = strpos($custom_router_params_token, '{PARAMS}');
270             if ($defined_params_pos) {
271                 $compare_ret = substr_compare($custom_router_params_token, $request_uri_string, 0, $defined_params_pos);
272             } else {
273                 $compare_ret = strcmp($custom_router_params_token, $request_uri_string);
274             }
275 
276             if ($compare_ret !== 0) {
277                 return false;
278             }
279 
280             //分段解析
281             $custom_router_params_token = substr($custom_router_params_token, $defined_params_pos + 8);
282             $request_uri_string = substr($request_uri_string, $defined_params_pos);
283 
284             if ($custom_router_params_token) {
285                 //下一个标识符的位置
286                 $next_defined_dot_pos = strpos($request_uri_string, $custom_router_params_token[0]);
287                 $params_value = substr($request_uri_string, 0, $next_defined_dot_pos);
288                 $request_uri_string = substr($request_uri_string, $next_defined_dot_pos);
289             } else {
290                 $params_value = $request_uri_string;
291             }
292 
293             $key_name = array_shift($params_keys);
294             if ($key_name && isset($this->rules[$key_name]) && !preg_match($this->rules[$key_name], $params_value)) {
295                 return false;
296             }
297 
298             if ($key_name) {
299                 $params[$key_name] = $params_value;
300             }
301         }
302 
303         return true;
304     }
305 
306     /**
307      * 输出结果
308      *
309      * @param Closure $process_closure
310      * @param array $params
311      * @throws CoreException
312      */
313     private function response(Closure $process_closure, array $params = array())
314     {
315         try {
316             $ref = new ReflectionFunction($process_closure);
317             $closure_params = array();
318             $parameters = $ref->getParameters();
319             if (!empty($parameters)) {
320                 foreach ($parameters as $p) {
321                     if (!isset($params[$p->name])) {
322                         throw new CoreException("未指定的参数: {$p->name}");
323                     }
324 
325                     $closure_params[$p->name] = $params[$p->name];
326                 }
327             }
328 
329             $content = call_user_func_array($process_closure, $closure_params);
330             if (null != $content) {
331                 $this->delegate->getResponse()->display($content);
332             }
333         } catch (\Exception $e) {
334             throw new CoreException('Reflection ' . $e->getMessage());
335         }
336     }
337 
338     /**
339      * 解析自定义路由并保存参数key
340      *
341      * @param string $request_type
342      * @param string $custom_router
343      * @param Closure $process_closure
344      */
345     private function addCustomRouter($request_type, $custom_router, Closure $process_closure)
346     {
347         if ($this->request_type === $request_type) {
348             $custom_router = trim($custom_router);
349             $is_contain_params = preg_match_all("/(.*?)\{:(.*?)\}/", $custom_router, $params_keys);
350             if ($is_contain_params) {
351                 $prefix_string_length = strlen($params_keys[1][0]);
352                 $compare = substr_compare($this->request_string, $custom_router, 0, $prefix_string_length);
353                 if ($compare === 0) {
354                     $level = 'current';
355                     if ($prefix_string_length == 1) {
356                         $level = 'global';
357                     }
358 
359                     $this->custom_router_config[$request_type][$level][$custom_router] = array(
360                         'process_closure' => $process_closure,
361                         'params_count' => count($params_keys[2]),
362                         'params_key' => $params_keys[2],
363                     );
364                 }
365             } else {
366                 $this->custom_router_config[$request_type]['high'][$custom_router] = $process_closure;
367             }
368         }
369     }
370 }
371 
CrossPHP API documentation generated by ApiGen