options->routingTable; $currentTable = array('custom' => array('url' => $this->encodeRule($this->request->customPattern))); $parser = new Typecho_Router_Parser($currentTable); $currentTable = $parser->parse(); $regx = $currentTable['custom']['regx']; foreach ($routingTable as $key => $val) { if ('post' != $key && 'page' != $key) { $pathInfo = preg_replace("/\[([_a-z0-9-]+)[^\]]*\]/i", "{\\1}", $val['url']); $pathInfo = str_replace(array('{cid}', '{slug}', '{category}', '{year}', '{month}', '{day}', '{', '}'), array('123', 'hello', 'default', '2008', '08', '08', '', ''), $pathInfo); if (preg_match($regx, $pathInfo)) { return false; } } } return true; } /** * 检查pagePattern里是否含有必要参数 * * @param mixed $value * @access public * @return void */ public function checkPagePattern($value) { return strpos($value, '{slug}') !== false || strpos($value, '{cid}') !== false; } /** * 检查categoryPattern里是否含有必要参数 * * @param mixed $value * @access public * @return void */ public function checkCategoryPattern($value) { return strpos($value, '{slug}') !== false || strpos($value, '{mid}') !== false || strpos($value, '{directory}') !== false; } /** * 检测是否可以rewrite * * @access public * @param string $value 是否打开rewrite * @return void */ public function checkRewrite($value) { if ($value) { $this->user->pass('administrator'); /** 首先直接请求远程地址验证 */ $client = Typecho_Http_Client::get(); $hasWrote = false; if (!file_exists(__TYPECHO_ROOT_DIR__ . '/.htaccess') && !Typecho_Common::isAppEngine()) { if (is_writeable(__TYPECHO_ROOT_DIR__)) { $parsed = parse_url($this->options->siteUrl); $basePath = empty($parsed['path']) ? '/' : $parsed['path']; $basePath = rtrim($basePath, '/') . '/'; $hasWrote = file_put_contents(__TYPECHO_ROOT_DIR__ . '/.htaccess', " RewriteEngine On RewriteBase {$basePath} RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)$ {$basePath}index.php/$1 [L] "); } } try { if ($client) { /** 发送一个rewrite地址请求 */ $client->setData(array('do' => 'remoteCallback')) ->setHeader('User-Agent', $this->options->generator) ->send(Typecho_Common::url('/action/ajax', $this->options->siteUrl)); if (200 == $client->getResponseStatus() && 'OK' == $client->getResponseBody()) { return true; } } if (false !== $hasWrote) { @unlink(__TYPECHO_ROOT_DIR__ . '/.htaccess'); //增强兼容性,使用wordpress的redirect式rewrite规则,虽然效率有点地下,但是对fastcgi模式兼容性较好 $hasWrote = file_put_contents(__TYPECHO_ROOT_DIR__ . '/.htaccess', " RewriteEngine On RewriteBase {$basePath} RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . {$basePath}index.php [L] "); //再次进行验证 $client = Typecho_Http_Client::get(); if ($client) { /** 发送一个rewrite地址请求 */ $client->setData(array('do' => 'remoteCallback')) ->setHeader('User-Agent', $this->options->generator) ->send(Typecho_Common::url('/action/ajax', $this->options->siteUrl)); if (200 == $client->getResponseStatus() && 'OK' == $client->getResponseBody()) { return true; } } unlink(__TYPECHO_ROOT_DIR__ . '/.htaccess'); } } catch (Typecho_Http_Client_Exception $e) { if (false !== $hasWrote) { @unlink(__TYPECHO_ROOT_DIR__ . '/.htaccess'); } return false; } return false; } else if (file_exists(__TYPECHO_ROOT_DIR__ . '/.htaccess')) { @unlink(__TYPECHO_ROOT_DIR__ . '/.htaccess'); } return true; } /** * 输出表单结构 * * @access public * @return Typecho_Widget_Helper_Form */ public function form() { /** 构建表格 */ $form = new Typecho_Widget_Helper_Form($this->security->getRootUrl('index.php/action/options-permalink'), Typecho_Widget_Helper_Form::POST_METHOD); if (!defined('__TYPECHO_REWRITE__')) { /** 是否使用地址重写功能 */ $rewrite = new Typecho_Widget_Helper_Form_Element_Radio('rewrite', array('0' => _t('不启用'), '1' => _t('启用')), $this->options->rewrite, _t('是否使用地址重写功能'), _t('地址重写即 rewrite 功能是某些服务器软件提供的优化内部连接的功能.') . '
' . _t('打开此功能可以让你的链接看上去完全是静态地址.')); // disable rewrite check when rewrite opened if (!$this->options->rewrite && !$this->request->is('enableRewriteAnyway=1')) { $errorStr = _t('重写功能检测失败, 请检查你的服务器设置'); /** 如果是apache服务器, 可能存在无法写入.htaccess文件的现象 */ if (((isset($_SERVER['SERVER_SOFTWARE']) && false !== strpos(strtolower($_SERVER['SERVER_SOFTWARE']), 'apache')) || function_exists('apache_get_version')) && !file_exists(__TYPECHO_ROOT_DIR__ . '/.htaccess') && !is_writeable(__TYPECHO_ROOT_DIR__)) { $errorStr .= '
' . _t('我们检测到你使用了apache服务器, 但是程序无法在根目录创建.htaccess文件, 这可能是产生这个错误的原因.') . _t('请调整你的目录权限, 或者手动创建一个.htaccess文件.') . ''; } $errorStr .= '
' . ' '; $rewrite->addRule(array($this, 'checkRewrite'), $errorStr); } $form->addInput($rewrite); } $patterns = array('/archives/[cid:digital]/' => _t('默认风格') . ' /archives/{cid}/', '/archives/[slug].html' => _t('wordpress风格') . ' /archives/{slug}.html', '/[year:digital:4]/[month:digital:2]/[day:digital:2]/[slug].html' => _t('按日期归档') . ' /archives/{year}/{month}/{day}/{slug}.html', '/[category]/[slug].html' => _t('按分类归档') . ' /{category}/{slug}.html'); /** 自定义文章路径 */ $postPatternValue = $this->options->routingTable['post']['url']; /** 增加个性化路径 */ $customPatternValue = NULL; if (isset($this->request->__typecho_form_item_postPattern)) { $customPatternValue = $this->request->__typecho_form_item_postPattern; Typecho_Cookie::delete('__typecho_form_item_postPattern'); } else if (!isset($patterns[$postPatternValue])) { $customPatternValue = $this->decodeRule($postPatternValue); } $patterns['custom'] = _t('个性化定义') . ' '; $postPattern = new Typecho_Widget_Helper_Form_Element_Radio('postPattern', $patterns, $postPatternValue, _t('自定义文章路径'), _t('可用参数: {cid} 日志 ID, {slug} 日志缩略名, {category} 分类, {directory} 多级分类, {year} 年, {month} 月, {day} 日') . '
' . _t('选择一种合适的文章静态路径风格, 使得你的网站链接更加友好.') . '
' . _t('一旦你选择了某种链接风格请不要轻易修改它.')); if ($customPatternValue) { $postPattern->value('custom'); } $form->addInput($postPattern->multiMode()); /** 独立页面后缀名 */ $pagePattern = new Typecho_Widget_Helper_Form_Element_Text('pagePattern', NULL, $this->decodeRule($this->options->routingTable['page']['url']), _t('独立页面路径'), _t('可用参数: {cid} 页面 ID, {slug} 页面缩略名') . '
' . _t('请在路径中至少包含上述的一项参数.')); $pagePattern->input->setAttribute('class', 'mono w-60'); $form->addInput($pagePattern->addRule(array($this, 'checkPagePattern'), _t('独立页面路径中没有包含 {cid} 或者 {slug} '))); /** 分类页面 */ $categoryPattern = new Typecho_Widget_Helper_Form_Element_Text('categoryPattern', NULL, $this->decodeRule($this->options->routingTable['category']['url']), _t('分类路径'), _t('可用参数: {mid} 分类 ID, {slug} 分类缩略名, {directory} 多级分类') . '
' . _t('请在路径中至少包含上述的一项参数.')); $categoryPattern->input->setAttribute('class', 'mono w-60'); $form->addInput($categoryPattern->addRule(array($this, 'checkCategoryPattern'), _t('分类路径中没有包含 {mid} 或者 {slug} '))); /** 提交按钮 */ $submit = new Typecho_Widget_Helper_Form_Element_Submit('submit', NULL, _t('保存设置')); $submit->input->setAttribute('class', 'btn primary'); $form->addItem($submit); return $form; } /** * 执行更新动作 * * @access public * @return void */ public function updatePermalinkSettings() { /** 验证格式 */ if ($this->form()->validate()) { Typecho_Cookie::set('__typecho_form_item_postPattern', $this->request->customPattern); $this->response->goBack(); } $patternValid = $this->checkRule($this->request->postPattern); /** 解析url pattern */ if ('custom' == $this->request->postPattern) { $this->request->postPattern = '/' . ltrim($this->encodeRule($this->request->customPattern), '/'); } $settings = defined('__TYPECHO_REWRITE__') ? array() : $this->request->from('rewrite'); if (isset($this->request->postPattern) && isset($this->request->pagePattern)) { $routingTable = $this->options->routingTable; $routingTable['post']['url'] = $this->request->postPattern; $routingTable['page']['url'] = '/' . ltrim($this->encodeRule($this->request->pagePattern), '/'); $routingTable['category']['url'] = '/' . ltrim($this->encodeRule($this->request->categoryPattern), '/'); $routingTable['category_page']['url'] = rtrim($routingTable['category']['url'], '/') . '/[page:digital]/'; if (isset($routingTable[0])) { unset($routingTable[0]); } $settings['routingTable'] = serialize($routingTable); } foreach ($settings as $name => $value) { $this->update(array('value' => $value), $this->db->sql()->where('name = ?', $name)); } if ($patternValid) { $this->widget('Widget_Notice')->set(_t("设置已经保存"), 'success'); } else { $this->widget('Widget_Notice')->set(_t("自定义链接与现有规则存在冲突! 它可能影响解析效率, 建议你重新分配一个规则."), 'notice'); } $this->response->goBack(); } /** * 绑定动作 * * @access public * @return void */ public function action() { $this->user->pass('administrator'); $this->security->protect(); $this->on($this->request->isPost())->updatePermalinkSettings(); $this->response->redirect($this->options->adminUrl); } }