public function resolve(Request $request, Response $response) { foreach ($this->rules as $rule) { if ($rule['source']($request->uri('path'))) { if (is_callable(@$rule['target'])) { $target = $rule['target']($request, $response); } else { $target = @$rule['target']; } // do nothing if (empty($target)) { continue; } if (is_string($target)) { $request->setUri($target); } else { if (is_array($target)) { if (empty($target['uri']) && isset($target['options']['status'])) { $response->status($target['options']['status']); } else { if (isset($target['options'])) { $response->redirect($target['uri'], $target['options']); } else { $request->setUri($target['uri'] + $request->uri()); } } } } break; } } }
public function resolve(Request $request, Response $response) { $pathInfo = $request->uri('path'); // Inex 1 because request URI starts with a slash if (strpos($pathInfo, $this->dstPath) !== 1) { return; } else { $pathInfo = substr($pathInfo, strlen($this->dstPath) + 1); } $pathInfo = pathinfo($pathInfo); // Only serves .min.css requests if (!preg_match('/\\.min\\.css$/', $pathInfo['basename'])) { return; } $pathInfo['filename'] = preg_replace('/\\.min$/', '', $pathInfo['filename']); $_srcPath = "/{$pathInfo['dirname']}/{$pathInfo['filename']}.css"; $dstPath = "./{$this->dstPath}/{$pathInfo['dirname']}/{$pathInfo['filename']}.min.css"; foreach ($this->srcPath as $srcPath) { $srcPath = "./{$srcPath}{$_srcPath}"; // compile when: target file not exists, or source is newer if (file_exists($srcPath) && (!file_exists($dstPath) || @filemtime($srcPath) > @filemtime($dstPath))) { // empty results are ignored $result = trim(@CssMin::minify(file_get_contents($srcPath))); if ($result && !@file_put_contents($dstPath, $result)) { Log::warn('Permission denied, unable to minify CSS.'); } break; } } }
public function resolve(Request $request, Response $response) { $pathInfo = $request->uri('path'); // Inex 1 because request URI starts with a slash if (strpos($pathInfo, $this->dstPath) !== 1) { return; } else { $pathInfo = substr($pathInfo, strlen($this->dstPath) + 1); } $pathInfo = pathinfo($pathInfo); // Only serves .css requests if ($pathInfo['extension'] != 'css') { return; } // also takes care of .min requests $pathInfo['filename'] = preg_replace('/\\.min$/', '', $pathInfo['filename']); $_srcPath = "/{$pathInfo['dirname']}/{$pathInfo['filename']}.scss"; $dstPath = "./{$this->dstPath}/{$pathInfo['dirname']}/{$pathInfo['filename']}.css"; foreach ($this->srcPath as $srcPath) { $srcPath = "./{$srcPath}{$_srcPath}"; // compile when: target file not exists, or source is newer if (!file_exists($dstPath) || @filemtime($srcPath) > @filemtime($dstPath)) { $result = @trim((new Compiler())->compile(file_get_contents($srcPath))); // note; write empty file if target exists if ($result || file_exists($dstPath)) { if (!@file_put_contents($dstPath, $result)) { Log::warn('Permission denied, unable to compile SCSS.'); } } break; } } }
function resolve(Request $request, Response $response) { if ($response->status() != 200) { return; // only normal response will be processed } foreach ((array) $request->meta('output') as $outputFilter) { // format: func([param1[,param2[,param3 ...]]]) if (preg_match('/(\\w+)\\(([\\w\\s,]*)\\)/', $outputFilter, $matches)) { $func = @$this->funcMap[$matches[1]]; if (is_callable($func)) { if (@$matches[2]) { $func = call_user_func_array($func, explode(',', $matches[2])); } if (is_callable($func)) { try { $response->send(call_user_func_array($func, array($response->body()))); } catch (\Exception $e) { Log::error(sprintf('[InvokerPostProcessor] Error calling %s(): %s @ %s:%d', $matches[1], $e->getMessage(), basename($e->getFile()), $e->getLine()), $e->getTrace()); $response->send(array('error' => $e->getMessage(), 'code' => $e->getCode()), 500); } } } } } }
public function resolve(Request $request, Response $response) { // Then request params if (empty($locale)) { $locale = $request->meta('locale'); } // User preference if (empty($request->user)) { $locale = @$request->user['locale']; } // Accept from HTTP headers if (empty($locale)) { $locale = Locale::acceptFromHttp($request->header('Accept-Language')); } // TODO: Use Locale::lookup(); and its fallback mechanism for $this->defaultLocale. // TODO: Locale::getPrimaryLanguage() should be useful. // Default locale if (empty($locale)) { $locale = $this->defaultLocale; } if (!empty($locale)) { if ($request->meta('locale') != $locale) { $response->cookie('__locale', $locale, FRAMEWORK_COOKIE_EXPIRE_TIME, '/'); } $response->translation(new Translation($locale)); } }
/** * Use the new resolving mechanism to call for local services. */ static function call($service, $method, $parameters = array(), $options = array()) { $hostname = System::getHostname('service'); if (!$hostname) { throw new ServiceException('Service hostname undefined.'); } if (is_string($options)) { $options = array('method' => $options); } if (isset($options['type']) && empty($options['method'])) { $options['method'] = $options['type']; } $options = (array) $options + self::$defaultOptions; $prefix = conf::get('web::resolvers.service.prefix', '/service'); $options['uri'] = array('scheme' => (bool) @$options['secure'] ? 'https' : 'http', 'host' => $hostname, 'path' => "{$prefix}/{$service}/{$method}/" . implode('/', array_map('urlencode', (array) $parameters))); unset($prefix); // Customizable Resolver if (@$options['resolver'] instanceof Resolver) { $serviceResolver = $options['resolver']; } else { $serviceResolver = Resolver::getActiveInstance(); } unset($options['resolver']); if (@$options['response'] instanceof Response) { $serviceResponse = $options['response']; } else { $serviceResponse = new Response(); } unset($options['response']); $serviceRequest = new Request($options); // Explicitly force this request to be local. $serviceRequest->__local = true; return $serviceRequest->send($serviceResolver, $serviceResponse); }
public function resolve(Request $request, Response $response) { // Check whitelisted IP if (in_array($request->client('address'), $this->whitelist())) { return; } $request->setUri($this->template); }
/** * Add appropriate response header for response class to output. */ public function resolve(Request $req, Response $res) { $callback = $req->param('JSONP_CALLBACK_NAME'); if (!$callback) { $callback = $this->defaultCallback; } if ($callback && $req->param($callback)) { $res->header('X-JSONP-CALLBACK', $req->param($callback)); } }
/** * Makes GET request to the URL and return the results to the template’s $_text array, * where it will be rendered to the final template output * @param type $tree * @param type $content * @return type */ protected function _partial($tree, $content) { $address = trim($tree["raw"], " /"); if (StringMethods::indexOf($address, "http") != 0) { $host = RequestMethods::server("HTTP_HOST"); $address = "http://{$host}/{$address}"; } $request = new Request(); $response = addslashes(trim($request->get($address))); return "\$_text[] = \"{$response}\";"; }
/** * Make GET request to given URL and place the results * in the template file * @param array $tree Node from the template tree * @param mixed $content Content of node * @return string String to be included in template */ protected function _partial($tree, $content) { $address = trim($tree["raw"], " /"); // Convert a relative URl to an absolute URL if (StringMethods::indexOf($address, "http") != 0) { $host = RequestMethods::server("HTTP_HOST"); $address = "http://{$host}/{$address}"; } // Make GET request to URL and return results to // template $_text array $request = new Request(); $response = addslashes(trim($request->get($address))); return "\$_text[] = \"{$response}\";"; }
public function resolve(Request $request, Response $response) { $commandPath = $this->basePath . '/' . $request->uri(); if (!is_file($commandPath)) { throw new FrameworkException('Target command does not exist.'); } require_once $commandPath; $fx = compose(unshiftsArg('str_replace', ' ', ''), 'ucwords', 'strtolower', unshiftsArg('str_replace', '-', ' ')); $className = $fx($request->uri()); if (!class_exists($className) || is_a($className, 'IExecutableCommand', true)) { throw new FrameworkException("File is loaded, expecting class {$className} from {$commandPath}."); } $command = new $className(); $command->execute($request, $response); }
public function resolve(Request $request, Response $response) { global $argv; // Debug access log if (System::environment() == 'debug') { switch ($request->client('type')) { case 'cli': $message = implode(' ', array($request->client('type'), $request->uri())); break; default: $message = implode(' ', array($request->client('version'), strtoupper($request->method()), $request->uri('path'))); @Log::debug($message, array_filter(array('origin' => $request->client('referer'), 'userAgent' => util::cascade(@$request->client('userAgent'), 'Unknown'), 'timeElapsed' => round(microtime(1) - $request->timestamp(), 4) . ' secs'))); break; } } }
function resolve(Request $request, Response $response) { $pathname = $this->basePath . $request->uri('path'); switch (pathinfo($pathname, PATHINFO_EXTENSION)) { case 'md': case 'mdown': break; default: return; } if (is_file($pathname)) { $text = file_get_contents($pathname); $text = (new Parsedown())->text($text); $response->send($text, 200); } }
public static function Run() { self::$list['method'] = Request::getInstance()->method; self::$list['path'] = Request::getInstance()->path; self::$list['controller'] = str_replace('\\controller\\', '', Router::getInstance()->getControllerClass()); self::$list['action'] = Router::getInstance()->getAction(); require __DIR__ . '/src/view.php'; }
/** * Checks whether an update is available. */ public function resolve(Request $request, Response $response) { $path = $request->uri('path'); $hash = $request->param('v'); $info = Cache::getInfo($path, $hash); if (!$info) { return; } // Send a bunch of headers // 1. Conditional request // If-Modified-Since: Match against $info->getMTime(); // If-None-Match: Match against the md5_file(); // 2. Normal request // Content-Type + charset // Content-Length // Cache-Control // Date // Pragma (remove) // header('Content-Type: application/json; charset=utf-8', true); }
public function initialize() { require_once 'config/routing.php'; foreach ($this->routes as $route) { if (preg_match($route['path'], Request::getInstance()->path, $matches)) { $this->controller = $route['controller']; $this->action = $route['action']; if (!empty($matches)) { $this->matches = $matches; } } } }
public function resolve(Request $req, Response $res) { $req->user = new User(); // User from CLI switch ($req->client('type')) { case 'cli': // Retrieve user context from process data, then CLI argument. $userId = (int) Process::get('type'); if (!$userId) { $req->cli()->options('u', array('alias' => 'user', 'type' => 'integer', 'describe' => 'Idenitfier of target context user.')); $userId = (int) $req->meta('user'); } if ($userId) { $req->user->load($userId); } unset($userId); break; default: // Session ID provided, validate it. $sid = $req->meta('sid'); if ($sid) { $ret = Session::ensure($sid, $req->meta('token'), $req->fingerprint()); // Session doesn't exist, delete the cookie. if ($ret === false || $ret === Session::ERR_EXPIRED) { $res->cookie('__sid', '', time() - 3600); } else { if (is_integer($ret)) { switch ($ret) { // note: System should treat as public user. case Session::ERR_INVALID: break; } } else { // Success, proceed. $req->user->load(Session::current('username')); unset($req->user->password); } } } else { if ($this->setupSession && !@\core\Node::get('User')) { $req->user->data(['id' => 0, 'groups' => ['Administrators'], 'username' => '__default']); } } break; } }
public function resolve(Request $request, Response $response) { $path = $this->srcPath . $request->uri('path') . '.url'; // Check if target file is a proxy. if (!is_file($path)) { return; } $cacheTarget = parse_ini_file($path); $cacheTarget = @$cacheTarget['URL']; unset($path); if (!$cacheTarget) { Log::warning('Proxy file has not URL parameter.', array('requestUri' => $request->uri(), 'proxyFile' => $request->uri('path') . '.uri')); $response->status(502); // Bad Gateway return; } /*! Cache Header Notes * * # Cache-Control * [public | private] Cacheable when public, otherwise the client is responsible for caching. * [no-cache( \w+)?] When no fields are specified, the whole thing must revalidate everytime, * otherwise cache it except specified fields. * [no-store] Ignore caching and pipe into output. * [max-age=\d+] Seconds before this cache is meant to expire, this overrides Expires header. * [s-maxage=\d+] Overrides max-age and Expires header, behaves just like max-age. * (This is for CDN and we are using it.) * [must-revalidate] Tells those CDNs which are intended to serve stale contents to revalidate every time. * [proxy-revalidate] Like the "s-" version of max-age, a "must-revalidate" override only for CDN. * [no-transform] Some CDNs will optimize images and other formats, this "opt-out" of it. * * # Expires * RFC timestamp for an absolute cache expiration, overridden by Cache-Control header. * * # ETag * Hash of anything, weak ETags is not supported at this moment. * * # vary * Too much fun inside and we are too serious about caching, ignore this. * * # pragma * This guy is too old to recognize. * [no-cache] Only this is known nowadays and is already succeed by Cache-Control: no-cache. * */ // note; Use "cache-meta://" scheme for header and cache meta info, for performance. // 1. Check if cache exists. $cache = (array) Cache::get("cache-meta://{$cacheTarget}"); // Cache expiration, in seconds. // expires = ( s-maxage || max-age || Expires ); if (@$cache['expires'] && time() > $cache['expires']) { Cache::delete("cache-meta://{$cacheTarget}"); Cache::delete("cache://{$cacheTarget}"); $cache = null; } // - If not exists, make normal request to remote server. // - If exists, make conditional request to remote server. // - Revalidation, we can skip this request and serve the content if false. // revalidates = ( Cache-Control:proxy-revalidate || Cache-Control:must-revalidate ) if (!$cache || @$cache['revalidates']) { $_request = array('uri' => $cacheTarget); if ($cache) { // Last-Modified if (@$cache['headers']['Last-Modified']) { $_request['headers']['If-Modified-Since'] = $cache['Last-Modified']; } // Entity-Tag if (@$cache['headers']['ETag'] && strpos($cache['headers']['ETag'], 'W\\') !== 0) { $_request['headers']['If-None-Match'] = $cache['ETag']; } } else { $cache = array(); } // Make the request $_response = new Response(array('autoOutput' => false)); (new Request($_request))->send(null, $_response); unset($_request); // parse headers into cache settings. if (in_array($_response->status(), array(200, 304))) { $res = preg_split('/\\s*,\\s*/', util::unwrapAssoc($_response->header('Cache-Control'))); $res = array_reduce($res, function ($res, $value) { // todo; Take care of no-cache with field name. if (strpos($value, '=') > 0) { $value = explode('=', $value); $res[$value[0]] = $value[1]; } else { $res[$value] = true; } return $res; }, array()); // private, no-store, no-cache if (@$res['private'] || @$res['no-store'] || @$res['no-cache']) { // note; in case the upstream server change this to uncacheable Cache::delete("cache-meta://{$cacheTarget}"); Cache::delete("cache://{$cacheTarget}"); $_response->clearBody(); } if ($_response->status() == 200 && $_response->body()) { $cache['contents'] = $_response->body(); } // expires = ( s-maxage || max-age || Expires ); if (@$res['s-maxage']) { $cache['expires'] = time() + $res['s-maxage']; } elseif (@$res['max-age']) { $cache['expires'] = time() + $res['max-age']; } else { $res = util::unwrapAssoc($_response->header('Expires')); if ($res) { $cache['expires'] = strtotime($res); } } // revalidates = ( Cache-Control:proxy-revalidate || Cache-Control:must-revalidate ) if (@$res['proxy-revalidate'] || @$res['must-revalidate']) { $cache['revalidates'] = true; } unset($res); } $cache['headers'] = array_map('core\\Utility::unwrapAssoc', $_response->header()); // PHP does not support chunked, skip this one. unset($cache['headers']['Transfer-Encoding']); // note; If cache is to be ignored, the $cacheTarget variable will be already unset(). if (isset($cacheTarget)) { if (@$cache['contents']) { Cache::set("cache://{$cacheTarget}", $cache['contents']); } Cache::set("cache-meta://{$cacheTarget}", array_filter_keys($cache, isNot('contents'))); } unset($_response); } // note; Send cache headers regardless of the request condition. if (@$cache['headers']) { $response->clearHeaders(); foreach ($cache['headers'] as $name => $value) { $response->header($name, $value, true); } unset($name, $value); } // note; Handles conditional request $ch = array_map('core\\Utility::unwrapAssoc', (array) @$cache['headers']); $mtime = @$ch['Last-Modified'] ? strtotime($ch['Last-Modified']) : false; // Request headr: If-Modified-Since if (@$ch['Last-Modified'] && $mtime) { if (strtotime($request->header('If-Modified-Since')) >= $mtime) { return $response->status(304); } } // Request header: If-Range if ($request->header('If-Range')) { // Entity tag if (strpos(substr($request->header('If-Range'), 0, 2), '"') !== false && @$ch['ETag']) { if ($this->compareETags(@$ch['ETag'], $request->header('If-Range'))) { return $this->response()->status(304); } } elseif (strtotime($request->header('If-Range')) === $mtime) { return $this->response()->status(304); } } unset($mtime); // Request header: If-None-Match if (!$request->header('If-Modified-Since') && $request->header('If-None-Match')) { // Exists but not GET or HEAD switch ($request->method()) { case 'get': case 'head': break; default: return $this->response()->status(412); } /*! Note by Vicary @ 24 Jan, 2013 * If-None-Match means 304 when target resources exists. */ if ($request->header('If-None-Match') === '*' && @$ch['ETag']) { return $this->response()->status(304); } if ($this->compareETags(@$ch['ETag'], preg_split('/\\s*,\\s*/', $request->header('If-None-Match')))) { return $this->response()->status(304); } } // Request header: If-Match if (!$request->header('If-Modified-Since') && $request->header('If-Match')) { // Exists but not GET or HEAD switch ($request->method()) { case 'get': case 'head': break; default: return $this->response()->status(412); } if ($request->header('If-Match') === '*' && !@$ch['ETag']) { return $this->response()->status(412); } preg_match_all('/(?:^\\*$|(:?"([^\\*"]+)")(?:\\s*,\\s*(:?"([^\\*"]+)")))$/', $request->header('If-Match'), $eTags); // 412 Precondition Failed when nothing matches. if (@$eTags[1] && !in_array($eTag, (array) $eTags[1])) { return $this->response()->status(412); } } if ($cacheTarget && empty($cache['contents'])) { $cache['contents'] = Cache::get("cache://{$cacheTarget}"); } // Output the cahce content $response->send($cache['contents'], 200); }
public function resolve(Request $request, Response $response) { // Stop processing when previous resolvers has done something and given a response status code. if ($response->status()) { return; } $path = $request->uri('path'); // note; decode escaped URI characters into escaped shell path $path = preg_replace_callback('/%([\\dA-F]{2,2})/i', function ($matches) { return '\\' . chr(hexdec($matches[1])); }, $path); // Store original request if (empty($request->__directoryIndex)) { $request->__uri = $request->uri(); } if (stripos($path, $this->pathPrefix) === 0) { $path = substr($path, strlen($this->pathPrefix)); } if (strpos($path, '?') !== false) { $path = strstr($path, '?', true); } $path = urldecode($path); if (!$path) { $path = './'; } //------------------------------ // Emulate DirectoryIndex //------------------------------ if (is_dir($path)) { if (!is_file($path) && !isset($request->__directoryIndex)) { // Prevent redirection loop $request->__directoryIndex = true; foreach ($this->directoryIndex() as $file) { $request->setUri(preg_replace('/^\\.\\//', '', $path) . $file); // Exit whenever an index is handled successfully, this will exit. if ($this->resolve($request, $response)) { return; } } unset($request->__directoryIndex); // Nothing works, going down. if (isset($request->__uri)) { $request->setUri($request->__uri); } } } else { if (empty($request->__directoryIndex)) { $dirname = dirname($path); if ($dirname == '.') { $dirname = '/'; } if (in_array(pathinfo($path, PATHINFO_FILENAME), $this->directoryIndex())) { // extension-less if (!pathinfo($path, PATHINFO_EXTENSION) || is_file($path)) { $response->redirect($dirname); return true; } } unset($dirname); } } //------------------------------ // Virtual file handling //------------------------------ $this->createVirtualFile($path); if (is_file($path)) { try { $this->handle($path, $request, $response); } catch (ResolverException $e) { $response->status($e->statusCode()); } if (!$response->status()) { $response->status(200); } return true; } }
<?php error_reporting(E_ALL); ini_set('display_errors', 1); use FlickrTestApp\Config\AppConfig; use Framework\Resolver; use Framework\Router; use Framework\Request; // Composer autoload $loader = (require __DIR__ . '/../vendor/autoload.php'); // Load application configuration define('APP_CONFIG', realpath(__DIR__ . '/../src/FlickrTestApp/Config/AppConfig.php')); // Check if the app configuration is readable if (!is_readable(APP_CONFIG)) { die('No application configuration found. Please create an application configuration in ' . APP_CONFIG); } // Setup routes from AppConfig $router = new Router(AppConfig::$routes); // URL resolver $resolver = Resolver::build($router); // Build the current request to be served $request = Request::fromCurrent(); // Built response object $response = $resolver->handle($request); // Dispatch the response $response->dispatch();
static function authenticate(Request $r = null) { return $r && $r->method() == 'get'; }
public function resolve(Request $req, Response $res) { $auth = $this->paths; $pathNodes = trim($req->uri('path'), '/'); if ($pathNodes) { $pathNodes = explode('/', $pathNodes); } else { $pathNodes = ['/']; } $lastWildcard = @$auth['*']; foreach ($pathNodes as $index => $pathNode) { if (!util::isAssoc($auth)) { break; // No more definitions, break out. } if (isset($auth['*'])) { $lastWildcard = $auth['*']; } if (isset($auth[$pathNode])) { $auth = $auth[$pathNode]; } else { unset($auth); break; } } if (!isset($auth) || !is_bool($auth) && (!is_array($auth) || util::isAssoc($auth))) { if (empty($lastWildcard)) { throw new FrameworkException('Unable to resolve authentication chain from request URI.'); } else { $auth = $lastWildcard; } } unset($pathNodes, $lastWildcard); // Numeric array if (is_array($auth) && !util::isAssoc($auth)) { $auth = array_reduce($auth, function ($result, $auth) use($req) { if (!$result) { return $result; } if (is_callable($auth)) { $auth = $auth($req); } else { if (is_string($auth)) { if (strpos($auth, '/') === false) { $auth = "authenticators\\{$auth}"; } if (is_a($auth, 'framework\\interfaces\\IAuthenticator', true)) { $result = $result && $auth::authenticate($req); } else { throw new FrameworkException('Unknown authenticator type, must be ' . 'instance of IAuthenticator or callable.'); } } else { throw new FrameworkException('Unknown authenticator type, must be ' . 'instance of IAuthenticator or callable.'); } } return $result && $auth; }, true); } // Boolean if (is_bool($auth) && !$auth) { $res->status($this->statusCode); } // TODO: Mark allowed or denied according to the new resolver mechanism. }