This commit is contained in:
201
Stat/Plugin.php
Normal file
201
Stat/Plugin.php
Normal file
@@ -0,0 +1,201 @@
|
||||
<?php
|
||||
if (!defined('__TYPECHO_ROOT_DIR__')) exit;
|
||||
|
||||
/**
|
||||
* 页面浏览次数统计插件 【<a href="https://github.com/typecho-fans/plugins" target="_blank">TF</a>社区维护版】
|
||||
*
|
||||
* @package Stat
|
||||
* @author 羽中, Jozhn, Hanny
|
||||
* @version 1.0.4
|
||||
* @dependence 17.10.30-*
|
||||
* @link https://github.com/typecho-fans/plugins/tree/master/Stat
|
||||
*
|
||||
* version 1.0.4 at 2020-07-08
|
||||
* 增加计数输出和忽略重复访问功能
|
||||
* 增加排行输出可指定分类ID与类型
|
||||
*
|
||||
* version 1.0.3 at 2018-08-24
|
||||
* 修复PDO下数据表检测失败的错误
|
||||
*
|
||||
* 历史版本
|
||||
* version 1.0.2 at 2010-07-03
|
||||
* 终于支持前台调用了
|
||||
* 接口支持Typecho 0.8的计数
|
||||
* 增加SQLite的支持
|
||||
* version 1.0.1 at 2010-01-02
|
||||
* 修改安装出错处理
|
||||
* 修改安装时默认值错误
|
||||
* version 1.0.0 at 2009-12-12
|
||||
* 实现浏览次数统计的基本功能
|
||||
*/
|
||||
class Stat_Plugin implements Typecho_Plugin_Interface
|
||||
{
|
||||
|
||||
/**
|
||||
* 激活插件方法,如果激活失败,直接抛出异常
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
* @throws Typecho_Plugin_Exception
|
||||
*/
|
||||
public static function activate()
|
||||
{
|
||||
$info = Stat_Plugin::sqlInstall();
|
||||
Typecho_Plugin::factory('Widget_Archive')->singleHandle = array('Stat_Plugin', 'singleHandle');
|
||||
Typecho_Plugin::factory('Widget_Archive')->select = array('Stat_Plugin', 'selectHandle');
|
||||
/* 模版调用钩子 */
|
||||
Typecho_Plugin::factory('Widget_Archive')->callStat = array('Stat_Plugin', 'outputStat');
|
||||
/* 输出排行支持4种参数如: <?php $this->rank(
|
||||
'源码含{link}{title}',
|
||||
'类型如post/page/attachment',
|
||||
'分类或标签mid用逗号隔开',
|
||||
条目数
|
||||
); ?> */
|
||||
Typecho_Plugin::factory('Widget_Archive')->callRank = array('Stat_Plugin', 'outputRank');
|
||||
return _t($info);
|
||||
}
|
||||
|
||||
//SQL创建
|
||||
public static function sqlInstall()
|
||||
{
|
||||
$db = Typecho_Db::get();
|
||||
$type = explode('_', $db->getAdapterName());
|
||||
$type = array_pop($type);
|
||||
$prefix = $db->getPrefix();
|
||||
try {
|
||||
$select = $db->select('table.contents.views')->from('table.contents');
|
||||
$db->query($select, Typecho_Db::READ);
|
||||
return '检测到统计字段,插件启用成功';
|
||||
} catch (Typecho_Db_Exception $e) {
|
||||
$code = $e->getCode();
|
||||
if(('Mysql' == $type && ('42S22'==$code || 1054 == $code)) ||
|
||||
('SQLite' == $type && ('HY000' == $code || 1 == $code))) {
|
||||
try {
|
||||
if ('Mysql' == $type) {
|
||||
$db->query("ALTER TABLE `".$prefix."contents` ADD `views` INT( 10 ) NOT NULL DEFAULT '0' COMMENT '页面浏览次数';");
|
||||
} else if ('SQLite' == $type) {
|
||||
$db->query("ALTER TABLE `".$prefix."contents` ADD `views` INT( 10 ) NOT NULL DEFAULT '0'");
|
||||
} else {
|
||||
throw new Typecho_Plugin_Exception('不支持的数据库类型:'.$type);
|
||||
}
|
||||
return '建立统计字段,插件启用成功';
|
||||
} catch (Typecho_Db_Exception $e) {
|
||||
$code = $e->getCode();
|
||||
if(('Mysql' == $type && ('42S21'==$code || 1060 == $code)) ) {
|
||||
return '统计字段已经存在,插件启用成功';
|
||||
}
|
||||
throw new Typecho_Plugin_Exception('统计插件启用失败。错误号:'.$code);
|
||||
}
|
||||
}
|
||||
throw new Typecho_Plugin_Exception('数据表检测失败,统计插件启用失败。错误号:'.$code);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 禁用插件方法,如果禁用失败,直接抛出异常
|
||||
*
|
||||
* @static
|
||||
* @access public
|
||||
* @return void
|
||||
* @throws Typecho_Plugin_Exception
|
||||
*/
|
||||
public static function deactivate(){}
|
||||
|
||||
/**
|
||||
* 获取插件配置面板
|
||||
*
|
||||
* @access public
|
||||
* @param Typecho_Widget_Helper_Form $form 配置面板
|
||||
* @return void
|
||||
*/
|
||||
public static function config(Typecho_Widget_Helper_Form $form){}
|
||||
|
||||
/**
|
||||
* 个人用户的配置面板
|
||||
*
|
||||
* @access public
|
||||
* @param Typecho_Widget_Helper_Form $form
|
||||
* @return void
|
||||
*/
|
||||
public static function personalConfig(Typecho_Widget_Helper_Form $form){}
|
||||
|
||||
/**
|
||||
* 插件实现方法
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public static function outputStat($widget)
|
||||
{
|
||||
$db = Typecho_Db::get();
|
||||
$row = $db->fetchRow($db->select('views')->from('table.contents')->where('cid = ?', $widget->cid));
|
||||
echo $row['views'];
|
||||
}
|
||||
|
||||
public static function viewStat($cid)
|
||||
{
|
||||
$name = '__StatViews';
|
||||
$cids = Json::decode(Typecho_Cookie::get($name), true);
|
||||
if (!empty($cids) && in_array($cid, $cids)) {
|
||||
return;
|
||||
} else {
|
||||
if (!$cids) $cids = array();
|
||||
array_push($cids, $cid);
|
||||
Typecho_Cookie::set($name, Json::encode($cids), time()+60*60); //默认60分钟可自行修改
|
||||
|
||||
$db = Typecho_Db::get();
|
||||
$prefix = $db->getPrefix();
|
||||
$sql = "UPDATE `".$prefix."contents` SET `views` = `views` + 1 WHERE `cid` = ".intval($cid).";";
|
||||
$db->query($sql);
|
||||
}
|
||||
}
|
||||
|
||||
public static function selectHandle($archive)
|
||||
{
|
||||
$db = Typecho_Db::get();
|
||||
$options = Typecho_Widget::widget('Widget_Options');
|
||||
return $db->select('*')->from('table.contents')->where('table.contents.status = ?', 'publish')
|
||||
->where('table.contents.created < ?', $options->gmtTime);
|
||||
}
|
||||
|
||||
public static function singleHandle($select, $archive)
|
||||
{
|
||||
Stat_Plugin::viewStat($select->stack[0]['cid']);
|
||||
}
|
||||
|
||||
public static function outputRank($widget, array $params)
|
||||
{
|
||||
$db = Typecho_Db::get();
|
||||
$items = $db->fetchAll($db->select('table.metas.mid')->from('table.metas')
|
||||
->where('table.metas.type = ?', 'category'));
|
||||
foreach ($items as $item) {
|
||||
$all[] = $item['mid'];
|
||||
}
|
||||
|
||||
$format = !empty($params[0]) && is_string($params[0]) ? $params[0] : '<li><a href="{link}">{title}</a></li>';
|
||||
$type = !empty($params[1]) && is_string($params[1]) ? $params[1] : 'post';
|
||||
$category = !empty($params[2]) && is_string($params[2]) ? $params[2] : 'ALL';
|
||||
$limit = !empty($params[3]) && is_numeric($params[3]) ? $params[3] : 10;
|
||||
|
||||
if ($type == 'post') {
|
||||
$select = $db->select()->from('table.contents')
|
||||
->join('table.relationships', 'table.relationships.cid = table.contents.cid',Typecho_Db::INNER_JOIN)
|
||||
->where('table.contents.status = ?', 'publish')
|
||||
->where('table.relationships.mid in ('.($category=='ALL' ? implode(',', $all) : $category).')')
|
||||
->order('views', Typecho_Db::SORT_DESC)
|
||||
->limit($limit);
|
||||
} else {
|
||||
$select = $db->select()->from('table.contents')
|
||||
->where('table.contents.status = ?', 'publish')
|
||||
->where('table.contents.type = ?', ''.$type.'')
|
||||
->order('views', Typecho_Db::SORT_DESC)
|
||||
->limit($limit);
|
||||
}
|
||||
$posts = $db->fetchAll($select);
|
||||
|
||||
foreach ($posts as $post) {
|
||||
$value = Typecho_Widget::widget('Widget_Abstract_Contents')->push($post);
|
||||
echo str_replace(array('{link}','{title}'), array($value['permalink'], $value['title']), $format);
|
||||
}
|
||||
}
|
||||
}
|
||||
84
Stat/README.md
Normal file
84
Stat/README.md
Normal file
@@ -0,0 +1,84 @@
|
||||
<a href="https://typecho-fans.github.io">
|
||||
<img src="https://typecho-fans.github.io/text-logo.svg" alt="TF Logo" title="Typecho Fans开源作品社区" align="right" height="100" />
|
||||
</a>
|
||||
|
||||
Stat v1.0.4 - 社区维护版
|
||||
======================
|
||||
<h4 align="center">—— 老牌文章浏览计数器插件,首创单页句柄机制支持附件,现已加入模板输出钩子。</h4>
|
||||
|
||||
<p align="center">
|
||||
<a href="#使用说明">使用说明</a> •
|
||||
<a href="#版本历史">版本历史</a> •
|
||||
<a href="#贡献作者">贡献作者</a> •
|
||||
<a href="#附注链接">附注/链接</a> •
|
||||
<a href="#授权协议">授权协议</a>
|
||||
</p>
|
||||
|
||||
---
|
||||
|
||||
## 使用说明
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
###### 通过挂载单页句柄实现不依赖模板输出的计数功能,除文章外独立页面甚至附件页面均可作用。新版可忽略1小时内重复访问,增加输出函数并支持参数定制。
|
||||
|
||||
**使用方法**:
|
||||
##### 1. 下载本插件,放在 `usr/plugins/` 目录中,确保文件夹名为 Stat;
|
||||
##### 2. 激活插件,即可自动添加计数字段并按访问自增;
|
||||
##### 3. 需输出当前文章计数数字可在模板文件如post.php中添加`<?php $this->stat(); ?>`;
|
||||
##### 4. 需输出文章排行列表可在模板文件如sidebar.php中添加`<?php $this->rank(); ?>`。
|
||||
|
||||
**注意事项**:
|
||||
* ##### 以上排行列表输出函数内支持用英文逗号隔开4种参数,即`$this->rank( "源码规则", "页面类型", "分类或标签mid", "数目" )`,赋值如下表:
|
||||
|
||||
|参数|可用值|缺省值|说明|
|
||||
|---|:---:|:---:|:---:|
|
||||
|源码规则|任意Html代码<br/>{title}即文章标题<br/>{link}为文章地址|`<li><a href="{link}">{title}</a></li>`|每条输出源码格式|
|
||||
|页面类型|post<br/>page<br/>attachment|post<br/>(文章)|可排行页面或附件|
|
||||
|分类或标签mid|整数<br/>(多个可用,隔开)|ALL<br/>(所有)|仅对文章类型有效|
|
||||
|数目|整数|10|总共输出文章条数|
|
||||
|
||||
* ##### 查看分类标签mid方法:后台进入管理-分类或标签页面,点击分类名称或编辑标签,地址栏?后即会显示mid等于的值。
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
## 版本历史
|
||||
|
||||
* v1.0.4 (20-07-08 [@jzwalk](https://github.com/jzwalk))
|
||||
* 增加计数输出和忽略重复访问功能;
|
||||
* 增加排行输出可指定分类ID与类型。
|
||||
* v1.0.3 (18-08-24 [@jozhn](https://github.com/jozhn))
|
||||
* 修复PDO下数据表检测失败的错误。
|
||||
* v1.0.2 (10-07-03 [@Hanny](http://www.imhan.com))
|
||||
* 终于支持前台调用了;
|
||||
* 接口支持Typecho 0.8的计数;
|
||||
* 增加SQLite的支持。
|
||||
* v1.0.1 (10-01-02 [@Hanny](http://www.imhan.com))
|
||||
* 修改安装出错处理;
|
||||
* 修改安装时默认值错误。
|
||||
* v1.0.0 (09-12-12 [@Hanny](http://www.imhan.com))
|
||||
* 实现浏览次数统计的基本功能。
|
||||
|
||||
## 贡献作者
|
||||
|
||||
[](https://github.com/jzwalk) | [](https://github.com/jozhn) | [](http://www.imhan.com)
|
||||
:---:|:---:|:---:
|
||||
[jzwalk](https://github.com/jzwalk) (2020) | [jozhn](https://github.com/jozhn) (2018) | [Hanny](http://www.imhan.com) (2009)
|
||||
|
||||
## 附注/链接
|
||||
|
||||
* [微调版(jozhn)](https://github.com/jozhn/Stat-for-Typecho) - 修复激活报错。
|
||||
* [原版](http://www.imhan.com/typecho) - 实现浏览计数功能。
|
||||
|
||||
本插件最初仅为测试用未实现任何输出,可与[Attachment](https://github.com/typecho-fans/plugins/tree/master/Attachment)搭配统计附件下载。
|
||||
另有基于本作句柄机制的二次开发版[TeStat](https://github.com/jiangmuzi/TeStat)可供参考。
|
||||
|
||||
## 授权协议
|
||||
|
||||
TF目录下的社区维护版作品如果没有明确声明,默认采用与Typecho相同的[GPLv2](https://github.com/typecho/typecho/blob/master/LICENSE.txt)开源协议。(要求提及出处,保持开源并注明修改。)
|
||||
|
||||
> Stat原作未附协议声明,原作者保留所有权利。 © [Hanny](http://www.imhan.com)
|
||||
Reference in New Issue
Block a user