Files
cunkebao_v3/Moncter/app/utils/DataMaskingHelper.php
2026-01-05 10:16:20 +08:00

144 lines
4.5 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace app\utils;
/**
* 数据脱敏工具类
*
* 用于在接口返回和日志中脱敏敏感信息
*/
class DataMaskingHelper
{
/**
* 脱敏身份证号
*
* @param string|null $idCard 身份证号
* @return string 脱敏后的身份证号110101********1234
*/
public static function maskIdCard(?string $idCard): string
{
if (empty($idCard)) {
return '';
}
$config = config('encryption.masking.id_card', []);
$prefixLength = $config['prefix_length'] ?? 6;
$suffixLength = $config['suffix_length'] ?? 4;
$maskChar = $config['mask_char'] ?? '*';
$length = mb_strlen($idCard);
if ($length <= $prefixLength + $suffixLength) {
// 如果长度不足以脱敏,返回全部用*替代
return str_repeat($maskChar, $length);
}
$prefix = mb_substr($idCard, 0, $prefixLength);
$suffix = mb_substr($idCard, -$suffixLength);
$maskLength = $length - $prefixLength - $suffixLength;
return $prefix . str_repeat($maskChar, $maskLength) . $suffix;
}
/**
* 脱敏手机号
*
* @param string|null $phone 手机号
* @return string 脱敏后的手机号138****5678
*/
public static function maskPhone(?string $phone): string
{
if (empty($phone)) {
return '';
}
$config = config('encryption.masking.phone', []);
$prefixLength = $config['prefix_length'] ?? 3;
$suffixLength = $config['suffix_length'] ?? 4;
$maskChar = $config['mask_char'] ?? '*';
$length = mb_strlen($phone);
if ($length <= $prefixLength + $suffixLength) {
return str_repeat($maskChar, $length);
}
$prefix = mb_substr($phone, 0, $prefixLength);
$suffix = mb_substr($phone, -$suffixLength);
$maskLength = $length - $prefixLength - $suffixLength;
return $prefix . str_repeat($maskChar, $maskLength) . $suffix;
}
/**
* 脱敏邮箱
*
* @param string|null $email 邮箱
* @return string 脱敏后的邮箱ab***@example.com
*/
public static function maskEmail(?string $email): string
{
if (empty($email)) {
return '';
}
$config = config('encryption.masking.email', []);
$prefixLength = $config['prefix_length'] ?? 2;
$maskChar = $config['mask_char'] ?? '*';
$atPos = mb_strpos($email, '@');
if ($atPos === false) {
// 如果没有@符号,按普通字符串处理
$length = mb_strlen($email);
if ($length <= $prefixLength) {
return str_repeat($maskChar, $length);
}
$prefix = mb_substr($email, 0, $prefixLength);
return $prefix . str_repeat($maskChar, $length - $prefixLength);
}
$localPart = mb_substr($email, 0, $atPos);
$domain = mb_substr($email, $atPos);
$localLength = mb_strlen($localPart);
if ($localLength <= $prefixLength) {
$maskedLocal = str_repeat($maskChar, $localLength);
} else {
$prefix = mb_substr($localPart, 0, $prefixLength);
$maskedLocal = $prefix . str_repeat($maskChar, $localLength - $prefixLength);
}
return $maskedLocal . $domain;
}
/**
* 脱敏数组中的敏感字段
*
* @param array<string, mixed> $data 数据数组
* @param array<string> $sensitiveFields 敏感字段列表(如:['id_card', 'phone', 'email']
* @return array<string, mixed> 脱敏后的数组
*/
public static function maskArray(array $data, array $sensitiveFields = ['id_card', 'id_card_encrypted', 'phone', 'email']): array
{
$masked = $data;
foreach ($sensitiveFields as $field) {
if (isset($masked[$field]) && is_string($masked[$field])) {
switch ($field) {
case 'id_card':
case 'id_card_encrypted':
$masked[$field] = self::maskIdCard($masked[$field]);
break;
case 'phone':
$masked[$field] = self::maskPhone($masked[$field]);
break;
case 'email':
$masked[$field] = self::maskEmail($masked[$field]);
break;
}
}
}
return $masked;
}
}