PHP serializing array as object in JSON [duplicate] - php

This question already has an answer here:
Array after array_unique function is returned as an object in JSON response [duplicate]
(1 answer)
Closed 3 years ago.
I'm trying to call a REST endpoint that is expecting an object with an array 'campaigns' and a boolean 'getChildren'.
The issue is that the array is sometimes serialized as an object instead of an array.
The incorrect request I'm getting :
{
"campaigns":
{
"1":"1006352",
"2":"1006347",
"3":"1006350",
"4":"1006349",
"5":"1006348",
"6":"1006345",
"7":"1006344",
"8":"1006343"
},
"getChildren":false
}
What I want (and that I get sometimes) :
{
"campaigns":["1006351","1006346"],
"getChildren":false
}
Here is my code :
$campaignIds = array_map(function ($item) use ($networkIds) {
return $item->nid;
},
array_filter($items, function ($item) use ($networkIds) {
return empty((int)$item->nb_shared);
}));
$consoWithoutChildren = EndpointClient::getConsumptionByCampaign($networkIds, $campaignIds);
I want the 'campaigns' parameter to be always interpreted as an array.
I tried json_encode() but it escapes the array, causing issues in the use cases where I had valid JSON, like that :
{"campaigns":"[\"1006351\",\"1006346\"]","getChildren":false}
Any idea what is wrong ?

array_filter keeps the index of the array elements.
So if the first element of your array does not fulfill the condition of your array_filter, you have no element at the 0 index.
To be serialized properly, the array must not have null values in it.
The solution is to reassign the array elements to 0 to n index, with array_values().
Like this :
// array_values is needed to have arrays' indices beginning at 0.
// If not, the JSON parsing would consider the array an object.
// Like {"campaigns":{"1":"1006352","2":"1006347"}}
$campaignIds = array_values(
array_map(
function ($item) use ($networkIds) {
return $item->nid;
},
array_filter(
$items,
function ($item) use ($networkIds) {
return empty((int)$item->nb_shared);
}
)
)
);
$consoWithoutChildren = EndpointClient::getConsumptionByCampaign($networkIds, $campaignIds);

Related

Php filter object by key who contains a string [duplicate]

This question already has answers here:
Filter array to retain all elements that have a key containing a searched string
(3 answers)
Closed last year.
I'm not familiar with PHP and i met a problem to filter an object of array.
I have a function (get_post_meta_for_api) who return me an object of array but there're a lot of properties that i don't need ...
So i'd like to filter my object by key who contains "seopress"
function get_post_meta_for_api( $object ) {
$post_id = $object['id'];
return get_post_meta( $post_id );
}
Thanks in advance for your help :)
As per documentation, get_post_meta returns an array (https://developer.wordpress.org/reference/functions/get_post_meta/),
this should work:
function get_post_meta_for_api( $object ) {
return array_filter(
get_post_meta($object['id']),
function ($key) {
return preg_match('/_seopress_*/', $key) === 1;
},
ARRAY_FILTER_USE_KEY
);
}
Check get_post_meta for more information about how to use it.
get_post_meta comes with the option to retrieve a single meta value. Here's an example, using the meta value that you want to get.
get_post_meta($post_id, 'seopress', true);
The first argument is the post id, second is the meta key, third is if you want a single value.
get_post_meta without true in the third argument will return an array containing the value, with true it will return the value as is.

Extract particular array from multidimensional array

I have a JSON array of data that I am trying to extract particular value/keys(?) from, and would like to add them into a new array.
The array looks like this:
{ "total':2000,
"achievements":[
{
"id":6,
"achievement":{},
"criteria":{
"id":2050,
"is_completed":false
},
"completed_timestamp":1224053510000
},
{
"id":8,
"achievement":{},
"criteria":{
"id":1289,
"is_completed":true
},
"completed_timestamp":0000000
}
]
}
I want to search for true in the is_completed, and then add the id from that array into a new array.
Basically, find the id's of all the key/array (sorry unsure of terminology) where is_completed is true.
I've tried something simple like finding trying to find the key of an ID, but struggling to get that to work. And also seen some of the multi-level for loop examples but can't get them to work for my data.
Example:
$key = array_search('1289', array_column($array, 'id'));
As pointed out in the comments, you could combine array_filter (to filter completed events) and array_column (to extract their IDs).
$completedAchievements = array_filter(
$array->achievements,
static function (\stdClass $achievement): bool {
return $achievement->criteria->is_completed === true;
}
);
$completedAchievementsIds = array_column($completedAchievements, 'id');
print_r($completedAchievementsIds); // Array([0] => 8)
Note: the code above supposes your JSON was decoded as an object. If it was decoded as an array, just replace -> syntax with the corresponding array index access.
Demo

htmlspecialchar on HTML POST to PHP script with array and single inputs

I have an HTML form that uses POST to send data to a PHP script. Until now I have not used an array in an HTML form, but this form calls for some fields to be grouped (e.g., price and qty) while other fields remain single input fields (name, email, etc).
I would like to sanitize the input when it is received by the PHP script. With single input fields, I used to loop through the fields like this:
if( !empty($_POST) ) {
foreach( $_POST as $x => $y ) {
$_POST[$x] = htmlspecialchars($y);
$_POST[$x] = trim($y);
}
}
How can I sanitize the input when some of the items are in an array?
Modifying all of the leaf nodes in your multidimensional array is easily done with the native function array_walk_recursive() because it visits all of the "leaf nodes" by design.
Code: (Demo) (or as an anonymous one-liner)
$sweet = ['a' => 'apple ', 'b' => ' "banana" '];
$array = ['sweet' => $sweet, 'test' => " <a href='test'>Test</a>"];
function mySanitizer(&$value) {
$value = htmlspecialchars(trim($value));
}
array_walk_recursive($array, 'mySanitizer');
var_export($array);
Output:
array (
'sweet' =>
array (
'a' => 'apple',
'b' => '"banana"',
),
'test' => '<a href=\'test\'>Test</a>',
)
Notice the use of & on the value parameter. This tells the script to modify the data by reference -- otherwise no changes would persist outside of the scope of array_walk_recursive
How to apply this technique...
To apply this technique to all elements in the $_POST superglobal array, call:
array_walk_recursive($_POST, 'mySanitizer');
Of course, this requires you to write the custom function declaration (function mySanitizer() {...}).
Alternatively, if you don't wish to declare the custom function mySanitizer, then this is all you need to write:
array_walk_recursive($_POST, function(&$value){
$value = htmlspecialchars(trim($value));
});
It is more commonplace to have a return value from most functions, however array_walk_recursive() does not offer return data. For this function to be effective for your requirements, the input array must be directly affected by the custom function that it contains. "Modifying a variable by reference" means that you don't need to overwrite the $_POST variable by assignment (like $_POST = ...). Simply by feeding the input array into the native function, writing & before the $value parameter, then overwriting each encountered $value while iterating, your $_POST variable will be sanitized.
As for how array_walk_recursive() "iterates/loops"... there is a special behavior to enjoy. The function will traverse every level of your array. If it finds an "iterable" element, it will loop through the elements that it contains. If it encounters a non-iterable element (scalar elements might be a string, integer, float, boolean, null) it will execute a function / callback (whatever you command it to) on it.
Another example of a php function that modifies by reference is sort(). You don't make an assignment with this function, you just pass your data through it and when you next access the variable's data, it is already modified.
You need to create a recursive function for this.
function htmlentitiesRecursive($data)
{
if (is_array($data)) {
// If the data is an array, iterate through it and convert each item
foreach ($data as $key => $value) {
$data[$key] = htmlentitiesRecursive($value);
}
return $data;
}
// If the data is a string, convert it into html entities
return is_string($data)
? htmlentities(trim($data))
: $data;
}
Usage:
$_POST = htmlentitiesRecursive($_POST);

Extract elements from stdClass in PHP dynamically

I have stdClass returned from Laravel ORM result which looks like below,
I know I can access the value using $object->Tables_in_questip3_qgen, but "Tables_in_questip3_qgen" is dynamic. This can change to any string and I would like to extract values only from first element. I would like to have only adj_table,admin_fi and admin_fi_acount values across rows.
In Laravel 5+ you can do this:
collect($object)->map(function ($v) {
return head((array)$v);
});
To get a subarray of arbitrary items (by the order they appear):
$indices = [ 0, 1 ];
collect($object)->map(function ($v) use ($indices) {
$inner = collect($v)->values();
return $inner->only($indices); //This will return the requested indices as a collection, but you can realistically do whatever you want with them like e.g. ->implode or ->toArray
});

How to filter empty key/value pairs from a $_POST array?

I am trying to create php array (associative) declaration for non-empty key-value pairs only, which I am getting from $_POST. Any guesses, how to do this ?
$my_array = [
"k1"=>"$val1",
"k2"=>"$val2",
"k3"=>"$val3",
"k4"=>"$val4"
];
But, if $val4 & $val3 are empty / NULL / does'nt exist, then :
$my_array = [
"k1"=>"$val1",
"k2"=>"$val2"
];
Thanks
As others mentioned you can use array filter,
if you dont want values of 0 being treated as empty you can do something like this
$post = array_filter( $_POST, function( $item ){ return strlen( $item ); });
Array filter will treat 0, '', false, null and I think '0' and possibly some others all as empty. You can use a callback, such as my example. When the call back returns false 0 the item is removed when it returns true ( or > 0 ) it is retained. So strlen will return a value equal to the length of the string and any strings of 0 length are then removed.
-note- this should be fine on $_POST because it's generally not going to have any nested arrays, but if there are nested arrays then strlen will obviously not work on an array ( being this $item = array() in the callback ).
$_POST is already an associative array. For example, with a form, the key is the element 'name' and the value is the user's input. Empty inputs will still generate a key/value pair but you can easily filter these with array_filter()
EDIT:
Here is an example implementation:
array_filter($array, function(x) {
if is_null(x) return false;
else return true;
});
You can write a function to check null or empty values like this:
<?php
function transform(&$data) {
foreach(array_keys($data) as $key) {
if( is_null($data[$key])
|| empty($data[$key])
) {
unset($data[$key]);
}
}
}
// usage
$data = [
"example1" => 5,
"example2" => "some text",
"example3" => null,
"example4" => [],
];
transform($data);
print_r($data);
?>
Example output of print_r() :
Array
(
[example1] => 5
[example2] => some text
)

Categories