Projet

Général

Profil

Paste
Télécharger (10,5 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / feeds / plugins / FeedsHTTPFetcher.inc @ 13755f8d

1
<?php
2

    
3
/**
4
 * @file
5
 * Home of the FeedsHTTPFetcher and related classes.
6
 */
7

    
8
feeds_include_library('PuSHSubscriber.inc', 'PuSHSubscriber');
9

    
10
/**
11
 * Result of FeedsHTTPFetcher::fetch().
12
 */
13
class FeedsHTTPFetcherResult extends FeedsFetcherResult {
14
  protected $url;
15
  protected $file_path;
16
  protected $timeout;
17

    
18
  /**
19
   * Constructor.
20
   */
21
  public function __construct($url = NULL) {
22
    $this->url = $url;
23
    parent::__construct('');
24
  }
25

    
26
  /**
27
   * Overrides FeedsFetcherResult::getRaw();
28
   */
29
  public function getRaw() {
30
    feeds_include_library('http_request.inc', 'http_request');
31
    $result = http_request_get($this->url, NULL, NULL, NULL, $this->timeout);
32
    if (!in_array($result->code, array(200, 201, 202, 203, 204, 205, 206))) {
33
      throw new Exception(t('Download of @url failed with code !code.', array('@url' => $this->url, '!code' => $result->code)));
34
    }
35
    return $this->sanitizeRaw($result->data);
36
  }
37

    
38
  public function getTimeout() {
39
    return $this->timeout;
40
  }
41

    
42
  public function setTimeout($timeout) {
43
    $this->timeout = $timeout;
44
  }
45
}
46

    
47
/**
48
 * Fetches data via HTTP.
49
 */
50
class FeedsHTTPFetcher extends FeedsFetcher {
51

    
52
  /**
53
   * Implements FeedsFetcher::fetch().
54
   */
55
  public function fetch(FeedsSource $source) {
56
    $source_config = $source->getConfigFor($this);
57
    if ($this->config['use_pubsubhubbub'] && ($raw = $this->subscriber($source->feed_nid)->receive())) {
58
      return new FeedsFetcherResult($raw);
59
    }
60
    $fetcher_result = new FeedsHTTPFetcherResult($source_config['source']);
61
    // When request_timeout is empty, the global value is used.
62
    $fetcher_result->setTimeout($this->config['request_timeout']);
63
    return $fetcher_result;
64
  }
65

    
66
  /**
67
   * Clear caches.
68
   */
69
  public function clear(FeedsSource $source) {
70
    $source_config = $source->getConfigFor($this);
71
    $url = $source_config['source'];
72
    feeds_include_library('http_request.inc', 'http_request');
73
    http_request_clear_cache($url);
74
  }
75

    
76
  /**
77
   * Implements FeedsFetcher::request().
78
   */
79
  public function request($feed_nid = 0) {
80
    feeds_dbg($_GET);
81
    @feeds_dbg(file_get_contents('php://input'));
82
    // A subscription verification has been sent, verify.
83
    if (isset($_GET['hub_challenge'])) {
84
      $this->subscriber($feed_nid)->verifyRequest();
85
    }
86
    // No subscription notification has ben sent, we are being notified.
87
    else {
88
      try {
89
        feeds_source($this->id, $feed_nid)->existing()->import();
90
      }
91
      catch (Exception $e) {
92
        // In case of an error, respond with a 503 Service (temporary) unavailable.
93
        header('HTTP/1.1 503 "Not Found"', NULL, 503);
94
        drupal_exit();
95
      }
96
    }
97
    // Will generate the default 200 response.
98
    header('HTTP/1.1 200 "OK"', NULL, 200);
99
    drupal_exit();
100
  }
101

    
102
  /**
103
   * Override parent::configDefaults().
104
   */
105
  public function configDefaults() {
106
    return array(
107
      'auto_detect_feeds' => FALSE,
108
      'use_pubsubhubbub' => FALSE,
109
      'designated_hub' => '',
110
      'request_timeout' => NULL,
111
    );
112
  }
113

    
114
  /**
115
   * Override parent::configForm().
116
   */
117
  public function configForm(&$form_state) {
118
    $form = array();
119
    $form['auto_detect_feeds'] = array(
120
      '#type' => 'checkbox',
121
      '#title' => t('Auto detect feeds'),
122
      '#description' => t('If the supplied URL does not point to a feed but an HTML document, attempt to extract a feed URL from the document.'),
123
      '#default_value' => $this->config['auto_detect_feeds'],
124
    );
125
    $form['use_pubsubhubbub'] = array(
126
      '#type' => 'checkbox',
127
      '#title' => t('Use PubSubHubbub'),
128
      '#description' => t('Attempt to use a <a href="http://en.wikipedia.org/wiki/PubSubHubbub">PubSubHubbub</a> subscription if available.'),
129
      '#default_value' => $this->config['use_pubsubhubbub'],
130
    );
131
    $form['designated_hub'] = array(
132
      '#type' => 'textfield',
133
      '#title' => t('Designated hub'),
134
      '#description' => t('Enter the URL of a designated PubSubHubbub hub (e. g. superfeedr.com). If given, this hub will be used instead of the hub specified in the actual feed.'),
135
      '#default_value' => $this->config['designated_hub'],
136
      '#dependency' => array(
137
        'edit-use-pubsubhubbub' => array(1),
138
      ),
139
    );
140
   // Per importer override of global http request timeout setting.
141
   $form['request_timeout'] = array(
142
     '#type' => 'textfield',
143
     '#title' => t('Request timeout'),
144
     '#description' => t('Timeout in seconds to wait for an HTTP get request to finish.</br>' .
145
                         '<b>Note:</b> this setting will override the global setting.</br>' .
146
                         'When left empty, the global value is used.'),
147
     '#default_value' => $this->config['request_timeout'],
148
     '#element_validate' => array('element_validate_integer_positive'),
149
     '#maxlength' => 3,
150
     '#size'=> 30,
151
   );
152
    return $form;
153
  }
154

    
155
  /**
156
   * Expose source form.
157
   */
158
  public function sourceForm($source_config) {
159
    $form = array();
160
    $form['source'] = array(
161
      '#type' => 'textfield',
162
      '#title' => t('URL'),
163
      '#description' => t('Enter a feed URL.'),
164
      '#default_value' => isset($source_config['source']) ? $source_config['source'] : '',
165
      '#maxlength' => NULL,
166
      '#required' => TRUE,
167
    );
168
    return $form;
169
  }
170

    
171
  /**
172
   * Override parent::sourceFormValidate().
173
   */
174
  public function sourceFormValidate(&$values) {
175
    $values['source'] = trim($values['source']);
176

    
177
    if (!feeds_valid_url($values['source'], TRUE)) {
178
      $form_key = 'feeds][' . get_class($this) . '][source';
179
      form_set_error($form_key, t('The URL %source is invalid.', array('%source' => $values['source'])));
180
    }
181
    elseif ($this->config['auto_detect_feeds']) {
182
      feeds_include_library('http_request.inc', 'http_request');
183
      if ($url = http_request_get_common_syndication($values['source'])) {
184
        $values['source'] = $url;
185
      }
186
    }
187
  }
188

    
189
  /**
190
   * Override sourceSave() - subscribe to hub.
191
   */
192
  public function sourceSave(FeedsSource $source) {
193
    if ($this->config['use_pubsubhubbub']) {
194
      // If this is a feeds node we want to delay the subscription to
195
      // feeds_exit() to avoid transaction race conditions.
196
      if ($source->feed_nid) {
197
        $job = array('fetcher' => $this, 'source' => $source);
198
        feeds_set_subscription_job($job);
199
      }
200
      else {
201
        $this->subscribe($source);
202
      }
203
    }
204
  }
205

    
206
  /**
207
   * Override sourceDelete() - unsubscribe from hub.
208
   */
209
  public function sourceDelete(FeedsSource $source) {
210
    if ($this->config['use_pubsubhubbub']) {
211
      // If we're in a feed node, queue the unsubscribe,
212
      // else process immediately.
213
      if ($source->feed_nid) {
214
        $job = array(
215
          'type' => $source->id,
216
          'id' => $source->feed_nid,
217
          'period' => 0,
218
          'periodic' => FALSE,
219
        );
220
        JobScheduler::get('feeds_push_unsubscribe')->set($job);
221
      }
222
      else {
223
        $this->unsubscribe($source);
224
      }
225
    }
226
  }
227

    
228
  /**
229
   * Implement FeedsFetcher::subscribe() - subscribe to hub.
230
   */
231
  public function subscribe(FeedsSource $source) {
232
    $source_config = $source->getConfigFor($this);
233
    $this->subscriber($source->feed_nid)->subscribe($source_config['source'], url($this->path($source->feed_nid), array('absolute' => TRUE)), valid_url($this->config['designated_hub']) ? $this->config['designated_hub'] : '');
234
  }
235

    
236
  /**
237
   * Implement FeedsFetcher::unsubscribe() - unsubscribe from hub.
238
   */
239
  public function unsubscribe(FeedsSource $source) {
240
    $source_config = $source->getConfigFor($this);
241
    $this->subscriber($source->feed_nid)->unsubscribe($source_config['source'], url($this->path($source->feed_nid), array('absolute' => TRUE)));
242
  }
243

    
244
  /**
245
   * Implement FeedsFetcher::importPeriod().
246
   */
247
  public function importPeriod(FeedsSource $source) {
248
    if ($this->subscriber($source->feed_nid)->subscribed()) {
249
      return 259200; // Delay for three days if there is a successful subscription.
250
    }
251
  }
252

    
253
  /**
254
   * Convenience method for instantiating a subscriber object.
255
   */
256
  protected function subscriber($subscriber_id) {
257
    return PushSubscriber::instance($this->id, $subscriber_id, 'PuSHSubscription', PuSHEnvironment::instance());
258
  }
259
}
260

    
261
/**
262
 * Implement a PuSHSubscriptionInterface.
263
 */
264
class PuSHSubscription implements PuSHSubscriptionInterface {
265
  public $domain;
266
  public $subscriber_id;
267
  public $hub;
268
  public $topic;
269
  public $status;
270
  public $secret;
271
  public $post_fields;
272
  public $timestamp;
273

    
274
  /**
275
   * Load a subscription.
276
   */
277
  public static function load($domain, $subscriber_id) {
278
    if ($v = db_query("SELECT * FROM {feeds_push_subscriptions} WHERE domain = :domain AND subscriber_id = :sid", array(':domain' => $domain, ':sid' => $subscriber_id))->fetchAssoc()) {
279
      $v['post_fields'] = unserialize($v['post_fields']);
280
      return new PuSHSubscription($v['domain'], $v['subscriber_id'], $v['hub'], $v['topic'], $v['secret'], $v['status'], $v['post_fields'], $v['timestamp']);
281
    }
282
  }
283

    
284
  /**
285
   * Create a subscription.
286
   */
287
  public function __construct($domain, $subscriber_id, $hub, $topic, $secret, $status = '', $post_fields = '') {
288
    $this->domain = $domain;
289
    $this->subscriber_id = $subscriber_id;
290
    $this->hub = $hub;
291
    $this->topic = $topic;
292
    $this->status = $status;
293
    $this->secret = $secret;
294
    $this->post_fields = $post_fields;
295
  }
296

    
297
  /**
298
   * Save a subscription.
299
   */
300
  public function save() {
301
    $this->timestamp = time();
302
    $this->delete($this->domain, $this->subscriber_id);
303
    drupal_write_record('feeds_push_subscriptions', $this);
304
  }
305

    
306
  /**
307
   * Delete a subscription.
308
   */
309
  public function delete() {
310
    db_delete('feeds_push_subscriptions')
311
      ->condition('domain', $this->domain)
312
      ->condition('subscriber_id', $this->subscriber_id)
313
      ->execute();
314
  }
315
}
316

    
317
/**
318
 * Provide environmental functions to the PuSHSubscriber library.
319
 */
320
class PuSHEnvironment implements PuSHSubscriberEnvironmentInterface {
321
  /**
322
   * Singleton.
323
   */
324
  public static function instance() {
325
    static $env;
326
    if (empty($env)) {
327
      $env = new PuSHEnvironment();
328
    }
329
    return $env;
330
  }
331

    
332
  /**
333
   * Implements PuSHSubscriberEnvironmentInterface::msg().
334
   */
335
  public function msg($msg, $level = 'status') {
336
    drupal_set_message(check_plain($msg), $level);
337
  }
338

    
339
  /**
340
   * Implements PuSHSubscriberEnvironmentInterface::log().
341
   */
342
  public function log($msg, $level = 'status') {
343
    switch ($level) {
344
      case 'error':
345
        $severity = WATCHDOG_ERROR;
346
        break;
347
      case 'warning':
348
        $severity = WATCHDOG_WARNING;
349
        break;
350
      default:
351
        $severity = WATCHDOG_NOTICE;
352
        break;
353
    }
354
    feeds_dbg($msg);
355
    watchdog('FeedsHTTPFetcher', $msg, array(), $severity);
356
  }
357
}