Completed
Push — master ( 7ff64a...e0bee4 )
by adam
10s
created

GenFunctions.php (6 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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
 * Stores general functions that do not belong in a class
23
 */
24
25
/**
26
 * Case insensitive in_array function
27
 *
28
 * @param mixed $needle What to search for
29
 * @param array $haystack Array to search in
30
 * @param bool $strict
31
 * @return bool True if $needle is found in $haystack, case insensitive
32
 * @link http://us3.php.net/in_array
33
 */
34
function iin_array( $needle, $haystack, $strict = false ) {
35
	return in_array_recursive( strtoupper_safe( $needle ), array_map( 'strtoupper_safe', $haystack ), $strict );
36
}
37
38
/**
39
 * @return string
40
 */
41
function strtoupper_safe( $str ) {
42
	if( is_string( $str ) ) return strtoupper( $str );
43
	if( is_array( $str ) ) $str = array_map( 'strtoupper_safe', $str );
44
	return $str;
45
}
46
47
/**
48
 * Returns whether or not a string is found in another
49
 * Shortcut for strpos()
50
 *
51
 * @param string $needle What to search for
52
 * @param string $haystack What to search in
53
 * @param bool $insensitive Whether or not to do a case-insensitive search
54
 * @return bool True if $needle is found in $haystack
55
 * @link http://us3.php.net/strpos
56
 */
57
function in_string( $needle, $haystack, $insensitive = false ) {
58
	$fnc = 'strpos';
59
	if( $insensitive ) $fnc = 'stripos';
60
61
	return $fnc( $haystack, $needle ) !== false;
62
}
63
64
/**
65
 * Recursive in_array function
66
 *
67
 * @param string $needle What to search for
68
 * @param array $haystack What to search in
69
 * @param bool $insensitive Whether or not to do a case-insensitive search
70
 * @return bool True if $needle is found in $haystack
71
 * @link http://us3.php.net/in_array
72
 */
73
function in_array_recursive( $needle, $haystack, $insensitive = false ) {
74
	$fnc = 'in_array';
75
	if( $insensitive ) $fnc = 'iin_array';
76
77
	if( $fnc( $needle, $haystack ) ) return true;
78
	foreach( $haystack as $val ){
79
		if( is_array( $val ) ) {
80
			return in_array_recursive( $needle, $val );
81
		}
82
	}
83
	return false;
84
}
85
86
/**
87
 * Recursive glob() function.
88
 *
89
 * @access public
90
 * @param string $pattern . (default: '*')
91
 * @param int $flags . (default: 0)
92
 * @param string $path . (default: '')
93
 * @return array
94
 */
95
function rglob( $pattern = '*', $flags = 0, $path = '' ) {
96
	$paths = glob( $path . '*', GLOB_MARK | GLOB_ONLYDIR | GLOB_NOSORT );
97
	$files = glob( $path . $pattern, $flags );
98
	foreach( $paths as $path ){
99
		$files = array_merge( $files, rglob( $pattern, $flags, $path ) );
100
	}
101
	return $files;
102
}
103
104
/**
105
 * Detects the presence of a nobots template or one that denies editing by ours
106
 *
107
 * @access    public
108
 * @param    Wiki $wiki Wiki class
109
 * @param    string $text Text of the page to check (default: '')
110
 * @param    string $pgUsername Username to search for in the template (default: null)
111
 * @param    string|null $optout Text to search for in the optout= parameter. (default: null)
112
 * @param    string|null $taskname (default: null)
113
 * @return    bool                    True on match of an appropriate nobots template
114
 */
115
function checkExclusion( Wiki $wiki, $text = '', $pgUsername = null, $optout = null, $taskname = null ) {
116
	if( !$wiki->get_nobots() ) return false;
117
118
	if( in_string( "{{nobots}}", $text ) ) return true;
119
	if( in_string( "{{bots}}", $text ) ) return false;
120
121
	if( preg_match( '/\{\{bots\s*\|\s*allow\s*=\s*(.*?)\s*\}\}/i', $text, $allow ) ) {
122
		if( $allow[1] == "all" ) return false;
123
		if( $allow[1] == "none" ) return true;
124
		$allow = array_map( 'trim', explode( ',', $allow[1] ) );
125
		if( !is_null( $pgUsername ) && in_array( trim( $pgUsername ), $allow ) ) {
126
			return false;
127
		}
128
		return true;
129
	}
130
131
	if( preg_match( '/\{\{(no)?bots\s*\|\s*deny\s*=\s*(.*?)\s*\}\}/i', $text, $deny ) ) {
132
		if( $deny[2] == "all" ) return true;
133
		if( $deny[2] == "none" ) return false;
134
		$allow = array_map( 'trim', explode( ',', $deny[2] ) );
135
		if( ( !is_null( $pgUsername ) && in_array( trim( $pgUsername ), $allow ) ) || ( !is_null( $taskname ) && in_array( trim( $taskname ), $allow ) ) ) {
136
			return true;
137
		}
138
		return false;
139
	}
140
141
	if( !is_null( $optout ) && preg_match( '/\{\{(no)?bots\s*\|\s*optout\s*=\s*(.*?)\s*\}\}/i', $text, $allow ) ) {
142
		if( $allow[1] == "all" ) return true;
143
		$allow = array_map( 'trim', explode( ',', $allow[2] ) );
144
		if( in_array( trim( $optout ), $allow ) ) {
145
			return true;
146
		}
147
		return false;
148
	}
149
	return false;
150
}
151
152
/**
153
 * Outputs text if the given category is in the allowed types
154
 *
155
 * @param string $text Text to display
156
 * @param int $cat Category of text, such as PECHO_WARN, PECHO_NORMAL
157
 * @param string $func
158
 * @return void
159
 */
160
function outputText( $text, $cat = 0, $func = 'echo' ) {
161
	global $pgVerbose;
162
163
	Hooks::runHook( 'OutputText', array( &$text, &$cat, &$func ) );
164
165
	if( in_array( $cat, $pgVerbose ) ) {
166
		if( $func == 'echo' ) {
167
			echo $text;
168
		} else {
169
			$func( $text );
170
		}
171
	}
172
}
173
174
/**
175
 * Shortcut for {@link outputText}
176
 *
177
 * @param string $text Text to display
178
 * @param int $cat Category of text, such as PECHO_WARN, PECHO_NORMAL
179
 * @param string $func
180
 * @link outputText
181
 * @return void
182
 */
183
function pecho( $text, $cat = 0, $func = 'echo' ) {
184
	global $pgWebOutput;
185
	if( $pgWebOutput ) $text = str_replace( "\n", "<br>", $text );
186
	outputText( $text, $cat, $func );
187
}
188
189
/**
190
 * Echo function with color capabilities.
191
 *
192
 * Syntax:
193
 *
194
 * <i>[Text to colorize|NAME] where NAME is the name of a defined style.</i> For example:
195
 *
196
 * <i>This text is standard terminal color. [This text will be yellow.|COMMENT] [This text will be white on red.|ERROR]</i>
197
 *
198
 * Defined styles:
199
 * <ul>
200
 * <li>ERROR: White on red, bold</li>
201
 * <li>INFO: Green text, bold</li>
202
 * <li>PARAMETER: Cyan text</li>
203
 * <li>COMMENT: Yellow text</li>
204
 * <li>GREEN_BAR: White on green, bold</li>
205
 * <li>RED_BAR: White on red, bold</li>
206
 * <li>YELLOW_BAR: Black on yellow, bold</li>
207
 * <li>INFO_BAR: Cyan text, bold</li>
208
 * </ul>
209
 *
210
 * You can define your own styles by using this syntax:
211
 *
212
 *   <code>lime_colorizer::style('STYLE_NAME', array('bg' => 'red', 'fg' => 'white'));</code>
213
 *
214
 * (Available colors: black, red, green, yellow, blue, magenta, cyan, white)
215
 *
216
 * You can also set options for how the text is formatted (not available on all systems):
217
 *
218
 *   <code>lime_colorizer::style('STYLE_NAME', array('bg' => 'red', 'fg' => 'white', 'bold' => true ));</code> (sets bold text)
219
 *
220
 * Available options: bold, underscore, blink, reverse, conceal
221
 *
222
 *
223
 * @access public
224
 * @param string $text
225
 * @param bool $return
226
 * @return string
227
 */
228
function cecho( $text, $return = false ) {
229
	global $pgColorizer;
230
231
	if( !isset( $pgColorizer ) ) $pgColorizer = new lime_colorizer( true );
232
233
	$text = preg_replace( '/\[(.+?)\|(\w+)\]/se', '$pgColorizer->colorize("$1", "$2")', $text );
234
235
	if( $return ) return $text;
236
237
	echo $text;
238
239
}
240
241
242
/**
243
 * Generates a diff between two strings
244
 *
245
 * @package Text_Diff
246
 * @deprecated since 18 June 2013
247
 */
248
function getTextDiff() {
249
	Peachy::deprecatedWarn( 'getTextDiff()', 'Diff::load()' );
250
	$args = func_get_args();
251
	return call_user_func_array( array( 'Diff', 'load' ), $args );
252
}
253
254
/**
255
 * Gets the first defined Wiki object
256
 *
257
 * @return Wiki|bool
258
 * @package initFunctions
259
 */
260
function &getSiteObject() {
0 ignored issues
show
getSiteObject uses the super-global variable $GLOBALS which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
261
262
	foreach( $GLOBALS as $var ){
263
		if( is_object( $var ) ) {
264
			if( get_class( $var ) == "Wiki" ) {
265
				return $var;
266
			}
267
		}
268
	}
269
270
	return false;
271
}
272
273
/**
274
 * Returns an instance of the Page class as specified by $title or $pageid
275
 *
276
 * @param mixed $title Title of the page (default: null)
277
 * @param mixed $pageid ID of the page (default: null)
278
 * @param bool $followRedir Should it follow a redirect when retrieving the page (default: true)
279
 * @param bool $normalize Should the class automatically normalize the title (default: true)
280
 * @return Page
281
 * @package initFunctions
282
 */
283
function &initPage( $title = null, $pageid = null, $followRedir = true, $normalize = true ) {
284
	$wiki = getSiteObject();
285
	if( !$wiki ) return false;
286
287
	$page = new Page( $wiki, $title, $pageid, $followRedir, $normalize );
288
	return $page;
289
}
290
291
/**
292
 * Returns an instance of the User class as specified by $pgUsername
293
 *
294
 * @param mixed $pgUsername Username
295
 * @return User|false
296
 * @package initFunctions
297
 */
298
function &initUser( $pgUsername ) {
299
	$wiki = getSiteObject();
300
	if( !$wiki ) return false;
301
	return new User( $wiki, $pgUsername );
302
}
303
304
/**
305
 * Returns an instance of the Image class as specified by $filename or $pageid
306
 *
307
 * @param string $filename Filename
308
 * @return Image
309
 * @package initFunctions
310
 */
311
function &initImage( $filename = null ) {
312
313
	$wiki = getSiteObject();
314
	if( !$wiki ) return false;
315
316
	$image = new Image( $wiki, $filename );
317
	return $image;
318
}
319
320
if( !function_exists( 'mb_strlen' ) ) {
321
322
	/**
323
	 * Fallback implementation of mb_strlen.
324
	 *
325
	 * @link http://svn.wikimedia.org/svnroot/mediawiki/trunk/phase3/includes/GlobalFunctions.php
326
	 * @param string $str String to get
327
	 * @return int
328
	 * @package Fallback
329
	 */
330
	function mb_strlen( $str ) {
331
		$counts = count_chars( $str );
332
		$total = 0;
333
334
		// Count ASCII bytes
335
		for( $i = 0; $i < 0x80; $i++ ){
336
			$total += $counts[$i];
337
		}
338
339
		// Count multibyte sequence heads
340
		for( $i = 0xc0; $i < 0xff; $i++ ){
341
			$total += $counts[$i];
342
		}
343
344
		return $total;
345
	}
346
}
347
348
if( !function_exists( 'mb_substr' ) ) {
349
	/**
350
	 * Fallback implementation for mb_substr. This is VERY slow, from 5x to 100x slower. Use only if necessary.
351
	 * @link http://svn.wikimedia.org/svnroot/mediawiki/trunk/phase3/includes/GlobalFunctions.php
352
	 * @package Fallback
353
	 */
354
	function mb_substr( $str, $start, $count = 'end' ) {
355
		if( $start != 0 ) {
356
			$split = mb_substr_split_unicode( $str, intval( $start ) );
357
			$str = substr( $str, $split );
358
		}
359
360
		if( $count !== 'end' ) {
361
			$split = mb_substr_split_unicode( $str, intval( $count ) );
362
			$str = substr( $str, 0, $split );
363
		}
364
365
		return $str;
366
	}
367
368
	/**
369
	 * Continuing support for mb_substr. Do not use.
370
	 * @link http://svn.wikimedia.org/svnroot/mediawiki/trunk/phase3/includes/GlobalFunctions.php
371
	 * @package Fallback
372
	 * @param integer $splitPos
373
	 * @return int
374
	 */
375
	function mb_substr_split_unicode( $str, $splitPos ) {
376
		if( $splitPos == 0 ) {
377
			return 0;
378
		}
379
380
		$byteLen = strlen( $str );
381
382
		if( $splitPos > 0 ) {
383
			if( $splitPos > 256 ) {
384
				// Optimize large string offsets by skipping ahead N bytes.
385
				// This will cut out most of our slow time on Latin-based text,
386
				// and 1/2 to 1/3 on East European and Asian scripts.
387
				$bytePos = $splitPos;
388
				while( $bytePos < $byteLen && $str{$bytePos} >= "\x80" && $str{$bytePos} < "\xc0" ){
389
					++$bytePos;
390
				}
391
				$charPos = mb_strlen( substr( $str, 0, $bytePos ) );
392
			} else {
393
				$charPos = 0;
394
				$bytePos = 0;
395
			}
396
397
			while( $charPos++ < $splitPos ){
398
				++$bytePos;
399
				// Move past any tail bytes
400
				while( $bytePos < $byteLen && $str{$bytePos} >= "\x80" && $str{$bytePos} < "\xc0" ){
401
					++$bytePos;
402
				}
403
			}
404
		} else {
405
			$splitPosX = $splitPos + 1;
406
			$charPos = 0; // relative to end of string; we don't care about the actual char position here
407
			$bytePos = $byteLen;
408
			while( $bytePos > 0 && $charPos-- >= $splitPosX ){
409
				--$bytePos;
410
				// Move past any tail bytes
411
				while( $bytePos > 0 && $str{$bytePos} >= "\x80" && $str{$bytePos} < "\xc0" ){
412
					--$bytePos;
413
				}
414
			}
415
		}
416
417
		return $bytePos;
418
	}
419
}
420
421
if( !function_exists( 'iconv' ) ) {
422
	/**
423
	 * Fallback iconv function.
424
	 *
425
	 * iconv support is not in the default configuration and so may not be present.
426
	 * Assume will only ever use utf-8 and iso-8859-1.
427
	 * This will *not* work in all circumstances.
428
	 *
429
	 * @access public
430
	 * @param mixed $from
431
	 * @param mixed $to
432
	 * @param mixed $string
433
	 * @return void
434
	 * @package Fallback
435
	 */
436
	function iconv( $from, $to, $string ) {
437
		if( substr( $to, -8 ) == '//IGNORE' ) $to = substr( $to, 0, strlen( $to ) - 8 );
438
		if( strcasecmp( $from, $to ) == 0 ) return $string;
439
		if( strcasecmp( $from, 'utf-8' ) == 0 ) return utf8_decode( $string );
440
		if( strcasecmp( $to, 'utf-8' ) == 0 ) return utf8_encode( $string );
441
		return $string;
442
	}
443
}
444
445
if( !function_exists( 'istainted' ) ) {
446
447
	/**
448
	 * Fallback istainted function.
449
	 *
450
	 * @access public
451
	 * @param mixed $var
452
	 * @return integer
453
	 * @package Fallback
454
	 */
455
	function istainted( $var ) {
0 ignored issues
show
The parameter $var is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
456
		return 0;
457
	}
458
459
	/**
460
	 * Fallback taint function.
461
	 *
462
	 * @access public
463
	 * @param mixed $var
464
	 * @param int $level
465
	 * @return void
466
	 * @package Fallback
467
	 */
468
	function taint( $var, $level = 0 ) { }
0 ignored issues
show
The parameter $var is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
The parameter $level is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
469
470
	/**
471
	 * Fallback untaint function.
472
	 *
473
	 * @access public
474
	 * @param mixed $var
475
	 * @param int $level
476
	 * @return void
477
	 * @package Fallback
478
	 */
479
	function untaint( $var, $level = 0 ) { }
0 ignored issues
show
The parameter $var is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
The parameter $level is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
480
481
	/**
482
	 * @package Fallback
483
	 */
484
	define( 'TC_HTML', 1 );
485
486
	/**
487
	 * @package Fallback
488
	 */
489
	define( 'TC_SHELL', 1 );
490
491
	/**
492
	 * @package Fallback
493
	 */
494
	define( 'TC_MYSQL', 1 );
495
496
	/**
497
	 * @package Fallback
498
	 */
499
	define( 'TC_PCRE', 1 );
500
501
	/**
502
	 * @package Fallback
503
	 */
504
	define( 'TC_SELF', 1 );
505
}
506