何为缓存?
具体http://www.thinkphp.cn/code/1579.html
简单的说就是减少服务器压力,将用户常见的的网页事先静态存储好。个人认为,一般情况下TP用的是数据缓存,即将数据缓存到一个php文件中,文件名包含一个id来唯一标示(TP中是一个md5值)
搭建环境
配置数据库
1 2 3 4 5
| CREATE database article CREATE TABLE article ( content VARCHAR(255) ); 'DB_NAME' => 'aritcle'
|
写入代码
修改home/controller/indexController.class.php 如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <?php namespace Home\Controller; class IndexController { function index(){ echo "welcome"; } function save(){ $content = array('content' => I('get.content')); $amodel = M('article'); $amodel->data($content)->add(); } function cache(){ $amodel = M('article'); $content = $amodel->select(); var_dump($content); S('content',$content,3600); } }
|
缓存函数用法
在TP3.2版本中,起缓存功能的是S函数,用法如下
1 2 3 4 5 6
| S('data',$Data);
S('data',$Data,3600);
S('data',NULL);
|
下面为第一次创建缓存(理想情况下)的代码跟踪
跟进S函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
function S($name,$value='',$options=null) { static $cache = ''; }elseif(empty($cache)) { $cache = Think\Cache::getInstance(); } if(''=== $value){ return $cache->get($name); }elseif(is_null($value)) { return $cache->rm($name); }else { return $cache->set($name, $value, $expire); } }
|
创建缓存时进入Think\Cache::getInstance()
,这个方法检索静态数组是否已经有缓存实例,如果有就返回,没有则创建。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
static function getInstance($type='',$options=array()) { static $_instance = array(); $guid = $type.to_guid_string($options); if(!isset($_instance[$guid])){ $obj = new Cache(); $_instance[$guid] = $obj->connect($type,$options); } return $_instance[$guid]; }
|
md5标识号生成方式
1 2 3 4 5 6 7 8 9 10 11 12
|
function to_guid_string($mix) { } else { $mix = serialize($mix); } return md5($mix); }
|
跟进$obj->connect($type,$options);
这个方法是在配置一些初始值,比如缓存的类型,路径信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
public function connect($type='',$options=array()) { if(empty($type)) $type = C('DATA_CACHE_TYPE'); $class = strpos($type,'\\')? $type : 'Think\\Cache\\Driver\\'.ucwords(strtolower($type)); if(class_exists($class)) $cache = new $class($options); else E(L('_CACHE_TYPE_INVALID_').':'.$type); return $cache; }
|
最后一步写入缓存
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
public function set($name,$value,$expire=null) { $filename = $this->filename($name); $data = serialize($value); $data = "<?php\n//".sprintf('%012d',$expire).$check.$data."\n?>"; $result = file_put_contents($filename,$data); }
|
关键点在<?php\n//".sprintf('%012d',$expire).$check.$data."\n?>
理想情况下这里的利用条件得天独厚,因为两个尖括号都写好了,不用担心I函数过滤的问题。而其中的data就是传入进去的一句话:
在Runtime/Temp下 getshell
最后
文中一直提到是理想情况,这里解释一下,跟踪的时候省略了一些代码,其中有的是利用的前提条件,举个例子,文中提到理想情况下webshell文件名是MD5(‘content’)即9a0364b9e99bb480dd25e1f0284c8555
/原因是TP中有一个给MD5值加盐的参数可以在配置文件中申明DATA_CACHE_KEY
,如果管理员事先设置了这个参数,文件名就会变得不可猜,具体如下
还有一些前提条件,例如Runtime不在web目录内,一般情况也是利用不了的。
如何出错,恳请指点