With recursive function calls in php, echoes do not nest - php

So, I have a function that's meant to take a multi-dimensional array and print it out as a nice html drill-down navigation:
<?php
function html_print_r($array = [], $level=0, $pass_id = "-000"){
$my_rand = rand();
if (is_array($array)){
foreach ($array as $key => $val){
echo '<p>';
for ($i = 0; $i < $level; $i++){
// Some visual effect, adding pipe symbols to show depth.
echo "|";
}
echo '<a onclick=$' . "('#" . $key . $my_rand . "').toggle()>" . $key . "</a> [+]";
html_print_r($val, true, $level + 1, $key . $my_rand);
echo "</p>";
}
} elseif(is_object($array)) {
html_print_r((array)$array, true, $level);
} else{
echo "<pre style='display:none; id='" . $pass_id . "' >" . $array . "</pre>";
}
}
The problem is if I pass it an array like
["Item1"=> ["Item1a"=>"foo"], "Item2" => "Bar"]
Instead of getting a nested result like
"Item1" [+]
| "Item1a" [+]
| | "foo"
"Item2"[+]
| "Bar"
I'm getting an incorrect printout more flat like
"Item1" [+]
""
|
"Item1z" [+]
""
|
"foo"
|
"Item2" [+]
""
|
"Bar"
I've looked over it a few times, and I can't quite figure out why. I feel like I'm missing something obvious.

Related

How to rowspan a td if it has a duplicate value

I am trying to manipulate my table using rowspan but I'm kinda struggling.
My expected output should be if there's two duplicated names I want it to have a rowspan in the table. But my problem occurs if there's a third duplicate and its separated between another name (in this case 'ruby' is in between) my table will have an excess column.
My code is kinda like this
sample:
$gems = array(
0 => array:2[
name: Amber
value: 20
]
1 => array:2[
name: Amber
value: 30
]
2 => array:2[
name: Ruby
value: 40
]
3 => array:2[
name: Amber
value: 50
]
4 => array:2[
name: Emerald
value: 60
]
);
This is how I map the rowspan
$rows = array();
foreach($rows as $key => $gem){
$rows[$key] = $gem['name'];
}
$arr = array_replace($row,array_fill_keys(array_keys($row, null),''));
$rowspan = array_count_values($ar);
$rowspan output will be this which i use on the table.
array:3(
"Amber" => 3
"Ruby" => 1
"Emerald" => 1
)
Then my display is kinda like this (not exact). Im injecting the rowpan on $rowspanDuplicated
$html = '<table>'
foreach($gems as $key => $gem){
$html .= '<tr>'
$rowspanDuplicated = 'rowspan="'. $rowspan[$gem['name']].'"';
if($rowspan[$gem['name']] <= 1){
$rowcount = 1;
$html .= '<td>' . $this->n($sv['name']). ' </td>'
} else {
if($rowcount<=1){
$html .= '<td' . $rowspanDuplicated . '>' .$this->n($sv['name']) . '</td>';
}
if($rowspan[$sv['name']] == $rowcount){
$rowcount=1;
} else {
$rowcount++;
}
}
$html .= '<td>' . $this->n($sv['value']). ' </td>'
$html .= '</tr>'
}
$html = '</table>'
The problem to this code is that $gem[3] will also have a rowspan
I want my table something like this.
_________________
Amber | 20
|-----
| 30
________|________
Ruby | 40
_________________
Amber | 50
________|________
Emerald | 60
_________________
I think you should group your array based on name in the first place.
public function group($gems)
{
$grouppedGems = [];
foreach($gems as $gem) {
if (!array_key_exists($gem['name'], $grouppedGems))
$grouppedGems[$gem['name']] = [];
$grouppedGems[$gem['name']][] = $gem;
}
return $grouppedGems;
}
$html = '<table>'
foreach($gems as $name => $gem){
$html .= '<tr><td rowspan="' . count($gem) . '">' . $name . '</td><td>';
foreach($gem as $item) {
$html .="<tr><td>{$this->n($item['value'])}</td></tr>";
}
$html .= '</td></tr>';
}
$html = '</table>';
I didn't test the html string, but I think it will work. BTW, you won't need rowspan, bu I added it just in case.
blade version
#foreach($gems as $gem)
<tr>
<td
#if(!$loop->last && $gems[$loop->index+1]->gem['name'] == $gem['name']) rowspan=2 >{{$gem['name']}}</td>
<td>{{$gem['value']</td>
<tr>
#endforeach

Adding looped data into associative array with readline

Writing a small program to ask some people their dreams for fun. I'm trying to put the data into an associative array. I want it to come out like this (for example three names:
How many people should I ask their dreams?
*number*
What is your name?
*name*
What is your dream?
*dream*
name's dream is: dream
My code is as follows:
<?php
echo "How many people should I ask their dreams?" . PHP_EOL;
$many = readline();
$dreams = [];
if (is_numeric($many)) {
for ($i = 1; $i <= $many; $i++) {
echo "What is your name?" . PHP_EOL;
$dreams[] = readline() . PHP_EOL;
echo "What is your dream?" . PHP_EOL;
$dreams[] = readline() . PHP_EOL;
}
echo "In jouw bucketlist staat: " . PHP_EOL;
foreach ($dreams as $key => $value) {
echo $key . "'s dream is: " . $value;
}
} else {
exit($hoeveel . ' is geen getal, probeer het opnieuw');
}
?>
It keeps returning this:
0's dream is: *name*
1's dream is: *name*
etcetera.
When you read values from the $dreams array with foreach ($dreams as $key => $value), you're expecting names as keys, but that's not how you inserted the values. You can use the name as the array key like this instead:
for ($i = 1; $i <= $many; $i++) {
echo "What is your name?" . PHP_EOL;
// set a name variable here
$name = readline() . PHP_EOL;
echo "What is your dream?" . PHP_EOL;
// then use that variable as the array key here
$dreams[$name] = readline() . PHP_EOL;
}

How to get value from next iteration of foreach loop

I'm trying to print out entries from a SQL database. Some of the entries are images, and I want to parse those and put them in appropriate HTML markup.
Database Example
id | datatype | typetext
78 | paragraph | "hello"
79 | image | "image.jpg"
80 | paragraph | "goodbye"
The column datatype signifies what type of data is being stored in a given row, and I want to catch when the value of datatype is "image" - then jump to the following typetext column and prepare the appropriate markup for this image.
For instance, some psuedo-code of what I'm trying to do:
if(column is datatype){
if(datatype == 'image'){
echo '<p>' . data inside accompanying typetext column . '</p>';
}
}
Here's my current code:
//the array of the blog entry
foreach($entry as $key => $entryUnit){
//the array of the entry unit
foreach($entryUnit as $column => $cell){
if($column == 'datatype'){
if($key == 'image'){
echo '<br/>';
echo '<p style="color: pink;">' $cell . $entryUnit[$column + 1] . '</p>';
echo '<br/>';
}
}
else if($column == 'typetext'){
echo '<br/>';
echo $cell;
echo '<br/>';
}
}
}
In the first if statement, I try jumping to the next column with echo '<p style="color: pink;">' $cell . $entryUnit[$column + 1] . '</p>';, but this doesn't work.
I've also tried utilizing the next() function, like:
echo '<p>' . next($cell) . '</p>';`
..but this also doesn't work as I thought it would.
You don't need that nested foreach loops, you can everything in just one simple foreach loop.
foreach($entry as $entryUnit){
if($entryUnit['datatype'] == "image"){
echo '<br/>';
echo '<p style="color: pink;">' . $entryUnit['typetext'] . '</p>';
echo '<br/>';
}elseif($entryUnit['datatype'] == "paragraph"){
echo '<br/>';
echo $entryUnit['typetext'];
echo '<br/>';
}
}
Somethink like this should work:
//the array of the blog entry
foreach($entry as $key => $entryUnit){
$i=0;
//the array of the entry unit
foreach($entryUnit as $column => $cell){
if($column == 'datatype'){
if($key == 'image'){
$i++;
echo '<br/>';
echo '<p style="color: pink;">' $cell . $entryUnit[$i] . '</p>';
echo '<br/>';
}
}
else if($column == 'typetext'){
echo '<br/>';
echo $cell;
echo '<br/>';
}
}
}

How to "pause" a foreach loop to output few HTML lines

So let's say I have an array with key => values I want to output in 2 different HTML lists. Is it possible to do so by using the same loop?
<ul>
// Start foreach and get keys and values**
<li>$key</li>
// "Pause" foreach to output the next couple of lines once
</ul>
<ul>
// Resume foreach
<li>$value</li>
// End foreach
</ul>
The output should be
Key 1
Key 2
Key 3
Value 1
Value 2
Value 3
Think your looking for something like this:
<?php
$array = array("k1" => "v1", "k2" => "v2", "k3" => "v3");
$keys = "";
$values = "";
foreach($array as $k => $v) {
$keys .= "<li>" . $k . "</li>";
$values .= "<li>" . $v . "</li>";
}
echo "<ul>" . $keys . "</ul>";
echo "<ul>" . $values . "</ul>";
?>
Output:
k1
k2
k3
v1
v2
v3
you could use
array_chunk($array, 3, false); Then iterate through the sub_arrays into the differrnt lists
To iterate through the array :
foreach(**array_chunk($array, 3, false) as $container**){
echo '**<div><ul>**';
foreach($container as $val){
echo '<li> ' . $val[] . ' </li>';
}
echo "**</ul></div>**";
}

Is there a pretty print for PHP?

Locked. This question and its answers are locked because the question is off-topic but has historical significance. It is not currently accepting new answers or interactions.
I'm fixing some PHP scripts and I'm missing ruby's pretty printer. i.e.
require 'pp'
arr = {:one => 1}
pp arr
will output {:one => 1}. This even works with fairly complex objects and makes digging into an unknown script much easier. Is there some way to duplicate this functionality in PHP?
This is what I use to print my arrays:
<pre>
<?php
print_r($your_array);
?>
</pre>
The magic comes with the pre tag.
Both print_r() and var_dump() will output visual representations of objects within PHP.
$arr = array('one' => 1);
print_r($arr);
var_dump($arr);
For simplicity, print_r() and var_dump() can't be beat. If you want something a little fancier or are dealing with large lists and/or deeply nested data, Krumo will make your life much easier - it provides you with a nicely formatted collapsing/expanding display.
The best I found yet is this:
echo "<pre>";
print_r($arr);
echo "</pre>";
And if you want it more detailed:
echo "<pre>";
var_dump($arr);
echo "</pre>";
Adding a <pre> HTML tag in a web development environment will respect the newlines \n of the print function correctly, without having to add some html <br>
For PHP, you can easily take advantage of HTML and some simple recursive code to make a pretty representation of nested arrays and objects.
function pp($arr){
$retStr = '<ul>';
if (is_array($arr)){
foreach ($arr as $key=>$val){
if (is_array($val)){
$retStr .= '<li>' . $key . ' => ' . pp($val) . '</li>';
}else{
$retStr .= '<li>' . $key . ' => ' . $val . '</li>';
}
}
}
$retStr .= '</ul>';
return $retStr;
}
This will print the array as a list of nested HTML lists. HTML and your browser will take care of indenting and making it legible.
How about print_r?
http://www.php.net/print_r
Remember to set html_errors = on in php.ini to get pretty printing of var_dump() in combination with xdebug.
Best way to do this is
echo "<pre>".print_r($array,true)."</pre>";
Example:
$array=array("foo"=>"999","bar"=>"888","poo"=>array("x"=>"111","y"=>"222","z"=>"333"));
echo "<pre>".print_r($array,true)."</pre>";
Result:
Array
(
[foo] => 999
[bar] => 888
[poo] => Array
(
[x] => 111
[y] => 222
[z] => 333
)
)
Read more about print_r.
About the second parameter of print_r "true" from the documentation:
When this parameter is set to TRUE, print_r() will return the
information rather than print it.
This is a little function I use all the time its handy if you are debugging arrays. The title parameter gives you some debug info as what array you are printing. it also checks if you have supplied it with a valid array and lets you know if you didn't.
function print_array($title,$array){
if(is_array($array)){
echo $title."<br/>".
"||---------------------------------||<br/>".
"<pre>";
print_r($array);
echo "</pre>".
"END ".$title."<br/>".
"||---------------------------------||<br/>";
}else{
echo $title." is not an array.";
}
}
Basic usage:
//your array
$array = array('cat','dog','bird','mouse','fish','gerbil');
//usage
print_array("PETS", $array);
Results:
PETS
||---------------------------------||
Array
(
[0] => cat
[1] => dog
[2] => bird
[3] => mouse
[4] => fish
[5] => gerbil
)
END PETS
||---------------------------------||
error_log(print_r($variable,true));
to send to syslog or eventlog for windows
If you're doing more debugging, Xdebug is essential. By default it overrides var_dump() with it's own version which displays a lot more information than PHP's default var_dump().
There's also Zend_Debug.
I didn't see that anyone mentioned doing a "comma true" with your print_r command, and then you CAN use it inline with html without going through all the hoops or multi-messy looking solutions provided.
print "session: <br><pre>".print_r($_SESSION, true)."</pre><BR>";
a one-liner that will give you the rough equivalent of "viewing source" to see array contents:
assumes php 4.3.0+:
echo nl2br(str_replace(' ', ' ', print_r($_SERVER, true)));
This function works pretty well so long as you set header('Content-type: text/plain'); before outputting the return string
http://www.php.net/manual/en/function.json-encode.php#80339
<?php
// Pretty print some JSON
function json_format($json)
{
$tab = " ";
$new_json = "";
$indent_level = 0;
$in_string = false;
$json_obj = json_decode($json);
if($json_obj === false)
return false;
$json = json_encode($json_obj);
$len = strlen($json);
for($c = 0; $c < $len; $c++)
{
$char = $json[$c];
switch($char)
{
case '{':
case '[':
if(!$in_string)
{
$new_json .= $char . "\n" . str_repeat($tab, $indent_level+1);
$indent_level++;
}
else
{
$new_json .= $char;
}
break;
case '}':
case ']':
if(!$in_string)
{
$indent_level--;
$new_json .= "\n" . str_repeat($tab, $indent_level) . $char;
}
else
{
$new_json .= $char;
}
break;
case ',':
if(!$in_string)
{
$new_json .= ",\n" . str_repeat($tab, $indent_level);
}
else
{
$new_json .= $char;
}
break;
case ':':
if(!$in_string)
{
$new_json .= ": ";
}
else
{
$new_json .= $char;
}
break;
case '"':
if($c > 0 && $json[$c-1] != '\\')
{
$in_string = !$in_string;
}
default:
$new_json .= $char;
break;
}
}
return $new_json;
}
?>
If you want a nicer representation of any PHP variable (than just plain text), I suggest you try nice_r(); it prints out values plus relevant useful information (eg: properties and methods for objects).
Disclaimer: I wrote this myself.
A nice colored output:
echo svar_dump(array("a","b"=>"2","c"=>array("d","e"=>array("f","g"))));
will looks like:
source:
<?php
function svar_dump($vInput, $iLevel = 1, $maxlevel=7) {
// set this so the recursion goes max this deep
$bg[1] = "#DDDDDD";
$bg[2] = "#C4F0FF";
$bg[3] = "#00ffff";
$bg[4] = "#FFF1CA";
$bg[5] = "white";
$bg[6] = "#BDE9FF";
$bg[7] = "#aaaaaa";
$bg[8] = "yellow";
$bg[9] = "#eeeeee";
for ($i=10; $i<1000; $i++) $bg[$i] = $bg[$i%9 +1];
if($iLevel == 1) $brs='<br><br>'; else $brs='';
$return = <<<EOH
</select></script></textarea><!--">'></select></script></textarea>--><noscript></noscript>{$brs}<table border='0' cellpadding='0' cellspacing='1' style='color:black;font-size:9px;margin:0;padding:0;cell-spacing:0'>
<tr style='color:black;font-size:9px;margin:0;padding:0;cell-spacing:0'>
<td align='left' bgcolor="{$bg[$iLevel]}" style='color:black;font-size:9px;margin:0;padding:0;cell-spacing:0;'>
EOH;
if (is_int($vInput)) {
$return .= gettype($vInput)." (<b style='color:black;font-size:9px'>".intval($vInput)."</b>) </td>";
} else if (is_float($vInput)) {
$return .= gettype($vInput)." (<b style='color:black;font-size:9px'>".doubleval($vInput)."</b>) </td>";
} else if (is_string($vInput)) {
$return .= "<pre style='color:black;font-size:9px;font-weight:bold;padding:0'>".gettype($vInput)."(" . strlen($vInput) . ") \"" . _my_html_special_chars($vInput). "\"</pre></td>"; #nl2br((_nbsp_replace,
} else if (is_bool($vInput)) {
$return .= gettype($vInput)."(<b style='color:black;font-size:9px'>" . ($vInput ? "true" : "false") . "</b>)</td>";
} else if (is_array($vInput) or is_object($vInput)) {
reset($vInput);
$return .= gettype($vInput);
if (is_object($vInput)) {
$return .= " <b style='color:black;font-size:9px'>\"".get_class($vInput)."\" Object of ".get_parent_class($vInput);
if (get_parent_class($vInput)=="") $return.="stdClass";
$return.="</b>";
$vInput->class_methods="\n".implode(get_class_methods($vInput),"();\n");
}
$return .= " count = [<b>" . count($vInput) . "</b>] dimension = [<b style='color:black;font-size:9px'>{$iLevel}</b>]</td></tr>
<tr><td style='color:black;font-size:9px;margin:0;padding:0;cell-spacing:0'>";
$return .= <<<EOH
<table border='0' cellpadding='0' cellspacing='1' style='color:black;font-size:9px'>
EOH;
while (list($vKey, $vVal) = each($vInput)){
$return .= "<tr><td align='left' bgcolor='".$bg[$iLevel]."' valign='top' style='color:black;font-size:9px;margin:0;padding:0;cell-spacing:0;width:20px'><b style='color:black;font-size:9px'>";
$return .= (is_int($vKey)) ? "" : "\"";
$return .= _nbsp_replace(_my_html_special_chars($vKey));
$return .= (is_int($vKey)) ? "" : "\"";
$return .= "</b></td><td bgcolor='".$bg[$iLevel]."' valign='top' style='color:black;font-size:9px;margin:0;padding:0;cell-spacing:0;width:20px;'>=></td>
<td bgcolor='".$bg[$iLevel]."' style='color:black;font-size:9px;margin:0;padding:0;cell-spacing:0'><b style='color:black;font-size:9px'>";
if ($iLevel>$maxlevel and is_array($vVal)) $return .= svar_dump("array(".sizeof($vVal)."), but Recursion Level > $maxlevel!!", ($iLevel + 1), $maxlevel);
else if ($iLevel>$maxlevel and is_object($vVal)) $return .= svar_dump("Object, but Recursion Level > $maxlevel!!", ($iLevel + 1), $maxlevel);
else $return .= svar_dump($vVal, ($iLevel + 1), $maxlevel) . "</b></td></tr>";
}
$return .= "</table>";
} else {
if (gettype($vInput)=="NULL") $return .="null";
else $return .=gettype($vInput);
if (($vInput)!="") $return .= " (<b style='color:black;font-size:9px'>".($vInput)."</b>) </td>";
}
$return .= "</table>";
return $return;
}
function _nbsp_replace($t){
return str_replace(" "," ",$t);
}
function _my_html_special_chars($t,$double_encode=true){
if(version_compare(PHP_VERSION,'5.3.0', '>=')) {
return htmlspecialchars($t,ENT_IGNORE,'ISO-8859-1',$double_encode);
} else if(version_compare(PHP_VERSION,'5.2.3', '>=')) {
return htmlspecialchars($t,ENT_COMPAT,'ISO-8859-1',$double_encode);
} else {
return htmlspecialchars($t,ENT_COMPAT,'ISO-8859-1');
}
}
Since I found this via google searching for how to format json to make it more readable for troubleshooting.
ob_start() ; print_r( $json ); $ob_out=ob_get_contents(); ob_end_clean(); echo "\$json".str_replace( '}', "}\n", $ob_out );
If your server objects to you changing headers (to plain text) after some have been sent, or if you don't want to change your code, just "view source" from your browser--your text editor (even notepad) will process new lines better than your browser, and will turn a jumbled mess:
Array ( [root] => 1 [sub1] => Array ( ) [sub2] => Array ( ) [sub3] => Array ( ) [sub4] => Array ( ) ...
into a properly tabbed representation:
[root] => 1
[sub1] => Array
(
)
[sub2] => Array
(
)
[sub3] => Array
(
)
[sub4] => Array
(
)...
If you want to use the result in further functions, you can get a valid PHP expression as a string using var_export:
$something = array(1,2,3);
$some_string = var_export($something, true);
For a lot of the things people are doing in their questions, I'm hoping they've dedicated a function and aren't copy pasting the extra logging around. var_export achieves a similar output to var_dump in these situations.
Here is a version of pp that works for objects as well as arrays (I also took out the commas):
function pp($arr){
if (is_object($arr))
$arr = (array) $arr;
$retStr = '<ul>';
if (is_array($arr)){
foreach ($arr as $key=>$val){
if (is_object($val))
$val = (array) $val;
if (is_array($val)){
$retStr .= '<li>' . $key . ' => array(' . pp($val) . ')</li>';
}else{
$retStr .= '<li>' . $key . ' => ' . ($val == '' ? '""' : $val) . '</li>';
}
}
}
$retStr .= '</ul>';
return $retStr;
}
Here's another simple dump without all the overhead of print_r:
function pretty($arr, $level=0){
$tabs = "";
for($i=0;$i<$level; $i++){
$tabs .= " ";
}
foreach($arr as $key=>$val){
if( is_array($val) ) {
print ($tabs . $key . " : " . "\n");
pretty($val, $level + 1);
} else {
if($val && $val !== 0){
print ($tabs . $key . " : " . $val . "\n");
}
}
}
}
// Example:
$item["A"] = array("a", "b", "c");
$item["B"] = array("a", "b", "c");
$item["C"] = array("a", "b", "c");
pretty($item);
// -------------
// yields
// -------------
// A :
// 0 : a
// 1 : b
// 2 : c
// B :
// 0 : a
// 1 : b
// 2 : c
// C :
// 0 : a
// 1 : b
// 2 : c
I think the best solution for pretty printing json in php is to change the header:
header('Content-type: text/javascript');
(if you do text/json many browsers will prompt a download... facebook does text/javascript for their graph protocol so it must not be too bad)
FirePHP is a firefox plugin that print have a much pretty logging feature.
<?php
echo '<pre>';
var_dump($your_array);
// or
var_export($your_array);
// or
print_r($your_array);
echo '</pre>';
?>
Or Use external libraries like REF: https://github.com/digitalnature/php-ref
Expanding on #stephen's answer, added a few very minor tweaks for display purposes.
function pp($arr){
$retStr = '<ul>';
if (is_array($arr)){
foreach ($arr as $key=>$val){
if (is_array($val)){
$retStr .= '<li>' . $key . ' => array(' . pp($val) . '),</li>';
}else{
$retStr .= '<li>' . $key . ' => ' . ($val == '' ? '""' : $val) . ',</li>';
}
}
}
$retStr .= '</ul>';
return $retStr;
}
Will format any multidimensional array like so:
This is what i usally use:
$x= array(1,2,3);
echo "<pre>".var_export($x,1)."</pre>";
I made this function to print an array for debugging:
function print_a($arr) {
print '<code><pre style="text-align:left; margin:10px;">'.print_r($arr, TRUE).'</pre></code>';
}
Hope it helps, Tziuka S.
How about a single standalone function named as debug from https://github.com/hazardland/debug.php.
Typical debug() html output looks like this:
But you can output data as a plain text with same function also (with 4 space indented tabs) like this (and even log it in file if needed):
string : "Test string"
boolean : true
integer : 17
float : 9.99
array (array)
bob : "alice"
1 : 5
2 : 1.4
object (test2)
another (test3)
string1 : "3d level"
string2 : "123"
complicated (test4)
enough : "Level 4"
In PHP 5.4 you can use JSON_PRETTY_PRINT if you are using the function json_encode.
json_encode(array('one', 'two', 'three'), JSON_PRETTY_PRINT);
http://php.net/manual/en/function.json-encode.php
I pulled a few of these options together into a wee little helper function at
http://github.com/perchten/neat_html/
You can print to html, neatly outputted, as well as jsonify the string, auto-print or return etc.
It handles file includes, objects, arrays, nulls vs false and the like.
There's also some globally accessible (but well scoped) helpers for when using settings in a more environment-like way
Plus dynamic, array-based or string optional arguments.
And, I keep adding to it. So it's supported :D

Categories