Building an E-Commerce Site Part 2: Managing Users with Sessions

This is the second article in a three-part series dealing with using PHP 4 and MySQL to make a comprehensive e-commerce storefront solution. This article covers session management within the store, user privileges, and a few security concerns.

Welcome to Part 2 of the E-Commerce Step-by-Step Guide. In this installment, we will add the ability to manage users and, to track them with PHP4 sessions. After completing this installment, you will have:

  • created the underlying tables for user management;
  • created PHP scripts to add users;
  • created PHP scripts to edit users;
  • created PHP scripts to delete users;
  • created PHP scripts to let people sign up for accounts;
  • created PHP scripts to handle logins and logouts;
  • created PHP scripts to handle forgotten passwords.
{mospagebreak title=Assumptions and Requirements}

Before reading this guide, you should have read and completed part 1 of this series. Specifically, you should have the mymarket database created and the product catalog administrative scripts up and running.

If you have not already done so, please read Part 1 of this guide at:

Also, if you want to follow this guide and get a working site, you must use PHP4 because of the built-in session management features. In most of the scripts, we use PHP4 specific features that are not available in PHP3.

NOTE: If you want to get these examples to work in PHP3, you will have to rewrite some of the functions used in the example script files. You need to:

– provide your own session library;

– reorganize all the scripts so that the functions are defined before you call them;

– change all occurrences of <?=$var?> to <?echo $var?>.

{mospagebreak title=Primer on Sessions}

Before we begin, let’s quickly go over the concept of a session and the reason we need it. It’s hard (for me) to define what a session is exactly, so let’s use an example that should be very familiar to you — logging in to your computer and using it every day. After you log in, your computer knows who you are. Every action that you perform is done so with your name.

So what’s so special about that — we take it for granted every time we have to login to any system. What’s the big deal with doing this on the web? Well, the web (or specifically, the HTTP protocol) is connectionless. That means each request made to a web server is independent of all the other requests. Whereas your computer keeps information about you in memory and knows when you log in and out, a web server doesn’t. A web server simply waits for requests and sends responses.

Let’s illustrate this a little bit:

Let’s say we only have two people, John Doe and Jane Doe, accessing MyMarket, and their actions are like this:

  1. John looks at the product catalog.
  2. Jane looks at the product catalog.
  3. John adds an item to his basket.
  4. Jane adds an item to her basket.
  5. John goes to the checkout.
  6. Jane goes to the checkout.

Since HTTP is connectionless, each request is completely isolated from the other requests. So how does the server know who’s doing what? How does the server know that actions 1, 3, 4 are from John, and actions 2, 4, 6 are from Jane? Well, to make a long story short, the web server doesn’t have to know. It can continue on happily responding to requests, session management has to be done with the backend scripting language.

What we need is a way to group together requests by the same person into the same session. This is where PHP4’s session management capabilities come in. It can group together requests made from the same source (eg. client’s browser) into the same session, we have to provide the smarts to associate users with sessions.

In other words, PHP4’s session management can tell us requests 1, 3, and 4 belong to the same session (call it session A). Our application has to know that session A is owned by John Doe.

{mospagebreak title=Session Management in PHP4}

PHP4 adds some session management functions that make our life easier when dealing with sessions. The ones we are interested in are:

  • session_start();
  • session_register();

session_start() is used to start up PHP4’s session management capabilities; you need to call it before you use any of the other session functions. session_register() is used to tell PHP which variables to track in the session. A typical call to these functions would look like this:

session_register(“SESSION”);

This tells PHP to start up the session manager, and tells PHP that the variable called SESSION is a session variable. You can register as many session variables as you like, but I prefer to only register one session variable called SESSION, and anything I need persistent I put into this variable. For example, I like to say:


session_register(“SESSION”); $SESSION[“var1”] = 5; $SESSION[“var2”] = 6;

instead of


session_register(“var1”); session_register(“var2”); $var1 = 5; $var2 = 6;

because after you register lots of session variables, you tend to forget what they were, well, at least I do :).

Anyhow, by now you probably want to see some code in action, so create a script called session_test.php somewhere accessible, and put into it:


<? session_start(); session_register(“SESSION”); if (! isset($SESSION)) { $SESSION[“count”] = 0; echo “<li>Counter initialized, please reload this page to see it increment”; } else { echo “<li>Waking up session $PHPSESSID”; $SESSION[“count”]++; } echo “<li>The counter is now $SESSION[count] “; ?>

Fire that up in your browser, the first time you hit the page, it should say ” Counter initialized, please reload this page to see it increment”. Each time you reload it, the counter value should increment by one. You will also see the session ID. If it does, then hurray, your PHP4 session manager works 🙂

So how does this work? Well, when you call session_start(), PHP4 determines a unique session ID for the client. This session ID is an MD5 hash of something (not sure what), and it is stored as a cookie on the client’s PC.

Now each time that client makes a request, PHP4 will read this session ID and load up the data for the session. When you call session_register(), you are telling PHP4 which variables you want kept in the session. Each page that loads up, the previous values for the registered variables will be reloaded, and each time the page ends PHP4 will save the values of the registered variables.

By default, PHP keeps track of the sessions in temporary files in the /tmp directory, take a listings and see for yourself:

You will see something like this:


-rw——- 1 apache web 10 May 7 15:27 sess_6dd9ea8e61cd49cd3ad6de -rw——- 1 apache web 10 May 7 19:49 sess_7d7f97afb6759948f554b00 -rw——- 1 apache web 6 May 9 01:00 sess_8ab78830e151add9d79b628 -rw——- 1 apache web 31 May 9 11:41 sess_a3058a6bb1baf57f565c384 -rw——- 1 apache web 30 May 9 11:42 sess_c379faad83ad3dc8ab6d22c -rw——- 1 apache web 6 May 8 01:00 sess_cd68a5054241aff1a8157c2 -rw——- 1 apache web 34 May 7 15:17 sess_cd97e41912b28c44cc0481b -rw——- 1 apache web 42 May 9 11:23 sess_d1285edd0c951c70b1aec17 -rw——- 1 apache web 30 May 9 11:42 sess_da93f6e19b6be01257d7a64 -rw——- 1 apache web 42 May 7 21:26 sess_e837123c1af78c538e89b47

Each one of those files is a session, let’s take a look at one of them (note, you probably have to su to root to peek inside a session file). Tip: don’t just cut and paste the following commands, you need to specify the name of a real file:


# more /tmp/sess_a3058a6bb1baf57f565c3844c8810f4b

You will see something like this:


SESSION|a:1:{s:5:”count”;i:234;}

Does that look familiar? It should if you’ve ever used the serialize() and unserialize() functions in PHP. If not, don’t worry about it. Anyhow, I just wanted to illustrate how sessions were stored. You can rewrite the PHP session handlers to store sessions into a database or whatever else, but that’s beyond the scope of this tutorial (but it’s not hard at all).

{mospagebreak title=User Management and Privileges}

Okay, we’ve spend enough time on PHP4’s session management, all you really need to get out of that was the two functions session_start() and session_register(). Let’s get back to the issue of keeping track of users.

PHP can help us keep track of sessions, and group requests from the same session together. Now, we have to do our part and associate user accounts with these sessions. We will use a variable called SESSION[“user”] to keep track of user information. When a user logs in, we will put their information into this variable. As long as this variable is defined, we will assume that a user has logged in. When a user logs off, we will clear out this variable.

Specifically, we will keep the following information about the user:

  • SESSION[“user”][“username”] This is the user’s login ID (their nick name if you will), and it is how we tell users apart from each other.
  • SESSION[“user”][“firstname”] The user’s firstname.
  • SESSION[“user”][“lastname”] The user’s lastname.
  • SESSION[“user”][“email”] The user’s email address.
  • SESSION[“user”][“priv”] The user’s privilege level.

Let’s talk a bit about the privilege levels. We are going to have two levels of security: (1) normal customers and (2) administrative users. Normal customers can use the system, browse through the catalog, and do other customer functions. Administrators can do everything a normal user can do, but also has the ability to perform system administrative functions (e.g. everything from part 1 of this guide). In real life, there are probably many more privilege levels that you want defined but we are going to keep things simple here.

This is all fine and dandy, but where do we get this user information from? We need to have a way to store all the users on the system, and the perfect place for that would be in the database. We’re going to create a users table to hold all our users.

{mospagebreak title=Step 1: Creating the Users Table}

Start up MySQL and login as the root user by issuing this command from the shell prompt:


$ mysql -u root -p

You should see MySQL started:


Your MySQL connection id is 412 to server version: 3.22.30 Type ‘help’ for help. mysql>

Now select the mymarket database:


mysql> USE mymarket;

Now you’re in the mymarket database, let’s create the user table:


mysql> CREATE TABLE users ( -> username char(16) not null, -> password char(32) not null, -> priv char(5) not null, -> firstname varchar(64) not null, -> lastname varchar(64) not null, -> email varchar(128) not null, -> phone varchar(32) not null, -> address varchar(255) not null, -> PRIMARY KEY (username), -> UNIQUE email (email) -> );

Notice the constraints we’ve put on the users table, the username is the primary key (which makes sense, you should be able to identify a user record based on the username). The email address has a unique constraint as well because we don’t want duplicate email addresses.

Now let’s add a record to create the root user with the password password:


mysql> INSERT INTO users VALUES ( -> ‘root’, -> ‘5f4dcc3b5aa765d61d8327deb882cf99’, -> ‘admin’, -> ‘System’, -> ‘Administrator’, -> ‘root@mymarket.com’, -> ‘555-5555’, -> ‘123 5 Avenue’ -> );

Notice the password looks a bit wierd, 5f4dcc3b5aa765d61d8327deb882cf99. This is the MD5 hash of the the word “password”, I won’t go into details here, but the important thing to note is that it’s a one-way algorithm and it always produces a 32 character string.

That’s it, we have a users table to track our users, and one administrative account so we can try logging in and out of the system.

{mospagebreak title=Step 2: Extracting the New Scripts}

Okay, we’ve got our user table, let’s make screens for the user to log in and log out. Download the mymarket2.tar.gz file and extract it into your web root directory. Note that this replaces the files from the first tutorial.

IMPORTANT NOTE: If you have made modifications to the files from the first tutorial, please make a backup copy and store it somewhere else. The files in mymarket2.tar.gz will overwrite any changes you made to the files from the first tutorial.

We do the same drill from the first tutorial. Download the mymarket2.tar.gz file and extract it into your web root directory. For example, if your web root is in

type


$ tar -zxf /tmp/mymarket2.tar.gz

Assuming that you’ve downloaded mymarket2.tar.gz into /tmp. Now, open up the file application.php and change the $CFG->wwwroot and $CFG->dirroot paths to match your server configuration.

Before we dive into the source code, let me explain how I’ve setup the directories and files. Once you go into the mymarket directory, you will see five directories, and four files. Everything in bold is new to this tutorial:


drwxrws— 2 ying web 1024 Apr 20 02:05 images/ drwxrws— 2 ying web 1024 May 4 09:18 lib/ drwxrws— 3 ying web 1024 May 9 11:20 templates/ drwxrwsr-x 3 lanuser web 1024 May 9 11:20 users/ -rw-rw—- 1 ying web 2074 May 7 14:58 application.php -rw-rw-r– 1 lanuser web 1488 May 7 12:21 index.php -rw-rw-r– 1 lanuser web 2427 May 7 14:51 login.php -rw-rw-r– 1 lanuser web 1040 May 9 11:19 logout.php

I won’t go over the files and directories that were from the first tutorial (admin, images, lib, templates) except to say that the scripts inside them have changed a bit. Take a look at them and see if you can spot what’s changed <grin>, just kidding, I will cover those as necessary 🙂

The users directory is where we keep the scripts relating to user functions. For now, it contains scripts to let the users signup for an account, change their password, change their settings, and retrieve forgotten passwords.

The index.php file is the MyMarket homepage. We didn’t have one of these from part 1 of this guide because we were only interested in the administrative functions. We have it now only to show a dummy homepage (which we will add to in part 3 of this guide).

The login.php and logout.php files handle the process of logging in and logging out. We’ve briefly gone over what was involved in logging in and logging out, see these scripts for more details.

{mospagebreak title=Step 3: General Script Changes from Tutorial 1}

Okay, now let’s go over some of the changes we’ve made since part 1 of this tutorial. Some new files were added, and some scripts were changed to include new functions.

Added 2 new configuration variables:

  1. $CFG->wordlist, points to a text file containing a list of words that we will use when generating random passwords, more on this later.
  2. $CFG->support, stores the email address of the MyMarket support staff (the non-existent ones :).

The value of $ME is now set by a function called qualified_me(), instead of just using $SCRIPT_NAME.

A bunch of new functions have been added to stdlib.php to make it more useful:

  • strip_querystring() Changes things like “foo.php?abc=xyz” to ” foo.php”
  • get_referer() Returns the URL of the referring page
  • me() Returns the name of the current script
  • qualified_me() Returns the name of the current script with the leading http:// or https:// qualification
  • match_referer() Returns true or false depending on if the referring page matches what you want
  • redirect() Uses META tags to redirect the client’s browser to another URL
  • read_template() Used to read a template file into a string

The file mymarket.php contains some standard functions that are used by this application. For example, the build_category_list() function that used to be in admin/products.php has been moved here so that we can use it in other scripts as well (eg. the admin/categories.php page). The other functions in this script are:

  • is_logged_in() Returns true if the user has logged in
  • require_login() If the user hasn’t logged in, show them the login screen and make then login first
  • require_priv() Make sure the user has a particular privilege, if they don’t show an insufficient privileges screen
  • has_priv() A less severe version of require_priv(), this just returns true or false depending on if the user has a particular privilege
  • build_category_list() Our favourite function moved here from the admin/categories.php script
  • generate_password() A nifty function that generates random passwords based on a word file ($CFG->wordlist)
  • err() A function to print out an error market (<<) if an error variable is defined
  • username_exists() Returns true if the username exists
  • email_exists() Returns true if the email address exists
  • reset_user_password() A function that resets the user’s password and sends them an email notification
{mospagebreak title=Step 4: New Administrative Screens}

Now that we’ve got login and privileges in place, we can put some protection on our administrative pages. If you look at the administrative pages:

  • admin/index.php
  • admin/categories.php
  • admin/products.php
  • admin/users.php

You will see two new commands at the top of the file: require_login() and require_priv(). The first function makes sure the user has logged in (if not, it will present the login screen) and the latter function makes sure the user has the required privileges.

The file admin/users.php is a new administrative screen that lets you (the administrator) create, edit, and remove users. It is built like the other maintenance screens, so look at the source code for details.

The file admin/categories.php has been modified so that it presents the list of parent categories in a bigger list box, like the one in products.php. This doesn’t really have anything to do with user management, but I thought it would be a nice change to make 🙂

The file admin/products.php has been modified, the build_category_tree function was taken from here and placed into the shared lib/mymarket.php file. All our shared functions that are specific to MyMarket will be kept in lib/mymarket.php.

{mospagebreak title=Step 5: User Scripts}

In the users directory, we keep a bunch of scripts to let users manage themselves (to some extent):

users/signup.php

This script lets a user signup for an account. Signing up for an account is a straight forward process. The user fills in their information, and selects a username and password. Note that in our validation function, we check to see that the user fills in all the required fields, and also that the username and email addresses do not already exist. If they do, the user will have to specify different ones.

users/forgot_password.php

The forgot password script asks the user for their email address and then looks up their user record in the database. If a user record is found, the user’s password gets reset to some random word and then their new password address gets sent to their email address. This is why it is important that there are no duplicate email addresses on the system.

users/change_password.php

A simple script to let the user change their password.

users/change_password.php

A simple script to let the user change their settings. Note, we can’t have the user changing their username (that’s a big no-no!), firstname, or lastname.

{mospagebreak title=Step 6: A Note on Security}

So you may be thinking, “how secure is all this”? That’s a good question. There are many places where security can be compromised here, you have to ask yourself:

  • How much do you trust PHP4’s session management functions to be immune to people trying to hijack other sessions — after all there is just one PHPSESSID variable that separates you from everyone else using the system (oooh, scarey thought). How unique is that PHPSESSID anyway?
  • Assuming PHP4’s session management functions are bulletproof, how much do you trust the my login routines, and my privilege / access checking routines?
  • How safe is your database? Can someone connect remotely and diddle with your tables and read or alter data without you knowing? (NOTE: Never ever ever ever ever ever ever ever store credit card information in your database. You don’t need it there, you don’t want the liability!)
  • How safe are your scripts? Can someone change them without you knowing? How safe is your ISP? When was the last time you verified all the permissions on your files so that no one else can read/edit them?

Anyhow, my point is that what we are developing here should NOT be used in a production environment without you understanding all the risks involved. I’ve just presented a few to get your mind thinking about security risks.

{mospagebreak title=Step 7: Putting It All Together}

We’ve covered the sessions as well as user management. We’ve also gone over the changes that have happened since part 1 of this guide. Now let’s put everything together. Open up mymarket/ with your browser and you should see the (boring) home page. Now click on the “login” link and sign on as:

username: root

password: password

First thing you should do is change your password! Next, go to the administrative home page and create a new user account (that doesn’t have the “admin” privilege). Note you should specify a real email address when doing this because the password is going to get sent to that email address.

TROUBLESHOOTING EMAIL: If your PHP4 refuses to send email, make sure the settings in the [mail function] section of your php.ini are correct.

Now log out and try to access the administrative pages in mymarket/admin, notice that it asks you to login first. Neat-o isn’t it 🙂 Okay, just keep playing with the system until you’re comfortable with it.

As always, go over the code and comments while you play with the system to get a good feel for what is happening. Stay tuned for the next part where we look at letting customers (regular users) to look through the product catalog and order things!

[gp-comments width="770" linklove="off" ]

chat sex hikayeleri Ensest hikaye