Convert 3D array into a HTML table - php

ARRAY
$array['1'] = null;
$array['2']['21'] = null;
$array['3']['31'] = null;
$array['3']['32'] = null;
$array['4']['41'] = null;
$array['4']['42']['421'] = null;
$array['4']['42']['422'] = null;
$array['5']['51'] = null;
$array['5']['52'] = null;
$array['5']['53']['531'] = null;
$array['5']['53']['532'] = null;
$array['5']['53']['533'] = null;
$array['6']['61']['611'] = null;
$array['6']['62'] = null;
$array['6']['63']['631'] = null;
$array['6']['63']['632'] = null;
$array['6']['63']['633'] = null;
$array['6']['63']['634'] = null;
$array['7']['71']['711'] = null;
$array['8']['81']['811'] = null;
$array['8']['81']['812'] = null;
$array['9']['91']['911'] = null;
$array['9']['91']['912'] = null;
$array['9']['92']['921'] = null;
$array['9']['92']['922'] = null;
I'm trying to convert array above into a HTML table. I need to add rowspan to get output like shown as image below but run out of juice.
PHP
//If condition is satistied
if (isset($array) && count($array) > 0)
{
//echo '<pre>'; print_r($array); exit;
//Initiate variables
$row = null;
$level_one_array = $array;
//Iterate through menu level one
foreach ($level_one_array as $level_one_name => $level_two_array)
{
//If level two is an array
if (is_array($level_two_array))
{
//Iterate through menu level two
foreach ($level_two_array as $level_two_name => $level_three_array)
{
//If level two is an array
if (is_array($level_three_array))
{
//Iterate through menu level three
foreach ($level_three_array as $level_three_name => $null)
{
$row .= '<tr>';
$row .= '<td class="td_data">' . $level_one_name . '</td>';
$row .= '<td class="td_data">' . $level_two_name . '</td>';
$row .= '<td class="td_data">' . $level_three_name . '</td>';
$row .= '</tr>';
}
}
//If level two is not an array
else
{
$row .= '<tr>';
$row .= '<td class="td_data">' . $level_one_name . '</td>';
$row .= '<td class="td_data">' . $level_two_name . '</td>';
$row .= '<td class="td_data"> </td>';
$row .= '</tr>';
}
}
}
//If level two is not an array
else
{
$row .= '<tr>';
$row .= '<td class="td_data">' . $level_one_name . '</td>';
$row .= '<td class="td_data"> </td>';
$row .= '<td class="td_data"> </td>';
$row .= '</tr>';
}
}
$table = '<table>';
$table .= '<tr><td class="td_title">Menus</td><td class="td_title">Submenus/Items</td><td class="td_title">Items</td></tr>';
$table .= $row;
$table .= '</table>';
echo $table;
}
else
{
echo '<center>No record found</center>';
}
WHAT I NEED IS THIS:

I wrote new code that will do the trick. Working with rowspan is very tricky. The key elements are calculate_rowspan() and the flag $on_level_X_row to determine whether or not it is necessary to add <tr>.
It was necessary to detach the output from the most inner foreach because you have to handle multiple rows with it. Also I added "\n" after each </tr> to make the output a little more human readable.
function calculate_rowspan($array)
{
if (!is_array($array) || count($array) == 0)
return 1;
$rowspan = 0;
foreach ($array as $key=>$value)
{
$rowspan++;
if (is_array($value) && count($value) > 0)
{
$rowspan += count($value);
// -1 because first element is one same row
$rowspan--;
}
}
return $rowspan;
}
if (is_array($array) && count($array) > 0)
{
$output = '';
foreach ($array as $level_one_name => $level_two_array)
{
if (!is_array($level_two_array) || count($level_two_array) == 0)
{
$output .= '<tr><td>';
$output .= $level_one_name;
$output .= '</td><td></td><td></td></tr>'."\n";
}
else
{
$output .= '<tr>';
$output .= '<td rowspan="'.calculate_rowspan($level_two_array).'">';
$output .= $level_one_name;
$output .= '</td>';
$on_level_one_row = TRUE;
foreach ($level_two_array as $level_two_name => $level_three_array)
{
if ( ! $on_level_one_row)
$output .= '<tr>';
else
$on_level_one_row = FALSE;
if (!is_array($level_three_array) || count($level_three_array) == 0)
{
$output .= '<td>';
$output .= $level_two_name;
$output .= '</td><td></td></tr>'."\n";
}
else
{
$output .= '<td rowspan="'.calculate_rowspan($level_three_array).'">';
$output .= $level_two_name;
$output .= '</td>';
$on_level_two_row = TRUE;
foreach ($level_three_array as $level_three_name => $null)
{
if ( ! $on_level_two_row)
$output .= '<tr>';
else
$on_level_two_row = FALSE;
$output .= '<td>';
$output .= $level_three_name;
$output .= '</td></tr>'."\n";
}
}
}
}
}
print '<table>'."\n";
print $output;
print '</table>';
}

Related

How to place HTML tags in a CSV?

I have an excel sheet. In this excel sheet it contains Parts Number, Summary, Brand, Status. I would like to be able to import CSV data which contains text that already has html so I don’t have to apply all the formatting after import.
In this new csv, it should only contain 3 columns, Parts Number, Summary and html table. In this html table, it contains Parts Number, Summary, Brand, Status.
I have already created a table using php and it worked, now I am having difficulty trying to bring the table to csv.
Here is my code:
<?php
$file = fopen("Book1.csv","r");
$file2 = fopen("Book2.csv","w");
$data = [];
$description = '<table class="table">';
while($row = fgetcsv($file)) {
$data[] = $row; //Get all the data
}
if($data){
$n_columns = count($data[0]); //Get number of columns
}
$description .= '<table border="1">';
for ($col = 0; $col < $n_columns; $col++) {
$description .= '<tr>';
foreach ($data as $row_k => $row) {
if ($row_k == 0) {
$description .= '<th>';
} else {
$description .= '<td>';
}
$description .= $row[$col] ?? '';
if ($row_k == 0) {
$description .= '</th>';
} else {
$description .= '</td>';
}
}
$description .= '</tr>';
fputcsv($file2, $data); // line 50
}
$description .= '</table>';
fclose($file);
fclose($file2);
?>
I am desperate, any help is appreciated.
If I understood you correctly, this should accomplish the task. It uses 3 functions, array_to_csv, csv_to_array and build_table.
<?php
function csv_to_array($filename, $header_row=true)
{
$handle = fopen($filename, 'r');
if ($header_row === true)
$header = fgetcsv($handle);
$data = [];
while ($row = fgetcsv($handle)) {
if ($header_row)
$data[] = array_combine($header, $row);
else
$data[] = $row;
}
return $data;
}
function array_to_csv($data, $filename, $header_row=true)
{
$handle = fopen($filename, 'w');
if ($header_row == true) {
$header = array_keys($data[0]);
fputcsv($handle, $header);
}
foreach ($data as $line) {
fputcsv($handle, $line);
}
fclose($handle);
}
function transpose_array($array)
{
$headers = array_keys($array[0]);
$transposed = [];
foreach ($array as $row) {
foreach ($headers as $header) {
if (!isset($transposed[$header]))
$transposed[$header] = [];
$transposed[$header][] = $row[$header];
}
}
return $transposed;
}
function build_table($array)
{
$transposed = transpose_array($array);
$table = '<table><tbody>';
foreach ($transposed as $heading => $row) {
$table .= '<tr><th>' . $heading .'</th>';
foreach ($row as $element) {
$table .= '<td>' . $element . '</td>';
}
$table .= '</tr>';
}
$table .= '</tbody></table>';
return $table;
}
$book1 = csv_to_array('Book1.csv');
$book2 = [];
foreach ($book1 as $row) {
$key = $row['Parts Number'];
if (!isset($book2[$key])) {
$book2[$key] = [
'Parts Number' => $key,
'Summary' => $row['Summary']
];
}
$book2[$key]['rows'][] = $row;
}
foreach ($book2 as &$product) {
$product['html table'] = build_table($product['rows']);
unset($product['rows']);
}
unset($product);
$book2 = array_values($book2);
array_to_csv($book2, 'Book2.csv');
Book1.csv contains:
Parts Number,Summary,Brand,Status,Country
6SE1200-1EA70-1,SIMOVERT P 6,Siemens,Discontinued,Germany
6SE1200-1EA70-1,SIMOVERT P 6,Siemens,Discontinued,France
6SE1200-1EA70-1,SIMOVERT P 6,Siemens,In Stock,England
6SE3012-0BA00,SIMOVERT P M,Siemens,Discontinued,-
Book2.csv output:
"Parts Number",Summary,"html table"
6SE1200-1EA70-1,"SIMOVERT P 6","<table><tbody><tr><th>Parts Number</th><td>6SE1200-1EA70-1</td><td>6SE1200-1EA70-1</td><td>6SE1200-1EA70-1</td></tr><tr><th>Summary</th><td>SIMOVERT P 6</td><td>SIMOVERT P 6</td><td>SIMOVERT P 6</td></tr><tr><th>Brand</th><td>Siemens</td><td>Siemens</td><td>Siemens</td></tr><tr><th>Status</th><td>Discontinued</td><td>Discontinued</td><td>In Stock</td></tr><tr><th>Country</th><td>Germany</td><td>France</td><td>England</td></tr></tbody></table>"
6SE3012-0BA00,"SIMOVERT P M","<table><tbody><tr><th>Parts Number</th><td>6SE3012-0BA00</td></tr><tr><th>Summary</th><td>SIMOVERT P M</td></tr><tr><th>Brand</th><td>Siemens</td></tr><tr><th>Status</th><td>Discontinued</td></tr><tr><th>Country</th><td>-</td></tr></tbody></table>"

First row of mysql data fetched through PHP is not displayed in the table

I have written a function to display the data fetched from MySQL database using PHP mysqli_query( $db_conn, $sql ); when I am calling the following display function first row of the data is not displayed. Please suggest how can I get the first row.
function display_data($retval) {
$output = '<table border="1">';
foreach($retval as $key => $var) {
$output .= '<tr>';
foreach($var as $k => $v) {
if ($key === 0) {
$output .= '<td><strong>' . $k . '</strong></td>';
} else {
$output .= '<td>' . $v . '</td>';
}
}
$output .= '</tr>';
}
$output .= '</table>';
echo $output;
}
Code for display data
if (isset( $_POST['submit'])){
$_date = $_POST["date"];
//echo $_date;
$resultArray = array();
$sql = "SELECT * FROM outstanding WHERE ondate='$_date' ";
};
/*echo json_encode($retval);*/
$retval = mysqli_query( $db_conn, $sql );
display_data($retval);
}
EDIT 2:
I was able to achieve this by the following code, please suggest if there are any better methods to display in HTML/web page.
//code to display data in table form
function display_data($retval)
{
$output = '<table border="1">';
foreach ($retval as $key => $var)
{
echo $key;
if ($key === 0)
{
$output .= '<tr>';
foreach ($var as $k => $v)
{
$output .= '<th><strong>' . $k . '</strong></th>';
};
$output .= '</tr>';
};
$output .= '<tr>';
foreach ($var as $k => $v)
{
if ($key === 0)
{
$output .= '<td>' . $v . '</td>';
echo $v;
}
else
{
$output .= '<td>' . $v . '</td>';
};
};
$output .= '</tr>';
}
$output .= '</table>';
echo $output;
}
The reason why you cannot see the first row is that you never display it. If the iteration is on the first row, you only display the header, but you skip the data.
foreach ($var as $k => $v) {
if ($key === 0) {
// If this is the first row, you display the key, but not the value.
$output .= '<td><strong>' . $k . '</strong></td>';
} else {
$output .= '<td>' . $v . '</td>';
}
}
Your suggested solution is the correct one. You need to loop the first row twice. Once to display the header and then once to display the data.
function display_data1($retval) {
$output = '<table border="1">';
foreach ($retval as $key => $var) {
if ($key === 0) {
// If key is 0, meaning first row...
$output .= '<thead><tr>';
// create new HTML row and loop the first MySQL row
foreach ($var as $k => $v) {
$output .= '<th>' . $k . '</th>';
}
$output .= '</tr></thead>';
}
// Then loop as normal all rows including the first one.
$output .= '<tr>';
foreach ($var as $k => $v) {
$output .= '<td>' . $v . '</td>';
}
$output .= '</tr>';
}
$output .= '</table>';
echo $output;
}
Warning: You are wide open to SQL Injections and should use parameterized prepared statements instead of manually building your queries. They are provided by PDO or by MySQLi. Never trust any kind of input! Even when your queries are executed only by trusted users, you are still in risk of corrupting your data. Escaping is not enough!

Display PHP Query results in table regardless of # of columns returned?

So I'm exploring the wonderful world of PHP and I'm still creating very dirty, poorly build code but I'm trying to get better! So my question is as follows:
Is there a way to automatically calculate the columns in the result set and spit out a pretty HTML table regardless of query used?
Here the current code:
<?php
include '../includes/connect.php';
include '../includes/queries.php';
$stid = oci_parse($conn, $export);
oci_execute($stid);
echo "<table class='pure-table pure-table-striped' style='font-size:11px;'><thead><tr><th>Name</th><th>File Name</th><th>Export Date</th></tr></thead>";
while (oci_fetch($stid)) {
echo "<tr><td>" . oci_result($stid, 'DISPLAY_NAME') . "</td>";
echo "<td>" . oci_result($stid, 'LAST_EXPORT_FILE') . "</td>";
echo "<td>" . oci_result($stid, 'LAST_EXPORT_DATE') . "</td></tr>";
}
echo "</table>\n";
oci_free_statement($stid);
oci_close($conn);
I'd like to use the same table every time, but just have it auto detect column header names and number of columns and return it in a table.
Is it possible or does it make sense?
I do exactly that using PDO.
$out = '';
$q = $conn->prepare($SQL);
if ($q->execute()) {
$rows = $q->fetchAll();
if (!empty($rows)) {
//We have something
$out .= "<table class='pure-table pure-table-striped' style='font-size:11px;'>";
$first = true;
//iterate on rows
foreach($rows as $row) {
//Clean out all the numeric keys - stops duplicate values
foreach ($row as $key => $value) {
if (is_int($key)) {
unset($row[$key]);
}
}
//header
if ($first) {
//write header
$out .= '<thead><tr>';
foreach ($row as $key => $value) {
$out .= '<th>' . $key . '</th>';
}
$out .= '</tr></thead>';
$first = false;
}
//write line
$out .= '<tr>';
foreach($row as $key => $value) {
$out .= '<td>' . $value . '</td>';
}
$out .= '</tr>';
}
$out .= '</table>';
}
}
echo ($out);

PHP Fetch array in table with individual styling

I have an array that i pull from a database that looks like this
id - name - shortlink - downloadurl - count - date
Now I want to display that array as a table so the administartor of the site can se the content of the database. For that, I'm using this code:
function build_table($array){
// start table
$html = '<table id="usertable">';
// header row
$html .= '<tr class="header">';
foreach($array[0] as $key=>$value){
$html .= '<th>' . $key . '</th>';
}
$html .= '</tr>';
// data rows
foreach( $array as $key=>$value){
$html .= '<tr>';
foreach($value as $key2=>$value2){
$html .= '<td>' . $value2 . '</td>';
}
$html .= '</tr>';
}
// finish table and return it
$html .= '</table>';
return $html;
And it works great.
The problem is that i wan't do display some of the columns with a different code. E.g. 'downloadurl' which is an webadress, i want to make clickable. I just can't figure out how to split up the function so that i can write the code for the individual columns.
You could try something similar to the following:
using conditionals
This is probably the most straight forward way to go about handling different attributes per column - not without its drawbacks (noted below)
// data rows
foreach( $array as $key => $value) {
$html .= '<tr>';
foreach($value as $key2 => $value2) {
if ($key2 == 'downloadurl') {
$html .= '<td>Download</td>';
} else {
$html .= '<td>' . $value2 . '</td>';
}
}
$html .= '</tr>';
}
using switch statement
If you decide on this route, it may be a bit easier to manage in the long run as if () elseif () else() can become difficult to read over time.
foreach($value as $key2 => $value2) {
switch($key2) {
case 'downloadurl':
$html .= '<td>Download</td>';
break;
default:
$html .= '<td>' . $value2 . '</td>';
}
}
use this function to generate urls:
function getURL($downloadURL)
{
$html = "<a href = '$downloadURL'>Download</a>";
return $html;
}
And your function build_table():
function build_table($array){
// start table
$html = '<table id = "usertable">';
// header row
$html .= '<tr class = "header">';
foreach($array[0] as $key => $value){
$html .= '<th>' . $key . '</th>';
}
$html .= '</tr>';
// data rows
foreach( $array as $key => $value){
$html .= '<tr>';
foreach($value as $key2 => $value2){
$value2 = ($key2 == 'downloadurl') ? getURL($value2) : $value2;
$html .= '<td>' . $value2 . '</td>';
}
$html .= '</tr>';
}
// finish table and return it
$html .= '</table>';
return $html;
}

How do I sort an associative array and split into two div's based on a value?

I like to sort an associative array into two div's based on a value.
Here's what I have now:
function showDivs($array) {
/*
* sort en group by
*/
$luxury = false;
$no_luxury = false;
$return = '';
while (list($key, $value) = each($array)) {
if ($value["MinimumRate"] < 500) {
if ($no_luxury === false) {
$return .= '<div id="no_luxury" >';
}
$return .= $value['Description'] . " : " . $value["MinimumRate"] . "<br />";
if ($no_luxury === false) {
$return .='</div>';
$no_luxury = true;
}
}
if ($value["MinimumRate"] > 500) {
if ($luxury === false) {
$return .='<div id="luxury" >';
}
$return .= $value['Description'] . " : " . $value["MinimumRate"] . "<br />";
if ($luxury === false) {
$return .='</div>';
$luxury = true;
}
}
}
return $return;
}
My code doesn't work correctly.
The div is being created and closed on the first item only. I think you meant to open it on start and close it in the end. Try this:
function showDivs($array) {
/*
* sort en group by
*/
$luxury = array();
$not_luxury = array();
foreach ($array as $value) {
if ($value["MinimumRate"] > 500) {
$luxury[] = $value;
} else {
$not_luxury[] = $value;
}
}
$return = '<div id="no_luxury" >';
foreach ($luxury as $value) {
$return .= $value['Description'] . " : " . $value["MinimumRate"] . "<br />";
}
$return .= '</div>';
$return .= '<div id="luxury" >';
foreach ($luxury as $value) {
$return .= $value['Description'] . " : " . $value["MinimumRate"] . "<br />";
}
$return .= '</div>';
return $return;
}
If the problem is when MinimumRate = 500, you whould do:
if ($value["MinimumRate"] <= 500) // this is your first 'if' in your code
or
if ($value["MinimumRate"] >= 500) // this is the second 'if' in your code

Categories