Completed
Branch BUG/11167/fix-runaway-ee-trans... (3205ed)
by
unknown
102:42 queued 91:11
created
core/services/cache/TransientCacheStorage.php 2 patches
Indentation   +375 added lines, -375 removed lines patch added patch discarded remove patch
@@ -19,381 +19,381 @@
 block discarded – undo
19 19
 class TransientCacheStorage implements CacheStorageInterface
20 20
 {
21 21
 
22
-    /**
23
-     * wp-option option_name for tracking transients
24
-     *
25
-     * @type string
26
-     */
27
-    const TRANSIENT_SCHEDULE_OPTIONS_KEY = 'ee_transient_schedule';
28
-
29
-    /**
30
-     * @var int $current_time
31
-     */
32
-    private $current_time;
33
-
34
-    /**
35
-     * how often to perform transient cleanup
36
-     *
37
-     * @var string $transient_cleanup_frequency
38
-     */
39
-    private $transient_cleanup_frequency;
40
-
41
-    /**
42
-     * options for how often to perform transient cleanup
43
-     *
44
-     * @var array $transient_cleanup_frequency_options
45
-     */
46
-    private $transient_cleanup_frequency_options = array();
47
-
48
-    /**
49
-     * @var array $transients
50
-     */
51
-    private $transients;
52
-
53
-
54
-
55
-    /**
56
-     * TransientCacheStorage constructor.
57
-     */
58
-    public function __construct()
59
-    {
60
-        $this->transient_cleanup_frequency = $this->setTransientCleanupFrequency();
61
-        // round current time down to closest 5 minutes to simplify scheduling
62
-        $this->current_time = $this->roundTimestamp(time(), '5-minutes', false);
63
-        $this->transients = (array)get_option(TransientCacheStorage::TRANSIENT_SCHEDULE_OPTIONS_KEY, array());
64
-        if ( ! (defined('DOING_AJAX') && DOING_AJAX) && $this->transient_cleanup_frequency !== 'off') {
65
-            add_action('shutdown', array($this, 'checkTransientCleanupSchedule'), 999);
66
-        }
67
-    }
68
-
69
-
70
-
71
-    /**
72
-     * Sets how often transient cleanup occurs
73
-     *
74
-     * @return string
75
-     */
76
-    private function setTransientCleanupFrequency()
77
-    {
78
-        // sets how often transients are cleaned up
79
-        $this->transient_cleanup_frequency_options = apply_filters(
80
-            'FHEE__TransientCacheStorage__transient_cleanup_schedule_options',
81
-            array(
82
-                'off',
83
-                '15-minutes',
84
-                'hour',
85
-                '12-hours',
86
-                'day',
87
-            )
88
-        );
89
-        $transient_cleanup_frequency = apply_filters(
90
-            'FHEE__TransientCacheStorage__transient_cleanup_schedule',
91
-            'hour'
92
-        );
93
-        return in_array(
94
-            $transient_cleanup_frequency,
95
-            $this->transient_cleanup_frequency_options,
96
-            true
97
-        )
98
-            ? $transient_cleanup_frequency
99
-            : 'hour';
100
-    }
101
-
102
-
103
-
104
-    /**
105
-     * we need to be able to round timestamps off to match the set transient cleanup frequency
106
-     * so if a transient is set to expire at 1:17 pm for example, and our cleanup schedule is every hour,
107
-     * then that timestamp needs to be rounded up to 2:00 pm so that it is removed
108
-     * during the next scheduled cleanup after its expiration.
109
-     * We also round off the current time timestamp to the closest 5 minutes
110
-     * just to make the timestamps a little easier to round which helps with debugging.
111
-     *
112
-     * @param int    $timestamp [required]
113
-     * @param string $cleanup_frequency
114
-     * @param bool   $round_up
115
-     * @return int
116
-     */
117
-    private function roundTimestamp($timestamp, $cleanup_frequency = 'hour', $round_up = true)
118
-    {
119
-        $cleanup_frequency = $cleanup_frequency ? $cleanup_frequency : $this->transient_cleanup_frequency;
120
-        // in order to round the time to the closest xx minutes (or hours),
121
-        // we take the minutes (or hours) portion of the timestamp and divide it by xx,
122
-        // round down to a whole number, then multiply by xx to bring us almost back up to where we were
123
-        // why round down ? so the minutes (or hours) don't go over 60 (or 24)
124
-        // and bump the hour, which could bump the day, which could bump the month, etc,
125
-        // which would be bad because we don't always want to round up,
126
-        // but when we do we can easily achieve that by simply adding the desired offset,
127
-        $minutes = '00';
128
-        $hours = 'H';
129
-        switch ($cleanup_frequency) {
130
-            case '5-minutes' :
131
-                $minutes = floor((int)date('i', $timestamp) / 5) * 5;
132
-                $minutes = str_pad($minutes, 2, '0', STR_PAD_LEFT);
133
-                $offset = MINUTE_IN_SECONDS * 5;
134
-                break;
135
-            case '15-minutes' :
136
-                $minutes = floor((int)date('i', $timestamp) / 15) * 15;
137
-                $minutes = str_pad($minutes, 2, '0', STR_PAD_LEFT);
138
-                $offset = MINUTE_IN_SECONDS * 15;
139
-                break;
140
-            case '12-hours' :
141
-                $hours = floor((int)date('H', $timestamp) / 12) * 12;
142
-                $hours = str_pad($hours, 2, '0', STR_PAD_LEFT);
143
-                $offset = HOUR_IN_SECONDS * 12;
144
-                break;
145
-            case 'day' :
146
-                $hours = '03'; // run cleanup at 3:00 am (or first site hit after that)
147
-                $offset = DAY_IN_SECONDS;
148
-                break;
149
-            case 'hour' :
150
-            default :
151
-                $offset = HOUR_IN_SECONDS;
152
-                break;
153
-        }
154
-        $rounded_timestamp = (int) strtotime(date("Y-m-d {$hours}:{$minutes}:00", $timestamp));
155
-        $rounded_timestamp += $round_up ? $offset : 0;
156
-        return apply_filters(
157
-            'FHEE__TransientCacheStorage__roundTimestamp__timestamp',
158
-            $rounded_timestamp,
159
-            $timestamp,
160
-            $cleanup_frequency,
161
-            $round_up
162
-        );
163
-    }
164
-
165
-
166
-
167
-    /**
168
-     * Saves supplied data to a transient
169
-     * if an expiration is set, then it automatically schedules the transient for cleanup
170
-     *
171
-     * @param string $transient_key [required]
172
-     * @param string $data          [required]
173
-     * @param int    $expiration    number of seconds until the cache expires
174
-     * @return bool
175
-     */
176
-    public function add($transient_key, $data, $expiration = 0)
177
-    {
178
-        $expiration = (int)abs($expiration);
179
-        $saved = set_transient($transient_key, $data, $expiration);
180
-        if ($saved && $expiration) {
181
-            $this->scheduleTransientCleanup($transient_key, $expiration);
182
-        }
183
-        return $saved;
184
-    }
185
-
186
-
187
-
188
-    /**
189
-     * retrieves transient data
190
-     * automatically triggers early cache refresh for standard cache items
191
-     * in order to avoid cache stampedes on busy sites.
192
-     * For non-standard cache items like PHP Session data where early refreshing is not wanted,
193
-     * the $standard_cache parameter should be set to false when retrieving data
194
-     *
195
-     * @param string $transient_key [required]
196
-     * @param bool   $standard_cache
197
-     * @return mixed|null
198
-     */
199
-    public function get($transient_key, $standard_cache = true)
200
-    {
201
-        if (isset($this->transients[ $transient_key ])) {
202
-            // to avoid cache stampedes (AKA:dogpiles) for standard cache items,
203
-            // check if known cache expires within the next minute,
204
-            // and if so, remove it from our tracking and and return nothing.
205
-            // this should trigger the cache content to be regenerated during this request,
206
-            // while allowing any following requests to still access the existing cache
207
-            // until it gets replaced with the refreshed content
208
-            if (
209
-                $standard_cache
210
-                && $this->transients[$transient_key] - time() <= MINUTE_IN_SECONDS
211
-            ) {
212
-                unset($this->transients[$transient_key]);
213
-                $this->updateTransients();
214
-                return null;
215
-            }
216
-
217
-            // for non standard cache items, remove the key from our tracking,
218
-            // but proceed to retrieve the transient so that it also gets removed from the db
219
-            if ($this->transients[$transient_key] <= time()) {
220
-                unset($this->transients[$transient_key]);
221
-                $this->updateTransients();
222
-            }
223
-        }
224
-
225
-        $content = get_transient($transient_key);
226
-        return $content !== false ? $content : null;
227
-    }
228
-
229
-
230
-
231
-    /**
232
-     * delete a single transient and remove tracking
233
-     *
234
-     * @param string $transient_key [required] full or partial transient key to be deleted
235
-     */
236
-    public function delete($transient_key)
237
-    {
238
-        $this->deleteMany(array($transient_key));
239
-    }
240
-
241
-
242
-
243
-    /**
244
-     * delete multiple transients and remove tracking
245
-     *
246
-     * @param array $transient_keys [required] array of full or partial transient keys to be deleted
247
-     * @param bool  $force_delete   [optional] if true, then will not check incoming keys against those being tracked
248
-     *                              and proceed directly to deleting those entries from the cache storage
249
-     */
250
-    public function deleteMany(array $transient_keys, $force_delete = false)
251
-    {
252
-        $full_transient_keys = $force_delete ? $transient_keys : array();
253
-        if(empty($full_transient_keys)){
254
-            foreach ($this->transients as $transient_key => $expiration) {
255
-                foreach ($transient_keys as $transient_key_to_delete) {
256
-                    if (strpos($transient_key, $transient_key_to_delete) !== false) {
257
-                        $full_transient_keys[] = $transient_key;
258
-                    }
259
-                }
260
-            }
261
-        }
262
-        if ($this->deleteTransientKeys($full_transient_keys)) {
263
-            $this->updateTransients();
264
-        }
265
-    }
266
-
267
-
268
-
269
-    /**
270
-     * sorts transients numerically by timestamp
271
-     * then saves the transient schedule to a WP option
272
-     */
273
-    private function updateTransients()
274
-    {
275
-        asort($this->transients, SORT_NUMERIC);
276
-        update_option(
277
-            TransientCacheStorage::TRANSIENT_SCHEDULE_OPTIONS_KEY,
278
-            $this->transients
279
-        );
280
-    }
281
-
282
-
283
-
284
-    /**
285
-     * schedules a transient for cleanup by adding it to the transient tracking
286
-     *
287
-     * @param string $transient_key [required]
288
-     * @param int    $expiration    [required]
289
-     */
290
-    private function scheduleTransientCleanup($transient_key, $expiration)
291
-    {
292
-        // make sure a valid future timestamp is set
293
-        $expiration += $expiration < time() ? time() : 0;
294
-        // and round to the closest 15 minutes
295
-        $expiration = $this->roundTimestamp($expiration);
296
-        // save transients to clear using their ID as the key to avoid duplicates
297
-        $this->transients[$transient_key] = $expiration;
298
-        $this->updateTransients();
299
-    }
300
-
301
-
302
-
303
-    /**
304
-     * Since our tracked transients are sorted by their timestamps
305
-     * we can grab the first transient and see when it is scheduled for cleanup.
306
-     * If that timestamp is less than or equal to the current time,
307
-     * then cleanup is triggered
308
-     */
309
-    public function checkTransientCleanupSchedule()
310
-    {
311
-        if (empty($this->transients)) {
312
-            return;
313
-        }
314
-        // when do we run the next cleanup job?
315
-        reset($this->transients);
316
-        $next_scheduled_cleanup = current($this->transients);
317
-        // if the next cleanup job is scheduled for the current hour
318
-        if ($next_scheduled_cleanup <= $this->current_time) {
319
-            if ($this->cleanupExpiredTransients()) {
320
-                $this->updateTransients();
321
-            }
322
-        }
323
-    }
324
-
325
-
326
-
327
-    /**
328
-     * loops through the array of tracked transients,
329
-     * compiles a list of those that have expired, and sends that list off for deletion.
330
-     * Also removes any bad records from the transients array
331
-     *
332
-     * @return bool
333
-     */
334
-    private function cleanupExpiredTransients()
335
-    {
336
-        $update = false;
337
-        // filter the query limit. Set to 0 to turn off garbage collection
338
-        $limit = (int)abs(
339
-            apply_filters(
340
-                'FHEE__TransientCacheStorage__clearExpiredTransients__limit',
341
-                50
342
-            )
343
-        );
344
-        // non-zero LIMIT means take out the trash
345
-        if ($limit) {
346
-            $transient_keys = array();
347
-            foreach ($this->transients as $transient_key => $expiration) {
348
-                if ($expiration > $this->current_time) {
349
-                    continue;
350
-                }
351
-                if ( ! $expiration || ! $transient_key) {
352
-                    unset($this->transients[$transient_key]);
353
-                    $update = true;
354
-                    continue;
355
-                }
356
-                $transient_keys[] = $transient_key;
357
-            }
358
-            // delete expired keys, but maintain value of $update if nothing is deleted
359
-            $update = $this->deleteTransientKeys($transient_keys, $limit) ? true : $update;
360
-            do_action( 'FHEE__TransientCacheStorage__clearExpiredTransients__end', $this);
361
-        }
362
-        return $update;
363
-    }
364
-
365
-
366
-
367
-    /**
368
-     * calls delete_transient() on each transient key provided, up to the specified limit
369
-     *
370
-     * @param array $transient_keys [required]
371
-     * @param int   $limit
372
-     * @return bool
373
-     */
374
-    private function deleteTransientKeys(array $transient_keys, $limit = 50)
375
-    {
376
-        if (empty($transient_keys)) {
377
-            return false;
378
-        }
379
-        $counter = 0;
380
-        foreach ($transient_keys as $transient_key) {
381
-            if($counter === $limit){
382
-                break;
383
-            }
384
-            // remove any transient prefixes
385
-            $transient_key = strpos($transient_key,  '_transient_timeout_') === 0
386
-                ? str_replace('_transient_timeout_', '', $transient_key)
387
-                : $transient_key;
388
-            $transient_key = strpos($transient_key,  '_transient_') === 0
389
-                ? str_replace('_transient_', '', $transient_key)
390
-                : $transient_key;
391
-            delete_transient($transient_key);
392
-            unset($this->transients[$transient_key]);
393
-            $counter++;
394
-        }
395
-        return $counter > 0;
396
-    }
22
+	/**
23
+	 * wp-option option_name for tracking transients
24
+	 *
25
+	 * @type string
26
+	 */
27
+	const TRANSIENT_SCHEDULE_OPTIONS_KEY = 'ee_transient_schedule';
28
+
29
+	/**
30
+	 * @var int $current_time
31
+	 */
32
+	private $current_time;
33
+
34
+	/**
35
+	 * how often to perform transient cleanup
36
+	 *
37
+	 * @var string $transient_cleanup_frequency
38
+	 */
39
+	private $transient_cleanup_frequency;
40
+
41
+	/**
42
+	 * options for how often to perform transient cleanup
43
+	 *
44
+	 * @var array $transient_cleanup_frequency_options
45
+	 */
46
+	private $transient_cleanup_frequency_options = array();
47
+
48
+	/**
49
+	 * @var array $transients
50
+	 */
51
+	private $transients;
52
+
53
+
54
+
55
+	/**
56
+	 * TransientCacheStorage constructor.
57
+	 */
58
+	public function __construct()
59
+	{
60
+		$this->transient_cleanup_frequency = $this->setTransientCleanupFrequency();
61
+		// round current time down to closest 5 minutes to simplify scheduling
62
+		$this->current_time = $this->roundTimestamp(time(), '5-minutes', false);
63
+		$this->transients = (array)get_option(TransientCacheStorage::TRANSIENT_SCHEDULE_OPTIONS_KEY, array());
64
+		if ( ! (defined('DOING_AJAX') && DOING_AJAX) && $this->transient_cleanup_frequency !== 'off') {
65
+			add_action('shutdown', array($this, 'checkTransientCleanupSchedule'), 999);
66
+		}
67
+	}
68
+
69
+
70
+
71
+	/**
72
+	 * Sets how often transient cleanup occurs
73
+	 *
74
+	 * @return string
75
+	 */
76
+	private function setTransientCleanupFrequency()
77
+	{
78
+		// sets how often transients are cleaned up
79
+		$this->transient_cleanup_frequency_options = apply_filters(
80
+			'FHEE__TransientCacheStorage__transient_cleanup_schedule_options',
81
+			array(
82
+				'off',
83
+				'15-minutes',
84
+				'hour',
85
+				'12-hours',
86
+				'day',
87
+			)
88
+		);
89
+		$transient_cleanup_frequency = apply_filters(
90
+			'FHEE__TransientCacheStorage__transient_cleanup_schedule',
91
+			'hour'
92
+		);
93
+		return in_array(
94
+			$transient_cleanup_frequency,
95
+			$this->transient_cleanup_frequency_options,
96
+			true
97
+		)
98
+			? $transient_cleanup_frequency
99
+			: 'hour';
100
+	}
101
+
102
+
103
+
104
+	/**
105
+	 * we need to be able to round timestamps off to match the set transient cleanup frequency
106
+	 * so if a transient is set to expire at 1:17 pm for example, and our cleanup schedule is every hour,
107
+	 * then that timestamp needs to be rounded up to 2:00 pm so that it is removed
108
+	 * during the next scheduled cleanup after its expiration.
109
+	 * We also round off the current time timestamp to the closest 5 minutes
110
+	 * just to make the timestamps a little easier to round which helps with debugging.
111
+	 *
112
+	 * @param int    $timestamp [required]
113
+	 * @param string $cleanup_frequency
114
+	 * @param bool   $round_up
115
+	 * @return int
116
+	 */
117
+	private function roundTimestamp($timestamp, $cleanup_frequency = 'hour', $round_up = true)
118
+	{
119
+		$cleanup_frequency = $cleanup_frequency ? $cleanup_frequency : $this->transient_cleanup_frequency;
120
+		// in order to round the time to the closest xx minutes (or hours),
121
+		// we take the minutes (or hours) portion of the timestamp and divide it by xx,
122
+		// round down to a whole number, then multiply by xx to bring us almost back up to where we were
123
+		// why round down ? so the minutes (or hours) don't go over 60 (or 24)
124
+		// and bump the hour, which could bump the day, which could bump the month, etc,
125
+		// which would be bad because we don't always want to round up,
126
+		// but when we do we can easily achieve that by simply adding the desired offset,
127
+		$minutes = '00';
128
+		$hours = 'H';
129
+		switch ($cleanup_frequency) {
130
+			case '5-minutes' :
131
+				$minutes = floor((int)date('i', $timestamp) / 5) * 5;
132
+				$minutes = str_pad($minutes, 2, '0', STR_PAD_LEFT);
133
+				$offset = MINUTE_IN_SECONDS * 5;
134
+				break;
135
+			case '15-minutes' :
136
+				$minutes = floor((int)date('i', $timestamp) / 15) * 15;
137
+				$minutes = str_pad($minutes, 2, '0', STR_PAD_LEFT);
138
+				$offset = MINUTE_IN_SECONDS * 15;
139
+				break;
140
+			case '12-hours' :
141
+				$hours = floor((int)date('H', $timestamp) / 12) * 12;
142
+				$hours = str_pad($hours, 2, '0', STR_PAD_LEFT);
143
+				$offset = HOUR_IN_SECONDS * 12;
144
+				break;
145
+			case 'day' :
146
+				$hours = '03'; // run cleanup at 3:00 am (or first site hit after that)
147
+				$offset = DAY_IN_SECONDS;
148
+				break;
149
+			case 'hour' :
150
+			default :
151
+				$offset = HOUR_IN_SECONDS;
152
+				break;
153
+		}
154
+		$rounded_timestamp = (int) strtotime(date("Y-m-d {$hours}:{$minutes}:00", $timestamp));
155
+		$rounded_timestamp += $round_up ? $offset : 0;
156
+		return apply_filters(
157
+			'FHEE__TransientCacheStorage__roundTimestamp__timestamp',
158
+			$rounded_timestamp,
159
+			$timestamp,
160
+			$cleanup_frequency,
161
+			$round_up
162
+		);
163
+	}
164
+
165
+
166
+
167
+	/**
168
+	 * Saves supplied data to a transient
169
+	 * if an expiration is set, then it automatically schedules the transient for cleanup
170
+	 *
171
+	 * @param string $transient_key [required]
172
+	 * @param string $data          [required]
173
+	 * @param int    $expiration    number of seconds until the cache expires
174
+	 * @return bool
175
+	 */
176
+	public function add($transient_key, $data, $expiration = 0)
177
+	{
178
+		$expiration = (int)abs($expiration);
179
+		$saved = set_transient($transient_key, $data, $expiration);
180
+		if ($saved && $expiration) {
181
+			$this->scheduleTransientCleanup($transient_key, $expiration);
182
+		}
183
+		return $saved;
184
+	}
185
+
186
+
187
+
188
+	/**
189
+	 * retrieves transient data
190
+	 * automatically triggers early cache refresh for standard cache items
191
+	 * in order to avoid cache stampedes on busy sites.
192
+	 * For non-standard cache items like PHP Session data where early refreshing is not wanted,
193
+	 * the $standard_cache parameter should be set to false when retrieving data
194
+	 *
195
+	 * @param string $transient_key [required]
196
+	 * @param bool   $standard_cache
197
+	 * @return mixed|null
198
+	 */
199
+	public function get($transient_key, $standard_cache = true)
200
+	{
201
+		if (isset($this->transients[ $transient_key ])) {
202
+			// to avoid cache stampedes (AKA:dogpiles) for standard cache items,
203
+			// check if known cache expires within the next minute,
204
+			// and if so, remove it from our tracking and and return nothing.
205
+			// this should trigger the cache content to be regenerated during this request,
206
+			// while allowing any following requests to still access the existing cache
207
+			// until it gets replaced with the refreshed content
208
+			if (
209
+				$standard_cache
210
+				&& $this->transients[$transient_key] - time() <= MINUTE_IN_SECONDS
211
+			) {
212
+				unset($this->transients[$transient_key]);
213
+				$this->updateTransients();
214
+				return null;
215
+			}
216
+
217
+			// for non standard cache items, remove the key from our tracking,
218
+			// but proceed to retrieve the transient so that it also gets removed from the db
219
+			if ($this->transients[$transient_key] <= time()) {
220
+				unset($this->transients[$transient_key]);
221
+				$this->updateTransients();
222
+			}
223
+		}
224
+
225
+		$content = get_transient($transient_key);
226
+		return $content !== false ? $content : null;
227
+	}
228
+
229
+
230
+
231
+	/**
232
+	 * delete a single transient and remove tracking
233
+	 *
234
+	 * @param string $transient_key [required] full or partial transient key to be deleted
235
+	 */
236
+	public function delete($transient_key)
237
+	{
238
+		$this->deleteMany(array($transient_key));
239
+	}
240
+
241
+
242
+
243
+	/**
244
+	 * delete multiple transients and remove tracking
245
+	 *
246
+	 * @param array $transient_keys [required] array of full or partial transient keys to be deleted
247
+	 * @param bool  $force_delete   [optional] if true, then will not check incoming keys against those being tracked
248
+	 *                              and proceed directly to deleting those entries from the cache storage
249
+	 */
250
+	public function deleteMany(array $transient_keys, $force_delete = false)
251
+	{
252
+		$full_transient_keys = $force_delete ? $transient_keys : array();
253
+		if(empty($full_transient_keys)){
254
+			foreach ($this->transients as $transient_key => $expiration) {
255
+				foreach ($transient_keys as $transient_key_to_delete) {
256
+					if (strpos($transient_key, $transient_key_to_delete) !== false) {
257
+						$full_transient_keys[] = $transient_key;
258
+					}
259
+				}
260
+			}
261
+		}
262
+		if ($this->deleteTransientKeys($full_transient_keys)) {
263
+			$this->updateTransients();
264
+		}
265
+	}
266
+
267
+
268
+
269
+	/**
270
+	 * sorts transients numerically by timestamp
271
+	 * then saves the transient schedule to a WP option
272
+	 */
273
+	private function updateTransients()
274
+	{
275
+		asort($this->transients, SORT_NUMERIC);
276
+		update_option(
277
+			TransientCacheStorage::TRANSIENT_SCHEDULE_OPTIONS_KEY,
278
+			$this->transients
279
+		);
280
+	}
281
+
282
+
283
+
284
+	/**
285
+	 * schedules a transient for cleanup by adding it to the transient tracking
286
+	 *
287
+	 * @param string $transient_key [required]
288
+	 * @param int    $expiration    [required]
289
+	 */
290
+	private function scheduleTransientCleanup($transient_key, $expiration)
291
+	{
292
+		// make sure a valid future timestamp is set
293
+		$expiration += $expiration < time() ? time() : 0;
294
+		// and round to the closest 15 minutes
295
+		$expiration = $this->roundTimestamp($expiration);
296
+		// save transients to clear using their ID as the key to avoid duplicates
297
+		$this->transients[$transient_key] = $expiration;
298
+		$this->updateTransients();
299
+	}
300
+
301
+
302
+
303
+	/**
304
+	 * Since our tracked transients are sorted by their timestamps
305
+	 * we can grab the first transient and see when it is scheduled for cleanup.
306
+	 * If that timestamp is less than or equal to the current time,
307
+	 * then cleanup is triggered
308
+	 */
309
+	public function checkTransientCleanupSchedule()
310
+	{
311
+		if (empty($this->transients)) {
312
+			return;
313
+		}
314
+		// when do we run the next cleanup job?
315
+		reset($this->transients);
316
+		$next_scheduled_cleanup = current($this->transients);
317
+		// if the next cleanup job is scheduled for the current hour
318
+		if ($next_scheduled_cleanup <= $this->current_time) {
319
+			if ($this->cleanupExpiredTransients()) {
320
+				$this->updateTransients();
321
+			}
322
+		}
323
+	}
324
+
325
+
326
+
327
+	/**
328
+	 * loops through the array of tracked transients,
329
+	 * compiles a list of those that have expired, and sends that list off for deletion.
330
+	 * Also removes any bad records from the transients array
331
+	 *
332
+	 * @return bool
333
+	 */
334
+	private function cleanupExpiredTransients()
335
+	{
336
+		$update = false;
337
+		// filter the query limit. Set to 0 to turn off garbage collection
338
+		$limit = (int)abs(
339
+			apply_filters(
340
+				'FHEE__TransientCacheStorage__clearExpiredTransients__limit',
341
+				50
342
+			)
343
+		);
344
+		// non-zero LIMIT means take out the trash
345
+		if ($limit) {
346
+			$transient_keys = array();
347
+			foreach ($this->transients as $transient_key => $expiration) {
348
+				if ($expiration > $this->current_time) {
349
+					continue;
350
+				}
351
+				if ( ! $expiration || ! $transient_key) {
352
+					unset($this->transients[$transient_key]);
353
+					$update = true;
354
+					continue;
355
+				}
356
+				$transient_keys[] = $transient_key;
357
+			}
358
+			// delete expired keys, but maintain value of $update if nothing is deleted
359
+			$update = $this->deleteTransientKeys($transient_keys, $limit) ? true : $update;
360
+			do_action( 'FHEE__TransientCacheStorage__clearExpiredTransients__end', $this);
361
+		}
362
+		return $update;
363
+	}
364
+
365
+
366
+
367
+	/**
368
+	 * calls delete_transient() on each transient key provided, up to the specified limit
369
+	 *
370
+	 * @param array $transient_keys [required]
371
+	 * @param int   $limit
372
+	 * @return bool
373
+	 */
374
+	private function deleteTransientKeys(array $transient_keys, $limit = 50)
375
+	{
376
+		if (empty($transient_keys)) {
377
+			return false;
378
+		}
379
+		$counter = 0;
380
+		foreach ($transient_keys as $transient_key) {
381
+			if($counter === $limit){
382
+				break;
383
+			}
384
+			// remove any transient prefixes
385
+			$transient_key = strpos($transient_key,  '_transient_timeout_') === 0
386
+				? str_replace('_transient_timeout_', '', $transient_key)
387
+				: $transient_key;
388
+			$transient_key = strpos($transient_key,  '_transient_') === 0
389
+				? str_replace('_transient_', '', $transient_key)
390
+				: $transient_key;
391
+			delete_transient($transient_key);
392
+			unset($this->transients[$transient_key]);
393
+			$counter++;
394
+		}
395
+		return $counter > 0;
396
+	}
397 397
 
398 398
 
399 399
 
Please login to merge, or discard this patch.
Spacing   +12 added lines, -12 removed lines patch added patch discarded remove patch
@@ -60,7 +60,7 @@  discard block
 block discarded – undo
60 60
         $this->transient_cleanup_frequency = $this->setTransientCleanupFrequency();
61 61
         // round current time down to closest 5 minutes to simplify scheduling
62 62
         $this->current_time = $this->roundTimestamp(time(), '5-minutes', false);
63
-        $this->transients = (array)get_option(TransientCacheStorage::TRANSIENT_SCHEDULE_OPTIONS_KEY, array());
63
+        $this->transients = (array) get_option(TransientCacheStorage::TRANSIENT_SCHEDULE_OPTIONS_KEY, array());
64 64
         if ( ! (defined('DOING_AJAX') && DOING_AJAX) && $this->transient_cleanup_frequency !== 'off') {
65 65
             add_action('shutdown', array($this, 'checkTransientCleanupSchedule'), 999);
66 66
         }
@@ -128,17 +128,17 @@  discard block
 block discarded – undo
128 128
         $hours = 'H';
129 129
         switch ($cleanup_frequency) {
130 130
             case '5-minutes' :
131
-                $minutes = floor((int)date('i', $timestamp) / 5) * 5;
131
+                $minutes = floor((int) date('i', $timestamp) / 5) * 5;
132 132
                 $minutes = str_pad($minutes, 2, '0', STR_PAD_LEFT);
133 133
                 $offset = MINUTE_IN_SECONDS * 5;
134 134
                 break;
135 135
             case '15-minutes' :
136
-                $minutes = floor((int)date('i', $timestamp) / 15) * 15;
136
+                $minutes = floor((int) date('i', $timestamp) / 15) * 15;
137 137
                 $minutes = str_pad($minutes, 2, '0', STR_PAD_LEFT);
138 138
                 $offset = MINUTE_IN_SECONDS * 15;
139 139
                 break;
140 140
             case '12-hours' :
141
-                $hours = floor((int)date('H', $timestamp) / 12) * 12;
141
+                $hours = floor((int) date('H', $timestamp) / 12) * 12;
142 142
                 $hours = str_pad($hours, 2, '0', STR_PAD_LEFT);
143 143
                 $offset = HOUR_IN_SECONDS * 12;
144 144
                 break;
@@ -175,7 +175,7 @@  discard block
 block discarded – undo
175 175
      */
176 176
     public function add($transient_key, $data, $expiration = 0)
177 177
     {
178
-        $expiration = (int)abs($expiration);
178
+        $expiration = (int) abs($expiration);
179 179
         $saved = set_transient($transient_key, $data, $expiration);
180 180
         if ($saved && $expiration) {
181 181
             $this->scheduleTransientCleanup($transient_key, $expiration);
@@ -198,7 +198,7 @@  discard block
 block discarded – undo
198 198
      */
199 199
     public function get($transient_key, $standard_cache = true)
200 200
     {
201
-        if (isset($this->transients[ $transient_key ])) {
201
+        if (isset($this->transients[$transient_key])) {
202 202
             // to avoid cache stampedes (AKA:dogpiles) for standard cache items,
203 203
             // check if known cache expires within the next minute,
204 204
             // and if so, remove it from our tracking and and return nothing.
@@ -250,7 +250,7 @@  discard block
 block discarded – undo
250 250
     public function deleteMany(array $transient_keys, $force_delete = false)
251 251
     {
252 252
         $full_transient_keys = $force_delete ? $transient_keys : array();
253
-        if(empty($full_transient_keys)){
253
+        if (empty($full_transient_keys)) {
254 254
             foreach ($this->transients as $transient_key => $expiration) {
255 255
                 foreach ($transient_keys as $transient_key_to_delete) {
256 256
                     if (strpos($transient_key, $transient_key_to_delete) !== false) {
@@ -335,7 +335,7 @@  discard block
 block discarded – undo
335 335
     {
336 336
         $update = false;
337 337
         // filter the query limit. Set to 0 to turn off garbage collection
338
-        $limit = (int)abs(
338
+        $limit = (int) abs(
339 339
             apply_filters(
340 340
                 'FHEE__TransientCacheStorage__clearExpiredTransients__limit',
341 341
                 50
@@ -357,7 +357,7 @@  discard block
 block discarded – undo
357 357
             }
358 358
             // delete expired keys, but maintain value of $update if nothing is deleted
359 359
             $update = $this->deleteTransientKeys($transient_keys, $limit) ? true : $update;
360
-            do_action( 'FHEE__TransientCacheStorage__clearExpiredTransients__end', $this);
360
+            do_action('FHEE__TransientCacheStorage__clearExpiredTransients__end', $this);
361 361
         }
362 362
         return $update;
363 363
     }
@@ -378,14 +378,14 @@  discard block
 block discarded – undo
378 378
         }
379 379
         $counter = 0;
380 380
         foreach ($transient_keys as $transient_key) {
381
-            if($counter === $limit){
381
+            if ($counter === $limit) {
382 382
                 break;
383 383
             }
384 384
             // remove any transient prefixes
385
-            $transient_key = strpos($transient_key,  '_transient_timeout_') === 0
385
+            $transient_key = strpos($transient_key, '_transient_timeout_') === 0
386 386
                 ? str_replace('_transient_timeout_', '', $transient_key)
387 387
                 : $transient_key;
388
-            $transient_key = strpos($transient_key,  '_transient_') === 0
388
+            $transient_key = strpos($transient_key, '_transient_') === 0
389 389
                 ? str_replace('_transient_', '', $transient_key)
390 390
                 : $transient_key;
391 391
             delete_transient($transient_key);
Please login to merge, or discard this patch.