<?php

/**
 * MySQL Database Abstraction class
 * Intended for use in replicated servers.
 *
 * @author Rick Hodger <rick@fuzzi.org.uk>
 * @version 1.0
 * @copyright Copyright &copy; 2006, Rick Hodger
 * @package mysql-replication
 * @filesource
 */
/**
 * MySQL Database Replication-aware class.
 *
 * The class is simply named mysqlrep.
 * @package mysql-replication
 */
class mysqlrep {
    
/**
     * Local MySQL server configuration.
     * @var array
     */
    
var $config = array();
    
/**
     * Master MySQL server configuration.
     */
    
var $master_config = array();
    var 
$conn 0;
    var 
$master_conn 0;
    var 
$master_host "";
    
/**
     * Contains the result handler.
     */
    
var $result 0;
    
/**
     * If we encounter an error, store the error string in here.
     */
    
var $error "";
    
/**
     * Determines if we are running on the slave server or not.
     */
    
var $weareslave false;
    var 
$lastquery "";

    
/**
     * Open MySQL connection.
     *
     * Opens the initial connection to the 'local' MySQL server and determines if we are running on a master or slave.
     * No connection is made to the master server until such time as it is required. This saves on resources and improves
     * script speed.
     *
     * Returns true on success, false on failure.
     * @return bool
     */
    
function Open() {
        if (
$this->conn=mysql_connect($this->config['host'],$this->config['user'],$this->config['pass'],true)) {
            if (
mysql_select_db($this->config['dbase'],$this->conn)) {
                
// figure out if we're the master
                
if ($this->Query("show slave status;")) {
                    if (
$this->NumRows() > 0) {
                        
// crap, we're the slave
                        
list($this->master_host)=$this->FetchRow();
                        
$this->weareslave=true;
                    }
                } else {
//            die("DATABASE CLASS ERROR: $this->error");
                
}
                return 
true;
            } else {
                
$this->error mysql_error($this->conn);
                
$this->Close;
                return 
false;
            }
        } else {
            return 
false;
        }
    }

    
/**
     * Closes the open connections to the database servers.
     */
    
function Close() {
        
mysql_close($this->conn);
        if (
$this->weareslave==true) {
            
// check and close master
            
if (is_resource($this->master_conn)) {
                
$this->CloseMaster();
            }
        }
    }

    
/**
     * Opens connection to the master server
     * @access private
     */
    
function OpenMaster() {
        if (
$this->master_conn=mysql_connect($this->master_config['host'],$this->master_config['user'],$this->master_config['pass'],true)) {
            if (
mysql_select_db($this->master_config['dbase'],$this->master_conn)) {
                return 
true;
            } else {
                
$this->error mysql_error($this->master_conn);
                
$this->CloseMaster();
                return 
false;
            }
        } else {
            return 
false;
        }
    }

    
/**
     * Closes the connection to the master server.
     * @access private
     */
    
function CloseMaster() {
        
mysql_close($this->master_conn);
        
$this->master_conn=0;
    }

    
/**
     * Performs a query on the SQL database.
     * Attempts to determine if the query is a 'write' request, and if so attempts to perform the query on the master server.
     * @param string $sql
     * @return bool
     */
    
function Query($sql) {
        
// first, record the query for debugging
        // check if this is an alteration
        
$fword=strtolower(substr($sql,0,strpos($sql," ")));
        if ((
$fword==="update" || $fword==="insert" || $fword==="alter" || $fword==="delete") && $this->weareslave==true) {
            
// alteration and we're the slave!
            
if (!is_resource($this->master_conn)) {
                
// not connected to master atm
                
if ($this->OpenMaster()==false) {
                    die(
"Could not connect to master SQL server!");
                }
            }
            if (
$this->result=mysql_query($sql,$this->master_conn)) {
                return 
true;
            } else {
                
$this->error=mysql_error($this->master_conn);
                if (
$this->error==="Lost connection to MySQL server during query") {
                    if (
$this->result=mysql_query($sql,$this->master_conn)) {
                        return 
true;
                    } else {
                        echo 
$this->error;
                        return 
false;
                    }
                } else {
                    echo 
$this->error;
                    return 
false;
                }
            }
        } else {
            
// run as normal
            
if ($this->result=mysql_query($sql,$this->conn)) {
                return 
true;
            } else {
                
$this->error=mysql_error($this->conn);
                if (
$this->error==="Lost connection to MySQL server during query") {
                    if (
$this->result=mysql_query($sql,$this->conn)) {
                        return 
true;
                    } else {
                        echo 
$this->error;
                        return 
false;
                    }
                }
            }
        }
    }

    
/**
     * Fetch's an array from the most recent query.
     * Optional paramter allows you to specify a result handle.
     * @param mixed $result
     * @return mixed
     */
    
function FetchArray($result=0) {
        if (
$result==0) {
            
$result=$this->result;
        }
        return 
mysql_fetch_array($result);
    }

    
/**
     * Returns the number of rows in the most recent query.
     * Optional paramter allows you to specify a result handle.
     * @param mixed $result
     * @return mixed
     */
    
function NumRows($result=0) {
        if (
$result==0) {
            
$result=$this->result;
        }
        if (
$ret=mysql_num_rows($result)) {
            return 
$ret;
        } else {
            return 
false;
        }
    }

    
/**
     * Returns an autoincrement ID number from the most recent write query.
     * As this requires use of the connection handle, there is no option for a result handle.
     * @return integer
     */
    
function LastInsertId() {
        if (
$this->weareslave==true) {
            return 
mysql_insert_id($this->master_conn);
        } else {
            return 
mysql_insert_id($this->conn);
        }
    }
}

?>