TigerZF
🌐Español

33.11. Zend_Feed_Pubsubhubbub

Zend_Feed_Pubsubhubbub es una implementación de la Especificación Core 0.2 de PubSubHubbub (Working Draft). Ofrece implementaciones de un Publicador y un Suscriptor Pubsubhubbub adecuadas para Zend Framework y otras aplicaciones PHP.

33.11.1. ¿Qué es Pubsubhubbub?

Pubsubhubbub es un protocolo pubsub abierto, simple y de escala web. Un caso de uso habitual es permitir que los blogs (Publicadores) "empujen" actualizaciones desde sus fuentes RSS o Atom (Temas) hacia los Suscriptores finales. Estos Suscriptores se habrán suscrito a la fuente RSS o Atom del blog a través de un Hub, un servidor central al que el Publicador notifica cualquier actualización y que luego distribuye estas actualizaciones a todos los Suscriptores. Cualquier fuente puede anunciar que soporta uno o más Hubs mediante un elemento link con espacio de nombres Atom y un atributo rel de "hub".

Pubsubhubbub ha atraído atención porque es un protocolo pubsub fácil de implementar y que opera sobre HTTP. Su filosofía consiste en reemplazar el modelo tradicional en el que las fuentes de los blogs se sondeaban (polling) a intervalos regulares para detectar y recuperar actualizaciones. Dependiendo de la frecuencia del sondeo, esto puede tardar mucho tiempo en propagar las actualizaciones a las partes interesadas, desde agregadores planetarios hasta lectores de escritorio. Con un sistema pubsub implementado, las actualizaciones no son simplemente sondeadas por los Suscriptores, sino que se les empujan (push), eliminando cualquier retraso. Por esta razón, Pubsubhubbub forma parte de lo que se ha denominado la web en tiempo real.

El protocolo no existe de forma aislada. Los sistemas pubsub llevan ya un tiempo existiendo, como el conocido protocolo Jabber Publish-Subscribe, XEP-0060, o el menos conocido rssCloud (descrito en 2001). Sin embargo, estos no han logrado una adopción generalizada, típicamente debido a su complejidad, a un momento de aparición inoportuno o a su falta de idoneidad para aplicaciones web. rssCloud, que fue recientemente revivido como respuesta a la aparición de Pubsubhubbub, también ha visto aumentar su uso de forma significativa, aunque carece de una especificación formal y actualmente no soporta fuentes Atom 1.0.

Quizás sorprendentemente dada su corta edad relativa, Pubsubhubbub ya está en uso, incluyendo Google Reader, Feedburner, y existen plugins disponibles para blogs de Wordpress.

33.11.2. Arquitectura

Zend_Feed_Pubsubhubbub implementa dos lados de la Especificación 0.2 de Pubsubhubbub: un Publicador y un Suscriptor. Actualmente no implementa un Servidor Hub, aunque esto está en desarrollo para una futura versión de Zend Framework.

Un Publicador es responsable de notificar a todos los Hubs soportados (se pueden soportar varios para añadir redundancia al sistema) sobre cualquier actualización de sus fuentes, ya sean basadas en Atom o RSS. Esto se logra haciendo ping a los Servidores Hub soportados con la URL de la fuente actualizada. En la terminología de Pubsubhubbub, cualquier recurso actualizable que pueda ser suscrito se denomina Tema (Topic). Una vez recibido un ping, el Hub solicitará la fuente actualizada, la procesará en busca de elementos actualizados y reenviará todas las actualizaciones a todos los Suscriptores suscritos a esa fuente.

Un Suscriptor es cualquier parte o aplicación que se suscribe a uno o más Hubs para recibir actualizaciones de un Tema alojado por un Publicador. El Suscriptor nunca se comunica directamente con el Publicador, ya que el Hub actúa como intermediario, aceptando suscripciones y enviando actualizaciones a los Suscriptores suscritos. Por lo tanto, el Suscriptor se comunica únicamente con el Hub, ya sea para suscribirse o cancelar la suscripción a Temas, o cuando recibe actualizaciones del Hub. Este diseño de comunicación ("Fat Pings") elimina eficazmente la posibilidad de un problema de "Estampida" (Thundering Herd). Esto ocurre en un sistema pubsub en el que el Hub simplemente informa a los Suscriptores de que hay una actualización disponible, lo que hace que todos los Suscriptores recuperen inmediatamente la fuente del Publicador, dando lugar a un pico de tráfico. En Pubsubhubbub, el Hub distribuye la actualización real en un "Fat Ping", de modo que el Publicador no queda sometido a ningún pico de tráfico.

Zend_Feed_Pubsubhubbub implementa Publicadores y Suscriptores de Pubsubhubbub con las clases Zend_Feed_Pubsubhubbub_Publisher y Zend_Feed_Pubsubhubbub_Subscriber. Además, la implementación del Suscriptor puede gestionar cualquier actualización de fuente reenviada desde un Hub usando Zend_Feed_Pubsubhubbub_Subscriber_Callback. Estas clases, sus casos de uso y sus APIs se tratan en las siguientes secciones.

33.11.3. Zend_Feed_Pubsubhubbub_Publisher

En Pubsubhubbub, el Publicador es la parte que publica una fuente en vivo y la actualiza con frecuencia con contenido nuevo. Esto puede ser un blog, un agregador, o incluso un servicio web con una API pública basada en fuentes. Para que estas actualizaciones se empujen a los Suscriptores, el Publicador debe notificar a todos sus Hubs soportados de que se ha producido una actualización mediante una simple solicitud HTTP POST que contenga la URI del Tema actualizado (es decir, la fuente RSS o Atom actualizada). El Hub confirmará la recepción de la notificación, obtendrá la fuente actualizada y reenviará cualquier actualización a los Suscriptores que se hayan suscrito a ese Hub para recibir actualizaciones de la fuente correspondiente.

Por diseño, esto significa que el Publicador tiene muy poco que hacer, salvo enviar estos pings al Hub cada vez que sus fuentes cambian. Como resultado, la implementación del Publicador es extremadamente sencilla de usar y requiere muy poco trabajo de configuración y uso cuando se actualizan las fuentes.

Zend_Feed_Pubsubhubbub_Publisher implementa un Publicador Pubsubhubbub completo. Su configuración para su uso también es sencilla, requiriendo principalmente que se configure con el punto final URI de todos los Hubs a los que se debe notificar sobre actualizaciones, y las URIs de todos los Temas a incluir en las notificaciones.

El siguiente ejemplo muestra un Publicador notificando a un conjunto de Hubs sobre actualizaciones de un par de fuentes RSS y Atom locales. La clase mantiene una colección de errores que incluyen las URLs de los Hubs, de modo que la notificación pueda reintentarse más tarde y/o registrarse si alguna notificación llegara a fallar. Cada array de error resultante también incluye una clave "response" que contiene el objeto de respuesta HTTP correspondiente. En caso de errores, se recomienda encarecidamente intentar la operación de nuevo al menos una vez más en el futuro para los Puntos Finales de Hub que hayan fallado. Esto puede requerir el uso de una tarea programada para este propósito o de una cola de trabajos, aunque estos pasos adicionales son opcionales.

$publisher = new Zend_Feed_Pubsubhubbub_Publisher;
$publisher->addHubUrls(array(
    'http://pubsubhubbub.appspot.com/',
    'http://hubbub.example.com',
));
$publisher->addUpdatedTopicUrls(array(
    'http://www.example.net/rss',
    'http://www.example.net/atom',
));
$publisher->notifyAll();

if (!$publisher->isSuccess()) {
    // check for errors
    $errors     = $publisher->getErrors();
    $failedHubs = array()
    foreach ($errors as $error) {
        $failedHubs[] = $error['hubUrl'];
    }
}

// reschedule notifications for the failed Hubs in $failedHubs

Si prefiere tener un control más concreto sobre el Publicador, los métodos addHubUrls() y addUpdatedTopicUrls() pasan cada valor del array a los métodos públicos singulares addHubUrl() y addUpdatedTopicUrl(). También existen los métodos correspondientes removeUpdatedTopicUrl() y removeHubUrl().

También puede omitir la configuración de URIs de Hub y notificar a cada uno por turno usando el método notifyHub(), que acepta la URI de un punto final de Hub como único argumento.

No hay otras tareas que cubrir. La implementación del Publicador es muy sencilla, ya que la mayor parte del procesamiento y distribución de la fuente lo gestionan los Hubs seleccionados. Sin embargo, es importante detectar errores y reprogramar las notificaciones lo antes posible (con un número máximo razonable de reintentos) para garantizar que las notificaciones lleguen a todos los Suscriptores. En muchos casos, como alternativa final, los Hubs pueden sondear con frecuencia sus fuentes para ofrecer cierta tolerancia adicional a fallos, tanto en términos de su propia caída temporal como de errores o caídas del Publicador.

33.11.4. Zend_Feed_Pubsubhubbub_Subscriber

En Pubsubhubbub, el Suscriptor es la parte que desea recibir actualizaciones de cualquier Tema (fuente RSS o Atom). Lo consigue suscribiéndose a uno o más de los Hubs anunciados por ese Tema, generalmente como un conjunto de uno o más enlaces Atom 1.0 con un atributo rel de "hub". A partir de ese momento, el Hub enviará una fuente Atom o RSS que contenga todas las actualizaciones a la URL de Callback del Suscriptor cuando reciba una notificación de actualización del Publicador. De este modo, el Suscriptor nunca necesita visitar realmente la fuente original (aunque sigue recomendándose hacerlo en cierta medida para garantizar que las actualizaciones se recuperen si alguna vez un Hub queda fuera de línea). Todas las solicitudes de suscripción deben contener la URI del Tema al que se suscriben y una URL de Callback que el Hub usará para confirmar la suscripción y reenviar las actualizaciones.

El Suscriptor tiene, por lo tanto, dos funciones. Crear y gestionar suscripciones, incluyendo la suscripción a nuevos Temas con un Hub, la cancelación de suscripciones (si es necesario) y la renovación periódica de las suscripciones, ya que pueden tener una validez limitada establecida por el Hub. Esto lo gestiona Zend_Feed_Pubsubhubbub_Subscriber.

La segunda función es aceptar las actualizaciones enviadas por un Hub a la URL de Callback del Suscriptor, es decir, la URI que el Suscriptor ha asignado para gestionar las actualizaciones. La URL de Callback también gestiona los eventos en los que el Hub contacta con el Suscriptor para confirmar todas las suscripciones y cancelaciones de suscripción. Esto lo gestiona el uso de una instancia de Zend_Feed_Pubsubhubbub_Subscriber_Callback cuando se accede a la URL de Callback.

[Important] Importante

Zend_Feed_Pubsubhubbub_Subscriber implementa la Especificación 0.2 de Pubsubhubbub. Al tratarse de una versión de especificación nueva, no todos los Hubs la implementan actualmente. La nueva especificación permite que la URL de Callback incluya una cadena de consulta usada por esta clase, pero no soportada por todos los Hubs. En aras de maximizar la compatibilidad, se recomienda por tanto que el componente de cadena de consulta de la URI de Callback del Suscriptor se presente como un elemento de ruta, es decir, reconocido como un parámetro en la ruta asociada con la URI de Callback y utilizado por el Router de la aplicación.

33.11.4.1. Suscribirse y cancelar la suscripción

Zend_Feed_Pubsubhubbub_Subscriber implementa un Suscriptor Pubsubhubbub completo, capaz de suscribirse a, o cancelar la suscripción de, cualquier Tema a través de cualquier Hub anunciado por ese Tema. Funciona en conjunto con Zend_Feed_Pubsubhubbub_Subscriber_Callback, que acepta solicitudes de un Hub para confirmar todos los intentos de suscripción o cancelación de suscripción (para evitar el uso indebido por terceros).

Cualquier suscripción (o cancelación de suscripción) requiere la información pertinente antes de continuar, es decir, la URI del Tema (fuente Atom o RSS) al que se va a suscribir para recibir actualizaciones, y la URI del punto final del Hub que gestionará la suscripción y el reenvío de las actualizaciones. El tiempo de vida de una suscripción puede ser determinado por el Hub, pero la mayoría de los Hubs deberían soportar renovaciones automáticas de suscripción comprobando con el Suscriptor. Esto lo soporta Zend_Feed_Pubsubhubbub_Subscriber_Callback y no requiere ningún trabajo adicional por su parte. Aun así, se recomienda encarecidamente usar el tiempo de vida (ttl) de la suscripción proporcionado por el Hub para programar la creación de nuevas suscripciones (el proceso es idéntico al de cualquier nueva suscripción) para renovarla con el Hub. Aunque no debería ser estrictamente necesario, cubre los casos en los que un Hub pueda no soportar la renovación automática de suscripciones y descarta errores del Hub para obtener redundancia adicional.

Con la información pertinente a mano, se puede intentar una suscripción como se muestra a continuación:

$storage = new Zend_Feed_Pubsubhubbub_Model_Subscription;

$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();

Para almacenar las suscripciones y ofrecer acceso a estos datos para uso general, el componente requiere una base de datos (más adelante en esta sección se ofrece un esquema). Por defecto, se asume que el nombre de la tabla es "subscription" y utiliza Zend_Db_Table_Abstract internamente, lo que significa que usará el adaptador predeterminado que haya configurado para su aplicación. También puede pasar una instancia personalizada específica de Zend_Db_Table_Abstract al modelo asociado Zend_Feed_Pubsubhubbub_Model_Subscription. Este adaptador personalizado puede ser tan simple en su intención como cambiar el nombre de la tabla a usar, o tan complejo como usted considere necesario.

Aunque este Modelo se ofrece como una solución lista para usar por defecto, puede crear su propio Modelo usando cualquier otra capa de backend o de base de datos (por ejemplo, Doctrine), siempre que la clase resultante implemente la interfaz Zend_Feed_Pubsubhubbub_Model_SubscriptionInterface.

Un ejemplo de esquema (MySQL) para una tabla de suscripción accesible por el modelo proporcionado puede ser similar a:

CREATE TABLE IF NOT EXISTS `subscription` (
  `id` varchar(32) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
  `topic_url` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `hub_url` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `created_time` datetime DEFAULT NULL,
  `lease_seconds` bigint(20) DEFAULT NULL,
  `verify_token` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `secret` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `expiration_time` datetime DEFAULT NULL,
  `subscription_state` varchar(12) COLLATE utf8_unicode_ci DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

Entre bastidores, el Suscriptor anterior enviará una solicitud al punto final del Hub que contendrá los siguientes parámetros (basado en el ejemplo anterior):

Tabla 33.9. Parámetros de la solicitud de suscripción

Parámetro Valor Explicación
hub.callback http://www.mydomain.com/hubbub/callback?xhub.subscription=5536df06b5dcb966edab3a4c4d56213c16a8184

La URI que un Hub usa para contactar con el Suscriptor y solicitar confirmación de una solicitud de (des)suscripción, o enviar actualizaciones de las fuentes suscritas. La cadena de consulta añadida contiene un parámetro personalizado (de ahí la denominación xhub). Es un parámetro de cadena de consulta preservado por el Hub y reenviado con todas las solicitudes del Suscriptor. Su propósito es permitir al Suscriptor identificar y buscar la suscripción asociada a cualquier solicitud del Hub en un medio de almacenamiento de backend. Este es un parámetro no estándar usado por este componente en lugar de codificar una clave de suscripción en la ruta de la URI, lo cual es más difícil de implementar en una aplicación de Zend Framework.

Sin embargo, dado que no todos los Hubs soportan parámetros de cadena de consulta, seguimos recomendando encarecidamente añadir la clave de suscripción como un componente de ruta con la forma http://www.mydomain.com/hubbub/callback/5536df06b5dcb966edab3a4c4d56213c16a8184. Para lograr esto, se requiere definir una ruta capaz de extraer el valor final de la clave y luego recuperar el valor y pasarlo al objeto Callback del Suscriptor. El valor se pasaría al método Zend_Pubsubhubbub_Subscriber_Callback::setSubscriptionKey(). Más adelante se ofrece un ejemplo detallado.

hub.lease_seconds 2592000

El número de segundos durante los cuales el Suscriptor desea que una nueva suscripción permanezca válida (es decir, un TTL). Los Hubs pueden imponer su propio período máximo de suscripción. Todas las suscripciones deberían renovarse simplemente volviéndose a suscribir antes de que finalice el período de suscripción, para garantizar la continuidad de las actualizaciones. Además, los Hubs deberían intentar renovar automáticamente las suscripciones antes de que caduquen, contactando con los Suscriptores (gestionado automáticamente por la clase Callback).

hub.mode subscribe

Valor simple que indica que se trata de una solicitud de suscripción. Las solicitudes de cancelación de suscripción usarían el valor "unsubscribe".

hub.topic http://www.example.net/rss.xml

La URI del tema (es decir, la fuente Atom o RSS) al que el Suscriptor desea suscribirse para recibir actualizaciones.

hub.verify sync

Indica al Hub el modo preferido de verificación de suscripciones o cancelaciones de suscripción. Se repite dos veces en orden de preferencia. Técnicamente, este componente no distingue entre ambos modos y los trata por igual.

hub.verify async

Indica al Hub el modo preferido de verificación de suscripciones o cancelaciones de suscripción. Se repite dos veces en orden de preferencia. Técnicamente, este componente no distingue entre ambos modos y los trata por igual.

hub.verify_token 3065919804abcaa7212ae89.879827871253878386

Un token de verificación devuelto al Suscriptor por el Hub cuando confirma una suscripción o cancelación de suscripción. Ofrece una medida de confianza de que la solicitud de confirmación se origina en el Hub correcto, para evitar el uso indebido.


Puede modificar varios de estos parámetros para indicar una preferencia distinta. Por ejemplo, puede establecer un valor de lease seconds diferente usando Zend_Pubsubhubbub_Subscriber::setLeaseSeconds() o mostrar una preferencia por el modo de verificación async usando setPreferredVerificationMode(Zend_Feed_Pubsubhubbub::VERIFICATION_MODE_ASYNC). Sin embargo, los Hubs conservan la capacidad de imponer sus propias preferencias, y por esta razón el componente está deliberadamente diseñado para funcionar con casi cualquier conjunto de opciones con una configuración mínima requerida por parte del usuario final. ¡Las convenciones son geniales cuando funcionan!

[Note] Nota

Aunque los Hubs pueden requerir el uso de un modo de verificación específico (ambos están soportados por Zend_Pubsubhubbub), puede indicar una preferencia específica usando el método setPreferredVerificationMode(). En modo "sync" (síncrono), el Hub intenta confirmar una suscripción tan pronto como la recibe, y antes de responder a la solicitud de suscripción. En modo "async" (asíncrono), el Hub devolverá una respuesta a la solicitud de suscripción de inmediato, y su solicitud de verificación puede producirse más tarde. Dado que Zend_Pubsubhubbub implementa la función de verificación del Suscriptor como una clase callback independiente y requiere el uso de un medio de almacenamiento de backend, en realidad soporta ambos modos de forma transparente, aunque en términos de rendimiento para el usuario final, la verificación asíncrona es muy preferible para eliminar el impacto de un Hub con un rendimiento deficiente que ocupe los recursos y conexiones del servidor del usuario final durante demasiado tiempo.

Cancelar la suscripción de un Tema sigue exactamente el mismo patrón que el ejemplo anterior, con la excepción de que deberíamos llamar a unsubscribeAll() en su lugar. Los parámetros incluidos son idénticos a los de una solicitud de suscripción, con la excepción de que "hub.mode" se establece en "unsubscribe".

Por defecto, una nueva instancia de Zend_Pubsubhubbub_Subscriber intentará usar un medio de almacenamiento respaldado por base de datos, que por defecto usa el adaptador predeterminado de Zend_Db con un nombre de tabla "subscription". Se recomienda establecer una solución de almacenamiento personalizada cuando estos valores predeterminados no sean adecuados, ya sea pasando un nuevo Modelo que soporte la interfaz requerida o pasando una nueva instancia de Zend_Db_Table_Abstract al constructor del Modelo predeterminado para cambiar el nombre de la tabla utilizada.

33.11.4.2. Gestión de los Callbacks del Suscriptor

Cada vez que se realiza una solicitud de suscripción o cancelación de suscripción, el Hub debe verificar la solicitud reenviando una nueva solicitud de verificación a la URL de Callback establecida en los parámetros de suscripción o cancelación de suscripción. Para gestionar estas solicitudes del Hub, que incluirán todas las comunicaciones futuras que contengan actualizaciones de Tema (fuente), la URL de Callback debería desencadenar la ejecución de una instancia de Zend_Pubsubhubbub_Subscriber_Callback para gestionar la solicitud.

La clase Callback debería configurarse para usar el mismo medio de almacenamiento que la clase Subscriber. Su uso es bastante simple, ya que la mayor parte de su trabajo se realiza internamente.

$storage = new Zend_Feed_Pubsubhubbub_Model_Subscription;
$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.
 * Typically we need do nothing other than add feed update handling - the rest
 * is handled internally by the class.
 */
if ($callback->hasFeedUpdate()) {
    $feedString = $callback->getFeedUpdate();
    /**
     *  Process the feed update asynchronously to avoid a Hub timeout.
     */
}
[Note] Nota

Cabe señalar que Zend_Feed_Pubsubhubbub_Subscriber_Callback puede analizar de forma independiente cualquier cadena de consulta y otros parámetros entrantes. Esto es necesario porque PHP altera la estructura y las claves de una cadena de consulta cuando se analiza en las superglobales $_GET o $_POST. Por ejemplo, se ignoran todas las claves duplicadas y los puntos se convierten en guiones bajos. Pubsubhubbub presenta ambas características en las cadenas de consulta que genera.

[Important] Importante

Es esencial que los desarrolladores reconozcan que a los Hubs solo les interesa enviar solicitudes y recibir una respuesta que verifique su recepción. Si se recibe una actualización de fuente, nunca debería procesarse en el acto, ya que esto dejaría al Hub esperando una respuesta. Más bien, cualquier procesamiento debería delegarse a otro proceso o posponerse hasta después de que se haya devuelto una respuesta al Hub. Un síntoma de no completar con prontitud las solicitudes del Hub es que este puede continuar intentando la entrega de la actualización o de la solicitud de verificación, lo que provoca que el Suscriptor procese intentos de actualización duplicados. Esto parece problemático, pero en realidad un Hub puede aplicar un tiempo de espera de solo unos segundos, y si no recibe respuesta dentro de ese tiempo, puede desconectarse (asumiendo un fallo en la entrega) y reintentarlo más tarde. Tenga en cuenta que se espera que los Hubs distribuyan grandes volúmenes de actualizaciones, por lo que sus recursos están al límite; procese las fuentes de forma asíncrona (por ejemplo, en un proceso separado, una cola de trabajos o incluso una tarea programada por cron) tanto como sea posible.

33.11.4.3. Configuración y uso de una ruta de URL de Callback

Como se señaló anteriormente, la clase Zend_Feed_Pubsubhubbub_Subscriber_Callback recibe la clave combinada asociada a cualquier suscripción desde el Hub mediante uno de dos métodos. El método técnicamente preferido es añadir esta clave a la URL de Callback empleada por el Hub en todas las solicitudes futuras usando un parámetro de cadena de consulta con la clave "xhub.subscription". Sin embargo, por razones históricas, principalmente porque esto no estaba soportado en Pubsubhubbub 0.1 (se añadió recientemente solo en la 0.2), se recomienda encarecidamente usar el medio más compatible de añadir esta clave a la URL de Callback, añadiéndola a la ruta de la URL.

Así, la URL http://www.example.com/callback?xhub.subscription=key se convertiría en http://www.example.com/callback/key.

Dado que el método de cadena de consulta es el predeterminado, en previsión de un mayor nivel de soporte futuro para la especificación 0.2 completa, esto requiere algo de trabajo adicional para implementarlo.

El primer paso es hacer que la clase Zend_Feed_Pubsubhubbub_Subscriber_Callback sea consciente de la clave de suscripción contenida en la ruta. Por lo tanto, se inyecta manualmente, ya que también requiere definir manualmente una ruta para este propósito. Esto se logra simplemente llamando al método Zend_Feed_Pubsubhubbub_Subscriber_Callback::setSubscriptionKey() con el parámetro siendo el valor de la clave disponible desde el Router. El ejemplo siguiente muestra esto usando un controlador de Zend Framework.

class CallbackController extends Zend_Controller_Action
{

    public function indexAction()
    {
        $storage = new Zend_Feed_Pubsubhubbub_Model_Subscription;
        $callback = new Zend_Feed_Pubsubhubbub_Subscriber_Callback;
        $callback->setStorage($storage);
        /**
         * Inject subscription key parsing from URL path using
         * a parameter from Router.
         */
        $subscriptionKey = $this->_getParam('subkey');
        $callback->setSubscriptionKey($subscriptionKey);
        $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. Typically we need do nothing other than add feed update
         * handling - the rest is handled internally by the class.
         */
        if ($callback->hasFeedUpdate()) {
            $feedString = $callback->getFeedUpdate();
            /**
             *  Process the feed update asynchronously to avoid a Hub timeout.
             */
        }
    }

}

La forma de añadir realmente la ruta que asignaría la clave añadida al final de la ruta a un parámetro para su recuperación desde un controlador se puede lograr usando una configuración de Route como el siguiente ejemplo con formato INI, para su uso con el arranque de Zend_Application.

; Callback Route to enable appending a PuSH Subscription's lookup key
resources.router.routes.callback.route = "callback/:subkey"
resources.router.routes.callback.defaults.module = "default"
resources.router.routes.callback.defaults.controller = "callback"
resources.router.routes.callback.defaults.action = "index"