Searching 4 level deep array in PHP - php

Good evening,
I found myself in a bit of a pickle here, with an overcomplicated (i think) $_SESSION array that is set right after a user logs in and contains the info of all User Groups where that user is on, and also this user type of permissions on Group of Devices where that specific user group is allowed.
Here's the deal with irrelevant info ommited:
Array
(
... other stuff ...
[user_groups] => Array
(
[0] => Array
(
[GroupUsersId] => 4
[GroupUsersName] => XXXX
[idUserType] => 2
[NameTypeUser] => Manager
[DevicesAllowed] => Array
(
[GroupDevicesId] => Array
(
[0] => 2
)
[DevicesOnGroup] => Array
(
[0] => 22,24,16
)
)
)
[1] => Array
(
[GroupUsersId] => 5
[GroupUsersName] => YYYY
[idUserType] => 3
[NameTypeUser] => Guest
[DevicesAllowed] => Array
(
)
)
[2] => Array
(
[GroupUsersId] => 1
[GroupUsersName] => ZZZ
[idUserType] => 1
[NameTypeUser] => Admin
[DevicesAllowed] => Array
(
[GroupDevicesId] => Array
(
[0] => 2
)
[DevicesOnGroup] => Array
(
[0] => 1,5,13,12,17,21,22,24,16
)
)
)
)
... more stuff ...
I need to find out what kind of permissions, if any, does the guy has if trying to browse the device with, let's say, DeviceId = 5. If that particular Id is not on any of the arrays, the user isn't even allowed to see it...
I already tryed to change the code in this question How to search by key=>value in a multidimensional array in PHP, but I guess I'm missing some kind of iteration over the arrays.
Any help?
Cheers and thanks in advance.
Edit: $_SESSION can be changed if needed...

(Updated as per comment below) I might be completely missing your point, but would not just iterative processing of your array help?
$user_groups = array(
0 => array(
'GroupUsersName' => 'XXX',
'NameTypeUser' => 'Admin',
'idUserType' => 3,
'DevicesAllowed' => array(
'DevicesOnGroup' => array(
1, 2, 3
)
)
),
1 => array(
'GroupUsersName' => 'YYY',
'NameTypeUser' => 'ReadOnly',
'idUserType' => 1,
'DevicesAllowed' => array(
'DevicesOnGroup' => array(
3, 4, 5
)
)
)
);
$device = 3;
$right = 0;
foreach ($user_groups as $group) {
if (array_key_exists('DevicesOnGroup', $group['DevicesAllowed'])) {
if (in_array($device, $group['DevicesAllowed']['DevicesOnGroup'])) {
if ($group['idUserType'] > $right) {
$right = $group['idUserType'];
}
}
}
}
print_r($right);
Outputs:
3
If you would ask for device which is in no group, it would return 0 (i.e. no access).

iterate the array like this
$guysDeviceId ;
$bGuyMayPass = false;
foreach($_SESSION["user_group"] as $userGroup ){
if(!isset($userGroup[DevicesAllowed]) || !isset($userGroup[DevicesAllowed][DevicesOnGroup])){
continue;
}
if(in_array($userGroup[DevicesAllowed][DevicesOnGroup], $guysDeviceId ){
$bGuyMayPass= true;
}
}
if($bGuyMayPass){
//login, whatever
}

Related

Setting a session in steps

Is it possible to set multiple session elements to the same session at different times? I have 2 classes and each class should set 2 session elements. What I'm getting back is an empty array. I am using session_start() on each page.
Also, I can set the session successfully from within a single class, but get an empty array back when setting from each class.
// User class
$_SESSION['user'] = array('id' => 1);
$_SESSION['user'] = array('name' => 'Tim Miller');
// Part class
$_SESSION['user'] = array('model' => '12311');
$_SESSION['user'] = array('part' => 'AA34F');
EDIT:
Here is the array I would like to create:
Array (
[user] => Array (
[id] => 1
[name] => Tim Miller
[model] => 12311
[part] => AA34F
[order] => 119026
[serial] => 12001923S3
)
)
Elements 0 and 1 should be set in the user class
Elements 2-3 should be set in the part class
Elements 4-5 should be set in the serial class
You can set it but bit different approach need to be used. You can create an array of sessions with different values.
You have to write session_start() on top of each file where you need to use session.
session_start();
// User class
$_SESSION['user'][] = array('id' => 1);
$_SESSION['user'][] = array('name' => 'Tim Miller');
// Part class
$_SESSION['user'][] = array('model' => '12311');
$_SESSION['user'][] = array('part' => 'AA34F');
print_r( $_SESSION['user'] );
Output looks like:
Array
(
[0] => Array
(
[id] => 1
)
[1] => Array
(
[name] => Tim Miller
)
[2] => Array
(
[model] => 12311
)
[3] => Array
(
[part] => AA34F
)
)
It's upto you how do you want to crate this array.
EDIT:
To get your desire format output and add values to array later in different files you can give a try like:
// Your code here!
session_start();
// User class
$_SESSION['user'][] = array('id' => 1, 'name' => 'Tim Miller');
// Part class
$key = -1
$key = array_search( 1, array_column($_SESSION['user'], 'id') );
// Here 1 in array_search is id of user your can use $id to add data to correct user's by id.
if( $key > -1 ) {
$_SESSION['user'][ $key ] = array_merge( $_SESSION['user'][ $key ], array('model' => '12311', 'part' => 'AA34F') );
}
print_r( $_SESSION['user'] );
This will give you following output:
Array
(
[0] => Array
(
[id] => 1
[name] => Tim Miller
[model] => 12311
[part] => AA34F
)
)

Remove all duplicate data from a multi-dimensional array [duplicate]

This question already has answers here:
Filter/Remove rows where column value is found more than once in a multidimensional array
(4 answers)
Closed 9 months ago.
I'm trying to remove all keys with repeated numbers, I've tried some solutions posted here like the one I'm using in my script but none of it worked for my purpose.
This is my array:
There are at least 4 card IDs repeated.
Array
(
[0] => Array
(
[id_card] => 11883834
[type] => 1
[registed] => 1547610891
)
[1] => Array
(
[id_card] => 20311077
[type] => 1
[registed] => 1547610891
)
[2] => Array
(
[id_card] => 16187903
[type] => 3
[registed] => 1547610891
)
[3] => Array
(
[id_card] => 16354099
[type] => 1
[registed] => 1547610891
)
[4] => Array
(
[id_card] => 21133393
[type] => 4
[registed] => 1547610891
)
[5] => Array
(
[id_card] => 15452852
[type] => 2
[registed] => 1547610891
)
[6] => Array
(
[id_card] => 19775869
[type] => 2
[registed] => 1547610891
)
[7] => Array
(
[id_card] => 20311077
[type] => 1
[registed] => 1547610891
)
[8] => Array
(
[id_card] => 21133393
[type] => 4
[registed] => 1547610891
)
[9] => Array
(
[id_card] => 11883834
[type] => 1
[registed] => 1547610891
)
)
1
At the moment I have something like this:
<?php
$array_data = array_map('unserialize', array_unique(array_map('serialize', $myArray)));
echo '<pre>';
print_r($array_data);
echo '</pre>';
?>
With only 10 keys is working perfectly, but when it goes through this with, for example, 50, 100 keys, no longer works.
Any help appreciated.
So the issue here is that the array_unique solutions expect the entire value to be equivalent - they don't just compare based on your ID field.
Instead, you probably want to loop through the array and keep track of which IDs you've seen, and only take those elements for which you haven't seen the ID before.
function filter_duplicate_id_cards($data) {
$seen = array(); // To keep track of the IDs we've seen
$filtered = array(); // Will hold the result
foreach($data as $item) {
if(array_key_exists($item['id_card'], $seen)) {
// We already encountered this id card before.
continue;
}
// Never-before seen id card, append it to the result and set the key in $seen
$filtered[] = $item;
$seen[$item['id_card']] = TRUE;
}
return $filtered;
}
Note that this uses the map form of a PHP array, rather than just appending seen IDs to the list form and using something like in_array to check if we've seen the key. That's important for performance reasons, especially if we're going to be working on large datasets - in_array is O(n) with the # of items in the array whereas array_key_exists is O(1).
A more generic version of this function would look like this:
function filter_duplicate_field($data, $field) {
$seen = array(); // To keep track of the keys we've seen
$filtered = array(); // Will hold the result
foreach($data as $item) {
if(array_key_exists($item[$field], $seen)) {
// We already encountered this key before.
continue;
}
// Never-before seen key, append it to the result and set the key in $seen
$filtered[] = $item;
$seen[$item[$field]] = TRUE;
}
return $filtered;
}
You could then call it like $result = filter_duplicate_field($data, 'id_card');.
This doesn't preserve the original input order, but because the data is indexed so I'll assume that that doesn't matter.
With just 3 calls in a one-liner, you assign temporary associative keys from back to front to eliminate latter duplicates (because php does not permit duplicate keys), then optionally remove the temporary keys with array_values(). No iterated function calls. No lookup arrays.
Code: (Demo)
$array = [
['id_card' => 11883834, 'type' => 1, 'registed' => 1547610891],
['id_card' => 20311077, 'type' => 1, 'registed' => 1547610891],
['id_card' => 16187903, 'type' => 3, 'registed' => 1547610891],
['id_card' => 16354099, 'type' => 1, 'registed' => 1547610891],
['id_card' => 21133393, 'type' => 4, 'registed' => 1547610891],
['id_card' => 15452852, 'type' => 2, 'registed' => 1547610891],
['id_card' => 19775869, 'type' => 2, 'registed' => 1547610891],
['id_card' => 20311077, 'type' => 1, 'registed' => 1547610891],
['id_card' => 21133393, 'type' => 4, 'registed' => 1547610891],
['id_card' => 11883834, 'type' => 1, 'registed' => 1547610891]
];
var_export(array_values(array_column(array_reverse($array), null, 'id_card')));
If you change you mind about wanting to keep the first occurrence, you can remove array_reverse(). If the first level keys are irrelevant in the output, you can remove array_values(). These changes would allow the solution to be a one function call task.
p.s. "registered"

Right way to separate array specific values into another arrays

There is the following array in my application:
array (
[item_name_1] => GTA V
[item_quantity_1] => 4
[item_price_1] => 5990
[item_name_2] => Watch_Dogs
[item_quantity_2] => 1
[item_price_2] => 5990
)
I want to divide/split this array into two pieces like that:
array (
[item_name_1] => GTA V
[item_quantity_1] => 4
[item_price_1] => 5990
)
array (
[item_name_2] => Watch_Dogs
[item_quantity_2] => 1
[item_price_2] => 5990
)
If you didn't realized, I want to separate items suffixed by 1 and 2 – and successively – unto different matrices and I really don't see the best way to perform this. Maybe regex?
I already tried to play with explode() and implode(), but no success – I have no creativity enough to explore their best.
<?php
$src = array (
'item_name_1' => 'GTA V',
'item_quantity_1' => 4,
'item_price_1' => 5990,
'item_name_2' => 'Watch_Dogs',
'item_quantity_2' => 1,
'item_price_2' => 5990,
);
$dest = array();
foreach($src as $k => $v) {
$sfx = preg_replace('/.*?_([0-9]+)$/', '$1',$k);
$dest[$sfx][$k] = $v;
}
print_r($dest);

Iterating through multiple arrays and assigning positions

Been working on this for 4 hours. My eyes are starting to hurt and my brain is weary from paradox.
So here is the setup. 3 arrays:
An array of posts that are advertisements
An array of normal posts
An array of taken positions which is pulled from array 1
The ad array has predefined spots.
I have merged the 2 arrays because the ads are basically integrated into the normal flow of posts. I have even been able to assign every post a spot based on the natural order of the posts, and the assigned spot for the ad. So if a post's natural spot has an ad in it, then that posts's position needs to bump forward one. This is easy if there is only 1 ad in the stream. But the thing is set up for multiple ads of arbitrary number.
So here is how I bump the position of each non-ad element in the array. I could run this again a few times I think and that should cover when there are additional ads but it seems wrong and unholy.
Wondering if anyone can solve this problem because I am sick of the taste of my own tears.
if(in_array($newarray[$key]['position'],$taken)){
$newkey = ($newarray[$key]['position'] + 1);
$newarray[$key]['position'] = $newkey;
$taken[] = $newkey;
In the end I need the merged array with all positions correctly assigned and unique.
You could write a recursive function to pull the next available position number, but if you're working with a small number of posts + ads, something like below would be quick and easy. Note that this assumes you need to preserve the original keys for the ads and posts arrays. If you don't need to do that then you can simplify it even further.
// Sample array of ads
$ads = array('ad1' => array('position' => 1),
'ad2' => array('position' => 4),
'ad3' => array('position' => 6),
'ad4' => array('position' => 10));
// Identify ad positions
foreach ( $ads as $k => $v ) {
$adPositions[$v['position']] = $v['position'];
}
// Identify available positions
$availablePositions = array_combine(range(1,100), range(1,100));
$availablePositions = array_diff_key($availablePositions, $adPositions);
// Sample posts
$posts = array('post1' => array('position' => false),
'post2' => array('position' => false),
'post3' => array('position' => false),
'post4' => array('position' => false),
'post5' => array('position' => false),
'post6' => array('position' => false));
// Use first (lowest number) available position as post position
foreach ( $posts as $k => $v ) {
$posts[$k]['position'] = array_shift($availablePositions);
}
// Merge arrays
$merged = array_merge($ads, $posts);
// Create list of positions for use with array_multisort
foreach ( $merged as $k => $v ) {
$position[$k] = $v['position'];
}
// Sort $merged by ['position']
array_multisort($position, SORT_ASC, $merged);
Gives you:
Array
(
[ad1] => Array
(
[position] => 1
)
[post1] => Array
(
[position] => 2
)
[post2] => Array
(
[position] => 3
)
[ad2] => Array
(
[position] => 4
)
[post3] => Array
(
[position] => 5
)
[ad3] => Array
(
[position] => 6
)
[post4] => Array
(
[position] => 7
)
[post5] => Array
(
[position] => 8
)
[post6] => Array
(
[position] => 9
)
[ad4] => Array
(
[position] => 10
)
)

Cakephp using Set class to fetch data with key starting at zero

I'm using Set class of Cakephp to format the find returned array but cannot seem to find a way to get the counter starting at zero and auto-increment for array keys so it is like
[0] => 3
[1] => 6
[2] => 12
I'm currently using below query to get the data from my HasAndBelongsToMany table.
$interest_ids = Set::combine($this->User->Interestsub->find('threaded', array
(
'conditions' => array
(
'Interestsub.name' => $interests
),
//'fields' => array('Interestsub.id'),
'recursive' => -1
)
),
'{n}.Interestsub.id',
'{n}.Interestsub.id'
);
The reason why I need this is that I'm currently trying to get the returned array as part of bigger parent array preparing to be saved for SaveAll function. To be formatted properly, I need below nested array coming out:
[0] => Array
(
[interestssub_id] => 12
[user_id] => 2
)
[1] => Array
(
[interestssub_id] => 22
[user_id] => 2
)
[2] => Array
(
[interestssub_id] => 32
[user_id] => 2
)
Is there a way we can use Combine class to format the returned array like above?
There's no real reason to use the Set class in this case. Just use good old fashioned php:
$threaded = $this->User->Interestsub->find('threaded', array(
'conditions' => array(
'Interestsub.name' => $interests
),
'recursive' => -1
));
$interest_ids = array();
foreach ($threaded as $thread) {
$interest_ids[] = array(
'interestssub_id' => $thread['Interestsub.id'],
'interestssub_id' => $thread['Interestsub.user_id']
);
}

Categories