I am trying to deal with some input that may or may not be an array, with the intent of obtaining the first item if the input is an array, and the item itself otherwise.
Here is how I was planning to go about it:
$payload = ((array)json_decode($mapOrArray))[0];
This did not sit well with the interpreter, however. Instead, I am currently using this:
$payload = array_values((array)json_decode($mapOrArray))[0];
Only once I've wrapped the casted array in a useless method call can I use this approach.
Is accessing an index of the result of a cast impossible with a single statement? If so, what is a better way to deal with this task, preferably without introducing an extraneous variable?
list($payload) = (array) json_decode($mapOrArray);
Related
So... I need to save a large-ish amount of data from a platform with an excruciatingly limited amount of memory.
Because of this, I'm basically storing the data on my webserver, using a php script to just write JSON to a flat file, because I'm lazy af.
I could go to the trouble of having it store the data in my mysql server, but frankly the flat file thing should have been trivial, but I've run up against a problem. There are several quick and dirty workarounds that would fix it, but I've been trying to fix it the "right" way (I know, I know, the right way would be to just store the data in mysql, but I actually need to be able to take the json file this produces and send it back to the platform that needs the data (In a ridiculously roundabout fashion), so it made sense to just have the php save it as a flat file in the first place. And It's already working, aside from this one issue, so I hate to reimpliment.
See... Because of the low memory on the platform I'm sending the json to my server from... I'm sending things one field at a time. Each call to the php script is only setting ONE field.
So basically what I'm doing is loading the file from disk if it exists, and running it through json_decode to get my storage object, and then the php file gets a key argument and a value argument, and if the key is something like "object1,object2", it explodes that, gets the length of the resulting array, and then stores the value in $data->$key[0]->$key[1].
Then it's saved back to disk with fwrite($file, json_encode($data));
This is all working perfectly. Except when $value is a simple string. If it's an array, it works perfectly. If it's a number, it works fine. If it's a string, I get null from json_decode. I have tried every way I can think of to force quotes on to the ends of the $value variable in the hopes of getting json_decode to recognize it. Nothing works.
I've tried setting $data->$key[0]->$key[1] = $value in cases where value is a string, and not an array or number. No dice, php just complains that I'm trying to set an object that doesn't exist. It's fine if I'm using the output of json_decode to set the field, but it simply will not accept a string on its own.
So I have no idea.
Does anyone know how I can either get json_decode to not choke on a string that's just a string, or add a new field to an existing php object without using the output of json_decode?
I'm sure there's something obvious I'm missing. It should be clear I'm no php guru. I've never really used arrays and objects in php, so their vagaries are not something I'm familiar with.
Solutions I'm already aware of, but would prefer to avoid, are: I could have the platform that's sending the post requests wrap single, non-numeric values with square braces, creating a single item array, but this shouldn't be necessary, as far as I'm aware, so doing this bothers me (And ends up costing me something like half a kilobyte of storage that shouldn't need to be used).
I could also change some of my json from objects to arrays in order to get php to let me add items more readily, but it seems like there should be a solution that doesn't require that, so I'd really prefer not to...
I skim through your post.
And I know this works for StdClass :
$yourClass->newField = $string;
Is this what you wanted ?
OK so... ultimately, as succinctly as possible, the problem was this:
Assuming we have this JSON in $data:
{
"key1":
{
"key2":["somedata","someotherdata"]
}
}
And we want it to be:
{
"key1":
{
"key2":["somedata","someotherdata"],
"key3":"key3data"
}
}
The php script has received "key=key1,key3&value=key3data" as its post data, and is initialized thusly:
$key = $_POST["key"];
$key = explode($key,",");
$value = $_POST["value"];
...which provides us with an array ($key) representing the nested json key we want to set as a field, and a variable ($value) holding the value we want to set it to.
Approach #1:
$data->$key[0]->$key[1] = json_decode($value);
...fails. It creates this JSON when we re-encode $data:
{
"key1":
{
"key2":["somedata","someotherdata"],
"key3":null
}
}
Approach #2:
$data->$key[0]->$key[1] = $value;
...also fails. It fails to insert the field into $data at all.
But then I realized... the problem with #2 is that it won't let me set the nonexistent field, and the problem with approach #1 is that it sets the field wrong.
So all I have to do is brute force it thusly:
$data->$key[0]->$key[1] = json_decode($value);
if (json_decode($value) == NULL)
{
$data->$key[0]->$key[1] = $value;
}
This works! Since Approach #1 has created the field (Albeit with the incorrect value), PHP now allows me to set the value of that field without complaint.
It's a very brute force sort of means of fixing the problem, and I'm sure there are better ones, if I understood PHP objects better. But this works, so at least I have my code working.
stricly speaking / best practice: do I need to set up every 'deeper nested sub array' or can you just access it?
//so do I need to do this:
if(!isset($multiArray[$newKey])) $multiArray[$newKey] = array();
//before I can do this?
$multiArray[$newKey][] = 'somevalue';
Strictly speaking no, PHP will create the new array before pushing the value to it, without any problem.
Best practice? It's probably personal opinion based, I would say create the array first for readability and it makes sense logically. If another developer picks up your code, it might not be obvious that you are creating a new array, as opposed to pushing to an existing array.
It is not necessary to initialize variables in PHP however it is a very good practice. Uninitialized variables have a default value of their type depending on the context in which they are used - booleans default to FALSE, integers and floats default to zero, strings (e.g. used in echo) are set as an empty string and arrays become to an empty array.
Source : PHP Manual http://fr2.php.net/manual/en/function.array-multisort.php
What would you say is the most efficient way to get a single value out of an Array. I know what it is, I know where it is. Currently I'm doing it with:
$array = unserialize($storedArray);
$var = $array['keyOne'];
Wondering if there is a better way.
You are doing it fine, I can't think of a better way than what you are doing.
You unserialize
You get an array
You get value by specifying index
That's the way it can be done.
Wondering if there is a better way.
For the example you give with the array, I think you're fine.
If the serialized string contains data and objects you don't want to unserialize (e.g. creating objects you really don't want to have), you can use the Serialized PHP library which is a complete parser for serialized data.
It offers low-level access to serialized data statically, so you can only extract a subset of data and/or manipulate the serialized data w/o unserializing it. However that looks too much for your example as you only have an array and you don't need to filter/differ too much I guess.
Its most efficient way you can do, unserialize and get data, if you need optimize dont store all variables serialized.
Also there is always way to parse it with regexp :)
If you dont want to unseralize the whole thing (which can be costly, especially for more complex objects), you can just do a strpos and look for the features you want and extract them
Sure.
If you need a better way - DO NOT USE serialized arrays.
Serialization is just a transport format, of VERY limited use.
If you need some optimized variant - there are hundreds of them.
For example, you can pass some single scalar variable instead of whole array. And access it immediately
I, too, think the right way is to un-serialize.
But another way could be to use string operations, when you know what you want from the array:
$storedArray = 'a:2:{s:4:"test";s:2:"ja";s:6:"keyOne";i:5;}';
# another: a:2:{s:4:"test";s:2:"ja";s:6:"keyOne";s:3:"sdf";}
$split = explode('keyOne', $storedArray, 2);
# $split[1] contains the value and junk before and after the value
$splitagain = explode(';', $split[1], 3);
# $splitagain[1] should be the value with type information
$value = array_pop(explode(':', $splitagain[1], 3));
# $value contains the value
Now, someone up for a benchmark? ;)
Another way might be RegEx ?
I have a string. It's a user submitted string. (And you should never ever trust user submitted anything.)
If certain (not unsafe) characters exist in the string, it's supposed to become a multi dimensional array/tree. First I tried splits, regex and loops. Too difficult. I've found a very easy solution with a few simple str_replace's and the result is a string that looks like an array definition. Eg:
array('body', array('div', array('x'), array(), array('')), array(array('oele')))
It's a silly array, but it's very easily created. Now that string has to become that array. I'm using eval() for that and I don't like it. Since it's user submitted (and must be able to contain just about anything), there could be any sort of function calls in that string.
So the million dollar question: is there some kind of var_import, or array_import that creates an array from a string and does nothing else (like mysterious, dangerous calls to exec etc)?
Yes, I have tried php.net and neither of the above _import functions exist.
What I'm looking for is the exact opposite of var_import, becasuse the string I have as input, looks exactly like the string var_export would output.
Any other suggestions to make it safer then eval are also welcome! But I'm not abandoning the current method (it's just too simple).
Using
array('body', array('div', array('x'), array(), array('')), array(array('oele')))
as input, I replaced some chars to make it a valid JSON string and imported that via json_decode.
Works perfectly. If some illegal chars are present, json_decode will trip over them (and not execute any dangerous code).
After hours of debugging, I found an error in one of my scripts. For saving different event types in a database, I have an array of unique data for each event that can be used to identify the event.
So I basically have some code like
$key = md5(json_encode($data));
to generate a unique key for each event.
Now, in some cases, a value in the $data array is an integer, sometimes a string (depending on where it comes from - database or URL). That causes the outputs of json_encode() to be different from each other, though - once including quotes, once not.
Does anybody know a way to "unify" the variable types in the $data array? That would probably mean converting all strings that only contain an integer value to integer. Anything else I have to take care of when using json_encode()?
array_walk_recursive combined with a function you have written to the effect of maybe_intval which performs the conversion you talk about on a single element.
EDIT: having read the documentation for array_walk_recursive more closely you'll actually want to write your own recursive function
function to_json($obj){
if(is_object($obj))
$obj=(array)$obj;
if(is_array($obj))
return array_map('to_json',$obj);
return "$obj"; // or return is_int($obj)?intval($obj):$obj;
}