Skip to page content or skip to Accesskey List.
Search evolt.org
evolt.org login: or register

Work

Main Page Content

The ABCs of CMS - Part II

Rated 3.8 (Ratings: 8) (Add your rating)

Log in to add a comment
(18 comments so far)

Want more?

 
Picture of eli

Jay Blanchard

Member info | Full bio

User since: March 21, 2001

Last login: August 27, 2008

Articles written: 6

In this installment we will cover logging in a user, presenting them with appropriate navigation according to their user level, and setting up an article table.

User Registration

In the previous article, The ABCs of CMS, we succeeded in creating a users table (tblUser) that will hold the identification and login information. You should have set up a PHP form page to accept the information, insert the information into the database table, and notify an administrator that someone has registered. (Make sure that you have at least one administrator level person entered into tblUser.) If not here is a sample page that will do just that;

<html>
<head>
<title>CMS User Registration</title>
</head>
<body>

<h1>CMS User Registration</h1>
<form action="cmsregistration.php" method="POST">
<table cellpadding="3" cellspacing="0" border="1">
<tr>
<td>User Name</td>
<td><input type="text" name="username" size="64" maxlength="64"></td>
</tr>
<tr>
<td>E-Mail Address</td>
<td><input type="text" name="email" size="64" maxlength="128"></td>
</tr>
<tr>
<td>Password</td>
<td><input type="password" name="password" size="32" maxlength="64"></td>
</tr>
<tr>
<td></td>
<td><INPUT type="submit" value="Send"> <INPUT type="reset"></td>
</tr>
</table>
</form>

</body>
</html>

And here is the PHP (cmsregistration.php) script to process the registration. Make sure that the cms_user has INSERT privileges;


<?

//connect to and select database
if(!($dbconnect = mysql_pconnect("127.0.0.1", "cms_user", "cms_password"))){
	print("Failed to connect to database!\n");
	exit();
	}
if(!mysql_select_db("cms", $dbconnect)){
	print("Failed to select database!\n");
	exit();
	}

//insert user information into table
$query = "INSERT INTO tblUser (name, email, password) ";
$query .= "VALUES ('$username', '$email', '$password') ";

if(!($dbresult = mysql_query($query, $dbconnect))){
	print("MySQL reports: " . mysql_error() . "\n");
	exit();
	}

//query user table for admin email address
$qadmin = "SELECT email ";
$qadmin .= "FROM tblUser ";
$qadmin .= "WHERE accesslevel = 'admin' ";

if(!($dbresult = mysql_query($qadmin, $dbconnect))){
	print("MySQL reports: " . mysql_error() . "\n");
	exit();
	}

//email message to admin
$dbadmin = mysql_fetch_object($dbresult);
$messadm = "$username has registered as an Author in the\n";
$messadm .= "Content Management System.\n\n";

mail("$dbadmin->email", "CMS Author Registration", $messadm, "From: CMS System");

//send them to the login page
header("Location: login.php"); exit; 

?>

This script could also be modified to send a mail to the user who registered, complete with a copy of their password for their records. Other interfaces you could create for user management would include a form where a user could update their information and a form for administrators that would allow then to perform modification or deletion of user files.

User Login

Next is creating a login page for the CMS. For simplicity we will use the email address as the login name, due to the fact that email addresses are unique and easy for users to remember, and combine that with their password. Once a user is logged in we will check their user level and send them to the appropriate page.

<html>
<head>
<title>CMS User Login</title>
</head>
<body>

<h1>CMS User Login</h1>
<form action="cmslogin.php" method="POST">
<table cellpadding="3" cellspacing="0" border="1">
<tr>
<td>E-Mail Address</td>
<td><input type="text" name="email" size="64" maxlength="128"></td>
</tr>
<tr>
<td>Password</td>
<td><input type="password" name="password" size="32" maxlength="64"></td>
</tr>
<tr>
<td></td>
<td><INPUT type="submit" value="Send"> <INPUT type="reset"></td>
</tr>
</table>
</form>

</body>
</html>

Which will use the following (cmslogin.php) script to process the login;


<?

//connect to and select database
if(!($dbconnect = mysql_pconnect("127.0.0.1", "cms_user", "cms_password"))){
	print("Failed to connect to database!\n");
	exit();
	}
if(!mysql_select_db("cms", $dbconnect)){
	print("Failed to select database!\n");
	exit();
	}

//query to compare user to database
$quser = "SELECT email, password, accesslevel ";
$quser .= "FROM tblUser ";
$quser .= "WHERE email = '$email' ";
$quser .= "AND password = '$password' ";

if(!($dbresult = mysql_query($quser, $dbconnect))){
	print("MySQL reports: " . mysql_error() . "\n");
	exit();
	}

//start session
session_start();
session_register("emailid");
session_register("level");

//set session variables for identification
$dbuser = mysql_fetch_object($dbresult);
$emailid = $dbuser->email;
$level = $dbuser->accesslevel;

//send the user to a page based on their user level

switch($level)
{
	case "author":
	header("Location: myart.php"); exit; 
	break;
	case "editor":
	header("Location: editor.php"); exit;
	break;
	case "approve":
	header("Location: approve.php"); exit;
	break;
	case "schedule":
	header("Location: sched.php"); exit;
	break;
	case "admin":
	header("Location: admin.php"); exit;
	break;
	default:
	header("Location: loginfail.php"); exit;
}

?>

Navigation Within The CMS

Once a user arrives at the appropriate page they will need access to various functions within the CMS based on their user level. One of the cleanest ways to do this is to set up a table in the CMS for navigation items and assign those items user levels as well. This also makes it easy to edit navigation items later as they are located in a single place. Some developers will want to use include files for these navigation items, there is nothing wrong with that.

The database approach gives you the opportunity to easily construct an interface (you can do that as an extracurricular activity, it will not be covered here) with which to manage navigation items, part of the beauty of a CMS. If a certain navigation item needs to change access levels, or if new navigation needs to be added for a particular level it is easy to accomplish.

CREATE TABLE `tblNavigation` (
  `ID` int(11) NOT NULL auto_increment,
  `URL` varchar(128) default NULL,
  `accesslevel` varchar(64) default NULL,
  PRIMARY KEY  (`ID`)
)

Where do we keep the user level information during the user's session? It's a matter of preference as some developers will want to use cookies, others will pass hidden form fields, and still others will use session variables. The preference for this project will be session variables and we set the user and user level during login.

session_register(&quot;emailid&quot;);<br>
session_register(&quot;level&quot;);<br>
.

Make sure to put &lt;? session_start(); ?&gt; as the very first line of each page in the CMS. If you fail to do this your session variables will not get passed properly. If you place the code after a print statement it will throw header errors.

Th only activities that will be provided for an Author at this point are;

  • Submit An Article
  • Edit User Information (only e-mail and password information)
  • My Articles (a list of all of the articles for this author, perhaps with publishing dates)

The URLs for those items will have to be placed in the navigation table, along with their access level information.

INSERT INTO tblNavigation (URL, accesslevel) VALUES ('<a href="subart.php" title="Submit An Article">Submit An Article</a>', 'author');
INSERT INTO tblNavigation (URL, accesslevel) VALUES ('<a href="eduser.php" title="Edit User Information">Edit User Information</a>', 'author');
INSERT INTO tblNavigation (URL, accesslevel) VALUES ('<a href="myart.php" title="My Articles">My Articles</a>', 'author');

The Author's Experience

Once an author has logged in to the system they are sent to the myart.php ("My Articles") page where they are presented with a list of navigation items based on their user level and a list of the articles that they have placed in the CMS. This gives them the opportunity to review material that has been published, and we will later give them the opportunity to be able to edit their own article before sending it through the work flow.

Since myart.php relies on a number of tables (tblUser, tblNavigation, and tblArticle) let's create our article table.

CREATE TABLE `tblArticle` (
  `ID` int(4) NOT NULL auto_increment,
  `title` varchar(64) default NULL,
  `teaser` tinytext,
  `body` longtext,
  `submitted` datetime default NULL,
  'edited' date default NULL,	
  'approved' date default NULL,
  `publish` date default NULL,
  `expire` date default NULL,
  `author` varchar(128) default NULL,
  `editor` varchar(128) default NULL,
  `type` varchar(32) default NULL,
  PRIMARY KEY  (`ID`)
);

This article table will allow control of many factors concerning each article, such as when it gets published, or if it should expire on a certain date. If you need to create an archive of articles that have been published but have now expired you can query for articles whose expiration dates have passed. Aside from dates, the article table also will contain a plethora of information that can be used in multiple ways.

Create myart.php, which will show an author their list of articles and allow them to navigate through the CMS.

<?
session_start();

//connect to and select database
if(!($dbconnect = mysql_pconnect("127.0.0.1", "cms_user", "cms_password"))){
	print("Failed to connect to database!\n");
	exit();
	}
if(!mysql_select_db("cms", $dbconnect)){
	print("Failed to select database!\n");
	exit();
	}

//query to get navigation from database
$qnav = "SELECT URL ";
$qnav .= "FROM tblNavigation ";
$qnav .= "WHERE accesslevel = '$level' ";

if(!($dbnav = mysql_query($qnav, $dbconnect))){
	print("MySQL reports: " . mysql_error() . "\n");
	exit();
	}

//query to get article information
$qart = "SELECT a.ID, a.title, a.publish, u.name ";
$qart .= "FROM tblArticle a, tblUser u ";
$qart .= "WHERE u.email = '$emailid' ";
$qart .= "AND a.author = u.email ";

if(!($dbart = mysql_query($qart, $dbconnect))){
	print("MySQL reports: " . mysql_error() . "\n");
	exit();
	}

?>
<html>
<head>
<title>CMS</title>
<LINK REL="StyleSheet" HREF="cms.css" type="text/css">
</head>
<body>

<div class="left">
<?
while($dbrow = mysql_fetch_object($dbnav)){
	print($dbrow->URL . "<br>\n");
	}
?>



<div class="right">
<?
$dbartrow = mysql_fetch_object($dbart);

if($dbartrow->ID == ""){
	//if there are no articles for this author
	print("You have not placed any articles in the Content Management System");
	}
else 
	{
	//print article links for this author
	mysql_data_seek($dbart, 0);
	print("<h3>Welcome " . $dbartrow->name . "</h3>\n");

	while($dbartrow = mysql_fetch_object($dbart)){
		print("<a href=\"artprvw.php?aid=" . $dbartrow->ID . "\">" . $dbartrow->title . "</a><br>\n");
		}
	}
?>
</div>

</body>
</html>

And here is cms.css, the basic style sheet that can be modified for use with the CMS;

/*general tags*/
body {
	margin: 0px 0px 0px 0px;
	background-color: #FFFFFF;
	font-family: Arial, Helvetica, sans-serif;
}

/*div tags*/

div.left {
	position: absolute;
	left: 0px;
	top:10px;
	width:185px;
	padding-left: 10px;
}

div.right {
	top: 10px;
	margin-top: 10px;
	margin-left: 201px;
	margin-right: 30px;
}

On The Horizon

Play around with the system that has been created, add nav items, or perhaps create the pages for other access levels. Your exploration will prepare you for things that are to come.

Meanwhile we have chewed on quite a bit of information, but there is still plenty to consider and do. In the next article we will cover article submission, allowing an author to preview and edit his or her own articles, and more workflow theory.

A long time code-jockey Jay enjoys music (especially horn bands like Tower of Power, and for those in the know...drum corps), furniture building, physics, and philosophy. His latest projects include several mission-specific web-based project tracking systems.

Jay lives in Central Texas, but has never forgotten his South Louisiana heritage. His daughter, Kaitlyn, is his pride and joy. She is learning web development.

good work

Submitted by Martin Tsachev on April 26, 2002 - 18:06.

It's a nice article but what's that obsession for table prefixes, are you comming from a M$ background or you just have incovinient habits?

login or register to post comments

Escaping!

Submitted by bobince on April 28, 2002 - 14:27.

$query .= "VALUES ('$username', '$email', '$password') ";

Uh oh.

What do you think will happen when the username contains an apostrophe?

Not only will it break, but it's a potential security hole. An attacker can put any SQL in that string after an apostrophe. This is not as catastrophic in MySQL as with other databases which allow queries to be chained (eg. ';DROP TABLE tblUser --'), but it's still dangerous if the attacker can guess the form of your query.

Use addslashes to encode dangerous characters when putting text in SQL queries.

print("MySQL reports: " . mysql_error() . "\n");

But what if the error contains HTML special characters, like left angle bracket? By using the above vulnerability to make MySQL generate an error with HTML in it ("You have an error in your SQL near [submitted code here]") we can put a script element into the error page. As this operates in the security context of your site, it can read the user's cookies and send them to an attacker who persuaded the user to go to the error page, who can then steal that user's session and gain full access to the CMS.

Use htmlspecialchars to encode dangerous characters when putting text in HTML pages.

I know this article is only supposed to be teaching the basics, but the basics should include thinking about security, and escaping when going from one representation of text to another is very important. Tutorials like this never seem to mention it, which is probably why such a large proportion of websites out there are completely insecure.

login or register to post comments

more on security

Submitted by Martin Tsachev on April 28, 2002 - 16:22.

register_globals is something that should be turned off if you have security in mind.

And if the code is supposed to be portable the best thing is to use <?php ?> and not <? ?>. After all everybody has a coding style but I usually don't like code that throws errors when I test it at home I suppose most people won't like it also.

login or register to post comments

Table Prefixes...

Submitted by eli on April 29, 2002 - 06:18.

Shaggy, the reason for the table prefixes is simple. Since this is a how-to article I find that it makes sense to make these things clear. The last shop I was in was a M$ shop, and they didn't use this "tbl" convention at all. I have found when teaching that this little convention leaves little confusion.

bobince, you're right of course. Those single quotes around the variables are force of habit. When inserting values into a database using an INSERT statement it is de rigeur to place single quotes around the values to be inserted.

Security is an extremely important issue, especially where systems like a CMS are concerned. As applications developers we are all compelled to learn about and utilize whatever security measures are available to us. While this series of articles does not contain enough space to cover these issues in detail, we should all be aware and mindful to use any security measures at our disposal.

login or register to post comments

Error reporting....

Submitted by eli on April 29, 2002 - 06:21.

I am going to make note of this later in the series, but all of the print("MySQL reports: " . mysql_error() . "\n"); should either be removed after testing, or used to send error reports to an administrator of the CMS. These are primarily meant for the developer during design and tesing.

login or register to post comments

looking for a good CMS...

Submitted by lethanek93 on April 30, 2002 - 14:01.

i have been looking at off the shelf content management applications, and i came across Ektron. they have a whole line of CMS applications, and even ones that i can afford. I don't have the time to put together my own content management application, so i am looking at purchasing one from them. they are inexpensive compared to others, and offer just as much features. eveything about them looks good. the different applications look pretty easy to use. the applications run on either ASP or ColdFusion. they even include thier web-based WYSIWYG editor, ewebeditpro in it. This is the best that i have seen so far. Here is a link to their web site. www.ektron.com if you want to check it out.

login or register to post comments

php 4.06 and 'Warning: Cannot add header informat

Submitted by branko on May 16, 2002 - 08:05.

Thanks for this great series. I am using your tutorials to further familiarise myself with PHP, MySQL and CMSes in general.

Since I am a bit lazy, I copy your examples verbatim; they do not necessarily work from the start, though. A little past the introduction of cmslogin.php you write:

Make sure to put &lt;? session_start(); ?&gt; as the very first line of each page in the CMS. If you fail to do this your session variables will not get passed properly. If you place the code after a print statement it will throw header errors.

Apparently, this has only been a problem since PHP 4.something; I use 4.06.

It's not just print statements that cause these errors to appear. Also whitespace before &lt;?php and after the closing ?&gt; and any whitespace before the session_start() call seem to generate these errors.

Before I got cmslogin.php to work I had to put session_start() at the top of the php file and remove a stray newline at the end of the file.

login or register to post comments

You're welcome..

Submitted by eli on May 16, 2002 - 08:21.

Thanks for the kind words!

Unfortunately I missed a couple of things while writing the article, such as making the code more portable with <?php . As for the whitespace, some of that in the code may be due to the way the information is used within the constraints of an article. I am testing this code on a platform for which the system is going to be run on (in this case) removing less generic items from the code.

The point of the series is to learn something about CMS (and MySQL and PHP to boot) and to see code examples which remove the mystery from designing this kind of system. I will have to do better next time as many flaws of one type or another have been pointed out.

login or register to post comments

Re: cannot add headers

Submitted by Martin Tsachev on May 16, 2002 - 12:05.

Yes any output would cause this error if you have disabled the output buffering. If you want to turn it on you can do that locally in a .htaccess file or using PHP's ini_set function.

login or register to post comments

Suffering with header problems

Submitted by dunstan on August 27, 2002 - 15:01.

Hi Eli,

Could you please explain which of these files should have at the top? All I get at the moment are header errors (although registration does work, the errors are all the user sees).

  1. registration.php -- html form
  2. cmsregistration.php -- only contains the php script for registration
  3. login.php -- html form
  4. cmslogin.php -- only contains the php script for logging user in
  5. myart.php, etc -- all the files used once the user is logged in

I've tried putting at the top of all of them, none of them, and every other combination I can think of - but I still get the header errors. This is trying to login:

Warning: Cannot add header information - headers already sent by (output started at /home/sites/site34/web/testarea/cms/cmslogin.php:3) in /home/sites/site34/web/testarea/cms/cmslogin.php on line 52.

and the final line listing (52 in this case) is always the line appropriate for the login level (admin in this case):

<strong>52:</strong> header("Location: admin.php"); exit;

Thanks very much - Dunstan

login or register to post comments

I think I see the error ...

Submitted by eli on August 28, 2002 - 04:41.

The error report that you are getting has to do with this line in cmslogin.php . If you remove that the error should go away. PHP has attempted to put this out (view the source of the error page and you will see the comment) and therefore has sent an output header. Therefore it can send no further headers such as the one in line 52. HTH!

login or register to post comments

crud!

Submitted by eli on August 28, 2002 - 04:44.

Remove the HTML comment line at the top of the cmslogin.php that says login script

login or register to post comments

Newbie, cant connect to DB

Submitted by osj on November 4, 2002 - 06:28.

Hi! Im new at all this DB and PHP, how do I get the pages to connect to my DB, if I use your code, and put it on the onternet to test, it says it cant connect to the DB. What should I change?

login or register to post comments

Change the database information

Submitted by eli on November 4, 2002 - 06:33.

//connect to and select database
if(!($dbconnect = mysql_pconnect("127.0.0.1", "cms_user", "cms_password"))){
	print("Failed to connect to database!\n");
	exit();
	}
if(!mysql_select_db("cms", $dbconnect)){
	print("Failed to select database!\n");
	exit();
	}
You have to change the server, user, and password information as well as the database name (if it is not named "cms")

login or register to post comments

DB again

Submitted by osj on November 4, 2002 - 06:40.

The database is named CMS, so I have to change 127.0.0.1 to the IP number of my site? and what should I change cms_user and cms_password to? Sorry but I dont know much about all this I just wanted to try this out.

login or register to post comments

Databse user and password

Submitted by eli on November 4, 2002 - 06:43.

You have to change cms_user to the database user you have granted for handling the CMS database. Likewise the cms_password should be the password of the cms_user.

login or register to post comments

cms_registration.php

Submitted by Rajesh on June 26, 2003 - 06:21.

I am using PHP 4.3.2, MySQL 4.0.13-nt, and IIS 5.1

Apparently the variables used in the form on cms_registration.html and the values in them are not getting passed to cms_registration.php. The INSERT statement does create a new record, but with the exception of the access_level field (having a default value), every else is left NULL.

Also, when I query out the administrator's e-mail, I get a result of "Resource id #3", not the e-mail address. I tested both SQL statements in MySQL command line and they work fine within MySQL, so I know it is a PHP issue. Any thoughts? Thanks!

Rajesh Nakrani Jeremiah 29:11-13

login or register to post comments

Error..

Submitted by bobd314 on November 16, 2003 - 00:53.

I get some.. session_start(): Cannot send sesson cookie - headers alardy sent by (out put started at............... And so on, I read that some one else had this problem, I moved the sessions start thing to the beginning of the file and it still didnt work..

login or register to post comments

The access keys for this page are: ALT (Control on a Mac) plus:

evolt.orgEvolt.org is an all-volunteer resource for web developers made up of a discussion list, a browser archive, and member-submitted articles. This article is the property of its author, please do not redistribute or use elsewhere without checking with the author.