PluginProbe ʕ •ᴥ•ʔ
WooCommerce / 10.9.3
WooCommerce v10.9.3
10.9.4 10.9.3 10.9.2 10.9.1 10.9.0 10.9.0-rc.1 10.9.0-beta.2 10.9.0-beta.1 10.8.1 10.8.0 10.8.0-rc.1 10.8.0-beta.2 10.8.0-beta.1 7.8.0-beta.1 7.8.0-beta.2 7.8.0-rc.1 7.8.0-rc.2 7.8.1 7.8.2 7.8.3 7.8.4 7.9.0 7.9.0-beta.1 7.9.0-beta.2 7.9.0-rc.2 7.9.0-rc.3 7.9.1 7.9.2 8.0.0 8.0.0-beta.1 8.0.0-beta.2 8.0.0-rc.1 8.0.0-rc.2 8.0.1 8.0.2 8.0.3 8.0.4 8.0.5 8.1.0 8.1.0-beta.1 8.1.0-rc.1 8.1.0-rc.2 8.1.1 8.1.2 8.1.3 8.1.4 8.2.0 8.2.0-beta.1 8.2.0-rc.1 8.2.0-rc.2 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.3.0 8.3.0-beta.1 8.3.0-rc.1 8.3.0-rc.2 8.3.1 8.3.2 8.3.3 8.3.4 8.4.0 8.4.0-beta.1 8.4.0-rc.1 8.4.1 8.4.2 8.4.3 8.5.0 8.5.0-beta.1 8.5.0-rc.1 8.5.1 8.5.2 8.5.3 8.5.4 8.5.5 8.6.0 8.6.0-beta.1 8.6.0-rc.1 8.6.1 8.6.2 8.6.3 8.6.4 8.7.0 8.7.0-beta.1 8.7.0-beta.2 8.7.0-rc.1 8.7.1 8.7.2 8.7.3 8.8.0 8.8.0-beta.1 8.8.0-rc.1 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.8.6 8.8.7 8.9.0 8.9.0-beta.1 8.9.0-rc.1 8.9.1 8.9.2 8.9.3 8.9.4 8.9.5 9.0.0 9.0.0-beta.1 9.0.0-beta.2 9.0.0-rc.1 9.0.1 9.0.2 9.0.3 9.0.4 9.1.0 9.1.0-beta.1 9.1.0-rc.1 9.1.1 9.1.2 9.1.3 9.1.4 9.1.5 9.1.6 9.2.0 9.2.0-beta.1 9.2.0-rc.1 9.2.1 9.2.2 9.2.3 9.2.4 9.2.5 9.3.0 9.3.0-beta.1 9.3.0-rc.1 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.3.6 9.4.0 9.4.0-beta.1 9.4.0-beta.2 9.4.0-rc.1 9.4.0-rc.2 9.4.0-rc.3 9.4.0-rc.4 9.4.1 9.4.2 9.4.3 9.4.4 9.4.5 9.5.0 9.5.0-beta.1 9.5.0-beta.2 9.5.0-rc.1 9.5.1 9.5.2 9.5.3 9.5.4 9.6.0 9.6.0-beta.1 9.6.0-beta.2 9.6.0-rc.1 9.6.1 9.6.2 9.6.3 9.6.4 9.7.0 9.7.0-beta.1 9.7.0-rc.1 9.7.1 9.7.2 9.7.3 9.8.0 9.8.0-beta.1 9.8.0-rc.1 9.8.1 9.8.2 9.8.3 9.8.4 9.8.5 9.8.6 9.8.7 9.9.0 9.9.0-beta.1 9.9.0-rc.1 9.9.1 9.9.2 9.9.3 9.9.4 9.9.5 9.9.6 9.9.7 3.7.3 7.1.2 3.8.0 7.2.0 3.8.0-beta.1 7.2.0-beta.1 3.8.0-rc.1 7.2.0-beta.2 3.8.0-rc.2 7.2.0-rc.1 3.8.1 7.2.0-rc.2 3.8.2 7.2.1 3.8.3 7.2.2 3.9.0 7.2.3 3.9.0-beta.1 7.2.4 3.9.0-beta.2 7.3.0 3.9.0-rc.1 7.3.0-beta.1 3.9.0-rc.2 7.3.0-beta.2 3.9.0-rc.3 7.3.0-rc.1 3.9.0-rc.4 7.3.0-rc.2 3.9.1 7.3.1 3.9.2 7.4.0 3.9.3 7.4.0-beta.1 3.9.4 7.4.0-beta.2 3.9.5 7.4.0-rc.1 4.0.0 7.4.0-rc.2 4.0.0-beta.1 7.4.1 4.0.0-rc.1 7.4.2 4.0.0-rc.2 7.5.0 4.0.1 7.5.0-beta.1 4.0.2 7.5.0-beta.2 4.0.3 7.5.0-rc.1 4.0.4 7.5.1 4.1.0 7.5.2 4.1.0-beta.1 7.6.0 4.1.0-beta.2 7.6.0-beta.1 4.1.0-rc.1 7.6.0-beta.2 4.1.0-rc.2 7.6.0-rc.1 4.1.1 7.6.0-rc.2 4.1.2 7.6.0-rc.3 4.1.3 7.6.1 4.1.4 7.6.2 4.2.0 7.7.0 4.2.0-RC.1 7.7.0-beta.1 4.2.0-RC.2 7.7.0-beta.2 4.2.0-beta.1 7.7.0-rc.1 4.2.1 7.7.1 4.2.2 7.7.2 4.2.3 7.7.3 4.2.4 7.8.0 4.2.5 4.3.0 4.3.0-beta.1 4.3.0-rc.1 4.3.0-rc.2 4.3.0-rc.3 4.3.1 4.3.2 4.3.3 4.3.4 4.3.5 4.3.6 4.4.0 4.4.0-beta.1 4.4.0-rc.1 4.4.1 4.4.2 4.4.3 4.4.4 4.5.0 4.5.0-beta.1 4.5.0-rc.1 4.5.0-rc.3 4.5.1 4.5.2 4.5.3 4.5.4 4.5.5 4.6.0 4.6.0-beta.1 4.6.0-rc.1 4.6.1 4.6.2 4.6.3 4.6.4 4.6.5 4.7.0 4.7.0-beta.1 4.7.0-beta.2 4.7.0-rc.1 4.7.1 4.7.1-beta.1 4.7.2 4.7.3 4.7.4 4.8.0 4.8.0-beta.1 4.8.0-rc.1 4.8.0-rc.2 4.8.1 4.8.2 4.8.3 4.9.0 4.9.0-beta.1 4.9.0-rc.1 4.9.0-rc.2 4.9.1 4.9.2 4.9.3 4.9.4 4.9.5 5.0.0 5.0.0-beta.1 5.0.0-beta.2 5.0.0-rc.1 5.0.0-rc.2 5.0.0-rc.3 5.0.1 5.0.2 5.0.3 5.1.0 5.1.0-beta.1 5.1.0-rc.1 trunk 5.1.1 10.0.0 5.1.2 10.0.0-rc.1 5.1.3 10.0.0-rc.2 5.2.0 10.0.1 5.2.0-beta.1 10.0.2 5.2.0-rc.1 10.0.3 5.2.0-rc.2 10.0.4 5.2.1 10.0.5 5.2.2 10.0.6 5.2.3 10.1.0 5.2.4 10.1.0-rc.1 5.2.5 10.1.0-rc.2 5.3.0 10.1.0-rc.3 5.3.0-beta.1 10.1.0-rc.4 5.3.0-rc.1 10.1.1 5.3.0-rc.2 10.1.2 5.3.1 10.1.3 5.3.2 10.1.4 5.3.3 10.2.0 5.4.0 10.2.0-beta.1 5.4.0-beta.1 10.2.0-beta.2 5.4.0-rc.1 10.2.0-rc.1 5.4.1 10.2.1 5.4.2 10.2.2 5.4.3 10.2.3 5.4.4 10.2.4 5.4.5 10.3.0 5.5.0 10.3.0-beta.1 5.5.0-beta.1 10.3.0-beta.2 5.5.0-rc.1 10.3.0-rc.1 5.5.0-rc.2 10.3.0-rc.2 5.5.1 10.3.1 5.5.2 10.3.2 5.5.3 10.3.3 5.5.4 10.3.4 5.5.5 10.3.5 5.6.0 10.3.6 5.6.0-beta.1 10.3.7 5.6.0-rc.1 10.3.8 5.6.0-rc.2 10.4.0 5.6.1 10.4.0-beta.1 5.6.2 10.4.0-beta.2 5.6.3 10.4.0-rc.1 5.7.0 10.4.1 5.7.0-beta.1 10.4.2 5.7.0-rc.1 10.4.3 5.7.1 10.4.4 5.7.2 10.5.0 5.7.3 10.5.0-beta.1 5.8.0 10.5.0-beta.2 5.8.0-beta.1 10.5.0-rc.1 5.8.0-beta.2 10.5.0-rc.2 5.8.0-rc.1 10.5.0-rc.3 5.8.1 10.5.1 5.8.2 10.5.2 5.9.0 10.5.3 5.9.0-beta.1 10.6.0 5.9.0-rc.1 10.6.0-beta.1 5.9.0-rc.2 10.6.0-beta.2 5.9.1 10.6.0-rc.1 5.9.2 10.6.1 6.0.0 10.6.2 6.0.0-beta.1 10.7.0 6.0.0-rc.1 10.7.0-beta.1 6.0.1 10.7.0-beta.2 6.0.2 10.7.0-rc.1 6.1.0 3.0.0 6.1.0-beta.1 3.0.1 6.1.0-rc.1 3.0.2 6.1.0-rc.2 3.0.3 6.1.1 3.0.4 6.1.2 3.0.5 6.1.3 3.0.6 6.2.0 3.0.7 6.2.0-beta.1 3.0.8 6.2.0-rc.1 3.0.9 6.2.0-rc.2 3.1.0 6.2.1 3.1.1 6.2.2 3.1.2 6.2.3 3.2.0 6.3.0 3.2.1 6.3.0-beta.1 3.2.2 6.3.0-rc.1 3.2.3 6.3.0-rc.2 3.2.4 6.3.1 3.2.5 6.3.2 3.2.6 6.4.0 3.3.0 6.4.0-beta.1 3.3.1 6.4.0-rc.1 3.3.2 6.4.1 3.3.2-rc.1 6.4.2 3.3.3 6.5.0 3.3.4 6.5.0-beta.1 3.3.5 6.5.0-rc.1 3.3.6 6.5.0-rc.2 3.4.0 6.5.1 3.4.0-beta.1 6.5.2 3.4.0-rc.2 6.6.0 3.4.1 6.6.0-beta.1 3.4.2 6.6.0-rc.1 3.4.3 6.6.0-rc.2 3.4.4 6.6.1 3.4.5 6.6.2 3.4.6 6.7.0 3.4.7 6.7.0-beta.1 3.4.8 6.7.0-beta.2 3.5.0 6.7.0-rc.1 3.5.0-beta.1 6.7.1 3.5.0-rc.1 6.8.0 3.5.0-rc.2 6.8.0-beta.1 3.5.1 6.8.0-beta.2 3.5.10 6.8.0-rc.1 3.5.2 6.8.1 3.5.3 6.8.2 3.5.4 6.8.3 3.5.5 6.9.0 3.5.6 6.9.0-beta.1 3.5.7 6.9.0-beta.2 3.5.8 6.9.0-rc.1 3.5.9 6.9.1 3.6.0 6.9.2 3.6.0-beta.1 6.9.3 3.6.0-rc.1 6.9.4 3.6.0-rc.2 6.9.5 3.6.0-rc.3 7.0.0 3.6.1 7.0.0-beta.1 3.6.2 7.0.0-beta.2 3.6.3 7.0.0-beta.3 3.6.4 7.0.0-rc.1 3.6.5 7.0.0-rc.2 3.6.6 7.0.1 3.6.7 7.0.2 3.7.0 7.1.0 3.7.0-beta.1 7.1.0-beta.1 3.7.0-rc.1 7.1.0-beta.2 3.7.0-rc.2 7.1.0-rc.1 3.7.1 7.1.0-rc.2 3.7.2 7.1.1
woocommerce / src / StoreApi / Utilities / RateLimits.php
woocommerce / src / StoreApi / Utilities Last commit date
AgenticCheckoutUtils.php 4 months ago ArrayUtils.php 2 years ago CartController.php 1 month ago CartTokenUtils.php 1 year ago CheckoutTrait.php 1 month ago DraftOrderTrait.php 1 year ago JsonWebToken.php 11 months ago LocalPickupUtils.php 5 months ago NoticeHandler.php 1 year ago OrderAuthorizationTrait.php 6 months ago OrderController.php 1 month ago Pagination.php 2 years ago PaymentUtils.php 1 year ago ProductItemTrait.php 1 month ago ProductLinksTrait.php 3 months ago ProductQuery.php 2 months ago ProductQueryFilters.php 11 months ago QuantityLimits.php 11 months ago RateLimits.php 1 year ago SanitizationUtils.php 2 years ago ValidationUtils.php 2 years ago
RateLimits.php
253 lines
1 <?php
2 namespace Automattic\WooCommerce\StoreApi\Utilities;
3
4 use WC_Rate_Limiter;
5 use WC_Cache_Helper;
6
7 /**
8 * RateLimits class.
9 */
10 class RateLimits extends WC_Rate_Limiter {
11
12 /**
13 * Cache group.
14 */
15 const CACHE_GROUP = 'store_api_rate_limit';
16
17 /**
18 * Rate limiting enabled default value.
19 *
20 * @var boolean
21 */
22 const ENABLED = false;
23
24 /**
25 * Proxy support enabled default value.
26 *
27 * @var boolean
28 */
29 const PROXY_SUPPORT = false;
30
31 /**
32 * Default amount of max requests allowed for the defined timeframe.
33 *
34 * @var int
35 */
36 const LIMIT = 25;
37
38 /**
39 * Default time in seconds before rate limits are reset.
40 *
41 * @var int
42 */
43 const SECONDS = 10;
44
45 /**
46 * Gets a cache prefix.
47 *
48 * @param string $action_id Identifier of the action.
49 * @return string
50 */
51 protected static function get_cache_key( $action_id ): string {
52 return WC_Cache_Helper::get_cache_prefix( 'store_api_rate_limit' . $action_id );
53 }
54
55 /**
56 * Get current rate limit row from DB and normalize types. This query is not cached, and returns
57 * a new rate limit row if none exists.
58 *
59 * @param string $action_id Identifier of the action.
60 *
61 * @return object Object containing reset and remaining.
62 */
63 protected static function get_rate_limit_row( string $action_id ): object {
64 global $wpdb;
65
66 $time = time();
67
68 $row = $wpdb->get_row(
69 $wpdb->prepare(
70 "
71 SELECT rate_limit_expiry as reset, rate_limit_remaining as remaining
72 FROM {$wpdb->prefix}wc_rate_limits
73 WHERE rate_limit_key = %s
74 AND rate_limit_expiry > %s
75 ",
76 $action_id,
77 $time
78 ),
79 'OBJECT'
80 );
81
82 if ( empty( $row ) ) {
83 $options = self::get_options();
84
85 return (object) [
86 'reset' => (int) $options->seconds + $time,
87 'remaining' => (int) $options->limit,
88 ];
89 }
90
91 return (object) [
92 'reset' => (int) $row->reset,
93 'remaining' => (int) $row->remaining,
94 ];
95 }
96
97 /**
98 * Returns current rate limit values using cache where possible.
99 *
100 * @param string $action_id Identifier of the action.
101 *
102 * @return object
103 */
104 public static function get_rate_limit( string $action_id ): object {
105 $current_limit = self::get_cached( $action_id );
106
107 if ( false === $current_limit ) {
108 $current_limit = self::get_rate_limit_row( $action_id );
109 self::set_cache( $action_id, $current_limit );
110 }
111
112 return $current_limit;
113 }
114
115 /**
116 * If exceeded, seconds until reset.
117 *
118 * @param string $action_id Identifier of the action.
119 *
120 * @return bool|int
121 */
122 public static function is_exceeded_retry_after( string $action_id ) {
123 $current_limit = self::get_rate_limit( $action_id );
124 $time = time();
125 // Before the next run is allowed, retry forbidden.
126 if ( $time <= (int) $current_limit->reset && 0 === (int) $current_limit->remaining ) {
127 return (int) $current_limit->reset - $time;
128 }
129
130 // After the next run is allowed, retry allowed.
131 return false;
132 }
133
134 /**
135 * Sets the rate limit delay in seconds for action with identifier $id.
136 *
137 * @param string $action_id Identifier of the action.
138 *
139 * @return object Current rate limits.
140 */
141 public static function update_rate_limit( string $action_id ): object {
142 global $wpdb;
143
144 $options = self::get_options();
145 $time = time();
146 $rate_limit_expiry = $time + (int) $options->seconds;
147
148 $wpdb->query(
149 $wpdb->prepare(
150 "INSERT INTO {$wpdb->prefix}wc_rate_limits
151 (`rate_limit_key`, `rate_limit_expiry`, `rate_limit_remaining`)
152 VALUES
153 (%s, %d, %d)
154 ON DUPLICATE KEY UPDATE
155 `rate_limit_remaining` = IF(`rate_limit_expiry` < %d, VALUES(`rate_limit_remaining`), GREATEST(`rate_limit_remaining` - 1, 0)),
156 `rate_limit_expiry` = IF(`rate_limit_expiry` < %d, VALUES(`rate_limit_expiry`), `rate_limit_expiry`);
157 ",
158 $action_id,
159 $rate_limit_expiry,
160 (int) $options->limit - 1,
161 $time,
162 $time
163 )
164 );
165
166 $current_limit = self::get_rate_limit_row( $action_id );
167
168 self::set_cache( $action_id, $current_limit );
169
170 return $current_limit;
171 }
172
173 /**
174 * Retrieve a cached store api rate limit.
175 *
176 * @param string $action_id Identifier of the action.
177 * @return false|object
178 */
179 protected static function get_cached( $action_id ) {
180 return wp_cache_get( self::get_cache_key( $action_id ), self::CACHE_GROUP );
181 }
182
183 /**
184 * Cache a rate limit.
185 *
186 * @param string $action_id Identifier of the action.
187 * @param object $current_limit Current limit object with expiry and retries remaining.
188 * @return bool
189 */
190 protected static function set_cache( $action_id, $current_limit ): bool {
191 return wp_cache_set( self::get_cache_key( $action_id ), $current_limit, self::CACHE_GROUP );
192 }
193
194 /**
195 * Return options for Rate Limits, to be returned by the "woocommerce_store_api_rate_limit_options" filter.
196 *
197 * @return object Default options.
198 */
199 public static function get_options(): object {
200 $default_options = [
201 /**
202 * Filters the Store API rate limit check, which is disabled by default.
203 *
204 * This can be used also to disable the rate limit check when testing API endpoints via a REST API client.
205 */
206 'enabled' => self::ENABLED,
207
208 /**
209 * Filters whether proxy support is enabled for the Store API rate limit check. This is disabled by default.
210 *
211 * If the store is behind a proxy, load balancer, CDN etc. the user can enable this to properly obtain
212 * the client's IP address through standard transport headers.
213 */
214 'proxy_support' => self::PROXY_SUPPORT,
215
216 'limit' => self::LIMIT,
217 'seconds' => self::SECONDS,
218 ];
219
220 return (object) array_merge( // By using array_merge we ensure we get a properly populated options object.
221 $default_options,
222 /**
223 * Filters options for Rate Limits.
224 *
225 * @param array $rate_limit_options Array of option values.
226 * @return array
227 *
228 * @since 8.9.0
229 */
230 apply_filters(
231 'woocommerce_store_api_rate_limit_options',
232 $default_options
233 )
234 );
235 }
236
237 /**
238 * Gets a single option through provided name.
239 *
240 * @param string $option Option name.
241 *
242 * @return mixed
243 */
244 public static function get_option( $option ) {
245
246 if ( ! is_string( $option ) || ! defined( 'RateLimits::' . strtoupper( $option ) ) ) {
247 return null;
248 }
249
250 return self::get_options()[ $option ];
251 }
252 }
253