Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.11.x will end 14 Nov 2022 (12 months plus 6 months extension).
  • Bug fixes for security issues in 3.11.x will end 13 Nov 2023 (18 months plus 12 months extension).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is supported too.

Differences Between: [Versions 310 and 311] [Versions 311 and 400] [Versions 311 and 401] [Versions 311 and 402] [Versions 311 and 403] [Versions 39 and 311]

   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  /**
  18   * The library file for the file cache store.
  19   *
  20   * This file is part of the file cache store, it contains the API for interacting with an instance of the store.
  21   * This is used as a default cache store within the Cache API. It should never be deleted.
  22   *
  23   * @package    cachestore_file
  24   * @category   cache
  25   * @copyright  2012 Sam Hemelryk
  26   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  27   */
  28  
  29  /**
  30   * The file store class.
  31   *
  32   * Configuration options
  33   *      path:           string: path to the cache directory, if left empty one will be created in the cache directory
  34   *      autocreate:     true, false
  35   *      prescan:        true, false
  36   *
  37   * @copyright  2012 Sam Hemelryk
  38   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  39   */
  40  class cachestore_file extends cache_store implements cache_is_key_aware, cache_is_configurable, cache_is_searchable  {
  41  
  42      /**
  43       * The name of the store.
  44       * @var string
  45       */
  46      protected $name;
  47  
  48      /**
  49       * The path used to store files for this store and the definition it was initialised with.
  50       * @var string
  51       */
  52      protected $path = false;
  53  
  54      /**
  55       * The path in which definition specific sub directories will be created for caching.
  56       * @var string
  57       */
  58      protected $filestorepath = false;
  59  
  60      /**
  61       * Set to true when a prescan has been performed.
  62       * @var bool
  63       */
  64      protected $prescan = false;
  65  
  66      /**
  67       * Set to true if we should store files within a single directory.
  68       * By default we use a nested structure in order to reduce the chance of conflicts and avoid any file system
  69       * limitations such as maximum files per directory.
  70       * @var bool
  71       */
  72      protected $singledirectory = false;
  73  
  74      /**
  75       * Set to true when the path should be automatically created if it does not yet exist.
  76       * @var bool
  77       */
  78      protected $autocreate = false;
  79  
  80      /**
  81       * Set to true if a custom path is being used.
  82       * @var bool
  83       */
  84      protected $custompath = false;
  85  
  86      /**
  87       * An array of keys we are sure about presently.
  88       * @var array
  89       */
  90      protected $keys = array();
  91  
  92      /**
  93       * True when the store is ready to be initialised.
  94       * @var bool
  95       */
  96      protected $isready = false;
  97  
  98      /**
  99       * The cache definition this instance has been initialised with.
 100       * @var cache_definition
 101       */
 102      protected $definition;
 103  
 104      /**
 105       * A reference to the global $CFG object.
 106       *
 107       * You may be asking yourself why on earth this is here, but there is a good reason.
 108       * By holding onto a reference of the $CFG object we can be absolutely sure that it won't be destroyed before
 109       * we are done with it.
 110       * This makes it possible to use a cache within a destructor method for the purposes of
 111       * delayed writes. Like how the session mechanisms work.
 112       *
 113       * @var stdClass
 114       */
 115      private $cfg = null;
 116  
 117      /**
 118       * Constructs the store instance.
 119       *
 120       * Noting that this function is not an initialisation. It is used to prepare the store for use.
 121       * The store will be initialised when required and will be provided with a cache_definition at that time.
 122       *
 123       * @param string $name
 124       * @param array $configuration
 125       */
 126      public function __construct($name, array $configuration = array()) {
 127          global $CFG;
 128  
 129          if (isset($CFG)) {
 130              // Hold onto a reference of the global $CFG object.
 131              $this->cfg = $CFG;
 132          }
 133  
 134          $this->name = $name;
 135          if (array_key_exists('path', $configuration) && $configuration['path'] !== '') {
 136              $this->custompath = true;
 137              $this->autocreate = !empty($configuration['autocreate']);
 138              $path = (string)$configuration['path'];
 139              if (!is_dir($path)) {
 140                  if ($this->autocreate) {
 141                      if (!make_writable_directory($path, false)) {
 142                          $path = false;
 143                          debugging('Error trying to autocreate file store path. '.$path, DEBUG_DEVELOPER);
 144                      }
 145                  } else {
 146                      $path = false;
 147                      debugging('The given file cache store path does not exist. '.$path, DEBUG_DEVELOPER);
 148                  }
 149              }
 150              if ($path !== false && !is_writable($path)) {
 151                  $path = false;
 152                  debugging('The file cache store path is not writable for `'.$name.'`', DEBUG_DEVELOPER);
 153              }
 154          } else {
 155              $path = make_cache_directory('cachestore_file/'.preg_replace('#[^a-zA-Z0-9\.\-_]+#', '', $name));
 156          }
 157          $this->isready = $path !== false;
 158          $this->filestorepath = $path;
 159          // This will be updated once the store has been initialised for a definition.
 160          $this->path = $path;
 161  
 162          // Check if we should prescan the directory.
 163          if (array_key_exists('prescan', $configuration)) {
 164              $this->prescan = (bool)$configuration['prescan'];
 165          } else {
 166              // Default is no, we should not prescan.
 167              $this->prescan = false;
 168          }
 169          // Check if we should be storing in a single directory.
 170          if (array_key_exists('singledirectory', $configuration)) {
 171              $this->singledirectory = (bool)$configuration['singledirectory'];
 172          } else {
 173              // Default: No, we will use multiple directories.
 174              $this->singledirectory = false;
 175          }
 176      }
 177  
 178      /**
 179       * Performs any necessary operation when the file store instance has been created.
 180       */
 181      public function instance_created() {
 182          if ($this->isready && !$this->prescan) {
 183              // It is supposed the store instance to expect an empty folder.
 184              $this->purge_all_definitions();
 185          }
 186      }
 187  
 188      /**
 189       * Returns true if this store instance is ready to be used.
 190       * @return bool
 191       */
 192      public function is_ready() {
 193          return $this->isready;
 194      }
 195  
 196      /**
 197       * Returns true once this instance has been initialised.
 198       *
 199       * @return bool
 200       */
 201      public function is_initialised() {
 202          return true;
 203      }
 204  
 205      /**
 206       * Returns the supported features as a combined int.
 207       *
 208       * @param array $configuration
 209       * @return int
 210       */
 211      public static function get_supported_features(array $configuration = array()) {
 212          $supported = self::SUPPORTS_DATA_GUARANTEE +
 213                       self::SUPPORTS_NATIVE_TTL +
 214                       self::IS_SEARCHABLE +
 215                       self::DEREFERENCES_OBJECTS;
 216          return $supported;
 217      }
 218  
 219      /**
 220       * Returns false as this store does not support multiple identifiers.
 221       * (This optional function is a performance optimisation; it must be
 222       * consistent with the value from get_supported_features.)
 223       *
 224       * @return bool False
 225       */
 226      public function supports_multiple_identifiers() {
 227          return false;
 228      }
 229  
 230      /**
 231       * Returns the supported modes as a combined int.
 232       *
 233       * @param array $configuration
 234       * @return int
 235       */
 236      public static function get_supported_modes(array $configuration = array()) {
 237          return self::MODE_APPLICATION + self::MODE_SESSION;
 238      }
 239  
 240      /**
 241       * Returns true if the store requirements are met.
 242       *
 243       * @return bool
 244       */
 245      public static function are_requirements_met() {
 246          return true;
 247      }
 248  
 249      /**
 250       * Returns true if the given mode is supported by this store.
 251       *
 252       * @param int $mode One of cache_store::MODE_*
 253       * @return bool
 254       */
 255      public static function is_supported_mode($mode) {
 256          return ($mode === self::MODE_APPLICATION || $mode === self::MODE_SESSION);
 257      }
 258  
 259      /**
 260       * Initialises the cache.
 261       *
 262       * Once this has been done the cache is all set to be used.
 263       *
 264       * @param cache_definition $definition
 265       */
 266      public function initialise(cache_definition $definition) {
 267          $this->definition = $definition;
 268          $hash = preg_replace('#[^a-zA-Z0-9]+#', '_', $this->definition->get_id());
 269          $this->path = $this->filestorepath.'/'.$hash;
 270          make_writable_directory($this->path, false);
 271          if ($this->prescan && $definition->get_mode() !== self::MODE_REQUEST) {
 272              $this->prescan = false;
 273          }
 274          if ($this->prescan) {
 275              $this->prescan_keys();
 276          }
 277      }
 278  
 279      /**
 280       * Pre-scan the cache to see which keys are present.
 281       */
 282      protected function prescan_keys() {
 283          $files = glob($this->glob_keys_pattern(), GLOB_MARK | GLOB_NOSORT);
 284          if (is_array($files)) {
 285              foreach ($files as $filename) {
 286                  $this->keys[basename($filename)] = filemtime($filename);
 287              }
 288          }
 289      }
 290  
 291      /**
 292       * Gets a pattern suitable for use with glob to find all keys in the cache.
 293       *
 294       * @param string $prefix A prefix to use.
 295       * @return string The pattern.
 296       */
 297      protected function glob_keys_pattern($prefix = '') {
 298          if ($this->singledirectory) {
 299              return $this->path . '/'.$prefix.'*.cache';
 300          } else {
 301              return $this->path . '/*/'.$prefix.'*.cache';
 302          }
 303      }
 304  
 305      /**
 306       * Returns the file path to use for the given key.
 307       *
 308       * @param string $key The key to generate a file path for.
 309       * @param bool $create If set to the true the directory structure the key requires will be created.
 310       * @return string The full path to the file that stores a particular cache key.
 311       */
 312      protected function file_path_for_key($key, $create = false) {
 313          if ($this->singledirectory) {
 314              // Its a single directory, easy, just the store instances path + the file name.
 315              return $this->path . '/' . $key . '.cache';
 316          } else {
 317              // We are using a single subdirectory to achieve 1 level.
 318             // We suffix the subdir so it does not clash with any windows
 319             // reserved filenames like 'con'.
 320              $subdir = substr($key, 0, 3) . '-cache';
 321              $dir = $this->path . '/' . $subdir;
 322              if ($create) {
 323                  // Create the directory. This function does it recursivily!
 324                  make_writable_directory($dir, false);
 325              }
 326              return $dir . '/' . $key . '.cache';
 327          }
 328      }
 329  
 330      /**
 331       * Retrieves an item from the cache store given its key.
 332       *
 333       * @param string $key The key to retrieve
 334       * @return mixed The data that was associated with the key, or false if the key did not exist.
 335       */
 336      public function get($key) {
 337          $filename = $key.'.cache';
 338          $file = $this->file_path_for_key($key);
 339          $ttl = $this->definition->get_ttl();
 340          $maxtime = 0;
 341          if ($ttl) {
 342              $maxtime = cache::now() - $ttl;
 343          }
 344          $readfile = false;
 345          if ($this->prescan && array_key_exists($filename, $this->keys)) {
 346              if ((!$ttl || $this->keys[$filename] >= $maxtime) && file_exists($file)) {
 347                  $readfile = true;
 348              } else {
 349                  $this->delete($key);
 350              }
 351          } else if (file_exists($file) && (!$ttl || filemtime($file) >= $maxtime)) {
 352              $readfile = true;
 353          }
 354          if (!$readfile) {
 355              return false;
 356          }
 357          // Open ensuring the file for reading in binary format.
 358          if (!$handle = fopen($file, 'rb')) {
 359              return false;
 360          }
 361  
 362          // Note: There is no need to perform any file locking here.
 363          // The cache file is only ever written to in the `write_file` function, where it does so by writing to a temp
 364          // file and performing an atomic rename of that file. The target file is never locked, so there is no benefit to
 365          // obtaining a lock (shared or exclusive) here.
 366  
 367          $data = '';
 368          // Read the data in 1Mb chunks. Small caches will not loop more than once.  We don't use filesize as it may
 369          // be cached with a different value than what we need to read from the file.
 370          do {
 371              $data .= fread($handle, 1048576);
 372          } while (!feof($handle));
 373  
 374          // Return it unserialised.
 375          return $this->prep_data_after_read($data);
 376      }
 377  
 378      /**
 379       * Retrieves several items from the cache store in a single transaction.
 380       *
 381       * If not all of the items are available in the cache then the data value for those that are missing will be set to false.
 382       *
 383       * @param array $keys The array of keys to retrieve
 384       * @return array An array of items from the cache. There will be an item for each key, those that were not in the store will
 385       *      be set to false.
 386       */
 387      public function get_many($keys) {
 388          $result = array();
 389          foreach ($keys as $key) {
 390              $result[$key] = $this->get($key);
 391          }
 392          return $result;
 393      }
 394  
 395      /**
 396       * Deletes an item from the cache store.
 397       *
 398       * @param string $key The key to delete.
 399       * @return bool Returns true if the operation was a success, false otherwise.
 400       */
 401      public function delete($key) {
 402          $filename = $key.'.cache';
 403          $file = $this->file_path_for_key($key);
 404          if (file_exists($file) && @unlink($file)) {
 405              unset($this->keys[$filename]);
 406              return true;
 407          }
 408  
 409          return false;
 410      }
 411  
 412      /**
 413       * Deletes several keys from the cache in a single action.
 414       *
 415       * @param array $keys The keys to delete
 416       * @return int The number of items successfully deleted.
 417       */
 418      public function delete_many(array $keys) {
 419          $count = 0;
 420          foreach ($keys as $key) {
 421              if ($this->delete($key)) {
 422                  $count++;
 423              }
 424          }
 425          return $count;
 426      }
 427  
 428      /**
 429       * Sets an item in the cache given its key and data value.
 430       *
 431       * @param string $key The key to use.
 432       * @param mixed $data The data to set.
 433       * @return bool True if the operation was a success false otherwise.
 434       */
 435      public function set($key, $data) {
 436          $this->ensure_path_exists();
 437          $filename = $key.'.cache';
 438          $file = $this->file_path_for_key($key, true);
 439          $result = $this->write_file($file, $this->prep_data_before_save($data));
 440          if (!$result) {
 441              // Couldn't write the file.
 442              return false;
 443          }
 444          // Record the key if required.
 445          if ($this->prescan) {
 446              $this->keys[$filename] = cache::now() + 1;
 447          }
 448          // Return true.. it all worked **miracles**.
 449          return true;
 450      }
 451  
 452      /**
 453       * Prepares data to be stored in a file.
 454       *
 455       * @param mixed $data
 456       * @return string
 457       */
 458      protected function prep_data_before_save($data) {
 459          return serialize($data);
 460      }
 461  
 462      /**
 463       * Prepares the data it has been read from the cache. Undoing what was done in prep_data_before_save.
 464       *
 465       * @param string $data
 466       * @return mixed
 467       * @throws coding_exception
 468       */
 469      protected function prep_data_after_read($data) {
 470          $result = @unserialize($data);
 471          if ($result === false && $data != serialize(false)) {
 472              throw new coding_exception('Failed to unserialise data from file. Either failed to read, or failed to write.');
 473          }
 474          return $result;
 475      }
 476  
 477      /**
 478       * Sets many items in the cache in a single transaction.
 479       *
 480       * @param array $keyvaluearray An array of key value pairs. Each item in the array will be an associative array with two
 481       *      keys, 'key' and 'value'.
 482       * @return int The number of items successfully set. It is up to the developer to check this matches the number of items
 483       *      sent ... if they care that is.
 484       */
 485      public function set_many(array $keyvaluearray) {
 486          $count = 0;
 487          foreach ($keyvaluearray as $pair) {
 488              if ($this->set($pair['key'], $pair['value'])) {
 489                  $count++;
 490              }
 491          }
 492          return $count;
 493      }
 494  
 495      /**
 496       * Checks if the store has a record for the given key and returns true if so.
 497       *
 498       * @param string $key
 499       * @return bool
 500       */
 501      public function has($key) {
 502          $filename = $key.'.cache';
 503          $maxtime = cache::now() - $this->definition->get_ttl();
 504          if ($this->prescan) {
 505              return array_key_exists($filename, $this->keys) && $this->keys[$filename] >= $maxtime;
 506          }
 507          $file = $this->file_path_for_key($key);
 508          return (file_exists($file) && ($this->definition->get_ttl() == 0 || filemtime($file) >= $maxtime));
 509      }
 510  
 511      /**
 512       * Returns true if the store contains records for all of the given keys.
 513       *
 514       * @param array $keys
 515       * @return bool
 516       */
 517      public function has_all(array $keys) {
 518          foreach ($keys as $key) {
 519              if (!$this->has($key)) {
 520                  return false;
 521              }
 522          }
 523          return true;
 524      }
 525  
 526      /**
 527       * Returns true if the store contains records for any of the given keys.
 528       *
 529       * @param array $keys
 530       * @return bool
 531       */
 532      public function has_any(array $keys) {
 533          foreach ($keys as $key) {
 534              if ($this->has($key)) {
 535                  return true;
 536              }
 537          }
 538          return false;
 539      }
 540  
 541      /**
 542       * Purges the cache definition deleting all the items within it.
 543       *
 544       * @return boolean True on success. False otherwise.
 545       */
 546      public function purge() {
 547          if ($this->isready) {
 548              $files = glob($this->glob_keys_pattern(), GLOB_MARK | GLOB_NOSORT);
 549              if (is_array($files)) {
 550                  foreach ($files as $filename) {
 551                      @unlink($filename);
 552                  }
 553              }
 554              $this->keys = array();
 555          }
 556          return true;
 557      }
 558  
 559      /**
 560       * Purges all the cache definitions deleting all items within them.
 561       *
 562       * @return boolean True on success. False otherwise.
 563       */
 564      protected function purge_all_definitions() {
 565          // Warning: limit the deletion to what file store is actually able
 566          // to create using the internal {@link purge()} providing the
 567          // {@link $path} with a wildcard to perform a purge action over all the definitions.
 568          $currpath = $this->path;
 569          $this->path = $this->filestorepath.'/*';
 570          $result = $this->purge();
 571          $this->path = $currpath;
 572          return $result;
 573      }
 574  
 575      /**
 576       * Given the data from the add instance form this function creates a configuration array.
 577       *
 578       * @param stdClass $data
 579       * @return array
 580       */
 581      public static function config_get_configuration_array($data) {
 582          $config = array();
 583  
 584          if (isset($data->path)) {
 585              $config['path'] = $data->path;
 586          }
 587          if (isset($data->autocreate)) {
 588              $config['autocreate'] = $data->autocreate;
 589          }
 590          if (isset($data->singledirectory)) {
 591              $config['singledirectory'] = $data->singledirectory;
 592          }
 593          if (isset($data->prescan)) {
 594              $config['prescan'] = $data->prescan;
 595          }
 596  
 597          return $config;
 598      }
 599  
 600      /**
 601       * Allows the cache store to set its data against the edit form before it is shown to the user.
 602       *
 603       * @param moodleform $editform
 604       * @param array $config
 605       */
 606      public static function config_set_edit_form_data(moodleform $editform, array $config) {
 607          $data = array();
 608          if (!empty($config['path'])) {
 609              $data['path'] = $config['path'];
 610          }
 611          if (isset($config['autocreate'])) {
 612              $data['autocreate'] = (bool)$config['autocreate'];
 613          }
 614          if (isset($config['singledirectory'])) {
 615              $data['singledirectory'] = (bool)$config['singledirectory'];
 616          }
 617          if (isset($config['prescan'])) {
 618              $data['prescan'] = (bool)$config['prescan'];
 619          }
 620          $editform->set_data($data);
 621      }
 622  
 623      /**
 624       * Checks to make sure that the path for the file cache exists.
 625       *
 626       * @return bool
 627       * @throws coding_exception
 628       */
 629      protected function ensure_path_exists() {
 630          global $CFG;
 631          if (!is_writable($this->path)) {
 632              if ($this->custompath && !$this->autocreate) {
 633                  throw new coding_exception('File store path does not exist. It must exist and be writable by the web server.');
 634              }
 635              $createdcfg = false;
 636              if (!isset($CFG)) {
 637                  // This can only happen during destruction of objects.
 638                  // A cache is being used within a destructor, php is ending a request and $CFG has
 639                  // already being cleaned up.
 640                  // Rebuild $CFG with directory permissions just to complete this write.
 641                  $CFG = $this->cfg;
 642                  $createdcfg = true;
 643              }
 644              if (!make_writable_directory($this->path, false)) {
 645                  throw new coding_exception('File store path does not exist and can not be created.');
 646              }
 647              if ($createdcfg) {
 648                  // We re-created it so we'll clean it up.
 649                  unset($CFG);
 650              }
 651          }
 652          return true;
 653      }
 654  
 655      /**
 656       * Performs any necessary clean up when the file store instance is being deleted.
 657       *
 658       * 1. Purges the cache directory.
 659       * 2. Deletes the directory we created for the given definition.
 660       */
 661      public function instance_deleted() {
 662          $this->purge_all_definitions();
 663          @rmdir($this->filestorepath);
 664      }
 665  
 666      /**
 667       * Generates an instance of the cache store that can be used for testing.
 668       *
 669       * Returns an instance of the cache store, or false if one cannot be created.
 670       *
 671       * @param cache_definition $definition
 672       * @return cachestore_file
 673       */
 674      public static function initialise_test_instance(cache_definition $definition) {
 675          $name = 'File test';
 676          $path = make_cache_directory('cachestore_file_test');
 677          $cache = new cachestore_file($name, array('path' => $path));
 678          if ($cache->is_ready()) {
 679              $cache->initialise($definition);
 680          }
 681          return $cache;
 682      }
 683  
 684      /**
 685       * Generates the appropriate configuration required for unit testing.
 686       *
 687       * @return array Array of unit test configuration data to be used by initialise().
 688       */
 689      public static function unit_test_configuration() {
 690          return array();
 691      }
 692  
 693      /**
 694       * Writes your madness to a file.
 695       *
 696       * There are several things going on in this function to try to ensure what we don't end up with partial writes etc.
 697       *   1. Files for writing are opened with the mode xb, the file must be created and can not already exist.
 698       *   2. Renaming, data is written to a temporary file, where it can be verified using md5 and is then renamed.
 699       *
 700       * @param string $file Absolute file path
 701       * @param string $content The content to write.
 702       * @return bool
 703       */
 704      protected function write_file($file, $content) {
 705          // Generate a temp file that is going to be unique. We'll rename it at the end to the desired file name.
 706          // in this way we avoid partial writes.
 707          $path = dirname($file);
 708          while (true) {
 709              $tempfile = $path.'/'.uniqid(sesskey().'.', true) . '.temp';
 710              if (!file_exists($tempfile)) {
 711                  break;
 712              }
 713          }
 714  
 715          // Open the file with mode=x. This acts to create and open the file for writing only.
 716          // If the file already exists this will return false.
 717          // We also force binary.
 718          $handle = @fopen($tempfile, 'xb+');
 719          if ($handle === false) {
 720              // File already exists... lock already exists, return false.
 721              return false;
 722          }
 723          fwrite($handle, $content);
 724          fflush($handle);
 725          // Close the handle, we're done.
 726          fclose($handle);
 727  
 728          if (md5_file($tempfile) !== md5($content)) {
 729              // The md5 of the content of the file must match the md5 of the content given to be written.
 730              @unlink($tempfile);
 731              return false;
 732          }
 733  
 734          // Finally rename the temp file to the desired file, returning the true|false result.
 735          $result = rename($tempfile, $file);
 736          @chmod($file, $this->cfg->filepermissions);
 737          if (!$result) {
 738              // Failed to rename, don't leave files lying around.
 739              @unlink($tempfile);
 740          }
 741          return $result;
 742      }
 743  
 744      /**
 745       * Returns the name of this instance.
 746       * @return string
 747       */
 748      public function my_name() {
 749          return $this->name;
 750      }
 751  
 752      /**
 753       * Finds all of the keys being used by this cache store instance.
 754       *
 755       * @return array
 756       */
 757      public function find_all() {
 758          $this->ensure_path_exists();
 759          $files = glob($this->glob_keys_pattern(), GLOB_MARK | GLOB_NOSORT);
 760          $return = array();
 761          if ($files === false) {
 762              return $return;
 763          }
 764          foreach ($files as $file) {
 765              $return[] = substr(basename($file), 0, -6);
 766          }
 767          return $return;
 768      }
 769  
 770      /**
 771       * Finds all of the keys whose keys start with the given prefix.
 772       *
 773       * @param string $prefix
 774       */
 775      public function find_by_prefix($prefix) {
 776          $this->ensure_path_exists();
 777          $prefix = preg_replace('#(\*|\?|\[)#', '[$1]', $prefix);
 778          $files = glob($this->glob_keys_pattern($prefix), GLOB_MARK | GLOB_NOSORT);
 779          $return = array();
 780          if ($files === false) {
 781              return $return;
 782          }
 783          foreach ($files as $file) {
 784              // Trim off ".cache" from the end.
 785              $return[] = substr(basename($file), 0, -6);
 786          }
 787          return $return;
 788      }
 789  }