405 lines
12 KiB
PHP
Executable file
405 lines
12 KiB
PHP
Executable file
<?php
|
|
|
|
/**
|
|
* Database abstraction layer for MySQL
|
|
*
|
|
* All database usage inside PICKLES-based sites should be done via the database
|
|
* object that is a part of every model ($this->db). Because the database
|
|
* object can execute raw SQL, there should be no limitations.
|
|
*
|
|
* @package PICKLES
|
|
* @author Joshua Sherman <josh@phpwithpickles.org>
|
|
* @copyright 2007-2008 Joshua Sherman
|
|
* @todo Internally document the functions better.
|
|
* @todo Potentially switch to PDO to be able to easily accomodate different
|
|
* database types.
|
|
* @todo Eventually finish adding in my ActiveRecord class, even though I
|
|
* feel active record dumbs people down since it's a crutch for
|
|
* actually being able to write SQL.
|
|
*/
|
|
class DB extends Singleton {
|
|
|
|
/**
|
|
* Private instance of the DB class
|
|
*/
|
|
private static $instance;
|
|
|
|
/**
|
|
* Private database information and login credentials
|
|
*/
|
|
private $hostname;
|
|
private $username;
|
|
private $password;
|
|
private $database;
|
|
|
|
/**
|
|
* Private MySQL resources
|
|
*/
|
|
private $connection;
|
|
private $results;
|
|
|
|
/**
|
|
* Private constructor
|
|
*/
|
|
private function __construct() { }
|
|
|
|
/**
|
|
* Gets an instance of the database object
|
|
*
|
|
* Determines if a DB object has already been instantiated, if so it will use
|
|
* it. If not, it will check to see if a frozen copy of the object is
|
|
* available. If not, then a new object will be created.
|
|
*
|
|
* @return object An instace of the DB class
|
|
*/
|
|
public static function getInstance() {
|
|
$class = __CLASS__;
|
|
|
|
if (isset($_SESSION['objects'][$class])) {
|
|
self::$instance = Singleton::thaw($class);
|
|
}
|
|
else if (!self::$instance instanceof $class) {
|
|
self::$instance = new $class();
|
|
}
|
|
|
|
return self::$instance;
|
|
}
|
|
|
|
/**
|
|
* Opens database connection
|
|
*
|
|
* Establishes a connection to the MySQL database based on the configuration
|
|
* options that are available in the Config object.
|
|
*
|
|
* @return boolean Based on the success or failure of mysql_connect()
|
|
* @todo Remove the error supressing @ from mysql_connect()
|
|
* @todo Currently the DBO is not being cached in the object, since it stores the password, it's a security issue.
|
|
*/
|
|
public function open() {
|
|
if (!is_resource($this->connection)) {
|
|
$config = Config::getInstance();
|
|
|
|
$this->hostname = $config->get('database', 'hostname');
|
|
$this->username = $config->get('database', 'username');
|
|
$this->password = $config->get('database', 'password');
|
|
$this->database = $config->get('database', 'database');
|
|
|
|
if (isset($this->hostname) && isset($this->username) && isset($this->password) && isset($this->database)) {
|
|
$this->connection = @mysql_connect($this->hostname, $this->username, $this->password);
|
|
|
|
if (is_resource($this->connection)) {
|
|
if (!mysql_select_db($this->database, $this->connection)) {
|
|
Error::addWarning("There was an error selecting the '" . $this->database , "' database");
|
|
return false;
|
|
}
|
|
else {
|
|
return true;
|
|
}
|
|
}
|
|
else {
|
|
Error::addError('There was an error connecting to the database server');
|
|
}
|
|
|
|
return false;
|
|
}
|
|
else {
|
|
Error::addError('There was an error loading the configuration');
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Closes database connection
|
|
*
|
|
* Checks to see if the connection is available, and if so, closes it out.
|
|
*
|
|
* @return boolean Returns the status of mysql_close() or false (default)
|
|
*/
|
|
public function close() {
|
|
if (is_resource($this->connection)) {
|
|
return mysql_close($this->connection);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Executes SQL
|
|
*
|
|
* Executes the passed SQL without any manipulation. If no SQL is passed in
|
|
* the function will return false (why return true if it didn't actually do
|
|
* something?)
|
|
*
|
|
* @param string $sql SQL statement to be executed
|
|
* @return boolean Returns the status of the execution
|
|
* @todo Need to get rid of the error suppressing @ symbol.
|
|
*/
|
|
public function execute($sql) {
|
|
$this->open();
|
|
|
|
if (trim($sql) != '') {
|
|
$this->results = @mysql_query($sql, $this->connection);
|
|
if (empty($this->results)) {
|
|
Error::addError('There was an error executing the SQL');
|
|
Error::addError(mysql_error());
|
|
}
|
|
else {
|
|
return true;
|
|
}
|
|
}
|
|
else {
|
|
Error::addWarning('There was no SQL to execute');
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Gets a field from a result set
|
|
*
|
|
* Returns the value of a single field from either a previously executed
|
|
* query, or from the passed SQL. This function assumes your query results
|
|
* only contain a single field. If multiple fields are returned, this
|
|
* function will only return the first one.
|
|
*
|
|
* @param string $sql SQL statement to be executed (optional)
|
|
* @return string Returns the value of the field or null if none
|
|
* @todo Need to remove the error supression
|
|
* @todo Right now it assumes your query only returns a single field, that
|
|
* probably should be changed to allow someone to specify what field
|
|
* they want from a row of data. Actually, this is still debatable
|
|
* as someone could use getRow and reference the field they want to
|
|
* accomplish the same goal.
|
|
* @todo Another debate point, should it return false instead of null, or
|
|
* perhaps have some sort of error indicator in the result set?
|
|
*/
|
|
public function getField($sql = null) {
|
|
if (isset($sql)) {
|
|
$this->execute($sql);
|
|
}
|
|
|
|
if (is_resource($this->results)) {
|
|
$results = @mysql_fetch_row($this->results);
|
|
if (is_array($results)) {
|
|
return $results[0];
|
|
}
|
|
else {
|
|
Error::addWarning('There is nothing to return');
|
|
}
|
|
}
|
|
else {
|
|
Error::addError('There is no valid MySQL result resource');
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Gets a row from a result set
|
|
*
|
|
* Returns a row in an associative array from either a previously executed
|
|
* query, or from the passed SQL. This function assumes your query results
|
|
* only contain a single row. If multiple rows are returned, this function
|
|
* will only return the first one.
|
|
*
|
|
* @param string $sql SQL statement to be executed (optional)
|
|
* @return string Returns the row in an associative array or null if none
|
|
* @todo Need to remove the error supression
|
|
* @todo Right now it assumes your query only returns a single row, that
|
|
* probably should be changed to allow someone to specify what row
|
|
* they want from a set of data. Actually, this is still debatable
|
|
* as someone could use getArray and reference the row they want to
|
|
* accomplish the same goal.
|
|
* @todo Another debate point, should it return false instead of null, or
|
|
* perhaps have some sort of error indicator in the result set?
|
|
* @todo Calling bullshit on my own code, apparently this should only be
|
|
* returning a single row, but returns all the rows instead of just
|
|
* the first one. So basically, this function is functioning exactly
|
|
* the same as DB::getArray(). Just goes to show how often I
|
|
* actually use this function.
|
|
*/
|
|
public function getRow($sql = null) {
|
|
if (isset($sql)) {
|
|
$this->execute($sql);
|
|
}
|
|
|
|
if (is_resource($this->results)) {
|
|
$results = @mysql_fetch_assoc($this->results);
|
|
if (is_array($results)) {
|
|
return $results;
|
|
}
|
|
else {
|
|
Error::addWarning('There is nothing to return');
|
|
}
|
|
}
|
|
else {
|
|
Error::addError('There is no valid MySQL result resource');
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Gets all the rows from a result set
|
|
*
|
|
* Returns all the rows (each row in an associative array) from either a
|
|
* previously executed query, or from the passed SQL.
|
|
*
|
|
* @param string $sql SQL statement to be executed (optional)
|
|
* @return string Returns the rows in an array or null if none
|
|
* @todo Need to remove the error supression
|
|
* @todo Another debate point, should it return false instead of null, or
|
|
* perhaps have some sort of error indicator in the result set?
|
|
*/
|
|
public function getArray($sql = null) {
|
|
if (isset($sql)) {
|
|
$this->execute($sql);
|
|
}
|
|
|
|
if (is_resource($this->results)) {
|
|
$return = null;
|
|
while ($row = mysql_fetch_assoc($this->results)) {
|
|
if (!is_array($return)) {
|
|
$return = array();
|
|
}
|
|
|
|
array_push($return, $row);
|
|
}
|
|
|
|
return $return;
|
|
}
|
|
else {
|
|
Error::addError('There is no valid MySQL result resource');
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Inserts a row into a table
|
|
*
|
|
* Easy insertion of a row into a table without being too savvy with SQL.
|
|
*
|
|
* @param string $table Name of the table you want to insert to
|
|
* @param array $columnValues Associative array of name value pairs
|
|
* (Corresponds with the column names for the table)
|
|
* @return boolean Returns the status of the execution
|
|
* @todo Convert from camel case to underscores
|
|
* @todo Check that the table exists, and possibly check that the columns
|
|
* exist as well
|
|
*/
|
|
public function insert($table, $columnValues) {
|
|
$this->open();
|
|
|
|
if (trim($table) != '') {
|
|
if (is_array($columnValues)) {
|
|
foreach ($columnValues as $key => $value) {
|
|
$columnValues[$key] = $value == null ? 'NULL' : "'" . mysql_real_escape_string(stripslashes($value), $this->connection) . "'";
|
|
}
|
|
|
|
$this->execute("
|
|
INSERT INTO {$table} (
|
|
" . implode(array_keys($columnValues), ', ') . "
|
|
) VALUES (
|
|
" . implode($columnValues, ", ") . "
|
|
);
|
|
");
|
|
|
|
return mysql_insert_id($this->connection);
|
|
}
|
|
else {
|
|
Error::addError('No data was specified');
|
|
}
|
|
}
|
|
else {
|
|
Error::addError('No database table was specified');
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Updates an existing row row in a table
|
|
*
|
|
* Easy update of an existing row or rows (depending on the passed
|
|
* conditions) in a table without being too savvy with SQL.
|
|
*
|
|
* @params string $table Name of the table you want to insert to
|
|
* @params array $columnValues Associative array of name value pairs
|
|
* (Corresponds with the column names for the table)
|
|
* @params array $conditions Associative array of name value pairs that will
|
|
* be used to create a WHERE clause in the SQL.
|
|
* @return boolean Returns the status of the execution
|
|
* @todo Convert from camel case to underscores
|
|
* @todo Check that the table exists, and possibly check that the columns
|
|
* exist and conditional columns exist as well
|
|
*/
|
|
public function update($table, $columnValues, $conditions) {
|
|
$this->open();
|
|
|
|
if (trim($table) != '') {
|
|
$fields = $where = null;
|
|
if (is_array($columnValues)) {
|
|
foreach ($columnValues as $key => $value) {
|
|
$fields .= ($fields ? ', ' : null) . $key . " = '" . mysql_real_escape_string(stripslashes($value), $this->connection) . "'";
|
|
}
|
|
|
|
if (is_array($conditions)) {
|
|
foreach ($conditions as $key => $value) {
|
|
$where = ($where == null) ? 'WHERE ' : ' AND ';
|
|
|
|
if ($value == null) {
|
|
$where .= $key . ' IS NULL';
|
|
}
|
|
else {
|
|
$where .= $key . " = '" . mysql_real_escape_string(stripslashes($value), $this->connection) . "'";
|
|
}
|
|
}
|
|
|
|
$sql = 'UPDATE ' . $table . ' SET ' . $fields . $where;
|
|
if ($this->execute($sql)) {
|
|
return true;
|
|
}
|
|
}
|
|
else {
|
|
Error::addError('No conditions were specified');
|
|
}
|
|
}
|
|
else {
|
|
Error::addError('No data was specified');
|
|
}
|
|
}
|
|
else {
|
|
Error::addError('No database table was specified');
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Deletes an existing row row in a table
|
|
*
|
|
* Easy deletion of an existing row or rows (depending on the passed
|
|
* conditions) in a table without being too savvy with SQL.
|
|
*
|
|
* @access private
|
|
* @params string $table Name of the table you want to insert to
|
|
* @params array $columnValues Associative array of name value pairs
|
|
* (Corresponds with the column names for the table)
|
|
* @params array $conditions Associative array of name value pairs that will
|
|
* be used to create a WHERE clause in the SQL.
|
|
* @return boolean Returns the status of the execution
|
|
* @todo This function doesn't exist yet
|
|
* @todo Convert from camel case to underscores
|
|
*/
|
|
public function delete($table, $columnValues, $conditions) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
?>
|