Search for an array value with keys from another array - php

I have two arrays with nearly the same structure.
The first array is $_POST data while the second one holds regex rules and some other stuff for data validation.
Example:
$data = array(
'name' => 'John Doe',
'address' => array(
'city' => 'Somewhere far beyond'
)
);
$structure = array(
'address' => array(
'city' => array(
'regex' => 'someregex'
)
)
);
Now I want to check
$data['address']['city'] with $structure['address']['city']['regex']
or
$data['foo']['bar']['baz']['xyz'] with $structure['foo']['bar']['baz']['xyz']['regex']
Any ideas how to achieve this with a PHP function?
Edit: It seems that I found a solution by myself.
$data = array(
'name' => 'John Doe',
'address' => array(
'city' => 'Somewhere far beyond'
),
'mail' => 'test#test.tld'
);
$structure = array(
'address' => array(
'city' => array(
'regex' => 'some_city_regex1',
)
),
'mail' => array(
'regex' => 'some_mail_regex1',
)
);
function getRegex($data, $structure)
{
$return = false;
foreach ($data as $key => $value) {
if (empty($structure[$key])) {
continue;
}
if (is_array($value) && is_array($structure[$key])) {
getRegex($value, $structure[$key]);
}
else {
if (! empty($structure[$key]['regex'])) {
echo sprintf('Key "%s" with value "%s" will be checked with regex "%s"', $key, $value, $structure[$key]['regex']) . '<br>';
}
}
}
return $return;
}
getRegex($data, $structure);

Given these arrays:
$data = array(
'name' => 'John Doe',
'address' => array(
'city' => 'Somewhere far beyond'
),
'foo' => array(
'bar' => array(
'baz' => array(
'xyz' => 'hij'
)
)
)
);
$structure = array(
'address' => array(
'city' => array(
'regex' => '[a-Z]'
)
),
'foo' => array(
'bar' => array(
'baz' => array(
'xyz' => array(
'regex' => '[0-9]+'
)
)
)
)
);
and this function:
function validate ($data, $structure, &$validated) {
if (is_array($data)) {
foreach ($data as $key => &$value) {
if (
array_key_exists($key, $structure)
and is_array($structure[$key])
) {
if (array_key_exists('regex', $structure[$key])) {
if (!preg_match($structure[$key]['regex'])) {
$validated = false;
}
}
validate($value, $structure[$key], $validated);
}
}
}
}
you can check the arrays against each other and get a validation result like so:
$validated = true;
validate($data, $structure, $validated);
if ($validated) {
echo 'everything validates!';
}
else {
echo 'validation error';
}
Ah, you've found a solution. Very nice.

Related

Convert a PHP data structure into serialised XML

I have the following array. I'm not even sure if that array is properly formatted. I am not even sure if my array is right.
I want to convert the following array to a serialized XML using PHP. I am using attr tag for the attributes.
Here is the array:
$data = Array(
'name' => 'account',
'attr' => Array(
'id' => 123456
),
'children' => Array(
Array(
'name' => 'name',
'attr' => Array(),
'children' => Array(
'BBC'
),
),
Array(
'name' => 'monitors',
'attr' => Array(),
'children' => Array(
Array(
'name' => 'monitor',
'attr' => Array(
'id' => 5235632
),
'children' => Array(
Array(
'name' => 'url',
'attr' => Array(),
'children' => Array(
'http://www.bbc.co.uk/'
)
)
)
),
Array(
'name' => 'monitor',
'attr' => Array(
'id' => 5235633
),
'children' => Array(
Array(
'name' => 'url',
'attr' => Array(),
'children' => Array(
'http://www.bbc.co.uk/news'
)
)
)
)
)
)
)
);
It is quite easy with a recursive function. Your basic array contains 3 elements, the name, the attribute list and the children. So your function has to create and append a node with the name, set all attributes and iterate the child data. If the child is an scalar it is a text node, for an array call the function itself.
function appendTo($parent, $data) {
$document = $parent->ownerDocument ?: $parent;
$node = $parent->appendChild($document->createElement($data['name']));
if (isset($data['attr']) && is_array($data['attr'])) {
foreach ($data['attr'] as $name => $value) {
$node->setAttribute($name, $value);
}
}
if (isset($data['children']) && is_array($data['children'])) {
foreach ($data['children'] as $name => $childData) {
if (is_scalar($childData)) {
$node->appendChild($document->createTextNode($childData));
} elseif (is_array($childData)) {
appendTo($node, $childData);
}
}
}
}
$document = new DOMDocument();
$document->formatOutput = TRUE;
appendTo($document, $data);
echo $document->saveXml();
Output:
<?xml version="1.0"?>
<account id="123456">
<name>BBC</name>
<monitors>
<monitor id="5235632">
<url>http://www.bbc.co.uk/</url>
</monitor>
<monitor id="5235633">
<url>http://www.bbc.co.uk/news</url>
</monitor>
</monitors>
</account>
Try the following function
function assocArrayToXML($root_element_name,$ar)
{
$xml = new SimpleXMLElement("<?xml version=\"1.0\"?><{$root_element_name}></{$root_element_name}>");
$f = function($f,$c,$a) {
foreach($a as $k=>$v) {
if(is_array($v)) {
$ch=$c->addChild($k);
$f($f,$ch,$v);
} else {
$c->addChild($k,$v);
}
}
};
$f($f,$xml,$ar);
return $xml->asXML();
}
echo assocArrayToXML("root",$data);
test it here
Hope this will help.
<?php
function array2xml($arr)
{
$dom = new DomDocument('1.0');
/*
*Create Root
*/
$root = $dom->createElement($arr['name']);
if(isset($arr['attr']) && !empty($arr['attr']))
{
foreach($arr['attr'] as $key=>$val)
$root->setAttribute($key, $val);
}
$root = $dom->appendChild($root);
createChilds($arr['children'], $dom, $root);
header('Content-type: text/xml');
echo $dom->saveXML();
}
function createChilds($arr, $dom, $parent)
{
foreach($arr as $child)
{
if(isset($child['name']))
$node = $dom->createElement($child['name']);
/*
*Add Attributes
*/
if(isset($child['attr']) && !empty($child['attr']))
{
foreach($child['attr'] as $key=>$val)
$node->setAttribute($key, $val);
}
/*
*Add Childs Recursively
*/
if(isset($child['children']) && is_array($child['children']))
{
createChilds($child['children'], $dom, $node);
}
else if(isset($child) && is_string($child))
{
$text = $dom->createTextNode($child);
$parent->appendChild($text);
}
if(isset($node))
$parent->appendChild($node);
}
}
$data = Array(
'name' => 'account',
'attr' => Array(
'id' => 123456
),
'children' => Array(
Array(
'name' => 'name',
'attr' => Array(),
'children' => Array(
'BBC'
),
),
Array(
'name' => 'monitors',
'attr' => Array(),
'children' => Array(
Array(
'name' => 'monitor',
'attr' => Array(
'id' => 5235632
),
'children' => Array(
Array(
'name' => 'url',
'attr' => Array(),
'children' => Array(
'http://www.bbc.co.uk/'
)
)
)
),
Array(
'name' => 'monitor',
'attr' => Array(
'id' => 5235633
),
'children' => Array(
Array(
'name' => 'url',
'attr' => Array(),
'children' => Array(
'http://www.bbc.co.uk/news'
)
)
)
)
)
)
)
);
array2xml($data);
?>

Sort and merge in a array

I have trouble in handle array PHP, I have an array:
[0] {
'email' => 'test#gmail.com',
'meta' => {
'product' => {
'id' => '1',
'content' => 'This is content'
}
}
}
[1] {
'email' => 'test2#gmail.com',
'meta' => {
'product' => {
'id' => '2',
'content' => 'This is content'
}
}
}
[2] {
'email' => 'test2#gmail.com',
'meta' => {
'product' => {
'id' => '3',
'content' => 'This is content'
}
}
}
I need to merge this array by value 'email', like this:
[0] {
'email' => 'test#gmail.com',
'meta' => {
'product' => {
'id' => '1',
'content' => 'This is content'
}
}
}
[1] {
'email' => 'test2#gmail.com',
'meta' => {
'product' => [0] {
'id' => '2',
'content' => 'This is content'
}
[1] {
'id' => '3',
'content' => 'This is content'
}
}
}
Could somebody help me?
$sorted_array = [];
$emails = [];
$i = 0;
foreach ($arr as $array) {
if(!empty($array['email']) && !empty($array['meta']['product'])){
if( in_array($array['email'], $emails)){
$i--;
} else {
$emails[] = $array['email'];
}
$sorted_array[$i]['email'] = $array['email'];
$sorted_array[$i]['meta']['product'][] = $array['meta']['product'];
$i++;
}
}
echo "<pre>";
print_r($sorted_array);
Hope this will help you
Php has many function to sort an Array. You can consult the documentation to choice the better algorithms to your case http://php.net/manual/en/array.sorting.php. And you can merge result Arrays with array_merge function, like it:
array_merge($a1,$a2)
I created an example for your code here:
http://codepad.org/zzkndGQZ
You can use the email like array's key, to end, use array_combine to have indeces since 0 to N number...
<?php
$oldArray = array(
array(
'email' => 'test#gmail.com',
'meta' => array(
'product' => array(
'id' => '1',
'content' => 'This is content'
)
)
), array(
'email' => 'test2#gmail.com',
'meta' => array(
'product' => array(
'id' => '2',
'content' => 'This is content'
)
)
), array(
'email' => 'test2#gmail.com',
'meta' => array(
'product' => array(
'id' => '3',
'content' => 'This is content'
)
)
)
);
$newArray = array();
foreach($oldArray as $element){
if(isset($newArray[$element['email']])) {
if(!isset($newArray[$element['email']]['meta']['product'][0]))
$newArray[$element['email']]['meta']['product'] = array($newArray[$element['email']]['meta']['product']);
$newArray[$element['email']]['meta']['product'][] = $element['meta']['product'];
} else {
$newArray[$element['email']] = $element;
}
}
//For index since 0 to n
print_r(array_combine(range(0,count($newArray)-1), $newArray));
You can build a new array with the sorted informations.
It should be working with something like this, but not tested:
$sorted_array = [];
$i = 0;
foreach ($unsorted_array as $array) {
if(!empty($array['email']) && !empty($array['meta']['product'])){
$sorted_array[$i]['email'] = $array['email'];
$sorted_array[$i]['meta']['product'][] = $array['meta']['product'];
$i++;
}
}
print_r($sorted_array);

Change Array Value

I have simple questions, How to change text if id = cur_three from array below ?
$arr = array(
'id' => 'curr',
'lists' => array(
array(
'id' => 'cur_one',
'text' => 'Dollar',
),
array(
'id' => 'cur_two',
'text' => 'Euro',
),
array(
'id' => 'cur_three',
'text' => 'Peso',
),
)
);
Thank you very much...
Something simple:
foreach($arr['lists'] as $subArr) {
if ($subArr['id'] == 'cur_three') {
$subArr['text'] = 'not Peso';
}
}
Sure. Like this:
foreach($arr['lists'] as $key => $child) {
if($child['id'] == 'cur_three') {
$arr['lists'][$key]['text'] = "INR";
}
}

How to unflatten array in PHP using dot notation

I have php array structure like this:
array(
'servicemanagement.scheduler.events.edit' => 'Edit',
'servicemanagement.scheduler.events.delete' => 'Delete',
'servicemanagement.scheduler.events' => 'Events',
'servicemanagement.scheduler' => 'Scheduler',
'servicemanagement.subscribers' => 'Subscribers',
'servicemanagement.subscribers.index' => 'Index',
'servicemanagement' => 'Service management',
);
And I would like to convert is to multidimensional array like:
array(
'servicemanagement' => array(
'id' => 'servicemanagement',
'title' => 'Service Management',
'children' => array(
'scheduler' => array(
'id' => 'servicemanagement.scheduler',
'title' => 'Scheduler',
'children' => array(
'events' => array(
'id' => 'servicemanagement.scheduler.events',
'title' => 'Events',
'children' => array(
'edit' => array(
'id' => 'servicemanagement.scheduler.events.edit',
'title' => 'Edit',
'children' => array(),
),
'delete' => array(
'id' => 'servicemanagement.scheduler.events.delete',
'title' => 'Delete',
'children' => array(),
),
),
),
),
),
'subscribers' => array(
'id' => 'servicemanagement.subscribers',
'title' => 'Subscribers',
'children' => array(
'index' => array(
'id' => 'servicemanagement.subscribers.index',
'title' => 'Index',
)
),
),
),
),
);
I have checked some answers already like this one:
How to set a deep array in PHP
But it seems that i could not manage to clear up the writing on top of the arrays and the last record 'servicemanagement' removes all of the previous records.
The function that is used there is
function setArray(&$array, $keys, $value) {
$keys = explode(".", $keys);
$current = &$array;
foreach($keys as $key) {
$current = &$current[$key];
}
$current = $value;
}
Another function that I have found but it is not doing the expected result is:
function unflatten($array,$prefix = '')
{
$result = array();
foreach($array as $key=>$value) {
if (!empty($prefix)) {
$key = preg_replace('#^'.preg_quote($prefix).'#','',$key);
}
if (strpos($key,'.') !== false) {
parse_str('result['.str_replace('.','][',$key)."]=".$value);
} else {
$result[$key] = $value;
}
}
return $result;
}
It is an option to use recursion to unflatten this array since the end format is the same for all records.
May anyone give me a tip ot this one?
I created an unflatten function for reference here:
https://gist.github.com/Gerst20051/b14c05b72c73b49bc2d306e7c8b86223
$results = [
'id' => 'abc123',
'address.id' => 'def456',
'address.coordinates.lat' => '12.345',
'address.coordinates.lng' => '67.89',
'address.coordinates.geo.accurate' => true,
];
function unflatten($data) {
$output = [];
foreach ($data as $key => $value) {
$parts = explode('.', $key);
$nested = &$output;
while (count($parts) > 1) {
$nested = &$nested[array_shift($parts)];
if (!is_array($nested)) $nested = [];
}
$nested[array_shift($parts)] = $value;
}
return $output;
}
echo json_encode(unflatten($results));
/*
{
"id": "abc123",
"address": {
"id": "def456",
"coordinates": {
"lat": "12.345",
"lng": "67.89",
"geo": {
"accurate": true
}
}
}
}
*/
This was slightly influenced by the following resources:
https://gist.github.com/tanftw/8f159fec2c898af0163f
https://medium.com/#assertchris/dot-notation-3fd3e42edc61
This isn't the cleanest solution but it works as a single function
$your_array = array(
'servicemanagement.scheduler.events.edit' => 'Edit',
'servicemanagement.scheduler.events.delete' => 'Delete',
'servicemanagement.scheduler.events' => 'Events',
'servicemanagement.scheduler' => 'Scheduler',
'servicemanagement.subscribers' => 'Subscribers',
'servicemanagement.subscribers.index' => 'Index',
'servicemanagement' => 'Service management',
);
function expand($array, $level = 0)
{
$result = array();
$next = $level + 1;
foreach($array as $key=>$value) {
$tree = explode('.', $key);
if(isset($tree[$level])) {
if(!isset($tree[$next])) {
$result[$tree[$level]]['id'] = $key;
$result[$tree[$level]]['title'] = $value;
if(!isset($result[$tree[$level]]['children'])) {
$result[$tree[$level]]['children'] = array();
}
} else {
if(isset($result[$tree[$level]]['children'])) {
$result[$tree[$level]]['children'] = array_merge_recursive($result[$tree[$level]]['children'], expand(array($key => $value), $next));
} else {
$result[$tree[$level]]['children'] = expand(array($key => $value), $next);
}
}
}
}
return $result;
}
var_export(expand($your_array));

how to get the value of my var, which double dollar var is set from multidimensional array?

i managed to dynamically create my arrays (as $$myGenre contains each name => id), but $myGenre does not contain anything... how can i make this work : $myGenre should contain every $$myGenre, $$myGenre should have its content as name => id, and we should keep each $myGenre separated from one another (here, because of the foreach, we're overriding $myGenre for each different genre) :
<?php function findSection() {
global $post, $custom_meta_fields, $myGenre;
foreach ($custom_meta_fields as $fields) {
foreach ($fields as $field) {
if ($field == $fields['genre']) {
$myGenre = array($field['title']);
$$myGenre = array();
} else {
${$myGenre}[$field['name']] = $field['id'];
}
}
var_dump($$myGenre);
}
}
$custom_meta_fields = array(
array( //THRILLER
'genre' => array( 'title' => 'Thriller'),
'fields' => array(
'name' => 'Movie1',
'desc' => 'Desc movie1',
'id' => 'id1',
'type' => 'text'),
array(
'name' => 'Movie2',
'desc' => 'desc movie2',
'id' => 'id2',
'type' => 'text'
),
array(
'name' => 'movie3',
'desc' => 'desc',
'id' => 'id3',
'type' => 'image'
)
),
array(
'genre' => array( 'title' => 'Action'),
'fields' => array('name' => 'Action1',
'desc' => 'desc act1',
'id' => 'idAction1')
)
);
findSection();
Thanks for your help
I modified your code so that it uses associative arrays, since you were doing pretty weird things with your double dollars.
<?php
function findSection() {
global $post, $custom_meta_fields, $myGenre;
foreach ($custom_meta_fields as $fields) {
foreach ($fields as $field) {
if ($field == $fields['genre']) {
$genre =$field['title'];
$all[$genre]= array();
} else {
$all[$genre][$field['name']] = $field['id'];
}
}
}
echo "<pre>".var_export($all,TRUE)."</pre>";
}
Result:
array (
'Thriller' =>
array (
'Movie1' => 'id1',
'Movie2' => 'id2',
'movie3' => 'id3',
),
'Action' =>
array (
'Action1' => 'idAction1',
),
)

Categories