( time() - 900 )
) {
$msg = __( 'Currently a scheduled scan in progress. Please wait until it is finished.', 'wp-cerber' );
$status = 1;
}
else {
$msg = sprintf( __( 'Previous scan started %s has not been completed. Continue scanning?', 'wp-cerber' ), cerber_date( $scan['started'], false ) );
$status = 2;
}
}
else {
$status = 3;
}
}
$start_quick = '
';
$controls = '';
switch ( $status ) {
case 0:
case 3:
$controls = $start_quick . $start_full;
break;
case 1:
$controls = '';
break;
case 2:
$controls = $start_quick . $start_full . $continue;
break;
}
$controls .= $stop;
$class = ( $status ) ? '' : 'crb-scanner-has-data';
echo '
';
cerber_scanner_show_dashboard( $msg, $status );
$d = '';
if ( nexus_is_valid_request() && ! nexus_is_granted( 'submit' ) ) {
$d = 'disabled="disabled"';
}
?>
';
}
function cerber_ref_upload_form() {
?>
$console_log,
'cerber_scan_do' => $next_do,
'cerber_scanner' => $scanner,
//'scan' => cerber_get_scan(), // debug only
);
if ( $scan_do != 'continue_scan' ) {
$ret['strings'] = cerber_get_strings();
}
ob_end_clean();
echo json_encode( $ret );
crb_admin_stop_ajax();
}
/**
* File viewer, server side AJAX
*
*/
add_action( 'wp_ajax_cerber_view_file', function () {
cerber_check_ajax_permissions();
$get = crb_get_query_params();
if ( ! $file_name = $get['file'] ) {
crb_admin_stop_ajax( 'Error: Filename not specified. Please run a new malware scan.' );
}
if ( ! @file_exists( $file_name ) ) {
crb_admin_stop_ajax( 'Error: The requested file doesn\'t exist or has been deleted: ' . htmlspecialchars( $file_name ). '. Please run a new malware scan.' );
return;
}
if ( ! @is_file( $file_name ) ) {
crb_admin_stop_ajax( 'Error: The requested file is not an ordinary file: ' . htmlspecialchars( $file_name ) );
return;
}
$file_size = filesize( $file_name );
if ( $file_size > 8000000 ) {
crb_admin_stop_ajax( 'Error: The requested is too large to display: ' . crb_size_format( $file_size ) );
return;
}
if ( $file_size <= 0 ) {
crb_admin_stop_ajax( 'The requested file is empty.' );
return;
}
$scan_id = absint( $get['scan_id'] );
$the_file = cerber_db_get_row( 'SELECT * FROM ' . cerber_get_db_prefix() . CERBER_SCAN_TABLE . ' WHERE scan_id = ' . $scan_id . ' AND file_name = "' . $file_name . '"' );
if ( ! $the_file ) {
crb_admin_stop_ajax( __( 'File access error. Possibly scan results are outdated. Please run Quick or Full Scan.', 'wp-cerber' ) );
return;
}
if ( ! $source = file_get_contents( $file_name ) ) {
crb_admin_stop_ajax( 'Error: Unable to load file.' );
return;
}
$source = htmlspecialchars( $source, ENT_SUBSTITUTE );
if ( ! $source ) {
$source = 'Unable to display the contents of the file. This file contains non-printable characters.';
}
if ( cerber_detect_exec_extension( $file_name )
|| cerber_check_extension( $file_name, array( 'js', 'css', 'inc' ) )
|| cerber_is_htaccess( $file_name )
) {
$paint = true;
}
else {
$paint = false;
}
$overlay = '';
if ( $paint ) {
$overlay = '
Loading, please wait...
';
}
//$sh_url = plugin_dir_url( __FILE__ ) . 'assets/sh/';
$sh_url = CRB_Globals::$assets_url . 'sh/';
$sheight = absint( $get['sheight'] ) - 100; // highlighter is un-responsible, so we need tell him the real height
?>
' . $source . '';
if ( $the_file ) {
echo '
Issue: ' . cerber_get_issue_label( $the_file['scan_status'] ) . '
';
}
if ( $paint ) :
?>
$folder->get_error_message() ) );
}
if ( isset( $_FILES['refile'] ) ) {
// Step 1, saving file
if ( ! is_uploaded_file( $_FILES['refile']['tmp_name'] ) ) {
$error = 'Unable to read uploaded file';
}
if ( ! cerber_check_extension( $_FILES['refile']['name'], array( 'zip' ) ) ) {
$error = __( 'This type of file is not supported. Please upload a ZIP archive.', 'wp-cerber' );
}
if ( cerber_detect_exec_extension( $_FILES['refile']['name'] ) ) {
$error = __( 'Executable files are not supported. Please upload a ZIP archive.', 'wp-cerber' );
}
if ( false !== strpos( $_FILES['refile']['name'], '/' ) ) {
$error = 'Incorrect filename';
}
if ( $error ) {
cerber_end_ajax( array( 'error' => $error ) );
}
if ( false === @move_uploaded_file( $_FILES['refile']['tmp_name'], $folder . $_FILES['refile']['name'] ) ) {
cerber_end_ajax( array( 'error' => 'Unable to copy file to ' . $folder ) );
}
}
else {
// Step 2, creating hash
$result = cerber_need_for_hash();
if ( crb_is_wp_error( $result ) ) {
cerber_end_ajax( array( 'error' => $result->get_error_message() ) );
}
}
cerber_end_ajax();
} );
/**
* Deleting files, server side AJAX
*
*/
add_action( 'wp_ajax_cerber_scan_bulk_files', function () {
cerber_check_ajax_permissions();
$post = crb_get_post_fields();
if ( empty( $post['files'] ) || empty( $post['scan_id'] ) ) {
crb_admin_stop_ajax( 'Error!' );
return;
}
$scan_id = absint( $post['scan_id'] );
if ( ! cerber_get_scan( $scan_id ) ) {
crb_admin_stop_ajax( 'Error!' );
return;
}
$operation = $post['scan_file_operation'];
if ( ( ! $ignore = cerber_get_set( 'ignore-list' ) ) || ! is_array( $ignore ) ) {
$ignore = array();
}
global $crb_list;
$crb_list = array();
$i = 0;
$errors = array();
$time = time();
$user_id = get_current_user_id();
foreach ( $post['files'] as $file_name ) {
if ( ! is_file( $file_name ) ) {
continue;
}
$the_file = cerber_db_get_row( 'SELECT * FROM ' . cerber_get_db_prefix() . CERBER_SCAN_TABLE . ' WHERE scan_id = ' . $scan_id . ' AND file_name = "' . $file_name . '"', MYSQL_FETCH_OBJECT );
if ( ! $the_file || ! is_file( $the_file->file_name ) ) {
$errors[] = 'Unknown file: ' . $file_name;
continue;
}
switch ( $operation ) {
case 'delete_file':
$result = cerber_quarantine_file( $file_name, $scan_id );
break;
case 'ignore_add_file':
$ignore[ $the_file->file_name_hash ] = array(
$the_file->file_name,
@hash_file( 'sha256', $the_file->file_name ),
$user_id,
$time,
);
$result = true;
break;
}
if ( crb_is_wp_error( $result ) ) {
$errors[] = $result->get_error_message();
}
elseif ( ! $result ) {
$errors[] = 'Unknown error 55';
}
else {
$i ++;
$crb_list[] = $file_name;
}
}
if ( $operation == 'ignore_add_file' ) {
// Update the last scan results to keep it up to date and avoid user confusing
if ( $scan = cerber_get_scan() ) {
crb_file_filter( $scan['issues'], function ( $file_name ) {
global $crb_list;
if ( in_array( $file_name, $crb_list ) ) {
return false;
}
return true;
} );
cerber_update_scan( $scan );
}
if ( ! cerber_update_set( 'ignore-list', $ignore ) ) {
$errors [] = 'Unable to update the ignore list';
}
}
crb_scan_debug( $errors );
cerber_end_ajax( array( 'errors' => $errors, 'number' => $i, 'processed' => $crb_list ) );
} );
/**
* Finalizes current AJAX request and sends data to the client
*
* @param $data array
*/
function cerber_end_ajax( $data = array() ) {
if ( ! $data ) {
$data = array();
}
$data['cerber_db_errors'] = cerber_db_get_errors();
if ( ! $data['cerber_db_errors'] ) {
$data['OK'] = 'OK!';
}
echo json_encode( $data );
if ( ! nexus_is_valid_request() ) {
wp_die();
}
}
function crb_admin_stop_ajax( $msg = '' ) {
if ( $msg ) {
echo $msg;
}
if ( ! nexus_is_valid_request() ) {
exit;
}
}
function cerber_show_quarantine() {
$folder = cerber_get_the_folder( true );
if ( crb_is_wp_error( $folder ) ) {
echo $folder->get_error_message();
return;
}
$no_files = '
' . __( 'There are no files in the quarantine at the moment.', 'wp-cerber' ) . '
';
$per_page = crb_admin_get_per_page();
$first = ( cerber_get_pn() - 1 ) * $per_page;
$last = $first + $per_page;
$list = array();
$filter_scan = crb_get_query_params( 'scan', '\d+' );
list ( $list, $count, $scan_list ) = cerber_quarantine_get_files( $first, $last, $filter_scan );
_crb_qr_total_sync( $count );
if ( ! $list ) {
if ( ! $filter_scan ) {
echo $no_files;
}
else {
echo __( 'No files match the specified filter.', 'wp-cerber' ) . '
' . __( 'Click here to see the full list of files', 'wp-cerber' ) . '.';
}
return;
}
$rows = array();
$ofs = get_option( 'gmt_offset' ) * 3600;
$confirm = ' onclick="return confirm(\'' . __( 'Are you sure?', 'wp-cerber' ) . '\');"';
foreach ( $list as $file ) {
$p = array(
'cerber_admin_do' => 'scan_tegrity',
'crb_scan_id' => $file['scan_id'],
'crb_file_id' => $file['qfile']
);
$p['crb_scan_adm'] = 'delete';
$delete = '
' . __( 'Delete permanently', 'wp-cerber' ) . '';
$p['crb_scan_adm'] = 'restore';
$restore = ( ! $file['can'] ) ? '' : ' |
' . __( 'Restore', 'wp-cerber' ) . '';
$moved = strtotime( $file['date'] ) - $ofs;
$will = cerber_auto_date( $file['scan_id'] + DAY_IN_SECONDS * crb_get_settings( 'scan_qcleanup' ) );
$file_name = str_replace( DIRECTORY_SEPARATOR, '
' . DIRECTORY_SEPARATOR, $file['source'] );
$rows[] = array(
'' . cerber_auto_date( $file['scan_id'] ) . '',
'' . cerber_auto_date( $moved ) . '',
$will,
$file['size'],
$file_name,
'' . $delete . $restore . ''
);
}
$heading = array(
__( 'Scanned', 'wp-cerber' ),
__( 'Quarantined', 'wp-cerber' ),
__( 'Automatic deletion', 'wp-cerber' ),
__( 'Size', 'wp-cerber' ),
__( 'File', 'wp-cerber' ),
__( 'Action', 'wp-cerber' ),
);
$table = cerber_make_table( $rows, $heading, 'crb-quarantine' );
$table .= cerber_page_navi( $count, $per_page );
$filter = '';
if ( count( $scan_list ) > 1 ) {
krsort( $scan_list );
$list = array( 0 => __( 'All scans', 'wp-cerber' ) );
foreach ( $scan_list as $s ) {
$list[ $s ] = cerber_date( $s, false );
}
$filter = '';
}
echo $filter . $table;
}
function cerber_quarantine_do( $what, $scan_id, $qfile ) {
$scan_id = absint( $scan_id );
if ( ! $scan_id ) {
cerber_admin_notice( 'Error: Wrong scan parameters.' );
return;
}
//$dir = cerber_get_the_folder() . 'quarantine' . DIRECTORY_SEPARATOR . $scan_id;
$dir = cerber_get_the_folder( true );
if ( crb_is_wp_error( $dir ) ) {
cerber_admin_notice( $dir->get_error_message() );
return;
}
$dir .= 'quarantine' . DIRECTORY_SEPARATOR . $scan_id;
$file = $dir . DIRECTORY_SEPARATOR . $qfile;
if ( ! @is_file( $file ) || is_link( $file ) ) {
cerber_admin_notice( 'Error: No file to process' );
return;
}
$rst = $dir . '/.restore';
if ( ! file_exists( $rst ) || ! $handle = @fopen( $rst, 'r' ) ) {
cerber_admin_notice( 'Error: A restore registry file is corrupt or missing.' );
return;
}
$data = null;
while ( ( $line = fgets( $handle ) ) !== false ) {
if ( $p = crb_parse_qline( $dir, $line ) ) {
if ( $p['qfile'] == $qfile ) {
$data = $p;
break;
}
}
}
if ( ! $data ) {
cerber_admin_notice( 'Error: No information about this file. Unable to proceed.' );
return;
}
$err = null;
$msg = null;
switch ( $what ) {
case 'delete':
if ( unlink( $file ) ) {
$msg = __( 'The file has been deleted permanently.', 'wp-cerber' );
crb_qr_total_update( -1 );
}
else {
$err = 'Unable to delete the file: ' . $file;
}
break;
case 'restore':
if ( $data['can'] ) {
$target_dir = dirname( $data['source'] );
if ( ! file_exists( $target_dir ) && ! mkdir( $target_dir, 0755, true ) ) {
$err = 'Unable to create the folder ' . $target_dir . '. Check permissions of parent folders.';
}
if ( ! $err ) {
if ( @rename( $file, $data['source'] ) ) {
$msg = __( 'The file has been restored to its original location.', 'wp-cerber' );
crb_qr_total_update( -1 );
}
else {
$err = 'A file error occurred while restoring the file. Check permissions of folders.';
}
}
}
else {
$err = 'This file cannot be restored and needs to be manually copied. See instructions in this file: ' . $rst . '
';
}
break;
}
if ( $err ) {
cerber_admin_notice( __( 'ERROR:', 'wp-cerber' ) . ' ' . $err );
}
if ( $msg ) {
cerber_admin_message( $msg );
}
}
function cerber_show_ignore() {
// For translators
__( 'Apply', 'wp-cerber' );
__( 'Remove from the list', 'wp-cerber' );
__( 'User Insights', 'wp-cerber' );
__( 'Traffic Insights', 'wp-cerber' );
__( 'Activity Insights', 'wp-cerber' );
$no_files = __( 'The list is empty.', 'wp-cerber' );
$per_page = crb_admin_get_per_page();
$first = ( cerber_get_pn() - 1 ) * $per_page;
if ( ! $list = cerber_get_set( 'ignore-list' ) ) {
echo '' . $no_files . '
';
return;
}
$count = count( $list );
$list = array_slice( $list, $first, $per_page );
$rows = array();
$confirm = ' onclick="return confirm(\'' . __( 'Are you sure?', 'wp-cerber' ) . '\');"';
foreach ( $list as $key => $file ) {
$delete = '' . __( 'Remove from the list', 'wp-cerber' ) . '';
$rows[] = array(
cerber_date( $file[3] ),
cerber_date( cerber_get_date( $file[0] ) ),
crb_size_format( cerber_get_size( $file[0] ) ),
$file[0],
'' . $delete . ''
);
}
$heading = array(
__( 'Added', 'wp-cerber' ),
__( 'Modified', 'wp-cerber' ),
__( 'Size', 'wp-cerber' ),
__( 'File', 'wp-cerber' ),
__( 'Action', 'wp-cerber' ),
);
$table = cerber_make_table( $rows, $heading );
$table .= cerber_page_navi( $count, $per_page );
echo $table;
}
function crb_remove_ignore( $id ) {
if ( ! $list = cerber_get_set( 'ignore-list' ) ) {
return false;
}
if ( ! isset( $list[ $id ] ) ) {
return false;
}
unset( $list[ $id ] );
return cerber_update_set( 'ignore-list', $list );
}
// Scan analytics ===========================================================
function crb_scan_no_message() {
return '' .
__( 'No data for generating reports', 'wp-cerber' ) . '
' .
__( ' Please run the Full Scan. After the scan is completed, analytics reports will be generated.', 'wp-cerber' ) . '
';
}
function cerber_scan_insights() {
if ( ! $scan_id = crb_scan_last_full() ) {
echo crb_scan_no_message();
return;
}
if ( $ext = crb_get_query_params( 'fext' ) ) {
cerber_show_files( $ext, $scan_id );
return;
}
?>
No files found. Please run the Full Scan.';
return;
}
$title = ( $ext == '.' ) ? __( 'Files without extension', 'wp-cerber' ) : 'Files with the "' . $ext . '" extension';
echo '' . $title . '
';
echo crb_make_file_table( $files ) . cerber_page_navi( $total, $per_page );
}
/**
* @param string $type
*
* @return string[]
*
* @since 8.6.4
*/
function cerber_generate_insights( $type ) {
if ( ! $scan_id = crb_scan_last_full() ) {
return array( 'html' => crb_scan_no_message() );
}
$key = 'scan_insights_' . $type;
// Cache
if ( $report = cerber_get_set( $key, $scan_id, false ) ) {
return array( 'html' => $report );
}
switch ( $type ) {
case 1:
$report = crb_scan_insights_brief( $scan_id );
break;
case 2:
$report = crb_scan_insights_lrgst( $scan_id );
break;
case 3:
$report = crb_scan_insights_exts( $scan_id );
break;
}
// Cache
if ( $report ) {
cerber_update_set( $key, $report, $scan_id, false, time() + 24 * 3600 );
}
else {
$report = 'ERROR: Unknown report';
}
$response = array( 'html' => $report, 'error' => '' );
/*if ( $_REQUEST['request'] < 2 ) {
$response['continue'] = 1;
}*/
return $response;
}
function crb_scan_insights_brief( $scan_id ) {
$scan_id = absint( $scan_id );
$table = cerber_get_db_prefix() . CERBER_SCAN_TABLE;
$result = '' . __( 'Brief summary', 'wp-cerber' ) . '
';
$list = array(
array( 'WordPress root folder (ABSPATH) ', ABSPATH ),
array( 'WordPress uploads folder', cerber_get_upload_dir() ),
array( 'WordPress content folder', dirname( cerber_get_plugins_dir() ) ),
array( 'WordPress plugins folder', cerber_get_plugins_dir() ),
array( 'WordPress themes folder', cerber_get_themes_dir() ),
array( 'WordPress must-use plugin folder (WPMU_PLUGIN_DIR) ', WPMU_PLUGIN_DIR ),
array( 'PHP folder for uploading files', ini_get( 'upload_tmp_dir' ) ),
array( 'Server folder for temporary files', sys_get_temp_dir() ),
array( 'Server folder for users\' session data', session_save_path() ),
);
/*
It's not scanned by the scanner
$cerber_folder = cerber_get_my_folder();
if ( ! crb_is_wp_error( $cerber_folder ) ) {
$list[] = array( 'WP Cerber\'s folder', $cerber_folder );
}*/
$folders = array();
foreach ( $list as $item ) {
if ( ! $item[1] || ! @file_exists( $item[1] ) ) {
continue;
}
$item[2] = 0;
$item[3] = 0;
$item[1] = rtrim( $item[1], DIRECTORY_SEPARATOR ) . DIRECTORY_SEPARATOR;
if ( $files = cerber_db_get_col( 'SELECT file_size FROM ' . $table . ' WHERE scan_id = ' . $scan_id . ' AND file_name LIKE "' . $item[1] . '%"' ) ) {
$item[2] = count( $files );
if ( $sum = array_sum( $files ) ) {
$item[3] = crb_size_format( $sum );
}
}
$folders[] = $item;
}
$sql = 'SELECT file_size FROM ' . $table . ' WHERE scan_id = ' . $scan_id . ' AND file_name NOT LIKE "' . ABSPATH . '%"';
$files = cerber_db_get_col( $sql );
if ( $files ) {
if ( $sum = array_sum( $files ) ) {
$sum = crb_size_format( $sum );
}
$folders[] = array( 'Above the WordPress installation folder', '', count( $files ), $sum );
}
$column = array_column( $folders, 2 );
array_multisort( $column, SORT_DESC, $folders );
return $result . cerber_make_table( $folders, array(
__( 'Folder', 'wp-cerber' ),
__( 'Path', 'wp-cerber' ),
__( 'Files', 'wp-cerber' ),
__( 'Space Occupied', 'wp-cerber' )
), '', 'crb_align_right crb_align_left_2', 'crb-monospace' );
}
function crb_scan_insights_exts( $scan_id ) {
$scan_id = absint( $scan_id );
$table = cerber_get_db_prefix() . CERBER_SCAN_TABLE;
$list = array();
$offset = 0;
$total = 0;
$done = false;
//cerber_exec_timer( 15 );
while ( true ) {
if ( ! $files = cerber_db_get_results( 'SELECT file_name, file_name_hash, file_mtime, file_size, file_ext FROM ' . $table . ' WHERE scan_id = ' . $scan_id . ' LIMIT ' . CRB_SQL_CHUNK . ' OFFSET ' . $offset ) ) {
$done = true;
break;
}
$offset += CRB_SQL_CHUNK;
foreach ( $files as $file ) {
if ( ! $ext = crb_get_extension( $file['file_name'] ) ) {
$ext = '.';
}
if ( empty( $file['file_ext'] ) ) {
cerber_db_query( 'UPDATE ' . $table . ' SET file_ext = "' . $ext . '" WHERE scan_id = ' . $scan_id . ' AND file_name_hash = "' . $file['file_name_hash'] . '"' );
}
if ( ! isset( $list[ $ext ] ) ) {
$list[ $ext ] = array( 0, 0, array(), array() );
}
$list[ $ext ][0] ++;
$list[ $ext ][1] += $file['file_size'];
$list[ $ext ][2][] = $file['file_size'];
$list[ $ext ][3][] = $file['file_mtime'];
$total ++;
}
}
if ( ! $done && ( count( $files ) < CRB_SQL_CHUNK ) ) {
$done = true;
}
if ( ! $done ) {
return array( 'continue' => 1 );
}
if ( ! $list ) {
return crb_scan_no_message();
}
$base = cerber_admin_link( 'scan_insights' );
$none = __( 'No extension', 'wp-cerber' );
$result = array();
foreach ( $list as $ext => $data ) {
$text = ( $ext == '.' ) ? $none : $ext;
$result[] = array(
'' . $text . '',
$data[0],
crb_size_format( $data[1] ),
crb_size_format( min( $data[2] ) ),
crb_size_format( max( $data[2] ) ),
crb_size_format( round( $data[1] / $data[0], 0 ) ),
cerber_date( min( $data[3] ) ),
cerber_date( max( $data[3] ) ),
);
}
// Sorting by a column in a multidimensional array
$column = array_column( $result, 1 );
array_multisort( $column, SORT_DESC, $result );
// Create table
//$report = 'The file system report is based on the last full scan.
';
$report = '' . __( 'File extensions statistics', 'wp-cerber' ) . '
';
$report .= cerber_make_table( $result, array(
__( 'Extension', 'wp-cerber' ),
__( 'Files', 'wp-cerber' ),
__( 'Space Occupied', 'wp-cerber' ),
__( 'Smallest', 'wp-cerber' ),
__( 'Largest', 'wp-cerber' ),
__( 'Average Size', 'wp-cerber' ),
__( 'Oldest', 'wp-cerber' ),
__( 'Newest', 'wp-cerber' ),
), 'crb-ext-statistics', 'crb_align_right', 'crb-monospace crb-anchor-decorated' );
return $report;
}
function crb_scan_insights_lrgst( $scan_id ) {
$scan_id = absint( $scan_id );
$table = cerber_get_db_prefix() . CERBER_SCAN_TABLE;
if ( ! $files = cerber_db_get_results( 'SELECT file_name, file_mtime, file_size FROM ' . $table . ' WHERE scan_id = ' . $scan_id . ' ORDER BY file_size DESC LIMIT 10' ) ) {
return crb_scan_no_message();
}
$title = '' . __( 'Top 10 largest files', 'wp-cerber' ) . '
';
return $title . crb_make_file_table( $files );
}
function crb_scan_insights_duplicates( $scan_id ) {
$scan_id = absint( $scan_id );
// SQL Doesn't work
/* ( ! $files = cerber_db_get_results( 'SELECT file_name, file_mtime, file_size, file_hash FROM ' . cerber_get_db_prefix() . CERBER_SCAN_TABLE . ' WHERE scan_id = ' . $scan_id . ' GROUP BY file_hash HAVING COUNT(*) > 1 LIMIT 100' ) ) {
return '';
}*/
if ( ! $files = cerber_db_get_col( 'SELECT file_hash FROM ' . cerber_get_db_prefix() . CERBER_SCAN_TABLE . ' WHERE scan_id = ' . $scan_id . ' AND file_size !=0 AND file_hash !="" ' ) ) {
return crb_scan_no_message();
}
$dup = array_unique( array_diff_assoc( $files, array_unique( $files ) ) );
rsort( $dup );
$list = array();
foreach ( $dup as $hash ) {
if ( $fl = cerber_db_get_results( 'SELECT file_name, file_mtime, file_size FROM ' . cerber_get_db_prefix() . CERBER_SCAN_TABLE . ' WHERE scan_id = ' . $scan_id . ' AND file_hash = "' . $hash . '"' ) ) {
$list = array_merge( $list, $fl );
}
}
$result = 'Duplicate files
';
return $result . crb_make_file_table( $list );
}
function crb_scan_last_full() {
$scans = cerber_db_get_col( 'SELECT DISTINCT scan_id FROM ' . cerber_get_db_prefix() . CERBER_SCAN_TABLE . ' WHERE scan_mode = 1 ORDER BY scan_id DESC LIMIT 1' );
if ( $scans ) {
$scan_id = $scans[0];
$scan = cerber_get_scan( $scan_id );
if ( $scan['finished']
|| ( $scan['aborted'] && $scan['next_step'] > 5 ) ) { // Step 5 is enough for analysis
return $scan_id;
}
}
return false;
}
/**
* @param int $user_id
* @param string $tab
* @param bool $cache_only
*
* @return string
*/
function crb_generate_user_insights( $user_id, $tab, $cache_only = false ) {
if ( $tab != 'activity' ) {
$tab = 'traffic';
}
$result = '';
$links = array();
if ( $user = get_userdata( $user_id ) ) {
$labels = cerber_get_labels();
$list = array();
if ( $data = crb_q_cache_get( 'SELECT COUNT(activity) as cnt, activity FROM ' . CERBER_LOG_TABLE . ' WHERE user_id = ' . $user_id . ' GROUP BY activity', CERBER_LOG_TABLE, $cache_only ) ) {
foreach ( $data as $item ) {
$list[ $item[1] ] = 1;
$links[] = array( array( 'filter_activity' => $item[1], 'filter_user' => $user_id ), crb_array_get( $labels, $item[1], 'Unknown' ) . ' - ' . $item[0] );
}
}
if ( $tab == 'activity' ) {
if ( $data = crb_q_cache_get( 'SELECT COUNT(activity) as cnt, activity FROM ' . CERBER_LOG_TABLE . ' WHERE user_login = "' . $user->user_login . '" OR user_login = "' . $user->user_email . '" GROUP BY activity', CERBER_LOG_TABLE, $cache_only ) ) {
foreach ( $data as $item ) {
if ( isset( $list[ $item[1] ] ) ) {
continue;
}
$links[] = array( array( 'filter_activity' => $item[1], 'filter_login' => $user->user_login . '|' . $user->user_email ), crb_array_get( $labels, $item[1], 'Unknown' ) . ' - ' . $item[0] );
}
}
}
if ( $links ) {
array_unshift( $links, array( array( 'filter_user' => $user_id ), __( 'All' ) ) );
$result = '' . crb_make_nav_links( $links, $tab ) . '
';
}
}
if ( ! $result ) {
if ( $cache_only ) {
return '';
}
$result = __( 'No activity has been logged yet.', 'wp-cerber' );
}
return $result;
}
// Miscellaneous admin routines ===========================================================
/**
* Detects file extension
*
* @param string $file_name
*
* @return string
*/
function crb_get_extension( $file_name ) {
$name = basename( $file_name );
if ( $name == '.htaccess' ) {
return '';
}
if ( false === ( $last_dot = strrpos( $name, '.' ) ) ) {
return '';
}
/*$first_dot = strpos( $name, '.' );
if ( $last_dot !== $first_dot
&& cerber_detect_exec_extension( $name ) ) {
$ext = substr( $name, $first_dot + 1 );
}
else {
$ext = substr( $name, $last_dot + 1 );
}*/
$ext = substr( $name, $last_dot + 1 );
if ( ! $ext ) {
$ext = '';
}
return $ext;
}
function crb_make_file_table( $files ) {
$result = array();
foreach ( $files as $file ) {
$result[] = array(
$file['file_name'],
crb_size_format( $file['file_size'] ),
cerber_date( $file['file_mtime'] ),
);
}
return cerber_make_table( $result, array(
__( 'File Name', 'wp-cerber' ),
__( 'Size', 'wp-cerber' ),
__( 'Modified', 'wp-cerber' ),
), '', 'crb_align_right', 'crb-monospace crb-anchor-decorated' );
}
/**
* Generates an HTML table
*
* @param $heading
* @param $rows
* @param string $id
* @param $class
* @param string $body_class
* @param string $head_class
* @param bool $show_footer
*
* @return string
* @since 8.6.4
*
*/
function cerber_make_table( $rows, $heading = array(), $id = '', $class = '', $body_class = '', $head_class = '', $show_footer = true ) {
$tr = array();
foreach ( $rows as $row ) {
$tr[] = '' . implode( ' | ', $row ) . ' | ';
}
$tfoot = '';
$thead = '';
if ( $heading ) {
$titles = '| ' . implode( ' | ', $heading ) . ' |
';
$thead = '' . $titles . '';
if ( $show_footer ) {
$tfoot = '' . $titles . '';
}
}
$id = ( $id ) ? 'id="' . $id . '"' : '';
return '' . $thead . $tfoot . '' . implode( '
', $tr ) . '
';
}
function cerber_get_chmod( $file ) {
return substr( sprintf( '%o', @fileperms( $file ) ), - 4 );
}
function cerber_get_size( $file ) {
$size = @filesize( $file );
return ( is_numeric( $size ) ) ? $size : 0;
}
function cerber_get_date( $file ) {
$mtime = @filemtime( $file );
return ( is_numeric( $mtime ) ) ? $mtime : 0;
}
function crb_show_admin_announcement( $text = '', $big = true ) {
$class = ( $big ) ? 'crb-cerber-logo-big' : 'crb-cerber-logo-small';
echo '';
}
/**
* Returns GET (query string) params of the currently displayed page
*
* @return array
*/
function crb_get_referrer_params() {
if ( cerber_is_wp_ajax() ) {
$referrer = array();
if ( $ref_url = crb_get_request_field( 'referrer_page_url' ) ) {
if ( $temp = parse_url( $ref_url, PHP_URL_QUERY ) ) {
parse_str( $temp, $referrer );
}
}
}
else {
$referrer = crb_get_query_params();
}
if ( ! is_array( $referrer ) ) {
$referrer = array();
}
array_walk_recursive( $referrer, function ( &$item ) {
$item = preg_replace( '/[^\w\-.:*|@]/i', '', $item ); // Some sanitization
} );
return $referrer;
}
add_filter( 'manage_application-passwords-user_columns', function ( $columns ) {
end( $columns );
$key = key( $columns );
$last = array_pop( $columns );
return array_merge( $columns,
array(
'app_cerber_log_ok' => __( 'Authorized', 'wp-cerber' ),
'app_cerber_log_fail' => __( 'Authorization Failed', 'wp-cerber' ),
$key => $last
) );
} );
add_action( 'manage_application-passwords-user_custom_column', function ( $column_name, $item ) {
global $user_id;
if ( $column_name == 'app_cerber_log_ok' && ! empty( $item['last_ip'] ) ) {
$link = cerber_activity_link( array( 4 ) ) . '&filter_user=' . $user_id;
echo 'View Log';
}
if ( $column_name == 'app_cerber_log_fail' ) {
$user = get_user_by( 'ID', $user_id );
$link = cerber_activity_link( array( 8 ) ) . '&filter_login=' . $user->user_email . '|' . $user->user_login;
echo 'View Log';
}
}, 10, 2 );
/**
* @param string $fname
* @param string $ct Content-Type @since 8.6.9
*/
function crb_file_headers( $fname, $ct = 'text/csv' ) {
$fname = rawurlencode( $fname ); // encode non-ASCII symbols
@ob_clean(); // This trick is crucial for some servers/environments (e.g. some IIS)
header( "Content-Type: " . $ct );
header( "Content-Disposition: attachment; filename*=UTF-8''{$fname}" );
}