<?php

namespace Helper;

use Abstracts\SingleTon;

/**
 * 可逆的php加密方法
 *
 * Link         :   http://www.phpcorner.net
 * User         :   phpcorner.net<780042175@qq.com>
 * Date         :   2019-05-23
 * Version      :   1.0
 *
 * Class Crypt
 * @package Helper
 */
class Crypt extends SingleTon
{
    private $_privateKey = 'phpcorner.net';

    protected $chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.";

    /**
     * 设置私钥
     * @param string $key
     */
    public function setPrivateKey($key)
    {
        $this->_privateKey = md5($key);
    }

    /**
     * 获取私钥
     * @return string
     */
    protected function getPrivateKey()
    {
        if (empty($this->_privateKey)) {
            $this->setPrivateKey('phpcorner.net');
        }
        return $this->_privateKey;
    }

    /**
     * 加密
     * @param string $txt
     * @param string $key
     * @return mixed|string
     */
    public function encode($txt, $key = 'qingbing')
    {
        $chars = $this->chars;
        $k_sum = 0;
        $i = 0;
        while (isset($key{$i})) {
            $k_sum += ord($key{$i++});
        }
        $n_1 = rand(0, 64);
        $n_2 = rand(0, 64);
        $n_3 = rand(0, 64);
        $c_1 = $chars{$n_1};
        $c_2 = $chars{$n_2};
        $c_3 = $chars{$n_3};
        $n_sum = $n_1 + $n_2 + $n_3;
        $m_key = substr(md5(md5(md5($key . $c_1) . $c_2 . $this->getPrivateKey()) . $c_3), $n_sum % 8, $k_sum % 8 + 19);
        $txt = base64_encode($txt);
        $txt = str_replace(array('+', '/', '='), array('-', '_', '.'), $txt);
        $t_len = strlen($txt);
        $k_len = strlen($m_key);
        $k = 0;
        $r = '';
        for ($i = 0; $i < $t_len; $i++) {
            $k = $k == $k_len ? 0 : $k;
            $j = ($n_sum + strpos($chars, $txt{$i}) + ord($m_key{$k++})) % 65;
            $r .= $chars{$j};
        }
        $r_len = strlen($r);
        $r = substr_replace($r, $c_3, $n_2 % ++$r_len, 0);
        $r = substr_replace($r, $c_2, $n_1 % ++$r_len, 0);
        $r = substr_replace($r, $c_1, $k_sum % ++$r_len, 0);
        return $r;
    }

    /**
     * 解密
     * @param string $txt
     * @param string $key
     * @return bool|string
     */
    public function decode($txt, $key = 'qingbing')
    {
        $chars = $this->chars;
        $k_sum = 0;
        $i = 0;
        while (isset($key{$i})) {
            $k_sum += ord($key{$i++});
        }
        $t_len = strlen($txt);
        $c_1 = $txt{$k_sum % $t_len};
        $n_1 = strpos($chars, $c_1);
        $txt = substr_replace($txt, '', $k_sum % $t_len--, 1);
        $c_2 = $txt{$n_1 % $t_len};
        $n_2 = strpos($chars, $c_2);
        $txt = substr_replace($txt, '', $n_1 % $t_len--, 1);
        $c_3 = $txt{$n_2 % $t_len};
        $n_3 = strpos($chars, $c_3);
        $txt = substr_replace($txt, '', $n_2 % $t_len--, 1);
        $n_sum = $n_1 + $n_2 + $n_3;
        $m_key = substr(md5(md5(md5($key . $c_1) . $c_2 . $this->getPrivateKey()) . $c_3), $n_sum % 8, $k_sum % 8 + 19);
        $k_len = strlen($m_key);
        $r = '';
        $k = 0;
        for ($i = 0; $i < $t_len; $i++) {
            $k = $k == $k_len ? 0 : $k;
            $j = strpos($chars, $txt[$i]) - $n_sum - ord($m_key{$k++});
            while ($j < 0) {
                $j += 65;
            }
            $r .= $chars{$j};
        }

        $txt = str_replace(array('-', '_', '.'), array('+', '/', '='), $r);
        return base64_decode($txt);
    }
}