PHP Classes
Icontem

File: simplesql.class.php5


  Search   All class groups All class groups   Latest entries Latest entries   Top 10 charts Top 10 charts   Newsletter Newsletter   Blog Blog   Forums Forums   Help FAQ Help FAQ  
  Login   Register  
Recommend this page to a friend! ReTweet ReTweet Stumble It! Stumble It! Bookmark in del.icio.us Bookmark in del.icio.us
  Classes of Paul Williamson  >  Simple SQL PHP 5  >  simplesql.class.php5  
File: simplesql.class.php5
Role: Class source
Content type: text/plain
Description: main class file
Class: Simple SQL PHP 5
PHP 5 version of a MySQL wrapper and query logger
 

Contents

Class file image Download
<?php
/** 
 * SimpleSQL - The Simplest Way to Query
 * Copyright (c) 2004 Paul Williamson <webmaster@protonage.net>
 *
 * This class is ment to shortcut common MySQL database access tasks.
 * FOR PHP 5 ONLY! This class will not work on any versons < PHP5!
 * Also, This class was designed for users who want to use the new
 * PHP5 Improved MySQL Extension (mysqli) but do not have MySQL > 4.1. 
 * Mysqli allows you to access the functionality provided by MySQL > 4.1
 * Later on in the future, I will add a layer to this class that allows
 * mysqli functionality.
 *
 * This program is free software; you can redistribute it and/or 
 * modify it under the terms of the GNU General Public License 
 * as published by the Free Software Foundation; either version 2 
 * of the License, or (at your option) any later version. 
 * 
 * This program is distributed in the hope that it will be useful, 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 * GNU General Public License for more details. 
 *
 * @category  Database
 * @package   SimpleSQL
 * @author    Paul Williamson <webmaster@protonage.net>
 * @readme    ./docs/README.txt
 * @example   ./docs/EXAMPLES.txt
 * @standards ./docs/CODING_STANDARDS.txt
 * @version   $Id: simplesql.class.php5,v 2.0 2004/08/08 19:37:45 paul Exp $
 */
 
define ('FETCH_ASSOC',  0);
define ('FETCH_NUM',    1);
define ('FETCH_OBJECT', 2);
 
class simplesql
{
    /**
     * Constants;
     *
     * VERSION; SimpleSQL Version                  @const string
     * LOG_PATH; Path to logs                      @const string
     * MAX_SIZE; Max size of log file              @const int
     * DATE_FORMAT; Date Format for Log            @const string
     * @access global
     */
    const VERSION      = 'SimpleSQL v2.0.1 PHP5';
    const LOG_PATH     = '.';
    const MAX_SIZE     = 2000000;
    const DATE_FORMAT  = 'F jS, Y, H:i:s T';

    /**
     * Database Variables;
     *
     * You may hardcode these variables and not have to worry
     * about providing any arguments when you create a new class
     * 
     * $fetch_default; How the result is returned  @var int
     * 
     * $host; Database Server                      @var string
     * $user; Database Username                    @var string
     * $pass; Database Password                    @var string
     * $dbname; Database name                      @var string
     * $socket; Database Socket                    @var string
     * $port; Database Port                        @var int
     *
     * $resultrows; Number of rows from query      @var int
     * $table; Last table used in query            @var string
     *
     * $connection; Connection link identifier     @var resource
     * $preg_sql_noquote; Regular Expression 
     *                    pattern for fix_sql()    @var string
     * $preg_sql_quote; Regular Expression 
     *                    pattern for fix_sql()    @var string
     * $preg_lst_noquote; Regular Expression 
     *                    pattern for fix_list()   @var string
     * $preg_lst_quote; Regular Expression 
     *                    pattern for fix_list()   @var string
     * Be careful with backrefs
     * @access mixed
     */
    public $fetch_default = FETCH_OBJECT;
    
    protected $host    = 'localhost'; 
    protected $user    = 'root'; 
    protected $pass    = ''; 
    protected $dbname  = 'database'; 
    protected $socket; 
    protected $port    = 3306; 
    
    protected $resultrows    = 0;
    protected $table         = '';
    
    private $connection        = false; 
    private $preg_sql_noquote  = '/^([a-zA-Z0-9\._]+ *= *[^, ]+)((, )|$)(.*)/i';
    private $preg_sql_quote    = '/^([a-zA-Z0-9\._]+( *= *[\'"`].*?[\'"`])?)((, )|$)(.*)/i';
    private $preg_lst_noquote  = '/^([a-zA-Z0-9\._]*) *(,|$) *(.*)$/is';
    private $preg_lst_quote    = '/^{quote}(.*?){quote} *(,|$) *(.*)$/is';

    /**
     * Common Variables;
     * 
     * $tracklog; Put every event in array         @var bool
     * $showlog; Print log array to screen (debug) @var bool
     * $logtofile; Log tracks to a data file       @var bool
     * $logfulltofile; Entire log array is         @var bool
     * serilized into file
     * @access protected
     */
    protected $common = array(
        'tracklog'      => true,
        'showlog'       => false,
        'logtofile'     => true,
        'logfulltofile' => true
    );

    /**
     * Debug Variables;
     * $session; Session ID for class              @var string
     * $birth; Time the class began                @var float
     * $querytime; Time spent executing queries    @var float
     * $querycount; Number of executed queries     @var int
     * $log; Log of actions & errors               @var array
     * $log; Log of just errors                    @var array
     * $result; Result from query                  @var resource
     */
    protected $session;
    protected $birth      = 0;
    protected $querytime  = 0; 
    protected $querycount = 0; 
    protected $log        = array(); 
    protected $error_log  = array();
    protected $result     = array();  
    
    /**
     * Constructor; sets up connection varables and connects
     *
     * @param string $db_host Server
     * @param string $db_user Username
     * @param string $db_pass Password
     * @param string $db_name Database Name
     * @param int $db_port Database Port
     * @param string $db_socket Database Socket
     * @author Paul Williamson <webmaster@protonage.net>
     * @access private
     * @return void
     */
    function __construct($db_host = NULL, $db_user = NULL,
        $db_pass = NULL, $db_name = NULL,
        $db_port = 3306, $db_socket = '')
    {
        $this->birth   = $this->timenow();
        $this->session = md5(round($this->birth, 3)*1000);
        
        $this->log=array(
            'session' => $this->session,
            'date'    => date("F jS, Y, H:i:s T"),
            'birth'   => $this->birth,
            'age'     => $this->age(),
            'mysql'   => array()
        );
        
        $this->set_param($db_host, 'host');
        $this->set_param($db_user, 'user');
        $this->set_param($db_pass, 'pass');
        $this->set_param($db_name, 'dbname');
        $this->set_param($db_port, 'port');
        $this->set_param($db_socket, 'socket');
        
        try {
            $this->connect();
        } catch (Exception $e) {
            $this->track('error', '__construct', self::VERSION 
                 . " session Id: {$this->log['session']}" 
                 . ' could not establish a connection'
                 . ' to server ' . $this->host . ' and'
                 . ' therefore could not be created.'
                 . ' View error log for more details.',
                 $e
            );       
            trigger_error(self::VERSION 
                 . " session Id: {$this->log['session']} could not"
                 . ' be created! The class will now terminate. Exception:'
                 . ' ' . $e->getmessage(), 
                E_USER_ERROR
            );
        }
        $this->track('event', '__construct', self::VERSION
            . " session Id: {$this->log['session']} has been"
            . " constructed @ {$this->log['date']}"
        );
    }
    
    /**
     * Destruct; destroys connection and reports logs
     *
     * @param boolean $re Reconnect
     * @author Paul Williamson <webmaster@protonage.net>
     * @access private
     * @return void
     */
    function __destruct()
    {
        $this->kill();
        $this->track('event', '__destruct', self::VERSION 
             . " session Id: {$this->log['session']} has been"
             . ' destructed @ ' . date(self::DATE_FORMAT) . '.'
        );
        $this->log['mysql'] = array_merge($this->log['mysql'], 
            array(
                'querycount' => $this->querycount,
                'querytime'  => $this->querytime
            )
        );
        $this->log['age'] = $this->age();
        if ($this->common['logtofile'])     $this->do_log();
        if ($this->common['logfulltofile']) $this->do_fulllog();
        if ($this->common['showlog'])       $this->printlog();
    }
    
    /**
     * Call; Picks up any undeclaired methods
     *
     * @param string $m Method called
     * @author Paul Williamson <webmaster@protonage.net>
     * @access private
     * @return void
     */
    function __call($m)
    {
        $from = trim($m);
        $this->track('error', $from, 
            'Method does not exists!'
        );
    }
    
    /**
     * Get; Get a variable's value
     *
     * @param string $var variable
     * @author Paul Williamson <webmaster@protonage.net>
     * @access private
     * @return mixed
     */
    function __get($var)
    {
        if (isset($this->common[$var])) {
            return $this->common[$var];
        } else {
            $this->track('error',
                '__get',
                "Variable {$var} does not exists"
            );
            return null;
        }
    }
    
    /**
     * Set; Set a variable's value
     *
     * @param string $var variable
     * @param string $val value to be assigned
     * @author Paul Williamson <webmaster@protonage.net>
     * @access private
     * @return void
     */
    function __set($var, $val)
    {
        if (isset($this->common[$var])) {
            $this->common[$var] = $val;
        } else {
            $this->track('error',
                '__set',
                "Variable {$var} does not exists"
            );
        }
    }
    
    /**
     * SelectDB; Selects the database
     *
     * @param string $db Database to select
     * @param resouce $conn conection resource
     * @author Paul Williamson <webmaster@protonage.net>
     * @access public
     * @return boolean
     */
    public function selectdb($db, $conn)
    {
        if (!@mysql_select_db($db, $conn)) {
            $this->track('error', 'connect',
                "Could not select database {$this->dbname}.",
                mysql_error($this->connection)
            );
            $this->connection = false;
            return false;
        }
        return true;
    }
     
    /**
     * Connect; connects to a database
     *
     * @param boolean $re Reconnect
     * @author Paul Williamson <webmaster@protonage.net>
     * @access public
     * @return boolean
     */
    public function connect($re = false)
    {
        $server = "{$this->host}:{$this->port}" 
        . (!$this->socket ? '' : $this->socket);
        $r = $re ? 'Rec' : 'C';
        if (!$this->connection || !$re) {
            if (($this->connection = @mysql_connect($server, $this->user, $this->pass)) === false) {
                $this->track('error', 'connect',
                    "Could not open a connection to `{$server}`.",
                    mysql_error()
                );
                throw new Exception(mysql_error($this->connection));
                return false;
            }
            if (!$this->selectdb($this->dbname, $this->connection)) {
                throw new Exception('Could not select database: ' . $this->dbname);
                return false;
            }
        } else {
            if (!mysql_ping($this->connection)) {
                $this->track('error', 'connect',
                    "Could not reconnect to `{$server}`.",
                    mysql_error($this->connection)
                );
                throw new Exception(mysql_error($this->connection));
                return false;
            }
        }
        $this->track('event', 'connect',
            "{$r}onnected to `{$server}`."
        );
        return true;
    }
    
    /**
     * Query; Sends query to database
     *
     * @param string $query Query String
     * @author Paul Williamson <webmaster@protonage.net>
     * @access public
     * @return resource
     */
    final public function query($query)
    {
        $start      = $this->timenow();
        $result     = @mysql_query($query, $this->connection);
        $querytime  = $this->timenow()-$start;
        $querydeath = $this->age();
        
        if ($result !== false) { 
            $this->track('event', 'query',
                "Query: {$query}", '',
                $querydeath
            );
        } else {
            $this->track('error', 'query',
                "Query Failed: `{$query}`",
                mysql_error($this->connection),
                $querydeath
            );
            throw new Exception(mysql_error($this->connection));
            return false;
        }
        
        $this->querytime  += $querytime;
        $this->querycount ++;
        
        $data = array();
        
        if (substr(trim(strtoupper($query)), 0, 6) == 'SELECT') {
            $data = mysql_fetch_array(mysql_query("EXPLAIN {$query}", 
                $this->connection), 
                MYSQL_ASSOC
            );
            $this->resultrows = mysql_num_rows($result);
        }
        
        $type          = '';
        $rows          = 0;
        $key           = '';
        $possible_keys = '';
        $Extra         = '';
        $intensity     = 1;
        
        extract($data);
        
        if ($querytime > 0.05) $intensity++;
        if ($querytime > 0.1)  $intensity++;
        if ($querytime > 1)    $intensity++;
        if ($type == 'ALL')    $intensity++;
        if ($type == 'index')  $intensity++;
        if ($type == 'range')  $intensity++;
        if ($type == 'ref')    $intensity++;
        if ($rows >= 200)      $intensity++;
        
        if (!empty($possible_keys) && empty($key)) {
            $intensity++;
        }
        
        if ((strpos($Extra, 'Using filesort') !== false) || (strpos($Extra, 'Using temporary') !== false)) {
            $intensity++;
        }
        
        $data['query']           = $query;
        $data['query_time']      = $querytime;
        $data['query_death']     = $querydeath;
        $data['query_intensity'] = $intensity;
        $data['result_rows']     = $this->resultrows;
        
        $this->log['mysql'][] = $data;
        
        if (isset($Comment)) {
            $this->track('error', 'query',
                "Query Warning",
                $Comment
            );
            throw new Exception($Comment);
            $result = false;
        }
        return $result;
    }
    
    /**
     * Fetch_Query; Send a query and fetch the results
     * 
     * @param mixed $query Query that will be sent
     * @param int $fetch Controls the result datatype
     * @author Paul Williamson <webmaster@protonage.net>
     * @access public
     * @return mixed
     */
    public function fetch_query($query, $fetch = NULL)
    {
        $this->set_param($fetch, 'fetch_default');
        $return = false;
        
        try {
            if (($result = $this->query($query)) !== false) {
                while($row = $this->fetch($result, $fetch)) {
                    $return[] = $row;
                }
                $this->result = $return;
            }
        } catch (Exception $e) {
            $this->track('error', 'fetch_query',
                $e->getmessage()
            );
        }
        $this->track('event', 'fetch_query',
            'Successful Call (Query: `' . $query . '`)'
        );
        return $return;
    }
    
    /**
     * Fetch_Col; Fetch (a) Coloumn(s) of data from the database
     * 
     * @param mixed $field Field(s) that will be used
     * @param mixed $table Table that will be used
     * @param int $fetch Controls the result datatype
     * @param string $order field to order by (append DESC if needed)
     * @param mixed $limit Limit the result to this number
     * @author Paul Williamson <webmaster@protonage.net>
     * @access public
     * @return mixed
     */
    public function fetch_col($field = NULL, $table = NULL, 
        $fetch = NULL, $order = NULL, $limit = NULL)
    {
        $this->set_param($table, 'table');
        $this->set_param($fetch, 'fetch_default');
        $sql    = array();
        $return = false;
        
        if (empty($field)) {
            unset($field);
            $field = $this->fetch(
                $this->query("SHOW COLUMNS FROM {$table}"), 
                FETCH_NUM
            );
            $field = $field[0];
        }
        
        for ($z = 0; $z < 2; $z++) {
            $a = $z ? 'table' : 'field';
            $sql[$a] = is_array($$a) ? implode(", ", $$a) : $$a;
        }
        
        $sql['order'] = $order;
        $sql['limit'] = $limit;
        
        try {
            $query = $this->fix_sql($sql);
            if (($result = $this->query($query)) !== false) {
                while($row = $this->fetch($result, $fetch)) {
                    $return[] = $row;
                }
                $this->result = $return;
            }
        } catch (Exception $e) {
            $this->track('error', 'fetch_col',
                $e->getmessage()
            );
        }
        $this->track('event', 'fetch_col',
            'Successful Call (Query: `' . $query . '`)'
        );
        return $return;
    }
        
    /**
     * Fetch_Row; Fetch (a) Row(s) of data from the database
     *
     * This function is nearly identical to Fetch Column but instead
     * this function will fetch all fields in the table instead of 
     * the ones listed in the arguments. Also this function has all
     * optional arguments.
     * 
     * @param mixed $field Field(s) that will be used
     * @param mixed $table Table that will be used
     * @param int $fetch Controls the result datatype (array or object)
     * @param string $order field to order by (append DESC if needed)
     * @param mixed $limit Limit the result to this number
     * @author Paul Williamson <webmaster@protonage.net>
     * @access public
     * @return mixed
     */
    public function fetch_row($field = NULL, $table = NULL, 
        $fetch = NULL, $order = NULL, $limit = NULL)
    {
        $this->set_param($table, 'table');
        $this->set_param($fetch, 'fetch_default');
        $sql    = array();
        $return = false;
        
        for ($z = 0; $z < 2; $z++) {
            $a = $z ? 'table' : 'field';
            $sql[$a] = is_array($$a) ? implode(", ", $$a) : $$a;
        }
        
        $sql['order'] = $order;
        $sql['limit'] = $limit;
        
        try {
            $query = $this->fix_sql($sql, 'ALL');
            if (($result = $this->query($query)) !== false) {
                while($row = $this->fetch($result, $fetch)) {
                    $return[] = $row;
                }
                $this->result = $return;
            }
        } catch (Exception $e) {
            $this->track('error', 'fetch_row',
                $e->getmessage()
            );
        }
        $this->track('event', 'fetch_row',
            'Successful Call (Query: `' . $query . '`)'
        );
        return $return;
    }
        
    /**
     * Fetch_Search; Fetch data bassed on a search pattern
     *
     * This function will pass a regular expression string ($find)
     * to the fix_sql private function.
     * 
     * @param string $find The varable that will be found in the DB (regexp)
     * @param mixed $field Field(s) that will be used
     * @param mixed $table Table that will be used
     * @param int $fetch Controls the result datatype (array or object)
     * @param string $order field to order by (append DESC if needed)
     * @param mixed $limit Limit the result to this number
     * @author Paul Williamson <webmaster@protonage.net>
     * @access public
     * @return mixed
     */
    public function fetch_search($find, $field = NULL, $table = NULL, 
        $fetch = NULL, $order = NULL, $limit = NULL)
    {
        $this->set_param($table, 'table');
        $this->set_param($fetch, 'fetch_default');
        $sql    = array();
        $return = false;
        
        if (empty($field)) {
            unset($field);
            $field = $this->fetch(
                $this->query("SHOW COLUMNS FROM {$table}"), 
                FETCH_NUM
            );
            $field = $field[0];
        }
        
        for ($z = 0; $z < 2; $z++) {
            $a = $z ? 'table' : 'field';
            $sql[$a] = is_array($$a) ? implode(", ", $$a) : $$a;
        }
        
        $sql['search'] = addcslashes($find, '\'');
        $sql['order'] = $order;
        $sql['limit'] = $limit;
        
        try {
            $query = $this->fix_sql($sql, 'ALL');
            if (($result = $this->query($query)) !== false) {
                while($row = $this->fetch($result, $fetch)) {
                    $return[] = $row;
                }
                $this->result = $return;
            }
        } catch (Exception $e) {
            $this->track('error', 'fetch_search',
                $e->getmessage()
            );
        }
        $this->track('event', 'fetch_search',
            'Successful Call (Query: `' . $query . '`)'
        );
        return $return;
    }
        
    /**
     * Insert; Insert data into a table
     * 
     * @param mixed $fields Field(s) that will inserted data
     * @param mixed $values Value(s) that will be inserted
     * @param string $table Table that will be used
     * @author Paul Williamson <webmaster@protonage.net>
     * @access public
     * @return boolean
     */
    public function insert($fields, $values, $table = NULL)
    {
        $this->set_param($table, 'table');
        $sql = array();
        
        try {
            for ($i = 0; $i < 2; $i++) {
                $a = $i ? 'fields' : 'values';
                ${substr($a, 0, 5)} = !is_array($$a) ? 
                    $this->fix_list($$a) : 
                    $$a;
            }
        } catch (Exception $e) {
            $this->track('error', 'insert',
                $e->getmessage()
            );
            return false;
        }
        
        if (count($field) != count($value)) {
            $this->track('error', 'insert',
                'Fields and Values do not match in array size'
            );
            return false;
        }
        
        unset($fields);
        foreach ($field as $f) {
            if (!$this->field_exists($f, $table)) {
                $this->track('error', 'insert',
                    "Field: {$f} does not exists in Table: {$table}"
                );
                return false;
            }
            $fields .= "{$f}, ";
        }
        
        $sql['insert'] = $table;
        $sql['field']  = $this->list_trim($fields);
        $sql['value']  = $value;
        
        try {
            $query = $this->fix_sql($sql);
            $this->query($query);
        } catch (Exception $e) {
            $this->track('error', 'insert',
                $e->getmessage()
            );
            return false;
        }
        $this->track('event', 'insert',
            'Successful Call (Query: `' . $query . '`)'
        );
        return true;
    }
        
    /**
     * Delete; Delete data from a table
     *
     * Call this function with limit argument set to -1
     * to truncat the table.
     * 
     * @param mixed $wfield Row that will be deleted
     * @param boolean $pass A verification array, set it to true
     *  if you are sure you do not want to add a limit to a no-where-clause
     *  DELETE query
     * @param string $table Table that will be used
     * @param mixed $limit Limit the result to this number
     * @author Paul Williamson <webmaster@protonage.net>
     * @access public
     * @return boolean
     */
    public function delete($wfield = NULL, $pass = false, $table = NULL, $limit = NULL)
    {
        $this->set_param($table, 'table');
        $sql = array();
        
        if (!$pass && is_null($wfield)) {
            $this->track('error', 'delete',
                'Function refused to execute query because '
              . 'table ' . $table . ' would have been truncated. '
              . 'To override this error message, set the second '
              . 'argument ($pass) to true.'
            );
            return false;
        }
        
        $sql['delete'] = $table;
        $sql['field']  = $wfield;
        $sql['limit']  = $limit;
        
        try {
            $query = $this->fix_sql($sql);
            $this->query($query);
        } catch (Exception $e) {
            $this->track('error', 'delete',
                $e->getmessage()
            );
            return false;
        }
        $this->track('event', 'delete',
            'Successful Call (Query: `' . $query . '`)'
        );
        return true;
    }
        
    /**
     * Update; Update data in a table
     * 
     * @param mixed $fields Field(s) that will be changed
     * @param mixed $values Value(s) that will be assigned
     * @param string $wfields Where fields clause
     * @param string $table Table that will be used
     * @param mixed $limit Limit the result to this number
     * @author Paul Williamson <webmaster@protonage.net>
     * @access public
     * @return boolean
     */
    public function update($fields, $values, $wfields = NULL, $table = NULL, $limit = NULL)
    {
        $this->set_param($table, 'table');
        $sql = array();
        
        try {
            for ($i = 0; $i < 2; $i++) {
                $a = $i ? 'fields' : 'values';
                ${substr($a, 0, 5)} = !is_array($$a) ? 
                    $this->fix_list($$a) : 
                    $$a;
            }
        } catch (Exception $e) {
            $this->track('error', 'update',
                $e->getmessage()
            );
            return false;
        }
        
        if (count($field) != count($value)) {
            $this->track('error', 'update',
                'Fields and Values do not match in array size'
            );
            return false;
        }
        
        unset($fields);
        $num = count($field);
        for ($i = 0; $i < $num; $i++) {
            $f = $field[$i];
            $v = $value[$i];
            if (!$this->field_exists($f, $table)) {
                $this->track('error', 'update',
                    "Field: {$f} does not exists in Table: {$table}"
                );
                return false;
            }
            $fields .= "{$f}, ";
            $set    .= "`{$f}` = '" . addcslashes($v, '\'') . "', ";
        }
        
        $sql['update'] = $table;
        $sql['field']  = $wfields;
        $sql['set']    = $this->list_trim($set);
        $sql['limit']  = $limit;
        
        try {
            $query = $this->fix_sql($sql);
            $this->query($query);
        } catch (Exception $e) {
            $this->track('error', 'update',
                $e->getmessage()
            );
            return false;
        }
        $this->track('event', 'update',
            'Successful Call (Query: `' . $query . '`)'
        );
        return true;
    }
    
    /**
     * Get_LastQuery; return string of the last executed query
     *
     * @author Paul Williamson <webmaster@protonage.net>
     * @access public
     * @return string
     */
    public function get_lastquery()
    {
        $num = count($this->log['mysql']) - 1;
        return $this->log['mysql'][$num]['query'];
    }
    
    /**
     * Get_Result; return result from last SELECT query
     *
     * @author Paul Williamson <webmaster@protonage.net>
     * @access public
     * @return mixed
     */
    public function get_result()
    {
        return $this->result;
    }
    
    /**
     * Get_Rows; return num rows from last SELECT query
     *
     * @author Paul Williamson <webmaster@protonage.net>
     * @access public
     * @return int
     */
    public function get_rows()
    {
        return $this->resultrows;
    }
    
    /**
     * Get_Log; return result from last SELECT query
     *
     * @param string $key If provided, function will return array of
     * only the key given. track, mysql, session, etc..
     * @author Paul Williamson <webmaster@protonage.net>
     * @access public
     * @return array
     */
    public function get_log($key = NULL)
    {
        return is_null($key) ? $this->log : $this->log[$key];
    }
    
    /**
     * Get_Error; Return the last error (default) or if the first
     * argument set to true then it will return the full error array
     *
     * @param boolean $full Return the full array (default false)
     * @author Paul Williamson <webmaster@protonage.net>
     * @access public
     * @return mixed
     */
    public function get_error($full = false)
    {
        return $full ? $this->error_log : end($this->error_log);
    }
    
    /**
     * Debug;
     *
     * Not quite finished with this function. I plan to 
     * make this function return a nice HTML layed out page
     * of all the logs, stored in raw file, and optomization solutions.
     *
     * @author Paul Williamson <webmaster@protonage.net>
     * @access public
     * @return string
     */
    public function debug()
    {
        //incomplete
    }

    /**
     * Field_Exists; See if field exists in givin table
     *
     * @param string $field Field to be found
     * @param string $table Table that will be searched
     * @author Paul Williamson <webmaster@protonage.net>
     * @access public
     * @return boolean
     */
    public function field_exists($field, $table = NULL)
    {
        $this->set_param($table, 'table');
        $exists = false;
        
        if (is_array($field) || is_array($table)) {
            $this->track('error', 'field_exists',
                'Function does not accept arrays'
            );
            return $exists;
        }
        try {
            $result = mysql_query('SHOW COLUMNS FROM ' . $table, $this->connection);
            while($row = $this->fetch($result, FETCH_ASSOC)) {
                if (strtolower($row['Field']) == strtolower($field)) {
                    $exists = true;
                    break;
                } 
            }
        } catch(Exception $e) {
            $this->track('error', 'field_exists',
                $e->getmessage()
            );
            return $exists;
        }
        
        return $exists;
    }

    /**
     * Track; Build log array
     *
     * @param string $type  Type of entry
     * @param string $from  Function orgin
     * @param string $msg   Message
     * @param string $error Server error message
     * @author Paul Williamson <webmaster@protonage.net>
     * @access private
     * @return void
     */
    private function track($type, $from, $msg, $error = '', $age = '')
    {
        if (!empty($error)) $this->error_log[] = $error;
        if (!$this->common['tracklog']) return;
        
        $new_entry = array(
            'type' => $type,
            'from' => $from,
            'msg'  => trim($msg),
            'age'  => empty($age) ? $this->age() : $age
        );
        $this->log['track'][] = empty($error) ? 
            $new_entry : 
            array_merge($new_entry, 
                array(
                    'error' => $error
                )
            );
    }
    

    /**
     * Fix_Sql; Fix the SQL array and return a queryable string
     *
     * @param array $sql SQL array
     * @param string $type Type of fetch
     * @author Paul Williamson <webmaster@protonage.net>
     * @access protected
     * @return string
     *
     * The long do statment in the fields case simply strips the field
     * string into an array and then makes a where clause if needed
     */
    final protected function fix_sql($sql, $Extra = NULL)
    {
        if (!is_array($sql)) {
            $this->track(
                "error", "fix_sql", 
                "No array found in `{$sql}`."
            );
            return false;
        }
        $sql_type = 'SELECT';
        
        foreach ($sql as $type => $value) {
            switch($type) {
            case 'delete':
                $delete = 'DELETE FROM `' . $value . '`';
                $sql_type = 'DELETE';
                break; //case 'delete'
            case 'insert':
                $insert = 'INSERT INTO `' . $value . '` ';
                $sql_type = 'INSERT';
                break; //case 'insert'
            case 'update':
                $update = 'UPDATE `' . $value . '`';
                $sql_type = 'UPDATE';
                break; //case 'insert'
            case 'set':
                $sql_set = 'SET ' . $value;
                break; //case 'insert'
            case 'value':
                foreach ($value as $v) {
                    $sql_values .= "'" . addcslashes($v, '\'') . "', ";
                }
                $this->list_trim($sql_values);
                break; //case 'insert'
            case 'search':
                $like = "LIKE '%{$value}%'";
                break; //case 'search'
            case 'table':
                $tables = $sql['table'];
                $from   = 'FROM `' . $tables . '`';
                break; //case 'table'
            case 'field':
                if (is_null($value)) {
                    $select = '*';
                    break;
                }
                $num_to_wheres = 0;
                $buf = $value;
                do {
                    $pre_buf = $buf;
                    for ($i = 0; $i < 2; $i++) {
                        $p = $i ? $this->preg_sql_noquote : 
                            $this->preg_sql_quote;
                        $r = $i ? '$4' : '$5';
                        while(preg_match($p, $buf)) {
                            $fields[] = preg_replace($p, '$1', $buf);
                            $buf      = preg_replace($p, $r, $buf);
                            if (preg_match('/=/', end($fields))) $num_to_wheres++;
                        }
                    }
                    if ($buf == $pre_buf) { 
                        $this->track(
                            "error", "fix_sql", 
                            "Parse error in Fields `{$value}`."
                        );
                        throw new Exception("Parse error in Fields `{$value}`.");
                        return false;
                    }
                } while(!empty($buf));
                
                $in_fields = array();
                $num_fields = count($fields);
                for ($i = 0; $i < $num_fields; $i++) {
                    $field = $fields[$i];
                    if (preg_match('/=/', $field)) {
                        $sql_where .= $this->fix_where($field);
                    }
                    $field = preg_replace(
                        '/(^[a-zA-Z0-9\._]+).*$/i',
                        '$1',
                        $field
                    );
                    if (array_search($field, $in_fields) === false) {
                        $sql_fields .= '`' . $field . '`, ';
                    }
                    $in_fields[] = $field;
                }
                $this->list_trim($sql_where, ' AND ');
                $this->list_trim($sql_fields);
                break; //case 'field'
            case 'order':
                $order =  is_null($value) ? '' : 'ORDER BY ' . $value;   
                break; //case 'order'
            case 'limit':
                if (!preg_match('/^[0-9]+(, ?[0-9]+)?$/', $value)) {
                    $limit = $value;
                } else {
                    $limit = '';
                }
                break; //case 'limit'
            } //switch($type)
        } //foreach ($sql as $type => $value)
        
        $select = $Extra != 'ALL' ? 'SELECT ' . 
            $sql_fields :
            'SELECT *';
        $where = !empty($sql_where) ? 
            'WHERE ' . $sql_where : 
            '';
        $insert = $insert . '(' . $sql_fields . ') VALUES (' . $sql_values . ')';
        $like = !empty($sql_where) ? 
            $like : 'WHERE ' . $sql_fields . 
            ' ' . $like;
            
        switch($sql_type) {
        case 'SELECT':
            $query = "{$select} {$from} {$where} {$like} {$order} {$limit}";
            break;
        case 'INSERT':
            $query = $insert;
            break;
        case 'UPDATE':
            $query = "{$update} {$sql_set} {$where} {$limit}";
            break;
        case 'DELETE':
            $query = "{$delete} {$where} {$limit}";
            break;
        }
            
        return trim(preg_replace('/ +/', ' ', $query)) . ';';
    }
    
    /**
     * Fix_Where; Return a where clause with proper MySQL syntax
     *
     * @param string $field Field that will be included in where clause
     * @author Paul Williamson <webmaster@protonage.net>
     * @access protected
     * @return string
     */
    protected function fix_where($field)
    {
        $parts = preg_split('/ *= */i', $field, 2);
        $wfield  = '`' . str_replace('`', '', $parts[0]) . '`=';
        // addcslashes to prevent query parse error
        $wfield .= '\'' . addcslashes(
            preg_replace('/(^[\'"`])|([\'"`]$)/i', '', 
                $parts[1]
            ), 
            '\''
        ) . '\'';
        return $wfield . ' AND ';
    }
    
    /**
     * Fix_List; Return an array of broken elements from a list 
     * seperated by commas and quotes
     *
     * @param string $list List to be converted to array
     * @author Paul Williamson <webmaster@protonage.net>
     * @access protected
     * @return array
     */
    protected function fix_list($list)
    {
        $buf = $list;
        $result = array();
        do {
            $pre_buf = $buf;
            
            for ($i = 0; $i < 2; $i++) {
                $q = $i ? preg_replace('/^ *([`\'"]).*/is', '$1', $buf) : '';
                $p = $i ? str_replace('{quote}', $q, $this->preg_lst_quote) : 
                    $this->preg_lst_noquote;
                while (preg_match($p, $buf) && !empty($buf)) {
                    $result[] = preg_replace($p, '$1', $buf);
                    $buf = preg_replace($p, '$3', $buf);
                }
            }
            if ($buf == $pre_buf) {
                $this->track(
                    "error", "fix_list", 
                    "Parse error in List `{$list}`."
                );
                throw new Exception("Parse error in List `{$list}`.");
                return false;
            }
        } while(!empty($buf));
        return $result;
    }

    /**
     * Set_Param; Set an argument value if already exists
     *
     * @param string  &$arg Argument varable
     * @param string  $name Argument name
     * @author Paul Williamson <webmaster@protonage.net>
     * @access private
     * @return void
     */
    private function set_param(&$arg, $name)
    {
        $arg = (is_null($arg)) ? $this->$name : $arg;
        if (is_null($arg)) {
            $this->track('error', 'set_param',
                'Parameter `' . $name . '` is not set'
            );
            throw new Exception('Parameter `' . $name . '` is not set');
            trigger_error('Parameter `' . $name . '` is not set', E_USER_ERROR);
        }
        $this->$name = $arg;
    }

    /**
     * Fetch; Impliment the mysql_fetch_* functions
     *
     * @param resource $res Query result
     * @param int $fetch Fetch Type
     * @author Paul Williamson <webmaster@protonage.net>
     * @access protected
     * @return mixed
     */
    protected function fetch($res, $fetch)
    {
        switch ($fetch) {
        case FETCH_ASSOC:
            $this->fetch_default = $fetch;
            return mysql_fetch_assoc($res);
            break;
        case FETCH_NUM:
            $this->fetch_default = $fetch;
            return mysql_fetch_row($res);
            break;
        case FETCH_OBJECT:
            $this->fetch_default = $fetch;
            return mysql_fetch_object($res);
            break;
        default:
            return mysql_fetch_assoc($res);
        }
    }

    /**
     * List_Trim; Trim the end of a list from a loop
     *
     * Function will take out extra ', ' on the end of a list string
     *
     * @param string &$str String to trim
     * @author Paul Williamson <webmaster@protonage.net>
     * @access protected
     * @return string
     */
    protected function list_trim(&$str, $tpat = ', ')
    {
        $preg_trim = '/(.*?)' . $tpat . '$/i';
        $str = preg_replace($preg_trim, '$1', $str);
        return $str;
    }

    /**
     * Kill; Disconnect from database
     *
     * @author Paul Williamson <webmaster@protonage.net>
     * @access private
     * @return void
     */
    private function kill()
    {
        @mysql_close($this->connection);
        $this->track('event', 'kill',
            "Connect to {$this->host} has been forced to close."
        );
    }
    
    /**
     * TimeNow; returns the current time
     *
     * In PHP 5, microtime() was givin a boolean
     * param, if true, microtime() would return a float
     * which is exactly what this function does.
     *
     * @author Paul Williamson <webmaster@protonage.net>
     * @access protected
     * @return float
     */
    protected function timenow()
    {
        /**
         * For PHP4:
         *
         * list($a, $b) = explode(' ', microtime());
         * return $a + $b;
         *
         * PHP5 makes it less painful with the same result.
         * Thanks to the new boolean argument provided by microtime()
         */
        return microtime(true);        
    }  
      
    /**
     * Age; how long the class has been alive
     *
     * @author Paul Williamson <webmaster@protonage.net>
     * @access protected
     * @return float microtime
     */
    protected function age()
    {
        return $this->timenow()-$this->birth;
    }
    
    /**
     * Do_FullLog; Write log track array to a file
     *
     * @author Paul Williamson <webmaster@protonage.net>
     * @access private
     * return void
     */
    /**
     * Do_Log; Write full log array to a file
     *
     * @author Paul Williamson <webmaster@protonage.net>
     * @access private
     * return void
     */
    private function do_fulllog()
    {
        $path = self::LOG_PATH;
        if (is_dir($path)) {
            
            for ($i = 1; file_exists($file = $path . '/simplesql_raw.' . $i); $i++) {
                if (filesize($file) < self::MAX_SIZE) break;
            }
            
            if ($handle = fopen($file, 'a')) {
                $add = '$Id' . serialize($this->log) . '/$Id' . "\n";
                if (fwrite($handle, $add) === false) {
                    trigger_error("Cannot write to file `{$file}`.", E_WARNING);
                }
            } else {
                trigger_error("Cannot open file `{$file}` for append.", E_WARNING);
            }
        } else {
            trigger_error("Cannot find path `{$path}`.", E_WARNING);
        }
    }
    
    /**
     * Do_Log; Write log track array to a file
     *
     * @author Paul Williamson <webmaster@protonage.net>
     * @access private
     * return void
     */
    private function do_log()
    {
        if (!$this->common['tracklog']) return ;
        $path = self::LOG_PATH;
        if (is_dir($path)) {
            
            for ($i = 1; file_exists($file = $path . '/simplesql_log.' . $i); $i++) {
                if (filesize($file) < self::MAX_SIZE) break;
            }
            
            if ($handle = fopen($file, 'a')) {
                $add = "\n\n=========================";
                $add .= "\nLog for session ID {$this->log['session']} 
                    @ {$this->log['date']}";
                $add .= "\n=========================\n";
                foreach ($this->log['track'] as $line  => $arr) {
                    if (is_int($line)) {
                        $tab = strlen($arr['from']) < 8 ? "\t" : '';
                        $add .= "\t{$line}: " . strtoupper($arr['type']) 
                        . "\t" . strtoupper($arr['from']) . "{$tab}\t{$arr['msg']}\n";
                    }
                }
                if (fwrite($handle, $add) === false) {
                    trigger_error("Cannot write to file `{$file}`.", E_WARNING);
                }
            } else {
                trigger_error("Cannot open file `{$file}` for append.", E_WARNING);
            }
        } else {
            trigger_error("Cannot find path `{$path}`.", E_WARNING);
        }
    }
    
    /**
     * PrintLog; Print the log array to the screen
     *
     * @author Paul Williamson <webmaster@protonage.net>
     * @access public
     * @return void
     */
    public function printlog()
     {
         print '<pre>';
         print_r($this->log);
         print '</pre>';
     }
} // end simplesql

?>

 
  Advertise on this site Advertise on this site   Site map Site map   Statistics Statistics   Site tips Site tips   Privacy policy Privacy policy   Contact Contact  

For more information send a message to :
info at phpclasses dot org.
Copyright (c) Icontem 1999-2009 PHP Classes - PHP Class Scripts
  PHP Book Reviews - Reviews of books and other products