1
1
<?php
2
- class MinecraftPingException extends Exception
3
- {
4
- //
5
- }
2
+
3
+ namespace xPaw ;
6
4
7
5
class MinecraftPing
8
6
{
@@ -27,104 +25,104 @@ class MinecraftPing
27
25
* echo '<img width="64" height="64" src="' . Str_Replace( "\n", "", $Info[ 'favicon' ] ) . '">';
28
26
*
29
27
*/
30
-
28
+
31
29
private $ Socket ;
32
30
private $ ServerAddress ;
33
31
private $ ServerPort ;
34
32
private $ Timeout ;
35
-
33
+
36
34
public function __construct ( $ Address , $ Port = 25565 , $ Timeout = 2 )
37
35
{
38
36
$ this ->ServerAddress = $ Address ;
39
37
$ this ->ServerPort = (int )$ Port ;
40
38
$ this ->Timeout = (int )$ Timeout ;
41
-
39
+
42
40
$ this ->Connect ( );
43
41
}
44
-
42
+
45
43
public function __destruct ( )
46
44
{
47
45
$ this ->Close ( );
48
46
}
49
-
47
+
50
48
public function Close ( )
51
49
{
52
50
if ( $ this ->Socket !== null )
53
51
{
54
52
fclose ( $ this ->Socket );
55
-
53
+
56
54
$ this ->Socket = null ;
57
55
}
58
56
}
59
-
57
+
60
58
public function Connect ( )
61
59
{
62
60
$ connectTimeout = $ this ->Timeout ;
63
61
$ this ->Socket = @fsockopen ( $ this ->ServerAddress , $ this ->ServerPort , $ errno , $ errstr , $ connectTimeout );
64
-
62
+
65
63
if ( !$ this ->Socket )
66
64
{
67
65
throw new MinecraftPingException ( "Failed to connect or create a socket: $ errno ( $ errstr) " );
68
66
}
69
-
67
+
70
68
// Set Read/Write timeout
71
69
stream_set_timeout ( $ this ->Socket , $ this ->Timeout );
72
70
}
73
-
71
+
74
72
public function Query ( )
75
73
{
76
74
$ TimeStart = microtime (true ); // for read timeout purposes
77
-
75
+
78
76
// See http://wiki.vg/Protocol (Status Ping)
79
77
$ Data = "\x00" ; // packet ID = 0 (varint)
80
-
78
+
81
79
$ Data .= "\x04" ; // Protocol version (varint)
82
80
$ Data .= Pack ( 'c ' , StrLen ( $ this ->ServerAddress ) ) . $ this ->ServerAddress ; // Server (varint len + UTF-8 addr)
83
81
$ Data .= Pack ( 'n ' , $ this ->ServerPort ); // Server port (unsigned short)
84
82
$ Data .= "\x01" ; // Next state: status (varint)
85
-
83
+
86
84
$ Data = Pack ( 'c ' , StrLen ( $ Data ) ) . $ Data ; // prepend length of packet ID + data
87
-
85
+
88
86
fwrite ( $ this ->Socket , $ Data ); // handshake
89
87
fwrite ( $ this ->Socket , "\x01\x00" ); // status ping
90
-
88
+
91
89
$ Length = $ this ->ReadVarInt ( ); // full packet length
92
-
90
+
93
91
if ( $ Length < 10 )
94
92
{
95
93
return FALSE ;
96
94
}
97
-
95
+
98
96
fgetc ( $ this ->Socket ); // packet type, in server ping it's 0
99
-
97
+
100
98
$ Length = $ this ->ReadVarInt ( ); // string length
101
-
99
+
102
100
$ Data = "" ;
103
101
do
104
102
{
105
103
if (microtime (true ) - $ TimeStart > $ this ->Timeout )
106
104
{
107
105
throw new MinecraftPingException ( 'Server read timed out ' );
108
106
}
109
-
107
+
110
108
$ Remainder = $ Length - StrLen ( $ Data );
111
109
$ block = fread ( $ this ->Socket , $ Remainder ); // and finally the json string
112
110
// abort if there is no progress
113
111
if (!$ block )
114
112
{
115
113
throw new MinecraftPingException ( 'Server returned too few data ' );
116
114
}
117
-
115
+
118
116
$ Data .= $ block ;
119
117
} while ( StrLen ($ Data ) < $ Length );
120
-
118
+
121
119
if ( $ Data === FALSE )
122
120
{
123
121
throw new MinecraftPingException ( 'Server didn \'t return any data ' );
124
122
}
125
-
123
+
126
124
$ Data = JSON_Decode ( $ Data , true );
127
-
125
+
128
126
if ( JSON_Last_Error ( ) !== JSON_ERROR_NONE )
129
127
{
130
128
if ( Function_Exists ( 'json_last_error_msg ' ) )
@@ -135,32 +133,32 @@ public function Query( )
135
133
{
136
134
throw new MinecraftPingException ( 'JSON parsing failed ' );
137
135
}
138
-
136
+
139
137
return FALSE ;
140
138
}
141
-
139
+
142
140
return $ Data ;
143
141
}
144
-
142
+
145
143
public function QueryOldPre17 ( )
146
144
{
147
145
fwrite ( $ this ->Socket , "\xFE\x01" );
148
146
$ Data = fread ( $ this ->Socket , 512 );
149
147
$ Len = StrLen ( $ Data );
150
-
148
+
151
149
if ( $ Len < 4 || $ Data [ 0 ] !== "\xFF" )
152
150
{
153
151
return FALSE ;
154
152
}
155
-
153
+
156
154
$ Data = SubStr ( $ Data , 3 ); // Strip packet header (kick message packet and short length)
157
155
$ Data = iconv ( 'UTF-16BE ' , 'UTF-8 ' , $ Data );
158
-
156
+
159
157
// Are we dealing with Minecraft 1.4+ server?
160
158
if ( $ Data [ 1 ] === "\xA7" && $ Data [ 2 ] === "\x31" )
161
159
{
162
160
$ Data = Explode ( "\x00" , $ Data );
163
-
161
+
164
162
return Array (
165
163
'HostName ' => $ Data [ 3 ],
166
164
'Players ' => IntVal ( $ Data [ 4 ] ),
@@ -169,9 +167,9 @@ public function QueryOldPre17( )
169
167
'Version ' => $ Data [ 2 ]
170
168
);
171
169
}
172
-
170
+
173
171
$ Data = Explode ( "\xA7" , $ Data );
174
-
172
+
175
173
return Array (
176
174
'HostName ' => SubStr ( $ Data [ 0 ], 0 , -1 ),
177
175
'Players ' => isset ( $ Data [ 1 ] ) ? IntVal ( $ Data [ 1 ] ) : 0 ,
@@ -180,36 +178,36 @@ public function QueryOldPre17( )
180
178
'Version ' => '1.3 '
181
179
);
182
180
}
183
-
181
+
184
182
private function ReadVarInt ( )
185
183
{
186
184
$ i = 0 ;
187
185
$ j = 0 ;
188
-
186
+
189
187
while ( true )
190
188
{
191
189
$ k = @fgetc ( $ this ->Socket );
192
-
190
+
193
191
if ( $ k === FALSE )
194
192
{
195
193
return 0 ;
196
194
}
197
-
195
+
198
196
$ k = Ord ( $ k );
199
-
197
+
200
198
$ i |= ( $ k & 0x7F ) << $ j ++ * 7 ;
201
-
199
+
202
200
if ( $ j > 5 )
203
201
{
204
202
throw new MinecraftPingException ( 'VarInt too big ' );
205
203
}
206
-
204
+
207
205
if ( ( $ k & 0x80 ) != 128 )
208
206
{
209
207
break ;
210
208
}
211
209
}
212
-
210
+
213
211
return $ i ;
214
212
}
215
213
}
0 commit comments