WEB APPLICATION CODING STANDARDS

slicedmitesΑσφάλεια

16 Φεβ 2014 (πριν από 3 χρόνια και 6 μήνες)

77 εμφανίσεις

WEB APPLICATION CODI
NG STANDARDS

Shaun Moss

September 2007

(updated March 2008)


CONTENTS

1.

Introduction

2.

Comments and Documentation

3.

Database Desi
gn

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
im
prove efficiency.




2.
COMMENTS AND DOCUMEN
TATION

2.1 COMMENTS

A
ll 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 programme
r, will be able to
understand its function.

S
tandard
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 function
s)

@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 considerat
ions 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



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



L
ower
-
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 ma
ny
-
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 aut
onumber
.
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 add
ress 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 addresse
s 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_ho
me”, “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 U
RLs (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:




ma
ss_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 inheritanc
e from a common base class of
person
.











person

person_id

name

ph_home

email_address

address_id

....

employee

employee_id

person_id

d_start

salary_aud_yr

...

customer

customer_id

person_id

category

...





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 h
ide 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 r
eflected 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 on
e 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++)


{



stateme
nt1();


}

}

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 op
ening 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 li
nes. 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_na
me; ?>”>

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 stateme
nt, 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]

o
r
$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_nam
e' />

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, u
se 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 ai
ds 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 CONVENTION
S



Classes are named using ProperCase.



Functions (including class methods) are named in came
lCase.



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 sc
ope, 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 settin
gs in your development environment:

short_open_tag = Off

magic_quotes_gpc = Off

register_globals = Off







5. PRESENTATION CODE

5.1 XHTML INPUT FIEL
DS AND VARIABLE NAME
S

1. XHTML
name
and
id

attributes and PHP and JavaScript variables that correspond d
irectly 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 o
r 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 VARIA
BLE 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 co
uld 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 AN
D CHECKBOXES

5.4.1 LABELS

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


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 ATTRIBUT
ES

T
he
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 dif
ferent. 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 l
abel 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 f
or collecting the checked boxes in the group after the form is posted:

e.g.

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




6
. DATA ACCESS CLASSE
S


Data access classes” correspond directly to database tables/objects, and should ideally provide the only
m
ethod 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 para
meterised 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 us
ing

$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 ADMINIST
RATION

For a standard table administra
tion 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);



Object
Edit.ph
p

(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 paramete
r, 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 VALIDA
TION

For maximum security and performance all user input via forms is to be validated on both the c
lient
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 FUN
CTIONS

This is to be done using a set of matc
hing 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 matc
h 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. pass
ing an id to a delete script), then only
data from the $_GET array should be used.