1
|
|
|
<?php |
|
|
|
|
2
|
|
|
/** |
3
|
|
|
* API-like class to deal with HTTP(S) requests to diaspora* using WP_HTTP API. |
4
|
|
|
* |
5
|
|
|
* Basic functionality includes: |
6
|
|
|
* - Logging in to diaspora* |
7
|
|
|
* - Fetching a user's aspects and connected services |
8
|
|
|
* - Posting to diaspora* |
9
|
|
|
* |
10
|
|
|
* Ideas in this class are based on classes from: |
11
|
|
|
* https://github.com/Faldrian/WP-diaspora-postwidget/blob/master/wp-diaspora-postwidget/diasphp.php -- Thanks, Faldrian! |
12
|
|
|
* https://github.com/meitar/diasposter/blob/master/lib/Diaspora_Connection.php -- Thanks, Meitar |
13
|
|
|
* |
14
|
|
|
* Which in turn are based on: |
15
|
|
|
* https://github.com/cocreature/diaspy/blob/master/client.py -- Thanks, Moritz |
16
|
|
|
* |
17
|
|
|
* @package WP_To_Diaspora\API |
18
|
|
|
* @since 1.2.7 |
19
|
|
|
*/ |
20
|
|
|
|
21
|
|
|
// Exit if accessed directly. |
22
|
|
|
defined( 'ABSPATH' ) || exit; |
23
|
|
|
|
24
|
|
|
/** |
25
|
|
|
* API class to talk to diaspora*. |
26
|
|
|
*/ |
27
|
|
|
class WP2D_API { |
|
|
|
|
28
|
|
|
|
29
|
|
|
/** |
30
|
|
|
* The provider name to display when posting to diaspora*. |
31
|
|
|
* |
32
|
|
|
* @var string |
33
|
|
|
*/ |
34
|
|
|
public $provider = 'WP to diaspora*'; |
35
|
|
|
|
36
|
|
|
/** |
37
|
|
|
* The last http request error that occurred. |
38
|
|
|
* |
39
|
|
|
* @var WP_Error |
40
|
|
|
*/ |
41
|
|
|
private $_last_error; |
42
|
|
|
|
43
|
|
|
/** |
44
|
|
|
* Security token to be used for making requests. |
45
|
|
|
* |
46
|
|
|
* @var string |
47
|
|
|
*/ |
48
|
|
|
private $_token; |
49
|
|
|
|
50
|
|
|
/** |
51
|
|
|
* Save the cookies for the requests. |
52
|
|
|
* |
53
|
|
|
* @var array |
54
|
|
|
*/ |
55
|
|
|
private $_cookies; |
56
|
|
|
|
57
|
|
|
/** |
58
|
|
|
* The last http request made to diaspora*. |
59
|
|
|
* Contains the response and request infos. |
60
|
|
|
* |
61
|
|
|
* @var object |
62
|
|
|
*/ |
63
|
|
|
private $_last_request; |
64
|
|
|
|
65
|
|
|
/** |
66
|
|
|
* Is this a secure server, use HTTPS instead of HTTP? |
67
|
|
|
* |
68
|
|
|
* @var boolean |
69
|
|
|
*/ |
70
|
|
|
private $_is_secure; |
71
|
|
|
|
72
|
|
|
/** |
73
|
|
|
* The pod domain to make the http requests to. |
74
|
|
|
* |
75
|
|
|
* @var string |
76
|
|
|
*/ |
77
|
|
|
private $_pod; |
78
|
|
|
|
79
|
|
|
/** |
80
|
|
|
* Username to use when logging in to diaspora*. |
81
|
|
|
* |
82
|
|
|
* @var string |
83
|
|
|
*/ |
84
|
|
|
private $_username; |
85
|
|
|
|
86
|
|
|
/** |
87
|
|
|
* Password to use when logging in to diaspora*. |
88
|
|
|
* |
89
|
|
|
* @var string |
90
|
|
|
*/ |
91
|
|
|
private $_password; |
92
|
|
|
|
93
|
|
|
/** |
94
|
|
|
* Remember the current login state. |
95
|
|
|
* |
96
|
|
|
* @var boolean |
97
|
|
|
*/ |
98
|
|
|
private $_is_logged_in = false; |
99
|
|
|
|
100
|
|
|
/** |
101
|
|
|
* The list of user's aspects, which get set after ever http request. |
102
|
|
|
* |
103
|
|
|
* @var array |
104
|
|
|
*/ |
105
|
|
|
private $_aspects = array(); |
106
|
|
|
|
107
|
|
|
/** |
108
|
|
|
* The list of user's connected services, which get set after ever http request. |
109
|
|
|
* |
110
|
|
|
* @var array |
111
|
|
|
*/ |
112
|
|
|
private $_services = array(); |
113
|
|
|
|
114
|
|
|
/** |
115
|
|
|
* List of regex expressions used to filter out details from http request responses. |
116
|
|
|
* |
117
|
|
|
* @var array |
118
|
|
|
*/ |
119
|
|
|
private $_regexes = array( |
120
|
|
|
'token' => '/content="(.*?)" name="csrf-token"|name="csrf-token" content="(.*?)"/', |
121
|
|
|
'aspects' => '/"aspects"\:(\[.*?\])/', |
122
|
|
|
'services' => '/"configured_services"\:(\[.*?\])/', |
123
|
|
|
); |
124
|
|
|
|
125
|
|
|
/** |
126
|
|
|
* The full pod url, with the used protocol. |
127
|
|
|
* |
128
|
|
|
* @param string $path Path to add to the pod url. |
129
|
|
|
* @return string Full pod url. |
130
|
|
|
*/ |
131
|
|
|
public function get_pod_url( $path = '' ) { |
132
|
|
|
$path = trim( $path, ' /' ); |
133
|
|
|
|
134
|
|
|
// Add a slash to the beginning? |
135
|
|
|
if ( '' !== $path ) { |
136
|
|
|
$path = '/' . $path; |
137
|
|
|
} |
138
|
|
|
|
139
|
|
|
return sprintf( 'http%s://%s%s', ( $this->_is_secure ) ? 's' : '', $this->_pod, $path ); |
140
|
|
|
} |
141
|
|
|
|
142
|
|
|
/** |
143
|
|
|
* Constructor to initialise the connection to diaspora*. |
144
|
|
|
* |
145
|
|
|
* @param string $pod The pod domain to connect to. |
146
|
|
|
* @param boolean $is_secure Is this a secure server? (Default: true). |
147
|
|
|
*/ |
148
|
|
|
public function __construct( $pod, $is_secure = true ) { |
149
|
|
|
// Set class variables. |
150
|
|
|
$this->_pod = $pod; |
151
|
|
|
$this->_is_secure = (bool) $is_secure; |
152
|
|
|
} |
153
|
|
|
|
154
|
|
|
/** |
155
|
|
|
* Initialise the connection to diaspora*. The pod and protocol can be changed by passing new parameters. |
156
|
|
|
* Check if we can connect to the pod to retrieve the token. |
157
|
|
|
* |
158
|
|
|
* @param string $pod Pod domain to connect to, if it should be changed. |
159
|
|
|
* @param boolean $is_secure Is this a secure server? (Default: true). |
160
|
|
|
* @return boolean True if we could get the token, else false. |
161
|
|
|
*/ |
162
|
|
|
public function init( $pod = null, $is_secure = true ) { |
163
|
|
|
// If we are changing pod, we need to fetch a new token. |
164
|
|
|
$force_new_token = false; |
165
|
|
|
|
166
|
|
|
// When initialising a connection, clear the last error. |
167
|
|
|
// This is important when multiple init tries happen. |
168
|
|
|
$this->_last_error = null; |
169
|
|
|
|
170
|
|
|
// Change the pod we are connecting to? |
171
|
|
|
if ( isset( $pod ) && ( $this->_pod !== $pod || $this->_is_secure !== $is_secure ) ) { |
172
|
|
|
$this->_pod = $pod; |
173
|
|
|
$this->_is_secure = (bool) $is_secure; |
174
|
|
|
$force_new_token = true; |
175
|
|
|
} |
176
|
|
|
|
177
|
|
|
// Get and save the token. |
178
|
|
|
if ( null === $this->_fetch_token( $force_new_token ) ) { |
179
|
|
|
$error = ( $this->has_last_error() ) ? ' ' . $this->get_last_error() : ''; |
180
|
|
|
$this->_error( 'wp2d_api_init_failed', |
181
|
|
|
sprintf( |
182
|
|
|
_x( 'Failed to initialise connection to pod "%s".', 'Placeholder is the full pod URL.', 'wp-to-diaspora' ), |
183
|
|
|
$this->get_pod_url() |
184
|
|
|
) . $error, |
185
|
|
|
array( 'help_tab' => 'troubleshooting' ) |
186
|
|
|
); |
187
|
|
|
|
188
|
|
|
return false; |
189
|
|
|
} |
190
|
|
|
return true; |
191
|
|
|
} |
192
|
|
|
|
193
|
|
|
/** |
194
|
|
|
* Check if there is an API error around. |
195
|
|
|
* |
196
|
|
|
* @return boolean If there is an API error around. |
197
|
|
|
*/ |
198
|
|
|
public function has_last_error() { |
199
|
|
|
return is_wp_error( $this->_last_error ); |
200
|
|
|
} |
201
|
|
|
|
202
|
|
|
/** |
203
|
|
|
* Get the last API error object. |
204
|
|
|
* |
205
|
|
|
* @param boolean $clear If the error should be cleared after returning it. |
206
|
|
|
* @return WP_Error|null The last API error object or null. |
207
|
|
|
*/ |
208
|
|
|
public function get_last_error_object( $clear = true ) { |
209
|
|
|
$last_error = $this->_last_error; |
210
|
|
|
$clear && $this->_last_error = null; |
211
|
|
|
return $last_error; |
212
|
|
|
} |
213
|
|
|
|
214
|
|
|
/** |
215
|
|
|
* Get the last API error message. |
216
|
|
|
* |
217
|
|
|
* @param boolean $clear If the error should be cleared after returning it. |
218
|
|
|
* @return string The last API error message. |
219
|
|
|
*/ |
220
|
|
|
public function get_last_error( $clear = false ) { |
221
|
|
|
$last_error = ( $this->has_last_error() ) ? $this->_last_error->get_error_message() : ''; |
222
|
|
|
$clear && $this->_last_error = null; |
223
|
|
|
return $last_error; |
224
|
|
|
} |
225
|
|
|
|
226
|
|
|
/** |
227
|
|
|
* Fetch the secure token from Diaspora and save it for future use. |
228
|
|
|
* |
229
|
|
|
* @param boolean $force Force to fetch a new token. |
230
|
|
|
* @return string The fetched token. |
231
|
|
|
*/ |
232
|
|
|
private function _fetch_token( $force = false ) { |
233
|
|
|
if ( ! isset( $this->_token ) || (bool) $force ) { |
234
|
|
|
// Go directly to the sign in page, as it would redirect to there anyway. |
235
|
|
|
// Since _request function automatically saves the new token, just call it with no data. |
236
|
|
|
$this->_request( '/users/sign_in' ); |
237
|
|
|
} |
238
|
|
|
return $this->_token; |
239
|
|
|
} |
240
|
|
|
|
241
|
|
|
/** |
242
|
|
|
* Check if the API has been initialised. Otherwise set the last error. |
243
|
|
|
* |
244
|
|
|
* @return boolean Has the connection been initialised? |
245
|
|
|
*/ |
246
|
|
|
private function _check_init() { |
247
|
|
|
if ( is_null( $this->_token ) ) { |
248
|
|
|
$this->_error( 'wp2d_api_connection_not_initialised', __( 'Connection not initialised.', 'wp-to-diaspora' ) ); |
249
|
|
|
return false; |
250
|
|
|
} |
251
|
|
|
return true; |
252
|
|
|
} |
253
|
|
|
|
254
|
|
|
/** |
255
|
|
|
* Check if we're logged in. Otherwise set the last error. |
256
|
|
|
* |
257
|
|
|
* @return boolean Are we logged in already? |
258
|
|
|
*/ |
259
|
|
|
private function _check_login() { |
260
|
|
|
if ( ! $this->_check_init() ) { |
261
|
|
|
return false; |
262
|
|
|
} |
263
|
|
|
if ( ! $this->is_logged_in() ) { |
264
|
|
|
$this->_error( 'wp2d_api_not_logged_in', __( 'Not logged in.', 'wp-to-diaspora' ) ); |
265
|
|
|
return false; |
266
|
|
|
} |
267
|
|
|
return true; |
268
|
|
|
} |
269
|
|
|
|
270
|
|
|
/** |
271
|
|
|
* Check if we are logged in. |
272
|
|
|
* |
273
|
|
|
* @return boolean Are we logged in already? |
274
|
|
|
*/ |
275
|
|
|
public function is_logged_in() { |
276
|
|
|
return $this->_is_logged_in; |
277
|
|
|
} |
278
|
|
|
|
279
|
|
|
/** |
280
|
|
|
* Log in to diaspora*. |
281
|
|
|
* |
282
|
|
|
* @param string $username Username used for login. |
283
|
|
|
* @param string $password Password used for login. |
284
|
|
|
* @param boolean $force Force a new login even if we are already logged in. |
285
|
|
|
* @return boolean Did the login succeed? |
286
|
|
|
*/ |
287
|
|
|
public function login( $username, $password, $force = false ) { |
288
|
|
|
// Has the connection been initialised? |
289
|
|
|
if ( ! $this->_check_init() ) { |
290
|
|
|
$this->logout(); |
291
|
|
|
return false; |
292
|
|
|
} |
293
|
|
|
|
294
|
|
|
// Username and password both need to be set. |
295
|
|
|
$username = ( isset( $username ) && '' !== $username ) ? $username : null; |
296
|
|
|
$password = ( isset( $password ) && '' !== $password ) ? $password : null; |
297
|
|
|
if ( ! isset( $username, $password ) ) { |
298
|
|
|
$this->logout(); |
299
|
|
|
return false; |
300
|
|
|
} |
301
|
|
|
|
302
|
|
|
// If we are already logged in and not forcing a relogin, return. |
303
|
|
|
if ( ! $force && $this->is_logged_in() && |
304
|
|
|
$username === $this->_username && |
305
|
|
|
$password === $this->_password ) { |
306
|
|
|
return true; |
307
|
|
|
} |
308
|
|
|
|
309
|
|
|
// Set the newly passed username and password. |
310
|
|
|
$this->_username = $username; |
311
|
|
|
$this->_password = $password; |
312
|
|
|
|
313
|
|
|
// Set up the login parameters. |
314
|
|
|
$params = array( |
315
|
|
|
'user[username]' => $this->_username, |
316
|
|
|
'user[password]' => $this->_password, |
317
|
|
|
'authenticity_token' => $this->_fetch_token(), |
318
|
|
|
); |
319
|
|
|
|
320
|
|
|
$args = array( |
321
|
|
|
'method' => 'POST', |
322
|
|
|
'body' => $params, |
323
|
|
|
); |
324
|
|
|
|
325
|
|
|
// Try to sign in. |
326
|
|
|
$this->_request( '/users/sign_in', $args ); |
327
|
|
|
|
328
|
|
|
// Can we load the bookmarklet to make sure we're logged in? |
329
|
|
|
$response = $this->_request( '/bookmarklet' ); |
330
|
|
|
|
331
|
|
|
// If the request isn't successful, we are not logged in correctly. |
332
|
|
|
if ( is_wp_error( $response ) || 200 !== $response->code ) { |
333
|
|
|
// Login failed. |
334
|
|
|
$this->_error( 'wp2d_api_login_failed', __( 'Login failed. Check your login details.', 'wp-to-diaspora' ), array( 'help_tab' => 'troubleshooting' ) ); |
335
|
|
|
$this->logout(); |
336
|
|
|
return false; |
337
|
|
|
} |
338
|
|
|
|
339
|
|
|
// Login succeeded. |
340
|
|
|
$this->_is_logged_in = true; |
341
|
|
|
return true; |
342
|
|
|
} |
343
|
|
|
|
344
|
|
|
/** |
345
|
|
|
* Perform a logout, resetting all login info. |
346
|
|
|
* |
347
|
|
|
* @since 1.6.0 |
348
|
|
|
*/ |
349
|
|
|
public function logout() { |
350
|
|
|
$this->_is_logged_in = false; |
351
|
|
|
$this->_username = null; |
352
|
|
|
$this->_password = null; |
353
|
|
|
$this->_aspects = array(); |
354
|
|
|
$this->_services = array(); |
355
|
|
|
} |
356
|
|
|
|
357
|
|
|
/** |
358
|
|
|
* Perform a deinitialisation, resetting all class variables. |
359
|
|
|
* |
360
|
|
|
* @since 1.7.0 |
361
|
|
|
*/ |
362
|
|
|
public function deinit() { |
363
|
|
|
$this->logout(); |
364
|
|
|
$this->_last_error = null; |
365
|
|
|
$this->_token = null; |
366
|
|
|
$this->_cookies = array(); |
367
|
|
|
$this->_last_request = null; |
368
|
|
|
} |
369
|
|
|
|
370
|
|
|
/** |
371
|
|
|
* Post to diaspora*. |
372
|
|
|
* |
373
|
|
|
* @param string $text The text to post. |
374
|
|
|
* @param array|string $aspects The aspects to post to. Array or comma seperated ids. |
375
|
|
|
* @param array $extra_data Any extra data to be added to the post call. |
376
|
|
|
* @return boolean|object Return the response data of the new diaspora* post if successfully posted, else false. |
377
|
|
|
*/ |
378
|
|
|
public function post( $text, $aspects = 'public', $extra_data = array() ) { |
379
|
|
|
// Are we logged in? |
380
|
|
|
if ( ! $this->_check_login() ) { |
381
|
|
|
return false; |
382
|
|
|
} |
383
|
|
|
|
384
|
|
|
// Put the aspects into a clean array. |
385
|
|
|
$aspects = array_filter( WP2D_Helpers::str_to_arr( $aspects ) ); |
386
|
|
|
|
387
|
|
|
// If no aspects have been selected or the public one is also included, choose public only. |
388
|
|
|
if ( empty( $aspects ) || in_array( 'public', $aspects ) ) { |
389
|
|
|
$aspects = 'public'; |
390
|
|
|
} |
391
|
|
|
|
392
|
|
|
// Prepare post data. |
393
|
|
|
$post_data = array( |
394
|
|
|
'aspect_ids' => $aspects, |
395
|
|
|
'status_message' => array( |
396
|
|
|
'text' => $text, |
397
|
|
|
'provider_display_name' => $this->provider, |
398
|
|
|
), |
399
|
|
|
); |
400
|
|
|
|
401
|
|
|
// Add any extra data to the post. |
402
|
|
|
if ( ! empty( $extra_data ) ) { |
403
|
|
|
$post_data += $extra_data; |
404
|
|
|
} |
405
|
|
|
|
406
|
|
|
// Check if we can use the new wp_json_encode function. |
407
|
|
|
$post_data = ( function_exists( 'wp_json_encode' ) ) |
408
|
|
|
? wp_json_encode( $post_data ) |
409
|
|
|
: json_encode( $post_data ); |
410
|
|
|
|
411
|
|
|
$args = array( |
412
|
|
|
'method' => 'POST', |
413
|
|
|
'body' => $post_data, |
414
|
|
|
'headers' => array( |
415
|
|
|
'Accept' => 'application/json', |
416
|
|
|
'Content-Type' => 'application/json', |
417
|
|
|
'X-CSRF-Token' => $this->_fetch_token(), |
418
|
|
|
), |
419
|
|
|
); |
420
|
|
|
|
421
|
|
|
// Submit the post. |
422
|
|
|
$response = $this->_request( '/status_messages', $args ); |
423
|
|
|
|
424
|
|
|
if ( is_wp_error( $response ) ) { |
425
|
|
|
$this->_error( 'wp2d_api_post_failed', $response->get_error_message() ); |
426
|
|
|
return false; |
427
|
|
|
} |
428
|
|
|
|
429
|
|
|
$diaspost = json_decode( $response->body ); |
430
|
|
|
if ( 201 !== $response->code ) { |
431
|
|
|
$this->_error( 'wp2d_api_post_failed', ( isset( $diaspost->error ) ) ? $diaspost->error : _x( 'Unknown error occurred.', 'When an unknown error occurred in the WP2D_API object.', 'wp-to-diaspora' ) ); |
432
|
|
|
return false; |
433
|
|
|
} |
434
|
|
|
|
435
|
|
|
// Add additional info to our diaspora post object. |
436
|
|
|
$diaspost->permalink = $this->get_pod_url( '/posts/' . $diaspost->guid ); |
437
|
|
|
|
438
|
|
|
return $diaspost; |
439
|
|
|
} |
440
|
|
|
|
441
|
|
|
/** |
442
|
|
|
* Delete a post or comment from diaspora*. |
443
|
|
|
* |
444
|
|
|
* @since 1.6.0 |
445
|
|
|
* |
446
|
|
|
* @param string $what What to delete, 'post' or 'comment'. |
447
|
|
|
* @param string $id The ID of the post or comment to delete. |
448
|
|
|
* @return boolean If the deletion was successful. |
449
|
|
|
*/ |
450
|
|
|
public function delete( $what, $id ) { |
451
|
|
|
// Are we logged in? |
452
|
|
|
if ( ! $this->_check_login() ) { |
453
|
|
|
return false; |
454
|
|
|
} |
455
|
|
|
|
456
|
|
|
// For now, only deleting posts and comments is allowed. |
457
|
|
|
if ( ! in_array( $what, array( 'post', 'comment' ) ) ) { |
458
|
|
|
$this->_error( 'wp2d_api_delete_failed', __( 'You can only delete posts and comments.', 'wp-to-diaspora' ) ); |
459
|
|
|
return false; |
460
|
|
|
} |
461
|
|
|
|
462
|
|
|
$args = array( |
463
|
|
|
'method' => 'DELETE', |
464
|
|
|
'headers' => array( |
465
|
|
|
'Accept' => 'application/json', |
466
|
|
|
'Content-Type' => 'application/json', |
467
|
|
|
'X-CSRF-Token' => $this->_fetch_token(), |
468
|
|
|
), |
469
|
|
|
); |
470
|
|
|
|
471
|
|
|
// Try to delete the post or comment. |
472
|
|
|
$response = $this->_request( '/' . $what . 's/' . $id, $args ); |
473
|
|
|
|
474
|
|
|
$error_message = ''; |
|
|
|
|
475
|
|
|
|
476
|
|
|
if ( is_wp_error( $response ) ) { |
477
|
|
|
$error_message = $response->get_error_message(); |
478
|
|
|
} else { |
479
|
|
|
switch ( $response->code ) { |
480
|
|
|
case 204: |
481
|
|
|
return true; |
482
|
|
|
case 404: |
483
|
|
|
$error_message = ( 'post' === $what ) |
484
|
|
|
? __( 'The post you tried to delete does not exist.', 'wp-to-diaspora' ) |
485
|
|
|
: __( 'The comment you tried to delete does not exist.', 'wp-to-diaspora' ); |
486
|
|
|
break; |
487
|
|
|
|
488
|
|
|
// Due to diaspora* returning a proper 403 when trying to delete a foreign comment |
489
|
|
|
// but returning a 500 when trying to delete a foreign post, this needs some special attention. |
490
|
|
|
case 403: |
491
|
|
|
if ( 'comment' === $what ) { |
492
|
|
|
$error_message = __( 'The comment you tried to delete does not belong to you.', 'wp-to-diaspora' ); |
493
|
|
|
break; |
494
|
|
|
} |
495
|
|
|
// Fall through... |
496
|
|
|
case 500: |
497
|
|
|
if ( 'post' === $what ) { |
498
|
|
|
$error_message = __( 'The post you tried to delete does not belong to you.', 'wp-to-diaspora' ); |
499
|
|
|
break; |
500
|
|
|
} |
501
|
|
|
// Fall through... |
502
|
|
|
default: |
503
|
|
|
$error_message = _x( 'Unknown error occurred.', 'When an unknown error occurred in the WP2D_API object.', 'wp-to-diaspora' ); |
504
|
|
|
break; |
505
|
|
|
} |
506
|
|
|
} |
507
|
|
|
|
508
|
|
|
$this->_error( 'wp2d_api_delete_' . $what . '_failed', $error_message ); |
509
|
|
|
return false; |
510
|
|
|
} |
511
|
|
|
|
512
|
|
|
/** |
513
|
|
|
* Get the list of aspects. |
514
|
|
|
* |
515
|
|
|
* @param boolean $force Force to fetch new aspects. |
516
|
|
|
* @return array Array of aspect objects. |
517
|
|
|
*/ |
518
|
|
|
public function get_aspects( $force = false ) { |
519
|
|
|
$this->_aspects = $this->_get_aspects_services( 'aspects', $this->_aspects, $force ); |
|
|
|
|
520
|
|
|
return ( is_array( $this->_aspects ) ) ? $this->_aspects : false; |
521
|
|
|
} |
522
|
|
|
|
523
|
|
|
/** |
524
|
|
|
* Get the list of connected services. |
525
|
|
|
* |
526
|
|
|
* @param boolean $force Force to fetch new connected services. |
527
|
|
|
* @return array Array of service objects. |
528
|
|
|
*/ |
529
|
|
|
public function get_services( $force = false ) { |
530
|
|
|
$this->_services = $this->_get_aspects_services( 'services', $this->_services, $force ); |
|
|
|
|
531
|
|
|
return ( is_array( $this->_services ) ) ? $this->_services : false; |
532
|
|
|
} |
533
|
|
|
|
534
|
|
|
/** |
535
|
|
|
* Get the list of aspects or connected services. |
536
|
|
|
* |
537
|
|
|
* @param string $type Type of list to get. |
538
|
|
|
* @param array $list The current list of items. |
539
|
|
|
* @param boolean $force Force to fetch new list. |
540
|
|
|
* @return boolean Was the list fetched successfully? |
541
|
|
|
*/ |
542
|
|
|
private function _get_aspects_services( $type, $list, $force ) { |
543
|
|
|
if ( ! $this->_check_login() ) { |
544
|
|
|
return false; |
545
|
|
|
} |
546
|
|
|
|
547
|
|
|
// Fetch the new list if the current list is empty or a reload is forced. |
548
|
|
|
if ( empty( $list ) || (bool) $force ) { |
549
|
|
|
$response = $this->_request( '/bookmarklet' ); |
550
|
|
|
|
551
|
|
|
if ( is_wp_error( $response ) || 200 !== $response->code ) { |
552
|
|
|
switch ( $type ) { |
553
|
|
|
case 'aspects': |
554
|
|
|
$this->_error( 'wp2d_api_getting_aspects_failed', __( 'Error loading aspects.', 'wp-to-diaspora' ) ); |
555
|
|
|
break; |
556
|
|
|
case 'services': |
557
|
|
|
$this->_error( 'wp2d_api_getting_services_failed', __( 'Error loading services.', 'wp-to-diaspora' ) ); |
558
|
|
|
break; |
559
|
|
|
default: |
560
|
|
|
$this->_error( 'wp2d_api_getting_aspects_services_failed', _x( 'Unknown error occurred.', 'When an unknown error occurred in the WP2D_API object.', 'wp-to-diaspora' ) ); |
561
|
|
|
break; |
562
|
|
|
} |
563
|
|
|
return false; |
564
|
|
|
} |
565
|
|
|
|
566
|
|
|
// Load the aspects or services. |
567
|
|
|
if ( is_array( $raw_list = json_decode( $this->_parse_regex( $type, $response->body ) ) ) ) { |
568
|
|
|
// In case this fetch is forced, empty the list. |
569
|
|
|
$list = array(); |
570
|
|
|
|
571
|
|
|
switch ( $type ) { |
572
|
|
|
case 'aspects': |
573
|
|
|
// Add the 'public' aspect, as it's global and not user specific. |
574
|
|
|
$list['public'] = __( 'Public', 'wp-to-diaspora' ); |
575
|
|
|
|
576
|
|
|
// Add all user specific aspects. |
577
|
|
|
foreach ( $raw_list as $aspect ) { |
578
|
|
|
$list[ $aspect->id ] = $aspect->name; |
579
|
|
|
} |
580
|
|
|
break; |
581
|
|
|
case 'services': |
582
|
|
|
foreach ( $raw_list as $service ) { |
583
|
|
|
$list[ $service ] = ucfirst( $service ); |
584
|
|
|
} |
585
|
|
|
break; |
586
|
|
|
} |
587
|
|
|
} |
588
|
|
|
} |
589
|
|
|
return $list; |
590
|
|
|
} |
591
|
|
|
|
592
|
|
|
/** |
593
|
|
|
* Send an http(s) request via WP_HTTP API. |
594
|
|
|
* |
595
|
|
|
* @see WP_Http::request() |
596
|
|
|
* |
597
|
|
|
* @param string $url The URL to request. |
598
|
|
|
* @param array $args Arguments to be posted with the request. |
599
|
|
|
* @return object An object containing details about this request. |
600
|
|
|
*/ |
601
|
|
|
private function _request( $url, $args = array() ) { |
602
|
|
|
// Prefix the full pod URL if necessary. |
603
|
|
|
if ( 0 === strpos( $url, '/' ) ) { |
604
|
|
|
$url = $this->get_pod_url( $url ); |
605
|
|
|
} |
606
|
|
|
|
607
|
|
|
// Disable redirections so we can verify HTTP response codes. |
608
|
|
|
$defaults = array( |
609
|
|
|
'redirection' => 0, |
610
|
|
|
'sslverify' => true, |
611
|
|
|
'timeout' => 60, |
612
|
|
|
'method' => 'GET', |
613
|
|
|
); |
614
|
|
|
|
615
|
|
|
// If the certificate bundle has been downloaded manually, use that instead. |
616
|
|
|
// NOTE: This should actually never be necessary, it's a fallback! |
617
|
|
|
if ( file_exists( WP2D_DIR . '/cacert.pem' ) ) { |
618
|
|
|
$defaults['sslcertificates'] = WP2D_DIR . '/cacert.pem'; |
619
|
|
|
} |
620
|
|
|
|
621
|
|
|
// Set the correct cookie. |
622
|
|
|
if ( ! empty( $this->_cookies ) ) { |
623
|
|
|
$defaults['cookies'] = $this->_cookies; |
624
|
|
|
} |
625
|
|
|
|
626
|
|
|
$args = wp_parse_args( $args, $defaults ); |
627
|
|
|
|
628
|
|
|
// Get the response from the WP_HTTP request. |
629
|
|
|
$response = wp_remote_request( $url, $args ); |
630
|
|
|
|
631
|
|
|
if ( is_wp_error( $response ) ) { |
632
|
|
|
$this->_last_error = $response; |
633
|
|
|
return $response; |
634
|
|
|
} |
635
|
|
|
|
636
|
|
|
// Get the headers and the html response. |
637
|
|
|
$headers = wp_remote_retrieve_headers( $response ); |
638
|
|
|
$body = wp_remote_retrieve_body( $response ); |
639
|
|
|
|
640
|
|
|
// Remember this request. |
641
|
|
|
$this->_last_request = new stdClass(); |
642
|
|
|
$this->_last_request->response = $response; |
643
|
|
|
$this->_last_request->headers = $headers; |
644
|
|
|
$this->_last_request->body = $body; |
645
|
|
|
$this->_last_request->message = wp_remote_retrieve_response_message( $response ); |
646
|
|
|
$this->_last_request->code = wp_remote_retrieve_response_code( $response ); |
647
|
|
|
|
648
|
|
|
// Save the new token. |
649
|
|
|
if ( $token = $this->_parse_regex( 'token', $body ) ) { |
650
|
|
|
$this->_token = $token; |
651
|
|
|
} |
652
|
|
|
|
653
|
|
|
// Save the latest cookies. |
654
|
|
|
if ( isset( $response['cookies'] ) ) { |
655
|
|
|
$this->_cookies = $response['cookies']; |
656
|
|
|
} |
657
|
|
|
|
658
|
|
|
// Return the last request details. |
659
|
|
|
return $this->_last_request; |
660
|
|
|
} |
661
|
|
|
|
662
|
|
|
/** |
663
|
|
|
* Helper method to set the last occurred error. |
664
|
|
|
* |
665
|
|
|
* @see WP_Error::__construct() |
666
|
|
|
* @since 1.6.0 |
667
|
|
|
* |
668
|
|
|
* @param string|int $code Error code. |
669
|
|
|
* @param string $message Error message. |
670
|
|
|
* @param mixed $data Error data. |
671
|
|
|
*/ |
672
|
|
|
private function _error( $code, $message, $data = '' ) { |
673
|
|
|
// Always add the code and message of the last request. |
674
|
|
|
$data = array_merge( array_filter( (array) $data ), array( |
675
|
|
|
'code' => ( isset( $this->_last_request->code ) ) ? $this->_last_request->code : null, |
676
|
|
|
'message' => ( isset( $this->_last_request->message ) ) ? $this->_last_request->message : null, |
677
|
|
|
) ); |
678
|
|
|
$this->_last_error = new WP_Error( $code, $message, $data ); |
679
|
|
|
} |
680
|
|
|
|
681
|
|
|
/** |
682
|
|
|
* Parse the regex and return the found string. |
683
|
|
|
* |
684
|
|
|
* @param string $regex Shorthand of a saved regex or a custom regex. |
685
|
|
|
* @param string $content Text to parse the regex with. |
686
|
|
|
* @return string The found string, or an empty string. |
687
|
|
|
*/ |
688
|
|
|
private function _parse_regex( $regex, $content ) { |
689
|
|
|
// Use a shorthand regex if available. |
690
|
|
|
if ( array_key_exists( $regex, $this->_regexes ) ) { |
691
|
|
|
$regex = $this->_regexes[ $regex ]; |
692
|
|
|
} |
693
|
|
|
|
694
|
|
|
preg_match( $regex, $content, $matches ); |
695
|
|
|
return trim( array_pop( $matches ) ); |
696
|
|
|
} |
697
|
|
|
} |
698
|
|
|
|
The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.
The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.
To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.