Example #1
0
 /**
  *   Render template
  *   @return string
  *   @param $file string
  *   @param $mime string
  *   @param $hive array
  *   @param $ttl int
  **/
 function render($file, $mime = 'text/html', array $hive = NULL, $ttl = 0)
 {
     $fw = Base::instance();
     $cache = Cache::instance();
     if (!is_dir($tmp = $fw->get('TEMP'))) {
         mkdir($tmp, Base::MODE, TRUE);
     }
     foreach ($fw->split($fw->get('UI')) as $dir) {
         $cached = $cache->exists($hash = $fw->hash($dir . $file), $data);
         if ($cached && $cached[0] + $ttl > microtime(TRUE)) {
             return $data;
         }
         if (is_file($view = $fw->fixslashes($dir . $file))) {
             if (!is_file($this->view = $tmp . $fw->hash($fw->get('ROOT') . $fw->get('BASE')) . '.' . $fw->hash($view) . '.php') || filemtime($this->view) < filemtime($view)) {
                 // Remove PHP code and comments
                 $text = preg_replace('/(?<!["\'])\\h*<\\?(?:php|\\s*=).+?\\?>\\h*' . '(?!["\'])|\\{\\*.+?\\*\\}/is', '', $fw->read($view));
                 $text = $this->parse($text);
                 $fw->write($this->view, $this->build($text));
             }
             if (isset($_COOKIE[session_name()])) {
                 @session_start();
             }
             $fw->sync('SESSION');
             if ($mime && PHP_SAPI != 'cli' && !headers_sent()) {
                 header('Content-Type: ' . ($this->mime = $mime) . '; ' . 'charset=' . $fw->get('ENCODING'));
             }
             $data = $this->sandbox($hive);
             if (isset($this->trigger['afterrender'])) {
                 foreach ($this->trigger['afterrender'] as $func) {
                     $data = $fw->call($func, $data);
                 }
             }
             if ($ttl) {
                 $cache->set($hash, $data);
             }
             return $data;
         }
     }
     user_error(sprintf(Base::E_Open, $file), E_USER_ERROR);
 }
Example #2
0
 /**
  *	Instantiate class
  *	@param $onsuspect callback
  **/
 function __construct($onsuspect = NULL)
 {
     session_set_save_handler(array($this, 'open'), array($this, 'close'), array($this, 'read'), array($this, 'write'), array($this, 'destroy'), array($this, 'cleanup'));
     register_shutdown_function('session_commit');
     @session_start();
     $fw = Base::instance();
     $headers = $fw->get('HEADERS');
     if (($ip = $this->ip()) && $ip != $fw->get('IP') || ($agent = $this->agent()) && (!isset($headers['User-Agent']) || $agent != $headers['User-Agent'])) {
         if (isset($onsuspect)) {
             $fw->call($onsuspect, array($this));
         } else {
             session_destroy();
             $fw->error(403);
         }
     }
     $csrf = $fw->hash($fw->get('ROOT') . $fw->get('BASE')) . '.' . $fw->hash(mt_rand());
     $jar = $fw->get('JAR');
     if (Cache::instance()->exists(($this->sid = session_id()) . '.@', $data)) {
         $data['csrf'] = $csrf;
         Cache::instance()->set($this->sid . '.@', $data, $jar['expire'] ? $jar['expire'] - time() : 0);
     }
 }
Example #3
0
 /**
  *	Strip Javascript/CSS files of extraneous whitespaces and comments;
  *	Return combined output as a minified string
  *	@return string
  *	@param $files string|array
  *	@param $mime string
  *	@param $header bool
  *	@param $path string
  **/
 function minify($files, $mime = NULL, $header = TRUE, $path = NULL)
 {
     $fw = Base::instance();
     if (is_string($files)) {
         $files = $fw->split($files);
     }
     if (!$mime) {
         $mime = $this->mime($files[0]);
     }
     preg_match('/\\w+$/', $files[0], $ext);
     $cache = Cache::instance();
     $dst = '';
     if (!isset($path)) {
         $path = $fw->get('UI') . ';./';
     }
     foreach ($fw->split($path, FALSE) as $dir) {
         foreach ($files as $file) {
             if (is_file($save = $fw->fixslashes($dir . $file))) {
                 if ($fw->get('CACHE') && ($cached = $cache->exists($hash = $fw->hash($save) . '.' . $ext[0], $data)) && $cached[0] > filemtime($save)) {
                     $dst .= $data;
                 } else {
                     $data = '';
                     $src = $fw->read($save);
                     for ($ptr = 0, $len = strlen($src); $ptr < $len;) {
                         if (preg_match('/^@import\\h+url' . '\\(\\h*([\'"])(.+?)\\1\\h*\\)[^;]*;/', substr($src, $ptr), $parts)) {
                             $path = dirname($file);
                             $data .= $this->minify(($path ? $path . '/' : '') . $parts[2], $mime, $header);
                             $ptr += strlen($parts[0]);
                             continue;
                         }
                         if ($src[$ptr] == '/') {
                             if ($src[$ptr + 1] == '*') {
                                 // Multiline comment
                                 $str = strstr(substr($src, $ptr + 2), '*/', TRUE);
                                 $ptr += strlen($str) + 4;
                             } elseif ($src[$ptr + 1] == '/') {
                                 // Single-line comment
                                 $str = strstr(substr($src, $ptr + 2), "\n", TRUE);
                                 $ptr += strlen($str) + 2;
                             } else {
                                 // Presume it's a regex pattern
                                 $regex = TRUE;
                                 // Backtrack and validate
                                 for ($ofs = $ptr; $ofs; $ofs--) {
                                     // Pattern should be preceded by
                                     // open parenthesis, colon,
                                     // object property or operator
                                     if (preg_match('/(return|[(:=!+\\-*&|])$/', substr($src, 0, $ofs))) {
                                         $data .= '/';
                                         $ptr++;
                                         while ($ptr < $len) {
                                             $data .= $src[$ptr];
                                             $ptr++;
                                             if ($src[$ptr - 1] == '\\') {
                                                 $data .= $src[$ptr];
                                                 $ptr++;
                                             } elseif ($src[$ptr - 1] == '/') {
                                                 break;
                                             }
                                         }
                                         break;
                                     } elseif (!ctype_space($src[$ofs - 1])) {
                                         // Not a regex pattern
                                         $regex = FALSE;
                                         break;
                                     }
                                 }
                                 if (!$regex) {
                                     // Division operator
                                     $data .= $src[$ptr];
                                     $ptr++;
                                 }
                             }
                             continue;
                         }
                         if (in_array($src[$ptr], array('\'', '"'))) {
                             $match = $src[$ptr];
                             $data .= $match;
                             $ptr++;
                             // String literal
                             while ($ptr < $len) {
                                 $data .= $src[$ptr];
                                 $ptr++;
                                 if ($src[$ptr - 1] == '\\') {
                                     $data .= $src[$ptr];
                                     $ptr++;
                                 } elseif ($src[$ptr - 1] == $match) {
                                     break;
                                 }
                             }
                             continue;
                         }
                         if (ctype_space($src[$ptr])) {
                             if ($ptr + 1 < strlen($src) && preg_match('/[\\w' . ($ext[0] == 'css' ? '#\\.%+\\-*()\\[\\]' : '\\$') . ']{2}|' . '[+\\-]{2}/', substr($data, -1) . $src[$ptr + 1])) {
                                 $data .= ' ';
                             }
                             $ptr++;
                             continue;
                         }
                         $data .= $src[$ptr];
                         $ptr++;
                     }
                     if ($fw->get('CACHE')) {
                         $cache->set($hash, $data);
                     }
                     $dst .= $data;
                 }
             }
         }
     }
     if (PHP_SAPI != 'cli' && $header) {
         header('Content-Type: ' . $mime . '; charset=' . $fw->get('ENCODING'));
     }
     return $dst;
 }
Example #4
0
 /**
  *	Match routes against incoming URI
  *	@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 = array();
     foreach ($keys = array_keys($this->hive['ROUTES']) as $key) {
         $paths[] = str_replace('@', '*@', $key);
     }
     $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($this->hive['URI']);
     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 = array();
     foreach ($this->hive['ROUTES'] as $pattern => $routes) {
         if (!($args = $this->mask($pattern, $req))) {
             continue;
         }
         ksort($args);
         $route = NULL;
         if (isset($routes[$ptr = $this->hive['AJAX'] + 1][$this->hive['VERB']])) {
             $route = $routes[$ptr];
         } elseif (isset($routes[self::REQ_SYNC | self::REQ_AJAX])) {
             $route = $routes[self::REQ_SYNC | self::REQ_AJAX];
         }
         if (!$route) {
             continue;
         }
         if ($this->hive['VERB'] != 'OPTIONS' && isset($route[$this->hive['VERB']])) {
             $parts = parse_url($req);
             if ($this->hive['VERB'] == 'GET' && preg_match('/.+\\/$/', $parts['path'])) {
                 $this->reroute(substr($parts['path'], 0, -1) . (isset($parts['query']) ? '?' . $parts['query'] : ''));
             }
             list($handler, $ttl, $kbps, $alias) = $route[$this->hive['VERB']];
             if (is_bool(strpos($pattern, '/*'))) {
                 foreach (array_keys($args) as $key) {
                     if (is_numeric($key) && $key) {
                         unset($args[$key]);
                     }
                 }
             }
             // Capture values of route pattern tokens
             $this->hive['PARAMS'] = $args = array_map('urldecode', $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)/', function ($id) use($args) {
                     return isset($args[$id[1]]) ? $args[$id[1]] : $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 && $cached[0] + $ttl > $now) {
                     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 (PHP_SAPI != '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, array($this, $args), 'beforeroute,afterroute');
                 $body = ob_get_clean();
                 // Template Parsing
                 if ($this->hive['TEMPLATE']) {
                     $this->hive['RESPONSE'] = $body;
                     $body = $this->send($this->hive['TEMPLATE'], true);
                 }
                 if (isset($cache) && !error_get_last()) {
                     // Save to cache backend
                     $cache->set($hash, array(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 (PHP_SAPI != '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;
 }