Search code examples
phpcsv

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;[email protected];52
Dan;Wong;[email protected];19
Tim;Hortons;[email protected];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;[email protected];52
1 champs à la ligne 3: 
Dan;Wong;[email protected];19
1 champs à la ligne 4: 
Tim;Hortons;[email protected];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


Solution

  • 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
    [email protected]
    52
    4 champs à la ligne 3: 
    
    Dan
    Wong
    [email protected]
    19
    4 champs à la ligne 4: 
    
    Tim
    Hortons
    [email protected]
    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

    function filter_delimiter($v) {
        return in_array($v, [',', ';'], true) ? $v : null;
    }
    
    // validate $_POST['delimiter'];
    $delimiter = filter_input(INPUT_POST, 'delimiter', FILTER_CALLBACK, ['options' => 'filter_delimiter']);
    if (!$delimiter) {
        $delimiter = ';';
        // optionally redirect to form error message
    }
    

    Alternatively parse the lines to determine the appropriate delimiter.

    // use absolute path
    $filename = __DIR__ . '/upload/' . $_FILES['fichier']['name'];
    if (false !== ($handle = fopen($filename, 'r'))) {
        $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 (!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";
            }
        }
    }