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/Parser.php (3 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-2013 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
 * Parser for raw killmails from ingame EVE.
21
 */
22
23
class Parser
24
{
25
26
	/**
27
	 * Parses a raw killmail, and spits out a nice pretty array.
28
	 * 
29
	 * @static
30
	 * @param $rawMail - the raw killmail
31
	 * @param $userID - the ID of the user who posted the raw mail
32
	 * @return array
33
	 */
34
	public static function parseRaw($rawMail, $userID)
35
	{
36
		$errors = array();
37
		$mail = trim(str_replace("\r", "", $rawMail));
38
39
		// Translate the killmail from whatever language it is to english.. ~CCP~
40
		$mail = self::Translate($mail);
41
42
		// If the site is in maintenance mode, the parser shouldn't even run..
43
		if (Util::isMaintenanceMode()) {
44
			$errors[] = "The site is currently in maintenance mode.  Manual posts are not accepted at the moment.";
45
		}
46
47
		// Fix a faction name that was previously set as an alliance
48
		if (Bin::get("FixFaction", false)) {
49
			$mail = str_ireplace("Alliance: Federation Navy", "Faction: Gallente Federation", $mail);
50
		}
51
52
		// Fix an error that has happened a few times, where Involved parties: and Name: are on the same line
53
		if(stristr($mail, "Involved parties:Name:"))
54
			$mail = str_replace("Involved parties:Name:", "Involved parties:\n\nName:", $mail);
55
56
		// Fix unicode and random CCP localization problems.
57
		$mail = utf8_decode($mail);
58
		$mail = preg_replace('/: (\d+),00/', ': $1', $mail);
59
		$mail = preg_replace('/(\d),(\d)/', '$1.$2', $mail);
60
		$mail = str_replace('?', '-', $mail);
61
62
		// Remove (Other) - because CCP fails at life.. Refer to https://github.com/EVE-KILL/zKillboard/issues/174
63
		$mail = str_replace(" (Other)", "", $mail);
64
65
		// Find the timestamp
66
		$timestamp = substr($mail, 0, 16);
67
		$timestamp = str_replace(".", "-", $timestamp);
68
		$timestamp .= ":00";
69
70
		// Make sure there is a timestamp
71
		if (!$timestamp)
72
			$errors[] = "No timestamp, probably not even a killmail";
73
74
		// Validate timestamp
75
		$time = DateTime::createFromFormat("Y-m-d H:i:s", $timestamp);
76
		if($time != false)
77
			$timestamp = $time->format("Y-m-d H:i:s");
78
		else
79
			$errors[] = "Error with the timestamp..";
80
81
		// Make sure there is an involved party
82
		if (stripos($mail, "Involved parties:") === false)
83
			$errors[] = "No involved parties..";
84
85
		// If there was an error now, we might aswell return it and give up
86
		if (sizeof($errors)) {
87
			return array("error" => $errors);
88
		}
89
90
		// Initialize the main array that we will be inserting stuff to.
91
		$killMail = array(
92
			"killID" => 0,
93
			"solarSystemID" => 0,
94
			"killTime" => $timestamp,
95
			"moonID" => 0,
96
			"victim" => array(
97
				"shipTypeID" => 0,
98
				"damageTaken" => 0,
99
				"factionName" => "",
100
				"factionID" => 0,
101
				"allianceName" => "",
102
				"allianceID" => 0,
103
				"corporationName" => "",
104
				"corporationID" => 0,
105
				"characterName" => "",
106
				"characterID" => 0,
107
			),
108
			"attackers" => array(),
109
			"items" => array()
110
		);
111
112
		$mail = trim(substr($mail, 16));
113
		if (Util::startsWith(":00", $mail)) $mail = substr($mail, 3);
114
115
		$exploded = explode("\n", $mail);
116
117
		$inVictim = true;
118
		$inAttackers = false;
119
		$inDestroyedItems = false;
120
		$inDroppedItems = false;
121
		$currentAttacker = null;
122
		$killValue = 0;
123
		$currentLowSlot = 11;
124
		$currentMidSlot = 19;
125
		$currentHighSlot = 27;
126
		$currentRigSlot = 92;
127
		$currentSubSlot = 125;
128
129
		foreach($exploded as $line) {
130
			$split = explode(":", $line);
131
			$key = $split[0] . ":";
132
			$value = isset($split[1]) ? trim($split[1]) : $line;
133
			switch($key) {
134
				case "Victim:":
135
					$killMail["victim"]["characterName"] = (string) $value;
136
					$killMail["victim"]["characterID"] = (int) Info::getCharID($value);
137
				break;
138
				case "Corp:":
139
					if ($inVictim) {
140
						$killMail["victim"]["corporationName"] = (string) $value;
141
						$killMail["victim"]["corporationID"] = (int) Info::getCorpID($value);
142
					} else if ($inAttackers) {
143
						$currentAttacker["corporationName"] = (string) $value;
144
						$currentAttacker["corporationID"] = (int) Info::getCorpID($value);
145
					}
146
				break;
147
				case "Alliance:":
148
					if (strcasecmp($value, "Unknown") == 0 || strcasecmp($value, "None") == 0) $value = "None";
149
					if ($inVictim) {
150
						$killMail["victim"]["allianceName"] = (string) $value;
151
						if ($value == "None") $killMail["victim"]["allianceID"] = 0;
152
						else $killMail["victim"]["allianceID"] = (int) Info::getAlliID($value);
153
					} else if ($inAttackers) {
154
						$currentAttacker["allianceName"] = (string) $value;
155
						if ($value == "None") $currentAttacker["allianceID"] = 0;
156
						else $currentAttacker["allianceID"] = (int) Info::getAlliID($value);
157
					}
158
				break;
159
				case "Faction:":
160
					if (strcasecmp($value, "Unknown") == 0 || strcasecmp($value, "None") == 0) $value = "None";
161
					if ($inVictim) {
162
						$killMail["victim"]["factionName"] = (string) $value;
163
						if ($value == "None") $killMail["victim"]["factionID"] = 0;
164
						else $killMail["victim"]["factionID"] = (int) Info::getFactionID($value);
165
					} else if ($inAttackers) {
166
						$currentAttacker["factionName"] = (string) $value;
167
						if ($value == "None") $currentAttacker["factionID"] = 0;
168
						else $currentAttacker["factionID"] = (int) Info::getFactionID($value);
169
					}
170
				break;
171
				case "Destroyed:":
172
					$killMail["victim"]["shipTypeID"] = (int) Info::getItemID($value);
173
					$killValue =+ Price::getItemPrice($killMail["victim"]["shipTypeID"]);
0 ignored issues
show
The call to getItemPrice() misses a required argument $date.

This check looks for function calls that miss required arguments.

Loading history...
174
				break;
175
				case "Damage Taken:":
176
					$killMail["victim"]["damageTaken"] = (int) $value;
177
				break;
178
				case "System:":
179
					$killMail["solarSystemID"] = (int) Info::getSystemID($value);
180
				break;
181
				case "Moon:":
182
					if (strcasecmp($value, "Unknown") == 0 || strcasecmp($value, "None") == 0) $value = "None";
183
					$split = explode("-", $value);
184
					$value = "";
185
					$size = sizeof($split) - 1;
186
					for ($a = $size; $a >= 0; $a--) {
187
						$value = $split[$a] . ($a == $size ? "" : "-") . $value;
188
						$moonID = (int) Db::queryField("select itemID from ccp_mapDenormalize where itemName = :name", "itemID", array(":name" => trim($value)));
189
						if ($moonID) break;
190
					}
191
					$value = trim($value);
192
					if ($value == "None") $killMail["moonID"] = 0;
193
					else {
194
						$moonID = (int) Db::queryField("select itemID from ccp_mapDenormalize where itemName = :name", "itemID", array(":name" => $value));
195
						if ($moonID > 0) $killMail["moonID"] = $moonID;
196
						else $errors[] = "Invalid Moon: $value";
197
					}
198
				break;
199
				case "Name:":
200
					if($inAttackers) $currentAttacker = self::createAttacker();
201
					if (stripos($value, "(laid the final blow)") !== false) {
202
						$currentAttacker["finalBlow"] = 1;
203
						$value = trim(str_ireplace("(laid the final blow)", "", $value));
204
					}
205
					$id = 0;
206
					if ($value != "" && strpos($value, "/") === false) $id = (int) Info::getCharID($value);
207
					if ($id != 0) {
208
						$currentAttacker["characterName"] = (string) $value;
209
						$currentAttacker["characterID"] = $id;
210
					}
211
					if ($id == 0) {
212
						// Might be an NPC?
213
						$npcSplit = explode("/", $value);
214
						$npc = trim($npcSplit[0]);
215
						$id = (int) Db::queryField("select typeID from ccp_invTypes where typeName = :name", "typeID", 
216
								array(":name" => $npc));
217
						$currentAttacker["weaponTypeID"] = $id;
218
						if (sizeof($npcSplit) > 1 && trim($npcSplit[1]) != "Unknown") {
219
							// Look up the corp
220
							$corpID = Info::getCorpID(trim($npcSplit[1]));
221
							if ($corpID > 0) {
222
								$currentAttacker["corporationID"] = $corpID;
223
								$currentAttacker["corporationName"] = trim($npcSplit[1]);
224
							} else {
225
								$errors[] = "Unable to determine item information: $value";
226
							}
227
						}
228
					}
229
				break;
230
				case "Security:":
231
					if ($inAttackers) $currentAttacker["securityStatus"] = (float) $value;
232
				break;
233
				case "Ship:":
234
					if ($inAttackers) $currentAttacker["shipTypeID"] = (int) Info::getItemID($value);
235
				break;
236
				case "Weapon:":
237
					if ($inAttackers) $currentAttacker["weaponTypeID"] = (int) Info::getItemID($value);
238
				break;
239
				case "Damage Done:":
240
					if ($inAttackers) $currentAttacker["damageDone"] = (int) $value;
241
					if ($currentAttacker != null) $killMail["attackers"][] = $currentAttacker;
242
				break;
243
244
                case "Involved parties:":
245
                    $inVictim = false;
246
                    $inAttackers = true;
247
        			$inDestroyedItems = false;
248
        			$inDroppedItems = false;
249
                break;
250
				case "Destroyed items:":
251
                    $inVictim = false;
252
                    $inAttackers = false;
253
        			$inDestroyedItems = true;
254
        			$inDroppedItems = false;
255
				break;
256
				case "Dropped items:":
257
                    $inVictim = false;
258
                    $inAttackers = false;
259
        			$inDestroyedItems = false;
260
        			$inDroppedItems = true;
261
				break;
262
				case "":
263
				case ":":
264
					continue;
265
				default:
266
					if ($inVictim || $inAttackers) throw new Exception("Unhandled prefix: $key");
267
					// We have an item!
268
					$value = $line;
269
					$flag = null;
270
					$qty = 1;
271
272
					// ADD ALL THE FLAGS!!!!!!!!!!!
273
					$dbFlags = Db::query("SELECT flagText, flagID FROM ccp_invFlags", array(), 3600);
274
					$flags = array();
275
					foreach($dbFlags as $f)
276
						$flags["(".$f["flagText"].")"] = (int) $f["flagID"];
277
278
					foreach($flags as $flagType => $flagID) {
279
						if (strpos($value, $flagType) !== false) {
280
							$flag = $flagID;
281
							$value = trim(str_replace($flagType, "", $value));
282
						}
283
					}
284
285
					$isBlueprintCopy = false;
286
					$bpc = "(Copy)";
287
					if (Util::endsWith($value, $bpc)) {
288
						$isBlueprintCopy = true;
289
						$value = trim(substr($value, 0, strlen($value) - strlen($bpc)));
290
					}
291
					$container = "(In Container)";
292
					$inContainer = Util::endsWith($value, $container);
293
					if ($inContainer) {
294
						$value = trim(substr($value, 0, strlen($value) - strlen($container)));
295
					}
296
					$qtyPos = stripos($value, ", Qty: ");
297
					if ($qtyPos !== false) {
298
						$qtyEx = explode(", Qty: ", $value);
299
						$qty = (int) $qtyEx[1];
300
						$value = $qtyEx[0] . str_replace("$qty", "", $qtyEx[1]);
301
					}
302
					$typeID = Info::getItemID($value);
303
					if ($typeID == 0) { 
304
						$errors[] = "Unknown Item: $value"; 
305
						continue;
306
					}
307
					if ($flag === null) {
308
						// Ok, we need to figure out which slot this is in...
309
						$flagSlot = Db::query("select e.effectID effectID from ccp_invTypes i left join ccp_dgmTypeEffects d on (d.typeID = i.typeID) left join ccp_dgmEffects e on (d.effectID = e.effectID) where i.typeID = :typeID", array(":typeID" => $typeID));
310
						foreach($flagSlot as $f)
311
						{
312
							$flagSlot = $f["effectID"];
313
							switch($flagSlot) {
314
								case 11:
315
									$flag = $currentLowSlot;
316
									$currentLowSlot++;
317
								break;
318
								case 12:
319
									$flag = $currentHighSlot;
320
									$currentHighSlot++;
321
								break;
322
								case 13:
323
									$flag = $currentMidSlot;
324
									$currentMidSlot++;
325
								break;
326
								case 2663:
327
									$flag = $currentRigSlot;
328
									$currentRigSlot++;
329
								break;
330
								case 3772:
331
									$flag = $currentSubSlot;
332
									$currentSubSlot++;
333
								break;
334
							}
335
						}
336
					}
337
338
					if ($flag == null || $flag == 0) $flag = 5;
339
					$item = self::createItem();
340
					$item["typeID"] = $typeID;
341
					$item["flag"] = $flag;
342
					$item["qtyDropped"] = $inDroppedItems ? $qty : 0;
343
					$item["qtyDestroyed"] = $inDestroyedItems ? $qty : 0;
344
					$item["singleton"] = $isBlueprintCopy ? 2 : 0;
345
					if ($inContainer) {
346
						$lastItem = $killMail["items"][sizeof($killMail["items"]) - 1];
347
						$lastItem["items"][] = $item;
348
						$killMail["items"][sizeof($killMail["items"]) - 1] = $lastItem;
349
					}
350
					else $killMail["items"][] = $item;
351
					$killValue += ($qty * Price::getItemPrice($typeID));
0 ignored issues
show
The call to getItemPrice() misses a required argument $date.

This check looks for function calls that miss required arguments.

Loading history...
352
			}
353
		}
354
355
		// Check that stuff is actually sane, and not some made up shit..
356
		// Victim must have a valid characterID and corporationID
357
		if ($killMail["victim"]["shipTypeID"] == 0) $errors[] = "Invalid destroyed ship.";
358
		else 
359
		{
360
			$victimGroupID = Info::getGroupID($killMail["victim"]["shipTypeID"]);
361
			$noCharGroups = array(
362
				311, // Refining Arrays
363
				363, // [Capital] Ship Maintenance Array
364
				365, // POS's
365
				397, // Assembly Arrays
366
				404, // Silos
367
				413, // Mobile POS Labs
368
				416, // Moon Harvester
369
				413, // Mobile POS Labs
370
				417, // Missile and Torpedo Batteries
371
				426, // Artillery Batteries
372
				430, // Laser Batteries
373
				438, // Reactor Arrays
374
				439, // ECM Batteries
375
				440, // Dampening Arrays
376
				441, // Web Batteries
377
				443, // Warp scrambling arrays
378
				444, // POS damage arrays (ballistic, explosion, heat, photon)
379
				449, // Blaster & Railgun Batteries
380
				471, // Corporation Hangar Array, ShipYard
381
				473, // Tracking Array
382
				707, // Jump Bridges
383
				709, // Scanning Arrays
384
				837, // Neut Batteries
385
				838, // Cynosural Generator Array
386
				839, // Cynosural System Jammer
387
				1003, // Territorial Claim Unit
388
				1003, // QA Territorial Claim Unit
389
				1005, // Sovereignty Blockade Unit
390
				1005, // QA Sovereignty Blockade Unit
391
				1012, // QA Infrastructure Hub
392
				1012, // Infrastructure Hub
393
				1025, // Customs Office
394
				1025, // Orbital Command Center
395
				1025, // Interbus Customs Office
396
				1106, // Customs Office Gantry
397
				1012, // IHUBS
398
			);
399
400
			// Allow POS's, POS modules, ihub's and poco's, TCU, SBU
401
			if (in_array($victimGroupID, $noCharGroups))  {  } // noop() - do nothing
0 ignored issues
show
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
402
			else if ($killMail["victim"]["characterName"] == "" || $killMail["victim"]["characterID"] == 0)
403
				$errors[] = "Invalid victim name: " . $killMail["victim"]["characterName"];
404
		}
405
406
		if ($killMail["victim"]["corporationName"] == "" || $killMail["victim"]["corporationID"] == 0)
407
			$errors[] = "Invalid victim corporation: " . $killMail["victim"]["corporationName"];
408
409
		if ($killMail["victim"]["allianceName"] != "" && strcasecmp($killMail["victim"]["allianceName"], "None") != 0 && $killMail["victim"]["allianceID"] == 0)
410
			$errors[] = "Unknown victim alliance: " . $killMail["victim"]["allianceName"];
411
412
		if ($killMail["victim"]["factionName"] != "" && strcasecmp($killMail["victim"]["factionName"], "None") != 0 && $killMail["victim"]["factionID"] == 0)
413
			$errors[] = "Invalid victim faction: " . $killMail["victim"]["factionName"];
414
415
		if (Bin::get("BreakOnInvalidDamage", true) && $killMail["victim"]["damageTaken"] == 0)
416
			$errors[] = "Invalid damage amount.";
417
418
		if ($killMail["solarSystemID"] == 0)
419
			$errors[] = "Invalid solar system.";
420
421
		// Verified the victim, lets forget the rest to see if there's a dupe!
422
        $stdMail = json_decode(json_encode($killMail), false);
423
        $hash = Util::getKillHash(null, $stdMail);
424
        $dupeKillID = Db::queryField("select killID from zz_killmails where hash = :hash limit 1", "killID", array(":hash" => $hash), 0);
425
        if ($dupeKillID > 0) {
426
            return array("dupe" => $dupeKillID);
427
        }
428
429
		// There can be only one final blow
430
		$finalBlowCount = 0;
431
432
		// All attackers must have a valid characterID and corporationID (unless NPC)
433
		// check for and deny NPC only mails
434
		// check for and deny friendly corp mails
435
		$npcOnly = true;
436
		$victimCorpOnly = true;
437
		$victim = $killMail["victim"];
438
		foreach ($killMail["attackers"] as $attacker) {
439
			$npcOnly &= $attacker["characterID"] == 0 && $attacker["corporationID"] < 9999999;
440
			$victimCorpOnly &= $attacker["corporationID"] == $victim["corporationID"] && $victim["corporationID"] > 9999999;
441
			if ($attacker["characterName"] != "" && $attacker["characterID"] == 0) $errors[] = "Invalid attacker name: " . $attacker["characterName"];
442
			if ($attacker["corporationName"] != "" && $attacker["corporationID"] == 0) $errors[] = "Invalid attacker corporation: " . $attacker["corporationName"];
443
			if ($attacker["allianceName"] != "" && strcasecmp($attacker["allianceName"], "None") != 0 && $attacker["allianceID"] == 0) $errors[] = "Invalid attacker alliance: " . $attacker["allianceName"];
444
			if ($attacker["factionName"] != "" && strcasecmp($attacker["factionName"], "None") != 0 && $attacker["factionID"] == 0) $errors[] = "Invalid attacker faction: " . $attacker["factionName"];
445
		}
446
		if ($npcOnly) $errors[] = "This is an NPC only mail.  Mails must contain other characters.";
447
		//if ($victimCorpOnly) $errors[] = "Corp friendly killmail...  sorry, can't post those!";
448
		if ($finalBlowCount > 1) $errors[] = "Too many attackers have the final blow.";
449
450
		// If the kill is worth more than 5b isk, time to throw errors!
451
		if ($killValue > 5000000000 && Bin::get("Disallow5bKills", true)) {
452
			$errors[] = "Kills worth more than 5 billion ISK require API verification.";
453
		}
454
455
		// Determine if ship has bays, if it does, complain
456
		$victimGroupID = Info::getGroupID($killMail["victim"]["shipTypeID"]);
457
		// Ships with specialized bays
458
		$bayShips = array(
459
			28, // Industrials
460
			30, // Titans
461
			659, // Supercarriers
462
			485, // Dreads
463
			547, // Carriers
464
			902, // Jump Freighters
465
			543, // Exhumers
466
			463, // Mining Barges
467
			898, // Black Ops
468
			941, // Industrial Command Ships
469
			883, // Captial Industiral Ships
470
		);
471
		if (in_array($victimGroupID, $bayShips)) $errors[] = "The victim ship has bays which are not displayed properly on manual killmails, please use API to post the kill";
472
473
		// We're done with sanity checks, if we have any errors return them
474
		if (sizeof($errors)) {
475
			return array("error" => $errors);
476
		}
477
478
		// Insert ignore allows us to "pretend" to insert dupes
479
		Db::execute("insert ignore into zz_manual_mails (hash) values (:hash)", array(":hash" => $hash));
480
		// Look up the manualKillID from the hash (good for those dupe inserts)
481
		$mKillID = Db::queryField("select mKillID from zz_manual_mails where hash = :hash order by mKillID desc limit 1", "mKillID", array(":hash" => $hash), 0);
482
483
		// yes, manual mails have a negative numbers, cuz they're BAD
484
		$mKillID = -1 * $mKillID;
485
486
		$killMail["killID"] = $mKillID;
487
488
		Db::execute("insert ignore into zz_killmails (killID, hash, source, kill_json) values (:killID, :hash, :source, :json)",
489
				array(":killID" => $mKillID, ":hash" => $hash, ":source" => "userID:$userID", ":json" => json_encode($killMail)));
490
491
		if ($userID != "EveKill") Log::log("Manual mail post from: $userID");
492
		while (true) {
493
			if (Bin::get("WaitForProcessing", true) == true) {
494
				sleep(1);
495
				$processed = Db::queryField("select processed from zz_killmails where killID = :killID", "processed", array(":killID" => $mKillID), 0);
496
			} else $processed = 1;
497
			if ($processed > 0) {
498
				return array("success" => $mKillID);
499
			}
500
		}
501
502
	}
503
504
	/**
505
	 * Inititates the item array
506
	 * @return array
507
	 */
508
	private static function createItem() {
509
		return array(
510
				"typeID" => 0,
511
				"flag" => 0,
512
				"qtyDropped" => 0,
513
				"qtyDestroyed" => 0,
514
				"singleton" => 0,
515
				);
516
	}
517
518
	/**
519
	 * Initiates the attacker array
520
	 * @return string
521
	 */
522
	private static function createAttacker() {
523
		return array(
524
				"characterID" => 0,	
525
				"characterName" => "",
526
				"corporationID" => 0,
527
				"corporationName" => "",
528
				"allianceID" => 0,
529
				"allianceName" => "",
530
				"factionID" => 0,
531
				"factionName" => "",
532
				"securityStatus" => 0,
533
				"damageDone" => 0,
534
				"finalBlow" => 0,
535
				"weaponTypeID" => 0,
536
				"shipTypeID" => 0,
537
				);
538
	}
539
540
	/**
541
	 * Translates a killmail
542
	 * @param string $mail the killmail that needs translation
543
	 * @return text
544
	 */
545
	private static function Translate($mail)
546
	{
547
		// German!
548
		if (strpos($mail, "Beteiligte Parteien:"))
549
		{
550
			$mail = str_replace(array(chr(195) . chr(182), chr(195) . chr(164)), array(chr(246), chr(228)), $mail);
551
			$translation = array(
552
					'Opfer:' => 'Victim:',
553
					'Ziel:' => 'Victim:',
554
					'Allianz: KEINE' => 'Alliance: None',
555
					'Allianz: NICHTS' => 'Alliance: None',
556
					'Allianz:' => 'Alliance:',
557
					'Fraktion: KEINE' => 'Faction: None',
558
					'Fraktion: NICHTS' => 'Faction: None',
559
					'Fraktion:' => 'Faction:',
560
					'Zerst' . chr(246) . 'rte Gegenst' . chr(228) . 'nde' => 'Destroyed items',
561
					'Zerst' . chr(246) . 'rt:' => 'Destroyed:',
562
					'Sicherheit:' => 'Security:',
563
					'Beteiligte Parteien:' => 'Involved parties:',
564
					'Anz:' => 'Qty:',
565
					'Anz.:' => 'Qty:',
566
					'Corporation:' => 'Corp:',
567
					'(Fracht)' => '(Cargo)',
568
					'Schiff:' => 'Ship:',
569
					'Waffe:' => 'Weapon:',
570
					'(Im Container)' => '(In Container)',
571
					'Verursachter Schaden:' => 'Damage Done:',
572
					'Erlittener Schaden:' => 'Damage Taken:',
573
					'(gab den letzten Schuss ab)' => '(laid the final blow)',
574
					'Hinterlassene Gegenst' . chr(228) . 'nde:' => 'Dropped items:',
575
					': Unbekannt' => ': None',
576
					'(Dronenhangar)' => '(Drone Bay)',
577
					'(Drohnenhangar)' => '(Drone Bay)',
578
					'(Drohnenbucht)' => '(Drone Bay)',
579
					'Mond:' => 'Moon:',
580
					'Kapsel' => 'Capsule',
581
					'Menge:' => 'Qty:'
582
						);
583
584
			foreach ($translation as $w => $t) {
585
				$mail = str_ireplace($w, $t, $mail);
586
			}
587
		}
588
589
		// Russian!
590
		if (strpos($mail, "Корпорация") || strpos($mail, "Неизвестно"))
591
		{
592
			$translation = array(
593
					'Жертва:' => 'Victim:',
594
					'Альянс: НЕТ' => 'Alliance: None',
595
					'Альянс: нет' => 'Alliance: None',
596
					'Альянс: Нет' => 'Alliance: None',
597
					': НЕТ' => ": None",
598
					': нет' => ": None",
599
					': Нет' => ": None",
600
					'Альянс:' => 'Alliance:',
601
					'Имя:' => 'Name:',
602
					'Фракция: Неизвестно' => 'Faction: None',
603
					'Фракция: НЕТ' => 'Faction: None',
604
					'Фракция: нет' => 'Faction: None',
605
					'Фракция: Нет' => 'Faction: None',
606
					'Фракция:' => 'Faction:',
607
					'Уничтоженные предметы:' => 'Destroyed items:',
608
					'Уничтожено:' => 'Destroyed:',
609
					'Уровень безопасности:' => 'Security:',
610
					'Система:' => 'System:',
611
					'Участники:' => 'Involved parties:',
612
					'кол-во:' => 'Qty:',
613
					'Корпорация:' => 'Corp:',
614
					'(Груз)' => '(Cargo)',
615
					'(Имплантат)' => '(Implant)',
616
					'Корабль:' => 'Ship:',
617
					'Оружие:' => 'Weapon:',
618
					'(В контейнере)' => '(In Container)',
619
					'Нанесенный ущерб:' => 'Damage Done:',
620
					'Полученный ущерб:' => 'Damage Taken:',
621
					'(нанес последний удар)' => '(laid the final blow)',
622
					'Сброшенные предметы:' => 'Dropped items:',
623
					'кол-во:' => 'Qty:',
624
					'Неизвестно' => 'None',
625
					'Отсек дронов' => 'Drone Bay',
626
					'Луна:' => 'Moon:',
627
628
				);
629
			foreach ($translation as $w => $t) {
630
				$mail = str_ireplace($w, $t, $mail);
631
			}
632
		}
633
634
		// Chinese
635
		if (strpos($mail, "军团") || strpos($mail, "受害者")) {
636
			// Just incase that weird : is standard on all chinese mails
637
			$mail = str_replace(":", ":", $mail);
638
639
			$translation = array(
640
					'受害者:' => 'Victim:',
641
					'联盟:' => 'Alliance:',
642
					'名称:' => 'Name:',
643
					'势力:' => 'Faction:',
644
					'被摧毁物:' => 'Destroyed:',
645
					'安全等级:' => 'Security:',
646
					'星系:' => 'System:',
647
					'参与者:' => 'Involved parties:',
648
					'军团:' => 'Corp:',
649
					'舰船:' => 'Ship:',
650
					'武器:' => 'Weapon:',
651
					'造成损伤:' => 'Damage Done:',
652
					'所受损伤:' => 'Damage Taken:',
653
					'(给予最后一击)' => '(laid the final blow)',
654
					'Сброшенные предметы:' => 'Dropped items:',
655
					'кол-во:' => 'Qty:',
656
					'Неизвестно' => 'None',
657
					'Отсек дронов' => 'Drone Bay',
658
					'Луна:' => 'Moon:',
659
					'(Груз)' => '(Cargo)',
660
					'(植入体)' => '(Implant)',
661
					'кол-во:' => 'Qty:',
662
					'(В контейнере)' => '(In Container)',
663
					'被毁物品:' => 'Destroyed items:',
664
				);
665
			foreach ($translation as $w => $t) {
666
				$mail = str_ireplace($w, $t, $mail);
667
			}
668
		}
669
		return $mail;
670
	}
671
}