getPrefix();
try {
$db->query("ALTER TABLE `{$prefix}users` ADD `user_feed` VARCHAR(255) DEFAULT NULL");
} catch (Exception $e) {
// 字段可能已存在
}
// 添加管理菜单
Helper::addPanel(3, 'UserCard/manage-users.php', 'RSS卡片', 'RSS卡片', 'administrator');
// 前端资源
Typecho_Plugin::factory('Widget_Archive')->header = array('UserCard_Plugin', 'addHeader');
return _t('用户卡片插件已激活');
}
/**
* 禁用插件
*/
public static function deactivate()
{
// 移除管理菜单
Helper::removePanel(3, 'UserCard/manage-users.php');
return _t('用户卡片插件已禁用');
}
/**
* 插件配置
*/
public static function config(Typecho_Widget_Helper_Form $form)
{
// 管理员评论是否显示卡片
$show_admin_card = new Typecho_Widget_Helper_Form_Element_Radio(
'show_admin_card',
array(
'1' => _t('显示'),
'0' => _t('不显示')
),
'1',
_t('管理员评论卡片'),
_t('是否在管理员发表的评论上显示用户卡片(普通用户不受此设置影响)')
);
$form->addInput($show_admin_card);
// RSS缓存时间
$cache_time = new Typecho_Widget_Helper_Form_Element_Text(
'cache_time',
NULL,
'3600',
_t('RSS缓存时间(秒)'),
_t('RSS数据缓存时间,建议设置为3600秒(1小时)')
);
$form->addInput($cache_time->addRule('required', _t('必须填写缓存时间'))->addRule('isInteger', _t('请输入整数')));
// 最多显示条数
$max_items = new Typecho_Widget_Helper_Form_Element_Text(
'max_items',
NULL,
'5',
_t('最多显示文章数'),
_t('用户卡片中最多显示的RSS文章数量')
);
$form->addInput($max_items->addRule('required', _t('必须填写显示条数'))->addRule('isInteger', _t('请输入整数')));
// RSS超时时间
$timeout = new Typecho_Widget_Helper_Form_Element_Text(
'timeout',
NULL,
'10',
_t('RSS请求超时时间(秒)'),
_t('获取RSS数据时的超时时间')
);
$form->addInput($timeout->addRule('required', _t('必须填写超时时间'))->addRule('isInteger', _t('请输入整数')));
// 添加卡片显示延迟
$hover_delay = new Typecho_Widget_Helper_Form_Element_Text(
'hover_delay',
NULL,
'200',
_t('卡片显示延迟(毫秒)'),
_t('鼠标悬停后显示卡片的延迟时间,防止误触发')
);
$form->addInput($hover_delay->addRule('required', _t('必须填写延迟时间'))->addRule('isInteger', _t('请输入整数')));
}
/**
* 个人配置 - 保持为空
*/
public static function personalConfig(Typecho_Widget_Helper_Form $form)
{
// 不在个人页面显示RSS地址字段
}
/**
* 添加头部资源
*/
public static function addHeader()
{
// 只在文章页面加载
if (!Typecho_Widget::widget('Widget_Archive')->is('single')) {
return;
}
// 获取配置
$options = Typecho_Widget::widget('Widget_Options')->plugin('UserCard');
$hover_delay = isset($options->hover_delay) ? intval($options->hover_delay) : 200;
echo '';
echo '';
}
/**
* 生成用户卡片(供主题调用)
*/
public static function render($comments)
{
if (!$comments || $comments->authorId == 0) {
// 游客
if ($comments->url) {
return '' . $comments->author . '';
} else {
return $comments->author;
}
}
try {
$db = Typecho_Db::get();
$user = $db->fetchRow($db->select()
->from('table.users')
->where('uid = ?', $comments->authorId));
if (!$user) {
return $comments->author;
}
// 获取插件配置
$options = Typecho_Widget::widget('Widget_Options')->plugin('UserCard');
$show_admin_card = isset($options->show_admin_card) ? intval($options->show_admin_card) : 1;
// 检查用户是否为管理员
$is_admin = ($user['group'] == 'administrator');
// 如果是管理员且配置为不显示卡片,则返回普通链接
if ($is_admin && !$show_admin_card) {
if (!empty($user['url'])) {
return '' . $comments->author . '';
} else {
return $comments->author;
}
}
// 评论数
$commentCount = $db->fetchObject($db->select('COUNT(*) as cnt')
->from('table.comments')
->where('authorId = ?', $user['uid'])
->where('status = ?', 'approved'))->cnt;
// RSS文章
$rssItems = array();
if (!empty($user['user_feed'])) {
$rssItems = self::getRssItems($user['user_feed']);
}
// 基本信息
$displayName = !empty($user['screenName']) ? $user['screenName'] : $user['name'];
$userUrl = !empty($user['url']) ? $user['url'] : '#';
// 构建HTML
$html = '';
return $html;
} catch (Exception $e) {
// 出错时返回简单链接
if ($comments->url) {
return '' . $comments->author . '';
} else {
return $comments->author;
}
}
}
/**
* 获取RSS文章
*/
private static function getRssItems($url)
{
if (empty($url)) {
return array();
}
// 检查缓存
$cacheKey = 'usercard_rss_' . md5($url);
$cache = self::getCache($cacheKey);
if ($cache !== false) {
return $cache;
}
// 获取配置
$options = Typecho_Widget::widget('Widget_Options')->plugin('UserCard');
$timeout = isset($options->timeout) ? intval($options->timeout) : 10;
// 固定从RSS获取最多10条数据保存到缓存
$fetch_max_items = 10;
// 获取RSS
$context = stream_context_create(array(
'http' => array('timeout' => $timeout),
'ssl' => array('verify_peer' => false)
));
$content = @file_get_contents($url, false, $context);
if (empty($content)) {
return array();
}
$xml = @simplexml_load_string($content);
if (!$xml) {
return array();
}
$items = array();
$counter = 0;
// RSS格式
if (isset($xml->channel->item)) {
foreach ($xml->channel->item as $item) {
if ($counter >= $fetch_max_items) break;
$title = trim((string)$item->title);
$link = trim((string)$item->link);
if ($title && $link) {
$pubDate = isset($item->pubDate) ? strtotime((string)$item->pubDate) : time();
$items[] = array(
'title' => $title,
'link' => $link,
'date' => $pubDate
);
$counter++;
}
}
}
// 设置缓存
$cacheTime = isset($options->cache_time) ? intval($options->cache_time) : 3600;
self::setCache($cacheKey, $items, $cacheTime);
return $items;
}
/**
* 获取缓存
*/
private static function getCache($key)
{
$cacheFile = dirname(__FILE__) . '/cache/' . $key . '.json';
if (file_exists($cacheFile)) {
$data = json_decode(file_get_contents($cacheFile), true);
if ($data && isset($data['expire']) && $data['expire'] > time()) {
return $data['data'];
}
}
return false;
}
/**
* 设置缓存
*/
private static function setCache($key, $data, $expire = 3600)
{
$cacheDir = dirname(__FILE__) . '/cache';
if (!is_dir($cacheDir)) {
@mkdir($cacheDir, 0777, true);
}
$cacheFile = $cacheDir . '/' . $key . '.json';
$cacheData = array(
'data' => $data,
'expire' => time() + $expire
);
@file_put_contents($cacheFile, json_encode($cacheData, JSON_UNESCAPED_UNICODE));
}
}