You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP如何检测文件开头字符 兼容处理UTF8与UTF8 BOM格式CSV

兼容带BOM/无BOM UTF-8格式CSV的PHP实现

核心实现逻辑

UTF-8编码的BOM头是文件起始位置固定的3个字节,对应十六进制值为 0xEF 0xBB 0xBF。不需要固定执行跳过3字节的操作,打开文件后先读取前3字节做匹配判断:

  • 若读取到的3字节和BOM标识完全一致,说明文件带BOM,当前文件指针已经停在BOM之后的有效内容起始位,直接开始读取CSV内容即可
  • 若读取到的3字节不符合BOM特征,说明是无BOM的普通UTF-8文件,将文件指针重置到文件起始位置(偏移0位),再开始读取内容即可

替换原有固定跳过BOM的代码

把原代码中写死的fseek($handle, 3);替换为以下检测逻辑:

// 自动检测UTF-8 BOM头,兼容两种格式文件
$bomCheck = fread($handle, 3);
if ($bomCheck !== "\xEF\xBB\xBF") {
    // 未检测到BOM,指针回到文件开头
    rewind($handle);
}

这里直接用双引号字符串写入转义的BOM字节比拼接chr()写法更简洁,rewind($handle)等价于fseek($handle, 0),是PHP专门提供的重置文件指针到开头的函数,可读性更好。

修改后的完整业务代码

<?php

include("connexion.php");

$dir   = '//server/d$/ftp/GET/';
$allFiles = scandir($dir);
$dest = '//server/d$/ftp/GET/COPIES/';

foreach($allFiles as $file) {

    if (!in_array($file,array(".","..")))
    { 
        $file = $dir.$file;
        $filename = basename( $file );
        
        if ( strpos( $filename, 'BI1_' ) === 0 ) 
        {
            
            if (($handle = fopen($file, "r")) !== false) 
            {
                 
                // 自动检测UTF-8 BOM,兼容带BOM/无BOM文件
                $bomCheck = fread($handle, 3);
                if ($bomCheck !== "\xEF\xBB\xBF") {
                    rewind($handle);
                }
                  
                     $bi1_values =  array();
                     while (($data = fgetcsv($handle, 9000000, ";")) !== false) 
                        {                                         
                                $bi1_values[] = "('$data[0]', '".str_replace("'", "''",$data[1])."','$date1','$date2','$data[2]','$data[4]','".str_replace("'", "''",$data[5])."','".str_replace("'", "''",$data[6])."')";                 
                                if (count($bi1_values) == 1000) 
                                { 
                                    $query = "insert into dbo.Sales (storenumber, storename, date, time, TransRef, stylecode, color, size) 
                                    values " . implode(',', $bi1_values);
                                    $stmt = $conn->query( $query );
                                    
                                    if (!$stmt) 
                                    { 
                                            $file1 = "D:/xampp/htdocs/errors/erreur_BI1.txt";                       
                                            file_put_contents($file1, $query . PHP_EOL, FILE_APPEND | LOCK_EX);
                                    }   
                                    $bi1_values = array();
                                } 
                        }

                    // 补充:处理最后一批不足1000条的剩余数据
                    if (!empty($bi1_values)) {
                        $query = "insert into dbo.Sales (storenumber, storename, date, time, TransRef, stylecode, color, size) 
                        values " . implode(',', $bi1_values);
                        $stmt = $conn->query( $query );
                        if (!$stmt) 
                        { 
                                $file1 = "D:/xampp/htdocs/errors/erreur_BI1.txt";                       
                                file_put_contents($file1, $query . PHP_EOL, FILE_APPEND | LOCK_EX);
                        }
                    }
                        
                    fclose($handle);
                      
                    // 处理完成后移动文件到备份文件夹             
                    if(!rename($file, $dest . $filename)) 
                    { 
                        echo "error";
                    }                
                }
            }
    }
}

?>

额外注意事项

  • 该检测逻辑仅针对UTF-8编码的BOM做判断,不会影响GBK、UTF-16等其他编码文件的读取逻辑
  • 现有代码通过字符串拼接生成SQL语句,即使做了单引号转义依然存在注入风险,生产环境建议改用PDO预处理语句绑定参数实现批量插入,安全性和稳定性更高
  • 原代码逻辑中如果CSV最后一批数据不足1000条不会执行入库操作,上述完整代码已经补充了剩余数据的入库逻辑,避免尾部数据丢失。

内容的提问来源于stack exchange,提问作者Eric27

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 16:57:49