After briefly describing how sessions work, Ill show you how you can use session variables to create a simple file-based login system and pass information from one page to another witho
Trang 1241
If you want to delete the original image after the thumbnail has been created, pass true as the second argument to the constructor like this:
$upload = new Ps2_ThumbnailUpload('C:/upload_test/', true);
The class has the following public methods:
• setThumbDestination(): This sets the path to the folder where the thumbnail images are to
be saved If you dont call this method, the thumbnails are stored in the same folder as the original images
• setThumbSuffix(): Use this to change the suffix inserted into the thumbnail names The default is _thb
• move(): This uploads the original image(s) and generates the thumbnail(s) By default, images that have the same name as an existing one are renamed To overwrite existing images, pass true as an argument to this method
It also inherits the following methods from the parent Ps2_Upload class:
• getMessages(): Retrieves messages generated by the upload and the thumbnail
• getMaxSize(): Gets the maximum upload size The default is 50kB
• setMaxSize(): Changes the maximum upload size The argument should be expressed as the number of bytes permitted
• addPermittedTypes(): This allows you to add other MIME types to the upload The Ps2_Thumbnail class rejects MIME types that it doesnt recognize, but the files are uploaded
as normal to the main destination folder
The Ps2_ThumbnailUpload class wasnt designed with mixed uploads in mind, so refine the messages generated by the Ps2_Thumbnail class if you want to use the inherited addPermittedTypes() method Because the Ps2_ThumbnailUpload class is dependent on the Ps2_Upload and Ps2_Thumbnail classes, you need to upload all three class definition files to your remote web server when using this class
on a live website
Chapter summary
This has been quite an intense chapter, showing not only how to generate thumbnails from larger images, but also introducing you to extending an existing class and overriding inherited methods Designing and extending classes can be confusing at first, but it becomes less intimidating if you concentrate on what each method is doing A key principle of class design is to break large tasks down into small, manageable units Ideally, a method should perform a single task, such as creating the image resource for the original image This isnt always possible For example, the createThumbnail() and processFile() methods perform multiple operations
The real advantage of using classes is the time and effort they save once you have defined them Instead
of typing dozens of lines of code each time you want to add file or thumbnail upload functionality to a website, calling the class involves just a few simple lines Also dont just think of the code in this chapter
as being for creating and uploading thumbnail images Many of the subroutines in the class files could be adapted for use in other situations
Trang 2CHAPTER 8
242
In the next chapter, youll learn all about PHP sessions, which preserve information related to a specific user and play a vital role in password-protecting web pages
Trang 3243
Pages That Remember:
Simple Login and Multipage Forms
The Web is a brilliant illusion When you visit a well-designed website, you get a great feeling of continuity,
as though flipping through the pages of a book or a magazine Everything fits together as a coherent entity The reality is quite different Each part of an individual page is stored and handled separately by the web server Apart from needing to know where to send the relevant files, the server has no interest in who you are Each time a PHP script runs, the variables exist only in the servers memory and are normally discarded as soon as the script finishes Even variables in the $_POST and $_GET arrays have only a brief life span Their value is passed once to the next script and then removed from memory unless you do something with it, such as store the information in a hidden form field Even then, it persists only if the form is submitted
To get around these problems, PHP uses sessions After briefly describing how sessions work, Ill show
you how you can use session variables to create a simple file-based login system and pass information from one page to another without the need to use hidden form fields
In this chapter, youll learn about the following:
• Understanding what sessions are and how to create them
• Creating a file-based login system
• Checking password strength with a custom-built class
• Setting a time limit for sessions
• Using sessions to keep track of information over multiple pages
What sessions are and how they work
A session ensures continuity by storing a random identifier—the session ID—on the web server and on the visitors computer (as a cookie) The web server uses the cookie to recognize that its communicating with the same person (or, to be more precise, with the same computer) Figures 9-1 through 9-3 show the details of a simple session created in my local testing environment
Trang 4CHAPTER 9
244
As Figure 9-1 shows, the cookie stored in the browser is called PHPSESSID, and the content is a jumble of letters and numbers This random string is the sessions ID
Figure 9-1 PHP sessions store a unique identifier as a cookie in the browser
A matching file, which contains the same jumble of letters and numbers as part of its filename, is created
on the web server, as shown in Figure 9-2
Figure 9-2 The content of the cookie identifies the session data stored on the web server
When a session is initiated, the server stores information in session variables that can be accessed by other pages as long as the session remains active (normally until the browser is closed) Because the session ID is unique to each visitor, the information stored in session variables cannot be seen by anyone else This means sessions are ideal for user authentication, although they can be used for any situation
Trang 5245
where you want to preserve information for the same user when passing from one page to the next, such
as with a multipage form or a shopping cart
The only information stored on the users computer is the cookie that contains the session ID, which is meaningless by itself This means there is no danger of private information being exposed through someone examining the contents of a cookie on a shared computer
The session variables and their values are stored on the web server Figure 9-3 shows the contents of a simple session file As you can see, its in plain text, and the content isnt difficult to decipher The session shown in the figure has one variable: name The variables name is followed by a vertical pipe, then the letter “s”, a colon, a number, another colon, and the variables value in quotes The “s” stands for string, and the number indicates how many characters the string contains So, this session variable contains my name as a string, which is five characters long
Figure 9-3 The details of the session are stored on the server in plain text
This setup has several implications The cookie containing the session ID normally remains active until the browser is closed So, if several people share the same computer, they all have access to each others sessions unless they always close the browser before handing over to the next person, something over which you have no control So, its important to provide a logout mechanism to delete both the cookie and the session variables, keeping your site secure You can also create a timeout mechanism, which automatically prevents anyone from regaining access after a certain period of inactivity
Storing session variables in plain text on the web server is not, in itself, a cause for concern As long as the server is correctly configured, the session files cannot be accessed through a browser Inactive files are also routinely deleted by PHP (in theory, the lifetime is 1,440 seconds—24 minutes—but this cannot
be relied upon) Nevertheless, it should be obvious that, if an attacker manages to compromise the server
or hijack a session, the information could be exposed So, although sessions are generally secure enough for password protecting parts of a website or working with multipage forms, you should never use session variables to store sensitive information, such as passwords or credit card details As youll see in “Using sessions to restrict access” later in this chapter, although a password is used to gain access to a protected site, the password itself is stored (preferably encrypted) in a separate location, and not as a session variable
Sessions are supported by default, so you dont need any special configuration However, sessions wont work if cookies are disabled in the users browser It is possible to configure PHP to send the session ID through a query string, but this is considered a security risk
Creating PHP sessions
Just put the following command in every PHP page that you want to use in a session:
session_start();
This command should be called only once in each page, and it must be called before the PHP script generates any output, so the ideal position is immediately after the opening PHP tag If any output is generated before the call to session_start(), the command fails and the session wont be activated for that page (See “The Headers already sent error” section later for an explanation.)
Trang 6CHAPTER 9
246
Creating and destroying session variables
You create a session variable by adding it to the $_SESSION superglobal array in the same way you would assign an ordinary variable Say you want to store a visitors name and display a greeting If the name is submitted in a login form as $_POST['name'], you assign it like this:
$_SESSION['name'] = $_POST['name'];
$_SESSION['name'] can now be used in any page that begins with session_start() Because session variables are stored on the server, you should get rid of them as soon as they are no longer required by your script or application Unset a session variable like this:
unset($_SESSION['name']);
To unset all session variables—for instance, when youre logging someone out—set the $_SESSION
superglobal array to an empty array, like this:
$_SESSION = array();
Do not be tempted to try unset($_SESSION) It works all right—but its a little too effective It not only clears the current session but also prevents any further session variables from being stored
Destroying a session
By itself, unsetting all the session variables effectively prevents any of the information from being reused, but you should also invalidate the session cookie like this:
if (isset($_COOKIE[session_name()])) {
setcookie(session_name(), '', time()-86400, '/');
}
This uses the function session_name() to get the name of the session dynamically and resets the session cookie to an empty string and to expire 24 hours ago (86400 is the number of seconds in a day) The final argument ('/') applies the cookie to the whole domain
Finally, destroy the session with the following command:
session_destroy();
By destroying a session like this, there is no risk of an unauthorized person gaining access either to a restricted part of the site or to any information exchanged during the session However, a visitor may forget to log out, so its not always possible to guarantee that the session_destroy() command will be triggered, which is why its so important not to store sensitive information in a session variable
You may find session_register() and session_unregister() in old scripts These functions are deprecated Use $_SESSION['variable_name'] and unset($_SESSION['variable_name']) instead
Trang 7247
Regenerating the session ID
When a user changes status, such as after logging in, its recommended as a security measure to regenerate the session ID This changes the random string of letters and numbers that identify the
session, but preserves all the information stored in session variables In PHP Pro Security (Apress,
2005, ISBN 978-1-59059-508-4), Chris Snyder and Michael Southwell explain that “the goal of generating a fresh session ID is to remove the possibility, however slight, that an attacker with knowledge of the low-level security session might be able to perform high-security tasks.”
To regenerate the session ID, simply call session_regenerate_id() and redirect the user to another page or reload the same one
The “Headers already sent” error
Although using PHP sessions is very easy, theres one problem that causes beginners a great deal of head banging Instead of everything working the way you expect, you see the following message:
Warning: Cannot add header information - headers already sent
Ive mentioned this problem several times before in conjunction with the header() function It affects session_start() and setcookie() as well In the case of session_start(), the solution is simple: make sure that you put it immediately after the opening PHP tag (or very soon thereafter), and check that theres no whitespace before the opening tag
Sometimes, the problem occurs even if there is no whitespace ahead of the PHP tag This is usually caused by editing software inserting the byte order mark (BOM) at the beginning of the script If this happens, open your script editors preferences and disable the use of the BOM in PHP pages
When using setcookie() to destroy the session cookie, though, its quite likely that you may need to send output to the browser before calling the function In this case, PHP lets you save the output in a buffer using ob_start() You then flush the buffer with ob_end_flush() after setcookie() has done its job Youll see how to do this in PHP Solution 9-2
Using sessions to restrict access
The first words that probably come to mind when thinking about restricting access to a website are
“username” and “password.” Although these generally unlock entry to a site, neither is essential to a session You can store any value as a session variable and use it to determine whether to grant access to
a page For instance, you could create a variable called $_SESSION['status'] and give visitors access
to different parts of the site depending on its value, or no access at all if it hasnt been set
A little demonstration should make everything clear and show you how sessions work in practice
PHP Solution 9-1: A simple session example
This should take only a few minutes to build, but you can also find the complete code in session_01.php, session_02.php, and session_03.php, in the ch09 folder
1 Create a page called session_01.php in a new folder called sessions in the phpsols site
root Insert a form with a text field called name and a submit button Set the method to post and action to session_02.php The form should look like this:
Trang 8CHAPTER 9
248
<form id="form1" method="post" action="session_02.php">
<p>
<label for="name">Name:</label>
<input type="text" name="name" id="name">
</p>
<p>
<input type="submit" name="Submit" value="Submit">
</p>
</form>
2 In another page called session_02.php, insert this above the DOCTYPE declaration:
<?php
// initiate session
session_start();
// check that form has been submitted and that name is not empty
if ($_POST && !empty($_POST['name'])) {
// set session variable
$_SESSION['name'] = $_POST['name'];
}
?>
The inline comments explain whats going on The session is started, and as long as
$_POST['name'] isnt empty, its value is assigned to $_SESSION['name']
3 Insert the following code between the <body> tags in session_02.php:
<?php
// check session variable is set
if (isset($_SESSION['name'])) {
// if set, greet by name
echo 'Hi, ' $_SESSION['name'] ' <a href="session_03.php">Next</a>'; } else {
// if not set, send back to login
echo 'Who are you? <a href="session_01.php">Login</a>';
}
?>
4 If $_SESSION['name'] has been set, a welcome message is displayed along with a link to
session_03.php Otherwise, the page tells the visitor that it doesnt recognize whos trying to gain access, and provides a link back to the first page
Take care when typing the following line:
echo 'Hi, ' $_SESSION['name'] ' <a href="session03.php">Next</a>';
The first two periods (surrounding $_SESSION['name']) are the PHP concatenation operator The third period (immediately after a single quote) is an ordinary period that will be displayed as part of the string
Trang 9249
5 Create session_03.php Type the following above the DOCTYPE to initiate the session:
<?php session_start(); ?>
6 Insert the following code between the <body> tags of session_03.php:
<?php
// check whether session variable is set
if (isset($_SESSION['name'])) {
// if set, greet by name
echo 'Hi, ' $_SESSION['name'] ' See, I remembered your name!<br>'; // unset session variable
unset($_SESSION['name']);
// invalidate the session cookie
if (isset($_COOKIE[session_name()])) {
setcookie(session_name(), '', time()-86400, '/');
}
// end session
session_destroy();
echo '<a href="session_02.php">Page 2</a>';
} else {
// display if not recognized
echo "Sorry, I don't know you.<br>";
echo '<a href="session_01.php">Login</a>';
}
?>
If $_SESSION['name'] has been set, the page displays it, then unsets it and invalidates the current session cookie By placing session_destroy() at the end of the first code block, the session and its associated variables cease to be available
7 Load session_01.php into a browser, type your name in the text field, and click Submit
You should see something like the following screenshot At this stage, there is no apparent difference between what happens here and in an ordinary form
8 When you click Nex t, the power of sessions begins to show The page remembers your name,
even though the $_POST array is no longer available to it Theres a problem, though, with that
headers already sent error message Youll fix that later
Trang 10CHAPTER 9
250
9 Click the link to Page 2 (just below the error message) The session has been destroyed, so
this time session_02.php has no idea who you are
10 Type the address of session_03.php in the browser address bar and load it It, too, has no
recollection of the session and displays an appropriate message
You need to get rid of the warning message in step 8, not only because it looks bad but also because it means setcookie() cant invalidate the session cookie Even though session_start() comes immediately after the opening PHP tag in session_03.php, the warning message is triggered by the DOCTYPE declaration, the <head>, and other HTML being output before setcookie()
PHP Solution 9-2: Buffering the output with ob_start()
Although you could put setcookie() in the PHP block above the DOCTYPE declaration, you would also need to assign the value of $_SESSION['name'] to an ordinary variable, because it ceases to exist after the session is destroyed Rather than pull the whole script apart, the answer is to buffer the output with ob_start()
Continue working with session_03.php from the previous section
1 Amend the PHP block above the DOCTYPE declaration like this: