Completed
Push — master ( c4688e...41b901 )
by Yannick
06:49
created

AIS::decode_ais()   D

Complexity

Conditions 16
Paths 16

Size

Total Lines 106
Code Lines 78

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 16
eloc 78
nc 16
nop 1
dl 0
loc 106
rs 4.8736
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/*
3
Copyright 2014 Aaron Gong Hsien-Joen <[email protected]>
4
5
Licensed under the Apache License, Version 2.0 (the "License");
6
you may not use this file except in compliance with the License.
7
You may obtain a copy of the License at
8
9
    http://www.apache.org/licenses/LICENSE-2.0
10
11
Unless required by applicable law or agreed to in writing, software
12
distributed under the License is distributed on an "AS IS" BASIS,
13
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
See the License for the specific language governing permissions and
15
limitations under the License.
16
*/
17
/*
18
Modified in 2017 by Ycarus <[email protected]>
19
Original version come from https://github.com/ais-one/phpais
20
*/
21
class AIS {
22
/* AIS Decoding
23
- Receive and get ITU payload
24
- Organises the binary bits of the Payload into 6-bit strings,
25
- Converts the 6-bit strings into their representative "valid characters" – see IEC 61162-1, table 7,
26
- Assembles the valid characters into an encapsulation string, and
27
- Transfers the encapsulation string using the VDM sentence formatter.
28
*/
29
30
	private function make_latf($temp) { // unsigned long 
31
		$flat = 0.0; // float
0 ignored issues
show
Unused Code introduced by
$flat is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
32
		$temp = $temp & 0x07FFFFFF;
33
		if ($temp & 0x04000000) {
34
			$temp = $temp ^ 0x07FFFFFF;
35
			$temp += 1;
36
			$flat = (float)($temp / (60.0 * 10000.0));
37
			$flat *= -1.0;
38
		} else $flat = (float)($temp / (60.0 * 10000.0));
39
		return $flat; // float
40
	}
41
42
	private function make_lonf($temp) { // unsigned long
43
		$flon = 0.0; // float
0 ignored issues
show
Unused Code introduced by
$flon is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
44
		$temp = $temp & 0x0FFFFFFF;
45
		if ($temp & 0x08000000) {
46
			$temp = $temp ^ 0x0FFFFFFF;
47
			$temp += 1;
48
			$flon = (float)($temp / (60.0 * 10000.0));
49
			$flon *= -1.0;
50
		} else $flon = (float)($temp / (60.0 * 10000.0));
51
		return $flon;
52
	}
53
54
	private function ascii_2_dec($chr) {
55
		$dec=ord($chr);//get decimal ascii code
56
		$hex=dechex($dec);//convert decimal to hex
0 ignored issues
show
Unused Code introduced by
$hex is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
57
		return ($dec);
58
	}
59
	
60
    /*
61
    $ais_map64 = array(
62
       '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', // 48
63
       ':', ';', '<', '=', '>', '?', '@', 'A', 'B', 'C',
64
       'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
65
       'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', // 87
66
       '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', // 96
67
       'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
68
       't', 'u', 'v', 'w' // 119
69
    ); // char 64
70
    */
71
	private function asciidec_2_8bit($ascii) {
72
		//only process in the following range: 48-87, 96-119
73
		if ($ascii < 48) { }
0 ignored issues
show
Unused Code introduced by
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...
74
		else {
75
			if($ascii>119) { }
0 ignored issues
show
Unused Code introduced by
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...
76
			else {
77
				if ($ascii>87 && $ascii<96) ;
78
				else {
79
					$ascii=$ascii+40;
80
					if ($ascii>128){
81
						$ascii=$ascii+32;
82
					} else {
83
						$ascii=$ascii+40;
84
					}
85
				}
86
			}
87
		}
88
		return ($ascii);
89
	}
90
91
	private function dec_2_6bit($dec) {
92
		$bin=decbin($dec);
93
		return(substr($bin, -6)); 
94
	}
95
96
	private function binchar($_str, $_start, $_size) {
97
		//  ' ' --- '?', // 0x20 - 0x3F
98
		//  '@' --- '_', // 0x40 - 0x5F
99
		$ais_chars = array(
100
		    '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',
101
		    'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
102
		    'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']',
103
		    '^', '_', ' ', '!', '\"', '#', '$', '%', '&', '\'',
104
		    '(', ')', '*', '+', ',', '-', '.', '/', '0', '1',
105
		    '2', '3', '4', '5', '6', '7', '8', '9', ':', ';',
106
		    '<', '=', '>', '?'
107
		);
108
		$rv = '';
109
		if ($_size % 6 == 0) {
110
			$len = $_size / 6;
111
			for ($i=0; $i<$len; $i++) {
112
				$offset = $i * 6;
113
				$rv .= $ais_chars[ bindec(substr($_str,$_start + $offset,6)) ];
114
			}
115
		}
116
		return $rv;
117
	}
118
119
	// function for decoding the AIS Message ITU Payload
120
	private function decode_ais($_aisdata) {
121
		$ro = new stdClass(); // return object
122
		$ro->cls = 0; // AIS class undefined, also indicate unparsed msg
123
		$ro->name = '';
124
		$ro->status = '';
125
		$ro->callsign = '';
126
		$ro->imo = '';
127
		$ro->typeid = '';
128
		$ro->type = '';
129
		$ro->sog = -1.0;
130
		$ro->cog = 0.0;
131
		$ro->lon = 0.0;
132
		$ro->lat = 0.0;
133
		$ro->heading = '';
134
		$ro->ts = time();
135
		$ro->id = bindec(substr($_aisdata,0,6));
136
		$ro->mmsi = bindec(substr($_aisdata,8,30));
137
		if ($ro->id >= 1 && $ro->id <= 3) {
138
			$ro->cog = bindec(substr($_aisdata,116,12))/10;
139
			$ro->sog = bindec(substr($_aisdata,50,10))/10;
140
			$ro->lon = $this->make_lonf(bindec(substr($_aisdata,61,28)));
141
			$ro->lat = $this->make_latf(bindec(substr($_aisdata,89,27)));
142
			$ro->cls = 1; // class A
143
		} else if ($ro->id == 4) {
144
			$ro->lon = $this->make_lonf(bindec(substr($_aisdata,79,28)));
145
			$ro->lat = $this->make_latf(bindec(substr($_aisdata,107,27)));
146
			$ro->cls = 1; // class A
147
		} else if ($ro->id == 5) {
148
			$ro->imo = bindec(substr($_aisdata,40,30));
149
			$ro->callsign = $this->binchar($_aisdata,70,42);
150
			$ro->name = $this->binchar($_aisdata,112,120);
151
			$ro->typeid = bindec(substr($_aisdata,232,8));
152
			$ro->type = $this->getShipType($ro->typeid);
153
			//$ro->to_bow = bindec(substr($_aisdata,240,9));
154
			//$ro->to_stern = bindec(substr($_aisdata,249,9));
155
			//$ro->to_port = bindec(substr($_aisdata,258,6));
156
			//$ro->to_starboard = bindec(substr($_aisdata,264,6));
157
			//$ro->eta_month = bindec(substr($_aisdata,274,4));
158
			//$ro->eta_day = bindec(substr($_aisdata,278,5));
159
			//$ro->eta_hour = bindec(substr($_aisdata,283,5));
160
			//$ro->eta_minute = bindec(substr($_aisdata,288,6));
161
			//$ro->draught = bindec(substr($_aisdata,294,8));
162
			//$ro->destination = $this->binchar($_aisdata,302,120);
163
			$ro->cls = 1; // class A
164
		} else if ($ro->id == 9) {
0 ignored issues
show
Unused Code introduced by
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...
165
			// Search and Rescue aircraft position report
166
		} else if ($ro->id == 18) {
167
			$ro->cog = bindec(substr($_aisdata,112,12))/10;
168
			$ro->sog = bindec(substr($_aisdata,46,10))/10;
169
			$ro->lon = $this->make_lonf(bindec(substr($_aisdata,57,28)));
170
			$ro->lat = $this->make_latf(bindec(substr($_aisdata,85,27)));
171
			$ro->heading = bindec(substr($_aisdata,124,9));
172
			if ($ro->heading == 511) $ro->heading = '';
173
			$ro->cls = 2; // class B
174
		} else if ($ro->id == 19) {
175
			$ro->cog = bindec(substr($_aisdata,112,12))/10;
176
			$ro->sog = bindec(substr($_aisdata,46,10))/10;
177
			$ro->lon = $this->make_lonf(bindec(substr($_aisdata,61,28)));
178
			$ro->lat = $this->make_latf(bindec(substr($_aisdata,89,27)));
179
			$ro->name = $this->binchar($_aisdata,143,120);
180
			$ro->cls = 2; // class B
181
			$ro->heading = bindec(substr($_aisdata,124,9));
182
			if ($ro->heading == 511) $ro->heading = '';
183
			$ro->typeid = bindec(substr($_aisdata,263,8));
184
			$ro->type = $this->getShipType($ro->typeid);
185
			//$ro->to_bow = bindec(substr($_aisdata,271,9));
186
			//$ro->to_stern = bindec(substr($_aisdata,280,9));
187
			//$ro->to_port = bindec(substr($_aisdata,289,6));
188
			//$ro->to_starboard = bindec(substr($_aisdata,295,6));
189
		} else if ($ro->id == 21) {
190
			$ro->lon = $this->make_lonf(bindec(substr($_aisdata,164,28)));
191
			$ro->lat = $this->make_latf(bindec(substr($_aisdata,192,27)));
192
			$ro->name = $this->binchar($_aisdata,43,120);
193
			//$ro->to_bow = bindec(substr($_aisdata,219,9));
194
			//$ro->to_stern = bindec(substr($_aisdata,228,9));
195
			//$ro->to_port = bindec(substr($_aisdata,237,6));
196
			//$ro->to_starboard = bindec(substr($_aisdata,243,6));
197
			$ro->cls = 2; // class B
198
		} else if ($ro->id == 24) {
199
			$pn = bindec(substr($_aisdata,38,2));
200
			if ($pn == 0) {
201
				$ro->name = $this->binchar($_aisdata,40,120);
202
			}
203
			$ro->typeid = bindec(substr($_aisdata,40,8));
204
			$ro->type = $this->getShipType($ro->typeid);
205
			$ro->callsign = $this->binchar($_aisdata,90,42);
206
			//$ro->to_bow = bindec(substr($_aisdata,132,9));
207
			//$ro->to_stern = bindec(substr($_aisdata,141,9));
208
			//$ro->to_port = bindec(substr($_aisdata,150,6));
209
			//$ro->to_starboard = bindec(substr($_aisdata,156,6));
210
			$ro->cls = 2; // class B
211
		} else if ($ro->id == 27) {
212
			$ro->cog = bindec(substr($_aisdata,85,9));
213
			if ($ro->cog == 511) $ro->cog = 0.0;
214
			$ro->sog = bindec(substr($_aisdata,79,6));
215
			if ($ro->sog == 63) $ro->sog = 0.0;
216
			$ro->lon = $this->make_lonf(bindec(substr($_aisdata,44,18))*10);
217
			$ro->lat = $this->make_latf(bindec(substr($_aisdata,62,17))*10);
218
			$ro->cls = 1; // class A
219
		
220
		}
221
		$ro->statusid = bindec(substr($_aisdata,38,4));
222
		$ro->status = $this->getStatus($ro->statusid);
223
		//var_dump($ro); // dump results here for demo purpose
224
		return $ro;
225
	}
226
227
	public function getStatus($statusid) {
228
		if ($statusid == 0) {
229
			return 'under way using engine';
230
		} elseif ($statusid == 1) {
231
			return 'at anchor';
232
		} elseif ($statusid == 2) {
233
			return 'not under command';
234
		} elseif ($statusid == 3) {
235
			return 'restricted maneuverability';
236
		} elseif ($statusid == 4) {
237
			return 'constrained by her draught';
238
		} elseif ($statusid == 5) {
239
			return 'moored';
240
		} elseif ($statusid == 6) {
241
			return 'aground';
242
		} elseif ($statusid == 7) {
243
			return 'engaged in fishing';
244
		} elseif ($statusid == 8) {
245
			return 'under way sailing';
246
		} elseif ($statusid == 9) {
247
			return 'reserved for future amendment of navigational status for ships carrying DG, HS, or MP, or IMO hazard or pollutant category C, high speed craft (HSC)';
248
		} elseif ($statusid == 10) {
249
			return 'reserved for future amendment of navigational status for ships carrying dangerous goods (DG), harmful substances (HS) or marine pollutants (MP), or IMO hazard or pollutant category A, wing in ground (WIG)';
250
		} elseif ($statusid == 11) {
251
			return 'power-driven vessel towing astern (regional use)';
252
		} elseif ($statusid == 12) {
253
			return 'power-driven vessel pushing ahead or towing alongside (regional use)';
254
		} elseif ($statusid == 13) {
255
			return 'reserved for future use';
256
		} elseif ($statusid == 14) {
257
			return 'AIS-SART (active), MOB-AIS, EPIRB-AIS';
258
		} elseif ($statusid == 15) {
259
			return 'undefined = default (also used by AIS-SART, MOB-AIS and EPIRB-AIS under test)';
260
		}
261
	}
262
	
263
	public function getShipType($code) {
264
		if ($code == 0) return 'Not available (default)';
265
		elseif ($code >= 1 && $code <= 19) return 'Reserved for future use';
266
		elseif ($code == 20) return 'Wing in ground (WIG), all ships of this type';
267
		elseif ($code == 21) return 'Wing in ground (WIG), Hazardous category A';
268
		elseif ($code == 22) return 'Wing in ground (WIG), Hazardous category B';
269
		elseif ($code == 23) return 'Wing in ground (WIG), Hazardous category C';
270
		elseif ($code == 24) return 'Wing in ground (WIG), Hazardous category D';
271
		elseif ($code == 25) return 'Wing in ground (WIG), Reserved for future use';
272
		elseif ($code == 26) return 'Wing in ground (WIG), Reserved for future use';
273
		elseif ($code == 27) return 'Wing in ground (WIG), Reserved for future use';
274
		elseif ($code == 28) return 'Wing in ground (WIG), Reserved for future use';
275
		elseif ($code == 29) return 'Wing in ground (WIG), Reserved for future use';
276
		elseif ($code == 30) return 'Fishing';
277
		elseif ($code == 31) return 'Towing';
278
		elseif ($code == 32) return 'Towing: length exceeds 200m or breadth exceeds 25m';
279
		elseif ($code == 33) return 'Dredging or underwater ops';
280
		elseif ($code == 34) return 'Diving ops';
281
		elseif ($code == 35) return 'Military ops';
282
		elseif ($code == 36) return 'Sailing';
283
		elseif ($code == 37) return 'Pleasure Craft';
284
		elseif ($code == 38) return 'Reserved';
285
		elseif ($code == 39) return 'Reserved';
286
		elseif ($code == 40) return 'High speed craft (HSC), all ships of this type';
287
		elseif ($code == 41) return 'High speed craft (HSC), Hazardous category A';
288
		elseif ($code == 42) return 'High speed craft (HSC), Hazardous category B';
289
		elseif ($code == 43) return 'High speed craft (HSC), Hazardous category C';
290
		elseif ($code == 44) return 'High speed craft (HSC), Hazardous category D';
291
		elseif ($code == 45) return 'High speed craft (HSC), Reserved for future use';
292
		elseif ($code == 46) return 'High speed craft (HSC), Reserved for future use';
293
		elseif ($code == 47) return 'High speed craft (HSC), Reserved for future use';
294
		elseif ($code == 48) return 'High speed craft (HSC), Reserved for future use';
295
		elseif ($code == 49) return 'High speed craft (HSC), No additional information';
296
		elseif ($code == 50) return 'Pilot Vessel';
297
		elseif ($code == 51) return 'Search and Rescue vessel';
298
		elseif ($code == 52) return 'Tug';
299
		elseif ($code == 53) return 'Port Tender';
300
		elseif ($code == 54) return 'Anti-pollution equipment';
301
		elseif ($code == 55) return 'Law Enforcement';
302
		elseif ($code == 56) return 'Spare - Local Vessel';
303
		elseif ($code == 57) return 'Spare - Local Vessel';
304
		elseif ($code == 58) return 'Medical Transport';
305
		elseif ($code == 59) return 'Noncombatant ship according to RR Resolution No. 18';
306
		elseif ($code == 60) return 'Passenger, all ships of this type';
307
		elseif ($code == 61) return 'Passenger, Hazardous category A';
308
		elseif ($code == 62) return 'Passenger, Hazardous category B';
309
		elseif ($code == 63) return 'Passenger, Hazardous category C';
310
		elseif ($code == 64) return 'Passenger, Hazardous category D';
311
		elseif ($code == 65) return 'Passenger, Reserved for future use';
312
		elseif ($code == 66) return 'Passenger, Reserved for future use';
313
		elseif ($code == 67) return 'Passenger, Reserved for future use';
314
		elseif ($code == 68) return 'Passenger, Reserved for future use';
315
		elseif ($code == 69) return 'Passenger, No additional information';
316
		elseif ($code == 70) return 'Cargo, all ships of this type';
317
		elseif ($code == 71) return 'Cargo, Hazardous category A';
318
		elseif ($code == 72) return 'Cargo, Hazardous category B';
319
		elseif ($code == 73) return 'Cargo, Hazardous category C';
320
		elseif ($code == 74) return 'Cargo, Hazardous category D';
321
		elseif ($code == 75) return 'Cargo, Reserved for future use';
322
		elseif ($code == 76) return 'Cargo, Reserved for future use';
323
		elseif ($code == 77) return 'Cargo, Reserved for future use';
324
		elseif ($code == 78) return 'Cargo, Reserved for future use';
325
		elseif ($code == 79) return 'Cargo, No additional information';
326
		elseif ($code == 80) return 'Tanker, all ships of this type';
327
		elseif ($code == 81) return 'Tanker, Hazardous category A';
328
		elseif ($code == 82) return 'Tanker, Hazardous category B';
329
		elseif ($code == 83) return 'Tanker, Hazardous category C';
330
		elseif ($code == 84) return 'Tanker, Hazardous category D';
331
		elseif ($code == 85) return 'Tanker, Reserved for future use';
332
		elseif ($code == 86) return 'Tanker, Reserved for future use';
333
		elseif ($code == 87) return 'Tanker, Reserved for future use';
334
		elseif ($code == 88) return 'Tanker, Reserved for future use';
335
		elseif ($code == 89) return 'Tanker, No additional information';
336
		elseif ($code == 90) return 'Other Type, all ships of this type';
337
		elseif ($code == 91) return 'Other Type, Hazardous category A';
338
		elseif ($code == 92) return 'Other Type, Hazardous category B';
339
		elseif ($code == 93) return 'Other Type, Hazardous category C';
340
		elseif ($code == 94) return 'Other Type, Hazardous category D';
341
		elseif ($code == 95) return 'Other Type, Reserved for future use';
342
		elseif ($code == 96) return 'Other Type, Reserved for future use';
343
		elseif ($code == 97) return 'Other Type, Reserved for future use';
344
		elseif ($code == 98) return 'Other Type, Reserved for future use';
345
		elseif ($code == 99) return 'Other Type, no additional information';
346
	}
347
348
	public function process_ais_itu($_itu, $_len, $_filler, $aux /*, $ais_ch*/) {
0 ignored issues
show
Unused Code introduced by
The parameter $_len is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $_filler is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $aux is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
349
		global $port; // tcpip port...
350
		
351
		static $debug_counter = 0;
352
		$aisdata168='';//six bit array of ascii characters
353
		$ais_nmea_array = str_split($_itu); // convert to an array
354
		foreach ($ais_nmea_array as $value) {
355
			$dec = $this->ascii_2_dec($value);
356
			$bit8 = $this->asciidec_2_8bit($dec);
357
			$bit6 = $this->dec_2_6bit($bit8);
358
			//echo $value ."-" .$bit6 ."";
359
			$aisdata168 .=$bit6;
360
		}
361
		//echo $aisdata168 . "<br/>";
362
		//return $this->decode_ais($aisdata168, $aux);
363
		return $this->decode_ais($aisdata168);
364
	}
365
366
	// char* - AIS \r terminated string
367
	// TCP based streams which send messages in full can use this instead of calling process_ais_buf
368
	public function process_ais_raw($rawdata, $aux = '') { // return int
369
		static $num_seq; // 1 to 9
370
		static $seq; // 1 to 9
371
		static $pseq; // previous seq
372
		static $msg_sid = -1; // 0 to 9, indicate -1 at start state of device, do not process messages
373
		static $cmsg_sid; // current msg_sid
374
		static $itu; // buffer for ITU message
375
376
		$filler = 0; // fill bits (int)
377
		$chksum = 0;
378
		// raw data without the \n
379
		// calculate checksum after ! till *
380
		// assume 1st ! is valid
381
		// find * ensure that it is at correct position
382
		$end = strrpos ( $rawdata , '*' );
383
		if ($end === FALSE) return -1; // check for NULLS!!!
384
		$cs = substr( $rawdata, $end + 1 );
385
		if ( strlen($cs) != 2 ) return -1; // correct cs length
386
		$dcs = (int)hexdec( $cs );
387
		for ( $alias=1; $alias<$end; $alias++) $chksum ^= ord( $rawdata[$alias] ); // perform XOR for NMEA checksum
388
		if ( $chksum == $dcs ) { // NMEA checksum pass
389
			$pcs = explode(',', $rawdata);
390
			// !AI??? identifier
391
			$num_seq = (int)$pcs[1]; // number of sequences
392
			$seq = (int)$pcs[2]; // get sequence
393
			// get msg sequence id
394
			if ($pcs[3] == '') $msg_sid = -1; // non-multipart message, set to -1
395
			else $msg_sid = (int)$pcs[3]; // multipart message
396
			$ais_ch = $pcs[4]; // get AIS channel
0 ignored issues
show
Unused Code introduced by
$ais_ch is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
397
			// message sequence checking
398
			if ($num_seq < 1 || $num_seq > 9) {
399
				echo "ERROR,INVALID_NUMBER_OF_SEQUENCES ".time()." $rawdata\n";
400
				return -1;
401
			} else if ($seq < 1 || $seq > 9) { // invalid sequences number
402
				echo "ERROR,INVALID_SEQUENCES_NUMBER ".time()." $rawdata\n";
403
				return -1;
404
			} else if ($seq > $num_seq) {
405
				echo "ERROR,INVALID_SEQUENCE_NUMBER_OR_INVALID_NUMBER_OF_SEQUENCES ".time()." $rawdata\n";
406
				return -1;
407
			} else { // sequencing ok, handle single/multi-part messaging
408
				if ($seq == 1) { // always init to 0 at first sequence
409
					$filler = 0; // ?
410
					$itu = ""; // init message length
411
					$pseq = 0; // note previous sequence number
412
					$cmsg_sid = $msg_sid; // note msg_sid
413
				}
414
				if ($num_seq > 1) { // for multipart messages
415
					if ($cmsg_sid != $msg_sid // different msg_sid
416
					    || $msg_sid == -1 // invalid initial msg_sid
417
					    || ($seq - $pseq) != 1 // not insequence
418
					) {  // invalid for multipart message
419
						$msg_sid = -1;
420
						$cmsg_sid = -1;
421
						echo "ERROR,INVALID_MULTIPART_MESSAGE ".time()." $rawdata\n";
422
						return -1;
423
					} else {
424
						$pseq++;
425
					}
426
				}
427
				$itu = $itu.$pcs[5]; // get itu message
428
				$filler += (int)$pcs[6][0]; // get filler
429
				if ($num_seq == 1 // valid single message
430
				    || $num_seq == $pseq // valid multi-part message
431
				) {
432
					if ($num_seq != 1) { // test
0 ignored issues
show
Unused Code introduced by
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...
433
						//echo $rawdata;
434
					}
435
					return $this->process_ais_itu($itu, strlen($itu), $filler, $aux /*, $ais_ch*/);
436
				}
437
			} // end process raw AIS string (checksum passed)
438
		}
439
		return -1;
440
	}
441
442
	// incoming data from serial or IP comms
443
	public function process_ais_buf($ibuf) {
444
		static $cbuf = "";
445
		$cbuf = $cbuf.$ibuf;
446
		$last_pos = 0;
447
		$result = new stdClass();
448
		while ( ($start = strpos($cbuf,"VDM",$last_pos)) !== FALSE) {
449
		//while ( ($start = strpos($cbuf,"!AI",$last_pos)) !== FALSE) {
450
			//DEBUG echo $cbuf;
451
			if ( ($end = strpos($cbuf,"\r\n", $start)) !== FALSE) { //TBD need to trim?
452
				$tst = substr($cbuf, $start - 3, ($end - $start + 3));
453
				//DEBUG echo "[$start $end $tst]\n";
454
				$result = $this->process_ais_raw( $tst, "" );
455
				$last_pos = $end + 1;
456
			} else break;
457
		}
458
		if ($last_pos > 0) $cbuf = substr($cbuf, $last_pos); // move...
459
		if (strlen($cbuf) > 1024) $cbuf = ""; // prevent overflow simple mode...
460
		return $result;
461
	}
462
463
	// incoming data from serial or IP comms
464
	public function process_ais_line($cbuf) {
465
		$result = new stdClass();
0 ignored issues
show
Unused Code introduced by
$result is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
466
		$start = strpos($cbuf,"VDM");
467
		$tst = substr($cbuf, $start - 3);
468
		$result = $this->process_ais_raw( $tst, "" );
469
		return $result;
470
	}
471
472
	/* AIS Encoding
473
	*/
474
	private function mk_ais_lat( $lat ) {
475
		//$lat = 1.2569;
476
		if ($lat<0.0) {
477
			$lat = -$lat;
478
			$neg=true;
479
		} else $neg=false;
480
		$latd = 0x00000000;
0 ignored issues
show
Unused Code introduced by
$latd is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
481
		$latd = intval ($lat * 600000.0);
482
		if ($neg==true) {
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...
483
			$latd = ~$latd;
484
			$latd+=1;
485
			$latd &= 0x07FFFFFF;
486
		}
487
		return $latd;
488
	}
489
490
	private function mk_ais_lon( $lon ) {
491
		//$lon = 103.851;
492
		if ($lon<0.0) {
493
			$lon = -$lon;
494
			$neg=true;
495
		} else $neg=false;
496
		$lond = 0x00000000;
0 ignored issues
show
Unused Code introduced by
$lond is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
497
		$lond = intval ($lon * 600000.0);
498
		if ($neg==true) {
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...
499
			$lond = ~$lond;
500
			$lond+=1;
501
			$lond &= 0x0FFFFFFF;
502
		}
503
		return $lond;
504
	}
505
506
	private function char2bin($name, $max_len) {
507
		$len = strlen($name);
508
		if ($len > $max_len) $name = substr($name,0,$max_len);
509
		if ($len < $max_len) $pad = str_repeat('0', ($max_len - $len) * 6);
510
		else $pad = '';
511
		$rv = '';
512
		$ais_chars = array(
513
		    '@'=>0, 'A'=>1, 'B'=>2, 'C'=>3, 'D'=>4, 'E'=>5, 'F'=>6, 'G'=>7, 'H'=>8, 'I'=>9,
514
		    'J'=>10, 'K'=>11, 'L'=>12, 'M'=>13, 'N'=>14, 'O'=>15, 'P'=>16, 'Q'=>17, 'R'=>18, 'S'=>19,
515
		    'T'=>20, 'U'=>21, 'V'=>22, 'W'=>23, 'X'=>24, 'Y'=>25, 'Z'=>26, '['=>27, '\\'=>28, ']'=>29,
516
		    '^'=>30, '_'=>31, ' '=>32, '!'=>33, '\"'=>34, '#'=>35, '$'=>36, '%'=>37, '&'=>38, '\''=>39,
517
		    '('=>40, ')'=>41, '*'=>42, '+'=>43, ','=>44, '-'=>45, '.'=>46, '/'=>47, '0'=>48, '1'=>49,
518
		    '2'=>50, '3'=>51, '4'=>52, '5'=>53, '6'=>54, '7'=>55, '8'=>56, '9'=>57, ':'=>58, ';'=>59,
519
		    '<'=>60, '='=>61, '>'=>62, '?'=>63
520
		);
521
		$_a = str_split($name);
522
		if ($_a) foreach ($_a as $_1) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $_a 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...
523
			if (isset($ais_chars[$_1])) $dec = $ais_chars[$_1];
524
			else $dec = 0;
525
			$bin = str_pad(decbin( $dec ), 6, '0', STR_PAD_LEFT);
526
			$rv .= $bin;
527
			//echo "$_1 $dec ($bin)<br/>";
528
		}
529
		return $rv.$pad;
530
	}
531
532
	private function mk_ais($_enc, $_part=1,$_total=1,$_seq='',$_ch='A') {
533
		$len_bit = strlen($_enc);
534
		$rem6 = $len_bit % 6;
535
		$pad6_len = 0;
536
		if ($rem6) $pad6_len = 6 - $rem6;
537
		//echo  $pad6_len.'<br>';
538
		$_enc .= str_repeat("0", $pad6_len); // pad the text...
539
		$len_enc = strlen($_enc) / 6;
540
		//echo $_enc.' '.$len_enc.'<br/>';
541
		$itu = '';
542
		for ($i=0; $i<$len_enc; $i++) {
543
			$offset = $i * 6;
544
			$dec = bindec(substr($_enc,$offset,6));
545
			if ($dec < 40) $dec += 48;
546
			else $dec += 56;
547
			//echo chr($dec)." $dec<br/>";
548
			$itu .= chr($dec);
549
		}
550
		// add checksum
551
		$chksum = 0;
552
		$itu = "AIVDM,$_part,$_total,$_seq,$_ch,".$itu.",0";
553
		$len_itu = strlen($itu);
554
		for ($i=0; $i<$len_itu; $i++) {
555
			$chksum ^= ord( $itu[$i] );
556
		}
557
		$hex_arr = array('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F');
558
		$lsb = $chksum & 0x0F;
559
		if ($lsb >=0 && $lsb <= 15 ) $lsbc = $hex_arr[$lsb];
560
		else $lsbc = '0';
561
		$msb = (($chksum & 0xF0) >> 4) & 0x0F;
562
		if ($msb >=0 && $msb <= 15 ) $msbc = $hex_arr[$msb];
563
		else $msbc = '0';
564
		$itu = '!'.$itu."*{$msbc}{$lsbc}\r\n";
565
		return $itu;
566
	}
567
568
	public function parse($buffer) {
569
		$data = $this->process_ais_buf($buffer);
570
		if (!is_object($data)) return array();
571
		if ($data->lon != 0) $result['longitude'] = $data->lon;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$result was never initialized. Although not strictly required by PHP, it is generally a good practice to add $result = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
572
		if ($data->lat != 0) $result['latitude'] = $data->lat;
0 ignored issues
show
Bug introduced by
The variable $result does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
573
		$result['ident'] = trim($data->name);
574
		$result['timestamp'] = $data->ts;
575
		$result['mmsi'] = $data->mmsi;
576
		if ($data->sog != -1.0) $result['speed'] = $data->sog;
577
		if ($data->cog != 0) $result['heading'] = $data->cog;
578
		/*
579
		    $ro->cls = 0; // AIS class undefined, also indicate unparsed msg
580
		    $ro->id = bindec(substr($_aisdata,0,6));
581
		*/
582
		return $result;
583
	}
584
585
	public function parse_line($buffer) {
586
		$result = array();
587
		$data = new stdClass();
0 ignored issues
show
Unused Code introduced by
$data is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
588
		$start = strpos($buffer,"VDM");
589
		$tst = substr($buffer, $start - 3);
590
		$data = $this->process_ais_raw( $tst, "" );
591
		if (!is_object($data)) return array();
592
		if ($data->lon != 0) $result['longitude'] = $data->lon;
593
		if ($data->lat != 0) $result['latitude'] = $data->lat;
594
		$result['ident'] = trim(str_replace('@','',$data->name));
595
		$result['timestamp'] = $data->ts;
596
		$result['mmsi'] = $data->mmsi;
597
		if ($data->sog != -1.0) $result['speed'] = $data->sog;
598
		if ($data->heading != '') $result['heading'] = $data->heading;
599
		elseif ($data->cog != 0) $result['heading'] = $data->cog;
600
		if ($data->status != '') $result['status'] = $data->status;
601
		if ($data->type != '') $result['type'] = $data->type;
602
		if ($data->imo != '') $result['imo'] = $data->imo;
603
		if ($data->callsign != '') $result['callsign'] = $data->callsign;
604
		$result['all'] = (array) $data;
605
		/*
606
		    $ro->cls = 0; // AIS class undefined, also indicate unparsed msg
607
		    $ro->id = bindec(substr($_aisdata,0,6));
608
		*/
609
		return $result;
610
	}
611
}
612