HEX
Server: LiteSpeed
System: Linux server315.web-hosting.com 4.18.0-553.54.1.lve.el8.x86_64 #1 SMP Wed Jun 4 13:01:13 UTC 2025 x86_64
User: globfdxw (6114)
PHP: 8.1.34
Disabled: NONE
Upload Files
File: /home/globfdxw/www/wp-content/plugins/wpforms-surveys-polls/src/Reporting/Helpers.php
<?php

namespace WPFormsSurveys\Reporting;

/**
 * Reporting helpers.
 *
 * Shared utilities for Surveys & Polls reporting layer.
 *
 * @since 1.18.0
 */
class Helpers {
	/**
	 * Recursively sanitize filters structure (keys and values).
	 *
	 * Use sanitize_key() for array keys, sanitize_text_field() for strings,
	 * cast numerics to int, and normalize booleans to 0/1. Arrays are processed
	 * recursively.
	 *
	 * @since 1.18.0
	 *
	 * @param mixed $value Raw value to sanitize.
	 *
	 * @return mixed Sanitized value.
	 */
	public static function sanitize_filters_array( $value ) {

		if ( is_numeric( $value ) ) {
			return (int) $value;
		}

		if ( is_bool( $value ) ) {
			return $value ? 1 : 0;
		}

		if ( is_string( $value ) ) {
			return sanitize_text_field( $value );
		}

		if ( is_array( $value ) ) {
			$sanitized = [];

			foreach ( $value as $key => $val ) {
				$sanitized[ sanitize_key( (string) $key ) ] = self::sanitize_filters_array( $val );
			}

			return $sanitized;
		}

		return $value;
	}

	/**
	 * Normalize filters for stable comparisons and cache keys.
	 *
	 * Recursively ksort associative arrays. For list-like arrays (numeric
	 * sequential keys starting at 0), cast values to strings and sort them.
	 * Booleans are normalized to integers 0/1 for stability.
	 *
	 * @since 1.18.0
	 *
	 * @param mixed $value Filters value.
	 *
	 * @return mixed Normalized value.
	 */
	public static function normalize_filters( $value ) {

		if ( ! is_array( $value ) ) {
			return is_bool( $value ) ? (int) $value : $value;
		}

		$value   = array_map( [ __CLASS__, 'normalize_filters' ], $value );
		$keys    = array_keys( $value );
		$is_list = $keys === array_keys( $keys );

		if ( ! $is_list ) {
			ksort( $value );

			return $value;
		}

		$casted = array_map( [ __CLASS__, 'cast_filter_value' ], $value );

		sort( $casted );

		return $casted;
	}

	/**
	 * Cast a single filter value to a string for locale-safe sorting.
	 *
	 * Booleans become '0'/'1'. Scalars and objects implementing __toString
	 * are cast to string. Everything else passes through unchanged.
	 *
	 * @since 1.18.0
	 *
	 * @param mixed $item Filter value.
	 *
	 * @return mixed Cast value.
	 */
	private static function cast_filter_value( $item ) {

		if ( is_bool( $item ) ) {
			return $item ? '1' : '0';
		}

		if ( is_scalar( $item ) || ( is_object( $item ) && method_exists( $item, '__toString' ) ) ) {
			return (string) $item;
		}

		return $item;
	}

	/**
	 * Ensure array-like filter keys use array values.
	 *
	 * Cast values for keys prefixed with 'field_'.
	 *
	 * @since 1.18.0
	 *
	 * @param mixed $filters Raw filters value.
	 *
	 * @return mixed Filters with array-like keys coerced to arrays.
	 */
	public static function ensure_array_fields( $filters ) {

		if ( ! is_array( $filters ) ) {
			return $filters;
		}

		foreach ( $filters as $key => $value ) {
			if ( strpos( (string) $key, 'field_' ) !== 0 ) {
				continue;
			}

			$filters[ $key ] = (array) $value;
		}

		return $filters;
	}
}