从零开始编写一个PHP框架 系列的《请求模块》
项目地址:terse
前言
当我们打开一个网页,浏览器会发出很多请求,有的是请求文件,有的是请求接口。
在编写和处理接口相关问题的时候,难免会需要分析请求相关的事情,比如:请求类型、请求头、请求相关的数据等。
需求分析
主要从几个大的方面来区分。
- 服务器相关变量的获取
- 请求类型的获取
- 请求参数的获取
文件结构
├── Interfaces
│ └── Request.php [接口]
└── Request.php [请求类]
为了规范一点,以后的模块尽量都加上相关接口。
由于这里接口的函数和子类的函数一致,这里就不重复写了。
服务器相关变量的获取
众所周知,服务端相关的变量都是从 $_SERVER
里获取的。所以我们需要对外提供一个 getServer
的接口。
为了使用方便,我们要将一些经常用到的参数,封装好方法给暴露给外界。
getServer($name);
if ($result) {
return $result;
}
return $this->getServer('HTTP_' . $name);
}
/**
* 获取 HTTP schema (http/https)
*
* @return string
*/
public function getScheme()
{
$https = $this->getServer('HTTPS');
return $https && $https != 'off' ? 'https' : 'http';
}
/**
* 获取服务器IP
*
* @return string
*/
public function getServerAddress()
{
$serverAddress = $this->getServer('SERVER_ADDR');
return $serverAddress ? $serverAddress : gethostbyname('localhost');
}
/**
* 获取服务器名称
*
* @return string
*/
public function getServerName()
{
$serverName = $this->getServer('SERVER_NAME');
return $serverName ? $serverName : 'localhost';
}
/**
* 获取请求头中 Host: 项的内容
*
* @return string
*/
public function getHttpHost()
{
return $this->getServer('HTTP_HOST');
}
/**
* 获取端口
*
* @return int
*/
public function getPort()
{
return $this->getServer('SERVER_PORT');
}
/**
* 获取URI
*
* @return string
*/
public final function getURI()
{
return $this->getServer('REQUEST_URI');
}
/**
* 获取客户端IP
*
* @return string
*/
public function getClientAddress()
{
return $this->getServer('REMOTE_ADDR');
}
/**
* 获取 UA
*
* @return string
*/
public function getUserAgent()
{
return $this->getServer('HTTP_USER_AGENT');
}
/**
* 获取 http referer
*
* @return string
*/
public function getHttpReferer()
{
return $this->getServer('HTTP_REFERER');
}
/**
* 获取请求方式
*
* @return string
*/
public function getMethod()
{
$method = $this->getServer('REQUEST_METHOD');
// 判断 是否存在
return $this->isValidMethod($method) ? $method : self::METHOD_GET;
}
}
请求类型的获取
关于请求类型,除了我们常用的 GET
和 POST
之外,还有一些像 OPTIONS
、PUT
、DELETE
、PATCH
、HEAD
等。
为了辨别请求是不是相关类型,我们需要有个函数作为判断,比如 is*
。
getMethod() === self::METHOD_GET;
}
/**
* 判断是否 POST
*
* @return bool
*/
public function isPost()
{
return $this->getMethod() === self::METHOD_POST;
}
/**
* 判断是否 PUT
*
* @return bool
*/
public function isPut()
{
return $this->getMethod() === self::METHOD_PUT;
}
/**
* 判断是否 DELETE
*
* @return bool
*/
public function isDelete()
{
return $this->getMethod() === self::METHOD_DELETE;
}
/**
* 判断是否 HEAD
*
* @return bool
*/
public function isHead()
{
return $this->getMethod() === self::METHOD_HEAD;
}
/**
* 判断是否 OPTIONS
*
* @return bool
*/
public function isOptions()
{
return $this->getMethod() === self::METHOD_OPTIONS;
}
/**
* 判断是否 PATCH
*
* @return bool
*/
public function isPatch()
{
return $this->getMethod() === self::METHOD_PATCH;
}
/**
* 获取请求方式
*
* @return string
*/
public function getMethod()
{
$method = $this->getServer('REQUEST_METHOD');
// 判断 是否存在
return $this->isValidMethod($method) ? $method : self::METHOD_GET;
}
/**
* 检查方法
*
* @param string $method
* @return bool
*/
protected function isValidMethod($method)
{
switch ($method) {
case self::METHOD_GET:
case self::METHOD_POST:
case self::METHOD_PUT:
case self::METHOD_DELETE:
case self::METHOD_HEAD:
case self::METHOD_OPTIONS:
case self::METHOD_PATCH:
case self::METHOD_PURGE:
case self::METHOD_TRACE:
case self::METHOD_CONNECT:
return true;
}
return false;
}
}
请求参数的获取
关于请求参数,这里有几种类型:REQUEST
、GET
、POST
、PUT
、RAW INPUT
、FILES
。
getHelper($_REQUEST, $name, $filters, $default);
}
/**
* 获取 $_POST 参数
*
* @param string $name
* @param string|array $filters
* @param mixed $default
* @return mixed
*/
public function getPost($name = null, $filters = null, $default = null)
{
return $this->getHelper($_POST, $name, $filters, $default);
}
/**
* 获取 $_GET 参数
*
* @param string $name
* @param string|array $filters
* @param mixed $default
* @return mixed
*/
public function getQuery($name = null, $filters = null, $default = null)
{
return $this->getHelper($_GET, $name, $filters, $default);
}
/**
* 获取上传的文件
*
* @return boolean
*/
public function getFiles()
{
return $_FILES;
}
/**
* Gets HTTP raw request body
*
* @return string
*/
public function getRawBody()
{
if (!$this->_rawBody) {
$this->_rawBody = @file_get_contents('php://input');
}
return $this->_rawBody;
}
/**
* Gets HTTP raw request body
*
* @return string
*/
public function getJsonRawBody()
{
$rawBody = $this->getRawBody();
return @json_decode($rawBody, true);
}
/**
* 判断参数是否存在,并启用过滤
*
* @param array $source
* @param string $name
* @param array $filters
* @param mixed $default
* @return mixed
*/
protected final function getHelper(array $source, $name, $filters, $default)
{
if (!$name) {
return $source;
}
$value = $default;
if (isset($source[$name])) {
$value = $source[$name];
}
// 本来想写filter的,这个放到第二期再做吧
if (!!$filters) {
# filter
}
return !$value && $default ? $default : $value;
}
}
有时候,我们需要判断某个参数是否存在,所以我们需要提供 has*
方法。
其它
由于我们经常使用 Ajax
,所以请求里面也提供了 isAjax
的接口供外界调用。
getServer('HTTP_X_REQUESTED_WITH');
return strtoupper($httpXRequest) == "XMLHTTPREQUEST";
}
}
完整代码
目前考虑的就是这些方法,在实际应用中,如果不够,则会不断的添加方法。
*/
class Request implements RequestInterface
{
const METHOD_GET = 'GET';
const METHOD_POST = 'POST';
const METHOD_PUT = 'PUT';
const METHOD_DELETE = 'DELETE';
const METHOD_HEAD = 'HEAD';
const METHOD_OPTIONS = 'OPTIONS';
const METHOD_PATCH = 'PATCH';
const METHOD_PURGE = 'PURGE';
const METHOD_TRACE = 'TRACE';
const METHOD_CONNECT = 'CONNECT';
protected $_rawBody;
/**
* 获取 $_REQUEST 参数
*
* @param string $name
* @param string|array $filters
* @param mixed $default
* @return mixed
*/
public function get($name = null, $filters = null, $default = null)
{
return $this->getHelper($_REQUEST, $name, $filters, $default);
}
/**
* 获取 $_POST 参数
*
* @param string $name
* @param string|array $filters
* @param mixed $default
* @return mixed
*/
public function getPost($name = null, $filters = null, $default = null)
{
return $this->getHelper($_POST, $name, $filters, $default);
}
/**
* 获取 $_GET 参数
*
* @param string $name
* @param string|array $filters
* @param mixed $default
* @return mixed
*/
public function getQuery($name = null, $filters = null, $default = null)
{
return $this->getHelper($_GET, $name, $filters, $default);
}
/**
* 获取上传的文件
*
* @return boolean
*/
public function getFiles()
{
return $_FILES;
}
/**
* Gets HTTP raw request body
*
* @return string
*/
public function getRawBody()
{
if (!$this->_rawBody) {
$this->_rawBody = @file_get_contents('php://input');
}
return $this->_rawBody;
}
/**
* Gets HTTP raw request body
*
* @return string
*/
public function getJsonRawBody()
{
$rawBody = $this->getRawBody();
return @json_decode($rawBody, true);
}
/**
* 检查 $_REQUEST 中是否存在指定参数
*
* @param string $name
* @return bool
*/
public function has($name)
{
return isset($_REQUEST[$name]);
}
/**
* 检查 $_POST 中是否存在指定参数
*
* @param string $name
* @return bool
*/
public function hasPost($name)
{
return isset($_POST[$name]);
}
/**
* 检查 $_GET 中是否存在指定参数
*
* @param string $name
* @return bool
*/
public function hasQuery($name)
{
return isset($_GET[$name]);
}
/**
* 检查 $_SERVER 中是否存在指定参数
*
* @param string $name
* @return bool
*/
public function hasServer($name)
{
return isset($_SERVER[$name]);
}
/**
* 判断是否存在上传文件
*
* @return boolean
*/
public function hasFiles()
{
return !!$_FILES;
}
/**
* 获取 $_SERVER 参数
*
* @param string $name
* @return mixed
*/
public function getServer($name)
{
if (isset($_SERVER[$name])) {
return $_SERVER[$name];
}
return null;
}
/**
* 获取 Header 信息
*
* @param string $name
* @return string
*/
public function getHeader($header)
{
$name = strtoupper(strtr($header, "-", "_"));
$result = $this->getServer($name);
if ($result) {
return $result;
}
return $this->getServer('HTTP_' . $name);
}
/**
* 获取 HTTP schema (http/https)
*
* @return string
*/
public function getScheme()
{
$https = $this->getServer('HTTPS');
return $https && $https != 'off' ? 'https' : 'http';
}
/**
* 获取服务器IP
*
* @return string
*/
public function getServerAddress()
{
$serverAddress = $this->getServer('SERVER_ADDR');
return $serverAddress ? $serverAddress : gethostbyname('localhost');
}
/**
* 获取服务器名称
*
* @return string
*/
public function getServerName()
{
$serverName = $this->getServer('SERVER_NAME');
return $serverName ? $serverName : 'localhost';
}
/**
* 获取请求头中 Host: 项的内容
*
* @return string
*/
public function getHttpHost()
{
return $this->getServer('HTTP_HOST');
}
/**
* 获取端口
*
* @return int
*/
public function getPort()
{
return $this->getServer('SERVER_PORT');
}
/**
* 获取URI
*
* @return string
*/
public final function getURI()
{
return $this->getServer('REQUEST_URI');
}
/**
* 获取客户端IP
*
* @return string
*/
public function getClientAddress()
{
return $this->getServer('REMOTE_ADDR');
}
/**
* 获取 UA
*
* @return string
*/
public function getUserAgent()
{
return $this->getServer('HTTP_USER_AGENT');
}
/**
* 获取 http referer
*
* @return string
*/
public function getHttpReferer()
{
return $this->getServer('HTTP_REFERER');
}
/**
* 获取请求方式
*
* @return string
*/
public function getMethod()
{
$method = $this->getServer('REQUEST_METHOD');
// 判断 是否POST
if ($method === self::METHOD_POST) {
$method = $this->validPost();
}
// 判断 是否存在
return $this->isValidMethod($method) ? $method : self::METHOD_GET;
}
/**
* 判断是否 GET
*
* @return bool
*/
public function isGet()
{
return $this->getMethod() === self::METHOD_GET;
}
/**
* 判断是否 POST
*
* @return bool
*/
public function isPost()
{
return $this->getMethod() === self::METHOD_POST;
}
/**
* 判断是否 PUT
*
* @return bool
*/
public function isPut()
{
return $this->getMethod() === self::METHOD_PUT;
}
/**
* 判断是否 DELETE
*
* @return bool
*/
public function isDelete()
{
return $this->getMethod() === self::METHOD_DELETE;
}
/**
* 判断是否 HEAD
*
* @return bool
*/
public function isHead()
{
return $this->getMethod() === self::METHOD_HEAD;
}
/**
* 判断是否 OPTIONS
*
* @return bool
*/
public function isOptions()
{
return $this->getMethod() === self::METHOD_OPTIONS;
}
/**
* 判断是否 PATCH
*
* @return bool
*/
public function isPatch()
{
return $this->getMethod() === self::METHOD_PATCH;
}
/**
* 判断是否 AJAX
*
* @return bool
*/
public function isAjax()
{
$httpXRequest = $this->getServer('HTTP_X_REQUESTED_WITH');
return strtoupper($httpXRequest) == "XMLHTTPREQUEST";
}
/**
* 待写
*/
protected function validPost()
{
return self::METHOD_POST;
}
/**
* 检查方法
*
* @param string $method
* @return bool
*/
protected function isValidMethod($method)
{
switch ($method) {
case self::METHOD_GET:
case self::METHOD_POST:
case self::METHOD_PUT:
case self::METHOD_DELETE:
case self::METHOD_HEAD:
case self::METHOD_OPTIONS:
case self::METHOD_PATCH:
case self::METHOD_PURGE:
case self::METHOD_TRACE:
case self::METHOD_CONNECT:
return true;
}
return false;
}
/**
* 判断参数是否存在,并启用过滤
*
* @param array $source
* @param string $name
* @param array $filters
* @param mixed $default
* @return mixed
*/
protected final function getHelper(array $source, $name, $filters, $default)
{
if (!$name) {
return $source;
}
$value = $default;
if (isset($source[$name])) {
$value = $source[$name];
}
if (!!$filters) {
# filter
}
return !$value && $default ? $default : $value;
}
}
调用方式
get();
$request->getPost();
$request->getQuery();
$request->getJsonRawBody();
$request->isGet();
$request->isPost();
$request->isAjax();
最后
通篇基本在贴代码了,毕竟基本是判断和获取,没有什么比较特别的东西在里面。
下一篇《路由模块》