Issues (438)

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.

classes/Kills.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
/* zKillboard
3
 * Copyright (C) 2012-2015 EVE-KILL Team and EVSCO.
4
 *
5
 * This program is free software: you can redistribute it and/or modify
6
 * it under the terms of the GNU Affero General Public License as published by
7
 * the Free Software Foundation, either version 3 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 Affero General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU Affero General Public License
16
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
 */
18
19
/**
20
 * General stuff for getting kills and manipulating them
21
 */
22
class Kills
23
{
24
	/**
25
	 * Gets killmails
26
	 *
27
	 * @param $parameters an array of parameters to fetch mails for
28
	 * @param $allTime gets all mails from the beginning of time or not
29
	 * @return array
30
	 */
31
	public static function getKills($parameters = array(), $allTime = true, $includeKillDetails = true)
32
	{
33
		$tables = array();
34
		$orWhereClauses = array();
35
		$andWhereClauses = array();
36
		Filters::buildFilters($tables, $orWhereClauses, $andWhereClauses, $parameters, $allTime);
37
38
		$tables = array_unique($tables);
39
		if (sizeof($tables) == 0) $tables[] = "zz_participants p";
40
		if (sizeof($tables) > 2) throw new Exception("More than 2 tables not supported yet");
41
42
		$tables = array_values($tables);
43
		$tablePrefix = substr($tables[0], strlen($tables[0]) - 1, 1);
44
		$tablePrefixOther = sizeof($tables) == 2 ? substr($tables[1], strlen($tables[1]) - 1, 1) : "p";
45
46
		$query = "select distinct ${tablePrefix}.killID from ";
47
		$query .= implode(" left join ", array_unique($tables));
48
		if (sizeof($tables) == 2) $query .= " on ($tablePrefix.killID = ${tablePrefixOther}.killID) ";
49
		if(isset($parameters["index"])) $query .= " use index (". $parameters["index"] . ") ";
50
		if (sizeof($andWhereClauses) || sizeof($orWhereClauses)) {
51
			$query .= " where ";
52
			if (sizeof($orWhereClauses) > 0) {
53
				$andOr = array_key_exists("combined", $parameters) && $parameters["combined"] == true ? " or " : " and ";
54
				$query .= " ( " . implode($andOr, $orWhereClauses) . " ) ";
55
				if (sizeof($andWhereClauses)) $query .= " and ";
56
			}
57
			if (sizeof($andWhereClauses)) $query .= implode(" and ", $andWhereClauses);
58
		}
59
60
		$limit = array_key_exists("limit", $parameters) ? (int)$parameters["limit"] : 100;
61
		$page = array_key_exists("page", $parameters) ? (int)$parameters["page"] : 1;
62
		$offset = ($page - 1) * $limit;
63
64
		if ($tablePrefix == "w") $orderBy = "w.killID";
65
		else $orderBy = array_key_exists("orderBy", $parameters) ? $parameters["orderBy"] : "${tablePrefix}.dttm";
66
		$orderDirection = array_key_exists("orderDirection", $parameters) ? $parameters["orderDirection"] : "desc";
67
		$orderDirection = "desc"; // only desc
68
		$query .= " order by $orderBy $orderDirection limit $offset, $limit";
69
70
		// Is isVictim is used, no need to use distinct, since isVictim is already distinct
71
		if(stristr($query, "isVictim = '1'"))
72
			$query = str_replace("distinct", "", $query);
73
74
		// This is a war query, lets replace the entire thing
75
		if(isset($parameters["war"]))
76
			$query = "SELECT p.killID FROM zz_participants p WHERE p.killID IN (SELECT killID FROM zz_warmails WHERE warID = " . $parameters["war"] . ") AND p.isVictim = 1 ORDER BY $orderBy $orderDirection LIMIT $offset, $limit";
77
78
		$cacheTime = array_key_exists("cacheTime", $parameters) ? (int)$parameters["cacheTime"] : 120;
79
		$cacheTime = max(120, $cacheTime);
80
		if (array_key_exists("log", $parameters)) Db::log($query, array());
81
		$kills = Db::query($query, array(), $cacheTime);
82
		if ($includeKillDetails == false) return $kills;
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
83
		$merged = self::getKillsDetails($kills);
84
		return $merged;
85
	}
86
87
	/**
88
	 * Gets details for kills
89
	 *
90
	 * @param $kills
91
	 * @return array
92
	 */
93
	public static function getKillsDetails($kills)
94
	{
95
		$merged = array();
96
		$killIDS = array();
97
98
		foreach ($kills as $kill) {
99
			$killIDS[] = $kill["killID"];
100
			$merged[$kill["killID"]] = array();
101
		}
102
103
		if (sizeof($killIDS)) {
104
			$imploded = implode(",", $killIDS);
105
			$victims = Db::query("select * from zz_participants where killID in ($imploded) and isVictim = 1", array(), 300);
106
			$finalBlows = Db::query("select * from zz_participants where killID in ($imploded) and finalBlow = 1", array(), 300);
107
			$info = $victims;
108
			$merged = self::killMerge($merged, "victim", $victims);
109
			$merged = self::killMerge($merged, "finalBlow", $finalBlows);
110
			$merged = self::killMerge($merged, "info", $info);
111
		}
112
		return $merged;
113
	}
114
115
	/**
116
	 * Merges killmail arrays
117
	 *
118
	 * @param $array1
119
	 * @param string $type
120
	 * @param $array2
121
	 * @return array
122
	 */
123
	private static function killMerge($array1, $type, $array2)
124
	{
125
		foreach ($array2 as $element) {
126
			$killid = $element["killID"];
127
			Info::addInfo($element);
128
			if (!isset($array1[$killid])) $array1[$killid] = array();
129
			$array1[$killid][$type] = $element;
130
			$array1[$killid][$type]["commentID"] = $killid;
131
		}
132
		return $array1;
133
	}
134
135
	/**
136
	 * Gets details for a kill
137
	 *
138
	 * @param $killID the killID of the kill you want details for
139
	 * @return array
140
	 */
141
	public static function getKillDetails($killID)
142
	{
143
		$victim = Db::queryRow("select * from zz_participants where killID = :killID and isVictim = 1", array(":killID" => $killID));
144
		$kill = $victim;
145
		$involved = Db::query("select * from zz_participants where killID = :killID and isVictim = 0 order by damage desc", array(":killID" => $killID));
146
		$items = self::getItems($killID);
147
148
		Info::addInfo($kill);
149
		Info::addInfo($victim);
150
		$infoInvolved = array();
151
		$infoItems = array();
152
		foreach ($involved as $i) $infoInvolved[] = Info::addInfo($i);
153
		unset($involved);
154
		foreach ($items as $i) $infoItems[] = Info::addInfo($i);
155
		unset($items);
156
157
		return array("info" => $kill, "victim" => $victim, "involved" => $infoInvolved, "items" => $infoItems);
158
	}
159
160
	public static function getItems($killID)
161
	{
162
		$json = Killmail::get($killID);
163
		$killArray = json_decode($json, true);
164
		$killTime = $killArray["killTime"];
165
		$items = array();
166
		if(isset($killArray["items"]))
167
			self::addItems($items, $killArray["items"], $killTime);
168
		return $items;
169
	}
170
171
	public static function addItems(&$itemArray, $items, $killTime, $inContainer = 0, $parentFlag = 0) {
172
		if (is_array($items)) foreach ($items as $item) {
173
			$typeID = $item["typeID"];
174
			$item["price"] = Price::getItemPrice($typeID, $killTime);
175
			$item["inContainer"] = $inContainer;
176
			if ($inContainer) $item["flag"] = $parentFlag;
177
			if ($inContainer && strpos(Info::getItemName($typeID), "Blueprint")) $item["singleton"] = 2;
178
			unset($item["_stringValue"]);
179
			$itemArray[] = $item;
180
			$subItems = isset($item["items"]) ? $item["items"] : null;
181
			unset($item["items"]);
182
			if ($subItems != null) self::addItems($itemArray, $subItems, $killTime, 1, $item["flag"]);
183
		}
184
	}
185
186
	/**
187
	 * Merges two kill arrays together
188
	 *
189
	 * @param $array1
190
	 * @param $array2
191
	 * @param $maxSize
192
	 * @param $key
193
	 * @param $id
194
	 * @return array
195
	 */
196
	public static function mergeKillArrays($array1, $array2, $maxSize, $key, $id)
197
	{
198
		$maxSize = max(0, $maxSize);
199
		$resultArray = array_diff_key($array1, $array2) + $array2;
200
		while (sizeof($resultArray) > $maxSize) array_pop($resultArray);
201
		foreach ($resultArray as $killID => $kill) {
202
			if (!isset($kill["victim"])) continue;
203
			$victim = $kill["victim"];
204
			if ($victim[$key] == $id) $kill["displayAsLoss"] = true;
205
			else $kill["displayAsKill"] = true;
206
			$resultArray[$killID] = $kill;
207
		}
208
		return $resultArray;
209
	}
210
211
	/**
212
	 * Returns an array of the kill
213
	 *
214
	 * @param $killID the ID of the kill
215
	 * @return array
216
	 */
217
	public static function getArray($killID)
218
	{
219
		$jsonRaw = Killmail::get($killID);
220
		$decode = json_decode($jsonRaw, true);
221
		$killarray = Info::addInfo($decode);
222
		return $killarray;
223
	}
224
225
	/**
226
	 * Returns json of the kill
227
	 *
228
	 * @param $killID the ID of the kill
229
	 * @return string
230
	 */
231
	public static function getJson($killID)
232
	{
233
		$jsonRaw = Killmail::get($killID);
234
		$decoded = json_decode($jsonRaw, true);
235
		$killarray = Info::addInfo($decoded);
236
		return json_encode($killarray);
237
	}
238
239
	/**
240
	 * Returns a raw mail, that it gets from the getArray function
241
	 *
242
	 * @static
243
	 * @param $killID the ID of the kill
244
	 * @return string
245
	 */
246
	public static function getRawMail($killID, $array = array(), $edk = true)
247
	{
248
		$cacheName = $killID;
249
		$sem = Semaphore::fetch($killID);
250
		if($edk)
251
			$cacheName = $killID."EDK";
252
253
		// Check if the mail has already been generated, then return it from the cache..
254
		$Cache = Cache::get($cacheName);
255
		if($Cache) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $Cache of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

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.

Loading history...
256
			Semaphore::release($sem);
257
			return $Cache;
258
		}
259
260
		// Find all groupIDs where they contain Deadspace
261
		$deadspaceIDs = array();
262
		$dIDs = Db::query("SELECT groupID FROM ccp_invGroups WHERE groupName LIKE '%deadspace%' OR groupName LIKE 'FW%' OR groupName LIKE 'Asteroid%'");
263
		foreach($dIDs as $dd)
264
			$deadspaceIDs[] = $dd["groupID"];
265
266
		// ADD ALL THE FLAGS!!!!!!!!!!!
267
		//$flags = array("(Cargo)" => 5, "(Drone Bay)" => 87, "(Implant)" => 89);
268
		$dbFlags = Db::query("SELECT flagText, flagID FROM ccp_invFlags", array(), 3600);
269
		$flags = array();
270
		foreach($dbFlags as $f)
271
			$flags[(int) $f["flagID"]] = $f["flagText"];
272
273
		if(!$array)
274
			$k = self::getArray($killID);
275
		else
276
			$k = $array;
277
278
		$mail = $k["killTime"] . "\n";
279
		$mail .= "\n";
280
		$mail .= "Victim: " . $k["victim"]["characterName"] . "\n";
281
		$mail .= "Corp: " . $k["victim"]["corporationName"] . "\n";
282
		if (!isset($k["victim"]["allianceName"]) || $k["victim"]["allianceName"] == "")
283
			$k["victim"]["allianceName"] = "None";
284
		$mail .= "Alliance: " . $k["victim"]["allianceName"] . "\n";
285
		if (!isset($k["victim"]["factionName"]) || $k["victim"]["factionName"] == "")
286
			$k["victim"]["factionName"] = "None";
287
		$mail .= "Faction: " . $k["victim"]["factionName"] . "\n";
288
		if (!isset($k["victim"]["shipName"]) || $k["victim"]["shipName"] == "")
289
			$k["victim"]["shipName"] = "None";
290
		$mail .= "Destroyed: " . $k["victim"]["shipName"] . "\n";
291
		if (!isset($k["solarSystemName"]) || $k["solarSystemName"] == "")
292
			$k["solarSystemName"] = "None";
293
		$mail .= "System: " . $k["solarSystemName"] . "\n";
294
		if (!isset($k["solarSystemSecurity"]) || $k["solarSystemSecurity"] == "")
295
			$k["solarSystemSecurity"] = (int) 0;
296
		$mail .= "Security: " . $k["solarSystemSecurity"] . "\n";
297
		if (!isset($k["victim"]["damageTaken"]) || $k["victim"]["damageTaken"] == "")
298
			$k["victim"]["damageTaken"] = (int) 0;
299
		$mail .= "Damage Taken: " . $k["victim"]["damageTaken"] . "\n\n";
300
		if(isset($k["attackers"]))
301
		{
302
			$mail .= "Involved parties:\n\n";
303
			foreach ($k["attackers"] as $inv)
304
			{
305
				// find groupID for the ship
306
				if(!isset($inv["shipName"])) $inv["shipName"] = "Unknown";
307
				$groupID = Db::queryField("SELECT groupID FROM ccp_invTypes WHERE typeName LIKE :shipName", "groupID", array(":shipName" => $inv["shipName"]));
308
				if(in_array($groupID, $deadspaceIDs))
309
				{
310
					// shipName isn't set, but it's an npc.. fml..
311
					if ($inv["finalBlow"] == 1)
312
						$mail .= "Name: ". $inv["shipName"] . " / " . $inv["corporationName"] . " (laid the final blow)\n";
313
					else
314
						$mail .= "Name: ". $inv["shipName"] . " / " . $inv["corporationName"] . "\n";
315
					$mail .= "Damage Done: " . $inv["damageDone"] . "\n\n";
316
				}
317
				else
318
				{
319
					if ($inv["finalBlow"] == 1)
320
						$mail .= "Name: " . $inv["characterName"] . " (laid the final blow)\n";
321
					else if (strlen($inv["characterName"]))
322
						$mail .= "Name: " . $inv["characterName"] . "\n";
323
					if (strlen($inv["characterName"])) $mail .= "Security: " . $inv["securityStatus"] . "\n";
324
					$mail .= "Corp: " . $inv["corporationName"] . "\n";
325
					if (!isset($inv["allianceName"]) || $inv["allianceName"] == "")
326
						$inv["allianceName"] = "None";
327
					$mail .= "Alliance: " . $inv["allianceName"] . "\n";
328
					if (!isset($inv["factionName"]) || $inv["factionName"] == "")
329
						$inv["factionName"] = "None";
330
					$mail .= "Faction: " . $inv["factionName"] . "\n";
331
					if (!isset($inv["shipName"]) || $inv["shipName"] == "")
332
						$inv["shipName"] = "None";
333
					$mail .= "Ship: " . $inv["shipName"] . "\n";
334
					if (!isset($inv["weaponName"]) || $inv["weaponName"] == "")
335
						$inv["weaponName"] = $inv["shipName"];
336
					$mail .= "Weapon: " . $inv["weaponName"] . "\n";
337
					$mail .= "Damage Done: " . $inv["damageDone"] . "\n\n";
338
				}
339
			}
340
		}
341
342
		$mail .= "\n";
343
		$dropped = array();
344
		$destroyed = array();
345
		if(isset($k["items"]))
346
		{
347
			foreach($k["items"] as $itm)
348
			{
349
				// Take the flags we get from $itemToSlot and replace it with the proper flag from the database
350
				if (!(isset($itm["flag"]) && isset($flags[$itm["flag"]]))) continue;
351
				$itm["flagName"] = $flags[$itm["flag"]];
352
353
				// create the flag!
354
				$copy = null;
355
				if($itm["singleton"] == 2)
356
					$copy = " (Copy)";
357
358
				$edkValidFlags = array("Cargo", "Drone Bay");
359
				if($edk && !in_array($itm["flagName"], $edkValidFlags))
360
					$flagName = null;
361
				else
362
					$flagName = " (". $itm["flagName"] . ")";
363
364
365
				if($itm["qtyDropped"]) // go to dropped list
366
				{
367
					$line = $itm["typeName"] . ", Qty: " . $itm["qtyDropped"] . $flagName . ($copy ? $copy : null);
368
					$dropped[] = $line;
369
				}
370
371
				if($itm["qtyDestroyed"]) // go to destroyed list
372
				{
373
					$line = $itm["typeName"] . ", Qty: " . $itm["qtyDestroyed"] . $flagName . ($copy ? $copy : null);
374
					$destroyed[] = $line;
375
				}
376
377
				if(isset($itm["items"]))
378
					foreach($itm["items"] as $key => $sub)
379
					{
380
						if($sub["qtyDropped"]) // go to dropped list
381
						{
382
							$line = $sub["typeName"] . ", Qty: " . $sub["qtyDropped"] . $flagName . ($copy ? $copy : null) . " (In Container)";
383
							$dropped[] = $line;
384
						}
385
						if($sub["qtyDestroyed"]) // go to destroyed list
386
						{
387
							$line = $sub["typeName"] . ", Qty: " . $sub["qtyDestroyed"] . $flagName . ($copy ? $copy : null) . " (In Container)";
388
							$destroyed[] = $line;
389
						}
390
					}
391
			}
392
		}
393
394
		if ($destroyed) {
395
			$mail .= "Destroyed items:\n\n";
396
			foreach ($destroyed as $items)
397
				$mail .= $items . "\n";
398
		}
399
		$mail .= "\n";
400
		if ($dropped) {
401
			$mail .= "Dropped items:\n\n";
402
			foreach ($dropped as $items)
403
				$mail .= $items . "\n";
404
		}
405
406
		// Store the generated mail in cache
407
		Cache::set($cacheName, $mail, 604800);
408
409
		Semaphore::release($sem);
410
		return $mail;
411
	}
412
413
	public static function cleanDupe($mKillID, $killID)
414
	{
415
		Db::execute("update zz_killmails set processed = 2 where killID = :mKillID", array(":mKillID" => $mKillID));
416
		Stats::calcStats($mKillID, false); // remove manual version from stats
417
	}
418
}
419