Page Menu
Home
In-Portal Phabricator
Search
Configure Global Search
Log In
Files
F1167097
db_connection.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Tue, Sep 23, 5:25 AM
Size
32 KB
Mime Type
text/x-php
Expires
Thu, Sep 25, 5:25 AM (1 d, 2 h)
Engine
blob
Format
Raw Data
Handle
755942
Attached To
rINP In-Portal
db_connection.php
View Options
<?php
/**
* @version $Id: db_connection.php 15552 2012-10-02 17:13:27Z alex $
* @package In-Portal
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
defined
(
'FULL_PATH'
)
or
die
(
'restricted access!'
);
/**
* Multi database connection class
*
*/
class
kDBConnection
extends
kBase
{
/**
* Current database type
*
* @var string
* @access protected
*/
protected
$dbType
=
'mysql'
;
/**
* Created connection handle
*
* @var resource
* @access protected
*/
protected
$connectionID
=
null
;
/**
* Remembers, that database connection was opened successfully
*
* @var bool
* @access public
*/
public
$connectionOpened
=
false
;
/**
* Connection parameters, that were used
*
* @var Array
* @access protected
*/
protected
$connectionParams
=
Array
(
'host'
=>
''
,
'user'
=>
''
,
'pass'
=>
''
,
'db'
=>
''
);
/**
* Index of database server
*
* @var int
* @access protected
*/
protected
$serverIndex
=
0
;
/**
* Handle of currently processed recordset
*
* @var resource
* @access protected
*/
protected
$queryID
=
null
;
/**
* DB type specific function mappings
*
* @var Array
* @access protected
*/
protected
$metaFunctions
=
Array
();
/**
* Function to handle sql errors
*
* @var Array|string
* @access public
*/
public
$errorHandler
=
''
;
/**
* Error code
*
* @var int
* @access protected
*/
protected
$errorCode
=
0
;
/**
* Error message
*
* @var string
* @access protected
*/
protected
$errorMessage
=
''
;
/**
* Defines if database connection
* operations should generate debug
* information
*
* @var bool
* @access public
*/
public
$debugMode
=
false
;
/**
* Save query execution statistics
*
* @var bool
* @access protected
*/
protected
$_captureStatistics
=
false
;
/**
* Last query to database
*
* @var string
* @access public
*/
public
$lastQuery
=
''
;
/**
* Total processed queries count
*
* @var int
* @access protected
*/
protected
$_queryCount
=
0
;
/**
* Total time, used for serving queries
*
* @var Array
* @access protected
*/
protected
$_queryTime
=
0
;
/**
* Indicates, that next database query could be cached, when memory caching is enabled
*
* @var bool
* @access public
*/
public
$nextQueryCachable
=
false
;
/**
* For backwards compatibility with kDBLoadBalancer class
*
* @var bool
* @access public
*/
public
$nextQueryFromMaster
=
false
;
/**
* Initializes connection class with
* db type to used in future
*
* @param string $dbType
* @param string $errorHandler
* @param int $server_index
* @access public
*/
public
function
__construct
(
$dbType
,
$errorHandler
=
''
,
$server_index
=
0
)
{
if
(
class_exists
(
'kApplication'
)
)
{
// prevents "Fatal Error" on 2nd installation step (when database is empty)
parent
::
__construct
();
}
$this
->
dbType
=
$dbType
;
$this
->
serverIndex
=
$server_index
;
// $this->initMetaFunctions();
if
(!
$errorHandler
)
{
$this
->
errorHandler
=
Array
(&
$this
,
'handleError'
);
}
else
{
$this
->
errorHandler
=
$errorHandler
;
}
$this
->
_captureStatistics
=
defined
(
'DBG_CAPTURE_STATISTICS'
)
&&
DBG_CAPTURE_STATISTICS
&&
!(
defined
(
'ADMIN'
)
&&
ADMIN
);
}
/**
* Set's custom error
*
* @param int $code
* @param string $msg
* @access protected
*/
protected
function
setError
(
$code
,
$msg
)
{
$this
->
errorCode
=
$code
;
$this
->
errorMessage
=
$msg
;
}
/**
* Checks if previous query execution
* raised an error.
*
* @return bool
* @access public
*/
public
function
hasError
()
{
return
$this
->
errorCode
!=
0
;
}
/**
* Caches function specific to requested
* db type
*
* @access protected
*/
protected
function
initMetaFunctions
()
{
$ret
=
Array
();
switch
(
$this
->
dbType
)
{
case
'mysql'
:
$ret
=
Array
();
// only define functions, that name differs from "dbType_<meta_name>"
break
;
}
$this
->
metaFunctions
=
$ret
;
}
/**
* Gets function for specific db type
* based on it's meta name
*
* @param string $name
* @return string
* @access protected
*/
protected
function
getMetaFunction
(
$name
)
{
/*if ( !isset($this->metaFunctions[$name]) ) {
$this->metaFunctions[$name] = $name;
}*/
return
$this
->
dbType
.
'_'
.
$name
;
}
/**
* Try to connect to database server
* using specified parameters and set
* database to $db if connection made
*
* @param string $host
* @param string $user
* @param string $pass
* @param string $db
* @param bool $force_new
* @param bool $retry
* @return bool
* @access public
*/
public
function
Connect
(
$host
,
$user
,
$pass
,
$db
,
$force_new
=
false
,
$retry
=
false
)
{
$this
->
connectionParams
=
Array
(
'host'
=>
$host
,
'user'
=>
$user
,
'pass'
=>
$pass
,
'db'
=>
$db
);
$func
=
$this
->
getMetaFunction
(
'connect'
);
$this
->
connectionID
=
$func
(
$host
,
$user
,
$pass
,
$force_new
);
if
(
$this
->
connectionID
)
{
if
(
defined
(
'DBG_SQL_MODE'
))
{
$this
->
Query
(
'SET sql_mode =
\'
'
.
DBG_SQL_MODE
.
'
\'
'
);
}
if
(
defined
(
'SQL_COLLATION'
)
&&
defined
(
'SQL_CHARSET'
))
{
$this
->
Query
(
'SET NAMES
\'
'
.
SQL_CHARSET
.
'
\'
COLLATE
\'
'
.
SQL_COLLATION
.
'
\'
'
);
}
$this
->
setError
(
0
,
''
);
// reset error
$this
->
setDB
(
$db
);
}
// process error (fatal in most cases)
$func
=
$this
->
getMetaFunction
(
'errno'
);
$this
->
errorCode
=
$this
->
connectionID
?
$func
(
$this
->
connectionID
)
:
$func
();
if
(
is_resource
(
$this
->
connectionID
)
&&
!
$this
->
hasError
()
)
{
$this
->
connectionOpened
=
true
;
return
true
;
}
$func
=
$this
->
getMetaFunction
(
'error'
);
$this
->
errorMessage
=
$this
->
connectionID
?
$func
(
$this
->
connectionID
)
:
$func
();
$error_msg
=
'Database connection failed, please check your connection settings.<br/>Error ('
.
$this
->
errorCode
.
'): '
.
$this
->
errorMessage
;
if
(
(
defined
(
'IS_INSTALL'
)
&&
IS_INSTALL
)
||
$retry
)
{
trigger_error
(
$error_msg
,
E_USER_WARNING
);
}
else
{
$this
->
Application
->
redirectToMaintenance
();
throw
new
RuntimeException
(
$error_msg
);
}
$this
->
connectionOpened
=
false
;
return
false
;
}
/**
* Checks if connection to database is opened
*
* @return bool
* @access public
*/
public
function
connectionOpened
()
{
return
$this
->
connectionOpened
;
}
/**
* Setups the connection according given configuration
*
* @param Array $config
* @return bool
* @access public
*/
public
function
setup
(
$config
)
{
if
(
is_object
(
$this
->
Application
)
)
{
$this
->
debugMode
=
$this
->
Application
->
isDebugMode
();
}
return
$this
->
Connect
(
$config
[
'Database'
][
'DBHost'
],
$config
[
'Database'
][
'DBUser'
],
$config
[
'Database'
][
'DBUserPassword'
],
$config
[
'Database'
][
'DBName'
]
);
}
/**
* Performs 3 reconnect attempts in case if connection to a DB was lost in the middle of script run (e.g. server restart)
*
* @param bool $force_new
* @return bool
* @access protected
*/
protected
function
ReConnect
(
$force_new
=
false
)
{
$retry_count
=
0
;
$connected
=
false
;
$func
=
$this
->
getMetaFunction
(
'close'
);
$func
(
$this
->
connectionID
);
while
(
$retry_count
<
3
)
{
sleep
(
5
);
// wait 5 seconds before each reconnect attempt
$connected
=
$this
->
Connect
(
$this
->
connectionParams
[
'host'
],
$this
->
connectionParams
[
'user'
],
$this
->
connectionParams
[
'pass'
],
$this
->
connectionParams
[
'db'
],
$force_new
,
true
);
if
(
$connected
)
{
break
;
}
$retry_count
++;
}
return
$connected
;
}
/**
* Shows error message from previous operation
* if it failed
*
* @param string $sql
* @param string $key_field
* @param bool $no_debug
* @return bool
* @access protected
*/
protected
function
showError
(
$sql
=
''
,
$key_field
=
null
,
$no_debug
=
false
)
{
static
$retry_count
=
0
;
$func
=
$this
->
getMetaFunction
(
'errno'
);
if
(!
$this
->
connectionID
)
{
// no connection while doing mysql_query
$this
->
errorCode
=
$func
();
if
(
$this
->
hasError
()
)
{
$func
=
$this
->
getMetaFunction
(
'error'
);
$this
->
errorMessage
=
$func
();
$ret
=
$this
->
callErrorHandler
(
$sql
);
if
(!
$ret
)
{
exit
;
}
}
return
false
;
}
// checking if there was an error during last mysql_query
$this
->
errorCode
=
$func
(
$this
->
connectionID
);
if
(
$this
->
hasError
()
)
{
$func
=
$this
->
getMetaFunction
(
'error'
);
$this
->
errorMessage
=
$func
(
$this
->
connectionID
);
$ret
=
$this
->
callErrorHandler
(
$sql
);
if
(
(
$this
->
errorCode
==
2006
||
$this
->
errorCode
==
2013
)
&&
(
$retry_count
<
3
)
)
{
// #2006 - MySQL server has gone away
// #2013 - Lost connection to MySQL server during query
$retry_count
++;
if
(
$this
->
ReConnect
()
)
{
return
$this
->
Query
(
$sql
,
$key_field
,
$no_debug
);
}
}
if
(!
$ret
)
{
exit
;
}
}
else
{
$retry_count
=
0
;
}
return
false
;
}
/**
* Sends db error to a predefined error handler
*
* @param $sql
* @return bool
* @access protected
*/
protected
function
callErrorHandler
(
$sql
)
{
if
(
is_array
(
$this
->
errorHandler
))
{
$func
=
$this
->
errorHandler
[
1
];
$ret
=
$this
->
errorHandler
[
0
]->
$func
(
$this
->
errorCode
,
$this
->
errorMessage
,
$sql
);
}
else
{
$func
=
$this
->
errorHandler
;
$ret
=
$func
(
$this
->
errorCode
,
$this
->
errorMessage
,
$sql
);
}
return
$ret
;
}
/**
* Default error handler for sql errors
*
* @param int $code
* @param string $msg
* @param string $sql
* @return bool
* @access public
*/
public
function
handleError
(
$code
,
$msg
,
$sql
)
{
echo
'<strong>Processing SQL</strong>: '
.
$sql
.
'<br/>'
;
echo
'<strong>Error ('
.
$code
.
'):</strong> '
.
$msg
.
'<br/>'
;
return
false
;
}
/**
* Set's database name for connection
* to $new_name
*
* @param string $new_name
* @return bool
* @access protected
*/
protected
function
setDB
(
$new_name
)
{
if
(!
$this
->
connectionID
)
return
false
;
$func
=
$this
->
getMetaFunction
(
'select_db'
);
return
$func
(
$new_name
,
$this
->
connectionID
);
}
/**
* Returns first field of first line
* of recordset if query ok or false
* otherwise
*
* @param string $sql
* @param int $offset
* @return string
* @access public
*/
public
function
GetOne
(
$sql
,
$offset
=
0
)
{
$row
=
$this
->
GetRow
(
$sql
,
$offset
);
if
(
!
$row
)
{
return
false
;
}
return
array_shift
(
$row
);
}
/**
* Returns first row of recordset
* if query ok, false otherwise
*
* @param string $sql
* @param int $offset
* @return Array
* @access public
*/
public
function
GetRow
(
$sql
,
$offset
=
0
)
{
$sql
.=
' '
.
$this
->
getLimitClause
(
$offset
,
1
);
$ret
=
$this
->
Query
(
$sql
);
if
(
!
$ret
)
{
return
false
;
}
return
array_shift
(
$ret
);
}
/**
* Returns 1st column of recordset as
* one-dimensional array or false otherwise
* Optional parameter $key_field can be used
* to set field name to be used as resulting
* array key
*
* @param string $sql
* @param string $key_field
* @return Array
* @access public
*/
public
function
GetCol
(
$sql
,
$key_field
=
null
)
{
$rows
=
$this
->
Query
(
$sql
);
if
(
!
$rows
)
{
return
$rows
;
}
$i
=
0
;
$row_count
=
count
(
$rows
);
$ret
=
Array
();
if
(
isset
(
$key_field
)
)
{
while
(
$i
<
$row_count
)
{
$ret
[
$rows
[
$i
][
$key_field
]]
=
array_shift
(
$rows
[
$i
]);
$i
++;
}
}
else
{
while
(
$i
<
$row_count
)
{
$ret
[]
=
array_shift
(
$rows
[
$i
]);
$i
++;
}
}
return
$ret
;
}
/**
* Returns iterator for 1st column of a recordset or false in case of error.
* Optional parameter $key_field can be used to set field name to be used
* as resulting array key.
*
* @param string $sql
* @param string $key_field
* @return bool|kMySQLQueryCol
*/
public
function
GetColIterator
(
$sql
,
$key_field
=
null
)
{
return
$this
->
GetIterator
(
$sql
,
$key_field
,
false
,
'kMySQLQueryCol'
);
}
/**
* Queries db with $sql query supplied
* and returns rows selected if any, false
* otherwise. Optional parameter $key_field
* allows to set one of the query fields
* value as key in string array.
*
* @param string $sql
* @param string $key_field
* @param bool $no_debug
* @return Array
* @access public
*/
public
function
Query
(
$sql
,
$key_field
=
null
,
$no_debug
=
false
)
{
$this
->
_queryCount
++;
$this
->
lastQuery
=
$sql
;
$query_func
=
$this
->
getMetaFunction
(
'query'
);
// set 1st checkpoint: begin
$start_time
=
$this
->
_captureStatistics
?
microtime
(
true
)
:
0
;
// set 1st checkpoint: end
$this
->
setError
(
0
,
''
);
// reset error
$this
->
queryID
=
$query_func
(
$sql
,
$this
->
connectionID
);
if
(
is_resource
(
$this
->
queryID
)
)
{
$ret
=
Array
();
$fetch_func
=
$this
->
getMetaFunction
(
'fetch_assoc'
);
if
(
isset
(
$key_field
)
)
{
while
((
$row
=
$fetch_func
(
$this
->
queryID
)))
{
$ret
[
$row
[
$key_field
]]
=
$row
;
}
}
else
{
while
((
$row
=
$fetch_func
(
$this
->
queryID
)))
{
$ret
[]
=
$row
;
}
}
// set 2nd checkpoint: begin
if
(
$this
->
_captureStatistics
)
{
$query_time
=
microtime
(
true
)
-
$start_time
;
if
(
$query_time
>
DBG_MAX_SQL_TIME
)
{
$this
->
Application
->
logSlowQuery
(
$sql
,
$query_time
);
}
$this
->
_queryTime
+=
$query_time
;
}
// set 2nd checkpoint: end
$this
->
Destroy
();
return
$ret
;
}
else
{
// set 2nd checkpoint: begin
if
(
$this
->
_captureStatistics
)
{
$this
->
_queryTime
+=
microtime
(
true
)
-
$start_time
;
}
// set 2nd checkpoint: end
}
return
$this
->
showError
(
$sql
,
$key_field
,
$no_debug
);
}
/**
* Returns iterator to a recordset, produced from running $sql query Queries db with $sql query supplied and returns kMySQLQuery iterator
* or false in case of error. Optional parameter $key_field allows to
* set one of the query fields value as key in string array.
*
* @param string $sql
* @param string $key_field
* @param bool $no_debug
* @param string $iterator_class
* @return kMySQLQuery|bool
* @access public
*/
public
function
GetIterator
(
$sql
,
$key_field
=
null
,
$no_debug
=
false
,
$iterator_class
=
'kMySQLQuery'
)
{
$this
->
_queryCount
++;
$this
->
lastQuery
=
$sql
;
$query_func
=
$this
->
getMetaFunction
(
'query'
);
// set 1st checkpoint: begin
$start_time
=
$this
->
_captureStatistics
?
microtime
(
true
)
:
0
;
// set 1st checkpoint: end
$this
->
setError
(
0
,
''
);
// reset error
$this
->
queryID
=
$query_func
(
$sql
,
$this
->
connectionID
);
if
(
is_resource
(
$this
->
queryID
)
)
{
$ret
=
new
$iterator_class
(
$this
->
queryID
,
$key_field
);
/* @var $ret kMySQLQuery */
// set 2nd checkpoint: begin
if
(
$this
->
_captureStatistics
)
{
$query_time
=
microtime
(
true
)
-
$start_time
;
if
(
$query_time
>
DBG_MAX_SQL_TIME
)
{
$this
->
Application
->
logSlowQuery
(
$sql
,
$query_time
);
}
$this
->
_queryTime
+=
$query_time
;
}
// set 2nd checkpoint: end
return
$ret
;
}
else
{
// set 2nd checkpoint: begin
if
(
$this
->
_captureStatistics
)
{
$this
->
_queryTime
+=
microtime
(
true
)
-
$start_time
;
}
// set 2nd checkpoint: end
}
return
$this
->
showError
(
$sql
,
$key_field
,
$no_debug
);
}
/**
* Free memory used to hold recordset handle
*
* @access public
*/
public
function
Destroy
()
{
$free_func
=
$this
->
getMetaFunction
(
'free_result'
);
$free_func
(
$this
->
queryID
);
unset
(
$this
->
queryID
);
}
/**
* Performs sql query, that will change database content
*
* @param string $sql
* @return bool
* @access public
*/
public
function
ChangeQuery
(
$sql
)
{
$this
->
Query
(
$sql
);
return
!
$this
->
hasError
();
}
/**
* Returns auto increment field value from
* insert like operation if any, zero otherwise
*
* @return int
* @access public
*/
public
function
getInsertID
()
{
$func
=
$this
->
getMetaFunction
(
'insert_id'
);
return
$func
(
$this
->
connectionID
);
}
/**
* Returns row count affected by last query
*
* @return int
* @access public
*/
public
function
getAffectedRows
()
{
$func
=
$this
->
getMetaFunction
(
'affected_rows'
);
return
$func
(
$this
->
connectionID
);
}
/**
* Returns LIMIT sql clause part for specific db
*
* @param int $offset
* @param int $rows
* @return string
* @access public
*/
public
function
getLimitClause
(
$offset
,
$rows
)
{
if
(
!(
$rows
>
0
)
)
{
return
''
;
}
switch
(
$this
->
dbType
)
{
default
:
return
'LIMIT '
.
$offset
.
','
.
$rows
;
break
;
}
}
/**
* If it's a string, adds quotes and backslashes (only work since PHP 4.3.0)
* Otherwise returns as-is
*
* @param mixed $string
* @return string
* @access public
*/
public
function
qstr
(
$string
)
{
if
(
is_null
(
$string
)
)
{
return
'NULL'
;
}
# This will also quote numeric values. This should be harmless,
# and protects against weird problems that occur when they really
# _are_ strings such as article titles and string->number->string
# conversion is not 1:1.
return
"'"
.
mysql_real_escape_string
(
$string
,
$this
->
connectionID
)
.
"'"
;
}
/**
* Calls "qstr" function for each given array element
*
* @param Array $array
* @param string $function
* @return Array
*/
public
function
qstrArray
(
$array
,
$function
=
'qstr'
)
{
return
array_map
(
Array
(&
$this
,
$function
),
$array
);
}
/**
* Escapes strings (only work since PHP 4.3.0)
*
* @param mixed $string
* @return string
* @access public
*/
public
function
escape
(
$string
)
{
if
(
is_null
(
$string
)
)
{
return
'NULL'
;
}
$string
=
mysql_real_escape_string
(
$string
,
$this
->
connectionID
);
// prevent double-escaping of MySQL wildcard symbols ("%" and "_") in case if they were already escaped
return
str_replace
(
Array
(
'
\\\\
%'
,
'
\\\\
_'
),
Array
(
'
\\
%'
,
'
\\
_'
),
$string
);
}
/**
* Returns last error code occurred
*
* @return int
* @access public
*/
public
function
getErrorCode
()
{
return
$this
->
errorCode
;
}
/**
* Returns last error message
*
* @return string
* @access public
*/
public
function
getErrorMsg
()
{
return
$this
->
errorMessage
;
}
/**
* Performs insert of given data (useful with small number of queries)
* or stores it to perform multiple insert later (useful with large number of queries)
*
* @param Array $fields_hash
* @param string $table
* @param string $type
* @param bool $insert_now
* @return bool
* @access public
*/
public
function
doInsert
(
$fields_hash
,
$table
,
$type
=
'INSERT'
,
$insert_now
=
true
)
{
static
$value_sqls
=
Array
();
if
(
$insert_now
)
{
$fields_sql
=
'`'
.
implode
(
'`,`'
,
array_keys
(
$fields_hash
))
.
'`'
;
}
$values_sql
=
''
;
foreach
(
$fields_hash
as
$field_name
=>
$field_value
)
{
$values_sql
.=
$this
->
qstr
(
$field_value
)
.
','
;
}
// don't use preg here, as it may fail when string is too long
$value_sqls
[]
=
rtrim
(
$values_sql
,
','
);
$insert_result
=
true
;
if
(
$insert_now
)
{
$insert_count
=
count
(
$value_sqls
);
if
((
$insert_count
>
1
)
&&
(
$value_sqls
[
$insert_count
-
1
]
==
$value_sqls
[
$insert_count
-
2
]))
{
// last two records are the same
array_pop
(
$value_sqls
);
}
$sql
=
strtoupper
(
$type
)
.
' INTO `'
.
$table
.
'` ('
.
$fields_sql
.
') VALUES ('
.
implode
(
'),('
,
$value_sqls
)
.
')'
;
$value_sqls
=
Array
();
// reset before query to prevent repeated call from error handler to insert 2 records instead of 1
$insert_result
=
$this
->
ChangeQuery
(
$sql
);
}
return
$insert_result
;
}
/**
* Update given field values to given record using $key_clause
*
* @param Array $fields_hash
* @param string $table
* @param string $key_clause
* @return bool
* @access public
*/
public
function
doUpdate
(
$fields_hash
,
$table
,
$key_clause
)
{
if
(!
$fields_hash
)
return
true
;
$fields_sql
=
''
;
foreach
(
$fields_hash
as
$field_name
=>
$field_value
)
{
$fields_sql
.=
'`'
.
$field_name
.
'` = '
.
$this
->
qstr
(
$field_value
)
.
','
;
}
// don't use preg here, as it may fail when string is too long
$fields_sql
=
rtrim
(
$fields_sql
,
','
);
$sql
=
'UPDATE `'
.
$table
.
'` SET '
.
$fields_sql
.
' WHERE '
.
$key_clause
;
return
$this
->
ChangeQuery
(
$sql
);
}
/**
* Allows to detect table's presence in database
*
* @param string $table_name
* @param bool $force
* @return bool
* @access public
*/
public
function
TableFound
(
$table_name
,
$force
=
false
)
{
static
$table_found
=
false
;
if
(
$table_found
===
false
)
{
$table_found
=
array_flip
(
$this
->
GetCol
(
'SHOW TABLES'
));
}
if
(
!
preg_match
(
'/^'
.
preg_quote
(
TABLE_PREFIX
,
'/'
)
.
'(.*)/'
,
$table_name
)
)
{
$table_name
=
TABLE_PREFIX
.
$table_name
;
}
if
(
$force
)
{
if
(
$this
->
Query
(
'SHOW TABLES LIKE '
.
$this
->
qstr
(
$table_name
))
)
{
$table_found
[
$table_name
]
=
1
;
}
else
{
unset
(
$table_found
[
$table_name
]);
}
}
return
isset
(
$table_found
[
$table_name
]);
}
/**
* Returns query processing statistics
*
* @return Array
* @access public
*/
public
function
getQueryStatistics
()
{
return
Array
(
'time'
=>
$this
->
_queryTime
,
'count'
=>
$this
->
_queryCount
);
}
/**
* Get status information from SHOW STATUS in an associative array
*
* @param string $which
* @return Array
* @access public
*/
public
function
getStatus
(
$which
=
'%'
)
{
$status
=
Array
();
$records
=
$this
->
Query
(
'SHOW STATUS LIKE "'
.
$which
.
'"'
);
foreach
(
$records
as
$record
)
{
$status
[
$record
[
'Variable_name'
]
]
=
$record
[
'Value'
];
}
return
$status
;
}
/**
* Get slave replication lag. It will only work if the DB user has the PROCESS privilege.
*
* @return int
* @access public
*/
public
function
getSlaveLag
()
{
// don't use kDBConnection::Query method, since it will create an array of all server processes
$processes
=
$this
->
GetIterator
(
'SHOW PROCESSLIST'
);
$skip_states
=
Array
(
'Waiting for master to send event'
,
'Connecting to master'
,
'Queueing master event to the relay log'
,
'Waiting for master update'
,
'Requesting binlog dump'
,
);
// find slave SQL thread
foreach
(
$processes
as
$process
)
{
if
(
$process
[
'User'
]
==
'system user'
&&
!
in_array
(
$process
[
'State'
],
$skip_states
)
)
{
// this is it, return the time (except -ve)
return
$process
[
'Time'
]
>
0x7fffffff
?
false
:
$process
[
'Time'
];
}
}
return
false
;
}
}
class
kDBConnectionDebug
extends
kDBConnection
{
protected
$_profileSQLs
=
false
;
/**
* Info about this database connection to show in debugger report
*
* @var string
* @access protected
*/
protected
$serverInfoLine
=
''
;
/**
* Initializes connection class with
* db type to used in future
*
* @param string $dbType
* @param string $errorHandler
* @param int $server_index
* @access public
*/
public
function
__construct
(
$dbType
,
$errorHandler
=
''
,
$server_index
=
0
)
{
parent
::
__construct
(
$dbType
,
$errorHandler
,
$server_index
);
$this
->
_profileSQLs
=
defined
(
'DBG_SQL_PROFILE'
)
&&
DBG_SQL_PROFILE
;
}
/**
* Try to connect to database server
* using specified parameters and set
* database to $db if connection made
*
* @param string $host
* @param string $user
* @param string $pass
* @param string $db
* @param bool $force_new
* @param bool $retry
* @return bool
* @access public
*/
public
function
Connect
(
$host
,
$user
,
$pass
,
$db
,
$force_new
=
false
,
$retry
=
false
)
{
if
(
defined
(
'DBG_SQL_SERVERINFO'
)
&&
DBG_SQL_SERVERINFO
)
{
$this
->
serverInfoLine
=
$this
->
serverIndex
.
' ('
.
$host
.
')'
;
}
return
parent
::
Connect
(
$host
,
$user
,
$pass
,
$db
,
$force_new
,
$retry
);
}
/**
* Queries db with $sql query supplied
* and returns rows selected if any, false
* otherwise. Optional parameter $key_field
* allows to set one of the query fields
* value as key in string array.
*
* @param string $sql
* @param string $key_field
* @param bool $no_debug
* @return Array
* @access public
*/
public
function
Query
(
$sql
,
$key_field
=
null
,
$no_debug
=
false
)
{
if
(
$no_debug
)
{
return
parent
::
Query
(
$sql
,
$key_field
,
$no_debug
);
}
global
$debugger
;
$this
->
_queryCount
++;
$this
->
lastQuery
=
$sql
;
$query_func
=
$this
->
getMetaFunction
(
'query'
);
// set 1st checkpoint: begin
if
(
$this
->
_profileSQLs
)
{
$queryID
=
$debugger
->
generateID
();
$debugger
->
profileStart
(
'sql_'
.
$queryID
,
$debugger
->
formatSQL
(
$sql
));
}
// set 1st checkpoint: end
$this
->
setError
(
0
,
''
);
// reset error
$this
->
queryID
=
$query_func
(
$sql
,
$this
->
connectionID
);
if
(
is_resource
(
$this
->
queryID
)
)
{
$ret
=
Array
();
$fetch_func
=
$this
->
getMetaFunction
(
'fetch_assoc'
);
if
(
isset
(
$key_field
)
)
{
while
((
$row
=
$fetch_func
(
$this
->
queryID
)))
{
$ret
[
$row
[
$key_field
]]
=
$row
;
}
}
else
{
while
((
$row
=
$fetch_func
(
$this
->
queryID
)))
{
$ret
[]
=
$row
;
}
}
// set 2nd checkpoint: begin
if
(
$this
->
_profileSQLs
)
{
$current_element
=
current
(
$ret
);
$first_cell
=
count
(
$ret
)
==
1
&&
count
(
$current_element
)
==
1
?
current
(
$current_element
)
:
null
;
if
(
strlen
(
$first_cell
)
>
200
)
{
$first_cell
=
substr
(
$first_cell
,
0
,
50
)
.
' ...'
;
}
$debugger
->
profileFinish
(
'sql_'
.
$queryID
,
null
,
null
,
$this
->
getAffectedRows
(),
$first_cell
,
$this
->
_queryCount
,
$this
->
nextQueryCachable
,
$this
->
serverInfoLine
);
$debugger
->
profilerAddTotal
(
'sql'
,
'sql_'
.
$queryID
);
$this
->
nextQueryCachable
=
false
;
}
// set 2nd checkpoint: end
$this
->
Destroy
();
return
$ret
;
}
else
{
// set 2nd checkpoint: begin
if
(
$this
->
_profileSQLs
)
{
$debugger
->
profileFinish
(
'sql_'
.
$queryID
,
null
,
null
,
$this
->
getAffectedRows
(),
null
,
$this
->
_queryCount
,
$this
->
nextQueryCachable
,
$this
->
serverInfoLine
);
$debugger
->
profilerAddTotal
(
'sql'
,
'sql_'
.
$queryID
);
$this
->
nextQueryCachable
=
false
;
}
// set 2nd checkpoint: end
}
return
$this
->
showError
(
$sql
,
$key_field
);
}
/**
* Queries db with $sql query supplied and returns kMySQLQuery iterator
* or false in case of error. Optional parameter $key_field allows to
* set one of the query fields value as key in string array.
*
* @param string $sql
* @param string $key_field
* @param bool $no_debug
* @param string $iterator_class
* @return kMySQLQuery|bool
* @access public
*/
public
function
GetIterator
(
$sql
,
$key_field
=
null
,
$no_debug
=
false
,
$iterator_class
=
'kMySQLQuery'
)
{
if
(
$no_debug
)
{
return
parent
::
Query
(
$sql
,
$key_field
,
$no_debug
,
$iterator_class
);
}
global
$debugger
;
$this
->
_queryCount
++;
$this
->
lastQuery
=
$sql
;
$query_func
=
$this
->
getMetaFunction
(
'query'
);
// set 1st checkpoint: begin
if
(
$this
->
_profileSQLs
)
{
$queryID
=
$debugger
->
generateID
();
$debugger
->
profileStart
(
'sql_'
.
$queryID
,
$debugger
->
formatSQL
(
$sql
));
}
// set 1st checkpoint: end
$this
->
setError
(
0
,
''
);
// reset error
$this
->
queryID
=
$query_func
(
$sql
,
$this
->
connectionID
);
if
(
is_resource
(
$this
->
queryID
)
)
{
$ret
=
new
$iterator_class
(
$this
->
queryID
,
$key_field
);
/* @var $ret kMySQLQuery */
// set 2nd checkpoint: begin
if
(
$this
->
_profileSQLs
)
{
$first_cell
=
count
(
$ret
)
==
1
&&
$ret
->
fieldCount
()
==
1
?
current
(
$ret
->
current
())
:
null
;
if
(
strlen
(
$first_cell
)
>
200
)
{
$first_cell
=
substr
(
$first_cell
,
0
,
50
)
.
' ...'
;
}
$debugger
->
profileFinish
(
'sql_'
.
$queryID
,
null
,
null
,
$this
->
getAffectedRows
(),
$first_cell
,
$this
->
_queryCount
,
$this
->
nextQueryCachable
,
$this
->
serverInfoLine
);
$debugger
->
profilerAddTotal
(
'sql'
,
'sql_'
.
$queryID
);
$this
->
nextQueryCachable
=
false
;
}
// set 2nd checkpoint: end
return
$ret
;
}
else
{
// set 2nd checkpoint: begin
if
(
$this
->
_profileSQLs
)
{
$debugger
->
profileFinish
(
'sql_'
.
$queryID
,
null
,
null
,
$this
->
getAffectedRows
(),
null
,
$this
->
_queryCount
,
$this
->
nextQueryCachable
,
$this
->
serverInfoLine
);
$debugger
->
profilerAddTotal
(
'sql'
,
'sql_'
.
$queryID
);
$this
->
nextQueryCachable
=
false
;
}
// set 2nd checkpoint: end
}
return
$this
->
showError
(
$sql
,
$key_field
);
}
}
class
kMySQLQuery
implements
Iterator
,
Countable
,
SeekableIterator
{
/**
* Current index in recordset
*
* @var int
* @access protected
*/
protected
$position
=
-
1
;
/**
* Query resource
*
* @var resource
* @access protected
*/
protected
$result
;
/**
* Field to act as key in a resulting array
*
* @var string
* @access protected
*/
protected
$keyField
=
null
;
/**
* Data in current row of recordset
*
* @var Array
* @access protected
*/
protected
$rowData
=
Array
();
/**
* Row count in a result
*
* @var int
* @access protected
*/
protected
$rowCount
=
0
;
/**
* Creates new instance of a class
*
* @param resource $result
* @param null|string $key_field
*/
public
function
__construct
(
$result
,
$key_field
=
null
)
{
$this
->
result
=
$result
;
$this
->
keyField
=
$key_field
;
$this
->
rowCount
=
mysql_num_rows
(
$this
->
result
);
$this
->
rewind
();
}
/**
* Moves recordset pointer to first element
*
* @return void
* @access public
* @implements Iterator::rewind
*/
public
function
rewind
()
{
$this
->
seek
(
0
);
}
/**
* Returns value at current position
*
* @return mixed
* @access public
* @implements Iterator::current
*/
function
current
()
{
return
$this
->
rowData
;
}
/**
* Returns key at current position
*
* @return mixed
* @access public
* @implements Iterator::key
*/
function
key
()
{
return
$this
->
keyField
?
$this
->
rowData
[
$this
->
keyField
]
:
$this
->
position
;
}
/**
* Moves recordset pointer to next position
*
* @return void
* @access public
* @implements Iterator::next
*/
function
next
()
{
$this
->
seek
(
$this
->
position
+
1
);
}
/**
* Detects if current position is within recordset bounds
*
* @return bool
* @access public
* @implements Iterator::valid
*/
public
function
valid
()
{
return
$this
->
position
<
$this
->
rowCount
;
}
/**
* Counts recordset rows
*
* @return int
* @access public
* @implements Countable::count
*/
public
function
count
()
{
return
$this
->
rowCount
;
}
/**
* Counts fields in current row
*
* @return int
* @access public
*/
public
function
fieldCount
()
{
return
count
(
$this
->
rowData
);
}
/**
* Moves cursor into given position within recordset
*
* @param int $position
* @throws OutOfBoundsException
* @access public
* @implements SeekableIterator::seek
*/
public
function
seek
(
$position
)
{
if
(
$this
->
position
==
$position
)
{
return
;
}
$this
->
position
=
$position
;
if
(
$this
->
valid
()
)
{
mysql_data_seek
(
$this
->
result
,
$this
->
position
);
$this
->
rowData
=
mysql_fetch_assoc
(
$this
->
result
);
}
/*if ( !$this->valid() ) {
throw new OutOfBoundsException('Invalid seek position (' . $position . ')');
}*/
}
/**
* Returns first recordset row
*
* @return Array
* @access public
*/
public
function
first
()
{
$this
->
seek
(
0
);
return
$this
->
rowData
;
}
/**
* Closes recordset and freese memory
*
* @return void
* @access public
*/
public
function
close
()
{
mysql_free_result
(
$this
->
result
);
unset
(
$this
->
result
);
}
/**
* Frees memory when object is destroyed
*
* @return void
* @access public
*/
public
function
__destruct
()
{
$this
->
close
();
}
/**
* Returns all keys
*
* @return Array
* @access public
*/
public
function
keys
()
{
$ret
=
Array
();
foreach
(
$this
as
$key
=>
$value
)
{
$ret
[]
=
$key
;
}
return
$ret
;
}
/**
* Returns all values
*
* @return Array
* @access public
*/
public
function
values
()
{
$ret
=
Array
();
foreach
(
$this
as
$value
)
{
$ret
[]
=
$value
;
}
return
$ret
;
}
/**
* Returns whole recordset as array
*
* @return Array
* @access public
*/
public
function
toArray
()
{
$ret
=
Array
();
foreach
(
$this
as
$key
=>
$value
)
{
$ret
[
$key
]
=
$value
;
}
return
$ret
;
}
}
class
kMySQLQueryCol
extends
kMySQLQuery
{
/**
* Returns value at current position
*
* @return mixed
* @access public
* @implements Iterator::current
*/
function
current
()
{
return
reset
(
$this
->
rowData
);
}
/**
* Returns first column of first recordset row
*
* @return string
* @access public
*/
public
function
first
()
{
$this
->
seek
(
0
);
return
reset
(
$this
->
rowData
);
}
}
Event Timeline
Log In to Comment