强制 fputcsv 对 *所有* 字段使用封装

发布于 2024-08-25 14:56:07 字数 281 浏览 7 评论 0原文

当我使用 fputcsv 将一行写入打开的文件句柄时,PHP 会向任何列添加一个封闭字符它认为需要它,但会让其他列没有外壳。

例如,您最终可能会得到这样的行,

11,"Bob ",Jenkins,"200 main st. USA ",etc

除了在每个字段的末尾附加一个虚假空格之外,有什么方法可以强制 fputcsv 始终用附件(默认为“)字符包围列?

When I use fputcsv to write out a line to an open file handle, PHP will add an enclosing character to any column that it believes needs it, but will leave other columns without the enclosures.

For example, you might end up with a line like this

11,"Bob ",Jenkins,"200 main st. USA ",etc

Short of appending a bogus space to the end of every field, is there any way to force fputcsv to always enclose columns with the enclosure (defaults to a ") character?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

墨洒年华 2024-09-01 14:56:07

否,fputcsv() 仅在以下条件下包围字段

/* enclose a field that contains a delimiter, an enclosure character, or a newline */
if (FPUTCSV_FLD_CHK(delimiter) ||
  FPUTCSV_FLD_CHK(enclosure) ||
  FPUTCSV_FLD_CHK(escape_char) ||
  FPUTCSV_FLD_CHK('\n') ||
  FPUTCSV_FLD_CHK('\r') ||
  FPUTCSV_FLD_CHK('\t') ||
  FPUTCSV_FLD_CHK(' ')
)

没有“始终包围”选项。

No, fputcsv() only encloses the field under the following conditions

/* enclose a field that contains a delimiter, an enclosure character, or a newline */
if (FPUTCSV_FLD_CHK(delimiter) ||
  FPUTCSV_FLD_CHK(enclosure) ||
  FPUTCSV_FLD_CHK(escape_char) ||
  FPUTCSV_FLD_CHK('\n') ||
  FPUTCSV_FLD_CHK('\r') ||
  FPUTCSV_FLD_CHK('\t') ||
  FPUTCSV_FLD_CHK(' ')
)

There is no "always enclose" option.

新一帅帅 2024-09-01 14:56:07

如果您想避免插入任何并非源自源数组的字符(< code>Chr(127)、Chr(0) 等),您可以将 fputcsv() 行替换为以下内容:

fputs($fp, implode(",", array_map("encodeFunc", $row))."\r\n");

当然,fputs() 比 fputcsv() 慢,但这是一个更干净的输出。完整的代码是这样的:

/***
 * @param $value array
 * @return string array values enclosed in quotes every time.
 */
function encodeFunc($value) {
    ///remove any ESCAPED double quotes within string.
    $value = str_replace('\\"','"',$value);
    //then force escape these same double quotes And Any UNESCAPED Ones.
    $value = str_replace('"','\"',$value);
    //force wrap value in quotes and return
    return '"'.$value.'"';
}

$fp = fopen("filename.csv", 'w');
foreach($table as $row){
    fputs($fp, implode(",", array_map("encodeFunc", $row))."\r\n");
}
fclose($fp);

Building on Martin's answer, if you want to avoid inserting any characters that don't stem from the source array (Chr(127), Chr(0), etc), you can replace the fputcsv() line with the following instead:

fputs($fp, implode(",", array_map("encodeFunc", $row))."\r\n");

Granted, fputs() is slower than fputcsv(), but it's a cleaner output. The complete code is thus:

/***
 * @param $value array
 * @return string array values enclosed in quotes every time.
 */
function encodeFunc($value) {
    ///remove any ESCAPED double quotes within string.
    $value = str_replace('\\"','"',$value);
    //then force escape these same double quotes And Any UNESCAPED Ones.
    $value = str_replace('"','\"',$value);
    //force wrap value in quotes and return
    return '"'.$value.'"';
}

$fp = fopen("filename.csv", 'w');
foreach($table as $row){
    fputs($fp, implode(",", array_map("encodeFunc", $row))."\r\n");
}
fclose($fp);
世界和平 2024-09-01 14:56:07

对这个解决方案不满意,但这就是我所做的和工作的。这个想法是在 fputcsv 上设置一个空字符作为封装字符,并在数组的每个元素上添加一些引号。

function encodeFunc($value) {
    return "\"$value\"";
}

fputcsv($handler, array_map(encodeFunc, $array), ',', chr(0));

Not happy with this solution but it is what I did and worked. The idea is to set an empty char as enclosure character on fputcsv and add some quotes on every element of your array.

function encodeFunc($value) {
    return "\"$value\"";
}

fputcsv($handler, array_map(encodeFunc, $array), ',', chr(0));
自找没趣 2024-09-01 14:56:07

经过大量的摸索和一些有些乏味的字符检查后,我得到了 Diego 和 < a href="https://gist.github.com/anonymous/223ea7353626bc6a6a9e#file-csvenlined-php" rel="nofollow noreferrer">Mahn 它将正确地去掉外壳并在所有字段上用双引号替换在fputcsv中。然后将文件输出到浏览器进行下载。

我还有一个次要问题,即无法确定双引号始终/从未转义。

特别适用于使用迭戈引用的 php://input 流直接输出到浏览器时。 Chr(127) 是一个空格字符,因此 CSV 文件比其他文件多一些空格,但我相信这回避了 UTF- 中 chr(0) NULL 字符的问题8.

/***
 * @param $value array
 * @return string array values enclosed in quotes every time.
 */
function encodeFunc($value) {
    ///remove any ESCAPED double quotes within string.
    $value = str_replace('\\"','"',$value);
    //then force escape these same double quotes And Any UNESCAPED Ones.
    $value = str_replace('"','\"',$value);
    //force wrap value in quotes and return
    return '"'.$value.'"';
}


$result = $array_Set_Of_DataBase_Results;
$fp = fopen('php://output', 'w');
if ($fp && $result) {
    header('Content-Type: text/csv');
    header('Content-Disposition: attachment; filename="export-'.date("d-m-Y").'.csv"');
    foreach($result as $row) {
        fputcsv($fp, array_map("encodeFunc", $row), ',', chr(127));
    }
    unset($result,$row);
    die;
}

我希望这对某人有用。

After a lot of scrafffing around and some somewhat tedious character checking, I have a version of the above referenced codes by Diego and Mahn that will correctly strip out encasings and replace with double quotes on all fields in fputcsv. and then output the file to the browser to download.

I also had a secondary issue of not being able to be sure that double quotes were always / never escaped.

Specifically for when outputting directly to browser using the php://input stream as referenced by Diego. Chr(127) is a space character so the CSV file has a few more spaces than otherwise but I believe this sidesteps the issue of chr(0) NULL characters in UTF-8.

/***
 * @param $value array
 * @return string array values enclosed in quotes every time.
 */
function encodeFunc($value) {
    ///remove any ESCAPED double quotes within string.
    $value = str_replace('\\"','"',$value);
    //then force escape these same double quotes And Any UNESCAPED Ones.
    $value = str_replace('"','\"',$value);
    //force wrap value in quotes and return
    return '"'.$value.'"';
}


$result = $array_Set_Of_DataBase_Results;
$fp = fopen('php://output', 'w');
if ($fp && $result) {
    header('Content-Type: text/csv');
    header('Content-Disposition: attachment; filename="export-'.date("d-m-Y").'.csv"');
    foreach($result as $row) {
        fputcsv($fp, array_map("encodeFunc", $row), ',', chr(127));
    }
    unset($result,$row);
    die;
}

I hope this is useful for some one.

谁人与我共长歌 2024-09-01 14:56:07

一种在浏览器中自动创建和下载 csv 同时强制包围所有或仅指定列的函数

它使用一个字符串,该字符串不太可能存在于数据集中,该字符串至少包含一个空格,这会强制包围。

在 fputsv 完成工作后,您检索文件并用空字符替换强制字符串。
这不能在大数据流中工作,除非您修改它,但对于大多数应用程序来说,它应该足够了

只需输入您想要强制 enlcose 或 ['*'] 包围所有内容的列,以防万一由于某种奇怪的原因强制字符串已经是包含在您的数据中,您可以传递不同的不存在字符串来强制括起来

function csvDownload(
        array   $array,
        string  $filename = "export.csv",
        ?string $separator = ",",
        ?string $enclosure = '"',
        ?string $escape = "\\",
        ?array  $forceEnclose = [],
        string  $forceString = '{ || force enclosing || }'
    ): void
    {
        $tempFile = fopen('php://memory', 'w');
        foreach ($array as $line) {
            fputcsv(
                $tempFile,
                array_map(
                    function ($value, $key) use ($forceEnclose, $forceString) {
                        if (
                            in_array($key, $forceEnclose, true) ||
                            in_array('*', $forceEnclose, true)
                        ) {
                            $value .= $forceString;
                        }
                        return $value;
                    },
                    $line,
                    array_keys($line)
                ),
                $separator,
                $enclosure,
                $escape
            );
        }
        rewind($tempFile);
        header('Content-Type: text/csv');
        header('Content-Disposition: attachment; filename="' . $filename . '";');
        echo str_replace(
            $forceString,
            '',
            stream_get_contents($tempFile)
        );
        exit;
    }

A function to auto create and download in browser a csv while forcing to enclose all or only specified columns

It uses a string, that is quite unlikely to existing in the dataset, which contains at least one space and this forces the the enclosure.

After fputsv does it's job you retrieve the file and replace the forcing string with empty character.
This cannot work in large streams of data unless you modify it but for most applications it's should be sufficient

Just input the columns you want to force enlcose or ['*'] to enclose everything and in case for some strange reason the forcing string is already included in your data you can pass a different non existing string to force enclose

function csvDownload(
        array   $array,
        string  $filename = "export.csv",
        ?string $separator = ",",
        ?string $enclosure = '"',
        ?string $escape = "\\",
        ?array  $forceEnclose = [],
        string  $forceString = '{ || force enclosing || }'
    ): void
    {
        $tempFile = fopen('php://memory', 'w');
        foreach ($array as $line) {
            fputcsv(
                $tempFile,
                array_map(
                    function ($value, $key) use ($forceEnclose, $forceString) {
                        if (
                            in_array($key, $forceEnclose, true) ||
                            in_array('*', $forceEnclose, true)
                        ) {
                            $value .= $forceString;
                        }
                        return $value;
                    },
                    $line,
                    array_keys($line)
                ),
                $separator,
                $enclosure,
                $escape
            );
        }
        rewind($tempFile);
        header('Content-Type: text/csv');
        header('Content-Disposition: attachment; filename="' . $filename . '";');
        echo str_replace(
            $forceString,
            '',
            stream_get_contents($tempFile)
        );
        exit;
    }
仅此而已 2024-09-01 14:56:07

我的解决方案速度较慢,但​​允许与 fputcsv 函数完全兼容:

function fputcsv2($f, $array, $key="*Th1S*JuNk*") {
    $temp=fopen("php://memory","r+");
    fputcsv($temp, array_map(fn($a) => $a." ".$key, $array));
    rewind($temp);
    $line=str_replace(" ".$key, "", stream_get_contents($temp));
    fclose($temp);
    fputs($f, $line."\n");
}

它的工作原理是在每个字段后添加一个空格和一些垃圾,使用 fputcsv 函数生成 CSV 行,然后从结果中删除垃圾。最后,将其作为字符串写入文件。您可以相应地调整“垃圾”,使其永远不会出现在您的数据中。

My solution is slower, but allows full compatibility with the fputcsv function:

function fputcsv2($f, $array, $key="*Th1S*JuNk*") {
    $temp=fopen("php://memory","r+");
    fputcsv($temp, array_map(fn($a) => $a." ".$key, $array));
    rewind($temp);
    $line=str_replace(" ".$key, "", stream_get_contents($temp));
    fclose($temp);
    fputs($f, $line."\n");
}

It works by adding a space and some junk after each field, generating the CSV line with fputcsv function then removing the junk from the result. Finally, writing it as a string to the file. You can adjust the "junk" accordingly so it never appears in your data.

别再吹冷风 2024-09-01 14:56:07

一个“快速而肮脏”的解决方案是在所有字段的末尾添加“”(如果您可以接受):

fputcsv($handle, array_map(fn($v) => $v.' ', $fields));

PS:为什么它有效?请参阅 Volkerk 答案;)

A "quick and dirty" solution is to add ' ' at the end of all of your fields, if it's acceptable for you:

fputcsv($handle, array_map(fn($v) => $v.' ', $fields));

PS: why it's working? see Volkerk answer ;)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文