Projet

Général

Profil

Paste
Télécharger (8,64 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / feeds / includes / FeedsHTTPCache.inc @ ed9a13f1

1
<?php
2

    
3
/**
4
 * @file
5
 * Contains FeedsHTTPCache class.
6
 */
7

    
8
/**
9
 * Cache implementation for the Feeds HTTP cache.
10
 */
11
class FeedsHTTPCache extends DrupalDatabaseCache {
12

    
13
  /**
14
   * Returns cache object.
15
   *
16
   * @param string $bin
17
   *   The cache bin.
18
   *
19
   * @return FeedsHTTPCache
20
   *   An instance of FeedsHTTPCache.
21
   */
22
  public static function getInstance($bin) {
23
    $cache_object = _cache_get_object($bin);
24
    if (!($cache_object instanceof self)) {
25
      // A different cache class could be used for the cache_feeds_http bin that
26
      // does not extend FeedsHTTPCache. In this case, just instantiate the
27
      // FeedsHTTPCache class.
28
      $cache_object = new self($bin);
29
    }
30
    return $cache_object;
31
  }
32

    
33
  /**
34
   * Returns cache dir.
35
   *
36
   * @return string
37
   *   The cache dir to use.
38
   */
39
  public function getCacheDir() {
40
    $dir = variable_get('feeds_http_file_cache_dir', NULL);
41
    if ($dir) {
42
      return $dir;
43
    }
44
    else {
45
      $schemes = file_get_stream_wrappers(STREAM_WRAPPERS_WRITE_VISIBLE);
46
      $scheme = isset($schemes['private']) ? 'private' : 'public';
47
      return $scheme . '://feeds/cache';
48
    }
49
  }
50

    
51
  /**
52
   * Returns a list of file names in the cache directory.
53
   *
54
   * @return array
55
   *   A list of files.
56
   */
57
  public function getFileList() {
58
    $files = array();
59

    
60
    $file_cache_dir = $this->getCacheDir();
61
    if (is_dir($file_cache_dir)) {
62
      $dir = dir($file_cache_dir);
63
      while (($entry = $dir->read()) !== FALSE) {
64
        if ($entry == '.' || $entry == '..') {
65
          continue;
66
        }
67
        $files[] = $entry;
68
      }
69
      $dir->close();
70
    }
71

    
72
    return $files;
73
  }
74

    
75
  /**
76
   * Constructs a file path for a certain cache ID.
77
   *
78
   * @param string $cid
79
   *   The cache ID to construct a file path for.
80
   *
81
   * @return string
82
   *   The constructed file path.
83
   */
84
  public function constructFilePath($cid) {
85
    return $this->getCacheDir() . '/' . $cid;
86
  }
87

    
88
  /**
89
   * Saves raw contents to a file in the cache directory.
90
   *
91
   * @param string $cid
92
   *   The cache ID.
93
   * @param object $response
94
   *   The HTTP Response object.
95
   *
96
   * @return string|null
97
   *   The name of the file that was created or NULL if no file was created.
98
   *
99
   * @throws Exception
100
   *   In case the cache dir is not writable.
101
   */
102
  public function saveFile($cid, $response) {
103
    if (isset($response->data)) {
104
      $file_cache_dir = $this->getCacheDir();
105
      if (!file_prepare_directory($file_cache_dir, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS)) {
106
        // Cache directory is not writeable.
107
        if (user_access('administer feeds')) {
108
          $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(
109
            '@dir' => $file_cache_dir,
110
            '@variable' => 'feeds_http_file_cache_dir',
111
          ));
112
        }
113
        else {
114
          $message = t('The feeds cache directory either cannot be created or is not writable. Please contact your site administrator.');
115
        }
116
        throw new Exception($message);
117
      }
118
      $filename = $this->constructFilePath($cid);
119
      file_put_contents($filename, $response->data);
120

    
121
      return $filename;
122
    }
123
  }
124

    
125
  /**
126
   * Deletes a file from the cache directory.
127
   *
128
   * @param string $cid
129
   *   The file to delete.
130
   */
131
  protected function deleteFile($cid) {
132
    $filename = $this->constructFilePath($cid);
133
    if (is_file($filename)) {
134
      drupal_unlink($filename);
135
    }
136
  }
137

    
138
  /**
139
   * Deletes multiple files from the cache directory.
140
   *
141
   * @param array $cids
142
   *   The files to delete.
143
   */
144
  protected function deleteMultipleFiles(array $cids) {
145
    foreach ($cids as $cid) {
146
      $this->deleteFile($cid);
147
    }
148
  }
149

    
150
  /**
151
   * Deletes all files from the cache directory.
152
   */
153
  protected function deleteAllFiles() {
154
    $file_cache_dir = $this->getCacheDir();
155
    if (drupal_realpath($file_cache_dir) && file_exists($file_cache_dir)) {
156
      @file_unmanaged_delete_recursive($file_cache_dir);
157
    }
158
  }
159

    
160
  /**
161
   * Deletes files from the cache directory starting with a certain string.
162
   *
163
   * @param string $string
164
   *   The string with which the file name should start.
165
   */
166
  protected function deleteFilesStartingWith($string) {
167
    $mask = '/^' . preg_quote($string) . '/';
168
    $files_to_delete = file_scan_directory($this->getCacheDir(), $mask);
169
    foreach ($files_to_delete as $file) {
170
      file_unmanaged_delete($file->uri);
171
    }
172
  }
173

    
174
  /**
175
   * {@inheritdoc}
176
   *
177
   * Converts data to a FeedsHTTPCacheItem object, if needed.
178
   */
179
  protected function prepareItem($cache) {
180
    $cache = parent::prepareItem($cache);
181

    
182
    if (isset($cache->data) && is_object($cache->data) && !($cache->data instanceof FeedsHTTPCacheItem)) {
183
      // Convert to a FeedsHTTPCacheItem object.
184
      $cache->data = new FeedsHTTPCacheItem($cache->cid, $cache->data);
185
    }
186

    
187
    return $cache;
188
  }
189

    
190
  /**
191
   * {@inheritdoc}
192
   */
193
  public function clear($cid = NULL, $wildcard = FALSE) {
194
    if (empty($cid)) {
195
      // Clean up expired cached files.
196
      $cache_lifetime = variable_get('cache_lifetime', 0);
197

    
198
      // Check if expired cached files should be cleaned up now.
199
      if ($cache_lifetime) {
200
        $cache_flush = variable_get('cache_flush_' . $this->bin, 0);
201
        $flush_expired = $cache_flush && REQUEST_TIME > ($cache_flush + $cache_lifetime);
202
      }
203
      else {
204
        $flush_expired = TRUE;
205
      }
206

    
207
      if ($flush_expired) {
208
        // Clear files for which the cache entries are expired.
209
        $result = db_select($this->bin)
210
          ->fields($this->bin, array('cid'))
211
          ->condition('expire', CACHE_PERMANENT, '<>')
212
          ->condition('expire', REQUEST_TIME, '<')
213
          ->execute()
214
          ->fetchAllAssoc('cid');
215
        $cids = array_keys($result);
216

    
217
        $this->deleteMultipleFiles($cids);
218
      }
219
    }
220
    else {
221
      if ($wildcard) {
222
        if ($cid == '*') {
223
          $this->deleteAllFiles();
224
        }
225
        else {
226
          $this->deleteFilesStartingWith($cid);
227
        }
228
      }
229
      elseif (is_array($cid)) {
230
        $this->deleteMultipleFiles($cid);
231
      }
232
      else {
233
        $this->deleteFile($cid);
234
      }
235
    }
236

    
237
    parent::clear($cid, $wildcard);
238
  }
239

    
240
  /**
241
   * {@inheritdoc}
242
   */
243
  public function set($cid, $item, $expire = CACHE_PERMANENT) {
244
    if ($item instanceof FeedsHTTPCacheItem) {
245
      // Given item already got rid of the raw data.
246
      $item->setCid($cid);
247
      return parent::set($cid, $item, $expire);
248
    }
249

    
250
    // Create a cache item to only cache what is needed.
251
    // The cache item will take care of saving the raw data to a file.
252
    $item = new FeedsHTTPCacheItem($cid, $item);
253

    
254
    parent::set($cid, $item, $expire);
255
  }
256

    
257
  /**
258
   * {@inheritdoc}
259
   */
260
  public function isEmpty() {
261
    // Check database first.
262
    if (!parent::isEmpty()) {
263
      return FALSE;
264
    }
265

    
266
    // Check if the cache directory is empty.
267
    $file_cache_dir = $this->getCacheDir();
268

    
269
    if (is_dir($file_cache_dir)) {
270
      $dir = dir($file_cache_dir);
271
      while (($entry = $dir->read()) !== FALSE) {
272
        if ($entry == '.' || $entry == '..') {
273
          continue;
274
        }
275
        // At least one file is found, so the cache directory is not empty.
276
        $dir->close();
277
        return FALSE;
278
      }
279
      // No files found. The cache directory is empty.
280
      $dir->close();
281
      return TRUE;
282
    }
283

    
284
    // No cache dir found.
285
    return TRUE;
286
  }
287

    
288
  /**
289
   * Queues all files to be synced with the cache list.
290
   */
291
  public function startSync() {
292
    // Get all files currently in the cache directory.
293
    $files = $this->getFileList();
294

    
295
    $queue = DrupalQueue::get('feeds_sync_cache_feeds_http');
296
    $queue->createItem(array(
297
      'files' => $files,
298
    ));
299
  }
300

    
301
  /**
302
   * Removes files for which an entry no longer appears in the cache.
303
   *
304
   * @param array $files
305
   *   The files to check.
306
   */
307
  public function sync(array $files) {
308
    if (count($files) > 50) {
309
      // There are more than 50 files in the cache directory to check. Take the
310
      // first 50 and put the rest on the queue.
311
      $queue = DrupalQueue::get('feeds_sync_cache_feeds_http');
312
      $queue->createItem(array(
313
        'files' => array_slice($files, 50),
314
      ));
315

    
316
      // Pick the first 50.
317
      $files = array_slice($files, 0, 50);
318
    }
319

    
320
    // Try to load cache entries for each file. Since the file names are passed
321
    // by reference and the file names for which a cache entry is found are
322
    // removed from the array, we end up with a list of file names for which NO
323
    // cache entry is found.
324
    cache_get_multiple($files, $this->bin);
325

    
326
    // The files for which no cache entry is found, can be removed.
327
    $this->deleteMultipleFiles($files);
328
  }
329

    
330
}