joshuahedlund
joshuahedlund

Reputation: 1782

filegetcsv causing infinite loop

Trying to use filegetcsv to parse a CSV file and do stuff with it, using the following code found all over the Internet, including the PHP function definition page:

if (($handle = fopen("test.csv", "r")) !== FALSE) {
    while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
        print_r($data);
    }
    fclose($handle);
}

But the code gives me an infinite loop of warnings on the $data = line:

PHP Warning: fgetcsv() expects parameter 1 to be resource, boolean given in...
  1. I know the file I'm opening is a valid file, because if I add a dummy character to the file name I get a different error and no loop.
  2. The file is in a folder with full permissions.
  3. I'm not using a CSV generated by an Excel on Mac (there's a quirky error there)
  4. PHP version 5.1.6, so there should be no problem with the function
  5. I know the file's not too big, or malformed, because I kept shrinking the original file to see if that was a problem and finally just created a custom file in Notepad with nothing more than two lines like:

    Value1A,Value1B,Value1C,Value1D

Still looping and giving no data. Here's the full code I'm working with now (using a variable that's greater than the number of lines so I can prove that it would loop infinitely without actually giving my server an infinite loop)

if ($handle = fopen($_SERVER['DOCUMENT_ROOT'].'/tmp/test-csv-file.csv', 'r') !== FALSE) {
    while ((($data = fgetcsv($handle, 1000, ',')) !== FALSE) && ($row < 10)) {
        print_r($data);
        $row++;
    }
    fclose($handle);
}

So I really have two questions.

1) What could I possibly be overlooking that is causing this loop? I'm half-convinced it's something really "face-palm" simple...

2) Why is the recommended code for this function something that can cause an infinite loop if the file exists but there is some unknown problem? I would have thought the purpose of the !== FALSE and so forth would be to prevent that kind of stuff.

Upvotes: 1

Views: 3873

Answers (2)

Kiran Maniya
Kiran Maniya

Reputation: 8979

            $row = 1;
            if (($handle = fopen($_FILES['csv-file']['tmp_name'], "r")) !== FALSE) {
                $data = fgetcsv($handle , 1000 , ",");
                while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {


                    $num = count($data);
                    echo "<p> $num fields in line $row: <br /></p>\n";
                    $row++;
                    for ($c=0; $c < $num; $c++) {
                        echo $data[$c] . "<br />\n";
                    }
                }
                fclose($handle);
            }

Try given Code Snippet once,because as i have noticed you are missing some important things in your code.

Upvotes: 0

Jon
Jon

Reputation: 437376

There's no question about what's going on here: the file is not opened successfully. That's why $handle is a bool instead of a resource (var_dump($handle) to confirm this yourself).

fgetcsv then returns null (not false!) because there's an error, and your test doesn't pick this up because you are testing with !== false. As the documentation states:

fgetcsv() returns NULL if an invalid handle is supplied or FALSE on other errors, including end of file.

I agree that returning null and false for different error conditions is not ideal, and furthermore that it's against the precedent established by lots of other functions, but that's just how it is (and things could be worse). As things stand, you can simply change the test to

while ($data = fgetcsv($handle, 1000, ","))

and it will work correctly in both cases.

Update:

You are the victim of assignment inside an if condition:

if ($handle = fopen($_SERVER['DOCUMENT_ROOT'].'/tmp/test-csv-file.csv', 'r') !== FALSE)

should have been

// wrap the assignment to $handle inside parens!
if (($handle = fopen($_SERVER['DOCUMENT_ROOT'].'/tmp/test-csv-file.csv', 'r')) !== FALSE)

I 'm sure you understand what went wrong here. This is the reason why I choose to never, ever, make assignments inside conditionals. I don't care that it's possible. I don't care that it's shorter. I don't even care that sometimes it's quite less "elegant" to write the loop if the assignment is taken out. If you value your sanity, consider doing the same.

Upvotes: 6

Related Questions