Search code examples
phpcsvfopenphp-8.1

CSV import problem since converting to PHP 8.1


I have the following Wordpress function that worked in PHP 7. Since converting to 8.1, it's not working.

function dropdown_handler() {

$output = drop_function();
//send back text to replace shortcode in post
return $output;
}

function drop_function() {
//get the csv file with amounts
if ($file_handle = fopen("wp-content/plugins/drop/amounts.csv", "r")) {
while (!feof($file_handle) ) {
    $lines[] = fgetcsv($file_handle, 1024);
    
}
fclose($file_handle);
$lines = str_replace ("£","£",$lines);

}
else {
echo "Sorry, something went wrong";
}

In my error log I'm seeing "PHP Warning: Array to string conversion in" relating to the $lines = str_replace line but I think there's something wrong with the fopen statement.

Basically, the word Array is being stored in the $lines variable rather than the contents of the CSV file. Any ideas please?


Solution

  • Your code was always broken, it's just broken in a slightly more obvious way than it used to be...

    $lines[] = fgetcsv($file_handle, 1024);
    

    fgetcsv, unless it fails, returns an array; you then add this array as a new item to another array, $lines. The result is an array of arrays, like this:

    $lines = [
        ['line 1 first item', 'line 1 second item'],
        ['line 2 first item', 'line 2 second item'],
    ];
    

    Later, you pass this whole array to str_replace; but str_replace only knows how to deal with a single dimension of array.

    So this works:

    $singleLine = ['line 1 first item', 'line 1 second item'];
    var_dump(str_replace('item', 'ITEM', $singleLine));
    

    But this doesn't:

    var_dump(str_replace('item', 'ITEM', $lines));
    

    Running that example on multiple versions of PHP reveals that under PHP 7.x, str_replace reacted by simply leaving the inner arrays untouched - in other words, it did nothing.

    In PHP 8, it instead tries to turn each inner array into a string, issuing the warning and producing the word "Array" (which will then have any substitutions applied to it).

    The fix for both PHP versions is to run the str_replace on each of the inner arrays, most simply by using array_map:

    var_dump(
        array_map(
            fn($innerArray) => str_replace('item', 'ITEM', $innerArray),
            $lines
        )
    );
    

    Alternatively, you can just delete the str_replace line completely, since you were apparently happy enough when it wasn't actually doing anything.