The Most Active and Friendliest
Affiliate Marketing Community Online!

“AdsEmpire”/  Direct Affiliate

Detailed -How To PHP A PM System

Scripter

New Member
affiliate
Private Messaging System
Part 1

Overview and Structure
The first thing we need to consider when planning a project such as this is what features we want included. We have limitless options at our disposal, and as with all other things PHP related, you are really only limited by your imagination. However, to keep everyone sane, we are simply going to include very basic, yet helpful features in this system. Here is a list of some of the features we will build into our PM system:
  • Send new messages to other users
  • Distinguish between read and unread messages in my inbox
  • Delete selected messages
  • View my sent messages
  • Record time message was sent as well as time message was opened for logging purposes
Some of these features, along with others, we have become so accustomed to having in email systems and other places that we may not even think about the logic that is needed to implement them. That is my primary goal in this tutorial: to get you to start thinking about the nuances behind every little addition and aspect of web application programming. The more you can think of and plan out in this, the planning stage, the more headache you will save yourself down the road.
Now that we have the basic overview out of the way, let's begin to develop our database to support the features mentioned above. For the sake of time, I will not be creating an entire membership system here, however, I will be "faking" it with some session variable to simulate what you may have in your own membership system. To help simulate this system, we will generate a small users table and populate it with some generic usernames:

MySQL Example:
---------------------------------------------------------------------
CREATE TABLE users (
id INT(11) AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(20) NOT NULL UNIQUE
);

INSERT INTO users (username) VALUES ('grant', 'ralph', 'carrie', 'stacy', 'gertrude', 'sam', 'steph');
----------------------------------------------------------------------

Once this simple table has been created and populated, we have a base set of users off of which we can build the application. The next thing we need is our PM table. All of the features we listed above can very easily be included in one fairly simple table. Here is the table I came up with to use. As a side note, the included INSERT statements will simply give us some random entries between our primary user and others so that we have some data to work our magic on.

MySQL Example:
----------------------------------------------------------------------
CREATE TABLE myPMs (
id INT(11) AUTO_INCREMENT PRIMARY KEY,
to_id INT(11) REFERENCES users (id),
from_id INT(11) REFERENCES users (id),
time_sent DATETIME NOT NULL,
subject VARCHAR(50) NOT NULL DEFAULT '',
message TEXT NOT NULL DEFAULT '',
opened CHAR(1) NOT NULL DEFAULT 'n',
time_opened DATETIME DEFAULT NULL
);

INSERT INTO myPMs (to_id, from_id, time_sent, subject, message) VALUES
(1, 2, '2006-02-14 02:34:22', 'Welcome to UKWW Forums!', 'Just wanted to wish you a happy heart day!'),
(1, 3, '2006-04-01 08:59:45', 'Have a great day!', 'And enjoy it to the fullest'),
(2, 1, '2006-02-14 10:14:52', 'Back at ya', 'Thanks for the note... happy valentines yourself ;-)'),
(1, 6, '2005-12-25 22:01:19', 'Merry Christmas!', '...and a Happy New Year, too!'),
(1, 4, '2006-09-18 16:48:02', 'Happy B-Day', 'It is your birthday, right???');

-------------------------------------------------------------------

As you can see by the structure of our PM table, we only have to provide five pieces of information any time we are creating a new PM: 1) user id of the recipient, 2) user id of the sender (our session user ID), 3) the date and time it was sent (will always be NOW() from our script), 4) a subject, and finally 5) the actual body of the message. All the other columns will be handled initially by the database, and we will modify a couple of the other fields as we start marking messages as "read" and so forth.
 
Detailed - How to PHP a PM system

Code Structure
Part 2

Since we are discussing a private messaging system, I thought it only fair to begin the coding section of the tutorial by dealing with how to send messages. If we consider what all is involved with the messaging, every aspect of reading and modifying depends upon the understanding that we have successfully generated a message in the first place. Since everything else stems from this central principle, let's delve into the details of it so we will understand how easily we can add features later. The following is a simple page that will allow a user to create a new PM. Please keep in mind that any time you see the $_SESSION['userID'] variable used, you need to replace it with the current user's unique ID from your membership system.
 
Im only allowed 10000 words in the thread, so i will post php example here:

PHP Example For Above Post:
-------------------------------------------------------------
<?php
// Process the message once it has been sent
if (isset($_POST['newMessage'
])) {
// Escape and prepare our variables for insertion into the database
// This is also where you would run any sort of editing, such as BBCode parsing
$to = mysql_real_escape_string($_POST['to'
]);
$from = $_SESSION['userID'
];
$sub = mysql_real_escape_string($_POST['subject'
]);
$msg = mysql_real_escape_string($_POST['message'
]);

// Handle all your specific error checking here
if (empty($to) || empty($sub) || empty($msg
)) {
$error = "<p>You must select a recipient and provide a subject and message.</p>\n"
;
} else {
// Notice carefully how we only have to provide the five values we previously discussed
$sql = "INSERT INTO myPMs (to_id, from_id, time_sent, subject, message) VALUES ('$to', '$from', NOW(), '$sub', '$msg')"
;
if (!
mysql_query($sql
)) {
$error = "<p>Could not send message!</p>\n"
;
} else {
$message = "<p>Message sent successfully!</p>\n"
;
}
}
}

echo isset(
$error) ? $error : ''
;
echo isset(
$message) ? $message : ''
;

echo
"<form name=\"newMessage\" action=\"\" method=\"post\">\n"
;
echo
"<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\">\n"
;
echo
"<tr>\n"
;
echo
"<td>To:</td>\n"
;
echo
"<td><select name=\"to\">\n"
;
echo
"<option value=\"\"></option>\n"
;

// Collect and loop through all usernames that are not the current user
$sql = mysql_query("SELECT * FROM users WHERE id != '$_SESSION[userID]' ORDER BY username"
);
if (
mysql_num_rows($sql) > 0
) {
while (
$x = mysql_fetch_assoc($sql)) echo "<option value=\"$x[id]\">$x[username]</option>\n"
;
}

echo
"</select></td>\n"
;
echo
"</tr>\n"
;
echo
"<tr>\n"
;
echo
"<td>Subject:</td>\n"
;
echo
"<td><input type=\"text\" name=\"subject\" value=\"" . (isset($error) ? $_POST['subject'] : '') . "\" maxlength=\"50\" /></td>\n"
;
echo
"</tr>\n"
;
echo
"<tr>\n"
;
echo
"<td>Message:</td>\n"
;
echo
"<td>\n"
;
echo
"<textarea name=\"message\" cols=\"\" rows=\"\">" . (isset($error) ? $_POST['message'] : '') . "</textarea>\n"
;
echo
"</td>\n"
;
echo
"</tr>\n"
;
echo
"<tr>\n"
;
echo
"<td></td>\n"
;
echo
"<td><input type=\"submit\" name=\"newMessage\" value=\"Send\" /></td>\n"
;
echo
"</tr>\n"
;
echo
"</table>\n"
;
echo
"</form>\n"
;
?>
-----------------------------------------------------------------
 
Generating an Inbox
Part 3


By default, I like to have a user see their inbox when they navigate to a PM system. In my mind, it's sort of like logging into an email application. Therefore, I want to give them any information about new messages they have received at their fingertips. Obviously, there are many different ways to go about presenting messages and data to the user, and this is where your creativity comes into play. We could list all unread messages first, followed by others, we could sort them alphabetically according to sender, or we could even let the user define how they prefer to have them displayed. For the sake of this example, I have simply chosen to list messages by time they were sent: newest first. You may recognize this as a typical default for many mail applications as well. So, with that in mind, we will first generate an inbox for our users, and then we will look at some code modifications that will allow us to see our sent messages with the same script as well.
Let's begin now. First of all, I want to explain the major differences between my sample script and your final one. I am creating a session variable defaulting to the first user in my database table. That way, I am simulating what may be seen if I were to be logged in as that user. To do this, I'm simply creating the $_SESSION['userID'] variable at the top of my page. So, here is how I have started out:

Php Example:
-----------------------------------------------------------------------
<?php
session_start
();
$_SESSION['userID'] = 1
;
?>
-----------------------------------------------------------------------


Easy enough, right? Now, keep in mind, this is done to assign the user ID variable I am using throughout the rest of the script. I can't stress enough how important it is that you replace all references to this variable with your own membership system ID variable for your final product. Now, we obviously can't do much with our table until we make a connection to the database, so let's handle that now as well:

Php Example:
-----------------------------------------------------------------------
<?php
$HOST
= 'localhost';
// Set to your database server
$USER = 'myDBUser';
// Set to your database user
$PASS = 'myDBPass';
// Set to your database password
$NAME = 'myDBName';
// Set to the appropriate database

$conn = mysql_connect($HOST, $USER, $PASS
);
if (!
$conn) die('Error connecting to server!'
);
mysql_select_db($NAME, $conn) or die('Error selecting database'
);
?>
----------------------------------------------------------------------

Notice that I am using some error checking to assure that I have successfully connected to my database server and selected the database I need. One of the most frustrating things when working with scripts like this is to get everything set up and spend hours debugging because it doesn't display anything, only to find out that your initial database connection is not working properly! So, hopefully, this little error checking will help you get your connection set up accurately

I should have just written a E-Book >.<
 
Continue...

Now that we have our database connection, there are a couple things we need to do to set up for displaying our messages. First, I have written up a couple functions to help obfuscate some of the clutter when collecting the messages to be displayed. Let's look at those functions, and then we'll include them into our script. I saved the functions into a file called simply functions.php for this script:

Php Example:
----------------------------------------------------------------------
<?php
// Returns an array of all my messages
// Defaults to current user and INBOX messages
// Make the $sent parameter "true" to retrieve sent messages
function getMyMessageList($id = '', $sent = false) {
$id = empty($id) ? $_SESSION['userID'] : $id;

$where = $sent ? "from_id = '$id'" : "to_id = '$id'";
$join = $sent ? "p.to_id = u.id" : "p.from_id = u.id";

$messages = array();

// Construct query
$sql = "SELECT p.id, to_id, from_id, time_sent, subject, message, opened,
time_opened, username FROM myPMs p LEFT JOIN users u
ON $join WHERE $where order by time_sent DESC";
$res = mysql_query($sql) or die(mysql_error());

// If there are records, populate the array to return
if (mysql_num_rows($res) > 0) {
while ($row = mysql_fetch_assoc($res)) {
$messages[] = $row;
}
}

// Return the array of messages to the caller
return $messages;
}

// Gets a specific message, but only if it corresponds to the
// provided user ID and type of message provided. Once again, we
// default to the current user and INCOMING messages.
function getMyMessage($id, $user = '', $sent = false) {
$user = empty($user) ? $_SESSION['userID'] : $user;

$where = $sent ? "from_id = '$user'" : "to_id = '$user'";
$join = $sent ? "p.to_id = u.id" : "p.from_id = u.id";

// Construct query
$sql = "SELECT p.id, to_id, from_id, time_sent, subject, message, opened,
time_opened, username FROM myPMs p LEFT JOIN users u
ON $join WHERE $where AND p.id = '$id'";

$res = mysql_query($sql);

// If there is a row found, return it as an associative array,
// otherwise, return false to show we didn't find anything.
if (mysql_num_rows($res) == 1) {
return mysql_fetch_assoc($res);
} else return false;
-----------------------------------------------------------------------

As you can tell, each of these functions simply assists us in more efficiently being able to grab the proper list or single message when the time comes. Now that we have the functions written, though, we must include them in our script. In addition, there is one constant variable that we will define since it could be used in multiple locations, and we want our output to be uniform. That variable is the Date Format that we want to use to display the message times. To do both these things, we just need to add two lines of code to our main script:

Php Example:
-----------------------------------------------------------------------
<?php
require_once("functions.php"); // include the functions we just wrote
define('DATE_FORMAT', 'Y-m-d g:ia'); // define our date format variable
?>

--------------------------------------------------------------
 
Continue...

Once these are set, we are ready to start the actual guts of our script. Preparation is wrapping up, and we are ready to start outputting some markup to display our actual messaging system. First off, as I mentioned before, we are going to attempt to use one single setup to display both our inbox and our sent messages. As such, we must do a little data gathering before we can know what we are to display. The first thing I did was to check and see if we were trying to send a new message. The following code is all we need to do that:

Php Example:
-----------------------------------------------------------------------
<?php
if (isset($_GET['action']) && $_GET['action'] == 'send') {
$title = "Send Message";
require('new.php');
exit();
}
?>
-----------------------------------------------------------------------

This snippet assumes that new.php is a file that contains your form and form handler we first discussed in this tutorial. That way, any time we pass the action "send" through the URL, we can expect to be able to create and send a new PM. Now that we have sending completely out of the way, we need to decide whether or not to show the inbox or our sent messages. I chose to do that, once again, by use of passing variables through the query string. In this case, I'm looking for a folder variable. If it is absent, I simply default to showing the inbox. Also, based on the folder I have chosen, I set a $title variable that will be used as the title of my HTML page.

Php Example:
-----------------------------------------------------------------------
<?php
$folder = isset($_GET['folder']) ? $_GET['folder'] : 'inbox';

switch($folder) {
case 'sent':
// Show my sent messages
$title = "Sent Messages";

// Notice we set the second parameter to "true" to pull sent messages
$myMessages = getMyMessageList('', true);

// Set the columns we will be using for our display
$cols = array('To', 'Subject', 'Time');
break;

default:
// Show our inbox
// Notice we are setting the same variables as above
$title = "Inbox";
$folder = "inbox"; // This is in case we have something errant entered
$myMessages = getMyMessageList();
$cols = array('From', 'Subject', 'Time', 'Del');
}

// This is so we know how many columns we actually have
$span = count($cols);
?>
-----------------------------------------------------------------------

Now that we have our display prepped, we can begin our layout. I will not go through the entire setup of DOCTYPE and all the header information here, as I will leave that up to the individual user, but if you have set your $title variable properly, you can simply echo it out now in your header like this:

Php Example:
-----------------------------------------------------------------------
<title><?php echo $title; ?> ~ PM System</title>
-----------------------------------------------------------------------
 
Continue On Inbox

Here is where we start to have a few options we need to consider. The first thing I want to check is to see whether or not the user has selected a message to view. If so, we want to display the message, otherwise, we want to show the inbox or sent messages accordingly. Since we've been using the query string to pass information to this point, let's continue. Based on whether or not we have an ID passed, we will display the message

Php Example:
-----------------------------------------------------------------------
if (isset($_GET['id'])) {
$id = $_GET['id'
];
switch(
$folder
) {
case
'sent'
:
$msg = getMyMessage($id, '', true
);
$back = "?folder=sent";
// Set my link back to Sent Messages
$from = "To"
;
break;

case
'inbox'
:
$msg = getMyMessage($id
);
$back = "?folder=inbox"
;
$from = "From"
;
break;

// Obviously, if you choose, you can easily add more boxes without
// too much difficulty.
}

// Output a "back" link
echo "<p><a href=\"$back\">&laquo; Back</a></p>\n"
;

// If there is no message returned, we have an error
if (!$msg
) {
echo
"<p>Invalid message requested</p>\n"
;
} else {

-----------------------------------------------------------------------


This code really does one major thing: retrieve the message that has been selected from the database and verify its existence. The other thing that happens is simply printing out a "Back" link for them to follow to get back to the box they were previously viewing. Notice how the code uses the functions we have previously defined to grab the message. This is much better than having to query each time, is it not? Now that we have our message, we can parse out the data and display it as you see fit. Keep in mind that this is a continuation from above, so we are inside of an "if" statement

Php Example:
-----------------------------------------------------------------------
<?php
// Define our variables (removing slashes)
// Add any other formating you like here (including BBCode, etc)
$user = stripslashes($msg['username'
]);
$date = date(DATE_FORMAT, strtotime($msg['time_sent']));
// Notice our defined constant
$subject = stripslashes($msg['subject'
]);
$message = nl2br(stripslashes($msg['message'
]));
$opened = $msg['opened'
];

// Mark a received message "read" when it's opened
if ($msg['to_id'] == $_SESSION['userID'] && $opened == 'n'
) {
$sql = "UPDATE myPMs SET opened = 'y', time_opened = NOW() WHERE id = '$id'"
;
mysql_query($sql
);
}

// Output our message
echo "<h3>$subject</h3>\n"
;
echo
"<p>$from <b>$user</b><br />on $date</p>\n"
;
echo
"<p>$message</p>\n"
;
}

} else {
// They haven't chosen a message, so show the box!
?>

-----------------------------------------------------------------------

We now are able to display any messages we have listed in our boxes. Now that we have that part of our script under our belt, we're ready to tackle the trickiest part of the application: the boxes themselves. We need to make sure we're aware of a few things up front. First, we don't want anyone to be able to edit messages in their sent box (unless, of course, you choose to let people retract unopened messages, but that's up to you to write that mod). In the inbox, on the other hand, people need to be able to read their messages, delete messages, and do any other sort of editing/modification of messages you see fit. One other note about the message display we just finished: you may want to consider coming up with some code that would allow a user to reply to the message he is currently viewing as well.
To start out our box display, I like to show a very simplistic navigation. I always want the user to be able to switch between the Inbox and the Sent Messages, but only from the Inbox do I want them to be able to send a new message. So, to get this sort of effect, I tap into the $folder variable we set a while back.

Php Example:
-----------------------------------------------------------------------
<?php
echo "<p><a href=\"?folder=inbox\">Inbox</a> |\n"
;
echo
"<a href=\"?folder=sent\">Sent Messages</a></p>\n"
;

// If we're in the inbox, show a Create link
if ($folder == 'inbox'
) {
echo
"<p><a href=\"?action=send\">Create New Message</a></p>\n"
;
}
?>
-----------------------------------------------------------------------

Now we're ready to actually output the message list we initially gathered for the currently selected box in a readable fashion.
 
You nearly complete...

When displaying a message box, we need to keep in mind that we want to provide enough markup variation that the webmaster (probably you, the reader, in this case) can use basic style sheets to display messages as he sees fit. For instance, we want to specify between read and unread messages, but I am of the opinion that I want to do as little as possible with markup since each person will have different preferences on how those distinctions should be made. So, I simply create some classes to attach to the rows of my messages. For the sake of this tutorial, I'm simply using "read" and "unread" as my classes.

Php Example:
-----------------------------------------------------------------------
// You'll notice throughout this snippet that we're only displaying
// the delete messages form if we are in the inbox.
if ($folder == 'inbox'
) {
echo
"<form name=\"deleteMessages\" action=\"\" method=\"post\">\n"
;
}

echo
"<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\">\n"
;
echo
"<tr>\n"
;

// Create our headings with the column names we defined previously
echo "<th>" . implode("</th>\n<th>", $cols) . "</th>\n"
;
echo
"</tr>\n"
;

// Make sure we have some messages to display
if (count($myMessages) > 0
) {

// Loop through each message and display it on a row
foreach ($myMessages as $msg
) {

// Determine to show the message as read or unread
$class = $msg['opened'] == 'y' ? 'read' : 'unread'
;
$date = date(DATE_FORMAT, strtotime($msg['time_sent'
]));

echo
"<tr class=\"$class\">\n"
;
echo
"<td>$msg[username]</td>\n"
;

// Hyperlink subject to display message
echo "<td><a href=\"?folder=$folder&amp;id=$msg[id]\">$msg[subject]</a></td>\n"
;
echo
"<td>$date<?td>\n"
;

// Checkbox to select which messages to delete
if ($folder == 'inbox'
) {
echo
"<td><input type=\"checkbox\" name=\"del[]\" value=\"$msg[id]\" /></td>\n"
;
}
echo
"</tr>\n"
;
}

// More of our delete form
// This will be our submit button to delete selected entries
if ($folder == 'inbox'
) {
echo
"<tr class=\"deleteRow\">\n"
;
echo
"<td colspan=\"$span\"><input type=\"submit\" name=\"delete\" value=\"Delete Selected\" /></td>\n"
;
echo
"</tr>\n"
;
}
} else {
// We have no messages in this box.
echo "<tr>\n"
;
echo
"<td colspan=\"$span\"></p>You have no messages</p></td>\n"
;
echo
"</tr>\n"
;
}

echo
"</table>\n"
;

if (
$folder == 'inbox'
) {
echo
"</form>\n"
;
}

}
// End Script


--------------------------------------------------------------
 
Extra Info

You may have noticed that I didn't account for the delete button actually being pressed. That's one of the nuances of the code I chose to leave up to the discretion of the reader. However, if you are strapped for ideas, here's one method of handling your message deletion. Keep in mind that for best results, you need to either redirect the user back to the inbox upon successful deletion, or at the very least, make sure you do this processing before you run your getMyMessageList() function to make sure your display reflects the newly deleted messages.

Php Example:
-----------------------------------------------------------------------
if (isset($_POST['delete']) && count($_POST['del']) > 0) {
// Make sure they are only attempting to delete their own messages!!!
$sql = "DELETE FROM myPMs WHERE id IN ('" . imlode("','", $_POST['del']) . "') AND to_id = '$_SESSION[userID]'"
;
if (!
mysql_query($sql
)) {
// Could not delete selected messages
} else {
// Successfully deleted messages
}
}

-----------------------------------------------------------------------


Notice the usage, yet again, of the $_SESSION['userID'] variable. This access to the identity of the person viewing the page is by far the single most important element of a PM system. Without accurately identifying the user and limiting access based on this identity, your PM system will not be worth having for your users.
 
Your Done!

Conclusion

If you've made it to this point by reading through the tutorial, you hopefully have a good understanding of some of the logic and principles resting behind a solid PM system. With those principles in place, you should be able to continue on the path of this very basic system and set up additional features and/or restrictions for your users. Additionally, if you get a good grasp on the techniques and logic for this system, you could revise and clean things up an incredible amount by writing up an Object Oriented solution.

If, on the other hand, you jumped right to the end of this tutorial to see how things end, I would recommend you take this tutorial a thread at a time. As with all my tutorials, please feel free to contact me with questions or suggestions for improvement! Thanks for sticking this one out with me, and I hope it is of some help.

Sincerly:
Scripter
 
Mod Review and Last words for this tutorial.
Ok i really did enjoy submiting every thread towards this tutorial.
I hope that you will enjoy coding your new system,
also that it benefits you in great ways.
Enjoy it!
 
MI
Back