0

I have an array created by using str_getcsv():

$array = array_map('str_getcsv', file($file['tmp_name']));
array_walk($array, function(&$a) use ($array) {
    $a = array_combine($array[0], $a);
});
array_shift($array);

The returned $array outputs this from var_dump($array).

array(18) {
  ["fund"]=>
  string(6) "Fund 1"
  ["name"]=>
  string(13) "Property Name"
  ["investment"]=>
  string(13) "Investment Name"
  ["region"]=>
  string(6) "London"
  ["sector"]=>
  string(6) "Office"
  ["status"]=>
  string(8) "Published"
  ["description"]=>
  string(0) ""
  ["acquisition_date"]=>
  string(0) ""
  ["size"]=>
  string(0) ""
  ["address_line_1"]=>
  string(0) ""
  ["address_line_2"]=>
  string(0) ""
  ["city"]=>
  string(6) "London"
  ["county"]=>
  string(0) ""
  ["postcode"]=>
  string(0) ""
  ["longitude"]=>
  string(0) ""
  ["latitude"]=>
  string(0) ""
  ["featured"]=>
  string(0) ""
  ["external_link"]=>
  string(0) ""
}

When I try and access $array['fund'];, I get Notice: Undefined index: fund. My first thought was that fund had a hidden character in the key name from the CSV headers because $array['name'] works, but I've checked and the only hidden characters are CR LF.

I've seen similar problems on StackOverflow for multi-dimensional arrays, but not for single dimension arrays.

Any help would be greatly appreciated. I've even tried casting to StdClass and $array->fund and get a similar error about property not existing.

I've tried renaming the first header column name to whatever, and it still has issues with it, so I'm wondering if it's a problem accessing the first key.

yivi
  • 42,438
  • 18
  • 116
  • 138
Stefan Dunn
  • 5,363
  • 7
  • 48
  • 84
  • 1
    Do: `$new = []; foreach ($array as $k => $v) { $new[trim($k)] = $v; }` before and check if it works with the new array. It should remove any invisible white spaces (including CR LF) – M. Eriksson Feb 19 '19 at 06:07
  • I tried that, and it didn't work. However, I just opened up the CSV file in Excel and re-saved using the `Comma Separated Vales (.csv)` option instead of `CSV UTF-8 (Comma Delimited) (.csv)` option from the `file > save as` menu and it worked. I'll try and update the answer for anyone else who encounters this. – Stefan Dunn Feb 19 '19 at 06:15
  • You may have had a BOM in your file - have a read of https://stackoverflow.com/questions/45240387/how-can-i-remove-the-bom-from-a-utf-8-file – Nigel Ren Feb 19 '19 at 07:19
  • You need to add the code you are actually using, and the problematic input file, at least that line. Otherwise we are left guessing. – yivi Feb 19 '19 at 08:01

1 Answers1

2

tldr;

You are trying to access $array['fund'] when you should be accessing $array[0]['fund']. You are treating this as a single-dimension array, but it is a multi-dimension array (dimension 1, indexed; dimension 2, associative).


Explanation:

You are not showing the specific code where you try to access $array['fund'], nor your specific input, but the problem seems to be that you misunderstand what's the structure of the resultant array for the code you are using to parse your CSV.

array_map() + array_walk() + array_combine() + array_shift() seem like a slightly confusing way to get what you want, and the results are showing. This is a clear example of "clever" code getting on the way of productivity. The two liner array construction is harder to parse than some alternatives.

I'm going to assume this input, since you do not provide any input and reading an external file is outside of the scope of this problem (and not really a problem on itself):

// input

$lines = <<<EOF
fund,name,investment,region,sector,status,description,acquisition_date,size,address_line_1,address_line_2,city,county,postcode,longitude,latitude,featured,external_link
"Fund 1","Property Name","Investment Name","London","Office","Published","","","","","","London","","","","","",""
EOF;

This matches the array you show in your question.

Let's try to dissect the code going forward:

$array = array_map('str_getcsv', explode(PHP_EOL, $lines));

This leaves you with an array of two elements. At index 0 you have the headers, and at index 1 you have the values.

array_walk($array, function(&$a) use ($array) {
    $a = array_combine($array[0], $a);
});

Here you walk each of these two arrays, and array_combine() each one with the array at index 0. You wan to create arrays where the keys are the values from the array that contain the headers ($array[0]).

Note: This should make obvious that $array in an indexed array, since you are already trying to access the element at position 0.

Obviously you'll end up with an extra array (header array combined with header array), but you'll deal with that later.

array_shift($array);

Here you get rid of the array of headers (the one with values like $element['fund'] = 'fund'). You remove the first element of your two element array. Again, this operation **only makes sense if $array is an indexed array to begin with.

At this point you have an array of one element, and that element is an array with 18 keys=>values.

If at that point you try to access $array['fund'] it's going to naturally fail. Because $array is an indexed array, not an associative array.

You'd need to access the elements of this indexed array, and then try to access fund.

E.g.: $array[$i]['fund'];

You can see it working here.

Community
  • 1
  • 1
yivi
  • 42,438
  • 18
  • 116
  • 138
  • So why does `var_dump($array)` not show a multi-dimensional array (and instead an assoc array) if you're suggesting it is. – Stefan Dunn Feb 20 '19 at 08:08
  • Stefan, I can't see the code you use after generating the array, nor the input you are using. But if you go to the working the example I've linked you'll see clearly that the result of that particular loop is an indexed array containing N associative arrays. – yivi Feb 20 '19 at 08:11
  • @Stefan the only change I made [here](https://3v4l.org/ru4e9) was to read from a multiline string instead of a multiline file. You must agree there is no practical difference. And the result is obviously an N dimensions array (which makes sense, since that would allow you to process CSV with more than 2 records; which I gather is the objetive). – yivi Feb 20 '19 at 08:15
  • To make it even more obvious, within the loop in your own code you are accessing `$array[0]`. So in your own code you are aware that `$array` is **indexed**, not associative. – yivi Feb 20 '19 at 08:21
  • @StefanDunn Got it now? I've further edited my answer to make it even clearer. – yivi Feb 20 '19 at 08:42