From 5dd0ae024f5011e657ea30de46f772b2e2228271 Mon Sep 17 00:00:00 2001 From: FusionPBX Date: Tue, 24 Feb 2026 15:00:52 -0700 Subject: [PATCH] Remove file caching in auto loader (#7752) --- resources/classes/auto_loader.php | 167 +++++++++--------------------- 1 file changed, 50 insertions(+), 117 deletions(-) diff --git a/resources/classes/auto_loader.php b/resources/classes/auto_loader.php index 90de03ea50..48eff5c0e2 100644 --- a/resources/classes/auto_loader.php +++ b/resources/classes/auto_loader.php @@ -35,21 +35,7 @@ class auto_loader { const CLASSES_KEY = 'autoloader_classes'; - const CLASSES_FILE = 'autoloader_cache.php'; const INTERFACES_KEY = "autoloader_interfaces"; - const INTERFACES_FILE = "autoloader_interface_cache.php"; - /** - * Cache path and file name for classes - * - * @var string - */ - private static $classes_file = null; - /** - * Cache path and file name for interfaces - * - * @var string - */ - private static $interfaces_file = null; private $classes; /** * Tracks the APCu extension for caching to RAM drive across requests @@ -64,6 +50,7 @@ class auto_loader { */ private $interfaces; /** + * Stores trait definitions (currently unused but kept for future expansion) * @var array */ private $traits; @@ -78,16 +65,6 @@ class auto_loader { //set if we can use RAM cache $this->apcu_enabled = function_exists('apcu_enabled') && apcu_enabled(); - //set classes cache location - if (empty(self::$classes_file)) { - self::$classes_file = sys_get_temp_dir() . DIRECTORY_SEPARATOR . self::CLASSES_FILE; - } - - //set interface cache location - if (empty(self::$interfaces_file)) { - self::$interfaces_file = sys_get_temp_dir() . DIRECTORY_SEPARATOR . self::INTERFACES_FILE; - } - //classes must be loaded before this object is registered if ($disable_cache || !$this->load_cache()) { //cache miss so load them @@ -100,42 +77,35 @@ class auto_loader { } /** - * Loads the class cache from various sources. + * Loads the class cache from APCu if available. * * @return bool True if the cache is loaded successfully, false otherwise. */ public function load_cache(): bool { $this->classes = []; $this->interfaces = []; - $this->traits = []; + $this->traits = []; // Reset traits array - //use apcu when available - if ($this->apcu_enabled && apcu_exists(self::CLASSES_KEY)) { + //use apcu when available - validate BOTH keys exist + if ($this->apcu_enabled && apcu_exists(self::CLASSES_KEY) && apcu_exists(self::INTERFACES_KEY)) { $this->classes = apcu_fetch(self::CLASSES_KEY, $classes_cached); $this->interfaces = apcu_fetch(self::INTERFACES_KEY, $interfaces_cached); - //don't use files when we are using apcu caching - if ($classes_cached && $interfaces_cached) + + //validate fetched data is arrays and not corrupted + if ($classes_cached && $interfaces_cached && + is_array($this->classes) && is_array($this->interfaces) && + !empty($this->classes)) { return true; + } + + //log when cache validation fails + if ($classes_cached || $interfaces_cached) { + self::log(LOG_WARNING, "APCu cache validation failed - classes_cached: " . ($classes_cached ? 'true' : 'false') . ", interfaces_cached: " . ($interfaces_cached ? 'true' : 'false') . ", is_array(classes): " . (is_array($this->classes) ? 'true' : 'false') . ", is_array(interfaces): " . (is_array($this->interfaces) ? 'true' : 'false')); + } } - //use PHP engine to parse it - if (file_exists(self::$classes_file)) { - $this->classes = include self::$classes_file; - } - - //do the same for interface to class mappings - if (file_exists(self::$interfaces_file)) { - $this->interfaces = include self::$interfaces_file; - } - - //catch edge case of first time using apcu cache - if ($this->apcu_enabled) { - apcu_store(self::CLASSES_KEY, $this->classes); - apcu_store(self::INTERFACES_KEY, $this->interfaces); - } - - //return true when we have classes and false if the array is still empty - return (!empty($this->classes) && !empty($this->interfaces)); + //return false when we don't have classes in memory + return false; } /** @@ -168,9 +138,6 @@ class auto_loader { $files = array_merge($files, glob($path)); } - //reset the current array - $class_list = []; - //store the class name (key) and the path (value) foreach ($files as $file) { $file_content = file_get_contents($file); @@ -246,50 +213,46 @@ class auto_loader { } /** - * Updates the cache by writing the classes and interfaces to files on disk. + * Updates the cache by storing classes and interfaces in APCu if available. * * @return bool True if the update was successful, false otherwise */ public function update_cache(): bool { - //guard against writing an empty file + //guard against empty cache if (empty($this->classes)) { return false; } - //update RAM cache when available + //update APCu cache when available if ($this->apcu_enabled) { - $classes_cached = apcu_store(self::CLASSES_KEY, $this->classes); - $interfaces_cached = apcu_store(self::INTERFACES_KEY, $this->interfaces); - //do not save to drive when we are using apcu - if ($classes_cached && $interfaces_cached) + $classes_stored = apcu_store(self::CLASSES_KEY, $this->classes, 0); + $interfaces_stored = apcu_store(self::INTERFACES_KEY, $this->interfaces, 0); + + //log failures to help diagnose APCu issues + if (!$classes_stored) { + self::log(LOG_WARNING, "Failed to store classes to APCu"); + } + if (!$interfaces_stored) { + self::log(LOG_WARNING, "Failed to store interfaces to APCu"); + } + + //both must succeed for consistency + if ($classes_stored && $interfaces_stored) { return true; + } + + //if one failed, clear APCu to prevent inconsistent state + if ($classes_stored || $interfaces_stored) { + apcu_delete(self::CLASSES_KEY); + apcu_delete(self::INTERFACES_KEY); + self::log(LOG_WARNING, "Cleared APCu cache due to partial store failure"); + } + + return false; } - //export the classes array using PHP engine - $classes_array = var_export($this->classes, true); - - //put the array in a form that it can be loaded directly to an array - $class_result = file_put_contents(self::$classes_file, "interfaces, true); - - //put the array in a form that it can be loaded directly to an array - $interface_result = file_put_contents(self::$interfaces_file, "classes[$class_name])) { @@ -471,6 +403,7 @@ class auto_loader { $project_path = dirname(__DIR__, 2); //build the search path array + $search_path = []; $search_path[] = glob($project_path . "/resources/interfaces/" . $class_name . ".php"); $search_path[] = glob($project_path . "/resources/traits/" . $class_name . ".php"); $search_path[] = glob($project_path . "/resources/classes/" . $class_name . ".php");