$action, 'user_id' => get_current_user_id(), ) ); if ( $die_on_fail ) { wp_die( __( 'Security check failed. Please refresh the page and try again.', 'hvac-community-events' ) ); } } return $is_valid; } /** * Check if current user has required capability * * @param string $capability The capability to check * @param bool $die_on_fail Whether to die on failure * @return bool */ public static function check_capability( $capability, $die_on_fail = false ) { $has_cap = current_user_can( $capability ); if ( ! $has_cap ) { HVAC_Logger::warning( 'Capability check failed', 'Security', array( 'capability' => $capability, 'user_id' => get_current_user_id(), ) ); if ( $die_on_fail ) { wp_die( __( 'You do not have permission to perform this action.', 'hvac-community-events' ) ); } } return $has_cap; } /** * Check if user is logged in with optional redirect * * @param string $redirect_to URL to redirect if not logged in * @return bool */ public static function require_login( $redirect_to = '' ) { if ( ! is_user_logged_in() ) { if ( ! empty( $redirect_to ) ) { wp_safe_redirect( $redirect_to ); exit; } return false; } return true; } /** * Sanitize and validate email * * @param string $email Email to validate * @return string|false Sanitized email or false if invalid */ public static function sanitize_email( $email ) { $email = sanitize_email( $email ); return is_email( $email ) ? $email : false; } /** * Sanitize and validate URL * * @param string $url URL to validate * @return string|false Sanitized URL or false if invalid */ public static function sanitize_url( $url ) { $url = esc_url_raw( $url ); return filter_var( $url, FILTER_VALIDATE_URL ) ? $url : false; } /** * Sanitize array of values * * @param array $array Array to sanitize * @param string $type Type of sanitization (text|email|url|int) * @return array */ public static function sanitize_array( $array, $type = 'text' ) { if ( ! is_array( $array ) ) { return array(); } $sanitized = array(); foreach ( $array as $key => $value ) { switch ( $type ) { case 'email': $clean = self::sanitize_email( $value ); if ( $clean ) { $sanitized[ $key ] = $clean; } break; case 'url': $clean = self::sanitize_url( $value ); if ( $clean ) { $sanitized[ $key ] = $clean; } break; case 'int': $sanitized[ $key ] = intval( $value ); break; default: $sanitized[ $key ] = sanitize_text_field( $value ); } } return $sanitized; } /** * Escape output based on context * * @param mixed $value Value to escape * @param string $context Context (html|attr|url|js) * @return string */ public static function escape_output( $value, $context = 'html' ) { switch ( $context ) { case 'attr': return esc_attr( $value ); case 'url': return esc_url( $value ); case 'js': return esc_js( $value ); case 'textarea': return esc_textarea( $value ); default: return esc_html( $value ); } } /** * Check if request is AJAX * * @return bool */ public static function is_ajax_request() { return defined( 'DOING_AJAX' ) && DOING_AJAX; } /** * Get user IP address * * @return string */ public static function get_user_ip() { $ip = ''; if ( ! empty( $_SERVER['HTTP_CLIENT_IP'] ) ) { $ip = $_SERVER['HTTP_CLIENT_IP']; } elseif ( ! empty( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) { $ip = $_SERVER['HTTP_X_FORWARDED_FOR']; } elseif ( ! empty( $_SERVER['REMOTE_ADDR'] ) ) { $ip = $_SERVER['REMOTE_ADDR']; } return sanitize_text_field( $ip ); } /** * Rate limiting check * * @param string $action Action to limit * @param int $limit Number of attempts allowed * @param int $window Time window in seconds * @param string $identifier User identifier (defaults to IP) * @return bool True if within limits, false if exceeded */ public static function check_rate_limit( $action, $limit = 5, $window = 300, $identifier = null ) { if ( null === $identifier ) { $identifier = self::get_user_ip(); } $key = 'hvac_rate_limit_' . md5( $action . $identifier ); $attempts = get_transient( $key ); if ( false === $attempts ) { set_transient( $key, 1, $window ); return true; } if ( $attempts >= $limit ) { HVAC_Logger::warning( 'Rate limit exceeded', 'Security', array( 'action' => $action, 'identifier' => $identifier, 'attempts' => $attempts, ) ); return false; } set_transient( $key, $attempts + 1, $window ); return true; } }