| 1 |
<?php |
| 2 |
|
| 3 |
namespace FluentCart\App\Services; |
| 4 |
|
| 5 |
class ReviewSubmissionLimiter |
| 6 |
{ |
| 7 |
/** Persist attempts across requests, including sites without Redis. */ |
| 8 |
public static function increment(string $identity): int |
| 9 |
{ |
| 10 |
$key = 'fct_review_rate_' . $identity; |
| 11 |
if (wp_using_ext_object_cache()) { |
| 12 |
wp_cache_add($key, 0, 'fluent_cart_reviews', HOUR_IN_SECONDS); |
| 13 |
$count = wp_cache_incr($key, 1, 'fluent_cart_reviews'); |
| 14 |
|
| 15 |
return $count === false ? PHP_INT_MAX : (int) $count; |
| 16 |
} |
| 17 |
|
| 18 |
global $wpdb; |
| 19 |
$lock = 'fct_review_rate_' . md5(constant('DB_NAME') . ':' . $wpdb->options . ':' . $key); |
| 20 |
if ((string) $wpdb->get_var($wpdb->prepare('SELECT GET_LOCK(%s, 1)', $lock)) !== '1') { |
| 21 |
return PHP_INT_MAX; |
| 22 |
} |
| 23 |
|
| 24 |
try { |
| 25 |
wp_cache_delete('_transient_' . $key, 'options'); |
| 26 |
wp_cache_delete('_transient_timeout_' . $key, 'options'); |
| 27 |
wp_cache_delete('notoptions', 'options'); |
| 28 |
$state = get_transient($key); |
| 29 |
$now = time(); |
| 30 |
if (!is_array($state) || ($state['expires'] ?? 0) <= $now) { |
| 31 |
$state = ['count' => 0, 'expires' => $now + HOUR_IN_SECONDS]; |
| 32 |
} |
| 33 |
$state['count']++; |
| 34 |
|
| 35 |
return set_transient($key, $state, max(1, $state['expires'] - $now)) |
| 36 |
? (int) $state['count'] : PHP_INT_MAX; |
| 37 |
} finally { |
| 38 |
$wpdb->get_var($wpdb->prepare('SELECT RELEASE_LOCK(%s)', $lock)); |
| 39 |
} |
| 40 |
} |
| 41 |
} |
| 42 |
|