Issues (4122)

Security Analysis    not enabled

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.

includes/profiler/Profiler.php (1 issue)

Labels
Severity

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
 * Base class for profiling.
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation; either version 2 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License along
16
 * with this program; if not, write to the Free Software Foundation, Inc.,
17
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18
 * http://www.gnu.org/copyleft/gpl.html
19
 *
20
 * @file
21
 * @ingroup Profiler
22
 * @defgroup Profiler Profiler
23
 */
24
use Wikimedia\ScopedCallback;
0 ignored issues
show
This use statement conflicts with another class in this namespace, ScopedCallback.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
25
26
/**
27
 * Profiler base class that defines the interface and some trivial
28
 * functionality
29
 *
30
 * @ingroup Profiler
31
 */
32
abstract class Profiler {
33
	/** @var string|bool Profiler ID for bucketing data */
34
	protected $profileID = false;
35
	/** @var bool Whether MediaWiki is in a SkinTemplate output context */
36
	protected $templated = false;
37
	/** @var array All of the params passed from $wgProfiler */
38
	protected $params = [];
39
	/** @var IContextSource Current request context */
40
	protected $context = null;
41
	/** @var TransactionProfiler */
42
	protected $trxProfiler;
43
	/** @var Profiler */
44
	private static $instance = null;
45
46
	/**
47
	 * @param array $params
48
	 */
49
	public function __construct( array $params ) {
50
		if ( isset( $params['profileID'] ) ) {
51
			$this->profileID = $params['profileID'];
52
		}
53
		$this->params = $params;
54
		$this->trxProfiler = new TransactionProfiler();
55
	}
56
57
	/**
58
	 * Singleton
59
	 * @return Profiler
60
	 */
61
	final public static function instance() {
62
		if ( self::$instance === null ) {
63
			global $wgProfiler, $wgProfileLimit;
64
65
			$params = [
66
				'class'     => 'ProfilerStub',
67
				'sampling'  => 1,
68
				'threshold' => $wgProfileLimit,
69
				'output'    => [],
70
			];
71
			if ( is_array( $wgProfiler ) ) {
72
				$params = array_merge( $params, $wgProfiler );
73
			}
74
75
			$inSample = mt_rand( 0, $params['sampling'] - 1 ) === 0;
76
			if ( PHP_SAPI === 'cli' || !$inSample ) {
77
				$params['class'] = 'ProfilerStub';
78
			}
79
80
			if ( !is_array( $params['output'] ) ) {
81
				$params['output'] = [ $params['output'] ];
82
			}
83
84
			self::$instance = new $params['class']( $params );
85
		}
86
		return self::$instance;
87
	}
88
89
	/**
90
	 * Replace the current profiler with $profiler if no non-stub profiler is set
91
	 *
92
	 * @param Profiler $profiler
93
	 * @throws MWException
94
	 * @since 1.25
95
	 */
96
	final public static function replaceStubInstance( Profiler $profiler ) {
97
		if ( self::$instance && !( self::$instance instanceof ProfilerStub ) ) {
98
			throw new MWException( 'Could not replace non-stub profiler instance.' );
99
		} else {
100
			self::$instance = $profiler;
101
		}
102
	}
103
104
	/**
105
	 * @param string $id
106
	 */
107
	public function setProfileID( $id ) {
108
		$this->profileID = $id;
109
	}
110
111
	/**
112
	 * @return string
113
	 */
114
	public function getProfileID() {
115
		if ( $this->profileID === false ) {
116
			return wfWikiID();
117
		} else {
118
			return $this->profileID;
119
		}
120
	}
121
122
	/**
123
	 * Sets the context for this Profiler
124
	 *
125
	 * @param IContextSource $context
126
	 * @since 1.25
127
	 */
128
	public function setContext( $context ) {
129
		$this->context = $context;
130
	}
131
132
	/**
133
	 * Gets the context for this Profiler
134
	 *
135
	 * @return IContextSource
136
	 * @since 1.25
137
	 */
138
	public function getContext() {
139
		if ( $this->context ) {
140
			return $this->context;
141
		} else {
142
			wfDebug( __METHOD__ . " called and \$context is null. " .
143
				"Return RequestContext::getMain(); for sanity\n" );
144
			return RequestContext::getMain();
145
		}
146
	}
147
148
	// Kept BC for now, remove when possible
149
	public function profileIn( $functionname ) {
150
	}
151
152
	public function profileOut( $functionname ) {
153
	}
154
155
	/**
156
	 * Mark the start of a custom profiling frame (e.g. DB queries).
157
	 * The frame ends when the result of this method falls out of scope.
158
	 *
159
	 * @param string $section
160
	 * @return ScopedCallback|null
161
	 * @since 1.25
162
	 */
163
	abstract public function scopedProfileIn( $section );
164
165
	/**
166
	 * @param SectionProfileCallback $section
167
	 */
168
	public function scopedProfileOut( SectionProfileCallback &$section = null ) {
169
		$section = null;
170
	}
171
172
	/**
173
	 * @return TransactionProfiler
174
	 * @since 1.25
175
	 */
176
	public function getTransactionProfiler() {
177
		return $this->trxProfiler;
178
	}
179
180
	/**
181
	 * Close opened profiling sections
182
	 */
183
	abstract public function close();
184
185
	/**
186
	 * Get all usable outputs.
187
	 *
188
	 * @throws MWException
189
	 * @return array Array of ProfilerOutput instances.
190
	 * @since 1.25
191
	 */
192
	private function getOutputs() {
193
		$outputs = [];
194
		foreach ( $this->params['output'] as $outputType ) {
195
			// The class may be specified as either the full class name (for
196
			// example, 'ProfilerOutputStats') or (for backward compatibility)
197
			// the trailing portion of the class name (for example, 'stats').
198
			$outputClass = strpos( $outputType, 'ProfilerOutput' ) === false
199
				? 'ProfilerOutput' . ucfirst( $outputType )
200
				: $outputType;
201
			if ( !class_exists( $outputClass ) ) {
202
				throw new MWException( "'$outputType' is an invalid output type" );
203
			}
204
			$outputInstance = new $outputClass( $this, $this->params );
205
			if ( $outputInstance->canUse() ) {
206
				$outputs[] = $outputInstance;
207
			}
208
		}
209
		return $outputs;
210
	}
211
212
	/**
213
	 * Log the data to some store or even the page output
214
	 *
215
	 * @since 1.25
216
	 */
217
	public function logData() {
218
		$request = $this->getContext()->getRequest();
219
220
		$timeElapsed = $request->getElapsedTime();
221
		$timeElapsedThreshold = $this->params['threshold'];
222
		if ( $timeElapsed <= $timeElapsedThreshold ) {
223
			return;
224
		}
225
226
		$outputs = $this->getOutputs();
227
		if ( !$outputs ) {
228
			return;
229
		}
230
231
		$stats = $this->getFunctionStats();
232
		foreach ( $outputs as $output ) {
233
			$output->log( $stats );
234
		}
235
	}
236
237
	/**
238
	 * Output current data to the page output if configured to do so
239
	 *
240
	 * @throws MWException
241
	 * @since 1.26
242
	 */
243
	public function logDataPageOutputOnly() {
244
		foreach ( $this->getOutputs() as $output ) {
245
			if ( $output instanceof ProfilerOutputText ) {
246
				$stats = $this->getFunctionStats();
247
				$output->log( $stats );
248
			}
249
		}
250
	}
251
252
	/**
253
	 * Get the content type sent out to the client.
254
	 * Used for profilers that output instead of store data.
255
	 * @return string
256
	 * @since 1.25
257
	 */
258
	public function getContentType() {
259
		foreach ( headers_list() as $header ) {
260
			if ( preg_match( '#^content-type: (\w+/\w+);?#i', $header, $m ) ) {
261
				return $m[1];
262
			}
263
		}
264
		return null;
265
	}
266
267
	/**
268
	 * Mark this call as templated or not
269
	 *
270
	 * @param bool $t
271
	 */
272
	public function setTemplated( $t ) {
273
		$this->templated = $t;
274
	}
275
276
	/**
277
	 * Was this call as templated or not
278
	 *
279
	 * @return bool
280
	 */
281
	public function getTemplated() {
282
		return $this->templated;
283
	}
284
285
	/**
286
	 * Get the aggregated inclusive profiling data for each method
287
	 *
288
	 * The percent time for each time is based on the current "total" time
289
	 * used is based on all methods so far. This method can therefore be
290
	 * called several times in between several profiling calls without the
291
	 * delays in usage of the profiler skewing the results. A "-total" entry
292
	 * is always included in the results.
293
	 *
294
	 * When a call chain involves a method invoked within itself, any
295
	 * entries for the cyclic invocation should be be demarked with "@".
296
	 * This makes filtering them out easier and follows the xhprof style.
297
	 *
298
	 * @return array List of method entries arrays, each having:
299
	 *   - name     : method name
300
	 *   - calls    : the number of invoking calls
301
	 *   - real     : real time elapsed (ms)
302
	 *   - %real    : percent real time
303
	 *   - cpu      : CPU time elapsed (ms)
304
	 *   - %cpu     : percent CPU time
305
	 *   - memory   : memory used (bytes)
306
	 *   - %memory  : percent memory used
307
	 *   - min_real : min real time in a call (ms)
308
	 *   - max_real : max real time in a call (ms)
309
	 * @since 1.25
310
	 */
311
	abstract public function getFunctionStats();
312
313
	/**
314
	 * Returns a profiling output to be stored in debug file
315
	 *
316
	 * @return string
317
	 */
318
	abstract public function getOutput();
319
}
320