<?php
/**
 * Created by PhpStorm.
 * User: 中闽 < 1464674022@qq.com >
 * Date: 2019/12/5
 * Time: 17:44
 */

// +----------------------------------------------------------------------
// 判断字符串匹配
// +----------------------------------------------------------------------

/**
 * 判断字符串是否以指定字符(串)开头
 * @param $str
 * @param $pattern
 * @return bool
 */
function startWith($str, $pattern)
{
    return (strpos($str, $pattern) === 0) ? true : false;
}

//判断字符串是否以指定字符(串)结束
function endWith($str, $pattern)
{
    $length = strlen($pattern);//这里只支持英文
    if ($length == 0) {
        return true;
    }
    return substr($str, -$length) === $pattern;
}

/**
 * 判断字符串$str是否包含$pattern
 * @param $str
 * @param $pattern
 * @return bool
 */
function ifContain($str, $pattern)
{
    return strpos($str, $pattern) !== false;
}

/**
 * 判断字符串是url格式
 */
function isUrl($str)
{
    $preg = "/http[s]?:\/\/[\w.]+[\w\/]*[\w.]*\??[\w=&\+\%]*/is";
    if (preg_match($preg, $str)) {
        return true;
    } else {
        return false;
    }
}
// +----------------------------------------------------------------------
// 字符串截取
// +----------------------------------------------------------------------

/**
 * 截取中文字符串
 * @param $str
 * @param $len [保留長度]
 * @return bool|string
 */
function subStrCN($str, $len)
{
    if (mb_strlen($str, "utf-8") > $len) {
        return $str = mb_substr($str, 0, $len, 'utf-8');
    }
    return $str;
}

/**
 * 截取字符串
 * @param $str
 * @param $len
 * @return bool|string
 */
function subStrEN($str, $len)
{
    if (strlen($str) > $len) {
        return $str = substr($str, 0, $len);
    }
    return $str;
}

/**
 * 限制ID字段的长度，防止非法格式导致入库失败
 * 超出長度的值，日志处理
 * @param $name [字段名]
 * @param $value [值]
 * @param int $len [限制长度]
 * @return int|string
 */
function limitNumLen($name, $value, $len = 10)
{
    if (!isset($value) || empty($value)) {
        return 0;
    }
    $value = trim($value);
    //判断是否为数字，或字符串数字
    if (is_numeric($value) && strlen($value) <= $len) {
        return $value;
    }
    \think\Log::log("limitLen error:$name = $value");
    return 0;
}

/**
 * 限制字段的长度，防止非法格式导致入库失败
 * 超出長度的值，日志处理
 * @param $name [字段名]
 * @param $value [值]
 * @param int $len [限制长度]
 * @return int|string
 */
function limitStrLen($name, $value, $len = 10)
{
    if (!isset($value) || empty($value)) {
        return '';
    }
    if (is_string($value) && mb_strlen($value, "utf-8") > $len) {
        \think\Log::notice("limitLen error:$name = $value");
    }
    return subStrCN($value, $len);
}


/**
 * 按指定长度，拆分中文字符串
 * @param $string
 * @param int $len
 * @return array
 * @throws Exception
 */
function mbStrSplit($string, $len = 1)
{
    if (0 >= $len) {
        throw new Exception('too short');
    }
    $start = 0;
    $array = [];
    $strlen = mb_strlen($string);
    while ($strlen) {
        $array[] = mb_substr($string, $start, $len, "utf8");
        $string = mb_substr($string, $len, $strlen, "utf8");
        $strlen = mb_strlen($string);
    }
    return $array;
}


// +----------------------------------------------------------------------
// 格式转换
// +----------------------------------------------------------------------

/**
 * 文字转拼音
 * @param $text
 * @return string
 */
function toPinyin($text)
{
    $pinyin = new \Overtrue\Pinyin\Pinyin();
    return $pinyin->permalink($text, '');//分隔符""
}

/**
 * 文字转首字母
 */
function toFirstLetter($text)
{
    $pinyin = new \Overtrue\Pinyin\Pinyin();
    return $pinyin->abbr($text, PINYIN_KEEP_NUMBER);//拼音首字母+数字
}

/**
 * 字节大小 格式化为合适的单位
 * @param  number $size 字节数
 * @param  string $delimiter 数字和单位分隔符
 * @return string   格式化后的带单位的大小
 */
function format_bytes($size, $delimiter = '')
{
    $units = array('B', 'KB', 'MB', 'GB', 'TB', 'PB');
    for ($i = 0; $size >= 1024 && $i < 5; $i++) $size /= 1024;
    return round($size, 2) . $delimiter . $units[$i];
}

/**
 * 隐藏昵称部分
 * @param $str
 * @param int $start
 * @param int $len
 * @return mixed
 */
function hide_name($str, $start = 3, $len = 6)
{
    return substr_replace($str, '******', $start, $len);
}

/**
 * 转为百分比格式
 * @param $number [计算好的rate必须是数字]
 * @return int|string
 */
function rateToPercent($number)
{
    return $number == 0 ? 0 : sprintf("%.4f", $number) * 100 . '%';
}


/**
 * 类似str_replace,但只替换一个
 * 或者 preg_replace(pattern,replacement,subject [, int limit 指定匹配个数])
 * @param $needle
 * @param $replace
 * @param $haystack
 * @return mixed
 */
function str_replace_once($needle, $replace, $haystack)
{
// Looks for the first occurence of $needle in $haystack
// and replaces it with $replace.
    $pos = strpos($haystack, $needle);
    if ($pos === false) {
        return $haystack;
    }
    return substr_replace($haystack, $replace, $pos, strlen($needle));
}

/**
 * 类似str_replace,但可指定替换次数
 * @param $search
 * @param $replace
 * @param $subject
 * @param int $limit
 * @return mixed
 */
function str_replace_limit($search, $replace, $subject, $limit = -1)
{
// constructing mask(s)...
    if (is_array($search)) {
        foreach ($search as $k => $v) {
            $search[$k] = '`' . preg_quote($search[$k], '`') . '`';
        }
    } else {
        $search = '`' . preg_quote($search, '`') . '`';
    }
// replacement
    return preg_replace($search, $replace, $subject, $limit);
}

// +----------------------------------------------------------------------
// 过滤函数
// +----------------------------------------------------------------------

/**
 * 过滤特殊字符，如微信昵称的表情符
 * @param $str
 * @return mixed
 */
function filterEmoji($str)
{
    $str = preg_replace_callback('/./u',
        function (array $match) {
            return strlen($match[0]) >= 4 ? '?' : $match[0];
        },
        $str);
    return $str;
}

/**
 * 去除换行符号
 * @param $str
 * @return mixed
 */
function filterLineFeedCharacter($str)
{
    return str_replace(array("\r\n", "\r", "\n"), "", $str);
}

/**
 * 过滤所有标点符号
 * @param $str
 * @return mixed|string
 */
function filterWord($str)
{
    if (trim($str) == '') return '';
    return preg_replace("/[^\x{4e00}-\x{9fa5}a-zA-Z0-9]/u", '', $str);
}

/**
 * 防止SQL注入
 * @param $value
 * @throws Exception
 */
function sqlInj($value)
{
    $arr = explode('|', 'UPDATEXML|UPDATE|WHERE|EXEC|INSERT|SELECT|DELETE|COUNT|CHR|MID|MASTER|TRUNCATE|DECLARE|BIND|DROP|CREATE| EXP |EXP%| OR |XOR| LIKE |NOTLIKE|NOT BETWEEN|NOTBETWEEN|BETWEEN|NOTIN|NOT IN|CONTACT|EXTRACTVALUE|LOAD_FILE|INFORMATION_SCHEMA|outfile|%20|into|union');
    if (is_string($value)) {
        foreach ($arr as $a) {
            //判断参数值中是否含有SQL关键字，如果有则跳出
            if (stripos($value, $a) !== false) {
                throw new Exception('参数错误，含有敏感字符' . $a);
            }
        }
    } elseif (is_array($value)) {
        //如果参数值是数组则递归遍历判断
        foreach ($value as $v) {
            sqlInj($v);
        }
    }
}

// +----------------------------------------------------------------------
// 匹配提取
// +----------------------------------------------------------------------

/**
 * 正则匹配出html中所有图片地址
 * @param $content
 * @return mixed
 */
function matchImg($content)
{
    $pattern_src = '/<[img|IMG].*?src=[\'|\"](.*?(?:[\.gif|\.jpg]))[\'|\"].*?[\/]?>/';
    $num = preg_match_all($pattern_src, $content, $match_src);
    $pic_arr = $match_src[1]; //获得图片数组
    return $pic_arr;
}

// +----------------------------------------------------------------------
// 加密相关
// +----------------------------------------------------------------------


/**
 * 生成随机密码
 * @param int $length [密码长度]
 * @param null $chars [设置密码字符集合]
 * @return bool|string
 */
function random_string($length = 32, $chars = null)
{
    if (empty($chars)) {
        $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
    }
    $chars = str_shuffle($chars);
    $num = $length < strlen($chars) - 1 ? $length : strlen($chars) - 1;
    return substr($chars, 0, $num);
}


/**
 * 不可逆加密,用于管理员密码加密
 * @param $password [密码]
 * @param $password_salt [可以自定义salt]
 * @return string
 */
function password($password, $password_salt = '')
{
    if ($password_salt == '') {
        $password_salt = system_salt();
    }
    return md5(md5($password) . md5($password_salt));
}

/**
 * 字符串(可逆)加密/解密
 * @param $value [需要加密的字符串]
 * @param int $type [加密解密（0：加密，1：解密）]
 * @return int|mixed    [加密或解密后的字符串]
 */
function encryption($value, $type = 0)
{
    $key = StrToBin(md5(system_salt()));
    if (!$type) {
        return str_replace('=', '', base64_encode($value ^ $key));
    } else {
        return base64_decode($value) ^ $key;
    }
}

/**
 * 将字符串转换成二进制
 * @param $str
 * @return string
 */
function StrToBin($str)
{
    //1.列出每个字符
    $arr = preg_split('/(?<!^)(?!$)/u', $str);
    //2.unpack字符
    foreach ($arr as &$v) {
        $temp = unpack('H*', $v);
        $v = base_convert($temp[1], 16, 2);
        unset($temp);
    }

    return join(' ', $arr);
}

/**
 * 二进制转换成字符串
 * @param $str
 * @return string
 */
function BinToStr($str)
{
    $arr = explode(' ', $str);
    foreach ($arr as &$v) {
        $v = pack("H" . strlen(base_convert($v, 2, 16)), base_convert($v, 2, 16));
    }
    return join('', $arr);
}

/**
 * 对id编码加密的函数，可用于生成不重复的邀请码
 *
 * https://www.php.cn/php-weizijiaocheng-388405.html
 * id是唯一的,转成36进制,就能得到简短的不重复的邀请码
 * 防止别人反推id，把0剔除，当做补位符号，变成35进制，再打乱$source_string
 *
 * @param $num [用户id]
 * @param $len [邀请码补位长度]
 * @param $source_str [范围为‘0-9A-Z’字符串再打乱就得到了$source_str]
 * @return string [邀请码]
 */
function inviteEncode($num, $len = 6, $source_str = 'ENV6J2R3HWXSTQA47MU5FCDGOPIB189KLYZ')
{
    $code = '';
    while ($num > 0) {
        $mod = $num % 35;
        $num = ($num - $mod) / 35;
        $code = $source_str[$mod] . $code;
    }
    if (empty($code[$len - 1]))
        $code = str_pad($code, $len, '0', STR_PAD_LEFT);
    return $code;
}

/**
 * inviteEncode对应的解码函数
 * @param $code [邀请码]
 * @param $source_str [需要和编码时的$source_str一致才能解码]
 * @return bool|int [用户id]
 */
function inviteDecode($code, $source_str = 'ENV6J2R3HWXSTQA47MU5FCDGOPIB189KLYZ')
{
    if (strrpos($code, '0') !== false)
        $code = substr($code, strrpos($code, '0') + 1);
    $len = strlen($code);
    $code = strrev($code);
    $num = 0;
    for ($i = 0; $i < $len; $i++) {
        $num += strpos($source_str, $code[$i]) * pow(35, $i);
    }
    return $num;
}


// +----------------------------------------------------------------------
// 分隔符
// +----------------------------------------------------------------------


//路径前追加文件分隔符
function appendStartDS($path, $separator = DS)
{
    return startWith($path, $separator) ? $path : $separator . $path;
}

//删除路径前的文件分隔符
function deleteStartDS($path, $separator = DS)
{
    return startWith($path, $separator) ? ltrim($path, $separator) : $path;
}

//路径后追加文件分隔符
function appendEndDS($path, $separator = DS)
{
    return endWith($path, $separator) ? $path : $path . $separator;
}

//路径后删除文件分隔符
function deleteEndDS($path, $separator = DS)
{
    return endWith($path, $separator) ? rtrim($path, $separator) : $path;
}

/**
 * 替换为当前系统文件分隔符
 */
function replaceDS($path)
{
    $WIN_DIRECTORY_SEPARATOR = "\\";
    $LINUX_DIRECTORY_SEPARATOR = "/";
    if (IS_WIN) {
        return str_replace($LINUX_DIRECTORY_SEPARATOR, $WIN_DIRECTORY_SEPARATOR, $path);
    } else {
        return str_replace($WIN_DIRECTORY_SEPARATOR, $LINUX_DIRECTORY_SEPARATOR, $path);
    }
}

/**
 * 替换为url分隔符
 * @param $uri
 * @return mixed
 */
function replaceUrlDS($uri)
{
    return str_replace("\\", "/", $uri);
}


