Undefined offset while accessing array element which exists - php

I have an array and PHP and when I print it out I can see the values I need to access, but when I try accessing them by their key I am getting a PHP Notice. I printed the array with print_r:
Array
(
[207] => sdf
[210] => sdf
)
When I try to access the array using the index I get an undefined offset notice. Here is my code:
print_r($output);
echo $output[207]; // Undefined Offset
echo $output["207"]; // Undefined Offset
The $output array is the result of a call to array_diff_key and is input originally as JSON through an HTTP POST request.
array_keys gives me the following:
Array
(
[0] => 207
[1] => 210
)
In response to the comments:
var_dump(key($output)); outputs:
string(3) "207"
var_dump(isset($output[key($output)])); outputs:
bool(false)

See this section on converting an object to an array in the PHP Manual:
The keys are the member variable names, with a few notable exceptions: integer properties are unaccessible; private variables have the class name prepended to the variable name; protected variables have a '*' prepended to the variable name.
When converting to an array from an object in PHP, integer array keys are stored internally as strings. When you access array elements in PHP or use an array normally, keys that contain valid integers will be converted to integers automatically. An integer stored internally as a string is an inaccessible key.
Note the difference:
$x = (array)json_decode('{"207":"test"}');
var_dump(key($x)); // string(3) "207"
var_dump($x);
// array(1) {
// ["207"]=>
// string(4) "test"
// }
$y['207'] = 'test';
var_dump(key($y)); // int(207)
var_dump($y);
// array(1) {
// [207]=>
// string(4) "test"
// }
print_r on both those arrays gives identical output, but with var_dump you can see the differences.
Here is some code that reproduces your exact problem:
$output = (array)json_decode('{"207":"sdf","210":"sdf"}');
print_r($output);
echo $output[207];
echo $output["207"];
And the simple fix is to pass in true to json_decode for the optional assoc argument, to specify that you want an array not an object:
$output = json_decode('{"207":"sdf","210":"sdf"}', true);
print_r($output);
echo $output[207];
echo $output["207"];

The problem arises when casting to array an object that has string keys that are valid integers.
If you have this object:
object(stdClass)#1 (2) {
["207"]=>
string(3) "sdf"
["210"]=>
string(3) "sdf"
}
and you cast it with
$array = (array)$object
you get this array
array(2) {
["207"]=>
string(3) "sdf"
["210"]=>
string(3) "sdf"
}
which has keys that can only be accessed by looping through them, since a direct access like $array["207"] will always be converted to $array[207], which does not exist.
Since you are getting an object like the one above from json_decode() applied to a string like
$json = '{"207":"sdf", "210":"sdf"}'
The best solution would be to avoid numeric keys in the first place. These are probably better modelled as numeric properties of an array of objects:
$json = '[{"numAttr":207, "strAttr":"sdf"}, {"numAttr":210, "strAttr":"sdf"}]'
This data structure has several advantages over the present one:
it better reflects the original data, as a collection of objects
which have a numeric property
it is readily extensible with other properties
it is more portable across different systems
(as you see, your current data structure is causing issues in PHP, but if you
should happen to use another language you may easily encounter
similar issues).
If a property → object map is needed, it can be quickly obtained, e.g., like this:
function getNumAttr($obj) { return $obj->numAttr; } // for backward compatibility
$arr = json_decode($json); // where $json = '[{"numAttr":...
$map = array_combine(array_map('getNumAttr', $arr), $arr);
The other solution would be to do as ascii-lime suggested: force json_decode() to output associative arrays instead of objects, by setting its second parameter to true:
$map = json_decode($json, true);
For your input data this produces directly
array(2) {
[207]=>
string(3) "sdf"
[210]=>
string(3) "sdf"
}
Note that the keys of the array are now integers instead of strings.
I would consider changing the JSON data structure a much cleaner solution, though, although I understand that it might not be possible to do so.

I've just found this bug which causes array elements to be inaccessible sometimes in PHP when the array is created by a call to unserialize.
Create a test PHP file containing (or run from the command line) the following script:
<?php
$a = unserialize('a:2:{s:2:"10";i:1;s:2:"01";i:2;}');
print $a['10']."\n";
$a['10'] = 3;
$a['01'] = 4;
print_r($a);
foreach ($a as $k => $v)
{
print 'KEY: ';
var_dump($k);
print 'VAL: ';
var_dump($v);
print "\n";
}
If you get errors you have a version of PHP with this bug in it and I recommend upgrading to PHP 5.3

Try
var_dump($output);
foreach ($output as $key => val) {
var_dump($key);
var_dump($val);
}
to learn more on what is happening.
What exact line/statement is throwing you a warning?

How did you print the array? I would suggest print_r($arrayName);
Next, you can print individual elements like: echo $arrayName[0];

Try use my approach:
class ObjectToArray {
public static function convert( $object ) {
if( !is_object( $object ) && !is_array( $object ) ) {
return $object;
}
if( is_object( $object ) ) {
$object = get_object_vars( $object );
}
return array_map( 'ObjectToArray::convert', $object );
}
}
$aNewArray = ObjectToArray::convert($oYourObject);

Just put error_reporting(0); in you method or at start of file. It will solved your issue.

Related

Can't use JSON array in a php loop

i have a json file, that has to be parsed in a loop.
i cant seem to succeed
JSON:
{"IMD":{"url":"http:\/\/www.google.com","timeOut":1515155361},"cvH":{"url":"http:\/\/www.google.com","timeOut":1515155364}}
PHP:
<?php
$linkyValues="./linky.json";
if (file_exists($linkyValues)) {
$fileStream = fopen($linkyValues, 'r');
$fileValue=json_decode(fread($fileStream, filesize($linkyValues)));
fclose($fileStream);
echo count($fileValue);//Always 1!
for($i=0;$i<count($fileValue);$i++){
$timeout=$fileValue->item($i)->timeOut;
if(time()>=$timeout){
unset($fileValue[$i]);
}
}
$fileStream = fopen($linkyValues, 'w');
fwrite($fileStream, json_encode($fileValue));
fclose($fileStream);
}
?>
my problem is that count($fileValue) is always 1.
Output of var_dump($fileValue):
object(stdClass)#2 (2) {
["IMD"]=>
object(stdClass)#1 (2) {
["url"]=>
string(21) "http://www.google.com"
["timeOut"]=>
int(1515155361)
}
["cvH"]=>
object(stdClass)#3 (2) {
["url"]=>
string(21) "http://www.google.com"
["timeOut"]=>
int(1515155364)
}
}
it looks like an array to me...
JSON does not support the concept of an associative array, but stores such maps as objects instead.
Your JSON file contains such an object. For PHP this means, that it can either import it as an stdClass ( object ) or as an associatiave array.
This is decided by the json_decode's second parameter, that is either TRUE to read the object as an associative array, or FALSE to read it as an object.
Therefore this will fix your problem:
$fileValue = json_decode(fread($fileStream, filesize($linkyValues)), TRUE);
json_decode documentation
In addition to that, your code has problems with iterating the array. You use $fileValue->item($i) as well as $fileValue[$i], while you have an associative array.
You work with it as if it was an indexed array, while it is an associative array, which means it has keys instead of indices, that identify the values in your array.
The propper way to iterate an associative array is with foreach, like deomstrated belo:
foreach($fileValue as $key => $value) {
if (time() >= $value['timeOut']) {
unset($fileValue[$key]);
}
}
Yet, since you only want to remove specific values, you can use array_filter as well:
$fileValue = array_filter($fileValue, function($value){
return time() < $value['timeOut'];
});
array_filter will then take care of removing the specified fields from your array, so you do not have to unset them manually.
You can use :
count((array)$fileValue);
You're mixing up arrays and objects here.
count() can only be used on arrays, however you can cast an object to array to achieve the same thing.
$fileValue[$i] is a method to access an array, which won't work with your json object.
I see a solution already is to just change your object to an array so I'd like to offer the solution if you wanted to stick with objects.
$linkyValues="./linky.json";
if (file_exists($linkyValues)) {
$fileStream = fopen($linkyValues, 'r');
$fileValue=json_decode($jsonString);
fclose($fileStream);
//Cast the object to an array to get the count, but count isn't really requierd
echo count((array)$fileValue);
//loop through the object
foreach($fileValue as $key=>$fv){
//pull the timeout
$timeout=$fv->timeOut;
//do the check
if(time()>=$timeout){
//remove the timeout from the object
unset($fileValue->$key);
}
}
$fileStream = fopen($linkyValues, 'w');
fwrite($fileStream, json_encode($fileValue));
fclose($fileStream);
}
?>

Echo specific item from array [duplicate]

This question already has answers here:
How can I access an array/object?
(6 answers)
Closed 5 years ago.
I want to echo value from this array, so it'll say "true"
::object(stdClass)#25 (2) { ["Name"]=> string(3) "DPV" ["Value"]=> string(4) "true" }
How can I do this in PHP?
assuming the object property of Value is public ( which it is or it wouldn't be output ) you can use PHP's object operator ->
Such as:
echo $obj->Value;
In the case that it isn't public, you would want to use a get menthod, such as this
class obj{
protected $Value = true;
public function getValue(){
return $this->Value;
}
}
$obj = new obj();
echo $obj->getValue();
AS you can see both access the objects property the same basic way ( using the -> ). Which is different then how you access elements in an array. You can implement ArrayAccess on an object, which allows you to use it as if it was an array, but that's a post for another time.
http://php.net/manual/en/class.arrayaccess.php
Simply
<?php
echo $objectVarName->Value;
Note: $objectVarName is not an array, it is an object.
A very common example of arrays in PHP as following:
$array = array(
"foo" => "bar",
"bar" => "foo",
);
Here is simple solution, might be helpful.
<?php
//Let suppose you have this array
$arr = array('id'=>1,'name'=>'alax','status'=>'true');
//Check out array (Basically return array with key and value).
print_r($arr);
// Get value from the particular index
echo "<br/>Your value is:".$arr['status'];
?>

php, json to specific string

By POST I get this JSON (can have more than 3 values in it)
{"preferences":["Theater","Opera","Danse"]}
Well, I need to get
array('Theater', 'Opera', 'Degustation')
json_decode doesn't work.
Do you have any ideas please?
Thank you by advance
Try adding the true parameter:
$jsonData = '{"preferences":["Theater","Opera","Danse"]}';
$arrayData = json_decode($jsonData, true );
var_dump($arrayData['preferences']);
The last line outputs the following:
array(3) {
[0]=>
string(7) "Theater"
[1]=>
string(5) "Opera"
[2]=>
string(5) "Danse"
}
Which is what you want. Good luck!
That JSON string is wrapped in an object (denoted by curly braces {}). json_decode will give you the wrapper object whose "preferences" property is the array you're looking for.
$wrapper = json_decode($json_string);
$array = $wrapper->preferences;
json_decode might also be unavailable if you're using and older version of php. In that case you should try a php json library.
You might have used the output of the json_decode() function as an associated array while you hadn't have told the function to provide an associated array for you, or vice versa!! However, the following will get you the array at the preferences index:
<?php
$decoded = json_decode('{"preferences":["Theater","Opera","Danse"]}', true); // <-- note the second parameter is true.
echo '<pre>';
print_r($decoded['preferences']); // output: Array ( [0] => Theater [1] => Opera [2] => Danse )
// ^^^^^^^^^^^^^^^^^^^^^^^
// Note the usage of the output of the function as an associated array :)
echo '</pre>';
?>

Reading JSON file in PHP

I tried this code
$jsonlogcontents='{"buildings":"townhall","Army":{ "Paladins":{ "325648":0, "546545":4 }, "Knights":{ "325648":-2, "546545":0 } } }';
$phpArray = json_decode($jsonlogcontents, false);
echo $phpArray->buildings;
echo $phpArray->Army;
This is just a sample of my code, the JSON file is too large to include and has sensitive information. The problem I'm having is I can't get the value or print the value of
$phpArray->Army
It give's me an error. I can however print or get the value of
$phpArray->buildings
I'm thinking that when you decode a JSON file/contents in PHP, you can't get/print/store the value of a 'key' that has more set of info (more { and }) or brackets in it. You can only print/get values for keys who's value's contain only 1 value and nothing else.
If this is the case, what can I do to get the contents of the key that has more JSON codes in it. Also, how can I convert the contents of a key that has more JSON info in it into a string? the conversion is so I can display the value of that key to the page or echo it
The error is because Army is an object, and echo doesn't know how to convert it to a string for display. Use:
print_r($phpArray->Army);
or:
var_dump($phpArray->Army);
to see its contents.
P.S. $phpArray not an array but an object.
For Army however, I will need to do another json_decode() for that.
You don't. json_decode() decodes the entire structure in one call, into one large object (or array). No matter how deeply nested the data is, you call json_decode() once and you're done. That's why Army is not a JSON string any more.
When you are adding false as the second parameter to the json_encode it will updating all array to the sdClass empty objects.In this way you can the main array as the object
<?php
$json = '{
"buildings": "townhall",
"Army": {
"Paladins": {
"325648": 0,
"546545": 4
},
"Knights": {
"325648": -2,
"546545": 0
}
}
}';
$array = json_decode($json, true);
$object = (object)$array;
var_dump($object->Army);
?>
OUTPUT
array(2) {
["Paladins"]=>
array(2) {
[325648]=>
int(0)
[546545]=>
int(4)
}
["Knights"]=>
array(2) {
[325648]=>
int(-2)
[546545]=>
int(0)
}
}
Working Demo
It's because the output from your json_decode looks like this:
object(stdClass)(
'buildings' => 'townhall',
'Army' => object(stdClass)(
'Paladins' => object(stdClass)(
325648 => 0,
546545 => 4
),
'Knights' => object(stdClass)(
325648 => -2,
546545 => 0
)
)
)
Army is a standard object so it can't know how to echo it. You can however var_dump it:
var_dump($phpArray->Army);
The easiest solution is to treat it as a normal array with:
$phpArray = json_decode($jsonlogcontents, true);

How to add array to array in PHP

So I thought this would be easy, but try as I might various methods of appending values to an array in PHP, I always get NULL.
$sites = array();
$sites[0] = $_POST['site0'];
foreach($sites as $site) {
var_dump($site);
}
$_POST['site0'] is an HTML form array, containing 11 keys and values. I get a invalid argument error for line 3. Any reason why this would occur?
Probably, $_POST['site0'] is null or empty.
You could push the value to the $sites array doing so:
$sites[] = $_POST['site0'];
The value will be pushed to the end of the array.
It's really work. Just check your
$_POST['site0'];
and try add
$sites[1] = 'spam';
Your code works for me (see codepad):
Code
$_POST['site0'] = 'foobar';
$sites = array();
$sites[0] = $_POST['site0'];
var_dump($sites); // returns NULL
Result
array(1) {
[0]=>
string(6) "foobar"
}
Try to var_dump($_POST); to see what's actually contained in $_POST.

Categories