Hello everyone. I am fairly new to PHP. Because of this I try and learn as much as I can with each problem that I encounter. In this particular case I have been left high and dry by the developer of a simple CMS that I had developed for me to bea ble to add some interactivity to my websites that I build for clients. While I am learning I still have to ask for help here and there so here goes...

The way this was built there is a template system that holds the html and short codes and then an includes system that holds the PHP coding. This keeps the structural elements separate from the interactive elements. When he built the system I wanted him to put together a simple system that allowed me to put the username or the first and last names anywhere I placed a shortcode. However, he split before I was able to get that completed evidently because the shortcodes do not work. So the goal here on this particular problem is to try and get that personalization function working again.

I will start out with the code to the functions and includes files which I think backs up the system that is supposed to display the contents in the database under the startpage heading.

INCLUDES.php

<?
    require_once('config.php');
    require_once($BasePath . 'data/template.php');

    $template = new Template();
    if (!is_dir('./templates')) {
        $template->set_rootdir($BasePath . 'templates');
    }

    require_once($BasePath . 'data/mysql.php');

    if (@is_dir($BasePath . 'install')) {
        include $BasePath . 'install/install.php';
        exit(0);
    }

    $SQL = new MySQL($SQLData);

    require_once($BasePath . 'data/constants.php');
    require_once($BasePath . 'data/users.php');
    require_once($BasePath . 'data/session.php');
    require_once($BasePath . 'data/images.php');
?>

CONSTANTS.php

<?

// User Databases
define('TABLE_USERS', SQLPrefix().'users');
define('TABLE_USERS_CUSTOM', SQLPrefix().'users_fields');
define('TABLE_USERS_DATA', SQLPrefix().'users_data');
define('TABLE_USERS_LOCS', SQLPrefix().'users_locations');
define('TABLE_CREDITCARD', SQLPrefix().'ccdata');

// Payout Databases
define('TABLE_ACCOUNT', SQLPrefix().'account');
define('TABLE_ACCOUNT_PAYOUT', SQLPrefix().'account_payout');

// Packages Databases
define('TABLE_PACKAGE', SQLPrefix().'package');
define('TABLE_PACKAGE_PAYOUT', SQLPrefix().'package_payout');
define('TABLE_PACKAGE_PURCHASE', SQLPrefix().'package_purchase');

// Resource Center Databases
define('TABLE_RESOURCE_CATEGORIES', SQLPrefix().'res_cat');
define('TABLE_RESOURCE_CENTER', SQLPrefix().'res');

// Shopping Center Databasess
define('TABLE_SHOPPING_CATEGORIES', SQLPrefix().'shoppingcat');
define('TABLE_SHOPPING_SHIPPING', SQLPrefix().'shoppingship');
define('TABLE_SHOPPING_ITEMS', SQLPrefix().'shopping');
define('TABLE_SHOPPING_SPECIALS', SQLPrefix().'shopping_spec');

// Config/Storage Databases
define('TABLE_CONFIG', SQLPrefix().'config');
define('TABLE_SESSION', SQLPrefix().'session');

define('TABLE_PDT', SQLPrefix().'pdt');
define('TABLE_PAYPAL_IPN', SQLPrefix().'paypal_ipn');
define('TABLE_MANUAL_IPN', SQLPrefix().'manual_ipn');
define('TABLE_SUBSCRIPTION', SQLPrefix().'subscription');

define('TABLE_NEWSLETTERS', SQLPrefix().'newsletters');
define('TABLE_NEWSLETTERS_USERS', SQLPrefix().'newsletters_users');

define('COOKIE_TAG', md5('«sESSioN_cpS»' . $InstallCode));

define('LOADUSER_UID', 1);
define('LOADUSER_USERNAME', 2);
define('LOADUSER_EMAIL', 3);

define('ULE_SILENTPOST_KEY', 'rXer5881qnwbMv3q8EhFN0GOFJ5Nagm1');
define('ULE_SILENTGET_KEY', 'hD5THAbvkTllg4GYtNX7aCOG3r8q5v8o');
?>

FUNCTIONS.php

<?

function Error($Header, $Body, $File, $Line) {
    global $template;
    $Body = str_replace("\n", "<br>\n", $Body);
    $Body = str_replace('\n', "<br>\n", $Body);
    $template->pparse('header');
    print "<h2>Error: $Header</h2><p>$Body<p>File: $File<br>Line: $Line";

    Debug('$_POST', $_POST);
    Debug('$_GET', $_GET);
    Debug('$_SESSION', $_SESSION);
    Debug('$_COOKIE', $_COOKIE);
    Debug('$_SERVER', $_SERVER);
//  Debug('$GLOBALS', $GLOBALS);
    Debug('MySQL Queries', $GLOBALS['SQL_Queries']);

    $template->pparse('footer');
    exit(0);
}

function SQLPrefix() {
    global $SQL, $SQLData;
    if (is_a($SQL, 'MySQL')) {
        return $SQL->GetPrefix();
    } else {
        return $SQLData['prefix'];
    }
    return false;
}

function Debug($Title, $Message) {
    global $template;
    if (getConfig('debug') == 1 && $GLOBALS['ActiveUser']['packagedata']['superadmin'] == 1) {
        if (is_array($Message)) {
            $template->assign_block_vars('Debug', array(
                'Title' => $Title,
                'Message' => '<font color=#006600>Array()</font>'
            ));
            foreach ($Message as $Key=>$Value) {
                Debug($Title . "[<font color=#990000>'$Key'</font>]", $Value);
            }
        } else {
            $template->assign_block_vars('Debug', array(
                'Title' => $Title,
                'Message' => $Message
            ));
        }
    }
}

function getConfig($Key) {
    global $SQL;
    if (!isset($GLOBALS['config']) && is_a($SQL, 'MySQL')) {
        $SQL->LoadConfig();
    }
    return $GLOBALS['config'][$Key];
}

function getTransactionData($TransID) {
    $agent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Sudra Shopping Cart 0.8)"; 
    $ref = $_SERVER['HTTP_REFERER']; // Replace this URL with the URL of this script 

    $ch=curl_init(); 
    curl_setopt($ch, CURLOPT_URL, "https://crosspointsolarcom:mnyulexpress1@www.eci-cart.net/orders/crosspointsolarcom/OnlineOrder.db?Invoice=" . $TransID); 
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); 
    curl_setopt($ch, CURLOPT_NOPROGRESS, 1); 
    curl_setopt($ch, CURLOPT_VERBOSE, 0); 
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION,0); 
    curl_setopt($ch, CURLOPT_HTTPGET, 1);
    curl_setopt($ch, CURLOPT_TIMEOUT, 120); 
    curl_setopt($ch, CURLOPT_USERAGENT, $agent); 
    curl_setopt($ch, CURLOPT_REFERER, $ref); 
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 

    $buffer = curl_exec($ch); 
    curl_close($ch); 

    if ($buffer == NULL) return false;

    $split[0] = explode("\r\n", $buffer);
    for ($x = 1; $x < count($split[0]); $x++) {
        $split[$x] = explode('","', $split[0][($x-1)]);
        $split[$x][(count($split[$x])-1)] = str_replace('",', '', $split[$x][(count($split[$x])-1)]);
    }

    for ($y = 2; $y < (count($split)); $y++) {
        for ($x = 0; $x < (count($split[1])-1); $x++) {
            if (!empty($split[1][$x])) {
                if (substr($split[1][$x], 0, 1) == '"') {
                    $split[1][$x] = substr($split[1][$x], 1);
                }

                if (substr($split[2][$x], 0, 1) == '"') {
                    $split[$y][$x] = substr($split[$y][$x], 1);
                }

                $OrderData['items'][($y-2)][$split[1][$x]] = $split[$y][$x];
            }
        }
        $OrderData['totalcost'] += $OrderData['items'][($y-2)]['Price'];
        $OrderData['shipping'] += $OrderData['items'][($y-2)]['Shipping+Handling'];
        $OrderData['tax'] += $OrderData['items'][($y-2)]['Sales_Tax'];
        $OrderData['weight'] += $OrderData['items'][($y-2)]['Order_Weight_Total'];
    }

    return $OrderData;
}

?>

MYSQL.php

<?
    session_name(getSessionID());
    session_start();
    getSessionData(getSessionID());

    if (!empty($_SESSION['user'])) {
        if ($t = getUser($_SESSION['user'], LOADUSER_USERNAME)) {
            Debug('Session User', $t);
            $GLOBALS['ActiveUser'] = $t;
            $GLOBALS['ActiveUser']['packagedata'] = getPackage($GLOBALS['ActiveUser']['package']);
            Debug('Session User Package', $GLOBALS['ActiveUser']['packagedata']);
            setcookie('UserLogin', $GLOBALS['ActiveUser']['uid'], time()+1800);
        } else {
            Debug('Removing Session User', $_SESSION['user']);
            unset($_SESSION['user']);
        }
    }

    Debug('Session ID', getSessionID());

    function getSessionData($sid) {
        global $SQL;

        $SQL->query('DELETE FROM ' . TABLE_SESSION . ' WHERE `expire` <= ' . time(), __FILE__, __LINE__);
        $result = $SQL->query('SELECT * FROM ' . TABLE_SESSION . ' WHERE `sid` = "' . $sid . '"', __FILE__, __LINE__);

        if (mysql_num_rows($result) > 0) {
            $Data = mysql_fetch_assoc($result);
            debug('Stored Session Data', $Data);
            session_decode($Data['data']);
        } else {
            return false;
        }
    }

    function setSessionData($sid) {
        global $SQL;

        $result = $SQL->query('SELECT * FROM ' . TABLE_SESSION . ' WHERE `sid` = "' . $sid . '"', __FILE__, __LINE__);

        if (mysql_num_rows($result) == 0) {
            $SQL->query('INSERT INTO ' . TABLE_SESSION . ' (`sid`, `expire`, `data`) VALUES ("' . $sid . '", ' . (time()+(60*30)) . ', "' . addslashes(session_encode()) . '")', __FILE__, __LINE__);
        } else {
            $SQL->query('UPDATE ' . TABLE_SESSION . ' SET `expire` = ' . (time()+(60*30*48)) . ', `data` = "' . addslashes(session_encode()) . '" WHERE `sid` = "' . $sid . '"', __FILE__, __LINE__);
        }
    }

    function getSessionID() {
        if (!isset($_COOKIE[COOKIE_TAG])) {
            $SID = IPtoHEX() . md5(getMicroTime());
        } else {
            $SID = $_COOKIE[COOKIE_TAG];
        }
        @setcookie(COOKIE_TAG, $SID, time()+(60*60*24), '/');
//      Debug('Session ID', $SID);
        return $SID;
    }

    function IPtoHEX($IP = '0') {
        if ($IP == '0') { $IP = $_SERVER['REMOTE_ADDR']; }
        $Segment = explode('.', $IP);
        return bin2hex(pack("cccc", $Segment[0], $Segment[1], $Segment[2], $Segment[3]));
    }

    function getMicroTime() {
        $T = explode(' ', microtime());
        return ($T[0] + $T[1]);
    }
?> <?

require_once($BasePath . 'data/functions.php');

class MySQL {

    var $SQLData = array(
        'server' => '',
        'database' => '',
        'username' => '',
        'password' => '',
        'prefix' => ''
    );

    var $QueryCount = 0;

    var $DBConnection = false;
    var $DBOpen = false;

    // Sets the server variables
    function MySQL($Data) {
        $this->SQLData['server'] = $Data['server'];
        $this->SQLData['database'] = $Data['database'];
        $this->SQLData['username'] = $Data['username'];
        $this->SQLData['password'] = $Data['password'];
        $this->SQLData['prefix'] = $Data['prefix'];
        $this->DBConnect();
    }

    // Connects to the server and selects database using variables set in SetServerVariables($Data);
    function DBConnect() {
        if ($this->SQLData['password'] != '') {
            $this->DBConnection = @mysql_pconnect($this->SQLData['server'], $this->SQLData['username'], $this->SQLData['password']);
        } else {
            $this->DBConnection = @mysql_pconnect($this->SQLData['server'], $this->SQLData['username']);
        }
        if (!$this->DBConnection) {
            Error('MySQL Error', "Unable to connect to MySQL Database:\nServer: ".$this->SQLData[server]."\n\n".@mysql_error($this->DBConnection), __FILE__, __LINE__);
        }

        $this->DBOpen = @mysql_select_db($this->SQLData['database'], $this->DBConnection);
        if (!$this->DBOpen) {
            Error('MySQL Error', "Unable to select MySQL Database:\nServer: ".$this->SQLData['server']."\nDatabase: ".$this->SQLData['database']."\n\n".@mysql_error($this->DBConnection), __FILE__, __LINE__);
        }
    }

    // Querys the SQL Server
    function query($sql, $file, $line) {
        $Result = @mysql_query($sql, $this->DBConnection);
        $this->QueryCount++;
        if (strstr(strtoupper($sql), 'SELECT')) {
            $ResultCount = @mysql_num_rows($Result);
        } else {
            $ResultCount = @mysql_affected_rows($this->DBConnection);
        }
        $GLOBALS['SQL_Queries'][] = $sql . ' - ' . $ResultCount . ' Results.';
        if (mysql_error($this->DBConnection)) {
            mail('sudrakoder@cox.net', 'SQL Error', "An error has occured in query:\n$sql\n\n".@mysql_error($this->DBConnection)."\n\nFile: ".$file."\nLine: ".$line);
            Error('MySQL Error', "An error has occured in query:\n$sql\n\n".@mysql_error($this->DBConnection),$file,$line);
        }

        return $Result;
    }

    function GetQueryCount() {
        return $this->QueryCount;
    }

    function GetPrefix() {
        return $this->SQLData['prefix'];
    }

    function LoadConfig() {
        $SQL = 'SELECT * FROM ' . TABLE_CONFIG;
        $query = $this->query($SQL, __FILE__, __LINE__);
        while (($row = mysql_fetch_row($query)) !== false) {
            $GLOBALS['config'][$row[0]] = $row[1];
        }
    }

    function DBDisconnect() {
        return mysql_close($this->DBConnection);
    }
}
?>

TEMPLATE.php

<?php
    class Template {
    var $classname = "Template";

    // variable that holds all the data we'll be substituting into
    // the compiled templates.
    // ...
    // This will end up being a multi-dimensional array like this:
    // $this->_tpldata[block.][iteration#][child.][iteration#][child2.][iteration#][variablename] == value
    // if it's a root-level variable, it'll be like this:
    // $this->_tpldata[.][0][varname] == value
    var $_tpldata = array();

    // Hash of filenames for each template handle.
    var $files = array();

    // Root template directory.
    var $root = "";

    // this will hash handle names to the compiled code for that handle.
    var $compiled_code = array();

    // This will hold the uncompiled code for that handle.
    var $uncompiled_code = array();

    /**
     * Constructor. Simply sets the root dir.
     *
     */
    function Template($root = "./templates")
    {
        $this->set_rootdir($root);
    }

    /**
     * Destroys this template object. Should be called when you're done with it, in order
     * to clear out the template data so you can load/parse a new template set.
     */
    function destroy()
    {
        $this->_tpldata = array();
    }

    /**
     * Sets the template root directory for this Template object.
     */
    function set_rootdir($dir)
    {
        if (!is_dir($dir))
        {
            return false;
        }

        $this->root = $dir;
        return true;
    }

    /**
     * Sets the template filenames for handles. $filename_array
     * should be a hash of handle => filename pairs.
     */
    function set_filenames($filename_array)
    {
        if (!is_array($filename_array))
        {
            return false;
        }

        reset($filename_array);
        while(list($handle, $filename) = each($filename_array))
        {
            $this->files[$handle] = $this->make_filename($filename);
        }

        return true;
    }


    /**
     * Load the file for the handle, compile the file,
     * and run the compiled code. This will print out
     * the results of executing the template.
     */
    function pparse($handle)
    {
        if (!$this->loadfile($handle))
        {
//          die("Template->pparse(): Couldn't load template file for handle $handle");
        }

        // actually compile the template now.
        if (!isset($this->compiled_code[$handle]) || empty($this->compiled_code[$handle]))
        {
            // Actually compile the code now.
            $this->compiled_code[$handle] = $this->compile($this->uncompiled_code[$handle]);
        }

        // Run the compiled code.
        global $encoded;
        eval($this->compiled_code[$handle]);
        return true;
    }

    /**
     * Inserts the uncompiled code for $handle as the
     * value of $varname in the root-level. This can be used
     * to effectively include a template in the middle of another
     * template.
     * Note that all desired assignments to the variables in $handle should be done
     * BEFORE calling this function.
     */
    function assign_var_from_handle($varname, $handle)
    {
        if (!$this->loadfile($handle))
        {
//          die("Template->assign_var_from_handle(): Couldn't load template file for handle $handle");
        }

        // Compile it, with the "no echo statements" option on.
        $_str = "";
        $code = $this->compile($this->uncompiled_code[$handle], true, '_str');

        // evaluate the variable assignment.
        eval($code);
        // assign the value of the generated variable to the given varname.
        $this->assign_var($varname, $_str);

        return true;
    }

    function block_reformat($handle) {
        if (!$this->loadfile($handle))
        {
            die("Template->nl2br(): Couldn't load template file for handle $handle");
        }

        $temp = $this->uncompiled_code[$handle];
        $temp = '<p>' . nl2br($temp);
        $temp = str_replace("\t", '     ', $temp);
        $temp = str_replace("  ", '  ', $temp);

        $this->uncompiled_code[$handle] = $temp;

        return true;
    }

    /**
     * Block-level variable assignment. Adds a new block iteration with the given
     * variable assignments. Note that this should only be called once per block
     * iteration.
     */
    function assign_block_vars($blockname, $vararray)
    {
        if (strstr($blockname, '.'))
        {
            // Nested block.
            $blocks = explode('.', $blockname);
            $blockcount = sizeof($blocks) - 1;
            $str = '$this->_tpldata';
            for ($i = 0; $i < $blockcount; $i++)
            {
                $str .= '[\'' . $blocks[$i] . '.\']';
                eval('$lastiteration = sizeof(' . $str . ') - 1;');
                $str .= '[' . $lastiteration . ']';
            }
            // Now we add the block that we're actually assigning to.
            // We're adding a new iteration to this block with the given
            // variable assignments.
            $str .= '[\'' . $blocks[$blockcount] . '.\'][] = $vararray;';

            // Now we evaluate this assignment we've built up.
            eval($str);
        }
        else
        {
            // Top-level block.
            // Add a new iteration to this block with the variable assignments
            // we were given.
            $this->_tpldata[$blockname . '.'][] = $vararray;
        }

        return true;
    }

    /**
     * Root-level variable assignment. Adds to current assignments, overriding
     * any existing variable assignment with the same name.
     */
    function assign_vars($vararray)
    {
        reset ($vararray);
        while (list($key, $val) = each($vararray))
        {
            $this->_tpldata['.'][0][$key] = $val;
        }

        return true;
    }

    /**
     * Root-level variable assignment. Adds to current assignments, overriding
     * any existing variable assignment with the same name.
     */
    function assign_var($varname, $varval)
    {
        $this->_tpldata['.'][0][$varname] = $varval;

        return true;
    }


    /**
     * Generates a full path+filename for the given filename, which can either
     * be an absolute name, or a name relative to the rootdir for this Template
     * object.
     */
    function make_filename($filename)
    {
        // Check if it's an absolute or relative path.
        if (substr($filename, 0, 1) != '/')
        {
            $filename = ($rp_filename = $this->root . '/' . $filename) ? $rp_filename : $filename;
        }

        if (!file_exists($filename))
        {
            die("Template->make_filename(): Error - file $filename does not exist");
        }

        return $filename;
    }


    /**
     * If not already done, load the file for the given handle and populate
     * the uncompiled_code[] hash with its code. Do not compile.
     */
    function loadfile($handle)
    {
        // If the file for this handle is already loaded and compiled, do nothing.
        if (isset($this->uncompiled_code[$handle]) && !empty($this->uncompiled_code[$handle]))
        {
            return true;
        }

        // If we don't have a file assigned to this handle, die.
        if (!isset($this->files[$handle]))
        {
//          die("Template->loadfile(): No file specified for handle $handle");
        }

        $filename = $this->files[$handle];

        if ($data = @file($filename)) {
            $str = implode("", $data);
            if (empty($str))
            {
//          die("Template->loadfile(): File $filename for handle $handle is empty");
            }
        }

        $this->uncompiled_code[$handle] = $str;

        return true;
    }



    /**
     * Compiles the given string of code, and returns
     * the result in a string.
     * If "do_not_echo" is true, the returned code will not be directly
     * executable, but can be used as part of a variable assignment
     * for use in assign_code_from_handle().
     */
    function compile($code, $do_not_echo = false, $retvar = '')
    {
        // replace \ with \\ and then ' with \'.
        $code = str_replace('\\', '\\\\', $code);
        $code = str_replace('\'', '\\\'', $code);

        // change template varrefs into PHP varrefs

        // This one will handle varrefs WITH namespaces
        $varrefs = array();
        preg_match_all('#\{(([a-z0-9\-_]+?\.)+?)([a-z0-9\-_]+?)\}#is', $code, $varrefs);
        $varcount = sizeof($varrefs[1]);
        for ($i = 0; $i < $varcount; $i++)
        {
            $namespace = $varrefs[1][$i];
            $varname = $varrefs[3][$i];
            $new = $this->generate_block_varref($namespace, $varname);

            $code = str_replace($varrefs[0][$i], $new, $code);
        }

        // This will handle the remaining root-level varrefs
        $code = preg_replace('#\{([a-z0-9\-_]*?)\}#is', '\' . ( ( isset($this->_tpldata[\'.\'][0][\'\1\']) ) ? $this->_tpldata[\'.\'][0][\'\1\'] : \'\' ) . \'', $code);

        // Break it up into lines.
        $code_lines = explode("\n", $code);

        $block_nesting_level = 0;
        $block_names = array();
        $block_names[0] = ".";

        // Second: prepend echo ', append ' . "\n"; to each line.
        $line_count = sizeof($code_lines);
        for ($i = 0; $i < $line_count; $i++)
        {
            $code_lines[$i] = chop($code_lines[$i]);
            if (preg_match('#<!-- BEGIN (.*?) -->#', $code_lines[$i], $m))
            {
                $n[0] = $m[0];
                $n[1] = $m[1];

                // Added: dougk_ff7-Keeps templates from bombing if begin is on the same line as end.. I think. :)
                if ( preg_match('#<!-- END (.*?) -->#', $code_lines[$i], $n) )
                {
                    $block_nesting_level++;
                    $block_names[$block_nesting_level] = $m[1];
                    if ($block_nesting_level < 2)
                    {
                        // Block is not nested.
                        $code_lines[$i] = '$_' . $n[1] . '_count = ( isset($this->_tpldata[\'' . $n[1] . '.\']) ) ?  sizeof($this->_tpldata[\'' . $n[1] . '.\']) : 0;';
                        $code_lines[$i] .= "\n" . 'for ($_' . $n[1] . '_i = 0; $_' . $n[1] . '_i < $_' . $n[1] . '_count; $_' . $n[1] . '_i++)';
                        $code_lines[$i] .= "\n" . '{';
                    }
                    else
                    {
                        // This block is nested.

                        // Generate a namespace string for this block.
                        $namespace = implode('.', $block_names);
                        // strip leading period from root level..
                        $namespace = substr($namespace, 2);
                        // Get a reference to the data array for this block that depends on the
                        // current indices of all parent blocks.
                        $varref = $this->generate_block_data_ref($namespace, false);
                        // Create the for loop code to iterate over this block.
                        $code_lines[$i] = '$_' . $n[1] . '_count = ( isset(' . $varref . ') ) ? sizeof(' . $varref . ') : 0;';
                        $code_lines[$i] .= "\n" . 'for ($_' . $n[1] . '_i = 0; $_' . $n[1] . '_i < $_' . $n[1] . '_count; $_' . $n[1] . '_i++)';
                        $code_lines[$i] .= "\n" . '{';
                    }

                    // We have the end of a block.
                    unset($block_names[$block_nesting_level]);
                    $block_nesting_level--;
                    $code_lines[$i] .= '} // END ' . $n[1];
                    $m[0] = $n[0];
                    $m[1] = $n[1];
                }
                else
                {
                    // We have the start of a block.
                    $block_nesting_level++;
                    $block_names[$block_nesting_level] = $m[1];
                    if ($block_nesting_level < 2)
                    {
                        // Block is not nested.
                        $code_lines[$i] = '$_' . $m[1] . '_count = ( isset($this->_tpldata[\'' . $m[1] . '.\']) ) ? sizeof($this->_tpldata[\'' . $m[1] . '.\']) : 0;';
                        $code_lines[$i] .= "\n" . 'for ($_' . $m[1] . '_i = 0; $_' . $m[1] . '_i < $_' . $m[1] . '_count; $_' . $m[1] . '_i++)';
                        $code_lines[$i] .= "\n" . '{';
                    }
                    else
                    {
                        // This block is nested.

                        // Generate a namespace string for this block.
                        $namespace = implode('.', $block_names);
                        // strip leading period from root level..
                        $namespace = substr($namespace, 2);
                        // Get a reference to the data array for this block that depends on the
                        // current indices of all parent blocks.
                        $varref = $this->generate_block_data_ref($namespace, false);

                        // Create the for loop code to iterate over this block.
                        $code_lines[$i] = '$_' . $m[1] . '_count = ( isset(' . $varref . ') ) ? sizeof(' . $varref . ') : 0;';
                        $code_lines[$i] .= "\n" . 'for ($_' . $m[1] . '_i = 0; $_' . $m[1] . '_i < $_' . $m[1] . '_count; $_' . $m[1] . '_i++)';
                        $code_lines[$i] .= "\n" . '{';
                    }
                }
            }
            else if (preg_match('#<!-- END (.*?) -->#', $code_lines[$i], $m))
            {
                // We have the end of a block.
                unset($block_names[$block_nesting_level]);
                $block_nesting_level--;
                $code_lines[$i] = '} // END ' . $m[1];
            }
            else
            {
                // We have an ordinary line of code.
                if (!$do_not_echo)
                {
                    $code_lines[$i] = 'echo \'' . $code_lines[$i] . '\' . "\\n";';
                }
                else
                {
                    $code_lines[$i] = '$' . $retvar . '.= \'' . $code_lines[$i] . '\' . "\\n";'; 
                }
            }
        }

        // Bring it back into a single string of lines of code.
        $code = implode("\n", $code_lines);
        return $code    ;

    }


    /**
     * Generates a reference to the given variable inside the given (possibly nested)
     * block namespace. This is a string of the form:
     * ' . $this->_tpldata['parent'][$_parent_i]['$child1'][$_child1_i]['$child2'][$_child2_i]...['varname'] . '
     * It's ready to be inserted into an "echo" line in one of the templates.
     * NOTE: expects a trailing "." on the namespace.
     */
    function generate_block_varref($namespace, $varname)
    {
        // Strip the trailing period.
        $namespace = substr($namespace, 0, strlen($namespace) - 1);

        // Get a reference to the data block for this namespace.
        $varref = $this->generate_block_data_ref($namespace, true);
        // Prepend the necessary code to stick this in an echo line.

        // Append the variable reference.
        $varref .= '[\'' . $varname . '\']';

        $varref = '\' . ( ( isset(' . $varref . ') ) ? ' . $varref . ' : \'\' ) . \'';

        return $varref;

    }


    /**
     * Generates a reference to the array of data values for the given
     * (possibly nested) block namespace. This is a string of the form:
     * $this->_tpldata['parent'][$_parent_i]['$child1'][$_child1_i]['$child2'][$_child2_i]...['$childN']
     *
     * If $include_last_iterator is true, then [$_childN_i] will be appended to the form shown above.
     * NOTE: does not expect a trailing "." on the blockname.
     */
    function generate_block_data_ref($blockname, $include_last_iterator)
    {
        // Get an array of the blocks involved.
        $blocks = explode(".", $blockname);
        $blockcount = sizeof($blocks) - 1;
        $varref = '$this->_tpldata';
        // Build up the string with everything but the last child.
        for ($i = 0; $i < $blockcount; $i++)
        {
            $varref .= '[\'' . $blocks[$i] . '.\'][$_' . $blocks[$i] . '_i]';
        }
        // Add the block reference for the last child.
        $varref .= '[\'' . $blocks[$blockcount] . '.\']';
        // Add the iterator for the last child if requried.
        if ($include_last_iterator)
        {
            $varref .= '[$_' . $blocks[$blockcount] . '_i]';
        }

        return $varref;
    }

}

?>

USERS.php

<?
    function getUser($key, $type = LOADUSER_UID) {
        global $SQL;

        if ($type == LOADUSER_UID) {
            $result = $SQL->query('SELECT * FROM ' . TABLE_USERS . ' WHERE `uid` = "' . $key . '"', __FILE__, __LINE__);
        } elseif ($type == LOADUSER_USERNAME) {
            $result = $SQL->query('SELECT * FROM ' . TABLE_USERS . ' WHERE `username` = "' . $key . '"', __FILE__, __LINE__);
        } elseif ($type == LOADUSER_EMAIL) {
            $result = $SQL->query('SELECT * FROM ' . TABLE_USERS . ' WHERE `email` = "' . $key . '"', __FILE__, __LINE__);
        } else {
            return false;
        }

        if (mysql_num_rows($result) == 1) {
            return mysql_fetch_assoc($result);
        } else {
            return false;
        }
    }

    function getCustom($key) {
        global $SQL;

        $result = $SQL->query('SELECT * FROM ' . TABLE_USERS_DATA . ' WHERE `uid` = "' . $key . '"', __FILE__, __LINE__);

        if (mysql_num_rows($result) > 0) {
            while ($row = mysql_fetch_assoc($result)) {
                $data[$row['fid']] = $row['data'];
            }
            return $data;
        } else {
            return false;
        }
    }

    function verifyUser($key) {
        global $SQL;

        $result = $SQL->query('UPDATE ' . TABLE_USERS . ' SET `active` = 1 WHERE `username` = "' . $key . '"');
        return true;
    }

    function getPackage($key) {
        global $SQL;

        $result = $SQL->query('SELECT * FROM ' . TABLE_PACKAGE . ' WHERE `pid` = "' . $key . '"', __FILE__, __LINE__);

        if (mysql_num_rows($result) == 1) {
            return mysql_fetch_assoc($result);
        } else {
            return false;
        }
    }

    function CheckLogin() {
        if ($GLOBALS['RequiresLogin']) {
            if ($GLOBALS['ActiveUser']['uid']) {
                return true;
            } else {
                $_SESSION['LoginRedirect'] = $_SERVER['QUERY_STRING'];
                header('Location: ?p=login&m=loginreq');
                return !$GLOBALS['RequiresLogin'];
            }
        } else {
            return true;
        }
    }
?>

Now with all these "control" php files we can now proceed to the implementation of the .tpl (template) files and the .php (control) files that are running the template system for this function. For this I will post the header.inc (header include), home.tpl, home.php, login.tpl and login.php files.

HEADER.inc

<!DOCTYPE HTML> <html> <head> <title>My Chance Up - Resource Clearing House for Ex-Offenders </title> <meta http-equiv="content-type" content="text/html; charset=utf-8" /> <meta name="description" content="Providing re-entry resources to ex-offenders. Our goal is to offer an interactive one stop resource clearinghouse for the myriad of services needed to effectively combat recidivism" /> <meta name="keywords" content="recidivism, combatting recidivism, ex-offender resources, resource center, driver's license, social security card, birth certificate, emergency food, emergency shelter, emergency healthcare" /> <!-- Favicon --> <link rel="shortcut icon" href="favicon.ico" type="image/x-icon"> <link rel="icon" href="favicon.ico" type="image/x-icon"> <!--[if lte IE 8]><script src="css/ie/html5shiv.js"></script><![endif]--> <!-- Scripts --> <script src="js/jquery.min.js"></script> <script src="js/jquery.dropotron.min.js"></script> <script src="js/skel.min.js"></script> <script src="js/skel-layers.min.js"></script> <script src="js/init.js"></script> <!-- Stylesheets only if no js--> <noscript> <link rel="stylesheet" href="css/skel.css" /> <link rel="stylesheet" href="css/style.css" /> <link rel="stylesheet" href="css/style-wide.css" /> </noscript> <!-- In Page Style Elements this page only --> <style>

        #faicons:hover
            {
            border: 3px solid green;
            cursor: pointer;
            }
        #faiconstext:hover
            {
            color: green;
            }
        </style> <!--[if lte IE 8]><link rel="stylesheet" href="css/ie/v8.css" /><![endif]--> </head> <body> <!-- Header --> <div id="header"> <!-- Logo --> <h1><img src="images/logo.png" height="200" id="logo"/></h1> <!-- Nav --> <nav id="nav"> <ul> <li><a href="../index.html">MCU Home</a></li> <li><a href="?">Resource Center Home</a> <ul> <li><a href="../map.html">Interactive Map</a></li> <li><a href="?p=resourcecenter&c=0#top">Direct Access Menu</a> <ul> <li><a href="?p=resourcecenter&c=9#top">Region One</a></li> <li><a href="?p=resourcecenter&c=65#top">Region Two</a></li> <li><a href="?p=resourcecenter&c=66#top">Region Three</a></li> <li><a href="?p=resourcecenter&c=67#top">Region Four</a></li> <li><a href="?p=resourcecenter&c=68#top">Region Five</a></li> <li><a href="?p=resourcecenter&c=72#top">Region Six</a></li> <li><a href="?p=resourcecenter&c=73#top">Region Seven</a></li> <li><a href="?p=resourcecenter&c=74#top">Region Eight</a></li> <li><a href="?p=resourcecenter&c=75#top">Region Nine</a></li> <li><a href="?p=resourcecenter&c=76#top">Region Ten</a></li> </ul> </li> </ul> </li> <li><a href="../mcu">Partner Network</a></li> <li><a href="../about.html">About Us</a></li> <!-- BEGIN ToggleNotLoggedIn --> <li><a href="?p=login">Login</a></li> <!-- END ToggleNotLoggedIn --> <!-- BEGIN ToggleSuper --> <li><a href="?p=admin">Administration</a></li> <!-- END ToggleSuper --> <!-- BEGIN ToggleLoggedIn --> <li><a href="?p=login&a=lo">Log Out</a></li> <!-- END ToggleLoggedIn --> </ul> </nav> </div> <!-- Main --> <section class="wrapper style1"> <div class="container"> <div id="content"> <!-- Content -->

HOME.tpl (template that is inserted where "content" leaves off in header.inc)

        <!-- Highlights --> <i id="faicons" class="icon major fa-dashboard"></i><h2>DASHBOARD</h2> <!-- BEGIN ToggleBasic --> <p style="padding: 20px;">Welcome to the My Chance Up User Dashboard.  The various tools for your use are contained in "widgets" which are below as you scroll down.  For example when you click on the "Interactive Map" widget and select your state you will be automatically taken to the resources for your state listed within the resource center. Any other widgets will take you to other functions based on your user type.</p> <section class="wrapper style1"> <div class="container"> <div class="row 200%"> <section class="4u 12u(narrower)"> <div class="box highlight" style="border-right: 1px solid #5F83B9;  border-bottom: 1px solid #5F83B9; border-radius: 5px; padding-right: 5px;"> <a href="../map.html" id="logo"><i id="faicons" class="icon major fa-briefcase"></i></a> <a href="../map.html"><h3 id="faiconstext">My Roadmap</h3></a> <p>Use your roadmap to keep you on track.</p> </div> </section> <section class="4u 12u(narrower)"> <div class="box highlight" style="border-right: 1px solid #5F83B9;  border-bottom: 1px solid #5F83B9; border-radius: 5px; padding-right: 5px;" > <a href="../map.html"><i id="faicons" class="icon major fa-map-marker"></i></a> <a href="../map.html"><h3 id="faiconstext">Interactive Map</h3></a> <p>Use our interactive map to find resources near you.</p> </div> </section> <section class="4u 12u(narrower)"> <div class="box highlight" style="border-right: 1px solid #5F83B9;  border-bottom: 1px solid #5F83B9; border-radius: 5px; padding-right: 5px;"> <a href="?p=resourcecenter&c=0"><i id="faicons" class="icon major fa-bars"></i></a> <a href="?p=resourcecenter&c=0"><h3 id="faiconstext">Directory</h3></a> <p>Use our easy menu based directory to find resources near you.</p> </div> </section> <section class="4u 12u(narrower)"> <div class="box highlight" style="border-right: 1px solid #5F83B9;  border-bottom: 1px solid #5F83B9; border-radius: 5px; padding-right: 5px;"> <a href="#mailform"><i id="faicons" class="icon major fa-bullhorn"></i></a> <a href="#mailform"><h3 id="faiconstext">Featured MCU Network Partner</h3></a> <p>This is where a formatted blurb about the featured network partner(s) can go.  Can be a paid position for advertising revenue as well.</p> </div> </section> </div> </div> </section> <!-- END ToggleBasic --> <!-- BEGIN ToggleAdmin --> <p style="padding: 20px;">Welcome to the My Chance Up Admin Dashboard.  The various tools for your use are contained in "widgets" which are below as you scroll down.  For example when you click on the "Interactive Map" widget and select your state you will be automatically taken to the resources for your state listed within the resource center. Any other widgets will take you to other functions based on your user type.</p> <section class="wrapper style1"> <div class="container"> <div class="row 200%"> <section class="4u 12u(narrower)"> <div class="box highlight" style="border-right: 1px solid #5F83B9;  border-bottom: 1px solid #5F83B9; border-radius: 5px; padding-right: 5px;"> <a href="../map.html"><i id="faicons" class="icon major fa-briefcase"></i></a> <a href="../map.html"><h3 id="faiconstext">My Roadmap</h3></a> <p>Use your roadmap to keep you on track.</p> </div> </section> <section class="4u 12u(narrower)"> <div class="box highlight" style="border-right: 1px solid #5F83B9;  border-bottom: 1px solid #5F83B9; border-radius: 5px; padding-right: 5px;"> <a href="../map.html"><i id="faicons" class="icon major fa-map-marker"></i></a> <a href="../map.html"><h3 id="faiconstext">Interactive Map</h3></a> <p>Use our interactive map to find resources near you.</p> </div> </section> <section class="4u 12u(narrower)"> <div class="box highlight" style="border-right: 1px solid #5F83B9;  border-bottom: 1px solid #5F83B9; border-radius: 5px; padding-right: 5px;"> <a href="?p=resourcecenter&c=0"><i id="faicons" class="icon major fa-bars"></i></a> <a href="?p=resourcecenter&c=0"><h3 id="faiconstext">Directory</h3></a> <p>Use our easy menu based directory to find resources near you.</p> </div> </section> <section class="4u 12u(narrower)"> <div class="box highlight" style="border-right: 1px solid #5F83B9;  border-bottom: 1px solid #5F83B9; border-radius: 5px; padding-right: 5px;"> <a href="#mailform"><i id="faicons" class="icon major fa-bullhorn"></i></a> <a href="#mailform"><h3 id="faiconstext">Featured MCU Network Partner</h3></a> <p>This is where a formatted blurb about the featured network partner(s) can go.  Can be a paid position for advertising revenue as well.</p> </div> </section> </div> </div> </section> <!-- END ToggleAdmin --> <!-- BEGIN ToggleSuper --> <p style="padding: 20px;">Welcome to the My Chance Up Super Admin Dashboard.  The various tools for your use are contained in "widgets" which are below as you scroll down.  For example when you click on the "Interactive Map" widget and select your state you will be automatically taken to the resources for your state listed within the resource center. Any other widgets will take you to other functions based on your user type.</p> <section class="wrapper style1"> <div class="container"> <div class="row 200%"> <section class="4u 12u(narrower)"> <div class="box highlight" style="border-right: 1px solid #5F83B9;  border-bottom: 1px solid #5F83B9; border-radius: 5px; padding-right: 5px;"> <a href="../map.html"><i id="faicons" class="icon major fa-briefcase"></i></a> <a href="../map.html"><h3 id="faiconstext">My Roadmap</h3></a> <p style="padding: 5px;">Use your roadmap to keep you on track.</p> </div> </section> <section class="4u 12u(narrower)"> <div class="box highlight" style="border-right: 1px solid #5F83B9;  border-bottom: 1px solid #5F83B9; border-radius: 5px; padding-right: 5px;"> <a href="../map.html"><i id="faicons" class="icon major fa-map-marker"></i></a> <a href="../map.html"><h3 id="faiconstext">Interactive Map</h3></a> <p>Use our interactive map to find resources near you.</p> </div> </section> <section class="4u 12u(narrower)"> <div class="box highlight" style="border-right: 1px solid #5F83B9;  border-bottom: 1px solid #5F83B9; border-radius: 5px; padding-right: 5px;"> <a href="?p=resourcecenter&c=0"><i id="faicons" class="icon major fa-bars"></i></a> <a href="?p=resourcecenter&c=0"><h3 id="faiconstext">Directory</h3></a> <p>Use our easy menu based directory to find resources near you.</p> </div> </section> <section class="4u 12u(narrower)"> <div class="box highlight" style="border-right: 1px solid #5F83B9;  border-bottom: 1px solid #5F83B9; border-radius: 5px; padding-right: 5px;"> <a href="#mailform"><i id="faicons" class="icon major fa-bullhorn"></i></a> <a href="#mailform"><h3 id="faiconstext">Featured MCU Network Partner</h3></a> <p>This is where a formatted blurb about the featured network partner(s) can go.  Can be a paid position for advertising revenue as well.</p> </div> </section> </div> </div> </section> <!-- END ToggleSuper -->        

HOME.php (code that inserts the home.tpl contents into the area designated for it in the template system (template.php).

<?
    $template->set_filenames(array(
        'body'=>'home.tpl'
    ));

    //Start page

    if ($GLOBALS['ActiveUser']['uid'] > 0) {
        if (strlen($GLOBALS['ActiveUser']['packagedata']['startpage']) > 0) {
            $startpage = $GLOBALS['ActiveUser']['packagedata']['startpage'];
            $startpage = str_replace('[FIRSTNAME]', $GLOBALS['ActiveUser']['firstname'], $startpage);
            $startpage = str_replace('[LASTNAME]', $GLOBALS['ActiveUser']['lastname'], $startpage);
            $startpage = str_replace('[USERNAME]', $GLOBALS['ActiveUser']['username'], $startpage);
            $template->assign_block_vars('UserLanding', array(
                'HTML' => ($startpage)
            ));
        }
    }
?>

LOGIN.tpl (template that holds the code for the login box - inserted in space set for templates run by template.php)

<div > <div style="margin-left: 15px; margin-right: 15px;"> <!-- BEGIN Messages --> <div >{Messages.Message}</div> <!-- END Messages --> <!-- BEGIN Message_LOGINREQ --> <div >In order to access this section of the website you need to log in.  If you have not yet created your My Chance Up account you can do so by clicking the button below the login box.</div> <!-- END Message_LOGINREQ --> <!-- BEGIN LoginBox --> <div  style="background-color: #D7E0F1; width: 600px; margin-left: auto; margin-right: auto; box-shadow: 10px 10px 5px #888888;  border-radius: 10px;"> <div style="padding: 15px 15px 15px 15px;"> <form method="post">
                        Username:<br /> <input type="text" name="un" value="{LoginBox.UN}" />
                        Password:<br /> <input type="password" name="pw" /><br /> <input type="submit" value="Log In" /> <input type="hidden" name="a" value="li" /> </form> <form style="display: inline" action="?p=profile&a=register" method="get"> <button>Not Registered?</button> </form> </div> </div> <!-- END LoginBox --> </div> </div>

LOGIN.php (code that controls the placing of the login.tpl file in the space designated by template.php)

<?
    $Action = (empty($_GET['a'])?'li':$_GET['a']);

    $template->set_filenames(array(
        'body' => 'login.tpl'
    ));

    $Error = array();

    if ($Action == 'forgotpassword') {
        $template->set_filenames(array(
            'body' => 'user/forgotpassword.tpl'
        ));

        if ($_POST['a'] == 'fp') {
            if ($User = getUser($_POST['uname'], LOADUSER_USERNAME)) {
                if ($User['email'] == $_POST['email']) {
                    $NewPass = substr(md5(implode('.', microtime()) . $User['email']), 2, 8);
                    $email = file_get_contents('./templates/email/user/forgotpassword.tpl');
                    $email = str_replace('[[FIRSTNAME]]', $User['firstname'], $email);
                    $email = str_replace('[[LASTNAME]]', $User['lastname'], $email);
                    $email = str_replace('[[NEWPASS]]', $NewPass, $email);
                    $email = str_replace('[[IP]]', $_SERVER['REMOTE_ADDR'], $email);
                    $email = str_replace('[[DATE]]', date('r'), $email);
                    mail($User['email'], 'Forgotten Password - ' . $User['firstname'] . ' ' . $User['lastname'], $email);
                    $SQL->query('UPDATE ' . TABLE_USERS . ' SET `password` = "' . md5($NewPass) . '" WHERE `uid` = ' . $User['uid'], __FILE__, __LINE__);
                    $Message = 'Password Sent';
                } else {
                    $Error = 1;
                }
            } else {
                $Error = 1;
            }

            if ($Error == 1) {
                $template->assign_block_vars('ForgotPassword', array(
                    'Message' => 'User and/or Email combination does not exist.'
                ));
            } else {
                $template->assign_block_vars('ForgotPassword', array('Message' => $Message));
            }
        } else {
            $template->assign_block_vars('ForgotPassword', array());
        }
    } elseif ($Action == 'lo') {
        unset($GLOBALS['ActiveUser']);
        unset($_SESSION['user']);
        $template->assign_block_vars('Messages', array(
            'Message' => 'You have been logged out.'
        ));
    } elseif ($Action == 'li') {
        if ($_POST['a'] == 'li') {
            if (empty($_POST['un']) || empty($_POST['pw'])) {
                $Error[] = 'Please enter your username and password.';
            } else {
                if (!($User = getUser($_POST['un'], LOADUSER_USERNAME))) {
                    $Error[] = 'Username and/or password are incorrect.';
                } elseif ($User['password'] != md5($_POST['pw'])) {
                    $Error[] = 'Username and/or password are incorrect.';
                }

                if (count($Error) == 0) {
                    $_SESSION['user'] = $User['username'];
                    $GLOBALS['ActiveUser'] = $User;
                }
            }

            if (count($Error) > 0) {
                foreach ($Error as $Message) {
                    $template->assign_block_vars('Messages', array(
                        'Message' => $Message
                    ));
                }
                $template->assign_block_vars('LoginBox', array());
            } else {
                if (!empty($_SESSION['LoginRedirect'])) {
                    header('Location: ?' . $_SESSION['LoginRedirect']);
                    $_SESSION['LoginRedirect'] = '';
                    unset($_SESSION['LoginRedirect']);
                } else {
                    header('Location: ?');
                }
                unset($_SESSION['LoginRedirect']);
            }
        } else {
            $template->assign_block_vars('LoginBox', array());
            if (!empty($_GET['m'])) {
                $template->assign_block_vars('Message_' . strtoupper($_GET['m']), array());
            }
        }
    }
?>

You will see a shortcode called UserLanding in the home.php code. This is the shortcode that is supposed to call the startpage content from the database. It is contained in the home.php file. However, I am not sure where it is referencing and what is missing to make it work. I was wondering if someone could look this over and help me out. I have spent some time looking this problem up and the solutions offered make me start over again because they are really not part of this system that was created. So I need a unique answer to my unique problem I guess? I would also be willing to allow someone (very limited) access to an FTP account to see the folder and file structure on this so that we could get a better handle on what was going on. This may end up bringing in more work with this system on this site because I really do want to get the CMS finished and this site is going to need some more customization as we go along and all those customizations need to be integrated into the CMS for future functionality on other sites (as I learn something or innovate something I like to include it as a function in the CMS). Well I am rambling but if someone could look at this and tell me what I need to do in order to fix this issue and also let me know what their availability is to work with this site for a while let me know.

Recommended Answers

All 3 Replies

I think you're better off to post a job at https://www.upwork.com/ or the likes. I don't think anyone here will go through all that code and your custom CMS for free.

There are many many issues there , just from a quick view I spotted more than 10 , and then I stopped spotting. Are you new to PHP or new to programming ? Has a meaning to share with you some architectural and logical errors there and motivate you to search them deeper , or you just want a fix ?

I am looking for a fix for now but I want to work with someone to update this code. It was created in 2004 and I am sure is out of date, which is the reason so many errors are being spotted. I am not sure how much that would cost to do. So not sure what to do now.

Thanks for the referral to upwork gentlmedia. That is a cool link. I will compare them to elance and see what works best. I just like this community and was looking to get something inhouse going. I like to support local if I can. :)

BTW I am also going to start a Github for this. I think the concept and the code is solid it's just outdated and needs some TLC. The right commiters will be into this once they see what it is doing outside of mainstream CMS providers. Works really well and is flat out open. There is an elementary integration of the Bootstrap responsive grid as the basic template for it and eventually would love to have integration of mods be in a mods folder with an admin UI(dashboard) and a user UI(dashboard). They will all be separate projects on the Git. One thing about GitHub that I don't like is that you cannot work on an entire project at once. You have to do it file by file, which sucks entirely. Somebody know where I can upload an entire web application and allow people to sandbox the entire thing at once? Seems a no brainer, but nobody that I can tell is doing it. Or am I missing some functionality at GitHub that I need to know (new there too, lol). Thanks a ton guys!

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.