AES-256 加密 PHP实现

class aes {

    static public $mode = MCRYPT_MODE_NOFB;

    static public function generateKey($length=32) {
        if (!in_array($length,array(16,24,32)))
            return False;

        $str = '';
        for ($i=0;$i<$length;$i++) {
            $str .= chr(rand(33,126));
        }

        return $str;
    }

    static public function encrypt($data, $key) {

        if (strlen($key) > 32 || !$key)
            return trigger_error('key too large or key is empty.', E_USER_WARNING) && False;

        $ivSize = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, self::$mode);
        $iv = mcrypt_create_iv($ivSize, (substr(PHP_OS,0,1) == 'W' ? MCRYPT_RAND : MCRYPT_DEV_URANDOM ));
        $encryptedData = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $data, self::$mode, $iv);
        $encryptedData = $iv . $encryptedData;

        return base64_encode($encryptedData);
    }

    static public function decrypt($data, $key) {

        if (strlen($key) > 32 || !$key)
            return trigger_error('key too large or key is empty.', E_USER_WARNING) && False;

        $data = base64_decode($data);
        if (!$data)
            return False;

        $ivSize = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, self::$mode);
        $iv = substr($data, 0, $ivSize);

        $data = substr($data, $ivSize);

        $decryptData = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $data, self::$mode, $iv);

        return $decryptData;
    }
}

调用

$key = aes::generateKey();

$encode = aes::encrypt('this is text data', $key);
$decode = aes::decrypt($encode, $key);

var_dump($encode);
var_dump($decode);

2016年4月22日更新

上面的方法并不是aes-256的加密。一直搞错了。PHP实现aes-256加密最好是使用OPENSSL。
Example:

// 加密

// 加密方式使用 aes-256-cfb 并获取iv长度
$iv_size = openssl_cipher_iv_length('aes-256-cfb');

// 生成IV
$iv = mcrypt_create_iv($iv_size,MCRYPT_RAND);

// 加密
$data = openssl_encrypt($data,'aes-256-cfb',$key,OPENSSL_RAW_DATA,$iv);
// 把IV放到data前面一并输出
echo base64_encode($iv.$data);

2/28/2018 更新

PHP7 对mcrypt模块做了删减 mcrypt_create_iv 被移除了,生成$iv参数应使用random_bytes(openssl_cipher_iv_length('aes-256-cfb'));

PHP Bt种子转磁力链

include 'BEncode.php';
include 'BDecode.php';

$torrent_content = file_get_contents('filename.torrent');

$desc = BDecode($torrent_content);
$info = $desc['info'];
$hash = strtoupper(sha1( BEncode($info) ));

sprintf('magnet:?xt=urn:btih:%s&dn=%s', $hash, $info['name']);


BEncode.php

class BEncode {
    // Dictionary keys must be sorted. foreach tends to iterate over the order
    // the array was made, so we make a new one in sorted order. 🙂
    function makeSorted($array) {
        // Shouldn't happen!
        if (empty($array))
            return $array;
        $i = 0;
        foreach($array as $key => $dummy)
            $keys[$i++] = stripslashes($key);
        sort($keys);
        for ($i=0; isset($keys[$i]); $i++)
            $return[addslashes($keys[$i])] = $array[addslashes($keys[$i])];
        return $return;
    }

    // Encodes strings, integers and empty dictionaries.
    // $unstrip is set to true when decoding dictionary keys
    function encodeEntry($entry, &$fd, $unstrip = false) {
        if (is_bool($entry)) {
            $fd .= 'de';
            return;
        }
        if (is_int($entry) || is_float($entry)) {
            $fd .= 'i'.$entry.'e';
            return;
        }
        if ($unstrip)
            $myentry = stripslashes($entry);
        else
            $myentry = $entry;
        $length = strlen($myentry);
        $fd .= $length.':'.$myentry;
    }

    // Encodes lists
    function encodeList($array, &$fd) {
        $fd .= 'l';
        // The empty list is defined as array();
        if (empty($array)) {
            $fd .= 'e';
            return;
        }
        for ($i = 0; isset($array[$i]); $i++)
            $this->decideEncode($array[$i], $fd);
        $fd .= 'e';
    }

    // Passes lists and dictionaries accordingly, and has encodeEntry handle
    // the strings and integers.
    function decideEncode($unknown, &$fd) {
        if (is_array($unknown)) {
            if (isset($unknown[0]) || empty($unknown))
                return $this->encodeList($unknown, $fd);
            else
                return $this->encodeDict($unknown, $fd);
        }
        $this->encodeEntry($unknown, $fd);
    }

    // Encodes dictionaries
    function encodeDict($array, &$fd) {
        $fd .= 'd';
        if (is_bool($array)) {
            $fd .= 'e';
            return;
        }
        // NEED TO SORT!
        $newarray = $this->makeSorted($array);
        foreach($newarray as $left => $right) {
            $this->encodeEntry($left, $fd, true);
            $this->decideEncode($right, $fd);
        }
        $fd .= 'e';
    }
}

function BEncode($array) {
    $string = '';
    $encoder = new BEncode;
    $encoder->decideEncode($array, $string);
    return $string;
}

BDecode.php

class BDecode {
    function numberdecode($wholefile, $offset) {
        // Funky handling of negative numbers and zero
        $negative = false;
        if ($wholefile[$offset] == '-') {
            $negative = true;
            $offset++;
        }
        if ($wholefile[$offset] == '0') {
            $offset++;
            if ($negative)
                return array(false);
            if ($wholefile[$offset] == ':' || $wholefile[$offset] == 'e')
                return array(0, ++$offset);
            return array(false);
        }
        $ret[0] = 0;
        for(;;) {
            if ($wholefile[$offset] >= '0' && $wholefile[$offset] <= '9') {
                $ret[0] *= 10;
                //Added 2005.02.21 - VisiGod
           //Changing the type of variable from integer to double to prevent a numeric overflow   
                settype($ret[0],'double');
                //Added 2005.02.21 - VisiGod
                $ret[0] += ord($wholefile[$offset]) - ord('0');
                $offset++;
            }   else if ($wholefile[$offset] == 'e' || $wholefile[$offset] == ':') {
                // Tolerate : or e because this is a multiuse function
                $ret[1] = $offset+1;
                if ($negative) {
                    if ($ret[0] == 0)
                        return array(false);
                    $ret[0] = - $ret[0];
                }
                return $ret;
            } else return array(false);
        }
    }

    function decodeEntry($wholefile, $offset=0) {
        if ($wholefile[$offset] == 'd')
            return $this->decodeDict($wholefile, $offset);
        if ($wholefile[$offset] == 'l')
            return $this->decodelist($wholefile, $offset);
        if ($wholefile[$offset] == 'i')
            return $this->numberdecode($wholefile, ++$offset);
        // String value: decode number, then grab substring

        $info = $this->numberdecode($wholefile, $offset);
        if ($info[0] === false)
            return array(false);
        $ret[0] = substr($wholefile, $info[1], $info[0]);
        $ret[1] = $info[1]+strlen($ret[0]);
        return $ret;
    }

    function decodeList($wholefile, $offset) {
        if ($wholefile[$offset] != 'l')
            return array(false);
        $offset++;
        $ret = array();
        for ($i=0;;$i++) {
            if ($wholefile[$offset] == 'e')
                break;
            $value = $this->decodeEntry($wholefile, $offset);
            if ($value[0] === false)
                return array(false);
            $ret[$i] = $value[0];
            $offset = $value[1];
        }
        // The empty list is an empty array. Seems fine.
        return array(0=>$ret, 1=>++$offset);
    }

    // Tries to construct an array
    function decodeDict($wholefile, $offset=0) {
        if ($wholefile[$offset] == 'l')
            return $this->decodeList($wholefile, $offset);
        if ($wholefile[$offset] != 'd')
            return false;
        $ret=array();
        $offset++;
        for (;;) {  
            if ($wholefile[$offset] == 'e')   {
                $offset++;
                break;
            }
            $left = $this->decodeEntry($wholefile, $offset);
            if (!$left[0])
                return false;
            $offset = $left[1];
            if ($wholefile[$offset] == 'd') {
                // Recurse
                $value = $this->decodedict($wholefile, $offset);
                if (!$value[0])
                    return false;
                $ret[addslashes($left[0])] = $value[0];
                $offset= $value[1];
                continue;
            }
            if ($wholefile[$offset] == 'l') {
                $value = $this->decodeList($wholefile, $offset);
                if (!$value[0] && is_bool($value[0]))
                    return false;
                $ret[addslashes($left[0])] = $value[0];
                $offset = $value[1];
                continue;
            }
            $value = $this->decodeEntry($wholefile, $offset);
            if ($value[0] === false)
                return false;
            $ret[addslashes($left[0])] = $value[0];
            $offset = $value[1];
        }
        return array(0=>(empty($ret)?true:$ret), 1=>$offset);
    }
}

function BDecode($wholefile) {
    $decoder = new BDecode;
    $return = $decoder->decodeEntry($wholefile);
    return $return[0];
}

PHP生成Ed2k(电驴)连接

function genEd2k($filepath) {

    $chunk_size = 9728000;

    $ed2khash = '';

    if (!is_file($filepath)) {
            trigger_error('file not found',E_USER_WARNING);
            return False;
        }
    $filesize = filesize($filepath);
    $filename = pathinfo($filepath, PATHINFO_BASENAME);

    if ($filesize <= $chunk_size) {
        $ed2khash = hash_file('md4', $filepath, true);
    } else {
        $_hash_str = '';
        $fp = fopen($filepath,'r');
        while (!feof($fp)) {
            $data = fread($fp, $chunk_size);
            $_hash_str .= hash('md4', $data, True);
        }
        fclose($fp);
        $ed2khash = hash('md4', $_hash_str);
    }

    return sprintf('ed2k://|file|%s|%s|%s', urlencode($filename), $filesize, strtoupper($ed2khash));
}

调用:

echo genEd2k(__DIR__.'/test.rar');
// 输出
// ed2k://|file|test.rar|4150800|4EB96EFD6600264ACB4FAE237C3F7895

高德云图PHP Simple SDK

高德云图周边搜索接口中filter参数无效,有需要这个参数的人就别用了。

只封装了我用到的几个功能,其他功能对照着文档自己封装,
调用:

$lbs = new lbsyun('table_id', 'key');
// 创建一个新的Point
$lbs->create('名称', '纬度', '经度', Array('其他自定义字段'=>'值') );
// 搜索周边的Point
$result = $lbs->around(Array(
    'center'=>'longitidue,latitude',
    'page'=>'1',
    'limit'=>'50',
    '_sortrule'=>'_distance:1',
    'radius'=>'10000')
);

var_dump($result);

源码:

<?php

/**
 * 高德云图 SDK
 *
 * @author cevin<cevin.cheung(at)gmail.com>
 * @site <http://cevin.net>
 */
class lbsyun {

    const SERVICE_URL = 'http://yuntuapi.amap.com';
    private $table_id = '';
    private $key = '';

    private $error = null;

    public function __construct($table_id,$key) {
        $this->table_id = $table_id;
        $this->key = $key;
    }

    public function create($name,$lat,$lng,Array $param = array()) {
        $data = array();
        $data['_name'] = $name;
        $data['_location'] = "{$lng},{$lat}";
        $data = json_encode(array_merge($data,$param));

        $ret = $this->process('/datamanage/data/create',$data,'post');

        $ret = $this->parse($ret);

        return $ret['status'] == 1 ? (int)$ret['_id'] : false;
    }

    public function update($id,Array $data) {
        $data['_id'] = $id;
        $data = json_encode($data);

        $ret = $this->process('/datamanage/data/update',$data,'post');
        $ret = $this->parse($ret);

        return $ret['status'] == 1 ? true : false;
    }

    public function delete($id) {

        $data = array();
        $data['tableid'] = $this->table_id;
        $data['key'] = $this->key;
        $data['ids'] = $id;

        $ret = $this->request('/datamanage/data/delete',$data,'post');
        $ret = $this->parse($ret);
        return $ret['status'] == 1 ? true : false;
    }

    /**
     * 周边检索
     * @return array [description]
     */
    public function around(Array $data) {
        $url = '/around';
        return $this->search($url,$data,'get');
    }

    private function search($url,Array $data,$method) {
        $url = '/datasearch'.$url;

        $data['key'] = $this->key;
        $data['tableid'] = $this->table_id;

        return $this->parse($this->request($url,$data,$method));
    }

    private function process($url,$data,$method) {

        $basedata = array();
        $basedata['tableid'] = $this->table_id;
        $basedata['key'] = $this->key;
        $basedata['loctype'] = 1;
        $basedata['data'] = $data;

        return $this->request($url,$basedata,$method);
    }

    private function request($url,Array $data,$method='get') {

        $method = strtoupper($method);
        $data = $this->build_query($data);

        $opts = array();

        $opts[CURLOPT_URL] = self::SERVICE_URL.$url;
        $opts[CURLOPT_SSL_VERIFYPEER] = false;
        $opts[CURLOPT_SSL_VERIFYHOST] = 2;
        $opts[CURLOPT_RETURNTRANSFER] = 1;

        if ($method != 'GET') {
            $opts[CURLOPT_CUSTOMREQUEST] = $method;
            $opts[CURLOPT_POSTFIELDS] = $data;
        } else {
            $opts[CURLOPT_URL] = $opts[CURLOPT_URL].'?'.$data;
        }

        $ch = curl_init();
        curl_setopt_array($ch,$opts);
        $ret = curl_exec($ch);
        curl_close($ch);
        return $ret;
    }

    private function parse($data) {
        $data = json_decode($data,1);

        if (!is_array($data)) {
            $this->error = 'remote_service_error';
        } else {
            if ($data['status'] == 0) {
                $this->error = $data['info'];
            }
        }

        return $data;
    }

    private function build_query(Array $data) {
        $str = '';
        foreach ($data as $key=>$item) {
            $str .= "{$key}=".rawurlencode($item)."&";
        }

        return substr($str,0,-1);
    }
    public function error() {
        return $this->error;
    }
}

花了点时间折腾了一下七牛云存储的一个基本上传逻辑,先放一下过些日子整理一个sdk出来

不得不再吐槽一下七牛,你真的是太可以了- -# 云存储做成你这样,也怪不容易的,好变态的接口啊

// CLI 模式下执行
<?php

error_reporting(E_ALL);


$localfile = __DIR__.'/do.png';

$access_key = 'n9fxNfp2oiHQJBR-kBJljkmNat9kAYO-Dg-oKgMP';
$secret_key = 'aaaaaaaa';

$token = Array();

// 定义参数
$bucket = 'cevin';

$filename = 'do.png';
$deadline = time()+3600;



// 组成Policy
$param = array(
    'scope' => "{$bucket}:{$filename}",
    'deadline' => $deadline
);
$param = json_encode($param);
$policy = safeEncode($param);

// 生成签名
$sign = hash_hmac('sha1',$policy,$secret_key,true);
$sign = safeEncode($sign);


// 生成上传凭证
$token['access_key'] = $access_key;
$token['sign'] = $sign;
$token['policy'] = $policy;
$token = implode(':',$token);


// 上传
$ch = curl_init();
curl_setopt_array($ch,array(
    CURLOPT_URL => 'http://up.qiniu.com',
    CURLOPT_RETURNTRANSFER => 1,
    CURLOPT_POST => 1,
    CURLOPT_HTTPHEADER => array('Content-type: multipart/form-data'),
    CURLOPT_POSTFIELDS => array('token'=>$token,'file' => new CURLFile($localfile),'key' => $filename ),
));
$ret = curl_exec($ch);$info=curl_getinfo($ch);curl_close($ch);

echo $ret;


function safeEncode($str) {
    return str_replace(array('+','/'),array('-','_'),base64_encode($str));
}

补充一下,CURLFile在PHP5.5.x之后才提供的,之前的版本请使用 ‘file’ => ‘@filepath’

阿里云OSS学习笔记

简单的概述一下,OSS的确是个好东西,用它做过图床、微网盘(已下线)。不需要考虑你的存储系统上限,即不需要考虑需要多大的硬盘,OSS无限空间自动伸缩;不用担心成本,OSS按需付费,每天结算一次;不用担心流量成本,OSS内网流量免费;不用担心安全,OSS每天自动备份……总之各种好处多多。

当然,OSS还算是个新的服务,有时候真的会抽风,但目前还没发现过数据丢失的问题!感觉还是很可以的嘛:)~~

简单的说一下学习过程和成果。

吐槽一下阿里云的签名机制,赶脚好蛋疼啊。比如拿上传文件和获取URL外链地址来做个比较吧,可能OSS的后端验证的问题吧,上传文件时必有参数为content-length(和content-md5二选一)、content-type、date。sign的时候是method+\n+content-md5+\n+content-type+\n+date+uri。好吧,赶脚还可以,然后再到获取URL外链地址,坑鸟。content-length、content-md5、content-type可以不要,但是在签名的时候又必须在!!只不过是空的。也就是说,sign的时候变成了method+\n+\n+\n+date+uri。- -#

所以,只能发挥php强大的数组的功能了。$options[‘content-type’] = ”然后生成签名的时候$signString = implode(“\n”,$options)。哈哈。搞定。

没错,OSS有自己的SDK,但是,,,programer,重在折腾:)。所以自己搞了个自己用的SDK,用法如下(只实现了简单的上传、删除、获取外链的功能):

$aliyun = new aliyun('bucket名称','授权ID','授权密钥');

// 上传
# 直接上传二进制内容
$aliyun->upload('1.jpg',file_get_contents('1.jpg'));
# 上传略大的文件 比如一个50M的压缩包
# OSS建议超过100M的文件使用分段上传提升速度但是经过实际测试在EC2上通过内网上传一个500M的压缩包,用时也就25秒的时间,还是可以接受的嘛~~:)
$aliyun->upload('xxx.zip','/data/xxx.zip');

// 删除
$aliyun->delete('1.jpg');
#批量删除 还无法正常使用,莫名的错误- -#我的问题不是OSS的
$aliyun->delete(array('1.jpg','xxx.zip'));

// 获取外链地址    默认有效时间是1天
$aliyun->getOutUrl('xxx.zip');
# 自定义有效时间 单位为 秒
$aliyun->getOutUrl('xxx.zip',10);

ok,暂时就这么多了,需要的童鞋可以留邮箱~~ 写的很丑~~不敢现世啊 🙂

淘宝开放平台PHP解析JSON得到科学计数法后的int

整体如下:

$ret = $tb->execute();
var_dump($ret);
/**
out:
array(
    ....
    'tid' => 2.33231123E+2
    ....
)
**/

在解析json之前,先酱紫处理一下:

$ret = $this->_curl->execute();
$ret = preg_replace("/(\d+)(,|})/",'"$1"$2',$ret);
return $ret;

Update

PHP的json_decode支持将大INT数字转换为字符串处理,譬如:

$json = '{"number": 12345678901234567890}';

var_dump(json_decode($json));
var_dump(json_decode($json, false, 512, JSON_BIGINT_AS_STRING));

详情请查阅手册:http://cn2.php.net/manual/zh/function.json-decode.php