Base::run PHP Method

run() public method

Match routes against incoming URI
public run ( ) : mixed
return mixed
    function run()
    {
        if ($this->blacklisted($this->hive['IP'])) {
            // Spammer detected
            $this->error(403);
        }
        if (!$this->hive['ROUTES']) {
            // No routes defined
            user_error(self::E_Routes, E_USER_ERROR);
        }
        // Match specific routes first
        $paths = [];
        foreach ($keys = array_keys($this->hive['ROUTES']) as $key) {
            $path = preg_replace('/@\\w+/', '*@', $key);
            if (substr($path, -1) != '*') {
                $path .= '+';
            }
            $paths[] = $path;
        }
        $vals = array_values($this->hive['ROUTES']);
        array_multisort($paths, SORT_DESC, $keys, $vals);
        $this->hive['ROUTES'] = array_combine($keys, $vals);
        // Convert to BASE-relative URL
        $req = $this->rel(urldecode($this->hive['PATH']));
        if ($cors = isset($this->hive['HEADERS']['Origin']) && $this->hive['CORS']['origin']) {
            $cors = $this->hive['CORS'];
            header('Access-Control-Allow-Origin: ' . $cors['origin']);
            header('Access-Control-Allow-Credentials: ' . ($cors['credentials'] ? 'true' : 'false'));
        }
        $allowed = [];
        foreach ($this->hive['ROUTES'] as $pattern => $routes) {
            if (!($args = $this->mask($pattern, $req))) {
                continue;
            }
            ksort($args);
            $route = NULL;
            $ptr = $this->hive['CLI'] ? self::REQ_CLI : $this->hive['AJAX'] + 1;
            if (isset($routes[$ptr][$this->hive['VERB']]) || isset($routes[$ptr = 0])) {
                $route = $routes[$ptr];
            }
            if (!$route) {
                continue;
            }
            if ($this->hive['VERB'] != 'OPTIONS' && isset($route[$this->hive['VERB']])) {
                if ($this->hive['VERB'] == 'GET' && preg_match('/.+\\/$/', $this->hive['PATH'])) {
                    $this->reroute(substr($this->hive['PATH'], 0, -1) . ($this->hive['QUERY'] ? '?' . $this->hive['QUERY'] : ''));
                }
                list($handler, $ttl, $kbps, $alias) = $route[$this->hive['VERB']];
                // Capture values of route pattern tokens
                $this->hive['PARAMS'] = $args;
                // Save matching route
                $this->hive['ALIAS'] = $alias;
                $this->hive['PATTERN'] = $pattern;
                if ($cors && $cors['expose']) {
                    header('Access-Control-Expose-Headers: ' . (is_array($cors['expose']) ? implode(',', $cors['expose']) : $cors['expose']));
                }
                if (is_string($handler)) {
                    // Replace route pattern tokens in handler if any
                    $handler = preg_replace_callback('/({)?@(\\w+\\b)(?(1)})/', function ($id) use($args) {
                        $pid = count($id) > 2 ? 2 : 1;
                        return isset($args[$id[$pid]]) ? $args[$id[$pid]] : $id[0];
                    }, $handler);
                    if (preg_match('/(.+)\\h*(?:->|::)/', $handler, $match) && !class_exists($match[1])) {
                        $this->error(404);
                    }
                }
                // Process request
                $result = NULL;
                $body = '';
                $now = microtime(TRUE);
                if (preg_match('/GET|HEAD/', $this->hive['VERB']) && $ttl) {
                    // Only GET and HEAD requests are cacheable
                    $headers = $this->hive['HEADERS'];
                    $cache = Cache::instance();
                    $cached = $cache->exists($hash = $this->hash($this->hive['VERB'] . ' ' . $this->hive['URI']) . '.url', $data);
                    if ($cached) {
                        if (isset($headers['If-Modified-Since']) && strtotime($headers['If-Modified-Since']) + $ttl > $now) {
                            $this->status(304);
                            die;
                        }
                        // Retrieve from cache backend
                        list($headers, $body, $result) = $data;
                        if (!$this->hive['CLI']) {
                            array_walk($headers, 'header');
                        }
                        $this->expire($cached[0] + $ttl - $now);
                    } else {
                        // Expire HTTP client-cached page
                        $this->expire($ttl);
                    }
                } else {
                    $this->expire(0);
                }
                if (!strlen($body)) {
                    if (!$this->hive['RAW'] && !$this->hive['BODY']) {
                        $this->hive['BODY'] = file_get_contents('php://input');
                    }
                    ob_start();
                    // Call route handler
                    $result = $this->call($handler, [$this, $args], 'beforeroute,afterroute');
                    $body = ob_get_clean();
                    if (isset($cache) && !error_get_last()) {
                        // Save to cache backend
                        $cache->set($hash, [preg_grep('/Set-Cookie\\:/', headers_list(), PREG_GREP_INVERT), $body, $result], $ttl);
                    }
                }
                $this->hive['RESPONSE'] = $body;
                if (!$this->hive['QUIET']) {
                    if ($kbps) {
                        $ctr = 0;
                        foreach (str_split($body, 1024) as $part) {
                            // Throttle output
                            $ctr++;
                            if ($ctr / $kbps > ($elapsed = microtime(TRUE) - $now) && !connection_aborted()) {
                                usleep(1000000.0 * ($ctr / $kbps - $elapsed));
                            }
                            echo $part;
                        }
                    } else {
                        echo $body;
                    }
                }
                return $result;
            }
            $allowed = array_merge($allowed, array_keys($route));
        }
        if (!$allowed) {
            // URL doesn't match any route
            $this->error(404);
        } elseif (!$this->hive['CLI']) {
            // Unhandled HTTP method
            header('Allow: ' . implode(',', array_unique($allowed)));
            if ($cors) {
                header('Access-Control-Allow-Methods: OPTIONS,' . implode(',', $allowed));
                if ($cors['headers']) {
                    header('Access-Control-Allow-Headers: ' . (is_array($cors['headers']) ? implode(',', $cors['headers']) : $cors['headers']));
                }
                if ($cors['ttl'] > 0) {
                    header('Access-Control-Max-Age: ' . $cors['ttl']);
                }
            }
            if ($this->hive['VERB'] != 'OPTIONS') {
                $this->error(405);
            }
        }
        return FALSE;
    }

Usage Example

Example #1
0
 /**
  * @test
  */
 public function testAssertNotZeroExitSuppressed()
 {
     // Command should yield an error
     $command = "exit 1";
     $this->_obj->expects($this->any())->method('getCommand')->will($this->returnValue($command));
     $this->_obj->setSuppressErrors(true);
     $this->_obj->run();
     $this->markTestIncomplete("Don't know how to check for the absence of a certain output regex");
 }
All Usage Examples Of Base::run