/** Retrieve from cache; or save query results to cache if not previously executed @param $query array @param $ttl int @private **/ private function cache(array $query, $ttl) { $cmd = json_encode($query, TRUE); $hash = 'mdb.' . self::hash($cmd); $cached = Cache::cached($hash); $db = (string) $this->db; $stats =& self::ref('STATS'); if ($ttl && $cached && $_SERVER['REQUEST_TIME'] - $cached < $ttl) { // Gather cached queries for profiler if (!isset($stats[$db]['cache'][$cmd])) { $stats[$db]['cache'][$cmd] = 0; } $stats[$db]['cache'][$cmd]++; // Retrieve from cache return Cache::get($hash); } else { $result = $this->exec($query); if ($ttl) { Cache::set($hash, $result, $ttl); } // Gather real queries for profiler if (!isset($stats[$db]['queries'][$cmd])) { $stats[$db]['queries'][$cmd] = 0; } $stats[$db]['queries'][$cmd]++; return $result; } }
private function compile($file) { $filestr = ''; require_once 'Cache.php'; $temp_cache = new Cache(array('cache_name' => md5($file), 'cache_path' => $this->temp_cache, 'cache_extension' => $this->extension * 60)); if ($temp_cache->cached("html")) { $filestr = $temp_cache->get("html"); } else { $keys = array('{if %%}' => '<?php if (\\1): ?>', '{elseif %%}' => '<?php ; elseif (\\1): ?>', '{for %%}' => '<?php for (\\1): ?>', '{foreach %%}' => '<?php foreach (\\1): ?>', '{while %%}' => '<?php while (\\1): ?>', '{/if}' => '<?php endif; ?>', '{/for}' => '<?php endfor; ?>', '{/foreach}' => '<?php endforeach; ?>', '{/while}' => '<?php endwhile; ?>', '{else}' => '<?php ; else: ?>', '{continue}' => '<?php continue; ?>', '{break}' => '<?php break; ?>', '{$%% = %%}' => '<?php $\\1 = \\2; ?>', '{$%%++}' => '<?php $\\1++; ?>', '{$%%--}' => '<?php $\\1--; ?>', '{$%%}' => '<?php echo $\\1; ?>', '{comment}' => '<?php /*', '{/comment}' => '*/ ?>', '{/*}' => '<?php /*', '{*/}' => '*/ ?>'); foreach ($keys as $key => $val) { $patterns[] = '#' . str_replace('%%', '(.+)', preg_quote($key, '#')) . '#U'; $replace[] = $val; } $filestr = preg_replace($patterns, $replace, file_get_contents($file)); $temp_cache->set("html", $filestr); } return $filestr; }
/** Retrieve from cache; or save SQL query results to cache if not previously executed @param $_cmd string @param $_bind mixed @param $_id string @param $_ttl integer @private **/ private static function sqlCache($_cmd, $_bind = NULL, $_id = 'DB', $_ttl = 0) { $_hash = 'sql.' . F3::hashCode($_cmd); $_db =& F3::$global[$_id]; $_cached = Cache::cached($_hash); if ($_cached && time() - $_cached['time'] < $_ttl) { // Gather cached SQL queries for profiler F3::$global['PROFILE'][$_id]['cache'][$_cmd]++; // Retrieve from cache $_db = Cache::fetch($_hash); } else { self::sqlExec($_cmd, NULL, $_id); if (!F3::$global['ERROR']) { // Save to cache unset($_db['pdo'], $_db['query']); Cache::store($_hash, $_db); } } }
/** Retrieve from cache; or save SQL query results to cache if not previously executed @param $_cmd string @param $_bind mixed @param $_id string @param $_ttl integer @private **/ private static function sqlCache($_cmd, $_bind = NULL, $_id = 'DB', $_ttl = 0) { $_hash = 'sql.' . F3::hashCode($_cmd); $_db =& F3::$global[$_id]; $_cached = Cache::cached($_hash); if ($_cached && time() - $_cached['time'] < $_ttl) { // Gather cached SQL queries for profiler F3::$global['PROFILE'][$_id]['cache'][$_cmd]++; // Retrieve from cache, unserialize, and restore DB variable $_db = unserialize(gzinflate(Cache::fetch($_hash))); } else { self::sqlExec($_cmd, NULL, $_id); if (!F3::$global['ERROR']) { // Serialize, compress and cache unset($_db['pdo'], $_db['query']); Cache::store($_hash, gzdeflate(serialize($_db))); } } }
/** Store PHP expression in flat-file @param $file string @param $expr mixed @public **/ function write($file, $expr) { if (!$expr) { $expr = array(); } if ($this->format == self::FORMAT_Plain) { $out = '<?php' . "\n\n" . 'return ' . self::stringify($expr) . ';' . "\n"; } elseif ($this->format == self::FORMAT_Serialized) { $out = serialize($expr); } else { $out = json_encode($expr); } // Create semaphore $hash = 'sem.' . self::hash($file); $cached = Cache::cached($hash); while ($cached) { // Locked by another process usleep(mt_rand(0, 100)); } Cache::set($hash, TRUE); file_put_contents($this->path . $file, $out, LOCK_EX); // Remove semaphore Cache::clear($hash); }
/** Render template @return string @param $file string @param $mime string @param $globals boolean @public **/ static function serve($file, $mime = 'text/html', $globals = TRUE) { $file = self::resolve($file); $found = FALSE; foreach (preg_split('/[\\|;,]/', self::$vars['GUI'], 0, PREG_SPLIT_NO_EMPTY) as $gui) { if (is_file($view = self::fixslashes($gui . $file))) { $found = TRUE; break; } } if (!$found) { trigger_error(sprintf(self::TEXT_Render, $file)); return ''; } if (PHP_SAPI != 'cli' && !headers_sent()) { // Send HTTP header with appropriate character set header(self::HTTP_Content . ': ' . $mime . '; ' . 'charset=' . self::$vars['ENCODING']); } $hash = 'tpl.' . self::hash($view); $cached = Cache::cached($hash); if ($cached && filemtime($view) < $cached) { if (self::$vars['CACHE']) { // Retrieve PHP-compiled template from cache $text = Cache::get($hash); } } else { // Parse raw template $doc = new F3markup($mime, $globals); $text = $doc->load(self::getfile($view)); if (self::$vars['CACHE'] && $doc->cache) { // Save PHP-compiled template to cache Cache::set($hash, $text); } } // Render in a sandbox $instance = new F3instance(); ob_start(); if (ini_get('allow_url_fopen') && ini_get('allow_url_include')) { // Stream wrap $instance->sandbox('data:text/plain,' . urlencode($text)); } else { // Save PHP-equivalent file in temporary folder if (!is_dir(self::$vars['TEMP'])) { self::mkdir(self::$vars['TEMP']); } $temp = self::$vars['TEMP'] . $_SERVER['SERVER_NAME'] . '.' . $hash; if (!$cached || !is_file($temp) || filemtime($temp) < Cache::cached($view)) { // Create semaphore $hash = 'sem.' . self::hash($view); $cached = Cache::cached($hash); while ($cached) { // Locked by another process usleep(mt_rand(0, 100)); } Cache::set($hash, TRUE); self::putfile($temp, $text); // Remove semaphore Cache::clear($hash); } $instance->sandbox($temp); } $out = ob_get_clean(); unset($instance); return self::$vars['TIDY'] ? self::tidy($out) : $out; }
/** Parse each URL recursively and generate sitemap @param $_url string @public **/ public static function sitemap($_url = '/') { $_map =& F3::$global['SITEMAP']; if (array_key_exists($_url, $_map) && $_map[$_url]['status'] !== NULL) { // Already crawled return; } preg_match('/^http[s]*:\\/\\/([^\\/$]+)/', $_url, $_host); if (!empty($_host) && $_host[1] != $_SERVER['SERVER_NAME']) { // Remote URL $_map[$_url]['status'] = FALSE; return; } F3::$global['QUIET'] = TRUE; F3::mock('GET ' . $_url); F3::run(); // Check if an error occurred or no HTTP response if (F3::$global['ERROR'] || !F3::$global['RESPONSE']) { $_map[$_url]['status'] = FALSE; // Reset error flag for next page unset(F3::$global['ERROR']); return; } $_doc = new XMLTree('1.0', F3::$global['ENCODING']); if ($_doc->loadHTML(F3::$global['RESPONSE'])) { // Valid HTML; add to sitemap if (!$_map[$_url]['level']) { // Web root $_map[$_url]['level'] = 0; } $_map[$_url]['status'] = TRUE; $_map[$_url]['mod'] = time(); $_map[$_url]['freq'] = 0; // Cached page $_hash = 'url.' . F3::hashCode('GET ' . $_url); $_cached = Cache::cached($_hash); if ($_cached) { $_map[$_url]['mod'] = $_cached['time']; $_map[$_url]['freq'] = $_SERVER['REQUEST_TTL']; } // Parse all links $_links = $_doc->getElementsByTagName('a'); foreach ($_links as $_link) { $_ref = $_link->getAttribute('href'); $_rel = $_link->getAttribute('rel'); if (!$_ref || $_rel && preg_match('/nofollow/', $_rel)) { // Don't crawl this link! continue; } if (!array_key_exists($_ref, $_map)) { $_map[$_ref] = array('level' => $_map[$_url]['level'] + 1, 'status' => NULL); } } // Parse each link array_walk(array_keys($_map), 'self::sitemap'); } unset($_doc); if (!$_map[$_url]['level']) { // Finalize sitemap $_depth = 1; while ($_ref = current($_map)) { // Find depest level while iterating if (!$_ref['status']) { // Remove remote URLs and pages with errors unset($_map[key($_map)]); } else { $_depth = max($_depth, $_ref['level'] + 1); next($_map); } } // Create XML document $_xml = simplexml_load_string('<?xml version="1.0" encoding="' . F3::$global['ENCODING'] . '"?>' . '<urlset xmlns="' . 'http://www.sitemaps.org/schemas/sitemap/0.9' . '"/>'); $_host = 'http://' . $_SERVER['SERVER_NAME']; foreach ($_map as $_key => $_ref) { // Add new URL $_item = $_xml->addChild('url'); // Add URL elements $_item->addChild('loc', $_host . $_key); $_item->addChild('lastMod', date('c', $_ref['mod'])); $_item->addChild('changefreq', self::frequency($_ref['freq'])); $_item->addChild('priority', sprintf('%1.1f', 1 - $_ref['level'] / $_depth)); } // Send output F3::$global['QUIET'] = FALSE; if (PHP_SAPI != 'cli' && !headers_sent()) { header(F3::HTTP_Content . ': application/xhtml+xml; ' . 'charset=' . F3::$global['ENCODING']); } $_xml = dom_import_simplexml($_xml)->ownerDocument; $_xml->formatOutput = TRUE; echo $_xml->saveXML(); } }
/** Parse each URL recursively and generate sitemap @param $url string @public **/ static function sitemap($url = NULL) { if (is_null($url)) { $url = self::$vars['BASE'] . '/'; } if ($url[0] == '#' || isset(self::$vars['SITEMAP'][$url]) && is_bool(self::$vars['SITEMAP'][$url]['status'])) { // Skip return; } $parse = parse_url($url); if (isset($parse['scheme']) && !preg_match('/https?:/', $parse['scheme'])) { return; } $response = self::http('GET ' . self::$vars['PROTOCOL'] . '://' . $_SERVER['SERVER_NAME'] . $url); if (!$response) { // No HTTP response self::$vars['SITEMAP'][$url]['status'] = FALSE; return; } foreach (self::$vars['HEADERS'] as $header) { if (preg_match('/HTTP\\/\\d\\.\\d\\s(\\d+)/', $header, $match) && $match[1] != 200) { self::$vars['SITEMAP'][$url]['status'] = FALSE; return; } } $doc = new DOMDocument('1.0', self::$vars['ENCODING']); // Suppress errors caused by invalid HTML structures libxml_use_internal_errors(TRUE); if ($doc->loadHTML($response)) { // Valid HTML; add to sitemap if (!self::$vars['SITEMAP'][$url]['level']) { // Web root self::$vars['SITEMAP'][$url]['level'] = 0; } self::$vars['SITEMAP'][$url]['status'] = TRUE; self::$vars['SITEMAP'][$url]['mod'] = time(); self::$vars['SITEMAP'][$url]['freq'] = 0; // Cached page $hash = 'url.' . self::hash('GET ' . $url); $cached = Cache::cached($hash); if ($cached) { self::$vars['SITEMAP'][$url]['mod'] = $cached['time']; self::$vars['SITEMAP'][$url]['freq'] = $_SERVER['REQUEST_TTL']; } // Parse all links $links = $doc->getElementsByTagName('a'); foreach ($links as $link) { $ref = $link->getAttribute('href'); preg_match('/^http[s]*:\\/\\/([^\\/$]+)/', $ref, $host); if (!empty($host) && $host[1] != $_SERVER['SERVER_NAME'] || !$ref || ($rel = $link->getAttribute('rel')) && preg_match('/nofollow/', $rel)) { // Don't crawl this link! continue; } if (!isset(self::$vars['SITEMAP'][$ref])) { self::$vars['SITEMAP'][$ref] = array('level' => self::$vars['SITEMAP'][$url]['level'] + 1, 'status' => NULL); } } // Parse each link $map = array_keys(self::$vars['SITEMAP']); array_walk($map, 'self::sitemap'); } unset($doc); if (!self::$vars['SITEMAP'][$url]['level']) { // Finalize sitemap $depth = 1; while ($ref = current(self::$vars['SITEMAP'])) { // Find deepest level while iterating if (!$ref['status']) { // Remove remote URLs and pages with errors unset(self::$vars['SITEMAP'][key(self::$vars['SITEMAP'])]); } else { $depth = max($depth, $ref['level'] + 1); next(self::$vars['SITEMAP']); } } // Create XML document $xml = simplexml_load_string('<?xml version="1.0" encoding="' . self::$vars['ENCODING'] . '"?>' . '<urlset xmlns=' . '"http://www.sitemaps.org/schemas/sitemap/0.9"' . '/>'); $host = self::$vars['PROTOCOL'] . '://' . $_SERVER['SERVER_NAME']; foreach (self::$vars['SITEMAP'] as $key => $ref) { // Add new URL $item = $xml->addChild('url'); // Add URL elements $item->addChild('loc', $host . $key); $item->addChild('lastmod', gmdate('c', $ref['mod'])); $item->addChild('changefreq', self::frequency($ref['freq'])); $item->addChild('priority', sprintf('%1.1f', 1 - $ref['level'] / $depth)); } // Send output if (PHP_SAPI != 'cli' && !headers_sent()) { header(self::HTTP_Content . ': application/xml; ' . 'charset=' . self::$vars['ENCODING']); } $xml = dom_import_simplexml($xml)->ownerDocument; $xml->formatOutput = TRUE; echo $xml->saveXML(); die; } }
/** Process routes based on incoming URI @public **/ static function run() { // Validate user against spam blacklists if (self::$vars['DNSBL'] && !self::privateip($addr = self::realip()) && (!self::$vars['EXEMPT'] || !in_array($addr, self::split(self::$vars['EXEMPT'])))) { // Convert to reverse IP dotted quad $quad = implode('.', array_reverse(explode('.', $addr))); foreach (self::split(self::$vars['DNSBL']) as $list) { // Check against DNS blacklist if (gethostbyname($quad . '.' . $list) != $quad . '.' . $list) { if (self::$vars['SPAM']) { // Spammer detected; Send to blackhole self::reroute(self::$vars['SPAM']); } else { // Forbidden self::error(403); die; } } } } // Process routes if (!isset(self::$vars['ROUTES']) || !self::$vars['ROUTES']) { trigger_error(self::TEXT_NoRoutes); return; } $found = FALSE; // Detailed routes get matched first krsort(self::$vars['ROUTES']); $time = time(); $req = preg_replace('/^' . preg_quote(self::$vars['BASE'], '/') . '\\b(.+)/', '\\1', rawurldecode($_SERVER['REQUEST_URI'])); foreach (self::$vars['ROUTES'] as $uri => $route) { if (!preg_match('/^' . preg_replace('/(?:{{)?@(\\w+\\b)(?:}})?/', '(?P<\\1>[^\\/&]+)', str_replace('\\*', '(.*)', preg_quote($uri, '/'))) . '\\/?(?:\\?.*)?$/ium', $req, $args)) { continue; } $wild = is_int(strpos($uri, '/*')); // Inspect each defined route foreach ($route as $method => $proc) { if (!preg_match('/HEAD|' . $method . '/', $_SERVER['REQUEST_METHOD'])) { continue; } $found = TRUE; list($funcs, $ttl, $throttle, $hotlink) = $proc; if (!$hotlink && isset(self::$vars['HOTLINK']) && isset($_SERVER['HTTP_REFERER']) && parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST) != $_SERVER['SERVER_NAME']) { // Hot link detected; Redirect page self::reroute(self::$vars['HOTLINK']); } if (!$wild) { // Save named uri captures foreach (array_keys($args) as $key) { // Remove non-zero indexed elements if (is_numeric($key) && $key) { unset($args[$key]); } } } self::$vars['PARAMS'] = $args; // Default: Do not cache self::expire(0); if ($_SERVER['REQUEST_METHOD'] == 'GET' && $ttl) { $_SERVER['REQUEST_TTL'] = $ttl; // Get HTTP request headers $req = self::headers(); // Content divider $div = chr(0); // Get hash code for this Web page $hash = 'url.' . self::hash($_SERVER['REQUEST_METHOD'] . ' ' . $_SERVER['REQUEST_URI']); $cached = Cache::cached($hash); $uri = '/^' . self::HTTP_Content . ':.+/'; if ($cached && $time - $cached < $ttl) { if (!isset($req[self::HTTP_IfMod]) || $cached > strtotime($req[self::HTTP_IfMod])) { // Activate cache timer self::expire($cached + $ttl - $time); // Retrieve from cache $buffer = Cache::get($hash); $type = strstr($buffer, $div, TRUE); if (PHP_SAPI != 'cli' && !headers_sent() && preg_match($uri, $type, $match)) { // Cached MIME type header($match[0]); } // Save response self::$vars['RESPONSE'] = substr(strstr($buffer, $div), 1); } else { // Client-side cache is still fresh self::status(304); die; } } else { // Activate cache timer self::expire($ttl); $type = ''; foreach (headers_list() as $hdr) { if (preg_match($uri, $hdr)) { // Add Content-Type header to buffer $type = $hdr; break; } } // Cache this page ob_start(); self::call($funcs, TRUE); self::$vars['RESPONSE'] = ob_get_clean(); if (!self::$vars['ERROR'] && self::$vars['RESPONSE']) { // Compress and save to cache Cache::set($hash, $type . $div . self::$vars['RESPONSE']); } } } else { // Capture output ob_start(); self::$vars['REQBODY'] = file_get_contents('php://input'); self::call($funcs, TRUE); self::$vars['RESPONSE'] = ob_get_clean(); } $elapsed = time() - $time; $throttle = $throttle ?: self::$vars['THROTTLE']; if ($throttle / 1000.0 > $elapsed) { // Delay output usleep(1000000.0 * ($throttle / 1000.0 - $elapsed)); } if (strlen(self::$vars['RESPONSE']) && !self::$vars['QUIET']) { // Display response echo self::$vars['RESPONSE']; } } if ($found) { // Hail the conquering hero return; } // Method not allowed if (PHP_SAPI != 'cli' && !headers_sent()) { header(self::HTTP_Allow . ': ' . implode(',', array_keys($route))); } self::error(405); return; } // No such Web page self::error(404); }
/** Process SQL statement(s) @return array @param $cmds mixed @param $args array @param $ttl int @public **/ function exec($cmds, array $args = NULL, $ttl = 0) { if (!$this->pdo) { self::instantiate(); } $stats =& self::ref('STATS'); if (!isset($stats[$this->dsn])) { $stats[$this->dsn] = array('cache' => array(), 'queries' => array()); } $batch = is_array($cmds); if ($batch) { if (!$this->trans && $this->auto) { $this->begin(TRUE); } if (is_null($args)) { $args = array(); for ($i = 0; $i < count($cmds); $i++) { $args[] = NULL; } } } else { $cmds = array($cmds); $args = array($args); } for ($i = 0, $len = count($cmds); $i < $len; $i++) { list($cmd, $arg) = array($cmds[$i], $args[$i]); $hash = 'sql.' . self::hash($cmd . var_export($arg, TRUE)); $cached = Cache::cached($hash); if ($ttl && $cached && $_SERVER['REQUEST_TIME'] - $cached < $ttl) { // Gather cached queries for profiler if (!isset($stats[$this->dsn]['cache'][$cmd])) { $stats[$this->dsn]['cache'][$cmd] = 0; } $stats[$this->dsn]['cache'][$cmd]++; $this->result = Cache::get($hash); } else { if (is_null($arg)) { $query = $this->pdo->query($cmd); } else { $query = $this->pdo->prepare($cmd); if (is_object($query)) { foreach ($arg as $key => $value) { if (!(is_array($value) ? $query->bindvalue($key, $value[0], $value[1]) : $query->bindvalue($key, $value, $this->type($value)))) { break; } } $query->execute(); } } // Check SQLSTATE foreach (array($this->pdo, $query) as $obj) { if ($obj->errorCode() != PDO::ERR_NONE) { if ($this->trans && $this->auto) { $this->rollback(); } $error = $obj->errorinfo(); trigger_error($error[2]); return FALSE; } } if (preg_match('/^\\s*(?:SELECT|PRAGMA|SHOW|EXPLAIN)\\s/i', $cmd)) { $this->result = $query->fetchall(PDO::FETCH_ASSOC); $this->rows = $query->rowcount(); } else { $this->rows = $this->result = $query->rowCount(); } if ($ttl) { Cache::set($hash, $this->result, $ttl); } // Gather real queries for profiler if (!isset($stats[$this->dsn]['queries'][$cmd])) { $stats[$this->dsn]['queries'][$cmd] = 0; } $stats[$this->dsn]['queries'][$cmd]++; } } if ($batch || $this->trans && $this->auto) { $this->commit(); } return $this->result; }
function ecache() { $this->set('title', 'Cache Engine'); $this->expect(is_null($this->get('ERROR')), 'No errors expected at this point', 'ERROR variable is set: ' . $this->get('ERROR.text')); $this->set('CACHE', TRUE); $this->expect($this->get('CACHE'), 'Cache back-end detected: \'' . $this->get('CACHE') . '\'', 'Cache disabled'); $this->set('x', 123, TRUE); $this->expect($this->cached('x'), 'Framework variable cached', 'Variable not cached: ' . var_export($this->cached('x'), TRUE)); $this->expect($this->get('x'), 'Value retrieved from cache', 'Caching issue: ' . var_export($this->get('x'), TRUE)); $this->clear('x'); $this->expect(is_bool($this->cached('x')), 'Variable removed from cache', 'Caching issue: ' . var_export($this->cached('x'), TRUE)); $this->clear('ROUTES'); $ttl = 3; $this->route('GET /caching', function () { echo 'here'; }, $ttl); $start = time(); $i = 0; while (TRUE) { $this->set('QUIET', TRUE); $this->mock('GET /caching'); sleep(1); $this->run(); $cached = Cache::cached('url.' . $this->hash('GET /caching')); if (is_bool($cached)) { break; } $this->set('QUIET', FALSE); if (!isset($saved)) { $saved = $cached; } if ($saved != $cached) { break; } $time = time(); $this->expect(TRUE, 'Cache age @' . date('G:i:s', $time) . ': ' . ($time - $cached) . ' secs'); $i++; if ($i == $ttl) { break; } } $this->expect($i == $ttl, 'Cache refreshed', 'Cache TTL has expired'); echo $this->render('basic/results.htm'); }
/** Grab file contents @return mixed @param $file string @public **/ function grab($file) { $file = F3::resolve($file); ob_start(); if (!ini_get('short_open_tag')) { $text = preg_replace_callback('/<\\?(?:\\s|\\s*(=))(.+?)\\?>/s', function ($tag) { return '<?php ' . ($tag[1] ? 'echo ' : '') . trim($tag[2]) . ' ?>'; }, $orig = file_get_contents($file)); if (ini_get('allow_url_fopen') && ini_get('allow_url_include')) { // Stream wrap $file = 'data:text/plain,' . urlencode($text); } elseif ($text != $orig) { // Save re-tagged file in temporary folder if (!is_dir($ref = F3::ref('TEMP'))) { F3::mkdir($ref); } $temp = $ref . $_SERVER['SERVER_NAME'] . '.tpl.' . F3::hash($file); if (!is_file($temp)) { // Create semaphore $hash = 'sem.' . F3::hash($file); $cached = Cache::cached($hash); while ($cached) { // Locked by another process usleep(mt_rand(0, 1000)); } Cache::set($hash, TRUE); file_put_contents($temp, $text, LOCK_EX); // Remove semaphore Cache::clear($hash); } $file = $temp; } } // Render $this->sandbox($file); return ob_get_clean(); }
/** Intercept calls to static methods of non-F3 classes and proxy for the called class if found in the autoload folder @return mixed @param $_func string @param $_args array @public **/ public static function __callStatic($_func, array $_args) { foreach (explode('|', self::$global['AUTOLOAD']) as $_auto) { foreach (glob(realpath($_auto) . '/*.php') as $_file) { $_class = strstr(basename($_file), '.php', TRUE); $_hash = 'reg.' . self::hashCode(strtolower($_class)); $_cached = Cache::cached($_hash); $_methods = array(); if (!$_cached || $_cached['time'] < filemtime($_file)) { if (!in_array(self::fixSlashes($_file), array_map('self::fixSlashes', get_included_files()))) { include $_file; } if (class_exists($_class, FALSE)) { // Update cache $_methods = array_map('strtolower', get_class_methods($_class)); Cache::store($_hash, $_methods); } } else { // Retrieve from cache $_methods = Cache::fetch($_hash); } if (in_array(strtolower($_func), $_methods)) { // Execute onLoad method if defined if (in_array('onload', $_methods)) { call_user_func(array($_class, 'onload')); self::$global['LOADED'][] = strtolower($_class); } // Proxy for method in autoload class return call_user_func_array(array($_class, $_func), $_args); } } } self::$global['CONTEXT'] = __CLASS__ . '::' . $_func; trigger_error(self::TEXT_Method); return FALSE; }
/** Send HTTP/S request to another host; Forward headers received (if QUIET variable is FALSE) and return content; Respect HTTP 30x redirects if last argument is TRUE @return mixed @param $_pattern string @param $_query string @param $_reqhdrs array @param $_follow boolean @public **/ public static function http($_pattern, $_query = '', $_reqhdrs = array(), $_follow = TRUE) { // Check if valid route pattern list($_method, $_route) = F3::checkRoute($_pattern); // Content divider $_div = chr(0); // Determine if page is in cache $_hash = 'url.' . F3::hashCode($_pattern); $_cached = Cache::cached($_hash); if ($_cached) { // Retrieve from cache $_buffer = Cache::fetch($_hash); $_rcvhdrs = strstr($_buffer, $_div, TRUE); $_response = substr(strstr($_buffer, $_div), 1); // Find out if cache is stale $_expires = NULL; foreach (explode(self::EOL, $_rcvhdrs) as $_hdr) { if (preg_match('/^' . F3::HTTP_Expires . ':(.+)/', $_hdr, $_match)) { $_expires = strtotime($_match[1]); break; } } if (!is_null($_expires) && time() < $_expires) { // Cached page is still fresh foreach (explode(self::EOL, $_rcvhdrs) as $_hdr) { F3::$global['HEADERS'][] = $_hdr; if (preg_match('/' . F3::HTTP_Content . '/', $_hdr)) { // Forward HTTP header header($_hdr); } } return $_response; } } $_url = parse_url($_route); if (!$_url['path']) { // Set to Web root $_url['path'] = '/'; } if ($_method != 'GET') { if ($_url['query']) { // Non-GET method; Query is distinct from URI $_query = $_url['query']; $_url['query'] = ''; } } else { if ($_query) { // GET method; Query is integral part of URI $_url['query'] = $_query; $_query = ''; } } // Set up host name and TCP port for socket connection if (preg_match('/https/', $_url['scheme'])) { if (!$_url['port']) { $_url['port'] = 443; } $_target = 'ssl://' . $_url['host'] . ':' . $_url['port']; } else { if (!$_url['port']) { $_url['port'] = 80; } $_target = $_url['host'] . ':' . $_url['port']; } $_socket = @fsockopen($_target, $_url['port'], $_errno, $_text); if (!$_socket) { // Can't establish connection trigger_error($_text); return FALSE; } // Send HTTP request fputs($_socket, $_method . ' ' . $_url['path'] . ($_url['query'] ? '?' . $_url['query'] : '') . ' ' . 'HTTP/1.0' . self::EOL . F3::HTTP_Host . ': ' . $_url['host'] . self::EOL . F3::HTTP_Agent . ': Mozilla/5.0 (' . 'compatible;' . F3::TEXT_AppName . ' ' . F3::TEXT_Version . ')' . self::EOL . ($_reqhdrs ? implode(self::EOL, $_reqhdrs) . self::EOL : '') . ($_method != 'GET' ? 'Content-Type: ' . 'application/x-www-form-urlencoded' . self::EOL . 'Content-Length: ' . strlen($_query) . self::EOL : '') . F3::HTTP_AcceptEnc . ': gzip' . self::EOL . ($_cached ? F3::HTTP_Cache . ': max-age=86400' . self::EOL : '') . F3::HTTP_Connect . ': close' . self::EOL . self::EOL . $_query . self::EOL . self::EOL); $_found = FALSE; $_expires = FALSE; $_gzip = FALSE; // Set connection timeout parameters stream_set_blocking($_socket, TRUE); stream_set_timeout($_socket, ini_get('default_socket_timeout')); $_info = stream_get_meta_data($_socket); // Get headers and response while (!feof($_socket) && !$_info['timed_out']) { $_response .= fgets($_socket, 4096); // MDFK97 $_info = stream_get_meta_data($_socket); if (!$_found) { $_rcvhdrs = strstr($_response, self::EOL . self::EOL, TRUE); if ($_rcvhdrs) { $_found = TRUE; if (PHP_SAPI != 'cli' && !headers_sent()) { ob_start(); if ($_follow && preg_match('/HTTP\\/1\\.\\d\\s30\\d/', $_rcvhdrs)) { // Redirection preg_match('/' . F3::HTTP_Location . ':\\s*(.+?)/', $_rcvhdrs, $_loc); return self::http($_method . ' ' . $_loc[1], $_query, $_reqhdrs); } foreach (explode(self::EOL, $_rcvhdrs) as $_hdr) { F3::$global['HEADERS'][] = $_hdr; if (!F3::$global['QUIET'] && preg_match('/' . F3::HTTP_Content . '/', $_hdr)) { // Forward HTTP header header($_hdr); } elseif (preg_match('/^' . F3::HTTP_Encoding . ':\\s*.*gzip/', $_hdr)) { // Uncompress content $_gzip = TRUE; } elseif (preg_match('/^' . F3::HTTP_Expires . ':\\s*.+/', $_hdr)) { // Cache this page $_expires = TRUE; } } ob_end_flush(); if ($_flag) { Cache::store($_hash, $_rcvhdrs . $_div . $_response); } } // Split content from HTTP response headers $_response = substr(strstr($_response, self::EOL . self::EOL), 4); } } } fclose($_socket); if ($_info['timed_out']) { trigger_error(self::TEXT_Timeout); return FALSE; } if (PHP_SAPI != 'cli' && !headers_sent()) { if ($_gzip) { $_response = gzinflate(substr($_response, 10)); } if ($_expires) { Cache::store($_hash, $_rcvhdrs . $_div . $_response); } } // Return content return $_response; }
/** Process SQL statement(s) @return array @param $cmds mixed @param $args array @param $ttl int @public **/ function exec($cmds, array $args = NULL, $ttl = 0) { if (!$this->pdo) { self::instantiate(); } $stats =& self::ref('STATS'); if (!isset($stats[$this->dsn])) { $stats[$this->dsn] = array('cache' => array(), 'queries' => array()); } $batch = is_array($cmds); if (!$batch) { $cmds = array($cmds); $args = array($args); } elseif (!$this->pdo->inTransaction()) { $this->begin(); } foreach (array_combine($cmds, $args) as $cmd => $arg) { $hash = 'sql.' . self::hash($cmd); $cached = Cache::cached($hash); if ($ttl && $cached && $_SERVER['REQUEST_TIME'] - $cached < $ttl) { // Gather cached queries for profiler if (!isset($stats[$this->dsn]['cache'][$cmd])) { $stats[$this->dsn]['cache'][$cmd] = 0; } $stats[$this->dsn]['cache'][$cmd]++; $this->result = Cache::get($hash); } else { if (is_null($arg)) { $query = $this->pdo->query($cmd); } else { $query = $this->pdo->prepare($cmd); $ok = TRUE; if (!is_object($query)) { $ok = FALSE; } else { foreach ($arg as $key => $value) { if (!(is_array($value) ? $query->bindvalue($key, $value[0], $value[1]) : $query->bindvalue($key, $value, $this->type($value)))) { $ok = FALSE; break; } } if ($ok) { $ok = $query->execute(); } } if (!$ok) { if ($this->pdo->inTransaction()) { $this->rollback(); } trigger_error(sprintf(self::TEXT_ExecFail, $cmd)); return FALSE; } } // Check SQLSTATE foreach (array($this->pdo, $query) as $obj) { if ($obj->errorCode() != PDO::ERR_NONE) { if ($this->pdo->inTransaction()) { $this->rollback(); } $error = $obj->errorinfo(); trigger_error($error[2]); return FALSE; } } $this->result = preg_match('/^\\s*(?:INSERT|UPDATE|DELETE)\\s/i', $cmd) ? $query->rowCount() : $query->fetchall(PDO::FETCH_ASSOC); if ($ttl) { Cache::set($hash, $this->result, $ttl); } // Gather real queries for profiler if (!isset($stats[$this->dsn]['queries'][$cmd])) { $stats[$this->dsn]['queries'][$cmd] = 0; } $stats[$this->dsn]['queries'][$cmd]++; } } if ($batch && !$this->pdo->inTransaction()) { $this->commit(); } return $this->result; }
/** Configure framework according to .ini file settings and cache auto-generated PHP code to speed up execution @param $_file string @public **/ public static function config($_file) { // Generate hash code for config file $_hash = 'php.' . self::hashCode($_file); $_cached = Cache::cached($_hash); if ($_cached && filemtime($_file) < $_cached['time']) { // Retrieve from cache $_save = gzinflate(Cache::fetch($_hash)); } else { if (!file_exists($_file)) { // .ini file not found self::$global['CONTEXT'] = $_file; trigger_error(self::TEXT_Config); return; } // Map sections to framework methods $_map = array('global' => 'set', 'routes' => 'route', 'maps' => 'map'); // Read the .ini file preg_match_all('/\\s*(?:\\[(.+?)\\]|(?:;.+?)*|(?:([^=]+)=(.+?)))(?:\\v|$)/s', file_get_contents($_file), $_matches, PREG_SET_ORDER); $_cfg = array(); $_ptr =& $_cfg; foreach ($_matches as $_match) { if ($_match[1]) { // Section header if (!isset($_map[$_match[1]])) { // Unknown section self::$global['CONTEXT'] = $_section; trigger_error(self::TEXT_Section); return; } $_ptr =& $_cfg[$_match[1]]; } elseif ($_match[2]) { $_csv = array_map(function ($_val) { // Typecast if necessary return is_numeric($_val) || preg_match('/^(TRUE|FALSE)\\b/i', $_val) ? eval('return ' . $_val . ';') : $_val; }, str_getcsv($_match[3])); // Convert comma-separated values to array $_match[3] = count($_csv) > 1 ? $_csv : $_csv[0]; if (preg_match('/(.+?)\\[(.*?)\\]/', $_match[2], $_sub)) { if ($_sub[2]) { // Associative array $_ptr[$_sub[1]][$_sub[2]] = $_match[3]; } else { // Numeric-indexed array $_ptr[$_sub[1]][] = $_match[3]; } } else { // Key-value pair $_ptr[$_match[2]] = $_match[3]; } } } ob_start(); foreach ($_cfg as $_section => $_pair) { $_func = $_map[$_section]; foreach ($_pair as $_key => $_val) { // Generate PHP snippet echo 'F3::' . $_func . '(' . var_export($_key, TRUE) . ',' . ($_func == 'set' || !is_array($_val) ? var_export($_val, TRUE) : self::listArgs($_val)) . ');' . "\n"; } } $_save = ob_get_contents(); ob_end_clean(); // Compress and save to cache Cache::store($_hash, gzdeflate($_save)); } // Execute cached PHP code eval($_save); if (self::$global['ERROR']) { // Remove from cache Cache::remove($_hash); } }