ecution_time = 0;
}
// Leave 1 second "buffer" for other operations if $max_execution_time has reasonable value.
if ( $max_execution_time > 10 ) {
$max_execution_time -= 1;
}
}
/**
* Filters the amount of storage space used by one directory and all its children, in megabytes.
*
* Return the actual used space to short-circuit the recursive PHP file size calculation
* and use something else, like a CDN API or native operating system tools for better performance.
*
* @since 5.6.0
*
* @param int|false $space_used The amount of used space, in bytes. Default false.
* @param string $directory Full path of a directory.
* @param string|string[]|null $exclude Full path of a subdirectory to exclude from the total,
* or array of paths.
* @param int $max_execution_time Maximum time to run before giving up. In seconds.
* @param array $directory_cache Array of cached directory paths.
*/
$size = apply_filters( 'pre_recurse_dirsize', false, $directory, $exclude, $max_execution_time, $directory_cache );
if ( false === $size ) {
$size = 0;
$handle = opendir( $directory );
if ( $handle ) {
while ( ( $file = readdir( $handle ) ) !== false ) {
$path = $directory . '/' . $file;
if ( '.' !== $file && '..' !== $file ) {
if ( is_file( $path ) ) {
$size += filesize( $path );
} elseif ( is_dir( $path ) ) {
$handlesize = recurse_dirsize( $path, $exclude, $max_execution_time, $directory_cache );
if ( $handlesize > 0 ) {
$size += $handlesize;
}
}
if ( $max_execution_time > 0 &&
( microtime( true ) - WP_START_TIMESTAMP ) > $max_execution_time
) {
// Time exceeded. Give up instead of risking a fatal timeout.
$size = null;
break;
}
}
}
closedir( $handle );
}
}
if ( ! is_array( $directory_cache ) ) {
$directory_cache = array();
}
$directory_cache[ $directory ] = $size;
// Only write the transient on the top level call and not on recursive calls.
if ( $save_cache ) {
$expiration = ( wp_using_ext_object_cache() ) ? 0 : 10 * YEAR_IN_SECONDS;
set_transient( 'dirsize_cache', $directory_cache, $expiration );
}
return $size;
}
/**
* Cleans directory size cache used by recurse_dirsize().
*
* Removes the current directory and all parent directories from the `dirsize_cache` transient.
*
* @since 5.6.0
* @since 5.9.0 Added input validation with a notice for invalid input.
*
* @param string $path Full path of a directory or file.
*/
function clean_dirsize_cache( $path ) {
if ( ! is_string( $path ) || empty( $path ) ) {
wp_trigger_error(
'',
sprintf(
/* translators: 1: Function name, 2: A variable type, like "boolean" or "integer". */
__( '%1$s only accepts a non-empty path string, received %2$s.' ),
'clean_dirsize_cache()
',
'' . gettype( $path ) . '
'
)
);
return;
}
$directory_cache = get_transient( 'dirsize_cache' );
if ( empty( $directory_cache ) ) {
return;
}
$expiration = ( wp_using_ext_object_cache() ) ? 0 : 10 * YEAR_IN_SECONDS;
if (
! str_contains( $path, '/' ) &&
! str_contains( $path, '\\' )
) {
unset( $directory_cache[ $path ] );
set_transient( 'dirsize_cache', $directory_cache, $expiration );
return;
}
$last_path = null;
$path = untrailingslashit( $path );
unset( $directory_cache[ $path ] );
while (
$last_path !== $path &&
DIRECTORY_SEPARATOR !== $path &&
'.' !== $path &&
'..' !== $path
) {
$last_path = $path;
$path = dirname( $path );
unset( $directory_cache[ $path ] );
}
set_transient( 'dirsize_cache', $directory_cache, $expiration );
}
/**
* Checks compatibility with the current WordPress version.
*
* @since 5.2.0
*
* @global string $wp_version The WordPress version string.
*
* @param string $required Minimum required WordPress version.
* @return bool True if required version is compatible or empty, false if not.
*/
function is_wp_version_compatible( $required ) {
global $wp_version;
// Strip off any -alpha, -RC, -beta, -src suffixes.
list( $version ) = explode( '-', $wp_version );
if ( is_string( $required ) ) {
$trimmed = trim( $required );
if ( substr_count( $trimmed, '.' ) > 1 && str_ends_with( $trimmed, '.0' ) ) {
$required = substr( $trimmed, 0, -2 );
}
}
return empty( $required ) || version_compare( $version, $required, '>=' );
}
/**
* Checks compatibility with the current PHP version.
*
* @since 5.2.0
*
* @param string $required Minimum required PHP version.
* @return bool True if required version is compatible or empty, false if not.
*/
function is_php_version_compatible( $required ) {
return empty( $required ) || version_compare( PHP_VERSION, $required, '>=' );
}
/**
* Checks if two numbers are nearly the same.
*
* This is similar to using `round()` but the precision is more fine-grained.
*
* @since 5.3.0
*
* @param int|float $expected The expected value.
* @param int|float $actual The actual number.
* @param int|float $precision Optional. The allowed variation. Default 1.
* @return bool Whether the numbers match within the specified precision.
*/
function wp_fuzzy_number_match( $expected, $actual, $precision = 1 ) {
return abs( (float) $expected - (float) $actual ) <= $precision;
}
/**
* Creates and returns the markup for an admin notice.
*
* @since 6.4.0
*
* @param string $message The message.
* @param array $args {
* Optional. An array of arguments for the admin notice. Default empty array.
*
* @type string $type Optional. The type of admin notice.
* For example, 'error', 'success', 'warning', 'info'.
* Default empty string.
* @type bool $dismissible Optional. Whether the admin notice is dismissible. Default false.
* @type string $id Optional. The value of the admin notice's ID attribute. Default empty string.
* @type string[] $additional_classes Optional. A string array of class names. Default empty array.
* @type string[] $attributes Optional. Additional attributes for the notice div. Default empty array.
* @type bool $paragraph_wrap Optional. Whether to wrap the message in paragraph tags. Default true.
* }
* @return string The markup for an admin notice.
*/
function wp_get_admin_notice( $message, $args = array() ) {
$defaults = array(
'type' => '',
'dismissible' => false,
'id' => '',
'additional_classes' => array(),
'attributes' => array(),
'paragraph_wrap' => true,
);
$args = wp_parse_args( $args, $defaults );
/**
* Filters the arguments for an admin notice.
*
* @since 6.4.0
*
* @param array $args The arguments for the admin notice.
* @param string $message The message for the admin notice.
*/
$args = apply_filters( 'wp_admin_notice_args', $args, $message );
$id = '';
$classes = 'notice';
$attributes = '';
if ( is_string( $args['id'] ) ) {
$trimmed_id = trim( $args['id'] );
if ( '' !== $trimmed_id ) {
$id = 'id="' . $trimmed_id . '" ';
}
}
if ( is_string( $args['type'] ) ) {
$type = trim( $args['type'] );
if ( str_contains( $type, ' ' ) ) {
_doing_it_wrong(
__FUNCTION__,
sprintf(
/* translators: %s: The "type" key. */
__( 'The %s key must be a string without spaces.' ),
'type
'
),
'6.4.0'
);
}
if ( '' !== $type ) {
$classes .= ' notice-' . $type;
}
}
if ( true === $args['dismissible'] ) {
$classes .= ' is-dismissible';
}
if ( is_array( $args['additional_classes'] ) && ! empty( $args['additional_classes'] ) ) {
$classes .= ' ' . implode( ' ', $args['additional_classes'] );
}
if ( is_array( $args['attributes'] ) && ! empty( $args['attributes'] ) ) {
$attributes = '';
foreach ( $args['attributes'] as $attr => $val ) {
if ( is_bool( $val ) ) {
$attributes .= $val ? ' ' . $attr : '';
} elseif ( is_int( $attr ) ) {
$attributes .= ' ' . esc_attr( trim( $val ) );
} elseif ( $val ) {
$attributes .= ' ' . $attr . '="' . esc_attr( trim( $val ) ) . '"';
}
}
}
if ( false !== $args['paragraph_wrap'] ) {
$message = "
$message
";
}
$markup = sprintf( '%4$s
', $id, $classes, $attributes, $message );
/**
* Filters the markup for an admin notice.
*
* @since 6.4.0
*
* @param string $markup The HTML markup for the admin notice.
* @param string $message The message for the admin notice.
* @param array $args The arguments for the admin notice.
*/
return apply_filters( 'wp_admin_notice_markup', $markup, $message, $args );
}
/**
* Outputs an admin notice.
*
* @since 6.4.0
*
* @param string $message The message to output.
* @param array $args {
* Optional. An array of arguments for the admin notice. Default empty array.
*
* @type string $type Optional. The type of admin notice.
* For example, 'error', 'success', 'warning', 'info'.
* Default empty string.
* @type bool $dismissible Optional. Whether the admin notice is dismissible. Default false.
* @type string $id Optional. The value of the admin notice's ID attribute. Default empty string.
* @type string[] $additional_classes Optional. A string array of class names. Default empty array.
* @type string[] $attributes Optional. Additional attributes for the notice div. Default empty array.
* @type bool $paragraph_wrap Optional. Whether to wrap the message in paragraph tags. Default true.
* }
*/
function wp_admin_notice( $message, $args = array() ) {
/**
* Fires before an admin notice is output.
*
* @since 6.4.0
*
* @param string $message The message for the admin notice.
* @param array $args The arguments for the admin notice.
*/
do_action( 'wp_admin_notice', $message, $args );
echo wp_kses_post( wp_get_admin_notice( $message, $args ) );
}
re_format Format where.
*
* @return int|false
*/
public function delete( $table, $where, $where_format = null ) {
$group = $this->_get_group( $table );
$this->_flush_cache_for_sql_group( $group, array( 'wpdb_delete' => $table ) );
return $this->next_injection->delete( $table, $where, $where_format );
}
/**
* Flushes cache.
*
* @param array $extras Extra arguments.
*
* @return bool
*/
public function flush_cache( $extras = array() ) {
return $this->_flush_cache_for_sql_group( 'remaining', $extras );
}
/**
* Flush cache for SQL groups.
*
* @access private
*
* @param string $group Group.
* @param array $extras Extra arguments.
*
* @return bool
*/
private function _flush_cache_for_sql_group( $group, $extras = array() ) {
$this->wpdb_mixin->timer_start();
if ( $this->debug ) {
$filename = Util_Debug::log(
'dbcache',
'flushing based on sqlquery group ' . $group .
' with extras ' . wp_json_encode( $extras )
);
}
if ( $this->_config->get_boolean( 'dbcache.debug_purge' ) ) {
Util_Debug::log_purge(
'dbcache',
'_flush_cache_for_sql_group',
array( $group, $extras )
);
}
$cache = $this->_get_cache();
$flush_groups = $this->_get_flush_groups( $group, $extras );
$v = true;
$this->cache_flushes++;
foreach ( $flush_groups as $f_group => $nothing ) {
if ( $this->debug ) {
$filename = Util_Debug::log( 'dbcache', 'flush group ' . $f_group );
}
$v &= $cache->flush( $f_group );
}
$this->time_total += $this->wpdb_mixin->timer_stop();
return $v;
}
/**
* Returns cache object.
*
* @return W3_Cache_Base
*/
public function _get_cache() {
static $cache = array();
if ( ! isset( $cache[0] ) ) {
$engine = $this->_config->get_string( 'dbcache.engine' );
switch ( $engine ) {
case 'memcached':
$engine_config = array(
'servers' => $this->_config->get_array( 'dbcache.memcached.servers' ),
'persistent' => $this->_config->get_boolean( 'dbcache.memcached.persistent' ),
'aws_autodiscovery' => $this->_config->get_boolean( 'dbcache.memcached.aws_autodiscovery' ),
'username' => $this->_config->get_string( 'dbcache.memcached.username' ),
'password' => $this->_config->get_string( 'dbcache.memcached.password' ),
'binary_protocol' => $this->_config->get_boolean( 'dbcache.memcached.binary_protocol' ),
);
break;
case 'redis':
$engine_config = array(
'servers' => $this->_config->get_array( 'dbcache.redis.servers' ),
'verify_tls_certificates' => $this->_config->get_boolean( 'dbcache.redis.verify_tls_certificates' ),
'persistent' => $this->_config->get_boolean( 'dbcache.redis.persistent' ),
'timeout' => $this->_config->get_integer( 'dbcache.redis.timeout' ),
'retry_interval' => $this->_config->get_integer( 'dbcache.redis.retry_interval' ),
'read_timeout' => $this->_config->get_integer( 'dbcache.redis.read_timeout' ),
'dbid' => $this->_config->get_integer( 'dbcache.redis.dbid' ),
'password' => $this->_config->get_string( 'dbcache.redis.password' ),
);
break;
case 'file':
$engine_config = array(
'use_wp_hash' => true,
'section' => 'db',
'locking' => $this->_config->get_boolean( 'dbcache.file.locking' ),
'flush_timelimit' => $this->_config->get_integer( 'timelimit.cache_flush' ),
);
break;
default:
$engine_config = array();
}
$engine_config['module'] = 'dbcache';
$engine_config['host'] = Util_Environment::host();
$engine_config['instance_id'] = Util_Environment::instance_id();
$cache[0] = Cache::instance( $engine, $engine_config );
}
return $cache[0];
}
/**
* Check if can cache sql.
*
* @param string $sql SQL query.
* @param string $cache_reject_reason Cache reject reason.
*
* @return boolean
*/
public function _can_cache( $sql, &$cache_reject_reason ) {
/**
* Skip if request-wide reject reason specified.
* Note - as a result requedt-wide checks are done only once per request.
*/
if ( ! is_null( $this->cache_reject_reason ) ) {
$cache_reject_reason = $this->cache_reject_reason;
$this->cache_reject_request_wide = true;
return false;
}
/**
* Do once-per-request check if needed.
*/
if ( is_null( $this->can_cache_once_per_request_result ) ) {
$this->can_cache_once_per_request_result = $this->_can_cache_once_per_request();
if ( ! $this->can_cache_once_per_request_result ) {
$this->cache_reject_request_wide = true;
return false;
}
}
/**
* Check for constants.
*/
foreach ( $this->reject_constants as $name ) {
if ( defined( $name ) && constant( $name ) ) {
$this->cache_reject_reason = $name . ' constant defined';
$cache_reject_reason = $this->cache_reject_reason;
return false;
}
}
/**
* Check for AJAX requests.
*/
$ajax_skip = false;
if ( defined( 'DOING_AJAX' ) ) {
$http_referer = isset( $_SERVER['HTTP_REFERER'] ) ?
filter_var( stripslashes( $_SERVER['HTTP_REFERER'] ), FILTER_SANITIZE_URL ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput
// wp_admin is always defined for ajax requests, check by referrer.
if ( strpos( $http_referer, '/wp-admin/' ) === false ) {
$ajax_skip = true;
}
}
/**
* Skip if admin.
*/
if ( defined( 'WP_ADMIN' ) && ! $ajax_skip ) {
$this->cache_reject_reason = 'WP_ADMIN';
$cache_reject_reason = $this->cache_reject_reason;
return false;
}
/**
* Skip if SQL is rejected.
*/
if ( ! $this->_check_sql( $sql ) ) {
$cache_reject_reason = 'query not cacheable';
return false;
}
/**
* Skip if user is logged in.
*/
if ( $this->reject_logged && ! $this->_check_logged_in() ) {
$this->cache_reject_reason = 'user.logged_in';
$cache_reject_reason = $this->cache_reject_reason;
return false;
}
return true;
}
/**
* Check if can cache sql, checks which have constant results during whole request.
*
* @return bool
*/
public function _can_cache_once_per_request() {
/**
* Skip if disabled
*/
if ( ! $this->_config->get_boolean( 'dbcache.enabled' ) ) {
$this->cache_reject_reason = 'dbcache.disabled';
return false;
}
/**
* Skip if request URI is rejected
*/
if ( ! $this->_check_request_uri() ) {
$this->cache_reject_reason = 'request';
return false;
}
/**
* Skip if cookie is rejected
*/
if ( ! $this->_check_cookies() ) {
$this->cache_reject_reason = 'cookie';
return false;
}
return true;
}
/**
* Check SQL
*
* @param string $sql SQL query.
*
* @return bool
*/
public function _check_sql( $sql ) {
$auto_reject_strings = $this->_config->get_array( 'dbcache.reject.words' );
if ( preg_match( '~' . implode( '|', $auto_reject_strings ) . '~is', $sql ) ) {
return false;
}
$reject_sql = $this->_config->get_array( 'dbcache.reject.sql' );
foreach ( $reject_sql as $expr ) {
$expr = trim( $expr );
$expr = str_replace( '{prefix}', $this->wpdb_mixin->prefix, $expr );
if ( ! empty( $expr ) && preg_match( '~' . $expr . '~i', $sql ) ) {
return false;
}
}
return true;
}
/**
* Check request URI
*
* @return boolean
*/
public function _check_request_uri() {
$auto_reject_uri = array(
'wp-login',
'wp-register',
);
$request_uri = isset( $_SERVER['REQUEST_URI'] ) ?
filter_var( stripslashes( $_SERVER['REQUEST_URI'] ), FILTER_SANITIZE_URL ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput
foreach ( $auto_reject_uri as $uri ) {
if ( strstr( $request_uri, $uri ) !== false ) {
return false;
}
}
$reject_uri = $this->_config->get_array( 'dbcache.reject.uri' );
$reject_uri = array_map( array( '\W3TC\Util_Environment', 'parse_path' ), $reject_uri );
foreach ( $reject_uri as $expr ) {
$expr = trim( $expr );
if ( ! empty( $expr ) && preg_match( '~' . $expr . '~i', $request_uri ) ) {
return false;
}
}
return true;
}
/**
* Checks for WordPress cookies.
*
* @return bool
*/
public function _check_cookies() {
foreach ( array_keys( $_COOKIE ) as $cookie_name ) {
if ( 'wordpress_test_cookie' === $cookie_name ) {
continue;
}
if ( preg_match( '/^wp-postpass|^comment_author/', $cookie_name ) ) {
return false;
}
}
foreach ( $this->_config->get_array( 'dbcache.reject.cookie' ) as $reject_cookie ) {
foreach ( array_keys( $_COOKIE ) as $cookie_name ) {
if ( strstr( $cookie_name, $reject_cookie ) !== false ) {
return false;
}
}
}
return true;
}
/**
* Check if user is logged in.
*
* @return bool
*/
public function _check_logged_in() {
foreach ( array_keys( $_COOKIE ) as $cookie_name ) {
if ( strpos( $cookie_name, 'wordpress_logged_in' ) === 0 ) {
return false;
}
}
return true;
}
/**
* Get group.
*
* @access private
*
* @param string $sql SQL query.
*
* @return string
*/
private function _get_group( $sql ) {
$sql = strtolower( $sql );
// Collect list of tables used in query.
if ( preg_match_all( '~(^|[\s,`])' . $this->wpdb_mixin->prefix . '([0-9a-zA-Z_]+)~i', $sql, $m ) ) {
$tables = array_unique( $m[2] );
} else {
$tables = array();
}
if ( $this->contains_only_tables( $tables, array( 'options' => '*' ) ) ) {
$group = 'options';
} elseif (
$this->contains_only_tables(
$tables,
array(
'comments' => '*',
'commentsmeta' => '*',
)
) ) {
$group = 'comments';
} elseif ( count( $tables ) <= 1 ) {
$group = 'singletables'; // Request with single table affected.
} else {
$group = 'remaining';
}
if ( $this->use_filters && function_exists( 'apply_filters' ) ) {
$group = apply_filters( 'w3tc_dbcache_get_sql_group', $group, $sql, $tables );
}
return $group;
}
/**
* Contains only tables.
*
* @accress private
*
* @param array $tables Tables.
*
* @param array $allowed Allowed.
*/
private function contains_only_tables( $tables, $allowed ) {
if ( empty( $tables ) ) {
return false;
}
foreach ( $tables as $t ) {
if ( ! isset( $allowed[ $t ] ) ) {
return false;
}
}
return true;
}
/**
* Get flush groups
*
* @access private
*
* @param string $group Group.
*
* @param array $extras Extra arguments.
*/
private function _get_flush_groups( $group, $extras = array() ) {
$groups_to_flush = array();
switch ( $group ) {
case 'remaining':
case 'singletables':
$groups_to_flush = array(
'remaining' => '*',
'options' => '*',
'comments' => '*',
'singletables' => '*',
);
break;
/**
* Options are updated on each second request,
* ignore by default probability that SELECTs with joins with options are critical and don't flush "remaining".
* That can be changed by w3tc_dbcache_get_flush_groups filter.
*/
case 'options':
$groups_to_flush = array( $group => '*' );
break;
default:
$groups_to_flush = array(
$group => '*',
'remaining' => '*',
);
}
if ( $this->use_filters && function_exists( 'apply_filters' ) ) {
$groups_to_flush = apply_filters( 'w3tc_dbcache_get_flush_groups', $groups_to_flush, $group, $extras );
}
return $groups_to_flush;
}
/**
* Get reject reason.
*
* @return string
*/
public function get_reject_reason() {
if ( is_null( $this->cache_reject_reason ) ) {
return '';
}
$request_wide_string = $this->cache_reject_request_wide ?
( function_exists( '__' ) ? __( 'Request-wide ', 'w3-total-cache' ) : 'Request ' ) : '';
return $request_wide_string . $this->_get_reject_reason_message( $this->cache_reject_reason );
}
/**
* Get reject reason message.
*
* @param string $key Key.
*
* @return string|void
*/
private function _get_reject_reason_message( $key ) {
if ( ! function_exists( '__' ) ) {
return $key;
}
switch ( $key ) {
case 'dbcache.disabled':
return __( 'Database caching is disabled', 'w3-total-cache' );
case 'DONOTCACHEDB':
return __( 'DONOTCACHEDB constant is defined', 'w3-total-cache' );
case 'DOING_AJAX':
return __( 'Doing AJAX', 'w3-total-cache' );
case 'request':
return __( 'Request URI is rejected', 'w3-total-cache' );
case 'cookie':
return __( 'Cookie is rejected', 'w3-total-cache' );
case 'DOING_CRONG':
return __( 'Doing cron', 'w3-total-cache' );
case 'APP_REQUEST':
return __( 'Application request', 'w3-total-cache' );
case 'XMLRPC_REQUEST':
return __( 'XMLRPC request', 'w3-total-cache' );
case 'WP_ADMIN':
return __( 'wp-admin', 'w3-total-cache' );
case 'SHORTINIT':
return __( 'Short init', 'w3-total-cache' );
case 'query':
return __( 'Query is rejected', 'w3-total-cache' );
case 'user.logged_in':
return __( 'User is logged in', 'w3-total-cache' );
default:
return $key;
}
}
/**
* Footer comment.
*
* @param array $strings Strings.
*
* @return array
*/
public function w3tc_footer_comment( $strings ) {
$reject_reason = $this->get_reject_reason();
$append = empty( $reject_reason ) ? '' : sprintf( ' (%1$s)', $reject_reason );
if ( $this->query_hits ) {
$strings[] = sprintf(
// translators: 1: Query hits, 2: Total queries, 3: Total time, 4: Engine name, 5: Reject reason.
__( 'Database Caching %1$d/%2$d queries in %3$.3f seconds using %4$s%5$s', 'w3-total-cache' ),
$this->query_hits,
$this->query_total,
$this->time_total,
Cache::engine_name( $this->_config->get_string( 'dbcache.engine' ) ),
$append
);
} else {
$strings[] = sprintf(
// translators: 1: Engine name, 2: Reject reason.
__( 'Database Caching using %1$s%2$s', 'w3-total-cache' ),
Cache::engine_name( $this->_config->get_string( 'dbcache.engine' ) ),
$append
);
}
if ( $this->debug ) {
$strings[] = '';
$strings[] = __( 'Db cache debug info:', 'w3-total-cache' );
$strings[] = sprintf( '%1$s%2$d', str_pad( __( 'Total queries: ', 'w3-total-cache' ), 20 ), $this->query_total );
$strings[] = sprintf( '%1$s%2$d', str_pad( __( 'Cached queries: ', 'w3-total-cache' ), 20 ), $this->query_hits );
$strings[] = sprintf( '%1$s%2$.4f', str_pad( __( 'Total query time: ', 'w3-total-cache' ), 20 ), $this->time_total );
}
if ( $this->log_filehandle ) {
fclose( $this->log_filehandle ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fclose
$this->log_filehandle = false;
}
return $strings;
}
/**
* Usage statistics of request.
*
* @param object $storage Storage object.
*
* @return void
*/
public function w3tc_usage_statistics_of_request( $storage ) {
$storage->counter_add( 'dbcache_calls_total', $this->query_total );
$storage->counter_add( 'dbcache_calls_hits', $this->query_hits );
$storage->counter_add( 'dbcache_flushes', $this->cache_flushes );
$time_ms = (int) ( $this->time_total * 1000 );
$storage->counter_add( 'dbcache_time_ms', $time_ms );
}
/**
* Log query.
*
* @access private
*
* @param string $line Line to add.
*
* @return void
*/
private function log_query( $line ) {
if ( ! $this->log_filehandle ) {
$filename = Util_Debug::log_filename( 'dbcache-queries' );
$this->log_filehandle = fopen( $filename, 'a' ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fopen
}
fputcsv( $this->log_filehandle, $line, "\t" );
}
}