月度归档:2015年07月

实时相似度计算实例

$a = [['Top','Hot','2015','Dress','Dear','Fest','mini','good'],['Welcome','Feval'],6];
$b = [['New','Arrival','Lastest','Hotest','AAA'],['Sale','Big'],4];
$c = [['x','y'],['z'],2];
//$ab = array($a,$b);
$ab = array($a,$b,$c);

$titles = [];
foreach($ab as $a){
    $newArr = [];
    if(count($a[1]) > 0){
        $hotCount = count($a[1]);
        for($i=$hotCount; $i>=0; $i--){
            $n = $a[2]-$i;
            if($n == 0){
                $newArr[] = $a[1];
            }else{
                $h  = ArrayCombination::get($a[1],$i);
                $nr = ArrayCombination::get($a[0],$n);
                
                $tmp = ArrayCombination::combine($h, $nr);
                $newArr = array_merge($newArr,$tmp);
            }
        }
    }else{
        $newArr = ArrayCombination::get($a[0],$a[2]);
    }
    if(empty($titles)){
        $titles = $newArr;
    }else{
        $titles = ArrayCombination::combine($titles,$newArr);
    }
}

echo "Total -- ".count($titles)."\n";

$limit = 20;
$silimar = 0.6;

print_r(getTitle($titles,$limit,$silimar));
echo "\n++++++++++++++++++++++++++++++++++++\n";
print_r(getTitle($titles,$limit,$silimar,true));


//////////////////////////////////////////////////
function getTitle(&$titles, $limit, $silimar=0.8, $force=false){
    $start = getTime();
    $ts = new TextSimilarity();
    
    $need[0] = array('rate'=>0,'title'=>$titles[0]);
    $index = array_keys($titles);

    $now = 0; $compute = 0;
    foreach($index as $kk=>$i){
      
        $ts->setWords('right',$titles[$i]);
        $wasBreak = false;
        $min = 1;
        foreach($need as $t){
            $ts->setWords('left',$t['title']);
            $rate = $ts->getRate();
            $compute++;
            if($rate > $silimar){
                $wasBreak = true;
                break;
            }else{
                if($rate < $min){
                    $min = $rate;
                }
            }
        }
        if(!$wasBreak){
            $need[] = array('rate'=>$min,'title'=>$titles[$i]);
            //去掉已经在集合中的
            unset($index[$kk]);
        }
        //数量已经够
        if(count($need) >= $limit){
            break;
        }
        //计算次数超过
        if(($compute > 200000) || ($time > 15)){
            if($time > 15){
                echo "time out";
            }else{
                echo "compute out";
            }
            break;
        }
        $now++;
    }
    
    //数量不够并且强制填充
    if($force){
        $ttl = count($index);
        $alsoNeed = $limit - count($need);
        if(($alsoNeed > 0) && ($ttl > 0)){
            $addArr = array();
            if($alsoNeed < $ttl){
                $addArr = array_rand($index,$alsoNeed);
            }else{
                $addArr = $index;
            }
            //echo $ttl, " ", $alsoNeed, " ",count($addArr);
            foreach($addArr as $ar){
                $need[] = array('rate'=>0,'title'=>$titles[$ar]);
            }
        }
        //如果还不够,拷贝
        $nowTotal = count($need);
        $nowNeed = $limit - $nowTotal;
        if($nowNeed > 0){
            for($jj=0;$jj<$nowNeed;$jj++){
                $idxx = $jj%$nowTotal;
                $need[] = $need[$idxx];
            }
        }
    }
    $ret = array();
    foreach($need as $nd){
        $ret[] = implode(" ", $nd['title']);
    }
    return $ret;
}


//////////////////////////////////////////////////
class ArrayCombination {
    // 计算组合数,比如3取2,组合数为3; 6取2,组合数15
    public static function countTotal($total,$count){
        $total = (int)$total;
        $count = (int)$count;
    
        if(($total < 1) || ($count < 1) || ($total < $count)){
            return 0;
        }
        $u = $d = 1;
        for($i=$count; $i>0; $i--) {
            $u *= $total--;
            $d *= $i;
        }
        return (int)($u/$d);
    }
    
    // 组合算法 获取所有组合
    public static function get($arr, $size = 1) {
        $len = count($arr);
        $max = pow(2,$len) - pow(2,$len-$size);
        $min = pow(2,$size)-1;
         
        $r_arr = array();
        for ($i=$min; $i<=$max; $i++){
            $count = 0;
            $t_arr = array();
            for ($j=0; $j<$len; $j++){
                $a = pow(2, $j);
                $t = $i&$a;
                if($t == $a){
                    $t_arr[] = $arr[$j];
                    $count++;
                }
            }
            if($count == $size){
                $r_arr[] = $t_arr;
            }
        }
        return $r_arr;
    } 
    
    /*********************
    [
        [1,2],
        [3,4]
    ]
    [
        [5],
        [6]
    ]
    -----------------------
    [
        [1,2,5],
        [1,2,6],
        [3,4,5],
        [3,4,6]
    ]
    */
    public static function combine($arr1,$arr2){
        if(!is_array($arr1)){ return array(); }
        if(!is_array($arr2)){ return $arr1; }
        
        $newArr = array();
        foreach($arr1 as $av) {
            foreach($arr2 as $bv){
                $newArr[] = array_merge($av,$bv);
            }
        }
        return $newArr;
    }
    
}
#----------- calculate time function-------------
function getTime(){
    $TIME=explode(" ",microtime());
    $TIME=$TIME[1].substr($TIME[0],1);
    return $TIME;
}
function runTime($t,$l=3){
    $dif=getTime()-$t;
    return $dif;
}

/*
 *   文本相似度
 *   Use 1:
 *   $s = new TextSimilarity($text1, $text2);
 *   echo $s->getRate();
 *
 *   Use 2:
 *   $s = new TextSimilarity();
 *   $s->setWords('left',$text1)->setWords('right',$text2);
 *   echo $s->getRate();
 */

class TextSimilarity {
    private $_excludeWords = array();
    private $_vectors = array();
    private $_leftWords = array();
    private $_rightWords = array();

    public function __construct($text1='', $text2='') {
        if(!empty($text1)){
            $this->setWords('left',$text1);
        }
        if(!empty($text2)){
            $this->setWords('right',$text2);
        }
        $this->setExcludeWords();
    }
     
    // 添加排除词
    public function addExcludeWords($words = array()){
        $this->_excludeWords = array_merge($this->_excludeWords, $words);
    }
     
    // 设置左右文本,可以传递字符串 或 数组
    public function setWords($type='left',$text){
        if(!in_array($type,array('left','right')) || empty($text)){ return; }
        $words = array();
        if(is_string($text)){
            $words = $this->segment($text);
        }
        if(empty($words) && is_array($text)){
            $words = $text;
        }
        if($type == 'left'){
            $this->_leftWords = $words;
        }else{
            $this->_rightWords = $words;
        }
        return $this;
    }
     
    // 获取相似度
    public function getRate() {
        if(empty($this->_leftWords) || empty($this->_rightWords)){ return 0; }
         
        // 计算向量数组
        $this->_vectors = array();
        foreach($this->_leftWords as $v){
            if( !in_array($v , $this->_excludeWords) ){
                if( !array_key_exists($v , $this->_vectors) ){
                    $this->_vectors[$v] = array(1 , 0);
                }else{
                    $this->_vectors[$v][0] += 1;
                }
            }
        }
        foreach($this->_rightWords as $v){
            if( !in_array($v , $this->_excludeWords) ){
                if( !array_key_exists($v , $this->_vectors) ){
                    $this->_vectors[$v] = array(0 , 1);
                }else{
                    $this->_vectors[$v][1] += 1;
                }
            }
        }
         
        // 计算相似度
        $sum = $left = $right = 0;
        foreach($this->_vectors as $vector) {
            $sum    += $vector[0] * $vector[1];
            $left  += pow($vector[0],2);
            $right  += pow($vector[1],2);
        }
         
        return $sum / (sqrt($left * $right));
    }
     
    // 分词
    private function segment($text) {
        return preg_split("/\s+/",trim($text));
    }
     
    // 去掉介词(英语)
    private function setExcludeWords() {
        $this->_excludeWords = array(
                "about",
                "above",
                "across",
                "after",
                "against",
                "along",
                "amidst",
                "among",
                "around",
                "as",
                "at",
                "before",
                "behind",
                "below",
                "beneath",
                "beside",
                "besides",
                "between",
                "beyond",
                "but",
                "by",
                "doncerning",
                "despite",
                "down",
                "during",
                "dxcept",
                "dxcepting",
                "for",
                "from",
                "in",
                "inside",
                "into",
                "like",
                "near",
                "of",
                "off",
                "on",
                "onto",
                "outside",
                "over",
                "past",
                "round",
                "since",
                "than",
                "through",
                "till",
                "to",
                "toward",
                "under",
                "until",
                "up",
                "upon",
                "with",
                "within",
                "without"
        );
    }
}

输出:

Total -- 22050
Array
(
    [0] => Welcome Feval Top Hot 2015 Dress Sale Big New Arrival z x
    [1] => Welcome Feval Top Hot 2015 Dear Sale Lastest Hotest AAA z y
    [2] => Welcome Feval Top Dress Dear Fest Big New Lastest Hotest x y
    [3] => Welcome Feval Hot 2015 Fest mini Big Arrival Lastest AAA x y
    [4] => Welcome Feval Dress Dear Fest mini Sale New Arrival AAA z y
    [5] => Welcome Feval Top Dress mini good Arrival Lastest Hotest AAA z x
    [6] => Welcome Hot 2015 Dress Dear good New Arrival Hotest AAA x y
    [7] => Welcome Hot Dress Dear Fest good Sale Big Lastest AAA z x
    [8] => Welcome Top Hot Dear mini good Big New Arrival Lastest z y
    [9] => Feval Top 2015 Dear mini good Sale Big Arrival Hotest x y
    [10] => Feval Hot 2015 Fest mini good Sale New Lastest Hotest z x
    [11] => Top Hot 2015 Dress Fest mini Big New Hotest AAA z y
)

++++++++++++++++++++++++++++++++++++
Array
(
    [0] => Welcome Feval Top Hot 2015 Dress Sale Big New Arrival z x
    [1] => Welcome Feval Top Hot 2015 Dear Sale Lastest Hotest AAA z y
    [2] => Welcome Feval Top Dress Dear Fest Big New Lastest Hotest x y
    [3] => Welcome Feval Hot 2015 Fest mini Big Arrival Lastest AAA x y
    [4] => Welcome Feval Dress Dear Fest mini Sale New Arrival AAA z y
    [5] => Welcome Feval Top Dress mini good Arrival Lastest Hotest AAA z x
    [6] => Welcome Hot 2015 Dress Dear good New Arrival Hotest AAA x y
    [7] => Welcome Hot Dress Dear Fest good Sale Big Lastest AAA z x
    [8] => Welcome Top Hot Dear mini good Big New Arrival Lastest z y
    [9] => Feval Top 2015 Dear mini good Sale Big Arrival Hotest x y
    [10] => Feval Hot 2015 Fest mini good Sale New Lastest Hotest z x
    [11] => Top Hot 2015 Dress Fest mini Big New Hotest AAA z y
    [12] => Welcome Feval Hot 2015 Dear Fest Big New Hotest AAA x y
    [13] => Welcome Feval Top 2015 Dress mini Sale New Hotest AAA z x
    [14] => Welcome Feval Hot 2015 Dear mini Sale Arrival Lastest Hotest x y
    [15] => Welcome Feval Hot 2015 mini good New Arrival Hotest AAA z x
    [16] => Welcome Hot 2015 Dress Dear Fest Big New Lastest Hotest z x
    [17] => Welcome 2015 Dress Fest mini good Sale Big Arrival Hotest x y
    [18] => Feval Top 2015 Dress mini good Sale Big New Hotest z y
    [19] => Top Hot 2015 Dear mini good New Arrival Lastest AAA x y
)

jQuery中的Deferred

官方参考:http://api.jquery.com/category/deferred-object/

从jQuery 1.5.0开始,jQuery提供了Deferred对象。defer的意思是“延迟”,那么deferred大概就是被延迟的意思,Deferred对象实际上就是一种回调函数解决方案。

jQuery中的ajax方法:

$.ajax({
	url:"getData.php",
	success:function(){},
	error:function(){}
});

在Ajax请求成功和失败时分别调用对应的方法。jQuery中最为强大的特征是链式操作,但是如果在jQuery 1.5.0之前,$.ajax是不支持链式操作的,因为它会返回XHR对象。但是在jQuery 1.5.0之后,就可以如下使用:

$.ajax("getData.php").done(function(){}).fail(function(){});

这个写法和前一个例子实现了相同的逻辑,不过这里的是链式操作。

在第一个例子中,$.ajax成功时调用success指定的方法,但是如果希望成功时想执行多个方法是做不到的。但是使用如下方法可以做到:

$.ajax("getData.php")
.done(function(){})
.done(function(){})
.fail(function(){})

可以在成功或失败时绑定多个回调函数。

同时发起多个Ajax请求的情况也是很常见的,如果希望多个请求都成功了,就调用指定的回调函数,这个传统做法也是实现不了的,jQuery中可以这样做:

$.when($.ajax("getData1.php"),$.ajax("getData2.php"))
.done(function(){})
.fail(function(){})

这个写法的意思是:如果两个Ajax请求都成功,执行done绑定的函数,只有有一个失败或都失败,执行fail绑定的函数。

以上针对的都是Ajax这种操作,实际上,可以扩展到一般情况,比如针对一个耗时操作,希望它执行完毕后调用回调函数:

var big = function(){
	var defer = $.deferred();
	//耗时操作
	defer.resolve();

	return defer;
}

var df = big();
$.when(df)
.done(function(){})
.fail(function(){})

这样,耗时操作执行完毕就可以执行对应回调了。这个例子实际就是jQuery 1.5.0之后$.ajax实现的基本原理(jQuery 1.5.0之后ajax实现被重写,内部使用$.deferred)。实际这个过程不难理解,$.deferred()获取一个Deferred对象,耗时操作完毕后调用它的resolve()标志Deferred对象是已经解决的(后续执行回调的切入点),$.when函数接收Deferred对象为参数,它会检查这个对象的状态(是否被resolve),然后对应执行相应的回调函数。

这里需要对resolve()做一些说明:
deferred对象有三种执行状态—-未完成,已完成和已失败。如果执行状态是”已完成”(resolved),deferred对象立刻调用done()方法指定的回调函数;如果执行状态是”已失败”,调用fail()方法指定的回调函数;如果执行状态是”未完成”,则继续等待,或者调用progress()方法指定的回调函数(jQuery1.7版本添加)

jQuery中的Ajax操作这个过程是自动完成的。但是如果是自定义的方式,我们就需要自己去调用deferred.resolve()方法和deferred.reject()方法(把未完成状态改为已失败)。

到这里,原理上的东西应该已经说明白了,但是,还有一个叫promise的东西。考虑如上的代码,它返回的是Deferred对象,这个对象状态被改变时执行相应的回调,但是我们完全可以对返回的Deferred对象再次调用deferred.reject()方法使得原本应该是成功的,变成失败,然后调用失败对应的回调函数,意思就是说,状态的改变可以在外部被再次改变,为了改变这个缺陷,引入了promise对象,它几乎跟deferred对象一样,只是被剔除了可以改变状态的方法,比如resolve()和reject()等方法,使得状态不会在外部被再次改变。所以以上代码可以改为:

var big = function(){
	var defer = $.deferred();
	//耗时操作
	defer.resolve();

	return defer.promise();
}

var df = big();
$.when(df)
.done(function(){})
.fail(function(){})

Deferred对象的promise()返回一个promise对象,是一个被处理过的(阉割了方法)的Deferred对象,后续操作跟之前的一样。

另外,jQuery中还提供了一些便利的操作手法:

var fn = function(df){
	//
	df.resolve();
}

var defer = $.Deferred(fn);

$.when(defer).done().fail();

就是$.Deferred可以接受一个函数,这个函数接受当前这个对象作为参数,玛尼,这个绝对是淫技。

———————————-
AngularJS中的$q服务,实现了类似的东西:

//AngularJS
var defer = $q.defer();
defer.resolve();
var promise = defer.promise();

$q.all([defer1,defer2,defer3]).then(function(){});

//jQuery
$.when(defer1,defer2,defer3).then(function(){});

jQuery中的$.when对应AngularJS中的$q.all。then方法一样意思。AngularJS中的$http服务,和jQuery中的Ajax用法是一样的:

// AngularJS
$http({
	method:'POST',
	url:'getData.php',
	params:{}
}).success(function(d){});

//jQuery
$.ajax(
	url:'getData.php',
	type:'POST',
	data:{},
	success:function(){}
);

$.ajax({
	url:'getData.php',
	type:'POST',
	data:{}	
}).done(function(d){});

———————————-

函数简单说明:

deferred.always()	//当Deferred(延迟)对象解决或拒绝时,调用添加处理程序。
deferred.done()		//当Deferred(延迟)对象解决时,调用添加处理程序。
deferred.fail()		//当Deferred(延迟)对象拒绝时,调用添加处理程序。
deferred.isRejected()	//确定一个Deferred(延迟)对象是否已被拒绝。
deferred.isResolved()	//确定一个Deferred(延迟)对象是否已被解决。
deferred.notify()	//根据给定的 args参数 调用Deferred(延迟)对象上进行中的回调 (progressCallbacks)。
deferred.notifyWith() 	//根据给定的上下文(context)和args递延调用Deferred(延迟)对象上进行中的回调(progressCallbacks )。
deferred.pipe()		//实用的方法来过滤 and/or 链Deferreds。
deferred.progress()	//当Deferred(延迟)对象生成进度通知时,调用添加处理程序。
deferred.promise()	//返回Deferred(延迟)的Promise(承诺)对象。
deferred.reject()	//拒绝Deferred(延迟)对象,并根据给定的args参数调用任何失败回调函数(failCallbacks)。
deferred.rejectWith()	//拒绝Deferred(延迟)对象,并根据给定的 context和args参数调用任何失败回调函数(failCallbacks)。
deferred.resolve()	//解决Deferred(延迟)对象,并根据给定的args参数调用任何完成回调函数(doneCallbacks)。
deferred.resolveWith()	//解决Deferred(延迟)对象,并根据给定的 context和args参数调用任何完成回调函数(doneCallbacks)。
deferred.state()	//确定一个Deferred(延迟)对象的当前状态。
deferred.then()		//当Deferred(延迟)对象解决,拒绝或仍在进行中时,调用添加处理程序。
jQuery.Deferred()	//一个构造函数,返回一个链式实用对象方法来注册多个回调,回调队列, 调用回调队列,并转达任何同步或异步函数的成功或失败状态。
jQuery.when()		//提供一种方法来执行一个或多个对象的回调函数, Deferred(延迟)对象通常表示异步事件。
deferred.promise()	//返回一个 Promise 对象用来观察当某种类型的所有行动绑定到集合,排队与否还是已经完成。

FTP客户端工具 – FileZilla Client

FileZilla Client是一个可以免费使用的FTP客户端工具,虽然是免费的,但是功能非常出色,绝对是一款神器。官网:https://filezilla-project.org/,也有对应的服务端(没有使用过)。

sitemanager
协议这里支持SFTP,一般,如果服务器安装了SSH,就可以通过账户链接,它是走SSH加密传输的,既安全也不需要在服务器端当独安装FTP工具,一般建议使用。在传输设置中设置FTP的传输模式,并发链接数等。可以发现,这个神器支持SFTP,但是好像不支持公钥认证方式登录(只支持密码),实际上,如果需要使用私钥的方式登录,需要到【编辑】 — 【设置】 — 【链接】 — 【SFTP】先把秘钥导入进来:
ftp-rsa

注:可能会提示私钥不支持,询问是否装换,确认后就可以导入。如果私钥设置了密码,还会提示让你输入秘钥密码然后清空私钥密码,确认后导入,实际上私钥密码是没有清空的。在建立站点时,正常输入用户名,如果有秘钥就输入秘钥密码,没有就随便填了(这个工具没有单独为秘钥提供特殊设置)。

默认的界面,使用起来不是很方便,需要经过一番设置:【编辑】 — 【设置】
ftpset
选中宽屏,这种方式以分别对本地和远程以目录,目录列表的方式4列摊开,对操作非常的变量。

另外,最好把消息日志拉到最底下,因为这个东西不是关注的重点,反而碍眼:
ftpset2

经过以上两个步骤设置之后,会得到如下视图:
ftpview
这个视图看起来是不是很直观?

还有一个非常便利的工具,那就是书签,FileZilla Client的书签意思就是设置一个本地和远程的一个对应关系,当打开本地目录时,远程对应目录也对应打开,反过来也一样。书签可以设置为全局的,也可以设置为针对站点的,充分利用这个功能,可以让你在本地和远程目录对应的切换的痛苦中解脱:
ftptag

另外,还有一些配置可以参考:
1 【编辑】 — 【设置】 — 【传输】 — 【文件类型】,默认的传输类型可以改为二进制,如果是自动或ASCII方式,对文本传输可能产生问题。
2 【编辑】 — 【设置】 — 【界面】 — 【文件大小格式】,在文件大小格式这里,可以改为“使用SI式二进制前缀”,这个方式可以以B或KB的后缀显示文件大小(默认是字节,卧槽,看到字节时你很难评估它到底有多大吧?)
3 【编辑】 — 【设置】 — 【界面】 — 【文件编辑】,这里可以关联一个外部编辑器,默认可能继承了Window的设置,这个可能让人很不爽。

函数参考 – 文件系统相关扩展 – Inotify

#安装
wget http://pecl.php.net/get/inotify-0.1.6.tgz
tar zxvf inotify-0.1.6.tgz
cd inotify-0.1.6
/usr/local/php-5.5.15/bin/phpize
./configure --with-php-config=/usr/local/php-5.5.15/bin/php-config
make -j 4
make install

#添加配置
extension = "inotify.so"

例子——————————————–

<?php
/***
常量 位操作
IN_ACCESS           :1
IN_MODIFY           :2
IN_ATTRIB           :4
IN_CLOSE_WRITE      :8
IN_CLOSE_NOWRITE    :16
IN_OPEN             :32
IN_MOVED_TO         :128
IN_MOVED_FROM       :64
IN_CREATE           :256
IN_DELETE           :512
IN_DELETE_SELF      :1024
IN_MOVE_SELF        :2048
IN_CLOSE            :24
IN_MOVE             :192
IN_ALL_EVENTS       :4095
IN_UNMOUNT          :8192
IN_Q_OVERFLOW       :16384
IN_IGNORED          :32768
IN_ISDIR            :1073741824
IN_ONLYDIR          :16777216
IN_DONT_FOLLOW      :33554432
IN_MASK_ADD         :536870912
IN_ONESHOT          :-2147483648
*/

$fd = inotify_init();
$watch_descriptor = inotify_add_watch($fd,'/data/web', IN_CREATE);

while (true) {
    $events = inotify_read($fd);

$watch_descriptor = inotify_add_watch($fd,'/data/web', IN_CREATE);

while (true) {
    $events = inotify_read($fd);

    if ($events) {
        foreach ($events as $event) {
                /*
                array(
                        wd 1?
                        mask 事件对应的数字
                        cookie 0?
                        name 文件名称
                )
                */
                //不支持监控子目录
                $file = $event['name'];
                $action = $event['mask'];
                if((int)preg_match("/(jpg|jpeg|png|gif)$/i",$file) > 0){
                        if($action === IN_CREATE){
                                echo "Create - ".$file."\n";

                                //if(rename("/data/web/$file","/data/webb/$file")){
                                //}
                        }

                }

        }
    }
}

inotify_rm_watch($fd, $watch_descriptor);
fclose($fd);

首先,不支持监控子目录,在子目录中操作,脚本无法得到通知。对于要在PHP中移动文件这类操作,实际测试也没有成功。

函数参考- 加密扩展 – Hash

PHP核心部分。

// 获取所有哈希算法,常用:md5   sha*  whirlpool  
array hash_algos ( void )
Array
(
    [0] => md2
    [1] => md4
    [2] => md5
    [3] => sha1
    [4] => sha224
    [5] => sha256
    [6] => sha384
    [7] => sha512
    [8] => ripemd128
    [9] => ripemd160
    [10] => ripemd256
    [11] => ripemd320
    [12] => whirlpool
    [13] => tiger128,3
    [14] => tiger160,3
    [15] => tiger192,3
    [16] => tiger128,4
    [17] => tiger160,4
    [18] => tiger192,4
    [19] => snefru
    [20] => snefru256
    [21] => gost
    [22] => adler32
    [23] => crc32
    [24] => crc32b
    [25] => fnv132
    [26] => fnv164
    [27] => joaat
    [28] => haval128,3
    [29] => haval160,3
    [30] => haval192,3
    [31] => haval224,3
    [32] => haval256,3
    [33] => haval128,4
    [34] => haval160,4
    [35] => haval192,4
    [36] => haval224,4
    [37] => haval256,4
    [38] => haval128,5
    [39] => haval160,5
    [40] => haval192,5
    [41] => haval224,5
    [42] => haval256,5
)

//计算一个文件的哈希
string hash_file ( string $algo , string $filename [, bool $raw_output = false ] )

// 计算字符串哈希
string hash ( string $algo , string $data [, bool $raw_output = false ] )

echo hash("md5","ifeeline");
echo "\n";
echo md5("ifeeline");

7f81fdb79742f0278f6e2c4c14a15826
7f81fdb79742f0278f6e2c4c14a15826


PHP函数参考 – 影响 PHP 行为的扩展 – Xhprof — 层次式性能分析器

##安装
wget http://pecl.php.net/get/xhprof-0.9.4.tgz
tar zxvf xhprof-0.9.4.tgz
cd xhprof-0.9.4/extension #注意是进入extension目录
/usr/local/php-5.5.15/bin/phpize
make 
make -j 4
make install

##检查扩展
ls /usr/local/php-5.5.15/lib/php/extensions/no-debug-zts-20121212
xhprof.so

##修改php.ini:
[xhprof]
extension = "xhprof.so"
xhprof.output_dir=/data/xhprof/  #确保建立了目录并可写

##确认安装
php -m | grep xhprof
xhprof

下载的扩展包下面提供了一个使用PHP编写的工具,需要配置一下通过Web方式访问。

#拷贝文件
cp -r examples xhprof_html xhprof_lib /data
#配置Nginx指向/data/xhprof_html
server {
	listen 80;
	server_name xhprof.ifeeline.com;
	root /data/xhprof_html;
        location ~ .*.(php|php5)?$ {
                fastcgi_pass 127.0.0.1:9000;
                fastcgi_index index.php;
                include fastcgi.conf;
        }
}
#启动Nginx和PHP

下载包中的例子:

cat sample/sample.php
<?php

function bar($x) {
  if ($x > 0) {
    bar($x - 1);
  }
}

function foo() {
  for ($idx = 0; $idx < 5; $idx++) {
    bar($idx);
    $x = strlen("abc");
  }
}

// start profiling
xhprof_enable();

// run program
foo();

// stop profiler
$xhprof_data = xhprof_disable();

// display raw xhprof data for the profiler run
print_r($xhprof_data);


$XHPROF_ROOT = realpath(dirname(__FILE__) .'/..');
include_once $XHPROF_ROOT . "/xhprof_lib/utils/xhprof_lib.php";
include_once $XHPROF_ROOT . "/xhprof_lib/utils/xhprof_runs.php";

// save raw data for this profiler run using default
// implementation of iXHProfRuns.
$xhprof_runs = new XHProfRuns_Default();

// save the run under a namespace "xhprof_foo"
$run_id = $xhprof_runs->save_run($xhprof_data, "xhprof_foo");

echo "---------------\n".
     "Assuming you have set up the http based UI for \n".
     "XHProf at some address, you can view run at \n".
     "http://<xhprof-ui-address>/index.php?run=$run_id&source=xhprof_foo\n".
     "---------------\n";

###运行查看输出
php sample.php 
Array
(
    [foo==>bar] => Array
        (
            [ct] => 5
            [wt] => 36
        )

    [foo==>strlen] => Array
        (
            [ct] => 5
            [wt] => 4
        )

    [bar==>bar@1] => Array
        (
            [ct] => 4
            [wt] => 9
        )

    [bar@1==>bar@2] => Array
        (
            [ct] => 3
            [wt] => 5
        )

    [bar@2==>bar@3] => Array
        (
            [ct] => 2
            [wt] => 2
        )

    [bar@3==>bar@4] => Array
        (
            [ct] => 1
            [wt] => 0
        )

    [main()==>foo] => Array
        (
            [ct] => 1
            [wt] => 92
        )

    [main()==>xhprof_disable] => Array
        (
            [ct] => 1
            [wt] => 0
        )

    [main()] => Array
        (
            [ct] => 1
            [wt] => 111
        )

)
---------------
Assuming you have set up the http based UI for 
XHProf at some address, you can view run at 
http://<xhprof-ui-address>/index.php?run=55aacc03e3317&source=xhprof_foo
---------------

最后的输出告诉我们可以通过Web方式查看结果(就是之前的配置)。

打开xhprof.ifeeline.com就可以看到输出:
xhprof_table

可以参考以上提示访问HTTP的格式,在自己的Web页面中输出嵌入这个链接,客户端通过firebug这样的插件直接打开,这样就不需要自己去定位了。

使用模板:

xhprof_enable(XHPROF_FLAGS_CPU + XHPROF_FLAGS_MEMORY);
//监控代码块
$data = xhprof_disable();

include_once "xhprof_lib/utils/xhprof_lib.php";  
include_once "xhprof_lib/utils/xhprof_runs.php"; 
 
$objXhprofRun = new XHProfRuns_Default();
$run_id = $objXhprofRun->save_run($data, "xhprof_xxx");

只要在需要分析性能的代码中加入如上代码即可。产生的报告会写入到对应位置(save_run()方法第二参数指定一个自定义名称,用来区分不同的输出)。

点击[View Full Callgraph]可以以图表的形式展示。如果提示错误,那应该是画图依赖的工具不存在,先安装:

yum install graphviz

之后就可以以图片形式查看:
xhprof_graph
红色部分就是比较耗时的部分,提醒优化(参考)。

XHProf扩展提供的PHP函数
1).xhprof_enable
函数原型:void xhprof_enable ([ int $flags = 0 [, array $options ]] )
功能:启动 xhprof 性能分析器
参数:$flags可选标识,由XHProf扩展定义,XHPROF_FLAGS_NO_BUILTINS 使得跳过所有内置(内部)函数,XHPROF_FLAGS_CPU使输出的性能数据中添加 CPU 数据,XHPROF_FLAGS_MEMORY使输出的性能数据中添加内存数据,多个标识可通过位运算进行组合;$options array类型的可选选项,就是通过传递 ‘ignored_functions’ 选项来忽略性能分析中的某些函数。
返回值:无
说明:在开始分析代码时调用此函数

2).xhprof_disable
函数原型:array xhprof_disable ( void )
功能:停止 xhprof 分析器
参数:无
返回值:本次运行的array类型的xhprof 数据
说明:在结束分析代码时调用此函数

3).xhprof_sample_enable
函数原型:void xhprof_sample_enable ( void )
功能:以采样模式启动 XHProf 性能分析
参数:无
返回值:无
说明:xhprof_enable()的更轻量的版本,以采样模式开始性能分析。抽样的间隔为 0.1 秒,样本记录了完整的函数调用堆栈。主要使用的情况是以较低的性能开销来进行性能监控和诊断。

4).xhprof_sample_disable
函数原型:array xhprof_sample_disable ( void )
功能:停止 xhprof 性能采样分析器
参数:无
返回值:本次运行的xhprof采样数据,array类型
说明:暂无

图片中的数据说明:

列名 描述
Function Name 方法名称。
Calls 方法被调用的次数。
Calls% 方法调用次数在同级方法总数调用次数中所占的百分比。
Incl.Wall Time (microsec) 方法执行花费的时间,包括子方法的执行时间。(单位:微秒)
IWall% 方法执行花费的时间百分比。
Excl. Wall Time (microsec) 方法本身执行花费的时间,不包括子方法的执行时间。(单位:微秒)
EWall% 方法本身执行花费的时间百分比。
Incl. CPU (microsecs) 方法执行花费的CPU时间,包括子方法的执行时间。(单位:微秒)
ICpu% 方法执行花费的CPU时间百分比。
Excl. CPU (microsec) 方法本身执行花费的CPU时间,不包括子方法的执行时间。(单位:微秒)
ECPU% 方法本身执行花费的CPU时间百分比。
Incl.MemUse (bytes) 方法执行占用的内存,包括子方法执行占用的内存。(单位:字节)
IMemUse% 方法执行占用的内存百分比。
Excl.MemUse (bytes) 方法本身执行占用的内存,不包括子方法执行占用的内存。(单位:字节)
EMemUse% 方法本身执行占用的内存百分比。
Incl.PeakMemUse (bytes) Incl.MemUse峰值。(单位:字节)
IPeakMemUse% Incl.MemUse峰值百分比。
Excl.PeakMemUse (bytes) Excl.MemUse峰值。单位:(字节)
EPeakMemUse% Excl.MemUse峰值百分比。

TFS架设案例

tfs_struct
这里使用nginx_tfs扩展作为操作TFS的接口。请求TFS的,有外部用户,只是取数据;内部用户,上传修改删除图片等;通过PHP访问TFS的内部或外部用户。通过PHP访问TFS主要是希望通过PHP的处理添加额外逻辑,比如内部用户,可以先认证,对来自外部的用户,可以对文件进行加工后返回…..

在Nginx中设置三个Host模拟:

tfs_upstream tfs_ns {
        server 192.168.1.102:8000;
        type ns;
}
#对外部用户,只允许GET
server {
	listen 80;
	server_name files.ifeeline.com;

        tfs_keepalive max_cached=10 bucket_count=2;

        location / {
	      if ($request_method != GET) {
	      	   return 403;
	      }
              tfs_pass tfs://tfs_ns;
        }
}
#对内部用户,可以进行所有操作,可能不好控制权限,如果这样可以走PHP
#让PHP返回调用
server {
        listen 80;
        server_name api.ifeeline.com;

        tfs_keepalive max_cached=10 bucket_count=2;

        location / {
              tfs_pass tfs://tfs_ns;
        }
}
#通过PHP层访问,PHP层可以直接使用PHP针对TFS的扩展,也可以在PHP中对nginx_tfs扩展提供的方法进行访问
server {
	listen 90;
	server_name tfs.ifeeline.com;
	root /data/web/tfs;
	location ~ .*.(php|php5)?$ {
		fastcgi_pass 127.0.0.1:9000;
		fastcgi_index index.php;
		include fastcgi.conf;
	}
}

以下是一段管理程序:

<?php
set_include_path(implode(PATH_SEPARATOR, array(
        realpath(__DIR__ . '/../library'),
        get_include_path(),
)));

if(file_exists('../vendor/autoload.php')){
    $loader = include '../vendor/autoload.php';
}else{
    exit("Autoload Failed. ");
}
$loader->setUseIncludePath(true);

$params = array(
        'username' =>'root',
        'password' =>'',
        'dbname' =>'tfs',
        'charset' =>'utf8'
);
$db = Zend_Db::factory('MYSQLI', $params);
Zend_Db_Table_Abstract::setDefaultAdapter($db);

$httpClient = new Tfs\HttpClient();

// 自己构建
// $reponse = $httpClient->setBaseUrl('http://files.ifeeline.com')->get('/v1/tfs/T1IRETByxT1RXrhCrK.jpg');
// if($reponse->isOk()){
//     $content = $reponse->getContent();
//     echo $content;
// }
// exit;

// 删除
if(isset($_REQUEST['type']) && ($_REQUEST['type'] == 'del') && isset($_REQUEST['file'])){
    $url = "http://api.ifeeline.com";
    $delUrl = "/v1/tfs/".trim($_REQUEST['file']);
    
    $ret = $httpClient->setBaseUrl($url)->delete($delUrl);
    
    if($ret->isOk()){
        //$rett = json_decode($ret->getContent(),'true');
        $db->delete("files","name_tfs='".$_REQUEST['file']."'");
    }
    header("Location:tfs.php");
}

// 批量添加
if(isset($_REQUEST['type']) && ($_REQUEST['type'] == 'add')){
    $dir = new DirTreee();
    $files = $dir->getTree("D:/files");
    
    $url = "http://api.ifeeline.com";
    $postUrl = "/v1/tfs?suffix=&simple_name=0";
    
    foreach($files as $fle) {
        $pinfo = pathinfo($fle);
        $fileName = $pinfo["filename"];
    
        $d = file_get_contents($fle);
        $fileMd5 = md5($d);
    
        $has = $db->fetchRow("SELECT * FROM files WHERE file_md5='".$fileMd5."'");
        if(empty($has)) {
            $ret = $httpClient->setBaseUrl($url)->post($postUrl,$d);
    
            if($ret->isOk()){
                $rett = json_decode($ret->getContent(),'true');
                $tfsFileName = $rett["TFS_FILE_NAME"];
    
                $db->insert("files", array("name"=>$fileName,"name_tfs"=>$tfsFileName,"file_md5"=>$fileMd5));
            }
        }   
    }
    header("Location:tfs.php");
}

class DirTreee {
    public $tree = array();
    public $treeView = '';
     
    public function __construct($source='') {
        if(!empty($source) && is_dir($source)){
            $this->tree = $this->getTree($source);
        }
    }
     
    public function getTree($source) {
        $dir = array();
        if(is_dir($source)){
            if ($dh = opendir($source)) {
                while (($file = readdir($dh)) !== false) {
                     
                    if(is_file($source.'/'.$file)){
                        
                        $ext = pathinfo($file);
                        $ext = $ext['extension'];
                        // 不读取图片文件
                        if(($file == '.') || ($file == '..')){ continue; }
                        $dir[] = $source.'/'.$file;
                    }
                }
                 
                closedir($dh);
            }
        }
        return $dir;
    }
}
?>
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<?php 
$list = $db->fetchAll("SELECT * FROM files");
echo "<table>";
foreach($list as $lst){
    echo "<tr>";
    echo "<td><a href='http://files.ifeeline.com/v1/tfs/".$lst['name_tfs']."'>".$lst['name'].' - '.$lst['name_tfs'].' - '.$lst['file_md5']."</a></td>";
    echo "<td><a href='tfs.php?type=del&file=".$lst['name_tfs']."'>删除</a></td>";
    echo "</tr>";
}
echo "</table>";
?>
<br />
<a href="tfs.php?type=add">批量添加</a>
</body>
</html>

文本相似度 – 余弦定理 – PHP实现

余弦定理计算文本相似度。Demo:余弦定理计算文本相似度Demo

similary

余弦定理计算相似度原理:http://www.ruanyifeng.com/blog/2013/03/cosine_similarity.html

<?php
/*
 *   文本相似度
 *   Use 1:
 *   $s = new TextSimilarity($text1, $text2);
 *   echo $s->getRate();
 *   
 *   Use 2:
 *   $s = new TextSimilarity();
 *   $s->setWords('left',$text1)->setWords('right',$text2);
 *   echo $s->getRate();
 */

class TextSimilarity {
    private $_excludeWords = array();
    private $_vectors = array();
    private $_leftWords = array();
    private $_rightWords = array();

    public function __construct($text1='', $text2='') {
        if(!empty($text1)){
            $this->setWords('left',$text1);
        }
        if(!empty($text2)){
            $this->setWords('right',$text2);
        }
        $this->setExcludeWords();
    }
    
    // 添加排除词
    public function addExcludeWords($words = array()){
        $this->_excludeWords = array_merge($this->_excludeWords, $words);
    }
    
    // 设置左右文本,可以传递字符串 或 数组
    public function setWords($type='left',$text){
        if(!in_array($type,array('left','right')) || empty($text)){ return; }
        $words = array();
        if(is_string($text)){
            $words = $this->segment($text);
        }
        if(empty($words) && is_array($text)){
            $words = $text;
        }
        if($type == 'left'){
            $this->_leftWords = $words;
        }else{
            $this->_rightWords = $words;
        }
        return $this;
    }
    
    // 获取相似度
    public function getRate() {
        if(empty($this->_leftWords) || empty($this->_rightWords)){ return 0; }
        
        // 计算向量数组
        $this->_vectors = array();
        foreach($this->_leftWords as $v){
            if( !in_array($v , $this->_excludeWords) ){
                if( !array_key_exists($v , $this->_vectors) ){
                    $this->_vectors[$v] = array(1 , 0);
                }else{
                    $this->_vectors[$v][0] += 1;
                }
            }
        }
        foreach($this->_rightWords as $v){
            if( !in_array($v , $this->_excludeWords) ){
                if( !array_key_exists($v , $this->_vectors) ){
                    $this->_vectors[$v] = array(0 , 1);
                }else{
                    $this->_vectors[$v][1] += 1;
                }
            }
        }
        
        // 计算相似度
        $sum = $left = $right = 0;
        foreach($this->_vectors as $vector) {
            $sum    += $vector[0] * $vector[1];
            $left  += pow($vector[0],2);
            $right  += pow($vector[1],2);
        }
        
        return $sum / (sqrt($left * $right));
    }
    
    // 分词
    private function segment($text) {
        return preg_split("/\s+/",trim($text));
    }
    
    // 去掉介词(英语)
    private function setExcludeWords() {
        $this->_excludeWords = array(
                "about",
                "above",
                "across",
                "after",
                "against",
                "along",
                "amidst",
                "among",
                "around",
                "as",
                "at",
                "before",
                "behind",
                "below",
                "beneath",
                "beside",
                "besides",
                "between",
                "beyond",
                "but",
                "by",
                "doncerning",
                "despite",
                "down",
                "during",
                "dxcept",
                "dxcepting",
                "for",
                "from",
                "in",
                "inside",
                "into",
                "like",
                "near",
                "of",
                "off",
                "on",
                "onto",
                "outside",
                "over",
                "past",
                "round",
                "since",
                "than",
                "through",
                "till",
                "to",
                "toward",
                "under",
                "until",
                "up",
                "upon",
                "with",
                "within",
                "without"             
        );
    }
}

按照规则分多段抽词自动生成标题…

根据给定的词,读取抽取词的数量(多个分段,重复这个过程),生成标题。看了实际实现,玛尼,实际就是把所有组合都找出来….,原有实现非常不直观,所以重写了代码用于测试:

<?php
// $a = array(
//         array('a','b'),
//         array('a','c'),
//         array('b','c')
// );

// $b = array(
//         array('1','2'),
//         array('3','4')
// );

// $c = array(
//         array('A1','A2','A3'),
//         array('A2','A4','A5'),
//         array('A3','A1','A2')
// );

// $ab = ArrayCombination::combine($a,$b);
// $abc = ArrayCombination::combine($ab,$c);
// print_r($abc);

// 两个维度
// 1、6个词中选3个
// 2、4个词中选3个
// 求所有组合数 与组合数组
/*
echo ArrayCombination::countTotal(6,3).' -- '.ArrayCombination::countTotal(4,3);//20 4

$a = ['a','b','c','d','e','f'];
$b = ['1','2','3','4'];
$ac = ArrayCombination::get($a,3);
$bc = ArrayCombination::get($b,3);

print_r($ac); // 20组  3单位
print_r($bc); // 4 组  3单位
print_r(ArrayCombination::combine($ac,$bc)); // 80组 6单位
*/

// $a = [['a','b','c','d'],['e','f'],3];
// $b = [['1','2'],['3','4'],3];
// $c = [['x','y'],['z'],1];
// //$ab = array($a,$b);
// $ab = array($a,$b,$c);

$a = [['Top','Hot','2015','Dress'],['Welcome','Feval'],3];
$b = [['New','Arrival'],['Sale','Big'],3];
$c = [['x','y'],['z'],1];
$ab = array($a,$b);  //6选3=20,4选3=4,得到80条不同组合的记录
//$ab = array($a,$b,$c);

$title = [];
foreach($ab as $a){
    $newArr = [];
    if(count($a[1]) > 0){
        $hotCount = count($a[1]);
        for($i=$hotCount; $i>=0; $i--){
            $n = $a[2]-$i;
            if($n == 0){
                $newArr[] = $a[1];
            }else{
                $h  = ArrayCombination::get($a[1],$i);
                $nr = ArrayCombination::get($a[0],$n);
                
                $tmp = ArrayCombination::combine($h, $nr);
                $newArr = array_merge($newArr,$tmp);
            }
        }
    }else{
        $newArr = ArrayCombination::get($a[0],$a[2]);
    }
    if(empty($title)){
        $title = $newArr;
    }else{
        $title = ArrayCombination::combine($title,$newArr);
    }
}
//print_r($title);
foreach($title as $t){
    echo implode(" ",$t)."\n";
}


class ArrayCombination {
    // 计算组合数,比如3取2,组合数为3; 6取2,组合数15
    public static function countTotal($total,$count){
        $total = (int)$total;
        $count = (int)$count;
    
        if(($total < 1) || ($count < 1) || ($total < $count)){
            return 0;
        }
        $u = $d = 1;
        for($i=$count; $i>0; $i--) {
            $u *= $total--;
            $d *= $i;
        }
        return (int)($u/$d);
    }
    
    // 组合算法 获取所有组合
    public static function get($arr, $size = 1) {
        $len = count($arr);
        $max = pow(2,$len) - pow(2,$len-$size);
        $min = pow(2,$size)-1;
         
        $r_arr = array();
        for ($i=$min; $i<=$max; $i++){
            $count = 0;
            $t_arr = array();
            for ($j=0; $j<$len; $j++){
                $a = pow(2, $j);
                $t = $i&$a;
                if($t == $a){
                    $t_arr[] = $arr[$j];
                    $count++;
                }
            }
            if($count == $size){
                $r_arr[] = $t_arr;
            }
        }
        return $r_arr;
    } 
    
    /*********************
    [
        [1,2],
        [3,4]
    ]
    [
        [5],
        [6]
    ]
    -----------------------
    [
        [1,2,5],
        [1,2,6],
        [3,4,5],
        [3,4,6]
    ]
    */
    public static function combine($arr1,$arr2){
        if(!is_array($arr1)){ return array(); }
        if(!is_array($arr2)){ return $arr1; }
        
        $newArr = array();
        foreach($arr1 as $av) {
            foreach($arr2 as $bv){
                $newArr[] = array_merge($av,$bv);
            }
        }
        return $newArr;
    }
    
}

TFS的Nginx扩展nginx_tfs 与 PHP包装器

Taobao官方有提供一个针对TFS的Nginx扩展,地址https://github.com/alibaba/nginx-tfs,设计成REST风格API,它就是一个适配器,任何的编程语言执行简单发送指令就可以操作TFS。

官方描述的安装:
1 TFS模块使用了一个开源的JSON库来支持JSON,请先安装yajl-2.0.1(http://lloyd.github.io/yajl/)。
2 下载nginx或tengine。
3 ./configure –add-module=/path/to/nginx-tfs
4 make && make install

实际操作过程:

#先安装Nginx需要的包
yum -y install zlib zlib-devel openssl openssl-devel pcre pcre-devel

#获取yajl
wget http://github.com/lloyd/yajl/zipball/2.1.0
mv 2.1.0 yajl-2.0.1.zip
unzip yajl-2.0.1.zip
cd yajl-2.0.1
##默认安装到/usr/local,库放入了/usr/local/lib中
./configure 
##这个玩意使用了cmake      
yum install cmake 
make && make install
#避免后面找不到这个库,玛尼,这里拷贝一下
cp -a /usr/local/libyajl* /lib64/

#获取nginx-tfs扩展,解压一下就好了
wget https://github.com/alibaba/nginx-tfs/archive/master.zip
unzip master.zip

#Ngingx-1.8.0无法适配这个扩展,所以找一个低一点的版本
wget http://nginx.org/download/nginx-1.2.9.tar.gz
tar zxvf nginx-1.2.9.tar.gz
cd nginx-1.2.9
useradd www
./configure --user=www --group=www --prefix=/usr/local/nginx-1.2.9 --add-module=/root/nginx-tfs-master
make && make install

配置:

vi nginx.conf 添加:
tfs_upstream tfs_ns {
        server 192.168.1.102:8000;
        type ns;
    }

server {
	listen       80;
	server_name  192.168.1.102;

        tfs_keepalive max_cached=10 bucket_count=2;

        location / {
              tfs_pass tfs://tfs_ns;
        }
}

我这里不使用rcServer,所以配置异常简单。具体配置参考:https://github.com/alibaba/nginx-tfs/blob/master/ReadMe.markdown

然后用如下程序POST一张图片:

/////////////////////////////////////////////////////
$url = 'http://192.168.1.102/v1/tfs?suffix=.jpg&simple_name=0';

$postBinary = file_get_contents('D:\v.jpg');

//初始化
$ch = curl_init();
curl_setopt($ch, CURLOPT_HEADER, '');
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
//
curl_setopt($ch, CURLOPT_POST, false);
//
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS,$postBinary);
//
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
//
curl_setopt($ch,CURLOPT_RETURNTRANSFER,true);
curl_setopt($ch,CURLOPT_FOLLOWLOCATION,true);
curl_setopt($ch,CURLOPT_MAXREDIRS,10);
//
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:21.0) Gecko/20100101 Firefox/21.0");

$result = curl_exec($ch);
$errn = curl_errno($ch);
curl_close($ch);

print_r($result);

######################################
输出:
{ "TFS_FILE_NAME": "T1IRETByxT1RXrhCrK" } 

说明:这个POST跟一般常见的POST是不一样的(RESTful风格),首先,参数作为URL的一部分,然后就是POST的数据不需要对应一个名称,直接是原生数据。

直接访问这个链接:
tfs_output

其它的API参考:https://github.com/alibaba/nginx-tfs/blob/master/TFS_RESTful_API.markdown,这些API的调用可以通过CURL来非常容易的使用。

针对一个nginx_tfs的这个扩展,在Github有一个针对它的PHP包装器:https://github.com/ifa6/php_tfs_client
这个包里面提供的HttpClient.php是对Curl的封装,HttpResponse.php是响应对象的封装,HttpClient.php提供了RESTfull风格的几个方法:

    public function get($url)
    {
        return $this->prepareCurlHandler(array(
            CURLOPT_URL => $this->prepareUrl($url),
            CURLOPT_CUSTOMREQUEST => 'GET',
        ))->send();
    }

    public function put($url, $content=null)
    {
        return $this->prepareCurlHandler(array(
            CURLOPT_URL => $this->prepareUrl($url),
            CURLOPT_CUSTOMREQUEST => 'PUT',
            CURLOPT_POSTFIELDS => $content,
        ))->send();
    }

    public function post($url, $content=null)
    {
        return $this->prepareCurlHandler(array(
            CURLOPT_URL => $this->prepareUrl($url),
            CURLOPT_CUSTOMREQUEST => 'POST',
            CURLOPT_POSTFIELDS => $content,
            CURLOPT_POST => true
        ))->send();
    }

    public function delete($url)
    {
        return $this->prepareCurlHandler(array(
            CURLOPT_URL => $this->prepareUrl($url),
            CURLOPT_CUSTOMREQUEST => 'DELETE',
        ))->send();
    }

    public function head($url)
    {
        return $this->prepareCurlHandler(array(
            CURLOPT_URL => $this->prepareUrl($url),
            CURLOPT_CUSTOMREQUEST => 'HEAD',
            CURLOPT_NOBODY => true
        ))->send();
    }

除了这些方法,还有一系列的set方法,比如设置请求URL,CURL用的头信息等:

$httpClient = new HttpClient();
$reponse = $httpClient->setBaseUrl('http://blog.ifeeline.com')->get('/xxx/api.php');
if($reponse->isOk()){
    $content = $response->getContent();
    // ......
}

这个包下面Client.php是利用HttpClient对nginx_tfs提供的API进行了二次封装,不过我觉得使用HttpClient已经足够好了。