$Id: STANDARD,v 1.13 2003/06/09 21:13:13 hpdl Exp $ osCommerce Coding Standards Coding standards are defined to keep the codebase in a maintainable state. The more developers working within the codebase means the more ways php logic can be written. If every developer follows the standards then everyone is able to review the codebase and not waste time thinking about why a certain style was used in a particular area compared to another area. File Format ----------- The source code should be saved in Unix format - meaning with Unix linefeeds. Most editors are able to set the preferred format method of Windows, Unix, or Macintosh. Some editors add a line to the bottom of the file. This is safe to have as long as a further character (including the space character) does not exist. Characters that exist at the end of the file may interfer when redirections occur as text has been sent to the client already. The filename of the files must be all lowercass characters and contain no more than 31 characters to be Apple/Mac compatible. Indentation ----------- Indentation of logic should be 2 whitespace characters. TABs should not be used. Starting and Ending PHP Logic ----------------------------- When starting PHP logic, the tag should be written as "<?php", not in the short form of "<?" or in ASP compatible tags such as "<%". The end tag to mark the end of the PHP logic should be written as "?>". A valid example: <?php echo "Hello World!"; ?> Defining Constants ------------------ Constants must be defined before they are being used - which also includes constants called from include()'d/require()'d files. Variable Scope* -------------- All variables must be accessed and set within their scope as: $HTTP_GET_VARS['variable'] $HTTP_POST_VARS['variable'] $HTTP_COOKIE_VARS['variable'] $variable (either local, or session) * This needs to be updated when the codebase has been made compatible with the register_global parameter. Session variables are then accessed and set within its scope as: $HTTP_SESSION_VARS['variable'] When PHP3 support is dropped, the following scope will be used: $_GET['variable'] $_POST['variable'] $_COOKIE['variable'] $_SESSION['variable'] PHP 4.0.x does not support the above scope which was introduced in PHP 4.1.x. The following can be used which is not compatible with PHP 3.x: $_GET =& $HTTP_GET_VARS; $_POST =& $HTTP_POST_VARS; $_COOKIE =& $HTTP_COOKIE_VARS; $_SESSION =& $HTTP_SESSION_VARS; include() vs require() ---------------------- The use of include() will include the specified file when needed, whereas the use of require() will always include the specified file regardless if it is needed or not. Example: <?php require('file.php'); if (condition == true) { include('file_true.php'); } else { ... } ?> Instantiating Classes --------------------- When instantiating classes into objects, the following style must be used: <?php // without class parameters* $object = new className; // with class parameters $object = new className($parameter1); ?> * PHP3 does not support the following style which includes an empty bracket set: <?php $object = new className(); ?> Displaying Strings ------------------ Strings or values should be displayed as: <?php echo 'Hello Mr Mister!'; ?> The following styles should be avoided: <?php print $variable; ?> <?=$variable;?> Singe-Quotes vs Double-Quotes ----------------------------- When displaying strings single quote characters should be used. Double quote characters should be used only when control characters are needed. For example: <?php echo 'Hello Mr Mister!' . "\n"; ?> Custom Functions ---------------- All custom functions should start with tep_ so that the developer knows a native PHP function is not being called.* An example custom function style: <?php function tep_my_function($parameter, $optional = '') { global $HTTP_GET_VARS, $another_variable; .... return true; } ?> * When 2.2 is finalized the custom functions should be renamed to osc_* as "tep" refers to the previous name of the project. Class Names ----------- There are two types of styles to use when classes are used. The first type of class set are the static classes that can be found in the includes/classes directory. If the class name contains more than one word, the words in the filename are separated with an underscore character. The actual class name is one whole word where words from the second onwards being capitalized. For example, a class name of myOwnClass has a filename of my_own_class.php. The second type of class set are the dynamic modules that can be found in the includes/modules/* directories. The class names must match the filename as most of them are include()'d dynamicly. For example, a class filename of my_own_module.php has a class name of my_own_module. Class Structure --------------- The class should be written in the following structure: <?php class myclass { var $variable; // class constuctor function myclass() { .... return true; } // class methods function do_something() { $this->variable = 'set'; return true; } } $class = new myclass; $class->do_something(); ?> Database Queries ---------------- Database queries are wrapped around custom functions and should be structured as: <?php // multi-result set $action_query = tep_db_query("select column1, ..."); while ($action = tep_db_fetch_array($action_query)) { echo $action['column1']; } // single result set $action_query = tep_db_query("select column1, ..."); $action = tep_db_fetch_array($action_query); echo $action['column1']; // return number of rows $action_query = tep_db_query("select count(*) as total from ..."); $action = tep_db_fetch_array($action_query); echo $action['total']; // query with parameters $action_query = tep_db_query("select column1 from table where field = '" . tep_db_input($some_id) . "'"); while ($action = tep_db_fetch_array($action_query)) { .... } ?> Unlike displaying strings, double quote characters are wrapped around the sql query. The following is currently for the Administration Tool but will also be implemented in the Catalog module. Before data can be entered in the database, it must be protected against possible attacks residing in the user input. The data is first prepared and then protected when inserting it into the table. The following structure is used: <?php $value1 = tep_db_prepare_input($HTTP_POST_VARS['value1']); tep_db_query("update table set column = '" . tep_db_input($value1) . "' where id = '" . (int)$id . "'"); ?> Variable type casting should be performed directly for integer based values, such as column IDs: (int)$variable Multiple values can be parsed, protected and inserted into the table in an easier fashion: <?php $value1 = tep_db_prepare_input($HTTP_POST_VARS['value1']); $value2 = tep_db_prepare_input($HTTP_POST_VARS['value2']); $value3 = tep_db_prepare_input($HTTP_POST_VARS['value3']); $sql_data_array = array('column1' => $value1, 'column2' => $value2, 'column3' => $value3); tep_db_perform('table', $sql_data_array); ?> A similar structure can be used for updating values in a table: <?php $value1 = tep_db_prepare_input($HTTP_POST_VARS['value1']); $value2 = tep_db_prepare_input($HTTP_POST_VARS['value2']); $value3 = tep_db_prepare_input($HTTP_POST_VARS['value3']); $sql_data_array = array('column1' => $value1, 'column2' => $value2, 'column3' => $value3); tep_db_perform('table', $sql_data_array, 'update', "id = '" . (int)$id . "'"); ?> Table names should not directly be entered in the query, but the constant parameter assigned to that table. A list of defined constant table names can currently be found in includes/database_tables.php. Function Output --------------- All custom functions should return strings; not directly via echo(). For example: <?php function tep_my_function($string) { return $string; } ?> and not: <?php function tep_my_function($string) { echo $string; } ?> Condition Statements -------------------- If statements should be written as: <?php if (condition == true) { .... } else { .... } ?> If the condition is to check for a boolean value, this should be added to the condition (as above) for clarity. The following should not be used: <?php if (!$condition) { .... } ?> instead use the following: <?php if ($condition == false) { .... } ?> Multiple conditions should reside in their own parenthesis, as: <?php if ( (condition == true) && (condition == true) ) { .... } ?> Simple boolean expressions can be written as: <?php $value = (($condition == true) ? 'true' : 'false'); ?> Simple statements can be written as: <?php if ($condition == true) .... ?> Functions do not need to be checked with a true/false statement. For the following valid example: <?php if (empty($string)) { ... } if ( (isset($variable)) && (tep_not_null($string)) ) { ... } ?> Switch-Case statements should be written as: <?php switch ($value) { case '1': .... break; case '2': .... break; default: .... break; } ?> Condition Checking ------------------ To see if a variable exists, use the following structure: <?php if (isset($variable)) { ... } ?> and not: <?php if ($variable) { ... } ?> Repetitive Statements --------------------- while loops should be written as: <?php while (condition == true) { .... } ?> Walking through an array should be written as: <?php // for php3 compatibility reset($array); while (list($key, $value) = each($array)) { .... } // the php4 way foreach ($array as $key => $value) { .... } ?> for loops should be written as: <?php for ($i=0, $n=sizeof($array); $i<$n; $i++) { .... } ?> Mixing HTML and PHP ------------------- Common HTML tags started in HTML must end in HTML, and tags started in PHP must end in PHP. Wrong: <td><?php echo "Hello</td>"; ?> Correct: <td><?php echo "Hello"; ?></td> Correct: <?php echo '<td>Hello</td>'; ?> Exceptions to this standard include the tep_draw_form() function: <?php echo tep_draw_form(); ?> [form input fields are placed here] </form> ?>