<?php
/* dbi4php - Generic database access for PHP
*
* The functions defined in this file are meant to provide a single API to the
* different PHP database APIs. Unfortunately, this is necessary since PHP does
* not yet have a common db API. The value of <var>$GLOBALS['db_type']</var>
* should be defined somewhere to one of the following:
* - mysql
* - mysqli
* - mssql
* - oracle (This uses the Oracle8 OCI API, so Oracle 8 libs are required)
* - postgresql
* - odbc
* - ibase (Interbase)
* - sqlite
* - ibm_db2
*
* <b>Limitations:</b>
* - This assumes a single connection to a single database for the sake of
* simplicity. Do not make a new connection until you are completely
* finished with the previous one. However, you can execute more than query
* at the same time.
* - Rather than use the associative arrays returned with xxx_fetch_array (),
* normal arrays are used with xxx_fetch_row (). (Some db APIs don't support
* xxx_fetch_array ().)
*
* @author Craig Knudsen <cknudsen@cknudsen.com>
* @copyright Craig Knudsen, <cknudsen@cknudsen.com>, http://www.k5n.us/cknudsen
* @license http://www.gnu.org/licenses/lgpl.html GNU LGPL
* @version $Id: dbi4php.php,v 1.26.2.4 2007/10/31 19:39:29 umcesrjones Exp $
* @package WebCalendar
*
* History:
* See ChangeLog
*
* License:
* Copyright (C) 2006 Craig Knudsen
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License,
* or (at your option) any later version.
*
* This library 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301, USA
*/
/* Opens up a database connection.
*
* Use a pooled connection if the db supports it and
* the <var>db_persistent</var> setting is enabled.
*
* <b>Notes:</b>
* - The database type is determined by the global variable
* <var>db_type</var>
* - For ODBC, <var>$host</var> is ignored, <var>$database</var> = DSN
* - For Oracle, <var>$database</var> = tnsnames name
* - Use the {@link dbi_error ()} function to get error information
* if the connection fails.
*
* @param string $host Hostname of database server
* @param string $login Database login
* @param string $password Database login password
* @param string $database Name of database
* @param string $lazy Wait until a query to connect?
*
* @return resource The connection
*/
function dbi_connect ( $host, $login, $password, $database, $lazy = true ) {
global $db_cache_count, $db_connection_info, $db_query_count,
$old_textlimit, $old_textsize, $db_sqlite_error_str;
$db_cache_count = $db_query_count = 0;
if ( ! isset ( $db_connection_info ) )
$db_connection_info = array ();
$db_connection_info['connected'] = false;
$db_connection_info['connection'] = 0;
$db_connection_info['database'] = $database;
$db_connection_info['host'] = $host;
$db_connection_info['login'] = $login;
$db_connection_info['password'] = $password;
// mysqli requires $db_connection_info['connection'] to be set
if ( strcmp ( $GLOBALS['db_type'], 'mysqli' ) == 0 )
$lazy == false;
// Lazy connections... do not connect until 1st call to dbi_query.
if ( $lazy )
// echo "<!-- Waiting on db connection made (lazy) -->\nRETURN!<br />";
return true;
if ( strcmp ( $GLOBALS['db_type'], 'mysql' ) == 0 ) {
$c = ( $GLOBALS['db_persistent']
? mysql_pconnect ( $host, $login, $password )
: mysql_connect ( $host, $login, $password ) );
if ( $c ) {
if ( ! mysql_select_db ( $database ) )
return false;
$db_connection_info['connected'] = true;
$db_connection_info['connection'] = $c;
return $c;
} else
return false;
} elseif ( strcmp ( $GLOBALS['db_type'], 'mysqli' ) == 0 ) {
$c = new mysqli( $host, $login, $password, $database );
if ( $c ) {
if ( mysqli_connect_errno() && ! empty ( $database ) )
return false;
$db_connection_info['connected'] = true;
$db_connection_info['connection'] = $GLOBALS['db_connection'] = $c;
return $c;
} else
return false;
} elseif ( strcmp ( $GLOBALS['db_type'], 'mssql' ) == 0 ) {
static $old_textlimit, $old_textsize;
$old_textlimit = ini_get ( 'mssql.textlimit' );
$old_textsize = ini_get ( 'mssql.textsize' );
ini_set ( 'mssql.textlimit', '2147483647' );
ini_set ( 'mssql.textsize', '2147483647' );
$c = ( $GLOBALS['db_persistent']
? mssql_pconnect ( $host, $login, $password )
: mssql_connect ( $host, $login, $password ) );
if ( $c ) {
if ( ! mssql_select_db ( $database ) )
return false;
$db_connection_info['connected'] = true;
$db_connection_info['connection'] = $c;
return $c;
} else
return false;
} elseif ( strcmp ( $GLOBALS['db_type'], 'oracle' ) == 0 ) {
$_ora_conn_func = 'OCI' . ( $GLOBALS['db_persistent'] ? 'P' : '' )
. 'Logon';
$c = $_ora_conn_func ( $login, $password,
( strlen ( $host ) && strcmp ( $host, 'localhost' )
? '(DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP) (HOST = '
. $host . ' ) (PORT = 1521))) (CONNECT_DATA = (SID = ' . $database
. ' )))'
: $database ) );
unset ( $_ora_conn_func );
$db_connection_info['connected'] = true;
$db_connection_info['connection'] = $GLOBALS['oracle_connection'] = $c;
return $c;
} elseif ( strcmp ( $GLOBALS['db_type'], 'postgresql' ) == 0 ) {
$dbargs = ( strlen ( $host ) ? 'host=' . "$host " : '' )
. 'dbname=' . $database . ' user=' . $login
. ( strlen ( $password ) ? ' password=' . $password : '' );
$c = ( $GLOBALS['db_persistent']
? pg_pconnect ( $dbargs ) : pg_connect ( $dbargs ) );
$GLOBALS['postgresql_connection'] = $c;
if ( ! $c )
return false;
$db_connection_info['connected'] = true;
$db_connection_info['connection'] = $c;
return $c;
} elseif ( strcmp ( $GLOBALS['db_type'], 'odbc' ) == 0 ) {
$c = ( $GLOBALS['db_persistent']
? odbc_pconnect ( $database, $login, $password )
: odbc_connect ( $database, $login, $password ) );
$db_connection_info['connected'] = true;
$db_connection_info['connection'] = $GLOBALS['odbc_connection'] = $c;
return $c;
} elseif ( strcmp ( $GLOBALS['db_type'], 'ibm_db2' ) == 0 ) {
$c = ( $GLOBALS['db_persistent']
? db2_pconnect ( $database, $login, $password )
: db2_connect ( $database, $login, $password ) );
$db_connection_info['connected'] = true;
$db_connection_info['connection'] = $GLOBALS['ibm_db2_connection'] = $c;
return $c;
} elseif ( strcmp ( $GLOBALS['db_type'], 'ibase' ) == 0 ) {
$host = $host . ':' . $database;
$c = ( $GLOBALS['db_persistent']
? ibase_pconnect ( $host, $login, $password )
: ibase_connect ( $host, $login, $password ) );
$db_connection_info['connected'] = true;
$db_connection_info['connection'] = $c;
return $c;
} elseif ( strcmp ( $GLOBALS['db_type'], 'sqlite' ) == 0 ) {
$c = ( $GLOBALS['db_persistent']
? sqlite_popen ( $database, 0666, $db_sqlite_error_str )
: sqlite_open ( $database, 0666, $db_sqlite_error_str ) );
if ( ! $c ) {
echo translate ( 'Error connecting to database' ) . ": " . $db_sqlite_error_str . ".\n";
exit;
}
$db_connection_info['connected'] = true;
$db_connection_info['connection'] = $GLOBALS['sqlite_c'] = $c;
return $c;
} else
dbi_fatal_error ( 'dbi_connect (): '
. ( empty ( $GLOBALS['db_type'] )
? translate ( 'db_type not defined.' )
: translate ( 'invalid db_type' ) . ' ' . $GLOBALS['db_type'] . '.' ) );
}
/* Closes a database connection.
*
* This is not necessary for any database that uses pooled connections, such as
* MySQL, but a good programming practice.
*
* @param resource $conn The database connection.
*
* @return bool True on success, false on error.
*/
function dbi_close ( $conn ) {
global $db_connection_info, $db_query_count,
$old_textlimit, $old_textsize, $SQLLOG;
if ( is_array ( $db_connection_info ) ) {
if ( ! $db_connection_info['connected'] )
// never connected
// echo '<!-- No db connection made (cached) -->' . "\n";
return true;
else {
$conn = $db_connection_info['connection'];
$db_connection_info['connected'] = false;
$db_connection_info['connection'] = 0;
// echo '<!-- Closing lazy db connection made after '
$db_query_count . " queries -->\n";
}
}
if ( strcmp ( $GLOBALS['db_type'], 'mysql' ) == 0 )
return mysql_close ( $conn );
elseif ( strcmp ( $GLOBALS['db_type'], 'mysqli' ) == 0 )
return $conn->close();
elseif ( strcmp ( $GLOBALS['db_type'], 'mssql' ) == 0 ) {
if ( ! empty ( $old_textlimit ) ) {
ini_set ( 'mssql.textlimit', $old_textlimit );
ini_set ( 'mssql.textsize', $old_textsize );
}
return mssql_close ( $conn );
} elseif ( strcmp ( $GLOBALS['db_type'], 'oracle' ) == 0 )
return OCILogOff ( $conn );
elseif ( strcmp ( $GLOBALS['db_type'], 'postgresql' ) == 0 )
return pg_close ( $GLOBALS['postgresql_connection'] );
elseif ( strcmp ( $GLOBALS['db_type'], 'odbc' ) == 0 )
return odbc_close ( $GLOBALS['odbc_connection'] );
elseif ( strcmp ( $GLOBALS['db_type'], 'ibm_db2' ) == 0 )
return db2_close ( $GLOBALS['ibm_db2_connection'] );
elseif ( strcmp ( $GLOBALS['db_type'], 'ibase' ) == 0 )
return ibase_close ( $conn );
elseif ( strcmp ( $GLOBALS['db_type'], 'sqlite' ) == 0 )
return sqlite_close ( $conn );
else
dbi_fatal_error ( 'dbi_close (): '
. translate ( 'db_type not defined.' ) );
}
/* Return the number of database queries that were executed.
* (This does not included cached queries.)
*/
function dbi_num_queries () {
global $db_query_count;
return $db_query_count;
}
/* Return the number of queries that were cached.
*/
function dbi_num_cached_queries () {
global $db_cache_count;
return $db_cache_count;
}
/* Executes an SQL query.
*
* <b>Note:</b> Use the {@link dbi_error ()} function to get error information
* if the connection fails.
*
* @param string $sql SQL of query to execute.
* @param bool $fatalOnError Abort execution if there is a database error?
* @param bool $showError Display error to user (including possibly the
* SQL) if there is a database error?
*
* @return mixed The query result resource on queries (which can then be
* passed to the {@link dbi_fetch_row ()} function to obtain the
* results), or true/false on insert or delete queries.
*/
function dbi_query ( $sql, $fatalOnError = true, $showError = true ) {
global $c, $db_connection_info, $db_query_count, $phpdbiVerbose, $SQLLOG;
if ( ! isset ( $SQLLOG ) && ! empty ( $db_connection_info['debug'] ) )
$SQLLOG = array ();
if ( ! empty ( $db_connection_info['debug'] ) )
$SQLLOG[] = $sql;
// echo "dbi_query!: " . htmlentities ( $sql ) . "<br />";
// Connect now if not connected.
if ( is_array ( $db_connection_info ) && ! $db_connection_info['connected'] ) {
$c = dbi_connect (
$db_connection_info['host'],
$db_connection_info['login'],
$db_connection_info['password'],
$db_connection_info['database'],
false// * not lazy
);
$db_connection_info['connected'] = true;
$db_connection_info['connection'] = $c;
// echo '<!-- Created delayed db connection (lazy) -->' . "\n";
}
$db_query_count++;
// If caching is enabled, then clear out the cache for any request
// that may update the datatabase.
if ( ! empty ( $db_connection_info['cachedir'] ) ) {
if ( ! preg_match ( '/^select/i', $sql ) ) {
dbi_clear_cache ();
if ( ! empty ( $db_connection_info['debug'] ) )
$SQLLOG[] = translate ( 'Cache cleared from previous SQL!' );
}
}
// do_debug ( "SQL:" . $sql);
$found_db_type = false;
if ( strcmp ( $GLOBALS['db_type'], 'mysql' ) == 0 ) {
$found_db_type = true;
$res = mysql_query ( $sql, $db_connection_info['connection'] );
} elseif ( strcmp ( $GLOBALS['db_type'], 'mysqli' ) == 0 ) {
$found_db_type = true;
$res = $GLOBALS['db_connection']->query( $sql );
} elseif ( strcmp ( $GLOBALS['db_type'], 'mssql' ) == 0 ) {
$found_db_type = true;
$res = mssql_query ( $sql );
} elseif ( strcmp ( $GLOBALS['db_type'], 'oracle' ) == 0 ) {
if ( false === $GLOBALS['oracle_statement'] =
OCIParse ( $GLOBALS['oracle_connection'], $sql ) )
dbi_fatal_error ( translate ( 'Error executing query.' )
. $phpdbiVerbose ? ( dbi_error () . "\n\n<br />\n" . $sql ) : ''
. '', $fatalOnError, $showError );
return OCIExecute ( $GLOBALS['oracle_statement'], OCI_COMMIT_ON_SUCCESS );
} elseif ( strcmp ( $GLOBALS['db_type'], 'postgresql' ) == 0 ) {
$found_db_type = true;
$res = pg_exec ( $GLOBALS['postgresql_connection'], $sql );
} elseif ( strcmp ( $GLOBALS['db_type'], 'odbc' ) == 0 )
return odbc_exec ( $GLOBALS['odbc_connection'], $sql );
elseif ( strcmp ( $GLOBALS['db_type'], "ibm_db2" ) == 0 ) {
$found_db_type = true;
$res = db2_exec ( $GLOBALS['ibm_db2_connection'], $sql );
} elseif ( strcmp ( $GLOBALS['db_type'], 'ibase' ) == 0 ) {
$found_db_type = true;
$res = ibase_query ( $sql );
} elseif ( strcmp ( $GLOBALS['db_type'], 'sqlite' ) == 0 ) {
$found_db_type = true;
$res = sqlite_query ( $GLOBALS['sqlite_c'], $sql, SQLITE_NUM );
}
if ( $found_db_type ) {
if ( ! $res )
dbi_fatal_error ( translate ( 'Error executing query.' )
. ( $phpdbiVerbose ? ( dbi_error () . "\n\n<br />\n" . $sql ) : '' ),
$fatalOnError, $showError );
return $res;
} else
dbi_fatal_error ( 'dbi_query (): ' . translate ( 'db_type not defined.' ) );
}
/* Retrieves a single row from the database and returns it as an array.
*
* <b>Note:</b> We don't use the more useful xxx_fetch_array because not all
* databases support this function.
*
* <b>Note:</b> Use the {@link dbi_error ()} function to get error information
* if the connection fails.
*
* @param resource $res The database query resource returned from
* the {@link dbi_query ()} function.
*
* @return mixed An array of database columns representing a single row in
* the query result or false on an error.
*/
function dbi_fetch_row ( $res ) {
if ( strcmp ( $GLOBALS['db_type'], 'mysql' ) == 0 )
return mysql_fetch_array ( $res, MYSQL_NUM );
elseif ( strcmp ( $GLOBALS['db_type'], 'mysqli' ) == 0 )
return $res->fetch_array( MYSQLI_NUM );
elseif ( strcmp ( $GLOBALS['db_type'], 'mssql' ) == 0 )
return mssql_fetch_array ( $res );
elseif ( strcmp ( $GLOBALS['db_type'], 'oracle' ) == 0 )
return ( OCIFetchInto ( $GLOBALS['oracle_statement'], $row,
OCI_NUM + OCI_RETURN_NULLS ) ? $row : 0 );
elseif ( strcmp ( $GLOBALS['db_type'], 'postgresql' ) == 0 ) {
// Note: row became optional in PHP 4.1.0.
$r = pg_fetch_array ( $res, null, PGSQL_NUM );
return ( ! $r ? false : $r );
} elseif ( strcmp ( $GLOBALS['db_type'], 'odbc' ) == 0 )
return ( ! odbc_fetch_into ( $res, $ret ) ? false : $ret );
elseif ( strcmp ( $GLOBALS['db_type'], 'ibm_db2' ) == 0 )
return db2_fetch_array ( $res );
elseif ( strcmp ( $GLOBALS['db_type'], 'ibase' ) == 0 )
return ibase_fetch_row ( $res );
elseif ( strcmp ( $GLOBALS['db_type'], 'sqlite' ) == 0 )
return sqlite_fetch_array ( $res );
else
dbi_fatal_error ( 'dbi_fetch_row (): '
. translate ( 'db_type not defined.' ) );
}
/* Returns the number of rows affected by the last INSERT, UPDATE or DELETE.
*
* <b>Note:</b> Use the {@link dbi_error ()} function to get error information
* if the connection fails.
*
* @param resource $conn The database connection
* @param resource $res The database query resource returned from the
* {@link dbi_query ()} function.
*
* @return int The number or database rows affected.
*/
function dbi_affected_rows ( $conn, $res ) {
if ( strcmp ( $GLOBALS['db_type'], 'mysql' ) == 0 )
return mysql_affected_rows ( $conn );
elseif ( strcmp ( $GLOBALS['db_type'], 'mysqli' ) == 0 )
return $conn->affected_rows;
elseif ( strcmp ( $GLOBALS['db_type'], 'mssql' ) == 0 )
return mssql_rows_affected ( $conn );
elseif ( strcmp ( $GLOBALS['db_type'], 'oracle' ) == 0 )
return ( $GLOBALS['oracle_statement'] >= 0
? OCIRowCount ( $GLOBALS['oracle_statement'] ) : -1 );
elseif ( strcmp ( $GLOBALS['db_type'], 'postgresql' ) == 0 )
return pg_affected_rows ( $res );
elseif ( strcmp ( $GLOBALS['db_type'], 'odbc' ) == 0 )
return odbc_num_rows ( $res );
elseif ( strcmp ( $GLOBALS['db_type'], 'ibm_db2' ) == 0 )
return db2_num_rows ( $res );
elseif ( strcmp ( $GLOBALS['db_type'], 'ibase' ) == 0 )
return ibase_affected_rows ( $conn );
elseif ( strcmp ( $GLOBALS['db_type'], 'sqlite' ) == 0 )
return sqlite_changes ( $conn );
else
dbi_fatal_error ( 'dbi_free_result (): '
. translate ( 'db_type not defined.' ) );
}
/* Update a BLOB (binary large object) in the database with the contents
* of the specified file.
* A BLOB field should be created in a separete INSERT statement using
* NULL as the initial value prior to this call.
*
* @param resource $table the table name that contains the blob
* @param resource $column the table column name for the blob
* @param resource $key the key for updating the table row
* @param resource $data the data to insert
*
* @return bool True on success
*/
function dbi_update_blob ( $table, $column, $key, $data ) {
global $unavail_DBI_Update_blob;
$unavail_DBI_Update_blob = str_replace ( 'XXX', '"dbi_update_blob"',
translate ( 'Unfortunately, XXX is not implemented for' ) ) . ' ('
. $GLOBALS['db_type'] . ').';
assert ( '! empty ( $table )' );
assert ( '! empty ( $column )' );
assert ( '! empty ( $key )' );
assert ( '! empty ( $data )' );
$sql = 'UPDATE ' . $table . ' SET ' . $column;
if ( strcmp ( $GLOBALS['db_type'], 'mysql' ) == 0 ) {
return dbi_execute ( $sql . ' = \''
. ( function_exists ( 'mysql_real_escape_string' )
? mysql_real_escape_string ( $data ) : addslashes ( $data ) )
. '\' WHERE ' . $key );
} elseif ( strcmp ( $GLOBALS['db_type'], 'sqlite' ) == 0 )
return dbi_execute ( $sql . ' = \''
. sqlite_udf_encode_binary ( $data ) . '\' WHERE ' . $key );
elseif ( strcmp ( $GLOBALS['db_type'], 'mssql' ) == 0 )
return dbi_execute ( $sql . ' = 0x'
. bin2hex ( $data ) . ' WHERE ' . $key );
elseif ( strcmp ( $GLOBALS['db_type'], 'postgresql' ) == 0 )
return dbi_execute ( $sql . ' = \''
. pg_escape_bytea ( $data ) . '\' WHERE ' . $key );
else
// TODO!
die_miserable_death ( $unavail_DBI_Update_blob );
}
/* Get a BLOB (binary large object) from the database.
*
* @param resource $table the table name that contains the blob
* @param resource $column the table column name for the blob
* @param resource $key the key for updating the table row
*
* @return bool True on success
*/
function dbi_get_blob ( $table, $column, $key ) {
global $unavail_DBI_Update_blob;
assert ( '! empty ( $table )' );
assert ( '! empty ( $column )' );
assert ( '! empty ( $key )' );
$res = dbi_execute ( 'SELECT ' . $column . ' FROM ' . $table . ' WHERE '
. $key );
if ( ! $res )
return false;
$ret = '';
if ( $row = dbi_fetch_row ( $res ) ) {
if ( strcmp ( $GLOBALS['db_type'], 'mysql' ) == 0 ||
strcmp ( $GLOBALS['db_type'], 'mssql' ) == 0 )
$ret = $row[0];
elseif ( strcmp ( $GLOBALS['db_type'], 'sqlite' ) == 0 )
$ret = sqlite_udf_decode_binary ( $row[0] );
elseif ( strcmp ( $GLOBALS['db_type'], 'postgresql' ) == 0 )
$ret = pg_unescape_bytea ( $row[0] );
else
// TODO!
die_miserable_death ( $unavail_DBI_Update_blob );
}
dbi_free_result ( $res );
return $ret;
}
/* Frees a result set.
*
* @param resource $res The database query resource returned from
* the {@link dbi_query ()} function.
*
* @return bool True on success
*/
function dbi_free_result ( $res ) {
if ( $res === true ) // Not needed for UPDATE, DELETE, etc
return;
if ( strcmp ( $GLOBALS['db_type'], 'mysql' ) == 0 )
return mysql_free_result ( $res );
elseif ( strcmp ( $GLOBALS['db_type'], 'mysqli' ) == 0 )
return mysqli_free_result ( $res );
elseif ( strcmp ( $GLOBALS['db_type'], 'mssql' ) == 0 )
return mssql_free_result ( $res );
elseif ( strcmp ( $GLOBALS['db_type'], 'oracle' ) == 0 ) {
// Not supported. Ingore.
if ( $GLOBALS['oracle_statement'] >= 0 ) {
OCIFreeStatement ( $GLOBALS['oracle_statement'] );
$GLOBALS['oracle_statement'] = -1;
}
} elseif ( strcmp ( $GLOBALS['db_type'], 'postgresql' ) == 0 )
return pg_freeresult ( $res );
elseif ( strcmp ( $GLOBALS['db_type'], 'odbc' ) == 0 )
return odbc_free_result ( $res );
elseif ( strcmp ( $GLOBALS['db_type'], 'ibm_db2' ) == 0 )
return db2_free_result ( $res );
elseif ( strcmp ( $GLOBALS['db_type'], 'ibase' ) == 0 )
return ibase_free_result ( $res );
elseif ( strcmp ( $GLOBALS['db_type'], 'sqlite' ) == 0 ) {
// Not supported
} else
dbi_fatal_error ( 'dbi_free_result (): '
. translate ( 'db_type not defined.' ) );
}
/* Gets the latest database error message.
*
* @return string The text of the last database error. (The type of information
* varies depending on which type of database is being used.)
*/
function dbi_error () {
if ( strcmp ( $GLOBALS['db_type'], 'mysql' ) == 0 )
$ret = mysql_error ();
elseif ( strcmp ( $GLOBALS['db_type'], 'mysqli' ) == 0 )
$ret = $GLOBALS['db_connection']->error;
elseif ( strcmp ( $GLOBALS['db_type'], 'mssql' ) == 0 )
// No real mssql_error function. This is as good as it gets.
$ret = mssql_get_last_message ();
elseif ( strcmp ( $GLOBALS['db_type'], 'oracle' ) == 0 )
$ret = OCIError ( $GLOBALS['oracle_connection'] );
elseif ( strcmp ( $GLOBALS['db_type'], 'postgresql' ) == 0 )
$ret = pg_errormessage ( $GLOBALS['postgresql_connection'] );
elseif ( strcmp ( $GLOBALS['db_type'], 'odbc' ) == 0 )
// No way to get error from ODBC API.
$ret = translate ( 'Unknown ODBC error.' );
elseif ( strcmp ( $GLOBALS['db_type'], 'ibase' ) == 0 )
$ret = ibase_errmsg ();
elseif ( strcmp ( $GLOBALS['db_type'], "ibm_db2" ) == 0 ) {
$ret = db2_conn_errormsg ();
if ( $ret == '' )
$ret = db2_stmt_errormsg ();
} elseif ( strcmp ( $GLOBALS['db_type'], 'sqlite' ) == 0 ) {
if ( empty ( $GLOBALS['db_sqlite_error_str'] ) ) {
$ret = sqlite_last_error ( $GLOBALS['sqlite_c'] );
} else {
$ret = $GLOBALS['db_sqlite_error_str'];
$GLOBALS['db_sqlite_error_str'] = '';
}
} else
$ret = 'dbi_error (): ' . translate ( 'db_type not defined.' );
return ( strlen ( $ret ) ? $ret : translate ( 'Unknown error.' ) );
}
/* Displays a fatal database error and aborts execution.
*
* @param string $msg The database error message.
* @param bool $doExit Abort execution?
* @param bool $showError Show the details of the error (possibly including
* the SQL that caused the error)?
*/
function dbi_fatal_error ( $msg, $doExit = true, $showError = true ) {
if ( $showError ) {
echo '<h2>' . translate ( 'Error' ) . '</h2>
<!--begin_error (dbierror)-->
' . $msg . '
<!--end_error-->
';
}
if ( $doExit )
exit;
}
/* Escapes a string accordingly to the DB type.
*
* @param string $string SQL of query to execute
*
* @return string The escaped string
*/
function dbi_escape_string ( $string ) {
global $db_connection_info;
// Return the string in original form; all possible escapings by
// magic_quotes_gpc (and possibly magic_quotes_sybase) will be rolled back.
// But, also, we may roll back escaping we have done ourselves.
// (maybe this should be removed)
// if ( get_magic_quotes_gpc () )
$string = stripslashes ( $string );
switch ( $GLOBALS['db_type'] ) {
case 'mysql':
// MySQL requires an active connection.
return ( empty ( $db_connection_info['connected'] )
? addslashes ( $string )
: ( version_compare ( phpversion (), '4.3.0' ) >= 0
? mysql_real_escape_string ( $string, $db_connection_info['connection'] )
: mysql_escape_string ( $string ) ) );
case 'mysqli':
return ( empty ( $db_connection_info['connected'] )
? addslashes ( $string )
: $db_connection_info['connection']->real_escape_string ( $string ) );
case 'ibase':
case 'mssql':
case 'oracle':
return str_replace ( "'", "''", $string );
case 'postgresql':
return pg_escape_string ( $string );
case 'sqlite':
return sqlite_escape_string ( $string );
case 'ibm_db2':
case 'odbc':
default:
return addslashes ( $string );
}
}
/* Executes a SQL query, supporting parameter binding in the ?-style
*
* <b>Note:</b> Use the {@link dbi_error ()} function to get error information
* if the connection fails.
*
* @param string $sql SQL of query to execute.
* May contain ?-placeholders
* @param array $params An array containing the values to put in
* placeolders. These values will be escaped with
* dbi_escape_string () and will be put in single
* quotes. A NULL param will be replaced with NULL
* without quotes around it.
* @param bool $fatalOnError Abort execution if there is a database error?
* @param bool $showError Display error to user (including possibly the
* SQL) if there is a database error?
*
* @return mixed The query result resource on queries (which can then be passed
* to the {@link dbi_fetch_row ()} function to obtain the
* results), or true/false on insert or delete queries.
*/
function dbi_execute ( $sql, $params = array (), $fatalOnError = true,
$showError = true ) {
if ( count ( $params ) == 0 )
return dbi_query ( $sql, $fatalOnError, $showError );
$prepared = '';
$offset = $phindex = 0;
while ( ( $pos = strpos ( $sql, '?', $offset ) ) !== false ) {
$prepared .= substr ( $sql, $offset, $pos - $offset )
. ( ( is_null ( $params[ $phindex ] ) )
? "NULL" : ( "'" . dbi_escape_string ( $params[ $phindex ] ) . "'" ) );
$offset = $pos + 1;
$phindex++;
}
$prepared .= substr ( $sql, $offset );
return dbi_query ( $prepared, $fatalOnError, $showError );
}
/* Execute a SQL query. First, look to see if the results of this query are in
* a cache. If they are, then return them. If not, then run the query and store
* them in the cache. Of course, caching is only performed for SELECT queries.
* Anything other than that will clear out the entire cache
* (until we add more intelligent caching logic).
*/
function dbi_get_cached_rows ( $sql, $params = array (),
$fatalOnError = true, $showError = true ) {
global $db_cache_count, $db_connection_info;
$file = '';
$save_query = false;
if ( ! empty ( $db_connection_info['cachedir'] ) &&
function_exists ( 'file_get_contents' ) ) {
// Cache enabled. Add some sire specific info to avoid cross-site data
//sharing
$hash = md5 ( $db_connection_info['database']
. $db_connection_info['password'] .$sql . serialize ( $params ) );
$file = $db_connection_info['cachedir'] . '/' . $hash . '.dat';
if ( file_exists ( $file ) ) {
$db_cache_count++;
return unserialize ( file_get_contents ( $file ) );
}
$save_query = true;
}
$res = dbi_execute ( $sql, $params, $fatalOnError, $showError );
if ( $res ) {
$rows = array ();
while ( $row = dbi_fetch_row ( $res ) ) {
$rows[] = $row;
}
dbi_free_result ( $res );
// Serialize and save in cache for later use.
if ( ! empty ( $file ) && $save_query ) {
$fd = @fopen ( $file, 'w+b', false );
if ( empty ( $fd ) ) {
if ( function_exists ( "translate" ) ) {
dbi_fatal_error ( translate ( 'Cache error' ) . ': '
. str_replace ( 'XXX', translate ( 'write' ),
translate ( 'Could not XXX file' ) ) . " $file." );
} else {
dbi_fatal_error ( 'Cache error' . ': '
. str_replace ( 'XXX', 'write',
'Could not XXX file' ) . " $file." );
}
}
fwrite ( $fd, serialize ( $rows ) );
fclose ( $fd );
chmod ( $file, 0666 );
}
return $rows;
} else
return false;
}
/* Specify the location of the cache directory.
* This directory will need to world-writable if this is a web-based application.
*/
function dbi_init_cache ( $dir ) {
global $db_connection_info;
if ( ! isset ( $db_connection_info ) )
$db_connection_info = array ();
$db_connection_info['cachedir'] = $dir;
}
/* Enable SQL debugging.
* This will keep an array of all SQL queries in the global variable $SQLLOG.
*/
function dbi_set_debug ( $status = false ) {
global $db_connection_info;
if ( ! isset ( $db_connection_info ) )
$db_connection_info = array ();
$db_connection_info['debug'] = $status;
}
/* Get the SQL debug status.
*/
function dbi_get_debug () {
global $db_connection_info;
return ( ! isset ( $db_connection_info )
? false : ( ! empty ( $db_connection_info['debug'] ) ) );
}
/* Clear out the db cache.
* Return the number of files deleted.
*/
function dbi_clear_cache () {
global $db_connection_info;
if ( empty ( $db_connection_info['cachedir'] ) )
return 0;
$cnt = 0;
$fd = @opendir ( $db_connection_info['cachedir'] );
if ( empty ( $fd ) )
dbi_fatal_error ( translate ( 'Error opening cache dir' ) . ': '
. $db_connection_info['cachedir'] );
$b = 0;
while ( false !== ( $file = readdir ( $fd ) ) ) {
if ( preg_match ( '/^\S\S\S\S\S\S\S\S\S\S+.dat$/', $file ) ) {
// echo 'Deleting ' . $file . '<br />';
$cnt++;
$fullpath = $db_connection_info['cachedir'] . '/' . $file;
$b += filesize ( $fullpath );
if ( ! unlink ( $fullpath ) )
echo '<!-- ' . translate ( 'Error' ) . ': '
. str_replace ( 'XXX', translate ( 'delete' ),
translate ( 'Could not XXX file' ) ) . " $file. -->\n";
// TODO: log this somewhere???
}
}
return $cnt;
}
?>