PHP公共函数合集
<?php
declare(strict_types=1);
/**
* 判断数组索引是否全为数字
* @param array $arr
* @return bool
*/
function is_index_array(array $arr)
{
$keys = array_keys($arr);
$stringKeys = array_filter($keys, function ($key) {
return is_string($key);
});
return empty($stringKeys);
}
/**
* 发送 HTTP 请求并处理结果
*
* @param string $url 请求地址
* @param string $method 请求类型(GET、POST)
* @param mixed $data 请求参数
* @param bool|array $headers 请求头数组
* @return array|mixed 请求结果数组或原始结果
*/
function send_http_request(string $url, string $method = 'get', mixed $data = [], mixed $header = false, $timeout = 15)
{
$curl = curl_init($url);
$method = strtoupper($method);
//请求方式
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
//携带参数
if ($method == 'POST') {
//当POST情况下的body数据为纯的数组(索引为自然数)时,需要将数组转成json字符串
if (is_array($data) && is_index_array($data)) {
$data = json_encode($data);
}
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
} elseif ($method == 'GET' && count($data)) {
$url .= '?' . http_build_query($data);
curl_setopt($curl, CURLOPT_URL, $url);
}
//超时时间
curl_setopt($curl, CURLOPT_TIMEOUT, $timeout);
//设置header头
if ($header !== false) {
curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
}
curl_setopt($curl, CURLOPT_FAILONERROR, false);
//返回抓取数据
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
//输出header头信息
curl_setopt($curl, CURLOPT_HEADER, true);
//TRUE 时追踪句柄的请求字符串,从 PHP 5.1.3 开始可用。这个很关键,就是允许你查看请求header
curl_setopt($curl, CURLINFO_HEADER_OUT, true);
//https请求
if (1 == strpos("$" . $url, "https://")) {
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
}
list($content, $status) = [curl_exec($curl), curl_getinfo($curl), curl_close($curl)];
$content = trim(substr($content, $status['header_size']));
if (intval($status["http_code"]) === 200) {
// 尝试将结果转码为数组
$decodedResponse = json_decode($content, true);
return $decodedResponse !== null ? $decodedResponse : $content;
} else {
// $res = compact('url', 'method', 'data', 'header', 'timeout');
return false;
}
}
/**
* 将JSON字符串转换为数组
*/
function json_to_array(string $jsonString): array
{
$result = json_decode($jsonString, true);
if (json_last_error() === JSON_ERROR_NONE) {
return is_array($result) ? $result : [];
}
return [];
}
/**
* 生成指定长度的随机字符串
* @param int $length 长度,默认10
* @param bool $onlyNum 是否只包含数字,默认false
* @return string
*/
function rand_str(int $length = 10, bool $onlyNum = false)
{
// 定义字符集
$charset = $onlyNum ? '0123456789' : 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_';
// 确保字符串长度至少为1
if ($length < 1) {
$length = 1;
}
// 使用 random_bytes 生成随机字节
$bytes = random_bytes($length);
// 将字节转换为$length位的随机字符串
$key = '';
for ($i = 0; $i < $length; $i++) {
// 取得一个介于0到字符集长度-1之间的随机索引
$index = ord($bytes[$i]) % strlen($charset);
$key .= $charset[$index];
}
return $key;
}
/**
* 将给定的数据数组转换为树形结构
*
* @param array $data 包含节点信息的数组,每个节点至少包含$idKey和$pidKey字段
* @param string $pidKey 父节点ID的键名,默认为'pid'
* @param string $idKey 节点ID的键名,默认为'id'
* @return array 返回树形结构的数组,根节点的$pidKey值应为0
*/
function tree($data, $pidKey = 'pid', $idKey = 'id')
{
// 初始化映射数组,用于快速查找每个节点的子节点
$map = [];
// 遍历所有节点,建立父节点ID到子节点的映射
foreach ($data as &$item) {
$map[$item[$pidKey]][] = &$item;
}
// 再次遍历所有节点,为每个节点添加其子节点数组
foreach ($data as &$item) {
if (isset($map[$item[$idKey]])) {
$item['child'] = $map[$item[$idKey]];
}
}
// 返回根节点数组,即父节点ID为0的节点及其所有子节点构成的树
return $map[0] ?? [];
}
/**
* 对二维数组根据指定键名去重
*
* @param array $data 二维数组
* @param string $key 指定的键名
* @return array 去重后的二维数组
*/
function array_multi_unique(array $data, string $key): array
{
$uniqueData = [];
$seenValues = [];
foreach ($data as $item) {
// 不能使用isset($item[$key]),当$item[$key]的值为null时,使用isset判断为false
if (array_key_exists($key, $item) && !in_array($item[$key], $seenValues, true)) {
$seenValues[] = $item[$key];
$uniqueData[] = $item;
}
}
return $uniqueData;
}
/**
* 对二维数组根据指定键名排序(支持升序/降序)
* 如果元素缺少指定键,则视为最小值(升序)或最大值(降序)
* @param array $data 二维数组
* @param string $key 指定的键名
* @param string $order 排序方式,'asc' 表示升序,'desc' 表示降序,默认为 'asc'
* @return array 排序后的二维数组
*/
function array_multi_sort(array $data, string $key, string $order = 'asc'): array
{
if (!in_array(strtolower($order), ['asc', 'desc'])) {
throw new InvalidArgumentException("排序方式必须是 'asc' 或 'desc'");
}
usort($data, function ($a, $b) use ($key, $order) {
// 如果元素缺少指定键,则视为最小值(升序)或最大值(降序)
$valueA = array_key_exists($key, $a) ? $a[$key] : (strtolower($order) === 'asc' ? null : INF);
$valueB = array_key_exists($key, $b) ? $b[$key] : (strtolower($order) === 'asc' ? null : INF);
// 使用空值安全的比较逻辑
return strtolower($order) === 'asc' ? ($valueA <=> $valueB) : ($valueB <=> $valueA);
});
return $data;
}
/**
* 将文件大小转换为人类可读的格式。
*
* 该函数接受一个以字节为单位的文件大小,并将其转换为更易读的格式,
* 例如 KB、MB 或 GB。转换后的值保留两位小数,并附带相应的单位。
*
* @param int $size 文件大小,以字节为单位。
* @return string 转换后的文件大小字符串,包含数值和单位(如 "1.23 MB")。
*/
function file_format_size($size)
{
if (!is_numeric($size)) {
throw new InvalidArgumentException("文件大小必须为数字");
}
if ($size < 0) {
throw new InvalidArgumentException("文件大小必须大于等于0");
}
// 定义文件大小单位数组,从字节到千兆字节。
$units = ['B', 'KB', 'MB', 'GB'];
$unitIndex = 0;
// 循环计算文件大小,直到找到合适的单位
while ($size >= 1024 && $unitIndex < count($units) - 1) {
$size /= 1024;
$unitIndex++;
}
// 返回格式化后的文件大小,保留两位小数
return round($size, 2) . ' ' . $units[$unitIndex];
}
/**
* 动态调整日期
*
* 该函数支持按分钟、小时、天、周、月、季度、年增减日期。
* 避免直接操作时间戳的复杂性,使用 DateTime 和 DateInterval 进行日期计算。
*
* @param string $date 输入日期,格式为 'Y-m-d H:i:s' 或其他可被 DateTime 解析的格式
* @param int $amount 调整的数量,正数表示增加,负数表示减少
* @param string $unit 调整单位,支持 'minute', 'hour', 'day', 'week', 'month', 'quarter', 'year'
* @return string 返回调整后的日期,格式为 'Y-m-d H:i:s'
* @throws InvalidArgumentException 如果 $unit 不在支持范围内
*/
function date_adjust(string $date, int $amount, string $unit): string
{
// 支持的单位映射
$unitMap = [
'minute' => 'PT%dM',
'hour' => 'PT%dH',
'day' => 'P%dD',
'week' => 'P%dW',
'month' => 'P%dM',
'quarter' => 'P%dM', // 季度按3个月处理
'year' => 'P%dY',
];
if (!isset($unitMap[$unit])) {
throw new InvalidArgumentException("不支持的调整单位: {$unit}");
}
// 创建 DateTime 对象
$dateTime = new DateTime($date);
// 特殊处理季度
if ($unit === 'quarter') {
$amount *= 3; // 季度转换为月
}
// 构造间隔字符串
$intervalSpec = sprintf($unitMap[$unit], abs($amount));
$interval = new DateInterval($intervalSpec);
// 根据正负调整日期
if ($amount >= 0) {
$dateTime->add($interval);
} else {
$dateTime->sub($interval);
}
// 返回调整后的日期
return $dateTime->format('Y-m-d H:i:s');
}
/**
* 计算两个日期之间的差异值
*
* 该函数支持按秒、分钟、小时、天、周、月、季度、年计算两个日期之间的差异。
* 使用 DateTime 和 DateInterval 进行日期计算。
*
* @param string $date1 第一个日期,格式为 'Y-m-d H:i:s' 或其他可被 DateTime 解析的格式
* @param string $date2 第二个日期,格式为 'Y-m-d H:i:s' 或其他可被 DateTime 解析的格式
* @param string $unit 计算差异的单位,支持 'second', 'minute', 'hour', 'day', 'week', 'month', 'quarter', 'year'
* @return int|float 返回两个日期之间的差异值
* @throws InvalidArgumentException 如果 $unit 不在支持范围内
*/
function date_subtract(string $date1, string $date2, string $unit): int|float
{
// 支持的单位映射
$unitMap = [
'second' => 's',
'minute' => 'i',
'hour' => 'h',
'day' => 'days',
'week' => 'days',
'month' => 'm',
'quarter' => 'm',
'year' => 'y',
];
if (!isset($unitMap[$unit])) {
throw new InvalidArgumentException("不支持的差异单位: {$unit}");
}
// 创建 DateTime 对象
$dateTime1 = new DateTime($date1);
$dateTime2 = new DateTime($date2);
// 计算日期差异
$interval = $dateTime1->diff($dateTime2);
// 特殊处理季度
if ($unit === 'quarter') {
return $interval->y * 4 + $interval->m / 3;
}
// 特殊处理周
if ($unit === 'week') {
return $interval->days / 7;
}
// 返回差异值
return $interval->{$unitMap[$unit]};
}
/**
* thinkphp
* 判断Redis列表中是否存在某个元素
* @param string $listKey 列表键名
* @param mixed $value 要查找的值
* @return bool
*/
function redis_list_in($listKey, $value)
{
// 使用LREM命令判断(性能优)
$count = Cache::store('redis')->lRem($listKey, $value, 0);
return $count > 0;
}
本文来自博客园,作者:tros,转载请注明原文链接:https://www.cnblogs.com/tros/p/18797271

浙公网安备 33010602011771号