4

PHP has a function for converting CSV strings to PHP arrays, but not a function for vice-versa, so I wrote one:

function echocsv(array $arr, $quo = '"', $sep = ',') {
    $escape = $quo . $quo;
    foreach($arr as &$val) {
        if(strpos($val, $quo) !== false) {
            $val = $quo . str_replace($quo, $escape, $val) . $quo;
        }
    }
    echo implode($sep, $arr) . PHP_EOL;
}

Is there anything I'm overlooking? From wikipedia it basically says that quotes should be escaped with another quote, and that's pretty much all there is to it. The .CSV file will need to be openable in MS Excel.

My primitive tests seem to suggest it's working.

(I'm echoing it rather than returning a string because I'm going to stream it right to the browser)

mpen
  • 272,448
  • 266
  • 850
  • 1,236

3 Answers3

7
$stdout = fopen('php://output','w'); // 'stdout' is for CLI, 'output' is for Browser
fputcsv($stdout, array('val,ue1','val"ue2','value3','etc'));
fflush($stdout); // flush for fun :)
fclose($stdout);

^ this outputs CSV to the Browser.

CodeAngry
  • 12,760
  • 3
  • 50
  • 57
  • 1
    I actually discovered this just recently; works like a charm! – mpen Jul 12 '13 at 16:02
  • It should be noted that `fputcsv()` always outputs LF as the EOL, regardless of OS (unless the `t` flag is used on the Windows _filesystem_, rather than an I/O stream). So this might need to be `trim()`'d and fixed if working on Windows. – MrWhite Oct 28 '13 at 22:13
  • FWIW, the constant `STDOUT` is an already opened stream to stdout: http://php.net/commandline.io-streams – cmbuckley Oct 28 '13 at 22:32
  • @cbuckley My C++ heritage forces my to nicely open and close everything :) Even if it's a bit redundant... – CodeAngry Oct 29 '13 at 08:20
  • @CodeAngry: Yes, they may well do, I'm only saying it _might_ need to be fixed, and it's not something that can be configured in the call to `fputcsv()`. It's one of those YMMV situations, just saying... it depends on the application and perhaps how the files are transferred (FTP in ASCII or binary mode for instance). I realise there's no standard, but [RFC 4180](http://tools.ietf.org/html/rfc4180) does suggest CRLF as the line ending. – MrWhite Oct 29 '13 at 09:38
6

PHP does indeed contain the function you need: fputcsv()

To stream to the browser, use stdout as your "file":

$stdout = fopen('php://stdout','w');
fputcsv($stdout, array('val,ue1','val"ue2','value3','etc'));
fclose($stdout);
Francis Avila
  • 31,233
  • 6
  • 58
  • 96
  • I actually tried that, but it wasn't working for me for some reason. I think it messed up the character encoding or something.... maybe I'll try it again. Seems like a bit of a hacky solution though; not sure why they don't have one that deals directly with strings. – mpen Dec 15 '11 at 02:38
  • You may try opening with `'wb'` (write binary) mode and/or setting your content-type header correctly. – Francis Avila Dec 15 '11 at 02:45
  • 1
    Forgot about this question. I actually re-visited this recently; `CodeAngry` is right. You have to use `php://output` to output to the the browser, `php://stdout` only works on the command-line. – mpen Jul 12 '13 at 16:01
3

You also need to check if $val contains $sep (i.e. quote the string if it contains a comma):

if (strpos($val, $quo) !== false || strpos($val, $sep) !== false) {
    ...
}

Otherwise, fputcsv() will do the job (but only to a file/stream).

cmbuckley
  • 40,217
  • 9
  • 77
  • 91