1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* This file is part of Peachy MediaWiki Bot API |
5
|
|
|
* |
6
|
|
|
* Peachy is free software: you can redistribute it and/or modify |
7
|
|
|
* it under the terms of the GNU General Public License as published by |
8
|
|
|
* the Free Software Foundation, either version 3 of the License, or |
9
|
|
|
* (at your option) any later version. |
10
|
|
|
* |
11
|
|
|
* This program is distributed in the hope that it will be useful, |
12
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
13
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14
|
|
|
* GNU General Public License for more details. |
15
|
|
|
* |
16
|
|
|
* You should have received a copy of the GNU General Public License |
17
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
18
|
|
|
*/ |
19
|
|
|
|
20
|
|
|
/** |
21
|
|
|
* @file |
22
|
|
|
* Wiki object |
23
|
|
|
*/ |
24
|
|
|
|
25
|
|
|
/** |
26
|
|
|
* Wiki class |
27
|
|
|
* Stores and runs methods that don't fit in User, Page, or Image, etc. |
28
|
|
|
*/ |
29
|
|
|
class Wiki { |
30
|
|
|
|
31
|
|
|
/** |
32
|
|
|
* URL to the API for the wiki. |
33
|
|
|
* |
34
|
|
|
* @var string |
35
|
|
|
* @access protected |
36
|
|
|
*/ |
37
|
|
|
protected $base_url; |
38
|
|
|
|
39
|
|
|
/** |
40
|
|
|
* SSH Object |
41
|
|
|
* |
42
|
|
|
* @var Object |
43
|
|
|
* @access protected |
44
|
|
|
*/ |
45
|
|
|
protected $SSH = false; |
46
|
|
|
|
47
|
|
|
/** |
48
|
|
|
* Username for the user editing the wiki. |
49
|
|
|
* |
50
|
|
|
* @var string |
51
|
|
|
* @access protected |
52
|
|
|
*/ |
53
|
|
|
protected $username; |
54
|
|
|
|
55
|
|
|
/** |
56
|
|
|
* Edit of editing for the wiki in EPM. |
57
|
|
|
* |
58
|
|
|
* @var int |
59
|
|
|
* @access protected |
60
|
|
|
*/ |
61
|
|
|
protected $edit_rate; |
62
|
|
|
|
63
|
|
|
/** |
64
|
|
|
* Maximum db lag that the bot will accept. False to disable. |
65
|
|
|
* |
66
|
|
|
* (default value: false) |
67
|
|
|
* |
68
|
|
|
* @var bool|int |
69
|
|
|
* @access protected |
70
|
|
|
*/ |
71
|
|
|
protected $maxlag = false; |
72
|
|
|
|
73
|
|
|
/** |
74
|
|
|
* Limit of results that can be returned by the API at one time. |
75
|
|
|
* |
76
|
|
|
* (default value: 49) |
77
|
|
|
* |
78
|
|
|
* @var int |
79
|
|
|
* @access protected |
80
|
|
|
*/ |
81
|
|
|
protected $apiQueryLimit = 49; |
82
|
|
|
|
83
|
|
|
/** |
84
|
|
|
* Does the user have to have the bot flag to edit. |
85
|
|
|
* |
86
|
|
|
* (default value: false) |
87
|
|
|
* |
88
|
|
|
* @var bool |
89
|
|
|
* @access protected |
90
|
|
|
*/ |
91
|
|
|
protected $requiresFlag = false; |
92
|
|
|
|
93
|
|
|
/** |
94
|
|
|
* Can the user continue editing logged out. |
95
|
|
|
* |
96
|
|
|
* (default value: false) |
97
|
|
|
* |
98
|
|
|
* @var bool |
99
|
|
|
* @access protected |
100
|
|
|
*/ |
101
|
|
|
protected $allowLoggedOutEditing = false; |
102
|
|
|
|
103
|
|
|
/** |
104
|
|
|
* Does the user have a bot flag. |
105
|
|
|
* |
106
|
|
|
* (default value: false) |
107
|
|
|
* |
108
|
|
|
* @var bool |
109
|
|
|
* @access protected |
110
|
|
|
*/ |
111
|
|
|
protected $isFlagged = false; |
112
|
|
|
|
113
|
|
|
/** |
114
|
|
|
* Array of extenstions on the Wiki in the form of name => version. |
115
|
|
|
* |
116
|
|
|
* @var array |
117
|
|
|
* @access protected |
118
|
|
|
*/ |
119
|
|
|
protected $extensions; |
120
|
|
|
|
121
|
|
|
/** |
122
|
|
|
* Array of tokens for editing. |
123
|
|
|
* |
124
|
|
|
* (default value: array()) |
125
|
|
|
* |
126
|
|
|
* @var array |
127
|
|
|
* @access protected |
128
|
|
|
*/ |
129
|
|
|
protected $tokens = array(); |
130
|
|
|
|
131
|
|
|
/** |
132
|
|
|
* Array of rights assigned to the user. |
133
|
|
|
* |
134
|
|
|
* (default value: array()) |
135
|
|
|
* |
136
|
|
|
* @var array |
137
|
|
|
* @access protected |
138
|
|
|
*/ |
139
|
|
|
protected $userRights = array(); |
140
|
|
|
|
141
|
|
|
/** |
142
|
|
|
* Array of namespaces by ID. |
143
|
|
|
* |
144
|
|
|
* (default value: null) |
145
|
|
|
* |
146
|
|
|
* @var array |
147
|
|
|
* @access protected |
148
|
|
|
*/ |
149
|
|
|
protected $namespaces = null; |
150
|
|
|
|
151
|
|
|
/** |
152
|
|
|
* array of namespaces that have subpages allowed, by namespace id. |
153
|
|
|
* |
154
|
|
|
* (default value: null) |
155
|
|
|
* |
156
|
|
|
* @var array |
157
|
|
|
* @access protected |
158
|
|
|
*/ |
159
|
|
|
protected $allowSubpages = null; |
160
|
|
|
|
161
|
|
|
/** |
162
|
|
|
* Should the wiki follow nobots rules? |
163
|
|
|
* |
164
|
|
|
* (default value: true) |
165
|
|
|
* |
166
|
|
|
* @var bool |
167
|
|
|
* @access protected |
168
|
|
|
*/ |
169
|
|
|
protected $nobots = true; |
170
|
|
|
|
171
|
|
|
/** |
172
|
|
|
* Nobots task name if nobots is enables. Perfect for multiple doing the same task. |
173
|
|
|
* |
174
|
|
|
* (default value: null) |
175
|
|
|
* |
176
|
|
|
* @var string |
177
|
|
|
* @access protected |
178
|
|
|
*/ |
179
|
|
|
protected $nobotsTaskname = null; |
180
|
|
|
|
181
|
|
|
/** |
182
|
|
|
* Text to search for in the optout= field of the {{nobots}} template |
183
|
|
|
* |
184
|
|
|
* (default value: null) |
185
|
|
|
* |
186
|
|
|
* @var null |
187
|
|
|
* @access protected |
188
|
|
|
*/ |
189
|
|
|
protected $optout = null; |
190
|
|
|
|
191
|
|
|
/** |
192
|
|
|
* Whether or not to not edit if the user has new messages |
193
|
|
|
* |
194
|
|
|
* (default value: false) |
195
|
|
|
* |
196
|
|
|
* @var bool |
197
|
|
|
* @access protected |
198
|
|
|
*/ |
199
|
|
|
protected $stoponnewmessages = false; |
200
|
|
|
|
201
|
|
|
/** |
202
|
|
|
* Page title to use for enable page |
203
|
|
|
* |
204
|
|
|
* @var string |
205
|
|
|
* @access protected |
206
|
|
|
*/ |
207
|
|
|
protected $runpage; |
208
|
|
|
|
209
|
|
|
/** |
210
|
|
|
* Configuration (sans password) |
211
|
|
|
* |
212
|
|
|
* @var array |
213
|
|
|
* @access protected |
214
|
|
|
*/ |
215
|
|
|
protected $configuration; |
216
|
|
|
|
217
|
|
|
/** |
218
|
|
|
* HTTP Class |
219
|
|
|
* |
220
|
|
|
* @var HTTP |
221
|
|
|
* @access protected |
222
|
|
|
*/ |
223
|
|
|
protected $http; |
224
|
|
|
|
225
|
|
|
/** |
226
|
|
|
* Whether or not to log in. True restricts logging in, false lets it log in. Setting to true restricts the available functions. |
227
|
|
|
* |
228
|
|
|
* @var bool |
229
|
|
|
* @access protected |
230
|
|
|
*/ |
231
|
|
|
protected $nologin; |
232
|
|
|
|
233
|
|
|
/** |
234
|
|
|
* Server that handled the last API query |
235
|
|
|
* |
236
|
|
|
* @var string |
237
|
|
|
* @access protected |
238
|
|
|
*/ |
239
|
|
|
protected $servedby; |
240
|
|
|
|
241
|
|
|
/** |
242
|
|
|
* Generator values for the generator parameter |
243
|
|
|
* |
244
|
|
|
* @var array |
245
|
|
|
* @access protected |
246
|
|
|
*/ |
247
|
|
|
protected $generatorvalues; |
248
|
|
|
|
249
|
|
|
/** |
250
|
|
|
* Version of MediaWiki server is running. |
251
|
|
|
* The only reason this is public is so the Peachy class can set it. It should not be changed again. |
252
|
|
|
* |
253
|
|
|
* @var string |
254
|
|
|
* @access public |
255
|
|
|
*/ |
256
|
|
|
public $mwversion; |
257
|
|
|
|
258
|
|
|
/** |
259
|
|
|
* Caches configuration information for logging back in with identical settings. |
260
|
|
|
* |
261
|
|
|
* @var array |
262
|
|
|
* @access protected |
263
|
|
|
*/ |
264
|
|
|
protected $cached_config; |
265
|
|
|
|
266
|
|
|
/** |
267
|
|
|
* If bot running with OAuth or not. |
268
|
|
|
* |
269
|
|
|
* @var array |
270
|
|
|
* @access protected |
271
|
|
|
*/ |
272
|
|
|
protected $oauthEnabled = false; |
273
|
|
|
|
274
|
|
|
/** |
275
|
|
|
* OAuth Consumer Key. |
276
|
|
|
* |
277
|
|
|
* @var array |
278
|
|
|
* @access protected |
279
|
|
|
*/ |
280
|
|
|
protected $consumerKey = ""; |
281
|
|
|
|
282
|
|
|
/** |
283
|
|
|
* Key secret to establish owner verification. |
284
|
|
|
* |
285
|
|
|
* @var array |
286
|
|
|
* @access protected |
287
|
|
|
*/ |
288
|
|
|
protected $consumerSecret = ""; |
289
|
|
|
|
290
|
|
|
/** |
291
|
|
|
* OAuth Access token to request access. |
292
|
|
|
* |
293
|
|
|
* @var array |
294
|
|
|
* @access protected |
295
|
|
|
*/ |
296
|
|
|
protected $accessToken = ""; |
297
|
|
|
|
298
|
|
|
/** |
299
|
|
|
* Token Secret for Authorization. |
300
|
|
|
* |
301
|
|
|
* @var array |
302
|
|
|
* @access protected |
303
|
|
|
*/ |
304
|
|
|
protected $accessTokenSecret = ""; |
305
|
|
|
|
306
|
|
|
/** |
307
|
|
|
* Construct function for the wiki. Handles login and related functions. |
308
|
|
|
* |
309
|
|
|
* @access public |
310
|
|
|
* @see Peachy::newWiki() |
311
|
|
|
* @param array $configuration Array with configuration data. At least needs username, password, and base_url. |
312
|
|
|
* @param array $extensions Array of names of extensions installed on the wiki and their versions (default: array()) |
313
|
|
|
* @param int $recursed Is the function recursing itself? Used internally, don't use (default: 0) |
314
|
|
|
* @param mixed $token Token if the wiki needs a token. Used internally, don't use (default: null) |
315
|
|
|
* @throws LoginError |
316
|
|
|
*/ |
317
|
|
|
public function __construct( $configuration, $extensions = array(), $recursed = 0, $token = null ) { |
318
|
|
|
global $pgProxy, $pgVerbose, $pgUseSSH, $pgHost, $pgPort, $pgUsername, $pgPrikey, $pgPassphrase, $pgProtocol, $pgTimeout; |
319
|
|
|
|
320
|
|
|
$this->cached_config['config'] = $configuration; |
321
|
|
|
$this->cached_config['extensions'] = $extensions; |
322
|
|
|
|
323
|
|
|
if( !array_key_exists( 'encodedparams', $configuration ) ) { |
324
|
|
|
$configuration['encodedparams'] = rawurlencode( serialize( $configuration ) ); |
325
|
|
|
} |
326
|
|
|
|
327
|
|
|
$this->base_url = $configuration['baseurl']; |
328
|
|
|
$this->username = $configuration['username']; |
329
|
|
|
$this->extensions = $extensions; |
330
|
|
|
$this->generatorvalues = array( |
331
|
|
|
'allcategories', 'allimages', 'alllinks', 'allpages', 'alltransclusions', 'backlinks', 'categories', |
332
|
|
|
'categorymembers', 'duplicatefiles', 'embeddedin', 'exturlusage', 'geosearch', 'images', 'imageusage', |
333
|
|
|
'iwbacklinks', 'langbacklinks', 'links', 'oldreviewedpages', 'protectedtitles', 'querypage', 'random', |
334
|
|
|
'recentchanges', 'search', 'templates', 'watchlist', 'watchlistraw' |
335
|
|
|
); |
336
|
|
|
|
337
|
|
|
if( isset( $configuration['editwhileloggedout'] ) ) $this->allowLoggedOutEditing = true; |
338
|
|
|
if( isset( $configuration['requirebotflag'] ) ) $this->requiresFlag = true; |
339
|
|
|
if( isset( $configuration['editsperminute'] ) && $configuration['editsperminute'] != 0 ) { |
340
|
|
|
$this->edit_rate = $configuration['editsperminute']; |
341
|
|
|
} |
342
|
|
|
|
343
|
|
|
if( isset( $configuration['proxyaddr'] ) ) { |
344
|
|
|
$pgProxy['addr'] = $configuration['proxyaddr']; |
345
|
|
|
|
346
|
|
|
if( isset( $configuration['proxytype'] ) ) { |
347
|
|
|
$pgProxy['type'] = $configuration['proxytype']; |
348
|
|
|
} |
349
|
|
|
|
350
|
|
|
if( isset( $configuration['proxyport'] ) ) { |
351
|
|
|
$pgProxy['port'] = $configuration['proxyport']; |
352
|
|
|
} |
353
|
|
|
|
354
|
|
|
if( isset( $configuration['proxyuser'] ) && isset( $configuration['proxypass'] ) ) { |
355
|
|
|
$pgProxy['userpass'] = $configuration['proxyuser'] . ':' . $configuration['proxypass']; |
356
|
|
|
} |
357
|
|
|
} |
358
|
|
|
|
359
|
|
|
$http_echo = ( isset( $configuration['httpecho'] ) && $configuration['httpecho'] === "true" ); |
360
|
|
|
if( is_null( $this->http ) ) $this->http = HTTP::getDefaultInstance( $http_echo ); |
361
|
|
|
|
362
|
|
|
if( $pgUseSSH ) { |
363
|
|
|
if( !$this->SSH ) $this->SSH = new SSH( $pgHost, $pgPort, $pgUsername, $pgPassphrase, $pgPrikey, $pgProtocol, $pgTimeout, $this->http ); |
364
|
|
|
if( !$this->SSH->connected ) $this->SSH = null; |
365
|
|
|
} else $this->SSH = null; |
366
|
|
|
|
367
|
|
|
if( isset( $configuration['runpage'] ) ) { |
368
|
|
|
$this->runpage = $configuration['runpage']; |
369
|
|
|
} |
370
|
|
|
|
371
|
|
|
if( isset( $configuration['useragent'] ) ) { |
372
|
|
|
$this->http->setUserAgent( $configuration['useragent'] ); |
373
|
|
|
} |
374
|
|
|
|
375
|
|
|
if( isset( $configuration['optout'] ) ) { |
376
|
|
|
$this->optout = $configuration['optout']; |
377
|
|
|
} |
378
|
|
|
|
379
|
|
|
if( isset( $configuration['stoponnewmessages'] ) ) { |
380
|
|
|
$this->stoponnewmessages = true; |
381
|
|
|
} |
382
|
|
|
|
383
|
|
|
if( isset( $configuration['verbose'] ) ) { |
384
|
|
|
$pgVerbose = array(); |
385
|
|
|
|
386
|
|
|
$tmp = explode( '|', $configuration['verbose'] ); |
387
|
|
|
|
388
|
|
|
foreach( $tmp as $setting ){ |
389
|
|
|
if( $setting == "ALL" ) { |
390
|
|
|
$pgVerbose = array( |
391
|
|
|
PECHO_NORMAL, |
392
|
|
|
PECHO_NOTICE, |
393
|
|
|
PECHO_WARN, |
394
|
|
|
PECHO_ERROR, |
395
|
|
|
PECHO_FATAL |
396
|
|
|
); |
397
|
|
|
break; |
398
|
|
|
} else { |
399
|
|
|
switch( $setting ){ |
400
|
|
|
case 'NORMAL': |
401
|
|
|
$pgVerbose[] = PECHO_NORMAL; |
402
|
|
|
break; |
403
|
|
|
case 'NOTICE': |
404
|
|
|
$pgVerbose[] = PECHO_NOTICE; |
405
|
|
|
break; |
406
|
|
|
case 'WARN': |
407
|
|
|
$pgVerbose[] = PECHO_WARN; |
408
|
|
|
break; |
409
|
|
|
case 'ERROR': |
410
|
|
|
$pgVerbose[] = PECHO_ERROR; |
411
|
|
|
break; |
412
|
|
|
case 'FATAL': |
413
|
|
|
$pgVerbose[] = PECHO_FATAL; |
414
|
|
|
break; |
415
|
|
|
case 'VERBOSE': |
416
|
|
|
$pgVerbose[] = PECHO_VERBOSE; |
417
|
|
|
break; |
418
|
|
|
} |
419
|
|
|
} |
420
|
|
|
} |
421
|
|
|
|
422
|
|
|
unset( $tmp ); |
423
|
|
|
} |
424
|
|
|
|
425
|
|
|
if( ( isset( $configuration['nobots'] ) && $configuration['nobots'] == 'false' ) || strpos( $configuration['baseurl'], '//en.wikipedia.org/w/api.php' ) === false ) { |
426
|
|
|
$this->nobots = false; |
427
|
|
|
} |
428
|
|
|
if( isset( $configuration['method'] ) && $configuration['method'] == 'legacy' ) { |
429
|
|
|
$lgarray = array( |
430
|
|
|
'lgname' => $this->username, |
431
|
|
|
'action' => 'login', |
432
|
|
|
); |
433
|
|
|
|
434
|
|
|
// Password may not be set (for example, where nologin is being used) |
435
|
|
|
if( isset( $configuration['password'] ) ) { |
436
|
|
|
$lgarray['lgpassword'] = $configuration['password']; |
437
|
|
|
} |
438
|
|
|
|
439
|
|
|
if( !is_null( $token ) ) { |
440
|
|
|
$lgarray['lgtoken'] = $token; |
441
|
|
|
} |
442
|
|
|
} else { |
443
|
|
|
if( !isset( $extensions['OAuth'] ) ) throw new DependencyError( "OAuth", "https://www.mediawiki.org/wiki/Extension:OAuth or try setting \'method = \"legacy\"\' in the cfg file." ); |
444
|
|
|
if( !isset( $configuration['consumerkey'] ) ) throw new LoginError( array( "Missing consumer key", "set consumerkey in cfg file" ) ); |
445
|
|
|
if( !isset( $configuration['consumersecret'] ) ) throw new LoginError( array( "Missing consumer secret", "set consumersecret in cfg file" ) ); |
446
|
|
|
if( !isset( $configuration['accesstoken'] ) ) throw new LoginError( array( "Missing access token", "set accesstoken in cfg file" ) ); |
447
|
|
|
if( !isset( $configuration['accesssecret'] ) ) throw new LoginError( array( "Missing access token secret", "set accesssecret in cfg file" ) ); |
448
|
|
|
if( !isset( $configuration['oauthurl'] ) ) throw new LoginError( array( "Missing OAuth URL", "set oauthurl in cfg file" ) ); |
449
|
|
|
$this->oauthEnabled = true; |
450
|
|
|
$this->consumerKey = $configuration['consumerkey']; |
451
|
|
|
$this->consumerSecret = $configuration['consumersecret']; |
452
|
|
|
$this->accessToken = $configuration['accesstoken']; |
453
|
|
|
$this->accessTokenSecret = $configuration['accesssecret']; |
454
|
|
|
$this->oauth_url = $configuration['oauthurl']; |
455
|
|
|
} |
456
|
|
|
|
457
|
|
|
if( isset( $configuration['maxlag'] ) && $configuration['maxlag'] != "0" ) { |
458
|
|
|
$this->maxlag = $configuration['maxlag']; |
459
|
|
|
$lgarray['maxlag'] = $this->maxlag; |
460
|
|
|
} |
461
|
|
|
|
462
|
|
|
// FIXME: Why is there a return in a constructor? Should an error be thrown? |
463
|
|
|
if( isset( $configuration['nologin'] ) ) { |
464
|
|
|
$this->nologin = true; |
465
|
|
|
return; |
466
|
|
|
} |
467
|
|
|
|
468
|
|
|
$use_cookie_login = false; |
469
|
|
|
if( isset( $configuration['cookiejar'] ) ) { |
470
|
|
|
$this->http->setCookieJar( $configuration['cookiejar'] ); |
471
|
|
|
} else { |
472
|
|
|
|
473
|
|
|
$this->http->setCookieJar( sys_get_temp_dir() . '/PeachyCookieSite' . sha1( $configuration['encodedparams'] ) ); |
474
|
|
|
|
475
|
|
|
if( $this->is_logged_in() ) $use_cookie_login = true; |
476
|
|
|
} |
477
|
|
|
|
478
|
|
|
if( $use_cookie_login ) { |
479
|
|
|
pecho( "Logging in to {$this->base_url} as {$this->username}, using a saved login cookie\n\n", PECHO_NORMAL ); |
480
|
|
|
|
481
|
|
|
$this->runSuccess( $configuration ); |
482
|
|
|
} elseif( !$this->nologin ) { |
483
|
|
|
Hooks::runHook( 'PreLogin', array( &$lgarray ) ); |
484
|
|
|
|
485
|
|
|
if( !$recursed ) { |
486
|
|
|
pecho( "Logging in to {$this->base_url}...\n\n", PECHO_NOTICE ); |
487
|
|
|
} |
488
|
|
|
|
489
|
|
|
if( isset( $configuration['method'] ) && $configuration['method'] == 'legacy' ) $loginRes = $this->apiQuery( $lgarray, true, true, false, false ); |
490
|
|
|
else { |
491
|
|
|
$loginRes = $this->apiQuery( array(), false, true, false, false, $this->oauth_url."/identify" ); |
492
|
|
|
if ( !$loginRes ) { |
493
|
|
|
throw new LoginError( ( array( 'BadData', 'The server returned unparsable data' ) ) ); |
494
|
|
|
} |
495
|
|
|
$err = json_decode( $loginRes ); |
496
|
|
|
if ( is_object( $err ) && isset( $err->error ) && $err->error === 'mwoauthdatastore-access-token-not-found' ) { |
497
|
|
|
// We're not authorized! |
498
|
|
|
throw new LoginError( ( array( 'AuthFailure', 'Missing authorization or authorization failed' ) ) ); |
499
|
|
|
} |
500
|
|
|
|
501
|
|
|
// There are three fields in the response |
502
|
|
|
$fields = explode( '.', $loginRes ); |
503
|
|
|
if ( count( $fields ) !== 3 ) { |
504
|
|
|
throw new LoginError( ( array( 'BadResponse', 'Invalid identify response: ' . htmlspecialchars( $loginRes ) ) ) ); |
505
|
|
|
} |
506
|
|
|
|
507
|
|
|
// Validate the header. MWOAuth always returns alg "HS256". |
508
|
|
|
$header = base64_decode( strtr( $fields[0], '-_', '+/' ), true ); |
509
|
|
|
if ( $header !== false ) { |
510
|
|
|
$header = json_decode( $header ); |
511
|
|
|
} |
512
|
|
|
if ( !is_object( $header ) || $header->typ !== 'JWT' || $header->alg !== 'HS256' ) { |
513
|
|
|
throw new LoginError( ( array( 'BadHeader', 'Invalid header in identify response: ' . htmlspecialchars( $loginRes ) ) ) ); |
514
|
|
|
} |
515
|
|
|
|
516
|
|
|
// Verify the signature |
517
|
|
|
$sig = base64_decode( strtr( $fields[2], '-_', '+/' ), true ); |
518
|
|
|
$check = hash_hmac( 'sha256', $fields[0] . '.' . $fields[1], $this->consumerSecret, true ); |
519
|
|
|
if ( $sig !== $check ) { |
520
|
|
|
throw new LoginError( ( array( 'BadSignature', 'JWT signature validation failed: ' . htmlspecialchars( $loginRes ) ) ) ); |
521
|
|
|
} |
522
|
|
|
|
523
|
|
|
// Decode the payload |
524
|
|
|
$payload = base64_decode( strtr( $fields[1], '-_', '+/' ), true ); |
525
|
|
|
if ( $payload !== false ) { |
526
|
|
|
$payload = json_decode( $payload ); |
527
|
|
|
} |
528
|
|
|
if ( !is_object( $payload ) ) { |
529
|
|
|
throw new LoginError( ( array( 'BadPayload', 'Invalid payload in identify response: ' . htmlspecialchars( $loginRes ) ) ) ); |
530
|
|
|
} |
531
|
|
|
|
532
|
|
|
pecho( "Successfully logged in to {$this->base_url} as {$payload->username}\n\n", PECHO_NORMAL ); |
533
|
|
|
|
534
|
|
|
$this->runSuccess( $configuration ); |
535
|
|
|
} |
536
|
|
|
|
537
|
|
|
Hooks::runHook( 'PostLogin', array( &$loginRes ) ); |
538
|
|
|
} |
539
|
|
|
|
540
|
|
|
if( !$this->oauthEnabled && isset( $loginRes['login']['result'] ) ) { |
541
|
|
|
switch( $loginRes['login']['result'] ){ |
542
|
|
|
case 'NoName': |
543
|
|
|
throw new LoginError( array( 'NoName', 'Username not specified' ) ); |
544
|
|
|
case 'Illegal': |
545
|
|
|
throw new LoginError( array( 'Illegal', 'Username with illegal characters specified' ) ); |
546
|
|
|
case 'NotExists': |
547
|
|
|
throw new LoginError( array( 'NotExists', 'Username specified does not exist' ) ); |
548
|
|
|
case 'EmptyPass': |
549
|
|
|
throw new LoginError( array( 'EmptyPass', 'Password not specified' ) ); |
550
|
|
|
case 'WrongPass': |
551
|
|
|
throw new LoginError( array( 'WrongPass', 'Incorrect password specified' ) ); |
552
|
|
|
case 'WrongPluginPass': |
553
|
|
|
throw new LoginError( array( 'WrongPluginPass', 'Incorrect password specified' ) ); |
554
|
|
|
case 'CreateBlocked': |
555
|
|
|
throw new LoginError( array( 'CreateBlocked', 'IP address has been blocked' ) ); |
556
|
|
|
case 'Throttled': |
557
|
|
|
if( $recursed > 2 ) { |
558
|
|
|
throw new LoginError( array( |
559
|
|
|
'Throttled', 'Login attempts have been throttled' |
560
|
|
|
) ); |
561
|
|
|
} |
562
|
|
|
|
563
|
|
|
$wait = $loginRes['login']['wait']; |
564
|
|
|
pecho( "Login throttled, waiting $wait seconds.\n\n", PECHO_NOTICE ); |
565
|
|
|
sleep( $wait ); |
566
|
|
|
|
567
|
|
|
$recres = $this->__construct( $configuration, $this->extensions, $recursed + 1 ); |
568
|
|
|
return $recres; |
569
|
|
|
case 'Blocked': |
570
|
|
|
throw new LoginError( array( 'Blocked', 'User specified has been blocked' ) ); |
571
|
|
|
case 'NeedToken': |
572
|
|
|
if( $recursed > 2 ) throw new LoginError( array( 'NeedToken', 'Token was not specified' ) ); |
573
|
|
|
|
574
|
|
|
$token = $loginRes['login']['token']; |
575
|
|
|
|
576
|
|
|
$recres = $this->__construct( $configuration, $this->extensions, $recursed + 1, $token ); |
577
|
|
|
return $recres; |
578
|
|
|
case 'Success': |
579
|
|
|
pecho( "Successfully logged in to {$this->base_url} as {$this->username}\n\n", PECHO_NORMAL ); |
580
|
|
|
|
581
|
|
|
$this->runSuccess( $configuration ); |
582
|
|
|
} |
583
|
|
|
} |
584
|
|
|
} |
585
|
|
|
|
586
|
|
|
public function is_logged_in() { |
587
|
|
|
$cookieInfo = $this->apiQuery( array( 'action' => 'query', 'meta' => 'userinfo' ) ); |
588
|
|
|
if( $cookieInfo['query']['userinfo']['id'] != 0 ) return true; |
589
|
|
|
return false; |
590
|
|
|
} |
591
|
|
|
|
592
|
|
|
|
593
|
|
|
/** |
594
|
|
|
* runSuccess function. |
595
|
|
|
* |
596
|
|
|
* @access protected |
597
|
|
|
* @param mixed &$configuration |
598
|
|
|
* @return void |
599
|
|
|
*/ |
600
|
|
|
protected function runSuccess( &$configuration ) { |
601
|
|
|
$userInfoRes = $this->apiQuery( |
602
|
|
|
array( |
603
|
|
|
'action' => 'query', |
604
|
|
|
'meta' => 'userinfo', |
605
|
|
|
'uiprop' => 'blockinfo|rights|groups' |
606
|
|
|
) |
607
|
|
|
); |
608
|
|
|
|
609
|
|
|
if( in_array( 'apihighlimits', $userInfoRes['query']['userinfo']['rights'] ) ) { |
610
|
|
|
$this->apiQueryLimit = 4999; |
611
|
|
|
} else { |
612
|
|
|
$this->apiQueryLimit = 499; |
613
|
|
|
} |
614
|
|
|
|
615
|
|
|
$this->userRights = $userInfoRes['query']['userinfo']['rights']; |
616
|
|
|
|
617
|
|
|
if( in_array( 'bot', $userInfoRes['query']['userinfo']['groups'] ) ) { |
618
|
|
|
$this->isFlagged = true; |
619
|
|
|
} |
620
|
|
|
|
621
|
|
|
$this->get_tokens(); |
622
|
|
|
|
623
|
|
|
$this->configuration = $configuration; |
624
|
|
|
unset( $this->configuration['password'] ); |
625
|
|
|
} |
626
|
|
|
|
627
|
|
|
/** |
628
|
|
|
* Logs the user out of the wiki. |
629
|
|
|
* |
630
|
|
|
* @access public |
631
|
|
|
* @return void |
632
|
|
|
*/ |
633
|
|
|
public function logout() { |
634
|
|
|
pecho( "Logging out of {$this->base_url}...\n\n", PECHO_NOTICE ); |
635
|
|
|
|
636
|
|
|
$this->apiQuery( array( 'action' => 'logout' ), true ); |
637
|
|
|
|
638
|
|
|
} |
639
|
|
|
|
640
|
|
|
/** |
641
|
|
|
* Sets a specific runpage for a script. |
642
|
|
|
* |
643
|
|
|
* @param string $page Page to set as the runpage. Default null. |
644
|
|
|
* @access public |
645
|
|
|
* @return void |
646
|
|
|
*/ |
647
|
|
|
public function set_runpage( $page = null ) { |
648
|
|
|
$this->runpage = $page; |
649
|
|
|
} |
650
|
|
|
|
651
|
|
|
/** |
652
|
|
|
* Sets a specific taskname to comply with the nobots template. |
653
|
|
|
* |
654
|
|
|
* @param string $taskname Name of bot task. Default null. |
655
|
|
|
* |
656
|
|
|
* @access public |
657
|
|
|
* @return void |
658
|
|
|
*/ |
659
|
|
|
public function set_taskname( $taskname = null ) { |
660
|
|
|
$this->nobotsTaskname = $taskname; |
661
|
|
|
} |
662
|
|
|
|
663
|
|
|
private function generateSignature( $method, $url, $params = array() ) { |
664
|
|
|
|
665
|
|
|
$parts = parse_url( $url ); |
666
|
|
|
|
667
|
|
|
// We need to normalize the endpoint URL |
668
|
|
|
$scheme = isset( $parts['scheme'] ) ? $parts['scheme'] : 'http'; |
669
|
|
|
$host = isset( $parts['host'] ) ? $parts['host'] : ''; |
670
|
|
|
$port = isset( $parts['port'] ) ? $parts['port'] : ( $scheme == 'https' ? '443' : '80' ); |
671
|
|
|
$path = isset( $parts['path'] ) ? $parts['path'] : ''; |
672
|
|
|
if ( ( $scheme == 'https' && $port != '443' ) || ( $scheme == 'http' && $port != '80' ) ) { |
673
|
|
|
// Only include the port if it's not the default |
674
|
|
|
$host = "$host:$port"; |
675
|
|
|
} |
676
|
|
|
|
677
|
|
|
// Also the parameters |
678
|
|
|
$pairs = array(); |
679
|
|
|
parse_str( isset( $parts['query'] ) ? $parts['query'] : '', $query ); |
680
|
|
|
$query += $params; |
681
|
|
|
unset( $query['oauth_signature'] ); |
682
|
|
|
if ( $query ) { |
683
|
|
|
$query = array_combine( |
684
|
|
|
// rawurlencode follows RFC 3986 since PHP 5.3 |
685
|
|
|
array_map( 'rawurlencode', array_keys( $query ) ), |
686
|
|
|
array_map( 'rawurlencode', array_values( $query ) ) |
687
|
|
|
); |
688
|
|
|
ksort( $query, SORT_STRING ); |
689
|
|
|
foreach ( $query as $k => $v ) { |
690
|
|
|
$pairs[] = "$k=$v"; |
691
|
|
|
} |
692
|
|
|
} |
693
|
|
|
|
694
|
|
|
$toSign = rawurlencode( strtoupper( $method ) ) . |
695
|
|
|
'&' . |
696
|
|
|
rawurlencode( "$scheme://$host$path" ) . |
697
|
|
|
'&' . |
698
|
|
|
rawurlencode( join( '&', $pairs ) ); |
699
|
|
|
$key = rawurlencode( $this->consumerSecret ) . |
700
|
|
|
'&' . |
701
|
|
|
rawurlencode( $this->accessTokenSecret ); |
702
|
|
|
|
703
|
|
|
return base64_encode( hash_hmac( 'sha1', $toSign, $key, true ) ); |
704
|
|
|
} |
705
|
|
|
|
706
|
|
|
/** |
707
|
|
|
* Queries the API. |
708
|
|
|
* |
709
|
|
|
* @access public |
710
|
|
|
* @param array $arrayParams Parameters given to query with (default: array()) |
711
|
|
|
* @param bool $post Should it be a POST request? (default: false) |
712
|
|
|
* @param bool $errorcheck |
713
|
|
|
* @param bool $recursed Is this a recursed request (default: false) |
714
|
|
|
* @param bool $assertcheck Use MediaWiki's assert feature to prevent unwanted edits (default: true) |
715
|
|
|
* @throws LoggedOut |
716
|
|
|
* @throws AssertFailure (see $assertcheck) |
717
|
|
|
* @throws MWAPIError (API unavailable) |
718
|
|
|
* @return array|bool Returns an array with the API result |
719
|
|
|
*/ |
720
|
|
|
public function apiQuery( $arrayParams = array(), $post = false, $errorcheck = true, $recursed = false, $assertcheck = true, $talktoOauth = false ) { |
721
|
|
|
|
722
|
|
|
global $pgIP, $pgMaxAttempts, $pgThrowExceptions, $pgDisplayGetOutData, $pgLogSuccessfulCommunicationData, $pgLogFailedCommunicationData, $pgLogGetCommunicationData, $pgLogPostCommunicationData, $pgLogCommunicationData; |
723
|
|
|
$requestid = mt_rand(); |
724
|
|
|
$header = ""; |
725
|
|
|
if( $talktoOauth === false ) { |
726
|
|
|
$arrayParams['format'] = 'php'; |
727
|
|
|
$arrayParams['servedby'] = ''; |
728
|
|
|
$arrayParams['requestid'] = $requestid; |
729
|
|
|
$assert = false; |
730
|
|
|
} |
731
|
|
|
$attempts = $pgMaxAttempts; |
732
|
|
|
|
733
|
|
|
if( !file_exists( $pgIP . 'Includes/Communication_Logs' ) ) mkdir( $pgIP . 'Includes/Communication_Logs', 02775 ); |
734
|
|
|
if( $post && $this->requiresFlag && $assertcheck ) { |
735
|
|
|
$arrayParams['assert'] = 'bot'; |
736
|
|
|
$assert = true; |
737
|
|
|
Hooks::runHook( 'QueryAssert', array( &$arrayParams['assert'], &$assert ) ); |
738
|
|
|
} elseif( $post && !$this->allowLoggedOutEditing && $assertcheck ) { |
739
|
|
|
$arrayParams['assert'] = 'user'; |
740
|
|
|
$assert = true; |
741
|
|
|
Hooks::runHook( 'QueryAssert', array( &$arrayParams['assert'], &$assert ) ); |
742
|
|
|
} elseif( isset( $arrayParams['assert'] ) ) unset( $arrayParams['assert'] ); |
743
|
|
|
|
744
|
|
|
pecho( "Running API query with params " . implode( ";", $arrayParams ) . "...\n\n", PECHO_VERBOSE ); |
745
|
|
|
|
746
|
|
|
if( $post ) { |
747
|
|
|
$is_loggedin = $this->get_nologin(); |
748
|
|
|
Hooks::runHook( 'APIQueryCheckLogin', array( &$is_loggedin ) ); |
749
|
|
|
if( $is_loggedin && $errorcheck ) throw new LoggedOut(); |
750
|
|
|
|
751
|
|
|
Hooks::runHook( 'PreAPIPostQuery', array( &$arrayParams ) ); |
752
|
|
|
for( $i = 0; $i < $attempts; $i++ ){ |
753
|
|
|
if( $this->oauthEnabled ) { |
|
|
|
|
754
|
|
|
$headerArr = array( |
755
|
|
|
// OAuth information |
756
|
|
|
'oauth_consumer_key' => $this->consumerKey, |
757
|
|
|
'oauth_token' => $this->accessToken, |
758
|
|
|
'oauth_version' => '1.0', |
759
|
|
|
'oauth_nonce' => md5( microtime() . mt_rand() ), |
760
|
|
|
'oauth_timestamp' => time(), |
761
|
|
|
|
762
|
|
|
// We're using secret key signatures here. |
763
|
|
|
'oauth_signature_method' => 'HMAC-SHA1', |
764
|
|
|
); |
765
|
|
|
$signature = $this->generateSignature( |
766
|
|
|
'POST', |
767
|
|
|
( $talktoOauth ? $talktoOauth : $this->base_url ), |
768
|
|
|
$headerArr |
769
|
|
|
); |
770
|
|
|
$headerArr['oauth_signature'] = $signature; |
771
|
|
|
|
772
|
|
|
$header = array(); |
773
|
|
|
foreach ( $headerArr as $k => $v ) { |
774
|
|
|
$header[] = rawurlencode( $k ) . '="' . rawurlencode( $v ) . '"'; |
775
|
|
|
} |
776
|
|
|
$header = 'Authorization: OAuth ' . join( ', ', $header ); |
777
|
|
|
unset( $headerArr ); |
778
|
|
|
} |
779
|
|
|
$logdata = "Date/Time: " . date( 'r' ) . "\nMethod: POST\nURL: {$this->base_url} (Parameters masked for security)\nRaw Data: "; |
780
|
|
|
$data = $this->get_http()->post( |
781
|
|
|
( $talktoOauth ? $talktoOauth : $this->base_url ), |
782
|
|
|
$arrayParams, |
783
|
|
|
$header |
784
|
|
|
); |
785
|
|
|
if( $talktoOauth !== false && $data !== false ) return $data; |
786
|
|
|
$logdata .= $data; |
787
|
|
|
$data2 = ( $data === false || is_null( $data ) ? false : unserialize( $data ) ); |
788
|
|
|
if( $data2 === false && serialize( $data2 ) != $data ) { |
789
|
|
|
$logdata .= "\nUNSERIALIZATION FAILED\n\n"; |
790
|
|
|
if( $pgLogFailedCommunicationData ) file_put_contents( $pgIP . 'Includes/Communication_Logs/Faileddata.log', $logdata, FILE_APPEND ); |
791
|
|
|
} else { |
792
|
|
|
$logdata .= "\nUNSERIALIZATION SUCCEEDED\n\n"; |
793
|
|
|
if( $pgLogSuccessfulCommunicationData ) file_put_contents( $pgIP . 'Includes/Communication_Logs/Succeededdata.log', $logdata, FILE_APPEND ); |
794
|
|
|
} |
795
|
|
|
|
796
|
|
|
if( $pgLogPostCommunicationData ) file_put_contents( $pgIP . 'Includes/Communication_Logs/Postdata.log', $logdata, FILE_APPEND ); |
797
|
|
|
if( $pgLogCommunicationData ) file_put_contents( $pgIP . 'Includes/Communication_Logs/Querydata.log', $logdata, FILE_APPEND ); |
798
|
|
|
|
799
|
|
|
$data = $data2; |
800
|
|
|
unset( $data2 ); |
801
|
|
|
if( isset( $data['error'] ) && $data['error']['code'] == 'badtoken' ) { |
802
|
|
|
pecho( "API Error...\n\nBadtoken detected retrying with new tokens...\n\n", PECHO_WARN ); |
803
|
|
|
$tokens = $this->get_tokens( true ); |
804
|
|
|
$arrayParams['token'] = $tokens[$arrayParams['action']]; |
805
|
|
|
continue; |
806
|
|
|
} |
807
|
|
|
if( $this->get_http()->get_HTTP_code() == 503 && $errorcheck ) { |
808
|
|
|
pecho( "API Error...\n\nCode: error503\nText: HTTP Error 503\nThe webserver's service is currently unavailable", PECHO_WARN ); |
809
|
|
|
$tempSetting = $pgDisplayGetOutData; |
810
|
|
|
$pgDisplayGetOutData = false; |
811
|
|
|
$histemp = $this->initPage( $arrayParams['title'] )->history( 1 ); |
812
|
|
|
if( $arrayParams['action'] == 'edit' && $histemp[0]['user'] == $this->get_username() && $histemp[0]['comment'] == $arrayParams['summary'] && strtotime( $histemp[0]['timestamp'] ) - time() < 120 ) { |
813
|
|
|
pecho( ", however, the edit appears to have gone through.\n\n", PECHO_WARN ); |
814
|
|
|
$pgDisplayGetOutData = $tempSetting; |
815
|
|
|
unset( $tempSetting ); |
816
|
|
|
return array( 'edit' => array( 'result' => 'Success', 'newrevid' => $histemp[0]['revid'] ) ); |
817
|
|
|
} else { |
818
|
|
|
pecho( ", retrying...\n\n", PECHO_WARN ); |
819
|
|
|
$pgDisplayGetOutData = $tempSetting; |
820
|
|
|
unset( $tempSetting ); |
821
|
|
|
continue; |
822
|
|
|
} |
823
|
|
|
} |
824
|
|
|
|
825
|
|
|
Hooks::runHook( 'APIQueryCheckAssertion', array( &$assert, &$data['edit']['assert'] ) ); |
826
|
|
|
if( isset( $data['error'] ) && isset( $data['error']['code'] ) && $assert && $errorcheck ) { |
827
|
|
|
if( $data['error']['code'] == 'assertbotfailed' && $pgThrowExceptions ) { |
828
|
|
|
throw new AssertFailure( 'bot' ); |
829
|
|
|
} |
830
|
|
|
if( $data['error']['code'] == 'assertuserfailed' && $pgThrowExceptions ) { |
831
|
|
|
throw new AssertFailure( 'user' ); |
832
|
|
|
} |
833
|
|
|
if( $data['error']['code'] == 'assertbotfailed' && !$pgThrowExceptions ) { |
834
|
|
|
if( $this->is_logged_in() ) { |
835
|
|
|
pecho( "Assertion Failure: This user does not have the bot flag. Waiting for bot flag...\n\n", PECHO_FATAL ); |
836
|
|
|
$this->isFlagged = false; |
837
|
|
|
return false; |
838
|
|
|
} else { |
839
|
|
|
$data['error']['code'] = 'assertuserfailed'; //If we are logged out, log back in. |
840
|
|
|
} |
841
|
|
|
} |
842
|
|
|
if( $data['error']['code'] == 'assertuserfailed' && !$pgThrowExceptions ) { |
843
|
|
|
pecho( "Assertion Failure: This user has logged out. Logging back in...\n\n", PECHO_FATAL ); |
844
|
|
|
$this->logout(); |
845
|
|
|
$this->__construct( $this->cached_config['config'], $this->cached_config['extensions'], 0, null ); |
846
|
|
|
$this->get_tokens( true ); |
847
|
|
|
} |
848
|
|
|
} |
849
|
|
|
if( !isset( $data['servedby'] ) && !isset( $data['requestid'] ) ) { |
850
|
|
|
pecho( "Warning: API is not responding, retrying...\n\n", PECHO_WARN ); |
851
|
|
|
} else break; |
852
|
|
|
} |
853
|
|
|
if( $this->get_http()->get_HTTP_code() == 503 && $errorcheck ) { |
854
|
|
|
pecho( "API Error...\n\nCode: error503\nText: HTTP Error 503\nThe webserver's service is currently unavailable", PECHO_WARN ); |
855
|
|
|
$tempSetting = $pgDisplayGetOutData; |
856
|
|
|
$pgDisplayGetOutData = false; |
857
|
|
|
$histemp = $this->initPage( $arrayParams['title'] )->history( 1 ); |
858
|
|
|
if( $arrayParams['action'] == 'edit' && $histemp['user'] == $this->get_username() && $histemp['comment'] == $arrayParams['summary'] && strtotime( $histemp['timestamp'] ) - time() < 120 ) { |
859
|
|
|
pecho( ", however, the edit, finally, appears to have gone through.\n\n", PECHO_WARN ); |
860
|
|
|
$pgDisplayGetOutData = $tempSetting; |
861
|
|
|
return array( 'edit' => array( 'result' => 'Success', 'newrevid' => $histemp['revid'] ) ); |
862
|
|
|
} else { |
863
|
|
|
$pgDisplayGetOutData = $tempSetting; |
864
|
|
|
if( $pgThrowExceptions ) { |
865
|
|
|
pecho( ". Terminating program.\n\n", PECHO_FATAL ); |
866
|
|
|
throw new MWAPIError( array( |
867
|
|
|
'code' => 'error503', 'info' => 'nThe webserver\'s service is currently unavailable' |
868
|
|
|
) ); |
869
|
|
|
} else { |
870
|
|
|
pecho( ". Aborting attempts.", PECHO_FATAL ); |
871
|
|
|
return false; |
872
|
|
|
} |
873
|
|
|
} |
874
|
|
|
} |
875
|
|
|
|
876
|
|
|
if( !isset( $data['servedby'] ) && !isset( $data['requestid'] ) ) { |
877
|
|
|
if( $pgThrowExceptions ) { |
878
|
|
|
pecho( "Fatal Error: API is not responding. Terminating program.\n\n", PECHO_FATAL ); |
879
|
|
|
throw new MWAPIError( array( 'code' => 'noresponse', 'info' => 'API is unresponsive' ) ); |
880
|
|
|
} else { |
881
|
|
|
pecho( "API Error: API is not responding. Aborting attempts.\n\n", PECHO_FATAL ); |
882
|
|
|
return false; |
883
|
|
|
} |
884
|
|
|
} |
885
|
|
|
|
886
|
|
|
Hooks::runHook( 'PostAPIPostQuery', array( &$data ) ); |
887
|
|
|
|
888
|
|
|
Hooks::runHook( 'APIQueryCheckError', array( &$data['error'] ) ); |
889
|
|
|
if( isset( $data['error'] ) && $errorcheck ) { |
890
|
|
|
|
891
|
|
|
pecho( "API Error...\n\nCode: {$data['error']['code']}\nText: {$data['error']['info']}\n\n", PECHO_FATAL ); |
892
|
|
|
return false; |
893
|
|
|
} |
894
|
|
|
|
895
|
|
|
if( isset( $data['servedby'] ) ) { |
896
|
|
|
$this->servedby = $data['servedby']; |
897
|
|
|
} |
898
|
|
|
|
899
|
|
|
if( isset( $data['requestid'] ) ) { |
900
|
|
|
if( $data['requestid'] != $requestid ) { |
901
|
|
|
if( $recursed ) { |
902
|
|
|
pecho( "API Error... requestid's didn't match twice.\n\n", PECHO_FATAL ); |
903
|
|
|
return false; |
904
|
|
|
} |
905
|
|
|
return $this->apiQuery( $arrayParams, $post, $errorcheck, true ); |
906
|
|
|
} |
907
|
|
|
} |
908
|
|
|
|
909
|
|
|
return $data; |
910
|
|
|
} else { |
911
|
|
|
|
912
|
|
|
Hooks::runHook( 'PreAPIGetQuery', array( &$arrayParams ) ); |
913
|
|
|
|
914
|
|
|
for( $i = 0; $i < $attempts; $i++ ){ |
915
|
|
|
if ( $this->oauthEnabled ) { |
|
|
|
|
916
|
|
|
$headerArr = array( |
917
|
|
|
// OAuth information |
918
|
|
|
'oauth_consumer_key' => $this->consumerKey, |
919
|
|
|
'oauth_token' => $this->accessToken, |
920
|
|
|
'oauth_version' => '1.0', |
921
|
|
|
'oauth_nonce' => md5( microtime() . mt_rand() ), |
922
|
|
|
'oauth_timestamp' => time(), |
923
|
|
|
|
924
|
|
|
// We're using secret key signatures here. |
925
|
|
|
'oauth_signature_method' => 'HMAC-SHA1', |
926
|
|
|
); |
927
|
|
|
$signature = $this->generateSignature( 'GET', |
928
|
|
|
( $talktoOauth ? $talktoOauth : $this->base_url ) . |
929
|
|
|
( !empty( $arrayParams ) ? '?' . http_build_query( $arrayParams ) : "" ), |
930
|
|
|
$headerArr |
931
|
|
|
); |
932
|
|
|
$headerArr['oauth_signature'] = $signature; |
933
|
|
|
|
934
|
|
|
$header = array(); |
935
|
|
|
foreach ( $headerArr as $k => $v ) { |
936
|
|
|
$header[] = rawurlencode( $k ) . '="' . rawurlencode( $v ) . '"'; |
937
|
|
|
} |
938
|
|
|
$header = 'Authorization: OAuth ' . join( ', ', $header ); |
939
|
|
|
unset( $headerArr ); |
940
|
|
|
} |
941
|
|
|
$logdata = "Date/Time: " . date( 'r' ) . "\nMethod: GET\nURL: {$this->base_url}\nParameters: " . print_r( $arrayParams, true ) . "\nRaw Data: "; |
942
|
|
|
$data = $this->get_http()->get( |
943
|
|
|
( $talktoOauth ? $talktoOauth : $this->base_url ), |
944
|
|
|
$arrayParams, |
945
|
|
|
$header |
946
|
|
|
); |
947
|
|
|
if( $talktoOauth !== false && $data !== false ) return $data; |
948
|
|
|
$logdata .= $data; |
949
|
|
|
$data2 = ( $data === false || is_null( $data ) ? false : unserialize( $data ) ); |
950
|
|
|
if( $data2 === false && serialize( $data2 ) != $data ) { |
951
|
|
|
$logdata .= "\nUNSERIALIZATION FAILED\n\n"; |
952
|
|
|
if( $pgLogFailedCommunicationData ) file_put_contents( $pgIP . 'Includes/Communication_Logs/Faileddata.log', $logdata, FILE_APPEND ); |
953
|
|
|
} else { |
954
|
|
|
$logdata .= "\nUNSERIALIZATION SUCCEEDED\n\n"; |
955
|
|
|
if( $pgLogSuccessfulCommunicationData ) file_put_contents( $pgIP . 'Includes/Communication_Logs/Succeededdata.log', $logdata, FILE_APPEND ); |
956
|
|
|
} |
957
|
|
|
|
958
|
|
|
if( $pgLogGetCommunicationData ) file_put_contents( $pgIP . 'Includes/Communication_Logs/Getdata.log', $logdata, FILE_APPEND ); |
959
|
|
|
if( $pgLogCommunicationData ) file_put_contents( $pgIP . 'Includes/Communication_Logs/Querydata.log', $logdata, FILE_APPEND ); |
960
|
|
|
|
961
|
|
|
$data = $data2; |
962
|
|
|
unset( $data2 ); |
963
|
|
|
if( $this->get_http()->get_HTTP_code() == 503 && $errorcheck ) { |
964
|
|
|
pecho( "API Error...\n\nCode: error503\nText: HTTP Error 503\nThe webserver's service is currently unavailable, retrying...", PECHO_WARN ); |
965
|
|
|
} |
966
|
|
|
|
967
|
|
|
if( !isset( $data['servedby'] ) && !isset( $data['requestid'] ) ) { |
968
|
|
|
pecho( "Warning: API is not responding, retrying...\n\n", PECHO_WARN ); |
969
|
|
|
} else break; |
970
|
|
|
} |
971
|
|
|
|
972
|
|
|
if( $this->get_http()->get_HTTP_code() == 503 && $errorcheck ) { |
973
|
|
|
if( $pgThrowExceptions ) { |
974
|
|
|
pecho( "Fatal Error: API Error...\n\nCode: error503\nText: HTTP Error 503\nThe webserver's service is still not available. Terminating program.\n\n", PECHO_FATAL ); |
975
|
|
|
throw new MWAPIError( array( |
976
|
|
|
'code' => 'error503', 'info' => 'nThe webserver\'s service is currently unavailable' |
977
|
|
|
) ); |
978
|
|
|
} else { |
979
|
|
|
pecho( "API Error...\n\nCode: error503\nText: HTTP Error 503\nThe webserver's service is still not available. Aborting attempts.\n\n", PECHO_FATAL ); |
980
|
|
|
return false; |
981
|
|
|
} |
982
|
|
|
|
983
|
|
|
} |
984
|
|
|
|
985
|
|
|
if( !isset( $data['servedby'] ) && !isset( $data['requestid'] ) ) { |
986
|
|
|
if( $pgThrowExceptions ) { |
987
|
|
|
pecho( "Fatal Error: API is not responding. Terminating program.\n\n", PECHO_FATAL ); |
988
|
|
|
throw new MWAPIError( array( 'code' => 'noresponse', 'info' => 'API is unresponsive' ) ); |
989
|
|
|
} else { |
990
|
|
|
pecho( "API Error: API is not responding. Aborting attempts.\n\n", PECHO_FATAL ); |
991
|
|
|
return false; |
992
|
|
|
} |
993
|
|
|
} |
994
|
|
|
|
995
|
|
|
Hooks::runHook( 'APIQueryCheckError', array( &$data['error'] ) ); |
996
|
|
|
if( isset( $data['error'] ) && $errorcheck ) { |
997
|
|
|
|
998
|
|
|
pecho( "API Error...\n\nCode: {$data['error']['code']}\nText: {$data['error']['info']}\n\n", PECHO_FATAL ); |
999
|
|
|
return false; |
1000
|
|
|
} |
1001
|
|
|
|
1002
|
|
|
if( isset( $data['servedby'] ) ) { |
1003
|
|
|
$this->servedby = $data['servedby']; |
1004
|
|
|
} |
1005
|
|
|
|
1006
|
|
|
if( isset( $data['requestid'] ) ) { |
1007
|
|
|
if( $data['requestid'] != $requestid ) { |
1008
|
|
|
if( $recursed ) { |
1009
|
|
|
pecho( "API Error... requestid's didn't match twice.\n\n", PECHO_FATAL ); |
1010
|
|
|
return false; |
1011
|
|
|
} |
1012
|
|
|
return $this->apiQuery( $arrayParams, $post, $errorcheck, true ); |
1013
|
|
|
} |
1014
|
|
|
} |
1015
|
|
|
|
1016
|
|
|
return $data; |
1017
|
|
|
} |
1018
|
|
|
} |
1019
|
|
|
|
1020
|
|
|
/** |
1021
|
|
|
* Returns the server that handled the previous request. Only works on MediaWiki versions 1.17 and up |
1022
|
|
|
* |
1023
|
|
|
* @return string |
1024
|
|
|
*/ |
1025
|
|
|
public function get_servedby() { |
1026
|
|
|
return $this->servedby; |
1027
|
|
|
} |
1028
|
|
|
|
1029
|
|
|
/** |
1030
|
|
|
* Returns the version of MediaWiki that is on the server |
1031
|
|
|
* |
1032
|
|
|
* @return string |
1033
|
|
|
*/ |
1034
|
|
|
public function get_mw_version() { |
1035
|
|
|
return $this->mwversion; |
1036
|
|
|
} |
1037
|
|
|
|
1038
|
|
|
/** |
1039
|
|
|
* Simplifies the running of API queries, especially with continues and other parameters. |
1040
|
|
|
* |
1041
|
|
|
* @access public |
1042
|
|
|
* @link http://wiki.peachy.compwhizii.net/wiki/Manual/Wiki::listHandler |
1043
|
|
|
* @param array $tArray Parameters given to query with (default: array()). In addition to those recognised by the API, ['_code'] should be set to the first two characters of all the parameters in a list=XXX API call - for example, with allpages, the parameters start with 'ap', with recentchanges, the parameters start with 'rc' - and is required; ['_limit'] imposes a hard limit on the number of results returned (optional) and ['_lhtitle'] simplifies a multidimensional result into a unidimensional result - lhtitle is the key of the sub-array to return. (optional) |
1044
|
|
|
* @param array $resume Parameter passed back at the end of a list-handler operation. Pass parameter back through to resume listhandler operation. (optional) |
1045
|
|
|
* @throws BadEntryError |
1046
|
|
|
* @return array Returns an array with the API result |
1047
|
|
|
*/ |
1048
|
|
|
public function listHandler( $tArray = array(), &$resume = null ) { |
1049
|
|
|
|
1050
|
|
|
if( isset( $tArray['_code'] ) ) { |
1051
|
|
|
$code = $tArray['_code']; |
1052
|
|
|
unset( $tArray['_code'] ); |
1053
|
|
|
} else { |
1054
|
|
|
throw new BadEntryError( "listHandler", "Parameter _code is required." ); |
1055
|
|
|
} |
1056
|
|
|
if( isset( $tArray['_limit'] ) ) { |
1057
|
|
|
$limit = $tArray['_limit']; |
1058
|
|
|
unset( $tArray['_limit'] ); |
1059
|
|
|
} else { |
1060
|
|
|
$limit = null; |
1061
|
|
|
} |
1062
|
|
|
if( isset( $tArray['_lhtitle'] ) ) { |
1063
|
|
|
$lhtitle = $tArray['_lhtitle']; |
1064
|
|
|
unset( $tArray['_lhtitle'] ); |
1065
|
|
|
} else { |
1066
|
|
|
$lhtitle = null; |
1067
|
|
|
} |
1068
|
|
|
if ( !is_null( $resume ) ) { |
1069
|
|
|
$tArray = array_merge( $tArray, $resume ); |
1070
|
|
|
} else { |
1071
|
|
|
$resume = array(); |
1072
|
|
|
} |
1073
|
|
|
|
1074
|
|
|
$tArray['action'] = 'query'; |
1075
|
|
|
$tArray[$code . 'limit'] = 'max'; |
1076
|
|
|
$tArray['rawcontinue'] = 1; |
1077
|
|
|
|
1078
|
|
|
if( isset( $limit ) && !is_null( $limit ) ) { |
1079
|
|
|
if( !is_numeric( $limit ) ) { |
1080
|
|
|
throw new BadEntryError( "listHandler", "limit should be a number or null" ); |
1081
|
|
|
} else { |
1082
|
|
|
$limit = intval( $limit ); |
1083
|
|
|
if( $limit < 0 || ( floor( $limit ) != $limit ) ) { |
1084
|
|
|
if( !$limit == -1 ) { |
1085
|
|
|
throw new BadEntryError( "listHandler", "limit should an integer greater than 0" ); |
1086
|
|
|
} else $limit = 'max'; |
1087
|
|
|
} |
1088
|
|
|
$tArray[$code . 'limit'] = $limit; |
1089
|
|
|
} |
1090
|
|
|
} |
1091
|
|
|
if( isset( $tArray[$code . 'namespace'] ) && !is_null( $tArray[$code . 'namespace'] ) ) { |
1092
|
|
|
if( is_array( $tArray[$code . 'namespace'] ) ) { |
1093
|
|
|
$tArray[$code . 'namespace'] = implode( '|', $tArray[$code . 'namespace'] ); |
1094
|
|
|
} elseif( strlen( $tArray[$code . 'namespace'] ) === 0 ) { |
1095
|
|
|
$tArray[$code . 'namespace'] = null; |
1096
|
|
|
} else { |
1097
|
|
|
$tArray[$code . 'namespace'] = (string)$tArray[$code . 'namespace']; |
1098
|
|
|
} |
1099
|
|
|
} |
1100
|
|
|
|
1101
|
|
|
$endArray = array(); |
1102
|
|
|
|
1103
|
|
|
$continue = null; |
1104
|
|
|
$offset = null; |
1105
|
|
|
$start = null; |
1106
|
|
|
$from = null; |
1107
|
|
|
|
1108
|
|
|
pecho( "Running list handler function with params " . implode( ";", $tArray ) . "...\n\n", PECHO_VERBOSE ); |
1109
|
|
|
|
1110
|
|
|
while( 1 ){ |
1111
|
|
|
|
1112
|
|
|
if( !is_null( $continue ) ) $tArray[$code . 'continue'] = $continue; |
1113
|
|
|
if( !is_null( $offset ) ) $tArray[$code . 'offset'] = $offset; |
1114
|
|
|
if( !is_null( $start ) ) $tArray[$code . 'start'] = $start; |
1115
|
|
|
if( !is_null( $from ) ) $tArray[$code . 'from'] = $from; |
1116
|
|
|
|
1117
|
|
|
$tRes = $this->apiQuery( $tArray ); |
1118
|
|
|
if( !isset( $tRes['query'] ) ) break; |
1119
|
|
|
|
1120
|
|
|
foreach ( $tRes['query'] as $x ) { |
1121
|
|
|
foreach ( $x as $y ) { |
1122
|
|
|
if ( !is_null( $lhtitle ) ) { |
1123
|
|
|
if ( isset( $y[$lhtitle] ) ) { |
1124
|
|
|
$y = $y[$lhtitle]; |
1125
|
|
|
if ( is_array( $y ) ) { |
1126
|
|
|
$endArray = array_merge( $endArray, $y ); |
1127
|
|
|
} else { |
1128
|
|
|
$endArray[] = $y; |
1129
|
|
|
} |
1130
|
|
|
continue; |
1131
|
|
|
} else { |
1132
|
|
|
continue; |
1133
|
|
|
} |
1134
|
|
|
} |
1135
|
|
|
$endArray[] = $y; |
1136
|
|
|
} |
1137
|
|
|
} |
1138
|
|
|
|
1139
|
|
|
if( isset( $tRes['query-continue'] ) ) { |
1140
|
|
|
foreach( $tRes['query-continue'] as $z ){ |
1141
|
|
|
if( isset( $z[$code . 'continue'] ) ) { |
1142
|
|
|
$continue = $resume[$code . 'continue'] = $z[$code . 'continue']; |
1143
|
|
|
} elseif( isset( $z[$code . 'offset'] ) ) { |
1144
|
|
|
$offset = $resume[$code . 'offset'] = $z[$code . 'offset']; |
1145
|
|
|
} elseif( isset( $z[$code . 'start'] ) ) { |
1146
|
|
|
$start = $resume[$code . 'start'] = $z[$code . 'start']; |
1147
|
|
|
} elseif( isset( $z[$code . 'from'] ) ) { |
1148
|
|
|
$from = $resume[$code . 'from'] = $z[$code . 'from']; |
1149
|
|
|
} |
1150
|
|
|
} |
1151
|
|
|
} else { |
1152
|
|
|
$resume = array(); |
1153
|
|
|
break; |
1154
|
|
|
} |
1155
|
|
|
|
1156
|
|
|
if ( !is_null( $limit ) && $limit != 'max' ) { |
1157
|
|
|
if ( count( $endArray ) >= $limit ) { |
1158
|
|
|
$endArray = array_slice( $endArray, 0, $limit ); |
1159
|
|
|
break; |
1160
|
|
|
} |
1161
|
|
|
} |
1162
|
|
|
|
1163
|
|
|
} |
1164
|
|
|
|
1165
|
|
|
return $endArray; |
1166
|
|
|
} |
1167
|
|
|
|
1168
|
|
|
/** |
1169
|
|
|
* Returns a reference to the HTTP Class |
1170
|
|
|
* |
1171
|
|
|
* @access public |
1172
|
|
|
* @see Wiki::$http |
1173
|
|
|
* @return HTTP |
1174
|
|
|
*/ |
1175
|
|
|
public function &get_http() { |
1176
|
|
|
return $this->http; |
1177
|
|
|
} |
1178
|
|
|
|
1179
|
|
|
/** |
1180
|
|
|
* Returns whether or not to log in |
1181
|
|
|
* |
1182
|
|
|
* @access public |
1183
|
|
|
* @see Wiki::$nologin |
1184
|
|
|
* @return bool |
1185
|
|
|
*/ |
1186
|
|
|
public function get_nologin() { |
1187
|
|
|
return $this->nologin; |
1188
|
|
|
} |
1189
|
|
|
|
1190
|
|
|
/** |
1191
|
|
|
* Returns the base URL for the wiki. |
1192
|
|
|
* |
1193
|
|
|
* @access public |
1194
|
|
|
* @see Wiki::$base_url |
1195
|
|
|
* @return string base_url for the wiki |
1196
|
|
|
*/ |
1197
|
|
|
public function get_base_url() { |
1198
|
|
|
return $this->base_url; |
1199
|
|
|
} |
1200
|
|
|
|
1201
|
|
|
/** |
1202
|
|
|
* Returns the api query limit for the wiki. |
1203
|
|
|
* |
1204
|
|
|
* @access public |
1205
|
|
|
* @see Wiki::$apiQueryLimit |
1206
|
|
|
* @return int apiQueryLimit fot the wiki |
1207
|
|
|
*/ |
1208
|
|
|
public function get_api_limit() { |
1209
|
|
|
return $this->apiQueryLimit; |
1210
|
|
|
} |
1211
|
|
|
|
1212
|
|
|
/** |
1213
|
|
|
* Returns the runpage. |
1214
|
|
|
* |
1215
|
|
|
* @access public |
1216
|
|
|
* @see Wiki::$runpage |
1217
|
|
|
* @return string Runpage for the user |
1218
|
|
|
*/ |
1219
|
|
|
public function get_runpage() { |
1220
|
|
|
return $this->runpage; |
1221
|
|
|
} |
1222
|
|
|
|
1223
|
|
|
/** |
1224
|
|
|
* Returns if maxlag is on or what it is set to for the wiki. |
1225
|
|
|
* |
1226
|
|
|
* @access public |
1227
|
|
|
* @see Wiki:$maxlag |
1228
|
|
|
* @return bool|int Max lag for the wiki |
1229
|
|
|
*/ |
1230
|
|
|
public function get_maxlag() { |
1231
|
|
|
return $this->maxlag; |
1232
|
|
|
} |
1233
|
|
|
|
1234
|
|
|
/** |
1235
|
|
|
* Returns the edit rate in EPM for the wiki. |
1236
|
|
|
* |
1237
|
|
|
* @access public |
1238
|
|
|
* @see Wiki::$edit_rate |
1239
|
|
|
* @return int Edit rate in EPM for the wiki |
1240
|
|
|
*/ |
1241
|
|
|
public function get_edit_rate() { |
1242
|
|
|
return $this->edit_rate; |
1243
|
|
|
} |
1244
|
|
|
|
1245
|
|
|
/** |
1246
|
|
|
* Returns the username. |
1247
|
|
|
* |
1248
|
|
|
* @access public |
1249
|
|
|
* @see Wiki::$pgUsername |
1250
|
|
|
* @return string Username |
1251
|
|
|
*/ |
1252
|
|
|
public function get_username() { |
1253
|
|
|
return $this->username; |
1254
|
|
|
} |
1255
|
|
|
|
1256
|
|
|
/** |
1257
|
|
|
* Returns if the Wiki should follow nobots rules. |
1258
|
|
|
* |
1259
|
|
|
* @access public |
1260
|
|
|
* @see Wiki::$nobots |
1261
|
|
|
* @return bool True for following nobots |
1262
|
|
|
*/ |
1263
|
|
|
public function get_nobots() { |
1264
|
|
|
return $this->nobots; |
1265
|
|
|
} |
1266
|
|
|
|
1267
|
|
|
/** |
1268
|
|
|
* Returns if the script should not edit if the user has new messages |
1269
|
|
|
* |
1270
|
|
|
* @access public |
1271
|
|
|
* @see Wiki::$stoponnewmessages |
1272
|
|
|
* @return bool True for stopping on new messages |
1273
|
|
|
*/ |
1274
|
|
|
public function get_stoponnewmessages() { |
1275
|
|
|
return $this->stoponnewmessages; |
1276
|
|
|
} |
1277
|
|
|
|
1278
|
|
|
/** |
1279
|
|
|
* Returns the text to search for in the optout= field of the {{nobots}} template |
1280
|
|
|
* |
1281
|
|
|
* @access public |
1282
|
|
|
* @see Wiki::$optout |
1283
|
|
|
* @return null|string String to search for |
1284
|
|
|
*/ |
1285
|
|
|
public function get_optout() { |
1286
|
|
|
return $this->optout; |
1287
|
|
|
} |
1288
|
|
|
|
1289
|
|
|
/** |
1290
|
|
|
* Returns the configuration of the wiki |
1291
|
|
|
* |
1292
|
|
|
* @param string $conf_name Name of configuration setting to get. Default null, will return all configuration. |
1293
|
|
|
* @access public |
1294
|
|
|
* @see Wiki::$configuration |
1295
|
|
|
* @return array Configuration array |
1296
|
|
|
*/ |
1297
|
|
|
public function get_configuration( $conf_name = null ) { |
1298
|
|
|
if( is_null( $conf_name ) ) { |
1299
|
|
|
return $this->configuration; |
1300
|
|
|
} else { |
1301
|
|
|
return $this->configuration[$conf_name]; |
1302
|
|
|
} |
1303
|
|
|
} |
1304
|
|
|
|
1305
|
|
|
public function get_conf( $conf_name = null ) { |
1306
|
|
|
return $this->get_configuration( $conf_name ); |
1307
|
|
|
} |
1308
|
|
|
|
1309
|
|
|
/** |
1310
|
|
|
* Purges a list of pages |
1311
|
|
|
* |
1312
|
|
|
* @access public |
1313
|
|
|
* @param array|string $titles A list of titles to work on |
1314
|
|
|
* @param array|string $pageids A list of page IDs to work on |
1315
|
|
|
* @param array|string $revids A list of revision IDs to work on |
1316
|
|
|
* @param bool $redirects Automatically resolve redirects. Default false. |
1317
|
|
|
* @param bool $force Update the links tables. Default false. |
1318
|
|
|
* @param bool $convert Convert titles to other variants if necessary. Default false. |
1319
|
|
|
* @param string $generator Get the list of pages to work on by executing the specified query module. Default null. |
1320
|
|
|
* @return boolean |
1321
|
|
|
*/ |
1322
|
|
|
public function purge( $titles = null, $pageids = null, $revids = null, $force = false, $redirects = false, $convert = false, $generator = null ) { |
1323
|
|
|
|
1324
|
|
|
$apiArr = array( |
1325
|
|
|
'action' => 'purge' |
1326
|
|
|
); |
1327
|
|
|
|
1328
|
|
|
if( is_null( $titles ) && is_null( $pageids ) && is_null( $revids ) ) { |
1329
|
|
|
pecho( "Error: Nothing to purge.\n\n", PECHO_WARN ); |
1330
|
|
|
return false; |
1331
|
|
|
} |
1332
|
|
|
Hooks::runHook( 'StartPurge', array( &$titles ) ); |
1333
|
|
|
if( !is_null( $titles ) ) { |
1334
|
|
|
if( is_array( $titles ) ) $titles = implode( '|', $titles ); |
1335
|
|
|
$apiArr['titles'] = $titles; |
1336
|
|
|
} |
1337
|
|
|
if( !is_null( $pageids ) ) { |
1338
|
|
|
if( is_array( $pageids ) ) $pageids = implode( '|', $pageids ); |
1339
|
|
|
$apiArr['pageids'] = $pageids; |
1340
|
|
|
} |
1341
|
|
|
if( !is_null( $revids ) ) { |
1342
|
|
|
if( is_array( $revids ) ) $revids = implode( '|', $revids ); |
1343
|
|
|
$apiArr['revids'] = $revids; |
1344
|
|
|
} |
1345
|
|
|
if( $redirects ) $apiArr['redirects'] = ''; |
1346
|
|
|
if( $force ) $apiArr['forcelinkupdate'] = ''; |
1347
|
|
|
if( $convert ) $apiArr['converttitles'] = ''; |
1348
|
|
|
|
1349
|
|
|
$genparams = $this->generatorvalues; |
1350
|
|
|
if( !is_null( $generator ) ) { |
1351
|
|
|
if( in_array( $generator, $genparams ) ) { |
1352
|
|
|
$apiArr['generator'] = 'g' . $generator; |
1353
|
|
|
} else pecho( "Invalid generator value detected. Omitting...\n\n", PECHO_WARN ); |
1354
|
|
|
} |
1355
|
|
|
|
1356
|
|
|
pecho( "Purging...\n\n", PECHO_NOTICE ); |
1357
|
|
|
|
1358
|
|
|
Hooks::runHook( 'StartPurge', array( &$apiArr ) ); |
1359
|
|
|
|
1360
|
|
|
$result = $this->apiQuery( $apiArr, true, true, false ); |
1361
|
|
|
|
1362
|
|
|
if( isset( $result['purge'] ) ) { |
1363
|
|
|
foreach( $result['purge'] as $page ){ |
1364
|
|
|
if( !isset( $page['purged'] ) ) { |
1365
|
|
|
pecho( "Purge error on {$page['title']}...\n\n" . print_r( $page, true ) . "\n\n", PECHO_FATAL ); |
1366
|
|
|
return false; |
1367
|
|
|
} |
1368
|
|
|
} |
1369
|
|
|
return true; |
1370
|
|
|
|
1371
|
|
|
} else { |
1372
|
|
|
pecho( "Purge error...\n\n" . print_r( $result, true ), PECHO_FATAL ); |
1373
|
|
|
return false; |
1374
|
|
|
} |
1375
|
|
|
} |
1376
|
|
|
|
1377
|
|
|
|
1378
|
|
|
/** |
1379
|
|
|
* Returns a list of recent changes |
1380
|
|
|
* |
1381
|
|
|
* @access public |
1382
|
|
|
* @param integer|array|string $namespace Namespace(s) to check |
1383
|
|
|
* @param string $pgTag Only list recent changes bearing this tag. |
1384
|
|
|
* @param int $start Only list changes after this timestamp. |
1385
|
|
|
* @param int $end Only list changes before this timestamp. |
1386
|
|
|
* @param string $user Only list changes by this user. |
1387
|
|
|
* @param string $excludeuser Only list changes not by this user. |
1388
|
|
|
* @param string $dir 'older' lists changes, most recent first; 'newer' least recent first. |
1389
|
|
|
* @param bool $minor Whether to only include minor edits (true), only non-minor edits (false) or both (null). Default null. |
1390
|
|
|
* @param bool $bot Whether to only include bot edits (true), only non-bot edits (false) or both (null). Default null. |
1391
|
|
|
* @param bool $anon Whether to only include anonymous edits (true), only non-anonymous edits (false) or both (null). Default null. |
1392
|
|
|
* @param bool $redirect Whether to only include edits to redirects (true), edits to non-redirects (false) or both (null). Default null. |
1393
|
|
|
* @param bool $patrolled Whether to only include patrolled edits (true), only non-patrolled edits (false) or both (null). Default null. |
1394
|
|
|
* @param array $prop What properties to retrieve. Default array( 'user', 'comment', 'flags', 'timestamp', 'title', 'ids', 'sizes', 'tags' ). |
1395
|
|
|
* @param int $limit A hard limit to impose on the number of results returned. |
1396
|
|
|
* @return array Recent changes matching the description. |
1397
|
|
|
*/ |
1398
|
|
|
public function recentchanges( $namespace = 0, $pgTag = null, $start = null, $end = null, $user = null, $excludeuser = null, $dir = 'older', $minor = null, $bot = null, $anon = null, $redirect = null, $patrolled = null, $prop = null, $limit = 50 ) { |
1399
|
|
|
|
1400
|
|
|
if( is_array( $namespace ) ) { |
1401
|
|
|
$namespace = implode( '|', $namespace ); |
1402
|
|
|
} |
1403
|
|
|
|
1404
|
|
|
if( is_null( $prop ) ) { |
1405
|
|
|
$prop = array( |
1406
|
|
|
'user', 'comment', 'flags', 'timestamp', 'title', 'ids', 'sizes', 'tags' |
1407
|
|
|
); |
1408
|
|
|
} |
1409
|
|
|
|
1410
|
|
|
$rcArray = array( |
1411
|
|
|
'list' => 'recentchanges', |
1412
|
|
|
'_code' => 'rc', |
1413
|
|
|
'rcnamespace' => $namespace, |
1414
|
|
|
'rcdir' => $dir, |
1415
|
|
|
'rcprop' => implode( '|', $prop ), |
1416
|
|
|
'_limit' => $limit |
1417
|
|
|
); |
1418
|
|
|
|
1419
|
|
|
if( !is_null( $pgTag ) ) $rcArray['rctag'] = $pgTag; |
1420
|
|
|
if( !is_null( $start ) ) $rcArray['rcstart'] = $start; |
1421
|
|
|
if( !is_null( $end ) ) $rcArray['rcend'] = $end; |
1422
|
|
|
if( !is_null( $user ) ) $rcArray['rcuser'] = $user; |
1423
|
|
|
if( !is_null( $excludeuser ) ) $rcArray['rcexcludeuser'] = $excludeuser; |
1424
|
|
|
|
1425
|
|
|
$rcshow = array(); |
1426
|
|
|
|
1427
|
|
|
if( !is_null( $minor ) ) { |
1428
|
|
|
if( $minor ) { |
1429
|
|
|
$rcshow[] = 'minor'; |
1430
|
|
|
} else { |
1431
|
|
|
$rcshow[] = '!minor'; |
1432
|
|
|
} |
1433
|
|
|
} |
1434
|
|
|
|
1435
|
|
|
if( !is_null( $bot ) ) { |
1436
|
|
|
if( $bot ) { |
1437
|
|
|
$rcshow[] = 'bot'; |
1438
|
|
|
} else { |
1439
|
|
|
$rcshow[] = '!bot'; |
1440
|
|
|
} |
1441
|
|
|
} |
1442
|
|
|
|
1443
|
|
|
if( !is_null( $anon ) ) { |
1444
|
|
|
if( $minor ) { |
1445
|
|
|
$rcshow[] = 'anon'; |
1446
|
|
|
} else { |
1447
|
|
|
$rcshow[] = '!anon'; |
1448
|
|
|
} |
1449
|
|
|
} |
1450
|
|
|
|
1451
|
|
|
if( !is_null( $redirect ) ) { |
1452
|
|
|
if( $redirect ) { |
1453
|
|
|
$rcshow[] = 'redirect'; |
1454
|
|
|
} else { |
1455
|
|
|
$rcshow[] = '!redirect'; |
1456
|
|
|
} |
1457
|
|
|
} |
1458
|
|
|
|
1459
|
|
|
if( !is_null( $patrolled ) ) { |
1460
|
|
|
if( $minor ) { |
1461
|
|
|
$rcshow[] = 'patrolled'; |
1462
|
|
|
} else { |
1463
|
|
|
$rcshow[] = '!patrolled'; |
1464
|
|
|
} |
1465
|
|
|
} |
1466
|
|
|
|
1467
|
|
|
if( count( $rcshow ) ) $rcArray['rcshow'] = implode( '|', $rcshow ); |
1468
|
|
|
|
1469
|
|
|
$rcArray['limit'] = $this->apiQueryLimit; |
1470
|
|
|
|
1471
|
|
|
Hooks::runHook( 'PreQueryRecentchanges', array( &$rcArray ) ); |
1472
|
|
|
|
1473
|
|
|
pecho( "Getting recent changes...\n\n", PECHO_NORMAL ); |
1474
|
|
|
|
1475
|
|
|
return $this->listHandler( $rcArray ); |
1476
|
|
|
|
1477
|
|
|
} |
1478
|
|
|
|
1479
|
|
|
/** |
1480
|
|
|
* Performs a search and retrieves the results |
1481
|
|
|
* |
1482
|
|
|
* @access public |
1483
|
|
|
* @param string $search What to search for |
1484
|
|
|
* @param bool $fulltext Whether to search the full text of pages (default, true) or just titles (false; may not be enabled on all wikis). |
1485
|
|
|
* @param array $namespaces The namespaces to search in (default: array( 0 )). |
1486
|
|
|
* @param array $prop What properties to retrieve (default: array('size', 'wordcount', 'timestamp', 'snippet') ). |
1487
|
|
|
* @param bool $includeredirects Whether to include redirects or not (default: true). |
1488
|
|
|
* @param int $limit A hard limit on the number of results to retrieve (default: null i.e. all). |
1489
|
|
|
* @return array |
1490
|
|
|
*/ |
1491
|
|
|
public function search( $search, $fulltext = true, $namespaces = array( 0 ), $prop = array( |
1492
|
|
|
'size', 'wordcount', 'timestamp', 'snippet' |
1493
|
|
|
), $includeredirects = true, $limit = 50 ) { |
1494
|
|
|
|
1495
|
|
|
$srArray = array( |
1496
|
|
|
'_code' => 'sr', |
1497
|
|
|
'list' => 'search', |
1498
|
|
|
'_limit' => $limit, |
1499
|
|
|
'srsearch' => $search, |
1500
|
|
|
'srnamespace' => $namespaces, |
1501
|
|
|
'srwhat' => ( $fulltext ) ? "text" : "title", |
1502
|
|
|
'srinfo' => '', |
1503
|
|
|
##FIXME: find a meaningful way of passing back 'totalhits' and 'suggestion' as required. |
1504
|
|
|
'srprop' => implode( '|', $prop ), |
1505
|
|
|
'srredirects' => $includeredirects |
1506
|
|
|
); |
1507
|
|
|
|
1508
|
|
|
pecho( "Searching for $search...\n\n", PECHO_NORMAL ); |
1509
|
|
|
|
1510
|
|
|
return $this->listHandler( $srArray ); |
1511
|
|
|
} |
1512
|
|
|
|
1513
|
|
|
/** |
1514
|
|
|
* Retrieves log entries from the wiki. |
1515
|
|
|
* |
1516
|
|
|
* @access public |
1517
|
|
|
* @link http://www.mediawiki.org/wiki/API:Query_-_Lists#logevents_.2F_le |
1518
|
|
|
* @param bool|string $type Type of log to retrieve from the wiki (default: false) |
1519
|
|
|
* @param bool|string $user Restrict the log to a certain user (default: false) |
1520
|
|
|
* @param bool|string $title Restrict the log to a certain page (default: false) |
1521
|
|
|
* @param bool|string $start Timestamp for the start of the log (default: false) |
1522
|
|
|
* @param bool|string $end Timestamp for the end of the log (default: false) |
1523
|
|
|
* @param string $dir Direction for retieving log entries (default: 'older') |
1524
|
|
|
* @param bool $pgTag Restrict the log to entries with a certain tag (default: false) |
1525
|
|
|
* @param array $prop Information to retieve from the log (default: array( 'ids', 'title', 'type', 'user', 'timestamp', 'comment', 'details' )) |
1526
|
|
|
* @param int $limit How many results to retrieve (default: null i.e. all). |
1527
|
|
|
* @return array Log entries |
1528
|
|
|
*/ |
1529
|
|
|
public function logs( $type = false, $user = false, $title = false, $start = false, $end = false, $dir = 'older', $pgTag = false, $prop = array( |
1530
|
|
|
'ids', 'title', 'type', 'user', 'userid', 'timestamp', 'comment', 'parsedcomment', 'details', 'tags' |
1531
|
|
|
), $limit = 50 ) { |
1532
|
|
|
|
1533
|
|
|
$leArray = array( |
1534
|
|
|
'list' => 'logevents', |
1535
|
|
|
'_code' => 'le', |
1536
|
|
|
'ledir' => $dir, |
1537
|
|
|
'leprop' => implode( '|', $prop ), |
1538
|
|
|
'_limit' => $limit |
1539
|
|
|
); |
1540
|
|
|
|
1541
|
|
|
if( $type ) $leArray['letype'] = $type; |
1542
|
|
|
if( $start ) $leArray['lestart'] = $start; |
1543
|
|
|
if( $end ) $leArray['leend'] = $end; |
1544
|
|
|
if( $user ) $leArray['leuser'] = $user; |
1545
|
|
|
if( $title ) $leArray['letitle'] = $title; |
1546
|
|
|
if( $pgTag ) $leArray['letag'] = $pgTag; |
1547
|
|
|
|
1548
|
|
|
Hooks::runHook( 'PreQueryLog', array( &$leArray ) ); |
1549
|
|
|
|
1550
|
|
|
if( $type ) { |
1551
|
|
|
if( $title || $user ) $title = ' for ' . $title; |
1552
|
|
|
pecho( "Getting $type logs{$title}{$user}...\n\n", PECHO_NORMAL ); |
1553
|
|
|
} else { |
1554
|
|
|
pecho( "Getting logs...\n\n", PECHO_NORMAL ); |
1555
|
|
|
} |
1556
|
|
|
|
1557
|
|
|
return $this->listHandler( $leArray ); |
1558
|
|
|
} |
1559
|
|
|
|
1560
|
|
|
/** |
1561
|
|
|
* Enumerate all categories |
1562
|
|
|
* |
1563
|
|
|
* @access public |
1564
|
|
|
* @link https://www.mediawiki.org/wiki/API:Allcategories |
1565
|
|
|
* @param string $prefix Search for all category titles that begin with this value. (default: null) |
1566
|
|
|
* @param string $from The category to start enumerating from. (default: null) |
1567
|
|
|
* @param string $min Minimum number of category members. (default: null) |
1568
|
|
|
* @param string $max Maximum number of category members. (default: null) |
1569
|
|
|
* @param string $dir Direction to sort in. (default: 'ascending') |
1570
|
|
|
* @param array $prop Information to retieve (default: array( 'size', 'hidden' )) |
1571
|
|
|
* @param int $limit How many categories to return. (default: null i.e. all). |
1572
|
|
|
* @return array List of categories |
1573
|
|
|
*/ |
1574
|
|
|
public function allcategories( $prefix = null, $from = null, $min = null, $max = null, $dir = 'ascending', $prop = array( |
1575
|
|
|
'size', 'hidden' |
1576
|
|
|
), $limit = 50 ) { |
1577
|
|
|
$leArray = array( |
1578
|
|
|
'list' => 'allcategories', |
1579
|
|
|
'_code' => 'ac', |
1580
|
|
|
'acdir' => $dir, |
1581
|
|
|
'acprop' => implode( '|', $prop ), |
1582
|
|
|
'_limit' => $limit |
1583
|
|
|
); |
1584
|
|
|
|
1585
|
|
|
if( !is_null( $from ) ) $leArray['acfrom'] = $from; |
1586
|
|
|
if( !is_null( $prefix ) ) $leArray['acprefix'] = $prefix; |
1587
|
|
|
if( !is_null( $min ) ) $leArray['acmin'] = $min; |
1588
|
|
|
if( !is_null( $max ) ) $leArray['acmax'] = $max; |
1589
|
|
|
|
1590
|
|
|
Hooks::runHook( 'PreQueryAllimages', array( &$leArray ) ); |
1591
|
|
|
|
1592
|
|
|
pecho( "Getting list of all categories...\n\n", PECHO_NORMAL ); |
1593
|
|
|
|
1594
|
|
|
return $this->listHandler( $leArray ); |
1595
|
|
|
|
1596
|
|
|
} |
1597
|
|
|
|
1598
|
|
|
/** |
1599
|
|
|
* Enumerate all images sequentially |
1600
|
|
|
* |
1601
|
|
|
* @access public |
1602
|
|
|
* @link http://www.mediawiki.org/wiki/API:Query_-_Lists#allimages_.2F_le |
1603
|
|
|
* @param string $prefix Search for all image titles that begin with this value. (default: null) |
1604
|
|
|
* @param string $sha1 SHA1 hash of image (default: null) |
1605
|
|
|
* @param string $base36 SHA1 hash of image in base 36 (default: null) |
1606
|
|
|
* @param string $from The image title to start enumerating from. (default: null) |
1607
|
|
|
* @param string $minsize Limit to images with at least this many bytes (default: null) |
1608
|
|
|
* @param string $maxsize Limit to images with at most this many bytes (default: null) |
1609
|
|
|
* @param string $dir Direction in which to list (default: 'ascending') |
1610
|
|
|
* @param array $prop Information to retieve (default: array( 'timestamp', 'user', 'comment', 'url', 'size', 'dimensions', 'sha1', 'mime', 'metadata', 'archivename', 'bitdepth' )) |
1611
|
|
|
* @param int $limit How many results to retrieve (default: null i.e. all). |
1612
|
|
|
* @return array List of images |
1613
|
|
|
*/ |
1614
|
|
|
public function allimages( $prefix = null, $sha1 = null, $base36 = null, $from = null, $minsize = null, $maxsize = null, $dir = 'ascending', $prop = array( |
1615
|
|
|
'timestamp', 'user', 'comment', 'url', 'size', 'dimensions', 'sha1', 'mime', 'metadata', 'archivename', |
1616
|
|
|
'bitdepth' |
1617
|
|
|
), $limit = 50 ) { |
1618
|
|
|
$leArray = array( |
1619
|
|
|
'list' => 'allimages', |
1620
|
|
|
'_code' => 'ai', |
1621
|
|
|
'aidir' => $dir, |
1622
|
|
|
'aiprop' => implode( '|', $prop ), |
1623
|
|
|
'_limit' => $limit |
1624
|
|
|
); |
1625
|
|
|
|
1626
|
|
|
if( !is_null( $from ) ) $leArray['aifrom'] = $from; |
1627
|
|
|
if( !is_null( $prefix ) ) $leArray['aiprefix'] = $prefix; |
1628
|
|
|
if( !is_null( $minsize ) ) $leArray['aiminsize'] = $minsize; |
1629
|
|
|
if( !is_null( $maxsize ) ) $leArray['aimaxsize'] = $maxsize; |
1630
|
|
|
if( !is_null( $sha1 ) ) $leArray['aisha1'] = $sha1; |
1631
|
|
|
if( !is_null( $base36 ) ) $leArray['aisha1base36'] = $base36; |
1632
|
|
|
|
1633
|
|
|
Hooks::runHook( 'PreQueryAllimages', array( &$leArray ) ); |
1634
|
|
|
|
1635
|
|
|
pecho( "Getting list of all images...\n\n", PECHO_NORMAL ); |
1636
|
|
|
|
1637
|
|
|
return $this->listHandler( $leArray ); |
1638
|
|
|
|
1639
|
|
|
} |
1640
|
|
|
|
1641
|
|
|
/** |
1642
|
|
|
* Enumerate all pages sequentially |
1643
|
|
|
* |
1644
|
|
|
* @access public |
1645
|
|
|
* @link http://www.mediawiki.org/wiki/API:Query_-_Lists#allpages_.2F_le |
1646
|
|
|
* @param array $namespace The namespace to enumerate. (default: array( 0 )) |
1647
|
|
|
* @param string $prefix Search for all page titles that begin with this value. (default: null) |
1648
|
|
|
* @param string $from The page title to start enumerating from. (default: null) |
1649
|
|
|
* @param string $redirects Which pages to list: all, redirects, or nonredirects (default: all) |
1650
|
|
|
* @param string $minsize Limit to pages with at least this many bytes (default: null) |
1651
|
|
|
* @param string $maxsize Limit to pages with at most this many bytes (default: null) |
1652
|
|
|
* @param array $protectiontypes Limit to protected pages. Examples: array( 'edit' ), array( 'move' ), array( 'edit', 'move' ). (default: array()) |
1653
|
|
|
* @param array $protectionlevels Limit to protected pages. Examples: array( 'autoconfirmed' ), array( 'sysop' ), array( 'autoconfirmed', 'sysop' ). (default: array()) |
1654
|
|
|
* @param string $dir Direction in which to list (default: 'ascending') |
1655
|
|
|
* @param string $interwiki Filter based on whether a page has langlinks (either withlanglinks, withoutlanglinks, or all (default)) |
1656
|
|
|
* @param int $limit How many results to retrieve (default: null i.e. all) |
1657
|
|
|
* @return array List of pages |
1658
|
|
|
*/ |
1659
|
|
|
public function allpages( $namespace = array( 0 ), $prefix = null, $from = null, $redirects = 'all', $minsize = null, $maxsize = null, $protectiontypes = array(), $protectionlevels = array(), $dir = 'ascending', $interwiki = 'all', $limit = 50 ) { |
1660
|
|
|
$leArray = array( |
1661
|
|
|
'list' => 'allpages', |
1662
|
|
|
'_code' => 'ap', |
1663
|
|
|
'apdir' => $dir, |
1664
|
|
|
'apnamespace' => $namespace, |
1665
|
|
|
'apfilterredir' => $redirects, |
1666
|
|
|
'apfilterlanglinks' => $interwiki, |
1667
|
|
|
'_limit' => $limit |
1668
|
|
|
); |
1669
|
|
|
|
1670
|
|
|
if( count( $protectiontypes ) ) { |
1671
|
|
|
// Trying to filter by protection status |
1672
|
|
|
$leArray['apprtype'] = implode( '|', $protectiontypes ); |
1673
|
|
|
if( count( $protectionlevels ) ) $leArray['apprlevel'] = implode( '|', $protectionlevels ); |
1674
|
|
|
} elseif( count( $protectionlevels ) ) { |
1675
|
|
|
pecho( 'If $protectionlevels is specified, $protectiontypes must also be specified.', PECHO_FATAL ); |
1676
|
|
|
return false; |
1677
|
|
|
} |
1678
|
|
|
|
1679
|
|
|
if( !is_null( $from ) ) $leArray['apfrom'] = $from; // |
1680
|
|
|
if( !is_null( $prefix ) ) $leArray['apprefix'] = $prefix; // |
1681
|
|
|
if( !is_null( $minsize ) ) $leArray['apminsize'] = $minsize; // |
1682
|
|
|
if( !is_null( $maxsize ) ) $leArray['apmaxsize'] = $maxsize; // |
1683
|
|
|
|
1684
|
|
|
Hooks::runHook( 'PreQueryAllpages', array( &$leArray ) ); |
1685
|
|
|
|
1686
|
|
|
pecho( "Getting list of all pages...\n\n", PECHO_NORMAL ); |
1687
|
|
|
|
1688
|
|
|
return $this->listHandler( $leArray ); |
1689
|
|
|
} |
1690
|
|
|
|
1691
|
|
|
/** |
1692
|
|
|
* Enumerate all internal links that point to a given namespace |
1693
|
|
|
* |
1694
|
|
|
* @access public |
1695
|
|
|
* @link http://www.mediawiki.org/wiki/API:Query_-_Lists#alllinks_.2F_le |
1696
|
|
|
* @param array $namespace The namespace to enumerate. (default: array( 0 )) |
1697
|
|
|
* @param string $prefix Search for all page titles that begin with this value. (default: null) |
1698
|
|
|
* @param string $from The page title to start enumerating from. (default: null) |
1699
|
|
|
* @param string $continue When more results are available, use this to continue. (default: null) |
1700
|
|
|
* @param bool $unique Set to true in order to only show unique links (default: true) |
1701
|
|
|
* @param array $prop What pieces of information to include: ids and/or title. (default: array( 'ids', 'title' )) |
1702
|
|
|
* @param int $limit How many results to retrieve (default: null i.e. all). |
1703
|
|
|
* @return array List of links |
1704
|
|
|
*/ |
1705
|
|
|
public function alllinks( $namespace = array( 0 ), $prefix = null, $from = null, $continue = null, $unique = false, $prop = array( |
1706
|
|
|
'ids', 'title' |
1707
|
|
|
), $limit = 50 ) { |
1708
|
|
|
$leArray = array( |
1709
|
|
|
'list' => 'alllinks', |
1710
|
|
|
'_code' => 'al', |
1711
|
|
|
'alnamespace' => $namespace, |
1712
|
|
|
'alprop' => implode( '|', $prop ), |
1713
|
|
|
'_limit' => $limit |
1714
|
|
|
); |
1715
|
|
|
|
1716
|
|
|
if( !is_null( $from ) ) $leArray['alfrom'] = $from; |
1717
|
|
|
if( !is_null( $prefix ) ) $leArray['alprefix'] = $prefix; |
1718
|
|
|
if( !is_null( $continue ) ) $leArray['alcontinue'] = $continue; |
1719
|
|
|
if( $unique ) $leArray['alunique'] = ''; |
1720
|
|
|
$leArray['limit'] = $this->apiQueryLimit; |
1721
|
|
|
|
1722
|
|
|
Hooks::runHook( 'PreQueryAlllinks', array( &$leArray ) ); |
1723
|
|
|
|
1724
|
|
|
pecho( "Getting list of all internal links...\n\n", PECHO_NORMAL ); |
1725
|
|
|
|
1726
|
|
|
return $this->listHandler( $leArray ); |
1727
|
|
|
} |
1728
|
|
|
|
1729
|
|
|
/** |
1730
|
|
|
* Enumerate all registered users |
1731
|
|
|
* |
1732
|
|
|
* @access public |
1733
|
|
|
* @link http://www.mediawiki.org/wiki/API:Query_-_Lists#alllinks_.2F_le |
1734
|
|
|
* @param string $prefix Search for all usernames that begin with this value. (default: null) |
1735
|
|
|
* @param array $groups Limit users to a given group name (default: array()) |
1736
|
|
|
* @param string $from The username to start enumerating from. (default: null) |
1737
|
|
|
* @param bool $editsonly Set to true in order to only show users with edits (default: false) |
1738
|
|
|
* @param array $prop What pieces of information to include (default: array( 'blockinfo', 'groups', 'editcount', 'registration' )) |
1739
|
|
|
* @param int $limit How many results to retrieve (default: null i.e. all). |
1740
|
|
|
* @return array List of users |
1741
|
|
|
*/ |
1742
|
|
|
public function allusers( $prefix = null, $groups = array(), $from = null, $editsonly = false, $prop = array( |
1743
|
|
|
'blockinfo', 'groups', 'editcount', 'registration' |
1744
|
|
|
), $limit = 50 ) { |
1745
|
|
|
$leArray = array( |
1746
|
|
|
'list' => 'allusers', |
1747
|
|
|
'_code' => 'au', |
1748
|
|
|
'auprop' => implode( '|', $prop ), |
1749
|
|
|
'_limit' => $limit |
1750
|
|
|
); |
1751
|
|
|
|
1752
|
|
|
if( !is_null( $from ) ) $leArray['aufrom'] = $from; |
1753
|
|
|
if( !is_null( $prefix ) ) $leArray['auprefix'] = $prefix; |
1754
|
|
|
if( count( $groups ) ) $leArray['augroup'] = implode( '|', $groups ); |
1755
|
|
|
if( $editsonly ) $leArray['auwitheditsonly'] = ''; |
1756
|
|
|
|
1757
|
|
|
Hooks::runHook( 'PreQueryAllusers', array( &$leArray ) ); |
1758
|
|
|
|
1759
|
|
|
pecho( "Getting list of all users...\n\n", PECHO_NORMAL ); |
1760
|
|
|
|
1761
|
|
|
return $this->listHandler( $leArray ); |
1762
|
|
|
} |
1763
|
|
|
|
1764
|
|
|
public function listblocks() { |
1765
|
|
|
pecho( "Error: " . __METHOD__ . " has not been programmed as of yet.\n\n", PECHO_ERROR ); |
1766
|
|
|
} |
1767
|
|
|
|
1768
|
|
|
/** |
1769
|
|
|
* Retrieves the titles of member pages of the given category |
1770
|
|
|
* |
1771
|
|
|
* @access public |
1772
|
|
|
* @param string $category Category to retieve |
1773
|
|
|
* @param bool $subcat Should subcategories be checked (default: false) |
1774
|
|
|
* @param string|array $namespace Restrict results to the given namespace (default: null i.e. all) |
1775
|
|
|
* @param int $limit How many results to retrieve (default: null i.e. all) |
1776
|
|
|
* @return array Array of titles |
1777
|
|
|
*/ |
1778
|
|
|
public function categorymembers( $category, $subcat = false, $namespace = null, $limit = 50 ) { |
1779
|
|
|
$cmArray = array( |
1780
|
|
|
'list' => 'categorymembers', |
1781
|
|
|
'_code' => 'cm', |
1782
|
|
|
'cmtitle' => $category, |
1783
|
|
|
'cmtype' => 'page', |
1784
|
|
|
'_limit' => $limit |
1785
|
|
|
); |
1786
|
|
|
|
1787
|
|
|
if( $subcat ) $cmArray['cmtype'] = 'page|subcat'; |
1788
|
|
|
if( $namespace !== null ) { |
1789
|
|
|
if( is_array( $namespace ) ) $namespace = implode( '|', $namespace ); |
1790
|
|
|
$cmArray['cmnamespace'] = $namespace; |
1791
|
|
|
} |
1792
|
|
|
|
1793
|
|
|
Hooks::runHook( 'PreQueryCategorymembers', array( &$cmArray ) ); |
1794
|
|
|
|
1795
|
|
|
pecho( "Getting list of pages in the $category category...\n\n", PECHO_NORMAL ); |
1796
|
|
|
|
1797
|
|
|
return $this->listHandler( $cmArray ); |
1798
|
|
|
} |
1799
|
|
|
|
1800
|
|
|
/** |
1801
|
|
|
* Returns array of pages that embed (transclude) the page given. |
1802
|
|
|
* |
1803
|
|
|
* @see Page::embeddedin() |
1804
|
|
|
* @access public |
1805
|
|
|
* @param string $title The title of the page being embedded. |
1806
|
|
|
* @param array $namespace Which namespaces to search (default: null). |
1807
|
|
|
* @param int $limit How many results to retrieve (default: null i.e. all). |
1808
|
|
|
* @return array A list of pages the title is transcluded in. |
1809
|
|
|
*/ |
1810
|
|
|
public function embeddedin( $title, $namespace = null, $limit = 50 ) { |
1811
|
|
|
Peachy::deprecatedWarn( 'Wiki::embeddedin()', 'Page::embeddedin()' ); |
1812
|
|
|
$page = $this->initPage( $title ); |
1813
|
|
|
return $page->embeddedin( $namespace, $limit ); |
1814
|
|
|
} |
1815
|
|
|
|
1816
|
|
|
/** |
1817
|
|
|
* List change tags enabled on the wiki. |
1818
|
|
|
* |
1819
|
|
|
* @access public |
1820
|
|
|
* @param array $prop Which properties to retrieve (default: array( 'name', 'displayname', 'description', 'hitcount' ) i.e. all). |
1821
|
|
|
* @param int $limit How many results to retrieve (default: null i.e. all). |
1822
|
|
|
* @return array The tags retrieved. |
1823
|
|
|
*/ |
1824
|
|
|
public function tags( $prop = array( 'name', 'displayname', 'description', 'hitcount' ), $limit = 50 ) { |
1825
|
|
|
$tgArray = array( |
1826
|
|
|
'list' => 'tags', |
1827
|
|
|
'_code' => 'tg', |
1828
|
|
|
'tgprop' => implode( '|', $prop ), |
1829
|
|
|
'_limit' => $limit |
1830
|
|
|
); |
1831
|
|
|
|
1832
|
|
|
Hooks::runHook( 'PreQueryTags', array( &$tgArray ) ); |
1833
|
|
|
|
1834
|
|
|
pecho( "Getting list of all tags...\n\n", PECHO_NORMAL ); |
1835
|
|
|
|
1836
|
|
|
return $this->listHandler( $tgArray ); |
1837
|
|
|
} |
1838
|
|
|
|
1839
|
|
|
/** |
1840
|
|
|
* @FIXME Implement this method |
1841
|
|
|
* |
1842
|
|
|
* @param null $minor |
1843
|
|
|
* @param null $bot |
1844
|
|
|
* @param null $anon |
1845
|
|
|
* @param null $patrolled |
1846
|
|
|
* @param null $namespace |
1847
|
|
|
* @param null $user |
1848
|
|
|
* @param null $excludeuser |
1849
|
|
|
* @param null $start |
1850
|
|
|
* @param null $end |
1851
|
|
|
* @param array $prop |
1852
|
|
|
* @param int $limit |
1853
|
|
|
*/ |
1854
|
|
|
public function get_watchlist( |
1855
|
|
|
$minor = null, |
1856
|
|
|
$bot = null, |
1857
|
|
|
$anon = null, |
1858
|
|
|
$patrolled = null, |
1859
|
|
|
$namespace = null, |
1860
|
|
|
$user = null, |
1861
|
|
|
$excludeuser = null, |
1862
|
|
|
$start = null, |
1863
|
|
|
$end = null, |
1864
|
|
|
$prop = array( 'ids', 'title', 'flags', 'user', 'comment', 'parsedcomment', 'timestamp', 'patrol', 'sizes', 'notificationtimestamp' ), |
1865
|
|
|
$limit = 50 |
1866
|
|
|
) { |
1867
|
|
|
|
1868
|
|
|
pecho( "Error: " . __METHOD__ . " has not been programmed as of yet.\n\n", PECHO_ERROR ); |
1869
|
|
|
} |
1870
|
|
|
|
1871
|
|
|
/** |
1872
|
|
|
* @FIXME Implement this method |
1873
|
|
|
* |
1874
|
|
|
* @param null $namespace |
1875
|
|
|
* @param null $changed |
1876
|
|
|
*/ |
1877
|
|
|
public function get_watchlistraw( $namespace = null, $changed = null ) { |
1878
|
|
|
pecho( "Error: " . __METHOD__ . " has not been programmed as of yet.\n\n", PECHO_ERROR ); |
1879
|
|
|
} |
1880
|
|
|
|
1881
|
|
|
/** |
1882
|
|
|
* Returns details of usage of an external URL on the wiki. |
1883
|
|
|
* |
1884
|
|
|
* @access public |
1885
|
|
|
* @param string $url The url to search for links to, without a protocol. * can be used as a wildcard. |
1886
|
|
|
* @param string $pgProtocol The protocol to accompany the URL. Only certain values are allowed, depending on how $wgUrlProtocols is set on the wiki; by default the allowed values are 'http://', 'https://', 'ftp://', 'irc://', 'gopher://', 'telnet://', 'nntp://', 'worldwind://', 'mailto:' and 'news:'. Default 'http://'. |
1887
|
|
|
* @param array $prop Properties to return in array form; the options are 'ids', 'title' and 'url'. Default null (all). |
1888
|
|
|
* @param string $namespace A pipe '|' separated list of namespace numbers to check. Default null (all). |
1889
|
|
|
* @param int $limit A hard limit on the number of transclusions to fetch. Default null (all). |
1890
|
|
|
* @return array Details about the usage of that external link on the wiki. |
1891
|
|
|
*/ |
1892
|
|
|
public function exturlusage( $url, $pgProtocol = 'http', $prop = array( 'title' ), $namespace = null, $limit = 50 ) { |
1893
|
|
|
$tArray = array( |
1894
|
|
|
'list' => 'exturlusage', |
1895
|
|
|
'_code' => 'eu', |
1896
|
|
|
'euquery' => $url, |
1897
|
|
|
'euprotocol' => $pgProtocol, |
1898
|
|
|
'_limit' => $limit, |
1899
|
|
|
'euprop' => implode( '|', $prop ) |
1900
|
|
|
); |
1901
|
|
|
|
1902
|
|
|
if( !is_null( $namespace ) ) { |
1903
|
|
|
$tArray['eunamespace'] = $namespace; |
1904
|
|
|
} |
1905
|
|
|
|
1906
|
|
|
Hooks::runHook( 'PreQueryExturlusage', array( &$tArray ) ); |
1907
|
|
|
|
1908
|
|
|
pecho( "Getting list of all pages that $url is used in...\n\n", PECHO_NORMAL ); |
1909
|
|
|
|
1910
|
|
|
return $this->listHandler( $tArray ); |
1911
|
|
|
|
1912
|
|
|
} |
1913
|
|
|
|
1914
|
|
|
/** |
1915
|
|
|
* @FIXME Implement this method |
1916
|
|
|
* |
1917
|
|
|
* @param array $users |
1918
|
|
|
* @param array $prop |
1919
|
|
|
*/ |
1920
|
|
|
public function users( |
1921
|
|
|
$users = array(), |
1922
|
|
|
$prop = array( 'blockinfo', 'groups', 'editcount', 'registration', 'emailable', 'gender' ) |
1923
|
|
|
) { |
1924
|
|
|
pecho( "Error: " . __METHOD__ . " has not been programmed as of yet.\n\n", PECHO_ERROR ); |
1925
|
|
|
} |
1926
|
|
|
|
1927
|
|
|
/** |
1928
|
|
|
* Returns the titles of some random pages. |
1929
|
|
|
* |
1930
|
|
|
* @access public |
1931
|
|
|
* @param array|string $namespaces Namespaces to select from (default: array( 0 ) ). |
1932
|
|
|
* @param int $limit The number of titles to return (default: 1). |
1933
|
|
|
* @param bool $onlyredirects Only include redirects (true) or only include non-redirects (default; false). |
1934
|
|
|
* @return array A series of random titles. |
1935
|
|
|
*/ |
1936
|
|
|
public function random( $namespaces = array( 0 ), $limit = 1, $onlyredirects = false ) { |
1937
|
|
|
$rnArray = array( |
1938
|
|
|
'_code' => 'rn', |
1939
|
|
|
'list' => 'random', |
1940
|
|
|
'rnnamespace' => $namespaces, |
1941
|
|
|
'_limit' => $limit, |
1942
|
|
|
'rnredirect' => ( is_null( $onlyredirects ) || !$onlyredirects ) ? null : "true", |
1943
|
|
|
'_lhtitle' => 'title' |
1944
|
|
|
); |
1945
|
|
|
|
1946
|
|
|
Hooks::runHook( 'PreQueryRandom', array( &$rnArray ) ); |
1947
|
|
|
|
1948
|
|
|
pecho( "Getting random page...\n\n", PECHO_NORMAL ); |
1949
|
|
|
|
1950
|
|
|
return $this->listHandler( $rnArray ); |
1951
|
|
|
} |
1952
|
|
|
|
1953
|
|
|
/** |
1954
|
|
|
* @FIXME Implement this method |
1955
|
|
|
* |
1956
|
|
|
* @param array $namespace |
1957
|
|
|
*/ |
1958
|
|
|
public function protectedtitles( $namespace = array( 0 ) ) { |
1959
|
|
|
|
1960
|
|
|
pecho( "Error: " . __METHOD__ . " has not been programmed as of yet.\n\n", PECHO_ERROR ); |
1961
|
|
|
} |
1962
|
|
|
|
1963
|
|
|
/** |
1964
|
|
|
* Returns meta information about the wiki itself |
1965
|
|
|
* |
1966
|
|
|
* @access public |
1967
|
|
|
* @param array $prop Information to retrieve. Default: array( 'general', 'namespaces', 'namespacealiases', 'specialpagealiases', 'magicwords', 'interwikimap', 'dbrepllag', 'statistics', 'usergroups', 'extensions', 'fileextensions', 'rightsinfo', 'languages' ) |
1968
|
|
|
* @param bool $iwfilter When used with prop 'interwikimap', returns only local or only nonlocal entries of the interwiki map. True = local, false = nonlocal. Default null |
1969
|
|
|
* @return array |
1970
|
|
|
*/ |
1971
|
|
|
public function siteinfo( $prop = array( |
1972
|
|
|
'general', 'namespaces', 'namespacealiases', 'specialpagealiases', 'magicwords', 'interwikimap', 'dbrepllag', |
1973
|
|
|
'statistics', 'usergroups', 'extensions', 'fileextensions', 'rightsinfo', 'languages' |
1974
|
|
|
), $iwfilter = null ) { |
1975
|
|
|
|
1976
|
|
|
$siArray = array( |
1977
|
|
|
'action' => 'query', |
1978
|
|
|
'meta' => 'siteinfo', |
1979
|
|
|
'siprop' => implode( '|', $prop ), |
1980
|
|
|
); |
1981
|
|
|
|
1982
|
|
|
if( in_array( 'interwikimap', $prop ) && $iwfilter ) { |
1983
|
|
|
$siArray['sifilteriw'] = ''; |
1984
|
|
|
} elseif( in_array( 'interwikimap', $prop ) && $iwfilter ) $siArray['sifilteriw'] = 'no'; |
1985
|
|
|
|
1986
|
|
|
if( in_array( 'dbrepllag', $prop ) ) $siArray['sishowalldb'] = ''; |
1987
|
|
|
if( in_array( 'usergroups', $prop ) ) $siArray['sinumberingroup'] = ''; |
1988
|
|
|
|
1989
|
|
|
Hooks::runHook( 'PreQuerySiteInfo', array( &$siArray ) ); |
1990
|
|
|
|
1991
|
|
|
pecho( "Getting site information...\n\n", PECHO_NORMAL ); |
1992
|
|
|
|
1993
|
|
|
return $this->apiQuery( $siArray ); |
1994
|
|
|
} |
1995
|
|
|
|
1996
|
|
|
/** |
1997
|
|
|
* Returns a list of system messages (MediaWiki:... pages) |
1998
|
|
|
* |
1999
|
|
|
* @access public |
2000
|
|
|
* @param string $filter Return only messages that contain this string. Default null |
2001
|
|
|
* @param array $messages Which messages to output. Default array(), which means all. |
2002
|
|
|
* @param bool $parse Set to true to enable parser, will preprocess the wikitext of message. (substitutes magic words, handle templates etc.) Default false |
2003
|
|
|
* @param array $args Arguments to be substituted into message. Default array(). |
2004
|
|
|
* @param string $lang Return messages in this language. Default null |
2005
|
|
|
* @return array |
2006
|
|
|
*/ |
2007
|
|
|
public function allmessages( $filter = null, $messages = array(), $parse = false, $args = array(), $lang = null ) { |
2008
|
|
|
$amArray = array( |
2009
|
|
|
'action' => 'query', |
2010
|
|
|
'meta' => 'allmessages', |
2011
|
|
|
); |
2012
|
|
|
|
2013
|
|
|
if( !is_null( $filter ) ) $amArray['amfilter'] = $filter; |
2014
|
|
|
if( count( $messages ) ) $amArray['ammessages'] = implode( '|', $messages ); |
2015
|
|
|
if( $parse ) $amArray['amenableparser'] = ''; |
2016
|
|
|
if( count( $args ) ) $amArray['amargs'] = implode( '|', $args ); |
2017
|
|
|
if( !is_null( $lang ) ) $amArray['amlang'] = $lang; |
2018
|
|
|
|
2019
|
|
|
Hooks::runHook( 'PreQueryAllMessages', array( &$amArray ) ); |
2020
|
|
|
|
2021
|
|
|
pecho( "Getting list of system messages...\n\n", PECHO_NORMAL ); |
2022
|
|
|
|
2023
|
|
|
return $this->apiQuery( $amArray ); |
2024
|
|
|
} |
2025
|
|
|
|
2026
|
|
|
/** |
2027
|
|
|
* Expand and parse all templates in wikitext |
2028
|
|
|
* |
2029
|
|
|
* @access public |
2030
|
|
|
* @param string $text Text to parse |
2031
|
|
|
* @param string $title Title to use for expanding magic words, etc. (e.g. {{PAGENAME}}). Default 'API'. |
2032
|
|
|
* @param bool $generatexml Generate XML parse tree. Default false |
2033
|
|
|
* @return string |
2034
|
|
|
*/ |
2035
|
|
|
public function expandtemplates( $text, $title = null, $generatexml = false ) { |
2036
|
|
|
$etArray = array( |
2037
|
|
|
'action' => 'expandtemplates', |
2038
|
|
|
'text' => $text |
2039
|
|
|
); |
2040
|
|
|
|
2041
|
|
|
if( $generatexml ) $etArray['generatexml'] = ''; |
2042
|
|
|
if( !is_null( $title ) ) $etArray['title'] = $title; |
2043
|
|
|
|
2044
|
|
|
Hooks::runHook( 'PreQueryExpandtemplates', array( &$etArray ) ); |
2045
|
|
|
|
2046
|
|
|
pecho( "Parsing templates...\n\n", PECHO_NORMAL ); |
2047
|
|
|
|
2048
|
|
|
$ret = $this->apiQuery( $etArray ); |
2049
|
|
|
return $ret['expandtemplates']['*']; |
2050
|
|
|
|
2051
|
|
|
} |
2052
|
|
|
|
2053
|
|
|
/** |
2054
|
|
|
* Parses wikitext and returns parser output |
2055
|
|
|
* |
2056
|
|
|
* @access public |
2057
|
|
|
* @param string $text Wikitext to parse. Default null. |
2058
|
|
|
* @param string $title Title of page the text belongs to, used for {{PAGENAME}}. Default null. |
2059
|
|
|
* @param string $summary Summary to parse. Default null. |
2060
|
|
|
* @param bool $pst Run a pre-save transform, expanding {{subst:}} and ~~~~. Default false. |
2061
|
|
|
* @param bool $onlypst Run a pre-save transform, but don't parse it. Default false. |
2062
|
|
|
* @param string $uselang Language to parse in. Default 'en'. |
2063
|
|
|
* @param array $prop Properties to retrieve. Default array( 'text', 'langlinks', 'categories', 'links', 'templates', 'images', 'externallinks', 'sections', 'revid', 'displaytitle', 'headitems', 'headhtml' ) |
2064
|
|
|
* @param string $page Parse the content of this page. Cannot be used together with $text and $title. |
2065
|
|
|
* @param string $oldid Parse the content of this revision. Overrides $page and $pageid. |
2066
|
|
|
* @param string $pageid Parse the content of this page. Overrides page. |
2067
|
|
|
* @param bool $redirects If the page or the pageid parameter is set to a redirect, resolve it. Default true. |
2068
|
|
|
* @param string $section Only retrieve the content of this section number. Default null. |
2069
|
|
|
* @param bool $disablepp Disable the PP Report from the parser output. Defaut false. |
2070
|
|
|
* @param bool $generatexml Generate XML parse tree (requires prop=wikitext). Default false. |
2071
|
|
|
* @param string $contentformat Content serialization format used for the input text. Default null. |
2072
|
|
|
* @param string $contentmodel Content model of the new content. Default null. |
2073
|
|
|
* @param string $mobileformat Return parse output in a format suitable for mobile devices. Default null. |
2074
|
|
|
* @param bool $noimages Disable images in mobile output |
2075
|
|
|
* @param bool $mainpage Apply mobile main page transformations |
2076
|
|
|
* @return array |
2077
|
|
|
*/ |
2078
|
|
|
public function parse( $text = null, $title = null, $summary = null, $pst = false, $onlypst = false, $prop = null, $uselang = 'en', $page = null, $oldid = null, $pageid = null, $redirects = false, $section = null, $disablepp = false, $generatexml = false, $contentformat = null, $contentmodel = null, $mobileformat = null, $noimages = false, $mainpage = false ) { |
2079
|
|
|
|
2080
|
|
|
if( $prop === null ) { |
2081
|
|
|
$prop = array( |
2082
|
|
|
'text', 'langlinks', 'categories', 'categorieshtml', 'languageshtml', 'links', 'templates', 'images', |
2083
|
|
|
'externallinks', 'sections', 'revid', 'displaytitle', 'headitems', 'headhtml', 'iwlinks', 'wikitext', |
2084
|
|
|
'properties' |
2085
|
|
|
); |
2086
|
|
|
}; |
2087
|
|
|
|
2088
|
|
|
$apiArray = array( |
2089
|
|
|
'action' => 'parse', |
2090
|
|
|
'uselang' => $uselang, |
2091
|
|
|
'prop' => implode( '|', $prop ), |
2092
|
|
|
); |
2093
|
|
|
|
2094
|
|
|
if( $generatexml ) { |
2095
|
|
|
if( !in_array( 'wikitext', $prop ) ) $prop[] = 'wikitext'; |
2096
|
|
|
$apiArray['generatexml'] = ''; |
2097
|
|
|
} |
2098
|
|
|
|
2099
|
|
|
if( !is_null( $text ) ) $apiArray['text'] = $text; |
2100
|
|
|
if( !is_null( $title ) ) $apiArray['title'] = $title; |
2101
|
|
|
if( !is_null( $summary ) ) $apiArray['summary'] = $summary; |
2102
|
|
|
if( !is_null( $pageid ) ) $apiArray['pageid'] = $pageid; |
2103
|
|
|
if( !is_null( $page ) ) $apiArray['page'] = $page; |
2104
|
|
|
if( !is_null( $oldid ) ) $apiArray['oldid'] = $oldid; |
2105
|
|
|
if( !is_null( $section ) ) $apiArray['section'] = $section; |
2106
|
|
|
if( !is_null( $contentformat ) ) { |
2107
|
|
|
if( $contentformat == 'text/x-wiki' || $contentformat == 'text/javascript' || $contentformat == 'text/css' || $contentformat == 'text/plain' ) { |
2108
|
|
|
$apiArray['contentformat'] = $contentformat; |
2109
|
|
|
} else pecho( "Error: contentformat not specified correctly. Omitting value...\n\n", PECHO_ERROR ); |
2110
|
|
|
} |
2111
|
|
|
if( !is_null( $contentmodel ) ) { |
2112
|
|
|
if( $contentmodel == 'wikitext' || $contentmodel == 'javascript' || $contentmodel == 'css' || $contentmodel == 'text' || $contentmodel == 'Scribunto' ) { |
2113
|
|
|
$apiArray['contentmodel'] = $contentmodel; |
2114
|
|
|
} else pecho( "Error: contentmodel not specified correctly. Omitting value...\n\n", PECHO_ERROR ); |
2115
|
|
|
} |
2116
|
|
|
if( !is_null( $mobileformat ) ) { |
2117
|
|
|
if( $mobileformat == 'wml' || $mobileformat == 'html' ) { |
2118
|
|
|
$apiArray['mobileformat'] = $mobileformat; |
2119
|
|
|
} else pecho( "Error: mobileformat not specified correctly. Omitting value...\n\n", PECHO_ERROR ); |
2120
|
|
|
} |
2121
|
|
|
|
2122
|
|
|
if( $pst ) $apiArray['pst'] = ''; |
2123
|
|
|
if( $onlypst ) $apiArray['onlypst'] = ''; |
2124
|
|
|
if( $redirects ) $apiArray['redirects'] = ''; |
2125
|
|
|
if( $disablepp ) $apiArray['disablepp'] = ''; |
2126
|
|
|
if( $noimages ) $apiArray['noimages'] = ''; |
2127
|
|
|
if( $mainpage ) $apiArray['mainpage'] = ''; |
2128
|
|
|
|
2129
|
|
|
Hooks::runHook( 'PreParse', array( &$apiArray ) ); |
2130
|
|
|
|
2131
|
|
|
pecho( "Parsing...\n\n", PECHO_NORMAL ); |
2132
|
|
|
|
2133
|
|
|
return $this->apiQuery( $apiArray ); |
2134
|
|
|
} |
2135
|
|
|
|
2136
|
|
|
/** |
2137
|
|
|
* Patrols a page or revision |
2138
|
|
|
* |
2139
|
|
|
* @access public |
2140
|
|
|
* @param int $rcid Recent changes ID to patrol |
2141
|
|
|
* @return array |
2142
|
|
|
*/ |
2143
|
|
|
public function patrol( $rcid = 0 ) { |
2144
|
|
|
Hooks::runHook( 'PrePatrol', array( &$rcid ) ); |
2145
|
|
|
|
2146
|
|
|
pecho( "Patrolling $rcid...\n\n", PECHO_NORMAL ); |
2147
|
|
|
|
2148
|
|
|
$this->get_tokens(); |
2149
|
|
|
|
2150
|
|
|
return $this->apiQuery( |
2151
|
|
|
array( |
2152
|
|
|
'action' => 'patrol', |
2153
|
|
|
'rcid' => $rcid, |
2154
|
|
|
'token' => $this->tokens['patrol'] |
2155
|
|
|
) |
2156
|
|
|
); |
2157
|
|
|
} |
2158
|
|
|
|
2159
|
|
|
/** |
2160
|
|
|
* Import a page from another wiki, or an XML file. |
2161
|
|
|
* |
2162
|
|
|
* @access public |
2163
|
|
|
* @param mixed|string $page local XML file or page to another wiki. |
2164
|
|
|
* @param string $summary Import summary. Default ''. |
2165
|
|
|
* @param string $site For interwiki imports: wiki to import from. Default null. |
2166
|
|
|
* @param bool $fullhistory For interwiki imports: import the full history, not just the current version. Default true. |
2167
|
|
|
* @param bool $templates For interwiki imports: import all included templates as well. Default true. |
2168
|
|
|
* @param int $namespace For interwiki imports: import to this namespace |
2169
|
|
|
* @param bool $root Import as subpage of this page. Default false. |
2170
|
|
|
* @return bool |
2171
|
|
|
*/ |
2172
|
|
|
public function import( $page = null, $summary = '', $site = null, $fullhistory = true, $templates = true, $namespace = null, $root = false ) { |
2173
|
|
|
|
2174
|
|
|
$tokens = $this->get_tokens(); |
2175
|
|
|
|
2176
|
|
|
$apiArray = array( |
2177
|
|
|
'action' => 'import', |
2178
|
|
|
'summary' => $summary, |
2179
|
|
|
'token' => $tokens['import'] |
2180
|
|
|
); |
2181
|
|
|
|
2182
|
|
|
if( $root ) $apiArray['rootpage'] = ''; |
2183
|
|
|
|
2184
|
|
|
if( !is_null( $page ) ) { |
2185
|
|
|
if( !is_file( $page ) ) { |
2186
|
|
|
$apiArray['interwikipage'] = $page; |
2187
|
|
|
if( !is_null( $site ) ) { |
2188
|
|
|
$apiArray['interwikisource'] = $site; |
2189
|
|
|
} else { |
2190
|
|
|
pecho( "Error: You must specify a site to import from.\n\n", PECHO_FATAL ); |
2191
|
|
|
return false; |
2192
|
|
|
} |
2193
|
|
|
if( !is_null( $namespace ) ) $apiArray['namespace'] = $namespace; |
2194
|
|
|
if( $fullhistory ) $apiArray['fullhistory'] = ''; |
2195
|
|
|
if( $templates ) $apiArray['templates'] = ''; |
2196
|
|
|
pecho( "Importing $page from $site...\n\n", PECHO_NOTICE ); |
2197
|
|
|
} else { |
2198
|
|
|
$apiArray['xml'] = "@$page"; |
2199
|
|
|
pecho( "Uploading XML...\n\n", PECHO_NOTICE ); |
2200
|
|
|
} |
2201
|
|
|
} else { |
2202
|
|
|
pecho( "Error: You must specify an interwiki page or a local XML file to import.\n\n", PECHO_FATAL ); |
2203
|
|
|
return false; |
2204
|
|
|
} |
2205
|
|
|
|
2206
|
|
|
$result = $this->apiQuery( $apiArray, true ); |
2207
|
|
|
|
2208
|
|
|
if( isset( $result['import'] ) ) { |
2209
|
|
|
if( isset( $result['import']['page'] ) ) { |
2210
|
|
|
return true; |
2211
|
|
|
} else { |
2212
|
|
|
pecho( "Import error...\n\n" . print_r( $result['import'], true ) . "\n\n", PECHO_FATAL ); |
2213
|
|
|
return false; |
2214
|
|
|
} |
2215
|
|
|
} else { |
2216
|
|
|
pecho( "Import error...\n\n" . print_r( $result, true ), PECHO_FATAL ); |
2217
|
|
|
return false; |
2218
|
|
|
} |
2219
|
|
|
|
2220
|
|
|
} |
2221
|
|
|
|
2222
|
|
|
public function export() { |
2223
|
|
|
pecho( "Error: " . __METHOD__ . " has not been programmed as of yet.\n\n", PECHO_ERROR ); |
2224
|
|
|
} |
2225
|
|
|
|
2226
|
|
|
/** |
2227
|
|
|
* Generate a diff between two or three revision IDs |
2228
|
|
|
* |
2229
|
|
|
* @access public |
2230
|
|
|
* |
2231
|
|
|
* @param string $method Revision method. Options: unified, inline, context, threeway, raw |
2232
|
|
|
* (default: 'unified') |
2233
|
|
|
* @param mixed $rev1 |
2234
|
|
|
* @param mixed $rev2 |
2235
|
|
|
* @param mixed $rev3 |
2236
|
|
|
* |
2237
|
|
|
* @return string|bool False on failure |
2238
|
|
|
* @see Diff::load |
2239
|
|
|
* |
2240
|
|
|
* @fixme: this uses Diff::load, which has been deprecated and Plugin removed from codebase |
2241
|
|
|
*/ |
2242
|
|
|
public function diff( $method = 'unified', $rev1, $rev2, $rev3 = null ) { |
2243
|
|
|
$r1array = array( |
2244
|
|
|
'action' => 'query', |
2245
|
|
|
'prop' => 'revisions', |
2246
|
|
|
'revids' => $rev1, |
2247
|
|
|
'rvprop' => 'content' |
2248
|
|
|
); |
2249
|
|
|
$r2array = array( |
2250
|
|
|
'action' => 'query', |
2251
|
|
|
'prop' => 'revisions', |
2252
|
|
|
'revids' => $rev2, |
2253
|
|
|
'rvprop' => 'content' |
2254
|
|
|
); |
2255
|
|
|
$r3array = array( |
2256
|
|
|
'action' => 'query', |
2257
|
|
|
'prop' => 'revisions', |
2258
|
|
|
'revids' => $rev3, |
2259
|
|
|
'rvprop' => 'content' |
2260
|
|
|
); |
2261
|
|
|
|
2262
|
|
|
Hooks::runHook( 'PreDiff', array( &$r1array, &$r2array, &$r3array, &$method ) ); |
2263
|
|
|
|
2264
|
|
|
$r1text = $r2text = $r3text = null; |
2265
|
|
|
if( !is_null( $rev3 ) ) { |
2266
|
|
|
pecho( "Getting $method diff of revisions $rev1, $rev2, and $rev3...\n\n", PECHO_NORMAL ); |
2267
|
|
|
$r3 = $this->apiQuery( $r3array ); |
2268
|
|
|
|
2269
|
|
|
if( isset( $r3['query']['badrevids'] ) ) { |
2270
|
|
|
pecho( "A bad third revision ID was passed.\n\n", PECHO_FATAL ); |
2271
|
|
|
return false; |
2272
|
|
|
} |
2273
|
|
|
|
2274
|
|
|
foreach( $r3['query']['pages'] as $r3pages ){ |
2275
|
|
|
$r3text = $r3pages['revisions'][0]['*']; |
2276
|
|
|
} |
2277
|
|
|
} else { |
2278
|
|
|
pecho( "Getting $method diff of revisions $rev1 and $rev2...\n\n", PECHO_NORMAL ); |
2279
|
|
|
} |
2280
|
|
|
|
2281
|
|
|
$r1 = $this->apiQuery( $r1array ); |
2282
|
|
|
$r2 = $this->apiQuery( $r2array ); |
2283
|
|
|
|
2284
|
|
|
if( isset( $r1['query']['badrevids'] ) ) { |
2285
|
|
|
pecho( "A bad first revision ID was passed.\n\n", PECHO_FATAL ); |
2286
|
|
|
return false; |
2287
|
|
|
} elseif( isset( $r2['query']['badrevids'] ) ) { |
2288
|
|
|
pecho( "A bad second revision ID was passed.\n\n", PECHO_FATAL ); |
2289
|
|
|
return false; |
2290
|
|
|
} else { |
2291
|
|
|
foreach( $r1['query']['pages'] as $r1pages ){ |
2292
|
|
|
$r1text = $r1pages['revisions'][0]['*']; |
2293
|
|
|
} |
2294
|
|
|
foreach( $r2['query']['pages'] as $r2pages ){ |
2295
|
|
|
$r2text = $r2pages['revisions'][0]['*']; |
2296
|
|
|
} |
2297
|
|
|
|
2298
|
|
|
if( $method == "raw" ) return array( $r1text, $r2text, $r3text ); |
|
|
|
|
2299
|
|
|
return Diff::load( $method, $r1text, $r2text, $r3text ); |
2300
|
|
|
} |
2301
|
|
|
} |
2302
|
|
|
|
2303
|
|
|
/** |
2304
|
|
|
* Regenerate and return edit tokens |
2305
|
|
|
* |
2306
|
|
|
* @access public |
2307
|
|
|
* @param bool $force Whether to force use of the API, not cache. |
2308
|
|
|
* @return array Edit tokens |
2309
|
|
|
*/ |
2310
|
|
|
public function get_tokens( $force = false ) { |
2311
|
|
|
Hooks::runHook( 'GetTokens', array( &$this->tokens ) ); |
2312
|
|
|
|
2313
|
|
|
if( !$force && !empty( $this->tokens ) ) return $this->tokens; |
2314
|
|
|
|
2315
|
|
|
$tokens = $this->apiQuery( |
2316
|
|
|
array( |
2317
|
|
|
'action' => 'tokens', |
2318
|
|
|
'type' => 'block|delete|deleteglobalaccount|edit|email|import|move|options|patrol|protect|setglobalaccountstatus|unblock|watch' |
2319
|
|
|
) |
2320
|
|
|
); |
2321
|
|
|
|
2322
|
|
|
foreach( $tokens['tokens'] as $y => $z ){ |
2323
|
|
|
if( in_string( 'token', $y ) ) { |
2324
|
|
|
$this->tokens[str_replace( 'token', '', $y )] = $z; |
2325
|
|
|
} |
2326
|
|
|
} |
2327
|
|
|
|
2328
|
|
|
$token = $this->apiQuery( |
2329
|
|
|
array( |
2330
|
|
|
'action' => 'query', |
2331
|
|
|
'list' => 'users', |
2332
|
|
|
'ususers' => $this->username, |
2333
|
|
|
'ustoken' => 'userrights' |
2334
|
|
|
) |
2335
|
|
|
); |
2336
|
|
|
|
2337
|
|
|
if( isset( $token['query']['users'][0]['userrightstoken'] ) ) { |
2338
|
|
|
$this->tokens['userrights'] = $token['query']['users'][0]['userrightstoken']; |
2339
|
|
|
} else { |
2340
|
|
|
pecho( "Error retrieving userrights token...\n\n", PECHO_FATAL ); |
2341
|
|
|
return array(); |
2342
|
|
|
} |
2343
|
|
|
|
2344
|
|
|
return $this->tokens; |
2345
|
|
|
|
2346
|
|
|
} |
2347
|
|
|
|
2348
|
|
|
/** |
2349
|
|
|
* Returns extensions. |
2350
|
|
|
* |
2351
|
|
|
* @access public |
2352
|
|
|
* @see Wiki::$extensions |
2353
|
|
|
* @return array Extensions in format name => version |
2354
|
|
|
*/ |
2355
|
|
|
public function get_extensions() { |
2356
|
|
|
return $this->extensions; |
2357
|
|
|
} |
2358
|
|
|
|
2359
|
|
|
/** |
2360
|
|
|
* Returns an array of the namespaces used on the current wiki. |
2361
|
|
|
* |
2362
|
|
|
* @access public |
2363
|
|
|
* @param bool $force Whether or not to force an update of any cached values first. |
2364
|
|
|
* @return array The namespaces in use in the format index => local name. |
2365
|
|
|
*/ |
2366
|
|
|
public function get_namespaces( $force = false ) { |
2367
|
|
|
if( is_null( $this->namespaces ) || $force ) { |
2368
|
|
|
$tArray = array( |
2369
|
|
|
'meta' => 'siteinfo', |
2370
|
|
|
'action' => 'query', |
2371
|
|
|
'siprop' => 'namespaces' |
2372
|
|
|
); |
2373
|
|
|
$tRes = $this->apiQuery( $tArray ); |
2374
|
|
|
|
2375
|
|
|
foreach( $tRes['query']['namespaces'] as $namespace ){ |
2376
|
|
|
$this->namespaces[$namespace['id']] = $namespace['*']; |
2377
|
|
|
$this->allowSubpages[$namespace['id']] = ( ( isset( $namespace['subpages'] ) ) ? true : false ); |
2378
|
|
|
} |
2379
|
|
|
} |
2380
|
|
|
return $this->namespaces; |
2381
|
|
|
} |
2382
|
|
|
|
2383
|
|
|
/** |
2384
|
|
|
* Removes the namespace from a title |
2385
|
|
|
* |
2386
|
|
|
* @access public |
2387
|
|
|
* @param string $title Title to remove namespace from |
2388
|
|
|
* @return string |
2389
|
|
|
*/ |
2390
|
|
|
|
2391
|
|
|
public function removeNamespace( $title ) { |
2392
|
|
|
$this->get_namespaces(); |
2393
|
|
|
|
2394
|
|
|
$exploded = explode( ':', $title, 2 ); |
2395
|
|
|
|
2396
|
|
|
foreach( $this->namespaces as $namespace ){ |
2397
|
|
|
if( $namespace == $exploded[0] ) { |
2398
|
|
|
return $exploded[1]; |
2399
|
|
|
} |
2400
|
|
|
} |
2401
|
|
|
|
2402
|
|
|
return $title; |
2403
|
|
|
} |
2404
|
|
|
|
2405
|
|
|
/** |
2406
|
|
|
* Returns an array of subpage-allowing namespaces. |
2407
|
|
|
* |
2408
|
|
|
* @access public |
2409
|
|
|
* @param bool $force Whether or not to force an update of any cached values first. |
2410
|
|
|
* @return array An array of namespaces that allow subpages. |
2411
|
|
|
*/ |
2412
|
|
|
public function get_allow_subpages( $force = false ) { |
2413
|
|
|
if( is_null( $this->allowSubpages ) || $force ) { |
2414
|
|
|
$this->get_namespaces( true ); |
2415
|
|
|
} |
2416
|
|
|
return $this->allowSubpages; |
2417
|
|
|
} |
2418
|
|
|
|
2419
|
|
|
/** |
2420
|
|
|
* Returns a boolean equal to whether or not the namespace with index given allows subpages. |
2421
|
|
|
* |
2422
|
|
|
* @access public |
2423
|
|
|
* @param int $namespace The namespace that might allow subpages. |
2424
|
|
|
* @return bool Whether or not that namespace allows subpages. |
2425
|
|
|
*/ |
2426
|
|
|
public function get_ns_allows_subpages( $namespace = 0 ) { |
2427
|
|
|
$this->get_allow_subpages(); |
2428
|
|
|
|
2429
|
|
|
return (bool)$this->allowSubpages[$namespace]; |
2430
|
|
|
} |
2431
|
|
|
|
2432
|
|
|
/** |
2433
|
|
|
* Returns user rights. |
2434
|
|
|
* |
2435
|
|
|
* @access public |
2436
|
|
|
* @see Wiki::$userRights |
2437
|
|
|
* @return array Array of user rights |
2438
|
|
|
*/ |
2439
|
|
|
public function get_userrights() { |
2440
|
|
|
return $this->userRights; |
2441
|
|
|
} |
2442
|
|
|
|
2443
|
|
|
/** |
2444
|
|
|
* Returns all the pages which start with a certain prefix, shortcut for {@link Wiki}::{@link allpages}() |
2445
|
|
|
* |
2446
|
|
|
* @param string $prefix Prefix to search for |
2447
|
|
|
* @param array $namespace Namespace IDs to search in. Default array( 0 ) |
2448
|
|
|
* @param int $limit A hard limit on the number of pages to fetch. Default null (all). |
2449
|
|
|
* @return array Titles of pages that transclude this page |
2450
|
|
|
*/ |
2451
|
|
|
public function prefixindex( $prefix = null, $namespace = array( 0 ), $limit = 50 ) { |
2452
|
|
|
return $this->allpages( $namespace, $prefix, null, 'all', null, null, array(), array(), 'ascending', 'all', $limit ); |
2453
|
|
|
} |
2454
|
|
|
|
2455
|
|
|
/** |
2456
|
|
|
* Returns an instance of the Page class as specified by $title or $pageid |
2457
|
|
|
* |
2458
|
|
|
* @access public |
2459
|
|
|
* @param mixed $title Title of the page (default: null) |
2460
|
|
|
* @param mixed $pageid ID of the page (default: null) |
2461
|
|
|
* @param bool $followRedir Should it follow a redirect when retrieving the page (default: true) |
2462
|
|
|
* @param bool $normalize Should the class automatically normalize the title (default: true) |
2463
|
|
|
* @param string $timestamp Timestamp of a reference point in the program. Used to detect edit conflicts. |
2464
|
|
|
* @return Page |
2465
|
|
|
* @package initFunctions |
2466
|
|
|
*/ |
2467
|
|
|
public function &initPage( $title = null, $pageid = null, $followRedir = true, $normalize = true, $timestamp = null ) { |
2468
|
|
|
$page = new Page( $this, $title, $pageid, $followRedir, $normalize, $timestamp ); |
2469
|
|
|
return $page; |
2470
|
|
|
} |
2471
|
|
|
|
2472
|
|
|
/** |
2473
|
|
|
* Returns an instance of the User class as specified by $pgUsername |
2474
|
|
|
* |
2475
|
|
|
* @access public |
2476
|
|
|
* @param mixed $pgUsername Username |
2477
|
|
|
* @return User |
2478
|
|
|
* @package initFunctions |
2479
|
|
|
*/ |
2480
|
|
|
public function &initUser( $pgUsername ) { |
2481
|
|
|
return new User( $this, $pgUsername ); |
2482
|
|
|
} |
2483
|
|
|
|
2484
|
|
|
/** |
2485
|
|
|
* Returns an instance of the Image class as specified by $filename or $pageid |
2486
|
|
|
* |
2487
|
|
|
* @access public |
2488
|
|
|
* @param string $filename Filename |
2489
|
|
|
* @param int $pageid Page ID of image |
2490
|
|
|
* @param array $prop Informatation to set. Default array( 'timestamp', 'user', 'comment', 'url', 'size', 'dimensions', 'sha1', 'mime', 'metadata', 'archivename', 'bitdepth' ) |
2491
|
|
|
* @return Image |
2492
|
|
|
* @package initFunctions |
2493
|
|
|
*/ |
2494
|
|
|
public function &initImage( $filename = null, $pageid = null ) { |
2495
|
|
|
$image = new Image( $this, $filename, $pageid ); |
2496
|
|
|
return $image; |
2497
|
|
|
} |
2498
|
|
|
|
2499
|
|
|
/** |
2500
|
|
|
* Get the difference between 2 pages |
2501
|
|
|
* |
2502
|
|
|
* @access public |
2503
|
|
|
* @param string $fromtitle First title to compare |
2504
|
|
|
* @param string $fromid First page ID to compare |
2505
|
|
|
* @param string $fromrev First revision to compare |
2506
|
|
|
* @param string $totitle Second title to compare |
2507
|
|
|
* @param string $toid Second page ID to compare |
2508
|
|
|
* @param string $torev Second revision to compare |
2509
|
|
|
* @return array |
2510
|
|
|
*/ |
2511
|
|
|
public function compare( $fromtitle = null, $fromid = null, $fromrev = null, $totitle = null, $toid = null, $torev = null ) { |
2512
|
|
|
|
2513
|
|
|
pecho( "Getting differences...\n\n", PECHO_NORMAL ); |
2514
|
|
|
$apiArray = array( |
2515
|
|
|
'action' => 'compare' |
2516
|
|
|
); |
2517
|
|
|
if( !is_null( $fromrev ) ) { |
2518
|
|
|
$apiArray['fromrev'] = $fromrev; |
2519
|
|
|
} else { |
2520
|
|
|
if( !is_null( $fromid ) ) { |
2521
|
|
|
$apiArray['fromid'] = $fromid; |
2522
|
|
|
} else { |
2523
|
|
|
if( !is_null( $fromtitle ) ) { |
2524
|
|
|
$apiArray['fromtitle'] = $fromtitle; |
2525
|
|
|
} else { |
2526
|
|
|
pecho( "Error: a from parameter must be specified.\n\n", PECHO_FATAL ); |
2527
|
|
|
return false; |
|
|
|
|
2528
|
|
|
} |
2529
|
|
|
} |
2530
|
|
|
} |
2531
|
|
|
if( !is_null( $torev ) ) { |
2532
|
|
|
$apiArray['torev'] = $torev; |
2533
|
|
|
} else { |
2534
|
|
|
if( !is_null( $toid ) ) { |
2535
|
|
|
$apiArray['toid'] = $toid; |
2536
|
|
|
} else { |
2537
|
|
|
if( !is_null( $totitle ) ) { |
2538
|
|
|
$apiArray['totitle'] = $totitle; |
2539
|
|
|
} else { |
2540
|
|
|
pecho( "Error: a to parameter must be specified.\n\n", PECHO_FATAL ); |
2541
|
|
|
return false; |
|
|
|
|
2542
|
|
|
} |
2543
|
|
|
} |
2544
|
|
|
} |
2545
|
|
|
$results = $this->apiQuery( $apiArray ); |
2546
|
|
|
|
2547
|
|
|
if( isset( $results['compare']['*'] ) ) { |
2548
|
|
|
return $results['compare']['*']; |
2549
|
|
|
} else { |
2550
|
|
|
pecho( "Compare failure... Please check your parameters.\n\n", PECHO_FATAL ); |
2551
|
|
|
return false; |
|
|
|
|
2552
|
|
|
} |
2553
|
|
|
} |
2554
|
|
|
|
2555
|
|
|
/** |
2556
|
|
|
* Search the wiki using the OpenSearch protocol. |
2557
|
|
|
* |
2558
|
|
|
* @access public |
2559
|
|
|
* @param string $text Search string. Default empty. |
2560
|
|
|
* @param int $limit Maximum amount of results to return. Default 10. |
2561
|
|
|
* @param array $namespaces Namespaces to search. Default array(0). |
2562
|
|
|
* @param bool $suggest Do nothing if $wgEnableOpenSearchSuggest is false. Default true. |
2563
|
|
|
* @return array |
2564
|
|
|
*/ |
2565
|
|
|
public function opensearch( $text = '', $limit = 10, $namespaces = array( 0 ), $suggest = true ) { |
2566
|
|
|
|
2567
|
|
|
$apiArray = array( |
2568
|
|
|
'search' => $text, |
2569
|
|
|
'action' => 'opensearch', |
2570
|
|
|
'limit' => $limit, |
2571
|
|
|
'namespace' => implode( '|', $namespaces ) |
2572
|
|
|
); |
2573
|
|
|
if( $suggest ) $apiArray['suggest'] = ''; |
2574
|
|
|
|
2575
|
|
|
$OSres = $this->get_http()->get( $this->get_base_url(), $apiArray ); |
2576
|
|
|
return ( $OSres === false || is_null( $OSres ) ? false : json_decode( $OSres, true ) ); |
2577
|
|
|
|
2578
|
|
|
} |
2579
|
|
|
|
2580
|
|
|
/** |
2581
|
|
|
* Export an RSD (Really Simple Discovery) schema. |
2582
|
|
|
* |
2583
|
|
|
* @access public |
2584
|
|
|
* @return array |
2585
|
|
|
*/ |
2586
|
|
|
public function rsd() { |
2587
|
|
|
|
2588
|
|
|
$apiArray = array( |
2589
|
|
|
'action' => 'rsd' |
2590
|
|
|
); |
2591
|
|
|
|
2592
|
|
|
$OSres = $this->get_http()->get( $this->get_base_url(), $apiArray ); |
2593
|
|
|
return ( $OSres === false || is_null( $OSres ) ? false : XMLParse::load( $OSres ) ); |
2594
|
|
|
} |
2595
|
|
|
|
2596
|
|
|
/** |
2597
|
|
|
* Change preferences of the current user. |
2598
|
|
|
* |
2599
|
|
|
* @access public |
2600
|
|
|
* @param bool $reset Resets preferences to the site defaults. Default false. |
2601
|
|
|
* @param array|string $resetoptions List of types of options to reset when the "reset" option is set. Default 'all'. |
2602
|
|
|
* @param array|string $changeoptions PartList of changes, formatted name=value (e.g. skin=vector), value cannot contain pipe characters. If no value is given (not even an equals sign), e.g., optionname|otheroption|..., the option will be reset to its default value. Default empty. |
2603
|
|
|
* @param string $optionname A name of a option which should have an optionvalue set. Default null. |
2604
|
|
|
* @param string $optionvalue A value of the option specified by the optionname, can contain pipe characters. Default null. |
2605
|
|
|
* @return boolean |
2606
|
|
|
*/ |
2607
|
|
|
public function options( $reset = false, $resetoptions = array( 'all' ), $changeoptions = array(), $optionname = null, $optionvalue = null ) { |
2608
|
|
|
$this->get_tokens(); |
2609
|
|
|
$apiArray = array( |
2610
|
|
|
'action' => 'options', |
2611
|
|
|
'token' => $this->tokens['options'] |
2612
|
|
|
); |
2613
|
|
|
|
2614
|
|
|
if( $reset ) { |
2615
|
|
|
$apiArray['reset'] = ''; |
2616
|
|
|
$apiArray['resetkinds'] = implode( '|', $resetoptions ); |
2617
|
|
|
} |
2618
|
|
|
|
2619
|
|
|
if( !empty( $changeoptions ) ) $apiArray['change'] = implode( '|', $changeoptions ); |
2620
|
|
|
|
2621
|
|
|
if( !is_null( $optionname ) ) $apiArray['optionname'] = $optionname; |
2622
|
|
|
if( !is_null( $optionvalue ) ) $apiArray['optionvalue'] = $optionvalue; |
2623
|
|
|
|
2624
|
|
|
$result = $this->apiQuery( $apiArray, true ); |
2625
|
|
|
if( isset( $result['options'] ) && $result['options'] == 'success' ) { |
2626
|
|
|
if( isset( $result['warnings'] ) ) pecho( "Options set successfully, however a warning was thrown:\n" . print_r( $result['warnings'], true ), PECHO_WARN ); |
2627
|
|
|
return true; |
2628
|
|
|
} else { |
2629
|
|
|
pecho( "Options error...\n\n" . print_r( $result, true ), PECHO_FATAL ); |
2630
|
|
|
return false; |
2631
|
|
|
} |
2632
|
|
|
} |
2633
|
|
|
|
2634
|
|
|
/** |
2635
|
|
|
* Returns the SSH object |
2636
|
|
|
* |
2637
|
|
|
* @access public |
2638
|
|
|
* @return Object |
2639
|
|
|
*/ |
2640
|
|
|
public function getSSH() { |
2641
|
|
|
return $this->SSH; |
2642
|
|
|
} |
2643
|
|
|
|
2644
|
|
|
/** |
2645
|
|
|
* Performs nobots checking, new message checking, etc |
2646
|
|
|
* |
2647
|
|
|
* @param string $action Name of action. |
2648
|
|
|
* @param null|string $title Name of page to check for nobots |
2649
|
|
|
* @param null $pageidp |
2650
|
|
|
* |
2651
|
|
|
* @throws AssertFailure |
2652
|
|
|
* @throws EditError |
2653
|
|
|
* @throws LoggedOut |
2654
|
|
|
* @throws MWAPIError |
2655
|
|
|
* @access public |
2656
|
|
|
*/ |
2657
|
|
|
public function preEditChecks( $action = "Edit", $title = null, $pageidp = null ) { |
2658
|
|
|
global $pgDisablechecks, $pgMasterrunpage; |
2659
|
|
|
if( $pgDisablechecks ) return; |
2660
|
|
|
$preeditinfo = array( |
2661
|
|
|
'action' => 'query', |
2662
|
|
|
'meta' => 'userinfo', |
2663
|
|
|
'uiprop' => 'hasmsg|blockinfo', |
2664
|
|
|
'prop' => 'revisions', |
2665
|
|
|
'rvprop' => 'content' |
2666
|
|
|
); |
2667
|
|
|
|
2668
|
|
|
if( !is_null( $this->get_runpage() ) ) { |
2669
|
|
|
$preeditinfo['titles'] = $this->get_runpage(); |
2670
|
|
|
} |
2671
|
|
|
if( !is_null( $title ) ) { |
2672
|
|
|
$preeditinfo['titles'] = ( !is_null( $this->get_runpage() ) ? $preeditinfo['titles'] . "|" : "" ) . $title; |
2673
|
|
|
} |
2674
|
|
|
|
2675
|
|
|
$preeditinfo = $this->apiQuery( $preeditinfo ); |
2676
|
|
|
|
2677
|
|
|
$messages = false; |
2678
|
|
|
$blocked = false; |
2679
|
|
|
$oldtext = ''; |
2680
|
|
|
$runtext = 'enable'; |
2681
|
|
|
if( isset( $preeditinfo['query']['pages'] ) ) { |
2682
|
|
|
//$oldtext = $preeditinfo['query']['pages'][$this->pageid]['revisions'][0]['*']; |
2683
|
|
|
foreach( $preeditinfo['query']['pages'] as $pageid => $page ){ |
2684
|
|
|
if( $pageid == $pageidp ) { |
2685
|
|
|
$oldtext = $page['revisions'][0]['*']; |
2686
|
|
|
} elseif( $pageid == "-1" ) { |
2687
|
|
|
if( $page['title'] == $this->get_runpage() ) { |
2688
|
|
|
pecho( "$action failed, enable page does not exist.\n\n", PECHO_WARN ); |
2689
|
|
|
throw new EditError( "Enablepage", "Enable page does not exist." ); |
2690
|
|
|
} else { |
2691
|
|
|
$oldtext = ''; |
2692
|
|
|
} |
2693
|
|
|
} else { |
2694
|
|
|
$runtext = $page['revisions'][0]['*']; |
2695
|
|
|
} |
2696
|
|
|
} |
2697
|
|
|
if( isset( $preeditinfo['query']['userinfo']['messages'] ) ) $messages = true; |
2698
|
|
|
if( isset( $preeditinfo['query']['userinfo']['blockedby'] ) ) $blocked = true; |
2699
|
|
|
} |
2700
|
|
|
|
2701
|
|
|
//Perform nobots checks, login checks, /Run checks |
2702
|
|
|
if( checkExclusion( $this, $oldtext, $this->get_username(), $this->get_optout(), $this->nobotsTaskname ) && $this->get_nobots() ) { |
2703
|
|
|
throw new EditError( "Nobots", "The page has a nobots template" ); |
2704
|
|
|
} |
2705
|
|
|
|
2706
|
|
|
if( !is_null( $pgMasterrunpage ) && !preg_match( '/enable|yes|run|go|true/i', $this->initPage( $pgMasterrunpage )->get_text() ) ) { |
2707
|
|
|
throw new EditError( "Enablepage", "Script was disabled by Master Run page" ); |
2708
|
|
|
} |
2709
|
|
|
|
2710
|
|
|
if( !is_null( $this->get_runpage() ) && !preg_match( '/enable|yes|run|go|true/i', $runtext ) ) { |
2711
|
|
|
throw new EditError( "Enablepage", "Script was disabled by Run page" ); |
2712
|
|
|
} |
2713
|
|
|
|
2714
|
|
|
if( $messages && $this->get_stoponnewmessages() ) { |
2715
|
|
|
throw new EditError( "NewMessages", "User has new messages" ); |
2716
|
|
|
} |
2717
|
|
|
|
2718
|
|
|
if( $blocked ) { |
2719
|
|
|
throw new EditError( "Blocked", "User has been blocked" ); |
2720
|
|
|
} |
2721
|
|
|
} |
2722
|
|
|
} |
2723
|
|
|
|
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.