<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2019/5/16
 * Time: 15:45
 */

namespace Services\Library;


use Services\Service;

class Aes extends Service
{
    const KEY="lnlqwynwmolymxnp";
    const IV ="1234567812345678";
    #是否开启debug模式，debug模式会记录日志信息，生产环境请设置为false
    const DEBUG				=true;

    #构造方法
    public function __construct(){
        if(self::DEBUG){
            $this->debug('是从这里开始的',str_pad('=',200,'='));
        }
    }

    /**
     * pkcs7补码
     * @param string $string  明文
     * @param int $blocksize Blocksize , 以 byte 为单位
     * @return String
     */
    private function addPkcs7Padding($string, $blocksize = 32) {
        $len = strlen($string); //取得字符串长度
        $pad = $blocksize - ($len % $blocksize); //取得补码的长度
        $string .= str_repeat(chr($pad), $pad); //用ASCII码为补码长度的字符， 补足最后一段
        if(self::DEBUG){
            $this->debug('pkcs7补码：',$string);
        }
        return $string;
    }

    /**
     * 加密然后base64转码
     *
     * @param String 明文
     * @param 加密的初始向量（IV的长度必须和Blocksize一样， 且加密和解密一定要用相同的IV）
     * @param $key 密钥
     */
    function aes256cbcEncrypt($str, $iv, $key ) {
        if(self::DEBUG){
            $this->debug('接口调用：AES256加密【加密原串】',$str);
        }
        $result = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $this->addPkcs7Padding($str) , MCRYPT_MODE_CBC, $iv));
        if(self::DEBUG){
            $this->debug('加密然后base64转码：',$result);
        }
        return $result;
    }

    /**
     * 除去pkcs7 padding
     *
     * @param String 解密后的结果
     *
     * @return String
     */
    private function stripPkcs7Padding($string){
        $slast = ord(substr($string, -1));
        $slastc = chr($slast);
        $pcheck = substr($string, -$slast);

        if(preg_match("/$slastc{".$slast."}/", $string)){
            $string = substr($string, 0, strlen($string)-$slast);
            if(self::DEBUG){
                $this->debug('除去pkcs7：',$string);
            }
            return $string;
        } else {
            return false;
        }
    }
    /**
     * 解密
     *
     * @param String $encryptedText 二进制的密文
     * @param String $iv 加密时候的IV
     * @param String $key 密钥
     * @return String
     */
    function aes256cbcDecrypt($encryptedText, $iv, $key) {
        if(self::DEBUG){
            $this->debug('接口调用：AES256解密【解密原串】',$encryptedText);
        }
        $encryptedText =base64_decode($encryptedText);
        $result = $this->stripPkcs7Padding(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $encryptedText, MCRYPT_MODE_CBC, $iv));
        if(self::DEBUG){
            $this->debug('解密后数据：',$result);
        }
        return $result;
    }

    function aes128cbcDecrypt($encryptedText, $iv=self::IV, $key=self::KEY) {
        if(self::DEBUG){
            $this->debug('接口调用：AES128解密【解密原串】',$encryptedText);
        }
        $encryptedText =base64_decode($encryptedText);
        $result = $this->stripPkcs7Padding(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $encryptedText, MCRYPT_MODE_CBC, $iv));
        if(self::DEBUG){
            $this->debug('解密后数据：',$result);
        }
        return $result;
    }

    function hexToStr($hex)//十六进制转字符串
    {
        $string="";
        for($i=0;$i<strlen($hex)-1;$i+=2)
            $string.=chr(hexdec($hex[$i].$hex[$i+1]));
        if(self::DEBUG){
            $this->debug('十六进制转字符串：',$string);
        }
        return  $string;
    }
    function strToHex($string)//字符串转十六进制
    {
        $hex="";
        $tmp="";
        for($i=0;$i<strlen($string);$i++)
        {
            $tmp = dechex(ord($string[$i]));
            $hex.= strlen($tmp) == 1 ? "0".$tmp : $tmp;
        }
        //$hex=strtoupper($hex);
        if(self::DEBUG){
            $this->debug('字符串转十六进制：',$hex);
        }
        return $hex;
    }
    function aes128cbcHexDecrypt($encryptedText, $iv=self::IV, $key=self::KEY) {
        if(self::DEBUG){
            $this->debug('接口调用：AES128 16进制解密【解密原串】',$encryptedText);
        }
        $str = $this->hexToStr($encryptedText);
        $str =base64_decode($str);
        $base = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $str, MCRYPT_MODE_CBC, $iv);
        if(self::DEBUG){
            $this->debug('解密后数据：',$base);
        }
        $result = $this->stripPkcs7Padding($base);
        return $result;
    }

    function aes128cbcEncrypt($str, $iv=self::IV, $key=self::KEY ) {    // $this->addPkcs7Padding($str,16)
        if(self::DEBUG){
            $this->debug('接口调用：AES128 16进制加密【加密原串】',$str);
        }
        $base = (mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key,$this->addPkcs7Padding($str,16) , MCRYPT_MODE_CBC, $iv));
        $base = base64_encode($base);
        if(self::DEBUG){
            $this->debug('加密然后base64转码：',$base);
        }
        return $this->strToHex($base);
    }

    #日志记录
    function debug($tempType,$tempStr){
        //$log_name = DOXCX_FRAME_PATH.'Payment/CpayAPI/file/log.txt';
        $tempStr=date('Y-m-d H:i:s').' '.$tempType."\r\n".$tempStr."\r\n\r\n";
        file_put_contents(DOXCX_FRAME_PATH.'/log/aes/'.date('Y_m_d',time()).'.log', $tempStr,FILE_APPEND);
    }
}