How to loop and get serialized values from database with php - php

I'm developing a pizza's restaurant ecommerce and now I'm trying to get the size (Familiar) and the ingredients (Pernil dol�, Bac�, Emmental) of a pizza that was ordered previously. The data I want to get (the italic values in this paragraph) becomes serialized from database:
a:4:{s:10:"attributes";a:2:{s:6:"Tamany";a:1:{i:3;s:8:"Familiar";}s:11:"Ingredients";a:3:{i:318;s:12:"Pernil dol�";i:270;s:5:"Bac�";i:294;s:8:"Emmental";}}s:9:"shippable";s:1:"0";s:4:"type";s:5:"pizza";s:6:"module";s:10:"uc_product";}array(4) { ["attributes"]=> array(2) { ["Tamany"]=> array(1) { [3]=> string(8) "Familiar" } ["Ingredients"]=> array(3) { [318]=> string(11) "Pernil dol�" [270]=> string(4) "Bac�" [294]=> string(8) "Emmental" } } ["shippable"]=> string(1) "0" ["type"]=> string(5) "pizza" ["module"]=> string(10) "uc_product" }
I discovered 'unserialized' php method and I tried this:
$attr = $row['data']; // data from database
$data = preg_replace('!s:(\d+):"(.*?)";!e', "'s:'.strlen('$2').':\"$2\";'", $attr); // I did this because I get some errors...
After I did that, I got this multidimensional array (a bit more human readable):
array(4) { ["attributes"]=> array(2) { ["Tamany"]=> array(1) { [3]=> string(8) "Familiar" } ["Ingredients"]=> array(3) { [318]=> string(11) "Pernil dol�" [270]=> string(4) "Bac�" [294]=> string(8) "Emmental" } } ["shippable"]=> string(1) "0" ["type"]=> string(5) "pizza" ["module"]=> string(10) "uc_product" }
Next step was try to loop the resulting data with a foreach loop, like the following:
foreach($data['attributes'] as $item)
{
print '<ul>';
foreach($item as $value)
{
print_r('<li>' . $value . '</li>');
}
print '</ul>';
}
I'm a php beginner PHP developer and I can't figure out how can I loop this array in order to get the values I need. I'm getting this error:
Warning: Invalid argument supplied for foreach() in /home/my_host/public_html/dev.mysite.com/inc/file.php on line 79
Can anybody tell me how I have to loop this array to get the data?
Any help will be very, very appreciated.
Best regards,

I created this example for you. First I declared an array which believe mimics the array you have to parse. Then I looped through and outputed the contents of the array.
<?php
$array = array(
0 => array(
'0' => 'John Doe',
'1' => 'john#example.com'
),
1 => array(
'0' => 'Jane Doe',
'1' => 'jane#example.com'
),
);
foreach ($array as $key => $value) {
$thisArray = $array[$key];
print_r('<ul>');
foreach ($thisArray as $key2 => $value){
print_r('<li>'.$thisArray[$key2].'</li>');
}
print_r('</ul>');
}
?>

Finally, and based on the answer of #Gregory Hart, I reached my goal. This is the final code that makes it possible in my particular case:
$data = $row['data'];
$attrib = preg_replace('!s:(\d+):"(.*?)";!e', "'s:'.strlen('$2').':\"$2\";'", $data);
$attr = unserialize($attrib);
foreach ($attr as $key => $value)
{
print_r('<ul>');
$thisArray = $attr[$key];
foreach ($thisArray as $key2 => $value2)
{
print_r('<li>' . $key2 . ': ');
$thisArray2 = $attr[$key][$key2];
foreach ($thisArray2 as $key3 => $value3)
{
if ($key2 == 'Tamany')
print_r('<span class="label label-warning">' . utf8_encode($thisArray2[$key3]) . '</span> ');
if ($key2 == 'Ingredients')
print_r('<span class="label label-success">' . utf8_encode($thisArray2[$key3]) . '</span> ');
if ($key2 == 'Salsa')
print_r('<span class="label label-primary">' . utf8_encode($thisArray2[$key3]) . '</span> ');
}
print '</li>';
}
print_r('</ul>');
}
Thanks for you help!

Try this logic:
$data_unserialize = unserialize($row->data);
foreach ($data_unserialize as $data_key => $data_value) {
if($data_key =='size')
{
$thisArray = $data_unserialize[$data_key ];
foreach ($thisArray as $key2 => $value2){
if($key2=='attributes')
{
switch ($value2)
{
case "Pernil dol�":
echo'Pernil dol �';
break;
case "Emmental":
echo'Emmental';
break;
default:
echo 'Nothing';
}
}
}
}
}
NB:- And remove the break; from switch statement to display all ingrediants.

Related

Template Engine refactoring

$global_models =
array(12) {
["page.login"]=>
string(1) "2"
["page.item.id"]=>
string(3) "new"
["page.content.title"]=>
string(0) ""
["page.trigger.date"]=>
string(0) ""
["page.trigger.url"]=>
string(0) ""
["page.trigger.admin_only"]=>
string(1) "N"
["page.content.body"]=>
string(0) ""
["page..ga"]=>
string(27) "GA1.2.1694644634.1491872034"
["prompt.message"]=>
string(0) ""
["prompt.error"]=>
string(0) ""
["page.tags"]=>
array(1) {
["name"]=>
array(2) {
[0]=>
string(2) "xx"
[1]=>
string(2) "yy"
}
}
["page.custom"]=>
array(2) {
["header"]=>
array(2) {
[0]=>
string(0) "1"
[1]=>
string(1) "a"
}
["value"]=>
array(2) {
[0]=>
string(0) "2"
[1]=>
string(1) "b"
}
}
}
Code:
foreach ($global_models as $var => $data) {
// when model data is an array
if (is_array($data)) {
// fetch for blocks and render loops
$forblocks = array();
preg_match_all('/(?<block>\[for:'.$var.'\](?<content>[\s\S]+)\[end:'.$var.'\])/ix', $view_output, $forblocks, PREG_SET_ORDER);
if (count($forblocks)) {
foreach ($forblocks as $foundForBlock) {
$foreach_data = '';
foreach ($data as $mykey => $row) {
// set model values within the loop, ex: blocks.x value
$block_content = $foundForBlock['content'];
foreach ($row as $subvar => $value) {
if (!is_array($value)) {
$block_content = str_replace('['.$var.'.'.$subvar.']', $value, $block_content);
//$block_content = str_replace('['.$var.'.'.$mykey.']', $value, $block_content);
}
}
// append the parsed new block (of for loop) as processed view to render (ifs and setters for example)
$foreach_data .= $this->process_view($controller, $block_content, $recursion_level + 1);
}
$view_output = str_replace($foundForBlock['block'], $foreach_data, $view_output);
}
}
} else {
// simple model, replace model with value ex: "[stats.x]" by "18"
$view_output = str_replace('['.$var.']', $data, $view_output);
}
}
Issue:
Key to value pair works
my blocks of data don't work...
$viewoutput =
"
[page.login]
"
should result in
"
2
"
This:
$viewoutput =
"
[for:page.custom]
[page.custom.header] - [page.custom.value]
[end:page.custom]
"
should result in
"
1 - 2
a - b
"
This:
$viewoutput =
"
[for:page.tags]
[page.tags.name]
[end:page.tags]
"
should result in
"
xx
yy
"
I've refactored my code about 20 times and each time I get a headache...!
Someone please help?
Thanks and viva la community! :)
I have tried my self best to get it done. I know this is not a generic solution but it will solve your current problem. You must use different function for using loop([for:page.custom]) and simple([page.login]) attribute. I have already went through this issue. I also solved one of my problem by this, Here you should define seperate function which will first decide which function will handle modification whether it is for loop or for simple. But for now i have fixed your issue with a single php function.
Try this code snippet here
<?php
ini_set('display_errors', 1);
$global_models = array(
"page.login" => "2",
"page.item.id" => "new",
"page.content.title" => "",
"page.trigger.date" => "",
"page.trigger.url" => "",
"page.trigger.admin_only" => "N",
"page.content.body" => "testing",
"page..ga" => "GA1.2.1694644634.1491872034",
"prompt.message" => "",
"prompt.error" => "",
"page.tags" =>
array(
"name" =>
array(
0 => "xx",
1 => "yy"
)
),
"page.custom" =>
array(
"header" =>
array(
0 => "1",
1 => "a",
),
"value" =>
array(
0 => "2",
1 => "b",
)
)
);
$viewoutput =
"
[page.content.body]
[for:page.custom]
[page.custom.header] - [page.custom.value]
[end:page.custom]
";
echo modify($viewoutput);
function modify($viewoutput)
{
$returnString="";
global $global_models;
$segments=explode("\n", $viewoutput);
$counter=0;
while(count($segments)>0)
{
$segment=$segments[$counter];
if (preg_match("/\[for:\K([\w\.]+)\]/", $segment,$matches))
{
unset($segments[$counter]);
$counter++;
$segment=$segments[$counter];
$pointer=0;
$data=array();
preg_match_all("/\.([\w]+)\]/", $segment,$segmentMatches);
for($x=0;$x<count($global_models[$matches[1]][$segmentMatches[1][0]]);$x++)
{
$newString=$segment;
foreach($segmentMatches[1] as $toReplace)
{
$newString= str_replace("[".$matches[1].".".$toReplace."]", $global_models[$matches[1]][$toReplace][$x], $newString);
}
$data[]=$newString;
}
}
elseif(preg_match("/\[end:\K([\w\.]+)\]/", $segment))
{
$returnString.= implode("\n", $data);
}
elseif(preg_match("/\[([\w\.]+)\]/", $segment,$matches1) && !preg_match("/\[for:\K([\w\.]+)\]/", $segment,$matches))
{
$returnString=$returnString.$global_models[$matches1[1]]."\n";
}
else
{
$returnString=$returnString.$segment."\n";
}
unset($segments[$counter]);
$counter++;
}
return $returnString;
}
Fixed myself...
// process shared models (variables)
foreach ($global_models as $var => $data) {
// when model data is an array
if (is_array($data)) {
// fetch for blocks and render loops
$forblocks = array();
preg_match_all('/(?<block>\[for:'.$var.'\](?<content>[\s\S]+)\[end:'.$var.'\])/ix', $view_output, $forblocks, PREG_SET_ORDER);
if (count($forblocks)) {
foreach ($forblocks as $foundForBlock) {
$block_content = array();
foreach ($data as $mykey => $row) {
//$foreach_data = '';
// set model values within the loop, ex: blocks.x value
foreach ($row as $subvar => $value) {
if (!isset($block_content[$subvar])) $block_content[$subvar] = $foundForBlock['content'];
if (!is_array($value)) {
if (is_numeric($subvar)) {
$block_content[$subvar] = str_replace('['.$var.'.'.$mykey.']', $value, $block_content[$subvar]);
}
}
}
// append the parsed new block (of for loop) as processed view to render (ifs and setters for example)
}
$block_content = implode("\n", $block_content);
$view_output = str_replace($foundForBlock['block'], $block_content, $view_output);
}
}
} else {
// simple model, replace model with value ex: "[stats.x]" by "18"
$view_output = str_replace('['.$var.']', $data, $view_output);
}
}

How can I output only the values of subarrays?

I have an array and I want to output some data:
array(4) {
[123]=>
array(2) {
["color"]=>
string(3) "red"
["name"]=>
string(5) "harry"
}
[345]=>
array(2) {
["color"]=>
string(4) "blue"
["name"]=>
string(4) "fred"
}
["animal"]=>
string(5) "horse"
["plant"]=>
string(4) "tree"
}
This is my solution, which I have the feeling is very unsmart:
echo "<b>These are all the colors:</b><br>";
foreach ($properties as $key => $val) {
if ($key != "plant" AND $key != "animal"){
echo $val['color']."<br>";
}
}
echo "<b>This is the animal:</b><br>";
foreach ($properties as $key => $val) {
if ($key == "animal"){
echo $val."<br>";
}
}
echo "<b>This is the plant:</b><br>";
foreach ($properties as $key => $val) {
if ($key == "plant"){
echo $val."<br>";
}
}
It gives me the desired result...
These are all the colors:
red
blue
This is the animal:
horse
This is the plant:
tree
...but I thought maybe you know a more simple solution. I am sure it must be possible to talk only to subarrays, but I couldn't find a way to do it.
Since php 5.5, you can use array_column:
$color = array_column($properties, 'color');
Since php 5.3, you can use array_map with an anonymous function, like this:
$color = array_map(function ($ar) {return $ar['color'];}, $properties);
print_r($color);
exit;
I think, Use Switch in foreach and it will help for this problem.
foreach ($properties as $key => $val) {
switch($key){
case '':
break;
}
}

Different array structures and breaking of foreach

I generate XML file from dynamic content but I get 2 array types to get images:
First array type is when there are more than 1 images, example:
array(1) {
["Images"]=>
array(3) {
[0]=>
array(2) {
["Url"]=>
string(57) "http://example.net/image1.jpg"
["Default"]=>
bool(true)
}
[1]=>
array(2) {
["Url"]=>
string(57) "http://example.net/image2.jpg"
["Default"]=>
bool(false)
}
[2]=>
array(2) {
["Url"]=>
string(57) "http://example.net/image3.jpg"
["Default"]=>
bool(false)
}
}
}
Second type is when I had only 1 image, example:
array(1) {
["Images"]=>
array(2) {
["Url"]=>
string(57) "http://example.net/image111.jpg"
["Default"]=>
bool(true)
}
}
How I can make second type to use type of first array, because when I looping these arrays with foreach there is a problem with content. Is there any function to fix this or something?!
Edit:
This is the foreach now and it works:
$productImages = $product->appendChild($this->_xmlDoc->createElement('ProductImages'));
if(isset($productInfo['ProductImages'])) {
foreach($productInfo['ProductImages']['Images'] as $image) {
if(!is_array($image) && is_string($image)) {
$productImage = $productImages->appendChild($this->_xmlDoc->createElement('ProductImage'));
$productImage->appendChild($this->_xmlDoc->createElement('ImagePath', $image));
}
if(isset($image['Url']) && is_array($image)) {
$productImage = $productImages->appendChild($this->_xmlDoc->createElement('ProductImage'));
$productImage->appendChild($this->_xmlDoc->createElement('ImagePath', $image['Url']));
}
}
}
This is how foreach looks 20 minutes after my question. So I'll vote for first answer, because its similar to my work around :)
Cheers,
Georgi!
I've encountered the same issue before with using a SOAP call. You don't need to change the structure of the array. You can simply change the behaviour of your foreach loop instead, using is_array. It checks if the variable is an array or not. Example, using your arrays:
$first_array = array(
"Images" => array(
array("Url" => "http://example.net/image1.jpg", "Default" => true),
array("Url" => "http://example.net/image2.jpg", "Default" => false),
array("Url" => "http://example.net/image3.jpg", "Default" => false)
)
);
$second_array = array(
"Images" => array(
"Url" => "http://example.net/image111.jpg",
"Default" => true
)
);
echo "Results on the first array:<br />";
foreach ($first_array["Images"] as $element) {
if (is_array($element)) {
foreach ($element as $value) {
echo $value . "<br />";
}
} else {
echo $element . "<br />";
}
}
echo "<br />";
echo "Result on the second array:<br />";
foreach ($second_array["Images"] as $element) {
if (is_array($element)) {
foreach ($element as $value) {
echo $value . "<br />";
}
} else {
echo $element . "<br />";
}
}
PHPFiddle Link: http://phpfiddle.org/main/code/4y8j-4jd1

Using a variable outside foreach with if statement?

This code should explain it all..
foreach($this->sections as $k => $section){
$preview = array();
foreach ($section['fields'] as $k => $type) {
$preview[] = $type['type'];
}
if ($preview == 'header_preview'){
echo $preview;
// I will loop content here based on the $section loop NOT the $type loop
}
}
I just need to get each $section['fields'] then outside that loop, which again gets a list of all the $section['fields'] then use one of those field types to create an if statement. The above is non working, I will show you working code here.
foreach($this->sections as $k => $section){
foreach ($section['fields'] as $k => $type) {
if ($type['type'] == 'header_preview'){
//I work but im in a nested loop I need out
}
}
//The main loop here.. the above loop is just to setup data to use inside this loop? Make sense? I hope!
}
I hope this makes sense...
Snippet of var_dump $this->sections
array(26) { ["general"]=> array(3) { ["title"]=> string(7) "General" ["icon"]=> string(106) "img/icons/sub.png" ["fields"]=> array(5) { [0]=> array(6) { ["id"]=> string(10) "responsive" ["type"]=> string(6) "switch" ["title"]=> string(35) "Responsive" ["desc"]=> string(10) "Responsive" ["options"]=> array(2) { [1]=> string(2) "On" [0]=> string(3) "Off" }
It could be possible $k has been duplicated and therefore the loop doesn't know what to do. You can try changing $k to $x, see if it works.
foreach($this->sections as $k => $section){
$preview = array();
foreach ($section['fields'] as $x => $type) {
$preview[] = $type['type'];
}
foreach($preview as $elem){
if ($elem == 'header_preview'){
echo($elem);
}
}
}
Hmm... Maybe
foreach($this->sections as $k => $section){
$preview = array();
foreach ($section['fields'] as $x => $type) {
$preview[] = $type['type'];
}
if(!in_array('header_preview', $preview)){
// Here $preview DOES NOT contain 'header_preview'
// Do stuff
}
}
$header_preview=false;
foreach($this->sections as $k => $section){
$header_preview=false;// reset the var $header_preview
foreach ($section['fields'] as $k => $type) {
if ($type['type'] == 'header_preview') $header_preview = true;
}
if($header_preview==true){
//here you can add or extract from this array that has `header_preview` value for one of it's field type
}
}

Foreach loop working, but outputting "invalid argument"?

I hope to give enough information here, but I am confused as to why the foreach loop works, it gets each data and outputs it in an li but I am getting an invalid argument error?
Here is the result of the var_dump
array(1) { ["questions"]=>
array(2) { ["title"]=> string(5) "Keanu" [1]=>
array(1) { ["questionlist"]=> array(2) { [0]=>
array(1) {
["a-question"]=> string(1) "1" } [1]=> array(1) {
["a-question"]=> string(5) "civil" } } } } }
Here is my foreach statement
foreach($questions['questions'] as $key => $value){
foreach($value['questionlist'] as $key => $subquestion){ //line 119
echo '<li>'.$subquestion['a-question'].'</li>';
}
}
$questions is a variable used to get the data from the database like this.
$questions = $wpdb->get_row("SELECT * FROM $table_name ORDER BY id DESC LIMIT 1" , ARRAY_A);
The data comes from ajax, I modify the ajax $_POST like this before sending to the database.
// Add modifications
$questions['questions'] = $_POST['questions']['data'];
// DB data
$name = $wpdb->escape($questions['questions']['title']);
$data = $wpdb->escape(json_encode($questions));
Screenshot:
I am not sure why I am getting the invalid argument, I suspect its because the array may not be formatted properly, if you need any more information let me know.
A Solution: Thanks to #didierc
I used his code and modified it a bit to display my data in a loop, basically all I did was add another foreach.
foreach($questions['questions'] as $key => $value){
if(is_array($value) && isset($value[ 'questionlist'])){
foreach($value as $key => $subquestion){ //line 119
foreach ($subquestion as $key => $value){
// This loops all the ['a-question'] data
echo '<li>''.$value['a-question'].''</li>';
}
}
}
}
Try this:
foreach ($questions['questions'] as $key => $value) {
if (is_array($value) && isset($value[ 'questionlist'])) {
foreach ($value['questionlist'] as $subnum => $subquestion) {
foreach ($subquestion as $qtitle => $qanswer) {
With variable names hopefully explicit enough. That should get you started.
NB: The data is probably easier to understand when formatted as below:
array(1) {
["questions"]=> array(2) {
["title"] => string(5) "Keanu"
[1] => array(1) {
["questionlist"]=> array(2) {
[0]=> array(1) {
["a-question"]=> string(1) "1"
}
[1]=> array(1) {
["a-question"]=> string(5) "civil"
}
}
}
}
}

Categories