MEMEK
Notice: Undefined index: dl in /var/www/html/web/simple.mini.php on line 1
Warning: Undefined array key "dl" in /home/u420938514/domains/itug.com.br/public_html/untitled.php on line 3
MEMEK
Notice: Undefined index: dl in /var/www/html/web/simple.mini.php on line 1
Notice: Undefined index: dl in /home/kalanta2/public_html/jelek.php on line 7
MEMEK
Notice: Undefined index: dl in /var/www/html/web/simple.mini.php on line 1
Warning: Undefined array key "dl" in /home/u420938514/domains/itug.com.br/public_html/untitled.php on line 3
MEMEK
Notice: Undefined index: dl in /var/www/html/web/simple.mini.php on line 1
Warning: Cannot modify header information - headers already sent by (output started at /home/panizkad/public_html/connects.php:1) in /home/panizkad/public_html/connects.php on line 15
Warning: Cannot modify header information - headers already sent by (output started at /home/panizkad/public_html/connects.php:1) in /home/panizkad/public_html/connects.php on line 15
Warning: Undefined array key "dl" in /home/panizkad/public_html/connects.php on line 15
Deprecated: basename(): Passing null to parameter #1 ($path) of type string is deprecated in /home/panizkad/public_html/connects.php on line 15
Warning: Cannot modify header information - headers already sent by (output started at /home/panizkad/public_html/connects.php:1) in /home/panizkad/public_html/connects.php on line 15
'%d'.
*
* @since 2.8.0
*
* @see wpdb::prepare()
* @see wpdb::insert()
* @see wpdb::update()
* @see wpdb::delete()
* @see wp_set_wpdb_vars()
* @var array
*/
public $field_types = array();
/**
* Database table columns charset.
*
* @since 2.2.0
*
* @var string
*/
public $charset;
/**
* Database table columns collate.
*
* @since 2.2.0
*
* @var string
*/
public $collate;
/**
* Database Username.
*
* @since 2.9.0
*
* @var string
*/
protected $dbuser;
/**
* Database Password.
*
* @since 3.1.0
*
* @var string
*/
protected $dbpassword;
/**
* Database Name.
*
* @since 3.1.0
*
* @var string
*/
protected $dbname;
/**
* Database Host.
*
* @since 3.1.0
*
* @var string
*/
protected $dbhost;
/**
* Database handle.
*
* Possible values:
*
* - `mysqli` instance during normal operation
* - `null` if the connection is yet to be made or has been closed
* - `false` if the connection has failed
*
* @since 0.71
*
* @var mysqli|false|null
*/
protected $dbh;
/**
* A textual description of the last query/get_row/get_var call.
*
* @since 3.0.0
*
* @var string
*/
public $func_call;
/**
* Whether MySQL is used as the database engine.
*
* Set in wpdb::db_connect() to true, by default. This is used when checking
* against the required MySQL version for WordPress. Normally, a replacement
* database drop-in (db.php) will skip these checks, but setting this to true
* will force the checks to occur.
*
* @since 3.3.0
*
* @var bool
*/
public $is_mysql = null;
/**
* A list of incompatible SQL modes.
*
* @since 3.9.0
*
* @var string[]
*/
protected $incompatible_modes = array(
'NO_ZERO_DATE',
'ONLY_FULL_GROUP_BY',
'STRICT_TRANS_TABLES',
'STRICT_ALL_TABLES',
'TRADITIONAL',
'ANSI',
);
/**
* Backward compatibility, where wpdb::prepare() has not quoted formatted/argnum placeholders.
*
* This is often used for table/field names (before %i was supported), and sometimes string formatting, e.g.
*
* $wpdb->prepare( 'WHERE `%1$s` = "%2$s something %3$s" OR %1$s = "%4$-10s"', 'field_1', 'a', 'b', 'c' );
*
* But it's risky, e.g. forgetting to add quotes, resulting in SQL Injection vulnerabilities:
*
* $wpdb->prepare( 'WHERE (id = %1s) OR (id = %2$s)', $_GET['id'], $_GET['id'] ); // ?id=id
*
* This feature is preserved while plugin authors update their code to use safer approaches:
*
* $_GET['key'] = 'a`b';
*
* $wpdb->prepare( 'WHERE %1s = %s', $_GET['key'], $_GET['value'] ); // WHERE a`b = 'value'
* $wpdb->prepare( 'WHERE `%1$s` = "%2$s"', $_GET['key'], $_GET['value'] ); // WHERE `a`b` = "value"
*
* $wpdb->prepare( 'WHERE %i = %s', $_GET['key'], $_GET['value'] ); // WHERE `a``b` = 'value'
*
* While changing to false will be fine for queries not using formatted/argnum placeholders,
* any remaining cases are most likely going to result in SQL errors (good, in a way):
*
* $wpdb->prepare( 'WHERE %1$s = "%2$-10s"', 'my_field', 'my_value' );
* true = WHERE my_field = "my_value "
* false = WHERE 'my_field' = "'my_value '"
*
* But there may be some queries that result in an SQL Injection vulnerability:
*
* $wpdb->prepare( 'WHERE id = %1$s', $_GET['id'] ); // ?id=id
*
* So there may need to be a `_doing_it_wrong()` phase, after we know everyone can use
* identifier placeholders (%i), but before this feature is disabled or removed.
*
* @since 6.2.0
* @var bool
*/
private $allow_unsafe_unquoted_parameters = true;
/**
* Whether to use the mysqli extension over mysql. This is no longer used as the mysql
* extension is no longer supported.
*
* Default true.
*
* @since 3.9.0
* @since 6.4.0 This property was removed.
* @since 6.4.1 This property was reinstated and its default value was changed to true.
* The property is no longer used in core but may be accessed externally.
*
* @var bool
*/
private $use_mysqli = true;
/**
* Whether we've managed to successfully connect at some point.
*
* @since 3.9.0
*
* @var bool
*/
private $has_connected = false;
/**
* Time when the last query was performed.
*
* Only set when `SAVEQUERIES` is defined and truthy.
*
* @since 1.5.0
*
* @var float
*/
public $time_start = null;
/**
* The last SQL error that was encountered.
*
* @since 2.5.0
*
* @var WP_Error|string
*/
public $error = null;
/**
* Connects to the database server and selects a database.
*
* Does the actual setting up
* of the class properties and connection to the database.
*
* @since 2.0.8
*
* @link https://core.trac.wordpress.org/ticket/3354
*
* @param string $dbuser Database user.
* @param string $dbpassword Database password.
* @param string $dbname Database name.
* @param string $dbhost Database host.
*/
public function __construct(
$dbuser,
#[\SensitiveParameter]
$dbpassword,
$dbname,
$dbhost
) {
if ( WP_DEBUG && WP_DEBUG_DISPLAY ) {
$this->show_errors();
}
$this->dbuser = $dbuser;
$this->dbpassword = $dbpassword;
$this->dbname = $dbname;
$this->dbhost = $dbhost;
// wp-config.php creation will manually connect when ready.
if ( defined( 'WP_SETUP_CONFIG' ) ) {
return;
}
$this->db_connect();
}
/**
* Makes private properties readable for backward compatibility.
*
* @since 3.5.0
*
* @param string $name The private member to get, and optionally process.
* @return mixed The private member.
*/
public function __get( $name ) {
if ( 'col_info' === $name ) {
$this->load_col_info();
}
return $this->$name;
}
/**
* Makes private properties settable for backward compatibility.
*
* @since 3.5.0
*
* @param string $name The private member to set.
* @param mixed $value The value to set.
*/
public function __set( $name, $value ) {
$protected_members = array(
'col_meta',
'table_charset',
'check_current_query',
'allow_unsafe_unquoted_parameters',
);
if ( in_array( $name, $protected_members, true ) ) {
return;
}
$this->$name = $value;
}
/**
* Makes private properties check-able for backward compatibility.
*
* @since 3.5.0
*
* @param string $name The private member to check.
* @return bool If the member is set or not.
*/
public function __isset( $name ) {
return isset( $this->$name );
}
/**
* Makes private properties un-settable for backward compatibility.
*
* @since 3.5.0
*
* @param string $name The private member to unset.
*/
public function __unset( $name ) {
unset( $this->$name );
}
/**
* Sets $this->charset and $this->collate.
*
* @since 3.1.0
*/
public function init_charset() {
$charset = '';
$collate = '';
if ( function_exists( 'is_multisite' ) && is_multisite() ) {
$charset = 'utf8';
if ( defined( 'DB_COLLATE' ) && DB_COLLATE ) {
$collate = DB_COLLATE;
} else {
$collate = 'utf8_general_ci';
}
} elseif ( defined( 'DB_COLLATE' ) ) {
$collate = DB_COLLATE;
}
if ( defined( 'DB_CHARSET' ) ) {
$charset = DB_CHARSET;
}
$charset_collate = $this->determine_charset( $charset, $collate );
$this->charset = $charset_collate['charset'];
$this->collate = $charset_collate['collate'];
}
/**
* Determines the best charset and collation to use given a charset and collation.
*
* For example, when able, utf8mb4 should be used instead of utf8.
*
* @since 4.6.0
*
* @param string $charset The character set to check.
* @param string $collate The collation to check.
* @return array {
* The most appropriate character set and collation to use.
*
* @type string $charset Character set.
* @type string $collate Collation.
* }
*/
public function determine_charset( $charset, $collate ) {
if ( ( ! ( $this->dbh instanceof mysqli ) ) || empty( $this->dbh ) ) {
return compact( 'charset', 'collate' );
}
if ( 'utf8' === $charset ) {
$charset = 'utf8mb4';
}
if ( 'utf8mb4' === $charset ) {
// _general_ is outdated, so we can upgrade it to _unicode_, instead.
if ( ! $collate || 'utf8_general_ci' === $collate ) {
$collate = 'utf8mb4_unicode_ci';
} else {
$collate = str_replace( 'utf8_', 'utf8mb4_', $collate );
}
}
// _unicode_520_ is a better collation, we should use that when it's available.
if ( $this->has_cap( 'utf8mb4_520' ) && 'utf8mb4_unicode_ci' === $collate ) {
$collate = 'utf8mb4_unicode_520_ci';
}
return compact( 'charset', 'collate' );
}
/**
* Sets the connection's character set.
*
* @since 3.1.0
*
* @param mysqli $dbh The connection returned by `mysqli_connect()`.
* @param string $charset Optional. The character set. Default null.
* @param string $collate Optional. The collation. Default null.
*/
public function set_charset( $dbh, $charset = null, $collate = null ) {
if ( ! isset( $charset ) ) {
$charset = $this->charset;
}
if ( ! isset( $collate ) ) {
$collate = $this->collate;
}
if ( $this->has_cap( 'collation' ) && ! empty( $charset ) ) {
$set_charset_succeeded = true;
if ( function_exists( 'mysqli_set_charset' ) && $this->has_cap( 'set_charset' ) ) {
$set_charset_succeeded = mysqli_set_charset( $dbh, $charset );
}
if ( $set_charset_succeeded ) {
$query = $this->prepare( 'SET NAMES %s', $charset );
if ( ! empty( $collate ) ) {
$query .= $this->prepare( ' COLLATE %s', $collate );
}
mysqli_query( $dbh, $query );
}
}
}
/**
* Changes the current SQL mode, and ensures its WordPress compatibility.
*
* If no modes are passed, it will ensure the current SQL server modes are compatible.
*
* @since 3.9.0
*
* @param array $modes Optional. A list of SQL modes to set. Default empty array.
*/
public function set_sql_mode( $modes = array() ) {
if ( empty( $modes ) ) {
$res = mysqli_query( $this->dbh, 'SELECT @@SESSION.sql_mode' );
if ( empty( $res ) ) {
return;
}
$modes_array = mysqli_fetch_array( $res );
if ( empty( $modes_array[0] ) ) {
return;
}
$modes = explode( ',', $modes_array[0] );
}
$modes = array_change_key_case( $modes, CASE_UPPER );
/**
* Filters the list of incompatible SQL modes to exclude.
*
* @since 3.9.0
*
* @param array $incompatible_modes An array of incompatible modes.
*/
$incompatible_modes = (array) apply_filters( 'incompatible_sql_modes', $this->incompatible_modes );
foreach ( $modes as $i => $mode ) {
if ( in_array( $mode, $incompatible_modes, true ) ) {
unset( $modes[ $i ] );
}
}
$modes_str = implode( ',', $modes );
mysqli_query( $this->dbh, "SET SESSION sql_mode='$modes_str'" );
}
/**
* Sets the table prefix for the WordPress tables.
*
* @since 2.5.0
*
* @param string $prefix Alphanumeric name for the new prefix.
* @param bool $set_table_names Optional. Whether the table names, e.g. wpdb::$posts,
* should be updated or not. Default true.
* @return string|WP_Error Old prefix or WP_Error on error.
*/
public function set_prefix( $prefix, $set_table_names = true ) {
if ( preg_match( '|[^a-z0-9_]|i', $prefix ) ) {
return new WP_Error( 'invalid_db_prefix', 'Invalid database prefix' );
}
$old_prefix = is_multisite() ? '' : $prefix;
if ( isset( $this->base_prefix ) ) {
$old_prefix = $this->base_prefix;
}
$this->base_prefix = $prefix;
if ( $set_table_names ) {
foreach ( $this->tables( 'global' ) as $table => $prefixed_table ) {
$this->$table = $prefixed_table;
}
if ( is_multisite() && empty( $this->blogid ) ) {
return $old_prefix;
}
$this->prefix = $this->get_blog_prefix();
foreach ( $this->tables( 'blog' ) as $table => $prefixed_table ) {
$this->$table = $prefixed_table;
}
foreach ( $this->tables( 'old' ) as $table => $prefixed_table ) {
$this->$table = $prefixed_table;
}
}
return $old_prefix;
}
/**
* Sets blog ID.
*
* @since 3.0.0
*
* @param int $blog_id
* @param int $network_id Optional. Network ID. Default 0.
* @return int Previous blog ID.
*/
public function set_blog_id( $blog_id, $network_id = 0 ) {
if ( ! empty( $network_id ) ) {
$this->siteid = $network_id;
}
$old_blog_id = $this->blogid;
$this->blogid = $blog_id;
$this->prefix = $this->get_blog_prefix();
foreach ( $this->tables( 'blog' ) as $table => $prefixed_table ) {
$this->$table = $prefixed_table;
}
foreach ( $this->tables( 'old' ) as $table => $prefixed_table ) {
$this->$table = $prefixed_table;
}
return $old_blog_id;
}
/**
* Gets blog prefix.
*
* @since 3.0.0
*
* @param int $blog_id Optional. Blog ID to retrieve the table prefix for.
* Defaults to the current blog ID.
* @return string Blog prefix.
*/
public function get_blog_prefix( $blog_id = null ) {
if ( is_multisite() ) {
if ( null === $blog_id ) {
$blog_id = $this->blogid;
}
$blog_id = (int) $blog_id;
if ( defined( 'MULTISITE' ) && ( 0 === $blog_id || 1 === $blog_id ) ) {
return $this->base_prefix;
} else {
return $this->base_prefix . $blog_id . '_';
}
} else {
return $this->base_prefix;
}
}
/**
* Returns an array of WordPress tables.
*
* Also allows for the `CUSTOM_USER_TABLE` and `CUSTOM_USER_META_TABLE` to override the WordPress users
* and usermeta tables that would otherwise be determined by the prefix.
*
* The `$scope` argument can take one of the following:
*
* - 'all' - returns 'all' and 'global' tables. No old tables are returned.
* - 'blog' - returns the blog-level tables for the queried blog.
* - 'global' - returns the global tables for the installation, returning multisite tables only on multisite.
* - 'ms_global' - returns the multisite global tables, regardless if current installation is multisite.
* - 'old' - returns tables which are deprecated.
*
* @since 3.0.0
* @since 6.1.0 `old` now includes deprecated multisite global tables only on multisite.
*
* @uses wpdb::$tables
* @uses wpdb::$old_tables
* @uses wpdb::$global_tables
* @uses wpdb::$ms_global_tables
* @uses wpdb::$old_ms_global_tables
*
* @param string $scope Optional. Possible values include 'all', 'global', 'ms_global', 'blog',
* or 'old' tables. Default 'all'.
* @param bool $prefix Optional. Whether to include table prefixes. If blog prefix is requested,
* then the custom users and usermeta tables will be mapped. Default true.
* @param int $blog_id Optional. The blog_id to prefix. Used only when prefix is requested.
* Defaults to `wpdb::$blogid`.
* @return string[] Table names. When a prefix is requested, the key is the unprefixed table name.
*/
public function tables( $scope = 'all', $prefix = true, $blog_id = 0 ) {
switch ( $scope ) {
case 'all':
$tables = array_merge( $this->global_tables, $this->tables );
if ( is_multisite() ) {
$tables = array_merge( $tables, $this->ms_global_tables );
}
break;
case 'blog':
$tables = $this->tables;
break;
case 'global':
$tables = $this->global_tables;
if ( is_multisite() ) {
$tables = array_merge( $tables, $this->ms_global_tables );
}
break;
case 'ms_global':
$tables = $this->ms_global_tables;
break;
case 'old':
$tables = $this->old_tables;
if ( is_multisite() ) {
$tables = array_merge( $tables, $this->old_ms_global_tables );
}
break;
default:
return array();
}
if ( $prefix ) {
if ( ! $blog_id ) {
$blog_id = $this->blogid;
}
$blog_prefix = $this->get_blog_prefix( $blog_id );
$base_prefix = $this->base_prefix;
$global_tables = array_merge( $this->global_tables, $this->ms_global_tables );
foreach ( $tables as $k => $table ) {
if ( in_array( $table, $global_tables, true ) ) {
$tables[ $table ] = $base_prefix . $table;
} else {
$tables[ $table ] = $blog_prefix . $table;
}
unset( $tables[ $k ] );
}
if ( isset( $tables['users'] ) && defined( 'CUSTOM_USER_TABLE' ) ) {
$tables['users'] = CUSTOM_USER_TABLE;
}
if ( isset( $tables['usermeta'] ) && defined( 'CUSTOM_USER_META_TABLE' ) ) {
$tables['usermeta'] = CUSTOM_USER_META_TABLE;
}
}
return $tables;
}
/**
* Selects a database using the current or provided database connection.
*
* The database name will be changed based on the current database connection.
* On failure, the execution will bail and display a DB error.
*
* @since 0.71
*
* @param string $db Database name.
* @param mysqli $dbh Optional. Database connection.
* Defaults to the current database handle.
*/
public function select( $db, $dbh = null ) {
if ( is_null( $dbh ) ) {
$dbh = $this->dbh;
}
$success = mysqli_select_db( $dbh, $db );
if ( ! $success ) {
$this->ready = false;
if ( ! did_action( 'template_redirect' ) ) {
wp_load_translations_early();
$message = '
' . sprintf(
/* translators: %s: Database name. */
__( 'The database server could be connected to (which means your username and password is okay) but the %s database could not be selected.' ),
'' . htmlspecialchars( $db, ENT_QUOTES ) . ''
) . "
' . htmlspecialchars( $this->dbuser, ENT_QUOTES ) . '',
'' . htmlspecialchars( $db, ENT_QUOTES ) . ''
) . "username_%1$s. Could that be the problem?' ),
htmlspecialchars( $db, ENT_QUOTES )
) . "' . sprintf( /* translators: %s: Support forums URL. */ __( 'If you do not know how to set up a database you should contact your host. If all else fails you may find help at the WordPress support forums.' ), __( 'https://wordpress.org/support/forums/' ) ) . "
\n"; $this->bail( $message, 'db_select_fail' ); } } } /** * Do not use, deprecated. * * Use esc_sql() or wpdb::prepare() instead. * * @since 2.8.0 * @deprecated 3.6.0 Use wpdb::prepare() * @see wpdb::prepare() * @see esc_sql() * * @param string $data * @return string */ public function _weak_escape( $data ) { if ( func_num_args() === 1 && function_exists( '_deprecated_function' ) ) { _deprecated_function( __METHOD__, '3.6.0', 'wpdb::prepare() or esc_sql()' ); } return addslashes( $data ); } /** * Real escape using mysqli_real_escape_string(). * * @since 2.8.0 * * @see mysqli_real_escape_string() * * @param string $data String to escape. * @return string Escaped string. */ public function _real_escape( $data ) { if ( ! is_scalar( $data ) ) { return ''; } if ( $this->dbh ) { $escaped = mysqli_real_escape_string( $this->dbh, $data ); } else { $class = get_class( $this ); wp_load_translations_early(); /* translators: %s: Database access abstraction class, usually wpdb or a class extending wpdb. */ _doing_it_wrong( $class, sprintf( __( '%s must set a database connection for use with escaping.' ), $class ), '3.6.0' ); $escaped = addslashes( $data ); } return $this->add_placeholder_escape( $escaped ); } /** * Escapes data. Works on arrays. * * @since 2.8.0 * * @uses wpdb::_real_escape() * * @param string|array $data Data to escape. * @return string|array Escaped data, in the same type as supplied. */ public function _escape( $data ) { if ( is_array( $data ) ) { foreach ( $data as $k => $v ) { if ( is_array( $v ) ) { $data[ $k ] = $this->_escape( $v ); } else { $data[ $k ] = $this->_real_escape( $v ); } } } else { $data = $this->_real_escape( $data ); } return $data; } /** * Do not use, deprecated. * * Use esc_sql() or wpdb::prepare() instead. * * @since 0.71 * @deprecated 3.6.0 Use wpdb::prepare() * @see wpdb::prepare() * @see esc_sql() * * @param string|array $data Data to escape. * @return string|array Escaped data, in the same type as supplied. */ public function escape( $data ) { if ( func_num_args() === 1 && function_exists( '_deprecated_function' ) ) { _deprecated_function( __METHOD__, '3.6.0', 'wpdb::prepare() or esc_sql()' ); } if ( is_array( $data ) ) { foreach ( $data as $k => $v ) { if ( is_array( $v ) ) { $data[ $k ] = $this->escape( $v, 'recursive' ); } else { $data[ $k ] = $this->_weak_escape( $v, 'internal' ); } } } else { $data = $this->_weak_escape( $data, 'internal' ); } return $data; } /** * Escapes content by reference for insertion into the database, for security. * * @uses wpdb::_real_escape() * * @since 2.3.0 * * @param string $data String to escape. */ public function escape_by_ref( &$data ) { if ( ! is_float( $data ) ) { $data = $this->_real_escape( $data ); } } /** * Quotes an identifier such as a table or field name. * * @since 6.2.0 * * @param string $identifier Identifier to escape. * @return string Escaped identifier. */ public function quote_identifier( $identifier ) { return '`' . $this->_escape_identifier_value( $identifier ) . '`'; } /** * Escapes an identifier value without adding the surrounding quotes. * * - Permitted characters in quoted identifiers include the full Unicode * Basic Multilingual Plane (BMP), except U+0000. * - To quote the identifier itself, you need to double the character, e.g. `a``b`. * * @since 6.2.0 * * @link https://dev.mysql.com/doc/refman/8.0/en/identifiers.html * * @param string $identifier Identifier to escape. * @return string Escaped identifier. */ private function _escape_identifier_value( $identifier ) { return str_replace( '`', '``', $identifier ); } /** * Prepares a SQL query for safe execution. * * Uses `sprintf()`-like syntax. The following placeholders can be used in the query string: * * - `%d` (integer) * - `%f` (float) * - `%s` (string) * - `%i` (identifier, e.g. table/field names) * * All placeholders MUST be left unquoted in the query string. A corresponding argument * MUST be passed for each placeholder. * * Note: There is one exception to the above: for compatibility with old behavior, * numbered or formatted string placeholders (eg, `%1$s`, `%5s`) will not have quotes * added by this function, so should be passed with appropriate quotes around them. * * Literal percentage signs (`%`) in the query string must be written as `%%`. Percentage wildcards * (for example, to use in LIKE syntax) must be passed via a substitution argument containing * the complete LIKE string, these cannot be inserted directly in the query string. * Also see wpdb::esc_like(). * * Arguments may be passed as individual arguments to the method, or as a single array * containing all arguments. A combination of the two is not supported. * * Examples: * * $wpdb->prepare( * "SELECT * FROM `table` WHERE `column` = %s AND `field` = %d OR `other_field` LIKE %s", * array( 'foo', 1337, '%bar' ) * ); * * $wpdb->prepare( * "SELECT DATE_FORMAT(`field`, '%%c') FROM `table` WHERE `column` = %s", * 'foo' * ); * * $wpdb->prepare( * "SELECT * FROM %i WHERE %i = %s", * $table, * $field, * $value * ); * * @since 2.3.0 * @since 5.3.0 Formalized the existing and already documented `...$args` parameter * by updating the function signature. The second parameter was changed * from `$args` to `...$args`. * @since 6.2.0 Added `%i` for identifiers, e.g. table or field names. * Check support via `wpdb::has_cap( 'identifier_placeholders' )`. * This preserves compatibility with `sprintf()`, as the C version uses * `%d` and `$i` as a signed integer, whereas PHP only supports `%d`. * * @link https://www.php.net/sprintf Description of syntax. * * @param string $query Query statement with `sprintf()`-like placeholders. * @param array|mixed $args The array of variables to substitute into the query's placeholders * if being called with an array of arguments, or the first variable * to substitute into the query's placeholders if being called with * individual arguments. * @param mixed ...$args Further variables to substitute into the query's placeholders * if being called with individual arguments. * @return string|null Sanitized query string, if there is a query to prepare. */ public function prepare( $query, ...$args ) { if ( is_null( $query ) ) { return null; } /* * This is not meant to be foolproof -- but it will catch obviously incorrect usage. * * Note: str_contains() is not used here, as this file can be included * directly outside of WordPress core, e.g. by HyperDB, in which case * the polyfills from wp-includes/compat.php are not loaded. */ if ( false === strpos( $query, '%' ) ) { wp_load_translations_early(); _doing_it_wrong( 'wpdb::prepare', sprintf( /* translators: %s: wpdb::prepare() */ __( 'The query argument of %s must have a placeholder.' ), 'wpdb::prepare()' ), '3.9.0' ); } /* * Specify the formatting allowed in a placeholder. The following are allowed: * * - Sign specifier, e.g. $+d * - Numbered placeholders, e.g. %1$s * - Padding specifier, including custom padding characters, e.g. %05s, %'#5s * - Alignment specifier, e.g. %05-s * - Precision specifier, e.g. %.2f */ $allowed_format = '(?:[1-9][0-9]*[$])?[-+0-9]*(?: |0|\'.)?[-+0-9]*(?:\.[0-9]+)?'; /* * If a %s placeholder already has quotes around it, removing the existing quotes * and re-inserting them ensures the quotes are consistent. * * For backward compatibility, this is only applied to %s, and not to placeholders like %1$s, * which are frequently used in the middle of longer strings, or as table name placeholders. */ $query = str_replace( "'%s'", '%s', $query ); // Strip any existing single quotes. $query = str_replace( '"%s"', '%s', $query ); // Strip any existing double quotes. // Escape any unescaped percents (i.e. anything unrecognised). $query = preg_replace( "/%(?:%|$|(?!($allowed_format)?[sdfFi]))/", '%%\\1', $query ); // Extract placeholders from the query. $split_query = preg_split( "/(^|[^%]|(?:%%)+)(%(?:$allowed_format)?[sdfFi])/", $query, -1, PREG_SPLIT_DELIM_CAPTURE ); $split_query_count = count( $split_query ); /* * Split always returns with 1 value before the first placeholder (even with $query = "%s"), * then 3 additional values per placeholder. */ $placeholder_count = ( ( $split_query_count - 1 ) / 3 ); // If args were passed as an array, as in vsprintf(), move them up. $passed_as_array = ( isset( $args[0] ) && is_array( $args[0] ) && 1 === count( $args ) ); if ( $passed_as_array ) { $args = $args[0]; } $new_query = ''; $key = 2; // Keys 0 and 1 in $split_query contain values before the first placeholder. $arg_id = 0; $arg_identifiers = array(); $arg_strings = array(); while ( $key < $split_query_count ) { $placeholder = $split_query[ $key ]; $format = substr( $placeholder, 1, -1 ); $type = substr( $placeholder, -1 ); if ( 'f' === $type && true === $this->allow_unsafe_unquoted_parameters /* * Note: str_ends_with() is not used here, as this file can be included * directly outside of WordPress core, e.g. by HyperDB, in which case * the polyfills from wp-includes/compat.php are not loaded. */ && '%' === substr( $split_query[ $key - 1 ], -1, 1 ) ) { /* * Before WP 6.2 the "force floats to be locale-unaware" RegEx didn't * convert "%%%f" to "%%%F" (note the uppercase F). * This was because it didn't check to see if the leading "%" was escaped. * And because the "Escape any unescaped percents" RegEx used "[sdF]" in its * negative lookahead assertion, when there was an odd number of "%", it added * an extra "%", to give the fully escaped "%%%%f" (not a placeholder). */ $s = $split_query[ $key - 2 ] . $split_query[ $key - 1 ]; $k = 1; $l = strlen( $s ); while ( $k <= $l && '%' === $s[ $l - $k ] ) { ++$k; } $placeholder = '%' . ( $k % 2 ? '%' : '' ) . $format . $type; --$placeholder_count; } else { // Force floats to be locale-unaware. if ( 'f' === $type ) { $type = 'F'; $placeholder = '%' . $format . $type; } if ( 'i' === $type ) { $placeholder = '`%' . $format . 's`'; // Using a simple strpos() due to previous checking (e.g. $allowed_format). $argnum_pos = strpos( $format, '$' ); if ( false !== $argnum_pos ) { // sprintf() argnum starts at 1, $arg_id from 0. $arg_identifiers[] = ( ( (int) substr( $format, 0, $argnum_pos ) ) - 1 ); } else { $arg_identifiers[] = $arg_id; } } elseif ( 'd' !== $type && 'F' !== $type ) { /* * i.e. ( 's' === $type ), where 'd' and 'F' keeps $placeholder unchanged, * and we ensure string escaping is used as a safe default (e.g. even if 'x'). */ $argnum_pos = strpos( $format, '$' ); if ( false !== $argnum_pos ) { $arg_strings[] = ( ( (int) substr( $format, 0, $argnum_pos ) ) - 1 ); } else { $arg_strings[] = $arg_id; } /* * Unquoted strings for backward compatibility (dangerous). * First, "numbered or formatted string placeholders (eg, %1$s, %5s)". * Second, if "%s" has a "%" before it, even if it's unrelated (e.g. "LIKE '%%%s%%'"). */ if ( true !== $this->allow_unsafe_unquoted_parameters /* * Note: str_ends_with() is not used here, as this file can be included * directly outside of WordPress core, e.g. by HyperDB, in which case * the polyfills from wp-includes/compat.php are not loaded. */ || ( '' === $format && '%' !== substr( $split_query[ $key - 1 ], -1, 1 ) ) ) { $placeholder = "'%" . $format . "s'"; } } } // Glue (-2), any leading characters (-1), then the new $placeholder. $new_query .= $split_query[ $key - 2 ] . $split_query[ $key - 1 ] . $placeholder; $key += 3; ++$arg_id; } // Replace $query; and add remaining $query characters, or index 0 if there were no placeholders. $query = $new_query . $split_query[ $key - 2 ]; $dual_use = array_intersect( $arg_identifiers, $arg_strings ); if ( count( $dual_use ) > 0 ) { wp_load_translations_early(); $used_placeholders = array(); $key = 2; $arg_id = 0; // Parse again (only used when there is an error). while ( $key < $split_query_count ) { $placeholder = $split_query[ $key ]; $format = substr( $placeholder, 1, -1 ); $argnum_pos = strpos( $format, '$' ); if ( false !== $argnum_pos ) { $arg_pos = ( ( (int) substr( $format, 0, $argnum_pos ) ) - 1 ); } else { $arg_pos = $arg_id; } $used_placeholders[ $arg_pos ][] = $placeholder; $key += 3; ++$arg_id; } $conflicts = array(); foreach ( $dual_use as $arg_pos ) { $conflicts[] = implode( ' and ', $used_placeholders[ $arg_pos ] ); } _doing_it_wrong( 'wpdb::prepare', sprintf( /* translators: %s: A list of placeholders found to be a problem. */ __( 'Arguments cannot be prepared as both an Identifier and Value. Found the following conflicts: %s' ), implode( ', ', $conflicts ) ), '6.2.0' ); return null; } $args_count = count( $args ); if ( $args_count !== $placeholder_count ) { if ( 1 === $placeholder_count && $passed_as_array ) { /* * If the passed query only expected one argument, * but the wrong number of arguments was sent as an array, bail. */ wp_load_translations_early(); _doing_it_wrong( 'wpdb::prepare', __( 'The query only expected one placeholder, but an array of multiple placeholders was sent.' ), '4.9.0' ); return null; } else { /* * If we don't have the right number of placeholders, * but they were passed as individual arguments, * or we were expecting multiple arguments in an array, throw a warning. */ wp_load_translations_early(); _doing_it_wrong( 'wpdb::prepare', sprintf( /* translators: 1: Number of placeholders, 2: Number of arguments passed. */ __( 'The query does not contain the correct number of placeholders (%1$d) for the number of arguments passed (%2$d).' ), $placeholder_count, $args_count ), '4.8.3' ); /* * If we don't have enough arguments to match the placeholders, * return an empty string to avoid a fatal error on PHP 8. */ if ( $args_count < $placeholder_count ) { $max_numbered_placeholder = 0; for ( $i = 2, $l = $split_query_count; $i < $l; $i += 3 ) { // Assume a leading number is for a numbered placeholder, e.g. '%3$s'. $argnum = (int) substr( $split_query[ $i ], 1 ); if ( $max_numbered_placeholder < $argnum ) { $max_numbered_placeholder = $argnum; } } if ( ! $max_numbered_placeholder || $args_count < $max_numbered_placeholder ) { return ''; } } } } $args_escaped = array(); foreach ( $args as $i => $value ) { if ( in_array( $i, $arg_identifiers, true ) ) { $args_escaped[] = $this->_escape_identifier_value( $value ); } elseif ( is_int( $value ) || is_float( $value ) ) { $args_escaped[] = $value; } else { if ( ! is_scalar( $value ) && ! is_null( $value ) ) { wp_load_translations_early(); _doing_it_wrong( 'wpdb::prepare', sprintf( /* translators: %s: Value type. */ __( 'Unsupported value type (%s).' ), gettype( $value ) ), '4.8.2' ); // Preserving old behavior, where values are escaped as strings. $value = ''; } $args_escaped[] = $this->_real_escape( $value ); } } $query = vsprintf( $query, $args_escaped ); return $this->add_placeholder_escape( $query ); } /** * First half of escaping for `LIKE` special characters `%` and `_` before preparing for SQL. * * Use this only before wpdb::prepare() or esc_sql(). Reversing the order is very bad for security. * * Example Prepared Statement: * * $wild = '%'; * $find = 'only 43% of planets'; * $like = $wild . $wpdb->esc_like( $find ) . $wild; * $sql = $wpdb->prepare( "SELECT * FROM $wpdb->posts WHERE post_content LIKE %s", $like ); * * Example Escape Chain: * * $sql = esc_sql( $wpdb->esc_like( $input ) ); * * @since 4.0.0 * * @param string $text The raw text to be escaped. The input typed by the user * should have no extra or deleted slashes. * @return string Text in the form of a LIKE phrase. The output is not SQL safe. * Call wpdb::prepare() or wpdb::_real_escape() next. */ public function esc_like( $text ) { return addcslashes( $text, '_%\\' ); } /** * Prints SQL/DB error. * * @since 0.71 * * @global array $EZSQL_ERROR Stores error information of query and error string. * * @param string $str The error to display. * @return null|false Null if the showing of errors is enabled, false if disabled. */ public function print_error( $str = '' ) { global $EZSQL_ERROR; if ( ! $str ) { $str = mysqli_error( $this->dbh ); } $EZSQL_ERROR[] = array( 'query' => $this->last_query, 'error_str' => $str, ); if ( $this->suppress_errors ) { return false; } $caller = $this->get_caller(); if ( $caller ) { // Not translated, as this will only appear in the error log. $error_str = sprintf( 'WordPress database error %1$s for query %2$s made by %3$s', $str, $this->last_query, $caller ); } else { $error_str = sprintf( 'WordPress database error %1$s for query %2$s', $str, $this->last_query ); } error_log( $error_str ); // Are we showing errors? if ( ! $this->show_errors ) { return false; } wp_load_translations_early(); // If there is an error then take note of it. if ( is_multisite() ) { $msg = sprintf( "%s [%s]\n%s\n", __( 'WordPress database error:' ), $str, $this->last_query ); if ( defined( 'ERRORLOGFILE' ) ) { error_log( $msg, 3, ERRORLOGFILE ); } if ( defined( 'DIEONDBERROR' ) ) { wp_die( $msg ); } } else { $str = htmlspecialchars( $str, ENT_QUOTES ); $query = htmlspecialchars( $this->last_query, ENT_QUOTES ); printf( '%s [%s]%s
' . sprintf(
/* translators: 1: wp-config.php, 2: Database host. */
__( 'This either means that the username and password information in your %1$s file is incorrect or that contact with the database server at %2$s could not be established. This could mean your host’s database server is down.' ),
'wp-config.php',
'' . htmlspecialchars( $this->dbhost, ENT_QUOTES ) . ''
) . "
' . sprintf( /* translators: %s: Support forums URL. */ __( 'If you are unsure what these terms mean you should probably contact your host. If you still need help you can always visit the WordPress support forums.' ), __( 'https://wordpress.org/support/forums/' ) ) . "
\n"; $this->bail( $message, 'db_connect_fail' ); return false; } elseif ( $this->dbh ) { if ( ! $this->has_connected ) { $this->init_charset(); } $this->has_connected = true; $this->set_charset( $this->dbh ); $this->ready = true; $this->set_sql_mode(); $this->select( $this->dbname, $this->dbh ); return true; } return false; } /** * Parses the DB_HOST setting to interpret it for mysqli_real_connect(). * * mysqli_real_connect() doesn't support the host param including a port or socket * like mysql_connect() does. This duplicates how mysql_connect() detects a port * and/or socket file. * * @since 4.9.0 * * @param string $host The DB_HOST setting to parse. * @return array|false { * Array containing the host, the port, the socket and * whether it is an IPv6 address, in that order. * False if the host couldn't be parsed. * * @type string $0 Host name. * @type string|null $1 Port. * @type string|null $2 Socket. * @type bool $3 Whether it is an IPv6 address. * } */ public function parse_db_host( $host ) { $socket = null; $is_ipv6 = false; // First peel off the socket parameter from the right, if it exists. $socket_pos = strpos( $host, ':/' ); if ( false !== $socket_pos ) { $socket = substr( $host, $socket_pos + 1 ); $host = substr( $host, 0, $socket_pos ); } /* * We need to check for an IPv6 address first. * An IPv6 address will always contain at least two colons. */ if ( substr_count( $host, ':' ) > 1 ) { $pattern = '#^(?:\[)?(?P' . sprintf(
/* translators: %s: Database host. */
__( 'This means that the contact with the database server at %s was lost. This could mean your host’s database server is down.' ),
'' . htmlspecialchars( $this->dbhost, ENT_QUOTES ) . ''
) . "
' . sprintf( /* translators: %s: Support forums URL. */ __( 'If you are unsure what these terms mean you should probably contact your host. If you still need help you can always visit the WordPress support forums.' ), __( 'https://wordpress.org/support/forums/' ) ) . "
\n"; // We weren't able to reconnect, so we better bail. $this->bail( $message, 'db_connect_fail' ); /* * Call dead_db() if bail didn't die, because this database is no more. * It has ceased to be (at least temporarily). */ dead_db(); } /** * Performs a database query, using current database connection. * * More information can be found on the documentation page. * * @since 0.71 * * @link https://developer.wordpress.org/reference/classes/wpdb/ * * @param string $query Database query. * @return int|bool Boolean true for CREATE, ALTER, TRUNCATE and DROP queries. Number of rows * affected/selected for all other queries. Boolean false on error. */ public function query( $query ) { if ( ! $this->ready ) { $this->check_current_query = true; return false; } /** * Filters the database query. * * Some queries are made before the plugins have been loaded, * and thus cannot be filtered with this method. * * @since 2.1.0 * * @param string $query Database query. */ $query = apply_filters( 'query', $query ); if ( ! $query ) { $this->insert_id = 0; return false; } $this->flush(); // Log how the function was called. $this->func_call = "\$db->query(\"$query\")"; // If we're writing to the database, make sure the query will write safely. if ( $this->check_current_query && ! $this->check_ascii( $query ) ) { $stripped_query = $this->strip_invalid_text_from_query( $query ); /* * strip_invalid_text_from_query() can perform queries, so we need * to flush again, just to make sure everything is clear. */ $this->flush(); if ( $stripped_query !== $query ) { $this->insert_id = 0; $this->last_query = $query; wp_load_translations_early(); $this->last_error = __( 'WordPress database error: Could not perform query because it contains invalid data.' ); return false; } } $this->check_current_query = true; // Keep track of the last query for debug. $this->last_query = $query; $this->_do_query( $query ); // Database server has gone away, try to reconnect. $mysql_errno = 0; if ( $this->dbh instanceof mysqli ) { $mysql_errno = mysqli_errno( $this->dbh ); } else { /* * $dbh is defined, but isn't a real connection. * Something has gone horribly wrong, let's try a reconnect. */ $mysql_errno = 2006; } if ( empty( $this->dbh ) || 2006 === $mysql_errno ) { if ( $this->check_connection() ) { $this->_do_query( $query ); } else { $this->insert_id = 0; return false; } } // If there is an error then take note of it. if ( $this->dbh instanceof mysqli ) { $this->last_error = mysqli_error( $this->dbh ); } else { $this->last_error = __( 'Unable to retrieve the error message from the database server' ); } if ( $this->last_error ) { // Clear insert_id on a subsequent failed insert. if ( $this->insert_id && preg_match( '/^\s*(insert|replace)\s/i', $query ) ) { $this->insert_id = 0; } $this->print_error(); return false; } if ( preg_match( '/^\s*(create|alter|truncate|drop)\s/i', $query ) ) { $return_val = $this->result; } elseif ( preg_match( '/^\s*(insert|delete|update|replace)\s/i', $query ) ) { $this->rows_affected = mysqli_affected_rows( $this->dbh ); // Take note of the insert_id. if ( preg_match( '/^\s*(insert|replace)\s/i', $query ) ) { $this->insert_id = mysqli_insert_id( $this->dbh ); } // Return number of rows affected. $return_val = $this->rows_affected; } else { $num_rows = 0; if ( $this->result instanceof mysqli_result ) { while ( $row = mysqli_fetch_object( $this->result ) ) { $this->last_result[ $num_rows ] = $row; ++$num_rows; } } // Log and return the number of rows selected. $this->num_rows = $num_rows; $return_val = $num_rows; } return $return_val; } /** * Internal function to perform the mysqli_query() call. * * @since 3.9.0 * * @see wpdb::query() * * @param string $query The query to run. */ private function _do_query( $query ) { if ( defined( 'SAVEQUERIES' ) && SAVEQUERIES ) { $this->timer_start(); } if ( ! empty( $this->dbh ) ) { $this->result = mysqli_query( $this->dbh, $query ); } ++$this->num_queries; if ( defined( 'SAVEQUERIES' ) && SAVEQUERIES ) { $this->log_query( $query, $this->timer_stop(), $this->get_caller(), $this->time_start, array() ); } } /** * Logs query data. * * @since 5.3.0 * * @param string $query The query's SQL. * @param float $query_time Total time spent on the query, in seconds. * @param string $query_callstack Comma-separated list of the calling functions. * @param float $query_start Unix timestamp of the time at the start of the query. * @param array $query_data Custom query data. */ public function log_query( $query, $query_time, $query_callstack, $query_start, $query_data ) { /** * Filters the custom data to log alongside a query. * * Caution should be used when modifying any of this data, it is recommended that any additional * information you need to store about a query be added as a new associative array element. * * @since 5.3.0 * * @param array $query_data Custom query data. * @param string $query The query's SQL. * @param float $query_time Total time spent on the query, in seconds. * @param string $query_callstack Comma-separated list of the calling functions. * @param float $query_start Unix timestamp of the time at the start of the query. */ $query_data = apply_filters( 'log_query_custom_data', $query_data, $query, $query_time, $query_callstack, $query_start ); $this->queries[] = array( $query, $query_time, $query_callstack, $query_start, $query_data, ); } /** * Generates and returns a placeholder escape string for use in queries returned by ::prepare(). * * @since 4.8.3 * * @return string String to escape placeholders. */ public function placeholder_escape() { static $placeholder; if ( ! $placeholder ) { // Old WP installs may not have AUTH_SALT defined. $salt = defined( 'AUTH_SALT' ) && AUTH_SALT ? AUTH_SALT : (string) rand(); $placeholder = '{' . hash_hmac( 'sha256', uniqid( $salt, true ), $salt ) . '}'; } /* * Add the filter to remove the placeholder escaper. Uses priority 0, so that anything * else attached to this filter will receive the query with the placeholder string removed. */ if ( false === has_filter( 'query', array( $this, 'remove_placeholder_escape' ) ) ) { add_filter( 'query', array( $this, 'remove_placeholder_escape' ), 0 ); } return $placeholder; } /** * Adds a placeholder escape string, to escape anything that resembles a printf() placeholder. * * @since 4.8.3 * * @param string $query The query to escape. * @return string The query with the placeholder escape string inserted where necessary. */ public function add_placeholder_escape( $query ) { /* * To prevent returning anything that even vaguely resembles a placeholder, * we clobber every % we can find. */ return str_replace( '%', $this->placeholder_escape(), $query ); } /** * Removes the placeholder escape strings from a query. * * @since 4.8.3 * * @param string $query The query from which the placeholder will be removed. * @return string The query with the placeholder removed. */ public function remove_placeholder_escape( $query ) { return str_replace( $this->placeholder_escape(), '%', $query ); } /** * Inserts a row into the table. * * Examples: * * $wpdb->insert( * 'table', * array( * 'column1' => 'foo', * 'column2' => 'bar', * ) * ); * $wpdb->insert( * 'table', * array( * 'column1' => 'foo', * 'column2' => 1337, * ), * array( * '%s', * '%d', * ) * ); * * @since 2.5.0 * * @see wpdb::prepare() * @see wpdb::$field_types * @see wp_set_wpdb_vars() * * @param string $table Table name. * @param array $data Data to insert (in column => value pairs). * Both `$data` columns and `$data` values should be "raw" (neither should be SQL escaped). * Sending a null value will cause the column to be set to NULL - the corresponding * format is ignored in this case. * @param string[]|string $format Optional. An array of formats to be mapped to each of the value in `$data`. * If string, that format will be used for all of the values in `$data`. * A format is one of '%d', '%f', '%s' (integer, float, string). * If omitted, all values in `$data` will be treated as strings unless otherwise * specified in wpdb::$field_types. Default null. * @return int|false The number of rows inserted, or false on error. */ public function insert( $table, $data, $format = null ) { return $this->_insert_replace_helper( $table, $data, $format, 'INSERT' ); } /** * Replaces a row in the table or inserts it if it does not exist, based on a PRIMARY KEY or a UNIQUE index. * * A REPLACE works exactly like an INSERT, except that if an old row in the table has the same value as a new row * for a PRIMARY KEY or a UNIQUE index, the old row is deleted before the new row is inserted. * * Examples: * * $wpdb->replace( * 'table', * array( * 'ID' => 123, * 'column1' => 'foo', * 'column2' => 'bar', * ) * ); * $wpdb->replace( * 'table', * array( * 'ID' => 456, * 'column1' => 'foo', * 'column2' => 1337, * ), * array( * '%d', * '%s', * '%d', * ) * ); * * @since 3.0.0 * * @see wpdb::prepare() * @see wpdb::$field_types * @see wp_set_wpdb_vars() * * @param string $table Table name. * @param array $data Data to insert (in column => value pairs). * Both `$data` columns and `$data` values should be "raw" (neither should be SQL escaped). * A primary key or unique index is required to perform a replace operation. * Sending a null value will cause the column to be set to NULL - the corresponding * format is ignored in this case. * @param string[]|string $format Optional. An array of formats to be mapped to each of the value in `$data`. * If string, that format will be used for all of the values in `$data`. * A format is one of '%d', '%f', '%s' (integer, float, string). * If omitted, all values in `$data` will be treated as strings unless otherwise * specified in wpdb::$field_types. Default null. * @return int|false The number of rows affected, or false on error. */ public function replace( $table, $data, $format = null ) { return $this->_insert_replace_helper( $table, $data, $format, 'REPLACE' ); } /** * Helper function for insert and replace. * * Runs an insert or replace query based on `$type` argument. * * @since 3.0.0 * * @see wpdb::prepare() * @see wpdb::$field_types * @see wp_set_wpdb_vars() * * @param string $table Table name. * @param array $data Data to insert (in column => value pairs). * Both `$data` columns and `$data` values should be "raw" (neither should be SQL escaped). * Sending a null value will cause the column to be set to NULL - the corresponding * format is ignored in this case. * @param string[]|string $format Optional. An array of formats to be mapped to each of the value in `$data`. * If string, that format will be used for all of the values in `$data`. * A format is one of '%d', '%f', '%s' (integer, float, string). * If omitted, all values in `$data` will be treated as strings unless otherwise * specified in wpdb::$field_types. Default null. * @param string $type Optional. Type of operation. Either 'INSERT' or 'REPLACE'. * Default 'INSERT'. * @return int|false The number of rows affected, or false on error. */ public function _insert_replace_helper( $table, $data, $format = null, $type = 'INSERT' ) { $this->insert_id = 0; if ( ! in_array( strtoupper( $type ), array( 'REPLACE', 'INSERT' ), true ) ) { return false; } $data = $this->process_fields( $table, $data, $format ); if ( false === $data ) { return false; } $formats = array(); $values = array(); foreach ( $data as $value ) { if ( is_null( $value['value'] ) ) { $formats[] = 'NULL'; continue; } $formats[] = $value['format']; $values[] = $value['value']; } $fields = '`' . implode( '`, `', array_keys( $data ) ) . '`'; $formats = implode( ', ', $formats ); $sql = "$type INTO `$table` ($fields) VALUES ($formats)"; $this->check_current_query = false; return $this->query( $this->prepare( $sql, $values ) ); } /** * Updates a row in the table. * * Examples: * * $wpdb->update( * 'table', * array( * 'column1' => 'foo', * 'column2' => 'bar', * ), * array( * 'ID' => 1, * ) * ); * $wpdb->update( * 'table', * array( * 'column1' => 'foo', * 'column2' => 1337, * ), * array( * 'ID' => 1, * ), * array( * '%s', * '%d', * ), * array( * '%d', * ) * ); * * @since 2.5.0 * * @see wpdb::prepare() * @see wpdb::$field_types * @see wp_set_wpdb_vars() * * @param string $table Table name. * @param array $data Data to update (in column => value pairs). * Both $data columns and $data values should be "raw" (neither should be SQL escaped). * Sending a null value will cause the column to be set to NULL - the corresponding * format is ignored in this case. * @param array $where A named array of WHERE clauses (in column => value pairs). * Multiple clauses will be joined with ANDs. * Both $where columns and $where values should be "raw". * Sending a null value will create an IS NULL comparison - the corresponding * format will be ignored in this case. * @param string[]|string $format Optional. An array of formats to be mapped to each of the values in $data. * If string, that format will be used for all of the values in $data. * A format is one of '%d', '%f', '%s' (integer, float, string). * If omitted, all values in $data will be treated as strings unless otherwise * specified in wpdb::$field_types. Default null. * @param string[]|string $where_format Optional. An array of formats to be mapped to each of the values in $where. * If string, that format will be used for all of the items in $where. * A format is one of '%d', '%f', '%s' (integer, float, string). * If omitted, all values in $where will be treated as strings unless otherwise * specified in wpdb::$field_types. Default null. * @return int|false The number of rows updated, or false on error. */ public function update( $table, $data, $where, $format = null, $where_format = null ) { if ( ! is_array( $data ) || ! is_array( $where ) ) { return false; } $data = $this->process_fields( $table, $data, $format ); if ( false === $data ) { return false; } $where = $this->process_fields( $table, $where, $where_format ); if ( false === $where ) { return false; } $fields = array(); $conditions = array(); $values = array(); foreach ( $data as $field => $value ) { if ( is_null( $value['value'] ) ) { $fields[] = "`$field` = NULL"; continue; } $fields[] = "`$field` = " . $value['format']; $values[] = $value['value']; } foreach ( $where as $field => $value ) { if ( is_null( $value['value'] ) ) { $conditions[] = "`$field` IS NULL"; continue; } $conditions[] = "`$field` = " . $value['format']; $values[] = $value['value']; } $fields = implode( ', ', $fields ); $conditions = implode( ' AND ', $conditions ); $sql = "UPDATE `$table` SET $fields WHERE $conditions"; $this->check_current_query = false; return $this->query( $this->prepare( $sql, $values ) ); } /** * Deletes a row in the table. * * Examples: * * $wpdb->delete( * 'table', * array( * 'ID' => 1, * ) * ); * $wpdb->delete( * 'table', * array( * 'ID' => 1, * ), * array( * '%d', * ) * ); * * @since 3.4.0 * * @see wpdb::prepare() * @see wpdb::$field_types * @see wp_set_wpdb_vars() * * @param string $table Table name. * @param array $where A named array of WHERE clauses (in column => value pairs). * Multiple clauses will be joined with ANDs. * Both $where columns and $where values should be "raw". * Sending a null value will create an IS NULL comparison - the corresponding * format will be ignored in this case. * @param string[]|string $where_format Optional. An array of formats to be mapped to each of the values in $where. * If string, that format will be used for all of the items in $where. * A format is one of '%d', '%f', '%s' (integer, float, string). * If omitted, all values in $where will be treated as strings unless otherwise * specified in wpdb::$field_types. Default null. * @return int|false The number of rows deleted, or false on error. */ public function delete( $table, $where, $where_format = null ) { if ( ! is_array( $where ) ) { return false; } $where = $this->process_fields( $table, $where, $where_format ); if ( false === $where ) { return false; } $conditions = array(); $values = array(); foreach ( $where as $field => $value ) { if ( is_null( $value['value'] ) ) { $conditions[] = "`$field` IS NULL"; continue; } $conditions[] = "`$field` = " . $value['format']; $values[] = $value['value']; } $conditions = implode( ' AND ', $conditions ); $sql = "DELETE FROM `$table` WHERE $conditions"; $this->check_current_query = false; return $this->query( $this->prepare( $sql, $values ) ); } /** * Processes arrays of field/value pairs and field formats. * * This is a helper method for wpdb's CRUD methods, which take field/value pairs * for inserts, updates, and where clauses. This method first pairs each value * with a format. Then it determines the charset of that field, using that * to determine if any invalid text would be stripped. If text is stripped, * then field processing is rejected and the query fails. * * @since 4.2.0 * * @param string $table Table name. * @param array $data Array of values keyed by their field names. * @param string[]|string $format Formats or format to be mapped to the values in the data. * @return array|false An array of fields that contain paired value and formats. * False for invalid values. */ protected function process_fields( $table, $data, $format ) { $data = $this->process_field_formats( $data, $format ); if ( false === $data ) { return false; } $data = $this->process_field_charsets( $data, $table ); if ( false === $data ) { return false; } $data = $this->process_field_lengths( $data, $table ); if ( false === $data ) { return false; } $converted_data = $this->strip_invalid_text( $data ); if ( $data !== $converted_data ) { $problem_fields = array(); foreach ( $data as $field => $value ) { if ( $value !== $converted_data[ $field ] ) { $problem_fields[] = $field; } } wp_load_translations_early(); if ( 1 === count( $problem_fields ) ) { $this->last_error = sprintf( /* translators: %s: Database field where the error occurred. */ __( 'WordPress database error: Processing the value for the following field failed: %s. The supplied value may be too long or contains invalid data.' ), reset( $problem_fields ) ); } else { $this->last_error = sprintf( /* translators: %s: Database fields where the error occurred. */ __( 'WordPress database error: Processing the values for the following fields failed: %s. The supplied values may be too long or contain invalid data.' ), implode( ', ', $problem_fields ) ); } return false; } return $data; } /** * Prepares arrays of value/format pairs as passed to wpdb CRUD methods. * * @since 4.2.0 * * @param array $data Array of values keyed by their field names. * @param string[]|string $format Formats or format to be mapped to the values in the data. * @return array { * Array of values and formats keyed by their field names. * * @type array ...$0 { * Value and format for this field. * * @type mixed $value The value to be formatted. * @type string $format The format to be mapped to the value. * } * } */ protected function process_field_formats( $data, $format ) { $formats = (array) $format; $original_formats = $formats; foreach ( $data as $field => $value ) { $value = array( 'value' => $value, 'format' => '%s', ); if ( ! empty( $format ) ) { $value['format'] = array_shift( $formats ); if ( ! $value['format'] ) { $value['format'] = reset( $original_formats ); } } elseif ( isset( $this->field_types[ $field ] ) ) { $value['format'] = $this->field_types[ $field ]; } $data[ $field ] = $value; } return $data; } /** * Adds field charsets to field/value/format arrays generated by wpdb::process_field_formats(). * * @since 4.2.0 * * @param array $data { * Array of values and formats keyed by their field names, * as it comes from the wpdb::process_field_formats() method. * * @type array ...$0 { * Value and format for this field. * * @type mixed $value The value to be formatted. * @type string $format The format to be mapped to the value. * } * } * @param string $table Table name. * @return array|false { * The same array of data with additional 'charset' keys, or false if * the charset for the table cannot be found. * * @type array ...$0 { * Value, format, and charset for this field. * * @type mixed $value The value to be formatted. * @type string $format The format to be mapped to the value. * @type string|false $charset The charset to be used for the value. * } * } */ protected function process_field_charsets( $data, $table ) { foreach ( $data as $field => $value ) { if ( '%d' === $value['format'] || '%f' === $value['format'] ) { /* * We can skip this field if we know it isn't a string. * This checks %d/%f versus ! %s because its sprintf() could take more. */ $value['charset'] = false; } else { $value['charset'] = $this->get_col_charset( $table, $field ); if ( is_wp_error( $value['charset'] ) ) { return false; } } $data[ $field ] = $value; } return $data; } /** * For string fields, records the maximum string length that field can safely save. * * @since 4.2.1 * * @param array $data { * Array of values, formats, and charsets keyed by their field names, * as it comes from the wpdb::process_field_charsets() method. * * @type array ...$0 { * Value, format, and charset for this field. * * @type mixed $value The value to be formatted. * @type string $format The format to be mapped to the value. * @type string|false $charset The charset to be used for the value. * } * } * @param string $table Table name. * @return array|false { * The same array of data with additional 'length' keys, or false if * information for the table cannot be found. * * @type array ...$0 { * Value, format, charset, and length for this field. * * @type mixed $value The value to be formatted. * @type string $format The format to be mapped to the value. * @type string|false $charset The charset to be used for the value. * @type array|false $length { * Information about the maximum length of the value. * False if the column has no length. * * @type string $type One of 'byte' or 'char'. * @type int $length The column length. * } * } * } */ protected function process_field_lengths( $data, $table ) { foreach ( $data as $field => $value ) { if ( '%d' === $value['format'] || '%f' === $value['format'] ) { /* * We can skip this field if we know it isn't a string. * This checks %d/%f versus ! %s because its sprintf() could take more. */ $value['length'] = false; } else { $value['length'] = $this->get_col_length( $table, $field ); if ( is_wp_error( $value['length'] ) ) { return false; } } $data[ $field ] = $value; } return $data; } /** * Retrieves one value from the database. * * Executes a SQL query and returns the value from the SQL result. * If the SQL result contains more than one column and/or more than one row, * the value in the column and row specified is returned. If $query is null, * the value in the specified column and row from the previous SQL result is returned. * * Returns null both on failure and when the matched cell value is an empty * string. To distinguish the two cases, check {@see self::$last_error}. * * @since 0.71 * * @param string|null $query Optional. SQL query. Defaults to null, use the result from the previous query. * @param int $x Optional. Column of value to return. Indexed from 0. Default 0. * @param int $y Optional. Row of value to return. Indexed from 0. Default 0. * @return string|null Database query result (as string), or null on failure or when the value is an empty string. * @phpstan-return non-empty-string|null */ public function get_var( $query = null, $x = 0, $y = 0 ) { $this->func_call = "\$db->get_var(\"$query\", $x, $y)"; if ( $query ) { if ( $this->check_current_query && $this->check_safe_collation( $query ) ) { $this->check_current_query = false; } $this->query( $query ); } // Extract var out of cached results based on x,y vals. if ( ! empty( $this->last_result[ $y ] ) ) { /** * Column values. * * These are returned from the database as strings, or null for SQL NULL, but get_object_vars() types the * property values as mixed. * * @var list' . $error . "