Array to String conversion on phpredis zScan - php

When using a sorted set and doing a zScan call on it, I get a Notice for Array to String conversion and I do wonder where that comes from. Does anyone have an idea?
This is the code:
$redis = new Redis();
$redis->connect('127.0.0.1');
$redis->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_PHP);
$redis->zAdd('check', 0, array('a'));
$it = NULL;
$redis->zScan('check', $it);
Tried that with Redis::SERIALIZER_IGBINARY too but got the same results. It must be the value set because if I do a $redis->zAdd('check', 0,'a'); everything is fine.
I am using PHP 7.1.12 with php-redis 3.1.4

PHP doesn't allow array keys to be arrays. The following script will cause an illegal offset type error.
<?php
$array = [
['one'] => 0,
['two'] => 1
];
?>
A few phpredis commands "zip" the responses which means the actual Redis reply of [key, value, key, value] is turned into the PHP like associative array [key => value, key => value].
You're running into this problem with zScan as internally when it is attempting to zip the values, PHP is forced to use the value "Array" as an array key cannot be an array.
You would see the same problem if you tried to do this:
$redis->zRange('check', 0, -1, true);
I didn't step through the code but my guess is that the problem happens precisely here.
I don't know anything about what you're trying to build, so it's difficult to say what a proper workaround might be. You can always disable serialization before attempting to execute ZSCAN or ZRANGE WITHSCORES but then you'd need to deal with the serialized data manually.

Related

Undefined offset in array - But I know it's in there

I have an array (or associative array), with keys and values.
Then, when trying to read one of the keys, which IS in the array, I get an "undefined offset" notice.
I have two examples where it happened. One was "exploding" a string like "AAA|BBB|CCC", using | as the separator, then trying to read the resulting array at position 1.
var_dump() correctly shows an array having offsets 0 to 2, with the correct values. But I still get the notice.
Another example is I get an array (from an AJAX call, I json_decode it, etc), then I typed the following code:
foreach (array_keys($myDecodedArray) as $k) {
$value = $myDecodedArray[$k];
someOtherCode();
}
I had that damn notice appear when trying to read $myDecodedArray[$k], although php itself had just told me the key existed !
So, I solved that last case by going
foreach ($myDecodedArray as $k => $value) {
someOtherCode();
}
but still, this is extremely annoying, and makes no sense to me.
Any of you run into that problem before?
Do you have any information about what could cause that?
[EDIT]
Rahul Meshram's suggestion (which I upvoted in the comments) solved my second problem case.
However, the first case still happens (exploding a string into an array, then trying to access that array's values by their numeric keys).
The keys ARE numeric (gettype returns 'integer', var_dump on that key shows an integer too, with the right value), but trying to access $explodedArray[1] still results in that notice being displayed, despite $explodedArray having keys 0, 1, and 2, with associated values.

filter_var_array with floats causes too many decimal places in result

I have a problem with the filter_var_array function, in particular with the 'FILTER_VALIDATE_FLOAT' flag, which returns me floats with way too many decimal places
Code first:
if (property_exists($this->rawRequest, $varName)) {
$res = filter_var_array($this->rawRequest->$varName, FILTER_VALIDATE_FLOAT);
}
This is my code, where I validate parameters that I received from a client via JSON
The rawRequest is a stdClass, like the following (printed with var_export):
stdClass::__set_state(
array(
'Action' => 'CreateObject',
'Template' => 'none',
'LatLng' => array (
0 => '48.14914653539144',
1 => '11.577623201171932',
)
)
After the 'LatLng' parameter was filtered with filter_var_array, the result looks like the following:
'LatLng' => array (
0 => 48.149146535391433732957206666469573974609375,
1 => 11.5776232011719315551090403459966182708740234375,
)
Why does this happen?
I even can not fix this with round(), typecasting to float, to string and back to float, I tried to subtract 0.00000001 and then adding 0.00000001 again, nothing helps
UPDATE:
I wrote following little test script on the same machine, same apache server:
<?php
$test = '48.158308230848306';
$test2 = (float) $test;
$test3 = floatval($test);
echo($test2);
echo('<br />');
echo($test3);
exit(0);
output is here:
48.158308230848
48.158308230848
THAT is what I expect
I retested it with my prod code and used floatval() and typecasting to float, but it DID NOT work. I don't know, the only difference is that in the prod code the input comes as json and I parse it with the following code:
json_decode(file_get_contents('php://input'))
So, I finally found the answer to my problem
The problem was never the filter_var_array() function, actually, the problem occurred far earlier.
After retrieving the POST parameters via file_get_contents("php://input") everything is still fine.
But when I decode the returned string with json_decode(), the float values are serialized in this process, resulting in the higher precision.
I found two ways to "solve" this:
Change the "serialize_precision" parameter in the php.ini (mine was per default 100, setting it to the same as my "precision" parameter was successful)
I DO NOT RECOMMEND this approach, since the effects of changing this parameter might be devastating somewhere else
Enclose the float in the request in quotes
So change in your JSON {"test": 48.58495135846} to {"test": "48.58495135846"}
This prevents the serialization of the float, as it is effectively a string now
Hope this helps someone else, maybe this is already common knowledge, but I was tearing my hair out about this.

presumed difference in php versions causing difference in JSON output - quotes around integers

I have a testing server with PHP version 5.5.9, and we have a QA server with PHP version 5.6.16.
I am for the sake of this post using the same code branch on both instances (full disclosure: it's a Laravel install but I'm not sure this is a Laravel issue)
On the QA server, an API returns JSON with the integers unquoted as follows (this is simplified):
{["id":1,"name":"John"],["id":2,"name":"Sam"]}
But on my server (the 5.6.16 one), the same exact API call returns:
{["id":"1","name":"John"],["id":"2","name":"Sam"]}
And, Angular is not liking that and does not parse it.
It's not the data
The data and tables the data is coming from are exactly alike in structure - I have verified this.
I don't want to "fix" Angular
Though in theory Angular should handle this(?), I don't want to touch our coding for the front end.
I want the output to be the same..
Regardless of what Angular is doing, the obvious solution is to have the outputs be exactly equal.
What do I do?
I want to avoid upgrading PHP on my server - that might open up more problems
I am thinking that there is a setting in json_encode() which can be set to change this but I do not know which one.
Also there may be a setting in laravel itself which could be at least locally changed on my end. For the record there are well over 100+ json_encode calls in the codebase.
Its not an issue in json_encode() it is what you are encoding that makes a difference. See this simple example
$a = array(
'id' => 111,
'astring' => 'test',
'OhLookItsANumberRecordedAsAString' => '456'
);
$json = json_encode($a);
echo $json;
Result
{"id":111,
"astring":"test",
"OhLookItsANumberRecordedAsAString":"456"
}
But if you make sure the integers are integers all is as you expect
$a = array(
'id' => 111,
'astring' => 'test',
'OhLookItsANumberRecordedAsAString' => '456',
'ANumber' => (int)'456'
);
$json = json_encode($a);
echo $json;
Result
{"id":111,
"astring":"test",
"OhLookItsANumberRecordedAsAString":"456",
"ANumber":456
}
As #RiggsFolly it definitely depends on how the source is providing the integer data. If the numbers are quoted from source, json_decoder treats them as a string.
Something you can try: json_encode as a 2nd parameter called $options. Set it to attempt to encode numbers as integers rather than strings.
http://php.net/manual/en/function.json-encode.php
PHP json_encode encoding numbers as strings

array_keys error while running artisan basset

I am receiving the proceeding error exception when I run php artisan basset --tidy-up from the command line.
[ErrorException]
array_keys() expects parameter 1 to be array, object given
basset [--delete-manifest] [--tidy-up]
I was unfortunate in finding any details online.
Although I've not used Basset, the reason for this error is that you are passing in an object, rather than an array, for the first argument of array_keys.
For example, were I to have an array as follows:
$myGreatArray = array('first' => 'foo', 'bar' => 'sup');
And then pass it in to array keys:
print_r(array_keys($myGreatArray));
I'd get this as the output:
Array
(
[0] => first
[1] => bar
)
However, I can't do the same thing with an object, even if it's structured the same way.
In other words, we can't do something like this (and not just because you need to var_dump objects, but also because you need to pass in arrays to array_keys()):
$myGreatArray = new stdClass;
$myGreatArray->first = 'foo';
$myGreatArray->bar = 'sup';
print_r(array_keys($myGreatArray));
You'll get an error similar to what you're seeing, although what you're seeing appears to be in a format of an exception handled by Basset. You can also see it when running a script from other than the command line, depending on your level of error reporting.
Edit:
I just pulled up the source for Basset's command line script, and it looks like you're getting the error on line 120, which reads as follows:
$collections = array_keys($this->environment->all()) + array_keys($this->manifest->all());
You might want to check the way your manifest and environment are structured.

Problem with json_encode()

i have an simple array:
array
0 => string 'Kum' (length=3)
1 => string 'Kumpel' (length=6)
when I encode the array using json_encode(), i get following:
["Kum","Kumpel"]
My question is, what is the reason to get ["Kum","Kumpel"] instead of { "0" : "Kum", "1" : "Kumpel" }?
"{}" brackets specify an object and "[]" are used for arrays according to JSON specification. Arrays don't have enumeration, if you look at it from memory allocation perspective. It's just data followed by more data, objects from other hand have properties with names and the data is assigned to the properties, therefore to encode such object you must also pass the correct property names. But for array you don't need to specify the indexes, because they always will be 0..n, where n is the length of the array - 1, the only thing that matters is the order of data.
$array = array("a","b","c");
json_encode($array); // ["a","b","c"]
json_encode($array, JSON_FORCE_OBJECT); // {"0":"a", "1":"b","2":"c"}
The reason why JSON_FORCE_OBJECT foces it to use "0,1,2" is because to assign data to obeject you must assign it to a property, since no property names are given by developer (only the data) the encoder uses array indexes as property names, because those are the only names which would make sense.
Note: according to PHP manual the options parameters are only available from PHP 5.3.
For older PHP versions refer to chelmertz's answer for a way to make json_encode to use indexes.
As Gumbo said, on the JS-side it won't matter. To force PHP into it, try this:
$a = new stdClass();
$a->{0} = "Kum";
$a->{1} = "Kumpel";
echo json_encode($a);
Not that usable, I'd stick with the array notation.
Just cast as an object and it will work fine...the JSON_FORCE_OBJECT parameter does exactly the same thing.
json_encode((object)$array);
Don't forget to convert it back into a php array so you can access its values in php:
$array = (object)$array;
$array = (array)$array;
json_encode($array);
Since you’re having a PHP array with just numeric keys, there is no need to use a JavaScript object. But if you need one, try Maiku Mori’s suggestion.
I personally think this is a bug that needs to be fixed in PHP. JSON_FORCE_OBJECT is absolutely not an answer. If you try to do any sort of generic programming you get tripped up constantly. For example, the following is valid PHP:
array("0" => array(0,1,2,3), "1" => array(4,5,6,7));
And should be converted to
{"0": [0,1,2,3], "1": [4,5,6,7]}
Yet PHP expects me to either accept
[[0,1,2,3],[4,5,6,7]]
or
{"0":{"0":1,"1":1,"2":2,"3":3},"1":{"0":4,"1":5,"2":6,"3":7}}
Neither of which are right at all. How can I possibly decode an object like that? What possible reason is there to ever change something that is clearly using strings as indexes? It's like PHP was trying to be clever to help out idiotic people who can't differentiate strings from ints, but in the process messed up anyone legitimately using strings as indexes, regardless of what the value COULD be turned into.

Categories