Typechoソース分析(2)


目次
  • 前情提要
  • インストールプロセス
  • に進む.
  • インストール第1ステップ
  • は構成
  • に入る.
  • 来`start`
  • 結語
  • 前情提要
    前回はinstall.phpファイルのset_include_pathを分析した.今日は続けます.
    インストールプロセスに入るTypecho/Common.phpの導入に来たので、不思議かもしれませんが、このディレクトリが見つからないのではないでしょうか.いくつかの導入経路が設定されていることを忘れないでください.だから、一つ一つ探して、最後にvarディレクトリの下で、Typecho/Common.phpを見つけます.この方法で導入するのを見てください.書類を探しても扱いにくいです.そのため、ネーミングスペースなどがますます重要になり、set_include_pathという導入案も徐々に減少していきます.
    次にTypecho_Common::init();という行のコードを実行する方法は、さっき導入したファイルで、この方法に入ります.
    /**
         *      
         *
         * @param $className
         */
        public static function __autoLoad($className)
        {
            @include_once str_replace(array('\\', '_'), '/', $className) . '.php';
        }
    
        /**
         *        
         *
         * @access public
         * @return void
         */
        public static function init()
        {
            /**          */
            spl_autoload_register(array('Typecho_Common', '__autoLoad'));
    
            /**   php6 */
            if (function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc()) {
                $_GET = self::stripslashesDeep($_GET);
                $_POST = self::stripslashesDeep($_POST);
                $_COOKIE = self::stripslashesDeep($_COOKIE);
    
                reset($_GET);
                reset($_POST);
                reset($_COOKIE);
            }
    
            /**          */
            set_exception_handler(array('Typecho_Common', 'exceptionHandle'));
        }
    

    まずif (function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc()) {の部分を見て、これはphp 5.4以降永遠にfalseに戻ったので、5.4以降は実行されません.古いバージョンであれば、この処理はいくつかのエスケープに反斜線のある文字を復元し、元の内容にすることです.そして残りの部分は自動ロードと異常処理関数を登録することです.自動ロードは私の前の文章を見て、自分で理解することができます.
    異常処理部は、debugであるか否かに応じた2種類の出力モードである.
    /**
         *       
         *
         * @access public
         * @param $exception      
         * @return void
         */
        public static function exceptionHandle($exception)
        {
            if (defined('__TYPECHO_DEBUG__')) {
                echo '
    '
    ;
    echo '' . htmlspecialchars($exception->getMessage()) . '';
    echo htmlspecialchars($exception->__toString());
    echo '';
    } else {
    @ob_end_clean();
    if (404 == $exception->getCode() && !empty(self::
    $exceptionHandle)) {
    $handleClass = self::$exceptionHandle;
    new $handleClass($exception);
    } else {
    self::error($exception);
    }
    }
    exit;
    }self::$exceptionHandleこれは の にまた します.EXceptionHandleがない はerrorメソッドが び され、エラー が われ、error_logが される
    /**
         *       
         *
         * @access public
         * @param mixed $exception     
         * @return void
         */
        public static function error($exception)
        {
            $isException = is_object($exception);
            $message = '';
    
            if ($isException) {
                $code = $exception->getCode();
                $message = $exception->getMessage();
            } else {
                $code = $exception;
            }
    
            $charset = self::$charset;
    
            if ($isException && $exception instanceof Typecho_Db_Exception) {
                $code = 500;
                @error_log($message);
    
                //        
                $message = 'Database Server Error';
    
                if ($exception instanceof Typecho_Db_Adapter_Exception) {
                    $code = 503;
                    $message = 'Error establishing a database connection';
                } else if ($exception instanceof Typecho_Db_Query_Exception) {
                    $message = 'Database Query Error';
                }
            } else {
                switch ($code) {
                    case 500:
                        $message = 'Server Error';
                        break;
    
                    case 404:
                        $message = 'Page Not Found';
                        break;
    
                    default:
                        $code = 'Error';
                        break;
                }
            }
    
    
            /**   http code */
            if (is_numeric($code) && $code > 200) {
                Typecho_Response::setStatus($code);
            }
    
            $message = nl2br($message);
    
            if (defined('__TYPECHO_EXCEPTION_FILE__')) {
                require_once __TYPECHO_EXCEPTION_FILE__;
            } else {
                echo
    <<<EOF
    
    
        
            {$charset}">
            <span class="token interpolation"><span class="token punctuation">{</span><span class="token variable">$code</span><span class="token punctuation">}</span></span>
            
        
        
            
    {$message}
    EOF; } exit; }

    ここまでinitメソッドは みで、install.phpファイルに って を けます.
    //          
    if (!empty($_GET) || !empty($_POST)) {
        if (empty($_SERVER['HTTP_REFERER'])) {
            exit;
        }
    
        $parts = parse_url($_SERVER['HTTP_REFERER']);
    	if (!empty($parts['port'])) {
            $parts['host'] = "{$parts['host']}:{$parts['port']}";
        }
    
        if (empty($parts['host']) || $_SERVER['HTTP_HOST'] != $parts['host']) {
            exit;
        }
    }
    

    これはドメイン をブロックします. えばiframeのネストされたページです. のために、refererが されたhostと しなければブロックしないと します.
    $options = new stdClass();
    $options->generator = 'Typecho ' . Typecho_Common::VERSION;
    list($soft, $currentVersion) = explode(' ', $options->generator);
    
    $options->software = $soft;
    $options->version = $currentVersion;
    
    list($prefixVersion, $suffixVersion) = explode('/', $currentVersion);
    
    /**      */
    $lang = _r('lang', Typecho_Cookie::get('__typecho_lang'));
    $langs = Widget_Options_General::getLangs();
    
    if (empty($lang) || (!empty($langs) && !isset($langs[$lang]))) {
        $lang = 'zh_CN';
    }
    
    if ('zh_CN' != $lang) {
        $dir = defined('__TYPECHO_LANG_DIR__') ? __TYPECHO_LANG_DIR__ : __TYPECHO_ROOT_DIR__ . '/usr/langs';
        Typecho_I18n::setLang($dir . '/' . $lang . '.mo');
    }
    
    Typecho_Cookie::set('__typecho_lang', $lang);
    

    セットアップバージョン、セットアップ 、ついでにcookieに を き みます.
    りの はインストールプロセスなので、ゆっくり してみましょう.まずインストールファイルの の についてお しします
    
    include 'admin/copyright.php';
    include 'admin/footer.php';
    ?>
    

    この2つのファイルはすべて のためです
     if(!defined('__TYPECHO_ADMIN__')) exit; ?>
    

    その を せずに したので、この2つの は たちが っている に します.
    <li if (!isset($_GET['finish']) && !isset($_GET['config'])) : ?> class="current" endif; ?>><span>1</span> _e('    '); ?></li>
            <li if (isset($_GET['config'])) : ?> class="current" endif; ?>><span>2</span> _e('     '); ?></li>
            <li if (isset($_GET['start'])) : ?> class="current" endif; ?>><span>3</span> _e('    '); ?></li>
            <li if (isset($_GET['finish'])) : ?> class="current" endif; ?>><span>4</span> _e('    '); ?></li>
    

    これがurlのパラメータ に づいて される _e_tはいずれも であり、echoは であり、もう1つは である. ですよ、startという は、 な では えませんよ. してこそ えます.
    インストールの のステップ
    いくつかの ファイルが されます. が ある は、 リストボックスが されますが、デフォルトでは は1つしかありません. に、 のステップをクリックすると、 のurlにジャンプし、configパラメータを します.
    へのアクセス
    のステップをクリックすると、 のステップに ります. するデータパラメータを し、 を した 、 のステップをクリックすると、postメソッドが のconfig URLにジャンプします.ここで な は、データベースのアダプタを すると、 するデータベースアダプタの ページを り えることです.また、ページロード にどのデータがサポートされているかを します.この2つのセグメントは のコードにあります.
    
                        $adapters = array('Mysql', 'Mysqli', 'Pdo_Mysql', 'SQLite', 'Pdo_SQLite', 'Pgsql', 'Pdo_Pgsql');
                        foreach ($adapters as $firstAdapter) {
                            if (_p($firstAdapter)) {
                                break;
                            }
                        }
                        $adapter = _r('dbAdapter', $firstAdapter);
                        $parts = explode('_', $adapter);
    
                        $type = $adapter == 'Mysqli' ? 'Mysql' : array_pop($parts);
                ?>
     require_once './install/' . $type . '.php'; ?>
    
    <script>
    var _select = document.config.dbAdapter;
    _select.onchange = function() {
        setTimeout("window.location.href = 'install.php?config&dbAdapter=" + this.value + "'; ",0);
    }
    </script>
    

    アダプタによって なるデータベース ページがロードされます.こちらではmysqlを しています.install/mysql.phpページに ります.sae、gae、baeなどの がたくさんあります.これらはすべてスキップして、 を ます.
      else: ?>
        <li>
            <label class="typecho-label" for="dbHost"> _e('     '); ?></label>
            <input type="text" class="text" name="dbHost" id="dbHost" value=""/>
            <p class="description"> _e('       "%s"', 'localhost'); ?></p>
        </li>
        <li>
            <label class="typecho-label" for="dbPort"> _e('     '); ?></label>
            <input type="text" class="text" name="dbPort" id="dbPort" value=""/>
            <p class="description"> _e('            ,        '); ?></p>
        </li>
        <li>
            <label class="typecho-label" for="dbUser"> _e('      '); ?></label>
            <input type="text" class="text" name="dbUser" id="dbUser" value="" />
            <p class="description"> _e('       "%s"', 'root'); ?></p>
        </li>
        <li>
            <label class="typecho-label" for="dbPassword"> _e('     '); ?></label>
            <input type="password" class="text" name="dbPassword" id="dbPassword" value="" />
        </li>
        <li>
            <label class="typecho-label" for="dbDatabase"> _e('    '); ?></label>
            <input type="text" class="text" name="dbDatabase" id="dbDatabase" value="" />
            <p class="description"> _e('         '); ?></p>
        </li>
    
      endif; ?>
    <input type="hidden" name="dbCharset" value="" />
    
        <li>
            <label class="typecho-label" for="dbCharset"> _e('     '); ?></label>
            <select name="dbCharset" id="dbCharset">
                <option value="utf8" if (_r('dbCharset') == 'utf8'): ?> selected endif; ?>>utf8</option>
                <option value="utf8mb4" if (_r('dbCharset') == 'utf8mb4'): ?> selected endif; ?>>utf8mb4</option>
            </select>
            <p class="description"> _e('   utf8mb4        MySQL 5.5.3   '); ?></p>
        </li>
    
        <li>
            <label class="typecho-label" for="dbEngine"> _e('     '); ?></label>
            <select name="dbEngine" id="dbEngine">
                <option value="MyISAM" if (_r('dbEngine') == 'MyISAM'): ?> selected endif; ?>>MyISAM</option>
                <option value="InnoDB" if (_r('dbEngine') == 'InnoDB'): ?> selected endif; ?>>InnoDB</option>
            </select>
        </li>
    

    これが たちが を す ですよ. を した 、postに のページを し、 の に ります.
    if (_r('created') && !file_exists('./config.inc.php')) {
                                        echo '

    '

    . _t(' , ') . ''; $success = false; } else { if (NULL == _r('userUrl')) { $success = false; echo '

    '

    . _t(' ') . ''; } else if (NULL == _r('userName')) { $success = false; echo '

    '

    . _t(' ') . ''; } else if (NULL == _r('userMail')) { $success = false; echo '

    '

    . _t(' ') . ''; } else if (32 < strlen(_r('userName'))) { $success = false; echo '

    '

    . _t(' , 32 ') . ''; } else if (200 < strlen(_r('userMail'))) { $success = false; echo '

    '

    . _t(' , 200 ') . ''; } }

    この はいくつかの に するものがあります. に わない はif (_r('created') && !file_exists('./config.inc.php')) {を えて します. してください. で しましょう.
    $_dbConfig = _rFrom('dbHost', 'dbUser', 'dbPassword', 'dbCharset', 'dbPort', 'dbDatabase', 'dbFile', 'dbDsn', 'dbEngine');
    
                                    $_dbConfig = array_filter($_dbConfig);
                                    $dbConfig = array();
                                    foreach ($_dbConfig as $key => $val) {
                                        $dbConfig[strtolower(substr($key, 2))] = $val;
                                    }
    
                                    //                 
                                    if (_r('config')) {
                                        $replace = array_keys($dbConfig);
                                        foreach ($replace as &$key) {
                                            $key = '{' . $key . '}';
                                        }
    
                                        if (!empty($_dbConfig['dbDsn'])) {
                                            $dbConfig['dsn'] = str_replace($replace, array_values($dbConfig), $dbConfig['dsn']);
                                        }
                                        $config = str_replace($replace, array_values($dbConfig), _r('config'));
                                    }
    
                                    if (!isset($config) && $success && !_r('created')) {
                                        $installDb = new Typecho_Db($adapter, _r('dbPrefix'));
                                        $installDb->addServer($dbConfig, Typecho_Db::READ | Typecho_Db::WRITE);
    
    
                                        /**         */
                                        try {
                                            $installDb->query('SELECT 1=1');
                                        } catch (Typecho_Db_Adapter_Exception $e) {
                                            $success = false;
                                            echo '

    '

    . _t(' , , ') . ''; } catch (Typecho_Db_Exception $e) { $success = false; echo '

    '

    . _t(' : " %s ". , .',$e->getMessage()) . ''; } }

    これはデータベース の を して、それからデータベースに して、データベース のコードはtypecho のパッケージで、みんなは で ることができて、すごいです. に すると、エラーが します. したら、データベース をリセットします.これは インストールに するはずです.その 、cookieがデータベース を き む
    //          
                                        if (isset($installDb)) {
                                            try {
                                                $installDb->query($installDb->update('table.options')
                                                    ->rows(array('value' => 0))->where('name = ?', 'installed'));
                                            } catch (Exception $e) {
                                                // do nothing
                                            }
                                        }
    
                                        Typecho_Cookie::set('__typecho_config', base64_encode(serialize(array_merge(array(
                                            'prefix'    =>  _r('dbPrefix'),
                                            'userName'  =>  _r('userName'),
                                            'userPassword'  =>  _r('userPassword'),
                                            'userMail'  =>  _r('userMail'),
                                            'adapter'   =>  $adapter,
                                            'siteUrl'   =>  _r('userUrl')
                                        ), $dbConfig))));
    

    の に してください.
    if (_r('created')) {
                                            header('Location: ./install.php?start');
                                            exit;
                                        }
    

    これはどういう ですか. で そう
    /**         */
                                        $lines = array_slice(file(__FILE__), 1, 31);
                                        $lines[] = "
    /**         */
    \$db = new Typecho_Db('{$adapter}', '" . _r('dbPrefix') . "');
    \$db->addServer(" . (empty($config) ? var_export($dbConfig, true) : $config) . ", Typecho_Db::READ | Typecho_Db::WRITE);
    Typecho_Db::set(\$db);
    ";
                                        $contents = implode('', $lines);
                                        if (!Typecho_Common::isAppEngine()) {
                                            @file_put_contents('./config.inc.php', $contents);
                                        }
    

    このセクションはプロファイルに き まれます.
    if (!file_exists('./config.inc.php')) {
                                        ?>
    <div class="message notice"><p> _e('           config.inc.php   '); ?><br />
     _e('               config.inc.php   ,           '); ?></p>
    <p><textarea rows="5" onmouseover="this.select();" class="w-100 mono" readonly> echo htmlspecialchars($contents); ?></textarea></p>
    <p><button name="created" value="1" type="submit" class="btn primary">    ,      &raquo;</button></p></div>
                                        
                                        } else {
                                            header('Location: ./install.php?start');
                                            exit;
                                        }
    

    ファイルの き みに すると、 のページにジャンプしてcreatedパラメータを し、 のステップの に します. き みに すると、startにジャンプします.
    //            
                                    if(!$success && file_exists(__TYPECHO_ROOT_DIR__ . '/config.inc.php')) {
                                        @unlink(__TYPECHO_ROOT_DIR__ . '/config.inc.php');
                                    }
    

    インストールに したら、ファイルを します.start
    この は な に した.
    require_once dirname(__FILE__) . '/config.inc.php';
    
    //        
    $db = Typecho_Db::get();
    try {
        $installed = $db->fetchRow($db->select()->from('table.options')->where('name = ?', 'installed'));
        if (empty($installed) || $installed['value'] == 1) {
            Typecho_Response::setStatus(404);
            exit;
        }
    } catch (Exception $e) {
        // do nothing
    }
    

    これは の り、プロファイルが まれている はデータベースにリンクし、インストールされているかどうかを し、インストールされている は404とエラーを します.
     if (!isset($db)) : ?>
                    <h1 class="typecho-install-title"> _e('    !'); ?></h1>
                    <div class="typecho-install-body">
                        <form method="post" action="?config" name="config">
                        <p class="message error"> _e('      config.inc.php   ,       !'); ?> <button class="btn primary" type="submit"> _e('     »'); ?></button></p>
                        </form>
                    </div>
                     else : ?>
    
    dbが されていなければ、エラーが されます.すべてがうまくいけば、データベースの を し、プロファイルを します. した はインストール を し、 した はジャンプし、インストールに します.インストールプロセスのページが えないというのは、 すぎるので してしまいますが、 の がはっきりしていませんので、ここで します.
     if(('Mysql' == $type && (1050 == $code || '42S01' == $code)) ||
                                            ('SQLite' == $type && ('HY000' == $code || 1 == $code)) ||
                                            ('Pgsql' == $type && '42P07' == $code)) {
                                                if(_r('delete')) {
                                                    //      
                                                    $dbPrefix = $config['prefix'];
                                                    $tableArray = array($dbPrefix . 'comments', $dbPrefix . 'contents', $dbPrefix . 'fields', $dbPrefix . 'metas', $dbPrefix . 'options', $dbPrefix . 'relationships', $dbPrefix . 'users',);
                                                    foreach($tableArray as $table) {
                                                        if($type == 'Mysql') {
                                                            $installDb->query("DROP TABLE IF EXISTS `{$table}`");
                                                        } elseif($type == 'Pgsql') {
                                                            $installDb->query("DROP TABLE {$table}");
                                                        } elseif($type == 'SQLite') {
                                                            $installDb->query("DROP TABLE {$table}");
                                                        }
                                                    }
                                                    echo '

    '

    . _t(' ') . '

    . _t(' »') . ''; } elseif (_r('goahead')) { // // $installDb->query($installDb->update('table.options')->rows(array('value' => $config['siteUrl']))->where('name = ?', 'siteUrl')); unset($_SESSION['typecho']); header('Location: ./install.php?finish&use_old'); exit; } else { echo '

    '

    . _t(' .') . '

    '
    . ' . _t(' ') . ' ' . _t(' ') . ' . _t(' ') . ''; }

    これが にデータベースが する の である.ライブラリを したり、 のデータベースを したりして、 、インストールプロセスを します.
    めくくり
    これで、インストールはすべて しました. たちはインストールモジュールを しました. に を いますか.フロント、 、 に していないdb 、 にバックグラウンドを します.また ね