Jump to content
Larry Ullman's Book Forums

Recommended Posts

I created a chart demonstrating the site architecture of this example, which can be found here, and the database ERD of this example can be found here

 

REVIEW:
1.     What impact does a database's character set, or a PHP or HTML page's encoding have?
An HTML page or PHP script can specify its encoding, which dictates what characters, and therefore languages, are supported. Similarly, by setting your MySQL databases encoding, you can impact what characters can be stored in it. (Ullman 184)
 
2.     Why does the encoding and character set have to be the same everywhere? What happens if there are differences?
The encoding and character set affects what characters and languages are supported and can be stored. When communicating with MySQL those characters need to be transferred using the same encoding (Ullman 186). Failing to do so will likely result in odd characters when viewing the page in a Web browser. (Ullman 2)
 
3.     What is a primary key? What is a foreign key?
A Primary key is a unique identifier that has to abide by certain rules

  • Always have a value (cannot be NULL)
  • Have a value that remains the same (Never Changes)
  • Have a unique value for each record in a table.

A foreign key is the representation in Table B of the primary key from Table A (Ullman 167).
 
4.     What is the benefit of using UTC for stored dates and times?
Using UTC stores dates and times in a time-zone neutral way. UTC, like Greenwich Mean Time (GMT), provides a common point of origin, from which all times in the world can be expressed as UTC plus or minus some hours and minutes (Ullman 189)
 
5.     Why is the pass column in the users table set as a CHAR instead of a VARCHAR, when each user's password could be of a variable length?
CHAR will always be stored as a string the length of the column, using spaces to pad it (Ullman 117). The SHA1() function is being used to encrypt the password, which creates an encrypted string that is always exactly 40 characters long. Therefore, the users table's pass column is defined as CHAR(40) (Ullman 135).
 
6.     How do you begin a session in PHP? How do you store a value in a session? How do you retrieve a previously stored value?

session_start();
$_SESSION['key'] = value;
$_SESSION['var'];

 
7.     How do you create an alias in a SQL command? What are the benefits of using an alias?
Aliases are created using the term AS within queries. An alias is a symbolic renaming of an item used in a query to a shorter length alternative for easier callback and less typing work (Ullman 153).
 
PURSUE:

  • Modify the header and other files so that each page’s title uses both the default lang page title and a subtitle based upon the page being viewed (e.g., the name of the thread currently shown).
  • Add pagination to the forum.php script (see p316, view_users.php).
  • If you want, add the necessary columns to the words table, and the appropriate code to the PHP scripts, so that every navigational, error, and other element is language-specific. Use a Web site such as Yahoo! BabelFish (http://babelfish.yahoo.com) for the Translations.
  • Apply the redirect_user() function to post_form.php here (see p372).
  • Create a search page for this forum. If you need help, see the search.php basic example available in the downloadable code.
Link to comment
Share on other sites

1. Modify the header and other files so that each page’s title uses both the default lang page title and a subtitle based upon the page being viewed (e.g., the name of the thread currently shown).

 

Currently, the content of the page title is set in header.html by querying the words table in the database for the language-specific title. This means that every page displays the same page title set in header.html, namely, "PHP and MySQL For Dynamic Web Sites: The Forum!" (except in either english or the language set by registered users). 

 

I believe this request is asking for the title of each page to read "Default Page title - name of the thread."

 

One possible solution is to concatenate the page title set in header.html to include page-specific subtitles. I will have to set the page title in header.html to it's own variable, which I've done right after the results of the language database query are assigned to an associate array at or around line 50:

//Set the page title:
$page_title = $words['title'];

Then I change the code in the title tag to reflect the variable:

<title><?php echo $page_title; ?></title>

After I do that, I then concatenate $page_title to include the name of the thread in read.php right after assigning the fetched database rows to another associative array at or around line 55:

$page_title .=  ' - ' . $messages['subject'];

​This is where I admit defeat on my first attempt at completing the books "Review and Pursue" suggestions. Nothing is happening in the title as a result of this code. 

 

P.S. I am aware that the instructions for the Review and Pursue may very well be asking to implement a broader execution whereby the title of each page would read "Default Page title - page specific message," in each language and for every page. I believe that would require adding a new column to the words table for the subtitle of each page. Then assigning base name($SERVER['PHP_SELF']) to a variable and checking its result in a switch statement to determine which row in the database to fetch and display in the title. However, I'm not even going to try it until I figure out how to crack this much softer nut that I've been struggling with above!

Link to comment
Share on other sites

I've made some progress, namely, if I place the code: 

$page_title .=  ' - ' . $messages['subject'];
echo $page_title;

Within the conditional checking if the message is printed at or around line 60, which is itself within the while loop that assigns the queries results into an associative array, $messages[] (meaning that $messages['subject'] is local to the while loop). I can now print "Default Page title - name of the thread" onto the page as long as I do so within the while loop. However, outside of the while loop, $messages['subject'] is an unknown variable and, furthermore, the page title is not updated because the browser more than likely parses it waaay before I update it in read.php.

 

So, I see two issues to resolve in order to get this to work:

  1. Possibly turning the $messages['subject'] into a globally accessible variable.
  2. Concatenate $page_title within the code somewhere before the browser parses the page's title in order to reflect the updated $page_title variable.

 

Any tips, advice, or suggestions would be appreciated of course! Meanwhile, I will continue on to the next Pursue bullet point and consider alternative solutions to implement this bullet point.

Link to comment
Share on other sites

2. Add pagination to the forum.php script (see p316, view_users.php)

 

Instructions for paginating search results were given on p.316 and implemented in the file, view_users.php, from chapter 10. Mirroring those steps for the forum.php file, I begin by declaring a variable that sets the number of records to be displayed on each page. However, I've changed the number to be displayed to 4 so that I can test the pagination without having to create a dozen new threads. I added this new code right before the main database query in forum.php, and will simply include my heavily commented code here:

//set the number of records to be displayed on each page (this will correspond to the y in a LIMIT clause):
$display = 4;

//check if the number of pages, $_GET['p'] has already been determined in the
//URL (by the if ($pages > 1) function below) and is a numeric value:
if (isset($_GET['p']) && is_numeric($_GET['p'])) {
	//retrieve that information and store it in the $pages variable:
	$pages = $_GET['p'];
    } else {

A tip on page 322 says that "if the paginated links don't match the number of records returned it's most likely because the main query and the COUNT() query are too different. These two queries will never be the same, but they must perform the same join (if applicable) and have the same WHERE and/or GROUP BY clauses to be accurate" (Ullman 322). So, I took the main query and carried over the same JOIN and GROUP BY clauses to the COUNT() query in order to reconcile the 2 queries and get the correct amount of paginated links (let me know if it can be stripped further because now it's a MOTHER):

 //count the number of records in the db. Adjusted to match the main query, see tip2 p.322:
        $q = "SELECT COUNT(subject) FROM threads AS t
        INNER JOIN posts AS p USING (thread_id)
        INNER JOIN users AS u ON t.user_id = u.user_id
        WHERE t.lang_id = {$_SESSION['lid']}";

	$r = @mysqli_query ($dbc, $q);
	
	//Handle the returned row of the SELECT query as an Indexed array and assign to a variable:
	$row = @mysqli_fetch_array ($r, MYSQLI_NUM);
	
	//store the retrieved info in a variable:
	$records = $row[0];
	
	//if the # of records is greater then the # assigned to the $display variable (line 23):
	if ($records > $display) {
	    
            //determine the number of pages by dividing the # of records with $display
            $pages = ceil ($records/$display); //ceil returns the next highest integer of the result
	} else { //if $records is not greater than $display:
	    
            //only 1 page is required:
            $pages = 1;
	}
    } //end of check $_GET['p'] ---------------------------------------------------------

//check if the starting point, $_GET['s'] has already been set (by if ($pages > 1) function below):
if (isset($_GET['s']) && is_numeric($_GET['s'])) {
	
	//if it has, assign it to the $start variable (this will correspond to the x in a LIMIT clause):
	$start = $_GET['s'];
    } else {
	$start = 0;
    } //end the starting point conditional ----------------------------------------------

Adding sorting functionality, if the user sets the $sort by clicking a link in the table header, then $sort uses that value, otherwise $sort is assigned a default value of 'last' (corresponds with the alias set for the last post in the db query):

$sort = (isset($_GET['sort'])) ? $_GET['sort'] : 'last';

Just as in view_users.php, I determine how the results should be ordered in a switch statement (the variable, $order_by, will also be used in the db query):

switch ($sort) {
    case 'subj':
        $order_by = 't.subject ASC';
        break;
    case 'user':
        $order_by = 'username ASC';
        break;
    case 'resp':
        $order_by =  'responses ASC';
        break;
    case 'first':
        $order_by =  'first ASC';
        break;
    case 'last':
        $order_by =  'last ASC';
        break;
    default:
        $order_by = 'last ASC';
        $sort = 'last';
        break;
    } // end switch

Moving down the view_users.php file, I change forum.php's ORDER BY clause to reflect the number of records to return, as well as the sorting order. The ORDER BY clause is set by the $order_by variable within the switch statement and will indicate how the returned results should be ordered. The LIMIT clause dictates with which record to begin retrieving ($start) and how many to return ($display) from that point (see Ullman 320 & 326):

... ORDER BY $order_by LIMIT $start, $display";

Next, I adjusted the table header row in order to make the results sortable, assigning the values passed in the url to the corresponding values in the switch statement created above:

echo '<table width="100%" border="0" cellspacing="2" cellpadding="2" align="center">
    <tr>
        <td align="left" width="50%"><em><a href="forum.php?sort=subj">' . $words['subject'] . '</a></em>:</td>
        <td align="left" width="20%"><em><a href="forum.php?sort=user">' . $words['posted_by'] . '</a></em>:</td>
        <td align="center" width="10%"><em><a href="forum.php?sort=first">' . $words['posted_on'] . '</a></em>:</td>
        <td align="center" width="10%"><em><a href="forum.php?sort=resp">' . $words['replies'] . '</a></em>:</td>
        <td align="center" width="10%"><em><a href="forum.php?sort=last">' . $words['latest_reply'] . '</a></em>:</td>
    </tr>';

NOTE:

Nothing is displayed in the html table for the "latest reply" and "posted on" columns using the following in the database query: 

MAX(DATE_FORMAT($last, '%e-%b-%y %l:%i %p')) AS last, MIN(DATE_FORMAT($first, '%e-%b-%y %l:%i %p')) AS first 

After closing the html table, I inserted code directly from view_users.php, with minimal changes to reflect the page's url, as shown below with heavy commenting for explanation:

    //begin paginated-links creation section:
    if ($pages > 1) { //when there is more than 1 page:
        echo '<br /><p>';
        
        //determine the current page by dividing the starting number by the display number + 1 (p321):
        $current_page = ($start/$display) + 1;
        
        //create a 'Previous' link to the previous page when necessary:
        if ($current_page != 1) { //if the current page is not the first page:
         
            //create a previous link to the earlier result (made up of the script
            //name, the starting point, which is calculated by taking the starting
            //point minus the # being displayed, and the number of pages)
            //this has been modified to pass a sort value, see p326:
            echo '<a href="forum.php?s=' . ($start - $display) . '&p=' . $pages . '&sort=' . $sort . '">Previous</a> ';
        }
        
        //make the paginated-links (represented as numbers) by
        //looping from 1 to the total number of pages:
        for ($i = 1; $i <= $pages; $i++) {
            
            //make all the pages active links, except for the current one:
            if ($i != $current_page) {
                
                //For each link, the starting point, s, will be calculated by multiplying
                //the # of records to display per page times one less than $i (p322):
                //this has been modified to pass a sort value, see p326:
                echo '<a href="forum.php?s=' . (($display * ($i - 1))) . '&p=' . $pages . '&sort=' . $sort . '">' . $i . '</a> ';
            } else {
                echo $i . ' ';
            } //end of if conditional
            
        } // End of FOR loop.
        
        // If it's not the last page, make a 'Next' link:
        if ($current_page != $pages) {
            
            //this has been modified to pass a sort value, see p326:
            echo '<a href="forum.php?s=' . ($start + $display) . '&p=' . $pages . '&sort=' . $sort . '">Next</a>';
        }
        
    } //end of pagination link creation section

NOTE

Attempting to test this code, I discovered that I was unable to create a new thread using post.php. Looking over the downloaded code, the book's code, and the code that I've written using the book, there is no issue or discrepancies. I believe this issue is because only registered users can create new threads or post messages, and I haven't set up a registration or log-in system yet (I may just combine the message board and user registration example into one application, since a log-in system is assumed here).

 

Therefore, I have to manually insert new threads into the db. This would involve adding records into the thread and posts tables, which I did in phpMyAdmin (only changing the thread_id, post_id, subject, message, and posted_on values for each new thread):

INSERT INTO threads (thread_id, lang_id, user_id, subject) VALUES (13, 1, 1, 'Test 5');
INSERT INTO posts (post_id, thread_id, user_id, message, posted_on) VALUES (20, 13, 1, 'This is test 5.', '2011-07-29 05:01:02');

I've added 5 new threads all together and also changed the $display variable set in forum.php to 4 to test the pagination. 

Link to comment
Share on other sites

Hi Larry,

Thanks, it's so great that you have provided us all with this valuable resource and that you make yourself available to your adoring fans! I'm hoping that I can really get into web development and have realized that participating in a vibrant community of experts and novices could help me to achieve my goals.

Link to comment
Share on other sites

I have to say that the main database query in forum.php of chapter 17 was mind-boggling after the months since I've read this book or reviewed the scripts. At the same time, I view it's complexity as an opportunity to review many of the material covered in the book on querying databases with PHP. Since that's what I'm trying to do here, I thought I would break it down and try to understand every last bit of it:

$q = "SELECT t.thread_id, t.subject, username, COUNT(post_id) - 1 AS responses,
MAX(DATE_FORMAT($last, '%e-%b-%y %l:%i %p')) AS last, MIN(DATE_FORMAT($first,
'%e-%b-%y %l:%i %p')) AS first FROM threads AS t INNER JOIN posts AS p USING
(thread_id) INNER JOIN users AS u ON t.user_id = u.user_id WHERE t.lang_id =
{$_SESSION['lid']} GROUP BY (p.thread_id) ORDER BY $order_by LIMIT $start, $display";

The query returns the ID and subject of each thread from the threads table, the name of the user who started the thread from the users table, the # of replies to each thread (assigned to the alias, responses). NOTE:  When selecting from multiple tables dot syntax (table.column) is required (see Ullman 205):

$q = "SELECT t.thread_id, t.subject, username, COUNT(post_id) - 1 AS responses,

As well as the date the thread was started (assigned to the alias, last), and the date the thread last had a reply (assigned the alias, first), from the posts table:

MAX(DATE_FORMAT($last, '%e-%b-%y %l:%i %p')) AS last, 
MIN(DATE_FORMAT($first, '%e-%b-%y %l:%i %p')) AS first 

Meaning this query selects 3 tables, total, in order to produce a virtual table of results (see Ullman 204 on joins). The DATE_FORMAT function is explained on page 162 and can be used to format both the date and time using a combination of key codes and the percent sign to indicate what values you want returned (see table 5.5). The results of the formatting, %e-%b-%y %l:%i %p, would be 10-Jan-14 3:32 PM, for example. This function is used in conjunction with the MAX() and MIN() functions which predictably return the largest and smallest values in a column (see p.214).

 

The overarching structure of this query is a join between threads and posts using the thread_id column: 

FROM threads AS t INNER JOIN posts AS p USING (thread_id) 

An inner join returns all of the records from the named tables wherever a match is made (here, thread_id).

 

This result is then joined with the users table using the user_id column. Joining 3 or more tables results in a relationship between the initial virtual table and the third table:

INNER JOIN users AS u ON t.user_id = u.user_id WHERE t.lang_id = {$_SESSION['lid']}

An inner join between the newly created virtual table and the users table returns all of the records from the named tables wherever a match is made. Here, based on two conditionals, when the user_id in the threads table matches the user_id in the users table and where the lang_id column in the threads table matches the lid set in the session.

 

When those two conditions are met, the result is a final virtual table that finds every post from the posts table and returns 2 records from the threads table, and 3 records from the posts table (2 of which are the result of a function) based on a matching thread_id between the threads and posts tables. It then finds every username from the users table, but only when t.user_id = u.user_id between the threads (or if you'd like, the newly created virtual table because those results have already been filtered by the first joins conditions) and  the users tables and lastly, only those records where the language id matches the language id set in the session (see Ullman 205 on inner joins and 212 on joining multiple tables). Again, here is the code joining all 3 tables:

FROM threads AS t INNER JOIN posts AS p USING (thread_id) INNER JOIN users AS u ON t.user_id = u.user_id WHERE t.lang_id = {$_SESSION['lid']}

Lastly, the columns of the virtual table are grouped by the thread_id column in posts, the ORDER BY clause is set to reflect the sorting order and a LIMIT clause will determine the start and finish of the returned columns (much like an array set to start on x and finish on y). The ORDER BY clause is set by the $order_by variable within the switch statement and will indicate how the returned results should be ordered. The LIMIT clause dictates with which record to begin retrieving ($start) and how many to return ($display) from that point (see Ullman 320 & 326):

GROUP BY (p.thread_id) ORDER BY $order_by LIMIT $start, $display";

Now that mind-boggling query doesn't seem so mind-boggling anymore!

$q = "SELECT t.thread_id, t.subject, username, COUNT(post_id) - 1 AS responses,
MAX(DATE_FORMAT($last, '%e-%b-%y %1:%i %p')) AS last, MIN(DATE_FORMAT($first,
'%e-%b-%y %1:%i %p')) AS first FROM threads AS t INNER JOIN posts AS p USING
(thread_id) INNER JOIN users AS u ON t.user_id = u.user_id WHERE t.lang_id =
{$_SESSION['lid']} GROUP BY (p.thread_id) ORDER BY $order_by LIMIT $start, $display";
Link to comment
Share on other sites

3. If you want, add the necessary columns to the words table, and the appropriate code to the PHP scripts, so that every navigational, error, and other element is language-specific. Use a Web site such as Yahoo! BabelFish (http://babelfish.yahoo.com) for the Translations.

 

This would require a lot more digging and user-testing than I'm willing to put in, so I'll find one example where this is needed and try to implement a translation in another language. In fact, post.php is riddled with error messages and read.php has an error message in only english as well. I'll tackle read.php's single error message in order to consider that page completed:

} else { // invalid thread ID:
    echo '<p>This page has been accessed in error.</p>';
}  // End IF ($tid)

First, I would have to create a new column within the words table (see Ullman 222):

ALTER TABLE words ADD COLUMN access_error VARCHAR(40) NOT NULL;

phpMyAdmin says the query ran successfully, but I want to check that the new column exists in the table (Ullman 188):

SHOW COLUMNS FROM words;

After confirming that the new column exists, I add French and English translations using an UPDATE (Ullman 149):

UPDATE words SET access_error = 'This page has been accessed in error.' WHERE lang_id = 1;

Then I confirm the new row (Ullman 138 - 140):

SELECT access_error FROM words WHERE lang_id = 1;

NOTE:

I figured out how to do this by using phpMyAdmin's UI and then looking at the query that was used, so yes, I cheated. For instance, I wouldn't have thought I could get at the words table within a query that I previously thought was only meant to manipulate the database as a whole. But, I did learn a couple of things along the way, first, because the lang_id is assigned a UNIQUE index it cannot be replicated (Ullman 179), so trying a simple INSERT INTO will not work, second, you cannot use a WHERE clause with an INSERT INTO query (such as INSERT INTO WHERE lang_id = 1). It just didn't work. Third, using an IF conditional function within my query (Ullman 218) got me close as an alternative solution:

INSERT INTO words (access_error) VALUES (IF(lang_id = 1, 'This page has been accessed in error.', ''));

It went through all right, but nothing was inserted. I'm not sure what the issue was, but it seems like a reasonable alternative and I walked away from it thinking it's possible, but that I was doing something wrong.

 

 

Finally, to wrap up this bullet point, I simply change the original error message within read.php to this:

} else { //invalid thread ID:

    echo "<p>{$words['access_error']}</p>";

}  //End IF ($tid)

To test this out I go to, localhost/forum2/read.php?tid=1000 and there is my message!

Link to comment
Share on other sites

4. Apply the redirect_user() function to post_form.php here (see p372).

 

The redirect_user() function was introduced in Chapter 12, "Cookies and Sessions" and script 12.2 - login_functions.inc.php. Looking over that script, the function seems pretty straightforward, dynamically creating an absolute URL and redirecting users that log-in or to the home page when not logged-in.

 

The post_form.php is meant to be an included file and therefore it can never be accessed directly, also, because only logged-in users can access it, it makes sense to immediately re-direct users to index.php when they access this file in error. Currently, post_form.php has a function that redirects users, but the redirect_user() function seems much more versatile. But, to be honest it is that versatility that makes implementing this example no fun - it's a copy and paste job!

// Function that re-directs  a user upon successfully logging-in, or to an index page if they aren't logged-in

//begin defining the new function:
function redirect_user ($page = 'index.php') { //defines a default URL
   
    //start defining the URL:
    $url = 'http://' . $_SERVER['HTTP_HOST'] . dirname($_SERVER['PHP_SELF']);
    //assigns the values of http:// plus the host name (www or localhost), the current
    //directory and then the current script (http://www.example.com/somedir/)
   
    //remove any ending slashes from the URL:
    $url = rtrim($url, '/\\'); //by default rtrim removes spaces from the right side of a string, if provided with a list of characters as a second argument, it'll chop those off instead
   
    //append the specific page to the URL:
    $url .= '/' . $page; // '/' is added because all trailing slashes were removed by the rtrim function
   
    //redirect the user (see p355-357 on header function):
    header("Location: $url");
    exit(); //Quit the script
   
} //end of redirect_user() function

NOTE:

This function is invoked within login.php and logged in.php to redirect the user upon successful/unsuccessful log-ins. Come to think of it, it makes a lot of sense to define this function within login_functions.inc.php in order to modularize the site ("PHP Advanced and Object-Oriented Programming" 44). I don't see where I could use this in the current site's architecture, but I'm thinking this is going to be rethought when I integrate the message board with the user registration example from chapter 18...

Link to comment
Share on other sites

5. Create a search page for this forum. If you need help, see the search.php basic example available in the downloadable code.

 

The first thing I noticed about this is that search.php was nowhere to be found in the book, but I did find it in the downloaded scripts just as was instructed. So, this is going to have to be reverse-engineered like in the real world. I tested this in the browser right away and noticed that there is no translations in the words table for "search," so that will be the first thing to do:

ALTER TABLE words ADD COLUMN search VARCHAR(30) NOT NULL;
SHOW COLUMNS FROM words;

Then:

UPDATE words SET search = 'search' WHERE lang_id = 1;
SELECT search FROM words WHERE lang_id = 1;

I want a search bar in the main menu, so I'll use most of the same code from search.php in header.html. However, I don't want the results to show in the sidebar, so I'll get rid of this code and just let search.php handle the details:

// Handle the form.
if (isset($_GET['terms']) {

// Clean the terms:
$terms = mysqli_real_escape_string($dbc, htmlentities(strip_tags($_GET['terms'])));

 // Run the query...
$q = "SELECT * FROM languages WHERE lang_id = 100";
    $r = mysqli_query($dbc, $q);
    if (mysqli_num_rows($r) > 0) {
         echo '<h2>Search Results</h2>';
    } else {
        echo '<p>No results found.</p>';
    } 

After doing that I came across some formatting issues, so I decided to move the word "search" into the input field by setting it as the default value. I do this within the conditional that makes the input value sticky in both header.html and search.php:

} else {
    echo 'value="' .  $words['search'] . '" ';
}

This also means I had to make sure the submitted form ignores that default value in search.php:

if (isset($_GET['terms']) && $_GET['terms'] != $words['search']) {

This has a couple of effects. First, the message "No results found." no longer appears when the default value of "search" is used. This is probably because the IF conditional returns false right away and nothing happens. So, maybe I should add an else-if conditional to it (search.php):

} else if ($_GET['terms'] == $words['search']) {
            echo '<p>Please enter a search term.</p>';
}

Another thing that is happening is when I click submit within search.php's input I go to: http://localhost/forum2/forum.php?lid=0&terms=search&submit=Submit - Even with the else if clause, WHAT'S THAT! Also, this happens no matter the search term used within search.php's input field. I hope I didn't mess it up

 

P.S.

Can someone explain how the db query:

$q = "SELECT * FROM languages WHERE lang_id = 100";

Actually produces results specific to the search term? 

Link to comment
Share on other sites

Well, that completes all the bullet points for review and pursue. Sadly, there is still three known issues that I was unable to resolve:

 

  1. The first bullet point, modifying the page title to include a page-specific subtitle, was pretty much an epic failure, even though I went in thinking it was going to be the easiest. I would appreciate if anybody could provide new insights into the issue, see reply #3 for details.
  2. While adding paginating functionality, reply #5, the database query for the last and first posts within forum.php doesn't produce any results.
  3. Adding a search page, search.php - reply #12, redirects me to forum.php no matter what I search for and without filtering the results.

The code that I've developed for this example can be viewed here, if anyone would like to take a look at the completed examples and to offer any advice on fixing the known (or unknown) issues. I will move on to the next example, Ch.18 Review And Pursue - User Registration Example, but will integrate this example into that one in order to fulfill my larger goal of creating a finished web project, ready for launch on the web. Thanks for reading!

Link to comment
Share on other sites

  1. The first bullet point, modifying the page title to include a page-specific subtitle, was pretty much an epic failure, even though I went in thinking it was going to be the easiest. I would appreciate if anybody could provide new insights into the issue, see reply #3 for details.

I didn't take the time to look at your previous. code. I think what you need to do is in each page, set variable:

$subtitle = "here is subtitle for page one"

Place this before you include your header file.

Then header file echos $subtitle,

Link to comment
Share on other sites

Hi abigail!

 

Thanks for the tip, I never thought to tackle the issue from that angle and playing around with it I did get something going. However, I wanted to be able to add the name of each thread within read.php as the subtitle (namely, $messages['subject']), and maybe even use language-specific subtitles for the other pages (like $words['specific_page']). In my last attempt at a solution, reply #4 - this thread, I imagined that I needed to:

  1. Possibly turning the $messages['subject'] into a globally accessible variable.
  2. Concatenate $page_title within the code somewhere before the browser parses the page's title in order to reflect the updated $page_title variable.

Your tip aligns well with the second objective, but the first objective is a massive wrench in the gears of the larger goal. 

 

Link to comment
Share on other sites

If I understand correctly, which I might not because I don't have that book, you have the subject and other information in the database.

What you need to do is get any of the Page Title and others that Header uses, you have to get it from the database before you include the header.

So first include the config file, then open and retrieve from the database, then call the header.

 

You could make it global but I think that would really be overkill and not likely what Larry was looking for in this example.

But if there is no other way then that would be a solution.

Link to comment
Share on other sites

Hi abigail,

 

So first include the config file, then open and retrieve from the database, then call the header.

 

Ok, I think I know what needs to happen now! The message board example does not contain a config file and currently the database connection is established within header.html, meaning it absolutely must be included early in the script in order for any database query's to take place. So, adding a config file is necessary if I want to be able to untether the database connection file from the header file.

 

As a reminder, I ultimately want to retrieve the records from the database for the thread's subject ($messages['subject']), before calling the header in read.php in order to use each thread's subject as a subtitle within the title tags in header.html.

 

The issue that arises from this solution is that header.html currently queries the database as well for the language-specific words to use throughout the site ($words['welcome']). Apparently however, including both the config file and then the header.html file doesn't result in a database connection for header.html:

An error occured in script '../Sites/forum2/htdocs/includes/header.html' on line 40: Undefined variable: dbc

I've also discovered the following:

1.    Including config.inc.php in header.html results in a duplication of the custom error_handler function:

Fatal error: Cannot redeclare my_error_handler() (previously declared in ../Sites/forum2/htdocs/includes/config.inc.php:18) in ../Sites/forum2/htdocs/includes/config.inc.php on line 18

2.    Pasting the code that queries the database for the language-specific words ($words['welcome']) within config.inc.php doesn't work because there is no actual database connection in config.inc.php:

An error occured in script '../Sites/forum2/htdocs/includes/config.inc.php' on line 64: Undefined variable: dbc

You'll have to excuse me, I've gotten in over my head, or at the very least, I still don't understand a key feature of the basic nature about how php and mysql work together as yet. But I'm eagerly anticipating another a-ha moment soon!

Link to comment
Share on other sites

Because your header file already opens the database, can you get the subject there? That would actually be easier even. You will catch on when it works, that's probably why he challenges you to do this. When you see it working, where it's called from, and experiment a little it will all make sense.

Link to comment
Share on other sites

 Share

×
×
  • Create New...