Publishing System Settings Logout Login Register
Creating a simple Discussion Board
TutorialCommentsThe AuthorReport Tutorial
Tutorial Avatar
Rating
Add to Favorites
Posted on September 10th, 2007
11178 views
PHP Coding
First I want to say sorry for my bad english, it's not my native language as I'm german, but I'm giving my best. Feel free to correct me ^^

However, in this small tutorial I want to tell you to create a small discussion board similiar to the forum on this page, but of course, much smaller scaled. Here is a small feature list of what you should have after this tutorial:

As some are waiting for this tutorial i decided to put it online without all of the functions I wanted to include. I just can't find the time to do it all this weekend... but well... I will always update it or write tutorials that build up on this.

I'm using the Smarty template engine in this tutorial, so templates/skins can easily be made. You can get smarty here

      
  • Simple Administration (Configuration + Forum / Category Management) Comes in next version
  •   
  • User Management (Registration, Login, Userprofile, Userlvl, Avatars )
  •   
  • Forums, Categories, Topics and of course View
  •   
  • Signatures
  •   
  • Avatar in postings
  •   
  • Editing own posts
  •   
  • Simple BBcode for strong, italic, underlined, quotes and smilies
  •   
  • Simple Moderation via Listbox Comes in next version
  •   
  • Quotes
  •   
  • User Ranks Basics are in but no output yet
  •   
  • Topic Icons
  •   
  • Multi-Language
  •   
  • Templates/Skins

Here you can find what the result should look like: Tutorial Discussion Board

If you'd like to see some more features in this, feel free to tell me. So let's start! :)

I won't show you how to upload avatars or how to use templates etc. There are really enough tutorials out there, this tutorial just shows you how to code a nice small discussion board.

Files for this tutorial:

File Download: Template Images
File Download: Main Images (Images, Topic Icons)
File Download: My smarty folder

So first let's make a simple folder structure... I used the following:

You can click on the files to direclty jump to the page!

root
  | -> index.php
  |
  | -> backend (Administration things like configuration + forum management ) Will be relevant for future version
  |
  | -> cache
  |
  | -> core (Includes the php classes )
  |         |
  |         | -> _database.php
  |         | -> _forum.php
  |         | -> _login.php
  |
  | -> inc (configuration file)
  |       |
  |       | -> config.php
  |
  | -> lang (the language files)
  |       |
  |       | -> de
  |       |       |
  |       |       | -> main.conf
  |       |      
  |       | -> en
  |               |
  |               | -> main.conf
  |
  | -> smarty (the smarty folder)
  |
  | -> templates
  |            |
  |            | -> index.php
  |            | -> style.css
  |            |
  |            | -> backend (for future version)
  |            | -> images (template images)
  |            | -> main (main template files)
  |            |        |
  |            |        | -> content.tpl
  |            |        | -> footer.tpl
  |            |        | -> header.tpl
  |            |        | -> navi.tpl
  |            |        | -> stats.tpl
  |            |
  |            | -> post ( post related template files )
  |            |        |
  |            |        | -> view.tpl
  |            |
  |            | -> topics ( topics related template files )
  |            |        |
  |            |        | -> view.tpl
  |            |
  |            | -> user ( user related template files )
  |                     |
  |                     | -> profile.tpl
  |                     | -> register.tpl
  |                     | -> user.tpl
  |                     | -> userbox.tpl
  |
  | -> templates_c (smarty templates cache)
  |
  | -> tmp

On the next page we will begin with the database and themain config file.

SQL Dump


Ok first thing we need is the database:


CREATE TABLE `config` (
  `id` int(11) NOT NULL auto_increment,
  `name` varchar(50) NOT NULL,
  `value` varchar(255) NOT NULL,
  PRIMARY KEY  (`id`),
  UNIQUE KEY `name` (`name`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=10 ;

INSERT INTO `config` (`id`, `name`, `value`) VALUES (1, 'lang', 'en'),
(2, 'template', 'standard'),
(3, 'GZIP', '1'),
(4, 'ZLIB', '0'),
(5, 'TITLE', 'DiscussionBoard'),
(6, 'SUBTITLE', 'Exclusive tutorial for Pixel2Life'),
(7, 'ROOT', ''),
(8, 'REG_VIEW', '0'),
(9, 'NO_REG', '0');

CREATE TABLE `forum_cat` (
  `id` tinyint(4) unsigned NOT NULL auto_increment,
  `subtoid` tinyint(4) unsigned NOT NULL default '0',
  `name` varchar(255) NOT NULL default '',
  `desc` text NOT NULL,
  `sort` tinyint(4) unsigned NOT NULL default '0',
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COMMENT='Kategorien für das Forum' AUTO_INCREMENT=1 ;

CREATE TABLE `forum_posts` (
  `id` int(11) unsigned NOT NULL auto_increment,
  `subtoid` int(11) unsigned NOT NULL default '0',
  `userid` int(11) unsigned NOT NULL default '0',
  `catid` tinyint(4) unsigned NOT NULL default '0',
  `icon` int(5) NOT NULL default '0',
  `title` varchar(255) NOT NULL default '',
  `subtitle` varchar(255) NOT NULL default '',
  `message` text NOT NULL,
  `ip` varchar(255) NOT NULL default '',
  `last_update` datetime NOT NULL default '0000-00-00 00:00:00',
  `date` datetime NOT NULL default '0000-00-00 00:00:00',
  `views` int(11) unsigned NOT NULL default '0',
  `deleted` tinyint(1) NOT NULL default '0',
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COMMENT='Forumposts' AUTO_INCREMENT=1 ;

CREATE TABLE `user` (
  `id` int(11) NOT NULL auto_increment,
  `username` varchar(50) NOT NULL,
  `password` varchar(32) NOT NULL,
  `session` varchar(32) default NULL,
  `email` varchar(75) NOT NULL,
  `avatar` varchar(36) default NULL,
  `firstname` varchar(50) default NULL,
  `surname` varchar(50) default NULL,
  `country` varchar(50) default NULL,
  `location` varchar(50) default NULL,
  `icq` varchar(15) default NULL,
  `msn` varchar(75) default NULL,
  `yahoo` varchar(75) default NULL,
  `bio` tinytext,
  `hobbys` tinytext,
  `occupation` varchar(50) default NULL,
  `signature` tinytext,
  `template` int(11) NOT NULL default '1',
  `language` int(11) NOT NULL default '1',
  `usrlvl` enum('0','1','2','3') NOT NULL,
  `lastvisit` datetime NOT NULL,
  `lastaction` timestamp NOT NULL default CURRENT_TIMESTAMP,
  `changed` datetime NOT NULL,
  `registered` datetime NOT NULL,
  PRIMARY KEY  (`id`),
  UNIQUE KEY `username` (`username`),
  UNIQUE KEY `email` (`email`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

CREATE TABLE `user_ranks` (
  `id` int(11) NOT NULL auto_increment,
  `name` varchar(255) NOT NULL,
  `posts` int(11) NOT NULL,
  `image` varchar(50) NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

CREATE TABLE `languages` (
  `id` int(11) NOT NULL auto_increment,
  `name` varchar(50) NOT NULL,
  PRIMARY KEY  (`id`),
  KEY `name` (`name`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=3 ;

INSERT INTO `languages` (`id`, `name`) VALUES (1, 'en');
INSERT INTO `languages` (`id`, `name`) VALUES (2, 'de');

CREATE TABLE `templates` (
  `id` int(11) NOT NULL auto_increment,
  `name` varchar(50) NOT NULL,
  `info` tinytext NOT NULL,
  `author` varchar(50) NOT NULL,
  `version` varchar(5) NOT NULL,
  PRIMARY KEY  (`id`),
  KEY `name` (`name`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=2 ;

INSERT INTO `templates` (`id`, `name`, `info`, `author`, `version`) VALUES (1, 'Standard', 'This is the stanard discussion board layout.', 'Christian Weber', '0.1');


config.php

Ok so we have now our database set up... now we need our basic configuration file:


<?php
// Your mysql connection Data
define('SQL_HOST', 'localhost'); // Database Server
define('SQL_USER', ''); // Your mysql user
define('SQL_PASS', ''); // Your mysql Password
define('SQL_DB', ''); // your mysql database
define('SUFFIX',''); // Your mysql suffix, if you want to store more forums in one database.

// Smarty
define('SMARTY_DIR', '/srv/www/aso/'); // The path to your smarty directory
?>


I think everything should be self explanatory... now let's go on with database class...

_database.php

So here is the database class, it's just a very simple class, but it's easier to use classes as you can easily enhance them.
(called the file _database.php) in core folder

<?php
/***********************************************************
*
* Simple Discussion Board Tutorial Database Class
*
***********************************************************/

class cdb {
 
    // Construction
    function cdb() {
        // When initiated, it immidietly runs the connect function
        $this->connect();
    }
    // Connects to database server and to the database
    function connect() {
        // Connect to database server
        mysql_connect(SQL_HOST,SQL_USER,SQL_PASS) or die("Couldn't connect to database!");
        // Connect to database
        mysql_select_db(SQL_DB) or die("Coudln't find table!");
    }
    // Closes connection
    function close() {
        // disconnects
        mysql_close();
    }
    // Makes a query and returns the result
    function query($str) {
        // query the mysql statement
        $result = mysql_query($str);   
        // returns the result
        return $result;
    }   
    // Function to gather all the configrations located in the database.
    function get_config() {
        // sql statement
        $sql = "SELECT * FROM ".SUFFIX."config";
        // gather result
        $result = $this->query($sql);
        // if there are results go on
        if(mysql_num_rows($result)) {
            while($row = mysql_fetch_assoc($result)) {
                // if a constant is not defined
                if(!defined($row['name'])) {
                    // define a new constant with the database name + value
                    define($row['name'], $row['value']);
                }
            }
        }
    }
}
?>


_login.php

There is really nothing in this class that needs to be explained, there are just the main mysql functions... however, the next class is our userclass which I called _login.php als of course also located in core folder.

I recommend to use the md5 hash with salt for more security. Tutorial for this can be found here by NGPixel


<?php
/***********************************************************
*
* Simple Discussion Board Tutorial User Class
*
***********************************************************/

class clogin {
    var $db = '';
    var $userdata = array();
    var $users = array();
   
    // Constructor gets initiated with database class
    function clogin($db) {
        // define the local variable with the given database class
        $this->db = $db;
    }
   
    // Checks username and password, if there is a result it returns the userid, if not it returns false
    function checkuser($username, $password) {
        // SQL statement
        $sql = "SELECT `id` FROM `".SUFFIX."user` WHERE ((md5(`username`) = '".md5($username)."') && (`password` = '".md5($password)."')) LIMIT 1";
        // fetch result
        $result = $this->db->query($sql);
        // if there are results...
        if(mysql_num_rows($result)) {
            // gather the userid
            $userid = mysql_fetch_assoc($result);
            // and return it
            return $userid['id'];
        } else {
            // if not... return false
            return false;
        }
    }
   
    // log the user in
    function login($id) {
        // updates the user session to the local session where the id is the given userid and sets the lastvisit to now
        $sql = "UPDATE `".SUFFIX."user` SET `session` = '".session_id()."', lastvisit = NOW(), lastaction = NOW() WHERE `id` = '".$id."' ";
        // query it
        $this->db->query($sql);
    }
   
    // updates a user, to show that he's still active
    function isactive() {
        // sql statement.. sets lastaction to the current timestamp
        $sql = "UPDATE `".SUFFIX."user` SET `lastaction` = NOW() WHERE `session` = '".session_id()."' LIMIT 1";
        // query it
        $this->db->query($sql);
    }
   
    // checks if a user is logged in, if the users session is found in the database, he's logged in
    function loggedin() {
        // checks if the session exists
        $sql = "SELECT `id` FROM `".SUFFIX."user` WHERE (`session` = '".session_id()."') LIMIT 1";
        // check if users are online
        $this->check_online();
        // update online status of user
        $this->isactive();   
        // if there are any results return true, else return false
        return (mysql_num_rows($this->db->query($sql))) ? true:false;
    }
   
    // logs the user out
    function logout() {
        // Sets the session to none where database session is users session
        $sql = "UPDATE `".SUFFIX."user` SET `session` = '' WHERE `session` = '".session_id()."' LIMIT 1";
        // query it
        $this->db->query($sql);
    }

    // register a new user
    function register($username,$password,$email,$firstname,$surname,$country,$location) {
        // self-explanatory
        $sql = "INSERT INTO `".SUFFIX."user` SET `username` = '".$username."', `password` = '".md5($password)."', `email` = '".$email."', `firstname` = '".$firstname."', `surname` = '".$surname."', `country`= '".$country."', `location` = '".$location."', `usrlvl` = '0', `registered` = NOW()";
        // query it and return true or false
        return ($this->db->query($sql)) ? true:false;
    }
       
    // this functions checks if users had been online during the last 30 minutes... (automatic logout)
    function check_online() {
        // Set session to none where users lastaction is older than 30 minutes
        $sql = "UPDATE `".SUFFIX."user` SET `session` = '' WHERE  DATE_SUB(NOW(), INTERVAL 30 MINUTE) > `lastaction`";
        // query it
        $this->db->query($sql);
   
    }
   
    // updates a user
    function update($email, $firstname, $surname, $country, $location, $icq, $msn, $yahoo, $bio, $hobbys, $occupation, $signature, $template, $language) {
        // updates the user with the given data
        $sql = "UPDATE `".SUFFIX."user` SET `email` = '".$email."', `firstname` = '".$firstname."', `surname` = '".$surname."', `country` = '".$country."', `location` = '".$location."', `icq` = '".$icq."', `msn` = '".$msn."', `yahoo` = '".$yahoo."', `bio` = '".$bio."', `hobbys` = '".$hobbys."', `occupation` = '".$occupation."', `signature` = '".$signature."', `template` = '".$template."', `language` = '".$language."', `changed` = NOW() WHERE `session` = '".session_id()."'";
        // query it
        return (@$this->db->query($sql)) ? true:false;
    }
   
    // fetchs the userdata from a specific user
    function get_user($id) {
        // sql statement, selects all fields from usertable where id is the given id
        $sql = "SELECT * FROM `".SUFFIX."user` WHERE `id` = '".$id."' LIMIT 1";
        // fetch result
        $result = $this->db->query($sql);
        // if there is an result
        if(mysql_num_rows($result)) {
            // gather the data!
            $row = mysql_fetch_assoc($result);
            $this->userdata['id'] = $row['id'];
            $this->userdata['username'] = $row['username'];
            $this->userdata['email'] = $row['email'];
            $this->userdata['avatar'] = $row['avatar'];
            $this->userdata['firstname'] = $row['firstname'];
            $this->userdata['surname'] = $row['surname'];
            $this->userdata['country'] = $row['country'];
            $this->userdata['location'] = $row['location'];
            $this->userdata['icq'] = $row['icq'];
            $this->userdata['msn'] = $row['msn'];
            $this->userdata['yahoo'] = $row['yahoo'];
            $this->userdata['bio'] = $row['bio'];
            $this->userdata['hobbys'] = $row['hobbys'];
            $this->userdata['occupation'] = $row['occupation'];
            $this->userdata['signature'] = $row['signature'];
            $this->userdata['template'] = $this->get_template($row['template']);
            $this->userdata['language'] = $this->get_language($row['language']);
            $this->userdata['usrlvl'] = $row['usrlvl'];
            $this->userdata['lastvisit'] = $row['lastvisit'];
            $this->userdata['lastaction'] = $row['lastaction'];
            $this->userdata['changed'] = $row['changed'];
            $this->userdata['registered'] = $row['registered'];

                        return true;
        } else {
            // return false because there is no user with this id
            return false;
        }
    }
   
    // get own userid
    function get_ownid() {
        // selects the id via session id
        $sql = "SELECT `id` FROM `".SUFFIX."user` WHERE `session` = '".session_id()."' LIMIT 1";
        // query it
        $result = $this->db->query($sql);
        // check if there is a resource
        if(mysql_num_rows($result)) {
            // yes there is one... gather it
            $row = mysql_fetch_row($result);
            // return the id
            return $row[0];
        } else {
            // no data found, return false
            return false;
        }
    }
   
    // get the usertemplate
    function get_template($id) {
        // selects the name of the template from the given id
        $sql = "SELECT `name` FROM `".SUFFIX."templates` WHERE `id` = '".$id."' LIMIT 1";
        // query it
        $result = $this->db->query($sql);
        // if there are results
        if(mysql_num_rows($result)) {
            // get the name of the result
            $row = mysql_fetch_row($result);
            // return the name
            return $row[0];
        } else {
            // if there are no results, return false!
            return false;
        }
    }
   
    // get the userlanguage
    function get_language($id) {
        // selects the name of the language from the given id
        $sql = "SELECT `name` FROM `".SUFFIX."languages` WHERE `id` = '".$id."' LIMIT 1";
        // query it
        $result = $this->db->query($sql);
        // if there are results
        if(mysql_num_rows($result)) {
            // get the name of the result
            $row = mysql_fetch_row($result);
            // return the name
            return $row[0];
        } else {
            // if there are no results, return false!
            return false;
        }
   
    }
   
    // get the amount of posts a user already has
    function get_userposts($id) {
        // the sql statement just counts all results and gives them out as postcount where the userid is the given id
        $sql = "SELECT COUNT(*) AS 'postcount' FROM `".SUFFIX."form_posts` WHERE `userid` = '".$id."'";
        // query it
        $result = $this->db->query($sql);
        // if there are results...
        if(mysql_num_rows($result)) {
            // ... fetch them
            $row = mysql_fetch_row($result);
            // return the postcount
            return $row[0];
        } else {
            // ... if not... return false because this user has no posts yet
            return false;
        }
    }
   
    // returns the users rank for the given postcount
    function get_userrank($posts) {
        // the sql statement selects the rank that is smaller or even with the givin postcount.
        $sql = "SELECT * FROM `".SUFFIX."user_ranks` WHERE `posts` <= '".$posts."' ORDER BY `posts` DESC LIMIT 1";
        // fetch the result
        $result = $this->db->query($sql);
        // if there is an result...
        if(mysql_num_rows($result)) {
            // gather the result
            $row = mysql_fetch_assoc($result);
            $rank['name'] = $row['name'];
            $rank['image'] = $row['image'];
            // return the array with the name and the image of the rank
            return $rank;
        } else {
            // if there is no rank... return false
            return false;
        }
    }
       
    // get all users that are online (for onlinelist)
    function get_users() {
        // the sql statement selects only the important things from the userlist where session is not empty
        $sql = "SELECT `id`, `username`, `usrlvl` FROM `".SUFFIX."user` WHERE `session` != ''";
        // fetch the results
        $result = $this->db->query($sql);
        // if there are results
        if(mysql_num_rows($result)) {
            // gather them and put them in the class users array
            $i=0;
            while($row=mysql_fetch_assoc($result)) {
                $this->users[$i]['id'] = $row['id'];
                $this->users[$i]['user'] = $row['username'];
                $this->users[$i]['lvl'] = $row['usrlvl'];
                $i++;
            }
        }
    }
   
    // gets all available languages
    function get_languages() {
        // selects all languages
        $sql = "SELECT `id`, `name` FROM `".SUFFIX."languages`";
        // query it
        $result = $this->db->query($sql);
        // check for results
        if(mysql_num_rows($result)) {
            // there are results... get them
            $i=0;
            while($row = mysql_fetch_assoc($result)) {
                $languages[$i]['id'] = $row['id'];
                $languages[$i]['name'] = $row['name'];
                $i++;
            }
            // return the array
            return $languages;
        } else {
            // no results... return false
            return false;
        }
    }
   
    // gets all available templates
    function get_templates() {
        // selects all templates
        $sql = "SELECT `id`, `name` FROM `".SUFFIX."templates`";
        // query it
        $result = $this->db->query($sql);
        // check for results
        if(mysql_num_rows($result)) {
            // there are results... get them
            $i=0;
            while($row = mysql_fetch_assoc($result)) {
                $templates[$i]['id'] = $row['id'];
                $templates[$i]['name'] = $row['name'];
                $i++;
            }
            // return the array
            return $templates;
        } else {
            // no results... return false
            return false;
        }
    }
   

}
?>


This class is also very easy to understand, it doesn't do anything new, just the common things... logging in, checking if someone is logged in etc. It's  very well commented so there shouldn't be any questions open. On the next page we will go to the most important thing... the forumclass...

_forum.php

Good now we got all the basic things we need for a form but now we need the most important part... the forum class itself... I called it _forum.php and it's located in core.


<?php
/***********************************************************
*
* Simple Discussion Board Tutorial Forum Class
*
***********************************************************/
  
   class cforum {
           var $db;
        var $cats = array();
        var $topics = array();
        var $posts = array();
        var $postcat;
      
       // Constructor of the forum class, it defines the db variable with the given one and starts gathering all data
           function cforum($db) {
            // set database with given data
            $this->db = $db;
            // start gathering all needed information
            $this->fetchcats();
           }
       
        // This fetchs the main categories
        function fetchcats() {
            // selects all main categries (that are those that have no sub of course)
            $sql = "SELECT * FROM `forum_cat` WHERE `subtoid` = '0' ORDER BY `sort` ASC";
            // query it
            $result = $this->db->query($sql);
            // check if there are any categories
            if(mysql_num_rows($result)) {
                // if yes... get their data
                $i=0;
                while($row = mysql_fetch_assoc($result)) {
                    $this->cats[$i]['id'] = $row['id'];
                    $this->cats[$i]['name'] = $row['name'];
                    $this->cats[$i]['desc'] = $row['desc'];
                    // fetch the subcategories ( the $i is for the array we are making currently, so we know where this subcat goes to )
                    $this->fetchsubcats($row['id'], $i);
                    $i++;
                }
            } else {
                // if not return false, because we have no categories
                return false;
            }
           
        }
       
        // this fetchts the categories of the forums
        function fetchsubcats($catid, $id) {
            // selects all sub categories for the main category
            $sql = "SELECT * FROM `forum_cat` WHERE `subtoid` = '".$catid."' ORDER BY `sort` ASC";
            // query it
            $result = $this->db->query($sql);
            // check if there are any results
            if(mysql_num_rows($result)) {
                // if yes... gather the data
                $i=0;
                while($row = mysql_fetch_assoc($result)) {
                    $this->cats[$id]['subcats'][$i]['id'] = $row['id'];
                    $this->cats[$id]['subcats'][$i]['name'] = $row['name'];
                    $this->cats[$id]['subcats'][$i]['desc'] = $row['desc'];
                    // fetchs the data for this category... $id is the main category id in the array, $row['id'] is the id of the subcategory and $i is the subcategory id in the array
                    $this->fetchsubcatdata($id, $row['id'], $i);
                    $i++;
                }
            } else {
                // there are no subcategories!
                return false;
            }
        }
       
        // get alle the data we need for every category
        function fetchsubcatdata($cid, $subcat, $scid) {
            // selects the amount of topics in a subcategory
            $sql = "SELECT COUNT(*) AS 'topics' FROM `forum_posts` WHERE `catid` = '".$subcat."' AND `subtoid` = '0'";
            // query it
            $result = $this->db->query($sql);
            // check for results
            if(mysql_num_rows($result)) {
                // if there are results, gather them
                $amount = mysql_fetch_assoc($result);
                $topics = $amount['topics'];               
            } else {
                // if not, set topicscount to 0
                $topics = "0";
            }
            // add the topic-count to the subcategory data
            $this->cats[$cid]['subcats'][$scid]['topics'] =$topics;
           
            // selects the amount of postings in a subcategory
            $sql2 = "SELECT COUNT(*) AS 'posts' FROM `forum_posts` WHERE `catid` = '".$subcat."' AND `subtoid` != '0'";
            // query it
            $result2 = $this->db->query($sql2);
            // check for results
            if(mysql_num_rows($result)) {
                // if therea re results, gather them
                $amount2 = mysql_fetch_assoc($result2);
                $posts = $amount2['posts'];
            } else {
                // if not, set postingcount to 0
                $posts = "0";
            }
            // add the post-count to the subcategory data
            $this->cats[$cid]['subcats'][$scid]['posts'] = $posts;
        }
       
        // get all topics for a category
        function gettopics($id) {
            // selects all the topics from a subcategory includes the username + id of a user. (LEFT JOIN)
            $sql = "SELECT forum_posts.*, user.username AS 'username', user.id AS 'userid' FROM `forum_posts` LEFT JOIN `user` on forum_posts.userid = user.id WHERE `catid` = '".$id."' AND `subtoid` = '0' ORDER BY `last_update` DESC";
            // query it
            $result = $this->db->query($sql);
            // check for results
            if(mysql_num_rows($result)) {
                // there are results... gather them and add them to the topics class array
                $i=0;
                while($row = mysql_fetch_assoc($result)) {
                    $this->topics[$i]['id'] = $row['id'];
                    $this->topics[$i]['user'] = $row['username'];
                    $this->topics[$i]['userid'] = $row['userid'];
                    $this->topics[$i]['icon'] = $row['icon'];
                    $this->topics[$i]['title'] = $row['title'];
                    $this->topics[$i]['subtitle'] = $row['subtitle'];
                    $this->topics[$i]['views'] = $row['views'];
                    $this->topics[$i]['posts'] = $this->getpostcount($row['id']); // gets the postcount of this topic
                    $this->topics[$i]['latest'] = $this->getlatestpost($row['id']); // gets the latest posting of this topic
                    $i++;
                }
            } else {
                // there are no results... return false
                return false;
            }
        }
       
        // get postings of a topic
        function getposts($id) {
            // selects all the postings from a topic, includes users avatar, id, signatur and username (LEFT JOIN)
            $sql = "SELECT forum_posts.*, user.id AS 'userid', user.avatar AS 'thumb', user.signature AS 'signatur', user.username AS 'username' FROM `forum_posts` LEFT JOIN `user` ON forum_posts.userid = user.id WHERE forum_posts.id = '".$id."' OR forum_posts.subtoid = '".$id."' ORDER BY `date` ASC";
            // query it
            $result = $this->db->query($sql);
            // check for results
            if(mysql_num_rows($result)) {
                // gather data
                $i=0;
                while($row = mysql_fetch_assoc($result)) {
                    $this->posts[$i]['postid'] = $row['id'];
                    $this->posts[$i]['icon'] = $row['icon'];
                    $this->posts[$i]['title'] = $row['title'];
                    $this->postcat = $row['catid'];
                    $this->posts[$i]['subtitle'] = $row['subtitle'];
                    $this->posts[$i]['message'] = $row['message'];
                    $this->posts[$i]['bbmessage'] = $this->bbcode($row['message']);
                    $this->posts[$i]['date'] = $row['date'];
                    $this->posts[$i]['userid'] = $row['userid'];
                    $this->posts[$i]['username'] = $row['username'];
                    $this->posts[$i]['thumb'] = $row['thumb'];
                    $this->posts[$i]['posts'] = $this->getuserposts($row['userid']);
                    $this->posts[$i]['signature'] = $this->bbcode($row['signatur']);
                    $i++;
                }
            } else {
                // there are no results... return false
                return false;
            }
        }
       
        // get users posts
        function getuserposts($id) {
            // selects the amount of pots by a user
            $sql = "SELECT COUNT(id) AS 'amount' FROM `forum_posts` WHERE `userid` = '".$id."'";
            // query it
            $amount = mysql_fetch_assoc($this->db->query($sql));
            // return the amount
            return $amount['amount'];
        }
       
        // add a view to the topic   
        function addview($id) {
            // Update the views of a topic, just add one. (you should add some kind of ip blocking)
            $sql = "UPDATE `forum_posts` SET views = (views + 1) WHERE id = '".$id."'";
            // query it
            $this->db->query($sql);
        }
       
        // add a new posting
        function addpost($topic, $catid, $userid, $icon, $title, $subtitle, $message, $ip) {
            // insert a new posting to a topic with the given data
            $sql = "INSERT INTO `forum_posts` SET `subtoid` = '".$topic."', `catid` = '".$catid."', `userid` = '".$userid."', `icon` = '".$icon."', `title` = '".$title."', `subtitle` = '".$subtitle."', `message` = '".$message."', `ip` = '".$ip."', `date`  = NOW()";
            // update the topic, set the last action to now so it goes up in the topiclist
            $sql2 = "UPDATE `forum_posts` SET `last_update` = NOW() WHERE `id` = '".$topic."' LIMIT 1";
            // if the insert works go on, else return false
            if($this->db->query($sql)) {
                // now update the topic, if this works return true, else... retun false
                if($this->db->query($sql2)) {
                    return true;
                } else {
                    return false;
                }
            } else {
                return false;
            }
        }
       
        // edit a posting
        function editpost($id, $title, $subtitle, $icon, $message) {
            // Update a posting with the given data
            $sql = "UPDATE `forum_posts` SET `title` = '".$title."', `subtitle` = '".$subtitle."', `icon` = '".$icon."', `message` = '".$message."' WHERE `id` = '".$id."' LIMIT 1";
            // if the update works without a problem, return true, else false
            if($this->db->query($sql)) {
                return true;
            } else {
                return false;
            }
        }
       
        // get answers of a topic
        function getpostcount($id) {
            // selects the postingcount of a specific topic
            $sql = "SELECT count(*) AS 'postcount' FROM `forum_posts` WHERE subtoid = '".$id."'";
            // query it
            $result = $this->db->query($sql);
            // check for results
            if(mysql_num_rows($result)) {
                // data found, gather it
                $row = mysql_fetch_assoc($result);
                // return the postingcount
                return $row['postcount'];
            } else {
                // no data found, return false
                return false;
            }
        }
       
        // gets the last post from a topic
        function getlatestpost($id) {
            // selects the last post including userid and username from usertable for a specific topic (LEFT JOIN)
            $sql = "SELECT forum_posts.*, user.id AS 'userid', user.username AS 'username' FROM `forum_posts` LEFT JOIN `user` ON forum_posts.userid = user.id WHERE forum_posts.subtoid = '".$id."' ORDER BY forum_posts.date DESC LIMIT 1";
            // query it
            $result = $this->db->query($sql);
            // check for results
            if(mysql_num_rows($result)) {
                // data found, gather it
                $row = mysql_fetch_assoc($result);
                $latest = array(); // make new array
                $latest['userid'] = $row['userid'];
                $latest['username'] = $row['username'];
                $latest['date'] = $row['date'];
                // return the array
                return $latest;
            } else {
                // no data found, return false
                return false;
            }
        }
       
        // adds a new topic
        function addtopic($user, $catid, $icon, $title, $subtitle, $message, $ip) {
            // inserts a new topic with the given data
            $sql = "INSERT INTO `forum_posts` SET `userid` = '".$user."', `catid` = '".$catid."', `icon` = '".$icon."', `title` = '".$title."', `subtitle` = '".$subtitle."', `message` = '".$message."', `ip` = '".$ip."', `date` = NOW(), `last_update` = NOW()";
            // if the insert works return true, else false
            if($this->db->query($sql)) {
                return true;
            } else {
                return false;
            }
        }
       
        // BBcode system
        function bbcode($text) {
           
            // kill all html tags except the br           
            $text = strip_tags($text, '<br>');
       
            // the array with the bbcode you want to look for
            $suche = array('/(.+?)/i',
                           '/(.+?)/i',
                           '/(.+?)/i',
                           '/(.+?)/i',
                           '/:)/i',
                           '/;)/i',
                           '/:D/i',
                           '/:p/i',
                           '/:'(/i',
                           '/[quote](.+?)[/quote]/is',
                           '/(.+?)/i');
           
            // the array with the data that replaces the first arrays data
            $code = array('<b>$1</b>',
                          '<i>$1</i>',
                          '<u>$1</u>',
                          '<a href="$1" class="link" target="_blank">$2</a>',
                          '<img src="images/smilies/smile.gif" alt=":)" />',
                          '<img src="images/smilies/wink.gif" alt=";)" />',
                          '<img src="images/smilies/laugh.gif" alt=":D" />',
                          '<img src="images/smilies/tounge.gif" alt=":p" />',
                          '<img src="images/smilies/worried.gif" alt=":'(" />',
                          '<br /><div class="quote">$1</div><br />',
                          '<span style="color: $1;">$2</span>');
           
            // just to be sure... strip all slashes
            $text = stripslashes($text);
            // the main part of the bbcode system... replace all data using the two arrays and the given text
            $text = preg_replace($suche, $code, $text);
            // make a br out of /n
            $text = nl2br($text);
            // return the text
            return $text;
        }

  
   }
?>


Well that's some code... but it's all pretty easy, you only have to understand how it works. It begins gathering the main categories, when he finds a main category, he begins looking for subcategories. If he finds subcategories, he gathers the data of the subcategory. That's actually the most important and hardest part of this script. But it's actually pretty simple. This way we build a very big array with much information to read out. I don't like handling thousands of variables or arrays, I like to have it simple. Well no the next step is the main page... we now have all the important classes done.

Index.php

So let's make the main file of this discussion board. This script actually only gathers resources and puts things into the database... no loops or things like that in here... all that is happening in the template files.

So here it is, as always well commented.
 
<?php

    /*************************************************************************
    *
    * Simple Discussion Board Tutorial for Pixel2Life Community
    *
    * Features:
    *
    * - Simple Administration (Configuration + Forum / Category Management)
    * - User Management (Registration, Login, Profiles, Userlvl, Avatars)
    * - Forums, Categories, Topics and of course View
    * - Signatures
    * - Avatar in Postings
    * - Quoting others posts
    * - Editing own posts
    * - Simple BBcode for strong, italic, underlined, some smilies and color
    * - Simple moderation via listbox
    * - Topic Icons
    * - Multi-Language
    * - Template-System
    *
    * by Christian Weber
    *
    *
    *************************************************************************/
   
    // start the session!
    session_start();
    // load the configuration file
    include('inc/config.php');
    // load the database class
    require('core/_database.php');
    // initiate a new db class
    $db = new cdb();
    // gather all configuration informations from the database
    $db->get_config();
    // if gzip is enabled
    if(defined('GZIP') && GZIP) {
        // if zlib is enabled
        if(defined('ZLIB') && ZLIB) {
            // initiate gzip with zlib compression
            ini_set('zlib.output_compression_level', 9);
            ob_start("ob_gzhandler");
        } else {
            // initiate normal gzip
            ob_start();
         }
    }
    // load the smarty class
    require(SMARTY_DIR.'/Smarty.class.php');
    // load the login class
    require('core/_login.php');
    // initiate a new login class
    $login = new clogin($db);
    // load the forum class
    require('core/_forum.php');
    //initiate a new forum class
    $forum = new cforum($db);
    // set the error variable
    $error = '';
    // initiate the smart class
    $smarty = new Smarty();
   
    // if someone tries to login
    if(isset($_POST['login'])) {
        // check if username and password are set
        if($_POST['username'] && $_POST['pass']) {
            // Check if user is logged in
            if(!$login->loggedin()) {
                // he is not logged in so we can check the userdata
                $userid = $login->checkuser($_POST['username'], $_POST['pass']);
                // if userid is set we have a user
                if($userid) {
                    // log the user in
                    $login->login($userid);
                    $_SERVER['QUERY_STRING'] = '';
                } else {
                    // Output error #3 (Unknown user)
                    $smarty->assign('error',3);
                }
            } else {
                // Output error #2 (Already logged in)
                $smarty->assign('error',2);
            }
        } else {
            // Output error #1 (Username and Password need to be set)
            $smarty->assign('error', 1);
        }
    }
   
    // if someone tries to register
    if(isset($_POST['register'])) {
        // check if all important things are set
        if($_POST['username'] && $_POST['pass'] && $_POST['chckpass'] && $_POST['email']) {
            // check if the password is the same as the passwordcheck
            if($_POST['pass'] == $_POST['chckpass']) {
                // check if the registration was successful
                if($login->register($_POST['username'],$_POST['pass'],$_POST['email'],$_POST['firstname'],$_POST['surname'],$_POST['country'],$_POST['location'])) {
                    // Destroy the $_POST array
                    unset($_POST);
                    // Output #7 (Registration successful)
                    $smarty->assign('error',7);
                } else {
                    // Output error #9 (Error during registration)
                    $smarty->assign('error',9);
                }
            } else {
                // Output error #5 (Password is not the same as the passwordcheck)
                $smarty->assign('error',5);
            }
        } else {
            // Output error #4 (Not all required fields entered)
            $smarty->assign('error',4);
        }
    }
   
    // if someone tries to update his profile
    if(isset($_POST['update'])) {
        // you should check all the data here, but thats not part of this tutorial
        if($login->update($_POST['email'], $_POST['firstname'], $_POST['surname'], $_POST['country'], $_POST['location'], $_POST['icq'], $_POST['msn'], $_POST['yahoo'], $_POST['bio'], $_POST['hobbys'], $_POST['occupation'], addslashes($_POST['signature']), $_POST['template'], $_POST['language'])) {
            // Successfully updated, output #12
            $smarty->assign('error',12);
        } else {
            // Problem while updating, output error #11
            $smarty->assign('error',11);
           
        }
    }
   
    // if someone wants to create a new topic
    if(isset($_POST['newtopic'])) {
        // check if he's logged in
        if($login->loggedin()) {
            // he's logged in... add a new topic to the database
            if($forum->addtopic($login->get_ownid(), $_GET['cid'], $_POST['icon'], addslashes($_POST['title']), addslashes($_POST['subtitle']), addslashes($_POST['message']), $_SERVER['REMOTE_ADDR'])) {
                // worked... output #14
                $smarty->assign('error',14);
            } else {
                // something went wrong output error #13
                $smarty->assign('error',13);
            }
        } else {
            // not logged in.. output error #15
            $smarty->assign('error',15);
        }
    }
   
    // if someone wants to add a new post
    if(isset($_POST['newpost'])) {
        // check if he's logged in
        if($login->loggedin()) {
            // he's logged in... add a new post to the database
            if($forum->addpost($_GET['pid'], $_GET['cid'], $login->get_ownid(), $_POST['icon'], addslashes($_POST['title']), addslashes($_POST['subtitle']), addslashes($_POST['message']), $_SERVER['REMOTE_ADDR'])) {
                // worked... output #17
                $smarty->assign('error',17);
            } else {
                // something went wrong  output error #16
                $smarty->assign('error',16);
            }
        } else {
            // not logged in... output error #15
            $smarty->assign('error',15);
        }
    }
       
    // if someone wants to edit his own post
    if(isset($_POST['editpost'])) {
        if($forum->editpost($_POST['id'], addslashes($_POST['title']), addslashes($_POST['subtitle']), $_POST['icon'], addslashes($_POST['message']))) {
            // worked output #19
            $smarty->assign('error',19);
        } else {
            // something went wrong, output error #18
            $smarty->assign('error',18);
        }
    }
   
    // if someone tries to logout
    if(isset($_POST['logout'])) {
        // log him out
        $login->logout();
        // output #10
        $smarty->assign('error',10);
       
    }
   
    // check if the user is logged in
    if($login->loggedin()) {
        // set the smarty variable to true... the user is logged in
        $smarty->assign('loggedin',true);
        // get userdata from own id
        $login->get_user($login->get_ownid());
        // assign the own userdata to a smarty variable
        $smarty->assign('user',$login->userdata);
    }
    // If reg_view is enabled... only registered users can read the forum
    if(defined('REG_VIEW') && REG_VIEW) {
        // reg_view is enabled... set the smarty variable to true
        $smarty->assign('regview', true);
    }
   
    // if no_reg is enabled... nobody can register
    if(defined('NO_REG') && NO_REG) {
        // no_reg is enabled... set the smarty variable to true
        $smarty->assign('noreg', true);
    }
    // get all users that are online
    $login->get_users();
    // define the amount of users in a smarty variable
    $smarty->assign('usercount', count($login->users));
    // give the array of online users to a smarty variable
    $smarty->assign('users', $login->users);
    // check if the user has assigned his own template
    if(isset($login->userdata['template']) && $login->userdata['template'] != '') {
        // assign the users template as template
        $template = $login->userdata['template'];
    } else {
        // assign the default template as template
        $template = template;
    }
    // check if the user has assigned his own language
    if(isset($login->userdata['language']) && $login->userdata['language'] != '') {
        // assign the users language as language
        $lang = $login->userdata['language'];
    } else {
        // assign the default language as language
        $lang = lang;
    }
   
    // Assign the $lang as smarty variable
    $smarty->assign('language', $lang);
    // assign the $template as smarty variable
    $smarty->assign('template', $template);
    // assign the configruation TITLE as smarty variable
    $smarty->assign('page_title', TITLE);
    // assign the configuration SUBTITLE as smarty variable
    $smarty->assign('page_subtitle', SUBTITLE);
    // make lang the default config dir, as there are all language files
    $smarty->config_dir = 'lang/';
   
    // if someone wants to edit his profile
    if(isset($_GET['p']) && $_GET['p'] == 'profile') {
        // get all languages available on this board and assign them as smarty variable
        $smarty->assign('languages',$login->get_languages());
        // get all templates available on this board and assign them as smarty variable
        $smarty->assign('templates', $login->get_templates());
    }
   
    // check if someone wants to view someones user profile
    if(isset($_GET['p']) && $_GET['p'] == 'user') {
        // if userid is also set go on
        if(isset($_GET['uid']) && $_GET['uid']) {
            // try to get a user with this userid
            if($login->get_user($_GET['uid'])) {
                // everyting worked, assign the userdata to a smarty variable
                $smarty->assign('prof',$login->userdata);
            } else {
                // there is no user with this id
                $smarty->assign('noprof',true);
            }
        } else {
            // if not... tell smarty that there is no user like that
            $smarty->assign('noprof',true);
        }
    }
   
    // check if someone wants to see the topics of a category
    if(isset($_GET['p']) && $_GET['p'] == 'cat') {
        // load the topics of the category
        $forum->gettopics($_GET['cid']);
        // assign them to a smarty variable
        $smarty->assign('topics',$forum->topics);
    }
   
    // check if someone wants to see the posts of a topic
    if(isset($_GET['p']) && $_GET['p'] == 'view') {
        // load the posts of a topic
        $forum->getposts($_GET['pid']);
        // add a view to the topic
        $forum->addview($_GET['pid']);
        // assign them to a smarty variable
        $smarty->assign('posts',$forum->posts);
    }
   
    // if nothing is set... the main page will be shown
    if(!isset($_GET['p'])) {
        // so we have to assign the categories to a smarty variable... no need to load them, they are loaded directly as we initieated the class above.
        $smarty->assign('cats', $forum->cats);
    }
       
    // include the template
    include('templates/'.template.'/index.php');
   
   
?>


Template files

This is just as important as the other parts of this tutorial.. in here the discussion board gets actually created. That's why you have also be careful when creating new skins. This will show you a very very basic template with some bugs after w3c, but as it is only a basic template that shouldn't be used in any way it should be ok! :)

index.php (template)

So let's start with the index.php that should be in the main template folder (Example: templates -> standard -> index.php). It's actually the most simple file of the whole discussion board, all it does is to load template files from smarty at the needed positions and also load the right template files when different sites are requested. That's it!


<?php
    // load the standard templates that are always load the same
    $smarty->display($template.'/main/header.tpl');
    $smarty->display($template.'/main/navi.tpl');
    $smarty->display($template.'/user/userbox.tpl');
   
    // load the middle content... check if the p is set ( for other sites like userview etc. )
    if(isset($_GET['p']) && $_GET['p']) {
        // p is set so we will go on and see what page the user requests and then just load the template of the page
        switch($_GET['p']) {
            case 'register': $smarty->display($template.'/user/register.tpl'); break;
            case 'profile': $smarty->display($template.'/user/profile.tpl'); break;
            case 'user': $smarty->display($template.'/user/user.tpl'); break;
            case 'cat': $smarty->display($template.'/topics/view.tpl'); break;
            case 'view': $smarty->display($template.'/posts/view.tpl'); break;
            default:    $smarty->display($template.'/main/content.tpl'); break;
        }
    } else {
        // if p is not set, load the standard content template
        $smarty->display($template.'/main/content.tpl');
    }
   
    // load the standard templates that are always load the same
    $smarty->display($template.'/main/stats.tpl');
   
    $smarty->display($template.'/main/footer.tpl');
?>


header.tpl

The header file is also very simple, it's just the doctype of the file and in my template also the header of the page that is always the same.

Smarty template files: Comments are noted with {* COMMENT *}

Just a small note
Also {$topic.name} would be name of the array topic that we defined via php to smarty. And {#topic#} would be replaced with whatever topic is in the language file.


{* Loads the language file at the section of head *}
{config_load file="$language/main.conf" section="head"}
<!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>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
<title>{$page_title} - {$page_subtitle}</title>
<link rel="stylesheet" type="text/css" href="templates/{$template}/style.css" />
</head>
<body>
<div id="header">
    <div>
        <h2>{$page_title}</h2>
        <p>{$page_subtitle}</p>
    </div>
</div>



navi.tpl

In this file you can make your own navigation bar... and also parts that only registered users are able to see... for example profile and logout button!


{* Load up the language file at the navi section *}
{config_load file="$language/main.conf" section="navi"}
<div id="tabs">
  <ul>
    <li><a href="index.php" title="{#home#}"><span>{#home#}</span></a></li>
    {* If user is logged in, let him see also profile and logout tab button *}
    {if isset($loggedin)}
        <li><a href="index.php?p=profile" title="{#profile#}"><span>{#profile#}</span></a></li>
        <li><form name="logout" method="post" action="{$smarty.server.PHP_SELF}"><input type='hidden' name='logout' value='1' /><a href="#" onclick="logout.submit();" title="{#logout#}"><span>{#logout#}</span></a></form></li>
    {/if}
  </ul>
</div>


userbox.tpl

The userbox greets the user with his username or tells him where to register / login.


{* load up the language file at section userbox *}
{config_load file="$language/main.conf" section="userbox"}
<div id='userbox'>
    <div id='userbox_head'>
        {* if user is logged in, set header to logged in or to not logged in *}
        {if isset($loggedin)}
            {#loggedin#}
        {else}
            {#notloggedin#}
        {/if}
    </div>
    <div id='userbox_content'>
        {* if user is logged in greet him with his username...  *}
        {if isset($loggedin)}
            {#welcome#} {$user.username}!
        {else}
            {* else tell him where to register or where to login... (this checks if u have user registration activated) *}
            {if !isset($noreg)}
                {#register#}
            {else}
                {#login#}
            {/if}
        {/if}
    </div>
</div>



content.tpl

In the content.tpl one of your possible configuration gets active... you can choose if you want to have it a private board or not... if yes only registered members can view the board. In this file the main categories and its subcategories will be outputted.


{* load up language file at the section for content *}
{config_load file="$language/main.conf" section="content"}
<div style='margin: 20px 50px 2px 50px;'>
    {* create the backlink *}
    <a href='{$smarty.server.PHP_SELF}'>{#Root#}</a>
</div>
<div id='contentbox'>
    {* checks if non-registered users are able to view the board *}
    {if isset($loggedin) || !isset($regview)}
        <table border="0" cellspacing="0" cellpadding="0" style="width:100%;" class="forum">
        {* loop for main cats... give them all out :) *}
        {foreach from=$cats item='cats'}
            <tr>
            <td colspan="4" class="forum_main_title">
            {$cats.name}
            </td>
            </tr>
            <tr>
            <td></td>
            <td class="forum_main_head">{#categoryname#}</td>
            <td class="forum_main_head" align="center">{#posts#}</td>
            <td class="forum_main_head" align="center">{#topics#}</td>
            </tr>
            {* loop for subcats of main cats *}
            {foreach from=$cats.subcats item='subcat'}
                <tr class="forum_subcat">
                <td></td>
                <td class="forum_sub_title" width="60%"><a href="{$smarty.server.PHP_SELF}?p=cat&cid={$subcat.id}" class="link" >{$subcat.name}</a></td>
                <td class="forum_sub_count" width="20%" rowspan="2">{$subcat.posts}</td>
                <td class="forum_sub_count" width="20%" rowspan="2">{$subcat.topics}</td>
                </tr>
                <tr>
                <td></td>
                <td class="forum_sub_text">
                {$subcat.desc}
                </td>
                </tr>
                <tr><td colspan="4" class="forum_spacer" height="10px"></td></tr>
            {/foreach}
        {/foreach}
       
        </table>
    {else}
        {* tell the user that this is not a public board *}
        <div class='notice'>
            {#notpublic#}
        </div>
    {/if}
</div>


stats.tpl

This file just tells the user how many users are online at the moment and who is online + the users userlevel.


{* load up language file at statistics section *}
{config_load file="$language/main.conf" section="statistics"}
<div id='statistics'>
    {* tell the user in his language how many users are online at the moment *}
    {#users#} {$usercount} {#online#}<br />
    <strong>{#usersonline#}</strong><br />
    {* check if there are users online *}
    {if $users}
        {* output every single user with a specific color for his userlvl (Normal, Moderator, Super Moderator and Administrator) *}
        {foreach from=$users item='user'}
            <a href='{$smarty.server.PHP_SELF}?p=user&uid={$user.id}' title='{$user.user}'>
            {if $user.lvl eq 0}
                <span style='font-weight:bold;'>
            {elseif $user.lvl eq 1}
                <span style='font-weight:bold; font-style:italic; color:#FFCC33;'>
            {elseif $user.lvl eq 2}
                <span style='font-weight:bold;color:#CC0000;'>
            {elseif $user.lvl eq 3}
                <span style='font-weight:bold;color:#CC0000;font-style:italic;'>
            {/if}
            {$user.user}</span></a>
        {/foreach}
    {else}
        {* tell the user that there are no users online *}
        {#nousers#}
    {/if}
</div>



footer.tpl

The footer is really nothing special... also no comments in there... simple html


<div id='footer'>
    Copyright 2007 by Christian Weber<br />
    All Rights Reserved
</div>
</body>
</html>


register.tpl

In the register.tpl the user has the possibility to login or register if he isn't logged in already. If registrations are not allowed the register form won't be shown. This is another thing you can configure in this board.


{* load the language file at the register section *}
{config_load file="$language/main.conf" section="register"}
<div id='contentbox'>
    {* if there is a message... give out the site specific error possibilites and give the right one out *}
    {if $error}
        <div class='notice'>
            {if $error eq 1}
                {#error1#}
            {elseif $error eq 2}
                {#error2#}
            {elseif $error eq 3}
                {#error3#}
            {elseif $error eq 4}
                {#error4#}
            {elseif $error eq 5}
                {#error5#}
            {elseif $error eq 6}
                {#error6#}
            {elseif $error eq 7}
                {#error7#}
            {elseif $error eq 8}
                {#error8#}
            {elseif $error eq 9}
                {#error9#}
            {/if}
        </div>
    {/if}
    {* check if user is logged in or not *}
    {if !isset($loggedin)}
        {* not logged in... let him login using the login form *}
        <fieldset>
            <legend>{#login#}</legend>
            <div style='width:200px;margin: 2px auto;'>
                <form name='login' method='post' action='{$smarty.server.PHP_SELF}?p=register'>
                    <strong>{#username#}</strong><br />
                    <input type='text' name='username' style="width:100%;" /><br />
                    <strong>{#password#}</strong><br />
                    <input type='password' name='pass' style="width:100%;" /><br />
                    <input type='submit' class='button' name='login' value='{#login#}' />
                </form>
            </div>
        </fieldset>
        {* check if users are allowed to register *}
        {if !isset($noreg)}
            {* allowed to register... show him the register form *}
        <fieldset>
            <legend>{#register#}</legend>
                <form name='register' method='post' action='{$smarty.server.PHP_SELF}?p=register'>
                    <div style='float:left;width:45%;'>
                        <div style='margin: 2px; padding: 2px; height:15px;'>
                            {#username#}*
                        </div>
                        <div style='margin: 2px; padding: 2px; height:15px;'>
                            {#password#}*
                        </div>
                        <div style='margin: 2px; padding: 2px; height:15px;'>
                            {#chckpassword#}*
                        </div>
                        <div style='margin: 2px; padding: 2px; height:15px;'>
                            {#email#}*
                        </div>
                        <div style='margin: 2px; padding: 2px; height:15px;'>
                            {#firstname#}
                        </div>
                        <div style='margin: 2px; padding: 2px; height:15px;'>
                            {#surname#}
                        </div>
                        <div style='margin: 2px; padding: 2px; height:15px;'>
                            {#country#}
                        </div>
                        <div style='margin: 2px; padding: 2px; height:15px;'>
                            {#location#}
                        </div>
                    </div>
                   
                    <div style='float:right;text-align:left;width:45%;'>
                        <div style='margin: 2px; padding: 2px; height:15px;'>
                            <input type='text' name='username' value='{$smarty.post.username}' />
                        </div>
                        <div style='margin: 2px; padding: 2px; height:15px;'>
                            <input type='password' name='pass' />
                        </div>
                        <div style='margin: 2px; padding: 2px; height:15px;'>
                            <input type='password' name='chckpass' />
                        </div>
                        <div style='margin: 2px; padding: 2px; height:15px;'>
                            <input type='text' name='email' value='{$smarty.post.email}' />
                        </div>
                        <div style='margin: 2px; padding: 2px; height:15px;'>
                            <input type='text' name='firstname' value='{$smarty.post.firstname}' />
                        </div>
                        <div style='margin: 2px; padding: 2px; height:15px;'>
                            <input type='text' name='surname' value='{$smarty.post.surname}' />
                        </div>
                        <div style='margin: 2px; padding: 2px; height:15px;'>
                            <input type='text' name='country' value='{$smarty.post.country}' />
                        </div>
                        <div style='margin: 2px; padding: 2px; height:15px;'>
                            <input type='text' name='location' value='{$smarty.post.location}' />
                        </div>
                    </div>
                    <div class='cleardiv'></div>
                    <input type='submit' name="register" value="{#register#}" class='button' />
                </form>
        </fieldset>
        {/if}
    {else}
        {* tell the user that he's already logged in *}
        <div style='font-weight:bold;text-align:center;'>{#loggedin#}</div>
    {/if}
</div>


profile.tpl

In this file the user has the possibility to change all of his profile data... including board language, template and his signature.


{* load the language file at the profile section *}
{config_load file="$language/main.conf" section="profile"}
<div id='contentbox'>
    {* if there is a message... give out the site specific error possibilites and give the right one out *}
    {if $error}
        <div class='notice'>
            {if $error eq 11}
                {#error11#}
            {elseif $error eq 12}
                {#error12#}
            {/if}
        </div>
    {/if}
    <fieldset>
        {* show the user the profile update form *}
        <legend>{#profupdate#}</legend>
                <form name='update' method='post' action='{$smarty.server.PHP_SELF}?p=profile'>
                    <strong>{#firstname#}</strong><br />
                    <input type='text' name='firstname' style="width:100%;" value='{$user.firstname}' /><br />
                    <strong>{#surname#}</strong><br />
                    <input type='text' name='surname' style="width:100%;" value='{$user.surname}' /><br />
                    <strong>{#email#}</strong><br />
                    <input type='text' name='email' style="width:100%;" value='{$user.email}' /><br />
                    <strong>{#country#}</strong><br />
                    <input type='text' name='country' style="width:100%;" value='{$user.country}' /><br />
                    <strong>{#location#}</strong><br />
                    <input type='text' name='location' style="width:100%;" value='{$user.location}' /><br />
                    <strong>{#icq#}</strong><br />
                    <input type='text' name='icq' style="width:100%;" value='{$user.icq}' /><br />
                    <strong>{#msn#}</strong><br />
                    <input type='text' name='msn' style="width:100%;" value='{$user.msn}' /><br />
                    <strong>{#yahoo#}</strong><br />
                    <input type='text' name='yahoo' style="width:100%;" value='{$user.yahoo}' /><br />
                    <strong>{#occupation#}</strong><br />
                    <input type='text' name='occupation' style="width:100%;" value='{$user.occupation}' /><br />
                    <strong>{#bio#}</strong><br />
                    <textarea name='bio' style='width:100%;'>{$user.bio}</textarea><br />
                    <strong>{#hobbys#}</strong><br />
                    <textarea name='hobbys' style='width:100%;'>{$user.hobby}</textarea><br />
                    <strong>{#language#}</strong><br />
                        <select name='language'>
                            {* read out all possible languages *}
                            {foreach from=$languages item='lang'}
                                {* if users language is the current language... mark it as selected *}
                                {if $lang.name == $user.language}
                                    <option value="{$lang.id}" selected="selected">{$lang.name}</option>
                                {else}
                                    <option value="{$lang.id}">{$lang.name}</option>
                                {/if}
                            {/foreach}
                        </select><br />
                    <strong>{#template#}</strong><br />
                        <select name='template'>
                            {* read out all possible templates *}
                            {foreach from=$templates item='temp'}
                                {* if users template is the current template... mark it as selected *}
                                {if $temp.name == $user.template}
                                    <option value="{$temp.id}" selected="selected">{$temp.name}</option>
                                {else}
                                    <option value="{$temp.id}">{$temp.name}</option>
                                {/if}
                            {/foreach}
                        </select><br />
                    <strong>{#signature#}</strong><br />
                    <textarea name='signature' style='width:100%;'>{$user.signature}</textarea><br />
                    <input type='submit' class='button' name='update' value='{#update#}' />
                </form>
    </fieldset>
</div>


user.tpl

This file outputs the user information of a specific user

{* load the language file at the register section *}
{config_load file="$language/main.conf" section="profile"}
<div id='contentbox'>
    {* if there is no profile like this, tell user... *}
    {if isset($noprof)}
        <center><h2>{#nouser#}</h2></center>
    {else}
        {* give out all the userinformation *}
        <h2>{#prof#} {$prof.username}</h2>
        <center><img src='images/avatars/{$prof.avatar}' title="{$prof.username}" alt="{$prof.username}s avatar" /></center><br />
        <strong>{#firstname#}</strong><br />
        {$prof.firstname}<br />
        <strong>{#surname#}</strong><br />
        {$prof.surname}<br />
        <strong>{#email#}</strong><br />
        {$prof.email}<br />
        <strong>{#country#}</strong><br />
        {$prof.country}<br />
        <strong>{#location#}</strong><br />
        {$prof.location}<br />
        <strong>{#icq#}</strong><br />
        {$prof.icq}<br />
        <strong>{#msn#}</strong><br />
        {$prof.msn}<br />
        <strong>{#yahoo#}</strong><br />
        {$prof.yahoo}<br />
        <strong>{#occupation#}</strong><br />
        {$prof.occupation}<br />
        <strong>{#bio#}</strong><br />
        {$prof.bio}<br />
        <strong>{#hobbys#}</strong><br />
        {$prof.hobby}
    {/if}
</div>


view.tpl(topics)

This file will give out all the topics of a category and also lets users add new topics via a small form. You will be able to see some standard things like topic name, views, posts and last posting.


{* load the language file at the register section *}
{config_load file="$language/main.conf" section="content"}
<div style='margin: 20px 50px 2px 50px;'>
    <a href='{$smarty.server.PHP_SELF}'>{#Root#}</a>
</div>
<div id='contentbox'>
    {* if there is a message... give out the site specific error possibilites and give the right one out *}
    {if $error}
        <div class='notice'>
            {if $error eq 13}
                {#error13#}
            {elseif $error eq 14}
                {#error14#}
            {elseif $error eq 15}
                {#error15#}
            {/if}
        </div>
    {/if}
    {* start creating the topic list *}
    <table border="0" cellspacing="1" cellpadding="1" style="width:100%;" class="forum">
    <tr>
    <td class="forum_main_title" align="center" width="5%"></td>
    <td class="forum_main_title" align="center" width="70%">{#topicname#}</td>
    <td class="forum_main_title" align="center" width="5%">{#posts#}</td>
    <td class="forum_main_title" align="center" width="5%">{#views#}</td>
    <td class="forum_main_title" align="center" width="15%">{#lastanswer#}</td>
    </tr>
    {* check if there are any topics *}
    {if count($topics) > 0}
        {* there are topics, start with giving each one out in a new single row *}
        {foreach from=$topics item='topic'}
            <tr class="forum_cat">
            <td align="center" valign="middle"><img src="images/icons/{$topic.icon}.gif"  /></td>
            <td ><a href="{$smarty.server.PHP_SELF}?p=view&pid={$topic.id}&cid={$smarty.get.cid}" class="link" title="{$topic.title}">{$topic.title}</a><br /><span style="font-size: 12px; font-weight:normal; font-style: italic;">{$topic.subtitle}</span>
            <br />von <a href="{$smarty.server.PHP_SELF}?p=user&uid={$topic.userid}" class="link_user" title="{$topic.user}">{$topic.user}</a></td>
            <td align="center">{$topic.posts}</td>
            <td align="center">{$topic.views}</td>
            {* check for the last reply on this topic *}
            {if count($topic.latest.userid) > 0}
            {* give the last reply out *}
            <td align="center">{#writtenon#} {$topic.latest.date|date_format:"%d.%m.%Y %H:%M"} {#by#} <a href="{$smarty.server.PHP_SELF}?p=user&uid={$topic.latest.userid}" class="link_user" title="{$topic.latest.username}">{$topic.latest.username}</a></td>
            {else}
            {* nobody replied to this topic yet *}
            <td align="center">{#nobody#}</td>
            {/if}
            </tr>
        {/foreach}
    {else}
    {* no topics in here *}
        <tr>
        <td colspan="4" align="center"><strong>{#notopics#}!</strong></td>
        </tr>
    {/if}
   
    </table>
    {* form to add a new topic *}
    <br />
    <div><h3>{#newtopic#}:</h3></div>
    <hr style="border:none; border-top: 1px solid #4A4776; width:50%;" align="left" />
    <br />
    <form name="newtopic" method="post" action="{$smarty.server.PHP_SELF}?{$smarty.server.QUERY_STRING}">
    <strong>{#title#}:</strong><br />
    <input type="text" name="title" size="50" class="input" /><br />
    <strong>{#subtitle#}:</strong><br />
    <input type="text" name="subtitle" size="100" class="input" /><br />
    <strong>{#symbols#}:</strong><br />
    <input type="radio" name="icon" value="0" checked="checked" /><img src="images/icons/0.gif" width="24px" height="24px" />
    <input type="radio" name="icon" value="1" /><img src="images/icons/1.gif" width="24px" height="24px" />
    <input type="radio" name="icon" value="2" /><img src="images/icons/2.gif" width="24px" height="24px" />
    <input type="radio" name="icon" value="3" /><img src="images/icons/3.gif" width="24px" height="24px" />
    <input type="radio" name="icon" value="4" /><img src="images/icons/4.gif" width="24px" height="24px" />
    <input type="radio" name="icon" value="5" /><img src="images/icons/5.gif" width="24px" height="24px" />
    <input type="radio" name="icon" value="6" /><img src="images/icons/6.gif" width="24px" height="24px" /><br />
    <input type="radio" name="icon" value="7" /><img src="images/icons/7.gif" width="24px" height="24px" />
    <input type="radio" name="icon" value="8" /><img src="images/icons/8.gif" width="24px" height="24px" />
    <input type="radio" name="icon" value="9" /><img src="images/icons/9.gif" width="24px" height="24px" />
    <input type="radio" name="icon" value="10" /><img src="images/icons/10.gif" width="24px" height="24px" />
    <input type="radio" name="icon" value="11" /><img src="images/icons/11.gif" width="24px" height="24px" /><br />
    <strong>{#message#}:</strong><br />
    <textarea name="message" class="textbox" style="width:100%; height:150px;"></textarea><br />
    <input type="submit" name="newtopic" class="button" value="{#createtopic#}" style="width:100%;"/>
    </form>
   
</div>


view.tpl(posts)

This file will give out all the posts of a topic and also lets users add new posts via a small form. You can also edit your own posts and quote other posts. bbcode is allowed.


{* load the language file at the register section *}
{config_load file="$language/main.conf" section="content"}
<div style='margin: 20px 50px 2px 50px;'>
    {* backlink to the topics *}
    <a href='{$smarty.server.PHP_SELF}?p=cat&cid={$smarty.get.cid}'>{#topicview#}</a>
</div>
<div id='contentbox'>
    {* if there is a message... give out the site specific error possibilites and give the right one out *}
    {if $error}
        <div class='notice'>
            {if $error eq 15}
                {#error15#}
            {elseif $error eq 16}
                {#error16#}
            {elseif $error eq 17}
                {#error17#}
            {elseif $error eq 18}
                {#error18#}
            {elseif $error eq 19}
                {#error19#}
            {/if}
        </div>
    {/if}
   
    <table border="0" cellspacing="0" cellpadding="1" style="width:100%;" id="forum">
    {* check if there are any postings in this topics *}
    {if count($posts) > 0}   
        {* there are posts in this topic... start with output *}
        {foreach from=$posts item='post'}

            <tr >
                <td width="20%" style='{cycle values="background-color: #CCDDFF;,background-color: #FFFF99;"}' align="center">{#writtenon#}: {$post.date|date_format:"%d.%m.%Y %H:%M"}</td>
                <td width="80%" style='{cycle values="background-color: #CCDDFF; border-left: 1px solid #EEEEEE;,background-color: #FFFF99; border-left: 1px solid #AAAAAA;"}' >
                    <span style="font-weight:bold; font-size: 1.2em;"><img src="images/icons/{$post.icon}.gif"  width="24px" height="24px" /> {$post.title}</span><br />
                    <span style="font-weight:normal; font-style:italic; font-size: 12px;">{$post.subtitle}</span>
                </td>
            </tr>
            <tr>
                <td align="center" valign="top">
                <br />
                {* if user doesn't have an avatar, give him the standard *}
                {if $post.thumb eq ''}
                    <img src="images/avatars/0.gif" class"avatar" /><br />
                {else}
                {* ouput user avatar *}
                    <img src="images/avatars/{$post.thumb}" class="avatar" /><br />
                {/if}
                {* link to users profile *}
                {#username#}: <a href="{$smarty.server.PHP_SELF}?p=user&uid={$post.userid}" class="link_user" title="{$post.username}">{$post.username}</a><br />
                 {#posts#}: {$post.posts}<br />
                </td>
                <td style="border-left: 1px solid #CCCCCC; padding: 10px;" valign="top">
                {* message with bbcode *}
                {$post.bbmessage}
               
                {* check if the user has a signature *}
                {if $post.signature}
                    {* give the signature out, but cut it off from the message using a break line *}
                    <hr style="border:none; border-top: 1px solid #4A4776; width:50%;" align="left" />
                    {$post.signature}
                {/if}            
                </td>
            </tr>
            <tr>
                <td></td>
                <td align="right" style="border-left: 1px solid #CCCCCC;" valign="middle">
                    {* if users id is the current posting id... then this post is from the user and he can edit it *}
                    {if $user.id eq $post.userid}
                    <form name="edit{$post.postid}" method="post" style="display:inline;" action="{$smarty.server.PHP_SELF}?{$smarty.server.QUERY_STRING}#edit">
                    <input type="hidden" name="title" value="{$post.title}" />
                    <input type="hidden" name="subtitle" value="{$post.subtitle}" />
                    <input type="hidden" name="icon" value="{$post.icon}" />
                    <input type="hidden" name="id" value="{$post.postid}" />
                    <input type="hidden" name="message" value="{$post.message}" />
                    <input type="hidden" name="edit" value="1" />
                    <a href="javascript:document.edit{$post.postid}.submit()"><img src="images/ficons/edit.gif" alt="EDIT" /></a>
                    </form>
   
                    {/if}
                    {* small form for quoting *}
                    <form name="quote{$post.postid}" method="post" style="display:inline;" action="{$smarty.server.PHP_SELF}?{$smarty.server.QUERY_STRING}#neu">
                    <input type="hidden" name="user" value="{$post.username}" />
                    <input type="hidden" name="message" value="{$post.message}" />
                    <input type="hidden" name="quote" value="1" />
                    <a href="javascript:document.quote{$post.postid}.submit()"><img src="images/ficons/quote.gif" alt="QUOTE" /></a>
                    </form>
                </td>
            </tr>
            <tr>
                <td colspan="2" style="background-color: #CCCCCC; height: 10px;"></td>
            </tr>
            {/foreach}
        {else}
        {* no posts to this topic... dead topic? not a valid topic? *}
        <tr>
        <td colspan="4" align="center"><strong>{#noposts#}!</strong></td>
        </tr>
        {/if}
    </table>
    {* check if user wants to edit a post *}
    {if isset($smarty.post.edit)}
        {* show post form with post defined input fields *}
        <br />
        <a name="edit"><div id="userhead"><h3>{#editpost#}:</h3></div></a>
        <hr style="border:none; border-top: 1px solid #4A4776; width:50%;" align="left" />
        <br />
        <form name="newpost" method="post" action="{$smarty.server.PHP_SELF}?{$smarty.server.QUERY_STRING}">
        <strong>{#title#}:</strong><br />
        <input type="text" name="title" size="50" class="input" value="{$smarty.post.title}" /><br />
        <strong>{#subtitle#}:</strong><br />
        <input type="text" name="subtitle" size="100" class="input" value="{$smarty.post.subtitle}" /><br />
        <strong>{#symbols#}:</strong><br />
        <input type="radio" name="icon" value="0" {if $smarty.post.icon eq '0'} checked='checked' {/if} /><img src="images/icons/0.gif" width="24px" height="24px" />
        <input type="radio" name="icon" value="1" {if $smarty.post.icon eq '1'} checked='checked' {/if} /><img src="images/icons/1.gif" width="24px" height="24px" />
        <input type="radio" name="icon" value="2" {if $smarty.post.icon eq '2'} checked='checked' {/if} /><img src="images/icons/2.gif" width="24px" height="24px" />
        <input type="radio" name="icon" value="3" {if $smarty.post.icon eq '3'} checked='checked' {/if} /><img src="images/icons/3.gif" width="24px" height="24px" />
        <input type="radio" name="icon" value="4" {if $smarty.post.icon eq '4'} checked='checked' {/if} /><img src="images/icons/4.gif" width="24px" height="24px" />
        <input type="radio" name="icon" value="5" {if $smarty.post.icon eq '5'} checked='checked' {/if} /><img src="images/icons/5.gif" width="24px" height="24px" />
        <input type="radio" name="icon" value="6" {if $smarty.post.icon eq '6'} checked='checked' {/if} /><img src="images/icons/6.gif" width="24px" height="24px" /><br />
        <input type="radio" name="icon" value="7" {if $smarty.post.icon eq '7'} checked='checked' {/if} /><img src="images/icons/7.gif" width="24px" height="24px" />
        <input type="radio" name="icon" value="8" {if $smarty.post.icon eq '8'} checked='checked' {/if} /><img src="images/icons/8.gif" width="24px" height="24px" />
        <input type="radio" name="icon" value="9" {if $smarty.post.icon eq '9'} checked='checked' {/if} /><img src="images/icons/9.gif" width="24px" height="24px" />
        <input type="radio" name="icon" value="10" {if $smarty.post.icon eq '10'} checked='checked' {/if} /><img src="images/icons/10.gif" width="24px" height="24px" />
        <input type="radio" name="icon" value="11" {if $smarty.post.icon eq '11'} checked='checked' {/if} /><img src="images/icons/11.gif" width="24px" height="24px" /><br />
        <strong>{#message#}:</strong><br />
        <textarea name="message" class="textbox" style="width:100%; height:150px;">{$smarty.post.message}</textarea><br />
        <input type="hidden" name="id" value="{$smarty.post.id}" />
        <input type="submit" name="editpost" class="button" value="{#editpost#}" style="width:100%;"/>
        </form>
   
    {else}
    <br />
    {* show post form for new postings *}
    <a name="neu"><div id="userhead">{#newpost#}:</div></a>
    <hr style="border:none; border-top: 1px solid #4A4776; width:50%;" align="left" />
    <br />
    <form name="newpost" method="post" action="{$smarty.server.PHP_SELF}?{$smarty.server.QUERY_STRING}">
    <strong>{#title#}:</strong><br />
    <input type="text" name="title" size="50" class="input" value="{$posts.0.title}" /><br />
    <strong>{#subtitle#}:</strong><br />
    <input type="text" name="subtitle" size="100" class="input" value="{$posts.0.subtitle}" /><br />
    <strong>{#symbols#}:</strong><br />
    <input type="radio" name="icon" value="0" checked="checked" /><img src="images/icons/0.gif" width="24px" height="24px" />
    <input type="radio" name="icon" value="1" /><img src="images/icons/1.gif" width="24px" height="24px" />
    <input type="radio" name="icon" value="2" /><img src="images/icons/2.gif" width="24px" height="24px" />
    <input type="radio" name="icon" value="3" /><img src="images/icons/3.gif" width="24px" height="24px" />
    <input type="radio" name="icon" value="4" /><img src="images/icons/4.gif" width="24px" height="24px" />
    <input type="radio" name="icon" value="5" /><img src="images/icons/5.gif" width="24px" height="24px" />
    <input type="radio" name="icon" value="6" /><img src="images/icons/6.gif" width="24px" height="24px" /><br />
    <input type="radio" name="icon" value="7" /><img src="images/icons/7.gif" width="24px" height="24px" />
    <input type="radio" name="icon" value="8" /><img src="images/icons/8.gif" width="24px" height="24px" />
    <input type="radio" name="icon" value="9" /><img src="images/icons/9.gif" width="24px" height="24px" />
    <input type="radio" name="icon" value="10" /><img src="images/icons/10.gif" width="24px" height="24px" />
    <input type="radio" name="icon" value="11" /><img src="images/icons/11.gif" width="24px" height="24px" /><br />
    <strong>{#message#}:</strong><br />
    {* if the user wants to quote, it will just be added in the message box. it's just bbcode that will be added. nothing special *}
    <textarea name="message" class="textbox" style="width:100%; height:150px;">{if isset($smarty.post.quote)} Written by {$smarty.post.user}<br />[quote]{$smarty.post.message}[/quote] {/if}</textarea><br />
    <input type="submit" name="newpost" class="button" value="{#newpost#}" style="width:100%;"/>
    </form>
   
    {/if}
</div>


style.css

This is just the basic css class found in the template folder.


/* CSS Document */

body {
    background: url('images/stripe.png') top left repeat;
    margin: 0 0 0 0;
    padding: 0 0 0 0;
    font-family:Verdana, Arial, Helvetica, sans-serif;
    font-size:12px;
}

img { border: 0px; }

a, a:visited {
    color: #2763A5;
    text-decoration:none;
}

a:hover, a:active, a:focus {
    color:#CC0000;
    text-decoration:none;
}

input {
    border:1px solid #CCCCCC;
    color:#CCCCCC;
}

input:hover, input:active, input:focus {
    border:1px solid #2763A5;
    color:#2763A5;
}

#header {
    width: 100%;
    height:120px;
    background: url('images/header.jpg') top left repeat-x;
    border-bottom: 5px solid #2e42bd;
}

#footer {
    margin: 10px 50px;
    background-color:#FFFFFF;
    border: 1px solid #CCCCCC;
    font-weight:bold;
    padding: 2px;
    text-align:center;
}

#statistics {
    margin: 10px 50px;
    background-color:#FFFFFF;
    border: 1px solid #CCCCCC;
    padding: 5px;
}

#header div {
    padding: 10px;
    color:#FFFFFF;
    font-weight:bold;
    background: url('images/logo.jpg') top left no-repeat;
    height:100%;
}

#header h2 {
    margin-bottom: 0px;
    padding-bottom: 0px;
    text-indent:135px;
    font-size:22px;
}

#header p {
    margin-top: 0px;
    padding-top: 0px;
    text-indent:135px;
}

/*- Menu Tabs --------------------------- */

    #tabs {
      float:left;
      width:100%;
      font-size:93%;
      border-bottom:1px solid #2763A5;
      line-height:normal;
      background: url('images/navi/bg.jpg') top left repeat-x;
      }
    #tabs ul {
      margin:0;
      padding:10px 10px 0 50px;
      list-style:none;
      }
    #tabs li {
      display:inline;
      margin:0;
      padding:0;
      }
    #tabs a {
      float:left;
      background:url("images/navi/tableft.gif") no-repeat left top;
      margin:0;
      padding:0 0 0 4px;
      text-decoration:none;
      }
    #tabs a span {
      float:left;
      display:block;
      background:url("images/navi/tabright.gif") no-repeat right top;
      padding:5px 15px 4px 6px;
      color:#FFF;
      }
    /* Commented Backslash Hack hides rule from IE5-Mac */
    #tabs a span {float:none;}
    /* End IE5-Mac hack */
    #tabs a:hover span {
      color:#FFF;
      }
    #tabs a:hover {
      background-position:0% -42px;
      }
    #tabs a:hover span {
      background-position:100% -42px;
      }

#userbox {
    width: 650px;
    border: 1px solid #CCCCCC;
    margin: 50px auto 20px auto;
    background-color: #FFFFFF;
}

#userbox_head {
    color: white;
    font-weight:bold;
    background-color: #2763A5;
    border-bottom: 1px solid #CCCCCC;
    text-indent: 10px;
    padding: 2px;
}

#userbox_content {
    padding: 5px;
}

#contentbox {
    margin: 0px 50px 20px 50px;
    padding: 5px;
    background-color:#FFFFFF;
    border: 1px solid #CCCCCC;
}

.notice {
    background: #fff6bf url('images/icons/important.png') center no-repeat;
    background-position: 15px 50%; /* x-pos y-pos */
    text-align: left;
    padding: 5px 20px 5px 45px;
    border-top: 2px solid #ffd324;
    border-bottom: 2px solid #ffd324;
    margin: 2px 0px;
}

/* Forum style */

.forum_main_head {
    border: 1px solid #4A4776;
    background-color:#2763A5;
    color:#FFFFFF;
    font-weight:bold;
    padding: 2px;
    margin-bottom: 5px;
}

.forum_cat, #forum_cat:visited {
    margin: 2px;
    border: 1px solid #4A4776;
    background-color: #CCDDFF;
    font-weight: bold;
    padding-left: 5px;
}

.forum_cat:hover, #forum_cat:active {
    margin: 2px;
    border: 1px solid #FFCC00;
    background-color: #FFFF99;
    font-weight: bold;
    padding-left: 5px;
}

.forum_main_title {
    border: 1px solid #999999;
    background-color:#CCCCCC;
    font-weight: bold;
}

.forum_sub_title {
    font-weight: bold;
    padding: 5px;
    border-left: 1px solid #EEEEEE;
}

.forum_sub_count {
    text-align: center;
    font-weight: bold;
    border: 1px solid #EEEEEE;
}

.forum_sub_text {
    padding: 10px;
    border: 1px solid #EEEEEE;
    border-right: 0px;
}

.forum {
    border: 1px solid #DDDDDD;
    margin: 2px;
    padding: 1px;
}

.forum_spacer {
    background-color: #EEEEEE;
}

.forum_subcat {
    border: 1px solid #CCCCCC;
}


.button {
    border: 1px solid #2763A5;
    background-color: #DDEEFF;
    padding: 2px;
    margin: 2px;
    width:100%;
    font-weight:bold;
    color:#2763A5;
}

.quote {
    border: 1px solid #2763A5;
    background-color:#DDFFFF;
    padding: 4px;
}

.cleardiv {
    clear:both;
}



Now let's just add 2 more files... german and english language file :)

main.conf (de)

This file has to be put in lang->de->main.conf.


# global variables
error1 = "Benutzername UND Passwort eingeben!"
error2 = "Sie sind bereits eingeloggt!"
error3 = "Benutzername und/oder Passwort falsch!"
error4 = "Alle mit * gekennzeichneten Felder ausf&uuml;fllen!"
error5 = "Passw&ouml;rter stimmen nicht &uuml;berein!"
error6 = "Keine g&uuml;ltige Email!"
error7 = "Erfolgreich registriert! Sie k&ouml;nnen sich nun einloggen!"
error8 = "Erfolgreich registriert! Bitte &uuml;berpr&uuml;fen sie Ihre Email!"
error9 = "Fehler beim registrieren, bitte kontaktieren sie den Administrator!"
error10 = "Erfolgreich ausgeloggt!"
error11 = "Fehler beim update, bitte versuchen sie es sp&auml;ter noch einmal!"
error12 = "Erfolgreich upgedatet!"
error13 = "Thema konnte nicht erstellt werden!"
error14 = "Thema erfolgreich erstellt!"
error15 = "Sie sind nicht eingeloggt!"
error16 = "Konnte Beitrag nicht erstellen!"
error17 = "Beitrag erfolgreich erstellt!"
error18 = "Konnte Beitrag nicht bearbeiten!"
error19 = "Beitrag erfolgreich bearbeitet!"

[content]
Root = "Kategorie&uuml;bersicht"
categoryname = "Kategoriename"
posts = "Beitr&auml;ge"
topics = "Themen"
topicname = "Themenname"
views = "Angesehen"
lastanswer = "Letzte Antwort"
notopics = "Keine Beitr&auml;ge gefunden"
nobody = "Noch niemand"
writtenon = "geschrieben am"
by = "von"
newtopic = "Neues Thema"
createtopic = "Thema erstellen"
title = "Titel"
subtitle = "Untertitel"
symbols = "Symbol"
message = "Nachricht"
topicview = "Zur&uuml;ck zu den Themen"
username = "Benutzername"
noposts = "Keine Beitr&auml;ge."
editpost = "Beitrag bearbeiten"
newpost = "Beitrag erstellen"
notpublic = "Nicht &ouml;ffentlich!"

[userbox]
loggedin = "Eingeloggt"
notloggedin = "Nicht eingeloggt"
welcome = "Willkommen"
login = "Nicht eingeloggt, bitte loggen sie sich ein!"
register = "Nicht eingeloggt, bitte loggen sie sich ein oder registrieren sie sich <a href='index.php?p=register'>hier</a>!"

[navi]
home = "Home"
profile = "Profil"
logout = "Ausloggen"

[register]
login = "Einloggen"
register = "Registrieren"
loggedin = "Sie sind bereits eingeloggt!"
username = "Benutzername"
password = "Passwort"
chckpassword = "Passwort wiederholen"
email = "Email"
firstname = "Vorname"
surname = "Nachname"
country = "Land"
location = "Wohnort"

[profile]
firstname = "Vorname"
surname = "Nachname"
email = "Email"
country = "Land"
location = "Wohnort"
icq = "ICQ"
msn = "MSN"
yahoo = "Yahoo"
occupation = "Arbeit"
bio = "Lebenslauf"
hobbys = "Hobbys"
language = "Sprache"
template = "Template"
signature = "Signatur"
update = "Aktualisieren"
profupdate = "Profilupdate"
prof = "Profil von"
nouser = "Kein Benutzer gefunden!"

[statistics]
users = "Es sind"
online = "Benutzer online"
usersonline = "Benutzer Online:"
nousers = "Keine Benutzer online!"


main.conf (en)

This file has to be put in lang->en->main.conf.


# global variables
error1 = "Usnername AND Password needed!"
error2 = "You are already logged in!"
error3 = "Username and/or Password wrong!"
error4 = "All * marked fields are required!"
error5 = "Passwords are different!"
error6 = "Not a valid email!"
error7 = "Successfully registered! You can now login!"
error8 = "Successfully registered! Please check your email!"
error9 = "Error during registration, please contact the Administrator!"
error10 = "Successfully logged out!"
error11 = "Error during update, please try again later!"
error12 = "Successfully updatet!"
error13 = "Couldn't create topic!"
error14 = "Topic successfully created!"
error15 = "You're not logged in!"
error16 = "Couldn't create post!"
error17 = "Post successfully created!"
error18 = "Couldn't edit post!"
error19 = "Post successfully updated!"

[content]
Root = "Category View"
categoryname = "Category Name"
posts = "Posts"
topics = "Topics"
topicname = "Topic Name"
views = "Views"
lastanswer = "Last answer"
notopics = "No topics found"
nobody = "Nobody yet"
writtenon = "written on"
by = "by"
newtopic = "New Topic"
createtopic = "Create Topic"
title = "Title"
subtitle = "Subtitle"
symbols = "Symbol"
message = "Message"
topicview = "Back to topics"
username = "Username"
noposts = "No postings."
editpost = "Edit Post"
newpost = "New Post"
notpublic = "Not public!"

[userbox]
loggedin = "Logged In"
notloggedin = "Not logged in"
welcome = "Welcome"
login = "Not logged in, please login!"
register = "Not logged in, please login or register <a href='index.php?p=register'>here</a>!"

[navi]
home = "Home"
profile = "Profile"
logout = "Logout"

[register]
login = "Login"
register = "Register"
loggedin = "You are already logged in!"
username = "Username"
password = "Password"
chckpassword = "Retype password"
email = "Email"
firstname = "Firstname"
surname = "Surname"
country = "Country"
location = "Location"

[profile]
firstname = "Firstname"
surname = "Surname"
email = "Email"
country = "Country"
location = "Location"
icq = "ICQ"
msn = "MSN"
yahoo = "Yahoo"
occupation = "Occupation"
bio = "Bio"
hobbys = "Hobbys"
language = "Language"
template = "Template"
signature = "Signature"
update = "Update"
profupdate = "Profile Update"
prof = "Profile of"
nouser = "No user found!"

[statistics]
users = "There are"
online = "Users online"
usersonline = "Users Online:"
nousers = "No users online!"


And now?

Well before you can use this board seriously you should definantly implement a better md5 system, some more stable bbcode (can easily be done in the forum class), avatar uploads, a better layout :D as this one is quite unlayouted..., moderation system, maybe user groups, administration... and the most important thing... client data checks! The current data isn't checked, but it's really not hard to do. Also you should add an captcha or some sort of other security things in the registration form.

But this tutorial should give you a good start on how to make your own discussion board!

I hope you liked this tutorial, it's just the first of some I want to make. In my next tutorial I will tell you on how to make it more secure, some better client handling, administration and all the other features that are currently missing. It was fun making this tutorial but also quite hard work as I spent all my free time on it, you can ask my girlfriend... she's damn angry ;)

So lon, I hope to see you on my future tutorials.

Regards,
Chris
Dig this tutorial?
Thank the author by sending him a few P2L credits!

Send
Balor

I'm a freelancing webcoder from germany next to Frankfurt. I'm developing web application solutions for mid-sized companies. I'm a coder with minor art skills.
View Full Profile Add as Friend Send PM
Pixel2Life Home Advanced Search Search Tutorial Index Publish Tutorials Community Forums Web Hosting P2L On Facebook P2L On Twitter P2L Feeds Tutorial Index Publish Tutorials Community Forums Web Hosting P2L On Facebook P2L On Twitter P2L Feeds Pixel2life Homepage Submit a Tutorial Publish a Tutorial Join our Forums P2L Marketplace Advertise on P2L P2L Website Hosting Help and FAQ Topsites Link Exchange P2L RSS Feeds P2L Sitemap Contact Us Privacy Statement Legal P2L Facebook Fanpage Follow us on Twitter P2L Studios Portal P2L Website Hosting Back to Top