**目录:
Services业务代码
Controllers数据处理
Model数据处理**
## 一、 创建公共类
1、**在App目录下创建Helpers.php**
~~~
<?php
use App\Exceptions\AuthorizationException;
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
use Godruoyi\Snowflake\Snowflake;
/**
* @param float $money
* @return float
* 保留小数点后两位,不进行四舍五入
*/
function SubStr2(float $money): float
{
return substr(round($money, 3), 0, -1);
}
/**
* 根据身份证号码计算年龄
* author:xiaochuan
* @param string $identityId 身份证号码
* @return int $age
*/
function getUserAge(string $identityId): int
{
if ($identityId == "") {
return 0;
}
# 获得出生年月日的时间戳
$date = strtotime(substr($identityId, 6, 8));
# 获得今日的时间戳
$today = strtotime('today');
# 得到两个日期相差的大体年数
$diff = floor(($today - $date) / 86400 / 365);
# strtotime加上这个年数后得到那日的时间戳后与今日的时间戳相比
return strtotime(substr($identityId, 6, 8) . ' +' . $diff . 'years') > $today ? ($diff + 1) : $diff;
}
/**
* 判断字符串是否是身份证号
* author:xiaochuan
* @param string $identityId 身份证号码
*/
function checkIdentityId(string $identityId): bool
{
$id = strtoupper($identityId);
$regx = "/(^\d{15}$)|(^\d{17}([0-9]|X)$)/";
$arr_split = array();
if (!preg_match($regx, $id)) {
return false;
}
if (15 == strlen($id)) //检查15位
{
$regx = "/^(\d{6})+(\d{2})+(\d{2})+(\d{2})+(\d{3})$/";
@preg_match($regx, $id, $arr_split);
//检查生日日期是否正确
$dtm_birth = "19" . $arr_split[2] . '/' . $arr_split[3] . '/' . $arr_split[4];
if (!strtotime($dtm_birth)) {
return false;
} else {
return true;
}
} else //检查18位
{
$regx = "/^(\d{6})+(\d{4})+(\d{2})+(\d{2})+(\d{3})([0-9]|X)$/";
@preg_match($regx, $id, $arr_split);
$dtm_birth = $arr_split[2] . '/' . $arr_split[3] . '/' . $arr_split[4];
if (!strtotime($dtm_birth)) //检查生日日期是否正确
{
return false;
} else {
//检验18位身份证的校验码是否正确。
//校验位按照ISO 7064:1983.MOD 11-2的规定生成,X可以认为是数字10。
$arr_int = array(7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2);
$arr_ch = array('1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2');
$sign = 0;
for ($i = 0; $i < 17; $i++) {
$b = (int)$id[$i];
$w = $arr_int[$i];
$sign += $b * $w;
}
$n = $sign % 11;
$val_num = $arr_ch[$n];
if ($val_num != substr($id, 17, 1)) {
return false;
} else {
return true;
}
}
}
}
/**
* @param $phone
* @return bool
* 校验手机号
*/
function checkPhone($phone): bool
{
if (!preg_match("/^1[3456789]\d{9}$/", $phone)) {
return false;
}
return true;
}
function checkPassword(string $pwd): bool
{
if (!preg_match("/^[a-zA-Z0-9]{6,12}$/", $pwd)) {
return false;
}
return true;
}
/**
* 校验银行卡
* @param string $card
* @return bool
*/
function checkBankCard(string $card): bool
{
$len = strlen($card);
if ($len < 3) {
return false;
}
$all = [];
$sumOdd = 0;
$sumEven = 0;
for ($i = 0; $i < $len; $i++) {
$all[] = substr($card, $len - $i - 1, 1);
}
//all 里的偶数key都是我们要相加的奇数位
for ($k = 0; $k < $len; $k++) {
if ($k % 2 == 0) {
$sumOdd += $all[$k];
} else {
//奇数key都是要相加的偶数和
if ($all[$k] * 2 >= 10) {
$sumEven += $all[$k] * 2 - 9;
} else {
$sumEven += $all[$k] * 2;
}
}
}
$total = $sumOdd + $sumEven;
if ($total % 10 == 0) {
return true;
} else {
return false;
}
}
//校验用户姓名
function checkName($name): bool
{
if (empty($name)) {
return false;
}
//中文+身份证允许有.
if (!preg_match('/^[\x{4e00}-\x{9fa5}]+[·•]?[\x{4e00}-\x{9fa5}]+$/u', $name)) {
return false;
}
$strLen = mb_strlen($name);
if ($strLen < 2 || $strLen > 8) {//字符长度2到8之间
return false;
}
return true;
}
//删除字符串空格
function triMall($str)
{
$limit = array(" ", " ", "\t", "\n", "\r");
$rep = array("", "", "", "", "");
return str_replace($limit, $rep, $str);
}
/**
* @return string
* 返回当前日期
*/
function TimeNow(): string
{
date_default_timezone_set("PRC");
return date("Y-m-d H:i:s");
}
function GetTomorrow(): string
{
date_default_timezone_set("PRC");
return date("Y-m-d H:i:s", strtotime(date('Y-m-d', strtotime('+1 day'))));
}
function GetFirstDayMonth(): string
{
date_default_timezone_set("PRC");
return date("Y-m-01 00:00:00", strtotime(date('Y-m-d')));
}
/**
* 获取明日凌晨零点
* @return string
*/
function GetTomorrow0Hour(): string
{
date_default_timezone_set("PRC");
return date('Y-m-d 00:00:00', strtotime("+1 day"));
}
function GetToDay0Hour(): string
{
date_default_timezone_set("PRC");
return date('Y-m-d 00:00:00', time());
}
//时间戳转字符串
function NewId(): int
{
return (new Snowflake)->id();
}
function GetOrderSn(): string
{
return date('YmdHis') . substr(time(), -5) . substr(microtime(), 2, 5) . sprintf('%02d', rand(100000, 999999));
}
function getAge(string $id): int
{
# 1.从身份证中获取出生日期
$birthDate = strtotime(substr($id, 6, 8));//截取日期并转为时间戳
# 2.格式化[出生日期]
$year = date('Y', $birthDate);//yyyy
$month = date('m', $birthDate);//mm
$day = date('d', $birthDate);//dd
# 3.格式化[当前日期]
$currentY = date('Y');//yyyy
$currentM = date('m');//mm
$currentD = date('d');//dd
# 4.计算年龄()
$age = $currentY - $year;//今年减去生日年
if ($month > $currentM || $month == $currentM && $day > $currentD) {//深层判断(日)
$age--;//如果出生月大于当前月或出生月等于当前月但出生日大于当前日则减一岁
}
# 返回
return $age;
}
/**
* 获取IP地址
* @return mixed|string
*/
function getClientIP()
{
if (isset($_SERVER['HTTP_CLIENT_IP'])) {
return $_SERVER['HTTP_CLIENT_IP'];
} elseif (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
// 可能包含多个 IP,取最后一个 IP 为真实 IP
$ipAddresses = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
return trim(end($ipAddresses));
} elseif (isset($_SERVER['HTTP_X_FORWARDED'])) {
return $_SERVER['HTTP_X_FORWARDED'];
} elseif (isset($_SERVER['HTTP_X_CLUSTER_CLIENT_IP'])) {
return $_SERVER['HTTP_X_CLUSTER_CLIENT_IP'];
} elseif (isset($_SERVER['HTTP_FORWARDED_FOR'])) {
return $_SERVER['HTTP_FORWARDED_FOR'];
} elseif (isset($_SERVER['HTTP_FORWARDED'])) {
return $_SERVER['HTTP_FORWARDED'];
} else {
return $_SERVER['REMOTE_ADDR'];
}
}
~~~
## 二、密码生成于验证
1、**在App项目下创建Valobj目录,并且在Valobj中创建UserObj类(App/Valobj/UserObj.php)**
~~~
<?php
namespace App\Valobj;
class UserObj
{
public static function Encrypt($pwd): string
{
$salt = substr(sha1($pwd),0,16);
return $salt . sha1($salt.$pwd);
}
public static function VerifyEncryptPassword($pwd, $hashPassword): bool
{
$salt = substr($hashPassword, 0, 16);
$encrypt = $salt . sha1($salt . $pwd);
if ($hashPassword != $encrypt) {
return false;
}
return true;
}
}
~~~
## 三、 关于数据返回类相关方法
在App项目下创建System目录,并且在System中创建ApiRespons类(App/System/ApiResponse.php)
~~~
<?php
namespace App\System;
use App\Exceptions\InternException;
use App\Exceptions\SystemException;
use Illuminate\Http\JsonResponse;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
trait ApiResponse
{
/**
* 成功
* @param null $data
* @param array $codeResponse
* @return JsonResponse
*/
public function success($data = null,$msg="请求成功"): JsonResponse
{
return $this->jsonResponse( $msg, $data, null,200);
}
/**
* 失败
* @param array $codeResponse
* @param null $data
* @param null $error
* @return JsonResponse
*/
public function fail($msg, $data = null, $error=null): JsonResponse
{
return $this->jsonResponse( $msg, $data, $error,400);
}
/**
* json响应
* @param $status
* @param $codeResponse
* @param $data
* @param $error
* @return JsonResponse
*/
private function jsonResponse( $msg, $data, $error,$httpCode): JsonResponse
{
if (is_array($data)){
$data = $this->changeHump($data);
}
if (is_object($data)){
$data = $this->changeHump($this->objectArray($data));
}
return response()->json([
'code' => $httpCode,
'msg' => $msg,
'data' => $data ?? null,
'error' => $error,
],$httpCode)->setEncodingOptions(JSON_UNESCAPED_UNICODE);
}
/**
* 成功分页返回
* @param $page
* @return JsonResponse
*/
protected function successPaginate($page): JsonResponse
{
return $this->success($this->paginate($page));
}
private function paginate($page)
{
if ($page instanceof LengthAwarePaginator){
return [
'total' => $page->total(),
'page' => $page->currentPage(),
'limit' => $page->perPage(),
'pages' => $page->lastPage(),
'list' => $page->items()
];
}
if ($page instanceof Collection){
$page = $page->toArray();
}
if (!is_array($page) && !is_object($page)){
return $page;
}
$total = count($page);
return [
'total' => $total, //数据总数
'page' => 1, // 当前页码
'limit' => $total, // 每页的数据条数
'pages' => 1, // 最后一页的页码
'list' => $page // 数据
];
}
/**
* 内置错误返回
* @param array $codeResponse
* @param string $info
* @throws InternException
*/
public function throwInternException(array $codeResponse=SysCode::HTTP_ERROR, string $info = '')
{
throw new InternException($codeResponse, $info);
}
/**
* 业务错误返回
* @param array $codeResponse
* @param string $info
* @throws SystemException
*/
public function throwSystemException(string $msg,string $code="400")
{
throw new SystemException($msg, $code);
}
//转换驼峰(只转key)
public function changeHump($params):array
{
if (empty($params)){
return [];
}
if (is_object($params)){
$params = get_object_vars($params);
}
if (is_array($params)) {
foreach ($params as $key => $value) {
if (is_int($value)&&strlen($value)>16){
$value = (string)$value;
}
unset($params[$key]);
$params[$this->convertUnderline($key)] = is_array($value) ? $this->changeHump($value) : $value;
}
}
return $params;
}
public function unChangeHump(array $params):array
{
if (empty($params)){
return [];
}
foreach ($params as $key => $value) {
if (is_int($value)&&strlen($value)>16){
$value = (string)$value;
}
unset($params[$key]);
$params[$this->uncamelize($key)] = is_array($value) ? $this->unChangeHump($value) : $value;
}
return $params;
}
public function uncamelize(string $camelCaps,$separator='_'):string{
return strtolower(preg_replace('/([a-z])([A-Z])/', "$1" . $separator . "$2", $camelCaps));
}
public function convertUnderline($str): string
{
return preg_replace_callback('/([-_]+([a-z]{1}))/i', function ($matches) {
return strtoupper($matches[2]);
}, $str);
}
function objectArray($array)
{
if (is_object($array)) {
$array = (array)$array;
}
if (is_array($array)) {
foreach ($array as $key => $value) {
$array[$key] = $this->objectArray($value);
}
}
return $array;
}
/**
* 赋值给结构体
* @param array $arr1
* @param array $arr2
* @return array
*/
function bestowStruct(array $arr1,array $arr2):array{
foreach ($arr1 as $key=>$value){
$arr2[$key]=$value;
}
return $arr2;
}
}
~~~
## 四、 三方请求类(三方请求的相关类都可以放里面)
在App中创建Facade文件,在Facade中创建BaseFacade.php类(App/Facade/BaseFacade.php)
~~~
<?php
namespace App\Facade;
use App\System\ApiResponse;
class BaseFacade
{
use ApiResponse;
protected function curlPost(string $url, array $postFields)
{
$postFields = json_encode($postFields);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json; charset=utf-8' //json版本需要填写 Content-Type: application/json;
)
);
curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); //若果报错 name lookup timed out 报错时添加这一行代码
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postFields);
curl_setopt($ch, CURLOPT_TIMEOUT, 60);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
$ret = curl_exec($ch);
if (false === $ret) {
$result = curl_error($ch);
} else {
$rsp = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if (200 != $rsp) {
$result = "请求状态 " . $rsp . " " . curl_error($ch);
} else {
$result = $ret;
}
}
curl_close($ch);
return json_decode($result, true);
}
/**
* get 请求
*/
protected function curlGet(string $url = '', $header = [])
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HTTPGET, true);
if ($header) {
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
}
curl_setopt($ch, CURLOPT_TIMEOUT, 30); //设置超时时间:30s
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); //忽略ssl检测
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); //1 或 TRUE 将curl_exec()获取的信息以字符串返回,而不是直接输出。-
curl_setopt($ch, CURLINFO_HEADER_OUT, true); //TRUE 时追踪句柄的请求字符串,从 PHP 5.1.3 开始可用。这个很关键,就是允许你查看请求header
$result = curl_exec($ch);
if (!$result){
return [];
}
curl_close($ch);
return json_decode($result, true);
}
}
~~~
## 三方类(redis锁)
在App中创建RedisClient.php类(App/Pkg/redis/RedisClient.php)
~~~
<?php
use App\Exceptions\SystemException;
class RedisClient
{
private \Redis $redis;
/**
*这里我直接使用的$this->connect();连接的redis
*用tp的Cache::handler();一直报错,不知道什么情况。。
*如果有人知道请在下方留言 感激不敬
* @throws SystemException
*/
public function __construct()
{
try {
$this->redis = $this->connect();
} catch (SystemException $e) {
throw new SystemException($e->getMessage());
}
}
/**
* 获取锁
* @param String $key 锁标识
* @param Int $expire 锁过期时间
* @param Int $num 重试次数
* @return Boolean
*/
public function lock(string $key, int $expire = 5, int $num = 0): bool
{
$isLock = $this->syntax($key, time() + $expire);
if (!$isLock) {
//获取锁失败则重试{$num}次
for ($i = 0; $i < $num; $i++) {
$isLock = $this->syntax($key, time() + $expire);
if ($isLock) {
break;
}
sleep(1);
}
}
// 不能获取锁
if (!$isLock) {
// 判断锁是否过期
$lockTime = $this->get($key);
// 锁已过期,删除锁,重新获取
if (time() > $lockTime) {
$this->unlock($key);
$isLock = $this->syntax($key, time() + $expire);
}
}
return (bool)$isLock;
}
/**
* 释放锁
* @param String $key 锁标识
* @return Boolean
*/
public function unlock(string $key): ?bool
{
return $this->del($key);
}
/**
* @param string $key
* @return false|mixed|\Redis|string
* 根据key获取值
* @throws SystemException
*/
public function get(string $key)
{
try {
return $this->redis->get($key);
} catch (\RedisException $e) {
throw new SystemException($e->getMessage(),500);
}
}
/**
* @throws SystemException
*/
public function set(string $key, $value, int $expire)
{
try {
return $this->redis->set($key, $value, $expire);
} catch (\RedisException $e) {
throw new SystemException($e->getMessage());
}
}
/**
* @throws SystemException
*/
public function del(string $key)
{
try {
return $this->redis->del($key);
} catch (\RedisException $e) {
throw new SystemException($e->getMessage());
}
}
/**
* @throws SystemException
*/
public function syntax(string $key, int $value)
{
try {
return $this->redis->setnx($key, $value);
} catch (\RedisException $e) {
throw new SystemException($e->getMessage());
}
}
/**
* 创建redis连接
* @throws SystemException
*/
private function connect(): \Redis
{
try {
$redis = new \Redis;
try {
$redis->connect(env("REDIS_HOST"), 6379);
} catch (\RedisException $e) {
throw new SystemException($e->getMessage());
}
try {
$redis->auth('57gc5av!WRWWuBD');
} catch (\RedisException $e) {
throw new SystemException($e->getMessage());
}
} catch (\Exception $e) {
throw new SystemException($e->getMessage());
}
return $redis;
}
}
~~~