L ISTING 28.16 Continued} else if mysql_num_rows$result==0 { echo “There is nobody subscribed to list number $listid”; return false; } else { include‘class.html.mime.mail.inc’; $mail = n
Trang 1L ISTING 28.16 Continued
}
else if (mysql_num_rows($result)==0)
{
echo “There is nobody subscribed to list number $listid”;
return false;
}
else
{
include(‘class.html.mime.mail.inc’);
$mail = new html_mime_mail();
// read in the text version
$filename = “archive/$listid/$mailid/text.txt”;
$fp = fopen ($filename, “r”);
$text = fread($fp, filesize($filename));
fclose ($fp);
// read in the HTML version
$filename = “archive/$listid/$mailid/index.html”;
$fp = fopen ($filename, “r”);
$html = fread($fp, filesize($filename));
fclose ($fp);
// get the list of images that relate to this message
$query = “select path, mimetype from images where mailid = $mailid”;
if(db_connect()) {
$result = mysql_query($query);
if(!$result) {
echo “<p>Unable to get image list from database.”;
return false;
}
$num = mysql_numrows($result);
for($i = 0; $i<$num; $i++) {
//load each image from disk
$filename = “archive/$listid/$mailid/”.mysql_result($result, $i, 0);
$fp = fopen($filename, ‘r’);
$image = fread($fp, filesize($filename));
fclose($fp);
// add images to the mimemail object
$mail->add_html_image($image,
mysql_result($result, $i, 0),
28
Trang 2L ISTING 28.16 Continued
mysql_result($result, $i, 1));
} }
// add HTML and text to the mimemail object
$mail->add_html($html, $text);
// note that we build and encode the message here outside the loop, // not repeatedly inside the loop
$mail->build_message();
if($status == ‘STORED’) {
//send the HTML version of the message to administrator
$mail->send(get_real_name($admin_user), $admin_user,
$from_name, $from_address, $subject);
//send the text version of the message to administrator mail(get_real_name($admin_user).” <”.$admin_user.”>”, $subject,
$text, “From: $from_name <$from_address>”);
echo “Mail sent to $admin_user”;
$query = “update mail set status = ‘TESTED’ where mailid = $mailid”; if(db_connect())
{
$result = mysql_query($query);
}
echo “<p>Press send again to send mail to whole list.<center>”; display_button(‘send’, “&id=$mailid”);
echo “</center>”;
} else if($status == ‘TESTED’) {
//send to whole list
$query = “select subscribers.realname, sub_lists.email,
subscribers.mimetype from sub_lists, subscribers where listid = $listid and sub_lists.email = subscribers.email”;
if(!db_connect()) return false;
Trang 3L ISTING 28.15 Continued
$result = mysql_query($query);
if(!$result) echo “<p>Error getting subscriber list”;
$count = 0;
// for each subscriber while( $subscriber = mysql_fetch_row($result) ) {
if($subscriber[2]==’H’) //send HTML version to people who want it
$mail->send($subscriber[0], $subscriber[1], $from_name,
$from_address, $subject);
else //send text version to people who don’t want HTML mail mail($subscriber[0].” <”.$subscriber[1].”>”, $subject,
$text, “From: $from_name <$from_address>”);
$count++;
}
$query = “update mail set status = ‘SENT’, sent = now()
where mailid = $mailid”;
if(db_connect()) {
$result = mysql_query($query);
} echo “<p>A total of $count messages were sent.”;
} else if($status == ‘SENT’) {
echo “<p>This mail has already been sent.”;
} }
}
This function does several different things
It test mails the newsletter to the administrator before sending it It keeps track of this by
track-ing the status of a piece of mail in the database When the upload script uploads a piece of
mail, it sets the initial status of that mail to “STORED”
“TESTED” and send it to the administrator The status “TESTED” means the newsletter has
been test mailed to the administrator If the status is “TESTED”, it will be changed to “SENT”
and sent to the whole list
28
Trang 4This means each piece of mail must essentially be sent twice: once in test mode and once
in real mode
The function also sends two different kinds of email: the text version, which it sends using PHP’s mail()function; and the HTML kind, which it sends using the HTML MIME Mail class We’ve used mail()many times in this book, so let’s look at how we use the HTML MIME Mail class We will not cover this class comprehensively, but instead explain how we have used it in this fairly typical application
We begin by including the class file and creating an instance of the class:
include(‘class.html.mime.mail.inc’);
$mail = new html_mime_mail();
We then load the image details from the database and loop through them, adding each image to the piece of mail we want to send:
$mail->add_html_image($image,
mysql_result($result, $i, 0), mysql_result($result, $i, 1));
The three parameters we pass to add_html_image()are the actual image content as read from the file, the filename, and the file’s MIME type
We also need to add the body text, in both HTML and text formats:
$mail->add_html($html, $text);
Then we create the actual body of the email:
$mail->build_message();
Finally, having built the message body, we can send it We do this by retrieving and looping through each of the users subscribed to this list, and using either the HTML MIMEMIME Mail
send()or regular mail()depending on the user’s MIME type preference:
if($subscriber[2]==’H’) //send HTML version to people who want it
$mail->send($subscriber[0], $subscriber[1], $from_name,
$from_address, $subject);
else //send text version to people who don’t want HTML mail mail($subscriber[0].” <”.$subscriber[1].”>”, $subject,
$text, “From: $from_name <$from_address>”);
The first parameter of $mail->send()should be the user’s actual name, and the second parameter should be his email address
That’s it! We have now completed building the mailing list application
Trang 5Extending the Project
As usual with these projects, there are many ways you could extend the functionality You
might like to
• Confirm membership with subscribers so that people can’t be subscribed without their permission This is typically done by sending email to their accounts and deleting those who do not reply This approach will also clean out any incorrect email addresses from the database
• Give the administrator powers to approve or reject users who want to subscribe to their lists
• Add open list functionality that allows any member to send email to the list
• Let only registered members see the archive for a particular mailing list
• Allow users to search for lists that match specific criteria For example, users might be interested in golf newsletters Once the number of newsletters grows past a particular size, a search would be useful to find specific ones
Next
In the next chapter, we will implement a Web forum application that will enable users to have
online discussions structured by topic and conversational threads
28
Trang 7CHAPTER 29
Building Web Forums
Trang 8One good way to get users to return to your site is to offer Web forums These can be used for purposes as varied as philosophical discussion groups and product technical support In this chapter, we implement a Web forum in PHP An alternative is to use an existing package, such
as Phorum, to set up your forums
Web forums are sometimes also called discussion boards or threaded discussion groups The
idea of a forum is that people can post articles or questions to them, and others can read and
reply to their questions Each topic of discussion in a forum is called a thread.
We will implement a Web forum called blah-blah with the following functionality Users will
be able to
• Start new threads of discussion by posting articles
• Post articles in reply to existing articles
• View articles that have been posted
• View the threads of conversation in the forum
• View the relationship between articles, that is, see which articles are replies to other articles
The Problem
Setting up a forum is actually quite an interesting problem We will need some way of storing the articles in a database with author, title, date, and content information At first glance this might not seem much different from the Book-O-Rama database
However, the way most threaded discussion software works is that, along with showing you the available articles, it will show you the relationship between articles That is, you are able to see which articles are replies to other articles (and which article they’re following up) and which articles are new topics of discussion
You can see examples of discussion boards that implement this in many places, including Slashdot:
http://slashdot.org
Deciding how to display these relationships will require some careful thought For this system,
a user should be able to view an individual message, a thread of conversation with the relation-ships shown, or all the threads on the system
Users must also be able to post new topics or replies This is the easy part
Solution Components
As we’ve said previously, storing and retrieving the author and text of a message is easy
Trang 9The most difficult part of this application is finding a database structure that will store the
information we want, and a way of navigating that structure efficiently
The structure of articles in a discussion might look like the one shown in Figure 29.1
29
Initial posting Reply 1 Reply 1 to Reply 1
Reply 2
Reply 3 Reply 1 to Reply 3
Reply 1 to Reply 1
F IGURE 29.1
An article in a threaded discussion might be the first article in a new topic, but more commonly it is a response to
another article.
In this diagram, you can see that we have an initial posting starting off a topic, with three
replies Some of the replies have replies These replies could have replies, and so on
Looking at the diagram gives us a clue as to how we can store and retrieve the article data and
the links between articles This diagram shows a tree structure If you’ve done much
program-ming, you’ll know that this is one of the staple data structures used In the diagram there are
nodes—or articles—and links—or relationships between articles—just as in any tree structure.
(If you are not familiar with trees as a data structure, don’t worry—we will cover the basics as
we go.)
The tricks to getting this all to work are
1 Finding a way to map this tree structure into storage—in our case, into a MySQL database
2 Finding a way to reconstruct the data as required
We will begin by implementing a MySQL database that will enable us to store articles
between use
We will build simple interfaces to enable saving of articles
When we load the list of articles for viewing, we will load the headers of each article into a
tree_nodePHP class Each tree_nodewill contain an article’s headers and a set of the replies
to that article
Trang 10The replies will be stored in an array Each reply will itself be a tree_node, that can contain an array of replies to that article, which are themselves tree_nodes, and so on This continues
until we reach the so-called leaf nodes of the tree, the nodes that do not have any replies We
will then have a tree structure that looks like the one in Figure 29.1
Some terminology: The message that we are replying to can be called the parent node of the current node Any replies to the message can be called the children of the current node If you
imagine that this tree structure is like a family tree, this will be easy to remember
The first article in this tree structure—the one with no parent—is sometimes called the root node.
This can be unintuitive because we usually draw the root node at the top of dia-grams, unlike the roots of real trees.
NOTE
To build and display this tree structure, we will write recursive functions (We discussed recur-sion in Chapter 5, “Reusing Code and Writing Functions.”)
We decided to use a class for this structure because it’s the easiest way to build a complex, dynamically expanding data structure for this application It also means we have quite simple, elegant code to do something quite complex
Solution Overview
To really understand what we have done with this project, it’s probably a good idea to work through the code, which we’ll do in a moment There is less bulk in this application than in some of the others, but the code is a bit more complex
There are only three real pages in the application
We will have a main index page that shows all the articles in the forum as links to the articles From here, you will be able to add a new article, view a listed article, or change the way the articles are viewed by expanding and collapsing branches of the tree (More on this in a minute.) From the article view, you will be able to post a reply to that article or view the existing replies
to that article
The new article page enables you to enter a new post, either a reply to an existing message, or
a new unrelated message
The system flow diagram is shown in Figure 29.2