/** * 独立页处理 * * @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); }
/** * pingbackPing * * @param string $source * @param string $target * @access public * @return void */ public function pingbackPing($source, $target) { /** 检查源地址是否存在*/ if (!($http = Typecho_Http_Client::get())) { return new IXR_Error(16, _t('源地址服务器错误')); } try { $http->setTimeout(5)->send($source); $response = $http->getResponseBody(); if (200 == $http->getResponseStatus()) { if (!$http->getResponseHeader('x-pingback')) { preg_match_all("/<link[^>]*rel=[\"']([^\"']*)[\"'][^>]*href=[\"']([^\"']*)[\"'][^>]*>/i", $response, $out); if (!isset($out[1]['pingback'])) { return new IXR_Error(50, _t('源地址不支持PingBack')); } } } else { return new IXR_Error(16, _t('源地址服务器错误')); } } catch (Exception $e) { return new IXR_Error(16, _t('源地址服务器错误')); } /** 检查目标地址是否正确*/ $pathInfo = Typecho_Common::url(substr($target, strlen($this->options->index)), '/'); $post = Typecho_Router::match($pathInfo); /** 这样可以得到cid或者slug*/ if (!$post instanceof Widget_Archive || !$post->have() || !$post->is('single')) { return new IXR_Error(33, _t('这个目标地址不存在')); } if ($post) { /** 检查是否可以ping*/ if ($post->allowPing) { /** 现在可以ping了,但是还得检查下这个pingback是否已经存在了*/ $pingNum = $this->db->fetchObject($this->db->select(array('COUNT(coid)' => 'num'))->from('table.comments')->where('table.comments.cid = ? AND table.comments.url = ? AND table.comments.type <> ?', $post->cid, $source, 'comment'))->num; if ($pingNum <= 0) { /** 现在开始插入以及邮件提示了 $response就是第一行请求时返回的数组*/ preg_match("/\\<title\\>([^<]*?)\\<\\/title\\>/is", $response, $matchTitle); $finalTitle = Typecho_Common::removeXSS(trim(strip_tags($matchTitle[1]))); /** 干掉html tag,只留下<a>*/ $text = Typecho_Common::stripTags($response, '<a href="">'); /** 此处将$target quote,留着后面用*/ $pregLink = preg_quote($target); /** 找出含有target链接的最长的一行作为$finalText*/ $finalText = ''; $lines = explode("\n", $text); foreach ($lines as $line) { $line = trim($line); if (NULL != $line) { if (preg_match("|<a[^>]*href=[\"']{$pregLink}[\"'][^>]*>(.*?)</a>|", $line)) { if (strlen($line) > strlen($finalText)) { /** <a>也要干掉,*/ $finalText = Typecho_Common::stripTags($line); } } } } /** 截取一段字*/ if (NULL == trim($finalText)) { return new IXR_Error('17', _t('源地址中不包括目标地址')); } $finalText = '[...]' . Typecho_Common::subStr($finalText, 0, 200, '') . '[...]'; $pingback = array('cid' => $post->cid, 'created' => $this->options->gmtTime, 'agent' => $this->request->getAgent(), 'ip' => $this->request->getIp(), 'author' => $finalTitle, 'url' => Typecho_Common::safeUrl($source), 'text' => $finalText, 'ownerId' => $post->author->uid, 'type' => 'pingback', 'status' => $this->options->commentsRequireModeration ? 'waiting' : 'approved'); /** 加入plugin */ $pingback = $this->pluginHandle()->pingback($pingback, $post); /** 执行插入*/ $insertId = $this->singletonWidget('Widget_Abstract_Comments')->insert($pingback); /** 评论完成接口 */ $this->pluginHandle()->finishPingback($this); return $insertId; /** todo:发送邮件提示*/ } else { return new IXR_Error(48, _t('PingBack已经存在')); } } else { return IXR_Error(49, _t('目标地址禁止Ping')); } } else { return new IXR_Error(33, _t('这个目标地址不存在')); } }
/** * 初始化函数 * * @access public * @return void * @throws Typecho_Widget_Exception */ public function action() { /** 回调方法 */ $callback = $this->request->type; $this->_content = Typecho_Router::match($this->request->permalink); /** 判断内容是否存在 */ if (false !== $this->_content && $this->_content instanceof Widget_Archive && $this->_content->have() && $this->_content->is('single') && in_array($callback, array('comment', 'trackback'))) { /** 如果文章不允许反馈 */ if ('comment' == $callback) { /** 评论关闭 */ if (!$this->_content->allow('comment')) { throw new Typecho_Widget_Exception(_t('对不起,此内容的反馈被禁止.'), 403); } /** 检查来源 */ if ($this->options->commentsCheckReferer && 'false' != $this->parameter->checkReferer) { $referer = $this->request->getReferer(); if (empty($referer)) { throw new Typecho_Widget_Exception(_t('评论来源页错误.'), 403); } $refererPart = parse_url($referer); $currentPart = parse_url($this->_content->permalink); if ($refererPart['host'] != $currentPart['host'] || 0 !== strpos($refererPart['path'], $currentPart['path'])) { //自定义首页支持 if ('page:' . $this->_content->cid == $this->options->frontPage) { $currentPart = parse_url(rtrim($this->options->siteUrl, '/') . '/'); if ($refererPart['host'] != $currentPart['host'] || 0 !== strpos($refererPart['path'], $currentPart['path'])) { throw new Typecho_Widget_Exception(_t('评论来源页错误.'), 403); } } else { throw new Typecho_Widget_Exception(_t('评论来源页错误.'), 403); } } } /** 检查ip评论间隔 */ if (!$this->user->pass('editor', true) && $this->_content->authorId != $this->user->uid && $this->options->commentsPostIntervalEnable) { $latestComment = $this->db->fetchRow($this->db->select('created')->from('table.comments')->where('cid = ?', $this->_content->cid)->order('created', Typecho_Db::SORT_DESC)->limit(1)); if ($latestComment && ($this->options->gmtTime - $latestComment['created'] > 0 && $this->options->gmtTime - $latestComment['created'] < $this->options->commentsPostInterval)) { throw new Typecho_Widget_Exception(_t('对不起, 您的发言过于频繁, 请稍侯再次发布.'), 403); } } } /** 如果文章不允许引用 */ if ('trackback' == $callback && !$this->_content->allow('ping')) { throw new Typecho_Widget_Exception(_t('对不起,此内容的引用被禁止.'), 403); } /** 调用函数 */ $this->{$callback}(); } else { throw new Typecho_Widget_Exception(_t('找不到内容'), 404); } }