parameter->setDefault(array( 'pageSize' => $this->options->pageSize, 'type' => NULL, 'checkPermalink' => true )); /** 用于判断是路由调用还是外部调用 */ if (NULL == $this->parameter->type) { $this->parameter->type = Typecho_Router::$current; } else { $this->_invokeFromOutside = true; } /** 用于判断是否为feed调用 */ if ($this->parameter->isFeed) { $this->_invokeByFeed = true; } /** 初始化皮肤路径 */ $this->_themeDir = rtrim($this->options->themeFile($this->options->theme), '/') . '/'; /** 处理feed模式 **/ if ('feed' == $this->parameter->type) { $this->_currentFeedUrl = ''; /** 判断聚合类型 */ switch (true) { case 0 === strpos($this->request->feed, '/rss/') || '/rss' == $this->request->feed: /** 如果是RSS1标准 */ $this->request->feed = substr($this->request->feed, 4); $this->_feedType = Typecho_Feed::RSS1; $this->_currentFeedUrl = $this->options->feedRssUrl; $this->_feedContentType = 'application/rdf+xml'; break; case 0 === strpos($this->request->feed, '/atom/') || '/atom' == $this->request->feed: /** 如果是ATOM标准 */ $this->request->feed = substr($this->request->feed, 5); $this->_feedType = Typecho_Feed::ATOM1; $this->_currentFeedUrl = $this->options->feedAtomUrl; $this->_feedContentType = 'application/atom+xml'; break; default: $this->_feedType = Typecho_Feed::RSS2; $this->_currentFeedUrl = $this->options->feedUrl; $this->_feedContentType = 'application/rss+xml'; break; } $feedQuery = $this->request->feed; //$this->parameter->type = Typecho_Router::$current; //$this->request->setParams($params); if ('/comments/' == $feedQuery || '/comments' == $feedQuery) { /** 专为feed使用的hack */ $this->parameter->type = 'comments'; } else { $matched = Typecho_Router::match($this->request->feed, 'pageSize=10&isFeed=1'); if ($matched && $matched instanceof Widget_Archive) { $this->import($matched); } else { throw new Typecho_Widget_Exception(_t('聚合页不存在'), 404); } } /** 初始化聚合器 */ $this->setFeed(new Typecho_Feed(Typecho_Common::VERSION, $this->_feedType, $this->options->charset, _t('zh-CN'))); /** 默认输出10则文章 **/ $this->parameter->pageSize = 10; } } /** * 评论地址 * * @access protected * @return string */ protected function ___commentUrl() { /** 生成反馈地址 */ /** 评论 */ $commentUrl = parent::___commentUrl(); //不依赖js的父级评论 $reply = $this->request->filter('int')->replyTo; if ($reply && $this->is('single')) { $commentUrl .= '?parent=' . $reply; } return $this->options->commentsAntiSpam ? $commentUrl : $this->security->getTokenUrl($commentUrl); } /** * 设置分页对象 * @param array $pageRow * @return void */ public function setPageRow($pageRow) { $this->_pageRow = $pageRow; } /** * @param string $archiveSlug the $_archiveSlug to set */ public function setArchiveSlug($archiveSlug) { $this->_archiveSlug = $archiveSlug; } /** * @param string $archiveSingle the $_archiveSingle to set */ public function setArchiveSingle($archiveSingle) { $this->_archiveSingle = $archiveSingle; } /** * @param $archiveType the $_archiveType to set */ public function setArchiveType($archiveType) { $this->_archiveType = $archiveType; } /** * @param $archiveTitle the $_archiveTitle to set */ public function setArchiveTitle($archiveTitle) { $this->_archiveTitle = $archiveTitle; } /** * 增加标题 * @param string $archiveTitle 标题 * @return void */ public function addArchiveTitle($archiveTitle) { $current = $this->getArchiveTitle(); $current[] = $archiveTitle; $this->setArchiveTitle($current); } /** * @param $feedType the $_feedType to set */ public function setFeedType($feedType) { $this->_feedType = $feedType; } /** * @param $description the $_description to set */ public function setDescription($description) { $this->_description = $description; } /** * @param $keywords the $_keywords to set */ public function setKeywords($keywords) { $this->_keywords = $keywords; } /** * @param $feedAtomUrl the $_feedAtomUrl to set */ public function setFeedAtomUrl($feedAtomUrl) { $this->_feedAtomUrl = $feedAtomUrl; } /** * @param $feedRssUrl the $_feedRssUrl to set */ public function setFeedRssUrl($feedRssUrl) { $this->_feedRssUrl = $feedRssUrl; } /** * @param $feedUrl the $_feedUrl to set */ public function setFeedUrl($feedUrl) { $this->_feedUrl = $feedUrl; } /** * @param $feed the $_feed to set */ public function setFeed($feed) { $this->_feed = $feed; } /** * @param $countSql the $_countSql to set */ public function setCountSql($countSql) { $this->_countSql = $countSql; } /** * @param $total the $_total to set */ public function setTotal($total) { $this->_total = $total; } /** * @param $themeFile the $_themeFile to set */ public function setThemeFile($themeFile) { $this->_themeFile = $themeFile; } /** * @param $themeDir the $_themeDir to set */ public function setThemeDir($themeDir) { $this->_themeDir = $themeDir; } /** * 获取分页对象 * @return array */ public function getPageRow() { return $this->_pageRow; } /** * @return string */ public function getArchiveSlug() { return $this->_archiveSlug; } /** * @return string */ public function getArchiveSingle() { return $this->_archiveSingle; } /** * @return string */ public function getArchiveType() { return $this->_archiveType; } /** * @return string */ public function getArchiveTitle() { return $this->_archiveTitle; } /** * @return string */ public function getFeedType() { return $this->_feedType; } /** * @return string */ public function getDescription() { return $this->_description; } /** * @return string */ public function getKeywords() { return $this->_keywords; } /** * @return string */ public function getFeedAtomUrl() { return $this->_feedAtomUrl; } /** * @return string */ public function getFeedRssUrl() { return $this->_feedRssUrl; } /** * @return string */ public function getFeedUrl() { return $this->_feedUrl; } /** * @return Typecho_Feed */ public function getFeed() { return $this->_feed; } /** * @return Typecho_Db_Query */ public function getCountSql() { return $this->_countSql; } /** * @return int */ public function getTotal() { if (false === $this->_total) { $this->_total = $this->size($this->_countSql); } return $this->_total; } /** * @return int */ public function getCurrentPage() { return $this->_currentPage; } /** * 获取页数 * * @return integer */ public function getTotalPage() { return ceil($this->getTotal() / $this->parameter->pageSize); } /** * @return string */ public function getThemeFile() { return $this->_themeFile; } /** * @return string */ public function getThemeDir() { return $this->_themeDir; } /** * 检查链接是否正确 * * @access private * @return void */ private function checkPermalink() { $type = $this->parameter->type; if (in_array($type, array('index', 'comment_page', 404)) || $this->_makeSinglePageAsFrontPage // 自定义首页不处理 || !$this->parameter->checkPermalink) { // 强制关闭 return; } if ($this->_archiveSingle) { $permalink = $this->permalink; } else { $value = array_merge($this->_pageRow, array( 'page' => $this->_currentPage )); $path = Typecho_Router::url($type, $value); $permalink = Typecho_Common::url($path, $this->options->index); } $requestUrl = $this->request->getRequestUrl(); $src = parse_url($permalink); $target = parse_url($requestUrl); if ($src['host'] != $target['host'] || urldecode($src['path']) != urldecode($target['path'])) { $this->response->redirect($permalink, true); } } /** * 导入对象 * * @access private * @param Widget_Archive $widget 需要导入的对象 * @return void */ private function import(Widget_Archive $widget) { $currentProperties = get_object_vars($this); foreach ($currentProperties as $name => $value) { if (false !== strpos('|request|response|parameter|_feed|_feedType|_currentFeedUrl|', '|' . $name . '|')) { continue; } if (isset($widget->{$name})) { $this->{$name} = $widget->{$name}; } else { $method = ucfirst(trim($name, '_')); $setMethod = 'set' . $method; $getMethod = 'get' . $method; if (method_exists($this, $setMethod) && method_exists($widget, $getMethod)) { $this->{$setMethod}($widget->{$getMethod}()); } } } } /** * 处理index * * @access private * @param Typecho_Db_Query $select 查询对象 * @param boolean $hasPushed 是否已经压入队列 * @return void */ private function indexHandle(Typecho_Db_Query $select, &$hasPushed) { $select->where('table.contents.type = ?', 'post'); /** 插件接口 */ $this->pluginHandle()->indexHandle($this, $select); } /** * 默认的非首页归档处理 * * @access private * @param Typecho_Db_Query $select 查询对象 * @param boolean $hasPushed 是否已经压入队列 * @return void * @throws Typecho_Widget_Exception */ private function archiveEmptyHandle(Typecho_Db_Query $select, &$hasPushed) { throw new Typecho_Widget_Exception(_t('请求的地址不存在'), 404); } /** * 404页面处理 * * @access private * @param Typecho_Db_Query $select 查询对象 * @param boolean $hasPushed 是否已经压入队列 * @return void */ private function error404Handle(Typecho_Db_Query $select, &$hasPushed) { /** 设置header */ $this->response->setStatus(404); /** 设置标题 */ $this->_archiveTitle = _t('页面没找到'); /** 设置归档类型 */ $this->_archiveType = 'archive'; /** 设置归档缩略名 */ $this->_archiveSlug = 404; /** 设置归档模板 */ $this->_themeFile = '404.php'; /** 设置单一归档类型 */ $this->_archiveSingle = false; $hasPushed = true; /** 插件接口 */ $this->pluginHandle()->error404Handle($this, $select); } /** * 独立页处理 * * @access private * @param Typecho_Db_Query $select 查询对象 * @param boolean $hasPushed 是否已经压入队列 * @return void * @throws Typecho_Widget_Exception */ private function singleHandle(Typecho_Db_Query $select, &$hasPushed) { if ('comment_page' == $this->parameter->type) { $params = array(); $matched = Typecho_Router::match($this->request->permalink); if ($matched && $matched instanceof Widget_Archive && $matched->is('single')) { $this->import($matched); $hasPushed = true; return; } } /** 将这两个设置提前是为了保证在调用query的plugin时可以在插件中使用is判断初步归档类型 */ /** 如果需要更细判断,则可以使用singleHandle来实现 */ $this->_archiveSingle = true; /** 默认归档类型 */ $this->_archiveType = 'single'; /** 匹配类型 */ if ('single' != $this->parameter->type) { $select->where('table.contents.type = ?', $this->parameter->type); } /** 如果是单篇文章或独立页面 */ if (isset($this->request->cid)) { $select->where('table.contents.cid = ?', $this->request->filter('int')->cid); } /** 匹配缩略名 */ if (isset($this->request->slug)) { $select->where('table.contents.slug = ?', $this->request->slug); } /** 匹配时间 */ if (isset($this->request->year)) { $year = $this->request->filter('int')->year; $fromMonth = 1; $toMonth = 12; $fromDay = 1; $toDay = 31; if (isset($this->request->month)) { $fromMonth = $this->request->filter('int')->month; $toMonth = $fromMonth; $fromDay = 1; $toDay = date('t', mktime(0, 0, 0, $toMonth, 1, $year)); if (isset($this->request->day)) { $fromDay = $this->request->filter('int')->day; $toDay = $fromDay; } } /** 获取起始GMT时间的unix时间戳 */ $from = mktime(0, 0, 0, $fromMonth, $fromDay, $year) - $this->options->timezone + $this->options->serverTimezone; $to = mktime(23, 59, 59, $toMonth, $toDay, $year) - $this->options->timezone + $this->options->serverTimezone; $select->where('table.contents.created >= ? AND table.contents.created < ?', $from, $to); } /** 保存密码至cookie */ if ($this->request->isPost() && isset($this->request->protectPassword)) { $this->security->protect(); Typecho_Cookie::set('protectPassword', $this->request->protectPassword, 0); } /** 匹配类型 */ $select->limit(1); $this->query($select); if (!$this->have() || (isset($this->request->category) && $this->category != $this->request->category) || (isset($this->request->directory) && $this->request->directory != implode('/', $this->directory))) { if (!$this->_invokeFromOutside) { /** 对没有索引情况下的判断 */ throw new Typecho_Widget_Exception(_t('请求的地址不存在'), 404); } else { $hasPushed = true; return; } } /** 设置模板 */ if ($this->template) { /** 应用自定义模板 */ $this->_themeFile = $this->template; } /** 设置头部feed */ /** RSS 2.0 */ //对自定义首页使用全局变量 if (!$this->_makeSinglePageAsFrontPage) { $this->_feedUrl = $this->feedUrl; /** RSS 1.0 */ $this->_feedRssUrl = $this->feedRssUrl; /** ATOM 1.0 */ $this->_feedAtomUrl = $this->feedAtomUrl; /** 设置标题 */ $this->_archiveTitle = $this->title; /** 设置关键词 */ $this->_keywords = implode(',', Typecho_Common::arrayFlatten($this->tags, 'name')); /** 设置描述 */ $this->_description = $this->description; } /** 设置归档类型 */ $this->_archiveType = $this->type; /** 设置归档缩略名 */ $this->_archiveSlug = ('post' == $this->type || 'attachment' == $this->type) ? $this->cid : $this->slug; /** 设置403头 */ if ($this->hidden) { $this->response->setStatus(403); } $hasPushed = true; /** 插件接口 */ $this->pluginHandle()->singleHandle($this, $select); } /** * 处理分类 * * @access private * @param Typecho_Db_Query $select 查询对象 * @param boolean $hasPushed 是否已经压入队列 * @return void * @throws Typecho_Widget_Exception */ private function categoryHandle(Typecho_Db_Query $select, &$hasPushed) { /** 如果是分类 */ $categorySelect = $this->db->select() ->from('table.metas') ->where('type = ?', 'category') ->limit(1); if (isset($this->request->mid)) { $categorySelect->where('mid = ?', $this->request->filter('int')->mid); } if (isset($this->request->slug)) { $categorySelect->where('slug = ?', $this->request->slug); } if (isset($this->request->directory)) { $directory = explode('/', $this->request->directory); $categorySelect->where('slug = ?', $directory[count($directory) - 1]); } $category = $this->db->fetchRow($categorySelect); if (empty($category)) { throw new Typecho_Widget_Exception(_t('分类不存在'), 404); } $categoryListWidget = $this->widget('Widget_Metas_Category_List', 'current=' . $category['mid']); $category = $categoryListWidget->filter($category); if (isset($directory) && ($this->request->directory != implode('/', $category['directory']))) { throw new Typecho_Widget_Exception(_t('父级分类不存在'), 404); } $children = $categoryListWidget->getAllChildren($category['mid']); $children[] = $category['mid']; /** fix sql92 by 70 */ $select->join('table.relationships', 'table.contents.cid = table.relationships.cid') ->where('table.relationships.mid IN ?', $children) ->where('table.contents.type = ?', 'post') ->group('table.contents.cid'); /** 设置分页 */ $this->_pageRow = array_merge($category, array( 'slug' => urlencode($category['slug']), 'directory' => implode('/', array_map('urlencode', $category['directory'])) )); /** 设置关键词 */ $this->_keywords = $category['name']; /** 设置描述 */ $this->_description = $category['description']; /** 设置头部feed */ /** RSS 2.0 */ $this->_feedUrl = $category['feedUrl']; /** RSS 1.0 */ $this->_feedRssUrl = $category['feedRssUrl']; /** ATOM 1.0 */ $this->_feedAtomUrl = $category['feedAtomUrl']; /** 设置标题 */ $this->_archiveTitle = $category['name']; /** 设置归档类型 */ $this->_archiveType = 'category'; /** 设置归档缩略名 */ $this->_archiveSlug = $category['slug']; /** 插件接口 */ $this->pluginHandle()->categoryHandle($this, $select); } /** * 处理标签 * * @access private * @param Typecho_Db_Query $select 查询对象 * @param boolean $hasPushed 是否已经压入队列 * @return void * @throws Typecho_Widget_Exception */ private function tagHandle(Typecho_Db_Query $select, &$hasPushed) { $tagSelect = $this->db->select()->from('table.metas') ->where('type = ?', 'tag')->limit(1); if (isset($this->request->mid)) { $tagSelect->where('mid = ?', $this->request->filter('int')->mid); } if (isset($this->request->slug)) { $tagSelect->where('slug = ?', $this->request->slug); } /** 如果是标签 */ $tag = $this->db->fetchRow($tagSelect, array($this->widget('Widget_Abstract_Metas'), 'filter')); if (!$tag) { throw new Typecho_Widget_Exception(_t('标签不存在'), 404); } /** fix sql92 by 70 */ $select->join('table.relationships', 'table.contents.cid = table.relationships.cid') ->where('table.relationships.mid = ?', $tag['mid']) ->where('table.contents.type = ?', 'post'); /** 设置分页 */ $this->_pageRow = array_merge($tag, array( 'slug' => urlencode($tag['slug']) )); /** 设置关键词 */ $this->_keywords = $tag['name']; /** 设置描述 */ $this->_description = $tag['description']; /** 设置头部feed */ /** RSS 2.0 */ $this->_feedUrl = $tag['feedUrl']; /** RSS 1.0 */ $this->_feedRssUrl = $tag['feedRssUrl']; /** ATOM 1.0 */ $this->_feedAtomUrl = $tag['feedAtomUrl']; /** 设置标题 */ $this->_archiveTitle = $tag['name']; /** 设置归档类型 */ $this->_archiveType = 'tag'; /** 设置归档缩略名 */ $this->_archiveSlug = $tag['slug']; /** 插件接口 */ $this->pluginHandle()->tagHandle($this, $select); } /** * 处理作者 * * @access private * @param Typecho_Db_Query $select 查询对象 * @param boolean $hasPushed 是否已经压入队列 * @return void * @throws Typecho_Widget_Exception */ private function authorHandle(Typecho_Db_Query $select, &$hasPushed) { $uid = $this->request->filter('int')->uid; $author = $this->db->fetchRow($this->db->select()->from('table.users') ->where('uid = ?', $uid), array($this->widget('Widget_Abstract_Users'), 'filter')); if (!$author) { throw new Typecho_Widget_Exception(_t('作者不存在'), 404); } $select->where('table.contents.authorId = ?', $uid) ->where('table.contents.type = ?', 'post'); /** 设置分页 */ $this->_pageRow = $author; /** 设置关键词 */ $this->_keywords = $author['screenName']; /** 设置描述 */ $this->_description = $author['screenName']; /** 设置头部feed */ /** RSS 2.0 */ $this->_feedUrl = $author['feedUrl']; /** RSS 1.0 */ $this->_feedRssUrl = $author['feedRssUrl']; /** ATOM 1.0 */ $this->_feedAtomUrl = $author['feedAtomUrl']; /** 设置标题 */ $this->_archiveTitle = $author['screenName']; /** 设置归档类型 */ $this->_archiveType = 'author'; /** 设置归档缩略名 */ $this->_archiveSlug = $author['uid']; /** 插件接口 */ $this->pluginHandle()->authorHandle($this, $select); } /** * 处理日期 * * @access private * @param Typecho_Db_Query $select 查询对象 * @param boolean $hasPushed 是否已经压入队列 * @return void */ private function dateHandle(Typecho_Db_Query $select, &$hasPushed) { /** 如果是按日期归档 */ $year = $this->request->filter('int')->year; $month = $this->request->filter('int')->month; $day = $this->request->filter('int')->day; if (!empty($year) && !empty($month) && !empty($day)) { /** 如果按日归档 */ $from = mktime(0, 0, 0, $month, $day, $year); $to = mktime(23, 59, 59, $month, $day, $year); /** 归档缩略名 */ $this->_archiveSlug = 'day'; /** 设置标题 */ $this->_archiveTitle = _t('%d年%d月%d日', $year, $month, $day); } else if (!empty($year) && !empty($month)) { /** 如果按月归档 */ $from = mktime(0, 0, 0, $month, 1, $year); $to = mktime(23, 59, 59, $month, date('t', $from), $year); /** 归档缩略名 */ $this->_archiveSlug = 'month'; /** 设置标题 */ $this->_archiveTitle = _t('%d年%d月', $year, $month); } else if (!empty($year)) { /** 如果按年归档 */ $from = mktime(0, 0, 0, 1, 1, $year); $to = mktime(23, 59, 59, 12, 31, $year); /** 归档缩略名 */ $this->_archiveSlug = 'year'; /** 设置标题 */ $this->_archiveTitle = _t('%d年', $year); } $select->where('table.contents.created >= ?', $from - $this->options->timezone + $this->options->serverTimezone) ->where('table.contents.created <= ?', $to - $this->options->timezone + $this->options->serverTimezone) ->where('table.contents.type = ?', 'post'); /** 设置归档类型 */ $this->_archiveType = 'date'; /** 设置头部feed */ $value = array('year' => $year, 'month' => str_pad($month, 2, '0', STR_PAD_LEFT), 'day' => str_pad($day, 2, '0', STR_PAD_LEFT)); /** 设置分页 */ $this->_pageRow = $value; /** 获取当前路由,过滤掉翻页情况 */ $currentRoute = str_replace('_page', '', $this->parameter->type); /** RSS 2.0 */ $this->_feedUrl = Typecho_Router::url($currentRoute, $value, $this->options->feedUrl); /** RSS 1.0 */ $this->_feedRssUrl = Typecho_Router::url($currentRoute, $value, $this->options->feedRssUrl); /** ATOM 1.0 */ $this->_feedAtomUrl = Typecho_Router::url($currentRoute, $value, $this->options->feedAtomUrl); /** 插件接口 */ $this->pluginHandle()->dateHandle($this, $select); } /** * 处理搜索 * * @access private * @param Typecho_Db_Query $select 查询对象 * @param boolean $hasPushed 是否已经压入队列 * @return void */ private function searchHandle(Typecho_Db_Query $select, &$hasPushed) { /** 增加自定义搜索引擎接口 */ //~ fix issue 40 $keywords = $this->request->filter('url', 'search')->keywords; $this->pluginHandle()->trigger($hasPushed)->search($keywords, $this); if (!$hasPushed) { $searchQuery = '%' . str_replace(' ', '%', $keywords) . '%'; /** 搜索无法进入隐私项保护归档 */ $select->where('table.contents.password IS NULL') ->where('table.contents.title LIKE ? OR table.contents.text LIKE ?', $searchQuery, $searchQuery) ->where('table.contents.type = ?', 'post'); } /** 设置关键词 */ $this->_keywords = $keywords; /** 设置分页 */ $this->_pageRow = array('keywords' => urlencode($keywords)); /** 设置头部feed */ /** RSS 2.0 */ $this->_feedUrl = Typecho_Router::url('search', array('keywords' => $keywords), $this->options->feedUrl); /** RSS 1.0 */ $this->_feedRssUrl = Typecho_Router::url('search', array('keywords' => $keywords), $this->options->feedAtomUrl); /** ATOM 1.0 */ $this->_feedAtomUrl = Typecho_Router::url('search', array('keywords' => $keywords), $this->options->feedAtomUrl); /** 设置标题 */ $this->_archiveTitle = $keywords; /** 设置归档类型 */ $this->_archiveType = 'search'; /** 设置归档缩略名 */ $this->_archiveSlug = $keywords; /** 插件接口 */ $this->pluginHandle()->searchHandle($this, $select); } /** * 重载select * * @access public * @return void */ public function select() { if ($this->_invokeByFeed) { // 对feed输出加入限制条件 return parent::select()->where('table.contents.allowFeed = ?', 1) ->where('table.contents.password IS NULL'); } else { return parent::select(); } } /** * 提交查询 * * @access public * @param mixed $select 查询对象 * @return void */ public function query($select) { $this->pluginHandle()->trigger($queryPlugged)->query($this, $select); if (!$queryPlugged) { $this->db->fetchAll($select, array($this, 'push')); } } /** * 执行函数 * * @access public * @return void */ public function execute() { /** 避免重复取数据 */ if ($this->have()) { return; } $handles = array( 'index' => 'indexHandle', 'index_page' => 'indexHandle', 'archive' => 'archiveEmptyHandle', 'archive_page' => 'archiveEmptyHandle', 404 => 'error404Handle', 'single' => 'singleHandle', 'page' => 'singleHandle', 'post' => 'singleHandle', 'attachment' => 'singleHandle', 'comment_page' => 'singleHandle', 'category' => 'categoryHandle', 'category_page' => 'categoryHandle', 'tag' => 'tagHandle', 'tag_page' => 'tagHandle', 'author' => 'authorHandle', 'author_page' => 'authorHandle', 'archive_year' => 'dateHandle', 'archive_year_page' => 'dateHandle', 'archive_month' => 'dateHandle', 'archive_month_page' => 'dateHandle', 'archive_day' => 'dateHandle', 'archive_day_page' => 'dateHandle', 'search' => 'searchHandle', 'search_page' => 'searchHandle' ); /** 处理搜索结果跳转 */ if (isset($this->request->s)) { $filterKeywords = $this->request->filter('search')->s; /** 跳转到搜索页 */ if (NULL != $filterKeywords) { $this->response->redirect(Typecho_Router::url('search', array('keywords' => urlencode($filterKeywords)), $this->options->index)); } } /** 自定义首页功能 */ $frontPage = $this->options->frontPage; if (!$this->_invokeByFeed && ('index' == $this->parameter->type || 'index_page' == $this->parameter->type)) { //显示某个页面 if (0 === strpos($frontPage, 'page:')) { // 对某些变量做hack $this->request->setParam('cid', intval(substr($frontPage, 5))); $this->parameter->type = 'page'; $this->_makeSinglePageAsFrontPage = true; } else if (0 === strpos($frontPage, 'file:')) { // 显示某个文件 $this->setThemeFile(substr($frontPage, 5)); return; } } if ('recent' != $frontPage && $this->options->frontArchive) { $handles['archive'] = 'indexHandle'; $handles['archive_page'] = 'indexHandle'; $this->_archiveType = 'front'; } /** 初始化分页变量 */ $this->_currentPage = isset($this->request->page) ? $this->request->page : 1; $hasPushed = false; /** select初始化 */ $select = $this->pluginHandle()->trigger($selectPlugged)->select($this); /** 定时发布功能 */ if (!$selectPlugged) { if ('post' == $this->parameter->type || 'page' == $this->parameter->type) { if ($this->user->hasLogin()) { $select = $this->select()->where('table.contents.status = ? OR table.contents.status = ? OR (table.contents.status = ? AND table.contents.authorId = ?)', 'publish', 'hidden', 'private', $this->user->uid); } else { $select = $this->select()->where('table.contents.status = ? OR table.contents.status = ?', 'publish', 'hidden'); } } else { if ($this->user->hasLogin()) { $select = $this->select()->where('table.contents.status = ? OR (table.contents.status = ? AND table.contents.authorId = ?)', 'publish', 'private', $this->user->uid); } else { $select = $this->select()->where('table.contents.status = ?', 'publish'); } } $select->where('table.contents.created < ?', $this->options->gmtTime); } /** handle初始化 */ $this->pluginHandle()->handleInit($this, $select); /** 初始化其它变量 */ $this->_feedUrl = $this->options->feedUrl; $this->_feedRssUrl = $this->options->feedRssUrl; $this->_feedAtomUrl = $this->options->feedAtomUrl; $this->_keywords = $this->options->keywords; $this->_description = $this->options->description; if (isset($handles[$this->parameter->type])) { $handle = $handles[$this->parameter->type]; $this->{$handle}($select, $hasPushed); } else { $hasPushed = $this->pluginHandle()->handle($this->parameter->type, $this, $select); } /** 初始化皮肤函数 */ $functionsFile = $this->_themeDir . 'functions.php'; if ((!$this->_invokeFromOutside || $this->parameter->type == 404) && file_exists($functionsFile)) { require_once $functionsFile; if (function_exists('themeInit')) { themeInit($this); } } /** 如果已经提前压入则直接返回 */ if ($hasPushed) { return; } /** 仅输出文章 */ $this->_countSql = clone $select; $select->order('table.contents.created', Typecho_Db::SORT_DESC) ->page($this->_currentPage, $this->parameter->pageSize); $this->query($select); } /** * 输出文章内容 * * @access public * @param string $more 文章截取后缀 * @return void */ public function content($more = NULL) { parent::content($this->is('single') ? false : $more); } /** * 输出分页 * * @access public * @param string $prev 上一页文字 * @param string $next 下一页文字 * @param int $splitPage 分割范围 * @param string $splitWord 分割字符 * @param string $template 展现配置信息 * @return void */ public function pageNav($prev = '«', $next = '»', $splitPage = 3, $splitWord = '...', $template = '') { if ($this->have()) { $hasNav = false; $default = array( 'wrapTag' => 'ol', 'wrapClass' => 'page-navigator' ); if (is_string($template)) { parse_str($template, $config); } else { $config = $template; } $template = array_merge($default, $config); $total = $this->getTotal(); $this->pluginHandle()->trigger($hasNav)->pageNav($this->_currentPage, $total, $this->parameter->pageSize, $prev, $next, $splitPage, $splitWord); if (!$hasNav && $total > $this->parameter->pageSize) { $query = Typecho_Router::url($this->parameter->type . (false === strpos($this->parameter->type, '_page') ? '_page' : NULL), $this->_pageRow, $this->options->index); /** 使用盒状分页 */ $nav = new Typecho_Widget_Helper_PageNavigator_Box($total, $this->_currentPage, $this->parameter->pageSize, $query); echo '<' . $template['wrapTag'] . (empty($template['wrapClass']) ? '' : ' class="' . $template['wrapClass'] . '"') . '>'; $nav->render($prev, $next, $splitPage, $splitWord, $template); echo ''; } } } /** * 前一页 * * @access public * @param string $word 链接标题 * @param string $page 页面链接 * @return void */ public function pageLink($word = '« Previous Entries', $page = 'prev') { if ($this->have()) { if (empty($this->_pageNav)) { $query = Typecho_Router::url($this->parameter->type . (false === strpos($this->parameter->type, '_page') ? '_page' : NULL), $this->_pageRow, $this->options->index); /** 使用盒状分页 */ $this->_pageNav = new Typecho_Widget_Helper_PageNavigator_Classic($this->getTotal(), $this->_currentPage, $this->parameter->pageSize, $query); } $this->_pageNav->{$page}($word); } } /** * 获取评论归档对象 * * @access public * @return Widget_Abstract_Comments */ public function comments() { $parameter = array( 'parentId' => $this->hidden ? 0 : $this->cid, 'parentContent' => $this->row, 'respondId' => $this->respondId, 'commentPage' => $this->request->filter('int')->commentPage, 'allowComment' => $this->allow('comment') ); return $this->widget('Widget_Comments_Archive', $parameter); } /** * 获取回响归档对象 * * @access public * @return Widget_Comments_Ping */ public function pings() { return $this->widget('Widget_Comments_Ping', array( 'parentId' => $this->hidden ? 0 : $this->cid, 'parentContent' => $this->row, 'allowPing' => $this->allow('ping') )); } /** * 获取附件对象 * * @access public * @param integer $limit 最大个数 * @param integer $offset 重新 * @return Widget_Contents_Attachment_Related */ public function attachments($limit = 0, $offset = 0) { return $this->widget('Widget_Contents_Attachment_Related@' . $this->cid . '-' . uniqid(), array( 'parentId' => $this->cid, 'limit' => $limit, 'offset' => $offset )); } /** * 显示下一个内容的标题链接 * * @access public * @param string $format 格式 * @param string $default 如果没有下一篇,显示的默认文字 * @param array $custom 定制化样式 * @return void */ public function theNext($format = '%s', $default = NULL, $custom = array()) { $content = $this->db->fetchRow($this->select()->where('table.contents.created > ? AND table.contents.created < ?', $this->created, $this->options->gmtTime) ->where('table.contents.status = ?', 'publish') ->where('table.contents.type = ?', $this->type) ->where('table.contents.password IS NULL') ->order('table.contents.created', Typecho_Db::SORT_ASC) ->limit(1)); if ($content) { $content = $this->filter($content); $default = array( 'title' => NULL, 'tagClass' => NULL ); $custom = array_merge($default, $custom); extract($custom); $linkText = empty($title) ? $content['title'] : $title; $linkClass = empty($tagClass) ? '' : 'class="' . $tagClass . '" '; $link = '' . $linkText . ''; printf($format, $link); } else { echo $default; } } /** * 显示上一个内容的标题链接 * * @access public * @param string $format 格式 * @param string $default 如果没有上一篇,显示的默认文字 * @param array $custom 定制化样式 * @return void */ public function thePrev($format = '%s', $default = NULL, $custom = array()) { $content = $this->db->fetchRow($this->select()->where('table.contents.created < ?', $this->created) ->where('table.contents.status = ?', 'publish') ->where('table.contents.type = ?', $this->type) ->where('table.contents.password IS NULL') ->order('table.contents.created', Typecho_Db::SORT_DESC) ->limit(1)); if ($content) { $content = $this->filter($content); $default = array( 'title' => NULL, 'tagClass' => NULL ); $custom = array_merge($default, $custom); extract($custom); $linkText = empty($title) ? $content['title'] : $title; $linkClass = empty($tagClass) ? '' : 'class="' . $tagClass . '" '; $link = '' . $linkText . ''; printf($format, $link); } else { echo $default; } } /** * 获取关联内容组件 * * @access public * @param integer $limit 输出数量 * @param string $type 关联类型 * @return Typecho_Widget */ public function related($limit = 5, $type = NULL) { $type = strtolower($type); switch ($type) { case 'author': /** 如果访问权限被设置为禁止,则tag会被置为空 */ return $this->widget('Widget_Contents_Related_Author', array('cid' => $this->cid, 'type' => $this->type, 'author' => $this->author->uid, 'limit' => $limit)); default: /** 如果访问权限被设置为禁止,则tag会被置为空 */ return $this->widget('Widget_Contents_Related', array('cid' => $this->cid, 'type' => $this->type, 'tags' => $this->tags, 'limit' => $limit)); } } /** * 输出头部元数据 * * @access public * @param string $rule 规则 * @return void */ public function header($rule = NULL) { $rules = array(); $allows = array( 'description' => htmlspecialchars($this->_description), 'keywords' => htmlspecialchars($this->_keywords), 'generator' => $this->options->generator, 'template' => $this->options->theme, 'pingback' => $this->options->xmlRpcUrl, 'xmlrpc' => $this->options->xmlRpcUrl . '?rsd', 'wlw' => $this->options->xmlRpcUrl . '?wlw', 'rss2' => $this->_feedUrl, 'rss1' => $this->_feedRssUrl, 'commentReply' => 1, 'antiSpam' => 1, 'atom' => $this->_feedAtomUrl ); /** 头部是否输出聚合 */ $allowFeed = !$this->is('single') || $this->allow('feed') || $this->_makeSinglePageAsFrontPage; if (!empty($rule)) { parse_str($rule, $rules); $allows = array_merge($allows, $rules); } $allows = $this->pluginHandle()->headerOptions($allows, $this); $header = ''; if (!empty($allows['description'])) { $header .= '' . "\n"; } if (!empty($allows['keywords'])) { $header .= '' . "\n"; } if (!empty($allows['generator'])) { $header .= '' . "\n"; } if (!empty($allows['template'])) { $header .= '' . "\n"; } if (!empty($allows['pingback'])) { $header .= '' . "\n"; } if (!empty($allows['xmlrpc'])) { $header .= '' . "\n"; } if (!empty($allows['wlw'])) { $header .= '' . "\n"; } if (!empty($allows['rss2']) && $allowFeed) { $header .= '' . "\n"; } if (!empty($allows['rss1']) && $allowFeed) { $header .= '' . "\n"; } if (!empty($allows['atom']) && $allowFeed) { $header .= '' . "\n"; } if ($this->options->commentsThreaded && $this->is('single')) { if ('' != $allows['commentReply']) { if (1 == $allows['commentReply']) { $header .= " "; } else { $header .= ''; } } } /** 反垃圾设置 */ if ($this->options->commentsAntiSpam && $this->is('single')) { if ('' != $allows['antiSpam']) { if (1 == $allows['antiSpam']) { $header .= ""; } else { $header .= ''; } } } /** 输出header */ echo $header; /** 插件支持 */ $this->pluginHandle()->header($header, $this); } /** * 支持页脚自定义 * * @access public * @return void */ public function footer() { $this->pluginHandle()->footer($this); } /** * 输出cookie记忆别名 * * @access public * @param string $cookieName 已经记忆的cookie名称 * @param boolean $return 是否返回 * @return string */ public function remember($cookieName, $return = false) { $cookieName = strtolower($cookieName); if (!in_array($cookieName, array('author', 'mail', 'url'))) { return ''; } $value = Typecho_Cookie::get('__typecho_remember_' . $cookieName); if ($return) { return $value; } else { echo htmlspecialchars($value); } } /** * 输出归档标题 * * @param mixed $defines * @param string $before * @param string $end * @access public * @return void */ public function archiveTitle($defines = NULL, $before = ' » ', $end = '') { if ($this->_archiveTitle) { $define = '%s'; if (is_array($defines) && !empty($defines[$this->_archiveType])) { $define = $defines[$this->_archiveType]; } echo $before . sprintf($define, $this->_archiveTitle) . $end; } } /** * 输出关键字 * * @access public */ public function keywords($split = ',', $default = '') { echo empty($this->_keywords) ? $default : str_replace(',', $split, htmlspecialchars($this->_keywords)); } /** * 判断归档类型和名称 * * @access public * @param string $archiveType 归档类型 * @param string $archiveSlug 归档名称 * @return boolean */ public function is($archiveType, $archiveSlug = NULL) { return ($archiveType == $this->_archiveType || (($this->_archiveSingle ? 'single' : 'archive') == $archiveType && 'index' != $this->_archiveType) || ('index' == $archiveType && $this->_makeSinglePageAsFrontPage)) && (empty($archiveSlug) ? true : $archiveSlug == $this->_archiveSlug); } /** * 获取主题文件 * * @access public * @param string $fileName 主题文件 * @return void */ public function need($fileName) { require $this->_themeDir . $fileName; } /** * 输出视图 * * @access public * @return void */ public function render() { /** 处理静态链接跳转 */ $this->checkPermalink(); /** 添加Pingback */ $this->response->setHeader('X-Pingback', $this->options->xmlRpcUrl); $validated = false; //~ 自定义模板 if (!empty($this->_themeFile)) { if (file_exists($this->_themeDir . $this->_themeFile)) { $validated = true; } } if (!$validated && !empty($this->_archiveType)) { //~ 首先找具体路径, 比如 category/default.php if (!$validated && !empty($this->_archiveSlug)) { $themeFile = $this->_archiveType . '/' . $this->_archiveSlug . '.php'; if (file_exists($this->_themeDir . $themeFile)) { $this->_themeFile = $themeFile; $validated = true; } } //~ 然后找归档类型路径, 比如 category.php if (!$validated) { $themeFile = $this->_archiveType . '.php'; if (file_exists($this->_themeDir . $themeFile)) { $this->_themeFile = $themeFile; $validated = true; } } //针对attachment的hook if (!$validated && 'attachment' == $this->_archiveType) { if (file_exists($this->_themeDir . 'page.php')) { $this->_themeFile = 'page.php'; $validated = true; } else if (file_exists($this->_themeDir . 'post.php')) { $this->_themeFile = 'post.php'; $validated = true; } } //~ 最后找归档路径, 比如 archive.php 或者 single.php if (!$validated && 'index' != $this->_archiveType && 'front' != $this->_archiveType) { $themeFile = $this->_archiveSingle ? 'single.php' : 'archive.php'; if (file_exists($this->_themeDir . $themeFile)) { $this->_themeFile = $themeFile; $validated = true; } } if (!$validated) { $themeFile = 'index.php'; if (file_exists($this->_themeDir . $themeFile)) { $this->_themeFile = $themeFile; $validated = true; } } } /** 文件不存在 */ if (!$validated) { Typecho_Common::error(500); } /** 挂接插件 */ $this->pluginHandle()->beforeRender($this); /** 输出模板 */ require_once $this->_themeDir . $this->_themeFile; /** 挂接插件 */ $this->pluginHandle()->afterRender($this); } /** * 输出feed * * @access public * @return void */ public function feed() { $this->_feed->setSubTitle($this->_description); $this->_feed->setFeedUrl($this->_currentFeedUrl); $this->_feed->setBaseUrl(('/' == $this->request->feed || 0 == strlen($this->request->feed) || '/comments' == $this->request->feed || '/comments/' == $this->request->feed) ? $this->options->siteUrl : Typecho_Common::url($this->request->feed, $this->options->index)); $this->_feed->setFeedUrl($this->request->makeUriByRequest()); if ($this->is('single') || 'comments' == $this->parameter->type) { $this->_feed->setTitle(_t('%s 的评论', $this->options->title . ($this->_archiveTitle ? ' - ' . $this->_archiveTitle : NULL))); if ('comments' == $this->parameter->type) { $comments = $this->widget('Widget_Comments_Recent', 'pageSize=10'); } else { $comments = $this->widget('Widget_Comments_Recent', 'pageSize=10&parentId=' . $this->cid); } while ($comments->next()) { $suffix = $this->pluginHandle()->trigger($plugged)->commentFeedItem($this->_feedType, $comments); if (!$plugged) { $suffix = NULL; } $this->_feed->addItem(array( 'title' => $comments->author, 'content' => $comments->content, 'date' => $comments->created, 'link' => $comments->permalink, 'author' => (object) array( 'screenName' => $comments->author, 'url' => $comments->url, 'mail' => $comments->mail ), 'excerpt' => strip_tags($comments->content), 'suffix' => $suffix )); } } else { $this->_feed->setTitle($this->options->title . ($this->_archiveTitle ? ' - ' . $this->_archiveTitle : NULL)); while ($this->next()) { $suffix = $this->pluginHandle()->trigger($plugged)->feedItem($this->_feedType, $this); if (!$plugged) { $suffix = NULL; } $feedUrl = ''; if (Typecho_Feed::RSS2 == $this->_feedType) { $feedUrl = $this->feedUrl; } else if (Typecho_Feed::RSS1 == $this->_feedType) { $feedUrl = $this->feedRssUrl; } else if (Typecho_Feed::ATOM1 == $this->_feedType) { $feedUrl = $this->feedAtomUrl; } $this->_feed->addItem(array( 'title' => $this->title, 'content' => $this->options->feedFullText ? $this->content : (false !== strpos($this->text, '') ? $this->excerpt . "

permalink}\" title=\"{$this->title}\">[...]

" : $this->content), 'date' => $this->created, 'link' => $this->permalink, 'author' => $this->author, 'excerpt' => $this->description, 'comments' => $this->commentsNum, 'commentsFeedUrl' => $feedUrl, 'suffix' => $suffix )); } } $this->response->setContentType($this->_feedContentType); echo $this->_feed->__toString(); } }