Showing posts with label mysql. Show all posts
Showing posts with label mysql. Show all posts

Simple AJAX with jQueryUI and PHP

This will be a short tutorial on how to incorporate AJAX interaction into a PHP site using jQuery and the jQueryUI framework.


Imagine we have a page that lets users manage a list of books that is stored in a database.  We want them to be able to easily edit the books via ajax without having to go to another page. Below is an example of what we want.



Here's the database table we'll use plus a few sample books.


CREATE TABLE `books` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `title` varchar(30) NOT NULL,
  `genre` enum('fantasy','mystery','nonfiction') NOT NULL,
  `description` text NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE = InnoDB;

INSERT INTO `book` (`id`, `title`, `genre`, `description`) VALUES
(1, 'The Lord of the Rings', 'fantasy', 'The Lord of the Rings is an epic fantasy novel written by philologist and University of Oxford professor J. R. R. Tolkien (from Wikipedia).'),
(2, 'The Maltese Falcon', 'mystery', 'The Maltese Falcon is a 1930 detective novel by Dashiell Hammett, originally serialized in the magazine Black Mask (from Wikipedia).'),
(3, 'Economics in One Lesson', 'nonfiction', 'Economics in One Lesson is an introduction to free market economics written by Henry Hazlitt and published in 1946, based on Frédéric Bastiat''s essay Ce qu''on voit et ce qu''on ne voit pas (English: "What is Seen and What is Not Seen") (from Wikipedia).');


First, let's create the PHP page that pulls these books from the database and displays them to the user. Later, we'll add javascript code to this page to make the edit link use AJAX to interact with the database.

//display.php
<div class='books'>
 <?php
 //connect to database
 mysql_connect('localhost', 'mysql_user', 'mysql_password');
 mysql_select_db('dbname');

 //get all books
 $query = "SELECT * FROM books";
 $result = mysql_query($query) or die("Error selecting books");

 //display books
 while($row = mysql_fetch_assoc($result)) {
 ?>
  <div class='book' id='book_<?php echo $row['id']; ?>'>
   <a class='edit' href='#'>edit</a>
   <h3 class='title'><?php echo $row['title']; ?></h3>
   <p><em class='genre'><?php echo $row['genre']; ?></em></p>
   <p class='description'><?php echo $row['description']; ?></p>
  </div>
 <?php
 }
 ?>
</div>

The next page to create is the edit.php page that the ajax link will call.


//edit.php
<?php
//connect to database
mysql_connect('localhost', 'mysql_user', 'mysql_password');
mysql_select_db('dbname');

//pull info from $_POST and sanitize it
$id = mysql_real_escape_string($_POST['id']);
$title = mysql_real_escape_string($_POST['title']);
$genre = mysql_real_escape_string($_POST['genre']);
$description = mysql_real_escape_string($_POST['description']);

//update in database
$query = 'Update books SET title="'.$title.'", genre="'.$genre.'", description="'.$description.'" WHERE id="'.$id.'"';
mysql_query($query);

//generate json code
echo json_encode(array(
 'id'=>$id,
 'title'=>$title,
 'genre'=>$genre,
 'description'=>$description
));
?>

When the user clicks the edit link for a book, we want a dialog box to pop up with a form that lets the user edit the data. We want the form to submit to the edit.php page via AJAX. Finally, we want the page to update to reflect the changes.


To do this, we first create the html for the dialog box. The submit button will be handled by jQuery, so we don't need to add it here. This goes at the bottom of the display.php page.


<div id='edit_dialog'>
 <form action='edit.php' method='post'>
  <input type='hidden' name='id' />

  Title: 
  <input type='text' name='title' /><br />
  
  Genre:
  <select name='genre'>
   <option value='fantasy'>Fantasy</option>
   <option value='mystery'>Mystery</option>
   <option value='nonfiction'>Nonfiction</option>
  </select><br />
  
  Description:
  <textarea name='description' cols='30' rows='3'></textarea>  
 </form>
</div>

Now we add the jQuery code to the display.php page to tie everything together. This requires jQuery, jQueryUI with the dialog widget, and a jQueryUI theme to be loaded. This goes somewhere on the display.php page.


$(document).ready(function() {
 //Create dialog
 $edit_dialog = $("#edit_dialog").dialog({
  autoOpen:false, 
  title:"Edit Book", 
  modal:true, 
  buttons:[
   {text: "Submit", click: function() { $('form',$(this)).submit(); }},
   {text: "Cancel", click: function() { $(this).dialog("close"); }},
  ]
 });
 
 //Submit action for dialog form
 $("#edit_dialog form").submit(function() {
  var form = $(this);
  //post form data to form's action attribute
  $.post($(this).attr('action'), $(this).serialize(),function(data) {   
   //get DOM element of updated book
   var book = $('#book_'+data.id);
  
   //update title
   $('.title',book).html(data.title);
   
   //update genre
   $('.genre',book).html(data.genre);
   
   //update description
   $('.description',book).html(data.description);
  
   //close the dialog
   $("#edit_dialog").dialog('close');
  },'json');
  
  //stop default form submit action
  return false;
 });

 //when the edit link is clicked
 function edit_link_action() {
  //get closest book div
  var book = $(this).closest('.book');
  
  //get id from div
  var id = book.attr('id').split('_');
  id = id[id.length-1];
  
  //set id in form
  $('#edit_dialog input[name="id"]').val(id);
  
  //set current title in form
  $('#edit_dialog input[name="title"]').val($('.title',book).html());
  
  //set current genre in form
  $('#edit_dialog select[name="genre"]').val($('.genre',book).html());
  
  //set current description in form
  $('#edit_dialog textarea[name="description"]').val($('.description',book).html());
  
  //open dialog
  $edit_dialog.dialog('open');
  
  //stop default link action
  return false;
 }
 
 //attach action to edit links
 $(".edit").click(edit_link_action);
});

Once all the parts are put together, you should have a fully functioning AJAX site. Below is the complete code for the display.php page.


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
 <script type='text/javascript' src='jquery-1.4.4.min.js'></script>
 <script type='text/javascript' src='jquery-ui-1.8.9.custom.min.js'></script>
 <link rel='stylesheet' href='jquery-ui-1.8.9.custom.css' />
 <script type='text/javascript'>
  $(document).ready(function() {
   //Create dialog
   $edit_dialog = $("#edit_dialog").dialog({
    autoOpen:false, 
    title:"Edit Book", 
    modal:true, 
    buttons:[
     {text: "Submit", click: function() { $('form',$(this)).submit(); }},
     {text: "Cancel", click: function() { $(this).dialog("close"); }},
    ]
   });
   
   //Submit action for dialog form
   $("#edit_dialog form").submit(function() {
    var form = $(this);
    //post form data to form's action attribute
    $.post($(this).attr('action'), $(this).serialize(),function(data) {   
     //get DOM element of updated book
     var book = $('#book_'+data.id);
    
     //update title
     $('.title',book).html(data.title);
     
     //update genre
     $('.genre',book).html(data.genre);
     
     //update description
     $('.description',book).html(data.description);
    
     //close the dialog
     $("#edit_dialog").dialog('close');
    },'json');
    
    //stop default form submit action
    return false;
   });

   //when the edit link is clicked
   function edit_link_action() {
    //get closest book div
    var book = $(this).closest('.book');
    
    //get id from div
    var id = book.attr('id').split('_');
    id = id[id.length-1];
    
    //set id in form
    $('#edit_dialog input[name="id"]').val(id);
    
    //set current title in form
    $('#edit_dialog input[name="title"]').val($('.title',book).html());
    
    //set current genre in form
    $('#edit_dialog select[name="genre"]').val($('.genre',book).html());
    
    //set current description in form
    $('#edit_dialog textarea[name="description"]').val($('.description',book).html());
    
    //open dialog
    $edit_dialog.dialog('open');
    
    //stop default link action
    return false;
   }
   
   //attach action to edit links
   $(".edit").click(edit_link_action);
  });
 </script>
</head>
<body>
 <div class='books'>
  <?php
  //connect to database
  mysql_connect('localhost', 'mysql_user', 'mysql_password');
  mysql_select_db('dbname');

  //get all books
  $query = "SELECT * FROM books";
  $result = mysql_query($query) or die("Error selecting books");

  //display books
  while($row = mysql_fetch_assoc($result)) {
  ?>
   <div class='book' id='book_<?php echo $row['id']; ?>'>
    <a class='edit' href='#'>edit</a>
    <h3 class='title'><?php echo $row['title']; ?></h3>
    <p><em class='genre'><?php echo $row['genre']; ?></em></p>
    <p class='description'><?php echo $row['description']; ?></p>
   </div>
  <?php
  }
  ?>
 </div>
 
 <div id='edit_dialog'>
  <form action='edit.php' method='post'>
   <input type='hidden' name='id' />

   Title: 
   <input type='text' name='title' /><br />
   
   Genre:
   <select name='genre'>
    <option value='fantasy'>Fantasy</option>
    <option value='mystery'>Mystery</option>
    <option value='nonfiction'>Nonfiction</option>
   </select><br />
   
   Description:
   <textarea name='description' cols='30' rows='3'></textarea>  
  </form>
 </div>
</body>
</html>

Storing Passwords in a Database

In this post, I'll go through three common ways to store and retrieve passwords in a database. I'll assume PHP and MySQL, but the techniques should be very similar for other setups.

Only the last method should ever be used for security reasons, but unfortunately, a large number of sites use one of the less secure methods and put their users in danger.

Storing a Password as Plain Text

This is the most basic and definitely least secure method for handling passwords. Never Use This Method!

The basic strategy is to store the password directly in the database. You would then authenticate a user by running a query like this:

SELECT id FROM users WHERE username='johnsmith' AND password='123456'

If the query returns a row, the username and password are correct. As you can see, if anyone intercepts this query along the way, they automatically have the user's username and password. Also if your database gets stolen, the thief has all of your users' usernames and passwords. This is an even bigger problem because most people use the same username and password for everything.

If you ever click a Forgot Your Password link and the site gives you your current password, they are using this method and I would highly suggest not using the site or at least using a unique password just for the site.

Using a Password Hash

This method is better than plain text, but still has some major, relatively little known, security holes in it. A lot of sites use this method thinking it is secure. Again, do not use this method.

This method takes a user's password and converts it to an md5 or similar hash before storing in the database. For example, "123456" becomes "e10adc3949ba59abbe56e057f20f883e". This seems like it solves the problem with plain text since a person cannot look at the hashed string and know the user's password. But, if you type this hash into Google, the second result is titled "Google Hash: md5(123456) = e10adc3949ba59abbe56e057f20f883e". Not as secure as it first looked, is it?

There are md5 hash tables you can download that contain every word in the dictionary and every common password that make this method very susceptible to attacks. Many sites require passwords with numbers, symbols, capital letters, etc., which helps fix the security hole, but why make things harder on your users when you can just use a password salt?

Using a Password Salt

There is no reason not to use this method. It provides an extra layer of security on top of a password hash with very little extra work.

This method generates a random string (salt) and appends it to the user's password before generating an md5 or similar hash. Then, both the password hash and the password salt are stored in the database and used to authenticate the user. For example, "123456" becomes "123456ghjfdweurt" becomes "8e1a92e8f87a5bbf36f26e330cf7f0b5". Try typing that hash into Google and the most you may find is this article.

Here's the PHP code for initially inserting a user into a database. The getRandomString() function is from http://www.lost-in-code.com/programming/php-code/php-random-string-with-numbers-and-letters/.

//get username and password
$username = $_REQUEST['username'];
$password = $_REQUEST['password'];

//generate password salt
$password_salt = genRandomString();

//generate password hash
$password_hash = $password . $password_salt;

//insert into database
$query = "INSERT INTO users (`username`,`password_hash`,`password_salt`) VALUES ('$username', '$password_hash', '$password_salt')";
mysql_query($query);



function  genRandomString() {
    $length = 10;
    $characters = ’0123456789abcdefghijklmnopqrstuvwxyz’;
    $string = ”;    

    for ($p = 0; $p < $length; $p++) {
        $string .= $characters[mt_rand(0, strlen($characters))];
    }

    return $string;
}

Here's the code for authenticating a user once they are already in the database:

//get username and password
$username = $_REQUEST['username'];
$password = $_REQUEST['password'];

//query database
$query = "SELECT * FROM users WHERE username='$username'";
$result = mysql_query($query);

//if no result, username is incorrect
if(!$result) {
    //authentication failed
}

//get database row
$row = mysql_fetch_assoc($result);

//generate password hash from entered password
$password_hash = md5($password . $row['password_salt']);

//check if the generated hash is equal to the hash in the database
if($password_hash === $row['password_hash']) {
     //authentication passed
}
else {
     //authentication failed
}

Important Safety Tip

No matter what method you use, SSL encryption is essential during authentication to protect against man-in-the-middle attacks. This is where an attacker intercepts data between the user and the server. If the user submits a login form and an attacker intercepts it, the password will be compromised no matter which method you use.

MyISAM vs InnoDB

I'm going to pit two of MySQL's most popular table engines against each other using the four S's as a guide: Speed, Storage, Stability, and Special features.

To test these catagories, I created two identical tables in the same database. One using MyISAM, one using InnoDB.

 CREATE TABLE `test`.`myisam` (
`field1` INT( 11 ) NOT NULL AUTO_INCREMENT ,
`field2` VARCHAR( 32 ) NOT NULL ,
`field3` TEXT NOT NULL ,
PRIMARY KEY ( `field1` )
) ENGINE = MYISAM 

 CREATE TABLE `test`.`innodb` (
`field1` INT( 11 ) NOT NULL AUTO_INCREMENT ,
`field2` VARCHAR( 32 ) NOT NULL ,
`field3` TEXT NOT NULL ,
PRIMARY KEY ( `field1` )
) ENGINE = INNODB 
  1. Speed

    I devised a few tests to compare the relative speeds of the two tables. I repeated each query 3 times and took the average execution time for each table.

    Insert 1,000 rows in one query

    MyISAM: An incredible .0094 second average
    InnoDB: A respectable .0849 second average

    SELECT 10,000 Rows

    MyISAM: A fast .0121 second average
    InnoDB: A decent .0302 second average

    Advanced UPDATE Query

    /* 1,000 rows with md5 hashes (21 rows match) */
    UPDATE innodb SET field3 = 'changed'
      WHERE field3 LIKE '%a12%';
    UPDATE myisam SET field3 = 'changed'
      WHERE field3 LIKE '%a12%';
    

    MyISAM: A good .0112 second average
    InnoDB: A slightly worse .0282 second average

    Conclusion

    I left out some measures of speed, but these numbers are pretty clear. MyISAM was anywhere from 2 to 10 times faster than InnoDB when performing the same tasks. MyISAM wins this round.

  2. Storage

    Here I'm comparing the disk space the two tables use when storing data.

    Empty Table

    MyISAM: 1kb of disk space
    InnoDB: 32kb of disk space

    1,000 Rows

    MyISAM: 166kb of disk space
    InnoDB: 256kb of disk space

    10,000 Rows

    MyISAM: 1,341kb of disk space
    InnoDB: 2,080kb of disk space

    Conclusion

    MyISAM is again the clear winner. MyISAM appears to use about 60% of the disk space that InnoDB uses to store the same amount of data.

  3. Stability

    One measure of stability is the ability of the table to handle simultaneous connections to the database without failing. I haven't tested this myself, but the consensus seems to be that InnoDB is better at this.

    Conclusion

    I personally haven't had stability issues with either table engine, but then again, I haven't had to manage hundreds of simultaneous connections. I'll trust the people that have and declare InnoDB the winner for this round.

  4. Special Features

    This is the category that matters most when choosing an engine type. Both MyISAM and InnoDB have very useful features the other one doesn't. I'll take a look at the main unique feature from each table type.

    Transaction Support

    InnoDB is transaction safe. This means that you can roll back changes you make to a database. This is primarily used for rolling back changes if an error occurs.

    For example, let's say you are transferring money between accounts and taking out a fee. You have three queries: take money out, take fee out, and put money in. If the last query fails, you can roll back the first two. This is a must-have for many applications.

    Full Text Support

    MyISAM supports full text indices and full text searches. This lets you search through text fields extremely quickly. Instead of using LIKE on large tables, which is very ineficient, you can use the MATCH AGAINST syntax for a fraction of the time and processing power. This is a must-have if your tables have description fields that are searchable or you store entire articles in a database.

    Using "article_text LIKE '%mysql%'" on 100 5-page articles would take forever. However using "MATCH(article_text) AGAINST('mysql')" would take no time at all. Another advantage is advanced relevancy scores for searches. If an article mentions mysql 3 times, it will be ranked higher. If you search for "the dog and the cat," only the words "dog" and "cat" will be taken into account when calculating relevancy.

    Conclusion

    Which feature is better depends entirely on what your application is.

And the winner is...

InnoDB. Although InnoDB is often slower and uses more space than MyISAM, I consider transactions as too important to give up. If you look at the times, we're talking a difference of at most .05 seconds. Also, most hosting companies today offer at least 100mb of space per database. 10,000 rows with 100 characters each took up 600kb extra using InnoDB. If you store images and files in the database, space might be an issue, but for most applications, it isn't.

There are certain types of applications that should use MyISAM, most notably Search Engines, but for most applications, InnoDB is the right choice.

Mysql Transactions with PHP

One feature of Mysql that is often overlooked is transactions. Transactions allow you to preform multiple queries and rollback the changes if any one fails.

In mysql, only InnoDB tables have transaction support. MyISAM, which is often the default table type, does not support this.

Let's say you are transferring funds between 2 accounts. You withdraw the money in one query and deposit the money in another one. What happens if the deposit query fails? The money just disappears. Transactions are an easy way to solve this problem.

We must add some helper functions to our mysql config file. First we'll make a wrapper function for mysql_query(). It takes a query and an optional error message.

function query_db($query,$error="Error")
{
  //perform query
  $result = mysql_query($query);
  if(!$result) //query fails
  {
    //exit with error message
    exit($error."<br>$query<br> ".mysql_error());
  }
  else //query succeeds
    return $result;
}

Next, are three transaction functions, begin_transaction(), commit_transaction(), and rollback_transaction().

//Begins the transaction
//Every query after this can be rolled back
function begin_transaction()
{
  query_db("SET AUTOCOMMIT=0");
  query_db("BEGIN");

  //Set the $begin_transaction variable to true 
  //so that other functions know a transaction started
  global $begin_transaction;
  $begin_transaction = true;
}

//Commits all queries.  Changes cannot be undone after this
function commit_transaction()
{
  //if transaction is started, commit changes
  global $begin_transaction;
  if($begin_transaction)
    query_db("COMMIT");

  //update global variable
  $begin_transaction = false;
}

//Rolls back all queries. All changes are canceled.
function rollback_transaction()
{
  //if transaction is started, roll back changes
  global $begin_transaction;
  if($begin_transaction)
    query_db("ROLLBACK");

  //update global variable
  $begin_transaction = false;
}

We need to alter the query_db() function to rollback changes if an error occurs.

function query_db($query,$error="Error")
{
  //get global variable
  global $begin_transaction;

  //perform query
  $result = mysql_query($query);
  if(!$result) //query fails 
  {
    //if transaction is started, rollback changes
    if($begin_transaction)
      rollback_transaction();

    //exit with error message
    exit($error."<br>$query<br> ".mysql_error());
  }
  else //query succeeds
    return $result;
}

That's all you need to use transactions. Here's an example of how to use this.

<?php
begin_transaction();
  query_db("UPDATE accounts 
    SET balance = balance-500
    WHERE id=1"
  );
  query_db("UPDATE accounts 
    SET balance = balance+500    
    WHERE id=2"
  );
commit_transaction();
?>

If either query fails, both accounts are unaffected. If both queries succeed, the accounts are updated.

Sometimes, you want to make sure a row is affected, not just that the query succeeded. I didn't build this into the functions, but it's easy to implement. Here's a simple way to do it:

<?php
begin_transaction();
  query_db("UPDATE accounts 
    SET balance = balance-500
    WHERE id=1"
  );
  if(!mysql_affected_rows()) //no rows affected
    exit("error".rollback_transaction());

  query_db("UPDATE accounts 
    SET balance = balance+500    
    WHERE id=2"
  );
  if(!mysql_affected_rows()) //no rows affected
    exit("error".rollback_transaction());

commit_transaction();
?>

Transactions also help with testing an application. You can perform 20 queries, do some tests, and then roll back the changes automatically. Think of how much time this could save.

Basic user accounts with PHP and MySQL

This is a tutorial on adding basic user accounts to your site.

Objective:
  1. Create a registration and sign in page.
  2. Require users to log in to view designated pages.
Target Audience:
  1. Someone with basic MySQL and PHP knowledge.
  2. Someone who wants user accounts without using a framework like Joomla or CakePHP.

First, let's create the 'users' mysql table.

CREATE TABLE `users` (
`id` int(11) NOT NULL auto_increment,
`username` varchar(20) NOT NULL,
`password_hash` varchar(40) NOT NULL,
`password_salt` varchar(8) NOT NULL,
`created` datetime default NULL,
PRIMARY KEY  (`id`)
);

To add some security to the site, I'm encrypting the passwords (hence the password_salt and password_hash fields). This stops anyone from knowing a password by looking in the database.

Next, we'll make the sign up form (signup.php). This is where users will register for your site.

<html>
<head>
<title>Sign Up</title>
</head>
<?php
if(isset($_REQUEST['username'])) //Form submitted
{
 //Connect to database
 $conn = mysql_connect('localhost', 'root', 'password') 
  or die('Could not connect: ' . mysql_error());
 mysql_select_db('database_name');

 //Sanitize entered info
 $username = mysql_real_escape_string($_REQUEST['username']);
 $password = mysql_real_escape_string($_REQUEST['password']);
 
 //Validate entered info
 $test = true;
 if(empty($username) || empty($password))
  $test = false;

 if($test) //Validation passed
 {
  //Generate random 8 character password salt
  $password_salt = "";

  //characters to choose from
  $chars = "0123456789abcdefghijklmnopqrstuvwxyz-_%#"; 
  for($C=0;$C<8;$C++)
  {
   $password_salt .= $chars{rand(0,strlen($chars)-1)};
  }
  
  //Generate hash based on entered password and salt
  $password_hash = md5($password_salt.$password);

  //Insert user in database
  $query = "INSERT INTO users 
    (username,password_salt,password_hash,created) VALUES 
    ('$username','$password_salt','$password_hash',NOW())";
  mysql_query($query) or 
    die ("Error creating new user: " . mysql_error());

  //Display success message and exit
  exit(
    "Account created successfully.  You may now 
    <a href='signin.php'>Sign In</a>"
  );
 }
 else //Validation failed
  echo "Please enter all information";
?>
<h1>Sign Up</h1>
<form action="signup.php" method="post">
Username: 
<input type="text" name="username" /><br />
Password: 
<input type="password" name="password" /><br />
<input type="submit" value="Sign Up" />
</form>
</body>
</html>

Make sure to change the mysql connection settings above to match your configuration.

Lastly, we'll make the sign in page (signin.php). If a user tries to access a restricted page, they will be redirected here.

<?php
session_start(); //Start session so we can sign user in
?>
<html>
<head>
<title>Sign In</title>
</head>
<?php
if(isset($_REQUEST['username'])) //Form submitted
{
 //Connect to database
 $conn = mysql_connect('localhost', 'root', 'password') 
  or die('Could not connect: ' . mysql_error());
 mysql_select_db('database_name');

 //Sanitize entered info
 $username = mysql_real_escape_string($_REQUEST['username']);
 $password = mysql_real_escape_string($_REQUEST['password']);
 
 //Select users with enetered username from database
 $query = "
    SELECT id,username,password_salt,password_hash 
    FROM users 
    WHERE username='$username'";
 $result = mysql_query($query) 
    or die("Error looking up user: " . mysql_error());
 
 
 if($row=mysql_fetch_assoc($result))//Row is returned
 {
  //Generate hash based on entered password and stored salt
  $password_hash = md5($row['password_salt'].$password);
  
  //If User entered correct password
  if($password_hash == $row['password_hash'])
  {
   //Sign them in by storing their id in a session variable
   $_SESSION['userid']=$row['id'];
   
   //Show message and exit
   exit( "You are successfully signed in." );
  }
  else //Incorrect password
  {
   echo "Incorrect Password";
  }
 }
 else //Incorrect Username
 {
  echo "Incorrect Username";
 }
}
//Show sign in form
?>
<h1>Sign In</h1>
<form action="signin.php" method="post">
Username: 
<input type="text" name="username" /><br />
Password: 
<input type="password" name="password" /><br />
<input type="submit" value="Sign In" />
</form>
</body>
</html>

Again, make sure you change the mysql settings.

Now that people can sign up and sign in, you need a way to require this. Put this at the top of a page to require the user to sign in:

<?php
session_start();//Start the session
if(!isset($_SESSION['userid']))//User not signed in
{
 header("Location: signin.php");//Redirect to sign in page
 exit();//Stop script from executing
}
?>

Here are a few things to keep in mind:

  • "session_start();" must be the first line in a file. If there are any characters or whitespace before the opening php tag, it will not work.
  • This post is meant to explain how something works, not the best way to implement it. There are many improvements to be made and I may address them in the future.