WebSub/PubSubHubbub - Version 1.6

Version Description

  • Added comment-feed support
  • Added simple subscriber functions
  • Added link header
Download this release

Release Info

Developer joshfraz
Plugin Icon 128x128 WebSub/PubSubHubbub
Version 1.6
Comparing to
See all releases

Version 1.6

Files changed (5) hide show
  1. publisher.php +89 -0
  2. pubsubhubbub.php +330 -0
  3. readme.txt +79 -0
  4. screenshot-1.png +0 -0
  5. subscriber.php +152 -0
publisher.php ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ // a PHP client library for pubsubhubbub
3
+ // as defined at http://code.google.com/p/pubsubhubbub/
4
+ // written by Josh Fraser | joshfraser.com | joshfraz@gmail.com
5
+ // modified by Matthias Pfefferle | notizblog.org | matthias@pfefferle.org
6
+ // Released under Apache License 2.0
7
+
8
+ /**
9
+ * a pubsubhubbub publisher
10
+ *
11
+ * @author Josh Fraser
12
+ * @author Matthias Pfefferle
13
+ */
14
+ class PshbPublisher {
15
+ protected $hub_url;
16
+ protected $last_response;
17
+
18
+ // create a new Publisher
19
+ public function __construct($hub_url) {
20
+
21
+ if (!isset($hub_url))
22
+ throw new Exception('Please specify a hub url');
23
+
24
+ if (!preg_match("|^https?://|i",$hub_url))
25
+ throw new Exception('The specified hub url does not appear to be valid: '.$hub_url);
26
+
27
+ $this->hub_url = $hub_url;
28
+ }
29
+
30
+ // accepts either a single url or an array of urls
31
+ public function publish_update($topic_urls, $http_function = false) {
32
+ if (!isset($topic_urls))
33
+ throw new Exception('Please specify a topic url');
34
+
35
+ // check that we're working with an array
36
+ if (!is_array($topic_urls)) {
37
+ $topic_urls = array($topic_urls);
38
+ }
39
+
40
+ // set the mode to publish
41
+ $post_string = "hub.mode=publish";
42
+ // loop through each topic url
43
+ foreach ($topic_urls as $topic_url) {
44
+ // lightweight check that we're actually working w/ a valid url
45
+ if (!preg_match("|^https?://|i",$topic_url))
46
+ throw new Exception('The specified topic url does not appear to be valid: '.$topic_url);
47
+
48
+ // append the topic url parameters
49
+ $post_string .= "&hub.url=".urlencode($topic_url);
50
+ }
51
+
52
+ // make the http post request and return true/false
53
+ // easy to over-write to use your own http function
54
+ if ($http_function)
55
+ return $http_function($this->hub_url,$post_string);
56
+ else
57
+ return $this->http_post($this->hub_url,$post_string);
58
+ }
59
+
60
+ // returns any error message from the latest request
61
+ public function last_response() {
62
+ return $this->last_response;
63
+ }
64
+
65
+ // default http function that uses curl to post to the hub endpoint
66
+ private function http_post($url, $post_string) {
67
+ // add any additional curl options here
68
+ $options = array(CURLOPT_URL => $url,
69
+ CURLOPT_POST => true,
70
+ CURLOPT_POSTFIELDS => $post_string,
71
+ CURLOPT_USERAGENT => "PubSubHubbub-Publisher-PHP/1.0");
72
+
73
+ $ch = curl_init();
74
+ curl_setopt_array($ch, $options);
75
+
76
+ $response = curl_exec($ch);
77
+ $this->last_response = $response;
78
+ $info = curl_getinfo($ch);
79
+
80
+ curl_close($ch);
81
+
82
+ // all good
83
+ if ($info['http_code'] == 204)
84
+ return true;
85
+
86
+ return false;
87
+ }
88
+ }
89
+ ?>
pubsubhubbub.php ADDED
@@ -0,0 +1,330 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Plugin Name: PubSubHubbub
4
+ Plugin URI: http://code.google.com/p/pubsubhubbub/
5
+ Description: A better way to tell the world when your blog is updated.
6
+ Version: 1.6
7
+ Author: Josh Fraser, Matthias Pfefferle
8
+ Author Email: joshfraz@gmail.com
9
+ Author URI: http://wordpress.org/extend/plugins/pubsubhubbub/
10
+ */
11
+
12
+ include("publisher.php");
13
+ include("subscriber.php");
14
+
15
+ // the ability for other plugins to hook into the PuSH code based on a
16
+ // fix by Stephen Paul Weber (http://singpolyma.net)
17
+ function pshb_publish_to_hub($feed_urls) {
18
+ // remove dups (ie. they all point to feedburner)
19
+ $feed_urls = array_unique($feed_urls);
20
+ // get the list of hubs
21
+ $hub_urls = pshb_get_pubsub_endpoints();
22
+ // loop through each hub
23
+ foreach ($hub_urls as $hub_url) {
24
+ $p = new PshbPublisher($hub_url);
25
+ // publish the update to each hub
26
+ if (!$p->publish_update($feed_urls)) {
27
+ // TODO: add better error handling here
28
+ }
29
+ }
30
+ }
31
+
32
+ // subscribe to a feed
33
+ // NOTE! THIS IS BETA STATE
34
+ function pshb_subscribe($url) {
35
+ try {
36
+ $s = new PshbSubscriber(site_url("/?pubsubhubbub=endpoint"));
37
+ $s->find_hub($url);
38
+
39
+ $subscriptions = get_option('pubsub_subscribe');
40
+ $subscriptions[] = $s->get_topic_url();
41
+ update_option('pubsub_subscribe', array_unique($subscriptions));
42
+
43
+ if ($s->subscribe($s->get_topic_url()) !== false) {
44
+ return true;
45
+ }
46
+ } catch (Exception $e) {
47
+ return $e->getMessage();
48
+ }
49
+
50
+ return false;
51
+ }
52
+
53
+ // unsubscribe from a feed
54
+ // NOTE! THIS IS BETA STATE
55
+ function pshb_unsubscribe($url) {
56
+ try {
57
+ $s = new PshbSubscriber(site_url("/?pubsubhubbub=endpoint"));
58
+ $s->find_hub($url);
59
+
60
+ $to_unsubscribe = get_option('pubsub_unsubscribe');
61
+ $to_unsubscribe[] = $s->get_topic_url();
62
+ update_option('pubsub_unsubscribe', array_unique($to_unsubscribe));
63
+
64
+ if ($s->unsubscribe($s->get_topic_url()) !== false) {
65
+ return true;
66
+ }
67
+ } catch (Exception $e) {
68
+ return $e->getMessage();
69
+ }
70
+
71
+ return false;
72
+ }
73
+
74
+ // function that is called whenever a new post is published
75
+ function pshb_publish_post($post_id) {
76
+ // we want to notify the hub for every feed
77
+ $feed_urls = array();
78
+ $feed_urls[] = get_bloginfo('atom_url');
79
+ $feed_urls[] = get_bloginfo('rss_url');
80
+ $feed_urls[] = get_bloginfo('rdf_url');
81
+ $feed_urls[] = get_bloginfo('rss2_url');
82
+ // customize default feeds
83
+ $feed_urls = apply_filters('pshb_feed_urls', $feed_urls);
84
+
85
+ pshb_publish_to_hub($feed_urls);
86
+
87
+ return $post_id;
88
+ }
89
+
90
+ // function that is called whenever a new comment is published
91
+ function pshb_publish_comment($comment_id) {
92
+ // we want to notify the hub for every feed
93
+ $feed_urls = array();
94
+ $feed_urls[] = get_bloginfo('comments_atom_url');
95
+ $feed_urls[] = get_bloginfo('comments_rss2_url');
96
+ // customize default feeds
97
+ $feed_urls = apply_filters('pshb_comment_feed_urls', $feed_urls);
98
+
99
+ pshb_publish_to_hub($feed_urls);
100
+
101
+ return $comment_id;
102
+ }
103
+
104
+ function pshb_add_atom_link_tag() {
105
+ $hub_urls = pshb_get_pubsub_endpoints();
106
+ foreach ($hub_urls as $hub_url) {
107
+ echo '<link rel="hub" href="'.$hub_url.'" />';
108
+ }
109
+ }
110
+
111
+ function pshb_add_rss_link_tag() {
112
+ $hub_urls = pshb_get_pubsub_endpoints();
113
+ foreach ($hub_urls as $hub_url) {
114
+ echo '<atom:link rel="hub" href="'.$hub_url.'"/>';
115
+ }
116
+ }
117
+
118
+ function pshb_add_rdf_ns_link() {
119
+ echo 'xmlns:atom="http://www.w3.org/2005/Atom"';
120
+ }
121
+
122
+ // hack to add the atom definition to the RSS feed
123
+ // start capturing the feed output. this is run at priority 9 (before output)
124
+ function pshb_start_rss_link_tag() {
125
+ ob_start();
126
+ }
127
+
128
+ // this is run at priority 11 (after output)
129
+ // add in the xmlns atom definition link
130
+ function pshb_end_rss_link_tag() {
131
+ $feed = ob_get_clean();
132
+ $pattern = '/<rss version="(.+)">/i';
133
+ $replacement = '<rss version="$1" xmlns:atom="http://www.w3.org/2005/Atom">';
134
+ // change <rss version="X.XX"> to <rss version="X.XX" xmlns:atom="http://www.w3.org/2005/Atom">
135
+ echo preg_replace($pattern, $replacement, $feed);
136
+ }
137
+
138
+ // add a link to our settings page in the WP menu
139
+ function pshb_add_plugin_menu() {
140
+ add_options_page('PubSubHubbub Settings', 'PubSubHubbub', 'administrator', __FILE__, 'pshb_add_settings_page');
141
+ }
142
+
143
+ // get the endpoints from the wordpress options table
144
+ // valid parameters are "publish" or "subscribe"
145
+ function pshb_get_pubsub_endpoints() {
146
+ $endpoints = get_option('pubsub_endpoints');
147
+ $hub_urls = explode("\n",$endpoints);
148
+
149
+ // if no values have been set, revert to the defaults (pubsubhubbub on app engine & superfeedr)
150
+ if (!$endpoints) {
151
+ $hub_urls[] = "http://pubsubhubbub.appspot.com";
152
+ $hub_urls[] = "http://pubsubhubbub.superfeedr.com";
153
+ }
154
+
155
+ // clean out any blank values
156
+ foreach ($hub_urls as $key => $value) {
157
+ if (is_null($value) || $value=="") {
158
+ unset($hub_urls[$key]);
159
+ } else {
160
+ $hub_urls[$key] = trim($hub_urls[$key]);
161
+ }
162
+ }
163
+
164
+ return $hub_urls;
165
+ }
166
+
167
+ // write the content for our settings page that allows you to define your endpoints
168
+ function pshb_add_settings_page() { ?>
169
+ <div class="wrap">
170
+ <h2>Define custom hubs</h2>
171
+
172
+ <form method="post" action="options.php">
173
+ <?php //wp_nonce_field('update-options'); ?>
174
+ <!-- starting -->
175
+ <?php settings_fields('my_settings_group'); ?>
176
+ <?php do_settings_sections('my_settings_section'); ?>
177
+ <!-- ending -->
178
+
179
+ <?php
180
+ // load the existing pubsub endpoint list from the wordpress options table
181
+ $pubsub_endpoints = trim(implode("\n",pshb_get_pubsub_endpoints()),"\n");
182
+ ?>
183
+
184
+ <table class="form-table">
185
+
186
+ <tr valign="top">
187
+ <th scope="row">Hubs (one per line)</th>
188
+ <td><textarea name="pubsub_endpoints" style='width:600px;height:100px'><?php echo $pubsub_endpoints; ?></textarea></td>
189
+ </tr>
190
+
191
+ </table>
192
+
193
+ <input type="hidden" name="action" value="update" />
194
+ <input type="hidden" name="page_options" value="pubsub_endpoints" />
195
+
196
+ <p class="submit">
197
+ <input type="submit" class="button-primary" value="<?php _e('Save Changes') ?>" />
198
+ </p>
199
+
200
+ </form>
201
+
202
+ <br /><br />
203
+ <div style='background-color:#FFFEEB;border:1px solid #CCCCCC;padding:12px'>
204
+ <strong>Thanks for using PubSubHubbub!</strong><br />
205
+ Visit these links to learn more about PubSubHubbub and the author of this plugin:<br />
206
+ <ul>
207
+ <li><a href='http://www.onlineaspect.com'>Subscribe to Online Aspect</a></li>
208
+ <li><a href='http://www.twitter.com/joshfraser'>Follow Josh Fraser on twitter</a></li>
209
+ <li><a href='http://code.google.com/p/pubsubhubbub/'>Learn more about the PubSubHubbub protocol</a></li>
210
+ </ul>
211
+ </div>
212
+ </div>
213
+
214
+ <?php }
215
+
216
+ // add a settings link next to deactive / edit
217
+ function pshb_add_settings_link( $links, $file ) {
218
+ if( $file == 'pubsubhubbub/pubsubhubbub.php' && function_exists( "admin_url" ) ) {
219
+ $settings_link = '<a href="' . admin_url( 'options-general.php?page=pubsubhubbub/pubsubhubbub' ) . '">' . __('Settings') . '</a>';
220
+ array_unshift( $links, $settings_link ); // before other links
221
+ }
222
+ return $links;
223
+ }
224
+
225
+ // adds some query vars
226
+ function pshb_query_var($vars) {
227
+ $vars[] = 'hub_mode';
228
+ $vars[] = 'hub_challenge';
229
+ $vars[] = 'hub_topic';
230
+ $vars[] = 'hub_url';
231
+ $vars[] = 'pubsubhubbub';
232
+ return $vars;
233
+ }
234
+
235
+ // parses the request
236
+ function pshb_parse_request() {
237
+ global $wp_query, $wp;
238
+ $query_vars = $wp->query_vars;
239
+
240
+ // handle (un)subscribe requests
241
+ if (array_key_exists('hub_mode', $query_vars)
242
+ && in_array($query_vars['hub_mode'], array("subscribe", "unsubscribe"))
243
+ && isset($query_vars['hub_challenge'])) {
244
+ $list = get_option('pubsub_'.$query_vars['hub_mode']);
245
+ if (is_array($list) && in_array($query_vars['hub_topic'], $list)) {
246
+ // remove urls from option lists when unsubscribing
247
+ if ($query_vars['hub_mode'] == "unsubscribe") {
248
+ pshb_remove_from_option($query_vars['hub_topic'], "unsubscribe");
249
+ pshb_remove_from_option($query_vars['hub_topic'], "subscribe");
250
+ }
251
+ echo $query_vars['hub_challenge'];
252
+ exit;
253
+ }
254
+ // handle pushes
255
+ } elseif (array_key_exists('pubsubhubbub', $query_vars)
256
+ && $query_vars['pubsubhubbub'] == "endpoint"
257
+ && $request_body = @file_get_contents('php://input')) {
258
+ do_action('pshb_push', $request_body);
259
+ exit;
260
+ }
261
+ }
262
+
263
+ // remove something from the option list
264
+ function pshb_remove_from_option($url, $option) {
265
+ if (!in_array($option, array("subscribe", "unsubscribe"))) {
266
+ return false;
267
+ }
268
+
269
+ $list = get_option('pubsub_'.$option);
270
+ $key = array_search($url, $list);
271
+ unset($list[$key]);
272
+ update_option('pubsub_'.$option, $list);
273
+ }
274
+
275
+ // adds link headers as defined in the curren v0.4 draft
276
+ // https://github.com/pubsubhubbub/PubSubHubbub/issues/2
277
+ function pshb_template_redirect() {
278
+ if ((is_comment_feed() && !is_singular())
279
+ || (is_feed() && !is_comment_feed() && !is_archive())) {
280
+ $hub_urls = pshb_get_pubsub_endpoints();
281
+ foreach ($hub_urls as $hub_url) {
282
+ header('Link: <'.$hub_url.'>; rel=hub');
283
+ }
284
+ header('Link: <'.( is_ssl() ? 'https://' : 'http://' ) . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'].'>; rel=self');
285
+ }
286
+ }
287
+
288
+ // attach the handler that gets called every time you publish a post
289
+ add_action('publish_post', 'pshb_publish_post');
290
+ // attach the handler that gets called every time you get a comment
291
+ add_action('comment_post', 'pshb_publish_comment');
292
+ // add the link to our settings page in the WP menu structure
293
+ add_action('admin_menu', 'pshb_add_plugin_menu');
294
+
295
+ // keep WPMU happy
296
+ add_action('admin_init', 'pshb_register_my_settings');
297
+ function pshb_register_my_settings() {
298
+ register_setting('my_settings_group','pubsub_endpoints');
299
+ }
300
+
301
+ // add the link tag that points to the hub in the header of our template...
302
+
303
+ // to our atom feed
304
+ add_action('atom_head', 'pshb_add_atom_link_tag');
305
+ add_action('comments_atom_head', 'pshb_add_atom_link_tag');
306
+ // to our RSS 0.92 feed (requires a bit of a hack to include the ATOM namespace definition)
307
+ add_action('do_feed_rss', 'pshb_start_rss_link_tag', 9); // run before output
308
+ add_action('do_feed_rss', 'pshb_end_rss_link_tag', 11); // run after output
309
+ add_action('rss_head', 'pshb_add_rss_link_tag');
310
+ // to our RDF / RSS 1 feed
311
+ add_action('rdf_ns', 'pshb_add_rdf_ns_link');
312
+ add_action('rdf_header', 'pshb_add_rss_link_tag');
313
+ // to our RSS 2 feed
314
+ add_action('rss2_head', 'pshb_add_rss_link_tag');
315
+ add_action('commentsrss2_head', 'pshb_add_rss_link_tag');
316
+ // to our main HTML header -- not sure if we want to include this long-term or not.
317
+ add_action('wp_head', 'pshb_add_atom_link_tag');
318
+ add_action('template_redirect', 'pshb_template_redirect');
319
+
320
+ add_filter('plugin_action_links', 'pshb_add_settings_link', 10, 2);
321
+ add_filter('query_vars', 'pshb_query_var');
322
+ add_action('parse_request', 'pshb_parse_request');
323
+
324
+ /**
325
+ * beeing backwards compatible
326
+ * @deprecated
327
+ */
328
+ function publish_to_hub($deprecated = null, $feed_urls) {
329
+ pshb_publish_to_hub($feed_urls);
330
+ }
readme.txt ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ === Plugin Name ===
2
+ Contributors: joshfraz, pfefferle
3
+ Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=5426516
4
+ Tags: pubsubhubbub
5
+ Requires at least: 2.5
6
+ Tested up to: 3.3
7
+ Stable tag: 1.6
8
+
9
+ A better way to tell the world when your blog is updated.
10
+
11
+ == Description ==
12
+
13
+ This [PubSubHubbub](http://code.google.com/p/pubsubhubbub/ "PubSubHubbub") plugin is a simple way to let people know in real-time when your blog is updated. PubSubHubbub is quickly gaining adoption and is already being used by Google Reader, Google Alerts, FriendFeed and more.
14
+
15
+ This plugin:
16
+
17
+ * Now supports multiple hubs!
18
+ * Supports all of the feed formats used by WordPress, not just ATOM and RSS2
19
+ * Announces which hubs you are using by adding `<link rel="hub" ...>` declarations to your template header and ATOM feed
20
+ * Adds `<atom:link rel="hub" ...>` to your RSS feeds along with the necessary XMLNS declaration for RSS 0.92/1.0
21
+
22
+ By default this plugin will ping the following hubs:
23
+
24
+ * [Demo hub on Google App Engine](http://pubsubhubbub.appspot.com "Demo hub on Google App Engine")
25
+ * [SuperFeedr](http://pubsubhubbub.superfeedr.com "SuperFeedr")
26
+
27
+ Please contact me if you operate a hub that you would like to be included as a default option.
28
+
29
+ == Installation ==
30
+
31
+ 1. Upload the `pubsubhubbub` directory to your `/wp-content/plugins/` directory
32
+ 2. Activate the plugin through the 'Plugins' menu in WordPress
33
+ 3. Select custom hubs under your PubSubHubbub Settings (optional)
34
+
35
+ == Frequently Asked Questions ==
36
+
37
+ = Where can I learn more about the PubSubHubbub protocol? =
38
+
39
+ You can visit [PubSubHubbb on Google Code](http://code.google.com/p/pubsubhubbub/ "PubSubHubbb on Google Code")
40
+
41
+ = Where can I learn more about the authors of this plugin? =
42
+
43
+ You can learn more about [Josh Fraser](http://www.joshfraser.com "Josh Fraser") at [Online Aspect](http://www.onlineaspect.com "Online Aspect")
44
+ and [Matthias Pfefferle](http://pfefferle.org "Matthias Pfefferle") at [Notizblog](http://notizblog.org/ "Notizblog")
45
+
46
+ == Screenshots ==
47
+
48
+ 1. The PubSubHubbub Settings page allows you to define which hubs you want to use
49
+
50
+ == Changelog ==
51
+
52
+ = 1.6 =
53
+ * Added comment-feed support
54
+ * Added simple subscriber functions
55
+ * Added link header
56
+
57
+ = 1.5 =
58
+ * Added filter to modify $feed_urls
59
+ * Re-Added Stephen Paul Webers changes
60
+
61
+ = 1.4 =
62
+ * Added name spacing to avoid conflicts with other plugins & added patch from pfefferle
63
+
64
+ = 1.3 =
65
+ * Added multi-user support and now tested up to 2.9.1
66
+
67
+ = 1.2 =
68
+ * Added support for multiple hubs
69
+
70
+ = 1.1 =
71
+ * Added RSS support
72
+
73
+ = 1.0 =
74
+ * First attempt
75
+
76
+ == Upgrade Notice ==
77
+
78
+ = 1.4 =
79
+ Upgrade eliminates conflicts with other Wordpress plugins
screenshot-1.png ADDED
Binary file
subscriber.php ADDED
@@ -0,0 +1,152 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ // a PHP client library for pubsubhubbub
3
+ // as defined at http://code.google.com/p/pubsubhubbub/
4
+ // written by Josh Fraser | joshfraser.com | joshfraz@gmail.com
5
+ // modified by Matthias Pfefferle | notizblog.org | matthias@pfefferle.org
6
+ // Released under Apache License 2.0
7
+
8
+ /**
9
+ * a pubsubhubbub subscriber
10
+ *
11
+ * @author Josh Fraser
12
+ * @author Matthias Pfefferle
13
+ */
14
+ class PshbSubscriber {
15
+ protected $hub_url;
16
+ protected $topic_url;
17
+ protected $callback_url;
18
+ protected $credentials;
19
+ // accepted values are "async" and "sync"
20
+ protected $verify = "sync";
21
+ protected $verify_token;
22
+ protected $lease_seconds;
23
+
24
+ // create a new Subscriber (credentials added for SuperFeedr support)
25
+ public function __construct($callback_url, $hub_url = null, $credentials = false) {
26
+ if ($hub_url && !preg_match("|^https?://|i",$hub_url))
27
+ throw new Exception('The specified hub url does not appear to be valid: '.$hub_url);
28
+
29
+ if (!isset($callback_url))
30
+ throw new Exception('Please specify a callback');
31
+
32
+ $this->hub_url = $hub_url;
33
+ $this->callback_url = $callback_url;
34
+ $this->credentials = $credentials;
35
+ }
36
+
37
+ public function subscribe($topic_url, $http_function = false) {
38
+ if (!$this->hub_url) {
39
+ $this->find_hub($topic_url);
40
+ }
41
+
42
+ return $this->change_subscription("subscribe", $topic_url, $http_function = false);
43
+ }
44
+
45
+ public function unsubscribe($topic_url, $http_function = false) {
46
+ return $this->change_subscription("unsubscribe", $topic_url, $http_function = false);
47
+ }
48
+
49
+ // helper function since sub/unsub are handled the same way
50
+ private function change_subscription($mode, $topic_url, $http_function = false) {
51
+ if (!isset($topic_url))
52
+ throw new Exception('Please specify a topic url');
53
+
54
+ // lightweight check that we're actually working w/ a valid url
55
+ if (!preg_match("|^https?://|i",$topic_url))
56
+ throw new Exception('The specified topic url does not appear to be valid: '.$topic_url);
57
+
58
+ // set the mode subscribe/unsubscribe
59
+ $post_string = "hub.mode=".$mode;
60
+ $post_string .= "&hub.callback=".urlencode($this->callback_url);
61
+ $post_string .= "&hub.verify=".$this->verify;
62
+ $post_string .= "&hub.verify_token=".$this->verify_token;
63
+ $post_string .= "&hub.lease_seconds=".$this->lease_seconds;
64
+
65
+ // append the topic url parameters
66
+ $post_string .= "&hub.topic=".urlencode($topic_url);
67
+
68
+ // make the http post request and return true/false
69
+ // easy to over-write to use your own http function
70
+ if ($http_function)
71
+ return $http_function($this->hub_url,$post_string);
72
+ else
73
+ return $this->http($this->hub_url,$post_string);
74
+ }
75
+
76
+ // default http function that uses curl to post to the hub endpoint
77
+ private function http($url, $post_string = null) {
78
+
79
+ // add any additional curl options here
80
+ $options = array(CURLOPT_URL => $url,
81
+ CURLOPT_USERAGENT => "PubSubHubbub-Subscriber-PHP/1.0",
82
+ CURLOPT_RETURNTRANSFER => true,
83
+ CURLOPT_FOLLOWLOCATION => true);
84
+
85
+ if ($post_string) {
86
+ $options[CURLOPT_POST] = true;
87
+ $options[CURLOPT_POSTFIELDS] = $post_string;
88
+ }
89
+
90
+ if ($this->credentials)
91
+ $options[CURLOPT_USERPWD] = $this->credentials;
92
+
93
+ $ch = curl_init();
94
+ curl_setopt_array($ch, $options);
95
+
96
+ $response = curl_exec($ch);
97
+ $info = curl_getinfo($ch);
98
+
99
+ // all good -- anything in the 200 range
100
+ if (substr($info['http_code'],0,1) == "2") {
101
+ return $response;
102
+ }
103
+
104
+ return false;
105
+ }
106
+
107
+ //
108
+ public function find_hub($topic_url) {
109
+ $self = $topic_url;
110
+ $xml = $this->http($topic_url);
111
+ if (!$xml)
112
+ throw new Exception('Please enter a valid URL');
113
+
114
+ $xml_parser = xml_parser_create('');
115
+ $xml_values = array();
116
+ $xml_tags = array();
117
+
118
+ if(!$xml_parser)
119
+ throw new Exception('Your webserver doesn\'t support xml-parsing');
120
+
121
+ xml_parser_set_option($xml_parser, XML_OPTION_TARGET_ENCODING, 'UTF-8');
122
+ xml_parser_set_option($xml_parser, XML_OPTION_CASE_FOLDING, 0);
123
+ xml_parser_set_option($xml_parser, XML_OPTION_SKIP_WHITE, 1);
124
+ xml_parse_into_struct($xml_parser, trim($xml), $xml_values);
125
+ xml_parser_free($xml_parser);
126
+
127
+ $hubs = array();
128
+
129
+ foreach ($xml_values as $value) {
130
+ // get hubs
131
+ if ($value['attributes']['rel'] == 'hub') {
132
+ $hubs[] = $value['attributes']['href'];
133
+ }
134
+ // get self url
135
+ if ($value['attributes']['rel'] == 'self') {
136
+ $self = $value['attributes']['href'];
137
+ }
138
+ }
139
+
140
+ if (count($hubs) >= 1)
141
+ $this->hub_url = $hubs[0];
142
+ else
143
+ throw new Exception('This feed doesn\'t reference a hub url');
144
+
145
+ $this->topic_url = $self;
146
+ }
147
+
148
+ public function get_topic_url() {
149
+ return $this->topic_url;
150
+ }
151
+ }
152
+ ?>