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/site/SiteImporter.php (2 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
 * Utility for importing site entries from XML.
5
 * For the expected format of the input, see docs/sitelist.txt and docs/sitelist-1.0.xsd.
6
 *
7
 * This program is free software; you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation; either version 2 of the License, or
10
 * (at your option) any later version.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License along
18
 * with this program; if not, write to the Free Software Foundation, Inc.,
19
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20
 * http://www.gnu.org/copyleft/gpl.html
21
 *
22
 * @since 1.25
23
 *
24
 * @file
25
 * @ingroup Site
26
 *
27
 * @license GNU GPL v2+
28
 * @author Daniel Kinzler
29
 */
30
class SiteImporter {
31
32
	/**
33
	 * @var SiteStore
34
	 */
35
	private $store;
36
37
	/**
38
	 * @var callable|null
39
	 */
40
	private $exceptionCallback;
41
42
	/**
43
	 * @param SiteStore $store
44
	 */
45
	public function __construct( SiteStore $store ) {
46
		$this->store = $store;
47
	}
48
49
	/**
50
	 * @return callable
51
	 */
52
	public function getExceptionCallback() {
53
		return $this->exceptionCallback;
54
	}
55
56
	/**
57
	 * @param callable $exceptionCallback
58
	 */
59
	public function setExceptionCallback( $exceptionCallback ) {
60
		$this->exceptionCallback = $exceptionCallback;
61
	}
62
63
	/**
64
	 * @param string $file
65
	 */
66
	public function importFromFile( $file ) {
67
		$xml = file_get_contents( $file );
68
69
		if ( $xml === false ) {
70
			throw new RuntimeException( 'Failed to read ' . $file . '!' );
71
		}
72
73
		$this->importFromXML( $xml );
74
	}
75
76
	/**
77
	 * @param string $xml
78
	 *
79
	 * @throws InvalidArgumentException
80
	 */
81
	public function importFromXML( $xml ) {
82
		$document = new DOMDocument();
83
84
		$oldLibXmlErrors = libxml_use_internal_errors( true );
85
		$ok = $document->loadXML( $xml, LIBXML_NONET );
86
87
		if ( !$ok ) {
88
			$errors = libxml_get_errors();
89
			libxml_use_internal_errors( $oldLibXmlErrors );
90
91
			foreach ( $errors as $error ) {
92
				/** @var LibXMLError $error */
93
				throw new InvalidArgumentException(
94
					'Malformed XML: ' . $error->message . ' in line ' . $error->line
95
				);
96
			}
97
98
			throw new InvalidArgumentException( 'Malformed XML!' );
99
		}
100
101
		libxml_use_internal_errors( $oldLibXmlErrors );
102
		$this->importFromDOM( $document->documentElement );
103
	}
104
105
	/**
106
	 * @param DOMElement $root
107
	 */
108
	private function importFromDOM( DOMElement $root ) {
109
		$sites = $this->makeSiteList( $root );
110
		$this->store->saveSites( $sites );
111
	}
112
113
	/**
114
	 * @param DOMElement $root
115
	 *
116
	 * @return Site[]
117
	 */
118
	private function makeSiteList( DOMElement $root ) {
119
		$sites = [];
120
121
		// Old sites, to get the row IDs that correspond to the global site IDs.
122
		// TODO: Get rid of internal row IDs, they just get in the way. Get rid of ORMRow, too.
123
		$oldSites = $this->store->getSites();
124
125
		$current = $root->firstChild;
126
		while ( $current ) {
127
			if ( $current instanceof DOMElement && $current->tagName === 'site' ) {
128
				try {
129
					$site = $this->makeSite( $current );
130
					$key = $site->getGlobalId();
131
132
					if ( $oldSites->hasSite( $key ) ) {
133
						$oldSite = $oldSites->getSite( $key );
134
						$site->setInternalId( $oldSite->getInternalId() );
135
					}
136
137
					$sites[$key] = $site;
138
				} catch ( Exception $ex ) {
139
					$this->handleException( $ex );
140
				}
141
			}
142
143
			$current = $current->nextSibling;
144
		}
145
146
		return $sites;
147
	}
148
149
	/**
150
	 * @param DOMElement $siteElement
151
	 *
152
	 * @return Site
153
	 * @throws InvalidArgumentException
154
	 */
155
	public function makeSite( DOMElement $siteElement ) {
156
		if ( $siteElement->tagName !== 'site' ) {
157
			throw new InvalidArgumentException( 'Expected <site> tag, found ' . $siteElement->tagName );
158
		}
159
160
		$type = $this->getAttributeValue( $siteElement, 'type', Site::TYPE_UNKNOWN );
161
		$site = Site::newForType( $type );
162
163
		$site->setForward( $this->hasChild( $siteElement, 'forward' ) );
164
		$site->setGlobalId( $this->getChildText( $siteElement, 'globalid' ) );
165
		$site->setGroup( $this->getChildText( $siteElement, 'group', Site::GROUP_NONE ) );
166
		$site->setSource( $this->getChildText( $siteElement, 'source', Site::SOURCE_LOCAL ) );
167
168
		$pathTags = $siteElement->getElementsByTagName( 'path' );
169
		for ( $i = 0; $i < $pathTags->length; $i++ ) {
170
			$pathElement = $pathTags->item( $i );
171
			$pathType = $this->getAttributeValue( $pathElement, 'type' );
0 ignored issues
show
$pathElement of type object<DOMNode> is not a sub-type of object<DOMElement>. It seems like you assume a child class of the class DOMNode to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
172
			$path = $pathElement->textContent;
173
174
			$site->setPath( $pathType, $path );
175
		}
176
177
		$idTags = $siteElement->getElementsByTagName( 'localid' );
178
		for ( $i = 0; $i < $idTags->length; $i++ ) {
179
			$idElement = $idTags->item( $i );
180
			$idType = $this->getAttributeValue( $idElement, 'type' );
0 ignored issues
show
$idElement of type object<DOMNode> is not a sub-type of object<DOMElement>. It seems like you assume a child class of the class DOMNode to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
181
			$id = $idElement->textContent;
182
183
			$site->addLocalId( $idType, $id );
184
		}
185
186
		// @todo: import <data>
187
		// @todo: import <config>
188
189
		return $site;
190
	}
191
192
	/**
193
	 * @param DOMElement $element
194
	 * @param $name
195
	 * @param string|null|bool $default
196
	 *
197
	 * @return null|string
198
	 * @throws MWException If the attribute is not found and no default is provided
199
	 */
200
	private function getAttributeValue( DOMElement $element, $name, $default = false ) {
201
		$node = $element->getAttributeNode( $name );
202
203 View Code Duplication
		if ( !$node ) {
204
			if ( $default !== false ) {
205
				return $default;
206
			} else {
207
				throw new MWException(
208
					'Required ' . $name . ' attribute not found in <' . $element->tagName . '> tag'
209
				);
210
			}
211
		}
212
213
		return $node->textContent;
214
	}
215
216
	/**
217
	 * @param DOMElement $element
218
	 * @param string $name
219
	 * @param string|null|bool $default
220
	 *
221
	 * @return null|string
222
	 * @throws MWException If the child element is not found and no default is provided
223
	 */
224
	private function getChildText( DOMElement $element, $name, $default = false ) {
225
		$elements = $element->getElementsByTagName( $name );
226
227 View Code Duplication
		if ( $elements->length < 1 ) {
228
			if ( $default !== false ) {
229
				return $default;
230
			} else {
231
				throw new MWException(
232
					'Required <' . $name . '> tag not found inside <' . $element->tagName . '> tag'
233
				);
234
			}
235
		}
236
237
		$node = $elements->item( 0 );
238
		return $node->textContent;
239
	}
240
241
	/**
242
	 * @param DOMElement $element
243
	 * @param string $name
244
	 *
245
	 * @return bool
246
	 * @throws MWException
247
	 */
248
	private function hasChild( DOMElement $element, $name ) {
249
		return $this->getChildText( $element, $name, null ) !== null;
250
	}
251
252
	/**
253
	 * @param Exception $ex
254
	 */
255
	private function handleException( Exception $ex ) {
256
		if ( $this->exceptionCallback ) {
257
			call_user_func( $this->exceptionCallback, $ex );
258
		} else {
259
			wfLogWarning( $ex->getMessage() );
260
		}
261
	}
262
263
}
264