Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP fgetcsv() delimiter ';' not recognized

Tags:

php

csv

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

like image 454
Zhang Avatar asked Jun 10 '16 12:06

Zhang


2 Answers

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

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.

$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";
        }
    }
}
like image 65
Will B. Avatar answered Sep 28 '22 20:09

Will B.


array fgetcsv ( resource $handle [, int $length = 0 [, string $delimiter = "," [, string $enclosure = '"' [, string $escape = "\" ]]]] )

Manual

Second parameter is the length.

fgetcsv($handle, 0, ";")
like image 25
Kevin Robatel Avatar answered Sep 28 '22 18:09

Kevin Robatel