PHP Developers Network

A community of PHP developers offering assistance, advice, discussion, and friendship.
 
Loading
It is currently Tue Sep 26, 2017 1:16 pm

All times are UTC - 5 hours




Post new topic Reply to topic  [ 24 posts ]  Go to page Previous  1, 2
Author Message
 Post subject:
PostPosted: Thu Sep 06, 2007 4:11 pm 
Offline
Forum Commoner

Joined: Sat Mar 13, 2004 11:21 pm
Posts: 66
Location: UK
Quote:
For more feedback perhaps you should post some source code or a subversion repository or something.


Well since it is going to be a community project I see no reason not to, like I said, but some things are best kept underground. I will post the database file since there is nothing special about it and maybe somebody will have some suggestions on how to improve it.

Cheers.

Syntax: [ Download ] [ Hide ]
<?php

class Database {

  const MAX_FETCH_ROWS = 50;

  private $_fetchRowOffset = 0;

  private $_fetchRows = 30;

  private $_allowedTypes = array('numeric', 'str', 'string');

  private $_link;

  private $_dataHandler;

  static private $_instance = NULL;

  private $_table;

  private $_tables;

  private $_queuedFields = array();

  private $_queuedValues = array();

  private $_result;

  private $_sql;

  private $_where;

  final private function __construct () {

    $this->_dataHandler = Data_Handler::GetInstance();

    $this->_link = new mysqli;

    $this->_link->init();

    if (!$this->_dbConnect()) {

      $this->_catchError('Critical exception on start procedure: framework unable to initiate database connection. Framework died, unable to recover.', TRUE);

    }

    $this->setFetchLimit($this->_fetchRows);

  }

  private function __set ($variable, $value) {

    $this->_catchError("Minor exception on start procedure: $$variable does not exist. Framework recovered from error.");

  }

  private function _catchError ($error, $die = FALSE) {

    file_put_contents(ROOT . 'error.log', "$error\r\n", FILE_APPEND);

    if ($die) die();

  }

  static public function getInstance () {

    if (self::$_instance == NULL) self::$_instance = new Database();

    return self::$_instance;

  }

  final private function _dbConnect () {

    return $this->_link->real_connect('127.0.0.1', 'root', 't0sara51947', 'ape');

  }

  final private function _query () {

    if (!$this->_result = $this->_link->query($this->_sql)) {

      $this->_catchError("Query failed: $this->_sql");

      return FALSE;

    }

    return TRUE;

  }

  private function _escape ($sql) {

    if (get_magic_quotes_gpc()) $sql = stripslashes($sql);

    return $this->_link->real_escape_string($sql);

  }

  public function useTable ($table) {

    $table = $this->_escape($table);

    $this->_sql = "SELECT '' FROM `" . $table . "` LIMIT 0";

    if ($this->_query()) {

      $this->_table = $table;

      $this->_sql = '';

      return TRUE;

    }

    $this->_sql = '';

    return FALSE;

  }

  public function useTables () {

    $tableCount = func_num_args();

    $setTables = func_get_args();

    for ($i = 0; $i < $tableCount; ++$i) {

      $currentTable = $this->_escape($setTables[$i]);

      $this->_sql = "SELECT '' FROM `" . $currentTable . "` LIMIT 0";

      if ($this->_query()) $tables[] = $currentTable;

      else return FALSE;

    }

    $this->_tables = '`' . implode('`, `', $tables) . '`';

    return TRUE;

  }

  public function useRef ($field, $value, $match = '') {

    if (empty($match)) $match = "= '%s'";



    if (empty($this->_where)) {

      $this->_where = sprintf(" WHERE `%s` $match", $this->_escape($field), $this->_escape($value));

    }

    else {

      $this->_where .= sprintf(" AND `%s` $match", $this->_escape($field), $this->_escape($value));

    }

  }

  public function setTableData ($field, $value, $type = '') {

    if (empty($field)) return FALSE;

    if (!empty($type)) {

      if (!in_array($type, $this->_allowedTypes)) return FALSE;

      if (!$this->_dataHandler->checkType($value, $type)) return FALSE;

    }

    $this->_queuedFields[] = $this->_escape($field);

    $this->_queuedValues[] = $this->_escape($value);

    return TRUE;

  }

  public function insertTableData () {

    if (!isset($this->_queuedFields[0])) return FALSE;

    $this->_queuedFields = '`' . implode('`, `', $this->_queuedFields) . '`';

    $this->_queuedValues = "'" . implode("', '", $this->_queuedValues) . "'";

    $this->_sql = "INSERT INTO `$this->_table` ($this->_queuedFields) VALUES ($this->_queuedValues)";

    if ($this->_query()) {

      $this->_freeBuffer();

      return TRUE;

    }

    return FALSE;

  }

  public function updateTableData () {

    if (!isset($this->_queuedFields[0])) return FALSE;

    $fieldCounter = count($this->_queuedFields);

    for ($i = 0; $i < $fieldCounter; ++$i) {

      $this->_sql[] = '`' . $this->_queuedFields[$i] . "` = '" . $this->_queuedValues[$i] . "'";

    }

    $this->_sql = implode (', ', $this->_sql);

    $this->_sql = "UPDATE `$this->_table` SET $this->_sql $this->_where LIMIT 1";

    if ($this->_query()) {

      $this->_freeBuffer();

      return TRUE;

    }

    return FALSE;

  }

  public function setFetchLimit ($limit) {

    if (!$this->_dataHandler->checkType($limit, 'int')) return FALSE;

    if ($limit > self::MAX_FETCH_ROWS) $this->_fetchRows = self::MAX_FETCH_ROWS;

    elseif (!$limit) return FALSE;

    else $this->_fetchRows = $limit;

  }

  public function setFetchOffset ($offset) {

    if (!$this->_dataHandler->checkType($offset, 'int')) return FALSE;

    $this->_fetchRowOffset = $offset;

  }

  public function fetchSingle ($table, $field) {

    $this->_sql = 'SELECT `' . $this->_escape($field) . '` FROM `' . $this->_escape($table) . "` $this->_where LIMIT 1";

    if ($this->_query()) return array_pop(mysqli_fetch_row($this->_result));

    else return FALSE;

  }

  public function fetchRow ($table) {

    $this->_sql = 'SELECT * FROM `' . $this->_escape($table) . "` $this->_where LIMIT 1";

    if ($this->_query()) return mysqli_fetch_assoc($this->_result);

    else return FALSE;

  }

  public function fetchField ($table, $field) {

    $this->_sql = 'SELECT `' . $this->_escape($field) . '` FROM `' . $this->_escape($table) . "` $this->_where LIMIT $this->_fetchRowOffset, $this->_fetchRows";

    if ($this->_query()) {

      $field = array();

      while ($row = mysqli_fetch_row($this->_result)) $field[] = $row[0];

      return $field;

    }

    else return FALSE;

  }

  public function fetchRange ($table, $fields) {

    $fieldArgs = func_get_args();

    $fieldCount = func_num_args() - 1;

    array_shift($fieldArgs);

    array_walk($fieldArgs, array($this, '_escape'));

    $fields = implode("`, `", $fieldArgs);

    $this->_sql = "SELECT `$fields` FROM `" . $this->_escape($table) . "` $this->_where LIMIT $this->_fetchRowOffset, $this->_fetchRows";

    if ($this->_query()) {

      while ($row = mysqli_fetch_assoc($this->_result)) {

        $fields = array();

        foreach ($fieldArgs as $field) $fields[$field] = $row[$field];

        $rows[] = $fields;

      }

      return $rows;

    }

    else return FALSE;

  }

  private function _freeBuffer () {

    $this->_queuedFields = array();

    $this->_queuedValues = array();

    $this->_where = '';

  }

}

define('REF_FULL_MATCH', "= '%s'");

define('REF_PART_MATCH', "LIKE '%%%s%%'");

define('REF_LEFT_MATCH', "LIKE '%%%s'");

define('REF_RIGHT_MATCH', "LIKE '%s%%'");

define('REF_FULL_OMIT', "!= '%s'");

define('REF_PART_OMIT', "NOT LIKE '%s'");

$db = Database::getInstance();

?>


Top
 Profile  
 
 Post subject:
PostPosted: Thu Sep 06, 2007 7:05 pm 
Offline
Site Administrator
User avatar

Joined: Wed Aug 25, 2004 7:54 pm
Posts: 13431
Location: New York, NY, US
I'd suggest burying it back underground. Where to start? The methods called useTable(s) does a query to see if a table exists; yet the method useRef appends conditions to the where clause?!? Then there are the strange insert and update methods.

There are a bunch of patterns for database access that deal with all this stuff ... you don't need to invent a lumpy wheel ...

_________________
(#10850)


Top
 Profile  
 
 Post subject:
PostPosted: Fri Sep 07, 2007 3:17 am 
Offline
Forum Commoner

Joined: Sat Mar 13, 2004 11:21 pm
Posts: 66
Location: UK
There might be strange methods but the whole idea of this is to create a RAD PHP framework suitable for business use.

Here is an example of how to use it:
Syntax: [ Download ] [ Hide ]
$db->useRef('name', 'GLOBAL', PART_MATCH);

if (!($rows = fetchRange('setting', 'name', 'value'))) {

  foreach ($rows as $setting => $value) {

    echo "Setting: $setting = $value\n";

  }

}


The above will basically output all global settings stored in the database.

To be honest, since the framework is going to be different to anything else out there, it does not matter if it is strange, you just have to open your mind and realise the power of it, and it works well - in addition to all that, this is the first release of it so it will change with suggestions.

I have noticed that people are increasingly using OOP in a manner which would probably better suit just using a bunch of functions.

I want to combine the benefits of OOP without overkill, in addition to making the framework so no, or little knowledge of HTML and SQL is needed (little if you want more flexibility). To be honest I am looking at ways to improve what I have and not negative comments, any realistic suggests will be taken in consideration, the database class was created around the comments that were said about the form class.

Starting from scratch is not realistic and if you feel something should be changed could you please be a little more in-depth, because if you just say "start it again" you will be wasting your and my time. Cheers.

Maybe having a database class and a table class will be a better solution, which I will look into. As after all, this will provide many benefits.


Last edited by Bon Bon on Fri Sep 07, 2007 5:06 am, edited 1 time in total.

Top
 Profile  
 
 Post subject:
PostPosted: Fri Sep 07, 2007 5:05 am 
Offline
Site Administrator
User avatar

Joined: Wed Aug 25, 2004 7:54 pm
Posts: 13431
Location: New York, NY, US
I don't think I am wasting either your time or mine. I am pretty sure you will rewrite from scratch the functionality that you have in the class above several times in the next year or two. I recognize that conviction.

My suggestion would be to pass a standard Connection class (like mysqli) to domain specific Model classes with insert/update/select functionality similar to the one above -- instead of a generic "Database" class. Table Data Gateway is proven finder-style pattern that you might find interesting.

_________________
(#10850)


Top
 Profile  
 
 Post subject:
PostPosted: Fri Sep 07, 2007 5:30 am 
Offline
Forum Commoner

Joined: Sat Mar 13, 2004 11:21 pm
Posts: 66
Location: UK
This needs to be generic as it is going to be used for lots of things, maybe having a database class that handles the initial connection to the database and any queries sent to it.

Then a table class that can be used to get, insert, update, and delete data from a specific table. This way multiple tables can be used at the same time for different reasons.

Then if a table like the session table is going to be used a lot, the session class would become a gateway in its own right, so a table data gateway would not be needed because it would be represented under a different form, thus a framework.

The reason I said you were wasting time is because you did not actually give any solution to the reasoning of "burying it back underground," you just provided a problem but now I can see a solution to the problem things can be improved.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Sep 07, 2007 10:18 am 
Offline
Forum Commoner

Joined: Sat Mar 13, 2004 11:21 pm
Posts: 66
Location: UK
I have not started any work on the rework but before I do I want to get something ironed out.

Is there any reason mysql_real_query() does not work for INSERT queries in the following method:
Syntax: [ Download ] [ Hide ]
final private function _query () {

    if (!$this->_result = $this->_link->query($this->_sql)) {

      $this->_catchError("Query failed: $this->_sql");

      return FALSE;

    }

    return TRUE;

  }


The full code is in a previous post.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Sep 07, 2007 12:08 pm 
Offline
Site Administrator
User avatar

Joined: Wed Aug 25, 2004 7:54 pm
Posts: 13431
Location: New York, NY, US
If you are going to use mysqli_real_query() you need to look into using mysqli_store_result() or mysqli_use_result().

_________________
(#10850)


Top
 Profile  
 
 Post subject:
PostPosted: Mon Sep 10, 2007 3:09 am 
Offline
Forum Commoner

Joined: Sat Mar 13, 2004 11:21 pm
Posts: 66
Location: UK
Some areas of the PHP documentation are a load of crap, I actually looked at the two functions you mentioned and thought nothing of it because the examples were not clear on what the method was supposed to do. Anyway, I have messed about with things and got it sorted now cheers.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Oct 19, 2007 10:37 am 
Offline
Forum Commoner

Joined: Sat Mar 13, 2004 11:21 pm
Posts: 66
Location: UK
Just an update, got a form implementation working but it has a lot of bugs and I am going to do a few changes to it.

There is a fair bit of sloppy crap in the file because I am having to do all this alongside building actual websites at work and I have to work at the speed of other people and deadlines to get things finished.

Syntax: [ Download ] [ Hide ]
<?php



class Form {

  public $submitted;

  private $_postLocation, $_name, $_form;

  private $_err = array();



  function __construct ($name, $postLocation = '') {

    $this->_name = $name;



    $html_name = strtolower(str_replace(' ', '_', htmlspecialchars($this->_name)));

    if (isset($_POST[$html_name]) && count($_POST)) $this->submitted = TRUE;

    else $this->submitted = FALSE;



    $this->_postLocation = empty($postLocation) ? $this->_getUrl(TRUE, FALSE) : $postLocation;



    $this->_form = '<form action="' . $this->_postLocation . '" method="post">';

    $this->_form .= '<fieldset>';

    $this->_form .= '<legend>' . $this->_name . '</legend>';



    // generate unique form key

    // insert form key into database

    // get database instance

  }



  public function combine ($formHtml, $label = '') {

    if (!empty($label)) $formHtml = preg_replace('|<legend>.*?</legend>|i', '<legend>' . $label . '</legend>', $formHtml);

    $formHtml = str_replace('</fieldset>', '', $formHtml);

    $formHtml = str_replace('</form>', '', $formHtml);

    $thisForm = str_replace('<form action="' . $this->_postLocation . '" method="post">', '', $this->_form);

    $thisForm = str_replace('<fieldset>', '', $thisForm);

    $thisForm = str_replace('<legend>' . $this->_name . '</legend>', '', $thisForm);

    return $formHtml . '<br />' . $thisForm;

  }



  public function getHtml () {

    $this->_form .= '</fieldset>';

    $this->_form .= '</form>';

    return $this->_form;

  }



  private function _getUrl () {

    $url = isset($_SERVER['HTTPS']) ? 'https://' : 'http://';

    $url .= $_SERVER['HTTP_HOST'];

    $path = $_SERVER['REQUEST_URI'] != '' ? $_SERVER['REQUEST_URI'] : $_SERVER['PHP_SELF'];

    $url .= pathinfo($path, PATHINFO_DIRNAME) != '/' ? pathinfo($path, PATHINFO_DIRNAME) != '\\' ? pathinfo($path, PATHINFO_DIRNAME).'/' : '/' : pathinfo($path, PATHINFO_DIRNAME);

    $url .= preg_replace("/\?".preg_quote($_SERVER['QUERY_STRING'])."/", "", pathinfo($path, PATHINFO_BASENAME));

    $url .= '?' . $_SERVER['QUERY_STRING'];

    return $url;

  }



  /**

   * mk_checkbox() - Draws a checkbox field and captures the default value if one has been posted

   *

   * @param string $name - The input name used in the $_POST capture

   * @param string $value - The symbolic value of the input

   * @param boolean $checked - Whether the checkbox is selected by default

   * @param string $attributes - Any additional HTML attributes that need passing to the tag

   * @return string

   */


  public function addCheckbox ($name, $checked = FALSE, $attributes = '') {

    if (isset($_POST[$name])) $checked = clean(stripslashes($_POST[$name]));

    $input_field = '<input name="' . $name . '" type="checkbox"';

    if ($checked) $input_field .= ' checked="checked"';

    $input_field .= empty($attributes) ? ' />' : " $attributes />";

    $this->_form .= $input_field;

  }



  /**

   * mk_textbox() - Draws a textbox field and captures the default value if one has been posted

   *

   * @param string $name - The input name used in the $_POST capture

   * @param string $cols - The number of columns that should be displayed in the textbox

   * @param string $rows - The number of rows that should be displayed in the textbox

   * @param string $text - The default text for the textbox

   * @param string $attributes - Any additional HTML attributes that need passing to the tag

   * @return string

   */




  // XXX add label title (full desc)

  // XXX add id override

  // XXX add required or not

  public function addTextbox ($name, $text = '', $rows = '1', $cols = '200', $attributes = '') {

    if ($name{0} == '*') $required = 'class="required"';

    else $required = FALSE;



    $html_name = strtolower(ltrim(str_replace(' ', '_', htmlspecialchars($name) . '_'  .$this->_name), '*_'));

    $text = isset($_POST[$html_name]) ? stripslashes($_POST[$html_name]) : $text;



    if ($rows == 1) $input_field = "<label for=\"$html_name\" $required>$name:</label> <input name=\"$html_name\" type=\"text\" value=\"$text\" id=\"$html_name\" $attributes /><br />";

    else $input_field = '<label for="' . $html_name . '"' .  $required . '>' . $name . ':</label> <textarea name="' . $html_name . '" cols="' . $cols . '" rows="' . $rows . "\" id=\"$html_name\" $attributes >$text</textarea><br />";



    $this->_form .= $input_field;



    if (isset($_POST[$html_name])) {

      $temp = clean($_POST[$html_name]);

      if ($required && empty($temp)) $this->_err[] = 'All required fields must be complete';

      return $temp;

    }

    else return '';

  }



  public function addSubmit ($text = 'Submit', $attributes = '') {

    $html_name = strtolower(str_replace(' ', '_', htmlspecialchars($this->_name)));

    $input_field = '<label><input name="' . $html_name . '" type="submit" value="' . $text . '" class="btn_submit" /></label>';

    $this->_form .= $input_field;



    if ($this->submitted) {

      if (!isset($_POST[$html_name])) {

        $this->_err[] = 'This form should not be used from outside of this website';

      }

    }

  }



  // XXX needs testing

  public function addPassword ($name, $text = '', $attributes = '') {

    if ($name{0} == '*') $required = 'class="required"';

    else $required = FALSE;



    $html_name = strtolower(ltrim(str_replace(' ', '_', htmlspecialchars($name) . '_'  .$this->_name), '*_'));



    $input_field = '<label for="' . $html_name . '">' . $name . ':</label> <input name="' . $html_name . '" type="password" value="' . $text . '" /><br />';

    $this->_form .= $input_field;



    if (isset($_POST[$html_name])) {

      $temp = clean($_POST[$html_name]);

      if ($required && empty($temp)) $this->_err[] = 'All required fields must be complete';

      return $temp;

    }

    else return '';

  }



  /**

   * mk_radio_btn() - Creates a group of radio buttons and captures the default value if one has been posted

   *

   * @param string $name - The input name used in the $_POST capture

   * @param string $value - Any number of values passed to the fucntion that make up the choices available

   * @param string $value - If the last field is identical to a value that already exists then this becomes the default value

   * @return string

   */


  public function addRadioBtn () {

    $num_args = func_num_args();

    $arg_list = func_get_args();

    $last_arg = $num_args - 1;



    // no values set for options

    if (!isset($arg_list[1])) {

      echo('mk_radio(): Missing arguments');

      return FALSE;

    }



    $name = $arg_list[0];

    $selected_option = isset($_POST[$name]) ? clean(stripslashes($_POST[$name])) : '';



    if (empty($selected_option)) {

      $provisionally_selected_option = $arg_list[$num_args - 1];



      // see if a provisionally selected option exists

      // if no such option exists then just make the select box

      if (empty($provisionally_selected_option)) for ($i = 1; $i < $num_args; ++$i) {

        $value = $arg_list[$i];

        $options .= "<input name=\"$name\" value=\"$value\" type=\"radio\" class=\"rbn\" /> " . ucfirst($value) . "<br />\n";

      }

      // try and make a default value

      else {

        for ($i = 1; $i < $num_args; ++$i) {

          $value = $arg_list[$i];

          if (strcmp($provisionally_selected_option, $value) == 0 && $i != $last_arg) {

            $options .= "<input name=\"$name\" value=\"$value\" type=\"radio\" checked=\"checked\" class=\"rbn\" /> " . ucfirst($value) . "<br />\n";

            --$num_args;

          }

          else $options .= "<input name=\"$name\" value=\"$value\" type=\"radio\" class=\"rbn\" /> " . ucfirst($value) . "<br />\n";

        }

      }

    }

    else {

      // use posted value as default value

      for ($i = 1; $i < $num_args; ++$i) {

        $value = $arg_list[$i];

        if (strcmp($selected_option, $value) == 0) $options .= "<input name=\"$name\" value=\"$value\" type=\"radio\" checked=\"checked\" class=\"rbn\" /> " . ucfirst($value) . "<br />\n";

        else $options .= "<input name=\"$name\" value=\"$value\" type=\"radio\" class=\"rbn\"  /> " . ucfirst($value) . "<br />\n";

      }

    }



    $this->_form .= $options;

  }



  /**

   * mk_select_list() - Creates selection of options in the form of a drop-down menu and captures the default value if one has been posted

   *

   * @param string $name - The input name used in the $_POST capture

   * @param string $value - Any number of values passed to the fucntion that make up the choices available

   * @param string $value - If the last field is identical to a value that already exists then this becomes the default value

   * @return string

   */


  public function addSelectList () {

    $num_args = func_num_args();

    $arg_list = func_get_args();

    $last_arg = $num_args - 2;



    // no values set for options

    if (!isset($arg_list[1])) {

      echo('mk_select(): Missing arguments');

      return FALSE;

    }



    $name = $arg_list[0];

    $html_name = strtolower(ltrim(str_replace(' ', '_', htmlspecialchars($name) . '_'  .$this->_name), '*_'));

    $attributes = $arg_list[1];



    if ($name{0} == '*') $required = TRUE;

    else $required = FALSE;



    // start opions tag

    $options = '<label for="' . $html_name . '">' . $name . ':</label> ';

    $options .= empty($attributes) ? "<select name=\"$html_name\">" : "<select name=\"$html_name\" $attributes>";



    // check to see if the value has been posted

    $selected_option = isset($_POST[$html_name]) ? clean(stripslashes($_POST[$html_name])) : '';



    if (is_array($arg_list[2])) {

      if (empty($selected_option) && isset($arg_list[3])) $selected_option = $arg_list[3];



      foreach($arg_list[2] as $option) {

        if (strcmp($selected_option, $option) == 0) $options .= '<option selected="selected">' . $option . '</option>';

        else $options .= '<option>' . $option . '</option>';

      }

    }

    else {

      // if no value posted

      if ($selected_option == '') {

        $provisionally_selected_option = $arg_list[$num_args - 1];



        // see if a provisionally selected option exists

        // if no such option exists then just make the select box

        if ($provisionally_selected_option === '') for ($i = 1; $i < $num_args; ++$i) $options .= '<option>' . $arg_list[$i] . '</option>';

        // try and make a default value

        else {

          for ($i = 2; $i < $num_args; ++$i) {

            $option = $arg_list[$i];

            if (strcmp($provisionally_selected_option, $option) == 0 && $i != $last_arg && $num_args > 4) {

              $options .= '<option selected="selected">' . $option . '</option>';

              --$num_args;

            }

            else $options .= '<option>' . $option . '</option>';

          }

        }

      }

      else {

        // use posted value as default value

        for ($i = 2; $i < $num_args; ++$i) {

          $option = $arg_list[$i];

          if (strcmp($selected_option, $option) == 0) $options .= '<option selected="selected">' . $option . '</option>';

          else $options .= '<option>' . $option . '</option>';

        }

      }

    }



    $options .= '</select><br />';



    $this->_form .= $options;



    if (isset($_POST[$html_name])) {

      $temp = clean($_POST[$html_name]);

      if ($required && empty($temp)) $this->_err[] = 'All required fields must be complete';

      return $temp;

    }

    else return '';

  }



  public function hasErrors () {

    if (count($this->_err)) return implode('. ', array_unique($this->_err)) . '.';

    else return FALSE;

  }

}



?>


I would not recommending using it yet because I lost 3 days working time when I experienced data loss using the class.

This is more or less just showing how things are getting on.

I have got a few more things in development including the database class which is now working quite well and really good error handler.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 24 posts ]  Go to page Previous  1, 2

All times are UTC - 5 hours


Who is online

Users browsing this forum: No registered users and 6 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Jump to:  
Powered by phpBB® Forum Software © phpBB Group