1

I'm working on a PHP script that updates some tracking numbers based on an uploaded CSV file. The import worked fine for some time, then the exports started having quotation marks around the values. I thought this would be fine, but it started rejecting the files. Doing some debugging and var_dumps, I discovered a very strange situation I have never seen before - An associative array with two indices with the same name. I ran the code setting the fields (shown below) and added a line:

$v['order_id'] = '119205';

After running that line, the var_dump was as follows:

array(15) {
  ["order_id"]=>
  string(6) "119205"
  ["Tracking Number"]=>
  string(22) "6735675476254654756"
  ["Postage"]=>
  string(4) "1.64"
  ["order_id"]=>
  string(6) "119205"
}

Some fields removed for brevity. As you can see, there are two ["order_id"] indices. How is this even possible?

Here is the code that sets the values of the array dumped above:

$v = array();
    foreach ($map as $k => $n) {
    $v[$n] = @$data[$k];
}

with $map being the CSV header row. Trying to reference $v['order_id'] without running the $v['order_id'] = '119205'; line resulted in this error:

Notice:  Undefined index: order_id in /dir/to/php/file/php_file.php</b> on line 29

Manually setting the index worked as expected, pulling the rest of the data from $v without issue.

EDIT:

Dumping the array_keys resulted in:

[0]=>
string(11) "order_id"

and:

[14]=>
string(8) "order_id"

making the first one three characters longer.

var_export still resulted in identical indices.

How can I get rid of these invisible characters? I've already tried $v[trim($n)] = @$data[$k]; in the foreach().

Quentin Skousen
  • 1,035
  • 1
  • 18
  • 30
  • There *are* corner cases in which an associative array with duplicate keys can be created, due to how they work in PHP. – Ignacio Vazquez-Abrams Aug 27 '12 at 23:05
  • your indices may have invisible characters. Try by replacing `var_dump()` with `var_export()`. – Skrol29 Aug 27 '12 at 23:06
  • try `strip_tags()` instead of `trim()` - that should handle cases where NULs are in the string, not just the beginning and the end – ernie Aug 27 '12 at 23:20
  • sadly, `strip_tags()` didn't change anything. – Quentin Skousen Aug 27 '12 at 23:25
  • 1
    maybe they're not NULs . . . if that's the case, [this answer](http://stackoverflow.com/questions/1176904/php-how-to-remove-all-non-printable-characters-in-a-string) should do the trick. It might be interesting to loop through the odd keys and determine what characters are causing you issues - [ord()](http://php.net/manual/en/function.ord.php) would help with that – ernie Aug 27 '12 at 23:31

2 Answers2

3

Try var_dump(array_keys($v)). Find the key that looks like order_id and make sure the string's length is exactly 8. I suspect there may be a NUL character in there, which would give it a length of 9 and cause it to not respond to order_id.

Niet the Dark Absol
  • 320,036
  • 81
  • 464
  • 592
  • I've updated my original question based on your helpful response. – Quentin Skousen Aug 27 '12 at 23:17
  • 2
    To further examine what characters are there, try looping through all characters in the string and outputting their [`ord`](http://php.net/ord) values. This will tell you exactly what extra characters you have and where they are. – Niet the Dark Absol Aug 27 '12 at 23:24
  • Success! Changing the assignment line to `$v[trim($n, chr(239).chr(187).chr(191))] = @$data[$k];` fixed it. However, it's not very pretty... If anyone knows a better way to do this, please let me know. Accepting your answer - Thanks! – Quentin Skousen Aug 27 '12 at 23:40
  • 1
    Ah, I see now. The sequence `239-187-191` is a [Byte Order Mark](http://en.wikipedia.org/wiki/Byte_order_mark). It is there because your file is in UTF-8. You should be able to save the file as UTF-8 without BOM, and that'll solve your problem. – Niet the Dark Absol Aug 27 '12 at 23:43
  • Sadly, I don't have any say in how the file is saved. Is there a way to remove these after the fact? – Quentin Skousen Aug 27 '12 at 23:46
  • If you're using anything like `file_get_contents` before processing the file contents, you could use `str_replace` (or `preg_replace` with a start-of-string anchor) to remove it. – Niet the Dark Absol Aug 27 '12 at 23:48
  • I'm using `fgetcsv()` so that's not an option. However, I moved the `trim()` to just run it once on the first map index, which works the same way as before but without running the `trim()` every loop. Thanks for your help! – Quentin Skousen Aug 28 '12 at 00:01
0

Quote:

In the output of var_dump(), the null bytes are not visible.

Technically you can not have two times the same key in PHP in an array. It might be that var_dump is not giving the right keys here (e.g. probably some null-chars or other non-displayable chars are dropped).

Instead you might want to check, what's going on:

var_dump(array_keys($data));

Maybe it helps, the following is a related question which demonstrates when var_dump hides some information:

Community
  • 1
  • 1
hakre
  • 193,403
  • 52
  • 435
  • 836