Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
Q
question2answer
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
outils
question2answer
Commits
769b2d38
Commit
769b2d38
authored
Jan 12, 2017
by
Scott
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Coding style (qa-db.php)
parent
b507ca2f
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
630 additions
and
585 deletions
+630
-585
qa-db.php
qa-include/qa-db.php
+630
-585
No files found.
qa-include/qa-db.php
View file @
769b2d38
...
@@ -20,414 +20,440 @@
...
@@ -20,414 +20,440 @@
More about this license: http://www.question2answer.org/license.php
More about this license: http://www.question2answer.org/license.php
*/
*/
if
(
!
defined
(
'QA_VERSION'
))
{
// don't allow this page to be requested directly from browser
if
(
!
defined
(
'QA_VERSION'
))
{
// don't allow this page to be requested directly from browser
header
(
'Location: ../'
);
header
(
'Location: ../'
);
exit
;
exit
;
}
}
/**
* Indicates to the Q2A database layer that database connections are permitted fro this point forwards
* (before this point, some plugins may not have had a chance to override some database access functions).
*/
function
qa_db_allow_connect
()
{
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
global
$qa_db_allow_connect
;
$qa_db_allow_connect
=
true
;
}
/**
* Connect to the Q2A database, select the right database, optionally install the $failhandler (and call it if necessary).
* Uses mysqli as of Q2A 1.7.
*/
function
qa_db_connect
(
$failhandler
=
null
)
{
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
global
$qa_db_connection
,
$qa_db_fail_handler
,
$qa_db_allow_connect
;
if
(
!
$qa_db_allow_connect
)
qa_fatal_error
(
'It appears that a plugin is trying to access the database, but this is not allowed until Q2A initialization is complete.'
);
if
(
isset
(
$failhandler
))
/**
$qa_db_fail_handler
=
$failhandler
;
// set this even if connection already opened
* Indicates to the Q2A database layer that database connections are permitted fro this point forwards
* (before this point, some plugins may not have had a chance to override some database access functions).
*/
function
qa_db_allow_connect
()
{
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
if
(
$qa_db_connection
instanceof
mysqli
)
global
$qa_db_allow_connect
;
return
;
$host
=
QA_FINAL_MYSQL_HOSTNAME
;
$qa_db_allow_connect
=
true
;
$port
=
null
;
}
if
(
defined
(
'QA_FINAL_WORDPRESS_INTEGRATE_PATH'
))
{
// Wordpress allows setting port inside DB_HOST constant, like 127.0.0.1:3306
$host_and_port
=
explode
(
':'
,
$host
);
if
(
count
(
$host_and_port
)
>=
2
)
{
$host
=
$host_and_port
[
0
];
$port
=
$host_and_port
[
1
];
}
}
elseif
(
defined
(
'QA_FINAL_MYSQL_PORT'
))
{
$port
=
QA_FINAL_MYSQL_PORT
;
}
if
(
QA_PERSISTENT_CONN_DB
)
/**
$host
=
'p:'
.
$host
;
* Connect to the Q2A database, select the right database, optionally install the $failhandler (and call it if necessary).
* Uses mysqli as of Q2A 1.7.
* @param null $failhandler
* @return mixed|void
*/
function
qa_db_connect
(
$failhandler
=
null
)
{
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
// in mysqli we connect and select database in constructor
global
$qa_db_connection
,
$qa_db_fail_handler
,
$qa_db_allow_connect
;
if
(
$port
!==
null
)
$db
=
new
mysqli
(
$host
,
QA_FINAL_MYSQL_USERNAME
,
QA_FINAL_MYSQL_PASSWORD
,
QA_FINAL_MYSQL_DATABASE
,
$port
);
else
$db
=
new
mysqli
(
$host
,
QA_FINAL_MYSQL_USERNAME
,
QA_FINAL_MYSQL_PASSWORD
,
QA_FINAL_MYSQL_DATABASE
);
// must use procedural `mysqli_connect_error` here prior to 5.2.9
if
(
!
$qa_db_allow_connect
)
$conn_error
=
mysqli_connect_error
();
qa_fatal_error
(
'It appears that a plugin is trying to access the database, but this is not allowed until Q2A initialization is complete.'
);
if
(
$conn_error
)
qa_db_fail_error
(
'connect'
,
$db
->
connect_errno
,
$conn_error
);
// From Q2A 1.5, we explicitly set the character encoding of the MySQL connection, instead of using lots of "SELECT BINARY col"-style queries.
if
(
isset
(
$failhandler
))
// Testing showed that overhead is minimal, so this seems worth trading off against the benefit of more straightforward queries, especially
$qa_db_fail_handler
=
$failhandler
;
// set this even if connection already opened
// for plugin developers.
if
(
!
$db
->
set_charset
(
'utf8'
))
qa_db_fail_error
(
'set_charset'
,
$db
->
errno
,
$db
->
error
);
qa_report_process_stage
(
'db_connected'
);
if
(
$qa_db_connection
instanceof
mysqli
)
return
;
$qa_db_connection
=
$db
;
}
$host
=
QA_FINAL_MYSQL_HOSTNAME
;
$port
=
null
;
/**
if
(
defined
(
'QA_FINAL_WORDPRESS_INTEGRATE_PATH'
))
{
* If a DB error occurs, call the installed fail handler (if any) otherwise report error and exit immediately.
// Wordpress allows setting port inside DB_HOST constant, like 127.0.0.1:3306
*/
$host_and_port
=
explode
(
':'
,
$host
);
function
qa_db_fail_error
(
$type
,
$errno
=
null
,
$error
=
null
,
$query
=
null
)
if
(
count
(
$host_and_port
)
>=
2
)
{
{
$host
=
$host_and_port
[
0
];
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
$port
=
$host_and_port
[
1
];
global
$qa_db_fail_handler
;
@
error_log
(
'PHP Question2Answer MySQL '
.
$type
.
' error '
.
$errno
.
': '
.
$error
.
(
isset
(
$query
)
?
(
' - Query: '
.
$query
)
:
''
));
if
(
function_exists
(
$qa_db_fail_handler
))
$qa_db_fail_handler
(
$type
,
$errno
,
$error
,
$query
);
else
{
echo
sprintf
(
'<hr><div style="color: red">Database %s<p>%s</p><code>%s</code></div>'
,
htmlspecialchars
(
$type
.
' error '
.
$errno
),
nl2br
(
htmlspecialchars
(
$error
)),
nl2br
(
htmlspecialchars
(
$query
))
);
qa_exit
(
'error'
);
}
}
}
elseif
(
defined
(
'QA_FINAL_MYSQL_PORT'
))
{
$port
=
QA_FINAL_MYSQL_PORT
;
}
}
if
(
QA_PERSISTENT_CONN_DB
)
/**
$host
=
'p:'
.
$host
;
* Return the current connection to the Q2A database, connecting if necessary and $connect is true.
*/
// in mysqli we connect and select database in constructor
function
qa_db_connection
(
$connect
=
true
)
if
(
$port
!==
null
)
{
$db
=
new
mysqli
(
$host
,
QA_FINAL_MYSQL_USERNAME
,
QA_FINAL_MYSQL_PASSWORD
,
QA_FINAL_MYSQL_DATABASE
,
$port
);
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
else
$db
=
new
mysqli
(
$host
,
QA_FINAL_MYSQL_USERNAME
,
QA_FINAL_MYSQL_PASSWORD
,
QA_FINAL_MYSQL_DATABASE
);
global
$qa_db_connection
;
// must use procedural `mysqli_connect_error` here prior to 5.2.9
if
(
$connect
&&
!
(
$qa_db_connection
instanceof
mysqli
))
{
$conn_error
=
mysqli_connect_error
();
qa_db_connect
();
if
(
$conn_error
)
qa_db_fail_error
(
'connect'
,
$db
->
connect_errno
,
$conn_error
);
if
(
!
(
$qa_db_connection
instanceof
mysqli
))
qa_fatal_error
(
'Failed to connect to database'
);
// From Q2A 1.5, we explicitly set the character encoding of the MySQL connection, instead of using lots of "SELECT BINARY col"-style queries.
}
// Testing showed that overhead is minimal, so this seems worth trading off against the benefit of more straightforward queries, especially
// for plugin developers.
return
$qa_db_connection
;
if
(
!
$db
->
set_charset
(
'utf8'
))
qa_db_fail_error
(
'set_charset'
,
$db
->
errno
,
$db
->
error
);
qa_report_process_stage
(
'db_connected'
);
$qa_db_connection
=
$db
;
}
/**
* If a DB error occurs, call the installed fail handler (if any) otherwise report error and exit immediately.
* @param $type
* @param int $errno
* @param string $error
* @param string $query
* @return mixed
*/
function
qa_db_fail_error
(
$type
,
$errno
=
null
,
$error
=
null
,
$query
=
null
)
{
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
global
$qa_db_fail_handler
;
@
error_log
(
'PHP Question2Answer MySQL '
.
$type
.
' error '
.
$errno
.
': '
.
$error
.
(
isset
(
$query
)
?
(
' - Query: '
.
$query
)
:
''
));
if
(
function_exists
(
$qa_db_fail_handler
))
$qa_db_fail_handler
(
$type
,
$errno
,
$error
,
$query
);
else
{
echo
sprintf
(
'<hr><div style="color: red">Database %s<p>%s</p><code>%s</code></div>'
,
htmlspecialchars
(
$type
.
' error '
.
$errno
),
nl2br
(
htmlspecialchars
(
$error
)),
nl2br
(
htmlspecialchars
(
$query
))
);
qa_exit
(
'error'
);
}
}
}
/**
/**
* Disconnect from the Q2A databas
e.
* Return the current connection to the Q2A database, connecting if necessary and $connect is tru
e.
*/
* @param bool $connect
function
qa_db_disconnect
()
* @return mixed
{
*/
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
function
qa_db_connection
(
$connect
=
true
)
{
global
$qa_db_connection
;
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
if
(
$qa_db_connection
instanceof
mysqli
)
{
global
$qa_db_connection
;
qa_report_process_stage
(
'db_disconnect'
);
if
(
!
QA_PERSISTENT_CONN_DB
)
{
if
(
$connect
&&
!
(
$qa_db_connection
instanceof
mysqli
))
{
if
(
!
$qa_db_connection
->
close
())
qa_db_connect
();
qa_fatal_error
(
'Database disconnect failed'
);
}
$qa_db_connection
=
null
;
if
(
!
(
$qa_db_connection
instanceof
mysqli
))
}
qa_fatal_error
(
'Failed to connect to database'
);
}
}
return
$qa_db_connection
;
}
/**
* Run the raw $query, call the global failure handler if necessary, otherwise return the result resource.
* If appropriate, also track the resources used by database queries, and the queries themselves, for performance debugging.
*/
function
qa_db_query_raw
(
$query
)
{
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
if
(
QA_DEBUG_PERFORMANCE
)
{
/**
global
$qa_usage
;
* Disconnect from the Q2A database.
*/
function
qa_db_disconnect
()
{
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
// time the query
global
$qa_db_connection
;
$oldtime
=
array_sum
(
explode
(
' '
,
microtime
()));
$result
=
qa_db_query_execute
(
$query
);
$usedtime
=
array_sum
(
explode
(
' '
,
microtime
()))
-
$oldtime
;
// fetch counts
if
(
$qa_db_connection
instanceof
mysqli
)
{
$gotrows
=
$gotcolumns
=
null
;
qa_report_process_stage
(
'db_disconnect'
);
if
(
$result
instanceof
mysqli_result
)
{
$gotrows
=
$result
->
num_rows
;
$gotcolumns
=
$result
->
field_count
;
}
$qa_usage
->
logDatabaseQuery
(
$query
,
$usedtime
,
$gotrows
,
$gotcolumns
);
}
else
$result
=
qa_db_query_execute
(
$query
);
// @error_log('Question2Answer MySQL query: '.$query);
if
(
$result
===
false
)
{
if
(
!
QA_PERSISTENT_CONN_DB
)
{
$db
=
qa_db_connection
();
if
(
!
$qa_db_connection
->
close
())
qa_db_fail_error
(
'query'
,
$db
->
errno
,
$db
->
error
,
$query
);
qa_fatal_error
(
'Database disconnect failed'
);
}
}
return
$result
;
$qa_db_connection
=
null
;
}
}
}
/**
* Lower-level function to execute a query, which automatically retries if there is a MySQL deadlock error.
/**
*/
* Run the raw $query, call the global failure handler if necessary, otherwise return the result resource.
function
qa_db_query_execute
(
$query
)
* If appropriate, also track the resources used by database queries, and the queries themselves, for performance debugging.
{
* @param $query
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
* @return mixed
*/
$db
=
qa_db_connection
();
function
qa_db_query_raw
(
$query
)
{
for
(
$attempt
=
0
;
$attempt
<
100
;
$attempt
++
)
{
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
$result
=
$db
->
query
(
$query
);
if
(
QA_DEBUG_PERFORMANCE
)
{
if
(
$result
===
false
&&
$db
->
errno
==
1213
)
global
$qa_usage
;
usleep
(
10000
);
// deal with InnoDB deadlock errors by waiting 0.01s then retrying
else
// time the query
break
;
$oldtime
=
array_sum
(
explode
(
' '
,
microtime
()));
$result
=
qa_db_query_execute
(
$query
);
$usedtime
=
array_sum
(
explode
(
' '
,
microtime
()))
-
$oldtime
;
// fetch counts
$gotrows
=
$gotcolumns
=
null
;
if
(
$result
instanceof
mysqli_result
)
{
$gotrows
=
$result
->
num_rows
;
$gotcolumns
=
$result
->
field_count
;
}
}
return
$result
;
$qa_usage
->
logDatabaseQuery
(
$query
,
$usedtime
,
$gotrows
,
$gotcolumns
)
;
}
}
else
$result
=
qa_db_query_execute
(
$query
);
/**
// @error_log('Question2Answer MySQL query: '.$query);
* Return $string escaped for use in queries to the Q2A database (to which a connection must have been made).
*/
function
qa_db_escape_string
(
$string
)
{
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
if
(
$result
===
false
)
{
$db
=
qa_db_connection
();
$db
=
qa_db_connection
();
return
$db
->
real_escape_string
(
$string
);
qa_db_fail_error
(
'query'
,
$db
->
errno
,
$db
->
error
,
$query
);
}
}
return
$result
;
}
/**
* Return $argument escaped for MySQL. Add quotes around it if $alwaysquote is true or it's not numeric.
* If $argument is an array, return a comma-separated list of escaped elements, with or without $arraybrackets.
*/
function
qa_db_argument_to_mysql
(
$argument
,
$alwaysquote
,
$arraybrackets
=
false
)
{
if
(
is_array
(
$argument
))
{
$parts
=
array
();
foreach
(
$argument
as
$subargument
)
/**
$parts
[]
=
qa_db_argument_to_mysql
(
$subargument
,
$alwaysquote
,
true
);
* Lower-level function to execute a query, which automatically retries if there is a MySQL deadlock error.
* @param $query
* @return mixed
*/
function
qa_db_query_execute
(
$query
)
{
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
if
(
$arraybrackets
)
$db
=
qa_db_connection
();
$result
=
'('
.
implode
(
','
,
$parts
)
.
')'
;
else
$result
=
implode
(
','
,
$parts
);
}
for
(
$attempt
=
0
;
$attempt
<
100
;
$attempt
++
)
{
elseif
(
isset
(
$argument
))
{
$result
=
$db
->
query
(
$query
);
if
(
$alwaysquote
||
!
is_numeric
(
$argument
))
$result
=
"'"
.
qa_db_escape_string
(
$argument
)
.
"'"
;
else
$result
=
qa_db_escape_string
(
$argument
);
}
else
$result
=
'NULL'
;
return
$result
;
if
(
$result
===
false
&&
$db
->
errno
==
1213
)
usleep
(
10000
);
// deal with InnoDB deadlock errors by waiting 0.01s then retrying
else
break
;
}
}
return
$result
;
}
/**
* Return $string escaped for use in queries to the Q2A database (to which a connection must have been made).
* @param $string
* @return mixed
*/
function
qa_db_escape_string
(
$string
)
{
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
$db
=
qa_db_connection
();
return
$db
->
real_escape_string
(
$string
);
}
/**
* Return $argument escaped for MySQL. Add quotes around it if $alwaysquote is true or it's not numeric.
* If $argument is an array, return a comma-separated list of escaped elements, with or without $arraybrackets.
* @param $argument
* @param $alwaysquote
* @param bool $arraybrackets
* @return mixed|string
*/
function
qa_db_argument_to_mysql
(
$argument
,
$alwaysquote
,
$arraybrackets
=
false
)
{
if
(
is_array
(
$argument
))
{
$parts
=
array
();
foreach
(
$argument
as
$subargument
)
$parts
[]
=
qa_db_argument_to_mysql
(
$subargument
,
$alwaysquote
,
true
);
if
(
$arraybrackets
)
$result
=
'('
.
implode
(
','
,
$parts
)
.
')'
;
else
$result
=
implode
(
','
,
$parts
);
/**
}
elseif
(
isset
(
$argument
))
{
* Return the full name (with prefix) of database table $rawname, usually if it used after a ^ symbol.
if
(
$alwaysquote
||
!
is_numeric
(
$argument
))
*/
$result
=
"'"
.
qa_db_escape_string
(
$argument
)
.
"'"
;
function
qa_db_add_table_prefix
(
$rawname
)
else
{
$result
=
qa_db_escape_string
(
$argument
);
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
}
else
$result
=
'NULL'
;
$prefix
=
QA_MYSQL_TABLE_PREFIX
;
return
$result
;
if
(
defined
(
'QA_MYSQL_USERS_PREFIX'
))
{
}
switch
(
strtolower
(
$rawname
))
{
case
'users'
:
case
'userlogins'
:
/**
case
'userprofile'
:
* Return the full name (with prefix) of database table $rawname, usually if it used after a ^ symbol.
case
'userfields'
:
* @param $rawname
case
'messages'
:
* @return string
case
'cookies'
:
*/
case
'blobs'
:
function
qa_db_add_table_prefix
(
$rawname
)
case
'cache'
:
{
case
'userlogins_ibfk_1'
:
// also special cases for constraint names
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
case
'userprofile_ibfk_1'
:
$prefix
=
QA_MYSQL_USERS_PREFIX
;
$prefix
=
QA_MYSQL_TABLE_PREFIX
;
break
;
}
if
(
defined
(
'QA_MYSQL_USERS_PREFIX'
))
{
switch
(
strtolower
(
$rawname
))
{
case
'users'
:
case
'userlogins'
:
case
'userprofile'
:
case
'userfields'
:
case
'messages'
:
case
'cookies'
:
case
'blobs'
:
case
'cache'
:
case
'userlogins_ibfk_1'
:
// also special cases for constraint names
case
'userprofile_ibfk_1'
:
$prefix
=
QA_MYSQL_USERS_PREFIX
;
break
;
}
}
return
$prefix
.
$rawname
;
}
}
return
$prefix
.
$rawname
;
/**
}
* Callback function to add table prefixes, as used in qa_db_apply_sub().
*/
function
qa_db_prefix_callback
(
$matches
)
/**
{
* Callback function to add table prefixes, as used in qa_db_apply_sub().
return
qa_db_add_table_prefix
(
$matches
[
1
]);
* @param $matches
}
* @return string
*/
function
qa_db_prefix_callback
(
$matches
)
/**
{
* Substitute ^, $ and # symbols in $query. ^ symbols are replaced with the table prefix set in qa-config.php.
return
qa_db_add_table_prefix
(
$matches
[
1
]);
* $ and # symbols are replaced in order by the corresponding element in $arguments (if the element is an array,
}
* it is converted recursively into comma-separated list). Each element in $arguments is escaped.
* $ is replaced by the argument in quotes (even if it's a number), # only adds quotes if the argument is non-numeric.
* It's important to use $ when matching a textual column since MySQL won't use indexes to compare text against numbers.
/**
*/
* Substitute ^, $ and # symbols in $query. ^ symbols are replaced with the table prefix set in qa-config.php.
function
qa_db_apply_sub
(
$query
,
$arguments
)
* $ and # symbols are replaced in order by the corresponding element in $arguments (if the element is an array,
{
* it is converted recursively into comma-separated list). Each element in $arguments is escaped.
$query
=
preg_replace_callback
(
'/\^([A-Za-z_0-9]+)/'
,
'qa_db_prefix_callback'
,
$query
);
* $ is replaced by the argument in quotes (even if it's a number), # only adds quotes if the argument is non-numeric.
* It's important to use $ when matching a textual column since MySQL won't use indexes to compare text against numbers.
if
(
!
is_array
(
$arguments
))
* @param $query
return
$query
;
* @param $arguments
* @return mixed
$countargs
=
count
(
$arguments
);
*/
$offset
=
0
;
function
qa_db_apply_sub
(
$query
,
$arguments
)
{
for
(
$argument
=
0
;
$argument
<
$countargs
;
$argument
++
)
{
$query
=
preg_replace_callback
(
'/\^([A-Za-z_0-9]+)/'
,
'qa_db_prefix_callback'
,
$query
);
$stringpos
=
strpos
(
$query
,
'$'
,
$offset
);
$numberpos
=
strpos
(
$query
,
'#'
,
$offset
);
if
(
!
is_array
(
$arguments
))
if
(
$stringpos
===
false
||
(
$numberpos
!==
false
&&
$numberpos
<
$stringpos
))
{
$alwaysquote
=
false
;
$position
=
$numberpos
;
}
else
{
$alwaysquote
=
true
;
$position
=
$stringpos
;
}
if
(
!
is_numeric
(
$position
))
qa_fatal_error
(
'Insufficient parameters in query: '
.
$query
);
$value
=
qa_db_argument_to_mysql
(
$arguments
[
$argument
],
$alwaysquote
);
$query
=
substr_replace
(
$query
,
$value
,
$position
,
1
);
$offset
=
$position
+
strlen
(
$value
);
// allows inserting strings which contain #/$ character
}
return
$query
;
return
$query
;
}
/**
* Run $query after substituting ^, # and $ symbols, and return the result resource (or call fail handler).
*/
function
qa_db_query_sub
(
$query
)
// arguments for substitution retrieved using func_get_args()
{
$funcargs
=
func_get_args
();
return
qa_db_query_raw
(
qa_db_apply_sub
(
$query
,
array_slice
(
$funcargs
,
1
)));
}
/**
* Return the number of rows in $result. (Simple wrapper for mysqli_result::num_rows.)
*/
function
qa_db_num_rows
(
$result
)
{
if
(
$result
instanceof
mysqli_result
)
return
$result
->
num_rows
;
return
0
;
$countargs
=
count
(
$arguments
);
}
$offset
=
0
;
/**
* Return the value of the auto-increment column for the last inserted row.
*/
function
qa_db_last_insert_id
()
{
$db
=
qa_db_connection
();
return
$db
->
insert_id
;
}
/**
* Return the number of rows affected by the last query.
*/
function
qa_db_affected_rows
()
{
$db
=
qa_db_connection
();
return
$db
->
affected_rows
;
}
for
(
$argument
=
0
;
$argument
<
$countargs
;
$argument
++
)
{
$stringpos
=
strpos
(
$query
,
'$'
,
$offset
);
$numberpos
=
strpos
(
$query
,
'#'
,
$offset
);
/**
if
(
$stringpos
===
false
||
(
$numberpos
!==
false
&&
$numberpos
<
$stringpos
))
{
* For the previous INSERT ... ON DUPLICATE KEY UPDATE query, return whether an insert operation took place.
$alwaysquote
=
false
;
*/
$position
=
$numberpos
;
function
qa_db_insert_on_duplicate_inserted
()
}
else
{
{
$alwaysquote
=
true
;
return
(
qa_db_affected_rows
()
==
1
)
;
$position
=
$stringpos
;
}
}
if
(
!
is_numeric
(
$position
))
qa_fatal_error
(
'Insufficient parameters in query: '
.
$query
);
/**
$value
=
qa_db_argument_to_mysql
(
$arguments
[
$argument
],
$alwaysquote
);
* Return a random integer (as a string) for use in a BIGINT column.
$query
=
substr_replace
(
$query
,
$value
,
$position
,
1
);
* Actual limit is 18,446,744,073,709,551,615 - we aim for 18,446,743,999,999,999,999.
$offset
=
$position
+
strlen
(
$value
);
// allows inserting strings which contain #/$ character
*/
function
qa_db_random_bigint
()
{
return
sprintf
(
'%d%06d%06d'
,
mt_rand
(
1
,
18446743
),
mt_rand
(
0
,
999999
),
mt_rand
(
0
,
999999
));
}
}
return
$query
;
/**
}
* Return an array of the names of all tables in the Q2A database, converted to lower case.
* No longer used by Q2A and shouldn't be needed.
*/
/**
function
qa_db_list_tables_lc
()
* Run $query after substituting ^, # and $ symbols, and return the result resource (or call fail handler).
{
* @param $query
return
array_map
(
'strtolower'
,
qa_db_list_tables
());
* @return mixed
}
*/
function
qa_db_query_sub
(
$query
)
// arguments for substitution retrieved using func_get_args()
{
/**
$funcargs
=
func_get_args
();
* Return an array of the names of all tables in the Q2A database.
*/
return
qa_db_query_raw
(
qa_db_apply_sub
(
$query
,
array_slice
(
$funcargs
,
1
)));
function
qa_db_list_tables
()
}
{
return
qa_db_read_all_values
(
qa_db_query_raw
(
'SHOW TABLES'
));
}
/**
* Return the number of rows in $result. (Simple wrapper for mysqli_result::num_rows.)
* @param $result
* @return int
*/
function
qa_db_num_rows
(
$result
)
{
if
(
$result
instanceof
mysqli_result
)
return
$result
->
num_rows
;
return
0
;
}
/**
* Return the value of the auto-increment column for the last inserted row.
*/
function
qa_db_last_insert_id
()
{
$db
=
qa_db_connection
();
return
$db
->
insert_id
;
}
/**
* Return the number of rows affected by the last query.
*/
function
qa_db_affected_rows
()
{
$db
=
qa_db_connection
();
return
$db
->
affected_rows
;
}
/**
* For the previous INSERT ... ON DUPLICATE KEY UPDATE query, return whether an insert operation took place.
*/
function
qa_db_insert_on_duplicate_inserted
()
{
return
(
qa_db_affected_rows
()
==
1
);
}
/**
* Return a random integer (as a string) for use in a BIGINT column.
* Actual limit is 18,446,744,073,709,551,615 - we aim for 18,446,743,999,999,999,999.
*/
function
qa_db_random_bigint
()
{
return
sprintf
(
'%d%06d%06d'
,
mt_rand
(
1
,
18446743
),
mt_rand
(
0
,
999999
),
mt_rand
(
0
,
999999
));
}
/**
* Return an array of the names of all tables in the Q2A database, converted to lower case.
* No longer used by Q2A and shouldn't be needed.
*/
function
qa_db_list_tables_lc
()
{
return
array_map
(
'strtolower'
,
qa_db_list_tables
());
}
/**
* Return an array of the names of all tables in the Q2A database.
*/
function
qa_db_list_tables
()
{
return
qa_db_read_all_values
(
qa_db_query_raw
(
'SHOW TABLES'
));
}
/*
/*
...
@@ -476,300 +502,319 @@
...
@@ -476,300 +502,319 @@
*/
*/
/**
/**
* Return the data specified by a single $selectspec - see long comment above.
* Return the data specified by a single $selectspec - see long comment above.
*/
* @param $selectspec
function
qa_db_single_select
(
$selectspec
)
* @return array|mixed
{
*/
// check for cached results
function
qa_db_single_select
(
$selectspec
)
if
(
isset
(
$selectspec
[
'caching'
]))
{
{
$cacheHandler
=
Q2A_Storage_CacheManager
::
getInstance
();
// check for cached results
$cacheKey
=
'query:'
.
$selectspec
[
'caching'
][
'key'
];
if
(
isset
(
$selectspec
[
'caching'
]))
{
$cacheHandler
=
Q2A_Storage_CacheManager
::
getInstance
();
if
(
$cacheHandler
->
isEnabled
())
{
$cacheKey
=
'query:'
.
$selectspec
[
'caching'
][
'key'
];
$queryData
=
$cacheHandler
->
get
(
$cacheKey
);
if
(
$queryData
!==
null
)
if
(
$cacheHandler
->
isEnabled
())
{
return
$queryData
;
$queryData
=
$cacheHandler
->
get
(
$cacheKey
);
}
if
(
$queryData
!==
null
)
return
$queryData
;
}
}
}
$query
=
'SELECT '
;
$query
=
'SELECT '
;
foreach
(
$selectspec
[
'columns'
]
as
$columnas
=>
$columnfrom
)
foreach
(
$selectspec
[
'columns'
]
as
$columnas
=>
$columnfrom
)
$query
.=
$columnfrom
.
(
is_int
(
$columnas
)
?
''
:
(
' AS '
.
$columnas
))
.
', '
;
$query
.=
$columnfrom
.
(
is_int
(
$columnas
)
?
''
:
(
' AS '
.
$columnas
))
.
', '
;
$results
=
qa_db_read_all_assoc
(
qa_db_query_raw
(
qa_db_apply_sub
(
$results
=
qa_db_read_all_assoc
(
qa_db_query_raw
(
qa_db_apply_sub
(
substr
(
$query
,
0
,
-
2
)
.
(
strlen
(
@
$selectspec
[
'source'
])
?
(
' FROM '
.
$selectspec
[
'source'
])
:
''
),
substr
(
$query
,
0
,
-
2
)
.
(
strlen
(
@
$selectspec
[
'source'
])
?
(
' FROM '
.
$selectspec
[
'source'
])
:
''
),
@
$selectspec
[
'arguments'
])
@
$selectspec
[
'arguments'
])
),
@
$selectspec
[
'arraykey'
]);
// arrayvalue is applied in qa_db_post_select()
),
@
$selectspec
[
'arraykey'
]);
// arrayvalue is applied in qa_db_post_select()
qa_db_post_select
(
$results
,
$selectspec
);
// post-processing
qa_db_post_select
(
$results
,
$selectspec
);
// post-processing
// save cached results
// save cached results
if
(
isset
(
$selectspec
[
'caching'
]))
{
if
(
isset
(
$selectspec
[
'caching'
]))
{
if
(
$cacheHandler
->
isEnabled
())
{
if
(
$cacheHandler
->
isEnabled
())
{
$cacheHandler
->
set
(
$cacheKey
,
$results
,
$selectspec
[
'caching'
][
'ttl'
]);
$cacheHandler
->
set
(
$cacheKey
,
$results
,
$selectspec
[
'caching'
][
'ttl'
]);
}
}
}
return
$results
;
}
}
return
$results
;
}
/**
* Return the data specified by each element of $selectspecs, where the keys of the
* returned array match the keys of the supplied $selectspecs array. See long comment above.
*/
function
qa_db_multi_select
(
$selectspecs
)
{
if
(
!
count
(
$selectspecs
))
return
array
();
// Perform simple queries if the database is local or there are only 0 or 1 selectspecs
/**
* Return the data specified by each element of $selectspecs, where the keys of the
* returned array match the keys of the supplied $selectspecs array. See long comment above.
* @param array $selectspecs
* @return array
*/
function
qa_db_multi_select
(
$selectspecs
)
{
if
(
!
count
(
$selectspecs
))
return
array
();
if
(
!
QA_OPTIMIZE_DISTANT_DB
||
(
count
(
$selectspecs
)
<=
1
))
{
// Perform simple queries if the database is local or there are only 0 or 1 selectspecs
$outresults
=
array
();
foreach
(
$selectspecs
as
$selectkey
=>
$selectspec
)
if
(
!
QA_OPTIMIZE_DISTANT_DB
||
(
count
(
$selectspecs
)
<=
1
))
{
$outresults
[
$selectkey
]
=
qa_db_single_select
(
$selectspec
);
$outresults
=
array
(
);
return
$outresults
;
foreach
(
$selectspecs
as
$selectkey
=>
$selectspec
)
}
$outresults
[
$selectkey
]
=
qa_db_single_select
(
$selectspec
);
// Otherwise, parse columns for each spec to deal with columns without an 'AS' specification
foreach
(
$selectspecs
as
$selectkey
=>
$selectspec
)
{
return
$outresults
;
$selectspecs
[
$selectkey
][
'outcolumns'
]
=
array
();
}
$selectspecs
[
$selectkey
][
'autocolumn'
]
=
array
();
foreach
(
$selectspec
[
'columns'
]
as
$columnas
=>
$columnfrom
)
{
// Otherwise, parse columns for each spec to deal with columns without an 'AS' specification
if
(
is_int
(
$columnas
))
{
$periodpos
=
strpos
(
$columnfrom
,
'.'
);
$columnas
=
is_numeric
(
$periodpos
)
?
substr
(
$columnfrom
,
$periodpos
+
1
)
:
$columnfrom
;
$selectspecs
[
$selectkey
][
'autocolumn'
][
$columnas
]
=
true
;
}
if
(
isset
(
$selectspecs
[
$selectkey
][
'outcolumns'
][
$columnas
]))
foreach
(
$selectspecs
as
$selectkey
=>
$selectspec
)
{
qa_fatal_error
(
'Duplicate column name in qa_db_multi_select()'
);
$selectspecs
[
$selectkey
][
'outcolumns'
]
=
array
();
$selectspecs
[
$selectkey
][
'autocolumn'
]
=
array
();
$selectspecs
[
$selectkey
][
'outcolumns'
][
$columnas
]
=
$columnfrom
;
foreach
(
$selectspec
[
'columns'
]
as
$columnas
=>
$columnfrom
)
{
if
(
is_int
(
$columnas
))
{
$periodpos
=
strpos
(
$columnfrom
,
'.'
);
$columnas
=
is_numeric
(
$periodpos
)
?
substr
(
$columnfrom
,
$periodpos
+
1
)
:
$columnfrom
;
$selectspecs
[
$selectkey
][
'autocolumn'
][
$columnas
]
=
true
;
}
}
if
(
isset
(
$selectspec
[
'arraykey'
]))
if
(
isset
(
$selectspecs
[
$selectkey
][
'outcolumns'
][
$columnas
]))
if
(
!
isset
(
$selectspecs
[
$selectkey
][
'outcolumns'
][
$selectspec
[
'arraykey'
]]))
qa_fatal_error
(
'Duplicate column name in qa_db_multi_select()'
);
qa_fatal_error
(
'Used arraykey not in columns in qa_db_multi_select()'
);
if
(
isset
(
$selectspec
[
'arrayvalue'
]))
$selectspecs
[
$selectkey
][
'outcolumns'
][
$columnas
]
=
$columnfrom
;
if
(
!
isset
(
$selectspecs
[
$selectkey
][
'outcolumns'
][
$selectspec
[
'arrayvalue'
]]))
qa_fatal_error
(
'Used arrayvalue not in columns in qa_db_multi_select()'
);
}
}
// Work out the full list of columns used
if
(
isset
(
$selectspec
[
'arraykey'
]))
if
(
!
isset
(
$selectspecs
[
$selectkey
][
'outcolumns'
][
$selectspec
[
'arraykey'
]]))
$outcolumns
=
array
();
qa_fatal_error
(
'Used arraykey not in columns in qa_db_multi_select()'
);
foreach
(
$selectspecs
as
$selectspec
)
$outcolumns
=
array_unique
(
array_merge
(
$outcolumns
,
array_keys
(
$selectspec
[
'outcolumns'
])));
// Build the query based on this full list
$query
=
''
;
if
(
isset
(
$selectspec
[
'arrayvalue'
]))
foreach
(
$selectspecs
as
$selectkey
=>
$selectspec
)
{
if
(
!
isset
(
$selectspecs
[
$selectkey
][
'outcolumns'
][
$selectspec
[
'arrayvalue'
]]))
$subquery
=
"(SELECT '"
.
qa_db_escape_string
(
$selectkey
)
.
"'"
.
(
empty
(
$query
)
?
' AS selectkey'
:
''
);
qa_fatal_error
(
'Used arrayvalue not in columns in qa_db_multi_select()'
);
}
foreach
(
$outcolumns
as
$columnas
)
{
$subquery
.=
', '
.
(
isset
(
$selectspec
[
'outcolumns'
][
$columnas
])
?
$selectspec
[
'outcolumns'
][
$columnas
]
:
'NULL'
);
if
(
empty
(
$query
)
&&
!
isset
(
$selectspec
[
'autocolumn'
][
$columnas
]))
$subquery
.=
' AS '
.
$columnas
;
}
if
(
strlen
(
@
$selectspec
[
'source'
]))
$subquery
.=
' FROM '
.
$selectspec
[
'source'
];
$subquery
.=
')'
;
if
(
strlen
(
$query
))
$query
.=
' UNION ALL '
;
$query
.=
qa_db_apply_sub
(
$subquery
,
@
$selectspec
[
'arguments'
]);
}
//
Perform query and extract results
//
Work out the full list of columns used
$rawresults
=
qa_db_read_all_assoc
(
qa_db_query_raw
(
$query
));
$outcolumns
=
array
();
foreach
(
$selectspecs
as
$selectspec
)
$outcolumns
=
array_unique
(
array_merge
(
$outcolumns
,
array_keys
(
$selectspec
[
'outcolumns'
])));
$outresults
=
array
();
// Build the query based on this full list
foreach
(
$selectspecs
as
$selectkey
=>
$selectspec
)
$outresults
[
$selectkey
]
=
array
();
foreach
(
$rawresults
as
$rawresult
)
{
$query
=
''
;
$selectkey
=
$rawresult
[
'selectkey'
];
foreach
(
$selectspecs
as
$selectkey
=>
$selectspec
)
{
$selectspec
=
$selectspecs
[
$selectkey
]
;
$subquery
=
"(SELECT '"
.
qa_db_escape_string
(
$selectkey
)
.
"'"
.
(
empty
(
$query
)
?
' AS selectkey'
:
''
)
;
$keepresult
=
array
();
foreach
(
$outcolumns
as
$columnas
)
{
foreach
(
$selectspec
[
'outcolumns'
]
as
$columnas
=>
$columnfrom
)
$subquery
.=
', '
.
(
isset
(
$selectspec
[
'outcolumns'
][
$columnas
])
?
$selectspec
[
'outcolumns'
][
$columnas
]
:
'NULL'
);
$keepresult
[
$columnas
]
=
$rawresult
[
$columnas
];
if
(
isset
(
$selectspec
[
'arraykey'
]))
if
(
empty
(
$query
)
&&
!
isset
(
$selectspec
[
'autocolumn'
][
$columnas
]))
$outresults
[
$selectkey
][
$keepresult
[
$selectspec
[
'arraykey'
]]]
=
$keepresult
;
$subquery
.=
' AS '
.
$columnas
;
else
$outresults
[
$selectkey
][]
=
$keepresult
;
}
}
// Post-processing to apply various stuff include sorting request, since we can't rely on ORDER BY due to UNION
if
(
strlen
(
@
$selectspec
[
'source'
]))
$subquery
.=
' FROM '
.
$selectspec
[
'source'
];
foreach
(
$selectspecs
as
$selectkey
=>
$selectspec
)
$subquery
.=
')'
;
qa_db_post_select
(
$outresults
[
$selectkey
],
$selectspec
);
// Return results
if
(
strlen
(
$query
))
$query
.=
' UNION ALL '
;
return
$outresults
;
$query
.=
qa_db_apply_sub
(
$subquery
,
@
$selectspec
[
'arguments'
])
;
}
}
// Perform query and extract results
/**
$rawresults
=
qa_db_read_all_assoc
(
qa_db_query_raw
(
$query
));
* Post-process $outresult according to $selectspec, applying 'sortasc', 'sortdesc', 'arrayvalue' and 'single'.
*/
function
qa_db_post_select
(
&
$outresult
,
$selectspec
)
{
// PHP's sorting algorithm is not 'stable', so we use '_order_' element to keep stability.
// By contrast, MySQL's ORDER BY does seem to give the results in a reliable order.
if
(
isset
(
$selectspec
[
'sortasc'
]))
{
require_once
QA_INCLUDE_DIR
.
'util/sort.php'
;
$index
=
0
;
foreach
(
$outresult
as
$key
=>
$value
)
$outresult
[
$key
][
'_order_'
]
=
$index
++
;
qa_sort_by
(
$outresult
,
$selectspec
[
'sortasc'
],
'_order_'
);
}
elseif
(
isset
(
$selectspec
[
'sortdesc'
]))
{
require_once
QA_INCLUDE_DIR
.
'util/sort.php'
;
if
(
isset
(
$selectspec
[
'sortdesc_2'
]))
$outresults
=
array
();
qa_sort_by
(
$outresult
,
$selectspec
[
'sortdesc'
],
$selectspec
[
'sortdesc_2'
]);
foreach
(
$selectspecs
as
$selectkey
=>
$selectspec
)
$outresults
[
$selectkey
]
=
array
();
else
{
foreach
(
$rawresults
as
$rawresult
)
{
$index
=
count
(
$outresult
);
$selectkey
=
$rawresult
[
'selectkey'
];
foreach
(
$outresult
as
$key
=>
$value
)
$selectspec
=
$selectspecs
[
$selectkey
];
$outresult
[
$key
][
'_order_'
]
=
$index
--
;
qa_sort_by
(
$outresult
,
$selectspec
[
'sortdesc'
],
'_order_'
);
$keepresult
=
array
();
}
foreach
(
$selectspec
[
'outcolumns'
]
as
$columnas
=>
$columnfrom
)
$keepresult
[
$columnas
]
=
$rawresult
[
$columnas
];
$outresult
=
array_reverse
(
$outresult
,
true
);
}
if
(
isset
(
$selectspec
[
'arrayvalue'
]))
if
(
isset
(
$selectspec
[
'arraykey'
]))
foreach
(
$outresult
as
$key
=>
$value
)
$outresults
[
$selectkey
][
$keepresult
[
$selectspec
[
'arraykey'
]]]
=
$keepresult
;
$outresult
[
$key
]
=
$value
[
$selectspec
[
'arrayvalue'
]];
else
$outresults
[
$selectkey
][]
=
$keepresult
;
if
(
@
$selectspec
[
'single'
])
$outresult
=
count
(
$outresult
)
?
reset
(
$outresult
)
:
null
;
}
}
// Post-processing to apply various stuff include sorting request, since we can't rely on ORDER BY due to UNION
/**
foreach
(
$selectspecs
as
$selectkey
=>
$selectspec
)
* Return the full results from the $result resource as an array. The key of each element in the returned array
qa_db_post_select
(
$outresults
[
$selectkey
],
$selectspec
);
* is from column $key if specified, otherwise it's integer. The value of each element in the returned array
* is from column $value if specified, otherwise it's a named array of all columns, given an array of arrays.
*/
function
qa_db_read_all_assoc
(
$result
,
$key
=
null
,
$value
=
null
)
{
if
(
!
(
$result
instanceof
mysqli_result
))
qa_fatal_error
(
'Reading all assoc from invalid result'
);
$assocs
=
array
();
// Return results
while
(
$assoc
=
$result
->
fetch_assoc
())
{
return
$outresults
;
if
(
isset
(
$key
))
}
$assocs
[
$assoc
[
$key
]]
=
isset
(
$value
)
?
$assoc
[
$value
]
:
$assoc
;
else
$assocs
[]
=
isset
(
$value
)
?
$assoc
[
$value
]
:
$assoc
;
}
return
$assocs
;
}
/**
* Post-process $outresult according to $selectspec, applying 'sortasc', 'sortdesc', 'arrayvalue' and 'single'.
* @param array $outresult
* @param array $selectspec
*/
function
qa_db_post_select
(
&
$outresult
,
$selectspec
)
{
// PHP's sorting algorithm is not 'stable', so we use '_order_' element to keep stability.
// By contrast, MySQL's ORDER BY does seem to give the results in a reliable order.
/**
if
(
isset
(
$selectspec
[
'sortasc'
]))
{
* Return the first row from the $result resource as an array of [column name] => [column value].
require_once
QA_INCLUDE_DIR
.
'util/sort.php'
;
* If there's no first row, throw a fatal error unless $allowempty is true.
*/
function
qa_db_read_one_assoc
(
$result
,
$allowempty
=
false
)
{
if
(
!
(
$result
instanceof
mysqli_result
))
qa_fatal_error
(
'Reading one assoc from invalid result'
);
$assoc
=
$result
->
fetch_assoc
();
$index
=
0
;
foreach
(
$outresult
as
$key
=>
$value
)
$outresult
[
$key
][
'_order_'
]
=
$index
++
;
if
(
is_array
(
$assoc
))
qa_sort_by
(
$outresult
,
$selectspec
[
'sortasc'
],
'_order_'
);
return
$assoc
;
if
(
$allowempty
)
return
null
;
else
qa_fatal_error
(
'Reading one assoc from empty results'
);
}
}
elseif
(
isset
(
$selectspec
[
'sortdesc'
]))
{
require_once
QA_INCLUDE_DIR
.
'util/sort.php'
;
/**
if
(
isset
(
$selectspec
[
'sortdesc_2'
]))
* Return a numbered array containing the first (and presumably only) column from the $result resource.
qa_sort_by
(
$outresult
,
$selectspec
[
'sortdesc'
],
$selectspec
[
'sortdesc_2'
]);
*/
function
qa_db_read_all_values
(
$result
)
{
if
(
!
(
$result
instanceof
mysqli_result
))
qa_fatal_error
(
'Reading column from invalid result'
);
$output
=
array
();
else
{
$index
=
count
(
$outresult
);
foreach
(
$outresult
as
$key
=>
$value
)
$outresult
[
$key
][
'_order_'
]
=
$index
--
;
while
(
$row
=
$result
->
fetch_row
())
qa_sort_by
(
$outresult
,
$selectspec
[
'sortdesc'
],
'_order_'
);
$output
[]
=
$row
[
0
];
}
return
$output
;
$outresult
=
array_reverse
(
$outresult
,
true
)
;
}
}
if
(
isset
(
$selectspec
[
'arrayvalue'
]))
/**
foreach
(
$outresult
as
$key
=>
$value
)
* Return the first column of the first row (and presumably only cell) from the $result resource.
$outresult
[
$key
]
=
$value
[
$selectspec
[
'arrayvalue'
]];
* If there's no first row, throw a fatal error unless $allowempty is true.
*/
if
(
@
$selectspec
[
'single'
])
function
qa_db_read_one_value
(
$result
,
$allowempty
=
false
)
$outresult
=
count
(
$outresult
)
?
reset
(
$outresult
)
:
null
;
{
}
if
(
!
(
$result
instanceof
mysqli_result
))
qa_fatal_error
(
'Reading one value from invalid result'
);
/**
$row
=
$result
->
fetch_row
();
* Return the full results from the $result resource as an array. The key of each element in the returned array
* is from column $key if specified, otherwise it's integer. The value of each element in the returned array
if
(
is_array
(
$row
))
* is from column $value if specified, otherwise it's a named array of all columns, given an array of arrays.
return
$row
[
0
];
* @param $result
* @param string $key
if
(
$allowempty
)
* @param mixed $value
return
null
;
* @return array
*/
function
qa_db_read_all_assoc
(
$result
,
$key
=
null
,
$value
=
null
)
{
if
(
!
(
$result
instanceof
mysqli_result
))
qa_fatal_error
(
'Reading all assoc from invalid result'
);
$assocs
=
array
();
while
(
$assoc
=
$result
->
fetch_assoc
())
{
if
(
isset
(
$key
))
$assocs
[
$assoc
[
$key
]]
=
isset
(
$value
)
?
$assoc
[
$value
]
:
$assoc
;
else
else
qa_fatal_error
(
'Reading one value from empty results'
);
$assocs
[]
=
isset
(
$value
)
?
$assoc
[
$value
]
:
$assoc
;
}
/**
* Suspend the updating of counts (of many different types) in the database, to save time when making a lot of changes
* if $suspend is true, otherwise reinstate it. A counter is kept to allow multiple calls.
*/
function
qa_suspend_update_counts
(
$suspend
=
true
)
{
global
$qa_update_counts_suspended
;
$qa_update_counts_suspended
+=
(
$suspend
?
1
:
-
1
);
}
}
return
$assocs
;
/**
}
* Returns whether counts should currently be updated (i.e. if count updating has not been suspended).
*/
function
qa_should_update_counts
()
/**
{
* Return the first row from the $result resource as an array of [column name] => [column value].
global
$qa_update_counts_suspended
;
* If there's no first row, throw a fatal error unless $allowempty is true.
* @param $result
return
(
$qa_update_counts_suspended
<=
0
);
* @param bool $allowempty
}
* @return array|null
*/
function
qa_db_read_one_assoc
(
$result
,
$allowempty
=
false
)
{
if
(
!
(
$result
instanceof
mysqli_result
))
qa_fatal_error
(
'Reading one assoc from invalid result'
);
$assoc
=
$result
->
fetch_assoc
();
if
(
is_array
(
$assoc
))
return
$assoc
;
if
(
$allowempty
)
return
null
;
else
qa_fatal_error
(
'Reading one assoc from empty results'
);
}
/**
* Return a numbered array containing the first (and presumably only) column from the $result resource.
* @param $result
* @return array
*/
function
qa_db_read_all_values
(
$result
)
{
if
(
!
(
$result
instanceof
mysqli_result
))
qa_fatal_error
(
'Reading column from invalid result'
);
$output
=
array
();
while
(
$row
=
$result
->
fetch_row
())
$output
[]
=
$row
[
0
];
return
$output
;
}
/**
* Return the first column of the first row (and presumably only cell) from the $result resource.
* If there's no first row, throw a fatal error unless $allowempty is true.
* @param $result
* @param bool $allowempty
* @return mixed|null
*/
function
qa_db_read_one_value
(
$result
,
$allowempty
=
false
)
{
if
(
!
(
$result
instanceof
mysqli_result
))
qa_fatal_error
(
'Reading one value from invalid result'
);
$row
=
$result
->
fetch_row
();
if
(
is_array
(
$row
))
return
$row
[
0
];
if
(
$allowempty
)
return
null
;
else
qa_fatal_error
(
'Reading one value from empty results'
);
}
/**
* Suspend the updating of counts (of many different types) in the database, to save time when making a lot of changes
* if $suspend is true, otherwise reinstate it. A counter is kept to allow multiple calls.
* @param bool $suspend
*/
function
qa_suspend_update_counts
(
$suspend
=
true
)
{
global
$qa_update_counts_suspended
;
$qa_update_counts_suspended
+=
(
$suspend
?
1
:
-
1
);
}
/**
* Returns whether counts should currently be updated (i.e. if count updating has not been suspended).
*/
function
qa_should_update_counts
()
{
global
$qa_update_counts_suspended
;
return
(
$qa_update_counts_suspended
<=
0
);
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment