', '', $config );
ob_start();
@eval( $config ); // This eval is OK. Getting site DB connection parameters.
ob_end_clean();
if ( defined( 'DB_USER' ) && defined( 'DB_PASSWORD' ) && defined( 'DB_NAME' ) && defined( 'DB_HOST' ) ) {
require_once( $db_class );
return new wpdb( DB_USER, DB_PASSWORD, DB_NAME, DB_HOST );
}
}
return false;
}
function crb_get_mysql_var( $var ) {
static $cache;
if ( ! isset( $cache[ $var ] ) ) {
if ( $v = cerber_db_get_row( 'SHOW VARIABLES LIKE "' . $var . '"' ) ) {
$cache[ $var ] = $v['Value'];
}
else {
$cache[ $var ] = false;
}
}
return $cache[ $var ];
}
/**
* Retrieve a value from the key-value storage
*
* @param string $key
* @param integer $id
* @param bool $unserialize
* @param bool $use_cache
*
* @return bool|array
*/
function cerber_get_set( $key, $id = null, $unserialize = true, $use_cache = null ) {
if ( ! $key ) {
return false;
}
$key = preg_replace( CRB_SANITIZE_KEY, '', $key );
$cache_key = 'crb#' . $key . '#';
$id = ( $id !== null ) ? absint( $id ) : 0;
$cache_key .= $id;
$ret = false;
$use_cache = ( isset( $use_cache ) ) ? $use_cache : cerber_cache_is_enabled();
if ( $use_cache ) {
$cache_value = cerber_cache_get( $cache_key, null );
if ( $cache_value !== null ) {
return $cache_value;
}
}
if ( $row = cerber_db_get_row( 'SELECT * FROM ' . cerber_get_db_prefix() . CERBER_SETS_TABLE . ' WHERE the_key = "' . $key . '" AND the_id = ' . $id ) ) {
if ( $row['expires'] > 0 && $row['expires'] < time() ) {
cerber_delete_set( $key, $id );
if ( $use_cache ) {
cerber_cache_delete( $cache_key );
}
return false;
}
if ( $unserialize ) {
if ( ! empty( $row['the_value'] ) ) {
$ret = crb_unserialize( $row['the_value'] );
}
else {
$ret = array();
}
}
else {
$ret = $row['the_value'];
}
}
if ( $use_cache ) {
cerber_cache_set( $cache_key, $ret );
}
return $ret;
}
/**
* Update/insert value to the key-value storage
*
* @param string $key A unique key for the data set. Max length is 255.
* @param $value
* @param integer $id An additional numerical key
* @param bool $serialize
* @param integer $expires Unix timestamp (UTC) when this element will be deleted
* @param bool $use_cache
*
* @return bool
*/
function cerber_update_set( $key, $value, $id = null, $serialize = true, $expires = null, $use_cache = null ) {
if ( ! $key ) {
return false;
}
$key = preg_replace( CRB_SANITIZE_KEY, '', $key );
$cache_key = 'crb#' . $key . '#';
$expires = ( $expires !== null ) ? absint( $expires ) : 0;
$id = ( $id !== null ) ? absint( $id ) : 0;
$cache_key .= $id;
$use_cache = ( isset( $use_cache ) ) ? $use_cache : cerber_cache_is_enabled();
if ( $use_cache ) {
cerber_cache_set( $cache_key, $value, $expires - time() );
}
if ( $serialize && ! is_string( $value ) ) {
$value = serialize( $value );
}
$value = cerber_real_escape( $value );
if ( false !== cerber_get_set( $key, $id, false, false ) ) {
$sql = 'UPDATE ' . cerber_get_db_prefix() . CERBER_SETS_TABLE . ' SET the_value = "' . $value . '", expires = ' . $expires . ' WHERE the_key = "' . $key . '" AND the_id = ' . $id;
}
else {
$sql = 'INSERT INTO ' . cerber_get_db_prefix() . CERBER_SETS_TABLE . ' (the_key, the_id, the_value, expires) VALUES ("' . $key . '",' . $id . ',"' . $value . '",' . $expires . ')';
}
unset( $value );
if ( cerber_db_query( $sql ) ) {
return true;
}
else {
return false;
}
}
/**
* Delete value from the storage
*
* @param string $key
* @param integer $id
*
* @return bool
*/
function cerber_delete_set( $key, $id = null ) {
$key = preg_replace( CRB_SANITIZE_KEY, '', $key );
$cache_key = 'crb#' . $key . '#';
$id = ( $id !== null ) ? absint( $id ) : 0;
$cache_key .= $id;
cerber_cache_delete( $cache_key );
if ( cerber_db_query( 'DELETE FROM ' . cerber_get_db_prefix() . CERBER_SETS_TABLE . ' WHERE the_key = "' . $key . '" AND the_id = ' . $id ) ) {
return true;
}
return false;
}
/**
* Clean up all expired sets. Usually by cron.
*
* @param bool $all if true, deletes all sets that has expiration
*
* @return bool
*/
function cerber_delete_expired_set( $all = false ) {
if ( ! $all ) {
$where = 'expires > 0 AND expires < ' . time();
}
else {
$where = 'expires > 0';
}
if ( cerber_db_query( 'DELETE FROM ' . cerber_get_db_prefix() . CERBER_SETS_TABLE . ' WHERE ' . $where ) ) {
return true;
}
else {
return false;
}
}
/**
* Remove comments from a given piece of code
*
* @param string $string
*
* @return mixed
*/
function cerber_remove_comments( $string = '' ) {
return preg_replace( '/#.*/', '', preg_replace( '#//.*#', '', preg_replace( '#/\*(?:[^*]*(?:\*(?!/))*)*\*/#', '', $string ) ) );
}
/**
* Set Cerber Groove to logged in user browser
*
* @param $expire
*/
function cerber_set_groove( $expire ) {
if ( ! headers_sent() ) {
cerber_set_cookie( CRB_GROOVE, md5( cerber_get_groove() ), $expire + 1 );
$groove_x = cerber_get_groove_x();
cerber_set_cookie( CRB_GROOVE . '_x_' . $groove_x[0], $groove_x[1], $expire + 1 );
}
}
function cerber_is_auth_cookie( $text ) {
return ( 0 === strpos( $text, cerber_get_cookie_prefix() . CRB_GROOVE ) );
}
/*
Get the special Cerber Sign for using with cookies
*/
function cerber_get_groove() {
$groove = cerber_get_site_option( 'cerber-groove', false );
if ( empty( $groove ) ) {
$groove = crb_random_string( 16 );
update_site_option( 'cerber-groove', $groove );
}
return $groove;
}
/*
Check if the special Cerber Sign valid
*/
function cerber_check_groove( $hash = '' ) {
if ( ! $hash ) {
if ( ! $hash = cerber_get_cookie( CRB_GROOVE ) ) {
return false;
}
}
$groove = cerber_get_groove();
if ( $hash == md5( $groove ) ) {
return true;
}
return false;
}
/**
* @since 7.0
*/
function cerber_check_groove_x() {
$groove_x = cerber_get_groove_x();
if ( cerber_get_cookie( CRB_GROOVE . '_x_' . $groove_x[0] ) == $groove_x[1] ) {
return true;
}
return false;
}
/*
Get the special public Cerber Sign for using with cookies
*/
function cerber_get_groove_x( $regenerate = false ) {
$groove_x = array();
if ( ! $regenerate ) {
$groove_x = cerber_get_site_option( 'cerber-groove-x' );
}
if ( $regenerate || empty( $groove_x ) ) {
$groove_0 = crb_random_string( 24, 32 );
$groove_1 = crb_random_string( 24, 32 );
$groove_x = array( $groove_0, $groove_1 );
update_site_option( 'cerber-groove-x', $groove_x );
crb_update_cookie_dependent();
}
return $groove_x;
}
function cerber_get_cookie_path() {
if ( defined( 'COOKIEPATH' ) ) {
return COOKIEPATH;
}
return '/';
}
function cerber_set_cookie( $name, $value, $expire = 0, $path = "", $domain = "" ) {
global $wp_cerber_cookies;
if ( cerber_is_wp_cron() ) {
return;
}
if ( ! $path ) {
$path = cerber_get_cookie_path();
}
$expire = absint( $expire );
$expire = ( $expire > 43009401600 ) ? 43009401600 : $expire;
setcookie( cerber_get_cookie_prefix() . $name, $value, $expire, $path, $domain, is_ssl(), false );
// No rush here: PHP 7.3 only
/*setcookie( cerber_get_cookie_prefix() . $name, $value, array(
'expires ' => $expire,
'path' => $path,
'domain' => $domain,
'secure' => is_ssl(),
'httponly' => false,
'samesite' => 'Strict',
) );*/
$wp_cerber_cookies[ cerber_get_cookie_prefix() . $name ] = array( $expire, $value );
/*if ( ( ! $cerber_cookies = cerber_get_set( 'cerber_sweets' ) )
|| ! is_array( $cerber_cookies ) ) {
$cerber_cookies = array();
}
$cerber_cookies[ cerber_get_cookie_prefix() . $name ] = array( $expire, $value );
cerber_update_set( 'cerber_sweets', $cerber_cookies );
*/
}
/**
* @param $name
* @param bool $default
*
* @return string|boolean value of the cookie, false if the cookie is not set
*/
function cerber_get_cookie( $name, $default = false ) {
return crb_array_get( $_COOKIE, cerber_get_cookie_prefix() . $name, $default );
}
function cerber_get_cookie_prefix() {
/*
if ( defined( 'CERBER_COOKIE_PREFIX' )
&& is_string( CERBER_COOKIE_PREFIX )
&& preg_match( '/^\w+$/', CERBER_COOKIE_PREFIX ) ) {
return CERBER_COOKIE_PREFIX;
}*/
if ( $p = (string) crb_get_settings( 'cookiepref' ) ) {
return $p;
}
return '';
}
function crb_update_cookie_dependent() {
static $done = false;
if ( $done ) {
return;
}
register_shutdown_function( function () {
cerber_htaccess_sync( 'main' ); // keep the .htaccess rule is up to date
} );
$done = true;
}
/**
* Synchronize plugin settings with rules in the .htaccess file
*
* @param $file string
* @param $settings array
*
* @return bool|string|WP_Error
*/
function cerber_htaccess_sync( $file, $settings = array() ) {
if ( ! $settings ) {
$settings = crb_get_settings();
}
if ( 'main' == $file ) {
$rules = array();
if ( ! empty( $settings['adminphp'] ) && ( ! defined( 'CONCATENATE_SCRIPTS' ) || ! CONCATENATE_SCRIPTS ) ) {
// https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-6389
if ( ! apache_mod_loaded( 'mod_rewrite', true ) ) {
cerber_add_issue( 'no_mod', 'The Apache mod_rewrite module is not enabled on your web server. Ask your server administrator for assistance.', 'adminphp' );
return new WP_Error( 'no_mod', 'The Apache mod_rewrite module is not enabled on your web server. Ask your server administrator for assistance.' );
}
$groove_x = cerber_get_groove_x();
$cookie = cerber_get_cookie_prefix() . CRB_GROOVE . '_x_' . $groove_x[0];
$rules [] = '# Protection of admin scripts is enabled (CVE-2018-6389)';
$rules [] = '';
$rules [] = 'RewriteEngine On';
$rules [] = 'RewriteBase /';
$rules [] = 'RewriteCond %{REQUEST_URI} ^(.*)wp-admin/+load-scripts\.php$ [OR,NC]'; // @updated 8.1
$rules [] = 'RewriteCond %{REQUEST_URI} ^(.*)wp-admin/+load-styles\.php$ [NC]'; // @updated 8.1
$rules [] = 'RewriteCond %{HTTP_COOKIE} !' . $cookie . '=' . $groove_x[1];
$rules [] = 'RewriteRule (.*) - [R=403,L]';
$rules [] = '';
}
return cerber_update_htaccess( $file, $rules );
}
if ( 'media' == $file ) {
/*if ( ! crb_is_php_mod() ) {
return 'ERROR: The Apache PHP module mod_php is not active.';
}*/
$rules = array();
if ( ! empty( $settings['phpnoupl'] ) ) {
$rules [] = '';
$rules [] = 'SetHandler none';
$rules [] = 'SetHandler default-handler';
$rules [] = 'Options -ExecCGI';
$rules [] = 'RemoveHandler .cgi .php .php3 .php4 .php5 .php7 .phtml .pl .py .pyc .pyo';
$rules [] = '';
$rules [] = '';
$rules [] = 'php_flag engine off';
$rules [] = '';
$rules [] = '';
$rules [] = 'php_flag engine off';
$rules [] = '';
}
return cerber_update_htaccess( $file, $rules );
}
return false;
}
/**
* Remove Cerber rules from the .htaccess file
*
*/
function cerber_htaccess_clean_up() {
cerber_update_htaccess( 'main', array() );
cerber_update_htaccess( 'media', array() );
}
/**
* Update the .htaccess file
*
* @param $file
* @param array $rules A set of rules (array of strings) for the section. If empty, the section will be cleaned.
*
* @return bool|string|WP_Error True on success, string with error message on failure
*/
function cerber_update_htaccess( $file, $rules = array() ) {
if ( $file == 'main' ) {
$htaccess = cerber_get_htaccess_file();
$marker = CERBER_MARKER1;
}
elseif ( $file == 'media' ) {
$htaccess = cerber_get_upload_dir() . '/.htaccess';
$marker = CERBER_MARKER2;
}
else {
return '???';
}
if ( ! is_file( $htaccess ) ) {
if ( ! touch( $htaccess ) ) {
return new WP_Error( 'htaccess-io', 'ERROR: Unable to create the file ' . $htaccess );
}
}
elseif ( ! is_writable( $htaccess ) ) {
return new WP_Error( 'htaccess-io', 'ERROR: Unable to get access to the file ' . $htaccess );
}
$result = crb_insert_with_markers( $htaccess, $marker, $rules );
if ( $result || $result === 0 ) {
$result = 'The ' . $htaccess . ' file has been updated';
}
else {
$result = new WP_Error( 'htaccess-io', 'ERROR: Unable to modify the file ' . $htaccess );
}
return $result;
}
/**
* Return .htaccess filename with full path
*
* @return bool|string full filename if the file can be written, false otherwise
*/
function cerber_get_htaccess_file() {
require_once( ABSPATH . 'wp-admin/includes/file.php' );
$home_path = get_home_path();
return $home_path . '.htaccess';
}
/**
* Check if the remote domain match mask
*
* @param $domain_mask array|string Mask(s) to check remote domain against
*
* @return bool True if hostname match at least one domain from the list
*/
function cerber_check_remote_domain( $domain_mask ) {
$hostname = @gethostbyaddr( cerber_get_remote_ip() );
if ( ! $hostname || filter_var( $hostname, FILTER_VALIDATE_IP ) ) {
return false;
}
if ( ! is_array( $domain_mask ) ) {
$domain_mask = array( $domain_mask );
}
foreach ( $domain_mask as $mask ) {
if ( substr_count( $mask, '.' ) != substr_count( $hostname, '.' ) ) {
continue;
}
$parts = array_reverse( explode( '.', $hostname ) );
$ok = true;
foreach ( array_reverse( explode( '.', $mask ) ) as $i => $item ) {
if ( $item != '*' && $item != $parts[ $i ] ) {
$ok = false;
break;
}
}
if ( $ok == true ) {
return true;
}
}
return false;
}
/**
* Prepare files (install/deinstall) for different boot modes
*
* @param $mode int A plugin boot mode
* @param $old_mode int
*
* @return bool|WP_Error
* @since 6.3
*/
function cerber_set_boot_mode( $mode = null, $old_mode = null ) {
if ( $mode === null ) {
$mode = crb_get_settings( 'boot-mode' );
}
$source = dirname( cerber_plugin_file() ) . '/modules/aaa-wp-cerber.php';
$target = WPMU_PLUGIN_DIR . '/aaa-wp-cerber.php';
if ( $mode == 1 ) {
if ( file_exists( $target ) ) {
if ( sha1_file( $source, true ) == sha1_file( $target, true ) ) {
return true;
}
}
if ( ! is_dir( WPMU_PLUGIN_DIR ) ) {
if ( ! mkdir( WPMU_PLUGIN_DIR, 0755, true ) ) {
// TODO: try to set permissions for the parent folder
return new WP_Error( 'cerber-boot', __( 'Unable to create the directory', 'wp-cerber' ) . ' ' . WPMU_PLUGIN_DIR );
}
}
if ( ! copy( $source, $target ) ) {
if ( ! wp_is_writable( WPMU_PLUGIN_DIR ) ) {
return new WP_Error( 'cerber-boot', __( 'Destination folder access denied', 'wp-cerber' ) . ' ' . WPMU_PLUGIN_DIR );
}
elseif ( ! file_exists( $source ) ) {
return new WP_Error( 'cerber-boot', __( 'File not found', 'wp-cerber' ) . ' ' . $source );
}
return new WP_Error( 'cerber-boot', __( 'Unable to copy the file', 'wp-cerber' ) . ' ' . $source . ' to the folder ' . WPMU_PLUGIN_DIR );
}
}
else {
if ( file_exists( $target ) ) {
if ( ! unlink( $target ) ) {
return new WP_Error( 'cerber-boot', __( 'Unable to delete the file', 'wp-cerber' ) . ' ' . $target );
}
}
return true;
}
return true;
}
/**
* How the plugin was loaded (initialized)
*
* @return int
* @since 6.3
*/
function cerber_get_mode() {
if ( function_exists( 'cerber_mode' ) && defined( 'CERBER_MODE' ) ) {
return cerber_mode();
}
return 0;
}
function cerber_is_permalink_enabled() {
static $ret;
if ( isset( $ret ) ) {
return $ret;
}
$ret = ( get_option( 'permalink_structure' ) ) ? true : false;
return $ret;
}
/**
* Given the path of a file or directory, this function
* will return the parent directory's path that is given levels up
*
* @param string $path
* @param integer $levels
*
* @return string Parent directory's path
*/
function cerber_dirname( $path, $levels = 1 ) {
if ( PHP_VERSION_ID >= 70000 || $levels == 1 ) {
return dirname( $path, $levels );
}
$ret = '.';
$path = explode( DIRECTORY_SEPARATOR, str_replace( array( '/', '\\' ), DIRECTORY_SEPARATOR, $path ) );
if ( 0 < ( count( $path ) - $levels ) ) {
$path = array_slice( $path, 0, count( $path ) - $levels );
$ret = implode( DIRECTORY_SEPARATOR, $path );
}
return $ret;
}
/**
* Implement basename() with multibyte support
*
* @param $file_name
*
* @return string
*/
function cerber_mb_basename( $file_name ) {
$pos = mb_strrpos( $file_name, DIRECTORY_SEPARATOR );
if ( $pos !== false ) {
return mb_substr( $file_name, $pos + 1 );
}
return $file_name;
}
function cerber_get_extension( $file_name ) {
$file_name = cerber_mb_basename( $file_name );
$pos = mb_strpos( $file_name, '.' );
if ( $pos !== false ) {
if ( $ext = mb_substr( $file_name, $pos + 1 ) ) {
return mb_strtolower( $ext );
}
}
return '';
}
/**
* True if version of WP is equal or greater than specified one
*
* @param string $ver
*
* @return bool|int
*/
function crb_wp_version_compare( $ver ) {
return version_compare( cerber_get_wp_version(), $ver, '>=' );
}
/**
* Returns an unaltered $wp_version variable
*
* @return string WordPress version
*/
function cerber_get_wp_version() {
static $ver;
if ( ! $ver ) {
include( ABSPATH . WPINC . DIRECTORY_SEPARATOR . 'version.php' );
$ver = (string) $wp_version;
}
return $ver;
}
/**
* Returns an unaltered $wp_local_package variable
*
* @return string WordPress locale
* @since 8.8.7.2
*/
function cerber_get_wp_locale() {
static $lc;
if ( ! $lc ) {
global $wp_local_package;
include( ABSPATH . WPINC . DIRECTORY_SEPARATOR . 'version.php' );
$lc = isset( $wp_local_package ) ? $wp_local_package : 'en_US';
}
return $lc;
}
function crb_get_themes() {
static $theme_headers = array(
'Name' => 'Theme Name',
'ThemeURI' => 'Theme URI',
'Description' => 'Description',
'Author' => 'Author',
'AuthorURI' => 'Author URI',
'Version' => 'Version',
'Template' => 'Template',
'Status' => 'Status',
'Tags' => 'Tags',
'TextDomain' => 'Text Domain',
'DomainPath' => 'Domain Path',
);
$themes = array();
if ( $list = search_theme_directories() ) {
foreach ( $list as $key => $info ) {
$css = $info['theme_root'] . '/' . $info['theme_file'];
if ( is_readable( $css ) ) {
$themes[ $key ] = get_file_data( $info['theme_root'] . '/' . $info['theme_file'], $theme_headers, 'theme' );
$themes[ $key ]['theme_root'] = $info['theme_root'];
$themes[ $key ]['theme_file'] = $info['theme_file'];
}
}
}
return $themes;
}
function cerber_is_base64_encoded( $val ) {
$val = trim( $val );
if ( empty( $val ) || is_numeric( $val ) || strlen( $val ) < 8 || preg_match( '/[^A-Z0-9\+\/=]/i', $val ) ) {
return false;
}
if ( $val = @base64_decode( $val ) ) {
if ( ! preg_match( '/[\x00-\x08\x0B-\x0C\x0E-\x1F]/', $val ) ) { // ASCII control characters must not be
if ( preg_match( '/[A-Z]/i', $val ) ) { // Latin chars must be
return $val;
}
}
}
return false;
}
function crb_is_alphanumeric( $str ) {
return ! preg_match( '/[^\w\-]/', $str );
}
/**
* @param array $arr
* @param array $fields
*
* @return bool
*/
function crb_arrays_similar( &$arr, $fields ) {
if ( crb_array_diff_keys( $arr, $fields ) ) {
return false;
}
foreach ( $fields as $field => $pattern ) {
if ( is_callable( $pattern ) ) {
if ( ! call_user_func( $pattern, $arr[ $field ] ) ) {
return false;
}
}
else {
if ( ! preg_match( $pattern, $arr[ $field ] ) ) {
return false;
}
}
}
return true;
}
function cerber_get_html_label( $iid ) {
//$css['scan-ilabel'] = 'color: #fff; margin-left: 6px; display: inline-block; line-height: 1em; padding: 3px 5px; font-size: 92%;';
$c = ( $iid == 1 ) ? '#33be84' : '#dc2f34';
return '' . cerber_get_issue_label( $iid ) . '';
}
function crb_getallheaders() {
if ( function_exists( 'getallheaders' ) ) {
return getallheaders();
}
// @since v. 7.7 for PHP-FPM
$headers = array();
foreach ( $_SERVER as $name => $value ) {
if ( substr( $name, 0, 5 ) == 'HTTP_' ) {
$headers[ str_replace( ' ', '-', ucwords( strtolower( str_replace( '_', ' ', substr( $name, 5 ) ) ) ) ) ] = $value;
}
}
return $headers;
}
/**
* @param $msg
* @param string $source
*/
function cerber_error_log( $msg, $source = '' ) {
//if ( crb_get_settings( 'log_errors' ) ) {
cerber_diag_log( $msg, $source, true );
//}
}
/**
* Write message to the diagnostic log
*
* @param string|array $msg
* @param string $source
* @param bool $error
*
* @return bool|int
*/
function cerber_diag_log( $msg, $source = '', $error = false ) {
if ( $source == 'CLOUD' ) {
if ( ! defined( 'CERBER_CLOUD_DEBUG' )
|| ( ! defined( 'WP_ADMIN' ) && ! defined( 'WP_NETWORK_ADMIN' ) ) ) {
return false;
}
}
if ( ! $msg || ! $log = @fopen( cerber_get_diag_log(), 'a' ) ) {
return false;
}
if ( $source ) {
$source = '[' . $source . ']';
}
if ( $error ) {
$source .= ' ERROR: ';
}
if ( ! is_array( $msg ) ) {
$msg = array( $msg );
}
foreach ( $msg as $line ) {
if ( is_array( $line ) ) {
$line = print_r( $line, 1 ); // workaround for CRB_Globals::$db_errors
}
//$ret = @fwrite( $log, '[' .cerber_get_remote_ip(). '][' . cerber_date( time() ) . ']' . $source . ' ' . $line . PHP_EOL );
$ret = @fwrite( $log, '[' . cerber_date( time(), false ) . ']' . $source . ' ' . $line . PHP_EOL );
}
@fclose( $log );
return $ret;
}
function cerber_get_diag_log() {
//$dir = ( defined( 'CERBER_DIAG_DIR' ) && is_dir( CERBER_DIAG_DIR ) ) ? CERBER_DIAG_DIR . '/' : cerber_get_the_folder();
if ( defined( 'CERBER_DIAG_DIR' ) && is_dir( CERBER_DIAG_DIR ) ) {
$dir = CERBER_DIAG_DIR;
}
else {
if ( ! $dir = cerber_get_the_folder() ) {
return false;
}
}
return rtrim( $dir, '/' ) . '/cerber-debug.log';
}
function cerber_truncate_log( $bytes = 10000000 ) {
$file = cerber_get_diag_log();
if ( ! is_file( $file ) || filesize( $file ) <= $bytes ) {
return;
}
if ( $bytes == 0 ) {
$log = @fopen( $file, 'w' );
@fclose( $log );
return;
}
if ( $text = file_get_contents( $file ) ) {
$text = substr( $text, 0 - $bytes );
if ( ! $log = @fopen( $file, 'w' ) ) {
return;
}
@fwrite( $log, $text );
@fclose( $log );
}
}
function crb_get_bloginfo( $what ) {
static $info = array();
if ( ! isset( $info[ $what ] ) ) {
$info[ $what ] = get_bloginfo( $what );
}
return $info[ $what ];
}
function crb_is_php_mod() {
require_once( ABSPATH . 'wp-admin/includes/misc.php' );
if ( apache_mod_loaded( 'mod_php7' ) ) {
return true;
}
if ( apache_mod_loaded( 'mod_php5' ) ) {
return true;
}
return false;
}
/**
* PHP implementation of fromCharCode
*
* @param $str
*
* @return string
*/
function cerber_fromcharcode( $str ) {
$vals = explode( ',', $str );
$vals = array_map( function ( $v ) {
$v = trim( $v );
if ( $v[0] == '0' ) {
$v = ( $v[1] == 'x' || $v[1] == 'X' ) ? hexdec( $v ) : octdec( $v );
}
else {
$v = intval( $v );
}
return '' . $v . ';';
}, $vals );
return mb_convert_encoding( implode( '', $vals ), 'UTF-8', 'HTML-ENTITIES' );
}
/**
* @param $dir string Directory to empty with a trailing directory separator
*
* @return int|WP_Error
*/
function cerber_empty_dir( $dir ) {
//$trd = rtrim( $dir, '/\\' );
if ( ! @is_dir( $dir )
|| 0 === strpos( $dir, ABSPATH ) ) { // Workaround for a non-legitimate use of this function
return new WP_Error( 'no-dir', 'This directory cannot be emptied' );
}
$files = @scandir( $dir );
if ( ! is_array( $files ) || empty( $files ) ) {
return true;
}
$fs = cerber_init_wp_filesystem();
if ( is_wp_error( $fs ) ) {
return $fs;
}
$ret = true;
foreach ( $files as $file ) {
$full = $dir . $file;
if ( @is_file( $full ) ) {
if ( ! @unlink( $full ) ) {
$ret = false;
}
}
elseif ( ! in_array( $file, array( '..', '.' ) ) && is_dir( $full ) ) {
if ( ! $fs->rmdir( $full, true ) ) {
$ret = false;
}
}
}
if ( ! $ret ) {
return new WP_Error( 'file-deletion-error', 'Some files or subdirectories in this directory cannot be deleted: ' . $dir );
}
return $ret;
}
/**
* Tries to raise PHP limits
*
*/
function crb_raise_limits( $mem = null ) {
@ini_set( 'max_execution_time', 180 );
if ( function_exists( 'set_time_limit' )
&& false === strpos( ini_get( 'disable_functions' ), 'set_time_limit' ) ) {
@set_time_limit( 0 );
}
if ( $mem ) {
@ini_set( 'memory_limit', $mem );
}
}
/**
* Masks email address
*
* @param string $email
*
* @return string
*/
function cerber_mask_email( $email ) {
list( $box, $host ) = explode( '@', $email );
$box = str_pad( $box[0], strlen( $box ), '*' );
$host = str_pad( substr( $host, strrpos( $host, '.' ) ), strlen( $host ), '*', STR_PAD_LEFT );
return str_replace( '*', '∗', $box . '@' . $host );
}
/**
* Masks username (login)
*
* @param string $login
*
* @return string
*
* @since 8.9.6.4
*/
function crb_mask_login( $login ) {
if ( is_email( $login ) ) {
return cerber_mask_email( $login );
}
$strlen = mb_strlen( $login );
return str_pad( mb_substr( $login, 0, intdiv( $strlen, 2 ) ), $strlen, '*' );
}
/**
* Masks IP address
*
* @param string $ip
*
* @return string
*
* @since 8.9.6.4
*/
function crb_mask_ip( $ip = '' ) {
if ( cerber_is_ipv6( $ip ) ) {
// Look for the third colon
$pos = strpos( $ip, ':', strpos( $ip, ':', strpos( $ip, ':' ) + 1 ) + 1 );
$delimiter = ':';
}
else {
// Look for the second dot
$pos = strpos( $ip, '.', strpos( $ip, '.' ) + 1 );
$delimiter = '.';
}
if ( ! $pos ) {
return $ip;
}
$net = substr( $ip, 0, $pos );
$sub = substr( $ip, $pos );
return $net . preg_replace( '/[^' . $delimiter . ']/', '*', $sub );
}
/**
* A modified clone of insert_with_markers() from wp-admin/includes/misc.php
* Removed switch_to_locale() and related stuff that were introduced in WP 5.3. and cause problem if calling ite before 'init' hook.
*
* Inserts an array of strings into a file (.htaccess ), placing it between
* BEGIN and END markers.
*
* Replaces existing marked info. Retains surrounding
* data. Creates file if none exists.
*
* @param string $filename Filename to alter.
* @param string $marker The marker to alter.
* @param array|string $insertion The new content to insert.
*
* @return bool True on write success, false on failure.
* @since 8.5.1
*
*/
function crb_insert_with_markers( $filename, $marker, $insertion ) {
if ( ! file_exists( $filename ) ) {
if ( ! is_writable( dirname( $filename ) ) ) {
return false;
}
if ( ! touch( $filename ) ) {
return false;
}
}
elseif ( ! is_writeable( $filename ) ) {
return false;
}
if ( ! is_array( $insertion ) ) {
$insertion = explode( "\n", $insertion );
}
$start_marker = "# BEGIN {$marker}";
$end_marker = "# END {$marker}";
$fp = fopen( $filename, 'r+' );
if ( ! $fp ) {
return false;
}
// Attempt to get a lock. If the filesystem supports locking, this will block until the lock is acquired.
flock( $fp, LOCK_EX );
$lines = array();
while ( ! feof( $fp ) ) {
$lines[] = rtrim( fgets( $fp ), "\r\n" );
}
// Split out the existing file into the preceding lines, and those that appear after the marker
$pre_lines = array();
$post_lines = array();
$existing_lines = array();
$found_marker = false;
$found_end_marker = false;
foreach ( $lines as $line ) {
if ( ! $found_marker && false !== strpos( $line, $start_marker ) ) {
$found_marker = true;
continue;
}
elseif ( ! $found_end_marker && false !== strpos( $line, $end_marker ) ) {
$found_end_marker = true;
continue;
}
if ( ! $found_marker ) {
$pre_lines[] = $line;
}
elseif ( $found_marker && $found_end_marker ) {
$post_lines[] = $line;
}
else {
$existing_lines[] = $line;
}
}
// Check to see if there was a change
if ( $existing_lines === $insertion ) {
flock( $fp, LOCK_UN );
fclose( $fp );
return true;
}
// Generate the new file data
$new_file_data = implode(
"\n",
array_merge(
$pre_lines,
array( $start_marker ),
$insertion,
array( $end_marker ),
$post_lines
)
);
// Write to the start of the file, and truncate it to that length
fseek( $fp, 0 );
$bytes = fwrite( $fp, $new_file_data );
if ( $bytes ) {
ftruncate( $fp, ftell( $fp ) );
}
fflush( $fp );
flock( $fp, LOCK_UN );
fclose( $fp );
return (bool) $bytes;
}
/**
* @return WP_Error|WP_Filesystem_Direct
*/
function cerber_init_wp_filesystem() {
global $wp_filesystem;
if ( $wp_filesystem instanceof WP_Filesystem_Direct ) { // @since 8.1.5
return $wp_filesystem;
}
require_once( ABSPATH . 'wp-admin/includes/file.php' );
add_filter( 'filesystem_method', '__ret_direct' );
if ( ! WP_Filesystem() ) {
return new WP_Error( 'cerber-file', 'Unable to init WP_Filesystem' );
}
remove_filter( 'filesystem_method', '__ret_direct' );
return $wp_filesystem;
}
function __ret_direct() {
return 'direct';
}
/**
* Returns a list of alert parameters for the currently displaying admin page in a specific order.
* The keys are used to create an alert URL.
* Values are used to calculate an alert hash.
*
* @return array The set of parameters
*/
function crb_get_alert_params() {
// A set of alert parameters
// A strictly particular order due to further using numeric array indexes.
$params = CRB_ALERT_PARAMS;
$get = crb_get_query_params();
if ( ! array_intersect_key( $params, $get ) ) {
return $params; // No parameters in the current query
}
// The IP field is processed differently than other fields
if ( ! empty( $get['filter_ip'] ) ) {
$begin = 0;
$end = 0;
$ip = cerber_any2range( $get['filter_ip'] );
if ( is_array( $ip ) ) {
$begin = $ip['begin'];
$end = $ip['end'];
$ip = 0;
}
elseif ( ! $ip ) {
$ip = 0;
}
$params['begin'] = $begin;
$params['end'] = $end;
$params['filter_ip'] = $ip;
}
// Getting values of the request fields (used as alert parameters)
$temp = $params;
unset( $temp['begin'], $temp['end'], $temp['filter_ip'] );
foreach ( array_keys( $temp ) as $key ) {
if ( ! empty( $get[ $key ] ) ) {
if ( is_array( $get[ $key ] ) ) {
$params[ $key ] = array_map( 'trim', $get[ $key ] );
}
else {
$params[ $key ] = trim( $get[ $key ] );
}
}
else {
$params[ $key ] = 0;
}
}
// Preparing/sanitizing values of the alert parameters
if ( ! empty( $params['al_expires'] ) ) {
$time = 24 * 3600 + strtotime( 'midnight ' . $params['al_expires'] );
$params['al_expires'] = $time - get_option( 'gmt_offset' ) * 3600;
}
$int_fields = array( 'al_limit', 'al_ignore_rate', 'al_send_emails', 'al_send_pushbullet' );
foreach ( $int_fields as $f ) {
$params[ $f ] = absint( $params[ $f ] );
}
if ( ! is_array( $params['filter_activity'] ) ) {
$params['filter_activity'] = array( $params['filter_activity'] );
}
$params['filter_activity'] = array_filter( $params['filter_activity'] );
// Basic XSS sanitization
array_walk_recursive( $params, function ( &$item ) {
$item = str_replace( array( '<', '>', '[', ']', '"', "'" ), '', $item );
} );
return $params;
}
/**
* @param array $params
*
* @return string
*
* @since 8.9.6
*/
function crb_get_alert_id( $params ) {
return sha1( json_encode( array_values( array_diff_key( $params, array_flip( CRB_NON_ALERT_PARAMS ) ) ) ) );
}
function crb_random_string( $length_min, $length_max = null, $inc_num = true, $upper_case = true, $extra = '' ) {
static $alpha1 = 'abcdefghijklmnopqrstuvwxyz';
static $alpha2 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
static $digits = '0123456789';
if ( ! $length_max ) {
$length_max = $length_min;
}
$str = $alpha1;
if ( $inc_num ) {
$str .= $digits;
}
if ( $upper_case ) {
$str .= $alpha2;
}
if ( $extra ) {
$str .= $extra;
}
$n = (int) ceil( $length_max / strlen( $str ) );
if ( $n > 1 ) {
$str = implode( '', array_fill( 0, $n, $str ) );
}
$length = ( $length_min != $length_max ) ? rand( $length_min, $length_max ) : $length_min;
return substr( str_shuffle( $str ), 0, $length );
}
/**
* Detects and decodes serialized or JSON encoded array
*
* @param $text string
*
* @return array
*
* @since 8.8
*/
function crb_auto_decode( &$text ) {
if ( ! $text ) {
return array();
}
if ( $text[0] == 'a' ) {
return crb_unserialize( $text );
}
return @json_decode( $text, true );
}
/**
* A safe version of unserialize()
*
* @param string $string
*
* @return mixed
*
*/
function crb_unserialize( &$string ) {
if ( PHP_VERSION_ID >= 70000 ) {
return @unserialize( $string, [ 'allowed_classes' => false ] );
}
return @unserialize( $string );
}
function crb_get_review_url( $vendor = null ) {
static $urls = array(
'tpilot' => array( 'https://www.trustpilot.com/review/wpcerber.com', 'https://www.trustpilot.com/evaluate/wpcerber.com' ),
'g2' => array( 'https://www.g2.com/products/cerber-security-antispam-malware-scan/reviews/start' ),
'wp' => array( 'https://wordpress.org/support/plugin/wp-cerber/reviews/#new-post' ),
'cap' => array( 'https://reviews.capterra.com/new/187653' ),
);
$ret = $urls[ $vendor ];
if ( $vendor == 'tpilot' ) {
shuffle( $ret );
}
return $ret[0];
}
function crb_was_activated( $ago ) {
static $actvd;
if ( ! isset( $actvd ) ) {
if ( ! $actvd = cerber_get_set( '_activated' ) ) {
return true;
}
}
return ( ( (int) crb_array_get( $actvd, 'time' ) + $ago ) <= time() );
}
/**
* Return a "session verifier" to identify the current admin session among others admin sessions
*
* Copy of WP_Session_Tokens->hash_token();
*
* @param $token
*
* @return string
*/
function cerber_hash_token( $token ) {
// If ext/hash is not present, use sha1() instead.
if ( function_exists( 'hash' ) ) {
return hash( 'sha256', $token );
}
else {
return sha1( $token );
}
}
// The key-value cache
final class CRB_Cache {
private static $cache = array();
private static $stat = array();
private static $wp_cache_group = 'wp_cerber';
private static $wp_key_list = 'wp_cerber_list';
static function set( $key, $value, $expire = 0 ) {
$exp = 0;
if ( $expire > 0 ) {
$exp = time() + (int) $expire;
if ( $exp < time() ) {
return false;
}
}
$element = array( $value, $exp );
self::$cache[ $key ] = $element;
if ( self::checker() ) {
wp_cache_set( $key, $element, self::$wp_cache_group );
$entries = wp_cache_get( self::$wp_key_list, self::$wp_key_list );
if ( ! $entries ) {
$entries = array();
}
$entries[ $key ] = $expire;
wp_cache_set( self::$wp_key_list, $entries, self::$wp_key_list );
}
if ( ! isset( self::$stat[ $key ] ) ) {
self::$stat[ $key ] = array( 0, 0 );
}
self::$stat[ $key ][0] ++;
return true;
}
static function get( $key, $default = null ) {
$element = crb_array_get( self::$cache, $key );
if ( ! is_array( $element ) ) {
if ( self::checker() ) {
$element = wp_cache_get( $key, self::$wp_cache_group );
}
}
if ( ! is_array( $element ) ) {
return $default;
}
if ( ! empty( $element[1] ) && $element[1] < time() ) {
self::delete( $key );
return $default;
}
if ( ! isset( self::$stat[ $key ] ) ) {
self::$stat[ $key ] = array( 0, 0 );
}
self::$stat[ $key ][1] ++;
return $element[0];
}
static function delete( $key ) {
if ( isset( self::$cache[ $key ] ) ) {
unset( self::$cache[ $key ] );
}
if ( self::checker() ) {
wp_cache_delete( $key, self::$wp_cache_group );
}
}
static function reset() {
self::$cache = array();
if ( $entries = wp_cache_get( self::$wp_key_list, self::$wp_key_list ) ) {
foreach ( $entries as $entry => $exp ) {
wp_cache_delete( $entry, self::$wp_cache_group );
}
wp_cache_delete( self::$wp_key_list, self::$wp_key_list );
}
}
static function get_stat( $recheck = false ) {
$entries = wp_cache_get( self::$wp_key_list, self::$wp_key_list );
if ( $recheck && $entries ) { // Make sure that our list of existing key doesn't contain wrong entries
foreach ( $entries as $key => $exp ) {
if ( ! $element = wp_cache_get( $key, self::$wp_cache_group ) ) {
unset( $entries[ $key ] );
}
}
wp_cache_set( self::$wp_key_list, $entries, self::$wp_key_list );
}
if ( empty( $entries ) ) {
$entries = array();
}
return array( self::$stat, $entries );
}
static function checker() {
$sid = get_wp_cerber()->getRequestID();
$check = wp_cache_get( '__checker__', self::$wp_cache_group );
if ( ! $check || ! isset( $check['t'] ) || ! isset( $check['s'] ) ) {
wp_cache_set( '__checker__', array(
't' => time(),
's' => $sid
), self::$wp_cache_group );
return 0;
}
if ( $check['s'] == $sid ) {
return 0;
}
return $check['t'];
}
}
/**
* @param $key string
* @param $value mixed
* @param $expire integer Element will expire in X seconds, 0 = never expires
*
* @return bool
*/
function cerber_cache_set( $key, $value, $expire = 0 ) {
return CRB_Cache::set( $key, $value, $expire );
}
/**
* @param $key string
* @param $default mixed
*
* @return mixed|null
*/
function cerber_cache_get( $key, $default = null ) {
return CRB_Cache::get( $key, $default );
}
function cerber_cache_delete( $key ) {
CRB_Cache::delete( $key );
}
function cerber_cache_enable() {
global $cerber_use_cache;
$cerber_use_cache = true;
}
function cerber_cache_disable() {
global $cerber_use_cache;
$cerber_use_cache = false;
}
function cerber_cache_is_enabled() {
global $cerber_use_cache;
return ! empty( $cerber_use_cache );
}
/**
* Retrieve and cache data from the DB. Make sense for heavy queries.
*
* @param array|string $sql One or more SQL queries with optional data format
* @param string $table DB table we're caching data from
* @param bool $cache_only
* @param string[] $hash_fields Fields to calculate hash
* @param int $order_by The key of the ORDER BY field in the $fieldset
*
* @return array|false
*
* @since 8.8.3.1
*/
function crb_q_cache_get( $sql, $table, $cache_only = false, $hash_fields = array( 'stamp', 'ip', 'session_id' ), $order_by = 0 ) {
global $wp_cerber_q_cache;
if ( is_string( $sql ) ) {
$sql = array( array( $sql ) );
}
$single = ( count( $sql ) == 1 );
$run = true;
$cache_key = 'q_cache_' . sha1( implode( '|', array_column( $sql, 0 ) ) );
$cache = cerber_get_set( $cache_key, 0, false, true );
if ( $cache ) {
$cache = json_decode( $cache );
if ( $cache->hash == crb_get_table_hash( $table, $hash_fields, $order_by ) ) {
$wp_cerber_q_cache = true;
$run = false;
}
}
if ( $run && $cache_only ) {
return false;
}
if ( ! $run ) {
$results = $cache->results;
}
else {
$new_cache = array();
$new_cache['hash'] = crb_get_table_hash( $table, $hash_fields, $order_by );
$results = array();
foreach ( $sql as $query ) {
$results[] = cerber_db_get_results( $query[0], crb_array_get( $query, 1 ) );
}
$new_cache['results'] = $results;
$new_cache = json_encode( $new_cache, JSON_UNESCAPED_UNICODE );
cerber_update_set( $cache_key, $new_cache, 0, false, time() + 7200, true );
}
if ( $single ) {
return $results[0];
}
return $results;
}
/**
* Returns pseudo "hash" for a given log table to detect changes in the table
*
* @param string $table
* @param string[] $hash_fields
* @param int $order_by
*
* @return string
* @since 8.8.3.1
*/
function crb_get_table_hash( $table, $hash_fields, $order_by ) {
static $hashes;
$fields = implode( ',', $hash_fields );
$key = sha1( $table . '|' . $fields . '|' . $order_by );
if ( ! isset( $hashes[ $key ] ) ) {
if ( $data = cerber_db_get_row( 'SELECT ' . $fields . ' FROM ' . $table . ' ORDER BY ' . $hash_fields[ $order_by ] . ' DESC LIMIT 1' ) ) {
$hashes[ $key ] = sha1( implode( '|', $data ) );
}
else {
$hashes[ $key ] = '';
}
}
return $hashes[ $key ];
}
/**
* A replacement for global PHP variables. It doesn't make them good (less ugly), but it helps to trace their usage easily (within IDE).
*
* @since 8.9.4
*
*/
class CRB_Globals {
static $session_status;
static $act_status;
static $do_not_log = array();
static $reset_pwd_msg;
static $reset_pwd_denied = false;
static $user_id;
static $req_status = 0;
static $assets_url = '';
static $ajax_loader = '';
static $logged;
static $blocked;
static $db_requests = array();
static $db_errors = array();
static $bot_status = 0;
static $doing_upgrade;
/**
* @param integer $val
*
* @return void
*/
static function set_bot_status( $val ) {
self::$bot_status = $val;
self::$act_status = $val; // For backward compatibility
}
/**
* @param integer $val
*
* @return void
*/
static function set_act_status( $val ) {
if ( ! self::$act_status ) {
self::$act_status = $val;
}
}
}