| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489 | <?phpif (!file_exists(dirname(__FILE__) . '/config.inc.php')) {    // site root path    define('__TYPECHO_ROOT_DIR__', dirname(__FILE__));    // plugin directory (relative path)    define('__TYPECHO_PLUGIN_DIR__', '/usr/plugins');    // theme directory (relative path)    define('__TYPECHO_THEME_DIR__', '/usr/themes');    // admin directory (relative path)    define('__TYPECHO_ADMIN_DIR__', '/admin/');    // register autoload    require_once __TYPECHO_ROOT_DIR__ . '/var/Typecho/Common.php';    // init    \Typecho\Common::init();} else {    require_once dirname(__FILE__) . '/config.inc.php';    $installDb = \Typecho\Db::get();}/** * get lang * * @return string */function install_get_lang(): string{    $serverLang = \Typecho\Request::getInstance()->getServer('TYPECHO_LANG');    if (!empty($serverLang)) {        return $serverLang;    } else {        $lang = 'zh_CN';        $request = \Typecho\Request::getInstance();        if ($request->is('lang')) {            $lang = $request->get('lang');            \Typecho\Cookie::set('lang', $lang);        }        return \Typecho\Cookie::get('lang', $lang);    }}/** * get site url * * @return string */function install_get_site_url(): string{    $request = \Typecho\Request::getInstance();    return install_is_cli() ? $request->getServer('TYPECHO_SITE_URL', 'http://localhost') : $request->getRequestRoot();}/** * detect cli mode * * @return bool */function install_is_cli(): bool{    return \Typecho\Request::getInstance()->isCli();}/** * get default router * * @return string[][] */function install_get_default_routers(): array{    return [        'index'              =>            [                'url'    => '/',                'widget' => '\Widget\Archive',                'action' => 'render',            ],        'archive'            =>            [                'url'    => '/blog/',                'widget' => '\Widget\Archive',                'action' => 'render',            ],        'do'                 =>            [                'url'    => '/action/[action:alpha]',                'widget' => '\Widget\Action',                'action' => 'action',            ],        'post'               =>            [                'url'    => '/archives/[cid:digital]/',                'widget' => '\Widget\Archive',                'action' => 'render',            ],        'attachment'         =>            [                'url'    => '/attachment/[cid:digital]/',                'widget' => '\Widget\Archive',                'action' => 'render',            ],        'category'           =>            [                'url'    => '/category/[slug]/',                'widget' => '\Widget\Archive',                'action' => 'render',            ],        'tag'                =>            [                'url'    => '/tag/[slug]/',                'widget' => '\Widget\Archive',                'action' => 'render',            ],        'author'             =>            [                'url'    => '/author/[uid:digital]/',                'widget' => '\Widget\Archive',                'action' => 'render',            ],        'search'             =>            [                'url'    => '/search/[keywords]/',                'widget' => '\Widget\Archive',                'action' => 'render',            ],        'index_page'         =>            [                'url'    => '/page/[page:digital]/',                'widget' => '\Widget\Archive',                'action' => 'render',            ],        'archive_page'       =>            [                'url'    => '/blog/page/[page:digital]/',                'widget' => '\Widget\Archive',                'action' => 'render',            ],        'category_page'      =>            [                'url'    => '/category/[slug]/[page:digital]/',                'widget' => '\Widget\Archive',                'action' => 'render',            ],        'tag_page'           =>            [                'url'    => '/tag/[slug]/[page:digital]/',                'widget' => '\Widget\Archive',                'action' => 'render',            ],        'author_page'        =>            [                'url'    => '/author/[uid:digital]/[page:digital]/',                'widget' => '\Widget\Archive',                'action' => 'render',            ],        'search_page'        =>            [                'url'    => '/search/[keywords]/[page:digital]/',                'widget' => '\Widget\Archive',                'action' => 'render',            ],        'archive_year'       =>            [                'url'    => '/[year:digital:4]/',                'widget' => '\Widget\Archive',                'action' => 'render',            ],        'archive_month'      =>            [                'url'    => '/[year:digital:4]/[month:digital:2]/',                'widget' => '\Widget\Archive',                'action' => 'render',            ],        'archive_day'        =>            [                'url'    => '/[year:digital:4]/[month:digital:2]/[day:digital:2]/',                'widget' => '\Widget\Archive',                'action' => 'render',            ],        'archive_year_page'  =>            [                'url'    => '/[year:digital:4]/page/[page:digital]/',                'widget' => '\Widget\Archive',                'action' => 'render',            ],        'archive_month_page' =>            [                'url'    => '/[year:digital:4]/[month:digital:2]/page/[page:digital]/',                'widget' => '\Widget\Archive',                'action' => 'render',            ],        'archive_day_page'   =>            [                'url'    => '/[year:digital:4]/[month:digital:2]/[day:digital:2]/page/[page:digital]/',                'widget' => '\Widget\Archive',                'action' => 'render',            ],        'comment_page'       =>            [                'url'    => '[permalink:string]/comment-page-[commentPage:digital]',                'widget' => '\Widget\Archive',                'action' => 'render',            ],        'feed'               =>            [                'url'    => '/feed[feed:string:0]',                'widget' => '\Widget\Archive',                'action' => 'feed',            ],        'feedback'           =>            [                'url'    => '[permalink:string]/[type:alpha]',                'widget' => '\Widget\Feedback',                'action' => 'action',            ],        'page'               =>            [                'url'    => '/[slug].html',                'widget' => '\Widget\Archive',                'action' => 'render',            ],    ];}/** * list all default options * * @return array */function install_get_default_options(): array{    static $options;    if (empty($options)) {        $options = [            'theme' => 'default',            'theme:default' => 'a:2:{s:7:"logoUrl";N;s:12:"sidebarBlock";a:5:{i:0;s:15:"ShowRecentPosts";i:1;s:18:"ShowRecentComments";i:2;s:12:"ShowCategory";i:3;s:11:"ShowArchive";i:4;s:9:"ShowOther";}}',            'timezone' => '28800',            'lang' => install_get_lang(),            'charset' => 'UTF-8',            'contentType' => 'text/html',            'gzip' => 0,            'generator' => 'Typecho ' . \Typecho\Common::VERSION,            'title' => 'Hello World',            'description' => 'Your description here.',            'keywords' => 'typecho,php,blog',            'rewrite' => 0,            'frontPage' => 'recent',            'frontArchive' => 0,            'commentsRequireMail' => 1,            'commentsWhitelist' => 0,            'commentsRequireURL' => 0,            'commentsRequireModeration' => 0,            'plugins' => 'a:0:{}',            'commentDateFormat' => 'F jS, Y \a\t h:i a',            'siteUrl' => install_get_site_url(),            'defaultCategory' => 1,            'allowRegister' => 0,            'defaultAllowComment' => 1,            'defaultAllowPing' => 1,            'defaultAllowFeed' => 1,            'pageSize' => 5,            'postsListSize' => 10,            'commentsListSize' => 10,            'commentsHTMLTagAllowed' => null,            'postDateFormat' => 'Y-m-d',            'feedFullText' => 1,            'editorSize' => 350,            'autoSave' => 0,            'markdown' => 1,            'xmlrpcMarkdown' => 0,            'commentsMaxNestingLevels' => 5,            'commentsPostTimeout' => 24 * 3600 * 30,            'commentsUrlNofollow' => 1,            'commentsShowUrl' => 1,            'commentsMarkdown' => 0,            'commentsPageBreak' => 0,            'commentsThreaded' => 1,            'commentsPageSize' => 20,            'commentsPageDisplay' => 'last',            'commentsOrder' => 'ASC',            'commentsCheckReferer' => 1,            'commentsAutoClose' => 0,            'commentsPostIntervalEnable' => 1,            'commentsPostInterval' => 60,            'commentsShowCommentOnly' => 0,            'commentsAvatar' => 1,            'commentsAvatarRating' => 'G',            'commentsAntiSpam' => 1,            'routingTable' => serialize(install_get_default_routers()),            'actionTable' => 'a:0:{}',            'panelTable' => 'a:0:{}',            'attachmentTypes' => '@image@',            'secret' => \Typecho\Common::randString(32, true),            'installed' => 0,            'allowXmlRpc' => 2        ];    }    return $options;}/** * get database driver type * * @param string $driver * @return string */function install_get_db_type(string $driver): string{    $parts = explode('_', $driver);    return $driver == 'Mysqli' ? 'Mysql' : array_pop($parts);}/** * list all available database drivers * * @return array */function install_get_db_drivers(): array{    $drivers = [];    if (\Typecho\Db\Adapter\Pdo\Mysql::isAvailable()) {        $drivers['Pdo_Mysql'] = _t('Pdo 驱动 Mysql 适配器');    }    if (\Typecho\Db\Adapter\Pdo\SQLite::isAvailable()) {        $drivers['Pdo_SQLite'] = _t('Pdo 驱动 SQLite 适配器');    }    if (\Typecho\Db\Adapter\Pdo\Pgsql::isAvailable()) {        $drivers['Pdo_Pgsql'] = _t('Pdo 驱动 PostgreSql 适配器');    }    if (\Typecho\Db\Adapter\Mysqli::isAvailable()) {        $drivers['Mysqli'] = _t('Mysql 原生函数适配器');    }    if (\Typecho\Db\Adapter\SQLite::isAvailable()) {        $drivers['SQLite'] = _t('SQLite 原生函数适配器');    }    if (\Typecho\Db\Adapter\Pgsql::isAvailable()) {        $drivers['Pgsql'] = _t('Pgsql 原生函数适配器');    }    return $drivers;}/** * get current db driver * * @return string */function install_get_current_db_driver(): string{    global $installDb;    if (empty($installDb)) {        $driver = \Typecho\Request::getInstance()->get('driver');        $drivers = install_get_db_drivers();        if (empty($driver) || !isset($drivers[$driver])) {            return key($drivers);        }        return $driver;    } else {        return $installDb->getAdapterName();    }}/** * generate config file * * @param string $adapter * @param string $dbPrefix * @param array $dbConfig * @param bool $return * @return string */function install_config_file(string $adapter, string $dbPrefix, array $dbConfig, bool $return = false): string{    global $configWritten;    $code = "<" . "?php// site root pathdefine('__TYPECHO_ROOT_DIR__', dirname(__FILE__));// plugin directory (relative path)define('__TYPECHO_PLUGIN_DIR__', '/usr/plugins');// theme directory (relative path)define('__TYPECHO_THEME_DIR__', '/usr/themes');// admin directory (relative path)define('__TYPECHO_ADMIN_DIR__', '/admin/');// register autoloadrequire_once __TYPECHO_ROOT_DIR__ . '/var/Typecho/Common.php';// init\Typecho\Common::init();// config db\$db = new \Typecho\Db('{$adapter}', '{$dbPrefix}');\$db->addServer(" . (var_export($dbConfig, true)) . ", \Typecho\Db::READ | \Typecho\Db::WRITE);\Typecho\Db::set(\$db);";    $configWritten = false;    if (!$return) {        $configWritten = @file_put_contents(__TYPECHO_ROOT_DIR__ . '/config.inc.php', $code) !== false;    }    return $code;}/** * remove config file if written */function install_remove_config_file(){    global $configWritten;    if ($configWritten) {        unlink(__TYPECHO_ROOT_DIR__ . '/config.inc.php');    }}/** * check install * * @param string $type * @return bool */function install_check(string $type): bool{    switch ($type) {        case 'config':            return file_exists(__TYPECHO_ROOT_DIR__ . '/config.inc.php');        case 'db_structure':        case 'db_data':            global $installDb;            if (empty($installDb)) {                return false;            }            try {                // check if table exists                $installed = $installDb->fetchRow($installDb->select()->from('table.options')                    ->where('user = 0 AND name = ?', 'installed'));                if ($type == 'db_data' && empty($installed['value'])) {                    return false;                }            } catch (\Typecho\Db\Adapter\ConnectionException $e) {                return true;            } catch (\Typecho\Db\Adapter\SQLException $e) {                return false;            }            return true;        default:            return false;    }}/** * raise install error * * @param mixed $error * @param mixed $config */function install_raise_error($error, $config = null){    if (install_is_cli()) {        if (is_array($error)) {            foreach ($error as $key => $value) {                echo (is_int($key) ? '' : $key . ': ') . $value . "\n";            }        } else {            echo $error . "\n";        }        exit(1);    } else {        install_throw_json([            'success' => 0,            'message' => is_string($error) ? nl2br($error) : $error,            'config' => $config        ]);    }}/** * @param $step * @param array|null $config */function install_success($step, ?array $config = null){    global $installDb;    if (install_is_cli()) {        if ($step == 3) {            \Typecho\Db::set($installDb);        }        if ($step > 0) {            $method = 'install_step_' . $step . '_perform';            $method();        }        if (!empty($config)) {            [$userName, $userPassword] = $config;            echo _t('安装成功') . "\n";            echo _t('您的用户名是') . " {$userName}\n";            echo _t('您的密码是') . " {$userPassword}\n";        }        exit(0);    } else {        install_throw_json([            'success' => 1,            'message' => $step,            'config'  => $config        ]);    }}/** * @param $data */function install_throw_json($data){    \Typecho\Response::getInstance()->setContentType('application/json')        ->addResponder(function () use ($data) {            echo json_encode($data);        })        ->respond();}/** * @param string $url */function install_redirect(string $url){    \Typecho\Response::getInstance()->setStatus(302)        ->setHeader('Location', $url)        ->respond();}/** * add common js support */function install_js_support(){    ?>    <div id="success" class="row typecho-page-main hidden">        <div class="col-mb-12 col-tb-8 col-tb-offset-2">            <div class="typecho-page-title">                <h2><?php _e('安装成功'); ?></h2>            </div>            <div id="typecho-welcome">                <p class="keep-word">                    <?php _e('您选择了使用原有的数据, 您的用户名和密码和原来的一致'); ?>                </p>                <p class="fresh-word">                    <?php _e('您的用户名是'); ?>: <strong class="warning" id="success-user"></strong><br>                    <?php _e('您的密码是'); ?>: <strong class="warning" id="success-password"></strong>                </p>                <ul>                    <li><a id="login-url" href=""><?php _e('点击这里访问您的控制面板'); ?></a></li>                    <li><a id="site-url" href=""><?php _e('点击这里查看您的 Blog'); ?></a></li>                </ul>                <p><?php _e('希望您能尽情享用 Typecho 带来的乐趣!'); ?></p>            </div>        </div>    </div>    <script>        let form = $('form'), errorBox = $('<div></div>');        errorBox.addClass('message error')            .prependTo(form);        function showError(error) {            if (typeof error == 'string') {                $(window).scrollTop(0);                errorBox                    .html(error)                    .addClass('fade');            } else {                for (let k in error) {                    let input = $('#' + k), msg = error[k], p = $('<p></p>');                    p.addClass('message error')                        .html(msg)                        .insertAfter(input);                    input.on('input', function () {                        p.remove();                    });                }            }            return errorBox;        }        form.submit(function (e) {            e.preventDefault();            errorBox.removeClass('fade');            $('button', form).attr('disabled', 'disabled');            $('.typecho-option .error', form).remove();            $.ajax({                url: form.attr('action'),                processData: false,                contentType: false,                type: 'POST',                data: new FormData(this),                success: function (data) {                    $('button', form).removeAttr('disabled');                    if (data.success) {                        if (data.message) {                            location.href = '?step=' + data.message;                        } else {                            let success = $('#success').removeClass('hidden');                            form.addClass('hidden');                            if (data.config) {                                success.addClass('fresh');                                $('.typecho-page-main:first').addClass('hidden');                                $('#success-user').html(data.config[0]);                                $('#success-password').html(data.config[1]);                                $('#login-url').attr('href', data.config[2]);                                $('#site-url').attr('href', data.config[3]);                            } else {                                success.addClass('keep');                            }                        }                    } else {                        let el = showError(data.message);                        if (typeof configError == 'function' && data.config) {                            configError(form, data.config, el);                        }                    }                },                error: function (xhr, error) {                    showError(error)                }            });        });    </script>    <?php}/** * @param string[] $extensions * @return string|null */function install_check_extension(array $extensions): ?string{    foreach ($extensions as $extension) {        if (extension_loaded($extension)) {            return null;        }    }    return _n('缺少PHP扩展', '请在服务器上安装以下PHP扩展中的至少一个', count($extensions))        . ': ' . implode(', ', $extensions);}function install_step_1(){    $langs = \Widget\Options\General::getLangs();    $lang = install_get_lang();    ?>    <div class="row typecho-page-main">        <div class="col-mb-12 col-tb-8 col-tb-offset-2">            <div class="typecho-page-title">                <h2><?php _e('欢迎使用 Typecho'); ?></h2>            </div>            <div id="typecho-welcome">                <form autocomplete="off" method="post" action="install.php">                    <h3><?php _e('安装说明'); ?></h3>                    <p class="warning">                        <strong><?php _e('本安装程序将自动检测服务器环境是否符合最低配置需求. 如果不符合, 将在上方出现提示信息, 请按照提示信息检查您的主机配置. 如果服务器环境符合要求, 将在下方出现 "开始下一步" 的按钮, 点击此按钮即可一步完成安装.'); ?></strong>                    </p>                    <h3><?php _e('许可及协议'); ?></h3>                    <ul>                        <li><?php _e('Typecho 基于 <a href="https://www.gnu.org/copyleft/gpl.html">GPL</a> 协议发布, 我们允许用户在 GPL 协议许可的范围内使用, 拷贝, 修改和分发此程序.'); ?>                            <?php _e('在GPL许可的范围内, 您可以自由地将其用于商业以及非商业用途.'); ?></li>                        <li><?php _e('Typecho 软件由其社区提供支持, 核心开发团队负责维护程序日常开发工作以及新特性的制定.'); ?>                            <?php _e('如果您遇到使用上的问题, 程序中的 BUG, 以及期许的新功能, 欢迎您在社区中交流或者直接向我们贡献代码.'); ?>                            <?php _e('对于贡献突出者, 他的名字将出现在贡献者名单中.'); ?></li>                    </ul>                    <p class="submit">                        <button class="btn primary" type="submit"><?php _e('我准备好了, 开始下一步 »'); ?></button>                        <input type="hidden" name="step" value="1">                        <?php if (count($langs) > 1) : ?>                            <select style="float: right" onchange="location.href='?lang=' + this.value">                                <?php foreach ($langs as $key => $val) : ?>                                    <option value="<?php echo $key; ?>"<?php if ($lang == $key) :                                        ?> selected<?php                                                   endif; ?>><?php echo $val; ?></option>                                <?php endforeach; ?>                            </select>                        <?php endif; ?>                    </p>                </form>            </div>        </div>    </div>    <?php    install_js_support();}/** * check dependencies before install */function install_step_1_perform(){    $errors = [];    $checks = [        'mbstring',        'json',        'Reflection',        ['mysqli', 'sqlite3', 'pgsql', 'pdo_mysql', 'pdo_sqlite', 'pdo_pgsql']    ];    foreach ($checks as $check) {        $error = install_check_extension(is_array($check) ? $check : [$check]);        if (!empty($error)) {            $errors[] = $error;        }    }    $uploadDir = '/usr/uploads';    $realUploadDir = \Typecho\Common::url($uploadDir, __TYPECHO_ROOT_DIR__);    $writeable = true;    if (is_dir($realUploadDir)) {        if (!is_writeable($realUploadDir) || !is_readable($realUploadDir)) {            if (!@chmod($realUploadDir, 0755)) {                $writeable = false;            }        }    } else {        if (!@mkdir($realUploadDir, 0755)) {            $writeable = false;        }    }    if (!$writeable) {        $errors[] = _t('上传目录无法写入, 请手动将安装目录下的 %s 目录的权限设置为可写然后继续升级', $uploadDir);    }    if (empty($errors)) {        install_success(2);    } else {        install_raise_error(implode("\n", $errors));    }}/** * display step 2 */function install_step_2(){    global $installDb;    $drivers = install_get_db_drivers();    $adapter = install_get_current_db_driver();    $type = install_get_db_type($adapter);    if (!empty($installDb)) {        $config = $installDb->getConfig(\Typecho\Db::WRITE)->toArray();        $config['prefix'] = $installDb->getPrefix();        $config['adapter'] = $adapter;    }    ?>    <div class="row typecho-page-main">        <div class="col-mb-12 col-tb-8 col-tb-offset-2">            <div class="typecho-page-title">                <h2><?php _e('初始化配置'); ?></h2>            </div>            <form autocomplete="off" action="install.php" method="post">                <ul class="typecho-option">                    <li>                        <label for="dbAdapter" class="typecho-label"><?php _e('数据库适配器'); ?></label>                        <select name="dbAdapter" id="dbAdapter" onchange="location.href='?step=2&driver=' + this.value">                            <?php foreach ($drivers as $driver => $name) : ?>                                <option value="<?php echo $driver; ?>"<?php if ($driver == $adapter) :                                    ?> selected="selected"<?php                                               endif; ?>><?php echo $name; ?></option>                            <?php endforeach; ?>                        </select>                        <p class="description"><?php _e('请根据您的数据库类型选择合适的适配器'); ?></p>                        <input type="hidden" id="dbNext" name="dbNext" value="none">                    </li>                </ul>                <ul class="typecho-option">                    <li>                        <label class="typecho-label" for="dbPrefix"><?php _e('数据库前缀'); ?></label>                        <input type="text" class="text" name="dbPrefix" id="dbPrefix" value="typecho_" />                        <p class="description"><?php _e('默认前缀是 "typecho_"'); ?></p>                    </li>                </ul>                <?php require_once './install/' . $type . '.php'; ?>                <ul class="typecho-option typecho-option-submit">                    <li>                        <button id="confirm" type="submit" class="btn primary"><?php _e('确认, 开始安装 »'); ?></button>                        <input type="hidden" name="step" value="2">                    </li>                </ul>            </form>        </div>    </div>    <script>        function configError(form, config, errorBox) {            let next = $('#dbNext'),                line = $('<p></p>');            if (config.code) {                let text = $('<textarea></textarea>'),                    btn = $('<button></button>');                btn.html('<?php _e('创建完毕, 继续安装 »'); ?>')                    .attr('type', 'button')                    .addClass('btn btn-s primary');                btn.click(function () {                    next.val('config');                    form.trigger('submit');                });                text.val(config.code)                    .addClass('mono')                    .attr('readonly', 'readonly');                errorBox.append(text)                    .append(btn);                return;            }            errorBox.append(line);            for (let key in config) {                let word = config[key],                    btn = $('<button></button>');                btn.html(word)                    .attr('type', 'button')                    .addClass('btn btn-s primary')                    .click(function () {                        next.val(key);                        form.trigger('submit');                    });                line.append(btn);            }        }        $('#confirm').click(function () {            $('#dbNext').val('none');        });        <?php if (!empty($config)) : ?>        function fillInput(config) {            for (let k in config) {                let value = config[k],                    key = 'db' + k.charAt(0).toUpperCase() + k.slice(1),                    input = $('#' + key)                        .attr('readonly', 'readonly')                        .val(value);                $('option:not(:selected)', input).attr('disabled', 'disabled');            }        }        fillInput(<?php echo json_encode($config); ?>);        <?php endif; ?>    </script>    <?php    install_js_support();}/** * perform install step 2 */function install_step_2_perform(){    global $installDb;    $request = \Typecho\Request::getInstance();    $drivers = install_get_db_drivers();    $configMap = [        'Mysql' => [            'dbHost' => 'localhost',            'dbPort' => 3306,            'dbUser' => null,            'dbPassword' => null,            'dbCharset' => 'utf8mb4',            'dbDatabase' => null,            'dbEngine' => 'InnoDB',            'dbSslCa' => null,            'dbSslVerify' => 'on',        ],        'Pgsql' => [            'dbHost' => 'localhost',            'dbPort' => 5432,            'dbUser' => null,            'dbPassword' => null,            'dbCharset' => 'utf8',            'dbDatabase' => null,        ],        'SQLite' => [            'dbFile' => __TYPECHO_ROOT_DIR__ . '/usr/' . uniqid() . '.db'        ]    ];    if (install_is_cli()) {        $config = [            'dbHost' => $request->getServer('TYPECHO_DB_HOST'),            'dbUser' => $request->getServer('TYPECHO_DB_USER'),            'dbPassword' => $request->getServer('TYPECHO_DB_PASSWORD'),            'dbCharset' => $request->getServer('TYPECHO_DB_CHARSET'),            'dbPort' => $request->getServer('TYPECHO_DB_PORT'),            'dbDatabase' => $request->getServer('TYPECHO_DB_DATABASE'),            'dbFile' => $request->getServer('TYPECHO_DB_FILE'),            'dbDsn' => $request->getServer('TYPECHO_DB_DSN'),            'dbEngine' => $request->getServer('TYPECHO_DB_ENGINE'),            'dbPrefix' => $request->getServer('TYPECHO_DB_PREFIX', 'typecho_'),            'dbAdapter' => $request->getServer('TYPECHO_DB_ADAPTER', install_get_current_db_driver()),            'dbNext' => $request->getServer('TYPECHO_DB_NEXT', 'none'),            'dbSslCa' => $request->getServer('TYPECHO_DB_SSL_CA'),            'dbSslVerify' => $request->getServer('TYPECHO_DB_SSL_VERIFY', 'on'),        ];    } else {        $config = $request->from([            'dbHost',            'dbUser',            'dbPassword',            'dbCharset',            'dbPort',            'dbDatabase',            'dbFile',            'dbDsn',            'dbEngine',            'dbPrefix',            'dbAdapter',            'dbNext',            'dbSslCa',            'dbSslVerify',        ]);    }    $error = (new \Typecho\Validate())        ->addRule('dbPrefix', 'required', _t('确认您的配置'))        ->addRule('dbPrefix', 'minLength', _t('确认您的配置'), 1)        ->addRule('dbPrefix', 'maxLength', _t('确认您的配置'), 16)        ->addRule('dbPrefix', 'alphaDash', _t('确认您的配置'))        ->addRule('dbAdapter', 'required', _t('确认您的配置'))        ->addRule('dbAdapter', 'enum', _t('确认您的配置'), array_keys($drivers))        ->addRule('dbNext', 'required', _t('确认您的配置'))        ->addRule('dbNext', 'enum', _t('确认您的配置'), ['none', 'delete', 'keep', 'config'])        ->run($config);    if (!empty($error)) {        install_raise_error($error);    }    $type = install_get_db_type($config['dbAdapter']);    $dbConfig = [];    foreach ($configMap[$type] as $key => $value) {        $config[$key] = !isset($config[$key]) ? (install_is_cli() ? $value : null) : $config[$key];    }    switch ($type) {        case 'Mysql':            $error = (new \Typecho\Validate())                ->addRule('dbHost', 'required', _t('确认您的配置'))                ->addRule('dbPort', 'required', _t('确认您的配置'))                ->addRule('dbPort', 'isInteger', _t('确认您的配置'))                ->addRule('dbUser', 'required', _t('确认您的配置'))                ->addRule('dbCharset', 'required', _t('确认您的配置'))                ->addRule('dbCharset', 'enum', _t('确认您的配置'), ['utf8', 'utf8mb4'])                ->addRule('dbDatabase', 'required', _t('确认您的配置'))                ->addRule('dbEngine', 'required', _t('确认您的配置'))                ->addRule('dbEngine', 'enum', _t('确认您的配置'), ['InnoDB', 'MyISAM'])                ->addRule('dbSslCa', 'file_exists', _t('确认您的配置'))                ->addRule('dbSslVerify', 'enum', _t('确认您的配置'), ['on', 'off'])                ->run($config);            break;        case 'Pgsql':            $error = (new \Typecho\Validate())                ->addRule('dbHost', 'required', _t('确认您的配置'))                ->addRule('dbPort', 'required', _t('确认您的配置'))                ->addRule('dbPort', 'isInteger', _t('确认您的配置'))                ->addRule('dbUser', 'required', _t('确认您的配置'))                ->addRule('dbCharset', 'required', _t('确认您的配置'))                ->addRule('dbCharset', 'enum', _t('确认您的配置'), ['utf8'])                ->addRule('dbDatabase', 'required', _t('确认您的配置'))                ->run($config);            break;        case 'SQLite':            $error = (new \Typecho\Validate())                ->addRule('dbFile', 'required', _t('确认您的配置'))                ->addRule('dbFile', function (string $path) {                    $pattern = "/^(\/[._a-z0-9-]+)*[a-z0-9]+\.[a-z0-9]{2,}$/i";                    if (strstr(PHP_OS, 'WIN')) {                        $pattern = "/(\/[._a-z0-9-]+)*[a-z0-9]+\.[a-z0-9]{2,}$/i";                    }                    return !!preg_match($pattern, $path);                }, _t('确认您的配置'))                ->run($config);            break;        default:            install_raise_error(_t('确认您的配置'));            break;    }    if (!empty($error)) {        install_raise_error($error);    }    foreach ($configMap[$type] as $key => $value) {        $dbConfig[lcfirst(substr($key, 2))] = $config[$key];    }    // intval port number    if (isset($dbConfig['port'])) {        $dbConfig['port'] = intval($dbConfig['port']);    }    // bool ssl verify    if (isset($dbConfig['sslVerify'])) {        $dbConfig['sslVerify'] = $dbConfig['sslVerify'] == 'on';    }    if (isset($dbConfig['file']) && preg_match("/^[a-z0-9]+\.[a-z0-9]{2,}$/i", $dbConfig['file'])) {        $dbConfig['file'] = __DIR__ . '/usr/' . $dbConfig['file'];    }    // check config file    if ($config['dbNext'] == 'config' && !install_check('config')) {        $code = install_config_file($config['dbAdapter'], $config['dbPrefix'], $dbConfig, true);        install_raise_error(_t('没有检测到您手动创建的配置文件, 请检查后再次创建'), ['code' => $code]);    } elseif (empty($installDb)) {        // detect db config        try {            $installDb = new \Typecho\Db($config['dbAdapter'], $config['dbPrefix']);            $installDb->addServer($dbConfig, \Typecho\Db::READ | \Typecho\Db::WRITE);            $installDb->query('SELECT 1=1');        } catch (\Typecho\Db\Adapter\ConnectionException $e) {            $code = $e->getCode();            if (('Mysql' == $type && 1049 == $code) || ('Pgsql' == $type && 7 == $code)) {                install_raise_error(_t('数据库: "%s"不存在,请手动创建后重试', $config['dbDatabase']));            } else {                install_raise_error(_t('对不起, 无法连接数据库, 请先检查数据库配置再继续进行安装: "%s"', $e->getMessage()));            }        } catch (\Typecho\Db\Exception $e) {            install_raise_error(_t('安装程序捕捉到以下错误: "%s". 程序被终止, 请检查您的配置信息.', $e->getMessage()));        }        $code = install_config_file($config['dbAdapter'], $config['dbPrefix'], $dbConfig);        if (!install_check('config')) {            install_raise_error(                _t('安装程序无法自动创建 <strong>config.inc.php</strong> 文件') . "\n" .                _t('您可以在网站根目录下手动创建 <strong>config.inc.php</strong> 文件, 并复制如下代码至其中'),                [                'code' => $code                ]            );        }    }    // delete exists db    if ($config['dbNext'] == 'delete') {        $tables = [            $config['dbPrefix'] . 'comments',            $config['dbPrefix'] . 'contents',            $config['dbPrefix'] . 'fields',            $config['dbPrefix'] . 'metas',            $config['dbPrefix'] . 'options',            $config['dbPrefix'] . 'relationships',            $config['dbPrefix'] . 'users'        ];        try {            foreach ($tables as $table) {                switch ($type) {                    case 'Mysql':                        $installDb->query("DROP TABLE IF EXISTS `{$table}`");                        break;                    case 'Pgsql':                    case 'SQLite':                        $installDb->query("DROP TABLE {$table}");                        break;                }            }        } catch (\Typecho\Db\Exception $e) {            install_raise_error(_t('安装程序捕捉到以下错误: "%s". 程序被终止, 请检查您的配置信息.', $e->getMessage()));        }    }    // init db structure    try {        $scripts = file_get_contents(__TYPECHO_ROOT_DIR__ . '/install/' . $type . '.sql');        $scripts = str_replace('typecho_', $config['dbPrefix'], $scripts);        if (isset($dbConfig['charset'])) {            $scripts = str_replace('%charset%', $dbConfig['charset'], $scripts);        }        if (isset($dbConfig['engine'])) {            $scripts = str_replace('%engine%', $dbConfig['engine'], $scripts);        }        $scripts = explode(';', $scripts);        foreach ($scripts as $script) {            $script = trim($script);            if ($script) {                $installDb->query($script, \Typecho\Db::WRITE);            }        }    } catch (\Typecho\Db\Exception $e) {        $code = $e->getCode();        if (            ('Mysql' == $type && (1050 == $code || '42S01' == $code)) ||            ('SQLite' == $type && ('HY000' == $code || 1 == $code)) ||            ('Pgsql' == $type && '42P07' == $code)        ) {            if ($config['dbNext'] == 'keep') {                if (install_check('db_data')) {                    install_success(0);                } else {                    install_success(3);                }            } elseif ($config['dbNext'] == 'none') {                install_remove_config_file();                install_raise_error(_t('安装程序检查到原有数据表已经存在.'), [                    'delete' => _t('删除原有数据'),                    'keep' => _t('使用原有数据')                ]);            }        } else {            install_remove_config_file();            install_raise_error(_t('安装程序捕捉到以下错误: "%s". 程序被终止, 请检查您的配置信息.', $e->getMessage()));        }    }    install_success(3);}/** * display step 3 */function install_step_3(){    $options = \Widget\Options::alloc();    ?>    <div class="row typecho-page-main">        <div class="col-mb-12 col-tb-8 col-tb-offset-2">            <div class="typecho-page-title">                <h2><?php _e('创建您的管理员帐号'); ?></h2>            </div>            <form autocomplete="off" action="install.php" method="post">                <ul class="typecho-option">                    <li>                        <label class="typecho-label" for="userUrl"><?php _e('网站地址'); ?></label>                        <input autocomplete="new-password" type="text" name="userUrl" id="userUrl" class="text" value="<?php $options->rootUrl(); ?>" />                        <p class="description"><?php _e('这是程序自动匹配的网站路径, 如果不正确请修改它'); ?></p>                    </li>                </ul>                <ul class="typecho-option">                    <li>                        <label class="typecho-label" for="userName"><?php _e('用户名'); ?></label>                        <input autocomplete="new-password" type="text" name="userName" id="userName" class="text" />                        <p class="description"><?php _e('请填写您的用户名'); ?></p>                    </li>                </ul>                <ul class="typecho-option">                    <li>                        <label class="typecho-label" for="userPassword"><?php _e('登录密码'); ?></label>                        <input type="password" name="userPassword" id="userPassword" class="text" />                        <p class="description"><?php _e('请填写您的登录密码, 如果留空系统将为您随机生成一个'); ?></p>                    </li>                </ul>                <ul class="typecho-option">                    <li>                        <label class="typecho-label" for="userMail"><?php _e('邮件地址'); ?></label>                        <input autocomplete="new-password" type="text" name="userMail" id="userMail" class="text" />                        <p class="description"><?php _e('请填写一个您的常用邮箱'); ?></p>                    </li>                </ul>                <ul class="typecho-option typecho-option-submit">                    <li>                        <button type="submit" class="btn primary"><?php _e('继续安装 »'); ?></button>                        <input type="hidden" name="step" value="3">                    </li>                </ul>            </form>        </div>    </div>    <?php    install_js_support();}/** * perform step 3 */function install_step_3_perform(){    global $installDb;    $request = \Typecho\Request::getInstance();    $defaultPassword = \Typecho\Common::randString(8);    $options = \Widget\Options::alloc();    if (install_is_cli()) {        $config = [            'userUrl' => $request->getServer('TYPECHO_SITE_URL'),            'userName' => $request->getServer('TYPECHO_USER_NAME', 'typecho'),            'userPassword' => $request->getServer('TYPECHO_USER_PASSWORD'),            'userMail' => $request->getServer('TYPECHO_USER_MAIL', 'admin@localhost.local')        ];    } else {        $config = $request->from([            'userUrl',            'userName',            'userPassword',            'userMail',        ]);    }    $error = (new \Typecho\Validate())        ->addRule('userUrl', 'required', _t('请填写站点地址'))        ->addRule('userUrl', 'url', _t('请填写一个合法的URL地址'))        ->addRule('userName', 'required', _t('必须填写用户名称'))        ->addRule('userName', 'xssCheck', _t('请不要在用户名中使用特殊字符'))        ->addRule('userName', 'maxLength', _t('用户名长度超过限制, 请不要超过 32 个字符'), 32)        ->addRule('userMail', 'required', _t('必须填写电子邮箱'))        ->addRule('userMail', 'email', _t('电子邮箱格式错误'))        ->addRule('userMail', 'maxLength', _t('邮箱长度超过限制, 请不要超过 200 个字符'), 200)        ->run($config);    if (!empty($error)) {        install_raise_error($error);    }    if (empty($config['userPassword'])) {        $config['userPassword'] = $defaultPassword;    }    try {        // write user        $hasher = new \Utils\PasswordHash(8, true);        $installDb->query(            $installDb->insert('table.users')->rows([                'name' => $config['userName'],                'password' => $hasher->hashPassword($config['userPassword']),                'mail' => $config['userMail'],                'url' => $config['userUrl'],                'screenName' => $config['userName'],                'group' => 'administrator',                'created' => \Typecho\Date::time()            ])        );        // write category        $installDb->query(            $installDb->insert('table.metas')                ->rows([                    'name' => _t('默认分类'),                    'slug' => 'default',                    'type' => 'category',                    'description' => _t('只是一个默认分类'),                    'count' => 1                ])        );        $installDb->query($installDb->insert('table.relationships')->rows(['cid' => 1, 'mid' => 1]));        // write first page and post        $installDb->query(            $installDb->insert('table.contents')->rows([                'title' => _t('欢迎使用 Typecho'),                'slug' => 'start', 'created' => \Typecho\Date::time(),                'modified' => \Typecho\Date::time(),                'text' => '<!--markdown-->' . _t('如果您看到这篇文章,表示您的 blog 已经安装成功.'),                'authorId' => 1,                'type' => 'post',                'status' => 'publish',                'commentsNum' => 1,                'allowComment' => 1,                'allowPing' => 1,                'allowFeed' => 1,                'parent' => 0            ])        );        $installDb->query(            $installDb->insert('table.contents')->rows([                'title' => _t('关于'),                'slug' => 'start-page',                'created' => \Typecho\Date::time(),                'modified' => \Typecho\Date::time(),                'text' => '<!--markdown-->' . _t('本页面由 Typecho 创建, 这只是个测试页面.'),                'authorId' => 1,                'order' => 0,                'type' => 'page',                'status' => 'publish',                'commentsNum' => 0,                'allowComment' => 1,                'allowPing' => 1,                'allowFeed' => 1,                'parent' => 0            ])        );        // write comment        $installDb->query(            $installDb->insert('table.comments')->rows([                'cid' => 1, 'created' => \Typecho\Date::time(),                'author' => 'Typecho',                'ownerId' => 1,                'url' => 'https://typecho.org',                'ip' => '127.0.0.1',                'agent' => $options->generator,                'text' => '欢迎加入 Typecho 大家族',                'type' => 'comment',                'status' => 'approved',                'parent' => 0            ])        );        // write options        foreach (install_get_default_options() as $key => $value) {            // mark installing finished            if ($key == 'installed') {                $value = 1;            }            $installDb->query(                $installDb->insert('table.options')->rows(['name' => $key, 'user' => 0, 'value' => $value])            );        }    } catch (\Typecho\Db\Exception $e) {        install_raise_error($e->getMessage());    }    $parts = parse_url($options->loginAction);    $parts['query'] = http_build_query([            'name'  => $config['userName'],            'password' => $config['userPassword'],            'referer' => $options->adminUrl        ]);    $loginUrl = \Typecho\Common::buildUrl($parts);    install_success(0, [        $config['userName'],        $config['userPassword'],        \Widget\Security::alloc()->getTokenUrl($loginUrl, $request->getReferer()),        $config['userUrl']    ]);}/** * dispatch install action * */function install_dispatch(){    // disable root url on cli mode    if (install_is_cli()) {        define('__TYPECHO_ROOT_URL__', 'http://localhost');    }    // init default options    $options = \Widget\Options::alloc(install_get_default_options());    \Widget\Init::alloc();    // display version    if (install_is_cli()) {        echo $options->generator . "\n";        echo 'PHP ' . PHP_VERSION . "\n";    }    // install finished yet    if (        install_check('config')        && install_check('db_structure')        && install_check('db_data')    ) {        // redirect to siteUrl if not cli        if (!install_is_cli()) {            install_redirect($options->siteUrl);        }        exit(1);    }    if (install_is_cli()) {        install_step_1_perform();    } else {        $request = \Typecho\Request::getInstance();        $step = $request->get('step');        $action = 1;        switch (true) {            case $step == 2:                if (!install_check('db_structure')) {                    $action = 2;                } else {                    install_redirect('install.php?step=3');                }                break;            case $step == 3:                if (install_check('db_structure')) {                    $action = 3;                } else {                    install_redirect('install.php?step=2');                }                break;            default:                break;        }        $method = 'install_step_' . $action;        if ($request->isPost()) {            $method .= '_perform';            $method();            exit;        }        ?><!DOCTYPE HTML><html><head>    <meta charset="<?php _e('UTF-8'); ?>" />    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">    <title><?php _e('Typecho 安装程序'); ?></title>    <link rel="stylesheet" type="text/css" href="<?php $options->adminStaticUrl('css', 'normalize.css') ?>" />    <link rel="stylesheet" type="text/css" href="<?php $options->adminStaticUrl('css', 'grid.css') ?>" />    <link rel="stylesheet" type="text/css" href="<?php $options->adminStaticUrl('css', 'style.css') ?>" />    <link rel="stylesheet" type="text/css" href="<?php $options->adminStaticUrl('css', 'install.css') ?>" />    <script src="<?php $options->adminStaticUrl('js', 'jquery.js'); ?>"></script></head><body>    <div class="body container">        <h1><a href="https://typecho.org" target="_blank" class="i-logo">Typecho</a></h1>        <?php $method(); ?>    </div></body></html>        <?php    }}install_dispatch();
 |