You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

339 lines
13 KiB

<?php
if (!defined('__TYPECHO_ROOT_DIR__')) exit;
/**
* 反馈提交
*
* @category typecho
* @package Widget
* @copyright Copyright (c) 2008 Typecho team (http://www.typecho.org)
* @license GNU General Public License 2.0
* @version $Id$
*/
/**
* 反馈提交组件
*
* @category typecho
* @package Widget
* @copyright Copyright (c) 2008 Typecho team (http://www.typecho.org)
* @license GNU General Public License 2.0
*/
class Widget_Feedback extends Widget_Abstract_Comments implements Widget_Interface_Do
{
/**
* 内容对象
*
* @access private
* @var Widget_Archive
*/
private $_content;
/**
* 评论处理函数
*
* @throws Typecho_Widget_Exception
* @throws Exception
* @throws Typecho_Exception
*/
private function comment()
{
// 使用安全模块保护
$this->security->protect();
$comment = array(
'cid' => $this->_content->cid,
'created' => $this->options->gmtTime,
'agent' => $this->request->getAgent(),
'ip' => $this->request->getIp(),
'ownerId' => $this->_content->author->uid,
'type' => 'comment',
'status' => !$this->_content->allow('edit') && $this->options->commentsRequireModeration ? 'waiting' : 'approved'
);
/** 判断父节点 */
if ($parentId = $this->request->filter('int')->get('parent')) {
if ($this->options->commentsThreaded && ($parent = $this->db->fetchRow($this->db->select('coid', 'cid')->from('table.comments')
->where('coid = ?', $parentId))) && $this->_content->cid == $parent['cid']) {
$comment['parent'] = $parentId;
} else {
throw new Typecho_Widget_Exception(_t('父级评论不存在'));
}
}
//检验格式
$validator = new Typecho_Validate();
$validator->addRule('author', 'required', _t('必须填写用户名'));
$validator->addRule('author', 'xssCheck', _t('请不要在用户名中使用特殊字符'));
$validator->addRule('author', array($this, 'requireUserLogin'), _t('您所使用的用户名已经被注册,请登录后再次提交'));
$validator->addRule('author', 'maxLength', _t('用户名最多包含200个字符'), 200);
if ($this->options->commentsRequireMail && !$this->user->hasLogin()) {
$validator->addRule('mail', 'required', _t('必须填写电子邮箱地址'));
}
$validator->addRule('mail', 'email', _t('邮箱地址不合法'));
$validator->addRule('mail', 'maxLength', _t('电子邮箱最多包含200个字符'), 200);
if ($this->options->commentsRequireUrl && !$this->user->hasLogin()) {
$validator->addRule('url', 'required', _t('必须填写个人主页'));
}
$validator->addRule('url', 'url', _t('个人主页地址格式错误'));
$validator->addRule('url', 'maxLength', _t('个人主页地址最多包含200个字符'), 200);
$validator->addRule('text', 'required', _t('必须填写评论内容'));
$comment['text'] = $this->request->text;
/** 对一般匿名访问者,将用户数据保存一个月 */
if (!$this->user->hasLogin()) {
/** Anti-XSS */
$comment['author'] = $this->request->filter('trim')->author;
$comment['mail'] = $this->request->filter('trim')->mail;
$comment['url'] = $this->request->filter('trim')->url;
/** 修正用户提交的url */
if (!empty($comment['url'])) {
$urlParams = parse_url($comment['url']);
if (!isset($urlParams['scheme'])) {
$comment['url'] = 'http://' . $comment['url'];
}
}
$expire = $this->options->gmtTime + $this->options->timezone + 30*24*3600;
Typecho_Cookie::set('__typecho_remember_author', $comment['author'], $expire);
Typecho_Cookie::set('__typecho_remember_mail', $comment['mail'], $expire);
Typecho_Cookie::set('__typecho_remember_url', $comment['url'], $expire);
} else {
$comment['author'] = $this->user->screenName;
$comment['mail'] = $this->user->mail;
$comment['url'] = $this->user->url;
/** 记录登录用户的id */
$comment['authorId'] = $this->user->uid;
}
/** 评论者之前须有评论通过了审核 */
if (!$this->options->commentsRequireModeration && $this->options->commentsWhitelist) {
if ($this->size($this->select()->where('author = ? AND mail = ? AND status = ?', $comment['author'], $comment['mail'], 'approved'))) {
$comment['status'] = 'approved';
} else {
$comment['status'] = 'waiting';
}
}
if ($error = $validator->run($comment)) {
/** 记录文字 */
Typecho_Cookie::set('__typecho_remember_text', $comment['text']);
throw new Typecho_Widget_Exception(implode("\n", $error));
}
/** 生成过滤器 */
try {
$comment = $this->pluginHandle()->comment($comment, $this->_content);
} catch (Typecho_Exception $e) {
Typecho_Cookie::set('__typecho_remember_text', $comment['text']);
throw $e;
}
/** 添加评论 */
$commentId = $this->insert($comment);
Typecho_Cookie::delete('__typecho_remember_text');
$this->db->fetchRow($this->select()->where('coid = ?', $commentId)
->limit(1), array($this, 'push'));
/** 评论完成接口 */
$this->pluginHandle()->finishComment($this);
$this->response->goBack('#' . $this->theId);
}
/**
* 引用处理函数
*
* @access private
* @return void
*/
private function trackback()
{
/** 如果不是POST方法 */
if (!$this->request->isPost() || $this->request->getReferer()) {
$this->response->redirect($this->_content->permalink);
}
/** 如果库中已经存在当前ip为spam的trackback则直接拒绝 */
if ($this->size($this->select()
->where('status = ? AND ip = ?', 'spam', $this->request->getIp())) > 0) {
/** 使用404告诉机器人 */
throw new Typecho_Widget_Exception(_t('找不到内容'), 404);
}
$trackback = array(
'cid' => $this->_content->cid,
'created' => $this->options->gmtTime,
'agent' => $this->request->getAgent(),
'ip' => $this->request->getIp(),
'ownerId' => $this->_content->author->uid,
'type' => 'trackback',
'status' => $this->options->commentsRequireModeration ? 'waiting' : 'approved'
);
$trackback['author'] = $this->request->filter('trim')->blog_name;
$trackback['url'] = $this->request->filter('trim')->url;
$trackback['text'] = $this->request->excerpt;
//检验格式
$validator = new Typecho_Validate();
$validator->addRule('url', 'required', 'We require all Trackbacks to provide an url.')
->addRule('url', 'url', 'Your url is not valid.')
->addRule('url', 'maxLength', 'Your url is not valid.', 200)
->addRule('text', 'required', 'We require all Trackbacks to provide an excerption.')
->addRule('author', 'required', 'We require all Trackbacks to provide an blog name.')
->addRule('author', 'xssCheck', 'Your blog name is not valid.')
->addRule('author', 'maxLength', 'Your blog name is not valid.', 200);
$validator->setBreak();
if ($error = $validator->run($trackback)) {
$message = array('success' => 1, 'message' => current($error));
$this->response->throwXml($message);
}
/** 截取长度 */
$trackback['text'] = Typecho_Common::subStr($trackback['text'], 0, 100, '[...]');
/** 如果库中已经存在重复url则直接拒绝 */
if ($this->size($this->select()
->where('cid = ? AND url = ? AND type <> ?', $this->_content->cid, $trackback['url'], 'comment')) > 0) {
/** 使用403告诉机器人 */
throw new Typecho_Widget_Exception(_t('禁止重复提交'), 403);
}
/** 生成过滤器 */
$trackback = $this->pluginHandle()->trackback($trackback, $this->_content);
/** 添加引用 */
$this->insert($trackback);
/** 评论完成接口 */
$this->pluginHandle()->finishTrackback($this);
/** 返回正确 */
$this->response->throwXml(array('success' => 0, 'message' => 'Trackback has registered.'));
}
/**
* 过滤评论内容
*
* @access public
* @param string $text 评论内容
* @return string
*/
public function filterText($text)
{
$text = str_replace("\r", '', trim($text));
$text = preg_replace("/\n{2,}/", "\n\n", $text);
return Typecho_Common::removeXSS(Typecho_Common::stripTags(
$text, $this->options->commentsHTMLTagAllowed));
}
/**
* 对已注册用户的保护性检测
*
* @access public
* @param string $userName 用户名
* @return void
*/
public function requireUserLogin($userName)
{
if ($this->user->hasLogin() && $this->user->screenName != $userName) {
/** 当前用户名与提交者不匹配 */
return false;
} else if (!$this->user->hasLogin() && $this->db->fetchRow($this->db->select('uid')
->from('table.users')->where('screenName = ? OR name = ?', $userName, $userName)->limit(1))) {
/** 此用户名已经被注册 */
return false;
}
return true;
}
/**
* 初始化函数
*
* @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);
}
}
}