You are on page 1of 16

WEB APPLICATION CODING STANDARDS

Shaun Moss
September 2007
(updated March 2008)

CONTENTS

1. Introduction

2. Comments and Documentation

3. Database Design

4. PHP Code

5. Presentation Code

6. Data Access Classes

7. Design Patterns
1. INTRODUCTION

These coding standards have been defined in order to ensure consistent coding patterns
across the entire software suite, including the database and all server- and client-side
code. They are probably applicable to any “XCJPM” (XHTML, CSS, JavaScript, PHP,
MySQL) application.

Following these standards will result in well-organised code that is easier to read,
understand and maintain. Furthermore, adhering to the software design patterns
described in this document will reduce errors and improve efficiency.
2. COMMENTS AND DOCUMENTATION

2.1 COMMENTS

All code must be clearly commented. The goal must be to provide enough information
about each section of code such that a future maintenance programmer, who may
possibly be a junior programmer, will be able to understand its function.

Standard phpdoc syntax is to be used for documenting functions, classes and methods.
The following tags are most important:

@package (for files and classes)


@author (for files and functions)
@param (for functions)
@return (for functions)
@see (wherever relevant)

2.3 DOCUMENTATION

Documentation for a significant software effort should include:

1. Specifications and requirements

2. Database and software design

3. Implementation strategy

4. Testing strategy

5. Security considerations and strategies


3. DATABASE DESIGN

These standards have been designed for MySQL, although they could equally be applied
to other database systems.

3.1 TABLE NAMES

• Always singular rather than plural, i.e. “car” not “cars”. This saves typing, makes
compound database table names simpler (e.g. 'person_address' rather than
'persons_addresses'), and simplifies refactoring.

• Lower-case, i.e. “car”, not “Car” or “CAR”. There are issues with upper-case
letters in MySQL table names on Linux systems, and this is the simplest solution.

• Use underscores to separate words, e.g. “shopping_cart”

• Use underscores to separate table names of linking tables that implement many-
to-many relationships, e.g. if there is are tables called “person” and “address”
that have a many-to-many relationship, then the linking table would be called
“person_address”.

3.2 COLUMN NAMES

3.2.1 GENERAL

• Lower-case, i.e. “name”, not “Name” or “NAME”. This is for harmony with table
names.

• Use underscores to separate words, e.g. “product_category”

3.2.2 PRIMARY KEYS

Primary keys should simply be the table name plus “_id”, e.g. if the table is called
“person”, the primary key should be called “person_id”.

Every table should have a primary key as the first column, which should be an unsigned
int autonumber. Primary keys should only be formed from this one column (i.e. never
from 2 or more columns).

3.2.3 FOREIGN KEYS

Foreign keys should be named the same as their matching primary keys. E.g. if there is
a table called “person” which links to the address table, the foreign key should be called
“address_id” – exactly the same as the primary key in the address table.

The only case when this does not apply is when there is more than one foreign key
linking to the same table. E.g. if there are 2 addresses stored for a person, then the
foreign keys may be named “address_1_id” and “address_2_id”, or “address_home_id”
and “address_work_id”.
3.2.4 PREFIXES

Use prefixes (not suffixes) to identify similar columns. Examples:

• “ph_” for phone numbers, e.g. “ph_home”, “ph_work”, “ph_mobile”

• “is_”, “to_”, “was_”, etc. for Booleans, e.g. “is_complete” rather than “complete”

• “d_” for dates, e.g. “d_birth”, “d_due”

• “t_” for times, e.g. “t_open”, “t_close”

• “dt_” for datetimes, e.g. “dt_create”, “dt_message”

• “url_” for URLs (should be varchar(255))

There should never be columns or tables named after any MySQL keyword such as
“date”, “time”, “text”, “column”, “order”, “group”, etc.

3.2.5 UNITS

Units of measurement should be shown as suffixes in column names. Examples:

• “mass_kg”, not “mass” or “kg”

• “price_aud”, not “price” (use “aud” for Australian Dollars, not “dollars”)

• “length_m”, “duration_h”, “area_ha”, etc.

3.3 OBJECT-ORIENTED DESIGN

3.3.1 INHERITANCE

Database design should follow principles of object-oriented design, including inheritance.

For example, if there are two types of person in the database such as employee and
customer, then rather than building two tables with a lot of similar information (e.g.
contact info), three tables are used that implement inheritance from a common base
class of person.

person

person_id
name
ph_home
email_address
address_id
....

employee customer

employee_id customer_id
person_id person_id
d_start category
salary_aud_yr ...
...
Note the use of the foreign key “person_id” in the derived classes, which provides a
reference to the base class person record.

“Employee” and “Customer” classes within the application should hide this
implementation. E.g. Employee::select() should return all the information from the
employee record as well as the associated person record.

3.3.2 COMPOSITION

Similarly, when a class can be created for re-use within other classes, this should be
reflected in the database.

A common example is the address table. Rather than including the same columns (e.g.
address_line_1, city, postcode, state, etc.) in multiple tables (e.g. person, company)
create a separate address table instead, and link to this table.
4. PHP CODE

The following guidelines should be used for all PHP code:

4.1 CURLY BRACES

The open curly brace should always be on its own line, and directly above the closing
brace. They should be used to enclose any block of code with more than one line, even if
not strictly required.

Hence, the following are acceptable:

for ($i = 0; $i < 10; $i++)


{
statement1();
}

for ($i = 0; $i < 10; $i++)


{
statement1();
statement2();
}

for ($i = 0; $i < 10; $i++)


{
for ($j = 0; $j < 10; $j++)
{
statement1();
}
}

But not:

for ($i = 0; $i < 10; $i++) statement1();

for ($i = 0; $i < 10; $i++)


statement1();

for ($i = 0; $i < 10; $i++) {


statement1();
statement2();
}

for ($i = 0; $i < 10; $i++)


for ($j = 0; $j < 10; $j++);
statement1();

4.2 INDENTING

As shown above, all statements in a statement block (between curly braces) should be
indented by one tab.
Use tabs for indenting rather than spaces, as this saves time, and allows easy indenting
and unindenting of blocks of code.

Do not indent after the opening PHP tag (“<?php”), just begin the code directly under this
tag, e.g.

<?php
$x = $_GET[‘x’];
?>

4.3 PHP TAGS

Always use standard open tags (“<?php”) as short open tags have been deprecated.

The opening and closing PHP tags should be on their own lines. e.g.

<?php
include “include/init.php”;
?>

rather than:

<?php include “include/init.php”; ?>

The exception is for single values embedded inline in HTML (equivalent to the <?= short
tag).

Example:

<input id=”first_name” value=”<?php echo $first_name; ?>”>

4.4 SPACES

• No space after a function or method name, i.e. func(x) but not func (x).

• A space after any control keyword (if, else, elseif, for, foreach, while, or switch),
e.g.
if ($a == $b)
{
// do stuff
}
elseif ($a == $c)
{
// do something else
}
This distinguishes flow control keywords from function calls.

• No spaces between function parameters and brackets, but a space after any
comma in a parameter list, e.g. func($x, $y, $z) but not func( $x, $y, $z )

• Spaces after semi-colons in a for statement, e.g. for ($i = 0; $i < 10; $i++)

• Spaces around all operators except ., -> and any unary operators,
e.g. $y = $car->n_wheels; $y++; $str = $p.$q;
$z = !$a; $x = -$y; $z = $x + $a - $b;
• No spaces around array square brackets, e.g. $a[1], not $a [1] or $a[ 1 ].

4.5 STRINGS

In general:

• Use single-quoted strings for array keys (never use unquoted strings for array
keys, this notation is deprecated)
e.g. $person[‘name’] but never $person[name]

• Use double-quoted strings for XHTML, JavaScript or SQL code. This makes it
possible to easily embed PHP variables if necessary. e.g.
echo “<input value=’$title’>”;
$sql = “SELECT * FROM car WHERE n_wheels={$car->n_wheels}”;

• Use single-quoted strings for XHTML attributes, e.g.


<input name='first_name' id='first_name' />
This saves time if you decide to put the XHTML code into a double-quoted PHP
string.

• For the same reason, use single-quoted strings as much as possible in JavaScript,
e.g.
var tbFirstName = document.getElementById('first_name');

In all other cases, use single-quoted strings unless the features of double-quoted strings
are required.

Generally, embed variables in a double-quoted string in preference to using the


concatenation operator.
e.g. $str = “Hello $name” rather than $str = “Hello “.$name;
This aids readability and saves typing.

In the case of array variables, use this syntax:


$str = “Hello {$name[1]}” or $str = “Hello {$person[‘name’]}”

4.6 NAMING CONVENTIONS

• Classes are named using ProperCase.

• Functions (including class methods) are named in camelCase.

• Private or protected methods within classes are named in _camelCase (with an


underscore prefix).

• Even though PHP variables are case-sensitive, do not create different variables
with the same name but different cases, e.g. if a variable $dog is in scope, do not
create a variable $Dog or $DOG.

• Class properties, PHP variables, JavaScript variables, or HTML name or id


attributes that map to database fields must always be named the exact same as
the database field (which should always be lower_case). e.g. if the database
column is “first_name”:
XHTML: <input name='first_name' id='first_name' />
JavaScript: var first_name =
document.getElementById('first_name').value;
CSS: #first_name {color: Red;}
PHP: $first_name = strip_tags($_POST['first_name']);

• Other class properties, PHP variables, JavaScript variables, or HTML name or id


attributes can be named with either camelCase or lower_case as desired – but be
consistent.

• Constants are named using UPPER_CASE.

• Array names or other collections should be plurals, i.e. $addresses, $customers.

• If you need to distinguish between an array representation of an object, and an


actual object, use Hungarian notation with an 'a' prefix., e.g. If the object is
named $cust, then the array would be named $aCust:
$aCust = $rs->fetch_assoc();
$cust = new Customer($aCust);

Note that most naming conventions for PHP are also applicable to JavaScript.

4.7 GENERAL

• Use “elseif” instead of “else if”.

• Use brackets for maximum clarity instead of relying on operator precedence, e.g.
$x = $a + ($b * $c);
not:
$x = $a + $b * $c;

• For constants that you often need to embed in strings, use variables instead, e.g.
$dir = “$baseDir/www/index.php”;
is more readable than
$dir = BASE_DIR.”/www/index.php”;
(The trade-off is that you need to include the variable using global to use it in
functions)

• Even though php function names are case-insensitve, pretend that they aren’t,
i.e. always call the function using the same name as it is declared with.

4.8 PHP.INI SETTINGS

Use the following php.ini settings in your development environment:

short_open_tag = Off
magic_quotes_gpc = Off
register_globals = Off
5. PRESENTATION CODE

5.1 XHTML INPUT FIELDS AND VARIABLE NAMES

1. XHTML name and id attributes and PHP and JavaScript variables that correspond
directly to database columns should always be named exactly the same as the database
column (i.e. in lower_case). This approach greatly reduces confusion and programmer
error, and allows some nice coding tricks such as creating objects from $_POST arrays or
database records, etc.

For example, in the form there may be a field as follows:

<input id='email_address' name='email_address' />

The PHP variable in the receiving script would therefore be $email_address, the
JavaScript variable for the textbox value would be email_address, and the column name
in the database table would be “email_address”.

2. Always make the id and name attributes of an HTML element the same (except in the
case of radio buttons – see below). The id attribute is needed by JavaScript, the name
attribute by PHP.

5.2 JAVASCRIPT VARIABLE NAMES

If the form control is accessed from JavaScript, the JavaScript variable representing the
actual textbox object should be given a name using Hungarian notation (a form of
camelCase) to differentiate it from the value of the form control.

e.g.

function GetEmailAddress()
{
var tbEmailAddress =
document.getElementById('email_address');
var email_address = tbEmailAddress.value;
}

Valid prefixes are as follows:

• “tb” for a textbox or hidden field

• “cb” for checkbox

• “rb” for radio button

• “ta” for textarea (not 'txt', as this can be confused with a textbox)

• “sb” for select box

• “opt” for select option

• “btn” for button


• “div” for a div element

• “img” for an image element

• “form” for a form (not 'frm' as this could be taken to mean 'frame')

• “spn” for a span element

5.3 CSS

CSS styles should always be used in preference to HTML tag attributes for all text and
form element colours, dimensions and styles. Attributes such as color, bgcolor, font,
align, etc. should never be used any more.

CSS is usually preferred for layout, although in some cases (such as displaying query
results), tables can be better.

5.4 RADIO BUTTONS AND CHECKBOXES

5.4.1 LABELS

If a radio button or a checkbox has a label associated with it, then:


a) The label should be on the right-hand side of the control.
b) The label should be surrounded by label tags that link it to the control.

e.g. <input type='checkbox' name='is_person' id='is_person' checked'


/><label for='is_person'> Person</label>

5.4.2 ID AND NAME ATTRIBUTES

The id attribute is needed for any element that is to be accessed from JavaScript, and
the name attribute is needed for any form control whose value is to be provided to PHP.

As a general rule, the id and name attributes of an HTML element should be the same.
However, this changes with radio buttons.

With radio buttons, the name attributes of all radio buttons in the same group must be
the same, so that they behave like a group. However, the id and value attributes must
be different. A useful approach is to use array notation for the id, combining the name
with the value (i.e. id = name[value]). This provides advantages if the radio buttons in
a group need to be processed in JavaScript. Note that the ‘for’ attribute of the label tag
must match the id.

e.g. <input type='radio' name='is_business' id='is_business[0]' value='0'


/><label for='is_business[0]'> Person</label>
<input type='radio' name='is_business' id='is_business[1]' value='1'
/><label for='is_business[1]'> Business</label>

For groups of checkboxes, array notation should also be used, for both the name and id
attributes.
e.g. <input type='checkbox' name='category[26]' id='category[26]' /><label
for='category[26]'> Accountant</label>

This enables a simple mechanism for collecting the checked boxes in the group after the
form is posted:

e.g. $categoryIds = array_keys($_POST['category']);


6. DATA ACCESS CLASSES

“Data access classes” correspond directly to database tables/objects, and should ideally
provide the only method for reading from and writing to the database.

6.1 CLASS NAMES

Classes are named to correspond with the database table they provide an interface for.
For example, a class called Address is used for interaction with the address table.

Class names are ProperCase with no underscores, e.g. Address class for the address
table, ProductType class for the product_type table.

Like database table names, class names should always be singular, except for classes
that implement collections.

6.2 SQL CODE

The only place that SQL code should appear in the application is within a data access
class. This improves security and increases efficiency when debugging. For efficiency in
coding, we generate SQL statements dynamically rather than use stored procedures or
parameterised SQL. However, this means extra care must be taken to protect against
SQL injection attacks. All input must be “cleaned and checked”, i.e. values that should
be integers must be cast to (int), and values that should be strings must be escaped
using
$db->escape_string();.

SQL keywords should always be in UPPER CASE, e.g. SELECT, FROM, WHERE.

There should be no spaces around equals signs or other operators in SQL code.
7. DESIGN PATTERNS

7.1 DATABASE ADMINISTRATION

For a standard table administration pattern, create the following files:

• ObjectList.php (e.g. ProductList.php) – lists all items in the table showing a


short string (usually the name or title field) as a link to ObjectView.php. This
page would usually call the static selectAll() method (or similar) of the class,
e.g.
$products = Product::selectAll();
or possibly a similar method that accepts search parameters.

• ObjectView.php (e.g. ProductView.php) – shows a table with field names


(which map to database columns) in the left-hand column, and values in the right-
hand column. This page receives the primary key as a querystring parameter,
e.g. ProductView.php?product_id=5, then calls the static select() method of
the relevant class, e.g.
$product = Product::select($product_id);

• ObjectEdit.php (e.g. ProductEdit.php) – shows a table with field names


(database columns) in the left-hand column and input controls in the right-hand
column. Most input controls will be textboxes, except that foreign keys will
usually be select boxes or radio button groups, and Boolean values will be
checkboxes. Obtain database object as above.

• ObjectUpdate.php (e.g. ProductUpdate.php) – script which receives input


from ObjectEdit.php and updates the database. Creates a database object and
calls the update() method, which transparently determines whether to execute an
UPDATE or INSERT statement.
e.g. $product_id = $product->update();

• ObjectDelete.php (e.g. ProductDelete.php) – script to delete an object. This


script receives the primary key as a querystring parameter, e.g.
ProductDelete.php?product_id=5, then calls the static delete() method of
the relevant class, e.g.
Product::delete($product_id);

7.2 USER INPUT VALIDATION

For maximum security and performance all user input via forms is to be validated on
both the client and the server.

Validate on the client for usability. Don't force the user to wait for a round-trip to the
server before receiving notifcation that their form isn't filled in properly.

Validate on the server for security. Crackers can easily submit code to your receiving
script without using your form, which means the $_POST array can literally contain
anything. Sanitize every element that you expect to receive from the $_POST array.
7.2.1 VALIDATION FUNCTIONS

This is to be done using a set of matching JavaScript and PHP functions that have a
common naming pattern, whereby each function returns a Boolean and has a name that
begins with either “isValid” or “looksLike”:

• isValidEmailAddress()

• isValidPassword()

• isValidPhoneNumber()

• looksLikeDate()

• etc.

7.2.2 CLIENT-SIDE VALIDATION

This is done using JavaScript. Generally speaking, there is no submit button, but rather a
regular button with an onclick event that calls a checkForm() JavaScript function.

This function checks every field in the form that is either required or must have valid
input. If all user entry is valid then the function submits the form, otherwise an alert box
is displayed informing the user of any issues, and the form does not submit. If an alert
box is not desired then an alternate method is to highlight the form fields in question,
and place a message alongside them.

7.2.3 SERVER-SIDE VALIDATION

The script receiving data from a form must validate every item of data received,
including checking for required fields. This should match the client-side validation
exactly. If invalid input is detected then the user is returned to the form, and a message
is displayed informing the user of any issues.

If data from a form is expected, then only the POST method should be used to submit the
data (i.e. method=”POST” in the form tag) and only the $_POST array inspected for user
input. The $_GET and $_COOKIE arrays should be ignored. Use hidden form fields if
necessary.

Similarly, if the querystring is being used to pass information (e.g. passing an id to a


delete script), then only data from the $_GET array should be used.

You might also like