Php fgetcsv/fputcsv$转义参数基本上已损坏 概述

Php fgetcsv/fputcsv$转义参数基本上已损坏 概述,php,csv,Php,Csv,并支持一个$escape参数,但是,它要么已损坏,要么我不理解它应该如何工作。忽略一个事实,即您没有看到fputcsv上记录的$escape参数,它在PHP源代码中受支持,文档中有一个小错误阻止它通过 该函数还支持$delimiter和$enclosure参数,默认分别为逗号和双引号。我希望应该传递$escape参数,以使字段包含这些元字符中的任何一个(反斜杠、逗号或双引号),但事实并非如此。(我现在从阅读中了解到,这些将用双引号括起来) 我试过的 例如,fgetcsv文档评论部分中的许多海报都

并支持一个
$escape
参数,但是,它要么已损坏,要么我不理解它应该如何工作。忽略一个事实,即您没有看到
fputcsv
上记录的
$escape
参数,它在PHP源代码中受支持,文档中有一个小错误阻止它通过

该函数还支持
$delimiter
$enclosure
参数,默认分别为逗号和双引号。我希望应该传递
$escape
参数,以使字段包含这些元字符中的任何一个(反斜杠、逗号或双引号),但事实并非如此。(我现在从阅读中了解到,这些将用双引号括起来)

我试过的 例如,
fgetcsv
文档评论部分中的许多海报都受到了陷阱的影响。在这种情况下,我们希望向字段写入一个反斜杠

$r = fopen('/tmp/test.csv', 'w');
fwrite($r, '"\"');
fclose($r);

$r = fopen('/tmp/test.csv', 'r');
var_dump(fgetcsv($r));
fclose($r);
这将返回
false
。我也尝试了
“\\”
,但是也返回了
false
。用模糊的文本填充反斜杠可以提供它所需要的增强
“hi\\there”
“hi\there”
都解析并具有相同的结果,但结果只有一个反斜杠,那么
$escape
的意义何在

我观察到了在不将反斜杠括在双引号中时的相同行为。编写包含字符串
\
\
的“CSV”文件时,使用
fgetcsv
1反斜杠进行分析时,结果相同

让我们询问PHP如何使用
fputcsv

$r = fopen('/tmp/test.csv', 'w');
fputcsv($r, array('\\'));
fclose($r);
echo file_get_contents('/tmp/test.csv');
结果是一个双引号括起来的单反斜杠(当
$enclose
支持被假定添加到
fputcsv
时,我尝试了3个版本的PHP>5.5.4)。有趣的是,
fgetcsv
甚至不能按照我上面的注释正确阅读它,它返回
false
。。。我希望
fputcsv
不要将反斜杠括在双引号中,或者
fgetcsv
能够像
fputcsv
所写的那样阅读
“\”
,或者在我明显误解的头脑中,为
fputcsv
编写一对双引号括起来的反斜杠,为
fgetcsv
正确解析它

重复性试验 尝试使用
fputcsv
将单引号写入文件,然后通过
fgetcsv
读取

$aBackslash = array('\\');

// Write a single backslash to a file using fputcsv
$r = fopen('/tmp/test.csv', 'w');
fputcsv($r, $aBackslash);
fclose($r);

// Read the file using fgetcsv
$r = fopen('/tmp/test.csv', 'r');
$aFgetcsv = fgetcsv($r);
fclose($r);

// Compare the read value from fgetcsv to our original value
if(count(array_diff($aBackslash, $aFgetcsv)))
  echo "PHP CSV support is broken\n";
问题 退一步,我有一些问题

  • $escape
    参数的意义是什么
  • 鉴于CSV文件定义松散,可以说PHP正确地支持它们吗
  • 在CSV文件中对反斜杠进行编码的“正确”方法是什么
背景 我最初发现这一点的时候,一位同事向我提供了一个由Python生成的CSV文件,该文件写了一个用双引号括起来的反斜杠,
fgetcsv
之后无法读取它。我让高卢人问他是否可以使用标准的Python函数。我一点也不知道PHP CSV工具包是一团乱麻!(FWIW:Python开发人员告诉我他正在使用CSV编写模块)。

EDIT 2 所以,在睡眠和重新查看代码之后,发现fputcsv不接受转义参数,我很愚蠢。我已将下面的代码更新为正确的工作代码。同样的基本原则也适用,escape参数用于更改escape参数,以便您可以加载带有反斜杠的CSV,而不将其视为转义字符。诀窍是使用csv中不包含的字符。您可以通过为特定字符对文件进行灰显,直到找到一个未返回的字符

编辑 好的,所以结论是它检查转义字符,然后从不停止检查。所以,如果它找到了,它就逃跑了。那很简单

这就是说,escape参数的目的是考虑到这种情况,您可以将escape字符更改为不需要的字符

在这里,我已将您的示例代码转换为工作代码:

$aBackslash = array('\\');

// Write a single backslash to a file using fputcsv
$r = fopen('/tmp/test.csv', 'w');
fputcsv($r, $aBackslash, ',', '"'); // EDIT 2: Removed escape param that causes PHP Notice.
fclose($r);

// Read the file using fgetcsv
$r = fopen('/tmp/test.csv', 'r');
$aFgetcsv = fgetcsv($r, ',', '"', '#');
fclose($r);

// Compare the read value from fgetcsv to our original value
if(count(array_diff($aBackslash, $aFgetcsv)))
  echo "PHP CSV support is broken\n";
else
  echo "PHP WORKS!\n";
一个重要的警告是
fgetcsv
fputcsv
必须具有相同的参数,否则返回的数组将与原始数组不匹配

原始答案 你说得很对。这是语言的一个缺陷。我已经尝试了我能想到的每一种斜杠排列,但我还没有从CSV获得成功的响应。它总是像你的例子所说的那样返回

我认为@deceze提到的是,在您的示例中,您使用
数组('\\')
,它实际上是PHP解释为的字符串文本“\”,并将“\”传递给CSV,然后以这种方式返回。这将返回错误的响应
\“
,正如我上面所说的,这肯定是错误的

我确实找到了解决办法,因此结果实际上是合适的:

首先,对于您的示例,我们需要以“\”作为主体生成/tmp/test.csv,或者稍微更改数组。最简单的方法是将数组更改为:

array('"\\\\"');
之后,我们应该稍微修改fgetcsv请求

$aFgetcsv = fgetcsv($r);
$aFgetcsv = array_map('stripslashes', $aFgetcsv);

通过这样做,我们告诉PHP去掉第一个斜杠,从而使$aFgetcsv“\”

中的字符串成为另一个双引号。快速查看Python上的文档,在封闭值(即双引号内)中使用的转义符是另一个双引号

对于PHP,默认转义字符是反斜杠(^);要匹配Python的行为,需要使用以下字符:

$data = fgetcsv($r, 0, ',', '"', '"');
(^)实际上
fgetcsv()
以相同的方式处理
$enclosure | |$enclosure
$escape | |$enclosure
两个参数,因此
$escape
参数用于避免将反斜杠视为特殊字符