moodle/lang/en_utf8/docs/coding.html
2006-09-12 08:56:10 +00:00

271 lines
19 KiB
HTML

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Moodle Docs: Coding Guidelines</title>
<link rel="stylesheet" href="docstyles.css" type="TEXT/CSS" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<h1>Moodle Coding Guidelines</h1>
<p class="normaltext">Any collaborative project needs consistency and stability
to stay strong.</p>
<p class="normaltext">These guidelines are to provide a goal for all Moodle code
to strive to. It's true that some of the older existing code falls short in
a few areas, but it will all be fixed eventually. All new code definitely must
adhere to these standards as closely as possible.</p>
<h2>General Rules</h2>
<ol class="normaltext">
<li class="spaced">All code files should use the .php extension.</li>
<li class="spaced">All template files should use the .html extension.</li>
<li class="spaced">All text files should use Unix-style text format (most text
editors have this as an option).</li>
<li class="spaced">All php tags must be 'full' tags like <font color="#339900">&lt;?php
?&gt;</font> ... not 'short' tags like <font color="#339900">&lt;? ?&gt;</font>.
</li>
<li class="spaced">All existing copyright notices must be retained. You can
add your own if necessary.</li>
<li class="spaced">Each file should include the main config.php file.</li>
<li class="spaced">Each file should check that the user is authenticated correctly,
using the correct has_capability() or required_capability() checks.</li>
<li class="spaced">All access to databases should use the functions in lib/datalib.php
whenever possible - this allows compatibility across a wide range of databases.
You should find that almost anything is possible using these functions. If you must write SQL code then make sure it is: cross-platform; restricted to specific functions
within your code (usually a lib.php file); and clearly marked.</li>
<li class="spaced">Don't create or use global variables except for the standard
$CFG, $SESSION, $THEME and $USER.</li>
<li class="spaced">All variables should be initialised or at least tested for
existence using isset() or empty() before they are used.</li>
<li class="spaced">All strings should be translatable - create new texts in
the &quot;lang/en&quot; files with concise English lowercase names and retrieve them
from your code using get_string() or print_string().</li>
<li class="spaced">All help files should be translatable - create new texts
in the &quot;en/help&quot; directory and call them using helpbutton().
<p>If you need to update a help file: </p>
<ul>
<li>with a minor change, where an old translation of the
file would still make sense, then it's OK to make the change
but you should notify translation@moodle.org</li>
<li>for a major change you should create a new file by adding
an incrementing number (eg filename2.html) so that translators
can easily see it's a new version of the file. Obviously the
new code and the help index files should also be modified to point
to the newest versions.</li>
</ul>
</li>
<li class="spaced">Incoming data from the browser (sent via GET or POST) automatically
has magic_quotes applied (regardless of the PHP settings) so that you can safely
insert it straight into the database. All other raw data (from files, or from databases)
must be escaped with <font color="#339900">addslashes()</font> before inserting it into the database.</li>
<li class="spaced">IMPORTANT: All texts within Moodle, especially those that have
come from users, should be printed using the format_text() function. This ensures that
text is filtered and cleaned correctly.</li>
</ol>
<p>&nbsp;</p>
<h2>Coding Style</h2>
<p class="normaltext">I know it can be a little annoying to change your style
if you're used to something else, but balance that annoyance against the annoyance
of all the people trying later on to make sense of Moodle code with mixed styles.
There are obviously many good points for and against any style that people use,
but the current style just <strong>is</strong>, so please stick to it. </p>
<ol class="normaltext">
<li class="spaced"><strong>Indenting</strong> should be consistently 4 spaces.
Don't use tabs AT ALL. </li>
<li class="spaced"><strong>Variable names</strong> should always be easy-to-read,
meaningful lowercase English words. If you really need more than one word
then run them together, but keep them short as possible. Use
plural names for arrays of objects.
<p class="examplecode"><font color="#006600">GOOD: $quiz<br />
GOOD: $errorstring<br />
GOOD: $assignments (for an array of objects)<br />
GOOD: $i (but only in little loops)<br />
<br />
BAD: $Quiz <br />
BAD: $aReallyLongVariableNameWithoutAGoodReason<br />
BAD: $error_string</font></p>
</li>
<li class="spaced"><strong>Constants</strong> should always be in upper case,
and always start with the name of the module. They should have words separated
by underscores.
<p class="examplecode"><font color="#006600">define(&quot;FORUM_MODE_FLATOLDEST&quot;,
1);</font></p>
</li>
<li class="spaced"><strong>Function names</strong> should be simple English
lowercase words, and start with the name of the module to avoid conflicts between modules.
Words should be separated by underscores. Parameters should always have sensible
defaults if possible. Note there is no space between the function name and
the following (brackets). <br />
<p class="examplecode"> <font color="#007700">function </font><font color="#0000BB">forum_set_display_mode</font><font color="#007700">(</font><font color="#0000BB">$mode</font><font color="#007700">=</font><font color="#0000BB">0</font><font color="#007700">)
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;global </font><font color="#0000BB">$USER</font><font color="#007700">,
</font><font color="#0000BB">$CFG</font><font color="#007700">;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;if (</font><font color="#0000BB">$mode</font><font color="#007700">)
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#0000BB">$USER</font><font color="#007700">-&gt;</font><font color="#0000BB">mode
</font><font color="#007700">= </font><font color="#0000BB">$mode</font><font color="#007700">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;} else if (empty(</font><font color="#0000BB">$USER</font><font color="#007700">-&gt;</font><font color="#0000BB">mode</font><font color="#007700">))
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#0000BB">$USER</font><font color="#007700">-&gt;</font><font color="#0000BB">mode
</font><font color="#007700">= </font><font color="#0000BB">$CFG</font><font color="#007700">-&gt;</font><font color="#0000BB">forum_displaymode</font><font color="#007700">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}</font></p>
</li>
<li class="spaced"><strong>Blocks</strong> must always be enclosed in curly
braces (even if there is only one line). Moodle uses this style:
<p class="examplecode"> <font color="#006600">if (</font><font color="#0000CC">$quiz</font><font color="#006600">-&gt;</font><font color="#0000CC">attempts</font><font color="#006600">)
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;if (</font><font color="#0000CC">$numattempts </font><font color="#006600">&gt;
</font><font color="#0000CC">$quiz</font><font color="#006600">-&gt;</font><font color="#0000CC">attempts</font><font color="#006600">)
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#0000CC">error</font><font color="#006600">(</font><font color="#0000BB">$strtoomanyattempts</font><font color="#006600">,
</font><font color="#CC0000">"view.php?id=$cm</font><font color="#006600">-&gt;</font><font color="#CC0000">id"</font><font color="#006600">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}</font></p>
</li>
<li class="spaced"><strong>Strings</strong> should be defined using single quotes
where possible, for increased speed.<br />
<p class="examplecode"> <font color="#006600">$var = 'some text without any
variables';<br />
$var = &quot;with special characters like a new line \n&quot;;<br />
$var = 'a very, very long string with a '.$single.' variable in it';<br />
$var = &quot;some $text with $many variables $within it&quot;; </font></p>
</li>
<li class="spaced"><strong>Comments</strong> should be added as much as is
practical, to explain the code flow and the purpose of functions and variables.
<ul>
<li>Every function (and class) should use the popular
<a target="_blank" href="http://www.phpdoc.org/">phpDoc format</a>.
This allows code documentation to be generated automatically.</li>
<li>Inline comments should use the // style, laid out neatly
so that it fits among the code and lines up with it.</li>
</ul>
<p class="examplecode"><font color="#FF8000">
/**<br />
* The description should be first, with asterisks laid out exactly<br />
* like this example. If you want to refer to a another function,<br />
* do it like this: {@link clean_param()}. Then, add descriptions <br />
* for each parameter as follows.<br />
*<br />
* @param int $postid The PHP type is followed by the variable name<br />
* @param array $scale The PHP type is followed by the variable name<br />
* @param array $ratings The PHP type is followed by the variable name<br />
* @return mixed<br />
*/</font><br />
<font color="#006600">function </font><font color="#0000BB">forum_get_ratings_mean</font><font color="#007700">(</font><font color="#0000BB">$postid</font><font color="#007700">,
</font><font color="#0000BB">$scale</font><font color="#007700">, </font><font color="#0000BB">$ratings</font><font color="#007700">=</font><font color="#0000BB">NULL</font><font color="#007700">)
{<br /></font>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#007700">if (!</font><font color="#0000BB">$ratings</font><font color="#007700">)
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#0000BB">$ratings
</font><font color="#007700">= array(); &nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#FF8000">//
Initialize the empty array</font><font color="#007700"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (</font><font color="#0000BB">$rates
</font><font color="#007700">= </font><font color="#0000BB">get_records</font><font color="#007700">(</font><font color="#DD0000">"forum_ratings"</font><font color="#007700">,
</font><font color="#DD0000">"post"</font><font color="#007700">, </font><font color="#0000BB">$postid</font><font color="#007700">))
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#FF8000">//
Process each rating in turn</font><font color="#007700"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;foreach
(</font><font color="#0000BB">$rates </font><font color="#007700">as </font><font color="#0000BB">$rate</font><font color="#007700">)
{</font> <br />
....etc </p>
</li>
<li class="spaced"><strong>Space</strong> should be used liberally - don't be
afraid to spread things out a little to gain some clarity. Generally, there
should be one space between brackets and normal statements, but no space between
brackets and variables or functions:<br />
<p class="examplecode"> <font color="#007700">foreach (</font><font color="#0000BB">$objects
</font><font color="#007700">as </font><font color="#0000BB">$key </font><font color="#007700">=&gt;</font><font color="#0000BB">
$thing</font><font color="#007700">)</font><font color="#006600"> {<br />
</font><font color="#007700">&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#0000BB">process($thing);</font><font color="#006600">
<br />
} <br />
<br />
</font><font color="#007700">if (</font><font color="#0000BB">$x </font><font color="#007700">==
</font><font color="#0000BB">$y</font><font color="#007700">)</font><font color="#006600">
{<br />
</font><font color="#007700">&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#0000BB">$a
</font><font color="#007700">= </font><font color="#0000BB">$b</font><font color="#007700">;</font><font color="#006600"><br />
} else if (</font><font color="#0000BB">$x </font><font color="#007700">==
</font><font color="#0000BB">$z</font><font color="#006600">) {<br />
</font><font color="#007700">&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#0000BB">$a
</font><font color="#007700">= </font><font color="#0000BB">$c</font><font color="#007700">;</font><font color="#006600"><br />
} else {<br />
</font><font color="#007700">&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#0000BB">$a
</font><font color="#007700">= </font><font color="#0000BB">$d</font><font color="#007700">;</font><font color="#006600"><br />
} </font></p>
</li>
</ol>
<p>&nbsp;</p>
<h2>Database structures</h2>
<ol class="normaltext">
<li class="spaced">Every table must have an auto-incrementing <strong>id</strong> field (INT10) as primary index.</li>
<li class="spaced">The main table containing instances of each module must have the same name as the module (eg <strong>widget</strong>) and contain the following minimum fields:
<ul>
<li><strong>id</strong> - as described above</li>
<li><strong>course</strong> - the id of the course that each instance belongs to</li>
<li><strong>name</strong> - the full name of each instance of the module</li>
</ul>
</li>
<li class="spaced">Other tables associated with a module that contain information about 'things' should be named <strong>widget_things</strong> (note the plural).</li>
<li class="spaced">Column names should be simple and short, following the same rules as for variable names.</li>
<li class="spaced">Where possible, columns that contain a reference to the id field of another table (eg <strong>widget</strong>) should be called <strong>widgetid</strong>. (Note that this convention is newish and not followed in some older tables)</li>
<li class="spaced">Boolean fields should be implemented as small integer fields (eg INT4) containing 0 or 1, to allow for later expansion of values if necessary.</li>
<li class="spaced">Most tables should have a <strong>timemodified</strong> field (INT10) which is updated with a current timestamp obtained with the PHP <strong>time</strong>() function.</li>
</ol>
<p>&nbsp;</p>
<h2>Security Issues (and handling form and URL data)</h2>
<ol class="normaltext">
<li class="spaced">Do not rely on 'register_globals'. <strong>Every</strong> variable must be
properly initialised in <strong>every</strong> code file. It must be obvious where the variable
came from</li>
<li class="spaced">Initialise all arrays and objects, even if empty. <code>$a = array()</code>
or <code>$obj = new stdClass();</code>.</li>
<li class="spaced">Do not use the <code>optional_variable()</code> function. Use the <code>optional_param()</code>
function instead. Pick the correct PARAM_XXXX value for the data type you expect. To check and set an optional
value for a variable, use the <code>set_default()</code> function.</li>
<li class="spaced">Do not use the <code>require_variable()</code> function. Use the <code>required_param()</code>
function instead. Pick the correct PARAM_XXXX value for the data type you expect.</li>
<li class="spaced">Use <code>data_submitted()</code>, with care. Data must still be cleaned before use.</li>
<li class="spaced">Do not use <code>$_GET</code>, <code>$_POST</code> or <code>$_REQUEST</code>. Use the
appropriate <code>required_param()</code> or <code>optional_param()</code> appropriate to your need.</li>
<li class="spaced">Do not check for an action using something like <code>if (isset($_GET['something']))</code>.
Use, e.g., <code>$something = optional_param( 'something',-1,PARAM_INT )</code> and then perform
proper test for it being in its expected range of values e.g., <code>if ($something>=0) {...</code>.</li>
<li class="spaced">Wherever possible group all your <code>required_param()</code>, <code>optional_param()</code>
and other variables initialisation at the beginning of each file to make them easy to find.</li>
<li class="spaced">Use 'sesskey' mechanism to protect form handling routines from attack.
Basic example of use: when form is generated,
include <code>&lt;input type="hidden" name="sesskey" value="&lt;?php echo sesskey(); ?&gt;" /&gt;</code>.
When you process the form check with <code>if (!confirm_sesskey()) {error('Bad Session Key');}</code>.</li>
<li class="spaced">All filenames must be 'cleaned' using the <code>clean_filename()</code> function, if this
has not been done already by appropriate use of <code>required_param()</code> or <code>optional_param()</code>
</li>
<li class="spaced">Any data read from the database must have <code>addslashes()</code> applied to it before it
can be written back. A whole object of data can be hit at once with <code>addslashes_object()</code>.</li>
<li class="spaced">Wherever possible, data to be stored in the database must come from <code>POST</code>
data (from a form with <code>method="POST"</code>) as opposed to <code>GET</code> data (ie, data from the URL line).</li>
<li class="spaced">Do not use data from <code>$_SERVER</code> if you can avoid it. This has portability
issues.</li>
<li class="spaced">If it hasn't been done somewhere else, make sure all data written to the database has
been through the <code>clean_param()</code> function using the appropriate PARAM_XXXX for the datatype.</li>
<li class="spaced">If you write custom SQL code, make very sure it is correct. In particular watch out for
missing quotes around values. Possible SQL 'injection' exploit.</li>
<li class="spaced">Check all data (particularly that written to the database) in <strong>every</strong>
file it is used. Do not expect or rely on it being done somewhere else.</li>
<li class="spaced">Blocks of code to be included should contain a definite PHP structure (e.g,
a class declaration, function definition(s) etc.) - straight blocks of code promote uninitialised
variable usage.</li>
</ol>
<hr />
<p align="center"><font size="1"><a href="." target="_top">Moodle Documentation</a></font></p>
<p align="center"><font size="1">Version: $Id$</font></p>
</body>
</html>