Advanced Webapp Development - Tips and Tricks


This chapter presents some tips and tricks for webapp development, including database programming, server-side programming (PHP and others), client-side programming (HTML/CSS/JavaScript); Version Control System (Git); etc.

Some parts are platform specific (e.g., Apache, PHP, Ubuntu only); while many are generic (e.g., Git, database naming convention).

Version Control System

You need to set up a Version Control System, such as Git, for backup, version control and collaboration. Read "How to setup and get started with Git".

Configuring Virtual Hosts in Apache Server

You may need to run multiple web sites under the same Apache server, e.g., production and test systems. It is common to run port-based Virtual Hosts on Apache, e.g., production system running on port 80, while test system on port 8080.

Read "Port-based Virtual Host" on how to configure port-based virtual host on Apache server.

For Ubuntu: Instead of adding the configuration directly into the main configuration file, you create virtual host configuration in "\etc\apache2\sites-available", run helper utility "a2ensite" to symlink it to the "\etc\apache2\sites-enabled", which is then picked up by the main configuration "apache.conf".

Database Convention

Webapp design typically begins with database design.

Over the years, I have developed my own conventions that greatly improve my productivity in writing webapp.

Naming Convention
  • Database name: in uppercase joined with underscore (e.g., QUIZ_SYSTEM)
  • Table name: in camel-case with initial cap (e.g., ProblemPool)
  • Column name: in camel-case with initial lowercase (e.g., problemNo, studentID). Acronyms like ID, OO shall be in uppercase.
  • ENUM name: Use the exact format to be displayed, e.g., 'NO - Wrong Output', 'Student'
  • Procedure name: in camel-case with prefix "proc" (e.g., procProcedureName)
  • Function name: in camel-case with prefix "fn" (e.g., fnFunctionName)
  • Procedure/Function parameters: in camel-case with prefix "in", "out" or "io" (e.g. inXxx, outXxx, ioXxx)
  • Trigger name: in camel-case with prefix "tg" (e.g., tgTriggerName)
  • Event name: in camel-case with prefix "evt" (e.g., evtEventName)

Do not use space (blank) or special characters in names, unless you are looking for more challenges.

Primary Keys

In general, the primary keys shall have suffix of "ID" (for Identification); or "No" (for number); or "code", e.g., userID, problemNo, tutorialNo, courseCode, groupCode. Do not simply use "ID" to name the primary key of all tables (although it is theoretically correct). You will get very confuse in your PHP/JavaScirpt programming codes. Use "ID" and "code" for string type (e.g. userID, courseCode); "No" for int type (e.g. submissionNo, tutorialNo, problemNo).

Validation Regexe

We should also define validation regexe for indexing columns during the database design. These regexe will then be used consistently in programming codes (such as PHP/JavaScript) to check the input validity and to present attack, e.g.,

  • loginID: /^[\w-]{4,20}$/ (4 to 20 word characters of [A-Za-z0-9_] and dash (-))
  • courseCode: /^[\w-]{3,15}$/ (3 to 15 word characters of [A-Za-z0-9_] and dash (-))
  • password: /^\w{4,}$/ (4 or more word characters of [A-Za-z0-9_])
  • int (problemNo, SubmissionNo, etc.): /^\d+$/ (1 or more digit characters of [0-9])

Ownership and Permission for Apache (Unix - Ubuntu/Mac OS X)

In Unix, Apache parent process is started by the superuser "root"; while the child processes are run by a special non-interactive user called "www-data". The user www-data is in group www-data only.

  1. The user www-data needs read access to public HTML/CSS/JavaScript and server-side scripts (such as PHP). It needs write access to directories such as "log" and "work".
  2. A group of developers (says Peter and Paul) need read/write access to all resources.
  3. Others shall have no permission at all to all resources.
Create Users and Group

To meet the requirements, we shall create a group called web-dev and places all developers (says users peter and paul) inside the group.

// create users "peter" and "paul"
$ sudo adduser peter
$ sudo adduser paul
// show user info
$ less /etc/passwd
// create group "web-dev" (for webapp developers)
$ sudo addgroup web-dev
// show groups
$ less /etc/group
// add users "peter" and "paul" to group "web-dev"
//   -a for append, -G for groupname
$ sudo usermod -a -G web-dev peter
$ sudo usermod -a -G web-dev paul
// If desired, also add to "sudo" group
File/Directory Ownership and Permissions

All directories/files are to be owned by user www-data and group web-dev.

For public HTML/CSS/JavaScript and server-side Scripts (e.g. /var/www):

  • Directory/Sub-directories: user www-data needs r-x (list, access), group web-dev needs rwx (list, write and access for maintenance), setgid to inherit group ownership, i.e. mode 2570 (dr-xrws---).
  • Files: user www-data needs r-- (read-only), group web-dev needs rw- (read-write for maintenance), i.e., mode 0460 (-r--rw----). (Note: No "x" needed for server-side scripts such as PHP.)
$ cd /var/www
// Change ownership to user www-data and group web-dev
//   -R for recursive
$ sudo chown -R www-data:web-dev .
// Change permissions of directory and sub-directories
//   -type d for directory
//   2 = setgid
//   570 = r-xrwx---
$ sudo find . -type d -exec chmod 2570 {} +

// Change permissions of files
//   -type f for file
//   460 = r--rw----
$ sudo find . -type f -exec chmod 0460 {} +
// Check
$ ls -al
// Repeat for all such directories

For "work" and "log" files: read-write and create.

  • Directory and sub-directories: user www-data needs rwx (list, write and access), group web-dev needs rwx (list, write and access), setgid to inherit group ownership, i.e. mode 2770 (drwxrws---).
  • Files: user www-data needs rw- (read-write), group web-dev needs rw- (read-write for maintenance), i.e., mode 0660 (-rw-rw----).
$ cd /path-to/work
// Change ownership to user www-data and group web-dev
//   -R for recursive
$ sudo chown -R www-data:web-dev .
// Change permissions of directory and sub-directories
//   -type d for directory
//   2 = setgid
//   770 = rwxrwx---
$ sudo find . -type d -exec chmod 2770 {} +

// Change permissions of files
//   -type f for file
//   660 = r--rw----
$ sudo find . -type f -exec chmod 0660 {} +
// Check
$ ls -al
// Repeat for all such directories

Webapp Directory Organization and File Conventions

Directory Organization

An example of webapp directory structure of PHP webapp is as follows:

 +-- www (read-only): public www (HTML/CSS/JavaScript + Server-side scripts)
 |    |
 |    +-- assets (read-only)
 |         |
 |         +-- include: Include files such as,,
 |         |            Include files are named as ".inc.php."
 |         +-- css: 
 |         +-- js: Do not named as "javascript", which causes conflict in some situation
 |         +-- images: Images used by HTML, e.g., favicon.ico
 |         |
 |         +-- upload (read-write): data/images uploaded by users, but need to be placed under public www
 |   (These directories are outside the public www for security)
 +-- php-lib (read-only): additional PHP libraries in sub-directories (such as kLogger) 
 +-- conf (read-only): Confidential configuration files, e.g., password 
 +-- export (read-write): data (report) exported by the app, may contain sensitive info
 +-- work (read-write): generated work files
 +-- log (read-write):  log file, may contains sub-directories for each type of logs,
 |         such as php-log, java-log
 |   (These are not used by the app in operation)
 +-- sql:  SQL scripts
 |    +-- init
 |    +-- maintenance
 +-- test: testing scripts (e.g., Selenium acceptance test scripts)
 +-- import: description files, used to populate the database
 +-- doc: public documentations (e.g., user guide in Wiki)
 +-- private: not too be shared or tracked by git.
      +-- doc: private documentations
      +-- test: private test scripts
      +-- data: confidential data

Each directory shall preferably contain a README.txt file to explain the contents of the directory.

Filename Conventions
  • Filename: in camel-case with initial cap (e.g., ForgotPassword.php, SetupProblems.php)
  • PHP Include Filename: *.inc.php (e.g.,,

PHP Logging - kLogger


PHP Webapp Examples



jQuery (@ is a JavaScript library that provides cross-browser support. Some JavaScript functions are not supported in certain broswer.

The "query" refers to querying DOM elements within the HTML document.



BootStrap (@ is set of CSS and JavaScript (jQuery) that greatly simplifies the client-side development. You can get a professional looking front-end in little time.

Setting up

  1. Download BootStrap from
  2. BootStrap requires jQuery. Download jQuery from
  3. Move the CSS files to sub-directory "css" and JavaScript files to "js".
  4. Include the BootStrap's CSS, BootStrap and jQuery JavaScript File in your HTML document as follows:
    <!DOCTYPE html>
    <html lang="en">
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <!-- Bootstrap viewport setup -->
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <!-- Bootstrap's CSS -->
        <link href="css/bootstrap.min.css" rel="stylesheet">
        <title>Your Title</title>
        <h1>Hello, world!</h1>
        <!-- Place the JavaScript at the end so the the page loads faster -->
        <!-- jQuery is needed for BootStrap -->
        <script src="js/jquery.min.js"></script>
        <!-- Include BootStrap's all compiled plugins -->
        <script src="js/bootstrap.min.js"></script>

Getting Started


  1. BootStrap CSS @
  2. Study the bootstrap examples @ "View Source" as well as using Firebug to study the HTML/CSS.
Some Basic Usage Notes:
  • Place your body content under a <div class="container"> or <div class="container-fluid"> (for full screen width).
  • BootStrap organizes the containers in rows. Each row has 12 columns.
  • [TODO] more

Tips ad Tricks

Login Page <form>'s width

To control the width of the login form (placed under a "container"):

<div class="container">
  <form method="post" style="max-width:500px; margin:0 auto;">


<body> Tag's padding-top to skip the navigation bar

If you use a fixed navigation bar (navbar-fixed-top) at the top of the page, which has a "position:fixed" attribute, you need to use padding-top to skip the navigation bar, e.g.,

body {
  padding-top: 50px;   /* To skip the "fixed" navigation bar */
  padding-left: 10px;
  padding-right: 10px;
  padding-bottom: 10px;
Collapsable Navigation Bar

When the screen width is too narrow to show all the menu items, a "collapse" button shown up, which contains the menu items.

<nav class="navbar navbar-default">
   <div class="navbar-header">
      <!-- Place "collapse button" and "brand" here -->
      <button type="button" class="navbar-toggle" data-toggle="collapse"
         <span class="sr-only">Toggle navigation</span>
         <!-- to draw 3 bars on the collapse button -->
         <span class="icon-bar"></span>
         <span class="icon-bar"></span>
         <span class="icon-bar"></span>
      <a class="navbar-brand" href="#">LOGO</a>
   <!-- Collect all the collapsable items here, with "id" targeted by the above button -->
   <div class="collapse navbar-collapse" id="navbar-collapse-menu">
      <ul class="nav navbar-nav">
         <li class="active"><a href="#">Item 1</a></li>
         <li><a href="#">Item 2</a></li>
         <li class="dropdown">
            <a href="#" class="dropdown-toggle" data-toggle="dropdown">
               Item 3<b class="caret"></b>
            <ul class="dropdown-menu">
               <li><a href="#">Item 3-1</a></li>
               <li><a href="#">Item 3-2</a></li>
               <li class="divider"></li>
               <li><a href="#">Item 3-3</a></li>


Parsley JS for Client-side Input Validation

Parsley JS (@ provides a JavaScript form validation library.

Setting Up


Example (with BootStrap)
<form method="post" data-parsley-validate>
      <!-- Enable Parsley for form input validation -->
  <div class="form_group">
    <label for="loginID">Login ID</label>
    <input type="text" name="loginID" id="loginID"
        data-parsley-pattern-message="Invalid Login ID" />
  <div class="form-group">
    <label class="control-label">Email</label>
    <input class="form-control"
        name="email" id="email"
        data-parsley-trigger="change" />

Setup HTTPS for Apache

For Windows: HERE.

For Ubuntu: HERE.

Profiling PHP Webapps with XDebug and WebGrind

The XDebug PHP extension helps you debugging your script by providing a lot of valuable debug information and generate trace and profiling information.

Webgrind (@ is an XDebug profiling web front end in PHP5. It implements a subset of the features of kcachegrind and installs in seconds and works on all platforms.