2007-07-02 05:51:26 +00:00
< ? php
2025-03-05 11:28:53 +01:00
namespace Adminer ;
2025-02-20 09:11:59 +01:00
// This file is used both in Adminer and Adminer Editor.
2025-03-28 09:13:36 +01:00
/** Get database connection */
2025-03-28 09:03:09 +01:00
function connection () : Db {
2009-09-22 10:51:40 +00:00
// can be used in customization, $connection is minified
global $connection ;
return $connection ;
2009-07-27 11:25:37 +00:00
}
2011-08-10 18:10:23 +02:00
/** Get Adminer object
* @ return Adminer
*/
function adminer () {
global $adminer ;
return $adminer ;
}
2025-03-17 08:07:24 +01:00
/** Get Driver object
* @ return Driver
*/
function driver () {
global $driver ;
return $driver ;
}
2009-08-31 10:11:52 +00:00
/** Unescape database identifier
2025-03-28 07:06:34 +01:00
* @ param string $idf text inside ``
2009-08-31 10:11:52 +00:00
*/
2025-03-28 09:03:09 +01:00
function idf_unescape ( string $idf ) : string {
2021-05-23 12:50:14 +02:00
if ( ! preg_match ( '~^[`\'"[]~' , $idf )) {
2021-05-14 06:21:09 +02:00
return $idf ;
}
2010-04-21 22:22:23 +00:00
$last = substr ( $idf , - 1 );
return str_replace ( $last . $last , $last , substr ( $idf , 1 , - 1 ));
2007-07-02 05:51:26 +00:00
}
2025-03-28 09:13:36 +01:00
/** Shortcut for $connection->quote($string) */
2025-03-28 09:03:09 +01:00
function q ( string $string ) : string {
2025-03-16 18:31:38 +01:00
global $connection ;
return $connection -> quote ( $string );
}
2025-03-28 09:13:36 +01:00
/** Escape string to use inside '' */
2025-03-28 09:03:09 +01:00
function escape_string ( string $val ) : string {
2010-10-13 18:04:40 +02:00
return substr ( q ( $val ), 1 , - 1 );
2009-10-16 12:26:16 +00:00
}
2025-03-26 04:16:17 +01:00
/** Get a possibly missing item from a possibly missing array
2025-03-26 12:41:52 +01:00
* idx ( $row , $key ) is better than $row [ $key ] ? ? null because PHP will report error for undefined $row
2025-03-28 07:06:34 +01:00
* @ param ? mixed [] $array
2025-03-28 13:15:14 +01:00
* @ param array - key $key
2025-03-28 07:06:34 +01:00
* @ param mixed $default
2025-03-26 04:16:17 +01:00
* @ return mixed
*/
2025-03-28 08:23:20 +01:00
function idx ( ? array $array , $key , $default = null ) {
2025-03-26 04:16:17 +01:00
return ( $array && array_key_exists ( $key , $array ) ? $array [ $key ] : $default );
}
2025-03-28 09:13:36 +01:00
/** Remove non-digits from a string */
2025-03-28 09:03:09 +01:00
function number ( string $val ) : string {
2018-01-22 13:51:47 +01:00
return preg_replace ( '~[^0-9]+~' , '' , $val );
2014-11-24 18:17:43 -08:00
}
2025-03-28 09:13:36 +01:00
/** Get regular expression to match numeric types */
2025-03-28 09:03:09 +01:00
function number_type () : string {
2018-02-06 14:52:12 +01:00
return '((?<!o)int(?!er)|numeric|real|float|double|decimal|money)' ; // not point, not interval
2018-02-06 12:17:01 +01:00
}
2010-07-26 14:47:26 +02:00
/** Disable magic_quotes_gpc
2025-03-28 07:06:34 +01:00
* @ param list < array > $process e . g . ( & $_GET , & $_POST , & $_COOKIE )
* @ param bool $filter whether to leave values as is
2025-03-26 13:09:49 +01:00
* @ return void modified in place
2010-07-26 14:47:26 +02:00
*/
2025-03-28 09:03:09 +01:00
function remove_slashes ( array $process , bool $filter = false ) : void {
2020-10-20 21:04:33 +02:00
if ( function_exists ( " get_magic_quotes_gpc " ) && get_magic_quotes_gpc ()) {
2010-07-26 14:47:26 +02:00
while ( list ( $key , $val ) = each ( $process )) {
foreach ( $val as $k => $v ) {
unset ( $process [ $key ][ $k ]);
if ( is_array ( $v )) {
$process [ $key ][ stripslashes ( $k )] = $v ;
$process [] = & $process [ $key ][ stripslashes ( $k )];
} else {
$process [ $key ][ stripslashes ( $k )] = ( $filter ? $v : stripslashes ( $v ));
}
}
}
}
}
2025-03-28 09:13:36 +01:00
/** Escape or unescape string to use inside form [] */
2025-03-28 09:03:09 +01:00
function bracket_escape ( string $idf , bool $back = false ) : string {
2009-06-21 23:20:32 +00:00
// escape brackets inside name="x[]"
2017-01-23 13:30:05 -08:00
static $trans = array ( ':' => ':1' , ']' => ':2' , '[' => ':3' , '"' => ':4' );
2007-07-02 05:51:26 +00:00
return strtr ( $idf , ( $back ? array_flip ( $trans ) : $trans ));
}
2018-01-29 19:34:26 +01:00
/** Check if connection has at least the given version
2025-03-28 07:06:34 +01:00
* @ param string | float $version required version
* @ param string | float $maria_db required MariaDB version
* @ param Db $connection2 defaults to $connection
2018-01-29 19:34:26 +01:00
*/
2025-03-28 09:03:09 +01:00
function min_version ( $version , $maria_db = " " , Db $connection2 = null ) : bool {
2018-01-29 19:34:26 +01:00
global $connection ;
2018-01-29 21:08:38 +01:00
if ( ! $connection2 ) {
$connection2 = $connection ;
}
$server_info = $connection2 -> server_info ;
2018-01-29 19:34:26 +01:00
if ( $maria_db && preg_match ( '~([\d.]+)-MariaDB~' , $server_info , $match )) {
$server_info = $match [ 1 ];
$version = $maria_db ;
}
2025-03-19 06:12:51 +01:00
return $version && version_compare ( $server_info , $version ) >= 0 ;
2018-01-29 19:34:26 +01:00
}
2025-03-28 09:13:36 +01:00
/** Get connection charset */
2025-03-28 09:03:09 +01:00
function charset ( Db $connection ) : string {
2018-01-30 23:53:04 +01:00
return ( min_version ( " 5.5.3 " , 0 , $connection ) ? " utf8mb4 " : " utf8 " ); // SHOW CHARSET would require an extra query
2014-06-26 13:22:35 +02:00
}
2025-03-28 09:13:36 +01:00
/** Get INI boolean value */
2025-03-28 09:03:09 +01:00
function ini_bool ( string $ini ) : bool {
2010-04-21 12:01:32 +00:00
$val = ini_get ( $ini );
2013-07-24 16:26:41 -07:00
return ( preg_match ( '~^(on|true|yes)$~i' , $val ) || ( int ) $val ); // boolean values set by php_value are strings
2010-04-21 12:01:32 +00:00
}
2025-03-28 09:13:36 +01:00
/** Check if SID is necessary */
2025-03-28 09:03:09 +01:00
function sid () : bool {
2010-12-29 18:15:42 +01:00
static $return ;
2012-05-13 23:54:07 -07:00
if ( $return === null ) { // restart_session() defines SID
2010-12-29 18:15:42 +01:00
$return = ( SID && ! ( $_COOKIE && ini_bool ( " session.use_cookies " ))); // $_COOKIE - don't pass SID with permanent login
}
return $return ;
2010-12-20 18:09:13 +01:00
}
2025-03-28 09:13:36 +01:00
/** Set password to session */
2025-03-28 13:15:14 +01:00
function set_password ( string $vendor , ? string $server , string $username , ? string $password ) : void {
2014-02-19 09:27:22 -08:00
$_SESSION [ " pwds " ][ $vendor ][ $server ][ $username ] = ( $_COOKIE [ " adminer_key " ] && is_string ( $password )
? array ( encrypt_string ( $password , $_COOKIE [ " adminer_key " ]))
: $password
);
}
/** Get password from session
2025-03-26 18:32:45 +01:00
* @ return string | false | null null for missing password , false for expired password
2014-02-19 09:27:22 -08:00
*/
function get_password () {
$return = get_session ( " pwds " );
if ( is_array ( $return )) {
$return = ( $_COOKIE [ " adminer_key " ]
? decrypt_string ( $return [ 0 ], $_COOKIE [ " adminer_key " ])
: false
);
}
return $return ;
}
2025-03-08 06:13:18 +01:00
/** Get single value from database
2025-03-28 15:11:12 +01:00
* @ return string | false false if error
2025-03-08 06:13:18 +01:00
*/
2025-03-28 15:11:12 +01:00
function get_val ( string $query , int $field = 0 , ? Db $conn = null ) {
2025-03-08 06:13:18 +01:00
global $connection ;
2025-03-28 19:12:31 +01:00
$conn = ( is_object ( $conn ) ? $conn : $connection );
2025-03-28 15:11:12 +01:00
$result = $conn -> query ( $query );
if ( ! is_object ( $result )) {
return false ;
}
$row = $result -> fetch_row ();
return ( $row ? $row [ $field ] : false );
2025-03-08 06:13:18 +01:00
}
2009-08-31 10:11:52 +00:00
/** Get list of values from database
2025-03-28 07:06:34 +01:00
* @ param mixed $column
2025-03-25 13:08:03 +01:00
* @ return list < string >
2009-08-31 10:11:52 +00:00
*/
2025-03-28 09:03:09 +01:00
function get_vals ( string $query , $column = 0 ) : array {
2009-09-22 10:51:40 +00:00
global $connection ;
2007-07-11 22:04:08 +00:00
$return = array ();
2009-09-22 10:51:40 +00:00
$result = $connection -> query ( $query );
2010-04-21 23:06:32 +00:00
if ( is_object ( $result )) {
2008-09-30 12:00:18 +00:00
while ( $row = $result -> fetch_row ()) {
2009-05-21 11:05:22 +00:00
$return [] = $row [ $column ];
2008-09-30 12:00:18 +00:00
}
2007-07-11 22:04:08 +00:00
}
return $return ;
}
2010-04-21 12:01:32 +00:00
/** Get keys from first column and values from second
2025-03-25 13:08:03 +01:00
* @ return string []
2010-04-21 12:01:32 +00:00
*/
2025-03-28 09:03:09 +01:00
function get_key_vals ( string $query , Db $connection2 = null , bool $set_keys = true ) : array {
2010-04-21 12:01:32 +00:00
global $connection ;
if ( ! is_object ( $connection2 )) {
$connection2 = $connection ;
}
$return = array ();
$result = $connection2 -> query ( $query );
2011-01-31 15:49:07 +01:00
if ( is_object ( $result )) {
while ( $row = $result -> fetch_row ()) {
2018-01-19 17:39:27 +01:00
if ( $set_keys ) {
$return [ $row [ 0 ]] = $row [ 1 ];
} else {
$return [] = $row [ 0 ];
}
2011-01-31 15:49:07 +01:00
}
2010-04-21 12:01:32 +00:00
}
return $return ;
}
2010-10-13 17:53:59 +02:00
/** Get all rows of result
2025-03-25 13:08:03 +01:00
* @ return list < string [] > of associative arrays
2010-10-13 17:53:59 +02:00
*/
2025-03-28 09:03:09 +01:00
function get_rows ( string $query , Db $connection2 = null , string $error = " <p class='error'> " ) : array {
2010-10-13 17:53:59 +02:00
global $connection ;
2012-01-06 00:56:30 -08:00
$conn = ( is_object ( $connection2 ) ? $connection2 : $connection );
2010-10-13 17:53:59 +02:00
$return = array ();
2012-01-06 00:56:30 -08:00
$result = $conn -> query ( $query );
2010-10-13 17:53:59 +02:00
if ( is_object ( $result )) { // can return true
while ( $row = $result -> fetch_assoc ()) {
$return [] = $row ;
}
2025-03-06 17:34:21 +01:00
} elseif ( ! $result && ! is_object ( $connection2 ) && $error && ( defined ( 'Adminer\PAGE_HEADER' ) || $error == " -- " )) {
2010-10-13 18:59:15 +02:00
echo $error . error () . " \n " ;
2010-10-13 17:53:59 +02:00
}
return $return ;
}
2009-08-31 10:11:52 +00:00
/** Find unique identifier of a row
2025-03-28 07:06:34 +01:00
* @ param string [] $row
2025-03-28 12:03:56 +01:00
* @ param Index [] $indexes
2025-03-26 15:38:04 +01:00
* @ return string [] | void null if there is no unique identifier
2009-08-31 10:11:52 +00:00
*/
2025-03-28 11:46:17 +01:00
function unique_array ( ? array $row , array $indexes ) {
2007-07-05 04:39:15 +00:00
foreach ( $indexes as $index ) {
2013-07-24 16:26:41 -07:00
if ( preg_match ( " ~PRIMARY|UNIQUE~ " , $index [ " type " ])) {
2007-07-05 04:39:15 +00:00
$return = array ();
foreach ( $index [ " columns " ] as $key ) {
2009-06-21 23:20:32 +00:00
if ( ! isset ( $row [ $key ])) { // NULL is ambiguous
2007-07-05 04:39:15 +00:00
continue 2 ;
2007-07-02 05:51:26 +00:00
}
2010-04-02 12:13:56 +00:00
$return [ $key ] = $row [ $key ];
2007-07-02 05:51:26 +00:00
}
2007-07-05 04:39:15 +00:00
return $return ;
2007-07-02 05:51:26 +00:00
}
}
2007-07-09 06:12:22 +00:00
}
2025-03-28 09:13:36 +01:00
/** Escape column key used in where() */
2025-03-28 09:03:09 +01:00
function escape_key ( string $key ) : string {
2014-06-26 14:36:47 +02:00
if ( preg_match ( '(^([\w(]+)(' . str_replace ( " _ " , " .* " , preg_quote ( idf_escape ( " _ " ))) . ')([ \w)]+)$)' , $key , $match )) { //! columns looking like functions
return $match [ 1 ] . idf_escape ( idf_unescape ( $match [ 2 ])) . $match [ 3 ]; //! SQL injection
}
return idf_escape ( $key );
}
2009-08-31 10:11:52 +00:00
/** Create SQL condition from parsed query string
2025-03-28 07:06:34 +01:00
* @ param array { where : string [], null : list < string > } $where parsed query string
* @ param Field [] $fields
2009-08-31 10:11:52 +00:00
*/
2025-03-28 09:03:09 +01:00
function where ( array $where , array $fields = array ()) : string {
2025-03-06 17:51:20 +01:00
global $connection ;
2007-07-09 06:12:22 +00:00
$return = array ();
2010-04-23 09:03:27 +00:00
foreach (( array ) $where [ " where " ] as $key => $val ) {
2025-03-26 19:29:50 +01:00
$key = bracket_escape ( $key , true ); // true - back
2014-06-26 14:36:47 +02:00
$column = escape_key ( $key );
2025-03-26 07:55:30 +01:00
$field = idx ( $fields , $key , array ());
2025-03-26 04:16:17 +01:00
$field_type = $field [ " type " ];
2013-06-04 19:40:17 -07:00
$return [] = $column
2025-03-12 09:26:17 +01:00
. ( JUSH == " sql " && $field_type == " json " ? " = CAST( " . q ( $val ) . " AS JSON) "
2025-03-06 17:51:20 +01:00
: ( JUSH == " sql " && is_numeric ( $val ) && preg_match ( '~\.~' , $val ) ? " LIKE " . q ( $val ) // LIKE because of floats but slow with ints
2025-03-12 09:26:17 +01:00
: ( JUSH == " mssql " && strpos ( $field_type , " datetime " ) === false ? " LIKE " . q ( preg_replace ( '~[_%[]~' , '[\0]' , $val )) // LIKE because of text but it does not work with datetime
2025-03-26 04:16:17 +01:00
: " = " . unconvert_field ( $field , q ( $val )))))
2010-04-26 16:22:58 +00:00
; //! enum and set
2025-03-12 09:26:17 +01:00
if ( JUSH == " sql " && preg_match ( '~char|text~' , $field_type ) && preg_match ( " ~[^ -@]~ " , $val )) { // not just [a-z] to catch non-ASCII characters
2014-06-26 13:22:35 +02:00
$return [] = " $column = " . q ( $val ) . " COLLATE " . charset ( $connection ) . " _bin " ;
2013-06-04 19:40:17 -07:00
}
2010-04-23 09:03:27 +00:00
}
foreach (( array ) $where [ " null " ] as $key ) {
2014-06-26 14:36:47 +02:00
$return [] = escape_key ( $key ) . " IS NULL " ;
2007-07-02 05:51:26 +00:00
}
2009-07-11 19:45:57 +00:00
return implode ( " AND " , $return );
2007-07-02 05:51:26 +00:00
}
2009-08-31 10:11:52 +00:00
/** Create SQL condition from query string
2025-03-28 07:06:34 +01:00
* @ param Field [] $fields
2009-08-31 10:11:52 +00:00
*/
2025-03-28 09:03:09 +01:00
function where_check ( string $val , array $fields = array ()) : string {
2009-06-07 23:53:51 +00:00
parse_str ( $val , $check );
2010-07-26 14:47:26 +02:00
remove_slashes ( array ( & $check ));
2012-12-11 21:25:56 -08:00
return where ( $check , $fields );
2009-06-07 23:53:51 +00:00
}
2009-08-31 10:11:52 +00:00
/** Create query string where condition from value
2025-03-28 07:06:34 +01:00
* @ param int $i condition order
* @ param string $column column identifier
2009-08-31 10:11:52 +00:00
*/
2025-03-28 09:03:09 +01:00
function where_link ( int $i , string $column , string $value , string $operator = " = " ) : string {
2012-05-13 23:54:07 -07:00
return " &where%5B $i %5D%5Bcol%5D= " . urlencode ( $column ) . " &where%5B $i %5D%5Bop%5D= " . urlencode (( $value !== null ? $operator : " IS NULL " )) . " &where%5B $i %5D%5Bval%5D= " . urlencode ( $value );
2009-07-15 14:56:27 +00:00
}
2013-04-26 22:57:44 -07:00
/** Get select clause for convertible fields
2025-03-28 07:06:34 +01:00
* @ param mixed [] $columns only keys are used
* @ param Field [] $fields
* @ param list < string > $select
2013-04-26 22:57:44 -07:00
*/
2025-03-28 09:03:09 +01:00
function convert_fields ( array $columns , array $fields , array $select = array ()) : string {
2013-04-26 22:57:44 -07:00
$return = " " ;
foreach ( $columns as $key => $val ) {
if ( $select && ! in_array ( idf_escape ( $key ), $select )) {
continue ;
}
$as = convert_field ( $fields [ $key ]);
if ( $as ) {
$return .= " , $as AS " . idf_escape ( $key );
}
}
return $return ;
}
2013-08-11 09:26:18 -07:00
/** Set cookie valid on current path
2025-03-28 07:06:34 +01:00
* @ param int $lifetime number of seconds , 0 for session cookie , 2592000 - 30 days
2009-09-09 20:49:30 +00:00
*/
2025-03-28 16:17:26 +01:00
function cookie ( string $name , ? string $value , int $lifetime = 2592000 ) : void {
2025-03-26 12:41:52 +01:00
header (
2025-03-05 09:14:49 +01:00
" Set-Cookie: $name = " . urlencode ( $value )
. ( $lifetime ? " ; expires= " . gmdate ( " D, d M Y H:i:s " , time () + $lifetime ) . " GMT " : " " )
. " ; path= " . preg_replace ( '~\?.*~' , '' , $_SERVER [ " REQUEST_URI " ])
2025-03-28 18:29:05 +01:00
. ( HTTPS ? " ; secure " : " " )
2025-03-05 09:14:49 +01:00
. " ; HttpOnly; SameSite=lax " ,
false
);
2009-09-09 20:49:30 +00:00
}
2025-03-16 18:53:49 +01:00
/** Get settings stored in a cookie
2025-03-25 13:08:03 +01:00
* @ return mixed []
2025-03-16 18:53:49 +01:00
*/
2025-03-28 09:03:09 +01:00
function get_settings ( string $cookie ) : array {
2025-03-16 18:53:49 +01:00
parse_str ( $_COOKIE [ $cookie ], $settings );
return $settings ;
}
/** Get setting stored in a cookie
* @ return mixed
*/
2025-03-28 08:23:20 +01:00
function get_setting ( string $key , string $cookie = " adminer_settings " ) {
2025-03-16 18:53:49 +01:00
$settings = get_settings ( $cookie );
return $settings [ $key ];
}
/** Store settings to a cookie
2025-03-28 07:06:34 +01:00
* @ param mixed [] $settings
2025-03-16 18:53:49 +01:00
*/
2025-03-28 09:03:09 +01:00
function save_settings ( array $settings , string $cookie = " adminer_settings " ) : void {
2025-03-26 12:41:52 +01:00
cookie ( $cookie , http_build_query ( $settings + get_settings ( $cookie )));
2025-03-16 18:53:49 +01:00
}
2025-03-28 09:13:36 +01:00
/** Restart stopped session */
2025-03-28 09:03:09 +01:00
function restart_session () : void {
2025-03-23 22:09:46 +01:00
if ( ! ini_bool ( " session.use_cookies " ) && ( ! function_exists ( 'session_status' ) || session_status () == 1 )) { // 1 - PHP_SESSION_NONE, session_status() available since PHP 5.4
2009-11-02 22:09:23 +00:00
session_start ();
}
}
2025-03-28 09:13:36 +01:00
/** Stop session if possible */
2025-03-28 09:03:09 +01:00
function stop_session ( bool $force = false ) : void {
2019-08-27 13:03:03 +02:00
$use_cookies = ini_bool ( " session.use_cookies " );
if ( ! $use_cookies || $force ) {
2018-02-20 23:14:36 +01:00
session_write_close (); // improves concurrency if a user opens several pages at once, may be restarted later
2025-03-27 18:27:51 +01:00
if ( $use_cookies && @ ini_set ( " session.use_cookies " , '0' ) === false ) { // @ - may be disabled
2019-08-27 13:03:03 +02:00
session_start ();
}
2012-08-19 13:42:13 -07:00
}
}
2010-04-21 12:01:32 +00:00
/** Get session variable for current server
* @ return mixed
*/
2025-03-28 08:23:20 +01:00
function & get_session ( string $key ) {
2010-04-21 12:01:32 +00:00
return $_SESSION [ $key ][ DRIVER ][ SERVER ][ $_GET [ " username " ]];
}
/** Set session variable for current server
2025-03-28 07:06:34 +01:00
* @ param mixed $val
2010-04-21 12:01:32 +00:00
* @ return mixed
*/
2025-03-28 08:23:20 +01:00
function set_session ( string $key , $val ) {
2010-04-21 12:01:32 +00:00
$_SESSION [ $key ][ DRIVER ][ SERVER ][ $_GET [ " username " ]] = $val ; // used also in auth.inc.php
}
2025-03-28 09:13:36 +01:00
/** Get authenticated URL */
2025-03-28 13:15:14 +01:00
function auth_url ( string $vendor , ? string $server , string $username , string $db = null ) : string {
2025-03-28 22:39:12 +01:00
$uri = remove_from_uri ( implode ( " | " , array_keys ( SqlDriver :: $drivers ))
2025-03-22 06:15:57 +01:00
. " |username|ext| "
2025-03-19 17:53:26 +01:00
. ( $db !== null ? " db| " : " " )
. ( $vendor == 'mssql' || $vendor == 'pgsql' ? " " : " ns| " ) // we don't have access to support() here
. session_name ())
;
preg_match ( '~([^?]*)\??(.*)~' , $uri , $match );
2010-05-06 14:21:22 +02:00
return " $match[1] ? "
2010-12-20 18:09:13 +01:00
. ( sid () ? SID . " & " : " " )
2013-07-05 08:28:37 -07:00
. ( $vendor != " server " || $server != " " ? urlencode ( $vendor ) . " = " . urlencode ( $server ) . " & " : " " )
2025-03-22 06:15:57 +01:00
. ( $_GET [ " ext " ] ? " ext= " . urlencode ( $_GET [ " ext " ]) . " & " : " " )
2010-05-06 14:21:22 +02:00
. " username= " . urlencode ( $username )
2012-05-14 00:24:23 -07:00
. ( $db != " " ? " &db= " . urlencode ( $db ) : " " )
2010-05-06 14:21:22 +02:00
. ( $match [ 2 ] ? " & $match[2] " : " " )
;
}
2025-03-28 09:13:36 +01:00
/** Find whether it is an AJAX request */
2025-03-28 09:03:09 +01:00
function is_ajax () : bool {
2011-01-25 16:13:31 +01:00
return ( $_SERVER [ " HTTP_X_REQUESTED_WITH " ] == " XMLHttpRequest " );
2010-10-18 13:57:22 +02:00
}
2009-08-31 10:11:52 +00:00
/** Send Location header and exit
2025-03-28 12:03:56 +01:00
* @ param ? string $location null to only set a message
2009-08-31 10:11:52 +00:00
*/
2025-03-28 12:03:56 +01:00
function redirect ( ? string $location , string $message = null ) : void {
2012-05-13 23:54:07 -07:00
if ( $message !== null ) {
2009-11-03 10:55:57 +00:00
restart_session ();
2012-05-13 23:54:07 -07:00
$_SESSION [ " messages " ][ preg_replace ( '~^[^?]*~' , '' , ( $location !== null ? $location : $_SERVER [ " REQUEST_URI " ]))][] = $message ;
2007-07-09 06:12:22 +00:00
}
2012-05-13 23:54:07 -07:00
if ( $location !== null ) {
2010-11-12 17:09:30 +01:00
if ( $location == " " ) {
$location = " . " ;
}
2012-04-15 22:18:03 -07:00
header ( " Location: $location " );
2010-11-23 11:50:53 +01:00
exit ;
2010-04-15 14:59:40 +00:00
}
2007-07-09 06:12:22 +00:00
}
2025-03-28 16:17:41 +01:00
/** Execute query and redirect if successful
* @ param bool $redirect
*/
2025-03-28 19:12:31 +01:00
function query_redirect ( string $query , ? string $location , string $message , $redirect = true , bool $execute = true , bool $failed = false , string $time = " " ) : bool {
2025-03-28 19:10:40 +01:00
global $connection , $adminer ;
2009-11-02 22:09:23 +00:00
if ( $execute ) {
2013-08-08 17:18:39 -07:00
$start = microtime ( true );
2009-11-02 22:09:23 +00:00
$failed = ! $connection -> query ( $query );
2014-03-11 09:37:56 -07:00
$time = format_time ( $start );
2009-11-02 22:09:23 +00:00
}
2025-03-28 19:10:40 +01:00
$sql = ( $query ? $adminer -> messageQuery ( $query , $time , $failed ) : " " );
2008-09-03 13:55:43 +00:00
if ( $failed ) {
2025-03-28 19:10:40 +01:00
$adminer -> error .= error () . $sql . script ( " messagesPrint(); " ) . " <br> " ;
2008-09-02 12:39:04 +00:00
return false ;
2008-09-02 08:42:14 +00:00
}
2008-09-02 12:39:04 +00:00
if ( $redirect ) {
redirect ( $location , $message . $sql );
}
return true ;
2008-09-02 08:42:14 +00:00
}
2025-03-26 17:04:30 +01:00
class Queries {
2025-03-28 09:20:10 +01:00
/** @var string[] */ static array $queries = array ();
2025-03-28 11:46:17 +01:00
static float $start = 0 ;
2025-03-26 17:04:30 +01:00
}
2009-08-31 10:11:52 +00:00
/** Execute and remember query
2025-03-28 07:06:34 +01:00
* @ param string $query end with ';' to use DELIMITER
2025-03-26 18:32:45 +01:00
* @ return Result | bool
2009-08-31 10:11:52 +00:00
*/
2025-03-28 08:23:20 +01:00
function queries ( string $query ) {
2009-09-22 10:51:40 +00:00
global $connection ;
2025-03-26 17:04:30 +01:00
if ( ! Queries :: $start ) {
Queries :: $start = microtime ( true );
2008-09-03 13:55:43 +00:00
}
2025-03-26 17:04:30 +01:00
Queries :: $queries [] = ( preg_match ( '~;$~' , $query ) ? " DELIMITER ;; \n $query ; \n DELIMITER " : $query ) . " ; " ;
2014-03-07 09:33:37 -08:00
return $connection -> query ( $query );
2008-09-03 13:55:43 +00:00
}
2010-05-17 18:18:32 +02:00
/** Apply command to all array items
2025-03-28 07:06:34 +01:00
* @ param list < string > $tables
* @ param callable ( string ) : string $escape
2010-05-17 18:18:32 +02:00
*/
2025-03-28 10:25:11 +01:00
function apply_queries ( string $query , array $tables , $escape = 'Adminer\table' ) : bool {
2010-05-17 18:18:32 +02:00
foreach ( $tables as $table ) {
if ( ! queries ( " $query " . $escape ( $table ))) {
return false ;
}
}
return true ;
}
2025-03-28 16:17:26 +01:00
/** Redirect by remembered queries
* @ param bool $redirect
*/
2025-03-28 19:12:31 +01:00
function queries_redirect ( ? string $location , string $message , $redirect ) : bool {
2025-03-26 17:04:30 +01:00
$queries = implode ( " \n " , Queries :: $queries );
$time = format_time ( Queries :: $start );
2014-03-07 09:33:37 -08:00
return query_redirect ( $queries , $location , $message , $redirect , false , ! $redirect , $time );
2009-10-13 20:01:52 +00:00
}
2014-03-11 09:37:56 -07:00
/** Format elapsed time
2025-03-28 07:06:34 +01:00
* @ param float $start output of microtime ( true )
2013-05-08 10:46:16 -07:00
* @ return string HTML code
*/
2025-03-28 09:03:09 +01:00
function format_time ( float $start ) : string {
2014-03-11 09:37:56 -07:00
return lang ( '%.3f s' , max ( 0 , microtime ( true ) - $start ));
2013-05-08 10:46:16 -07:00
}
2025-03-28 09:13:36 +01:00
/** Get relative REQUEST_URI */
2025-03-28 09:03:09 +01:00
function relative_uri () : string {
2020-05-11 12:35:19 +02:00
return str_replace ( " : " , " %3a " , preg_replace ( '~^[^?]*/([^?]*)~' , '\1' , $_SERVER [ " REQUEST_URI " ]));
2020-05-11 11:49:46 +02:00
}
2025-03-28 09:13:36 +01:00
/** Remove parameter from query string */
2025-03-28 09:03:09 +01:00
function remove_from_uri ( string $param = " " ) : string {
2020-05-11 11:49:46 +02:00
return substr ( preg_replace ( " ~(?<=[?&])( $param " . ( SID ? " " : " | " . session_name ()) . " )=[^&]*&~ " , '' , relative_uri () . " & " ), 0 , - 1 );
2007-07-27 11:43:44 +00:00
}
2009-11-21 09:08:52 +00:00
/** Get file contents from $_FILES
* @ return mixed int for error , string otherwise
2009-08-31 10:11:52 +00:00
*/
2025-03-28 08:23:20 +01:00
function get_file ( string $key , bool $decompress = false , string $delimiter = " " ) {
2009-08-28 11:49:57 +00:00
$file = $_FILES [ $key ];
2013-04-26 13:26:08 -07:00
if ( ! $file ) {
return null ;
2007-07-09 06:12:22 +00:00
}
2013-04-26 13:26:08 -07:00
foreach ( $file as $key => $val ) {
$file [ $key ] = ( array ) $val ;
}
2013-04-28 08:12:21 -07:00
$return = '' ;
2013-04-26 13:26:08 -07:00
foreach ( $file [ " error " ] as $key => $error ) {
if ( $error ) {
return $error ;
2011-03-07 14:27:03 +01:00
}
2013-04-26 13:26:08 -07:00
$name = $file [ " name " ][ $key ];
$tmp_name = $file [ " tmp_name " ][ $key ];
2025-03-05 14:51:17 +01:00
$content = file_get_contents (
$decompress && preg_match ( '~\.gz$~' , $name )
2013-04-29 14:00:35 -07:00
? " compress.zlib:// $tmp_name "
2013-04-26 13:26:08 -07:00
: $tmp_name
2013-04-29 14:00:35 -07:00
); //! may not be reachable because of open_basedir
2013-04-26 13:26:08 -07:00
if ( $decompress ) {
$start = substr ( $content , 0 , 3 );
2025-03-10 08:33:25 +01:00
if ( function_exists ( " iconv " ) && preg_match ( " ~^ \xFE \xFF |^ \xFF \xFE ~ " , $start )) { // not ternary operator to save memory
2013-04-26 13:26:08 -07:00
$content = iconv ( " utf-16 " , " utf-8 " , $content );
} elseif ( $start == " \xEF \xBB \xBF " ) { // UTF-8 BOM
$content = substr ( $content , 3 );
}
2025-03-10 08:33:25 +01:00
}
$return .= $content ;
if ( $delimiter ) {
$return .= ( preg_match ( " ( $delimiter\\s * \$ ) " , $content ) ? " " : $delimiter ) . " \n \n " ;
2013-04-26 13:26:08 -07:00
}
2011-03-07 14:27:03 +01:00
}
2013-04-28 08:12:21 -07:00
return $return ;
2007-07-09 06:12:22 +00:00
}
2025-03-28 09:13:36 +01:00
/** Determine upload error */
2025-03-28 09:03:09 +01:00
function upload_error ( int $error ) : string {
2011-08-24 14:16:11 +02:00
$max_size = ( $error == UPLOAD_ERR_INI_SIZE ? ini_get ( " upload_max_filesize " ) : 0 ); // post_max_size is checked in index.php
2009-08-25 15:58:04 +00:00
return ( $error ? lang ( 'Unable to upload a file.' ) . ( $max_size ? " " . lang ( 'Maximum allowed file size is %sB.' , $max_size ) : " " ) : lang ( 'File does not exist.' ));
2009-07-16 13:46:49 +00:00
}
2025-03-28 09:13:36 +01:00
/** Create repeat pattern for preg */
2025-03-28 09:03:09 +01:00
function repeat_pattern ( string $pattern , int $length ) : string {
2011-07-27 09:04:43 +02:00
// fix for Compilation failed: number too big in {} quantifier
return str_repeat ( " $pattern { 0,65535} " , $length / 65535 ) . " $pattern { 0, " . ( $length % 65535 ) . " } " ; // can create {0,0} which is OK
2010-10-19 01:40:49 +02:00
}
2025-03-28 09:13:36 +01:00
/** Check whether the string is in UTF-8 */
2025-03-28 13:15:14 +01:00
function is_utf8 ( ? string $val ) : bool {
2009-06-21 23:20:32 +00:00
// don't print control chars except \t\r\n
2018-02-20 16:27:40 +01:00
return ( preg_match ( '~~u' , $val ) && ! preg_match ( '~[\0-\x8\xB\xC\xE-\x1F]~' , $val ));
2009-06-11 05:05:35 +00:00
}
2009-08-31 10:11:52 +00:00
/** Shorten UTF - 8 string
* @ return string escaped string with appended ...
*/
2025-03-28 09:03:09 +01:00
function shorten_utf8 ( string $string , int $length = 80 , string $suffix = " " ) : string {
2017-02-20 16:22:30 +01:00
if ( ! preg_match ( " (^( " . repeat_pattern ( " [ \t \r \n - \ x { 10FFFF}] " , $length ) . " )( $ )?)u " , $string , $match )) { // ~s causes trash in $match[2] under some PHP versions, (.|\n) is slow
2011-01-10 17:23:47 +01:00
preg_match ( " (^( " . repeat_pattern ( " [ \t \r \n -~] " , $length ) . " )( $ )?) " , $string , $match );
2009-08-25 14:17:58 +00:00
}
2018-12-18 14:45:37 +01:00
return h ( $match [ 1 ]) . $suffix . ( isset ( $match [ 2 ]) ? " " : " <i>…</i> " );
2007-08-24 16:00:10 +00:00
}
2008-10-03 12:40:20 +00:00
2014-03-19 21:56:42 -07:00
/** Format decimal number
2025-03-28 07:06:34 +01:00
* @ param float | numeric - string $val
2014-03-19 21:56:42 -07:00
*/
2025-03-28 09:03:09 +01:00
function format_number ( $val ) : string {
2018-01-22 13:51:47 +01:00
return strtr ( number_format ( $val , 0 , " . " , lang ( ',' )), preg_split ( '~~u' , lang ( '0123456789' ), - 1 , PREG_SPLIT_NO_EMPTY ));
2014-03-19 21:56:42 -07:00
}
2025-03-28 09:13:36 +01:00
/** Generate friendly URL */
2025-03-28 09:03:09 +01:00
function friendly_url ( string $val ) : string {
2009-06-21 23:20:32 +00:00
// used for blobs and export
2025-02-26 16:44:30 +01:00
return preg_replace ( '~\W~i' , '-' , $val );
2009-06-11 05:18:40 +00:00
}
2013-06-24 05:53:23 -07:00
/** Get status of a single table and fall back to name on error
2025-03-26 02:23:29 +01:00
* @ return TableStatus one element from table_status ()
2013-06-24 05:53:23 -07:00
*/
2025-03-28 09:03:09 +01:00
function table_status1 ( string $table , bool $fast = false ) : array {
2013-06-24 05:53:23 -07:00
$return = table_status ( $table , $fast );
2025-03-26 01:34:48 +01:00
return ( $return ? reset ( $return ) : array ( " Name " => $table ));
2013-06-24 05:53:23 -07:00
}
2009-08-31 10:11:52 +00:00
/** Find out foreign keys for each column
2025-03-26 16:57:58 +01:00
* @ return list < ForeignKey > [] [ $col => []]
2009-08-31 10:11:52 +00:00
*/
2025-03-28 09:03:09 +01:00
function column_foreign_keys ( string $table ) : array {
2010-10-29 13:58:08 +02:00
global $adminer ;
2009-07-23 14:42:38 +00:00
$return = array ();
2010-10-29 13:58:08 +02:00
foreach ( $adminer -> foreignKeys ( $table ) as $foreign_key ) {
2009-07-23 14:42:38 +00:00
foreach ( $foreign_key [ " source " ] as $val ) {
$return [ $val ][] = $foreign_key ;
}
}
return $return ;
}
2014-01-11 15:44:03 -08:00
/** Compute fields () from $_POST edit data
2025-03-26 02:23:29 +01:00
* @ return Field [] same as fields ()
2014-01-11 15:44:03 -08:00
*/
2025-03-28 09:03:09 +01:00
function fields_from_edit () : array { // used by Mongo and SimpleDB
2014-01-11 17:27:04 -08:00
global $driver ;
2014-01-11 15:44:03 -08:00
$return = array ();
foreach (( array ) $_POST [ " field_keys " ] as $key => $val ) {
if ( $val != " " ) {
$val = bracket_escape ( $val );
$_POST [ " function " ][ $val ] = $_POST [ " field_funs " ][ $key ];
$_POST [ " fields " ][ $val ] = $_POST [ " field_vals " ][ $key ];
}
}
foreach (( array ) $_POST [ " fields " ] as $key => $val ) {
2025-03-26 19:29:50 +01:00
$name = bracket_escape ( $key , true ); // true - back
2014-01-11 17:27:04 -08:00
$return [ $name ] = array (
" field " => $name ,
2021-04-05 00:32:25 +02:00
" privileges " => array ( " insert " => 1 , " update " => 1 , " where " => 1 , " order " => 1 ),
2014-01-11 17:27:04 -08:00
" null " => 1 ,
" auto_increment " => ( $key == $driver -> primary ),
);
2014-01-11 15:44:03 -08:00
}
return $return ;
}
2011-02-17 11:43:21 +01:00
/** Send headers for export
* @ return string extension
*/
2025-03-28 09:03:09 +01:00
function dump_headers ( string $identifier , bool $multi_table = false ) : string {
2011-02-17 11:43:21 +01:00
global $adminer ;
$return = $adminer -> dumpHeaders ( $identifier , $multi_table );
2012-06-29 14:41:47 -07:00
$output = $_POST [ " output " ];
if ( $output != " text " ) {
2021-02-07 16:40:29 +01:00
header ( " Content-Disposition: attachment; filename= " . $adminer -> dumpFilename ( $identifier ) . " . $return " . ( $output != " file " && preg_match ( '~^[0-9a-z]+$~' , $output ) ? " . $output " : " " ));
2012-06-29 14:41:47 -07:00
}
2011-02-17 11:43:21 +01:00
session_write_close ();
2025-03-24 17:28:53 +01:00
if ( ! ob_get_level ()) {
ob_start ( null , 4096 );
}
2013-05-01 09:44:07 -07:00
ob_flush ();
flush ();
2011-02-17 11:43:21 +01:00
return $return ;
}
2009-08-31 10:11:52 +00:00
/** Print CSV row
2025-03-28 07:06:34 +01:00
* @ param string [] $row
2009-08-31 10:11:52 +00:00
*/
2025-03-28 09:03:09 +01:00
function dump_csv ( array $row ) : void {
2009-07-03 09:16:50 +00:00
foreach ( $row as $key => $val ) {
2021-02-07 09:41:07 +01:00
if ( preg_match ( '~["\n,;\t]|^0|\.\d*0$~' , $val ) || $val === " " ) {
2009-07-03 09:16:50 +00:00
$row [ $key ] = '"' . str_replace ( '"' , '""' , $val ) . '"' ;
}
}
2010-12-01 09:39:47 +01:00
echo implode (( $_POST [ " format " ] == " csv " ? " , " : ( $_POST [ " format " ] == " tsv " ? " \t " : " ; " )), $row ) . " \r \n " ;
2009-07-03 09:16:50 +00:00
}
2009-07-11 19:45:57 +00:00
2009-08-31 10:11:52 +00:00
/** Apply SQL function
2025-03-28 07:06:34 +01:00
* @ param string $column escaped column identifier
2009-08-31 10:11:52 +00:00
*/
2025-03-28 11:46:17 +01:00
function apply_sql_function ( ? string $function , string $column ) : string {
2010-04-21 12:01:32 +00:00
return ( $function ? ( $function == " unixepoch " ? " DATETIME( $column , ' $function ') " : ( $function == " count distinct " ? " COUNT(DISTINCT " : strtoupper ( " $function ( " )) . " $column ) " ) : $column );
2009-08-18 09:19:54 +00:00
}
2025-03-28 09:13:36 +01:00
/** Get path of the temporary directory */
2025-03-28 09:03:09 +01:00
function get_temp_dir () : string {
2014-03-21 22:47:34 -07:00
$return = ini_get ( " upload_tmp_dir " ); // session_save_path() may contain other storage path
if ( ! $return ) {
2010-05-06 15:45:34 +02:00
if ( function_exists ( 'sys_get_temp_dir' )) {
2014-03-21 22:47:34 -07:00
$return = sys_get_temp_dir ();
2010-05-06 15:45:34 +02:00
} else {
$filename = @ tempnam ( " " , " " ); // @ - temp directory can be disabled by open_basedir
if ( ! $filename ) {
2025-03-26 16:57:58 +01:00
return '' ;
2010-05-06 15:45:34 +02:00
}
2014-03-21 22:47:34 -07:00
$return = dirname ( $filename );
2010-05-06 15:45:34 +02:00
unlink ( $filename );
}
}
2014-03-21 22:47:34 -07:00
return $return ;
}
2018-01-24 12:04:53 +01:00
/** Open and exclusively lock a file
2025-03-26 16:57:58 +01:00
* @ return resource | void null for error
2018-01-24 12:04:53 +01:00
*/
2025-03-28 08:23:20 +01:00
function file_open_lock ( string $filename ) {
2025-03-16 20:49:52 +01:00
if ( is_link ( $filename )) {
return ; // https://cwe.mitre.org/data/definitions/61.html
}
2024-10-07 22:20:32 +02:00
$fp = @ fopen ( $filename , " c+ " ); // @ - may not be writable
if ( ! $fp ) {
return ;
}
chmod ( $filename , 0660 );
if ( ! flock ( $fp , LOCK_EX )) {
fclose ( $fp );
return ;
2018-01-24 12:04:53 +01:00
}
return $fp ;
}
2025-03-28 10:25:11 +01:00
/** Write and unlock a file
* @ param resource $fp
*/
function file_write_unlock ( $fp , string $data ) : void {
2018-01-24 12:04:53 +01:00
rewind ( $fp );
fwrite ( $fp , $data );
ftruncate ( $fp , strlen ( $data ));
2024-10-07 23:37:33 +02:00
file_unlock ( $fp );
}
2025-03-28 10:25:11 +01:00
/** Unlock and close a file
* @ param resource $fp
*/
function file_unlock ( $fp ) : void {
2018-01-24 12:04:53 +01:00
flock ( $fp , LOCK_UN );
fclose ( $fp );
}
2025-03-23 21:38:36 +01:00
/** Get first element of an array
2025-03-28 07:06:34 +01:00
* @ param mixed [] $array
2025-03-26 21:06:01 +01:00
* @ return mixed if not found
2025-03-23 21:38:36 +01:00
*/
2025-03-28 08:23:20 +01:00
function first ( array $array ) {
2025-03-23 21:38:36 +01:00
// reset(f()) triggers a notice
return reset ( $array );
}
2014-03-21 22:47:34 -07:00
/** Read password from file adminer . key in temporary directory or create one
2025-03-26 16:57:58 +01:00
* @ return string | false false if the file can not be created
2014-03-21 22:47:34 -07:00
*/
2025-03-28 08:23:20 +01:00
function password_file ( bool $create ) {
2014-03-21 22:47:34 -07:00
$filename = get_temp_dir () . " /adminer.key " ;
2024-10-07 23:37:33 +02:00
if ( ! $create && ! file_exists ( $filename )) {
return false ;
2010-05-06 15:45:34 +02:00
}
2024-10-07 23:37:33 +02:00
$fp = file_open_lock ( $filename );
if ( ! $fp ) {
return false ;
}
$return = stream_get_contents ( $fp );
if ( ! $return ) {
2013-08-11 09:26:18 -07:00
$return = rand_string ();
2024-10-07 23:37:33 +02:00
file_write_unlock ( $fp , $return );
} else {
file_unlock ( $fp );
2010-05-06 15:45:34 +02:00
}
return $return ;
}
2013-08-11 09:26:18 -07:00
/** Get a random string
* @ return string 32 hexadecimal characters
*/
2025-03-28 09:03:09 +01:00
function rand_string () : string {
2025-03-26 19:29:50 +01:00
return md5 ( uniqid ( strval ( mt_rand ()), true ));
2013-08-11 09:26:18 -07:00
}
2013-08-06 14:55:56 -07:00
/** Format value to use in select
2025-03-28 07:06:34 +01:00
* @ param string | string [] $val
* @ param Field $field
2025-03-28 13:15:14 +01:00
* @ param ? numeric - string $text_length
2013-08-06 14:55:56 -07:00
* @ return string HTML
*/
2025-03-28 13:15:14 +01:00
function select_value ( $val , string $link , array $field , ? string $text_length ) : string {
2018-01-30 19:12:49 +01:00
global $adminer ;
2013-08-06 14:55:56 -07:00
if ( is_array ( $val )) {
$return = " " ;
foreach ( $val as $k => $v ) {
$return .= " <tr> "
. ( $val != array_values ( $val ) ? " <th> " . h ( $k ) : " " )
. " <td> " . select_value ( $v , $link , $field , $text_length )
;
}
2025-02-23 11:42:05 +01:00
return " <table> $return </table> " ;
2013-08-06 14:55:56 -07:00
}
if ( ! $link ) {
$link = $adminer -> selectLink ( $val , $field );
}
if ( $link === null ) {
if ( is_mail ( $val )) {
$link = " mailto: $val " ;
}
2018-01-30 19:12:49 +01:00
if ( is_url ( $val )) {
$link = $val ; // IE 11 and all modern browsers hide referrer
2013-08-06 14:55:56 -07:00
}
}
2014-01-10 21:32:07 -08:00
$return = $adminer -> editVal ( $val , $field );
if ( $return !== null ) {
2018-02-20 16:02:25 +01:00
if ( ! is_utf8 ( $return )) {
2014-09-13 11:00:00 -07:00
$return = " \0 " ; // htmlspecialchars of binary data returns an empty string
} elseif ( $text_length != " " && is_shortable ( $field )) {
2014-01-10 21:32:07 -08:00
$return = shorten_utf8 ( $return , max ( 0 , + $text_length )); // usage of LEFT() would reduce traffic but complicate query - expected average speedup: .001 s VS .01 s on local network
2013-08-06 14:55:56 -07:00
} else {
2014-01-10 21:32:07 -08:00
$return = h ( $return );
2013-08-06 14:55:56 -07:00
}
}
2014-01-10 21:32:07 -08:00
return $adminer -> selectVal ( $return , $link , $field , $val );
2013-08-06 14:55:56 -07:00
}
2025-03-28 09:13:36 +01:00
/** Check whether the string is e-mail address */
2025-03-28 09:03:09 +01:00
function is_mail ( ? string $email ) : bool {
2009-07-11 19:45:57 +00:00
$atom = '[-a-z0-9!#$%&\'*+/=?^_`{|}~]' ; // characters of local-name
$domain = '[a-z0-9]([-a-z0-9]{0,61}[a-z0-9])' ; // one domain component
2010-04-21 22:21:47 +00:00
$pattern = " $atom +( \\ . $atom +)*@( $domain ? \\ .)+ $domain " ;
2013-08-06 14:55:56 -07:00
return is_string ( $email ) && preg_match ( " (^ $pattern (, \\ s* $pattern )* \$ )i " , $email );
2009-07-11 19:45:57 +00:00
}
2009-09-11 19:26:27 +00:00
2025-03-28 09:13:36 +01:00
/** Check whether the string is URL address */
2025-03-28 11:46:17 +01:00
function is_url ( ? string $string ) : bool {
2010-05-25 11:39:13 +02:00
$domain = '[a-z0-9]([-a-z0-9]{0,61}[a-z0-9])' ; // one domain component //! IDN
2018-01-30 19:12:49 +01:00
return preg_match ( " ~^(https?)://( $domain ? \\ .)+ $domain (: \\ d+)?(/.*)?( \\ ?.*)?(#.*)? \$ ~i " , $string ); //! restrict path, query and fragment characters
2009-10-02 14:25:18 +00:00
}
2012-08-19 17:12:19 -07:00
2012-09-22 07:34:51 -07:00
/** Check if field should be shortened
2025-03-28 07:06:34 +01:00
* @ param Field $field
2012-09-22 07:34:51 -07:00
*/
2025-03-28 09:03:09 +01:00
function is_shortable ( array $field ) : bool {
2018-02-09 13:48:33 +01:00
return preg_match ( '~char|text|json|lob|geometry|point|linestring|polygon|string|bytea~' , $field [ " type " ]);
2012-09-22 07:34:51 -07:00
}
2013-07-03 18:40:55 -07:00
/** Get query to compute number of found rows
2025-03-28 07:06:34 +01:00
* @ param list < string > $where
* @ param list < string > $group
2013-07-03 18:40:55 -07:00
*/
2025-03-28 09:03:09 +01:00
function count_rows ( string $table , array $where , bool $is_group , array $group ) : string {
2013-07-03 18:40:55 -07:00
$query = " FROM " . table ( $table ) . ( $where ? " WHERE " . implode ( " AND " , $where ) : " " );
2025-03-06 17:51:20 +01:00
return ( $is_group && ( JUSH == " sql " || count ( $group ) == 1 )
2013-07-03 18:40:55 -07:00
? " SELECT COUNT(DISTINCT " . implode ( " , " , $group ) . " ) $query "
2018-02-01 20:45:49 +01:00
: " SELECT COUNT(*) " . ( $is_group ? " FROM (SELECT 1 $query GROUP BY " . implode ( " , " , $group ) . " ) x " : $query )
2013-07-03 18:40:55 -07:00
);
}
2012-08-19 21:55:00 -07:00
/** Run query which can be killed by AJAX call after timing out
2025-03-25 13:08:03 +01:00
* @ return string []
2012-08-19 17:12:19 -07:00
*/
2025-03-28 09:03:09 +01:00
function slow_query ( string $query ) : array {
2025-03-28 18:49:26 +01:00
global $adminer , $driver ;
2012-08-19 23:25:23 -07:00
$db = $adminer -> database ();
2013-07-06 10:31:21 -07:00
$timeout = $adminer -> queryTimeout ();
2018-03-09 18:06:19 +01:00
$slow_query = $driver -> slowQuery ( $query , $timeout );
2025-03-08 21:45:21 +01:00
$connection2 = null ;
2025-03-27 18:27:51 +01:00
if ( ! $slow_query && support ( " kill " )) {
$connection2 = connect ( $adminer -> credentials ());
if ( is_object ( $connection2 ) && ( $db == " " || $connection2 -> select_db ( $db ))) {
2025-03-28 15:11:12 +01:00
$kill = get_val ( connection_id (), 0 , $connection2 ); // MySQL and MySQLi can use thread_id but it's not in PDO_MySQL
2025-03-28 18:49:26 +01:00
echo script ( " const timeout = setTimeout(() => { ajax(' " . js_escape ( ME ) . " script=kill', function () { }, 'kill= $kill &token= " . get_token () . " '); }, 1000 * $timeout ); " );
2025-03-27 18:27:51 +01:00
}
2012-08-19 19:38:53 -07:00
}
2012-08-19 17:12:19 -07:00
ob_flush ();
flush ();
2025-03-06 18:12:22 +01:00
$return = @ get_key_vals (( $slow_query ? : $query ), $connection2 , false ); // @ - may be killed
2012-08-19 21:55:00 -07:00
if ( $connection2 ) {
2018-01-12 15:27:44 +01:00
echo script ( " clearTimeout(timeout); " );
2012-08-19 19:38:53 -07:00
ob_flush ();
flush ();
2012-08-19 17:12:19 -07:00
}
2018-01-19 17:39:27 +01:00
return $return ;
2012-08-19 17:12:19 -07:00
}
2012-09-06 22:20:44 -07:00
2025-03-28 09:13:36 +01:00
/** Generate BREACH resistant CSRF token */
2025-03-28 09:03:09 +01:00
function get_token () : string {
2013-10-24 19:10:50 -07:00
$rand = rand ( 1 , 1e6 );
return ( $rand ^ $_SESSION [ " token " ]) . " : $rand " ;
}
2025-03-28 09:13:36 +01:00
/** Verify if supplied CSRF token is valid */
2025-03-28 09:03:09 +01:00
function verify_token () : bool {
2013-10-24 19:10:50 -07:00
list ( $token , $rand ) = explode ( " : " , $_POST [ " token " ]);
return ( $rand ^ $_SESSION [ " token " ]) == $token ;
}
2012-09-06 22:20:44 -07:00
// used in compiled version
2025-03-28 09:03:09 +01:00
function lzw_decompress ( string $binary ) : string {
2012-09-06 22:20:44 -07:00
// convert binary string to codes
$dictionary_count = 256 ;
$bits = 8 ; // ceil(log($dictionary_count, 2))
$codes = array ();
$rest = 0 ;
$rest_length = 0 ;
for ( $i = 0 ; $i < strlen ( $binary ); $i ++ ) {
$rest = ( $rest << 8 ) + ord ( $binary [ $i ]);
$rest_length += 8 ;
if ( $rest_length >= $bits ) {
$rest_length -= $bits ;
$codes [] = $rest >> $rest_length ;
$rest &= ( 1 << $rest_length ) - 1 ;
$dictionary_count ++ ;
if ( $dictionary_count >> $bits ) {
$bits ++ ;
}
}
}
// decompression
2025-03-26 13:49:11 +01:00
/** @var list<?string> */
2012-09-06 22:20:44 -07:00
$dictionary = range ( " \0 " , " \xFF " );
$return = " " ;
2025-03-26 13:49:11 +01:00
$word = " " ;
2012-09-06 22:20:44 -07:00
foreach ( $codes as $i => $code ) {
$element = $dictionary [ $code ];
if ( ! isset ( $element )) {
$element = $word . $word [ 0 ];
}
$return .= $element ;
if ( $i ) {
$dictionary [] = $word . $element [ 0 ];
}
$word = $element ;
}
return $return ;
}