Semi-advanced PHP array - php

So I'm new to Arrays, but I think this should be fairly easy, I just can't wrap my head around it.
I've got an array, that can have a varying amount of keys in it, based on how much input is given by the user.
$array = MY_Class( array(
'type' => 'representatives',
'show_this_many' => '10'
));
easy enough, right?
but I've got 1-4 more keys that could be in it, based on user input. They fill out a form on the first page, and it submits to the second page (which contains the array above).
I need to grab City, State, First, last, based on how many fields the user fills out on the previous page. I can't have blank ones so
$array = MY_Class( array(
'type' => 'representatives',
'show_this_many' => '10',
'city' => '',
'state' => '',
'first' => $_GET['first']
));
won't really work. I need a way to determine which fields have been submitted (preferrably via GET) and build the array that way. so can end up with
$array = MY_Class( array(
'type' => 'representatives',
'show_this_many' => '10',
'state' => $_GET['state'],
'first' => $_GET['first']
));
because state and first had a value while city and last did not.
The first thing that came to mind was something like
$array = MY_Class( array(
'type' => 'representatives',
'show_this_many' => '10',
$constants => $variables
));
//where
$constants = array( //_GET stuff values );
$variables = array( //_GET stuff with values );
// magic method to make it like
// CONSTANTS[0] => VARIABLES[0];
// CONSTANTS[1] => VARIABLES[1];
// so everything is lined up
but I'm not sure how to do it :/

You will want to use a whitelist of possible keys from $_GET so your array doesn't get polluted with spurious (or possibly malicious) keys, and then you can simply append them onto your array with a loop over $_GET.
// Your array is already initialized with some values:
$array = array(
'type' => 'representatives',
'show_this_many' => '10'
);
// Allowed GET keys
$allowed = array('city','state','first');
// Loop over get and add the keys (if allowed)
foreach ($_GET as $key => $value) {
// If the key is allowed and the value isn't blank...
if (in_array($allowed, $key) && !empty($value)) {
$array[$key] = $value;
}
}
// See all the newly added keys...
var_dump($array);
Another option is to just add all the keys to the array, then call array_filter() to remove the blanks.
$array = array(
'type' => 'representatives',
'show_this_many' => '10',
'city' => '',
'state' => '',
'first' => ''
);
// Add values from $_GET, then filter it
$array = array_filter($array, function($val) {
return $val !== '' && !is_null($val);
});

Try the below code
$array = array(
'type' => 'representatives',
'show_this_many' => '10'
);
$fields = array ('city', 'state', 'first');
foreach ($fields as $field) {
if (!empty($_GET[$field])) {
$array[$field] = $_GET[$field]
}
}

Related

How to linearize a JSON and make it part of the initial array

I have an array like the following:
array(
'session_id' => 'ea29e7ae5c976794896b4c256f455dd5',
'user_identifier' => "{'user_id':87,'username':'some username','email':'someuseremail.com','first_name':'Some','last_name':'User','company':'Company'}",
'request_uri' => '/'
);
And I would like to convert it to the following:
array(
'session_id' => 'ea29e7ae5c976794896b4c256f455dd5',
'user_id' => 87,
'username' => 'some username',
'email' => 'someuseremail.com',
'first_name' => 'Some',
'last_name' => 'User',
'company' => 'Company',
'request_uri' => '/'
);
Which means I am decoding the JSON at user_identifier key and I am making part of the initial array $original and then I am removing the user_identifier key.
So far this is what I have done:
foreach ($original as $key => $log) {
$original[$key] = (array) $log;
}
foreach ($original as $key => $log) {
foreach($log as $k => $v) {
if ($k === 'user_identifier') {
$original['decoded'] = (array) json_decode($v);
}
}
}
Which is giving me an array like this one:
array(
'session_id' => 'ea29e7ae5c976794896b4c256f455dd5',
'request_uri' => '/',
'user_identifier' => "{'user_id':87,'username':'some username','email':'someuseremail.com','first_name':'Some','last_name':'User','company':'Company'}",
'decoded' => array(
'user_id' => 87,
'username' => 'some username',
'email' => 'someuseremail.com',
'first_name' => 'Some',
'last_name' => 'User',
'company' => 'Company'
)
);
As you may notice this is not even the array I am looking for and I have already one foreach loop to convert the initial result to an array - it's coming as and stdClass object - and then a nested foreach loop for decode the JSON and try to make it part of the initial array.
In such case I will need to add another loop to linearize the array. My concern is this array is just an example but the one I need to convert is a big one.
Is there any better way to achieve this?
I am using PHP 5.3.3
I would do it like this:
Extract the JSON from the original into an array. (Be sure to set the second argument of json_decode so you end up with an array instead of an object.)
$identifier = json_decode($your_array['user_identifier'], true);
merge the extracted array with the original.
$your_array = array_merge($your_array, $identifier);
Unset the now-redundant JSON
unset($your_array['user_identifier']);

Add and modify value in a deep nested mixed array

Let's say you have an array like this:
$list = array(
'name' => 'foobar',
'id' => '12302',
'group' => array(array(
'name' => 'teamA',
'members' => array(
array(
'ID' => 'OAHSJLASJ8888'
'name' => 'eric',
'fname' => 'lu',
'age' => '22'
),
array(
'ID' => 'OKZ8JJLJYYH6'
'name' => 'franz',
'fname' => 'as',
'age' => '33'
),
array(
'ID' => 'OKOIYHJKKK'
'name' => 'Amr',
'fname' => 'ok',
'age' => '13'
)
)
),
array(
'name' => 'teamB',
'members' => array(
array(
'ID' => 'FGZ9ILKA'
'name' => 'Evan',
'fname' => 'lu',
'age' => '22'
),
array(
'ID' => 'KMLML2039KKK'
'name' => 'Michel',
'fname' => 'as',
'age' => '33'
),
array(
'ID' => 'AAA2039KKK'
'name' => 'Nickr',
'fname' => 'ok',
'age' => '13'
)
)
)
)
);
You want to add a value to the associative array named Amr which is the third element of the member key of the group key $list[group][0][members][2][newKey] = B
Using recursive function and foreach, I'm able to find anything I'm aiming at. Using array_walk_recursive I can also find the targeted key value and modify it.
Using RecursiveIteratorIterator and foreach, I can also find the element and modify it's value.
My issue is that I can not replace the modified object within the tree. I can follow the path down, but I'm not able to climb the tree back. I could maintain a index of each array I traverse and then recalculate the path to the key, but it looks culprit to me.
I can not modify the data structure, the dataset I have is as is.
Thanks for any help you could bring.
Code for Iterator:
$iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($list));
foreach($iterator as $key=>$value) {
if ($key === 'ID') {
$metas = get_relatedmeta_objects($value),true));
//metas key should be added to the current array
}
}
Recursive method:
function searchKeyAndAdd( &$element) {
if(is_array($element) || is_object($element)){
foreach ( $element as &$key => $value ) {
if ($key === "ID") {
$metas = get_relatedmeta_objects($value);
//metas key should be added to the current array
} else if (is_array($value)) {
searchObject($value);
}
}
}
}
array_walk_recursive method:
function alterArray(&$item, $key, &$parentRec) {
if (is_array($item) || is_object($item)) {
searchObject($item);
}
if ($key === 'ID') {
$parentRec = json_decode(json_encode($parentRec), true);
$parentRec['metas'] = get_field_objects($item);
// the current array is modified but the value does not go back to the $list initial array.
}
}
function searchObject( &$element, &$parent) {
array_walk_recursive($element, 'alterArray', $element);
}
The data set could be anything. You do not know the key, you just know that some nested object can have ID key and when they do you want to add more content to this object.
The recursive function can do it, but you should use the & prefix on $value instead of $key:
function searchKeyAndAdd( &$element) {
if(is_array($element) || is_object($element)){
foreach ( $element as $key => &$value ) {
if ($key === "ID") {
$element['meta'] = get_relatedmeta_objects($value);
} else {
searchKeyAndAdd($value);
}
}
}
}
searchKeyAndAdd($list);
The other two methods offer no reference to the parent, although in the case of array_walk_recursive you tried it with the third argument, but there things get messy: to make it work on each recursive depth, you call array_walk_recursive recursively... but array_walk_recursive already visits all the key/value pairs recursively. So this will lead to many calls to alterArray with the same key/value, but with a different ancestor as third argument for each of them.
Furthermore, with this line:
$parentRec = json_decode(json_encode($parentRec), true);
... you lose the reference to the original $parentRec, and so any modification you make to $parentRec will no longer have an effect on the original array.

php create a new array from search results of another array

My initial array is
$employees = array(
array('name' => 'jack',
'area' => 'crafts'),
array('name' => 'janet',
'area' => 'aquatics'),
array('name' => 'brad',
'area' => 'crafts')
);
I am trying to create a new array based on the search results of another array so the new array should look like this if I search for 'crafts':
$employees2 = array(
array('name' => 'jack',
'area' => 'crafts'),
array('name' => 'brad',
'area' => 'crafts')
);
What is the simplest solution I can do get get this new result.
foreach($employees as $key => $value){
if($value['area']=='crafts'){
$employees2[] = $value;
}
}
This quite simply loops through the first array and checks the value of "area" in the internal array. If the value is equal to "crafts" you can then put that into a new array which is called $employees2. You can change crafts to whatever you want and add anything you want between the [ ] in employees2 if you wish to customise the key.
Try this:
$employees = array(
array('name' => 'jack',
'area' => 'crafts'),
array('name' => 'janet',
'area' => 'aquatics'),
array('name' => 'brad',
'area' => 'crafts')
);
$employees2 = array();
foreach ($employees as $key) {
if($key['name'] == "jack")
{
array_push($employees2,array('name'=>$key['name'],'area'=>$key['area']));
}
}
var_dump($employees2);
The array_push do all the trick ;)
Saludos.
You could simplify the syntax (but not the algorythmic complexity) by using a utility-belt library Underscore.php (http://brianhaveri.github.com/Underscore.php/)
There's a number of array-"plucking" methods that saves you the need to write loops, but under the bonnet it does much of the same as decribed in answers above.
I will assume that the possible result set can be large. In which case you would want to process the array with as little extra memory as possible. For this I suggest iterating through the array by reference and unsetting the items that do not match your criteria. Possibly less overhead than creating a new array to store the items that match your filter. Then you can check if the array is empty or not to determine if the filter returns any results. Like so:
<?php
// maybe this will be set through an option from the UI
$area_filter = 'crafts';
// fetched results
$employees = array(
array('name' => 'jack',
'area' => 'crafts'),
array('name' => 'janet',
'area' => 'aquatics'),
array('name' => 'brad',
'area' => 'crafts')
);
// filter out the items that match your filter
foreach($employees as $i => &$employee){
if($employee['area'] != $area_filter){
unset($employees[$i]);
}
}
// do something with the results
if(!empty($employees)){
print_r($employees);
} else {
echo "Sorry, your filter '$area_filter' did not match any results\n";
}
?>
Try this :
$employees = array(
array('name' => 'jack',
'area' => 'crafts'),
array('name' => 'janet',
'area' => 'aquatics'),
array('name' => 'brad',
'area' => 'crafts')
);
$employees = array_filter($employees, function($employee) {
return ($employee['area'] == 'crafts' );
});
echo "<pre>";
print_r($employees);

Check if an array of an array contains a certain string

I'm checking to make sure an array of arrays does not contain certain strings before adding any new child arrays to the parent array
I want to make sure that if an array with the same website and condition exists a new child array will not be added to the parent array.
e.g. in this example the $newArr must not be inserted in to the array $arr because their already exists an array with the same website and condition.
$arr = array(
array(
'website' => 'amazon',
'price' => 20,
'location' => 'uk',
'link' => '...',
'condition' => 'new'
),
array(
'website' => 'abe',
'price' => 20,
'location' => 'uk',
'link' => '...',
'condition' => 'new'
)
);
$newArr = array(
'website' => 'amazon',
'price' => 60,
'location' => 'uk',
'link' => '...',
'condition' => 'new'
)
I'm looking for an easy solution as using the function in_array on the parent array is not enough.
code so far
$arr = array();
foreach($table->find('tr.result') as $row){
if(($website = $row->find('a img',0))
&& ($price = $row->find('span.results-price a',0))
&& ($location = $row->find('.results-explanatory-text-Logo'))
&& ($link = $row->find('a',0))){
$website = str_replace( array('.gif','.jpg','.png'), '', basename($website->src));
$price = floatval(trim(str_replace(',', '', $price->innertext), "£"));
$location = "uk";
$link = $link->href;
$arr[] = array(
'website' => $website,
'price' => $price,
'location' => $location,
'link' => $link,
'condition' => 'new'
);
}
}
You loop over $arr each time to look for $website and $condition (always 'new'?) or you can keep a secondary array of the found keys. If you're starting with an empty $arr each time, the second approach will work and be faster.
$arr = array();
$keys = array();
foreach($table->find('tr.result') as $row){
if(...){
...
$condition = 'new'; // set as needed
// track seen keys
$key = $website . '|' . $condition; // assumes neither field contains '|'
if (!isset($keys[$key])) {
$keys[$key] = true;
$arr[] = array(...);
}
}
}
I hope the comments in the below code speak for themselves... I'm not a PHP pro, and this is probably not the most elegant way, but I believe the logic makes sense. Obviously the $new_array object has some variables that aren't declared but it's for example only.
I hope that helps and that no one down votes me :)
<?php
// Original array
$arr = array();
foreach($result as $row) {
// Get the new array as an object first so we can check whether to add to the loop
$new_array = array(
'website' => $website,
'price' => $price,
'location' => $location,
'link' => $link,
'condition' => 'new'
);
// If the original array is empty there's no point in looping through it
if(!empty($arr)) {
foreach($arr as $child) {
// Check through each item of the original array
foreach($new_array as $compare) {
// Compare each item in the new array against the original array
if(in_array($compare, $child)) {
// if there's a match, the new array will not get added
continue;
}
}
}
}
// If there's no match, the new array gets added
$arr[] = $new_array;
}
?>

PHP input filtering for complex arrays

Official PHP documentation states that filter_var_array() supports array filtering in the following format:
$data = array(
'testarray' => array('2', '23', '10', '12')
);
$args = array(
'testarray' => array('filter' => FILTER_VALIDATE_INT,
'flags' => FILTER_FORCE_ARRAY
)
);
$myinputs = filter_var_array($data, $args);
However, if the array in question is multi-dimensional and requires different filters for different parts, how would you approach defining filtering options?
As an example:
$data = array(
'testhash' => array('level1'=>'email',
'level2'=> array('23', '10', '12'))
);
Idea 1
Consider using FILTER_CALLBACK. In this way, you can write a callback function that itself uses the filter extension, thus providing a recursive ability.
function validate_array($args) {
return function ($data) use ($args) {
return filter_input_array($data, $args);
};
}
This will generate the callback functions.
$args = array(
'user' => array(
'filter' => FILTER_CALLBACK,
'options' => validate_array(array(
'age' => array('filter' => FILTER_INPUT_INT),
'email' => array('filter' => FILTER_INPUT_EMAIL)
))
)
);
This is what the config array would then look like.
Idea 2
Do not hesitate to pat me on the back for this one because I am quite proud of it.
Take an arg array that looks like this. Slashes indicate depth.
$args = array(
'user/age' => array('filter' => FILTER_INPUT_INT),
'user/email' => array('filter' => FILTER_INPUT_EMAIL),
'user/parent/age' => array('filter' => FILTER_INPUT_INT),
'foo' => array('filter' => FILTER_INPUT_INT)
);
Assume your data looks something like this.
$data = array(
'user' => array(
'age' => 15,
'email' => 'foo#gmail.com',
'parent' => array(
'age' => 38
)
),
'foo' => 5
);
Then, you can generate an array of references that map keys such as 'user/age' to $data['user']['age']. In final production, you get something like this:
function my_filter_array($data, $args) {
$ref_map = array();
foreach ($args as $key => $a) {
$parts = explode('/', $key);
$ref =& $data;
foreach ($parts as $p) $ref =& $ref[$p];
$ref_map[$key] =& $ref;
}
return filter_var_array($ref_map, $args);
}
var_dump(my_filter_array($data, $args));
Now the only question is how you deal with the mismatch between the validation record and the original data set. This I cannot answer without knowing how you need to use them.

Categories