DRAFT REVISION

php(Reactor) Developers' Manual

Jakarta, 7 February 2001


Prepared for


phpreactor developers

php(Reactor) <phpreactor@lists.3wsi.com>


Prepared by


Angus D Madden <angus@3wsi.com>


Summary


The following manual is a description of the methods, styles, procedures and philosophies used in building php(Reactor). This is basically an abridged copy of the 3WSI Developers' Manual.


Changes



Attachments



Preface



I have included in this manual a few key concepts to make sure we all have the same mindset when at work. I start with a description of our design principles and goals, continue to talk about nitty-gritty stuff like coding style, and go on to talk about system architecture. Please use this as manual as a reference, I hope to add to it as time goes by and we grow larger.


Angus, 7 February 2001




Design Principles


php(Reactor) application design is based on the following principles:



If you are unsure about any of them, please ask your team or refer to http://3wsi.com/articles/index.php?artid=1


Design Goals


We want to get the most use out of our existing systems. We expand that simple concept to our application design goals:



Building for Distribution means that we make all of our code flexible and customizable. The idea is that if we build an application for site A, we can easily adapt the same solution when it is requested for site B.


Granted, building for distribution takes more time at the beginning, but saves us time in the long run. In general, building for distribution requires a greater investment at the beginning of a project. But it will gives us easier maintenance schedules and give our products economies of scale.


Reuse/Adaptation of Existing Code means that we try to get the most out of our code. Generally, it means that it is better to use an existing module than create a new one. An example of this is the comment functions in the articles and polls boards - they used the existing BBS code rather than creating a new system. It saves of the time of developing a new system, and more importantly, it saves us the time it would take to maintain a new system.


So, whenever you are developing a new app, make sure you have checked our existing apps to see if there is something that can be changed/modified to create a new system. A key part of this is knowing the existing code backward and forward.


Shared Code means that everyone works on the same code. If you notice a bug in someone else's code, go ahead and change it. That's why we use CVS. Of course, you should test any changes fully before you commit them. If it is a major change, confer with the developer beforehand. If you notice a stylistic problem or something that will cause serious problems in the future, bring it to everyone's attention on the mailing list.


Commodity Technologies means that we build our solutions to run on standard web servers with standard application environments. In general, most of the products we build should be deployable on shared web servers. You'll find that we generally interpret this to means that it will run on apache with the Linux operating system. You'll also find that we favor open source software. This is not a coincidence.


User Controlled Content means that we give our users the tools they need to operate and update their own web sites. All content should be easily configurable through a browser interface. Users demand this kind of control, and we'll give it to them. It also relieves us of an unimportant maintenance burden.




System Design


This section will cover the details of how design our applications; it will also outline our coding styles.


Application Design


A standardized application design is critical to our development process. The application design is a work in progress and should be continually evolving. A production example of the application design can be seen at our open source project, http://phpreactor.org/ .


To outline how script directories are organized:


inc/

contains library files and complete scipts. The scripts return no output by definition and care should be taken to make sure there is no extra whitespace at the beginning and end of the files. The naming convention is boardname.inc.php or boardnamescript.inc.php


conf/

contains configuration and language variables. Anything that can be put into a configuration variable should be put here. Any text output by your applications should have a customizable language value. The naming convention is boardname.conf.php


templates/

contains the templates for the main layout and graphic design of the site, in particular top.tpl.php and int.tpl.php . Examples of these files can be seen in the default distribution


modules/

contains small, portable snippets of code. Generally, modules are designed to be portable within the framework of other applications, allowing us to mix and match components. When building new modules remember to follow the framework set in the existing modules. Naming convention is board_in_board.module.php


sql/

contains the table definitions for the database that sits behind the applications. Naming convention is create_tablename.(my|pg)sql.php


backups/

contains a script to backup the database. Gzipped database dumps are stored here


cron/

contains a crontab file which contains any periodic jobs that should be run by the system


htdocs/

contains scripts accessible to the public. Scripts follow the following convention:


boardname/

a pseudo-directory which contains a set of apps. Example, forums/ or articles/ . The boardname concept is very important, as we shall see later. Note - when a portability of a directory is useful, scripts within the directory are symlinked or moved to the inc/ directory and included from there. With this method, it becomes very easy to maintain multiple extensions of the same application


boardname/admin/

the administration interface for a set of applications. Protected with .htaccess directtives, this directory should be accessed only with ssl-encrypted connections


img/

collection of standard images used by the applications


images/

collection of user-contributed or site-specific images used by the application


css/

collection of cascading style sheets used by the application


Let me also list some important variables with global scope:



There are quite a few important variables for more refined customization. Whenever including customization variables, remember to check the existing variables first, and if a similar variable already exists, use it.


Coding Style


Wars are fought over coding style - this is not necessary. The key point is that everyone's code should look the same, to the point that we couldn't figure out who wrote it by looking at it. I have posted a guidelines here, follow them. Please note that the indentation for the code below isn't correct as I haven't taken the time to put pre tags in the html. Assume standard C emacs-mode indentation.



function foobar($var1 = "foo", $var2 = "bar")

{

global $reactorcore, $boardname, $errormessage;

$out = '';


if ($boardname == 'forums')

{

$out .= 'this is not forums.\n';

$errormessage .= 'get out of here man<br>\n';

}

else

{

$out .= 'this is '.$boardname.'.\n';

}

$out .= '<h2>this script is located at '.getenv("PHP_SELF").'</h2>\n';

return($out);

}


Note the following:



<?php

/*

* filename - author - description of what it does - copright

* no warranty.

*/


//INCLUDE STATEMENTS FIRST


//ALWAYS INCLUDE THIS

if(!defined("REACTOR_INC_GLOBAL")) { include("inc/global.inc.php"); }

//INCLUDE DB FUNCTIONS

if(!defined("REACTOR_INC_BOARD")) { include($pathtohomedir."/inc/board.inc.php"); }


//initialize any variables

$out = "";


//deinfe template body function see template files for details


function tpl_body()

{


global $username, $password, $upload, $errormessage, $pathtohomedir, $out, $something;


//NOW VALIDATE VARIABLES


// username must be letters or numbers and between 4-20 chars long

if (!ereg("[[:alnum:]]{4,20}", $username))

{

$errormessage .= picklang($boardlang["bad username"]).'<br>\n';

}

// password must be letters or numbers or punctuation

if (!ereg("[[:alnum:][:punct:]]{4,20}", $password))

{

$errormessage .= picklang($boardlang["bad password"]).'<br>\n';

}

// MAKE SURE TO VALIDATE ALL VARIABLES ONE BY ONE

// I HAVE LEFT SOME OUT FOR BREVITY'S SAKE


// if uploading and no error, execute

if ($upload && !errormessage)

{

process_form($username, $password);


if (!$errormessage)

{

//now tell the user it was success

$tpl_title = picklang($boardlang["success"]);

$tpl_message = picklang($boardlang["success msg"]);

//include simple template

{ include($pathtohomedir."/templates/simple.tpl.php"); }

exit;

}

}


//if not uploading, or an error has been set, print the input form

if (!$salon || $errormessage)

{

//if an errormessage exists, show the error

if ($errormessage)

{

$out .= '<b style="color:red;">'.$errormessage.'</b><br>\n';

}

$out .= '<form action="'.getenv("PHP_SELF").'" method="post" name="pstfrm">\n';

//declare hidden variables at top of form

$out .= '<input type="hidden" value="1">\n';

$out .= 'enter username: \n';

$out .= '<input type="text" name="username" value"'.stripslashes($username).'" size="20" maxlength="20"><br>\n';

$out .= 'enter password: \n';

$out .= '<input type="password" name="password" value"'.stripslashes($password).'" size="20" maxlength="20"><br>\n';

$out .= 'choose something: ';

$out .= '<select name="something" size="1">\n';

$out .= '<option value="" '.(($something="")? 'selected' : '').'>\n';

$out .= '<option value="animal" '.(($something="animal")? 'selected' : '').'>\n';

$out .= '<option value="vegetable" '.(($something="vegetable")? 'selected' : '').'>\n';

$out .= '<option value="mineral" '.(($something="mineral")? 'selected' : '').'>\n';

$out .= '</select><br>\n';

$out .= '<input type="submit" value="'.picklang($boardlang["send"]).'"><br>\n';

$out .= '</form>\n';

}

//send to client - because this is a template function we use echo - normally we would just use return

echo $out;

}


//define other template functions

function tpl_additional_head()

{

global $reactorcore;

echo "<script type=text/javascript src=$reactorcore/global.js></script>";

}


// the following functions are rarely used - don't use them without a good reason

function tpl_page_top() {}

function tpl_page_foot() {}

function tpl_sidebar() {}


//include template

{ include($pathtohomedir."/templates/int.tpl.php"); }

?>


Note the following:



Remarks


This manual is most certainly incomplete - it will be added to as we grow and develop. It is a subset of the larger 3wsi Developers Manual, which I can't distribute for corporate reasons. I hope to publish the 3wsi developers manual of the 3wsi website, the manual has additional procedures for configuring a server, common development tools and utilities, and more. And finally, forgive the spelling mistakes in this text. My hands never do what I tell them.

general:/home/ii/docs/3wsi-developers-manual.sdw 12 6. Feb. 2001