Completed
Push — master ( cc50d0...0f8c33 )
by Yannick
09:46
created

AIS::process_ais_itu()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 16
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 11
nc 2
nop 4
dl 0
loc 16
rs 9.4285
c 0
b 0
f 0
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; // float
0 ignored issues
show
Bug introduced by
The variable $flat seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

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; // float
0 ignored issues
show
Bug introduced by
The variable $flon seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

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->sog = -1.0;
126
		$ro->cog = 0.0;
127
		$ro->lon = 0.0;
128
		$ro->lat = 0.0;
129
		$ro->ts = time();
130
		$ro->id = bindec(substr($_aisdata,0,6));
131
		$ro->mmsi = bindec(substr($_aisdata,8,30));
132
		if ($ro->id >= 1 && $ro->id <= 3) {
133
			$ro->cog = bindec(substr($_aisdata,116,12))/10;
134
			$ro->sog = bindec(substr($_aisdata,50,10))/10;
135
			$ro->lon = $this->make_lonf(bindec(substr($_aisdata,61,28)));
136
			$ro->lat = $this->make_latf(bindec(substr($_aisdata,89,27)));
137
			$ro->cls = 1; // class A
138
		} else if ($ro->id == 5) {
139
			//$imo = bindec(substr($_aisdata,40,30));
140
			//$cs = $this->binchar($_aisdata,70,42);
141
			$ro->name = $this->binchar($_aisdata,112,120);
142
			$ro->cls = 1; // class A
143
		} else if ($ro->id == 18) {
144
			$ro->cog = bindec(substr($_aisdata,112,12))/10;
145
			$ro->sog = bindec(substr($_aisdata,46,10))/10;
146
			$ro->lon = $this->make_lonf(bindec(substr($_aisdata,57,28)));
147
			$ro->lat = $this->make_latf(bindec(substr($_aisdata,85,27)));
148
			$ro->cls = 2; // class B
149
		} else if ($ro->id == 19) {
150
			$ro->cog = bindec(substr($_aisdata,112,12))/10;
151
			$ro->sog = bindec(substr($_aisdata,46,10))/10;
152
			$ro->lon = $this->make_lonf(bindec(substr($_aisdata,61,28)));
153
			$ro->lat = $this->make_latf(bindec(substr($_aisdata,89,27)));
154
			$ro->name = $this->binchar($_aisdata,143,120);
155
			$ro->cls = 2; // class B
156
		} else if ($ro->id == 24) {
157
			$pn = bindec(substr($_aisdata,38,2));
158
			if ($pn == 0) {
159
				$ro->name = $this->binchar($_aisdata,40,120);
160
			}
161
			$ro->cls = 2; // class B
162
		}
163
		$ro->statusid = bindec(substr($_aisdata,38,4));
164
		$ro->status = $this->getStatus($ro->statusid);
165
		//var_dump($ro); // dump results here for demo purpose
166
		return $ro;
167
	}
168
169
	public function getStatus($statusid) {
170
		if ($statusid == 0) {
171
			return 'under way using engine';
172
		} elseif ($statusid == 1) {
173
			return 'at anchor';
174
		} elseif ($statusid == 2) {
175
			return 'not under command';
176
		} elseif ($statusid == 3) {
177
			return 'restricted maneuverability';
178
		} elseif ($statusid == 4) {
179
			return 'constrained by her draught';
180
		} elseif ($statusid == 5) {
181
			return 'moored';
182
		} elseif ($statusid == 6) {
183
			return 'aground';
184
		} elseif ($statusid == 7) {
185
			return 'engaged in fishing';
186
		} elseif ($statusid == 8) {
187
			return 'under way sailing';
188
		} elseif ($statusid == 9) {
189
			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)';
190
		} elseif ($statusid == 10) {
191
			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)';
192
		} elseif ($statusid == 11) {
193
			return 'power-driven vessel towing astern (regional use)';
194
		} elseif ($statusid == 12) {
195
			return 'power-driven vessel pushing ahead or towing alongside (regional use)';
196
		} elseif ($statusid == 13) {
197
			return 'reserved for future use';
198
		} elseif ($statusid == 14) {
199
			return 'AIS-SART (active), MOB-AIS, EPIRB-AIS';
200
		} elseif ($statusid == 15) {
201
			return 'undefined = default (also used by AIS-SART, MOB-AIS and EPIRB-AIS under test)';
202
		}
203
	}
204
205
	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...
206
		global $port; // tcpip port...
207
		
208
		static $debug_counter = 0;
209
		$aisdata168='';//six bit array of ascii characters
210
		$ais_nmea_array = str_split($_itu); // convert to an array
211
		foreach ($ais_nmea_array as $value) {
212
			$dec = $this->ascii_2_dec($value);
213
			$bit8 = $this->asciidec_2_8bit($dec);
214
			$bit6 = $this->dec_2_6bit($bit8);
215
			//echo $value ."-" .$bit6 ."";
216
			$aisdata168 .=$bit6;
217
		}
218
		//echo $aisdata168 . "<br/>";
219
		return $this->decode_ais($aisdata168, $aux);
0 ignored issues
show
Unused Code introduced by
The call to AIS::decode_ais() has too many arguments starting with $aux.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
220
	}
221
222
	// char* - AIS \r terminated string
223
	// TCP based streams which send messages in full can use this instead of calling process_ais_buf
224
	public function process_ais_raw($rawdata, $aux = '') { // return int
225
		static $num_seq; // 1 to 9
226
		static $seq; // 1 to 9
227
		static $pseq; // previous seq
228
		static $msg_sid = -1; // 0 to 9, indicate -1 at start state of device, do not process messages
229
		static $cmsg_sid; // current msg_sid
230
		static $itu; // buffer for ITU message
231
232
		$filler = 0; // fill bits (int)
233
		$chksum = 0;
234
		// raw data without the \n
235
		// calculate checksum after ! till *
236
		// assume 1st ! is valid
237
		// find * ensure that it is at correct position
238
		$end = strrpos ( $rawdata , '*' );
239
		if ($end === FALSE) return -1; // check for NULLS!!!
240
		$cs = substr( $rawdata, $end + 1 );
241
		if ( strlen($cs) != 2 ) return -1; // correct cs length
242
		$dcs = (int)hexdec( $cs );
243
		for ( $alias=1; $alias<$end; $alias++) $chksum ^= ord( $rawdata[$alias] ); // perform XOR for NMEA checksum
244
		if ( $chksum == $dcs ) { // NMEA checksum pass
245
			$pcs = explode(',', $rawdata);
246
			// !AI??? identifier
247
			$num_seq = (int)$pcs[1]; // number of sequences
248
			$seq = (int)$pcs[2]; // get sequence
249
			// get msg sequence id
250
			if ($pcs[3] == '') $msg_sid = -1; // non-multipart message, set to -1
251
			else $msg_sid = (int)$pcs[3]; // multipart message
252
			$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...
253
			// message sequence checking
254
			if ($num_seq < 1 || $num_seq > 9) {
255
				echo "ERROR,INVALID_NUMBER_OF_SEQUENCES ".time()." $rawdata\n";
256
				return -1;
257
			} else if ($seq < 1 || $seq > 9) { // invalid sequences number
258
				echo "ERROR,INVALID_SEQUENCES_NUMBER ".time()." $rawdata\n";
259
				return -1;
260
			} else if ($seq > $num_seq) {
261
				echo "ERROR,INVALID_SEQUENCE_NUMBER_OR_INVALID_NUMBER_OF_SEQUENCES ".time()." $rawdata\n";
262
				return -1;
263
			} else { // sequencing ok, handle single/multi-part messaging
264
				if ($seq == 1) { // always init to 0 at first sequence
265
					$filler = 0; // ?
266
					$itu = ""; // init message length
267
					$pseq = 0; // note previous sequence number
268
					$cmsg_sid = $msg_sid; // note msg_sid
269
				}
270
				if ($num_seq > 1) { // for multipart messages
271
					if ($cmsg_sid != $msg_sid // different msg_sid
272
					    || $msg_sid == -1 // invalid initial msg_sid
273
					    || ($seq - $pseq) != 1 // not insequence
274
					) {  // invalid for multipart message
275
						$msg_sid = -1;
276
						$cmsg_sid = -1;
277
						echo "ERROR,INVALID_MULTIPART_MESSAGE ".time()." $rawdata\n";
278
						return -1;
279
					} else {
280
						$pseq++;
281
					}
282
				}
283
				$itu = $itu.$pcs[5]; // get itu message
284
				$filler += (int)$pcs[6][0]; // get filler
285
				if ($num_seq == 1 // valid single message
286
				    || $num_seq == $pseq // valid multi-part message
287
				) {
288
					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...
289
						//echo $rawdata;
290
					}
291
					return $this->process_ais_itu($itu, strlen($itu), $filler, $aux /*, $ais_ch*/);
292
				}
293
			} // end process raw AIS string (checksum passed)
294
		}
295
		return -1;
296
	}
297
298
	// incoming data from serial or IP comms
299
	public function process_ais_buf($ibuf) {
300
		static $cbuf = "";
301
		$cbuf = $cbuf.$ibuf;
302
		$last_pos = 0;
303
		$result = new stdClass();
304
		while ( ($start = strpos($cbuf,"VDM",$last_pos)) !== FALSE) {
305
		//while ( ($start = strpos($cbuf,"!AI",$last_pos)) !== FALSE) {
306
			//DEBUG echo $cbuf;
307
			if ( ($end = strpos($cbuf,"\r\n", $start)) !== FALSE) { //TBD need to trim?
308
				$tst = substr($cbuf, $start - 3, ($end - $start + 3));
309
				//DEBUG echo "[$start $end $tst]\n";
310
				$result = $this->process_ais_raw( $tst, "" );
311
				$last_pos = $end + 1;
312
			} else break;
313
		}
314
		if ($last_pos > 0) $cbuf = substr($cbuf, $last_pos); // move...
315
		if (strlen($cbuf) > 1024) $cbuf = ""; // prevent overflow simple mode...
316
		return $result;
317
	}
318
319
	// incoming data from serial or IP comms
320
	public function process_ais_line($cbuf) {
321
		$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...
322
		$start = strpos($cbuf,"VDM");
323
		$tst = substr($cbuf, $start - 3);
324
		$result = $this->process_ais_raw( $tst, "" );
325
		return $result;
326
	}
327
328
	/* AIS Encoding
329
	*/
330
	private function mk_ais_lat( $lat ) {
331
		//$lat = 1.2569;
332
		if ($lat<0.0) {
333
			$lat = -$lat;
334
			$neg=true;
335
		} else $neg=false;
336
		$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...
337
		$latd = intval ($lat * 600000.0);
338
		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...
339
			$latd = ~$latd;
340
			$latd+=1;
341
			$latd &= 0x07FFFFFF;
342
		}
343
		return $latd;
344
	}
345
346
	private function mk_ais_lon( $lon ) {
347
		//$lon = 103.851;
348
		if ($lon<0.0) {
349
			$lon = -$lon;
350
			$neg=true;
351
		} else $neg=false;
352
		$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...
353
		$lond = intval ($lon * 600000.0);
354
		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...
355
			$lond = ~$lond;
356
			$lond+=1;
357
			$lond &= 0x0FFFFFFF;
358
		}
359
		return $lond;
360
	}
361
362
	private function char2bin($name, $max_len) {
363
		$len = strlen($name);
364
		if ($len > $max_len) $name = substr($name,0,$max_len);
365
		if ($len < $max_len) $pad = str_repeat('0', ($max_len - $len) * 6);
366
		else $pad = '';
367
		$rv = '';
368
		$ais_chars = array(
369
		    '@'=>0, 'A'=>1, 'B'=>2, 'C'=>3, 'D'=>4, 'E'=>5, 'F'=>6, 'G'=>7, 'H'=>8, 'I'=>9,
370
		    'J'=>10, 'K'=>11, 'L'=>12, 'M'=>13, 'N'=>14, 'O'=>15, 'P'=>16, 'Q'=>17, 'R'=>18, 'S'=>19,
371
		    'T'=>20, 'U'=>21, 'V'=>22, 'W'=>23, 'X'=>24, 'Y'=>25, 'Z'=>26, '['=>27, '\\'=>28, ']'=>29,
372
		    '^'=>30, '_'=>31, ' '=>32, '!'=>33, '\"'=>34, '#'=>35, '$'=>36, '%'=>37, '&'=>38, '\''=>39,
373
		    '('=>40, ')'=>41, '*'=>42, '+'=>43, ','=>44, '-'=>45, '.'=>46, '/'=>47, '0'=>48, '1'=>49,
374
		    '2'=>50, '3'=>51, '4'=>52, '5'=>53, '6'=>54, '7'=>55, '8'=>56, '9'=>57, ':'=>58, ';'=>59,
375
		    '<'=>60, '='=>61, '>'=>62, '?'=>63
376
		);
377
		$_a = str_split($name);
378
		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...
379
			if (isset($ais_chars[$_1])) $dec = $ais_chars[$_1];
380
			else $dec = 0;
381
			$bin = str_pad(decbin( $dec ), 6, '0', STR_PAD_LEFT);
382
			$rv .= $bin;
383
			//echo "$_1 $dec ($bin)<br/>";
384
		}
385
		return $rv.$pad;
386
	}
387
388
	private function mk_ais($_enc, $_part=1,$_total=1,$_seq='',$_ch='A') {
389
		$len_bit = strlen($_enc);
390
		$rem6 = $len_bit % 6;
391
		$pad6_len = 0;
392
		if ($rem6) $pad6_len = 6 - $rem6;
393
		//echo  $pad6_len.'<br>';
394
		$_enc .= str_repeat("0", $pad6_len); // pad the text...
395
		$len_enc = strlen($_enc) / 6;
396
		//echo $_enc.' '.$len_enc.'<br/>';
397
		$itu = '';
398
		for ($i=0; $i<$len_enc; $i++) {
399
			$offset = $i * 6;
400
			$dec = bindec(substr($_enc,$offset,6));
401
			if ($dec < 40) $dec += 48;
402
			else $dec += 56;
403
			//echo chr($dec)." $dec<br/>";
404
			$itu .= chr($dec);
405
		}
406
		// add checksum
407
		$chksum = 0;
408
		$itu = "AIVDM,$_part,$_total,$_seq,$_ch,".$itu.",0";
409
		$len_itu = strlen($itu);
410
		for ($i=0; $i<$len_itu; $i++) {
411
			$chksum ^= ord( $itu[$i] );
412
		}
413
		$hex_arr = array('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F');
414
		$lsb = $chksum & 0x0F;
415
		if ($lsb >=0 && $lsb <= 15 ) $lsbc = $hex_arr[$lsb];
416
		else $lsbc = '0';
417
		$msb = (($chksum & 0xF0) >> 4) & 0x0F;
418
		if ($msb >=0 && $msb <= 15 ) $msbc = $hex_arr[$msb];
419
		else $msbc = '0';
420
		$itu = '!'.$itu."*{$msbc}{$lsbc}\r\n";
421
		return $itu;
422
	}
423
424
	public function parse($buffer) {
425
		$data = $this->process_ais_buf($buffer);
426
		if (!is_object($data)) return array();
427
		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...
428
		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...
429
		$result['ident'] = trim($data->name);
430
		$result['timestamp'] = $data->ts;
431
		$result['mmsi'] = $data->mmsi;
432
		if ($data->sog != -1.0) $result['speed'] = $data->sog;
433
		if ($data->cog != 0) $result['heading'] = $data->cog;
434
		/*
435
		    $ro->cls = 0; // AIS class undefined, also indicate unparsed msg
436
		    $ro->id = bindec(substr($_aisdata,0,6));
437
		*/
438
		return $result;
439
	}
440
441
	public function parse_line($buffer) {
442
		$result = array();
443
		$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...
444
		$start = strpos($buffer,"VDM");
445
		$tst = substr($buffer, $start - 3);
446
		$data = $this->process_ais_raw( $tst, "" );
447
		if (!is_object($data)) return array();
448
		if ($data->lon != 0) $result['longitude'] = $data->lon;
449
		if ($data->lat != 0) $result['latitude'] = $data->lat;
450
		$result['ident'] = trim(str_replace('@','',$data->name));
451
		$result['timestamp'] = $data->ts;
452
		$result['mmsi'] = $data->mmsi;
453
		if ($data->sog != -1.0) $result['speed'] = $data->sog;
454
		if ($data->cog != 0) $result['heading'] = $data->cog;
455
		if ($data->status != '') $result['status'] = $data->status;
456
		$result['all'] = (array) $data;
457
		/*
458
		    $ro->cls = 0; // AIS class undefined, also indicate unparsed msg
459
		    $ro->id = bindec(substr($_aisdata,0,6));
460
		*/
461
		return $result;
462
	}
463
}
464