isset( $args['locale'] ) ? $args['locale'] : '' ) ); case 'autoloaded': return miintg_list_autoloaded_code(); case 'uploads': return miintg_scan_uploads_anomalies(); case 'plugins': return miintg_verify_plugin_checksums( array( 'plugins' => isset( $args['plugins'] ) ? $args['plugins'] : '', 'max_plugins' => isset( $args['max_plugins'] ) ? $args['max_plugins'] : null, ) ); case 'config': return miintg_check_config_integrity(); case 'users': return miintg_audit_privileged_users(); default: return null; } } /** * Severity counts for one check's result. 'plugins' nests severity one * level deeper (per plugin), every other check exposes it at the top. * Shared by the synchronous wrapper and the background scanner so both * roll up totals the same way. * * @param string $check Check name. * @param array $out That check's enveloped result. * @return array { critical: int, review: int } */ function miintg_check_severity( $check, $out ) { $critical = 0; $review = 0; if ( 'plugins' === $check ) { foreach ( ( $out['plugins'] ?? array() ) as $plugin ) { $critical += (int) ( $plugin['severity']['critical'] ?? 0 ); $review += (int) ( $plugin['severity']['review'] ?? 0 ); } } else { $critical += (int) ( $out['severity']['critical'] ?? 0 ); $review += (int) ( $out['severity']['review'] ?? 0 ); } return array( 'critical' => $critical, 'review' => $review, ); } /** * @param array $args { * @type string $checks Optional comma-separated subset of * core,autoloaded,uploads,plugins,config,users. * Omit to run all six. * @type string $plugins Passed through to wp_verify_plugin_checksums. * @type int $max_plugins Passed through to wp_verify_plugin_checksums. * @type string $locale Passed through to wp_core_verify_checksums. * } * @return array */ function miintg_full_scan( $args = array() ) { $available = miintg_full_scan_available_checks(); $requested = $available; if ( ! empty( $args['checks'] ) ) { $requested = array_filter( array_map( 'trim', explode( ',', (string) $args['checks'] ) ) ); $requested = array_values( array_intersect( $available, $requested ) ); if ( empty( $requested ) ) { $requested = $available; } } $start = microtime( true ); $results = array(); $errors = array(); foreach ( $requested as $check ) { $out = miintg_run_single_check( $check, $args ); if ( null === $out ) { continue; } $results[ $check ] = $out; if ( empty( $out['ok'] ) ) { $errors[] = $check . ': ' . ( isset( $out['error'] ) ? $out['error'] : 'unknown error' ); } } /* ----------------------------------------------------------------- * Roll up severity. Tools that don't expose a 'severity' key * (wouldn't happen for these six, but defensive) contribute 0. * -------------------------------------------------------------- */ $critical = 0; $review = 0; foreach ( $results as $check => $out ) { $sev = miintg_check_severity( $check, $out ); $critical += $sev['critical']; $review += $sev['review']; } return miintg_envelope( 'wp_integrity_scan', array( 'checks_requested' => $requested, 'checks_completed' => array_keys( $results ), 'duration_seconds' => round( microtime( true ) - $start, 2 ), 'severity_totals' => array( 'critical' => $critical, 'review' => $review, ), 'results' => $results, 'errors' => $errors, 'notes' => 'Aggregates the six per-tool results unchanged — each retains its own notes and caveats (e.g. themes out of scope for plugins, no manifest for config files). This wrapper adds nothing beyond bundling calls and summing severities.', ), empty( $errors ) ); }