<?php
/*
a simple MySQL database handler class
Author: slave@codegrunt.com / http://codegrunt.com

OVERVIEW:

The purpose of this class is to make the most common cases of MySQL usage a lot simpler.
There are more feature complete MySQL handlers out but their added complexity does not
seem to ever add to their usability for common situations from what I have found.  This class
is easy to understand and use.  Results are returned as an array with associative column names.

For the average shared hosting MySQL / PHP installations there is little to no benefit
to grabbing a result one record at a time (it is not saving memory) and returning
query results as a single array in one shot tends to result in much cleaner,
easier to follow code which is why I find this class so useful.

There is no explicit destructor here as PHP closes database connections upon script completion internally.

There are two magic values returned in the first row of query results where relevant:

'insert_id'
'numrows'

For the magic "insert_id" value to be generated, the code assumes that "INSERT"
appears at the start of the passed query (case is not important).  For "affected_rows" attribute to be set,
the code assumes that "UPDATE" appears at the start of the passed query.

Error handling is mostly up to the caller though you can define "_debug_sql" if you want
the script to stop running if it encounters a MySQL error.  For development this should
definitely be set.

There are also a few utility methods here for dealing with the result array.
The most interesting one is "row2obj()" which assuming that you have setup your
MySQL database with column names that match your object attributes (or used aliases that do)
will take a MySQL result row and copy the values to a passed object.  This function relies
on an external method "$obj->check_attribute($k)" which needs to be present on the object to
confirm that the attribute exists.

USAGE:

To connect to your database you can either use defines and no arguments or pass server connection paramaters in the
constructor call (which is useful if you need multiple database connections at once):

// example using assumed defines

define('_db_server','mysql.example.com');
define('_db_user','gocanucksgo');
define('_db_pass','IG&(7821[asljk');

$GLOBALS['_mysql']=new cgMySQL;
$GLOBALS['_mysql']->select_db('my_database');

// example using passed paramaters

$GLOBALS['_mysql']=new cgMySQL($server,$user,$pass);
$GLOBALS['_mysql']->select_db('my_database');

// example of performing a query

$GLOBALS['_mysql']->do_query('SELECT favourite_team FROM nhl WHERE me="codegrunt" LIMIT 0,1');
if($GLOBALS['_mysql']->result[0]['numrows']>0)
{
    echo '<p>I only have '.$GLOBALS['_mysql']->result[0]['numrows'].' favourite team
    and that is The '.$GLOBALS['_mysql']->result[0]['favourite_team'].'.</p>';
}

The result set will look like:

array(
    0=>array(
        'numrows'=>1,
        'favourite_team'=>'Vancouver Canucks'
    )
);

The output will look like:

<p>I only have 1 favourite team
    and that is The Vancouver Canucks.</p>

*/

////////////////////////////
// cgMySQL class
//
// uncomment to cause stop script execution upon error
// define('_debug_sql',1);

class cgMySQL
{
    public 
$err// array of error messages
    
public $result// array of query results
    
public $rows_affected;

    private 
$db;

    function 
__construct($server='',$user='',$pass='')
    {
        
$this->err=array();
        
$this->db=NULL;

        
// see if if we are using passed arguments or assumed defines
        
foreach(array('server','user','pass') AS $v)
        {
            if(
strlen($$v)<&& defined('_db_'.$v)) $$v=constant('_db_'.$v);
        }
        if(
$server!='' && $user!='')
        {
            if(!
$this->db=mysql_connect($server,$user,$pass))
            {
                
$this->check_for_error();
            }
        }
        else
        {
            
$this->err[]='insufficient details available to make database connection';
            if(
defined('_debug_sql'))
            {
                die(
implode('<br />',$this->err));
            }
        }
        
$this->result=array();
        
$this->rows_affected=0;
    }

    function 
select_db($database)
    {
        if (!
mysql_select_db(mysql_real_escape_string($database),$this->db))
        {
            
$this->check_for_error();
        }
    }

    function 
affected_rows()
    {
        return(
mysql_affected_rows($this->db));
    }

    function 
do_query($query)
    {
        if(
$this->db)
        {
            
$this->result=array();
            
$result=mysql_query($query,$this->db);
            
$this->check_for_error($query);
            if(
count($this->err)<1)
            {
                
$x=0;
                
$num_rows=@mysql_num_rows($result);
                if(
$num_rows!=0)
                {
                    while(
$dbrow=mysql_fetch_array($result,MYSQL_ASSOC))
                    {
                        
$this->result[$x]=$dbrow;
                        
$x++;
                    }
                }
                
$this->result[0]['numrows']=$num_rows;
                if(
strtoupper(substr($query,0,6))=='UPDATE'$this->rows_affected=mysql_affected_rows($this->db);
                if(
strtoupper(substr($query,0,6))=='INSERT'$this->result[0]['insert_id']=mysql_insert_id();
                if(
$result) { @mysql_free_result($result); }
            }
            else if(
defined('_debug_sql'))
            {
                die(
'<p>'.implode('<br />',$this->err).'</p><blockquote>'.$query.'</blockquote>');
            }
        }
        else
        {
            
$this->err[]='no database connection';
            {
                die(
implode('<br />',$this->err));
            }
        }
        return(
count($this->err)<0);
    }

    
// grab array of column values from result array
    
function get_attributes(&$result,$col='id')
    {
        
$attr=array();
        if(
is_array($result))
        {
            if(
count($result)>0)
            {
                foreach(
$result AS $v)
                {
                    
array_push($attr,$v[$col]);
                }
            }
        }
        return 
$attr;
    }

    function 
get_one_attribute(&$result,$key=0,$src_col='id',$dest_col='')
    {
        if(
is_array($result))
        {
            if(
count($result)>0)
            {
                foreach(
$result AS $v)
                {
                    if(
$v[$src_col]===$key)
                    {
                        return 
$v[$dest_col];
                    }
                }
            }
        }
        return 
FALSE;
    }

    
// copy result array to object using associative array for attribute names
    
function row2obj(&$a,&$obj,$prefix='')
    {
        if(!
is_object($obj)) die('invalid object passed to row2obj');
        foreach(
$a AS $k=>$v)
        {
            if(
strlen($prefix)>0)
            {
                if(
substr($k,0,strlen($prefix)+1)==$prefix.'_')
                {
                    
$k=substr($k,strlen($prefix)+1);
                    
// echo $k.'<br />';
                
}
                else
                {
                    continue;
                }
            }
            if(!
$obj->check_attribute($k)) continue;

            if(
is_numeric($v))
            {
                if(
preg_match('/[^0-9]/',$v))
                {
                    
$obj->{$k}=(float)$v;
                }
                else
                {
                    
$obj->{$k}=(int)$v;
                }
            }
            else
            {
                
$obj->{$k}=$v;
            }
        }
    }

    function 
check_for_error($str='')
    {
        if(
mysql_errno($this->db))
        {
            
array_push($this->err,mysql_error($this->db));
            if(
defined('_debug_sql'))
            {
                if(
strlen($str)>0) die(implode('<br />',$this->err).'<blockquote>'.$str.'</blockquote>');
                else die(
implode('<br />',$this->err));
            }
        }
    }
}
?>