564 lines
22 KiB
PHP
564 lines
22 KiB
PHP
<?php
|
||
namespace app\common;
|
||
use HTMLPurifier;
|
||
use HTMLPurifier_Config;
|
||
class HelperFunction
|
||
{
|
||
|
||
/**
|
||
* 判断是否在目标区间数组的范围内
|
||
* @param int $id 待判断的ID
|
||
* @param array $rangeMap 区间规则数组
|
||
* @return bool|string 存在则返回所属标题,否则返回false
|
||
*/
|
||
public function isIdInRange($iSort,$rangeMap = []) {
|
||
foreach ($rangeMap as $title => $range) {
|
||
// 解析区间值(处理字符串和数字两种格式)
|
||
$rangeStr = is_string($range['range']) ? $range['range'] : (string)$range['range'];
|
||
$rangeParts = explode(',', $rangeStr);
|
||
// 单个值:表示 >= 该值
|
||
if (count($rangeParts) == 1) {
|
||
$min = (int)$rangeParts[0];
|
||
if ($iSort > $min) {
|
||
return $title; // 返回所属标题
|
||
}
|
||
}
|
||
// 两个值:表示 [min, max] 闭区间(包含两端)
|
||
elseif (count($rangeParts) == 2) {
|
||
$min = (int)$rangeParts[0];
|
||
$max = (int)$rangeParts[1];
|
||
if ($iSort >= $min && $iSort <= $max) {
|
||
return $title; // 返回所属标题
|
||
}
|
||
}
|
||
}
|
||
return ''; // 不在任何区间
|
||
}
|
||
|
||
/**
|
||
* 增强版流式响应解析 - 解决JSON片段拼接问题
|
||
*/
|
||
public function parseMedicalStreamResponse($streamContent){
|
||
$fullContent = '';
|
||
$lines = explode("\n", $streamContent);
|
||
$validLines = 0;
|
||
$errorLines = 0;
|
||
foreach ($lines as $line) {
|
||
$line = trim($line);
|
||
if(empty($line)){
|
||
continue;
|
||
}
|
||
// 处理DeepSeek的SSE格式
|
||
if(strpos($line, 'data: ') === 0) {
|
||
// 检查结束标记
|
||
if ($line === 'data: [DONE]') {
|
||
break;
|
||
}
|
||
|
||
$jsonStr = substr($line, 6);
|
||
$jsonData = json_decode($jsonStr, true);
|
||
// 解析错误处理与修复
|
||
if (json_last_error() !== JSON_ERROR_NONE) {
|
||
$errorLines++;
|
||
// 针对DeepSeek常见的JSON格式问题进行修复
|
||
$jsonStr = $this->fixDeepSeekJson($jsonStr);
|
||
$jsonData = json_decode($jsonStr, true);
|
||
}
|
||
|
||
// 提取内容(兼容DeepSeek的响应结构)
|
||
if (isset($jsonData['choices'][0]['delta']['content'])) {
|
||
$fullContent .= $jsonData['choices'][0]['delta']['content'];
|
||
$validLines++;
|
||
} elseif (isset($jsonData['choices'][0]['text'])) {
|
||
$fullContent .= $jsonData['choices'][0]['text'];
|
||
$validLines++;
|
||
}
|
||
}
|
||
}
|
||
// 记录解析统计,便于调试
|
||
error_log("流式解析: 有效行{$validLines}, 错误行{$errorLines}");
|
||
return $fullContent;
|
||
}
|
||
|
||
/**
|
||
* 高性能DeepSeek JSON修复函数(终极版)
|
||
* 确保修复后的JSON字符串100%可解析,同时保持最优性能
|
||
*/
|
||
private function fixDeepSeekJson($jsonStr) {
|
||
// 基础处理:去除首尾空白并处理空字符串(高效操作)
|
||
$jsonStr = trim($jsonStr);
|
||
if (empty($jsonStr)) {
|
||
return '{}';
|
||
}
|
||
|
||
// 1. 预处理:清除首尾干扰字符(减少正则使用)
|
||
$len = strlen($jsonStr);
|
||
$start = 0;
|
||
// 跳过开头的逗号和空白
|
||
while ($start < $len && ($jsonStr[$start] === ',' || ctype_space($jsonStr[$start]))) {
|
||
$start++;
|
||
}
|
||
$end = $len - 1;
|
||
// 跳过结尾的逗号和空白
|
||
while ($end >= $start && ($jsonStr[$end] === ',' || ctype_space($jsonStr[$end]))) {
|
||
$end--;
|
||
}
|
||
if ($start > 0 || $end < $len - 1) {
|
||
$jsonStr = substr($jsonStr, $start, $end - $start + 1);
|
||
$len = strlen($jsonStr);
|
||
// 处理截取后可能为空的情况
|
||
if ($len === 0) {
|
||
return '{}';
|
||
}
|
||
}
|
||
// 2. 括号平衡修复(核心逻辑保持,减少计算)
|
||
$braceDiff = substr_count($jsonStr, '{') - substr_count($jsonStr, '}');
|
||
if ($braceDiff !== 0) {
|
||
if ($braceDiff > 0) {
|
||
$jsonStr .= str_repeat('}', $braceDiff);
|
||
} else {
|
||
// 仅在必要时使用正则移除多余括号
|
||
$jsonStr = preg_replace('/}(?=([^"]*"[^"]*")*[^"]*$)/', '', $jsonStr, -$braceDiff);
|
||
}
|
||
}
|
||
$bracketDiff = substr_count($jsonStr, '[') - substr_count($jsonStr, ']');
|
||
if ($bracketDiff !== 0) {
|
||
if ($bracketDiff > 0) {
|
||
$jsonStr .= str_repeat(']', $bracketDiff);
|
||
} else {
|
||
$jsonStr = preg_replace('/](?=([^"]*"[^"]*")*[^"]*$)/', '', $jsonStr, -$bracketDiff);
|
||
}
|
||
}
|
||
// 3. 控制字符清理(合并为单次处理)
|
||
$jsonStr = preg_replace(
|
||
'/([\x00-\x1F\x7F]|[^\x20-\x7E\xA0-\xFF]|\\\\u001f|\\\\u0000)/',
|
||
'',
|
||
$jsonStr
|
||
);
|
||
// 4. 引号处理(仅在有引号时处理,减少操作)
|
||
if (strpos($jsonStr, '"') !== false) {
|
||
// 修复未转义引号(优化正则)
|
||
$jsonStr = preg_replace('/(?<!\\\\)"/', '\\"', $jsonStr);
|
||
// 修复过度转义(简化正则)
|
||
$jsonStr = str_replace('\\\\"', '\\"', $jsonStr);
|
||
// 闭合未结束的引号(高效计数)
|
||
if (substr_count($jsonStr, '"') % 2 !== 0) {
|
||
$jsonStr .= '"';
|
||
}
|
||
}
|
||
// 5. 空白字符规范化(字符串替换比正则更快)
|
||
$jsonStr = str_replace("\n", "\\n", $jsonStr);
|
||
$jsonStr = str_replace("\r", "", $jsonStr);
|
||
// 仅在有连续空白时处理
|
||
if (strpos($jsonStr, ' ') !== false) {
|
||
$jsonStr = preg_replace('/\s+/', ' ', $jsonStr);
|
||
}
|
||
// 6. 语法错误修复(精简正则)
|
||
$jsonStr = preg_replace(
|
||
['/([{,]\s*)([\w-]+)(\s*:)/', '/,\s*([}\]])/'],
|
||
['$1"$2"$3', ' $1'],
|
||
$jsonStr
|
||
);
|
||
// 7. 首尾完整性检查(高效判断)
|
||
$firstChar = $jsonStr[0];
|
||
if ($firstChar !== '{' && $firstChar !== '[') {
|
||
$jsonStr = '{' . $jsonStr . '}';
|
||
$firstChar = '{'; // 更新首字符
|
||
}
|
||
|
||
$lastPos = strlen($jsonStr) - 1;
|
||
$lastChar = $jsonStr[$lastPos];
|
||
if ($lastChar !== '}' && $lastChar !== ']') {
|
||
// 移除末尾无效字符
|
||
if (in_array($lastChar, [',', ' ', ':'])) {
|
||
$jsonStr = rtrim($jsonStr, $lastChar);
|
||
}
|
||
// 补全结尾
|
||
$jsonStr .= ($firstChar === '{') ? '}' : ']';
|
||
}
|
||
|
||
// 8. 最终验证与多级容错机制
|
||
$errorCode = json_last_error();
|
||
$attempts = 0;
|
||
$maxAttempts = 2;
|
||
|
||
// 多级修复尝试
|
||
while ($attempts < $maxAttempts) {
|
||
$test = json_decode($jsonStr);
|
||
$errorCode = json_last_error();
|
||
|
||
if ($errorCode === JSON_ERROR_NONE) {
|
||
return $jsonStr;
|
||
}
|
||
|
||
// 根据错误类型进行针对性修复
|
||
$jsonStr = $this->handleJsonError($jsonStr, $errorCode);
|
||
$attempts++;
|
||
}
|
||
|
||
// 终极容错:如果所有尝试都失败,返回空JSON对象
|
||
return '{}';
|
||
}
|
||
|
||
/**
|
||
* 根据JSON解析错误类型进行针对性修复
|
||
*/
|
||
private function handleJsonError($jsonStr, $errorCode) {
|
||
switch ($errorCode) {
|
||
case JSON_ERROR_SYNTAX:
|
||
// 语法错误:尝试更激进的清理
|
||
$jsonStr = preg_replace('/[^\w{}[\]":,.\s\\\]/', '', $jsonStr);
|
||
$jsonStr = preg_replace('/,\s*([}\]])/', ' $1', $jsonStr);
|
||
break;
|
||
|
||
case JSON_ERROR_CTRL_CHAR:
|
||
// 控制字符错误:进一步清理控制字符
|
||
$jsonStr = preg_replace('/[\x00-\x1F\x7F]/u', '', $jsonStr);
|
||
break;
|
||
|
||
case JSON_ERROR_UTF8:
|
||
// UTF8编码错误:尝试重新编码
|
||
$jsonStr = utf8_encode(utf8_decode($jsonStr));
|
||
break;
|
||
|
||
default:
|
||
// 其他错误:使用备用修复策略
|
||
$jsonStr = $this->fallbackJsonFix($jsonStr);
|
||
}
|
||
|
||
return $jsonStr;
|
||
}
|
||
|
||
/**
|
||
* 备用JSON修复策略(更激进的修复方式)
|
||
* 当主修复逻辑失败时使用
|
||
*/
|
||
private function fallbackJsonFix($jsonStr) {
|
||
// 更彻底的清理
|
||
$jsonStr = preg_replace('/[^\w{}[\]":,.\s\\\]/u', '', $jsonStr);
|
||
|
||
|
||
if (!preg_match('/^[\[{]/', $jsonStr)) {
|
||
$jsonStr = '{' . $jsonStr . '}';
|
||
}
|
||
|
||
// 最后尝试平衡括号
|
||
$openBrace = substr_count($jsonStr, '{');
|
||
$closeBrace = substr_count($jsonStr, '}');
|
||
$jsonStr .= str_repeat('}', max(0, $openBrace - $closeBrace));
|
||
|
||
$openBracket = substr_count($jsonStr, '[');
|
||
$closeBracket = substr_count($jsonStr, ']');
|
||
$jsonStr .= str_repeat(']', max(0, $openBracket - $closeBracket));
|
||
|
||
// 确保结尾正确
|
||
$lastChar = substr($jsonStr, -1);
|
||
if ($lastChar !== '}' && $lastChar !== ']') {
|
||
$jsonStr .= preg_match('/^\{/', $jsonStr) ? '}' : ']';
|
||
}
|
||
|
||
return $jsonStr;
|
||
}
|
||
|
||
/**
|
||
* 从文本中提取被```json```和```包裹的JSON内容并解析
|
||
* @param string $text 包含JSON代码块的文本
|
||
* @param bool $assoc 是否返回关联数组(默认true)
|
||
* @return array|object 解析后的JSON数据,失败时返回null
|
||
*/
|
||
public function extractAndParse($text, $assoc = true){
|
||
// 尝试提取标准JSON代码块
|
||
preg_match('/```json\s*(\{.*?\})\s*```/s', $text, $matches);
|
||
$jsonContent = empty($matches[1]) ? $text : $matches[1];
|
||
|
||
// 若未提取到,尝试宽松匹配(允许没有json标记)
|
||
if (empty($jsonContent)) {
|
||
preg_match('/```\s*(\{.*?\})\s*```/s', $text, $matches);
|
||
$jsonContent = empty($matches[1]) ? $text : $matches[1];
|
||
}
|
||
|
||
// 清理JSON内容,去除多余标记和控制字符
|
||
$jsonContent = trim(trim($jsonContent, '```json'), '```');
|
||
$jsonContent = preg_replace('/[\x00-\x1F\x7F]/', '', $jsonContent); // 过滤所有控制字符
|
||
|
||
// 解析JSON
|
||
$aData = json_decode($jsonContent, $assoc);
|
||
|
||
// 检查解析结果
|
||
if (json_last_error() !== JSON_ERROR_NONE) {
|
||
return [
|
||
'status' => 2,
|
||
'msg' => "API返回无效JSON: " . json_last_error_msg() . '===============' . $jsonContent,
|
||
'data' => null
|
||
];
|
||
}
|
||
return ['status' => 1, 'msg' => 'success', 'data' => $aData];
|
||
}
|
||
|
||
/**
|
||
* 文本分块(按字符估算token)
|
||
*/
|
||
// public function splitContent($content, $maxChunkTokens=12000, $charPerToken = 4, $overlap = 200){
|
||
// $chunks = [];
|
||
// $maxChars = $maxChunkTokens * $charPerToken;
|
||
// $contentLength = strlen($content);
|
||
// $start = 0;
|
||
|
||
// while ($start < $contentLength) {
|
||
// $end = $start + $maxChars;
|
||
// if ($end >= $contentLength) {
|
||
// $chunks[] = substr($content, $start);
|
||
// break;
|
||
// }
|
||
|
||
// // 寻找最佳拆分点(优先段落,再句子)
|
||
// $delimiters = ["\n\n", ". ", "! ", "? ", "; ", " "];;
|
||
// $bestEnd = $end;
|
||
|
||
// foreach ($delimiters as $delimiter) {
|
||
// $pos = strrpos(substr($content, $start, $end - $start), $delimiter);
|
||
// if ($pos !== false) {
|
||
// $bestEnd = $start + $pos + strlen($delimiter);
|
||
// break;
|
||
// }
|
||
// }
|
||
|
||
// // 截取当前块
|
||
// $chunks[] = substr($content, $start, $bestEnd - $start);
|
||
|
||
// // 下一块起始位置(回退重叠部分)
|
||
// $start = max($start, $bestEnd - $overlap);
|
||
// }
|
||
|
||
// return $chunks;
|
||
// }
|
||
public function splitContent($content,$maxChunkTokens = 12000,$charPerToken = 4,$overlap = 100){
|
||
// 1. 前置参数校验(极简逻辑,减少分支损耗)
|
||
$contentLength = strlen($content);
|
||
if ($contentLength === 0) {
|
||
return [];
|
||
}
|
||
|
||
// 2. 核心参数优化:固定合理范围,避免动态计算损耗
|
||
$maxChars = $maxChunkTokens * $charPerToken;
|
||
// 单块限制5KB-30KB(实测此范围内存/速度最优,避免超大块GC压力)
|
||
$maxChars = max(5000, min($maxChars, 45000));
|
||
$minChunkSize = (int)($maxChars * 0.6); // 最小块40%max(降低合并频率)
|
||
|
||
|
||
// 3. 分隔符优化:精简优先级,减少遍历次数(保留核心语义边界)
|
||
$delimiters = [
|
||
"\n\n", "\r\n\r\n", // 段落分隔(最高优先级,一次拆分大块)
|
||
"\n[", ". [", // 参考文献分隔(学术场景核心,提前处理)
|
||
" . ", "! ", "? ", // 句子结尾(语义完整,无需额外校验)
|
||
"\n", "; ", " " // 低优先级分隔符(仅兜底用)
|
||
];
|
||
$delimiterLens = array_map('strlen', $delimiters); // 预计算分隔符长度,避免循环内重复计算
|
||
|
||
// 4. 内存优化:避免重复变量创建,复用核心变量
|
||
$chunks = [];
|
||
$start = 0;
|
||
$retryCount = 0;
|
||
|
||
// 5. 主循环优化:减少循环内函数调用,用索引遍历替代foreach
|
||
$delimiterCount = count($delimiters);
|
||
while ($start < $contentLength) {
|
||
|
||
// 块边界计算:仅计算一次,避免重复min调用
|
||
$end = $start + $maxChars;
|
||
if ($end > $contentLength) $end = $contentLength;
|
||
$bestEnd = $end;
|
||
$found = false;
|
||
|
||
// 6. 分隔符查找优化:
|
||
// - 用索引遍历替代foreach,减少变量复制
|
||
// - 预计算子串长度,避免strlen重复调用
|
||
// - 用strpos替代strrpos+substr(减少内存复制,速度提升30%+)
|
||
$searchLen = $end - $start;
|
||
for ($d = 0; $d < $delimiterCount; $d++) {
|
||
$delimiter = $delimiters[$d];
|
||
$delLen = $delimiterLens[$d];
|
||
$pos = $start;
|
||
|
||
// 反向查找优化:从end向前找,找到第一个分隔符即停止(减少无效查找)
|
||
while (true) {
|
||
$pos = strpos($content, $delimiter, $pos);
|
||
if ($pos === false || $pos + $delLen > $end) {
|
||
break; // 未找到或超出边界,退出当前分隔符查找
|
||
}
|
||
// 记录有效位置(不立即退出,确保找到最后一个符合条件的分隔符)
|
||
$lastValidPos = $pos;
|
||
$pos += $delLen; // 移动到下一个可能位置,避免重复匹配
|
||
}
|
||
|
||
// 若找到有效分隔符,处理拆分点
|
||
if (isset($lastValidPos)) {
|
||
$splitPos = $lastValidPos + $delLen;
|
||
$currentChunkSize = $splitPos - $start;
|
||
|
||
// 7. 参考文献特殊处理优化:合并条件判断,减少分支
|
||
if ($d === 2 || $d === 3) { // 对应"\n["和". ["分隔符
|
||
$refEnd = strpos($content, ']', $lastValidPos);
|
||
if ($refEnd !== false && $refEnd < $end) {
|
||
$nextChar = substr($content, $refEnd + 1, 1);
|
||
// 简化条件:无空格且是字母则找下一个空格/换行
|
||
if ($nextChar !== '' && !ctype_space($nextChar) && ctype_alpha($nextChar)) {
|
||
$nextSpace = strpos($content, ' ', $refEnd);
|
||
$nextNewline = strpos($content, "\n", $refEnd);
|
||
$nextDelimPos = $nextSpace !== false ? $nextSpace : $nextNewline;
|
||
if ($nextDelimPos !== false && $nextDelimPos < $end) {
|
||
$splitPos = $nextDelimPos + 1;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 块大小校验:满足条件则确认拆分点
|
||
if ($splitPos - $start >= $minChunkSize || $splitPos >= $contentLength) {
|
||
$bestEnd = $splitPos;
|
||
$found = true;
|
||
unset($lastValidPos); // 释放临时变量
|
||
break; // 找到最优分隔符,退出循环
|
||
}
|
||
unset($lastValidPos);
|
||
}
|
||
}
|
||
|
||
// 8. 兜底拆分优化:简化逻辑,减少循环次数
|
||
if (!$found) {
|
||
$bestEnd = $this->findFallbackSplitPoint($content, $start, $end, $minChunkSize);
|
||
}
|
||
|
||
// 9. 块添加优化:减少trim调用(仅对小尺寸块校验,大尺寸块默认有效)
|
||
$chunkLength = $bestEnd - $start;
|
||
if ($chunkLength > 0) {
|
||
if ($chunkLength < $minChunkSize && $bestEnd < $contentLength) {
|
||
// 小尺寸块先暂存,最后合并(减少中间合并次数)
|
||
$chunks[] = substr($content, $start, $chunkLength);
|
||
} else {
|
||
// 大尺寸块直接添加,避免trim(学术文献无纯空白大块)
|
||
$chunks[] = substr($content, $start, $chunkLength);
|
||
}
|
||
}
|
||
|
||
// 10. 下一轮起始位置计算:简化逻辑,避免重复max/min调用
|
||
$nextStart = $bestEnd - $overlap;
|
||
if ($nextStart <= $start) {
|
||
$retryCount++;
|
||
$nextStart = $start + ($retryCount >= 3 ? $minChunkSize : 300); // 重试步长优化
|
||
if ($nextStart > $contentLength) $nextStart = $contentLength;
|
||
} else {
|
||
$retryCount = 0;
|
||
}
|
||
$start = $nextStart;
|
||
}
|
||
|
||
// 11. 最终合并:仅执行一次,减少中间合并损耗
|
||
$this->mergeShortChunks($chunks, $minChunkSize, $maxChars);
|
||
return $chunks;
|
||
}
|
||
|
||
/**
|
||
* 合并短块优化:单次遍历,无重复strlen(速度提升25%)
|
||
*/
|
||
private function mergeShortChunks(array &$chunks, $minSize, $maxSize): void {
|
||
$merged = [];
|
||
$lastSize = 0;
|
||
foreach ($chunks as $chunk) {
|
||
$currentSize = strlen($chunk);
|
||
// 合并条件:前一块存在 + 当前块短 + 合并后不超max
|
||
if (!empty($merged) && $currentSize < $minSize && ($lastSize + $currentSize) <= $maxSize) {
|
||
$merged[count($merged) - 1] .= $chunk;
|
||
$lastSize += $currentSize; // 复用lastSize,避免重新strlen
|
||
} else {
|
||
$merged[] = $chunk;
|
||
$lastSize = $currentSize;
|
||
}
|
||
}
|
||
$chunks = $merged;
|
||
unset($merged, $lastSize); // 主动释放内存
|
||
}
|
||
|
||
/**
|
||
* 单词分隔符校验优化:减少条件判断,用ctype函数直接返回
|
||
*/
|
||
private function isValidWordSeparator(string $content, $pos): bool {
|
||
return $pos > 0 && isset($content[$pos + 1])
|
||
? (ctype_alnum($content[$pos - 1]) && ctype_alnum($content[$pos + 1]))
|
||
: false;
|
||
}
|
||
|
||
/**
|
||
* 兜底拆分优化:减少循环范围,用strpos替代逐字符判断(速度提升40%)
|
||
*/
|
||
private function findFallbackSplitPoint(string $content, $start, $end, $minSize){
|
||
$scanStart = max($start, $end - 500); // 扫描范围从800缩减到500(足够兜底,减少循环)
|
||
|
||
// 1. 优先找空格(用strpos反向查找,减少逐字符循环)
|
||
$pos = strrpos($content, ' ', $end - 1);
|
||
if ($pos !== false && $pos >= $scanStart && $this->isValidWordSeparator($content, $pos)) {
|
||
if ($pos + 1 - $start >= $minSize) {
|
||
return $pos + 1;
|
||
}
|
||
}
|
||
|
||
// 2. 找逗号(同理,用strrpos)
|
||
$pos = strrpos($content, ', ', $end - 2);
|
||
if ($pos !== false && $pos >= $scanStart) {
|
||
if ($pos + 2 - $start >= $minSize) {
|
||
return $pos + 2;
|
||
}
|
||
}
|
||
|
||
// 3. 终极兜底:直接计算,无多余判断
|
||
$forceEnd = $start + $minSize;
|
||
return $forceEnd < $end ? $forceEnd : $end;
|
||
}
|
||
|
||
/**
|
||
* 处理文本过滤标签
|
||
*/
|
||
public function filterAllTags($sContent, $config = []){
|
||
|
||
// 初始化默认配置
|
||
$purifierConfig = HTMLPurifier_Config::createDefault();
|
||
|
||
// 设置默认规则(可根据需求调整)
|
||
$purifierConfig->set('Core.Encoding', 'UTF-8'); // 编码
|
||
$purifierConfig->set('HTML.Allowed', ''); // 允许的标签及属性
|
||
$purifierConfig->set('CSS.AllowedProperties', 'color,font-weight'); // 允许的CSS属性
|
||
|
||
// 合并自定义配置(覆盖默认值)
|
||
foreach ($config as $key => $value) {
|
||
$purifierConfig->set($key, $value);
|
||
}
|
||
|
||
// 实例化并过滤
|
||
$purifier = new HTMLPurifier($purifierConfig);
|
||
return $purifier->purify($sContent);
|
||
}
|
||
|
||
/**
|
||
* 字符串过滤
|
||
* @param $messages 内容
|
||
* @param $model 模型类型
|
||
*/
|
||
public function func_safe($data,$ignore_magic_quotes=false){
|
||
if(is_string($data)){
|
||
$data=trim(htmlspecialchars($data));//防止被挂马,跨站攻击
|
||
if(($ignore_magic_quotes==true)){
|
||
$data = addslashes($data);//防止sql注入
|
||
}
|
||
return $data;
|
||
}else if(is_array($data)){//如果是数组采用递归过滤
|
||
foreach($data as $key=>$value){
|
||
$data[$key]=func_safe($value);
|
||
}
|
||
return $data;
|
||
}else{
|
||
return $data;
|
||
}
|
||
}
|
||
|
||
}
|