<?php /** * @package VikBooking * @subpackage core * @author E4J s.r.l. * @copyright Copyright (C) 2021 E4J s.r.l. All Rights Reserved. * @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL * @link https://vikwp.com */ // No direct access defined('ABSPATH') or die('No script kiddies please!'); /** * VikBooking cron job scalar-elements array tracker. * * @since 1.5.10 */ trait VBOCronTrackerArray { /** * Defines the maximum number of characters that can occupy the list * containing all the tracked elements. Children classes can alter * this value according to their needs. * * @var int */ protected $maximumCharsTrackableElements = 10000; /** * Helper method used to flag the specified element as tracked. This is really helpful to easily * check whether a specific record has been already parsed, which can be done by passing the same * element argument to the `isTracked` method. * * It is recommended to register only scalar values in order to prevent an uncontrolled increase of the * total length, which can arrive up to 2^16-1 characters (65535). It's up to the sub-classes to take care of * this limit, which should clean the flag_char property in order to always have less than 65536 characters. * * @param mixed $element The element to track. * * @return boolean True on success, false otherwise. */ protected function track($element) { if ($this->isTracked($element) || !is_scalar($element)) { // element already tracked, avoid duplicate registration return false; } if (is_numeric($element)) { // cast to number to save some space occupied by json_encode for strings $element = is_float($element) ? (float) $element : (int) $element; } // make sure this trait has been attached only to a cron job instance if (!$this instanceof VBOCronJob) { throw new Exception('This tracker can be attached only to a VBOCronJob instance', 500); } // register the element at the beginning of the list $data = $this->getData(); array_unshift($data->flag_char, $element); // sanitize the elements contained within the cache in order // avoid a length exceeding the maximum threshold $this->sanitizeFlagCache($data); return true; } /** * Checks whether the specified element has been already processed. * * @param mixed $element The element to check. * * @return boolean True if already processed, false otherwise. */ protected function isTracked($element) { // make sure this trait has been attached only to a cron job instance if (!$this instanceof VBOCronJob) { throw new Exception('This tracker can be attached only to a VBOCronJob instance', 500); } return in_array($element, $this->getData()->flag_char); } /** * Ensures the array with the tracked elements doesn't exceed the maximum limit. * * @param object $data The cron job data. * * @return void */ private function sanitizeFlagCache($data) { // count the total number of characters that occupy the cache $len = 0; foreach ($data->flag_char as $element) { // sum value with the total number of characters $len += strlen((string) $element); if (!is_numeric($element)) { // we have a string element, we need to include other 2 characters reserved for wrapping $len += 2; } // increase the length by 1 to include also the elements separator (,) $len++; } if ($data->flag_char) { // remove the trailing comma separator $len--; } // sum also the initial and trailing brackets $len += 2; // even if the maximum number of allowed characters is 65535, we prefer to always stay under // 10000 elements, since json_encode may use a specific encoding for some characters if ($len > $this->maximumCharsTrackableElements) { // it is enough to pop the last 2 items from the list in order to stay under the desired limit, // since this method always triggers while registering a new element array_pop($data->flag_char); array_pop($data->flag_char); } } }