FireFox! The PHP Forum Loans and Credit
Panama Web Design for Hire Free Insurance Quotes!
Web Hosting Advertise Here $10 a Month Designer Children
Never Pay Taxes Again HGH Domain name registration
Web Hosting and Dedicated Servers Insurance Affordable web-hosting


HomeWatched TopicsRegisterSearchDirectory
FAQMemberlistUsergroupsLog inStoresItemsBank
Google

Reply to topic Page 1 of 1
Using PHP to Develop Three-Tier Architecture Applications
Message  
Reply with quote
Post Using PHP to Develop Three-Tier Architecture Applications 
Overview

This tutorial will be presented in two parts. Part one will present an overview of conceiving your dynamic web applications as a three-tier architecture, in which your PHP scripts play a key role in the business logic layer of the architecture. This part of the tutorial will introduce two PHP tools to help you manage the interactions between the tiers of your application.

Part two of this tutorial will present an architecture for your applications to take advantage of these tools and a three-tier design. This architecture will also highlight development and maintenance benefits of this design. The tutorial will develop a web link page, stored in a database and maintained in the web application itself, however, the concepts and architecture can be applied to any dynamic web application.

Designing your application in layers, or tiers, is useful for many different reasons. In a multiple tier design, each tier can be run a separate machine, or machines, allowing for improved processing performance. Depending on your design, multiprocessor machines, or many different independent computers can be used to improve performance. Efficient layering can give structure to you application, promote scalability, and ease long-term maintenance requirements for your code.

In the typical three-tier architecture, the first tier is persistent data storage. The underlying technology to implement this layer could be a variety of things including client side cookies, server side files or a database. The second tier is the business logic layer. This is where you code any rules regarding the data you have stored and generally is the bulk of your application. The third tier is presentation, enabling your users to see the results of your business logic applied to the data you have stored.

You can see the natural application of dynamic web applications to this three-tier architecture. The first tier is usually best satisfied with a database, running either on the web server itself, or easily accessible to the web server. The second tier is composed of a web server running a scripting language providing database access. While this same architecture could use any scripting language (Active Server Pages, Java Servelets, etc.) this tutorial will enumerate a number of reasons that PHP is well suited to this task. The third tier is clearly the browser-application/browser, rendering the output of your PHP scripts for your users. Through the very nature of the Internet, the third tier processing is distributed to the many computers browsing your site.

These tutorials will present a number of PHP based tools that will allow you to efficiently structure your applications into a three-tier architecture. Several tips aimed at the long-term maintainability of your application are also highlighted. The following figure depicts the structure and technologies for the architecture described in this Tutorial.

Learning Objectives

In this tutorial you will learn how to:

    * Use PHP to interact with the database tier and the presentation tier in your application
    * Apply the Smarty Template system
    * Apply the PEAR DB database abstraction classes

The following functions are also used in this code:

DB::isError(), DB::Connect(), strftime(), strtoupper()
Definitions

HTML ? HyperText Markup Language, the language web pages are composed in, and which our application separates out into the presentation layer

PEAR - PHP Extension and Application Repository, PEAR (http://www.php.net/manual/en/pear.about.php) is a code repository for PHP extensions and PHP library code inspired by TeX's CTAN and Perl's CPAN.

Smarty ? an extensive PHP template system providing the standard variable substitution and dynamic block functionality, but also incorporating configuration files, template functions, and variable modifiers. The underlying implementation is the creation of a "compiled" PHP script to generate the final template output.
Background Information
Database selection

For most sites with dynamic content, a database will be the most appropriate choice for persistent data storage. Selecting a database is important to the overall performance, reliability and ease of maintenance for your application. Many times, your environment dictates the selection of your relational database software. Clearly the hardware, operating system and web server software have a bearing on the database software selection. Often, your database solution will be dictated by a corporate directive from your company, a client or your service provider.

You should consider using a database abstraction layer in your application. Even if your database environment is fixed, and you do not expect to make and changes to the underlying database software for the life of your application, there are good reasons to use an abstraction lay. Once you become familiar with the abstraction layer, you can use the same programming techniques on other projects that may require a different database solution. Your project may be so successful that you want to market it or make it available via open source. In either case, have the database abstraction layer in place will make your application much more portable.

In selecting a database, you should try to locate a solution that will fit your long-term needs. You should look for a solution that includes: stored procedures, transactions, views, user and object level security, and triggers.

Many people have expressed the view that all you need for a web application is a database with the capability to perform fast select statements. Why then, do we need to find a database engine that supports all of the above features? The short answer is to provide for the reliability, security and ease of maintenance for your application.

The login/user you connect to the database from your script should only have the ability to: 1) select from views, 2) insert, update or delete only via stored procedures, and 3) have NO access to the base tables or ability to create additional objects in your database. This means that if an intruder gains access to your database using these credentials, they can only effect as many changes as you have coded into your application through the web site.

Triggers can be used to provide a "date created" and "date last changed" fields automatically, which can often provide insight when debugging problems with your application. Transactions can provide for atomic updates, and can often be incorporated within the stored procedures your application calls, even if the database abstraction layer does not support transactions.

Note: The database used in developing this tutorial is Sybase Adaptive Server Enterprise for Linux version 11.0.3.3, which is offered as a free, unsupported release for development as well as deployment from Sybase at http://www.sybase.com/linux/ase. While ASE 11.0.3.3 supports all of the above features, many commonly deployed open source database solutions do not. In the interest of making this tutorial provide utility to the widest possible audience, this tutorial will make minimal use of the features described above.
Template systems

There are several advantages to using a template system in your application. The primary advantage with respect to this tutorial is the ability to separate your HTML code from you database and business logic code. Template systems also allow for easy changes to the look and feel of your site, proper coding of HTML in your site, and for the possible separation of the skill sets between your developers doing the scripting and designers doing the HTML layout of your application.

There are a number of PHP based template systems to choose from. You should evaluate both the features available and the underlying technology used in each system. An article on template system selection was recently published on the Zend website (http://www.zend.com/zend/trick/tricks-nov-2001.php). Most systems perform a simple variable replacement using a regular expression. Smarty, the template system presented in this tutorial, pre-compiles the template into a PHP script that executes at the time a page is fetched. This structure, combined with server side caching, can provide significant speed advantages over other systems.

For any additional classes or code you are considering adding to your site, evaluate any development mailing lists and version release history for the project you are incorporating. If there is little activity, you will have to take more responsibility for understanding and making corrections to the code you are adding. If there is considerable support for the project, others may have already identified any problems you are encountering, and may have work-arounds or fixes available.
Prerequisites

Several requirements should be in place prior to beginning this tutorial:

    * A working web server with PHP
    * PEAR installed in the PHP library path
    * You have installed and have working access to a relational database
    * It is recommended that you have reviewed and tested PEAR DB. (A excellent quick start for PEAR DB is located at http://vulcanonet.com/soft/pear_tut/)
    * The Smarty template system downloaded from the Smarty site (http://www.phpinsider.com/php/code/Smarty/)
    * It is recommended that you have installed and tested Smarty per the quick start guide (http://www.phpinsider.com/php/code/Smarty/QUICKSTART)

How it Works
Description of Each Step

In this section, you will walk through using PHP to interact with the other tiers of your architecture. First, the PEAR DB database abstraction classes will be used to interact with your PHP script and your database. Then, you will use the Smarty template system to promote HTML code separation, enhancing your ability to effectively interact with the browser/presentation tier of your architecture.
Code Flow

To be more specific, the application has two tables in the database, link and link_group. You will use these tables to store the name, URL and description for hyperlinks you will display. The application will categorize these links into groups. The tables will also control the order in which these links are displayed. Our database is laid out as follows:

table link_group

link_group_id
    

Numeric(10,0)
      

IDENTITY not null

group_name
 

Varchar(50)
 

null

group_desc
      

Varchar(255)
        

null

group_ord
      

Numeric(5,0)
        

null

table link

link_id
      

Numeric(10,0)
      

IDENTITY not null

link_group_fk
      

Numeric(10,0)
      

not null

name
        

Varchar(50)
 

null

url
    

Varchar(150)
        

null

link_desc
      

Varchar(255)
        

null

link_ord
        

Numeric(10,0)
      

null
Tip ? IDENTITY property:

Sybase has an IDENTITY property for a field. This is an auto-incrementing number that will uniquely identify the row. This tutorial assumes when you insert a row into the database that this field will automatically be populated. Though the author is not familiar with MySQL, I believe IDENTITY behaves similarly to the AUTO_INCREMENT modifier in that database. If your database does not support this feature, you will need to insert an appropriate value by hand.

If you want some sample data in your application, use the following statements:
insert into link_group
    (group_name, group_desc, group_ord )
values
    ('Referenced', 'Links referenced in the body of the tutorial', 1);
insert into link_group
    (group_name, group_desc, group_ord )
values
    ('PHP Related', 'Links useful for PHP programming', 2);

If you have newly created tables, the IDENTITY property will start with 1 and you will be able to run the following sql statement:
select link_group_id, group_name from link_group;

 link_group_id group_name
 ------------- ------------------------------
             1 Referenced
             2 PHP Related

You can then use the following statements (if your insert statements return different values for link_group_id, please substitute the correct values below):
insert into link
    (link_group_fk, name, url, link_desc, link_ord )
values
    (1, 'Smarty', 'http://www.phpinsider.com/php/code/Smarty/', 'The compiling template system for PHP.', 1);
insert into link
    (link_group_fk, name, url, link_desc, link_ord )
values
    (1, 'Pear DB Quickstart', 'http://vulcanonet.com/soft/pear_tut/', 'An excellent quickstart guide for PEAR DB.', 2);
insert into link (link_group_fk, name, url, link_desc, link_ord )
values
    (2, 'Zend', 'http://www.zend.com/', 'The Zend website.', 1);
insert into link
    (link_group_fk, name, url, link_desc, link_ord )
values
    (2, 'PHP', 'http://www.php.net/', 'The PHP website.', 2);
PEAR DB ? Database Tier Interactions

The first step towards interacting with the database is including the PEAR DB class in your application, require_once('pear/DB.php');.

Note: PEAR should be installed by default with PHP, but you can follow the instructions in the PEAR DB quick-start to get the most recent version of PEAR DB.

The next step is to establish a connection to our database. Review of the pear db tutorial mentioned above would be helpful to understand the basics of using pear db. The following will be used in our application:
$db_type = 'sybase';
$db_user = 'zenduser';
$db_pass = 'zendpass';
$db_name = 'zenddb';
// create a string with the format 'sybase://zenduser:zendpass@SYBASE/zenddb'
$dsn = $db_type.'://'.$db_user.':'.$db_pass.'@'. strtoupper($db_type).'/'.$db_name;
$db = DB::Connect($dsn);

We can now use the handle to the database $db to execute other PEAR DB methods. To test, you might create a simple sql statement that will return a known result, i.e. $sql = 'select @@version'; will return the Sybase server version information (you might do 'select sysdate from dual' in Oracle, or whatever is appropriate in you db environment as a known query). To retrieve the results, execute the query method and store the results in a variable. ($rs for result set), verify the result set is not a PEAR::Error object, then fetch the first row of the result set into a variable. Your code to run this test might look like:
$rs = $db->query($sql);
if (!DB::isError($row = $rs->fetchRow())) {
        print $row[0];
} else {
        print 'dberror: '.$rs->getMessage();
}

Lets review loading some arrays from data in the database step by step. The purpose of this view will be to show the standard layout of the application (title, etc.), show a list of your groups of links grouped by each of the group titles in your database, and show your application footer information. Create an SQL statement to retrieve the groups we want, in this case all of the groups which are referenced by a link in the link table ($sql = "select distinct g.* from link l, link_group g where l.link_group_fk = g.link_group_id order by group_ord asc"Wink.

Note: This statement aliases each of the tables to a shorter name used as a prefix to the field names. This is done for clarity, and to promote long-term ease of maintenance for this code. If your database server does not support this syntax, you should be able to remove both the aliases (g and l) and explicitly list the table_name.field_name for each of the fields you want to query.

Next you create a result set by executing the SQL statement ($rs = $db->query($sql)Wink. Verify you received a valid result set (if (!DB::isError($rs)), then loop over the result set until you detect an "error", the error being the end of the result set (while (!DB::isError($row = $rs->fetchRow(DB_FETCHMODE_ASSOC)))). This last statement is fairly complex, but can be understood easiest by reading the inner most code first. $rs->fetchRow(DB_FETCHMODE_ASSOC) returns a row, which is assigned to the variable $row. $row is then check using the DB::isError, and if this check returns false, the code inside of the while loop continues. Inside the while loop, the next element of the $group array is assigned the value of the group_name field from the row ($group[] = $row['group_name']Wink.

Note: If you did note specify DB_FETCHMODE_ASSOC at the time you call the fetchrow method, you would have to populate the group_name using $row[0]. This would be much harder to review or debug in the future because you are forced to review the SQL statement for both content (what you are selecting) as well as sequence (the order you fetch the statement fields).

In the code, the results are being used in two ways. The first is to populate the $group variable, i.e. creating an array of information retrieved from the database. The second way you are using the result is in the construction of another sql query to retrieve the links associated with the group you have just queried. This code follows:
    $group[] = array(
    'id' =>  $row['link_group_id'],
    'name'=>  $row['group_name'],
    'desc'=>  $row['group_desc'],
    'ord'=>  $row['group_ord']    );
    $sql = "select l.* from
            link l, link_group g
            where
            l.link_group_fk = {$row['link_group_id']}
            and
            l.link_group_fk = g.link_group_id
            order by l.link_ord asc";

The results of the second query are then loaded into an array $link is a similar fashion.

Note: The $group[] = array(...) notation will create an array of arrays with the outer array starting at 0 and indexed by 1. The elements of the $group array referenced are then the associative arrays containing the data rows for each record queried from the database. Using this construct will be important for Smarty and the third tier interactions.
Smarty - Presentation Tier Interactions

Similar to PEAR DB, you need to include the Smarty class files in your application (require_once("Smarty.class.php")Wink. In addition, you should initialize a variable to hold your Smarty template , i.e. $tpl = new Smarty; You should also assign values to variables you intend to either pass to the template, or use in calling the template.
$title = 'Zend Link Demo';
$template = 'links1.tpl';
$cache_num = $PHP_SELF;

Title is self explanatory, template identified the name of the template file which contains the HTML for your application, and cache_num will be used with one very useful feature of Smarty: server side caching.

The assign function is used to pass information from your application to Smarty. The assign function will accept a string and a value, in which case the string is the name of the template variable, and the value will be the value of the template variable. The other syntax the assign function will accept is an associative array of template variable names and their associated values. The values can be any valid PHP type (strings, numbers, arrays) from any source (hard-coded, previously populated variables, function return results). After having populated the variables you want passed to your template, use the assign function.
        $tpl->assign( array(
        'title'=>  $title,
        'group'=>  $group,
        'link'=>  $link ));

Your next step is to display the Smarty template. This is done by calling $tpl->display($template, $cache_num);. This code loads the file you called (links1.tpl) from the ./templates directory and processes it. The first time the template is called after you have modified the template file, Smarty will compile the template (and store the compiled version in the ./templates_c directory). Subsequent calls (until the next time you change the template file) will be much faster because there will be no need to compile the template.

Now you can look at what the template file looks like. A sample Smarty template to display the index page follows:
<html>
<head>
<title>{$title}</title>
<meta http-equiv="Expires" content="0">
{*  We use a literal here because of the curly braces in the style definition *}
{literal}
    <style>
    .lr  { color: red;  font: 18pt; }
    .bdr { border: 5 black solid 1; }
    </style>
{/literal}
</head>
<body>
<center>
<h1>{$title|upper|spacify|replace:"   ":" &nbsp; "}</h1>
<p>Page Generated on {insert name=get_date format="%A, %B %d, %Y %X"}
<!--
page cached on {$smarty.now|date_format:"%Y-%m-%d %H:%M:%S"}
-->
<p class="lr">Links</p>
<div class="bdr">
<table border="0" cellpadding="5" cellspacing="0">
{section name=group_idx loop=$group}
{strip}
<tr align="center">
    <td colspan="2">
        <h1>
        <a name="{$group[group_idx].name}">{$group[group_idx].name}</a>
        </h1>
    </td>
</tr>
{section name=link_idx loop=$link}
    <tr align="left">
        <td>
            <a href="{$link[group_idx][link_idx].url}">
            {$link[group_idx][link_idx].name}
            </a>
        </td>
        <td>
            {$link[group_idx][link_idx].desc}
        </td>
    </tr>
{/section}
{/strip}
{/section}
</table></div>
<p>Thanks for visiting.</p>
</center>
</body>
</html>

The first thing you notice about the template is that it looks like the source for a web page. All of your HTML should be contained in your template files. The template represents the presentation layer of your three tier architecture, and should control all of the formatting and layout of the information loaded into the template by your PHP script, the business logic layer. Variables you assigned to the Smarty template can be referenced using the Smarty delimiters, { and } by default, and a $ preceding the variable name. In the example, <title>{$title}</title> will end up outputting <title>Zend Link Demo</title> in the final output send to the browser.

The next item you notice is a Smarty comment. The Smarty comment delimiters are {* and *}. Smarty comments are not displayed at all when the template is parsed, so you can put any information there and you do not have to worry about your end users being able to view source and see the comments (similar to PHP comments).

The Smarty literal built in function is used to protect the {} in the style definitions from being parsed as Smarty template information. This can also be useful if you want to include javascript in your template files.

You can reuse the assigned template variables as demonstrated by the <h1>{$title |upper|spacify|replace:" ":" &nbsp; "}</h1> statement, printing out the title of the application in the body of the HTML document. In the example show above, Smarty variable modifiers have been used. Variable modifiers allow the person responsible for display change the appearance of the data passed into the template. In the example above, we have changed the title to all upper case, added spaces between all of the characters to spread them out, and then replace instances of three spaces in a row with a space, an HTML non-breaking space and another space (because browsers will normally disregard the multiple spaces).

The Smarty built-in function strip is used to condense white space (tabs, spaces, carriage returns, etc.) from the output of your page. This helps promote long-term maintainability for your code by allowing you to use indentation of your code for readability, but allowing you to strip this white space from the final result. It also helps to reduce the size, thus improving the download speed, of your pages.

Smarty templates use sections for repeating blocks of output. In the example, {section name=group_idx loop=$group} starts the repeating block of output. The block is named group_idx, and uses group_idx as an index. The section will loop over the $group template variable as an array. This array should be indexed from 0 and fully populated to work correctly with Smarty. You reference the template array as shown by {$group[group_idx]}.

This example also shows one of the power features of the Smarty template system, variable modifiers. {$group[group_idx] |escape:"url"} will convert the group name to a URL encoded values, without you going to the effort of assigning these values to another array and passing them to the template.

The {sectionelse} lets you show something when there is no information in the array you are looping the section on.

Once you have your base application in place, there in one additional powerful feature of the Smarty template system you can use to significantly improve you applications performance: server side caching. This is implemented by using $tpl->caching = true; to enable caching and using $tpl->cache_lifetime = 86400; to set the duration of time the page should be cached (in seconds). In addition, you can specify a cache name to store multiple versions of the page in the cache. In this example, you need a separate copy per view and depending if you are an administator of the application. The $cache_num = $PHP_SELF; code creates a single cache for this script and adding the cache name to the Smarty display ($tpl->display('links.tpl', $cache_num)Wink uses it if caching is enabled. To make sure you are actually saving time, check to see if your template is cached before running your expensive database queries:
if ( !$tpl->is_cached($template, $cache_num) ) {
    //expensive queries here...
}
$tpl->display($template, $cache_num);

You may want to have some of the content of your page be dynamic, even though you would like to have most of the page cached. Smarty allows for this using the insert function. You can observe this behavior in the script presented, the html comment will show you the time at which the page was generated (<!-- page cached on {$smarty.now|date_format:"%Y-%m-%d %H:%M:%S"} --> ) but the visible greeting will always display the current time (<p>Page Generated on {insert name=get_date format="%A, %B %d, %Y %X"} ).

The Smarty template system has many more functions and variable modifiers than those listed here. In addition, the Smarty framework is extensible, allowing for additions you write as custom functions or variable modifiers.
The Script

The following is the PHP script and the Template file representing a complete application for this tutorial:

links1.php:
<?php
/*
    2001-10-27 Jason E. Sweat
    links1.php

    PHP script for the Zend Tutorial
    Using PHP to Develop Three-Tier Architecture Applications
    Part 1 - Tier Interactions
*/

/*
    include the required Smarty class file
    include the file for the PEAR Database class
*/
require_once('pear/DB.php');
require_once('Smarty.class.php');

$tpl = new Smarty;
$title = 'Zend Link Demo';
$template = 'links1.tpl';
$db_type = 'sybase';
$db_user = 'zenduser';
$db_pass = 'zendpass';
$db_name = 'zenddb';
$cache_num = $PHP_SELF;

/*
    create a string with the format
    "sybase://zenduser:zendpass@SYBASE/zenddb"
    then use a static call to the DB class connect
    method to return a database connection
*/
$dsn = "$db_type://$db_user:$db_pass@".strtoupper($db_type)."/$db_name";
$db = DB::Connect($dsn);

if (isset($clear_cache)) {
    $tpl->clear_all_cache();
}

/*
    by enabling caching, and checking to see if the cached version is current,
    the database is only queried once per day
*/
$tpl->caching = true;
$tpl->cache_lifetime = 86400; // in seconds, 84600 = 1 day
if ( !$tpl->is_cached($template, $cache_num) ) {
    $group = array();
    $link = array();
    $sql = "select distinct g.* from link l,
            link_group g where l.link_group_fk = g.link_group_id order by
            group_ord asc";
    $rs = $db->query($sql);
    $group_index = 0;
    if (!DB::isError($rs)) {
        while (!DB::isError($row = $rs->fetchRow(DB_FETCHMODE_ASSOC))) {
            $group[] = array(
'id'    =>    $row['link_group_id'],
                'name'    =>    $row['group_name'],
                'desc'    =>    $row['group_desc'],
                'ord'    =>    $row['group_ord']
            );
            $sql = "select l.* from
                    link l, link_group g
                    where
                    l.link_group_fk = {$row['link_group_id']}";
            $sql .= ' and l.link_group_fk = g.link_group_id order by l.link_ord asc';
            $rs_link = $db->query($sql);
            if (!DB::isError($rs_link)) {
                while (!DB::isError($row_link = $rs_link->fetchRow(DB_FETCHMODE_ASSOC))) {
                    $link[$group_index][] = array(
                        'name'        =>    $row_link['name'],
                        'url'        =>    $row_link['url'],
                        'desc'        =>    $row_link['link_desc']
                    );
                }
            }
            $group_index++;
        }
    }
    $tpl->assign( array(
        'title'        =>    $title,
        'group'        =>    $group,
        'link'        =>    $link
        ));
}

$tpl->display($template, $cache_num);

/************************************
    Functions section

    the main script is complete,
    include any functions here
************************************/

function insert_get_date($args = array('format' => '%A, %B %d, %Y') )
{
    return strftime($args['format']);
}

?>

links1.tpl:
{**
 *
 * @file         links.tpl
 * @author         Jason E. Sweat
 * @created     2001-10-27
 * @description Zend Tutorial template
 *                Smarty version 1.4.5
 *                http://www.phpinsider.com/php/code/Smarty/
 *}
<html>
<head>
<title>{$title}</title>
<meta http-equiv="Expires" content="0">
{*  We use a literal here because of the curly braces in the style definition,
    also useful for embedding java script in templates
*}
{literal}
    <style>
    .lr  { color: red;  font: 18pt; }
    .bdr { border: 5 black solid 1; }
    </style>
{/literal}
</head>
<body>
<center>
<h1>{$title|upper|spacify|replace:"   ":" &nbsp; "}</h1>
{*
    The Smarty insert function calls a php function and prints the returned
    output.  This is not cached with the other content in a cached
    Smarty Template (useful for banner adds, etc.).
*}
<p>Page Generated on {insert name=get_date format="%A, %B %d, %Y %X"}
<!--
page cached on {$smarty.now|date_format:"%Y-%m-%d %H:%M:%S"}
-->
<p class="lr">Links</p>
<div class="bdr">
<table border="0" cellpadding="5" cellspacing="0">
{section name=group_idx loop=$group}
{strip}
<tr align="center">
    <td colspan="2">
    <h1><a name="{$group[group_idx].name}">{$group[group_idx].name}</a></h1>
    </td>
</tr>
{section name=link_idx loop=$link}
    <tr align="left">
        <td>
            <a href="{$link[group_idx][link_idx].url}">{$link[group_idx][link_idx].name}</a>
        </td>
        <td>
            {$link[group_idx][link_idx].desc}
        </td>
    </tr>
{/section}
{/strip}
{/section}
</table>
</div>
<p>Thanks for visiting.</p>
</center>
</body>
</html>



http://www.zend.com/zend/tut/tutsweatpart1.php

View user's profile Send private message
Display posts from previous:
Reply to topic Page 1 of 1
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
  



Google

FireFox! The PHP Forum Loans and Credit
Panama Web Design for Hire Free Insurance Quotes!
Web Hosting Advertise Here $10 a Month Designer Children
Never Pay Taxes Again HGH Domain name registration
Web Hosting and Dedicated Servers Insurance Affordable web-hosting


Web Design by PlatinumShore.com & Web Hosting by TradeWebHosting.com