CodeConnoisseur
CodeConnoisseur

Reputation: 1879

Why is my PHP foreach loop not correctly outputting data into HTML Table?

I am outputting data from a text file (not csv) into an html table using php. I am exploding the data and it returns as an array but when I use a foreach loop the data turns back into a string so I am unable to sort(). Also, the data is printing into the table 5 times as a duplicate for each book and author. How do I keep my array as an array in the foreach loop so it can be sorted and how do I only get each line to display one time in the html table? (to be properly looped through to get the display I am looking for?).

PHP

<?php
$filename = 'books.txt';
list($rows, $html_table ) = returnTable($filename);

if (empty($rows))
{
    print "<p>Total Rows in Table: ".$rows."</p>";

    print $html_table;
}
else
{
    print "No file found";
}


//Read Information from a File into an HTML table

function returnTable($filename)
{

    $arr = array();

    $html_table = "<table border='2'>";
           $html_table.= "<tr>";
           $html_table.= "<th>Title</th>";
           $html_table.= "<th>Author</th>";
           $html_table.= "</tr>\n";

    $line_ctr = 0;


    $fp = fopen($filename, 'r'); 

    if ($fp)
    {
        while(true)
        {

            $line = fgets($fp);

            if (feof($fp))
            {
                break;
            }

            $line_ctr++;

            $arr = list($title, $author) = explode('*', $line);

            //var_dump($arr); // returns an array but changes to a string in the loop below!

            foreach($arr as $books){
                $html_table.= "<tr>";
                $html_table.= "<td>".$title."</td>";
                $html_table.= "<td>".$author."</td>";
                $html_table.= "</tr>\n";
            }//END OF FOREACH LOOP           

        } //END OF WHILE LOOP

        $html_table.= "</table>";

        fclose($fp ); //Close file

        //AT THIS POINT html_table is a string again but why?
        $return_data = array($line_ctr, $html_table);

    } else {
        $return_data = array("error", "No Content here");
    }

    return $return_data;
}
?>

Upvotes: 0

Views: 805

Answers (3)

Elementary
Elementary

Reputation: 1453

Your code in this state contains many minor error which prevent you to get the expected result .I put the explanations in the comments so pay attention to them in order to avoid such errors in the future:

$filename = 'books.txt';
list($rows, $html_table ) = returnTable($filename);

if ($rows>0)//here i change something look out
{
    print "<p>Total Rows in Table: ".$rows."</p>";

    print $html_table;
}
else
{
    print "No file found";
}


//Read Information from a File into an HTML table

function returnTable($filename)
{

    // $arr = array();you don't need at all this

    $html_table = "<table border='2'>";
           $html_table.= "<tr>";
           $html_table.= "<th>Title</th>";
           $html_table.= "<th>Author</th>";
           $html_table.= "</tr>\n";

    $line_ctr = 0;


    $fp = fopen($filename, 'rb'); 

    if ($fp)
    {
        while(true)
        {

            $line = fgets($fp);



            $line_ctr++;

            /*$arr = */list($title,$isbn, $author) = explode('*', $line);//i got a sample of the books.txt content from your previous question so i add isbn but you can remove it


            // foreach($arr as $books){ no no and no
                $html_table.= "<tr>";
                $html_table.= "<td>".$title."</td>";
                $html_table.= "<td>".$isbn."</td>";
                $html_table.= "<td>".$author."</td>";
                $html_table.= "</tr>\n";
            // }//END OF FOREACH LOOP           
             if (feof($fp)) //will now allow the last element  to be fetched too
            {
                break;
            }
        } //END OF WHILE LOOP

        $html_table.= "</table>";

        fclose($fp ); //Close file


        $return_data = array($line_ctr, $html_table);

    } else {
        $return_data = array("error", "No Content here");
    }

    // return $rtn; no 

    return $return_data;
}

This code works perfectly .I know it because I test it with a sample of your previous related question

But Based on this comment:

This works and brings back the data into a table but brings the data back as a string. I need to be able to sort the data as well. Can you implement a sort() in this code?

Implement sort in a code which use fopen and fgets can be really complex and painful however the following code should satisfy your expectation:

function returnTable($filename,$sortby='title',$sortType=SORT_REGULAR,$sortOrder=SORT_ASC)
{

    $column=[];
    $line_ctr = 0;
    $books= array_map(
                        function($val) use(&$column,$sortby,&$line_ctr){
                            $line_ctr++; 
                            $val=array_combine(['title','isbn','author'],array_map('trim',str_getcsv($val,'*')));
                            $column[]=$val[strtolower($sortby)]; 
                            return $val;
                        },
                    file($filename,FILE_SKIP_EMPTY_LINES|FILE_IGNORE_NEW_LINES)); 

   if($books){
        $sortOrder=$sortOrder!==SORT_ASC&&$sortOrder!==SORT_DESC?SORT_ASC:$sortOrder;
        $sortType=in_array( $sortType,
                                [
                                    SORT_REGULAR ,SORT_NUMERIC,SORT_STRING ,
                                    SORT_LOCALE_STRING ,SORT_NATURAL,SORT_FLAG_CASE,
                                    SORT_FLAG_CASE|SORT_STRING,SORT_FLAG_CASE|SORT_NATURAL
                                ],
                            true
                           )?$sortType:SORT_REGULAR;

        $html_table = "<table border='2'>";
        $html_table.= "<tr>";
        $html_table.= "<th>Title</th>";
        $html_table.= "<th>ISBN</th>";
        $html_table.= "<th>Author</th>";
        $html_table.= "</tr>\n";


        array_multisort($column,$sortOrder,$sortType,$books);
        unset($column);

        array_map(
            function($book) use(&$html_table){
                list($title,$isbn, $author) = array_values($book);
                $html_table.= "<tr>";
                $html_table.= "<td>".$title."</td>";
                $html_table.= "<td>".$isbn."</td>";
                $html_table.= "<td>".$author."</td>";
                $html_table.= "</tr>\n";
            }
            ,
            $books
        );
        $html_table.= "</table>";
        $return_data = array($line_ctr, $html_table);
    } else {
        $return_data = array("error", "No Content here");
    }

    return $return_data;
}

with this you should be able to sort by case insensitive column name in ascending or descending order using these types of sort SORT_REGULAR ,SORT_NUMERIC,SORT_STRING ,SORT_LOCALE_STRING,SORT_NATURAL,SORT_FLAG_CASE,SORT_FLAG_CASE|SORT_STRING,SORT_FLAG_CASE|SORT_NATURAL

Upvotes: 0

Drunken M
Drunken M

Reputation: 2714

Try to output 3 variables from your function.

Seperate it into 3 parts, table header, looping contents and table footer.

The function output something like

list($table_header, $rows, $table_footer ) = returnTable($filename);

In your function make the $arr data only output as $rows.

Then the final html output something like

echo $table_header.$rows.$table_footer

Upvotes: 0

Jessie Edmisten
Jessie Edmisten

Reputation: 290

From the comments in your code it looks like you are confusing the $arr and $html_table as the same variable. $arr is always an array. $html_table is always a string.

You are getting duplicates because the foreach loop is within the while loop.

It looks like you need to take the foreach loop out of the while loop. After the while loop is complete do the sorting that you want on $arr and then run the foreach loop to create your html table.

I would try something like the following: Change $arr = list($title, $author) = explode('*', $line); to $books[] = list($title, $author) = explode('*', $line);

This will make $books a multidimensional array like the following:

Array (
    [0] => Array
        (
            [0] => The Shining
            [1] => Stephen King
        )

    [1] => Array
        (
            [0] => Interview With The Vampire
            [1] => Anne Rice
        ) 
)

With the foreach loop moved outside of the while loop, update the foreach loop like this:

foreach($books as $book) {
  $html_table .= "<td>" . $book[0] . "</td>";
  $html_table .= "<td>" . $book[1] . "</td>";
}

I'm not sure what type of sorting you will need to do so you may need to create your books array differently than this example.

Upvotes: 1

Related Questions