【问题标题】:Remove BOM () from imported .csv file从导入的 .csv 文件中删除 BOM ()
【发布时间】:2015-11-18 00:46:06
【问题描述】:

我想从我导入的文件中删除 BOM,但它似乎不起作用。

我尝试preg_replace('/[\x00-\x1F\x80-\xFF]/', '', $file); 和一个str_replace。

我希望有人看到我做错了什么。

$filepath = get_bloginfo('template_directory')."/testing.csv";
            setlocale(LC_ALL, 'nl_NL');
            ini_set('auto_detect_line_endings',TRUE);
            $file = fopen($filepath, "r") or die("Error opening file");
            $i = 0;
            while(($line = fgetcsv($file, 1000, ";")) !== FALSE) {
                if($i == 0) {
                    $c = 0;
                    foreach($line as $col) {
                        $cols[$c] = utf8_encode($col);
                        $c++;
                    }
                } else if($i > 0) {
                    $c = 0;
                    foreach($line as $col) {
                        $data[$i][$cols[$c]] = utf8_encode($col);
                        $c++;
                    }
                }
                $i++;
            }

------------
已解决的版本:

setlocale(LC_ALL, 'nl_NL');
ini_set('auto_detect_line_endings',TRUE);
require_once(ABSPATH.'wp-admin/includes/file.php' );

$path = get_home_path();        
$filepath = $path .'wp-content/themes/pon/testing.csv';
$content = file_get_contents($filepath); 
file_put_contents($filepath, str_replace("\xEF\xBB\xBF",'', $content));

// FILE_PUT_CONTENTS AUTOMATICCALY CLOSES THE FILE
$file = fopen($filepath, "r") or die("Error opening file"); 

$i = 0;
while(($line = fgetcsv($file, 1000, ";")) !== FALSE) {
    if($i == 0) {
        $c = 0;
        foreach($line as $col) {
            $cols[$c] = $col;
            $c++;
        }
    } else if($i > 0) {
        $c = 0;
        foreach($line as $col) {
            $data[$i][$cols[$c]] = $col;
            $c++;
        }
    }
    $i++;
}

我发现它删除了 BOM 并通过用新数据覆盖它来调整文件。问题是我的脚本的其余部分不再起作用,我不明白为什么。这是一个新的 .csv 文件

【问题讨论】:

  • $cols[$c] 在你的第一个 foreach 中是没有意义的。 $cols 是您正在处理的任何行/字段的副本。你需要foreach($lines as $key => $col) { $lines[$key] = utf8_encode($col); }
  • fgetcsv 的 PHP 文档评论有一个很好的答案,php.net/manual/en/function.fgetcsv.php#122696 - 打开文件,读取并移动文件指针并检查前 3 个字节是否等于 BOM 字符串,如果不是,倒回然后继续使用 fgetcv
  • the Same issue has been solved here fixedstring = decodeURIComponent(escape(utfstring));

标签: php csv import fgetcsv


【解决方案1】:

试试这个:

function removeBomUtf8($s){
  if(substr($s,0,3)==chr(hexdec('EF')).chr(hexdec('BB')).chr(hexdec('BF'))){
       return substr($s,3);
   }else{
       return $s;
   }
}

【讨论】:

  • 它给了我这个:Warning: substr() expects parameter 1 to be string, resource given
  • 你向这个函数传递了什么?应该是这样的:$file = 'something.csv';$content = file_get_contents($file);var_dump(removeBomUtf8($content));然后开始处理这个文件。
  • 在这一行:$content = file_get_contents($file);$file 更改为$filepath
  • 好的,这是一些进展。谢谢。我现在得到一个字符串,其中包含我的所有 csv 数据,而没有 BOM。惊人的。如果我删除 var_dump 并让我的脚本继续使用 while(($line = fgetcsv(removeBomUtf8($content), 1000, ";")) !== FALSE) { 它会给我一个没有错误或进度的空白页。有什么想法吗?
  • 移除 UTF16 Little Endian BOM (substr($s, 0, 2) == chr(0xFF).chr(0xFE))
【解决方案2】:

正确的方法是跳过 BOM(如果文件中存在) (https://www.php.net/manual/en/function.fgetcsv.php#122696):

ini_set('auto_detect_line_endings',TRUE);
$file = fopen($filepath, "r") or die("Error opening file");
if (fgets($file, 4) !== "\xef\xbb\xbf") //Skip BOM if present
        rewind($file); //Or rewind pointer to start of file

$i = 0;
while(($line = fgetcsv($file, 1000, ";")) !== FALSE) {
    ...
}

【讨论】:

  • 这是对的,但它不会删除 bom,这就是问题
【解决方案3】:

如果字符编码功能对您不起作用(在某些情况下对我来说就是这种情况)并且您知道您的文件总是有 BOM,您可以简单地使用 fseek() 跳过前 3 个字节,即 BOM 的长度。

$fp = fopen("testing.csv", "r");
fseek($fp, 3);

你也不应该使用explode() 来分割你的CSV 行和列,因为如果你的列包含你分割的字符,你会得到一个不正确的结果。改用这个:

while (!feof($fp)) {
    $arrayLine = fgetcsv($fp, 0, ";", '"');
    ...
}

【讨论】:

  • 如果您不能确定是否有 BOM 标记,最好检查一下,如果没有则回退:if (!fread($handle, 3)==chr(0xEF).chr(0xBB).chr(0xBF)) { rewind($handle); } 而不是 fseek
【解决方案4】:

那里的 BOM 不是为您提供有关如何将输入重新编码为您的脚本/应用程序/数据库所需内容的线索吗?仅仅删除是没有用的。

这就是我如何强制将字符串(从带有file_get_contents() 的文件中提取)以 UTF-8 编码并去掉 BOM:

switch (true) { 
    case (substr($string,0,3) == "\xef\xbb\xbf") :
        $string = substr($string, 3);
        break;
    case (substr($string,0,2) == "\xfe\xff") :                            
        $string = mb_convert_encoding(substr($string, 2), "UTF-8", "UTF-16BE");
        break;
    case (substr($string,0,2) == "\xff\xfe") :                            
        $string = mb_convert_encoding(substr($string, 2), "UTF-8", "UTF-16LE");
        break;
    case (substr($string,0,4) == "\x00\x00\xfe\xff") :
        $string = mb_convert_encoding(substr($string, 4), "UTF-8", "UTF-32BE");
        break;
    case (substr($string,0,4) == "\xff\xfe\x00\x00") :
        $string = mb_convert_encoding(substr($string, 4), "UTF-8", "UTF-32LE");
        break;
    default:
        $string = iconv(mb_detect_encoding($string, mb_detect_order(), true), "UTF-8", $string);
};

【讨论】:

    【解决方案5】:

    file_get_contents读取数据,然后用mb_convert_encoding转换成UTF-8

    更新

    $filepath = get_bloginfo('template_directory')."/testing.csv";
    $fileContent = file_get_contents($filepath);
    $fileContent = mb_convert_encoding($fileContent, "UTF-8");
    $lines = explode("\n", $fileContent);
    foreach($lines as $line) {
        $conls = explode(";", $line);
        // etc...
    }
    

    【讨论】:

    • @Interactive file_get_contents 读取整个文件。 explode它由“\n”或“\r\n”。它返回一个数组。然后遍历这个数组。
    • 如果我运行它,它会给我一个数组,其中“titlefields”在第一个数组中,并且每个后面的数组都包含每个人的信息。这很棒,但我不知道如何将它用于我正在做的事情。所以我想我会熬夜。
    • 我稍微改变了你的想法(不知道它是否是最好的,但它有效。)我发现file_put_contents 关闭了文件,所以我只需要重新打开它。感谢您的帮助
    【解决方案6】:

    使用@Tomas'z answer作为主要灵感来源,@Nolwennig's comment

    // Strip byte order marks from a string
    function strip_bom($string, $type = 'utf8') {
        $length = 0;
    
        switch($type) {
            case 'utf8':
                $length = substr($string, 0, 3) === chr(0xEF) . chr(0xBB) . chr(0xBF) ? 3 : 0;
            break;
    
            case 'utf16_little_endian':
                $length = substr($string, 0, 2) === chr(0xFF) . chr(0xFE) ? 2 : 0;
            break;
        }
    
        return $length ? substr($string, $length) : $string;
    }
    

    【讨论】:

      【解决方案7】:

      检查这个解决方案,这解决了我的情况:https://www.php.net/manual/en/function.str-getcsv.php#116763

      $bom = pack('CCC', 0xEF, 0xBB, 0xBF);
      if (strncmp($yourString, $bom, 3) === 0) {
          $body = substr($yourString, 3);
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-08-30
        • 2021-02-16
        • 1970-01-01
        • 2020-05-20
        • 2014-01-20
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多