SquirrelMail  
Donations
News
About
Support
Screen shots
Download
Plugins
Documentation
Sponsors
Bounties



SquirrelMail Developer's Manual: General guidelines Next Previous Contents

2. General guidelines

2.1 Coding guidelines

To ensure that the SquirrelMail affects the logs as little as possible, executes as quickly as possible and stays readable to the developers, please follow these rules when coding.

Code with secure global variables

All code must work with the PHP setting register_globals set to off. This isn't hard, but you'll have to let go the idea that any variable that is passed via GET, POST, sessions or cookies is available right away. The PHP manual has a chapter on the subject, explaining the problem more in detail.

There's a special function in SquirrelMail, sqGetGlobalVar(), designed to retrieve variables in a safe way. Use this function instead of accessing $_GET etc. directly. Here's an example:

global $favorite_color;
sqgetGlobalVar('favorite_color', $favorite_color, SQ_FORM);

In the past, there have been some rather serious issues with PHP sessions and SquirrelMail. Thus, if you need to place any values into the user's session, there are some built-in SquirrelMail functions that you are strongly encouraged to make use of. Using them also makes your job easier.

Strictly speaking, globalizing the variable shouldn't be necessary for the SquirrelMail session functions, but certain versions of PHP seem to behave more predictably if you do.

function demo_session($favorite_color = 'green') {
    global $favorite_color;

    // Placing a variable into the session:
    sqsession_register($favorite_color, 'favorite_color');

    // Retrieving a variable from the session:
    sqgetGlobalVar('favorite_color', $favorite_color, SQ_SESSION);

    // Checking for the presence of a variable in the session:
    if (sqsession_is_registered('favorite_color')) {
        // do something important
    }

    // Removing a variable from the session:
    sqsession_unregister('favorite_color');
}

Don't use the standard PHP functions session_register() and session_unregister().

Be conscious of variable names and how they might interfere with one another for SquirrelMail installations with register_globals set to on. That is, if you use a variable called $username (and do not declare it as global), it will have a local scope and have no effect outside of the current function with register_globals set to off, but it would have potentially disastrous effects in an environment where register_globals is set to on.

Since SquirrelMail 1.4.7 and 1.5.1, globals are cleaned in functions/global.php. Make sure to include that file before setting any own global variables. If variables are set before loading functions/global.php, they can be corrupted in setups with register_globals set to on.

Read more about the functions in the SquirrelMail API Documentation.

Protect incoming and outgoing data

Any untrusted data must be escaped before output. This is to prevent cross site scripting attacks. Pass every variable that comes in through the URL, a mail message, or other external factors, through htmlspecialchars() before outputting it. Test incoming data to see if it's the right format. If, for instance, an integer is expected; test it with is_int(). If the data is expected to be within a certain range, make sure that it's really within that range before using it.

Keep the code log safe

SquirrelMail code must be log safe code, i.e. do everything to avoid PHP notices and other error messages, so SquirrelMail developers should always have error reporting turned all the way up. You can do this by changing two settings in your php.ini and restarting your web server:

display_errors = On
error_reporting = E_ALL

This way, you'll be sure to see all notices, warnings, and errors that your code might generate. Please make sure to fix them all before you releasing your code. This includes to initialize variables (just $a = 0 is initialization) and to use isset() or empty() in tests. Use ini_get("safe_mode") to determine if you can use putenv().

Since coding to eliminate the warnings produced by E_STRICT will result in code that's not backwards compatible all the way to SquirrelMail's minimal PHP requirements, E_STRICT should be off. Note that E_STRICT is part of E_ALL since PHP 6.0.0, so php.ini must be configured like this:

display_errors = On
error_reporting = E_ALL ^ E_STRICT

Do not end a file with a PHP end tag

At the very end of the file, do not use the PHP end tag ?> to close off the file. It may seem innocuous, but if you have any blank lines either before the first <?php tag or after the last ?> tag in any of your plugin files, you will break SquirrelMail in ways that may seem entirely unrelated. For instance, this will often cause a line feed character to be included with email attachments when they are viewed or downloaded, rendering them useless! Files which aren't included by other files, for instance the files in the directory src/, may of course end with HTML whereas included files may not.

To ensure compability with all PHP installations, SquirrelMail code uses the recommended PHP start tag <?php.

Group statements with braces

There shouldn't be a space between functions etc. and the brackets when using them, except when writing control structures. The use of braces, i.e. "{" and "}", is mandatory, even when grouping just one statement. The indentation is done using spaces, never tabulators, using four spaces per indentation level.

Examples:

if ($result > 5) {
    return TRUE;
} else {
    return FALSE;
}

function severeTesting() {
    ...
}

Keep the code internationalized

All SquirrelMail strings, but those in the configuration tools config/conf.pl and src/configtest.php, must be internationalized.

Use Single quotes when possible

Use single quotes (') instead of double quotes (") as much as possible because it's faster to execute, but remember that you must use double quotes (") with the gettext() strings (e.g. _("Translatable string")). Use single quotes (') to refer an index between brackets of an array (example: $foo['name'] and not $foo[name]).

Use UNIX style line breaks

Use UNIX style line breaks when coding (i.e. line feeds only - no carriage returns) and keep lines no longer than 80 characters when possible. Remember that it isn't allowed to have a break in the middle of a gettext() string.

Write useful documentation

The SquirrelMail Project use phpDocumentor to document the source code. Try to follow some common sense and document what is really needed. Documenting the code properly can be a big help for those who will take a look at your code, fix the bugs and even improve it, in the true open-source spirit that SquirrelMail was built upon. Anyone who adds or modifies a function, must add basic documentation about what it does. In short, that looks like this for the following fantasy function:

/**
 * This function sends an IMAP query to the server and checks for
 * errors.
 * @param string servername The hostname of the IMAP server.
 * @param string query The IMAP query to send.
 * @param bool silent True if errors should be ignored silently.
 * @return array An array containing the results of the query.
 */
function sqimap_query($servername, $query, $silent = false) {
...

Every PHP file must have a general description of its content, like the example below.

/**
 * about.php
 *
 * An "about box" detailing SquirrelMail info.
 *
 * @copyright 1999-2020 The SquirrelMail Project Team
 * @license http://opensource.org/licenses/gpl-license.php GNU Public License
 * @version $Id: about.php,v 1.12 2006/04/05 00:22:11 stekkel Exp $
 * @package squirrelmail
 */

Plugins must have the package "plugins" and a subpackage tag with the name of the plugin, which is "demo" in this example:

 * @package plugins
 * @subpackage demo

Extended phpDocumentor documentation can be found in the phpDocumentor Guide to Creating Fantastic Documentation.

Output larger chunks of HTML outside PHP

When echoing chunks of HTML code it is better/faster to do it outside of PHP mode and embed the occasional <?php echo $variable; ?> than to put the whole lot in one or more PHP echo statements.

Refer peekers to the top level

Every subdirectory of SquirrelMail, including the plugin directories, must contain an index file. In the documentation directory, the index file displays the various documents, but in all other directories it's a reference to the parent directory. At the root directory there's a reference to the login page.

Plugins developers can accomplish may copy the file index.php from the main plugins directory and then modify the documentation in it as mentioned above.

If you have any questions about security or are unsure, please contact the mailing list or IRC channel, because security is very important for a widely used application like SquirrelMail!

2.2 Including files

It's sometimes needed to reference functionality provided in other files, and therefore those files need to be included. Files that are included by SquirrelMail, such as functions/global.php or a plugin's setup.php, already have much of the functionality available, but files that are requested directly by the client browser, such as files in src/ or a plugin's custom options page (see Plugin pages called directly by the client browser), must have the initialization file included.

The initialization file will set up the SquirrelMail environment automatically to ensure that the user has been authenticated and is currently logged in, all user preferences are loaded, internationalization support is included, that stripslashes() is used on all incoming data (if magic_quotes_gpc is on), and that all other basic SquirrelMail resources and functions are initialized and included.

Note that as of SquirrelMail 1.4.0, all files are accessed using a constant called SM_PATH that always contains the relative path to the main SquirrelMail directory. This constant is always available for use when including other files from the SquirrelMail core or any plugins. For files that are requested directly by the client browser, it needs to be set.

Including the initialization file (before SquirrelMail 1.5.2)

Before you do anything else, you need to define the constant SM_PATH and include the initialization file. Make sure that SM_PATH points at the top level of the SquirrelMail installation. Here's an example for a plugin:

/** @ignore */
define('SM_PATH', '../../');

/* Including the SquirrelMail initialization file. */
include_once(SM_PATH . 'include/validate.php');

The list below contains the files that are included by include/validate.php. If the SquirrelMail version isn't listed, files are included from v.1.3.2.

1. class/mime.class.php
   1.1. class/mime/Rfc822Header.class.php
   1.2. class/mime/MessageHeader.class.php
   1.3. class/mime/AddressStructure.class.php
   1.4. class/mime/Message.class.php
   1.5. class/mime/SMimeMessage.class.php
   1.6. class/mime/Disposition.class.php
   1.7. class/mime/Language.class.php
   1.8. class/mime/ContentType.class.php
2. functions/global.php
   * Undoes magic_quotes_gpc=on sanitizing
   * Sets $PHP_SELF (since 1.5.1)
   * Starts session
3. functions/strings.php
   3.1. functions/global.php
   3.2. plugins/compatibility/functions.php (compatibility v.2.0.4+, requires
        code patching)
   * Sets squirrelmail version variable and constant.
   * Sets $PHP_SELF (before 1.5.1)
4. config/config.php
   4.1. config/config_local.php (from 1.4.0rc1)
5. functions/i18n.php
   5.1. functions/global.php (from 1.4.0)
   * Reads 'squirrelmail_language' cookie
   * Loads $languages (since 1.5.1 $languages array is built from
     locale/*/setup.php files)
   * Loads own gettext functions, if PHP gettext is unavailable
6. functions/auth.php
7. include/load_prefs.php
   7.1. include/validate.php
   7.2. functions/prefs.php
      7.2.1. functions/global.php (sqgetGlobalVar() function)
      7.2.2. functions/plugin.php (do_hook_function() function,,
             since 1.4.4 and 1.5.1, see 7.3)
      7.2.3. $prefs_backend (only in 1.4.3 and 1.5.0)
             do_hook_function('prefs_backend') (since 1.4.4 and 1.5.1)
             functions/db_prefs.php
             functions/file_prefs.php
        7.2.3.1. functions/display_messages.php
                 (loaded only by file_prefs.php)
        7.2.3.2. files loaded by plugin that uses 'prefs_backend' hook
   7.3. functions/plugin.php
      7.3.1. functions/global.php (from 1.4.0 and 1.5.0)
      7.3.2. functions/prefs.php (from 1.5.1)
      7.3.3. plugins/*/setup.php files for enabled plugins.
      * Starts all squirrelmail_plugin_init_pluginname functions
   7.4. functions/constants.php
   7.5. do_hook('loading_prefs')
      7.5.1. files loaded by plugins that use the 'loading_prefs' hook
8. functions/page_header.php
   8.1. functions/strings.php
   8.2. functions/html.php
   8.3. functions/imap_mailbox.php
      8.3.1. functions/imap_utf7_local.php
   8.4. functions/global.php
9. functions/prefs.php (already loaded. see 7.2)

Including the initialization file (since SquirrelMail 1.5.2)

Before you do anything else, you need to include the initialization file. Here's an example for a plugin:

/* Include the SquirrelMail initialization file. */
require('../../include/init.php');

This takes care of setting up the session, defining the constants like SM_PATH, and includes a minimum set of required files.

The files which are included by include/init.php depends on which file the client browser requested. All files in src/ include the following files:

  • config/config.php
  • functions/display_messages.php
  • functions/global.php
  • functions/html.php
  • functions/page_header.php
  • functions/plugin.php
  • include/constants.php
  • include/languages.php

Except for login.php and redirect.php, they also include:

  • functions/strings.php
  • functions/auth.php

login.php also includes:

  • functions/prefs.php
  • functions/db_prefs.php or functions/file_prefs.php depending of the configured preference backend.

Because the use of require() in include/init.php, a plugin will fail if it tries to include already included files. Be aware of that.

Including other files

When including files, please make sure to use the include_once() function and not include() or require(). They can cause fatal errors when other plugins or SquirrelMail files include the same file. If you use require_once() instead of include_once(), PHP will raise a fatal error if something goes wrong with the inclusion. That's the reason plugins must use include_once() instead of require_once().

Files that aren't included by the initialization file can be included like this:

include_once(SM_PATH . 'functions/imap_general.php');

2.3 The base URI funcion

FIXME: Add information about the base URI funcion.

2.4 Version numbering

The version number format

The approach we take for version numbering is very similar to the way the Linux kernel handles it. With this approach, it is easy to tell what's going on just by looking at the three-part version number. The full version number is a three-part number, using the format x.y.z, indicating a specific implementation of SquirrelMail. Our examples will be 1.0.6 and 1.1.2.

The first number is the major release number (that's the x). At first, this was 0 which meant we hadn't had any major releases yet. In January of 2001, we released 1.0.0 which was our first major stable release, and everything since then has been in the 1 family.

A major release of SquirrelMail should have a high-level set of specific goals that it is meeting. For SquirrelMail 1.0, this was the reaching of a stable release. For later versions, this may include implementation of more modular libraries and API behind the code, a templating system for the user-interface, and so forth.

The second number is the minor release number (that's the y). The minor release number will tell you whether a release is a stable or development branch of SquirrelMail. Even numbers (0, 2, 4...) mean that it's a stable release, and odd numbers (1, 3, 5...) mean it's a development release.

A minor release of SquirrelMail should have a lower-level set of specific goals that it is meeting. These goals should, somehow or another :), be a subset of the goals for the major release of which it is a part. Basically, the minor releases allow for the major goals of a major release to be broken into a more discrete, attainable set of objectives.

Lastly, the final number is a release incrementor (that's the z). In a stable branch, new versions of SquirrelMail will be release as bugs are found and squished. In a development branch, new versions of SquirrelMail will be released as progress is made toward the goals set for the next major and minor release. New releases will happen as needed in a stable branch. In a development branch, however, they should happen frequently, as more progress is made toward the next minor release.

Important points

  • Versions with a even minor release number are stable.
  • Versions with a odd minor release number are development.
  • New incremental releases in a stable branch should ONLY CONTAIN bug fixes. New features should always be implemented in the current development branch.

The release timeline

The goals and objectives for each minor release should be carefully chosen so that a new minor release can take place every three to four months. This is so that our users can see actual improvements and will stick with us as we work to make SquirrelMail a better web mail application.

2.5 Submitting a patch

If you do not have commit access to the SquirrelMail Project Subversion (SVN), you can provide a patch for bugs or features that you want to add. The developers will then decide whether or not it can be applied to SquirrelMail. You can submit your patch through the patches tracker on SourceForge.net, or you can attach it to an existing bug report or feature request.

Important points when writing a patch, to improve the chances that it will be committed:

  • Patch against the latest SVN version (prefered) or the latest released version.
  • Always use diff -u. Do not submit entire changed files or use different patch options. Make sure you don't reverse the patch.
  • Take care to follow the SquirrelMail coding guidelines.

Do you feel that your patch is ignored? Feel free to ask on the SquirrelMail development mailing list.


Next Previous Contents
© 1999-2016 by The SquirrelMail Project Team