// +---------------------------------------------------------------------- namespace think; use think\response\Redirect as RedirectResponse; class Response { /** * 原始数据 * @var mixed */ protected $data; /** * 应用对象实例 * @var App */ protected $app; /** * 当前contentType * @var string */ protected $contentType = 'text/html'; /** * 字符集 * @var string */ protected $charset = 'utf-8'; /** * 状态码 * @var integer */ protected $code = 200; /** * 是否允许请求缓存 * @var bool */ protected $allowCache = true; /** * 输出参数 * @var array */ protected $options = []; /** * header参数 * @var array */ protected $header = []; /** * 输出内容 * @var string */ protected $content = null; /** * 架构函数 * @access public * @param mixed $data 输出数据 * @param int $code * @param array $header * @param array $options 输出参数 */ public function __construct($data = '', $code = 200, array $header = [], $options = []) { $this->data($data); if (!empty($options)) { $this->options = array_merge($this->options, $options); } $this->contentType($this->contentType, $this->charset); $this->code = $code; $this->app = Container::get('app'); $this->header = array_merge($this->header, $header); } /** * 创建Response对象 * @access public * @param mixed $data 输出数据 * @param string $type 输出类型 * @param int $code * @param array $header * @param array $options 输出参数 * @return Response */ public static function create($data = '', $type = '', $code = 200, array $header = [], $options = []) { $class = false !== strpos($type, '\\') ? $type : '\\think\\response\\' . ucfirst(strtolower($type)); if (class_exists($class)) { return new $class($data, $code, $header, $options); } return new static($data, $code, $header, $options); } /** * 发送数据到客户端 * @access public * @return void * @throws \InvalidArgumentException */ public function send() { // 监听response_send $this->app['hook']->listen('response_send', $this); // 处理输出数据 $data = $this->getContent(); // Trace调试注入 if ('cli' != PHP_SAPI && $this->app['env']->get('app_trace', $this->app->config('app.app_trace'))) { $this->app['debug']->inject($this, $data); } if (200 == $this->code && $this->allowCache) { $cache = $this->app['request']->getCache(); if ($cache) { $this->header['Cache-Control'] = 'max-age=' . $cache[1] . ',must-revalidate'; $this->header['Last-Modified'] = gmdate('D, d M Y H:i:s') . ' GMT'; $this->header['Expires'] = gmdate('D, d M Y H:i:s', $_SERVER['REQUEST_TIME'] + $cache[1]) . ' GMT'; $this->app['cache']->tag($cache[2])->set($cache[0], [$data, $this->header], $cache[1]); } } if (!headers_sent() && !empty($this->header)) { // 发送状态码 http_response_code($this->code); // 发送头部信息 foreach ($this->header as $name => $val) { header($name . (!is_null($val) ? ':' . $val : '')); } } $this->sendData($data); if (function_exists('fastcgi_finish_request')) { // 提高页面响应 fastcgi_finish_request(); } // 监听response_end $this->app['hook']->listen('response_end', $this); // 清空当次请求有效的数据 if (!($this instanceof RedirectResponse)) { $this->app['session']->flush(); } } /** * 处理数据 * @access protected * @param mixed $data 要处理的数据 * @return mixed */ protected function output($data) { return $data; } /** * 输出数据 * @access protected * @param string $data 要处理的数据 * @return void */ protected function sendData($data) { echo $data; } /** * 输出的参数 * @access public * @param mixed $options 输出参数 * @return $this */ public function options($options = []) { $this->options = array_merge($this->options, $options); return $this; } /** * 输出数据设置 * @access public * @param mixed $data 输出数据 * @return $this */ public function data($data) { $this->data = $data; return $this; } /** * 是否允许请求缓存 * @access public * @param bool $cache 允许请求缓存 * @return $this */ public function allowCache($cache) { $this->allowCache = $cache; return $this; } /** * 设置响应头 * @access public * @param string|array $name 参数名 * @param string $value 参数值 * @return $this */ public function header($name, $value = null) { if (is_array($name)) { $this->header = array_merge($this->header, $name); } else { $this->header[$name] = $value; } return $this; } /** * 设置页面输出内容 * @access public * @param mixed $content * @return $this */ public function content($content) { if (null !== $content && !is_string($content) && !is_numeric($content) && !is_callable([ $content, '__toString', ]) ) { throw new \InvalidArgumentException(sprintf('variable type error: %s', gettype($content))); } $this->content = (string) $content; return $this; } /** * 发送HTTP状态 * @access public * @param integer $code 状态码 * @return $this */ public function code($code) { $this->code = $code; return $this; } /** * LastModified * @access public * @param string $time * @return $this */ public function lastModified($time) { $this->header['Last-Modified'] = $time; return $this; } /** * Expires * @access public * @param string $time * @return $this */ public function expires($time) { $this->header['Expires'] = $time; return $this; } /** * ETag * @access public * @param string $eTag * @return $this */ public function eTag($eTag) { $this->header['ETag'] = $eTag; return $this; } /** * 页面缓存控制 * @access public * @param string $cache 缓存设置 * @return $this */ public function cacheControl($cache) { $this->header['Cache-control'] = $cache; return $this; } /** * 设置页面不做任何缓存 * @access public * @return $this */ public function noCache() { $this->header['Cache-Control'] = 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0'; $this->header['Pragma'] = 'no-cache'; return $this; } /** * 页面输出类型 * @access public * @param string $contentType 输出类型 * @param string $charset 输出编码 * @return $this */ public function contentType($contentType, $charset = 'utf-8') { $this->header['Content-Type'] = $contentType . '; charset=' . $charset; return $this; } /** * 获取头部信息 * @access public * @param string $name 头部名称 * @return mixed */ public function getHeader($name = '') { if (!empty($name)) { return isset($this->header[$name]) ? $this->header[$name] : null; } return $this->header; } /** * 获取原始数据 * @access public * @return mixed */ public function getData() { return $this->data; } /** * 获取输出数据 * @access public * @return mixed */ public function getContent() { if (null == $this->content) { $content = $this->output($this->data); if (null !== $content && !is_string($content) && !is_numeric($content) && !is_callable([ $content, '__toString', ]) ) { throw new \InvalidArgumentException(sprintf('variable type error: %s', gettype($content))); } $this->content = (string) $content; } return $this->content; } /** * 获取状态码 * @access public * @return integer */ public function getCode() { return $this->code; } public function __debugInfo() { $data = get_object_vars($this); unset($data['app']); return $data; } }