17.6.1 Problem
17.6.2 Solution
// open a connection to the nntp server
$server = '{news.php.net/nntp:119}';
$group = 'php.general'; // main PHP mailing list
$nntp = imap_open("$server$group", '', '', OP_ANONYMOUS);
// get header
$header = imap_header($nntp, $msg);
// pull out fields
$subj = $header->subject;
$from = $header->from;
$email = $from[0]->mailbox."@".$from[0]->host;
$name = $from[0]->personal;
$date = date('m/d/Y h:i A', $header->udate);
// get body
$body = nl2br(htmlspecialchars(imap_fetchbody($nntp,$msg,1)));
// close connection
imap_close($nntp);
17.6.3 Discussion
Reading news from a news server requires you to connect to the
server and specify a group you're interested in reading:
// open a connection to the nntp server
$server = "{news.php.net/nntp:119}";
$group = "php.general";
$nntp = imap_open("$server$group",'','',OP_ANONYMOUS);
The function imap_open( )
takes four parameters. The first specifies the news server to use and the
newsgroup to read. The server here is news.php.net, the news server
that mirrors all the PHP mailing lists. Add /nntp to let the IMAP
extension know you're reading news instead of mail, and specify 119 as
a port; that's typically the port reserved for NNTP. NNTP stands for Network News Transport Protocol; it's used to communicate
with news servers, just as HTTP communicates with web servers. The group is
php.general, the main mailing list of the PHP
community.
The middle two arguments to imap_open( ) are a
username and password, in case you need to provide verification of your
identity. Because news.php.net is open to all
readers, leave them blank. Finally, pass the flag OP_ANONYMOUS, which
tells IMAP you're an anonymous reader; it will not then keep a record of you in
a special .newsrc file.
Once you're connected, you usually want to either get a general
listing of recent messages or all the details about one specific message. Here's
some code that displays recent messages:
// read and display posting index
$last = imap_num_msg($nntp);
$n = 10; // display last 10 messages
// table header
print <<<EOH
<table>
<tr>
<th align="left">Subject</th>
<th align="left">Sender</th>
<th align="left">Date</th>
</tr>
EOH;
// the messages
for ($i = $last-$n+1; $i <= $last; $i++) {
$header = imap_header($nntp, $i);
if (! $header->Size) { continue; }
$subj = $header->subject;
$from = $header->from;
$email = $from[0]->mailbox."@".$from[0]->host;
$name = $from[0]->personal ? $from[0]->personal : $email;
$date = date('m/d/Y h:i A', $header->udate);
print <<<EOM
<tr>
<td><a href="$_SERVER[PHP_SELF]"?msg=$i\">$subj</a></td>
<td><a href="mailto:$email">$name</a></td>
<td>$date</td>
</tr>
EOM;
}
// table footer
echo "</table>\n";
To browse a listing of posts, you need to specify what you want
by number. The first post ever to a group gets number 1, and the most recent
post is the number returned from imap_num_msg( ). So, to get the last
$n messages, loop from $last-$n+1 to $last.
Inside the loop, call imap_header( ) to pull out the header information
about a post. The header contains all the metainformation but not the actual
text of the message; that's stored in the body. Because the header is usually
much smaller than the body, this allows you to quickly retrieve data for many
posts without taking too much time.
Now pass imap_header( ) two
parameters: the server connection handle and the message number. It returns an
object with many properties, which are listed in Table 17-2.
|
Name
|
Description
|
Type
|
Example
|
|---|---|---|---|
|
date or Date
|
RFC 822 formatted date: date('r')
|
String
|
Fri, 16 Aug 2002 01:52:24 -0400
|
|
subject or Subject
|
Message subject
|
String
|
Re: PHP Cookbook Revisions
|
|
message_id
|
A unique ID identifying the message
|
String
|
<20030410020818.
33915.php@news.example.com>
|
|
newsgroups
|
The name of the group the message was posted to
|
String
|
php.general
|
|
toaddress
|
The address the message was sent to
|
String
|
php-general@lists.php.net
|
|
to
|
Parsed version of toaddress field
|
Object
|
mailbox: "php-general", host: "lists-php.net"
|
|
fromaddress
|
The address that sent the message
|
String
|
Ralph Josephs <ralph@example.net>
|
|
from
|
Parsed version of fromaddress field
|
Object
|
personal: "Ralph Josephs", mailbox: "ralph", host:
"example.net"
|
|
reply_toaddress
|
The address you should reply to, if you're trying to contact
the author
|
String
|
rjosephs@example.net
|
|
reply_to
|
Parsed version of reply_toaddress field
|
Object
|
Mailbox: "rjosephs", host: "example.net"
|
|
senderaddress
|
The person who sent the message; almost always identical to the
from field, but if the from field doesn't uniquely identify
who sent the message, this field does
|
String
|
Ralph Josephs <ralph@example.net>
|
|
sender
|
Parsed version of senderaddress field
|
Object
|
Personal: "Ralph Josephs", mailbox: "ralph", host:
"example.net"
|
|
Recent
|
If the message is recent, or new since the last time the user
checked for mail
|
String
|
Y or N
|
|
Unseen
|
If the message is unseen
|
String
|
Y or " "
|
|
Flagged
|
If the message is marked
|
String
|
Y or " "
|
|
Answered
|
If a reply has been sent to this message
|
String
|
Y or " "
|
|
Deleted
|
If the message is deleted
|
String
|
Y or " "
|
|
Draft
|
If the message is a draft
|
String
|
Y or " "
|
|
Size
|
Size of the message in bytes
|
String
|
1345
|
|
udate
|
Unix timestamp of message date
|
Int
|
1013480645
|
|
Mesgno
|
The number of the message in the group
|
String
|
34943
|
Some of the more useful fields are: size,
subject, the from list, and udate. The size
property is the size of the message in bytes; if it's 0, the message was either
deleted or otherwise removed. The subject field is the subject of the
post. The from list is more complicated. It's an array of objects; each
element in the array holds an object with three properties: personal,
mailbox and host. The personal field is the name of
the poster: Homer Simpson. The mailbox field is the part of
the email address before the @ sign: homer. The host is the
part of the email address after the @ sign: thesimpsons.com. Usually,
there's just one element in the from list array, because a message
usually has just one sender.
Pull the $header->from object into $from
because PHP can't directly access $header->from[0]->personal due
to the array in the middle. Then combine $from[0]->mailbox and
$from[0]->host to form the poster's email address. Use the ternary
operator to assign the personal field as the poster's name, if one is
supplied; otherwise, make it the email address.
The udate field is the posting time as an Unix
timestamp. Use date( ) to convert it from seconds to a more human-friendly format.
You can also view a specific posting as follows:
// read and display a single message
$header = imap_header($nntp, $msg);
$subj = $header->subject;
$from = $header->from;
$email = $from[0]->mailbox."@".$from[0]->host;
$name = $from[0]->personal;
$date = date('m/d/Y h:i A', $header->udate);
$body = nl2br(htmlspecialchars(imap_fetchbody($nntp,$msg,1)));
print <<<EOM
<table>
<tr>
<th align=left>From:</th>
<td>$name <<a href="mailto:$email">$email</a>></td>
</tr>
<tr>
<th align=left>Subject:</th>
<td>$subj</td>
</tr>
<tr>
<th align=left>Date:</th>
<td>$date</td>
</tr>
<tr>
<td colspan="2">$body</td>
</tr>
</table>
EOM;
The code to grab a single message is similar to one that grabs
a sequence of message headers. The main difference is that you define a
$body variable that's the result of three chained functions. Innermost,
you call imap_fetchbody( ) to return the
message body; it takes the same parameters as imap_header( ). You pass
that to htmlspecialchars( ) to escape any HTML that may interfere with yours. That
result then is passed to nl2br( ) , which
converts all the carriage returns to XHTML <br /> tags; the
message should now look correct on a web page.
To disconnect from the IMAP server and close the stream, pass
the IMAP connection handle to imap_close( ):
// close connection when finished imap_close($nntp);