0

I have an issue I cannot seem to fix. I have a function that takes a file and converts it to an array using the first row as the keys:

function parseCSVToArray($filePath)
{
    $csvData = [];

    if (($handle = fopen($filePath, "r")) !== false) {
        $keys = fgetcsv($handle); // Get the first row as keys

        while (($data = fgetcsv($handle)) !== false) {
            $rowData = array();
            foreach ($keys as $index => $key) {
                $rowData[$key] = $data[$index] ?? ''; // Assign each value to its corresponding key
            }
            $csvData[] = $rowData;
        }

        fclose($handle);
    }
    return $csvData;
}

Everything works as normal and creates the array as expected:

$getTheRecords = parseCSVToArray('Data/records.csv');

// File contents
record,subdomain,hub_knows,domain,type,value,action,rationale
mail.sub.domain.com.,sub.domain.com,Hub knows about this,domain.com,CNAME,dispatch.domain.com.,DELETE,Dispatch links can go
Array
(
    [record] => mail.sub.domain.com
    [subdomain] => sub.domain.com
    [hub_knows] => Hub knows about this
    [domain] => domain.com
    [type] => CNAME
    [value] => dispatch.domain.com.
    [action] => DELETE
    [rationale] => Dispatch links can go
)

Now the issue is when I go to use or print the data. When I loop through the array using:

foreach($getTheRecords as $element)
{
    echo "<div style='margin-bottom: 20px'>";
    echo($element['subdomain']); // This will print the subdomain as expected.
    echo "</div>";
}

If I change 'subdomain' to 'record' it prints nothing. However, every other 'key' prints the results just fine.

Thank you in advance for your help!

I have tried changing the name of the first key to 'mainrecord' or anything and it still will not print out.

Iside loop var_dmup():

array(8) {
  ["record"]=>
  string(31) "mail.0lemonade.starchapter.com."
  ["subdomain"]=>
  string(25) "0lemonade.starchapter.com"
  ["hub_knows"]=>
  string(20) "Hub knows about this"
  ["domain"]=>
  string(17) "scdomaintest3.com"
  ["type"]=>
  string(5) "CNAME"
  ["value"]=>
  string(22) "dispatch.scnetops.com."
  ["action"]=>
  string(6) "DELETE"
  ["rationale"]=>
  string(21) "Dispatch links can go"
}
Ray C
  • 164
  • 8

1 Answers1

0

Your file likely has a UTF8 Byte Order Mark [BOM] at the beginning which is throwing off the first key. While a BOM isn't necessary at all for UTF8, some programs still add it as a "hint" that the file is UTF8.

If you var_dump($keys[0], bin2hex($keys[0]) you'll likely see that the first key's is longer than what is visible, and the hex output will show it prefixed with EFBBBF which is the BOM.

Try replacing:

$keys = fgetcsv($handle);

With:

$keys = str_getcsv(preg_replace("/^\xef\xbb\xbf/", "", fgets($handle))); 

Which will trim off the BOM, if it exists.

Edit: A bit more broadly-applicable code.

function stream_skip_bom($stream_handle) {
    if( ! stream_get_meta_data($stream_handle)['seekable'] ) {
        throw new \Exception('Specified stream is not seekable, and cannot be rewound.');
    }
    
    $pos = ftell($stream_handle);
    $test = fread($stream_handle, 3);
    
    if( $test !== "\xef\xbb\xbf" ) {
        fseek($stream_handle, $pos);
    }
}

so after opening $handle you would call simply:

stream_skip_bom($handle);
Sammitch
  • 30,782
  • 7
  • 50
  • 77
  • [The fundamental goal of closing duplicate questions is to help people find the right answer by getting all of those answers in one place.](https://stackoverflow.com/help/duplicates#:~:text=The%20fundamental%20goal%20of%20closing%20duplicate%20questions%20is%20to%20help%20people%20find%20the%20right%20answer%20by%20getting%20all%20of%20those%20answers%20in%20one%20place.) – mickmackusa Jun 02 '23 at 22:11