Zhang
Zhang

Reputation: 101

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

Upvotes: 7

Views: 15027

Answers (3)

Will B.
Will B.

Reputation: 18426

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";
        }
    }
}

Upvotes: 10

Efr&#233;n
Efr&#233;n

Reputation: 435

The function fgetcsv contains five parameters. Here is its declaration:

fgetcsv(resource, lenght, delimiter, enclosure, escape)

This is my resource file.csv:

"mydata1|mydata2|mydata3|my;data;with;ugly"char;|myprice|etc|etc|

In my case, the delimiter is a pipe character |. The semicolon is not a delimiter. As we have double quotes " among the data, we use a single quote character ' as an enclosure. With no enclosure, the output will be empty.

Here is the source code:

$mycsv = fopen("file.csv", "r");

while (($data = fgetcsv($mycsv, 0, "|", "'")) == true) {
   print_r($data);
}

Here is the output data:

Array
(
    [0] => "mydata1
    [1] => mydata2
    [2] => mydata3
    [3] => my;data;with;ugly"char;
    [4] => myprice
    [5] => etc
    [6] => etc
    [7] => 
)

You can also look at the following Ideone snippet: https://ideone.com/30OF1K. The file.csv file was replaced with stdin.

Upvotes: 0

Kevin Robatel
Kevin Robatel

Reputation: 8386

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

Manual

Second parameter is the length.

fgetcsv($handle, 0, ";")

Upvotes: 2

Related Questions