phpcsvexport-to-csvfputcsv

CSV file without enclosure for space in string in PHP


I must generate a CSV with PHP to import it on a delivery optimization software.

This software required that header row matches a defined pattern :

tournée,véhicule,livré,type arrêt,date,heure,référence,nom,voie,complément,code postal,ville,pays,lat,lng,téléphone,email,commentaire,libellés,durée destination,référence visite,horaire début 1,horaire fin 1,horaire début 2,horaire fin 2,priorité,libellés visite,durée visite,répéter plages horaires,référence collecte,quantité,opération,codes barres,sans visite,durée client

But when I use fputcsv, the spaces in strings are enclosed and I got this (which is not accepted by the software) :

tournée,véhicule,livré,"type arrêt",date,heure,référence,nom,voie,complément,"code postal",ville,pays,lat,lng,téléphone,email,commentaire,libellés,"durée destination","référence visite","horaire début 1","horaire fin 1","horaire début 2","horaire fin 2",priorité,"libellés visite","durée visite","répéter plages horaires","référence collecte",quantité,opération,"codes barres","sans visite","durée client"

How can I "disable" enclosure for spaces but keep it for characters like comma and semi-colon ?


Solution

  • Your best option would probably be to use a CSV library from composer that would give you more configuration options than PHP's built in functions.

    However, I was able to find a hacky solution using fputcsv.

    fputcsv allows you to specify the $enclosure character (the quotes), however it must be one single-byte character. So, you can't change it to nothing with an empty string (""), nor can you set it to null. But, if you know the column headers will not change and it's safe to remove the enclosures, then you could set the enclosure character to a character that won't be used anywhere, and then just remove any occurrences of that character.

    So, for this example, I chose a character that would almost certainly not be used anywhere else (the DEL character) and set that to be used instead of quotes. Rather than having fputcsv write directly to a file, I wrote to memory so that the header string could be saved to a variable. From there, I just used str_replace to remove the temporary enclosure character. You could then proceed to just use fwrite to add the header line to the CSV, and then output the rest of the CSV using fputcsv as normal.

    $headerString = 'tournée,véhicule,livré,type arrêt,date,heure,référence,nom,voie,complément,code postal,ville,pays,lat,lng,téléphone,email,commentaire,libellés,durée destination,référence visite,horaire début 1,horaire fin 1,horaire début 2,horaire fin 2,priorité,libellés visite,durée visite,répéter plages horaires,référence collecte,quantité,opération,codes barres,sans visite,durée client';
    $headerColumns = explode(',', $headerString);
    
    $temporaryCharacter = "\x7F";
    
    // output up to 5MB is kept in memory, if it becomes bigger
    // it will automatically be written to a temporary file
    $tempHeader = fopen('php://temp/maxmemory:' . (5 * 1024 * 1024), 'r+');
    
    // Write the header to temporary memory
    fputcsv($tempHeader, $headerColumns, ',', $temporaryCharacter);
    
    rewind($tempHeader);
    
    // put it all in a variable
    $headerLine = stream_get_contents($tempHeader);
    
    // Remove the enclosure characters
    $headerLine = str_replace($temporaryCharacter, '', $headerLine);
    
    echo $headerLine . PHP_EOL;
    
    // fwrite the $headerLine to the file. 
    

    For your case, it might not even be necessary to use the temporary character; you could probably just leave it with the default quotes for the enclosure, and then use str_replace('"', '', $headerLine) to remove the quotes.