This repository has been archived by the owner on Aug 9, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 6
/
xrds-simple.php
283 lines (245 loc) · 8.5 KB
/
xrds-simple.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
<?php
/**
* Plugin Name: XRDS-Simple
* Plugin URI: https://github.com/diso/wordpress-xrds-simple
* Description: Provides framework for other plugins to advertise services via XRDS.
* Version: 1.2.1
* Author: DiSo Development Team
* Author URI: http://diso-project.org/
* License: MIT
* License URI: https://opensource.org/licenses/MIT
*/
// Public Functions
/**
* Convenience function for adding a new XRD to the XRDS structure.
*
* @param array $xrds current XRDS-Simple structure
* @param string $id ID of new XRD to add
* @param array $type service types for the new XRD
* @param string $expires expiration date for XRD, formatted as xs:dateTime
* @return array updated XRDS-Simple structure
* @since 1.0
*/
function xrds_add_xrd($xrds, $id, $type=array(), $expires=false) {
if(!is_array($xrds)) $xrds = array();
$xrds[$id] = array('type' => $type, 'expires' => $expires, 'services' => array());
return $xrds;
}
/**
* Convenience function for adding a new service endpoint to the XRDS structure.
*
* @param array $xrds current XRDS-Simple structure
* @param string $id ID of the XRD to add the new service to. If no XRD exists with the specified ID,
* a new one will be created.
* @param string $name human readable name of the service
* @param array $content content to be included in the service definition. Format:
* <code>
* array(
* 'NodeName (ie, Type)' => array(
* array('attribute' => 'value', 'content' => 'content string'),
* ...
* ),
* ...
* )
* </code>
* @param int $priority service priorty
* @return array updated XRDS-Simple structure
* @since 1.0
*/
function xrds_add_service($xrds, $xrd_id, $name, $content, $priority=10) {
if (!array_key_exists($xrd_id, $xrds) || !is_array($xrds[$xrd_id])) {
$xrds = xrds_add_xrd($xrds, $xrd_id);
}
$xrds[$xrd_id]['services'][$name] = array('priority' => $priority, 'content' => $content);
return $xrds;
}
/**
* Convenience function for adding a new service with minimal options.
* Services will always be added to the 'main' XRD with the default priority.
* No additional parameters such as httpMethod on URIs can be passed. If those
* are necessary, use xrds_add_service().
*
* @param array $xrds current XRDS-Simple structure
* @param string $name human readable name of the service
* @param mixed $type one type (string) or array of multiple types
* @param mixed $uri one URI (string) or array of multiple URIs
* @return array updated XRDS-Simple structure
* @since 1.0
*/
function xrds_add_simple_service($xrds, $name, $type, $uri) {
if (!is_array($type)) $type = array($type);
if (!is_array($uri)) $uri = array($uri);
$service = array('Type' => array(), 'URI' => array());
foreach ($type as $t) {
$service['Type'][] = array('content' => $t);
}
foreach ($uri as $u) {
$service['URI'][] = array('content' => $u);
}
return xrds_add_service($xrds, 'main', $name, $service);
}
// Private Functions
add_action('wp_head', 'xrds_meta');
add_action('parse_request', 'xrds_parse_request');
add_action('admin_menu', 'xrds_admin_menu');
add_filter('xrds_simple', 'xrds_atompub_service');
/**
* Print HTML meta tags, advertising the location of the XRDS document.
*/
function xrds_meta() {
echo '<meta http-equiv="X-XRDS-Location" content="'.get_bloginfo('url').'/?xrds" />'."\n";
echo '<meta http-equiv="X-Yadis-Location" content="'.get_bloginfo('url').'/?xrds" />'."\n";
}
/**
* Build the XRDS-Simple document.
*
* @return string XRDS-Simple document
*/
function xrds_write() {
$xrds = array(
'main' => array(
'type' => array('xri://$xrds*simple'),
),
);
$xrds = apply_filters('xrds_simple', $xrds);
//make sure main is last
if($xrds['main']) {
$o = $xrds['main'];
unset($xrds['main']);
$xrds['main'] = $o;
}
$xml = '<?xml version="1.0" encoding="UTF-8" ?>'."\n";
$xml .= '<xrds:XRDS xmlns:xrds="xri://$xrds" xmlns="xri://$xrd*($v*2.0)" xmlns:simple="http://xrds-simple.net/core/1.0" xmlns:openid="http://openid.net/xmlns/1.0">'."\n";
foreach($xrds as $id => $xrd) {
$xml .= ' <XRD xml:id="'.htmlspecialchars($id).'" version="2.0">' . "\n";
if(!array_key_exists('type', $xrd) || !$xrd['type']) $xrd['type'] = array();
if(!is_array($xrd['type'])) $xrd['type'] = array($xrd['type']);
foreach($xrd['type'] as $type)
$xml .= ' <Type>'.htmlspecialchars($type).'</Type>'."\n";
if(array_key_exists('expires', $xrd) && $xrd['expires'])
$xml .= ' <Expires>'.htmlspecialchars($xrd['expires']).'</Expires>'."\n";
foreach($xrd['services'] as $name => $service) {
$xml .= "\n".' <!-- ' . $name . ' -->'."\n";
$xml .= ' <Service priority="'.floor($service['priority']).'">'."\n";
foreach($service['content'] as $node => $nodes) {
if(!is_array($nodes)) $nodes = array($nodes);//sanity check
foreach($nodes as $attr) {
$xml .= ' <'.htmlspecialchars($node);
if(!is_array($attr)) $attr = array('content' => $attr);//sanity check
foreach($attr as $name => $v) {
if($name == 'content') continue;
$xml .= ' '.htmlspecialchars($name).'="'.htmlspecialchars($v).'"';
}//end foreach attr
$xml .= '>'.htmlspecialchars($attr['content']).'</'.htmlspecialchars($node).'>'."\n";
}//end foreach content
}//end foreach
$xml .= ' </Service>'."\n";
}//end foreach services
$xml .= ' </XRD>'."\n";
}//end foreach
$xml .= '</xrds:XRDS>'."\n";
return $xml;
}
/**
* Handle options page for XRDS-Simple.
*/
function xrds_options_page() {
echo "<div class=\"wrap\">\n";
echo "<h2>XRDS-Simple</h2>\n";
echo '<h3>XRDS Document</h3>';
echo '<pre>';
echo htmlentities(xrds_write());
echo '</pre>';
echo '<h3>Registered Filters</h3>';
global $wp_filter;
if (array_key_exists('xrds_simple', $wp_filter) && !empty($wp_filter['xrds_simple'])) {
echo '<ul>';
foreach ($wp_filter['xrds_simple'] as $priority) {
foreach ($priority as $idx => $data) {
$function = $data['function'];
if (is_array($function)) {
list($class, $func) = $function;
$function = "$class::$func";
}
echo '<li>'.$function.'</li>';
}
}
echo '</ul>';
} else {
echo '<p>No registered filters.</p>';
}
echo '</div>';
}//end xrds_options_page
function xrds_plugin_actions($links, $file) {
static $this_plugin;
if(!$this_plugin) $this_plugin = plugin_basename(__FILE__);
if($file == $this_plugin) {
$settings_link = '<a href="options-general.php?page=xrds-simple" style="font-weight:bold;">Settings</a>';
$links[] = $settings_link;
}//end if this_plugin
return $links;
}//end xrds_plugin_actions
/**
* Setup admin menu for XRDS.
*/
function xrds_admin_menu() {
add_options_page('XRDS-Simple', 'XRDS-Simple', 'manage_options', 'xrds-simple', 'xrds_options_page');
add_filter('plugin_action_links', 'xrds_plugin_actions', 10, 2);
}
/**
* Parse the WordPress request. If the request is for the XRDS document, handle it accordingly.
*
* @param object $wp WP instance for the current request
*/
function xrds_parse_request($wp) {
$accept = array();
if (isset($_SERVER['HTTP_ACCEPT'])) {
$accept = explode(',', $_SERVER['HTTP_ACCEPT']);
}
if(isset($_GET['xrds']) || in_array('application/xrds+xml', $accept)) {
if (isset($_REQUEST['format']) && $_REQUEST['format'] == 'text') {
header('Content-type: text/plain');
} else {
header('Content-type: application/xrds+xml');
}
echo xrds_write();
exit;
} else {
@header('X-XRDS-Location: '.get_bloginfo('url').'/?xrds');
@header('X-Yadis-Location: '.get_bloginfo('url').'/?xrds');
}
}
/**
* Contribute the AtomPub Service to XRDS-Simple.
*
* @param array $xrds current XRDS-Simple array
* @return array updated XRDS-Simple array
*/
function xrds_atompub_service($xrds) {
$xrds = xrds_add_service($xrds, 'main', 'AtomPub Service',
array(
'Type' => array( array('content' => 'http://www.w3.org/2007/app') ),
'MediaType' => array( array('content' => 'application/atomsvc+xml') ),
'URI' => array( array('content' => get_bloginfo('wpurl').'/wp-app.php/service' ) ),
)
);
return $xrds;
}
/**
* Check if data is well-formed XML.
*
* @param string $data XML structure to test
* @return mixed FALSE if data is well-formed XML, XML error code otherwise
*/
function xrds_checkXML($data) {//returns FALSE if $data is well-formed XML, errorcode otherwise
$rtrn = 0;
$theParser = xml_parser_create();
if(!xml_parse_into_struct($theParser,$data,$vals)) {
$errorcode = xml_get_error_code($theParser);
if($errorcode != XML_ERROR_NONE && $errorcode != 27)
$rtrn = $errorcode;
}//end if ! parse
xml_parser_free($theParser);
return $rtrn;
}
?>