Smarty.class.php Smarty_Compiler.class.php That gets Smarty installed, but you also need to create four subdirectories for every application that uses it. So create the new application directory temp just under the same document root where you just installed Smarty. This will hold the files for a temporary application that we’ll write to test Smarty. Inside the temp directory, create another one called smarty to house the folders con- taining the template files. Finally, create the following subdirectories within the new smarty directory: cache, config, templates, and templates_c. Your directory structure is now: temp smarty cache config templates templates_c Creating Scripts You are now ready to create some Smarty scripts. Type in the code in Example 12-1 and save it as smarty.php. Example 12-1. The smarty.php program <?php // smarty.php $path = $_SERVER['DOCUMENT_ROOT']; require "$path/Smarty/Smarty.class.php"; $smarty = new Smarty(); $smarty->template_dir = "$path/temp/smarty/templates"; $smarty->compile_dir = "$path/temp/smarty/templates_c"; $smarty->cache_dir = "$path/temp/smarty/cache"; $smarty->config_dir = "$path/temp/smarty/configs"; $smarty->assign('title', 'Test Web Page'); $smarty->display("$path/temp/index.tpl"); ?> This program tells Smarty where it can find the Smarty.class.php file, and where your Smarty templates are located. Because we will be using both .php and .tpl template files in this chapter, I have included everything you need in each file. Example 12-1 looks up the document root and sets the variable $path to that value. It then uses $path as a prefix for fetching the Smarty class files and the template files from the temp folder. This saves you the maintenance hassle of hard-wiring full path names into the code. Creating Scripts | 271 Note the penultimate $smarty->assign command. This creates a Smarty variable called title and assigns it the string value “Test Web Page”. You’ll see why shortly. Once you have typed the program in, save it using the filename smarty.php into the temp directory you created earlier. Creating Templates Now you need to write a simple Smarty template file to test whether everything is working, so type in Example 12-2 and save it in a file named index.tpl in the temp/ smarty/templates directory you created earlier. Example 12-2. The index.tpl template file <html> <head> <title>{$title}</title> </head> <body> This is a Smarty Test </body> </html> As you can see, this is simply an HTML file with a .tpl file extension. But note the use of the Smarty variable {$title} on the third line. This is the same variable that was defined in Example 12-1. Smarty will substitute the value of the variable instead of the text in Example 12-2, because of the surrounding curly braces {} (see Figure 12-1). Figure 12-1. The output from index.tpl in Example 12-2 A Practical Example Let’s take the program sqltest.php from Example 10-8 in Chapter 10 and rewrite it to use Smarty. This will be a two-part process: one part for the program code and one for the Smarty presentation layer. Example 12-3 is the revised program. Once you have typed it in, save it into the temp directory that you created earlier using the filename smartytest.php. 272 | Chapter 12: Templating with Smarty Example 12-3. The sqltest.php program rewritten for Smarty as smartytest.php <?php // smartytest.php $path = $_SERVER['DOCUMENT_ROOT']; require "$path/Smarty/Smarty.class.php"; $smarty = new Smarty(); $smarty->template_dir = "$path/temp/smarty/templates"; $smarty->compile_dir = "$path/temp/smarty/templates_c"; $smarty->cache_dir = "$path/temp/smarty/cache"; $smarty->config_dir = "$path/temp/smarty/configs"; require_once("$path/temp/login.php"); $db_server = mysql_connect($db_hostname, $db_username, $db_password); if (!$db_server) die("Unable to connect to MySQL: " . mysql_error()); mysql_select_db($db_database) or die("Unable to select database: " . mysql_error()); if (isset($_POST['author']) && isset($_POST['title']) && isset($_POST['category']) && isset($_POST['year']) && isset($_POST['isbn'])) { $author = get_post('author'); $title = get_post('title'); $category = get_post('category'); $year = get_post('year'); $isbn = get_post('isbn'); if (isset($_POST['delete']) && $isbn != "") { $query = "DELETE FROM classics WHERE isbn='$isbn'"; if (!mysql_query($query)) { echo "DELETE failed: $query<br>" . mysql_error() . "<p>"; } } else { $query = "INSERT INTO classics VALUES" . "('$author', '$title', '$category', '$year', '$isbn')"; if (!mysql_query($query)) { echo "INSERT failed: $query<br>" . mysql_error() . "<p>"; } } } $query = "SELECT * FROM classics"; A Practical Example | 273 $result = mysql_query($query); if (!$result) die ("Database access failed: " . mysql_error()); $rows = mysql_num_rows($result); for ($j = 0 ; $j < $rows ; ++$j) { $results[] = mysql_fetch_array($result); } mysql_close($db_server); $smarty->assign('results', $results); $smarty->display("$path/temp/smartytest.tpl"); function get_post($var) { return mysql_real_escape_string($_POST[$var]); } ?> There are a couple of things that you must have done to ensure this program will work: • You must have worked through the examples in Chapter 8 and have the table classics ready-populated in the publications database (or another database you may have used). • You must have copied the file login.php (created in Chapter 10) to the temp folder you created earlier, or Example 12-3 will be unable to access MySQL. The program starts off by loading in both the Smarty class and login.php files from their correct places. Then it is followed by the program code from the old sqltest.php file, without the HTML output that it used to have. In place of the HTML, we’ll use the presentation layer template that I’ll show next. The main thing remaining to note is the replacement of the mysql_fetch_row function with the new mysql_fetch_array function, just before the call to mysql_close. The rea- son for this is to fetch an entire row as an associative array. The function mysql_fetch_array returns a row from the database with the value in each column as an element of the array, and the column name as the array element name. The $results object is an array of arrays. Each execution of $results[] = mysql_fetch_array($result); adds another array of results to the $results array. This makes it easy to pass a lot of data directly to the Smarty template. How easy? Just a single line is used: $smarty->assign('results', $results); This passes an entire array of arrays using the name results. 274 | Chapter 12: Templating with Smarty The following line in Example 12-3 displays the Smarty template, then program exe- cution ends. So now let’s look at the template, which is in Example 12-4. Type it in and save it as smartytest.tpl in the temp/smarty/templates folder you created earlier. Example 12-4. The smartytest.tpl file <html><head> <title>Smarty Test</title> </head><body> <form action="smartytest.php" method="post"><pre> Author <input type="text" name="author"> Title <input type="text" name="title"> Category <input type="text" name="category"> Year <input type="text" name="year"> ISBN <input type="text" name="isbn"> <input type="submit" value="ADD RECORD"> </pre></form> {section name=row loop=$results} <form action="smartytest.php" method="post"> <input type="hidden" name="delete" value="yes"> <input type="hidden" name="isbn" value="{$results[row].isbn}"> <pre> Author {$results[row].author} Title {$results[row].title} Category {$results[row].category} Year {$results[row].year} ISBN {$results[row].isbn} <input type="submit" value="DELETE RECORD"></form> </pre> {/section} </body></html> In Figure 12-2, you can see the result of using this template file from the smartytest.php program. The first half of the file simply creates the form used to add more records to the MySQL database—the interesting stuff begins at the {section opening tag. A {section} tag is used for looping over arrays of data. Each time through the loop in this example, the Smarty variable row is assigned a value representing the iteration of the loop, starting from 0. In the same {section} tag, the loop keyword indicates the array that must be processed. In this case, it is the $results array we passed to the template from the previous pro- gram. Given these parameters, it is possible to pull any data wanted from the result rows that were returned by MySQL. For each row, any element can be accessed by its column name. For example, to output the current row’s year field, use {$results[row].year}, where row refers to the current iteration of the loop, or the current row being processed, and .year tells Smarty which column to reference. It can do this because we passed an associative array from A Practical Example | 275 smartytest.php (now you see why the program was changed from using mysql_fetch_row to mysql_fetch_array). The loop ends with a closing {/section} tag that will cause the loop to reiterate if there are any more rows to process. Otherwise, the HTML below it is displayed. As you can see, this leaves a tremendous amount of control over layout and design with whomever edits the template. They can place any items of data in any positions and in any order. But at no time do they have any access to your program code, and there is nothing they can do to inject bugs into your program or corrupt the MySQL database. And as for you the programmer? If you’re handing over the task of layout to a web designer, you’ll never have to worry what the output is going to look like. All you need do is give them a very simple Smarty template showing all the data you are passing to it, and the form input your pro- gram will accept from it. It’s up to them to then knock it all together into an award-winning design. Think of the freedom that gives you to write fast and effective code, without the dilemma of how to present its output. Figure 12-2. The result of combining smartytest.php and smartytest.tpl 276 | Chapter 12: Templating with Smarty You have now seen how to refer to both string and numeric variables, as well as arrays, within a Smarty template. If you think templating will be useful in your projects, you can learn what else it can do for you at http://www.smarty.net/crashcourse.php; the full documentation is available at http://www.smarty.net/manual/en/. In the next chapter, we’ll look at a range of practical PHP functions and techniques that you’ll need to create efficient programs. Test Your Knowledge: Questions Question 12-1 Name three benefits of using a templating system such as Smarty. Question 12-2 How does a PHP program pass a variable to a Smarty template? Question 12-3 How does a Smarty template access a variable that has been passed to it? Question 12-4 What Smarty programming tag is used to iterate through an array? Question 12-5 How do you enable Smarty templating in a PHP program? See the section “Chapter 12 Answers” on page 445 in Appendix A for the answers to these questions. Test Your Knowledge: Questions | 277 CHAPTER 13 Cookies, Sessions, and Authentication As your web projects grow larger and more complicated, you will find an increasing need to keep track of your users. Even if you aren’t offering logins and passwords, you will still often find a need to store details about a user’s current session and possibly also recognize them when they return to your site. Several technologies support this kind of interaction, ranging from simple browser cookies to session handling and HTTP authentication. Between them, they offer the opportunity for you to configure your site to your users’ preferences and ensure a smooth and enjoyable transition through it. Using Cookies in PHP A cookie is an item of data that a web server saves to your computer’s hard disk via a web browser. It can contain almost any alphanumeric information (as long as it’s under 4 KB) and can be retrieved from your computer and returned to the server. Common uses include session tracking, maintaining data across multiple visits, holding shopping cart contents, storing login details, and more. Because of their privacy implications, cookies can be read only from the issuing domain. In other words, if a cookie is issued by, for example, oreilly.com, it can be retrieved only by a web server using that domain. This prevents other websites from gaining access to details to which they are not authorized. Due to the way the Internet works, multiple elements on a web page can be embedded from multiple domains, each of which can issue its own cookies. When this happens, they are referred to as third-party cookies. Most commonly, these are created by ad- vertising companies in order to track users across multiple websites. Because of this, most browsers allow users to turn cookies off either for the current server’s domain, third-party servers, or both. Fortunately, most people who disable cookies do so only for third-party websites. 279 Cookies are exchanged during the transfer of headers, before the actual HTML of a web page is sent, and it is impossible to send a cookie once any HTML has been transferred. Therefore careful planning of cookie usage is important. Figure 13-1 illus- trates a typical request and response dialog between a web browser and web server passing cookies. This exchange shows a browser receiving two pages: 1. The browser issues a request to retrieve the main page, index.html, at the website http://www.webserver.com. The first header specifies the file and the second header specifies the server. 2. When the web server at webserver.com receives this pair of headers, it returns some of its own. The second header defines the type of content to be sent (text/html) and the third one sends a cookie of the name name and with the value value. Only then are the contents of the web page transferred. 3. Once the browser has received the cookie, it will then return it with every future request made to the issuing server until the cookie expires or is deleted. So, when the browser requests the new page /news.html, it also returns the cookie name with the value value. 4. Because the cookie has already been set, when the server receives the request to send /news.html, it does not have to resend the cookie, but just returns the reques- ted page. Figure 13-1. A browser/server request/response dialog with cookies 280 | Chapter 13: Cookies, Sessions, and Authentication . Example 1 2-1 and save it as smarty.php. Example 1 2-1 . The smarty.php program <?php // smarty.php $path = $_SERVER['DOCUMENT_ROOT']; require "$path/Smarty/Smarty.class.php"; $smarty. isset($_POST['title']) && isset($_POST['category']) && isset($_POST['year']) && isset($_POST['isbn'])) { $author = get_post('author'); $title. get_post('title'); $category = get_post('category'); $year = get_post('year'); $isbn = get_post('isbn'); if (isset($_POST['delete']) &&