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"]);
|
|
|
|
|
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));
|
|
|
|
|
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
|
|
|
|
|
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
|
|
|
} |
This check looks for function calls that miss required arguments.