Issues (165)

Security Analysis    no request data  

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

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_callback( '/\[(.+?)\|(\w+)\]/s', function ($m) {
234
                    global $pgColorizer;
235
                    return $pgColorizer->colorize($m[1], $m[2]);
236
                }, $text );
237
	if( $return ) return $text;
238
239
	echo $text;
240
241
}
242
243
244
/**
245
 * Generates a diff between two strings
246
 *
247
 * @package Text_Diff
248
 * @deprecated since 18 June 2013
249
 */
250
function getTextDiff() {
251
	Peachy::deprecatedWarn( 'getTextDiff()', 'Diff::load()' );
252
	$args = func_get_args();
253
	return call_user_func_array( array( 'Diff', 'load' ), $args );
254
}
255
256
/**
257
 * Gets the first defined Wiki object
258
 *
259
 * @return Wiki|bool
260
 * @package initFunctions
261
 */
262
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...
263
264
	foreach( $GLOBALS as $var ){
265
		if( is_object( $var ) ) {
266
			if( get_class( $var ) == "Wiki" ) {
267
				return $var;
268
			}
269
		}
270
	}
271
272
	return false;
273
}
274
275
/**
276
 * Returns an instance of the Page class as specified by $title or $pageid
277
 *
278
 * @param mixed $title Title of the page (default: null)
279
 * @param mixed $pageid ID of the page (default: null)
280
 * @param bool $followRedir Should it follow a redirect when retrieving the page (default: true)
281
 * @param bool $normalize Should the class automatically normalize the title (default: true)
282
 * @return Page
283
 * @package initFunctions
284
 */
285
function &initPage( $title = null, $pageid = null, $followRedir = true, $normalize = true ) {
286
	$wiki = getSiteObject();
287
	if( !$wiki ) return false;
288
289
	$page = new Page( $wiki, $title, $pageid, $followRedir, $normalize );
290
	return $page;
291
}
292
293
/**
294
 * Returns an instance of the User class as specified by $pgUsername
295
 *
296
 * @param mixed $pgUsername Username
297
 * @return User|false
298
 * @package initFunctions
299
 */
300
function &initUser( $pgUsername ) {
301
	$wiki = getSiteObject();
302
	if( !$wiki ) return false;
303
	return new User( $wiki, $pgUsername );
304
}
305
306
/**
307
 * Returns an instance of the Image class as specified by $filename or $pageid
308
 *
309
 * @param string $filename Filename
310
 * @return Image
311
 * @package initFunctions
312
 */
313
function &initImage( $filename = null ) {
314
315
	$wiki = getSiteObject();
316
	if( !$wiki ) return false;
317
318
	$image = new Image( $wiki, $filename );
319
	return $image;
320
}
321
322
if( !function_exists( 'mb_strlen' ) ) {
323
324
	/**
325
	 * Fallback implementation of mb_strlen.
326
	 *
327
	 * @link http://svn.wikimedia.org/svnroot/mediawiki/trunk/phase3/includes/GlobalFunctions.php
328
	 * @param string $str String to get
329
	 * @return int
330
	 * @package Fallback
331
	 */
332
	function mb_strlen( $str ) {
333
		$counts = count_chars( $str );
334
		$total = 0;
335
336
		// Count ASCII bytes
337
		for( $i = 0; $i < 0x80; $i++ ){
338
			$total += $counts[$i];
339
		}
340
341
		// Count multibyte sequence heads
342
		for( $i = 0xc0; $i < 0xff; $i++ ){
343
			$total += $counts[$i];
344
		}
345
346
		return $total;
347
	}
348
}
349
350
if( !function_exists( 'mb_substr' ) ) {
351
	/**
352
	 * Fallback implementation for mb_substr. This is VERY slow, from 5x to 100x slower. Use only if necessary.
353
	 * @link http://svn.wikimedia.org/svnroot/mediawiki/trunk/phase3/includes/GlobalFunctions.php
354
	 * @package Fallback
355
	 */
356
	function mb_substr( $str, $start, $count = 'end' ) {
357
		if( $start != 0 ) {
358
			$split = mb_substr_split_unicode( $str, intval( $start ) );
359
			$str = substr( $str, $split );
360
		}
361
362
		if( $count !== 'end' ) {
363
			$split = mb_substr_split_unicode( $str, intval( $count ) );
364
			$str = substr( $str, 0, $split );
365
		}
366
367
		return $str;
368
	}
369
370
	/**
371
	 * Continuing support for mb_substr. Do not use.
372
	 * @link http://svn.wikimedia.org/svnroot/mediawiki/trunk/phase3/includes/GlobalFunctions.php
373
	 * @package Fallback
374
	 * @param integer $splitPos
375
	 * @return int
376
	 */
377
	function mb_substr_split_unicode( $str, $splitPos ) {
378
		if( $splitPos == 0 ) {
379
			return 0;
380
		}
381
382
		$byteLen = strlen( $str );
383
384
		if( $splitPos > 0 ) {
385
			if( $splitPos > 256 ) {
386
				// Optimize large string offsets by skipping ahead N bytes.
387
				// This will cut out most of our slow time on Latin-based text,
388
				// and 1/2 to 1/3 on East European and Asian scripts.
389
				$bytePos = $splitPos;
390
				while( $bytePos < $byteLen && $str{$bytePos} >= "\x80" && $str{$bytePos} < "\xc0" ){
391
					++$bytePos;
392
				}
393
				$charPos = mb_strlen( substr( $str, 0, $bytePos ) );
394
			} else {
395
				$charPos = 0;
396
				$bytePos = 0;
397
			}
398
399
			while( $charPos++ < $splitPos ){
400
				++$bytePos;
401
				// Move past any tail bytes
402
				while( $bytePos < $byteLen && $str{$bytePos} >= "\x80" && $str{$bytePos} < "\xc0" ){
403
					++$bytePos;
404
				}
405
			}
406
		} else {
407
			$splitPosX = $splitPos + 1;
408
			$charPos = 0; // relative to end of string; we don't care about the actual char position here
409
			$bytePos = $byteLen;
410
			while( $bytePos > 0 && $charPos-- >= $splitPosX ){
411
				--$bytePos;
412
				// Move past any tail bytes
413
				while( $bytePos > 0 && $str{$bytePos} >= "\x80" && $str{$bytePos} < "\xc0" ){
414
					--$bytePos;
415
				}
416
			}
417
		}
418
419
		return $bytePos;
420
	}
421
}
422
423
if( !function_exists( 'iconv' ) ) {
424
	/**
425
	 * Fallback iconv function.
426
	 *
427
	 * iconv support is not in the default configuration and so may not be present.
428
	 * Assume will only ever use utf-8 and iso-8859-1.
429
	 * This will *not* work in all circumstances.
430
	 *
431
	 * @access public
432
	 * @param mixed $from
433
	 * @param mixed $to
434
	 * @param mixed $string
435
	 * @return void
436
	 * @package Fallback
437
	 */
438
	function iconv( $from, $to, $string ) {
439
		if( substr( $to, -8 ) == '//IGNORE' ) $to = substr( $to, 0, strlen( $to ) - 8 );
440
		if( strcasecmp( $from, $to ) == 0 ) return $string;
441
		if( strcasecmp( $from, 'utf-8' ) == 0 ) return utf8_decode( $string );
442
		if( strcasecmp( $to, 'utf-8' ) == 0 ) return utf8_encode( $string );
443
		return $string;
444
	}
445
}
446
447
if( !function_exists( 'istainted' ) ) {
448
449
	/**
450
	 * Fallback istainted function.
451
	 *
452
	 * @access public
453
	 * @param mixed $var
454
	 * @return integer
455
	 * @package Fallback
456
	 */
457
	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...
458
		return 0;
459
	}
460
461
	/**
462
	 * Fallback taint function.
463
	 *
464
	 * @access public
465
	 * @param mixed $var
466
	 * @param int $level
467
	 * @return void
468
	 * @package Fallback
469
	 */
470
	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...
471
472
	/**
473
	 * Fallback untaint function.
474
	 *
475
	 * @access public
476
	 * @param mixed $var
477
	 * @param int $level
478
	 * @return void
479
	 * @package Fallback
480
	 */
481
	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...
482
483
	/**
484
	 * @package Fallback
485
	 */
486
	define( 'TC_HTML', 1 );
487
488
	/**
489
	 * @package Fallback
490
	 */
491
	define( 'TC_SHELL', 1 );
492
493
	/**
494
	 * @package Fallback
495
	 */
496
	define( 'TC_MYSQL', 1 );
497
498
	/**
499
	 * @package Fallback
500
	 */
501
	define( 'TC_PCRE', 1 );
502
503
	/**
504
	 * @package Fallback
505
	 */
506
	define( 'TC_SELF', 1 );
507
}
508