/** * @constructor * * @param {?string|array} $options An array of request options, or the URI string. * @param {?string} $options['prefix'] Parameters keys start with this prefix * will be treated as meta-parameters and * not returned in param() related functions. * * Parameters values start with this prefix * will be tried to parsed as constants and * booleans. * * This defaults to the "@" character. * * @param {?string} $options['uri'] The request uri, defaults to $_SERVER['REQUEST_URI']. * @param {?string} $options['method'] Request method, defaults to $_SERVER['REQUEST_METHOD']. * @param {?array} $options['headers'] Request headers, defaults to the contents of getallhheaders() * if the function is available. * @param {?array} $options['client'] Request client details, defaults to everything from $_SERVER. * @param {?array} $options['get'] GET parameters in array format. * @param {?array} $options['post'] POST parameters in array format. * @param {?array} $options['cookies'] COOKIES in array format. * @param {?array} $options['files'] Upload files along with this request. (Use with care) * When doing CURL requests, files array must compatible with CURL. * Otherwise this must obey the resolver-request format. * @param {?string} $options['locale'] Requesting locale, defaults to en_US. */ public function __construct($options = array()) { global $argv; if ($options instanceof Resolver) { $this->resolver = $options; $options = array(); } if (@$options) { if (is_string($options)) { $options = array('uri' => $options); } // Special parameter prefix if (!empty($options['prefix'])) { $this->metaPrefix = $options['prefix']; } // Request URI if (empty($options['uri'])) { throw new FrameworkException('Request URI is required.'); } else { $this->setUri($options['uri']); } // Request method if (isset($options['method'])) { $this->method = strtolower($options['method']); } else { $this->method = 'get'; } // Request headers if (isset($options['headers'])) { $this->headers = (array) $options['headers']; } // Request client if (!empty($options['client'])) { $this->client = (array) $options['client']; } // Request parameters GET if (isset($options['get'])) { $this->paramCache['get'] = (array) $options['get']; } // Request parameters POST if (!empty($options['post'])) { $this->paramCache['post'] = (array) $options['post']; } // Cookies if (isset($options['cookies'])) { $this->paramCache['cookies'] = (array) $options['cookies']; } // File uploads if (isset($options['files'])) { $this->paramCache['files'] = (array) $options['files']; } // Request locale if (!empty($options['locale'])) { $this->locale = (string) $options['locale']; } } else { // Request client switch (constant('PHP_SAPI')) { case 'cli': $this->client = array('type' => 'cli', 'host' => gethostname(), 'user' => get_current_user()); break; default: $this->client = array_filter(array('type' => 'http', 'secure' => @$_SERVER['HTTPS'] && strtolower($_SERVER['HTTPS']) != 'off', 'address' => @$_SERVER['REMOTE_ADDR'], 'host' => @$_SERVER['REMOTE_HOST'], 'port' => @$_SERVER['REMOTE_PORT'], 'user' => @$_SERVER['REMOTE_USER'], 'referer' => @$_SERVER['HTTP_REFERER'], 'version' => @$_SERVER['SERVER_PROTOCOL'], 'userAgent' => @$_SERVER['HTTP_USER_AGENT'], 'forwarder' => @$_SERVER['HTTP_X_FORWARDED_FOR'], 'isAjax' => strtolower(@$_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest'), compose('not', 'is_null')); break; } // Request method switch ($this->client('type')) { case 'cli': $this->method = 'cli'; break; default: $this->method = strtolower(@$_SERVER['REQUEST_METHOD']); break; } // Request headers switch ($this->client('type')) { case 'cli': break; default: $this->headers = getallheaders(); break; } // Request parameters switch ($this->client('type')) { case 'cli': $this->paramCache['cli'] = new Optimist(); break; default: // Request parameters GET $this->paramCache['get'] = $_GET; // Request parameters POST if (preg_match('/^application\\/json/', $this->header('Content-Type'))) { $this->paramCache['post'] = ContentDecoder::json(file_get_contents('php://input'), true); } else { $this->paramCache['post'] = $_POST; } // Cookies $this->paramCache['cookies'] =& $_COOKIE; // File uploads if ($this->method() == 'put') { $this->paramCache['files'] = new RequestPutFile($this->header('Content-Type')); } else { util::filesFix(); $parseFile = function ($file) use(&$parseFile) { if (!is_array($file)) { return $file; } if (util::isAssoc($file)) { switch ($file['error']) { case UPLOAD_ERR_OK: return new RequestPostFile($file); case UPLOAD_ERR_NO_FILE: // Skip it. break; default: return $file['error']; } } else { return array_mapdef($file, $parseFile); } }; $this->paramCache['files'] = array_mapdef(array_filter_keys($_FILES, compose('not', startsWith('@'))), $parseFile); unset($parseFile); } break; } // Request URI // CLI requires request parameters switch ($this->client('type')) { case 'cli': /*! Note @ 9 May, 2015 * Usage: node-cli [OPTIONS] COMMAND * Only one command is supported, simply shift it out. */ $this->uri = @$this->paramCache['cli']['_'][0]; if (!$this->uri) { $this->uri = $argv[1]; } break; default: $uri = array('scheme' => $this->client('secure') ? 'https' : 'http', 'user' => @$_SERVER['REMOTE_USER'], 'host' => @$_SERVER['SERVER_NAME'], 'port' => @$_SERVER['SERVER_PORT'], 'path' => @$_SERVER['REQUEST_URI'], 'query' => $_GET); if (empty($uri['user'])) { $uri['user'] = @$_SERVER['PHP_AUTH_USER']; } $this->setUri(array_filter($uri)); // = parse_url(http_build_url($this->uri)); break; } // Parse special parameter values array_walk_recursive($this->paramCache, function (&$value) { if (is_string($value) && strpos($value, $this->metaPrefix) === 0) { $_value = substr($value, strlen($this->metaPrefix)); switch (strtolower($_value)) { case 'true': $value = true; break; case 'false': $value = false; break; default: if (defined($_value)) { $value = constant($_value); } break; } } }); // Request timestamp $this->timestamp = (double) @$_SERVER['REQUEST_TIME_FLOAT']; } // Unified params ($_REQUEST mimic) switch ($this->client('type')) { case 'cli': // $this->paramCache['request'] = $this->paramCache['cli']; break; default: $this->paramCache['request'] = array_merge((array) @$this->paramCache['cookies'], (array) @$this->paramCache['get'], (array) @$this->paramCache['post']); break; } // Failover in case of request time not exists. if (!$this->timestamp) { $this->timestamp = microtime(1); } }