<?php
/*
* Copyright (c) 2010, JRG Productions
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of the nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Standards to which my database drivers must adhere
*/
interface sqlStandard {
// Usual query
function query($sql);
// For fetching rows
function fetchRow($result = null);
function fetchAssoc($result = null);
function fetchObject($result = null);
// For fetching a single value in a row ith only one value
function fetchOne($result = null);
// Close connection
function close();
// Free result
function free($result = null);
// Free result given by last query(). Doesn't need an argument
function freeLast();
// Escape a string for safe query insertion
function esc($s);
// Die with an error message
function errorFatal($msg);
// Get an array of values unescaped and trimmed
function makePresentable($arr);
}
class MySQL implements sqlStandard {
/*
* Gotta store connection and last result
*/
private $connection, $last_result;
/*
* Connect; select db
*/
function __construct($settings) {
/*
* Try connecting, possibly persistently
*/
$this->connection = (array_key_exists('persist', $settings) && $settings['persist'] == true ?
@mysql_pconnect($settings['host'], $settings['user'], $settings['password']) :
@mysql_connect())
or $this->errorFatal('Error connecting: '.mysql_error());
/*
* Try selecting db
*/
@mysql_select_db($settings['db'], $this->connection) or
$this->errorFatal('Error selecting db: '.mysql_errno($this->connection));
}
/*
* Undo escaping and padded white space
*/
function makePresentable($arr) {
if (is_array($arr))
foreach ($arr as $k => $v)
$arr[$k] = is_numeric($k) ? $v : trim(stripslashes($v));
return $arr;
}
/*
* Run a query
*/
public function query($sql) {
/*
* Free last result, if exists
*/
$this->freelast();
/*
* Run query and die on error
*/
$result = @mysql_query($sql, $this->connection) or
$this->errorFatal('QUERY Error: '.mysql_error($this->connection));
/*
* Store result for use with $this->freeLast();
*/
$this->last_result = $result;
/*
* Return result
*/
return $result;
}
/*
* Return result as numeric array
*/
public function fetchRow($result = null) {
return $this->makePresentable(@mysql_fetchRow($result == null && is_resource($this->last_result) ? $this->last_result : $result));
}
/*
* Return result as associative array
*/
public function fetchAssoc($result = null) {
return $this->makePresentable(@mysql_fetchAssoc($result == null && is_resource($this->last_result) ? $this->last_result : $result));
}
/*
* Return result as object
*/
public function fetchObject($result = null) {
return (object) $this->fetchAssoc($result);
}
/*
* Return a single value from result
*/
public function fetchOne($result = null) {
$value = $this->fetchAssoc($result);
return is_array($value) ? (object) $value : $value;
}
/*
* Close connection, if connected
*/
public function close() {
return mysql_close($this->connection);
}
/*
* Free specified resource
*/
public function free($result = null) {
if (is_resource($result))
@mysql_free_result($result);
}
/*
* Free last resource
*/
public function freeLast() {
if (is_resource($this->last_result))
@mysql_free_result($this->last_result);
}
/*
* Escape string for safe query insertion
*/
public function esc($s) {
return ctype_digit($s) ? $s : mysql_real_escape_string($s, $this->connection) ;
}
/*
* Die with an error message
*/
public function errorFatal($msg) {
exit($msg);
}
}
class PostGres implements sqlStandard {
/*
* Gotta store connection and last result
*/
private $connection, $last_result;
/*
* Connect; select db
*/
function __construct($settings) {
/*
* Connection string. With port, if necessary to away from default
*/
$cstr = "host={$settings['host']} dbname={$settings['db']} user={$settings['user']} password={$settings['password']}";
if (ctype_digit($settings['port']) && $settings['port'] != 5432)
$cstr .= " port={$settings['port']}";
/*
* Go for it
*/
$this->connection = (array_key_exists('persist', $settings) && $settings['persist'] == true ?
@pg_pconnect($cstr) : @pg_connect($cstr)) or
$this->errorFatal('Cannot connect: ');
}
/*
* Return result as numeric array
*/
public function fetchRow($result = null) {
return $this->makePresentable(@pg_fetch_row(is_resource($this->last_result) ? $last_result : $result));
}
/*
* Return result as associative array
*/
public function fetchAssoc($result = null) {
return $this->makePresentable(@pg_fetch_assoc(is_resource($this->last_result) ? $last_result : $result));
}
/*
* Return result as object
*/
public function fetchObject($result = null) {
$value = $this->fetchAssoc($result);
return is_array($value) ? (object) $value : $value;
}
/*
* Return a single value from object
*/
public function fetchOne($result = null) {
$value = @pg_fetch_result(is_resource($this->last_result) ? $last_result : $result, 0, 0);
return $value == 't' ? true : ($value == 'f' ? false : (ctype_digit($value) ? $value : stripslashes(trim($value))));
}
/*
* Close connection, if connected
*/
public function close() {
if (is_resource($this->connection))
pg_close($this->connection);
}
/*
* Free specified resource
*/
public function free($result = null) {
pg_free_result($result);
}
/*
* Free last resource
*/
public function freeLast() {
if (is_resource($this->last_result))
pg_free_result($this->last_result);
}
/*
* Escape string for safe query insertion
*/
public function esc($s) {
return ctype_digit($s) ? $s : pg_escape_string($this->connection, $s);
}
/*
* Escape string for safe query insertion into a bytea field
*/
public function escBytea($s) {
return ctype_digit($s) ? $s : pg_escape_bytea($this->connection, $s);
}
/*
* Unescape string from bytea field
*/
public function unescBytea($s) {
return pg_unescape_bytea($s);
}
/*
* Die with an error message
*/
public function errorFatal($msg) {
exit($msg);
}
public function query($sql) {
$this->freelast();
$result = @pg_query($this->connection, $sql) or
$this->errorFatal('QUERY Error: '.pg_result_error_field(pg_get_result($this->connection), PGSQL_DIAG_SQLSTATE));
$this->last_result = $result;
return $result;
}
function makePresentable($arr) {
if (is_array($arr))
foreach ($arr as $k => $v)
$arr[$k] = is_numeric($k) ? $v : trim(stripslashes($v));
return $arr;
}
}
/*
* Fetch connected class instance when given driver type and settings
*/
function snagDb($type, $settings = array()) {
/*
* Compatibility.
*/
$type = strtolower($type);
/*
* Decide what
*/
switch ($type) {
/*
* MySQL
*/
case 'mysql':
extension_loaded('mysql') or exit('Lacking MySQLe extension');
return new MySQL($settings);
break;
/*
* PostgreSQL
*/
case 'postgres':
extension_loaded('pgsql') or exit('Lacking PostgreSQL extension');
return new PostGres($settings);
break;
/*
* Something either unsupported or crap
*/
default:
exit ('Invalid type');
break;
}
}