一、send方法,发送响应
// 发送响应数据到客户端
public function send()
{
// 已经发送,直接返回
if ($this->isSent) {
return;
}
// 响应发送前事件处理
$this->trigger(self::EVENT_BEFORE_SEND);
// 准备阶段
$this->prepare();
//准备阶段结束后事件
$this->trigger(self::EVENT_AFTER_PREPARE);
//发送头
$this->sendHeaders();
//发送内容
$this->sendContent();
// 响应发送后事件
$this->trigger(self::EVENT_AFTER_SEND);
//设置标志
$this->isSent = true;
}
二、clear方法,清除数据
// 清除数据
public function clear()
{
$this->_headers = null;
$this->_cookies = null;
$this->_statusCode = 200;
$this->statusText = 'OK';
$this->data = null;
$this->stream = null;
$this->content = null;
$this->isSent = false;
}
三、sendHeaders方法,发送响应头
// 发送响应头到客户端
protected function sendHeaders()
{
// 检查响应头是否已经发送了
if (headers_sent($file, $line)) {
throw new HeadersAlreadySentException($file, $line);
}
if ($this->_headers) {
foreach ($this->getHeaders() as $name => $values) {
$name = str_replace(
' ',
'-',
ucwords(// 每个词的首字母大写
str_replace('-', ' ', $name)
)
);
// 设置允许发送相同的头多次
// set replace for first occurrence of header but false afterwards to allow multiple
$replace = true;
foreach ($values as $value) {
header("$name: $value", $replace);
$replace = false;
}
}
}
// 获取响应码并发送
$statusCode = $this->getStatusCode();
header("HTTP/{$this->version} {$statusCode} {$this->statusText}");
//发送cookie
$this->sendCookies();
}
四、sendCookies方法,发送cookie
// 发送cookie到客户端
protected function sendCookies()
{
// cookie为空,返回
if ($this->_cookies === null) {
return;
}
// 返回request对象
$request = Yii::$app->getRequest();
// 是否启用cookie验证
if ($request->enableCookieValidation) {
if ($request->cookieValidationKey == '') {
throw new InvalidConfigException(get_class($request) . '::cookieValidationKey must be configured with a secret key.');
}
$validationKey = $request->cookieValidationKey;
}
// CookieCollection实现了IteratorAggregate接口
foreach ($this->getCookies() as $cookie) {
$value = $cookie->value;
//cookie校验
if ($cookie->expire != 1 && isset($validationKey)) {
$value = Yii::$app->getSecurity()->hashData(serialize([$cookie->name, $value]), $validationKey);
}
// php>=7.3.0
if (PHP_VERSION_ID >= 70300) {
setcookie($cookie->name, $value, [
'expires' => $cookie->expire,
'path' => $cookie->path,
'domain' => $cookie->domain,
'secure' => $cookie->secure,
'httpOnly' => $cookie->httpOnly,
'sameSite' => !empty($cookie->sameSite) ? $cookie->sameSite : null,
]);
} else {
// Work around for setting sameSite cookie prior PHP 7.3
// https://stackoverflow.com/questions/39750906/php-setcookie-samesite-strict/46971326#46971326
$cookiePath = $cookie->path;
if (!is_null($cookie->sameSite)) {
$cookiePath .= '; samesite=' . $cookie->sameSite;
}
setcookie($cookie->name, $value, $cookie->expire, $cookiePath, $cookie->domain, $cookie->secure, $cookie->httpOnly);
}
}
}
五、sendContent方法,发送内容
//发送响应内容到客户端
protected function sendContent()
{
if ($this->stream === null) {
echo $this->content;
return;
}
// Try to reset time limit for big files
if (!function_exists('set_time_limit') || !@set_time_limit(0)) {
Yii::warning('set_time_limit() is not available', __METHOD__);
}
if (is_callable($this->stream)) {
$data = call_user_func($this->stream);
foreach ($data as $datum) {
echo $datum;
flush();
}
return;
}
$chunkSize = 8 * 1024 * 1024; // 8MB per chunk
if (is_array($this->stream)) {
list($handle, $begin, $end) = $this->stream;
// only seek if stream is seekable
if ($this->isSeekable($handle)) {
fseek($handle, $begin);
}
while (!feof($handle) && ($pos = ftell($handle)) <= $end) {
if ($pos + $chunkSize > $end) {
$chunkSize = $end - $pos + 1;
}
echo fread($handle, $chunkSize);
flush(); // Free up memory. Otherwise large files will trigger PHP's memory limit.
}
fclose($handle);
} else {
while (!feof($this->stream)) {
echo fread($this->stream, $chunkSize);
flush();
}
fclose($this->stream);
}
}
总结:
阅读了5个方法:
- send方法,发送响应
- clear方法,清除数据
- sendHeaders方法,发送响应头
- sendCookies方法,发送cookie
- sendContent方法,发送内容