url = $url; parent::__construct('', $feed_nid); } /** * Implements FeedsImportBatch::getRaw(); */ public function getRaw() { feeds_include_library('http_request.inc', 'http_request'); $result = http_request_get($this->url); if (!in_array($result->code, array(200, 201, 202, 203, 204, 205, 206))) { throw new Exception(t('Download of @url failed with code !code.', array('@url' => $this->url, '!code' => $result->code))); } return $result->data; } } /** * Fetches data via HTTP. */ class FeedsHTTPFetcher extends FeedsFetcher { /** * Implements FeedsFetcher::fetch(). */ public function fetch(FeedsSource $source) { $source_config = $source->getConfigFor($this); if ($this->config['use_pubsubhubbub'] && ($raw = $this->subscriber($source->feed_nid)->receive())) { return new FeedsImportBatch($raw, $source->feed_nid); } return new FeedsHTTPBatch($source_config['source'], $source->feed_nid); } /** * Clear caches. */ public function clear(FeedsSource $source) { $source_config = $source->getConfigFor($this); $url = $source_config['source']; feeds_include_library('http_request.inc', 'http_request'); http_request_clear_cache($url); } /** * Implements FeedsFetcher::request(). */ public function request($feed_nid = 0) { feeds_dbg($_GET); @feeds_dbg(file_get_contents('php://input')); // A subscription verification has been sent, verify. if (isset($_GET['hub_challenge'])) { $this->subscriber($feed_nid)->verifyRequest(); } // No subscription notification has ben sent, we are being notified. else { try { feeds_source($this->id, $feed_nid)->existing()->import(); } catch (Exception $e) { // In case of an error, respond with a 503 Service (temporary) unavailable. header('HTTP/1.1 503 "Not Found"', null, 503); exit(); } } // Will generate the default 200 response. header('HTTP/1.1 200 "OK"', null, 200); exit(); } /** * Override parent::configDefaults(). */ public function configDefaults() { return array( 'auto_detect_feeds' => FALSE, 'use_pubsubhubbub' => FALSE, 'designated_hub' => '', ); } /** * Override parent::configForm(). */ public function configForm(&$form_state) { $form = array(); $form['auto_detect_feeds'] = array( '#type' => 'checkbox', '#title' => t('Auto detect feeds'), '#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.'), '#default_value' => $this->config['auto_detect_feeds'], ); $form['use_pubsubhubbub'] = array( '#type' => 'checkbox', '#title' => t('Use PubSubHubbub'), '#description' => t('Attempt to use a PubSubHubbub subscription if available.'), '#default_value' => $this->config['use_pubsubhubbub'], ); $form['designated_hub'] = array( '#type' => 'textfield', '#title' => t('Designated hub'), '#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.'), '#default_value' => $this->config['designated_hub'], // '#process' => array('ctools_dependent_process'), '#dependency' => array( 'edit-use-pubsubhubbub' => array(1), ), ); return $form; } /** * Expose source form. */ public function sourceForm($source_config) { $form = array(); $form['source'] = array( '#type' => 'textfield', '#title' => t('URL'), '#description' => t('Enter a feed URL.'), '#default_value' => isset($source_config['source']) ? $source_config['source'] : '', '#maxlength' => NULL, '#required' => TRUE, ); return $form; } /** * Override parent::sourceFormValidate(). */ public function sourceFormValidate(&$values) { if ($this->config['auto_detect_feeds']) { feeds_include_library('http_request.inc', 'http_request'); if ($url = http_request_get_common_syndication($values['source'])) { $values['source'] = $url; } } } /** * Override sourceSave() - subscribe to hub. */ public function sourceSave(FeedsSource $source) { if ($this->config['use_pubsubhubbub']) { $this->subscribe($source); } } /** * Override sourceDelete() - unsubscribe from hub. */ public function sourceDelete(FeedsSource $source) { if ($this->config['use_pubsubhubbub']) { $this->unsubscribe($source); } } /** * Implement FeedsFetcher::subscribe() - subscribe to hub. */ public function subscribe(FeedsSource $source) { $source_config = $source->getConfigFor($this); $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'] : ''); } /** * Implement FeedsFetcher::unsubscribe() - unsubscribe from hub. */ public function unsubscribe(FeedsSource $source) { $source_config = $source->getConfigFor($this); $this->subscriber($source->feed_nid)->unsubscribe($source_config['source'], url($this->path($source->feed_nid), array('absolute' => TRUE))); } /** * Implement FeedsFetcher::importPeriod(). */ public function importPeriod(FeedsSource $source) { if ($this->subscriber($source->feed_nid)->subscribed()) { return 259200; // Delay for three days if there is a successful subscription. } } /** * Convenience method for instantiating a subscriber object. */ protected function subscriber($subscriber_id) { return PushSubscriber::instance($this->id, $subscriber_id, 'PuSHSubscription', PuSHEnvironment::instance()); } } /** * Implement a PuSHSubscriptionInterface. */ class PuSHSubscription implements PuSHSubscriptionInterface { public $domain; public $subscriber_id; public $hub; public $topic; public $status; public $secret; public $post_fields; public $timestamp; /** * Load a subscription. */ public static function load($domain, $subscriber_id) { if ($v = db_query("SELECT * FROM {feeds_push_subscriptions} WHERE domain = :domain AND subscriber_id = :sid", array(':domain' => $domain, ':sid' => $subscriber_id))->fetchAssoc()) { $v['post_fields'] = unserialize($v['post_fields']); return new PuSHSubscription($v['domain'], $v['subscriber_id'], $v['hub'], $v['topic'], $v['secret'], $v['status'], $v['post_fields'], $v['timestamp']); } } /** * Create a subscription. */ public function __construct($domain, $subscriber_id, $hub, $topic, $secret, $status = '', $post_fields = '') { $this->domain = $domain; $this->subscriber_id = $subscriber_id; $this->hub = $hub; $this->topic = $topic; $this->status = $status; $this->secret = $secret; $this->post_fields = $post_fields; } /** * Save a subscription. */ public function save() { $this->timestamp = time(); $this->delete($this->domain, $this->subscriber_id); drupal_write_record('feeds_push_subscriptions', $this); } /** * Delete a subscription. */ public function delete() { db_delete('feeds_push_subscriptions') ->condition('domain', $this->domain) ->condition('subscriber_id', $this->subscriber_id) ->execute(); } } /** * Provide environmental functions to the PuSHSubscriber library. */ class PuSHEnvironment implements PuSHSubscriberEnvironmentInterface { /** * Singleton. */ public static function instance() { static $env; if (empty($env)) { $env = new PuSHEnvironment(); } return $env; } /** * Implements PuSHSubscriberEnvironmentInterface::msg(). */ public function msg($msg, $level = 'status') { drupal_set_message($msg, $level); } /** * Implements PuSHSubscriberEnvironmentInterface::log(). */ public function log($msg, $level = 'status') { switch ($level) { case 'error': $severity = WATCHDOG_ERROR; break; case 'warning': $severity = WATCHDOG_WARNING; break; default: $severity = WATCHDOG_NOTICE; break; } feeds_dbg($msg); watchdog('FeedsHTTPFetcher', $msg, array(), $severity); } }