getCacheDir(); if (is_dir($file_cache_dir)) { $dir = dir($file_cache_dir); while (($entry = $dir->read()) !== FALSE) { if ($entry == '.' || $entry == '..') { continue; } $files[] = $entry; } $dir->close(); } return $files; } /** * Constructs a file path for a certain cache ID. * * @param string $cid * The cache ID to construct a file path for. * * @return string * The constructed file path. */ public function constructFilePath($cid) { return $this->getCacheDir() . '/' . $cid; } /** * Saves raw contents to a file in the cache directory. * * @param string $cid * The cache ID. * @param object $response * The HTTP Response object. * * @return string|null * The name of the file that was created or NULL if no file was created. * * @throws Exception * In case the cache dir is not writable. */ public function saveFile($cid, $response) { if (isset($response->data)) { $file_cache_dir = $this->getCacheDir(); if (!file_prepare_directory($file_cache_dir, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS)) { // Cache directory is not writeable. if (user_access('administer feeds')) { $message = t("The feeds cache directory (@dir) either cannot be created or is not writable. You can change the cache directory by setting the '@variable' variable.", array( '@dir' => $file_cache_dir, '@variable' => 'feeds_http_file_cache_dir', )); } else { $message = t('The feeds cache directory either cannot be created or is not writable. Please contact your site administrator.'); } throw new Exception($message); } $filename = $this->constructFilePath($cid); file_put_contents($filename, $response->data); return $filename; } } /** * Deletes a file from the cache directory. * * @param string $cid * The file to delete. */ protected function deleteFile($cid) { $filename = $this->constructFilePath($cid); if (is_file($filename)) { drupal_unlink($filename); } } /** * Deletes multiple files from the cache directory. * * @param array $cids * The files to delete. */ protected function deleteMultipleFiles(array $cids) { foreach ($cids as $cid) { $this->deleteFile($cid); } } /** * Deletes all files from the cache directory. */ protected function deleteAllFiles() { $file_cache_dir = $this->getCacheDir(); if (drupal_realpath($file_cache_dir) && file_exists($file_cache_dir)) { @file_unmanaged_delete_recursive($file_cache_dir); } } /** * Deletes files from the cache directory starting with a certain string. * * @param string $string * The string with which the file name should start. */ protected function deleteFilesStartingWith($string) { $mask = '/^' . preg_quote($string) . '/'; $files_to_delete = file_scan_directory($this->getCacheDir(), $mask); foreach ($files_to_delete as $file) { file_unmanaged_delete($file->uri); } } /** * {@inheritdoc} * * Converts data to a FeedsHTTPCacheItem object, if needed. */ protected function prepareItem($cache) { $cache = parent::prepareItem($cache); if (isset($cache->data) && is_object($cache->data) && !($cache->data instanceof FeedsHTTPCacheItem)) { // Convert to a FeedsHTTPCacheItem object. $cache->data = new FeedsHTTPCacheItem($cache->cid, $cache->data); } return $cache; } /** * {@inheritdoc} */ public function clear($cid = NULL, $wildcard = FALSE) { if (empty($cid)) { // Clean up expired cached files. $cache_lifetime = variable_get('cache_lifetime', 0); // Check if expired cached files should be cleaned up now. if ($cache_lifetime) { $cache_flush = variable_get('cache_flush_' . $this->bin, 0); $flush_expired = $cache_flush && REQUEST_TIME > ($cache_flush + $cache_lifetime); } else { $flush_expired = TRUE; } if ($flush_expired) { // Clear files for which the cache entries are expired. $result = db_select($this->bin) ->fields($this->bin, array('cid')) ->condition('expire', CACHE_PERMANENT, '<>') ->condition('expire', REQUEST_TIME, '<') ->execute() ->fetchAllAssoc('cid'); $cids = array_keys($result); $this->deleteMultipleFiles($cids); } } else { if ($wildcard) { if ($cid == '*') { $this->deleteAllFiles(); } else { $this->deleteFilesStartingWith($cid); } } elseif (is_array($cid)) { $this->deleteMultipleFiles($cid); } else { $this->deleteFile($cid); } } parent::clear($cid, $wildcard); } /** * {@inheritdoc} */ public function set($cid, $item, $expire = CACHE_PERMANENT) { if ($item instanceof FeedsHTTPCacheItem) { // Given item already got rid of the raw data. $item->setCid($cid); return parent::set($cid, $item, $expire); } // Create a cache item to only cache what is needed. // The cache item will take care of saving the raw data to a file. $item = new FeedsHTTPCacheItem($cid, $item); parent::set($cid, $item, $expire); } /** * {@inheritdoc} */ public function isEmpty() { // Check database first. if (!parent::isEmpty()) { return FALSE; } // Check if the cache directory is empty. $file_cache_dir = $this->getCacheDir(); if (is_dir($file_cache_dir)) { $dir = dir($file_cache_dir); while (($entry = $dir->read()) !== FALSE) { if ($entry == '.' || $entry == '..') { continue; } // At least one file is found, so the cache directory is not empty. $dir->close(); return FALSE; } // No files found. The cache directory is empty. $dir->close(); return TRUE; } // No cache dir found. return TRUE; } /** * Queues all files to be synced with the cache list. */ public function startSync() { // Get all files currently in the cache directory. $files = $this->getFileList(); $queue = DrupalQueue::get('feeds_sync_cache_feeds_http'); $queue->createItem(array( 'files' => $files, )); } /** * Removes files for which an entry no longer appears in the cache. * * @param array $files * The files to check. */ public function sync(array $files) { if (count($files) > 50) { // There are more than 50 files in the cache directory to check. Take the // first 50 and put the rest on the queue. $queue = DrupalQueue::get('feeds_sync_cache_feeds_http'); $queue->createItem(array( 'files' => array_slice($files, 50), )); // Pick the first 50. $files = array_slice($files, 0, 50); } // Try to load cache entries for each file. Since the file names are passed // by reference and the file names for which a cache entry is found are // removed from the array, we end up with a list of file names for which NO // cache entry is found. cache_get_multiple($files, $this->bin); // The files for which no cache entry is found, can be removed. $this->deleteMultipleFiles($files); } }