PHP集成TCPDF生成PDF时hexdec()无效字符传入报错的解决咨询
问题背景
在PHP项目中集成TCPDF生成PDF时,触发了如下弃用警告:
Deprecated: Invalid characters passed for attempted conversion, these have been ignored in C:\wamp64\www\projects\include\tcpdf_colors.php on line 388
问题出在TCPDF处理十六进制颜色的代码段(tcpdf_colors.php第370-390行):
// HEXADECIMAL REPRESENTATION switch (strlen($color_code)) { case 3: { // 3-digit RGB hexadecimal representation $r = substr($color_code, 0, 1); $g = substr($color_code, 1, 1); $b = substr($color_code, 2, 1); $returncolor = array(); $returncolor['R'] = max(0, min(255, hexdec($r.$r))); $returncolor['G'] = max(0, min(255, hexdec($g.$g))); $returncolor['B'] = max(0, min(255, hexdec($b.$b))); break; } case 6: { // 6-digit RGB hexadecimal representation $returncolor = array(); $returncolor['R'] = max(0, min(255, hexdec(substr($color_code, 0, 2)))); $returncolor['G'] = max(0, min(255, hexdec(substr($color_code, 2, 2)))); $returncolor['B'] = max(0, min(255, hexdec(substr($color_code, 4, 2)))); break; }
排查发现传入的$color_code是带无效字符的超长十六进制数(比如末尾带“l”),临时用$color_code = substr($color_code, 0, -1);能生成PDF,但这个方案不可靠——无效字符的位置不固定,可能出现在颜色码的任意位置。
原因分析
高版本PHP对hexdec()、base_convert()等函数做了严格校验:传入无效字符时会触发弃用警告,尽管仍会忽略无效字符计算结果,但不符合新的规范。TCPDF原有代码没有对输入的颜色码做严格校验,导致非法字符流入hexdec()触发警告。
可靠解决方案
方案1:提前过滤非法字符
在处理颜色码前,先清理掉所有非十六进制字符,再按原有逻辑处理:
// 保留颜色码中的合法十六进制字符(0-9, a-f, A-F) $color_code = preg_replace('/[^0-9a-fA-F]/', '', $color_code); // HEXADECIMAL REPRESENTATION switch (strlen($color_code)) { case 3: { // 原代码不变 $r = substr($color_code, 0, 1); $g = substr($color_code, 1, 1); $b = substr($color_code, 2, 1); $returncolor = array(); $returncolor['R'] = max(0, min(255, hexdec($r.$r))); $returncolor['G'] = max(0, min(255, hexdec($g.$g))); $returncolor['B'] = max(0, min(255, hexdec($b.$b))); break; } case 6: { // 原代码不变 $returncolor = array(); $returncolor['R'] = max(0, min(255, hexdec(substr($color_code, 0, 2)))); $returncolor['G'] = max(0, min(255, hexdec(substr($color_code, 2, 2)))); $returncolor['B'] = max(0, min(255, hexdec(substr($color_code, 4, 2)))); break; } // 可选:处理清理后长度不足的情况,返回默认颜色 default: return array('R' => 0, 'G' => 0, 'B' => 0); }
方案2:严格校验颜色格式
先校验颜色码是否为合法的3位或6位十六进制值,非法则返回默认颜色:
// 校验颜色格式:仅允许3位或6位十六进制字符 if (!preg_match('/^[0-9a-fA-F]{3}$|^[0-9a-fA-F]{6}$/', $color_code)) { // 返回默认颜色(示例为黑色) return array('R' => 0, 'G' => 0, 'B' => 0); } // 处理3位转6位的情况 if (strlen($color_code) == 3) { $color_code = $color_code[0].$color_code[0].$color_code[1].$color_code[1].$color_code[2].$color_code[2]; } // 直接处理6位颜色 $returncolor = array(); $returncolor['R'] = max(0, min(255, hexdec(substr($color_code, 0, 2)))); $returncolor['G'] = max(0, min(255, hexdec(substr($color_code, 2, 2)))); $returncolor['B'] = max(0, min(255, hexdec(substr($color_code, 4, 2))));
方案3:封装安全的十六进制转十进制函数
自定义函数过滤非法字符后再调用hexdec(),替换原有代码中的hexdec:
// 安全的十六进制转十进制函数 function safe_hexdec($hex_str) { // 过滤非法字符 $clean_hex = preg_replace('/[^0-9a-fA-F]/', '', $hex_str); // 处理空值情况 return $clean_hex ? hexdec($clean_hex) : 0; } // 修改原有代码中的hexdec调用 switch (strlen($color_code)) { case 3: { $r = substr($color_code, 0, 1); $g = substr($color_code, 1, 1); $b = substr($color_code, 2, 1); $returncolor = array(); $returncolor['R'] = max(0, min(255, safe_hexdec($r.$r))); $returncolor['G'] = max(0, min(255, safe_hexdec($g.$g))); $returncolor['B'] = max(0, min(255, safe_hexdec($b.$b))); break; } case 6: { $returncolor = array(); $returncolor['R'] = max(0, min(255, safe_hexdec(substr($color_code, 0, 2)))); $returncolor['G'] = max(0, min(255, safe_hexdec(substr($color_code, 2, 2)))); $returncolor['B'] = max(0, min(255, safe_hexdec(substr($color_code, 4, 2)))); break; } }
为什么临时截断不可靠
无效字符可能出现在颜色码的开头、中间或末尾,直接截断会导致颜色值偏离预期;若清理后颜色码长度不符合3/6位,后续switch逻辑无法匹配,还可能引发其他异常。
内容的提问来源于stack exchange,提问作者Rinku27

