Zend_Feed_Pubsubhubbub.xml 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!-- EN-Revision: 24249 -->
  3. <!-- Reviewed: no -->
  4. <sect1 id="zend.feed.pubsubhubbub.introduction">
  5. <title>Zend_Feed_Pubsubhubbub</title>
  6. <para>
  7. <classname>Zend_Feed_Pubsubhubbub</classname> ist eine Implementation der PubSubHubbub Core
  8. 0.2 Spezifikation (Working Draft). Sie bietet eine Implementation eines Pubsubhubbub
  9. Publizisten und Abonnenten geeignet für den Zend Framework und andere <acronym>PHP</acronym>
  10. Anwendungen.
  11. </para>
  12. <sect2 id="zend.feed.pubsubhubbub.what.is.pubsubhubbub">
  13. <title>Was ist Pubsubhubbub?</title>
  14. <para>
  15. Pubsubhubbub ist ein offenes, einfaches Web-skalierbares Pubsub Protokoll. Der normale
  16. Anwendungsfall ist es Blogs (Publizist) zu erlauben Aktualisierungen von deren
  17. <acronym>RSS</acronym> oder Atom Feeds (Themen) an Abonnenten zu "senden". Diese
  18. Abonenten müssen dem <acronym>RSS</acronym> oder Atom Feed des Blogs über einen Hub
  19. abonniert haben. Das ist ein zentraler Server der benachrichtigt wird wenn es
  20. Aktualisierungen des Publizisten gibt und diese anschließend an alle Abonnenten
  21. verteilt. Jeder Feed kann bekanntgeben das er ein oder mehrere Hubs unterstützen indem
  22. ein Atom Namespaced Linkelement mit dem Rel Attribut "hub" verwendet wird.
  23. </para>
  24. <para>
  25. Pubsubhubbub hat Aufmerksamkeit erlangt weil es ein Pubsub Protokoll ist das einfach zu
  26. implementieren ist und über <acronym>HTTP</acronym> arbeitet. Seine Philosophie ist es
  27. das traditionelle Modell zu ersetzen indem Blog Feeds mit einem regulären Interfall
  28. abgefragt werden um Aktualisierungen zu erkennen und zu empfangen. Abhängig von der
  29. Frequenz der Abfrage kann es viel Zeit in Anspruch nehmen Aktualisierungen an
  30. interessierte Menschen bei Sammelstellen bis zu Desktop Lesern, bekannt zu machen. Mit
  31. der Verwendung eines Pubsub Systems werden Aktualisierungen nicht einfach von Abonnenten
  32. abgefragt sondern an die Abonnenten geschickt, was jegliche Verzögerung ausschaltet. Aus
  33. diesem Grund fungiert Pubsubhubbub als Teil von dem was als Echt-Zeit Web bekannt ist.
  34. </para>
  35. <para>
  36. Das Protokoll existiert nicht isoliert. PubSub Systems gibt es schon seit einiger Zeit,
  37. wie auch das übliche Jabber Publish-Subscribe Protokoll, <acronym>XEP-0060</acronym>,
  38. oder das nicht so bekannte rssCloud (beschrieben 2001). Trotzdem haben diese keine keine
  39. breite Anwendung gefunden weil Sie entweder komplex sind, ein schlechtes Timing haben,
  40. oder nicht für Web Anwendungen verwendbar sind. Bei rssCloud, welches zuletzt als
  41. Antwort auf das Erscheinen von Pubsubhubbub revidiert wurde, wurde auch eine
  42. signifikante Steigerung gesehen obwohl es an einer formalen Spezifikation fehlt und es
  43. aktuell keine Atom 1.0 Feeds unterstützt.
  44. </para>
  45. <para>
  46. Warscheinlich überraschend weil es noch relativ Jung ist, ist Pubsubhubbub trotzdem
  47. bereits in Verwendung unter anderem bei Google Reader, Feedburner und es sind Plugins
  48. für Wordpress Blogs vorhanden.
  49. </para>
  50. </sect2>
  51. <sect2 id="zend.feed.pubsubhubbub.architecture">
  52. <title>Architektur</title>
  53. <para>
  54. <classname>Zend_Feed_Pubsubhubbub</classname> implementiert zwei Seiten der Pubsubhubbub
  55. 0.2 Spezifikation: einen Publizisten und einen Abonnenten. Es implementiert aktuell
  56. keinen Hub Server. Dieser ist aber in Arbeit für ein zukünftiges Zend Framework Release.
  57. </para>
  58. <para>
  59. Ein Publizist ist verantwortlich für die Mitteilung aller Aktualisierungen seines Feeds
  60. an alle unterstützten Hubs (es können viele unterstützt werden um Redundanz zu einem
  61. System hinzuzufügen), egal ob es sich um Atom oder <acronym>RSS</acronym> basierte
  62. handelt. Das wird getan indem die unterstützten Hub Server mit der
  63. <acronym>URL</acronym> des aktualisierten Feeds gepingt werden. In der Pubsubhubbub
  64. Terminologie wird jede aktualisierbare Ressource welche in der Lage ist abonniert zu
  65. werden als Thema bezeichnet. Sobald ein Ping empfangen wird, frägt der Hub den
  66. aktualisierten Feed ab, bearbeitet die aktualisierten Elemente, und leitet alle
  67. Aktualisierungen an alle Abonnenten weiter die diesen Feed abonniert haben.
  68. </para>
  69. <para>
  70. Ein Abonnent ist jedes Mitglied oder jede Anwendung welche einen oder mehrere Hubs
  71. abonniert um Aktuslisierungen von einem Thema zu empfangen welches von einem Publizisten
  72. gehostet wird. Der Abonnent kommuniziert niemals direkt mit dem Publizisten da der Hub
  73. als Zwischenglied fungiert welches Abos akzeptiert und Aktualisierungen an Abonnenten
  74. sendet. Der Abonnent kommuniziert seinerseits nur mit dem Hub um Themen entweder zu
  75. abonnieren und Abos zu entfernen, oder wenn er Aktualisierungen vom Hub empfängt. Dieses
  76. Design der Kommunikation ("Fat Pings") entfernt effektiverweise die Möglichkeit eines
  77. "Thundering Herd" Problems. Dieses findet in einem Pubsub System statt in dem der Hub
  78. Abonnenten über eine vorhandene Aktualisierung informiert, und alle Abonnenten dazu
  79. auffordert den Feed sofort vom Publizisten zu empfangen, was zu einer Verkehrsspitze
  80. führt. In Pubsubhubbub verteilt der Hub das aktuelle Update in einem "Fat Ping" so dass
  81. der Publizist keine Verkehrsspitze aushalten muss.
  82. </para>
  83. <para>
  84. <classname>Zend_Feed_Pubsubhubbub</classname> implementiert Pubsubhubbub Publizisten und
  85. Abonnenten mit den Klassen <classname>Zend_Feed_Pubsubhubbub_Publisher</classname> und
  86. <classname>Zend_Feed_Pubsubhubbub_Subscriber</classname>. Zusätzlich kann die
  87. Implementation des Abonnenten alle Feed Aktualisierungen behandeln die von einem Hub
  88. weitergeleitet werden indem
  89. <classname>Zend_Feed_Pubsubhubbub_Subscriber_Callback</classname> verwendet wird. Diese
  90. Klassen, deren Verwendungszweck, und die <acronym>API</acronym>s werden in den
  91. weiterführenden Abschnitten behandelt.
  92. </para>
  93. </sect2>
  94. <sect2 id="zend.feed.pubsubhubbub.zend.feed.pubsubhubbub.publisher">
  95. <title>Zend_Feed_Pubsubhubbub_Publisher</title>
  96. <para>
  97. In Pubsubhubbub ist der Publizist der Teilnehmer welcher einen lebenden Feed
  98. veröffentlicht und Ihn regelmäßig mit neuem Inhalt aktualisiert. Das kann ein Blog, eine
  99. Sammlung, oder sogar ein Webservice mit einer öffentlichen Feed basierenden
  100. <acronym>API</acronym> sein. Damit diese Aktualisierungen zu den Abonnenten geschickt
  101. werden können, muss der Publizist alle seine unterstützten Hubs darüber informieren das
  102. eine Aktualisierung stattgefunden hat, indem eine einfache <acronym>HTTP</acronym>
  103. <acronym>POST</acronym> Anfrage verwendet wird, welche die <acronym>URI</acronym> oder
  104. das aktualisierte Thema enthält (z.B. den aktualisierten <acronym>RSS</acronym> oder
  105. Atom Feed). Der Hub bestätigt den Empfang der Benachrichtigung, holt den aktualisierten
  106. Feed, und leitet alle Aktualisierungen an alle Abonnenten weiter welche sich bei diesem
  107. Hub für Aktualisierungen für den relevanten Feed angemeldet haben.
  108. </para>
  109. <para>
  110. Vom Design her bedeutet dies dass der Publizist sehr wenig zu tun hat ausser diese Hub
  111. Pings jedesmal zu senden wenn sich seine Feeds ändern. Als Ergebnis hiervon ist die
  112. Implementation des Publizisten extrem einfach zu verwenden und benötigt sehr wenig
  113. Arbeit für die Einrichtung und Verwendung wenn Feeds aktualisiert werden.
  114. </para>
  115. <para>
  116. <classname>Zend_Feed_Pubsubhubbub_Publisher</classname> implementiert einen kompletten
  117. Pubsubhubbub Publizisten. Sein Setup ist sehr einfach und hauptsächlich müssen bei Ihm
  118. nur die <acronym>URI</acronym> Endpunkte für alle Hubs konfiguriert werden welche bei
  119. Aktualisierungen benachrichtigt werden müssen, und die <acronym>URI</acronym>s aller
  120. Themen die in Benachrichtigungen einzubinden sind.
  121. </para>
  122. <para>
  123. Das folgende Beispiel zeigt einen Publizisten der eine Sammlung von Hubs über
  124. Aktualisierungen zu einem Paar von lokalen <acronym>RSS</acronym> und Atom Feeds
  125. benachrichtigt. Die Klasse enthält eine Anzahl von Fehlern welche die
  126. <acronym>URL</acronym>s des Hubs enthalten, damit Benachrichtigungen stäter wieder
  127. ausgeführt oder protokolliert werden können wenn irgendeine Benachrichtigung
  128. fehlschlägt. Jedes resultierende Fehlerarray enthält auch einen "response" Schlüssel
  129. welche das betreffende <acronym>HTTP</acronym> Antwortobjekt enthält. In Falle
  130. irgendeines Fehlers wird empfohlen die Operation für den fehlgeschlagenen Hub Endpunkt
  131. in Zukunft zumindest noch einmal zu versuchen. Das kann die Verwendung einer geplanten
  132. Aufgabe für diesen Zweck oder einer Job Queue wenn solche extra Schritte optional sind.
  133. </para>
  134. <programlisting language="php"><![CDATA[
  135. $publisher = new Zend_Feed_Pubsubhubbub_Publisher;
  136. $publisher->addHubUrls(array(
  137. 'http://pubsubhubbub.appspot.com/',
  138. 'http://hubbub.example.com',
  139. ));
  140. $publisher->addUpdatedTopicUrls(array(
  141. 'http://www.example.net/rss',
  142. 'http://www.example.net/atom',
  143. ));
  144. $publisher->notifyAll();
  145. if (!$publisher->isSuccess()) {
  146. // Auf Fehler prüfen
  147. $errors = $publisher->getErrors();
  148. $failedHubs = array()
  149. foreach ($errors as $error) {
  150. $failedHubs[] = $error['hubUrl'];
  151. }
  152. }
  153. // Benachrichtigung für fehlgeschlagene Hubs in $failedHubs nochmals planen
  154. ]]></programlisting>
  155. <para>
  156. Wenn man eine konkretere Kontrolle über den Publizisten bevorzugt, gibt es die Methoden
  157. <methodname>addHubUrls()</methodname> und <methodname>addUpdatedTopicUrls()</methodname>
  158. welche jeden Arraywert an die einzelnen öffentlichen Methoden
  159. <methodname>addHubUrl()</methodname> und <methodname>addUpdatedTopicUrl()</methodname>
  160. übergeben. Es gibt auch passende <methodname>removeUpdatedTopicUrl()</methodname> und
  161. <methodname>removeHubUrl()</methodname> Methoden.
  162. </para>
  163. <para>
  164. Man kann das Setzen der Hub <acronym>URI</acronym>s auch überspringen und jeden in Folge
  165. benachrichtigen indem die Methode <methodname>notifyHub()</methodname> verwendet wird
  166. welche die <acronym>URI</acronym> eines Hub Endpunkts als sein einziges Argument
  167. akzeptiert.
  168. </para>
  169. <para>
  170. Es gibt keine anderen Aufgaben die abzudecken sind. Die Implementation des Publizisten
  171. ist sehr einfach da das meiste der Feedbearbeitung und Verteilung von den ausgewählten
  172. Hubs durchgeführt wird. Es ist trotzdem wichtig Fehler zu erkennen und
  173. Benachrichtigungen wieder so früh wie möglich zu planen (mit einer vernünftigen
  174. maximalen Anzahl an Versuchen) um sicherzustellen das Benachrichtigungen alle
  175. Abonnenten erreichen. In vielen Fällen können Hubs, als endgültige Alternative, den
  176. eigenen Feed regelmäßig abfragen um zusätzliche Toleranzen bei Fehlern anzubieten
  177. sowohl wegen deren eigenen temporären Downtime als auch den Fehlern und der Downtime
  178. des Publizisten.
  179. </para>
  180. </sect2>
  181. <sect2 id="zend.feed.pubsubhubbub.zend.feed.pubsubhubbub.subscriber">
  182. <title>Zend_Feed_Pubsubhubbub_Subscriber</title>
  183. <para>
  184. In Pubsubhubbub ist der Abonnent ein Teilnehmer welcher Aktualisierungen zu irgendeinem
  185. Thema (einem <acronym>RSS</acronym> oder Atom Feed) empfangen will. Er kann dass
  186. bewerkstelligen indem er einen oder mehrere Hubs abonniert welche von diesem Thema
  187. beworben werden, normalerweise als ein Set von ein oder mehreren Atom 1.0 Links mit dem
  188. Rel Attribut "hub". Ab diesem Punkt sendet der Hub, wenn er eine Benachrichtigung über
  189. eine Aktualisierung des Publizisten empfängt, einen Atom oder <acronym>RSS</acronym>
  190. Feed, welcher alle Aktualisierungen enthält, zur Callback <acronym>URL</acronym> des
  191. Abonnenten. Über diesen Weg muss der Abonnent niemals den originalen Feed besuchen
  192. (obwohl es trotzdem empfohlen wird um sicherzustellen das Aktualisierungen empfangen
  193. werden wenn ein Hub jemals offline geht). Alle Anfragen für Abos müssen die
  194. <acronym>URI</acronym> des Themas enthalten welches abonniert werden soll, und eine
  195. Callback <acronym>URL</acronym> welche der Hub verwendet um das Abo zu bestätigen und um
  196. Aktualisierungen weiterzuleiten.
  197. </para>
  198. <para>
  199. Der Abonnent hat deswegen zwei Rollen. Abos zu erstellen und zu managen, inklusive der
  200. Abonnierung von neuen Themen mit einem Hub, dem kündigen von Abos (wenn notwendig), und
  201. periodisch Abos zu erneuern da diese eine begrenzte Gültigkeit haben können was durch
  202. den Hub gesetzt wird. Dies wird von
  203. </para>
  204. <para>
  205. Die zweite Rolle ist es Aktualisierungen zu akzeptieren welche vom Hub zur Callback
  206. <acronym>URL</acronym> des Abonnenten gesendet werden, wenn z.B. die
  207. <acronym>URI</acronym> des Abonnenten zugeordnet wurde um Aktualisierungen zu
  208. behandeln. Die Callback <acronym>URL</acronym> behandelt auch Events wenn der Hub den
  209. Abonnenten kontaktiert um alle Abos zu das Löschen von Abos zu bestätigen. Dies wird
  210. behandelt indem eine Instanz von
  211. <classname>Zend_Feed_Pubsubhubbub_Subscriber_Callback</classname> verwendet wird wenn
  212. auf die Callback <acronym>URL</acronym> zugegriffen wird.
  213. </para>
  214. <important>
  215. <para>
  216. <classname>Zend_Feed_Pubsubhubbub_Subscriber</classname> implementiert die
  217. Pubsubhubbub Spezifikation 0.2. Da dies eine Version der Spezifikation ist
  218. implementieren Sie aktuell nicht alle Hubs. Die neue Spezifikation erlaubt der
  219. Callback <acronym>URL</acronym> einen Abfragestring einzubinden welcher von dieser
  220. Klasse verwendet, aber nicht von allen Hubs unterstützt wird. Im Interesse einer
  221. maximalen Kompatibilität wird deshalb empfohlen die Komponente des Abfragestrings
  222. der Callback <acronym>URI</acronym> des Abonnenten als Pfadelement darzustellen,
  223. z.B. als Parameter in der Route erkannt und mit der Callback <acronym>URI</acronym>
  224. assoziiert und vom Router der Anwendung verwendet.
  225. </para>
  226. </important>
  227. <sect3
  228. id="zend.feed.pubsubhubbub.zend.feed.pubsubhubbub.subscriber.subscribing.and.unsubscribing">
  229. <title>Abonnieren und Abos löschen</title>
  230. <para>
  231. <classname>Zend_Feed_Pubsubhubbub_Subscriber</classname> implementiert einen
  232. kompletten Pubsubhubbub Abonnenten der in der Lage ist jedes Thema über jeden Hub
  233. der von diesem Thema vermittelt wird zu abonnieren und Abos zu löschen. Er arbeitet
  234. in Verbindung mit <classname>Zend_Feed_Pubsubhubbub_Subscriber_Callback</classname>
  235. welcher Anfragen von einem Hub akzeptiert um alle Aboanfragen und das Löschen von
  236. Abos zu bestätigen (um Missbrauch durch andere zu verhindern).
  237. </para>
  238. <para>
  239. Jedes Abo (oder Löschen eines Abos) benötigt die betreffende Information bevor
  240. es bearbeitet werden kann, z.B. die <acronym>URI</acronym> des Themas (Atom oder
  241. <acronym>RSS</acronym> Feed) das für Aktualisierungen abonniert werden soll, und die
  242. <acronym>URI</acronym> des Endpunkts für den Hub welcher die Anmeldung auf das Abo
  243. bearbeitet und die Aktualisierungen weiterleitet. Die Lebenszeit eines Abos kann
  244. durch den Hub ermittelt werden, aber die meisten Hubs sollten die automatische
  245. Auffrischung des Abos unterstützen indem der Abonnenten geprüft wird. Das wird von
  246. <classname>Zend_Feed_Pubsubhubbub_Subscriber_Callback</classname> unterstützt und
  247. benötigt keine weitere Arbeit. Es wird trotzdem empfohlen dass man die vom Hub
  248. kommende Lebenszeit des Abos (time to live, ttl) verwendet um die Erstellung neuer
  249. Abos zu planen (der Prozess ist identisch mit dem eines neuen Abos) um es beim Hub
  250. zu aktualisieren. Wärend das per se nicht notwendig ist, deckt es Fälle ab in denen
  251. ein Hub die automatische Aktualisierung des Abos nicht unterstützt und deckt damit
  252. Fehler des Hubs mit zusätzlicher Redundanz ab.
  253. </para>
  254. <para>
  255. Mit der relevanten Information an der Hand kann eine Abonnierung wie anbei gezeigt
  256. versucht werden:
  257. </para>
  258. <programlisting language="php"><![CDATA[
  259. $storage = new Zend_Feed_Pubsubhubbub_Model_Subscription;
  260. $subscriber = new Zend_Feed_Pubsubhubbub_Subscriber;
  261. $subscriber->setStorage($storage);
  262. $subscriber->addHubUrl('http://hubbub.example.com');
  263. $subscriber->setTopicUrl('http://www.example.net/rss.xml');
  264. $subscriber->setCallbackUrl('http://www.mydomain.com/hubbub/callback');
  265. $subscriber->subscribeAll();
  266. ]]></programlisting>
  267. <para>
  268. Um Abos zu speichern und Zugriff auf dessen Daten für eine generelle Verwendung zu
  269. Speichern benötigt die Komponente eine Datenbank (ein Schema wird später in diesem
  270. Abschnitt angeboten). Standardmäßig wird angenommen das der Name der Tabelle
  271. "subscription" ist und im Hintergrund <classname>Zend_Db_Table_Abstract</classname>
  272. anwendet, was bedeutet das der Standardadapter verwendet wird welcher in der
  273. Anwendung gesetzt ist. Man kann auch eine eigene spezielle Instanz von
  274. <classname>Zend_Db_Table_Abstract</classname> in das assoziierte Modell von
  275. <classname>Zend_Feed_Pubsubhubbub_Model_Subscription</classname> übergeben. Dieser
  276. eigene Adapter kann so einfach wie gewünscht sein indem der Name der Tabelle welche
  277. zu verwenden ist geändert wird, oder so komplex wie es notwendig ist.
  278. </para>
  279. <para>
  280. Wärend das Modell als standardmäßige bereits verwendbare Lösung angeboten wird, kann
  281. man sein eigenes Modell verwenden indem irgendein anderes Backend oder
  282. Datenbanklayer (z.B. Doctrine) verwendet wird, solange die resultierende Klasse das
  283. Interface <classname>Zend_Feed_Pubsubhubbub_Model_SubscriptionInterface</classname>
  284. implementiert.
  285. </para>
  286. <para>
  287. Ein Beispielschema (MySQL) für eine Abotabelle auf welche vom angebotenen Modell aus
  288. zugegriffen werden kann, könnte wie folgt aussehen:
  289. </para>
  290. <programlisting language="sql"><![CDATA[
  291. CREATE TABLE IF NOT EXISTS `subscription` (
  292. `id` varchar(32) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
  293. `topic_url` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  294. `hub_url` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  295. `created_time` datetime DEFAULT NULL,
  296. `lease_seconds` bigint(20) DEFAULT NULL,
  297. `verify_token` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  298. `secret` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  299. `expiration_time` datetime DEFAULT NULL,
  300. `subscription_state` varchar(12) COLLATE utf8_unicode_ci DEFAULT NULL,
  301. PRIMARY KEY (`id`)
  302. ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
  303. ]]></programlisting>
  304. <para>
  305. Im Hintergrund sendet der Abonnent eine Anfrage an den Endpunkt des Hubs welche die
  306. folgenden Parameter enthält (basierend auf dem vorhergehenden Beispiel):
  307. </para>
  308. <table
  309. id="zend.feed.pubsubhubbub.zend.feed.pubsubhubbub.subscriber.subscribing.and.unsubscribing.table">
  310. <title>Anfrageparameter beim Abonnieren</title>
  311. <tgroup cols="3">
  312. <thead>
  313. <row>
  314. <entry>Parameter</entry>
  315. <entry>Wert</entry>
  316. <entry>Beschreibung</entry>
  317. </row>
  318. </thead>
  319. <tbody>
  320. <row>
  321. <entry><property>hub.callback</property></entry>
  322. <entry>http://www.mydomain.com/hubbub/callback?xhub.subscription=5536df06b5dcb966edab3a4c4d56213c16a8184</entry>
  323. <entry>
  324. <para>
  325. Die <acronym>URI</acronym> welche von einem Hub verwendet wird
  326. um den Abonnenten zu kontaktieren und entweder eine Bestätigung
  327. für eine Anfrage oder das Löschen eines Abos abzufragen oder
  328. Aktualisierungen für abonnierte Feeds zu senden. Der angehängte
  329. Abfragestring enthält einen eigenen Parameter (demzufolge der
  330. Zweck von xhub). Es ist ein Parameter für einen Abfragestring
  331. welcher vom Hub aufbewahrt um mit allen Anfragen des Abonnenten
  332. wieder versendet wird. Sein Zweck ist es dem Abonnenten zu
  333. erlauben sich zu identifizieren und die Abos zu betrachten
  334. welche mit einer beliebigen Hubanfrage in einem
  335. Backend-Speichermedium assoziiert sind. Das ist kein
  336. Standardparameter welcher von dieser Komponente verwendet wird
  337. statt einen Aboschlüssel im <acronym>URI</acronym> Pfad zu
  338. kodieren, was in einer Zend Framework Anwendung viel
  339. komplizierter zu implementieren wäre.
  340. </para>
  341. <para>
  342. Trotzdem, da nicht alle Hubs Parameter für den Abfragestring
  343. unterstützen wird empfohlen den Aboschlüssel als Pfadkomponente
  344. in der Form von
  345. http://www.mydomain.com/hubbub/callback/5536df06b5dcb966edab3a4c4d56213c16a8184
  346. hinzuzufügen. Um das zu bewerkstelligen, wird die Definition
  347. einer Route benötigt welche in der Lage ist den endgültigen
  348. Wert des Schlüssels herauszuparsen den Wert zu erhalten und Ihn
  349. an das Callback Objekt des Abonnenten zu übergeben. Der Wert
  350. würde an die Methode
  351. <methodname>Zend_Pubsubhubbub_Subscriber_Callback::setSubscriptionKey()</methodname>
  352. übergeben. Ein detailiertes Beispiel wird später gezeigt.
  353. </para>
  354. </entry>
  355. </row>
  356. <row>
  357. <entry><property>hub.lease_seconds</property></entry>
  358. <entry>2592000</entry>
  359. <entry>
  360. <para>
  361. Die Anzahl an Sekunden für welche der Abonnenten will dass
  362. ein neues Abo gültig bleibt (z.B. ein <acronym>TTL</acronym>).
  363. Hubs können Ihre eigene maximale Abodauer erzwingen. Alle Abos
  364. sollten erneuert werden indem einfach erneut abonniert wird
  365. bevor die Abodauer endet um die Kontinuierlichkeit der
  366. Aktualisierungen zu gewährleisten. Hubs sollten zusätzlich
  367. versuchen Abos automatisch zu aktualisieren bevor diese
  368. auslaufen indem die Abonnenten kontaktiert werden (dies wird
  369. automatisch von der Callback Klasse behandelt).
  370. </para>
  371. </entry>
  372. </row>
  373. <row>
  374. <entry><property>hub.mode</property></entry>
  375. <entry>subscribe</entry>
  376. <entry>
  377. <para>
  378. Ein einfacher Wert welche anzeigt das dies eine Aboanfrage ist.
  379. Anfragen für das Löschen von Abos würden den Wert
  380. "unsubscribe" verwenden.
  381. </para>
  382. </entry>
  383. </row>
  384. <row>
  385. <entry><property>hub.topic</property></entry>
  386. <entry>http://www.example.net/rss.xml</entry>
  387. <entry>
  388. <para>
  389. Die <acronym>URI</acronym> des Themas (z.B. Atom oder
  390. <acronym>RSS</acronym> Feed) welche der Abonnent zu abonnieren
  391. wünscht damit er Aktualisierungen bekommt.
  392. </para>
  393. </entry>
  394. </row>
  395. <row>
  396. <entry><property>hub.verify</property></entry>
  397. <entry>sync</entry>
  398. <entry>
  399. <para>
  400. Zeigt dem Hub die bevorzugte Methode der Prüfung von Abos und
  401. dem Löschen von Abos. Sie wird im Normalfall zwei mal
  402. wiederholt. Technisch gesehen unterscheidet diese Komponente
  403. nicht zwischen den zwei Modi und behandelt beide gleich.
  404. </para>
  405. </entry>
  406. </row>
  407. <row>
  408. <entry><property>hub.verify</property></entry>
  409. <entry>async</entry>
  410. <entry>
  411. <para>
  412. Zeigt dem Hub die bevorzugte Methode der Prüfung von Abos und
  413. dem Löschen von Abos. Sie wird im Normalfall zwei mal
  414. wiederholt. Technisch gesehen unterscheidet diese Komponente
  415. nicht zwischen den zwei Modi und behandelt beide gleich.
  416. </para>
  417. </entry>
  418. </row>
  419. <row>
  420. <entry><property>hub.verify_token</property></entry>
  421. <entry>3065919804abcaa7212ae89.879827871253878386</entry>
  422. <entry>
  423. <para>
  424. Ein Prüftoken welcher dem Abonnenten vom Hub zurückgegeben wird
  425. wenn er ein Abos oder das Löschen eines Abos bestätigt. Bietet
  426. ein Maß an Vertrauen dass die Bestätigung der Anfrage vom
  427. aktuellen Hub kommt um Missbrauch zu vermeiden.
  428. </para>
  429. </entry>
  430. </row>
  431. </tbody>
  432. </tgroup>
  433. </table>
  434. <para>
  435. Man kann verschiedene dieser Parameter verändern um eine andere Vorliebe anzuzeigen.
  436. Zum Beispiel kann man eine anderen Wert der Gültigkeit in Sekunden setzen indem man
  437. <methodname>Zend_Pubsubhubbub_Subscriber::setLeaseSeconds()</methodname> verwendet,
  438. oder eine Vorliebe für eine asynchrone Prüfung zeigen indem
  439. <methodname>setPreferredVerificationMode(Zend_Feed_Pubsubhubbub::VERIFICATION_MODE_ASYNC)</methodname>
  440. verwendet wird. Trotzdem bleiben die Hubs in der Lage Ihre eigenen Vorlieben zu
  441. erzwingen, und aus diesem Grund wurde die Komponente so designt dass Sie mit fast
  442. jedem Set an Optionen arbeitet und eine minimale Konfiguration des End-Benutzers
  443. erfordert. Konventionen sind toll wenn Sie funktionieren!
  444. </para>
  445. <note>
  446. <para>
  447. Wärend Hubs die Verwendung eines spezifischen Prüfmodus benötigen können (beide
  448. werden von <classname>Zend_Pubsubhubbub</classname> unterstützt), kann eine
  449. spezifische die zu bevorzugen ist durch Verwendung der Method
  450. <classname>Zend_Pubsubhubbub</classname> angezeigt werden. Im Modus "sync"
  451. (synchron) versucht der Hub eine Aboanfrage sofort zu bestätigen sobald diese
  452. empfangen, und noch bevor auf die Aboanfrage geantwortet wird. Im Modus "async"
  453. (asynchron) gibt der Hub sofort eine Antwort auf die Aboanfrage zurück, und die
  454. Prüfanfrage kann später stattfinden. Da <classname>Zend_Pubsubhubbub</classname>
  455. die Rolle der Aboprüfung als eigene Callback Klasse implementiert, und die
  456. Verwendung eines Backend Speichermediums, unterstützt Sie beide transparent im
  457. Sinne der Geschwindigkeit des Endbenutzers. Die acynchrone Prüfung ist stark zu
  458. bevorzugen um die Nachteile eines schlecht performenden Hubs zu eliminieren,
  459. und die Server Ressourcen des End-Benutzers und die Verbindungen nicht zu lange
  460. zu binden.
  461. </para>
  462. </note>
  463. <para>
  464. Das Löschen eines Abos folgt exakt dem gleichen Pattern wie im vorherigen Beispiel,
  465. mit der Ausnahme das stattdessen <methodname>unsubscribeAll()</methodname>
  466. aufgerufen wird. Die enthaltenen Parameter sind identisch mit einer Aboanfrage mit
  467. der Ausnahme das "<property>hub.mode</property>" auf "unsubscribe" gesetzt wird.
  468. </para>
  469. <para>
  470. Standardmäßig versucht eine neue Instanz von
  471. <classname>Zend_Pubsubhubbub_Subscriber</classname> ein Datenbank Backend
  472. Speichermedium zu verwenden mit Standardwerten um den standardmäßigen
  473. <classname>Zend_Db</classname> Adapter mit dem Tabellennamen "subscription" zu
  474. verwenden. Es wird empfohlen eine eigene Speicherlösung zu setzen welche diese
  475. Standardwerte nicht verwendet, entweder duch übergabe eines neuen Modells welches
  476. das benötigte Interface unterstützt, oder durch Übergabe einer neuen Instanz von
  477. <classname>Zend_Db_Table_Abstract</classname> an dem Constructor des standardmäßigen
  478. Modells um den verwendeten Tabellennamen zu verändern.
  479. </para>
  480. </sect3>
  481. <sect3 id="zend.feed.pubsubhubbub.zend.feed.pubsubhubbub.subscriber.handling.hub.callbacks">
  482. <title>Callbacks von Abonnenten behandeln</title>
  483. <para>
  484. Wann auch immer eine Aboanfrage oder eine Anfrage auf Löschen eines Abos gemacht
  485. wird muss der Hub die Anfrage prüfen indem er eine neue Prüfanfrage an die Callback
  486. <acronym>URL</acronym> weiterleitet welche in den Abo or Abo löschen Parametern
  487. gesetzt ist. Um diese Hub Anfragen zu behandeln, welche alle zukünftigen
  488. Kommunikationen enthalten können wie z.B. Themenaktualisierungen (Feed), sollte die
  489. Callback <acronym>URL</acronym> die Ausführung einer Instanz von
  490. <classname>Zend_Pubsubhubbub_Subscriber_Callback</classname> auslösen um die Anfrage
  491. zu behandeln.
  492. </para>
  493. <para>
  494. Die Callback Klasse sollte konfiguriert werden dass Sie das selbe Speichermedium wie
  495. die Subscriber Klasse verwendet. Ihre Verwendung ist sehr einfach da die meiste
  496. Arbeit intern erledigt wird.
  497. </para>
  498. <programlisting language="php"><![CDATA[
  499. $storage = new Zend_Feed_Pubsubhubbub_Model_Subscription;
  500. $callback = new Zend_Feed_Pubsubhubbub_Subscriber_Callback;
  501. $callback->setStorage($storage);
  502. $callback->handle();
  503. $callback->sendResponse();
  504. /**
  505. * Prüfe ob der resultierende Callback das Ergebnis eines Feed Updates ist.
  506. * Andernfalls war es entweder eine (De-)Abo-Prüfanfrage oder ungültig.
  507. * Typischerweise müssen wir nicht mehr tun als die Behandlung der
  508. * Aktualisierungen vom Feed hinzuzufügen - der Rest wird intern von der
  509. * Klasse behandelt.
  510. */
  511. if ($callback->hasFeedUpdate()) {
  512. $feedString = $callback->getFeedUpdate();
  513. /**
  514. * Die Aktualisierung des Feeds asynchron bearbeiten um ein Timeout
  515. * des Hubs zu vermeiden.
  516. */
  517. }
  518. ]]></programlisting>
  519. <note>
  520. <para>
  521. Es sollte beachtet werden dass
  522. <classname>Zend_Feed_Pubsubhubbub_Subscriber_Callback</classname> jeden
  523. hereinkommenden Anfragestring und andere Parameter unabhängig parsen kann. Dies
  524. ist notwendig da <acronym>PHP</acronym> die Struktur und Schlüssel eines
  525. Abfragestrings ändert wenn diese in die Superglobals <varname>$_GET</varname>
  526. oder <varname>$_POST</varname> geparst wird. Zum Beispiel werden alle doppelten
  527. Schlüssel ignoriert und Punkte werden in Unterstriche konvertiert.
  528. Pubsubhubbub unterstützt beide in den Abfragestring die es erzeugt.
  529. </para>
  530. </note>
  531. <important>
  532. <para>
  533. Es ist wichtig das Entwickler erkennen das Hubs nur mit dem Senden von Anfragen
  534. und dem Empfangen einer Antwort beschäftigt sind welche den Empfang prüft. Wenn
  535. eine Feedaktualisierung empfangen wird sollte Sie niemals nachfolgend bearbeitet
  536. werden da Sie den Hub auf eine Antwort warten lässt. Stattdessen sollte jede
  537. Bearbeitung auf einen anderen Prozess ausgelagert werden oder verzögert bis eine
  538. Antwort zum Hub zurückgesendet wird. Ein Symptom des Fehlers Hubanfragen sofort
  539. zu komplettieren besteht darin das ein Hub weitere Versuche durchführen kann die
  540. Aktualisierungs- oder Prüfanfrage zuzustellen was zu doppelten
  541. Aktualisierungsversuchen führen kann die vom Abonnenten bearbeitet werden. Das
  542. scheint problematisch zu sein -- aber in Wirklichkeit kann ein Hub ein Timeout
  543. von ein paar Sekunden anwenden, und wenn keine Antwort in dieser Zeit empfangen
  544. wird kann er trennen (in der annahme eines Zustellfehlers) und es später nochmal
  545. versuchen. Es ist zu beachten das von Hubs erwartet wird das Wie große Mengen an
  546. Aktualisierungen verteilen und Ihre Ressources deswegen gestreckt sind - bitte
  547. bearbeiten Sie Feeds asynchron (z.B. in einem separaten Prozess oder einer Job
  548. Queue oder sogar in einem geplanten Cron Task) soweit das möglich ist.
  549. </para>
  550. </important>
  551. </sect3>
  552. <sect3
  553. id="zend.feed.pubsubhubbub.zend.feed.pubsubhubbub.subscriber.setting.up.and.using.a.callback.url.route">
  554. <title>Eine Callback URL Route einstellen und verwenden</title>
  555. <para>
  556. Wie vorher erwähnt empfängt die Klasse
  557. <classname>Zend_Feed_Pubsubhubbub_Subscriber_Callback</classname> den kombinierten
  558. Schlüssel welche mit jedem Abo assoziiert ist vom Hub über eine oder zwei Methoden.
  559. Die technisch bevorzugte Methode ist das Hinzufügen dieses Schlüssels zur Callback
  560. <acronym>URL</acronym> welcher für den Hub in allen zukünftigen Anfragen tätig ist
  561. indem ein Stringparameter in der Abfrage mit dem Schlüssel "xhub.subscription"
  562. verwendet wird. Trotzdem, aus historischen Gründen, weil es in Pubsubhubbub 0.1
  563. nicht unterstützt wurde (es wurde kürzlich nur in 0.2 hinzugefügt) ist es stärkstens
  564. empfohlen das kompatibelste zu verwenden und den Schlüssel der Callback
  565. <acronym>URL</acronym> hinzuzugefügen indem er den <acronym>URL</acronym> Pfaden
  566. angehängt wird.
  567. </para>
  568. <para>
  569. Deshalb würde die <acronym>URL</acronym>
  570. http://www.example.com/callback?xhub.subscription=key zu
  571. http://www.example.com/callback/key werden.
  572. </para>
  573. <para>
  574. Da die Abfragestring Methode der Standard in der Vermeidung eines größeren Levels
  575. der zukünftigen Unterstützung der kompletten 0.2 Spezifikation ist, benötigt es
  576. etwas zusätzliche Arbeit um Sie zu implementieren.
  577. </para>
  578. <para>
  579. Der erste Schritt besteht darin der Klasse
  580. <classname>Zend_Feed_Pubsubhubbub_Subscriber_Callback</classname> dem Pfad bewusst
  581. zu machen welcher den Aboschlüssel enthält. Er wird hierfür manuell injiziert, da
  582. man für diesen Zweck auch eine Route manuell definieren muss. Das wird erzielt indem
  583. einfach die Methode
  584. <methodname>Zend_Feed_Pubsubhubbub_Subscriber_Callback::setSubscriptionKey()</methodname>
  585. mit dem Parameter aufgerufen wird welcher der Schlüsselwert ist der vom Router
  586. kommt. Das folgende Beispiel zeigt dies durch Verwendung eines Zend Framework
  587. Controllers.
  588. </para>
  589. <programlisting language="php"><![CDATA[
  590. class CallbackController extends Zend_Controller_Action
  591. {
  592. public function indexAction()
  593. {
  594. $storage = new Zend_Feed_Pubsubhubbub_Model_Subscription;
  595. $callback = new Zend_Feed_Pubsubhubbub_Subscriber_Callback;
  596. $callback->setStorage($storage);
  597. /**
  598. * Injiziert den Aboschlüssel welcher er vom URL Pfad geparst wird
  599. * indem ein Parameter vom Router verwendet wird
  600. */
  601. $subscriptionKey = $this->_getParam('subkey');
  602. $callback->setSubscriptionKey($subscriptionKey);
  603. $callback->handle();
  604. $callback->sendResponse();
  605. /**
  606. * Prüfen ob der Callback als Ergebnis den Empfang eines Feed Updates
  607. * enthält. Anderfalls war es entweder eine De-Aboprüfungsanfrage oder
  608. * eine ungültige Anfrage. Typischerweise muss nichts anderes getan
  609. * werden als das Handling der Feedaktualisierungen hinzuzufügen - der
  610. * Rest wird intern von der Klasse behandelt.
  611. */
  612. if ($callback->hasFeedUpdate()) {
  613. $feedString = $callback->getFeedUpdate();
  614. /**
  615. * Die Aktualisierung des Feeds asynchron behandeln um Hub
  616. * Timeouts zu vermeiden.
  617. */
  618. }
  619. }
  620. }
  621. ]]></programlisting>
  622. <para>
  623. Aktuell kann das Hinzufügen der Route zu einem Parameter welcher den Schlüssel der
  624. an den Pfad angehängt wird mappen würde durchgeführt werden indem eine
  625. Routenkonfiguration wie im kommenden <acronym>INI</acronym> formatierten Beispiel
  626. für die Verwendung mit dem Bootstrapping von <classname>Zend_Application</classname>
  627. verwendet wird.
  628. </para>
  629. <programlisting language="dosini"><![CDATA[
  630. ; Callback Route fürs Hinzufügen einer PuSH Aboschlüssel Abfrage zu aktivieren
  631. resources.router.routes.callback.route = "callback/:subkey"
  632. resources.router.routes.callback.defaults.module = "default"
  633. resources.router.routes.callback.defaults.controller = "callback"
  634. resources.router.routes.callback.defaults.action = "index"
  635. ]]></programlisting>
  636. </sect3>
  637. </sect2>
  638. </sect1>