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.
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:
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!
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 notinclude() 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:
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.
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.