• 本章继续学习函数 Response::getInstance()->sendHeaders()
 // 源文件 /var/Typecho/Response.php
177    /**
178     * send all headers
179     */
180    public function sendHeaders()
181    {
182        if ($this->sandbox) {
183            return;
184        }
185
186        $sentHeaders = [];
187        foreach (headers_list() as $header) {
188            [$key] = explode(':', $header, 2);
189            $sentHeaders[] = strtolower(trim($key));
190        }
191
192        header('HTTP/1.1 ' . $this->status . ' ' . self::HTTP_CODE[$this->status], true, $this->status);
193
194        // set header
195        foreach ($this->headers as $name => $value) {
196            if (!in_array(strtolower($name), $sentHeaders)) {
197                header($name . ': ' . $value, true);
198            }
199        }
200
201        // set cookie
202        foreach ($this->cookies as $cookie) {
203            [$key, $value, $timeout, $path, $domain, $secure, $httponly] = $cookie;
204
205            if ($timeout > 0) {
206                $now = time();
207                $timeout += $timeout > $now - 86400 ? 0 : $now;
208            } elseif ($timeout < 0) {
209                $timeout = 1;
210            }
211
212            setrawcookie($key, rawurlencode($value), $timeout, $path, $domain, $secure, $httponly);
213        }
214    }
  • 第182~184行:如果 $this->sandbox 的值为 true 则返回,否则继续执行函数体。
 // 源文件 /var/Typecho/Response.php
112    /**
113     * @var bool
114     */
115    private $sandbox = false;
  • 第115行:定义变量 $sandbox 默认值为 false 函数继续执行。
  • 第186行:定义变量 $sentHeaders 默认值为一个空数组。
  • 第187~190行:foreach 循环,headers_list() 返回已发送的 HTTP 响应头(或准备发送的),explode(':', $header, 2)用 ':' 分割 $header 成为含有两个元素的数组并赋值给 [$key],strtolower(trim($key)) 把 $key 中的元素两边的空格修剪掉并且转换为小写字母然后赋值给 $sentHeaders[]
  • 第192行:header() 发送原生 HTTP 头,header("HTTP/1.1 200 OK",true,200) 第二个参数 true 表明是否用后面的头替换前面相同类型的头,第三个参数强制指定 HTTP 响应的值为 200
  •  // 源文件 /var/Typecho/Response.php
    102    /**
    103     * @var int
    104     */
    105    private $status = 200;
    
    • 第105行:定义变量 $status 默认值为 200
     // 源文件 /var/Typecho/Response.php
        /**
         * http code
         *
         * @access private
         * @var array
         */
    23  private const HTTP_CODE = [
            100 => 'Continue',
            101 => 'Switching Protocols',
    26      200 => 'OK',
            201 => 'Created',
            202 => 'Accepted',
            203 => 'Non-Authoritative Information',
            204 => 'No Content',
            205 => 'Reset Content',
            206 => 'Partial Content',
            300 => 'Multiple Choices',
            301 => 'Moved Permanently',
            302 => 'Found',
            303 => 'See Other',
            304 => 'Not Modified',
            305 => 'Use Proxy',
            307 => 'Temporary Redirect',
            400 => 'Bad Request',
            401 => 'Unauthorized',
            402 => 'Payment Required',
            403 => 'Forbidden',
            404 => 'Not Found',
            405 => 'Method Not Allowed',
            406 => 'Not Acceptable',
            407 => 'Proxy Authentication Required',
            408 => 'Request Timeout',
            409 => 'Conflict',
            410 => 'Gone',
            411 => 'Length Required',
            412 => 'Precondition Failed',
            413 => 'Request Entity Too Large',
            414 => 'Request-URI Too Long',
            415 => 'Unsupported Media Type',
            416 => 'Requested Range Not Satisfiable',
            417 => 'Expectation Failed',
            500 => 'Internal Server Error',
            501 => 'Not Implemented',
            502 => 'Bad Gateway',
            503 => 'Service Unavailable',
            504 => 'Gateway Timeout',
            505 => 'HTTP Version Not Supported'
    64  ];
    
    • 第23-64行:定义了 self::HTTP_CODE[200] 的值为 'OK'
  • 第195~199行:foreach 循环,in_array - 检查数组中是否存在某个值,代码实现了=>检查$this->headers数组中不存在$sentHeaders数组中的元素并且用header()方法进行发送。
  • 第202~213行:foreach 循环,对 cookie 的超时时间进行处理,然后发送未经 URL 编码的 cookie ,但是 cookie 中的值按照 RFC 3986 对 URL 进行编码。
  • 本章到此结束,下一章继续学习源文件 install.php

    • 本章继续学习\Typecho\Common::init()方法
     // 源文件 /var/Typecho/Common.php
    191 /**
    192 * 程序初始化方法
    193 *
    194 * @access public
    195 * @return void
    196 */
    197 public static function init()
    198 {
    199    // init response
    200    Response::getInstance()->enableAutoSendHeaders(false);
    201 
    202    ob_start(function ($content) {
    203        Response::getInstance()->sendHeaders();
    204        return $content;
    205    });
    206 
    207    /** 设置异常截获函数 */
    208    set_exception_handler(function (\Throwable $exception) {
    209        echo '<pre><code>';
    210        echo '<h1>' . htmlspecialchars($exception->getMessage()) . '</h1>';
    211        echo htmlspecialchars($exception->__toString());
    212        echo '</code></pre>';
    213        exit;
    214    });
    215 }
    
    • 第197行:函数或方法定义。
    • 第198、215行:大括号内包含函数代码段。
    • 第200行:Response::getInstance()返回一个Response类的实例,->enableAutoSendHeaders(false)调用实例类中的函数。此函数做了什么操作请看下面两段代码的注释。
    • 第202~205行:此函数将打开输出缓冲。当输出缓冲激活后,脚本将不会输出内容(消息头除外),相反需要输出的内容被存储在内部缓冲区中。
    • 第208行:设置默认的异常处理程序,用于没有用 try/catch 块来捕获的异常。
    • 第209~212行:输入异常消息。
    • 第213行:退出程序,不再执行后面的代码。
     // 源文件 /var/Typecho/Response.php
    107    /**
    108     * @var bool
    109     */
    110    private $enableAutoSendHeaders = true;
    
    • 第110行:给私有变量 $enableAutoSendHeaders 赋值为 true 了。
     // 源文件 /var/Typecho/Response.php
    157    /**
    158     * @param bool $enable
    159     */
    160    public function enableAutoSendHeaders(bool $enable = true)
    161    {
    162        $this->enableAutoSendHeaders = $enable;
    163    }
    
    • 第162行:上面第200行代码传了一个参数 false 过来,看此行代码可知是给私有变量 $enableAutoSendHeaders 赋值为 false 了。

    本章到此结束,下一章学习上面第203行的函数 Response::getInstance()->sendHeaders() 做了些什么事情。

    • 上一章学习了源文件index.php中第1到16行,本章学习源文件install.php中第1到24行。
    // 源文件install.php
     1 <?php
     2
     3 if (!file_exists(dirname(__FILE__) . '/config.inc.php')) {
     4     // site root path
     5     define('__TYPECHO_ROOT_DIR__', dirname(__FILE__));
     6
     7     // plugin directory (relative path)
     8     define('__TYPECHO_PLUGIN_DIR__', '/usr/plugins');
     9
    10     // theme directory (relative path)
    11     define('__TYPECHO_THEME_DIR__', '/usr/themes');
    12
    13     // admin directory (relative path)
    14     define('__TYPECHO_ADMIN_DIR__', '/admin/');
    15
    16     // register autoload
    17     require_once __TYPECHO_ROOT_DIR__ . '/var/Typecho/Common.php';
    18 
    19     // init
    20     \Typecho\Common::init();
    21 } else {
    22     require_once dirname(__FILE__) . '/config.inc.php';
    23     $installDb = \Typecho\Db::get();
    24 }
    
    • 第1行:PHP标记。
    • 第3行:if控制语句,判断文件'/config.inc.php'是否存在,如果不存在就执行第4~20行代码。
    • 第4、7、10、13、16、19行:单行注释。
    • 第5行:定义常量'__TYPECHO_ROOT_DIR__'并赋值为当前文件所在的目录。
    • 第8、11、14行:定义常量。
    • 第17行:只包含一次文件'./var/Typecho/Common.php'
    • 第20行:调用或执行 命名空间 Typecho 中的 类 Common 中的 函数或方法 init()
    • 第21行:否则就执行第22~24行代码。
    • 第22行:只包含一次文件'./config.inc.php'
    • 第23行:给变量 $installDb 赋值为 命名空间 Typecho 中的 类 Db 中的 函数或方法 get() 的返回值。

    本章结束,下一章继续学习方法 \Typecho\Common::init()