Zhang Zhang - 5 months ago 52
PHP Question

PHP fgetcsv() delimiter ';' not recognized

it seems I have a problem with the ";" delimiter. Here's my csv file:

First Name;Last Name;Email;Age
Julie;Brown;julie@example.com;52
Dan;Wong;dan@example.com;19
Tim;Hortons;tim@example.com;27


and my PHP code:

$row = 1;
if (($handle = fopen("upload/".$_FILES['fichier']['name'], "r")) !== FALSE) {
while (($data = fgetcsv($handle, ";")) !== FALSE) {
$num = count($data);
echo "<p> $num champs à la ligne $row: <br /></p>\n";
$row++;
for ($c=0; $c < $num; $c++) {
echo $data[$c] . "<br />\n";
}
}
fclose($handle);
}


and I have this out put:

1 champs à la ligne 1:
First Name;Last Name;Email;Age
1 champs à la ligne 2:
Julie;Brown;julie@example.com;52
1 champs à la ligne 3:
Dan;Wong;dan@example.com;19
1 champs à la ligne 4:
Tim;Hortons;tim@example.com;27


instead of something like this when I use the ',' delimiter

4 champs à la ligne 1:
First Name
Last Name
Email
Age


Besides, I want to know if it is possible to have various delimiters. Because I want to display csv files uploaded by users and I don't want to force them to use one predetermined delimiter.

Thanks

Answer

The second parameter is the length, so your fgetcsv should be

fgetcsv($handle, 0, ';');

Resulting in

4 champs à la ligne 1: 

First Name
Last Name
Email
Age
4 champs à la ligne 2: 

Julie
Brown
julie@example.com
52
4 champs à la ligne 3: 

Dan
Wong
dan@example.com
19
4 champs à la ligne 4: 

Tim
Hortons
tim@example.com
27

As for your second question on variable delimiters. By far the easiest method would allow the user to define which delimiter to use on the upload form, possibly using a select element of acceptable delimiters and then use it when reading the csv.

For Example

$allowedDelimiters = [',', ';'];
$defaultDelimiter = ';';
if (true === empty($_POST['delimiter'])) {
    $_POST['delimiter'] = $defaultDelimiter;
}
if (!in_array($_POST['delimiter'], $allowedDelimiters, true)) {
    $_POST['delimiter'] = $defaultDelimiter;
    //alternatively redirect back to the form with an error message
}
$delimiter = $_POST['delimiter'];

You can also parse the lines checking for the desired delimiter.

$filename = "upload/".$_FILES['fichier']['name'];
if (($handle = fopen($filename, "r")) !== false) {
    $content = fread($handle, filesize($filename));
    fclose($handle);
    //count the delimiters
    $semiColons = substr_count($content, ';');
    $commas = substr_count($content, ',');
    //read each row
    $rows = str_getcsv($content, "\n");
    $rowCount = count($rows);
    $delimiter = null;
    foreach ($rows as $line => $row) {
        //check the delimiters
        if (false === isset($delimiter)) {
            /* 
              determine if the delimiter total divided by the number 
              of rows matches the delimiters found on this row 
              and use it to parse the columns 
            */
            if ($semiColons > 0 && $semiColons / $rowCount === substr_count($row, ';')) {
                $delimiter = ';';
            } elseif ($commas > 0 && $commas / $rowCount === substr_count($row, ',')) {
                $delimiter = ',';
            }
        }
        //read the columns using the detected delimiter 
        //otherwise use a default if a delimiter could not be determined
        $columns = str_getcsv($row, $delimiter ? : ';');
        echo "<p>$rowCount champs à la ligne " . ($line + 1) . "</p>\n";
        foreach ($columns as $column) {
            echo $column . "<br/>\n";
        }
    }
}