Chapter 2

Laying the Foundation

IN THIS CHAPTER

check Getting your directory structure set up

check Creating the app database and adding the required tables

check Understanding PHP sessions

check Creating your app’s startup files

check Making your coding life easier by taking a modular approach

Every great developer you know got there by solving problems they were unqualified to solve until they actually did it.

— PATRICK MCKENZIE

A well-built web app begins with a solid foundation. Sure, when you’ve got a great idea for a web app, it’s always tempting to work on the visible front end first, even if it’s just cobbling together a quick proof-of-concept page. However, party pooper that I am, I’m going to gently suggest that it’s a good idea to nail down at least some of the more fundamental work off the top. Not only does that give you some major items to check off your app to-do list, but having a solid foundation under your feet will help you immeasurably when it comes time to code the rest of your app.

This chapter is all about laying down that solid foundation. First I show you how to figure out your app’s directory structure. I then talk about constructing the database and tables. From there, I crank up the text editor and talk about some useful PHP techniques such as defining constants, setting up and securing sessions, and including code from one PHP file in another. Finally, I show you how to code the startup files your app needs for both its back end and its front end. Along the way, you see a practical example of every technique as I build out the foundation code for my own FootPower! app.

Setting Up the Directory Structure

Start by opening the “Employees Only” door and heading into the back room of the web app. Your back-end work begins by setting up some directories and subdirectories to store your app’s files. Doing this now offers two benefits:

  • remember Organization: Even a small app can end up with quite a few files, from PHP scripts to HTML code to external CSS and JavaScript files. If you add your directories on-the-fly as they’re needed, it’s a certainty they’ll end up a bit of a mess, with files scattered hither and thither (as my old grandmother used to say). It’s better to come up with a sensible directory structure now and stick with it throughout the development cycle.

  • Security: A smart back-end developer divides her files between those files that users need to view and operate the web app and those files that only do work behind the scenes. The former should be accessible to the public, but it’s best to configure things so that the latter aren’t accessible to anyone but you.

Okay, I hear you saying, “Organization I can get on board with, but what’s all this about security?” Good question. Here’s the answer:

warning When your app is on the web, it’s stored in a directory that the web server makes publicly available to anyone who comes along. This public accessibility means that it’s at least technically possible for someone to gain direct access to the files stored in that directory. That access isn’t a big thing for your HTML, CSS, and JavaScript files, which anyone can easily view. However, it’s a huge deal for your PHP files, which can contain sensitive information such as your database credentials.

remember To see how you prevent such unauthorized access, you need to understand that every web app has a top-level directory, which is known as either the web root or the document root. The web root is the directory that the server makes accessible to the public, which means that anything outside of the web root is inaccessible to remote users (while still being available to your web app).

So your directory structure begins by creating one directory and two subdirectories:

  • The directory is the overall storage location for your app. You can name this whatever you want, but it’s probably best to use the name of the app.
  • One subdirectory will be the web root. I’m going to name my web root public to reinforce that only files that should be publicly accessible go in this subdirectory.
  • The other subdirectory will contain the PHP files that you don't want remote users to be able to access. I’m going to name this subdirectory private to remind me that this is where I put files that should not have public access.

Setting up the public subdirectory

After you’ve created the public subdirectory, you need to tell the web server that this location is the new web root. If you set up the XAMPP web development environment as I describe in Book 1, Chapter 2, then you change the web root by editing a document named httpd.conf, the location of which depends on your operating system:

  • Windows: Look for httpd.conf in the following folder:

    c:/xampp/apache/conf

  • Mac: Look for httpd.conf here:

    /Applications/XAMPP/xamppfiles/etc

Open httpd.conf in a text editor and then scroll to or search for the line that begins with DocumentRoot. For example, here's the Mac version of the line:

DocumentRoot: "/Applications/XAMPP/xamppfiles/htdocs"

Edit this line to point to your app’s web root subdirectory. For example, if you added your main app folder to htdocs, add a slash (/), the app folder name, and then /public. Here's the web root path that I’m using for my FootPower! app:

DocumentRoot: "/Applications/XAMPP/xamppfiles/htdocs/footpower/public"

By default, the web server denies permission to the entire server filesystem, with one exception: the web root. Therefore, you must now tell the server that it’s okay for remote users to access the new web root. To do that, first look for the line in httpd.conf that begins with <Directory, followed by the path to the old web root. For example, here's the Mac version of the line:

<Directory "/Applications/XAMPP/xamppfiles/htdocs">

Edit this line to point to your app’s web root, as in this example:

<Directory "/Applications/XAMPP/xamppfiles/htdocs/footpower/public">

Save the file and restart the web server to put the new configuration into effect.

tip To make sure your web root is working properly, create a new PHP file in the public directory, give it the name index.php, and then add an echo statement, something like this:

<?php

echo "Hello World from the web root!";

?>

Now surf to localhost and make sure you see the correct output, as shown in Figure 2-1.

image

FIGURE 2-1: The new web root, ready for action.

remember It's unlikely you’ll have access to http.conf when you put your web app online. However, your web host will offer some sort of mechanism for specifying a particular directory as the web root, so check the host’s Help or Support documentation.

Your final chore for setting up the public directory is to add the subdirectories you'll use to store various file types. Here are my suggestions:

Subdirectory

What It Stores

/common

Files that are used in all your web app’s pages, including the top part of each page (the opening tags and the head section) and common page elements such as a header, sidebar, and footer

/css

Your web app's CSS files

/handlers

Files that handle Ajax requests from the front end

/images

Image files used in your web app

/js

Your web app's JavaScript files

To give you a kind of road map to where we’re going, Figure 2-2 shows the final file structure of my FootPower! app’s public directory.

image

FIGURE 2-2: All the public files and directories I use in the final version of my FootPower! app.

Setting up the private subdirectory

Getting the private subdirectory configured is much easier because you only have to create the subdirectories you need to organize your app's back-end files. Here are my suggestions:

Subdirectory

What It Stores

/classes

Files that contain the code for your web app’s classes

/common

Files that are used in other back-end files

/logs

Log files, such as the error log

Figure 2-3 shows the final file structure of my FootPower! app's private directory.

image

FIGURE 2-3: The private files and directories in the final version of my FootPower! app.

Creating the Database and Tables

You already know your web app's data requirements, so now it’s time to load phpMyAdmin on your development server (http://localhost/phpMyAdmin), and then use it to create your MySQL data stores. I go through this in detail in Book 5, Chapter 2, so I only list the general steps here:

  1. Create a database for your web app using the utf8_general_ci collation.
  2. If your app needs to support user accounts, create a table to hold the account data.

    At a minimum, this table will have an ID field, a username field, and a password field.

  3. If your app needs to save user-generated data, create a table to hold the data.

    This table should have an ID field as well as user ID field that, for each user, contains the same ID from the user table you created in Step 2.

  4. If your app is configured so that the user creates one main item and then many subitems, create a table to hold the subitems.

    To be clear, the table you created in Step 3 holds each user's main item, and this new table holds the subitems. This table should have an ID field, a field that points to the ID of the main item, and a field for each tidbit of data you want to store.

An example might make this clearer, so I’ll go through the data structures for my FootPower! app. First, here’s the users table:

Field Name

Type

Other Settings

user_id

INT

PRIMARY KEY, AUTO_INCREMENT

username

VARCHAR(150)

UNIQUE, NOT NULL

password

VARCHAR(255)

NOT NULL

distance_unit

VARCHAR(10)

DEFAULT 'miles'

verification_code

VARCHAR(32)

NOT NULL

verified

TINYINT

DEFAULT 0

creation_date

TIMESTAMP

DEFAULT CURRENT_TIMESTAMP

Each registered user gets an activity log in which to record her activities, so next up is the logs table:

Field Name

Type

Other Settings

log_id

INT

PRIMARY KEY, AUTO_INCREMENT

user_id

INT

NOT NULL

creation_date

TIMESTAMP

DEFAULT CURRENT_TIMESTAMP

Note that both the users and logs tables have a common user_id field. This enables me to link each log to the user who owns it.

For now, go ahead and add one record to this table, where user_id equals 1 and creation_date is today's date (in YYYY-MM-DD format).

Finally, each log records the user’s foot-propelled activities, so I’ll store this data in the activities table:

Field Name

Type

Other Settings

activity_id

INT

PRIMARY KEY, AUTO_INCREMENT

log_id

INT

NOT NULL

type

VARCHAR(25)

NOT NULL

date

DATE

NOT NULL

distance

DECIMAL(10,6)

duration

TIME

Note that both the logs and activities tables have a common log_id field. This will enable me to link each activity to the log in which it belongs.

Getting Some Back-End Code Ready

The back end of a web app consists of both the MySQL data and the PHP code that manipulates that data and returns information to the app's front end. You can get some of the PHP code written now, and you can add the rest as you build the app.

Defining PHP constants

It’s a rare web app that doesn’t have one or more variables that are used throughout the back-end code, but where the value of those variables must never change. For example, when you’re managing server data, your PHP files are constantly logging into the MySQL database, which requires credentials such as a username and password. That username and password are the same throughout your code, but your code will fail if, somehow, these values get changed.

remember A variable that never changes value sounds almost like an oxymoron, so perhaps that’s why programmers of yore came up with the idea of the constant, a special kind of variable that, once defined with a value, can’t be changed. You set up a constant in PHP by using the define() function:

define(name, value)

  • name: The name of the constant. By convention, constant names are all uppercase and don't begin with a dollar sign ($).
  • value: The value of the constant. The value must be an integer, floating point number, string, or Boolean.

Here's an example:

define("GREETING", "Hello Constant World!")

It’s good web app practice to gather all your constants and put them in a separate file, which you can then include in any other PHP file that requires one or more of the constants. (I talk about how you include a PHP file in another PHP file later in this chapter.) For example, here’s a PHP file that defines the database credentials for my FootPower! app:

<?php

define('HOST', 'localhost');

define('USER', 'root');

define('PASSWORD', '');

define('DATABASE', 'footpower');

?>

I’ve named this file constants.php and added it to the app’s private/common/ directory.

Understanding PHP sessions

One of the biggest web app challenges is keeping track of certain bits of information as the user moves from page to page within the app. For example, when someone first surfs to the app's home page, your PHP code might store the current date and time in a variable, with the goal of, say, tracking how long that person spends using the app. A worthy goal, to be sure, but when the user moves on to another page in the app, your saved date and time gets destroyed.

Similarly, suppose the user’s first name is stored in the database and you use the first name to personalize each page. Does that mean every time the user accesses a different page in your app, your code must query the database just to get the name?

remember The first scenario is ineffective and the second is inefficient, so is there a better way? You bet there is: PHP sessions. In the PHP world, a session is the period that a user spends interacting with a web app, no matter how many different app pages she navigates.

You start a session by invoking the session_start() function:

session_start();

Once you’ve done that, the session remains active until the user closes the browser window. Your web server also specifies a maximum lifetime for a session, usually 1,440 seconds (24 minutes). You can check this by running echo phpinfo() and looking for the session.gc_maxlifetime value. You can work around this timeout in one of two ways:

  • By adding the session_start() function to each page, which refreshes the session.
  • By running PHP's session_status() function, which returns the constant PHP_SESSION_NONE if the user doesn't have a current session.

How does a session help you keep track of information about a user? By offering an array called $_SESSION, which you can populate with whatever values you want to track:

$_SESSION['start_time'] = time();

$_SESSION['user_first_name'] = 'Biff';

$_SESSION['logged_in'] = 1;

Securing a PHP session

A PHP session is a vital link between your users and your app because it enables you to store data that make each user’s experience easier, more efficient, and more seamless. However, because sessions are such a powerful tool, the world’s dark-side hackers have come up with a number of ingenious ways to hijack user sessions and thereby gain access to session data.

A full tutorial on protecting your users from would-be session-stealers would require an entire book, but there’s a relatively simple technique you can use to thwart all but the most tenacious villains. The technique involves a value called a token, which is a random collection of numbers and letters, usually 32 characters long. How does a token serve to keep a session secure? It’s a three-step process:

  1. When the session begins, generate a new token and store it in the $_SESSION array.
  2. In each form used by your web app, include a hidden input field (that is, an <input> tag where the type attribute is set to hidden) and set the value of that field to the session's token value.
  3. In your PHP script that processes the form data, compare the value of the form’s hidden field with the token value stored in the $_SESSION array. If they’re identical, it means the form submission is secure (that is, the form was submitted by the session user) and you can safely proceed; if they’re different, however, it almost certainly means that an attacker was trying to pull a fast one and your code should stop processing the form data.

remember There are a bunch of ways to create some random data in PHP, but a good one for our purposes is openssl_random_pseudo_bytes():

openssl_random_pseudo_bytes(length)

  • length: An integer that specifies the number of random bytes you want returned

The openssl_random_pseudo_bytes() function returns a string of random bytes, but byte values aren't much good to us. We need to convert the binary string to a hexadecimal string, and that’s the job of PHP’s bin2hex() function:

bin2hex(str)

  • str: The binary string you want to convert

For example, 16 bytes will convert to 32 hex characters, so you can use something like the following expression to generate a token:

bin2hex(openssl_random_pseudo_bytes(16));

This creates a value similar to the following:

387f90ce4b3d8f9bd7e4b38068c9fce3

For your session, you'd store the result in the $_SESSION array, like so:

$_SESSION['token'] = bin2hex(openssl_random_pseudo_bytes(16));

It’s also good practice to generate a fresh token after a certain period of time has elapsed, say 15 minutes. To handle this, when the session starts you use the $_SESSION array to store the current time plus the expiration time:

$_SESSION['token_expires'] = time() + 900;

PHP's time() function returns the number of seconds since January 1, 1970, so adding 900 sets the expiration time to 15 minutes in the future. Your web app would then use each session refresh to check whether the token has expired:

if (time() > $_SESSION['token_expires']){

$_SESSION['token'] = bin2hex(openssl_random_pseudo_bytes(16));

$_SESSION['token_expires'] = time() + 900;

}

Including code from another PHP file

Most web apps are multi-page affairs, which means your app consists of multiple PHP files, each of which performs a specific task, such as creating data, retrieving data, or logging in a user. Depending on the structure of your app, each of these PHP files will include some or all of the following:

  • Constants used throughout the project
  • Database login credentials
  • Database connection code
  • Classes, functions, and other code used on each page
  • Common interface elements such as the header, app navigation, sidebar, and footer

You don't want to copy and paste all this code into each PHP file because if the code changes, then you have to update every instance of the code. Instead, place each chunk of common code in its own PHP file and save those files in a subdirectory. Earlier in this chapter, I explain that you should create two common subdirectories for such files, one in the public directory and one in the private directory. To get a common file's code into another PHP file, use PHP’s include_once statement:

include_once file;

  • file: The path and name of the file with the code you want to include

For example, here's a PHP file that defines some constants that hold the database credentials for my FootPower! app:

<?php

define('HOST', 'localhost');

define('USER', 'root');

define('PASSWORD', '');

define('DATABASE', 'footpower');

?>

I’ve stored this code in a file named constants.php in the private/common/ subdirectory, so I'd use the following statement to include it from the web root folder:

include_once '../private/common/constants.php';

The double dots (..) stand for “go up one directory,” so here they take the script up to the app’s filesystem root, and from there the statement adds the path to constants.php.

Creating the App Startup Files

All web apps perform a number of chores at the beginning of any task. On the back end, these initialization chores include starting a user session and connecting to the database, and on the front end the startup includes outputting the app's common HTML (especially the <head> section) and including the app’s common components, such as a header and footer.

Rather than repeating the code for these startup chores in every file, you should create two files — one for the back end initialization and one for the front end’s common code — and then include the files as you begin each web app task. The next two sections provide the details.

Creating the back-end initialization file

When performing any task, a typical web app must first run through a number of back-end chores, including the following:

  • Setting the error reporting level
  • Starting a session for the current user, if one hasn’t been started already
  • Creating a token for the session
  • Including common files, such as a file of constants used throughout the app
  • Connecting to the database, if the app uses server data

You should store this file in your web app’s private/common/ directory. For FootPower!, I created an initialization file named /private/common/initialization.php:

<?php

// Make sure we see all the errors and warnings

error_reporting(E_ALL | E_STRICT);

// Start a session

session_start();

// Have we not created a token for this session,

// or has the token expired?

if (!isset($_SESSION['token']) || time() > $_SESSION['token_expires']){

$_SESSION['token'] = bin2hex(openssl_random_pseudo_bytes(16));

$_SESSION['token_expires'] = time() + 900;

$_SESSION['log_id'] = 1;

}

// Include the app constants

include_once 'constants.php';

// Connect to the database

$mysqli = new MySQLi(HOST, USER, PASSWORD, DATABASE);

// Check for an error

if($mysqli->connect_error) {

echo 'Connection Failed!

Error #' . $mysqli->connect_errno

. ': ' . $mysqli->connect_error;

exit(0);

}

?>

This code cranks up the error reporting to 11 for the purposes of debugging, starts a new session, creates a session token (if needed), includes the constants file (which contains the database credentials), and then connects to the database and creates a MySQLi object. Note, too, that I set $_SESSION['log_id'] to 1, but this is temporary. In Book 7, Chapter 4, you see that this value gets set to the user's log ID value when the user signs in to the app.

warning You want to use error_reporting(E_ALL | E_STRICT) when you’re developing your web app because you want the PHP processor to let you know when something’s amiss, either as an error (E_ALL) or as non-standard PHP code (E_STRICT). However, you certainly don't want your app’s users to see these errors or warnings, so when you’re ready for your web app to go live, edit initialization.php to follow this statement:

error_reporting(E_ALL | E_STRICT)

with these statements:

ini_set('display_errors', 0);

ini_set('log_errors', 1);

ini_set('error_log', '../private/logs/error_log');

These statements configure PHP to not display errors onscreen, but to log them to a file, the name and path of which is specified in the final statement.

Creating the front-end common files

Each page of your web app has a common structure. For example, the top part of each page includes the following elements:

  • The DOCTYPE and the <html> tag
  • The head element, including the <meta> tags, page title, CSS <link> tags, and JavaScript <script> tags
  • An event handler for jQuery's ready event
  • The <body> tag
  • Common page elements, such as the <header>, <nav>, and <main> tags

Here's an example, which I’m going to name public/common/top.php:

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="utf-8">

<meta name="viewport" content="width=device-width, initial-scale=1.0">

<title>FootPower! | <?php echo $page_title ?></title>

<link href="css/styles.css" rel="stylesheet">

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>

<script>

$(document).ready(function() {

});

</script>

</head>

<body>

<header role="banner">

</header>

<main role="main">

<article role="contentinfo">

<header class="article-header" role="banner">

<div class="header-title">

<h1><?php echo $page_title ?></h1>

</div>

</header>

In this code, note that the page title is given by the following inline PHP:

<?php echo $page_title ?>

tip The idea here is that each page will set the $page_title variable just before including top.php, which enables you to define a custom title for each page. For example, the home page might do this:

<?php

$page_title = 'Home';

include_once 'common/top.php';

?>

Note that this same title also gets inserted in the page header element, within the <h1> tag.

Most web apps also include a sidebar — defined by an <aside> tag — that includes info common to all pages, such as a description of the app, instructions for using the app, the latest app news, or a newsletter sign-up form. For this sidebar, create a separate file called, say, publiccommonsidebar.php and include your code:

<aside role="complementary">

Your sidebar text and tags go here

</aside>

Finally, you need a file to handle the common elements that appear at the bottom of each page, including the </main> closing tag, a footer, and the </body> and </html> closing tags. For this code, create a separate file called, say, publiccommonottom.php and add your code:

</main>

<footer role="contentinfo">

Copyright <?php echo date('Y'); ?> Your Name

</footer>

<script src="js/data.js"></script>

<script src="js/user.js"></script>

</body>

</html>

tip The footer uses the PHP statement echo date('Y') to output the current year for the Copyright notice. This file also adds references to the app's two external JavaScript files: data.js and user.js. Adding these at the bottom of the page (instead of the usual place in the page's head section) ensures that your JavaScript code can work with the elements added to the page on the fly.

Building the app home page

With the initialization files in place, it’s time to build the skeleton for the app’s home page. At the moment, this page is nothing but PHP:

<?php

include_once '../private/common/initialization.php';

$page_title = 'Home';

include_once 'common/top.php';

?>

Main app content goes here

<?php

include_once 'common/sidebar.php';

include_once 'common/bottom.php';

?>

Save this file as index.php in the web root directory.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.222.138.230