range

If there were you, the world would be just right

1 电脑打开软件
2 手机连接wifi与电脑同一网段网络,wifi设置代理到电脑
3 下载安装证书 手机浏览器打开:http://www.charlesproxy.com/getssl
4 设置 代理-SSL代理-启用SSL代理-主机添加* 端口添加443


记录AES加密算法

<?php

namespace Aes;
 
class Aes
{
    /**
     * var string $method 加解密方法,可通过openssl_get_cipher_methods()获得
     */
    protected $method;
 
    /**
     * var string $secret_key 加解密的密钥
     */
    protected $secret_key;
 
    /**
     * var string $iv 加解密的向量,有些方法需要设置比如CBC
     */
    protected $iv;
 
    /**
     * var string $options (不知道怎么解释,目前设置为0没什么问题)
     */
    protected $options;
 
    /**
     * 构造函数
     *
     * @param string $key 密钥
     * @param string $method 加密方式
     * @param string $iv iv向量
     * @param mixed $options 还不是很清楚
     *
     */
    public function __construct($key, $method = 'AES-128-ECB', $iv = '', $options = 0)
    {
        // key是必须要设置的
        $this->secret_key = isset($key) ? $key : 'morefun';
 
        $this->method = $method;
 
        $this->iv = $iv;
 
        $this->options = $options;
    }
 
    /**
     * 加密方法,对数据进行加密,返回加密后的数据
     *
     * @param string $data 要加密的数据
     *
     * @return string
     *
     */
    public function encrypt($data)
    {
        return openssl_encrypt($data, $this->method, $this->secret_key, $this->options, $this->iv);
    }
 
    /**
     * 解密方法,对数据进行解密,返回解密后的数据
     *
     * @param string $data 要解密的数据
     *
     * @return string
     *
     */
    public function decrypt($data)
    {
        return openssl_decrypt($data, $this->method, $this->secret_key, $this->options, $this->iv);
    }
}

demo:

class Rsa
{
    private $_config = [
        'public_key' => '',
        'private_key' => '',
    ];

    public function __construct($private_key_filepath, $public_key_filepath) {
        $this->_config['private_key'] = $this->_getContents($private_key_filepath);
        $this->_config['public_key'] = $this->_getContents($public_key_filepath);
    }

    /**
     * @uses 获取文件内容
     * @param $file_path string
     * @return bool|string
     */
    private function _getContents($file_path) {
        file_exists($file_path) or die ('密钥或公钥的文件路径错误');
        return file_get_contents($file_path);
    }

    /**     
     * @uses 获取私钥
     * @return bool|resource     
     */ 
    private function _getPrivateKey() {
       $priv_key = $this->_config['private_key'];
       return openssl_pkey_get_private($priv_key);
    }

    /**     
     * @uses 获取公钥
     * @return bool|resource     
     */    
    private function _getPublicKey() {        
        $public_key = $this->_config['public_key'];
        return openssl_pkey_get_public($public_key);
    }

    /**     
     * @uses 私钥加密
     * @param string $data     
     * @return null|string     
     */    
    public function privEncrypt($data = '') {        
        if (!is_string($data)) {
            return null;       
        }
        return openssl_private_encrypt($data, $encrypted, $this->_getPrivateKey()) ? base64_encode($encrypted) : null;
    }

    /**     
     * @uses 公钥加密     
     * @param string $data     
     * @return null|string     
     */    
    public function publicEncrypt($data = '') {        
        if (!is_string($data)) {
            return null;        
        }        
        return openssl_public_encrypt($data, $encrypted, $this->_getPublicKey()) ? base64_encode($encrypted) : null;
    }

    /**     
     * @uses 私钥解密     
     * @param string $encrypted     
     * @return null     
     */    
    public function privDecrypt($encrypted = '') {        
        if (!is_string($encrypted)) {
            return null;        
        }
        return (openssl_private_decrypt(base64_decode($encrypted), $decrypted, $this->_getPrivateKey())) ? $decrypted : null;
    }    

    /**     
     * @uses 公钥解密     
     * @param string $encrypted     
     * @return null     
     */    
    public function publicDecrypt($encrypted = '') {        
        if (!is_string($encrypted)) {
            return null;        
        }        
           return (openssl_public_decrypt(base64_decode($encrypted), $decrypted, $this->_getPublicKey())) ? $decrypted : null;
    }
}

测试:

$private_key = 'private_key.pem'; // 私钥路径
$public_key = 'rsa_public_key.pem'; // 公钥路径
$rsa = new Rsa($private_key, $public_key);

$origin_data = '这是一条测试数据';

$ecryption_data = $rsa->privEncrypt($origin_data);

$decryption_data = $rsa->publicDecrypt($ecryption_data);

echo '私钥加密后的数据为:' . $ecryption_data;
echo PHP_EOL;
echo '公钥解密后的数据为: ' . $decryption_data;
echo PHP_EOL;

最后要说明的是,公钥、私钥都可以加密,也都可以解密。其中:用公钥加密需要私钥解密,称为“加密”。由于私钥是不公开的,确保了内容的保密,没有私钥无法获得内容;用私钥加密需要公钥解密,称为“签名”。由于公钥是公开的,任何人都可以解密内容,但只能用发布者的公钥解密,验证了内容是该发布者发出的。


单例模式的定义
确保某一个类只有一个实例,不能重复实例,只能它自己实例化,而且向整个系统提供这个实例。

在有trait之前,无法实现让父类实现单例模式,让子类去继承。trait的出现很自然地解决了这个问题,我们可以写一个实现单例的trait,然后把它组合到任何想实现单例的类

<?php

trait DlTrait {

    protected static $instance = null;

    public static function instance() {
        if (null === self::$instance) {
            self::$instance = new static();
        }
        return self::$instance;
    }
}

class a
{
    use DlTrait;
}

$a = a::instance();
$b = a::instance();

if($a === $b){
    echo "相同";
}else{
    echo "不相同";
}

分表?
将单个大的数据库表进行拆分,拆分成多个数据表,然后用户访问的时候,根据一定的算法(hash/取模),让用户访问不同的表,这样数据分散到多个数据表中,减少了单个数据表的访问压力,缩短查询时间提升了数据库访问性能。

场景1:
1000万用户user表,拆分为100个分表,命名 user_00 - user_99 ,通过用户id 取模的方法把数据分散到这100个表中
场景2:
用户登录操作日志类,日流量高达500万+,通过使用日期分表方法,将数据按日期保存表名 xxlog_20190918

分表缺点
查询汇总数据难度增大

分区

  • 逻辑上表仍然是一张完整的表,只是将表中的数据在物理上存放到多个表空间(物理文件)
  • 一个表最多只能有1024个分区。
  • 如果分区字段中有主键或者唯一索引的列,那么多有主键列和唯一索引列都必须包含进来。
    即:分区字段要么不包含主键或者索引列,要么包含全部主键和索引列。
  • 分区表中无法使用外键约束

分区类型

  • RANGE分区:基于属于一个给定连续区间的列值,把多行分配给分区。
  • LIST分区:类似于按RANGE分区,区别在于LIST分区是基于列值匹配一个离散值集合中的某个值来进行选择。
  • HASH分区:基于用户定义的表达式的返回值来进行选择的分区,该表达式使用将要插入到表中的这些行的列值进行计算。这个函数可以包含MySQL 中有效的、产生非负整数值的任何表达式。
  • KEY分区:类似于按HASH分区,区别在于KEY分区只支持计算一列或多列,且MySQL服务器提供其自身的哈希函数。必须有一列或多列包含整数值。

建立分区表注意:

  • 顺应MYSQL的要求,primary key和unique key必须包含在分区key的一部分 所以把分区字段加入到主键中,组成复合主键
  • 查询sql 必须走分区键,避免查所有区
  • 在where语句中包含分区条件时,可以只扫描一个或多个分区表来提高查询效率;
  • 插入数据,如果数据对应本该插入的分区不存在会报错
  • 单张表最多是只能有1024个分区的(所以不按日做表)

分区选择

这个看个人业务,此处主要说我用到的

1、list 分区键必须为整数类型( 弃用 )

2、RANGE 区间范围( 与日期相关的统一采用range )

#维护相关
  查分区内容
    SELECT * FROM tableName PARTITION (p1,p2)
  添加分区:
    alter table tableName add partition (partition p0 values less than(1991));  //只能添加大于分区键的分区  
  删除分区数据
    alter table tableName  truncate partition p1,p2;  
    alter table tableName  truncate partition all; 
  删除分区
    alter table tableName drop partition p0; //可以删除任意分区

3、hash 分区键必须为整数类型( 可用hash则不用key,userId 为整形选择hash作为用户表分区 )

TIPS:
1)hash的分区必须是整数列
2)drop partition命令只能用在RANGE和LIST分区中。
3)分区的字段必须是要包含在主键字段之内,不然会报错

维护相关
  添加分区:
    ALTER TABLE tableName ADD PARTITION PARTITIONS 6; // 加6个区
  减少分区:
    ALTER TABLE tableName COALESCE PARTITION 4; // 减4个区
  移除表的分区
    ALTER TABLE tablename REMOVE PARTITIONING ;

注意:使用remove移除分区是仅仅移除分区的定义,并不会删除数据和drop PARTITION不一样,后者会连同数据一起删除

4、key 分区键字段不限制为整数类型( 设备为字符串可选择key分区 )

TIPS:
1) KEY分区支持除text和BLOB之外的所有数据类型的分区
2) 数据会分布不均(多次测试结果,创建分区个数为奇数 如99,可使数据相对分布更均匀)
3) 无法直接定位数据在哪个分区