本文目录导读:

PHP 实现动态脱敏(数据掩码)有多种方法,以下是几种常用的实现方案:
基础函数封装法
<?php
class DataMasker {
/**
* 手机号脱敏:保留前3后4
*/
public static function maskMobile($mobile) {
if (empty($mobile)) return '';
return substr($mobile, 0, 3) . '****' . substr($mobile, -4);
}
/**
* 身份证号脱敏:保留前6后4
*/
public static function maskIdCard($idCard) {
if (empty($idCard)) return '';
$len = strlen($idCard);
if ($len < 10) return $idCard;
return substr($idCard, 0, 6) . str_repeat('*', $len - 10) . substr($idCard, -4);
}
/**
* 银行卡号脱敏:保留前4后4
*/
public static function maskBankCard($card) {
if (empty($card)) return '';
return substr($card, 0, 4) . '**** **** **** ' . substr($card, -4);
}
/**
* 邮箱脱敏
*/
public static function maskEmail($email) {
if (empty($email)) return '';
list($username, $domain) = explode('@', $email);
$maskedUsername = substr($username, 0, 1) . str_repeat('*', strlen($username) - 1);
return $maskedUsername . '@' . $domain;
}
/**
* 姓名脱敏:保留姓
*/
public static function maskName($name) {
if (empty($name)) return '';
if (mb_strlen($name) == 1) return $name;
return mb_substr($name, 0, 1) . str_repeat('*', mb_strlen($name) - 1);
}
/**
* 通用脱敏方法
*/
public static function mask($data, $type) {
switch ($type) {
case 'mobile': return self::maskMobile($data);
case 'idcard': return self::maskIdCard($data);
case 'bankcard': return self::maskBankCard($data);
case 'email': return self::maskEmail($data);
case 'name': return self::maskName($data);
default: return $data;
}
}
}
配置驱动的脱敏
<?php
class DynamicMasker {
// 脱敏规则配置
private static $rules = [
'user' => [
'mobile' => ['function' => 'maskMobile'],
'id_card' => ['function' => 'maskIdCard'],
'email' => ['function' => 'maskEmail'],
'real_name' => ['function' => 'maskName'],
'address' => ['function' => 'maskCustom', 'params' => ['start' => 3, 'end' => 2]],
],
'order' => [
'order_no' => ['function' => 'maskCustom', 'params' => ['start' => 2, 'end' => 2]],
'customer_name' => ['function' => 'maskName'],
]
];
/**
* 根据场景和字段动态脱敏
*/
public static function maskData(array $data, $scene) {
if (!isset(self::$rules[$scene])) {
return $data;
}
$result = $data;
foreach (self::$rules[$scene] as $field => $rule) {
if (isset($result[$field])) {
$result[$field] = self::{$rule['function']}(
$result[$field],
$rule['params'] ?? []
);
}
}
return $result;
}
// 自定义脱敏:保留开头和结尾指定长度
private static function maskCustom($value, $params = []) {
$start = $params['start'] ?? 0;
$end = $params['end'] ?? 0;
$len = mb_strlen($value);
if ($len <= $start + $end) {
return str_repeat('*', $len);
}
return mb_substr($value, 0, $start) .
str_repeat('*', $len - $start - $end) .
mb_substr($value, -$end);
}
// 其他方法同第一种方案...
}
使用魔术方法动态处理
<?php
class MagicMasker {
private $rawData;
private $maskFields = [
'mobile' => 'maskMobile',
'idcard' => 'maskIdCard',
'bankcard' => 'maskBankCard',
];
public function __construct(array $data) {
$this->rawData = $data;
}
public function __get($name) {
if (isset($this->rawData[$name])) {
// 如果是敏感字段,直接脱敏
if (isset($this->maskFields[$name])) {
$method = $this->maskFields[$name];
return DataMasker::$method($this->rawData[$name]);
}
return $this->rawData[$name];
}
return null;
}
// 获取脱敏后的完整数据
public function toArray() {
$result = [];
foreach ($this->rawData as $key => $value) {
if (isset($this->maskFields[$key])) {
$method = $this->maskFields[$key];
$result[$key] = DataMasker::$method($value);
} else {
$result[$key] = $value;
}
}
return $result;
}
}
// 使用示例
$userData = [
'name' => '张三',
'mobile' => '13812345678',
'idcard' => '110101199001011234',
'email' => 'zhangsan@example.com'
];
$maskedUser = new MagicMasker($userData);
echo $maskedUser->mobile; // 138****5678
支持注解的脱敏(需要反射)
<?php
class AnnotatedMasker {
/**
* @Mask(type="mobile")
*/
public $mobile;
/**
* @Mask(type="idcard")
*/
public $idCard;
public function process($className) {
$reflection = new ReflectionClass($className);
$properties = $reflection->getProperties();
foreach ($properties as $property) {
$docComment = $property->getDocComment();
if (preg_match('/@Mask\(type="(\w+)"\)/', $docComment, $matches)) {
$type = $matches[1];
unserialize($property->getName());
}
}
}
}
使用第三方库(推荐:PHP-Mask)
composer require makinacorpus/php-mask
<?php use MakinaCorpus\PHP-Mask\Masker; $masker = new Masker(); $masked = $masker->mask($data, 'mobile'); // 直接脱敏
动态规则配置示例
<?php
class DynamicConfigMasker {
// 从数据库或配置中心加载规则
private function getRules($scene) {
// 模拟从数据库加载配置
return [
'mobile' => [
'type' => 'replace',
'start' => 3,
'end' => 4,
'char' => '*'
],
'email' => [
'type' => 'regex',
'pattern' => '/^(.*?)(@.*)$/',
'replacement' => '$1***$2'
]
];
}
public function mask(array $data, $scene) {
$rules = $this->getRules($scene);
foreach ($rules as $field => $rule) {
if (!isset($data[$field])) continue;
switch ($rule['type']) {
case 'replace':
$data[$field] = $this->maskByRange(
$data[$field],
$rule['start'],
$rule['end'],
$rule['char'] ?? '*'
);
break;
case 'regex':
$data[$field] = preg_replace(
$rule['pattern'],
$rule['replacement'],
$data[$field]
);
break;
}
}
return $data;
}
}
使用建议
- 根据业务场景选择:如果是简单需求,使用函数封装即可
- 动态配置:如果规则经常变化,建议使用配置驱动
- 性能考虑:大量数据脱敏时,使用数组映射比对象更高效
- 安全性:脱敏操作应该在数据输出前统一处理,避免遗漏
这些方法可以根据你的具体需求灵活选择或组合使用。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播