|
|
@@ -0,0 +1,318 @@
|
|
|
+<?xml version="1.0" encoding="UTF-8"?>
|
|
|
+<!-- Reviewed: no -->
|
|
|
+<sect1 id="zend.feed.pubsubhubbub.pubsubhubbub.subscriber">
|
|
|
+ <title>Pubsubhubbub Subscriber</title>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ In Pubsubhubbub, the Subscriber is the party who wishes to receive updates to any Topic (RSS
|
|
|
+ or Atom feed). They achieve this by subscribing to one or more of the Hubs advertised by
|
|
|
+ that Topic, usually as a set of one or more atom links with a rel attribute of "hub". The
|
|
|
+ Hub from that point forward will send an Atom or RSS feed containing all updates to that
|
|
|
+ Subscriber's Callback URL when it receives an update notification from the Publisher. In
|
|
|
+ this way, the Subscriber need never actually visit the original feed (though it's still
|
|
|
+ recommended at some level to ensure updates are retrieved if ever a Hub goes offline). All
|
|
|
+ subscription requests must contain the URI of the Topic being subscribed and a Callback URL
|
|
|
+ which that the Hub will use to confirm the subscription and to forward updates.
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ The Subsciber therefore has two roles. To create and manage subscriptions, including
|
|
|
+ subscribing for new Topics with a Hub, unsubscribing (if necessary), and periodically
|
|
|
+ renewing subscriptions since they have a limited validity as set by the Hub. This is handled
|
|
|
+ by <classname>Zend_Feed_Pubsubhubbub_Subscriber</classname>.
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ The second role, is to accept updates sent by a Hub to the Subscriber's Callback URL, i.e.
|
|
|
+ the URI the Subscriber has assigned to handle updates. The Callback URL also handles events
|
|
|
+ where the Hub contacts the Subscriber to confirm all subscriptions and unsubscriptions.
|
|
|
+ This is handled by using an instance of
|
|
|
+ <classname>Zend_Feed_Pubsubhubbub_Subscriber_Callback</classname> when the Callback URL is
|
|
|
+ accessed.
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <important>
|
|
|
+ <para>
|
|
|
+ <classname>Zend_Feed_Pubsubhubbub_Subscriber</classname> implements the Pubsubhubbub 0.2
|
|
|
+ Specification. As this is a new specification version not all Hubs currently implement
|
|
|
+ it. The new specification allows the Callback URL to include a query string which is
|
|
|
+ used by this class, but not supported by all Hubs. Unfortunately, the previous
|
|
|
+ specification was difficult to use within an application using Routing, i.e. many
|
|
|
+ application frameworks, so this component does NOT support 0.1 Hubs.
|
|
|
+ </para>
|
|
|
+ </important>
|
|
|
+
|
|
|
+ <sect2 id="zend.feed.pubsubhubbub.pubsubhubbub.subscriber.subscribing.and.unsubscribing">
|
|
|
+ <title>Subscribing and Unsubscribing</title>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ <classname>Zend_Feed_Pubsubhubbub_Subscriber</classname> implements a full Pubsubhubbub
|
|
|
+ Subscriber capable of subscribing to, or unsubscribing from, any Topic via any Hub
|
|
|
+ advertised by that Topic. It operates in conjunction with
|
|
|
+ <classname>Zend_Feed_Pubsubhubbub_Subscriber_Callback</classname> which accepts requests
|
|
|
+ from a Hub to confirm all subscription or unsubscription attempts (to prevent
|
|
|
+ third-party misuse).
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ Any subscription (or unsubscription) requires the relevant information before
|
|
|
+ proceeding, i.e. the URI of the Topic (Atom or RSS feed) to be subscribed to for
|
|
|
+ updates, and the URI of the endpoint for the Hub which will handle the subscription and
|
|
|
+ forwarding of the updates. It should also be noted that subscriptions have a default
|
|
|
+ life of 30 days, changeable by the Hub, meaning that subscriptions must be renewed
|
|
|
+ periodically before they expire - simply attempt to re-subsribe before the expiry date
|
|
|
+ of the original subscription. This component does not handle automated subscription
|
|
|
+ renewals.
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ With the relevant information to hand, a subscription can be attempted:
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <programlisting lang="php"><![CDATA[
|
|
|
+$storage = new Zend_Feed_Pubsubhubbub_Storage_Filesystem;
|
|
|
+$storage->setDirectory('../tmp');
|
|
|
+
|
|
|
+$subscriber = new Zend_Feed_Pubsubhubbub_Subscriber;
|
|
|
+$subscriber->setStorage($storage);
|
|
|
+$subscriber->addHubUrl('http://hubbub.example.com');
|
|
|
+$subscriber->setTopicUrl('http://www.example.net/rss.xml');
|
|
|
+$subscriber->setCallbackUrl('http://www.mydomain.com/hubbub/callback');
|
|
|
+$subscriber->subscribeAll();
|
|
|
+]]></programlisting>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ Behind the scenes, the Subscriber will send a request to the Hub endpoint containing the
|
|
|
+ following parameters (based on the previous example):
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <table id="zend.feed.pubsubhubbub.pubsubhubbub.subscriber.subscribing.and.unsubscribing.table">
|
|
|
+ <title>Subscription request parameters</title>
|
|
|
+
|
|
|
+ <tgroup cols="3">
|
|
|
+ <thead>
|
|
|
+ <row>
|
|
|
+ <entry>Parameter</entry>
|
|
|
+
|
|
|
+ <entry>Value</entry>
|
|
|
+
|
|
|
+ <entry>Explanation</entry>
|
|
|
+ </row>
|
|
|
+ </thead>
|
|
|
+
|
|
|
+ <tbody>
|
|
|
+ <row>
|
|
|
+ <entry>hub.callback</entry>
|
|
|
+
|
|
|
+ <entry>http://www.mydomain.com/hubbub/callback?xhub.subscription=5536df06b5dcb966edab3a4c4d56213c16a8184</entry>
|
|
|
+
|
|
|
+ <entry>
|
|
|
+ <para>
|
|
|
+ The URI used by a Hub to contact the Subscriber and either request
|
|
|
+ confirmation of a (un)subscription request or send updates from
|
|
|
+ subscribed feeds. The appended query string contains a custom
|
|
|
+ parameter (hence the xhub designation). It is a query string
|
|
|
+ parameter preserved by the Hub and resent with all Subscriber
|
|
|
+ requests. Its purpose is to allow the Subscriber to identify and
|
|
|
+ look up the subscription associated with any Hub request in a
|
|
|
+ backend storage medium. This is a non-standard parameter used by
|
|
|
+ this component in preference to encoding a subscription key in the
|
|
|
+ URI path which is more difficult to implement in a Zend Framework
|
|
|
+ application.
|
|
|
+ </para>
|
|
|
+ </entry>
|
|
|
+ </row>
|
|
|
+
|
|
|
+ <row>
|
|
|
+ <entry>hub.lease_seconds</entry>
|
|
|
+
|
|
|
+ <entry>2592000</entry>
|
|
|
+
|
|
|
+ <entry>
|
|
|
+ <para>
|
|
|
+ The number of seconds for which the Subscriber would like a new
|
|
|
+ subscription to remain valid for. Hubs may enforce their own maximum
|
|
|
+ subscription period. All subscriptions must be renewed by simply
|
|
|
+ re-subscribing before the subscription period ends to ensure
|
|
|
+ continuity of updates.
|
|
|
+ </para>
|
|
|
+ </entry>
|
|
|
+ </row>
|
|
|
+
|
|
|
+ <row>
|
|
|
+ <entry>hub.mode</entry>
|
|
|
+
|
|
|
+ <entry>subscribe</entry>
|
|
|
+
|
|
|
+ <entry>
|
|
|
+ <para>
|
|
|
+ Simple value indicating this is a subscription request.
|
|
|
+ Unsubscription requests would use the "unsubscribe" value.
|
|
|
+ </para>
|
|
|
+ </entry>
|
|
|
+ </row>
|
|
|
+
|
|
|
+ <row>
|
|
|
+ <entry>hub.topic</entry>
|
|
|
+
|
|
|
+ <entry>http://www.example.net/rss.xml</entry>
|
|
|
+
|
|
|
+ <entry>
|
|
|
+ <para>
|
|
|
+ The URI of the topic (i.e. Atom or RSS feed) which the Subscriber
|
|
|
+ wishes to subscribe to for updates.
|
|
|
+ </para>
|
|
|
+ </entry>
|
|
|
+ </row>
|
|
|
+
|
|
|
+ <row>
|
|
|
+ <entry>hub.verify</entry>
|
|
|
+
|
|
|
+ <entry>sync</entry>
|
|
|
+
|
|
|
+ <entry>
|
|
|
+ <para>
|
|
|
+ Indicates to the Hub the preferred mode of verifying subscriptions
|
|
|
+ or unsubscriptions. It is repeated twice in order of preference.
|
|
|
+ </para>
|
|
|
+ </entry>
|
|
|
+ </row>
|
|
|
+
|
|
|
+ <row>
|
|
|
+ <entry>hub.verify</entry>
|
|
|
+
|
|
|
+ <entry>async</entry>
|
|
|
+
|
|
|
+ <entry>
|
|
|
+ <para>
|
|
|
+ Indicates to the Hub the preferred mode of verifying subscriptions
|
|
|
+ or unsubscriptions. It is repeated twice in order of preference.
|
|
|
+ </para>
|
|
|
+ </entry>
|
|
|
+ </row>
|
|
|
+
|
|
|
+ <row>
|
|
|
+ <entry>hub.verify_token</entry>
|
|
|
+
|
|
|
+ <entry>3065919804abcaa7212ae89.879827871253878386</entry>
|
|
|
+
|
|
|
+ <entry>
|
|
|
+ <para>
|
|
|
+ A verification token returned to the Subscriber by the Hub when it
|
|
|
+ is confirming a subscription or unsubscription. Offers a measure of
|
|
|
+ reliance that the confirmation request originates from the correct
|
|
|
+ Hub to prevent misuse.
|
|
|
+ </para>
|
|
|
+ </entry>
|
|
|
+ </row>
|
|
|
+ </tbody>
|
|
|
+ </tgroup>
|
|
|
+ </table>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ You can modify several of these parameters to indicate a different preference. For
|
|
|
+ example, you can set a different lease seconds value using
|
|
|
+ <methodname>Zend_Pubsubhubbub_Subscriber::setLeaseSeconds()</methodname> or show a
|
|
|
+ preference for the async verify mode by using <code>
|
|
|
+ setPreferredVerificationMode(Zend_Feed_Pubsubhubbub::VERIFICATION_MODE_ASYNC)</code>.
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <note>
|
|
|
+ <para>
|
|
|
+ While Hubs may require the use of a specific verification mode (both are supported
|
|
|
+ by <classname>Zend_Pubsubhubbub</classname>), you may indicate a specific preference
|
|
|
+ using the <methodname>setPreferredVerificationMode()</methodname> method. In "sync"
|
|
|
+ (synchronous) mode, the Hub attempts to confirm a subscription as soon as it is
|
|
|
+ received, and before responding to the subscription request. In "async"
|
|
|
+ (asynchronous) mode, the Hub will return a response to the subscription request
|
|
|
+ immediately, and its verification request may occur at a later time. Since
|
|
|
+ <classname>Zend_Pubsubhubbub</classname> implements the Subscriber verification role
|
|
|
+ as a separate callback class and requires the use of a backend storage medium, it
|
|
|
+ actually supports both transparently.
|
|
|
+ </para>
|
|
|
+ </note>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ Unsubscribing from a Topic follows the exact same pattern as the previous example, with
|
|
|
+ the exception that we should call <methodname>unsubscribeAll()</methodname> instead. The
|
|
|
+ parameters included are identical to a subscription request with the exception that
|
|
|
+ "hub.mode" is set to "unsubscribe".
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ By default, a new instance of <classname>Zend_Pubsubhubbub_Subscriber</classname> will
|
|
|
+ attempt to use a file backed storage medium which defaults to the location of your
|
|
|
+ system's temporary directory. It is recommended to set a custom storage solution where
|
|
|
+ possible. At present the available storage solutions include
|
|
|
+ <classname>Zend_Pubsubhubbub_Storage_Filesystem</classname> and
|
|
|
+ <classname>Zend_Pubsubhubbub_Storage_Memory</classname>. You may set a storage object
|
|
|
+ using <methodname>setStorage()</methodname>. All storage objects must implement the
|
|
|
+ interface <classname>Zend_Feed_Pubsubhubbub_StorageInterface</classname>.
|
|
|
+ <emphasis>TODO</emphasis>
|
|
|
+ </para>
|
|
|
+ </sect2>
|
|
|
+
|
|
|
+ <sect2 id="zend.feed.pubsubhubbub.pubsubhubbub.subscriber.handling.hub.callbacks">
|
|
|
+ <title>Handling Subscriber Callbacks</title>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ Whenever a subscription or unsubscription request is made, the Hub must verify the
|
|
|
+ request by forwarding a new verification request to the Callback URL set in the
|
|
|
+ subscription/unsubscription parameters. To handle these Hub requests, which will include
|
|
|
+ all future communications contain Topic updates, the Callback URL should trigger the
|
|
|
+ execution of an instance of <classname>Zend_Pubsubhubbub_Subscriber_Callback</classname>
|
|
|
+ to handle the request.
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ The Callback class should be configured to use the same storage medium as the Subscriber
|
|
|
+ class. Using it is quite simple since most of its work is performed internally.
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <programlisting lang="php"><![CDATA[
|
|
|
+$storage = new Zend_Feed_Pubsubhubbub_Storage_Filesystem;
|
|
|
+$storage->setDirectory('../tmp');
|
|
|
+
|
|
|
+$callback = new Zend_Feed_Pubsubhubbub_Subscriber_Callback;
|
|
|
+$callback->setStorage($storage);
|
|
|
+$callback->handle();
|
|
|
+$callback->sendResponse();
|
|
|
+
|
|
|
+/**
|
|
|
+ * Check if the callback resulting in the receipt of a feed update.
|
|
|
+ * Otherwise it was either a (un)sub verification request or invalid request.
|
|
|
+ */
|
|
|
+if ($callback->hasFeedUpdate()) {
|
|
|
+ $feedString = $callback->getFeedUpdate();
|
|
|
+ /**
|
|
|
+ * Process the feed update asynchronously to avoid a Hub timeout
|
|
|
+ */
|
|
|
+}
|
|
|
+]]></programlisting>
|
|
|
+
|
|
|
+ <note>
|
|
|
+ <para>
|
|
|
+ It should be noted that
|
|
|
+ <classname>Zend_Feed_Pubsubhubbub_Subscriber_Callback</classname> independently
|
|
|
+ parses any incoming query string and other parameters. This is necessary since PHP
|
|
|
+ alters the structure and keys of a query string when it is parsed into the
|
|
|
+ <varname>$_GET</varname> or <varname>$_POST</varname> superglobals. For example,
|
|
|
+ all duplicate keys are ignored and periods are converted to underscores.
|
|
|
+ Pubsubhubbub features both of these in the query strings it generates.
|
|
|
+ </para>
|
|
|
+ </note>
|
|
|
+
|
|
|
+ <important>
|
|
|
+ <para>
|
|
|
+ It is essential that developers recognise that Hubs are only concerned with sending
|
|
|
+ requests and receiving a response which verifies its receipt. If a feed update is
|
|
|
+ received, it should never be processed on the spot since this leaves the Hub waiting
|
|
|
+ for a response. Rather, any processing should be offloaded to another process or
|
|
|
+ deferred until after a response has been returned to the Hub. One symptom of a
|
|
|
+ failure to promptly complete Hub requests is that Hub may continue to attempt
|
|
|
+ delivery of the update/verification request leading to duplicated update attempts
|
|
|
+ being processed by the Subscriber.
|
|
|
+ </para>
|
|
|
+ </important>
|
|
|
+ </sect2>
|
|
|
+</sect1>
|