<?php

error_reporting
(E_ALL E_STRICT);

/**
 * Backtick
 * Applies backticks to a string or array, with support for periods in names.
 * @author Sam Barrow
 * @param mixed $columns Column(s)
 * @return mixed Column(s) with backticks
**/

function db_bt($columns) {
    if (
is_array($columns)) {
        foreach (
$columns as $key => $column) {
            
$columns[$key] = db_bt($column);
        }
        return 
$columns;
    }
    else {
        if (
substr_count($columns'.')) {
            
$exploded explode('.'$columns);
            foreach (
$exploded as $key => $value) {
                
$exploded[$key] = db_bt($value);
            }
            return 
implode('.'$exploded);
        }
        else {
            return 
'`' $columns '`';
        }
    }
}

/**
 * Escape
 * Escapes a value or array of values.
 * @author Sam Barrow
 * @param mixed $values Value(s)
 * @param bool $quotes Use quotes
 * @return mixed Value(s)
**/

function db_escape($values$quotes true) {
    global 
$cfg;
    if (
is_array($values)) {
        foreach (
$values as $key => $value) {
            
$values[$key] = db_escape($value$quotes);
        }
    }
    else if (
$values === null) {
        
$values 'NULL';
    }
    else if (
is_bool($values)) {
        
$values $values 0;
    }
    else if (!
is_numeric($values)) {
        
$values mysql_real_escape_string($values);
        if (
$quotes) {
            
$values '"' $values '"';
        }
    }
    return 
$values;
}

/**
 * Query condition classes.
**/

abstract class db_abstractConditionGroup {

    
abstract protected function operator();
    
    
private $conditions = array();
    
public function addCondition($condition) {
        
$this -> conditions[] = $condition;
        return 
true;
    }
    
public function addEqualCondition($field$value$escapeValue true$escapeField true) {
        if (
$escapeValue) {
            
$value db_escape($value);
        }
        if (
$escapeField) {
            
$field db_bt($field);
        }
        
$this -> conditions[] = $field ' = ' $value;
        return 
true;
    }
    
public function getConditions() {
        return 
$this -> conditions;
    }
    
    
private $conditionGroups = array();
    
public function getConditionGroups() {
        return 
$this -> conditionGroups;
    }
    
public function addConditionGroup(db_abstractConditionGroup $conditionGroups) {
        
$this -> conditionGroups[] = $conditionGroups;
        return 
true;
    }
    
    
public function parse() {
        
$codes = array();
        foreach (
$this -> getConditionGroups() as $conditionGroup) {
            
$codes[] = $conditionGroup -> parse();
        }
        foreach (
$this -> getConditions() as $condition) {
            
$codes[] = $condition;
        }
        
$code '(' implode(' ' $this -> operator() . ' '$codes) . ')';
        return 
$code;
    }
}

final class db_andConditionGroup extends db_abstractConditionGroup {
    
protected function operator() {
        return 
'AND';
    }
}
final class db_orConditionGroup extends db_abstractConditionGroup {
    
protected function operator() {
        return 
'OR';
    }
}

/**
 * Query classes.
**/

final class db_select {

    
private $fields;
    
public function addField($field$escape true) {
        if (
$escape) {
            
$field db_bt($field);
        }
        
$this -> fields[] = $field;
        return 
true;
    }
    
    
private $table;
    
public function getTable() {
        return 
$this -> table;
    }
    
public function setTable($table) {
        
$this -> table $table;
        return 
true;
    }
    
    
private $conditionGroup;
    
public function setConditionGroup(db_abstractConditionGroup $conditionGroup) {
        
$this -> conditionGroup $conditionGroup;
        return 
true;
    }
    
public function hasConditionGroup() {
        return isset(
$this -> conditionGroup);
    }
    
public function getConditionGroup() {
        return 
$this -> conditionGroup;
    }
    
    
private $orderBy;
    
public function addOrderBy($orderBy$escape true) {
        if (
$orderBy) {
            
$orderBy db_bt($orderBy);
        }
        
$this -> orderBy[] = $orderBy;
        return 
true;
    }
    
public function hasOrderBys() {
        return isset(
$this -> orderBy);
    }
    
public function getOrderBys() {
        return isset(
$this -> orderBy) ? $this -> orderBy : array();
    }
    
    
public function parse() {
        
$query 'SELECT ';
        if (isset(
$this -> fields)) {
            
$query .= implode(', '$this -> fields) . ' ';
        }
        else {
            
$query .= '* ';
        }
        
$query .= 'FROM ' db_bt($this -> getTable()) . ' ';
        if (
$this -> hasConditionGroup()) {
            
$query .= 'WHERE ' $this -> getConditionGroup() -> parse() . ' ';
        }
        if (
$this -> hasOrderBys()) {
            
$query .= 'ORDER BY ' implode(', '$this -> getOrderBys());
        }
        return 
$query;
    }
    
public function query() {
        return 
mysql_query($this -> parse());
    }
    
}

$conditionGroup = new db_andConditionGroup;
$conditionGroup -> addEqualCondition('field1'8);
$conditionGroup -> addEqualCondition('field2'3);

$conditionGroup2 = new db_orConditionGroup;
$conditionGroup2 -> addConditionGroup($conditionGroup);
$conditionGroup2 -> addEqualCondition('field3'5);

$query = new db_select;

$query -> setTable('table');

$query -> addField('field1');
$query -> addField('field2');
$query -> addField('`field3` + NOW() AS `field3`'false);

$query -> setConditionGroup($conditionGroup2);

$query -> addOrderBy('field1');

echo 
$query -> parse();