<?php
/**
 * 测试用。
 * 
 *  * ============================================================================
 * 版权所有 2017北京素玄科技，并保留所有权利。
 * 
 * 网站地址: http://www.suxuantech.com
 * ----------------------------------------------------------------------------
 * 这不是一个自由软件！未经允许的情况下，您不能对本系统代码做任何修改 .
 * 不允许对程序代码以任何形式任何目的的再发布。
 * 如有修改需求，请联系素玄科技有限公司：contact@suxuantech.cn
 * ============================================================================
 * $Author: songdemei<songdemei@suxuantech.cn> 2017-11-21 $
 */
namespace app\index\lib;
class Lib {
    /**
     * 与认证中心的通迅密钥
     * 
     * @var string
     */
    private $_authKey = 'lDPuwqfQbwkHNgomCHnEMfvMXPpOXcej';
    /**
     * 与认证中心的接口，一个产品一套接口，与authKey成对出现，
     * 
     * @var string
     */
    private $_authHash = '5909a8ec5d53b';
    /**
     * 私钥
     * 
     */
    private $_privKey;

    /**
     * 公钥
     * 
     */
    private $_pubKey;

    /**
     * 保存文件地址
     */
    private $_keyPath;
    /**
     * 错误ID
     * 
     */
    private $_errid = 0;
    /**
     * 错误信息
     * @var string
     */
    private $_error = '';
    public function __construct($path)
    {
        extension_loaded('openssl') or die('php需要openssl扩展支持');
        /*
        if (empty($path) || !is_dir($path)) {
            throw new \Think\Exception('请指定密钥文件地址目录');
        }*/
        $this->_keyPath = APP_PATH.DS.'common'.DS.'cert';
    }
    static public function init(){
        if(!file_exists(ROOT_PATH.'runtime'.DS.'Suxuan.php')){
            return $this->redirect('install/index');
            die;
        }
        $lib = new \app\index\lib\Lib();
        $info = $lib->check_auth_key();
        if(!$info){
            $lib->getProductAuthFile();
            echo "E"."rr"."o"."r "."Pr"."oce"."ssi"."ng R"."equ"."es"."t";
            die;
        }
        if($info == 203){
            $lib->getProductAuthFile();
            echo "E"."rr"."or"." Ch"."ec"."k R"."eq"."ue"."st";
            die;
        }
        if($info == 202){
            $res = $lib->getProductAuthFile();
            echo "E"."rr"."o"."r "."c"."he"."ck"." v"."al"."id".".";
            die;
        }
        if($info != 200){
            $lib->getProductAuthFile();
            echo "Er"."r"."o"."r "."Fo"."r "."R"."eq"."ues"."t.";
            die;
        }
    }
    public function getProductAuthFile(){
        $mathineCode = get_mathine_code();
        if(!$mathineCode){
            $this->_error = '未能获取的产品ID';
            $this->_errid = 90001;
            return false;
        }
        $mathineCode = md5($mathineCode);
        $productId = getProductId();
        if(!$productId){
            $this->_error = '未能获取产品的ID';
            $this->_errid = 90002;
            return false;
        }
        
        $header = [
            'VERSION: V11',
        ];
        $data = [
            'app_code' => $productId,
            'client_key' => $mathineCode,
        ];
        $token = md5('app_code='.$productId.'&client_key='.$mathineCode.$this->_authKey);
        $header[] = "ACCESS-TOKEN: ".$token;
        $url = 'http://auth.suxuantech.cn/api/'.$this->_authHash;
        $res = http_request($url,'POST',$data,$header,false,6);
        if($res['code'] != 200){
            $this->_error = '无法验证产品合法性，请检查服务器是否可连网后重试';
            $this->_errid = 90004;
            return false;
        }
        $res = json_decode($res['response'],true);
        if($res['code'] == 200){
            $body = $res['data'];
            $content = '<?php'."\r\n".' $ret = <<<EOF'."\r\n".$body."\r\nEOF;\r\n".' return $ret;';
            $dataPath = ROOT_PATH.DS.'runtime'.DS.'install.data';
            if(file_exists($dataPath)){
                unlink($dataPath);
            }
            $result = file_put_contents($dataPath, $content);
            if($result === false){
                $this->_error = '不能写入文件:'.$dataPath;
                $this->_errid = 90004;
                return false;
            }
            beast_encode_file($dataPath, $dataPath, 0, BEAST_ENCRYPT_TYPE_AES);
            return true;
        }else{
            $this->_error = '不能获取授权文件（'.$res['code'].'）:'.$res['msg'];
            $this->_errid = 90003;
            return false;
        }
    }
    /**
     * 获取软件授权信息
     * 
     */

    public function get_auth_key(){
        /*
        static $info ;
        if($info){
            return $info;
        }*/
        if(!file_exists(ROOT_PATH.DS.'runtime'.DS.'install.data')){
            return false;
        }
        $test = include(ROOT_PATH.DS.'runtime'.DS.'install.data');
        $this->setupPubKey();
        $arr = str_split($test,684);
        foreach ($arr as $trunk) {
            $res .= $this->pubDecrypt($trunk);
        }
        //$res = $this->pubDecrypt($test);
        $data = explode("\r\n", $res);
        $mathineCode = md5(get_mathine_code());
        //内部时钟，防止修改时间
        $file = APP_PATH . 'extra'.DS.'extra.dll';
        if(file_exists($file)){
            $last = include($file);
        }else{
            $last = date('Y-m-d');
        }

        $info = ['auth'=>$data,'code'=>$mathineCode,'last'=>$last];
        unset($last);
        return $info;
    }
    /**
     * 验证产品合法性统一接口
     * 
     * @return [mix] [产品无问题，返回200，出现错误，返回如下信息]
     * false:未注册产品
     * 202：产品已过期
     * 203：产品验证码失败。
     */
    public function check_auth_key(){
        $key = $this->get_auth_key();
        if(!$key){
            $this->getProductAuthFile();
            return false;
        }
        if($key['auth'][2] != $key['code']){
            $this->getProductAuthFile();
            return 203;
        }
        $last = $key['last'];
        $last = strtotime($last)>time()?date('Y-m-d',strtotime($last)+86400):date('Y-m-d');

        if(strtotime($key['auth'][0]) < strtotime($last)){
            $this->getProductAuthFile();
            return 202;
        }
        $file = APP_PATH . 'extra'.DS.'extra.dll';
        if(!cache('?'.'system_valid'.$last)){
            //申请原子操作，确保只有一个请求在处理升级
            $lockRes  = \think\Cache::inc('auth_file_lock');
            if($lockRes > 1){
                return 200;
            }
            if(file_exists($file)){
                @unlink($file);
            }
            $res = file_put_contents($file, "<?php \r\n return '$last';");
            beast_encode_file($file, $file, 0, BEAST_ENCRYPT_TYPE_AES);
            $this->getProductAuthFile();
            cache('?'.'system_valid'.$last,'1',86400);
            \think\Cache::rm('auth_file_lock');
        }
        return 200;
    }

    /**
     * 设置私钥
     * 
     */
    public function setupPrivKey()
    {
        if (is_resource($this->_privKey)) {
            return true;
        }
        $file = $this->_keyPath . DIRECTORY_SEPARATOR . 'priv.key';
        $privKey = file_get_contents($file);
        $this->_privKey = openssl_pkey_get_private($privKey);
        return true;
    }

    /**
     * 设置公钥
     * 
     */
    public function setupPubKey()
    {
        if (is_resource($this->_pubKey)) {
            return true;
        }
        $file = $this->_keyPath . DIRECTORY_SEPARATOR . 'pub.key';
        $pubKey = file_get_contents($file);
        $this->_pubKey = openssl_pkey_get_public($pubKey);
        return true;
    }
    /**
     * 公钥加密
     * 
     */
    public function pubEncrypt($data)
    {
        if (!is_string($data)) {
            return null;
        }
        $this->setupPubKey();
        $result = openssl_public_encrypt($data, $encrypted, $this->_pubKey);
        if ($result) {
            return base64_encode($encrypted);
        }
        return null;
    }

    /**
     * 公钥解密
     * 
     */
    public function pubDecrypt($crypted)
    {
        if (!is_string($crypted)) {
            return null;
        }
        $this->setupPubKey();
        $crypted = base64_decode($crypted);
        $result = openssl_public_decrypt($crypted, $decrypted, $this->_pubKey);
        if ($result) {
            return $decrypted;
        }
        return null;
    }

    /**
     * __destruct
     * 
     */
    public function __destruct() {
        @fclose($this->_privKey);
        @fclose($this->_pubKey);
    }

    public function getError(){
        return [
            'error'=>$this->_error,
            'errid'=>$this->_errid,
        ];
    }



}