/home/awneajlw/faizastore.com/wp-content/plugins/wp-ultimate-review/helper/helper.php
<?php
namespace WurReview\Helper;
use WurReview\Utilities\Whip_Ip_Validator\Whip;
defined('ABSPATH') || exit;
class Helper {
public static function avarage_loop($review, $limit) {
return $review * (100 / $limit);
}
public static function avarage_final($loop, $limit, $avarage) {
if ($loop == 0 || $limit == 0) {
return 0;
}
return $limit * ($avarage / $loop / 100);
}
/**
* get request client IP address
* Security Fix: CVE-2024-32708 - IP Spoofing Vulnerability
* By default, only trust REMOTE_ADDR to prevent authentication bypass by spoofing.
* Proxy headers (CF-Connecting-IP, X-Forwarded-For, etc.) can be easily
* spoofed by attackers to bypass IP-based rate limiting.
*
* Users can optionally enable proxy header detection if they trust their
* proxy infrastructure (e.g., behind CloudFlare with proper configuration).
*
* @return mixed
*/
public static function ip_address() {
//A third party library used from https://github.com/Vectorface/whip
// Get the IP detection method from settings (default to secure REMOTE_ADDR)
$global_settings = get_option('xs_review_global', []);
$ip_detection_method = isset($global_settings['ip_detection_method']) ? $global_settings['ip_detection_method'] : 'remote_addr';
// Security: Default to REMOTE_ADDR only - cannot be spoofed by clients
// Only enable proxy headers if explicitly configured by admin
if ($ip_detection_method === 'proxy_headers') {
// Allow CloudFlare and other proxy headers (user opted-in)
// WARNING: This can be bypassed by spoofing headers
$whip = new Whip(Whip::CLOUDFLARE_HEADERS | Whip::REMOTE_ADDR);
} else {
// Secure default: Only use REMOTE_ADDR
$whip = new Whip(Whip::REMOTE_ADDR);
}
$clientAddress = $whip->getValidIpAddress();
return $clientAddress ?? null;
}
/**
* todo - remove all usage of \WurReview\Init::$controls; later
*
* @return array
*/
public static function get_review_form_config() {
return [
'xs_reviwer_ratting' => [
'title_name' => 'Rating',
'type' => 'select',
'id' => 'xs_ratting_id',
'require' => 'Yes',
'class' => 'xs_rating_class',
'options' => [
'1' => '1 Star',
'2' => '2 Star',
'3' => '3 Star',
'4' => '4 Star',
'5' => '5 Star',
],
],
'xs_reviw_title' => [
'title_name' => 'Review Title',
'type' => 'text',
'require' => 'Yes',
'options' => [],
],
'xs_reviwer_name' => [
'title_name' => 'Reviewer Name',
'type' => 'text',
'require' => 'No',
'options' => [],
],
'xs_reviwer_email' => [
'title_name' => 'Reviewer Email',
'type' => 'text',
'require' => 'Yes',
'options' => [],
],
'xs_reviwer_website' => [
'title_name' => 'Website',
'type' => 'text',
'require' => 'No',
'options' => [],
],
'xs_reviw_summery' => [
'title_name' => 'Review Summary',
'type' => 'textarea',
'require' => 'Yes',
'options' => [],
],
];
}
public static function _decode_json_unicode($json_string = '') {
if (empty($json_string)) {
return null;
}
// First decode the JSON with proper flags
$decoded = json_decode($json_string, false, 512, JSON_UNESCAPED_UNICODE);
// If decoding was successful, process the result recursively
if ($decoded !== null) {
return self::_process_unicode_data($decoded);
}
return $decoded;
}
private static function _process_unicode_data($data) {
if (is_object($data)) {
foreach ($data as $key => $value) {
if (is_string($value)) {
$data->$key = self::_fix_unicode_string($value);
} elseif (is_object($value) || is_array($value)) {
$data->$key = self::_process_unicode_data($value);
}
}
} elseif (is_array($data)) {
foreach ($data as $key => $value) {
if (is_string($value)) {
$data[$key] = self::_fix_unicode_string($value);
} elseif (is_object($value) || is_array($value)) {
$data[$key] = self::_process_unicode_data($value);
}
}
}
return $data;
}
private static function _fix_unicode_string($string) {
// Handle emoji surrogate pairs FIRST (like ud83dude0a for emojis)
$string = preg_replace_callback('/u([0-9a-fA-F]{4})u([0-9a-fA-F]{4})/', function($matches) {
// This is a surrogate pair for emojis
$high = hexdec($matches[1]);
$low = hexdec($matches[2]);
if ($high >= 0xD800 && $high <= 0xDBFF && $low >= 0xDC00 && $low <= 0xDFFF) {
// Valid surrogate pair
$codepoint = 0x10000 + (($high & 0x3FF) << 10) + ($low & 0x3FF);
return mb_chr($codepoint, 'UTF-8');
}
// If not a valid surrogate pair, handle individually
return mb_convert_encoding(pack('H*', $matches[1]), 'UTF-8', 'UCS-2BE') .
mb_convert_encoding(pack('H*', $matches[2]), 'UTF-8', 'UCS-2BE');
}, $string);
// Handle Unicode sequences with backslashes (like \u00c1)
$string = preg_replace_callback('/\\\\u([0-9a-fA-F]{4})/', function($matches) {
return mb_convert_encoding(pack('H*', $matches[1]), 'UTF-8', 'UCS-2BE');
}, $string);
// Handle remaining single Unicode sequences without backslashes (like u00c1)
$string = preg_replace_callback('/u([0-9a-fA-F]{4})/', function($matches) {
return mb_convert_encoding(pack('H*', $matches[1]), 'UTF-8', 'UCS-2BE');
}, $string);
// Handle other JSON escape sequences
$string = str_replace(['\\"', '\\/', '\\\\', '\\b', '\\f', '\\n', '\\r', '\\t'],
['"', '/', '\\', "\b", "\f", "\n", "\r", "\t"], $string);
// Ensure proper UTF-8 encoding
if (!mb_check_encoding($string, 'UTF-8')) {
$string = mb_convert_encoding($string, 'UTF-8', 'auto');
}
return $string;
}
}