I'm trying to receive UDP data from a game. And update it on the page constantly. Using JSON to retrieve the data from a function.
Is it possible to separate socket_create/socket_bind from socket_recvfrom?
(I've cut some unnecessary code out of it)
private $socket;
public function socketConnect($port)
{
$ip = '0.0.0.0'; // local IP
$port = 20777; // port to listen
$this->socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
socket_bind($this->socket, $ip, $port) or die("Could not connect");
return view('telemetry');
}
public function getData()
{
while (socket_recvfrom($this->socket, $buf, $bytes, 0, $remote_ip, $remote_port)) {
// do something
return response()->json($data);
}
}
I've tried setting $this->socket to keep the data but that doesn't seem to work.
You cannot do that, no. Sockets created with the socket_* methods are not persistent, since they are low level sockets. And here your two functions are executed in two different page calls that are independent from each other (this is how PHP works).
Furthermore, what you are trying to do right now is a socket server (binding a socket is for server purposes usually), and socket servers need to be open continually to receive data. I would advise you to try to do a CLI program (that can still be done in PHP) and use the socket_recvfrom and socket_sendto methods to get and send your data (after doing your bind), and then store the received data in a database or in a file, to then have your website read from that to send it to your browser. Here is a howto that shows how to create a simple UDP server in PHP.
I'm in the process of creating my own service status script as both a chance to become more familiar with the PHP language and to design it from the ground up as being as efficient as possible for my needs.
A section of my code used in both my cron job and testing a connection parts queries the IP/Port of a service to make sure it is online. My issue is that the script simply queries whether the port is "Unblocked" on that IP so if for instance I was querying port 21 with an FTP server and that FTP server crashed my script would not detect any changes meaning its not doing what I want it to do. Instead I would be wanting the IP and port to be queried and for my script to see if there is actually something running on that port, if there is show online if not error out. I've had a look on google and it seems like I would have to send a packet/receive a response so PHP can tell there's something active? I'm not sure.
This is my current code below:
<?php
$host = $_POST['servip'];
$port = $_POST['servport'];
if (!$socket = #fsockopen($host, $port, $errno, $errstr, 3)) {
echo "Offline!";
} else {
echo "Online!";
fclose($socket);
}
?>
http://php.net/manual/en/function.fsockopen.php
fsockopen — Open Internet or Unix domain socket connection The socket
will by default be opened in blocking mode. You can switch it to
non-blocking mode by using stream_set_blocking(). The function
stream_socket_client() is similar but provides a richer set of
options, including non-blocking connection and the ability to provide
a stream context.
Since fsockopen will either connect or not connect (timeout) then that tells you whether or not a connection is available ("open") or being blocked (firewall, etc).
// Ping by website domain name, IP address or Hostname
function example_pingDomain($domain){
$starttime = microtime(true);
$file = #fsockopen($domain, 80, $errno, $errstr, 10);
$stoptime = microtime(true);
$status = 0;
if (!$file) {
$status = -1; // Site is down
} else {
fclose($file);
$status = ($stoptime - $starttime) * 1000;
$status = floor($status);
}
return $status;
}
If you really want to know if the FTP server is working or not, your best option is to actually send FTP commands through to it.
An FTP server, upon connect, should typically reply with the first three bytes "220" or "120". 220 is a "greeting". You can read more in RFC 959.
To be completely sure, you might be better off using ftp:// handling in PHP, e.g. actually authenticating a user (maybe user authentication is broken, but it's still able to send a greeting - does that count is "down"?)
Anyway, if you want better than "was I able to connect on that port?" or "did the connect succeed in a timely fashion?", you have to delve into actual communication over the socket. Ultimately, this means you have to do something special for each type of service (for some, read bytes, for others write bytes, etc.)
I want the users of my website to check if any other website (http and/or https) is up. There are sites out there that use google analytics for that (if I understood it right). But I don't understand how they do it.
Question 1) How do I use google-analytics on my website to check if some other site is up?
Question 2) How do I do it by myself? Using php or javascript? I wonder if google-analytics might be more reliable in terms if they use multiple server locations to check whether the site is online compared to a single location that I would use with my own code.
You can use server side Curl and monitor http response header, site timeouts.
One can try to connect directly to the http(s) port of the server.
$canConnect = FALSE;
$host = 'www.example.com';
$service_port = 80; // http, for https use 443;
$address = gethostbyname ($host);
$socket = socket_create (AF_INET, SOCK_STREAM, SOL_TCP);
if ($socket !== FALSE) {
$result = socket_connect ($socket, $address, $service_port);
if ($result) {
$canConnect = TRUE;
}
socket_close($socket);
}
You could ping the servers and monitor the responses. This link shows you the implementation in PHP: http://www.darian-brown.com/php-ping-script-to-check-remote-server-or-website/
I know that PHP does allow you to create a server but what about client? I would need a script that connects to my TCP/IP server on given port and send some data. Is that possible in PHP and if so, could you help me please? I did not find anything useful.
I have my TCP/IP server running on port 1301 and I would need users to be able by clicking on web page send one char to the server.
It's similar to how you would create a server. I'd recommend taking a look at the documentation for socket_connect.
Summaries:
socket_create
socket_bind
socket_connect
socket_write
socket_read
socket_close
Workflow:
Create the socket
Optionally bind it
Connect to the server
Read/write data
Close the socket
I've used this piece before. It's fairly simple; it connects to $ip_address on port $port, and sends the $sendData data to the server, and then reads the response and returns the response.
$sendData = chr(6).chr(0).chr(255).chr(255).'info';
function sendAndGetResponse($ip_address, $port, $sendData){
$socketHandler=#fsockopen($ip_address, $port, $errno, $errstr, 1);
if(!$socketHandler)
{
return false; //offline
}
else
{
$response = '';
stream_set_timeout($socketHandler, 2);
fwrite($socketHandler, $sendData);
while (!feof($socketHandler))
{
stream_set_timeout($socketHandler, 2);
$response .= fgets($socketHandler, 1024);
}
fclose($socketHandler);
return $response;
}
}
You can use CURL if it is HTTP server or create a socket connection http://php.net/manual/en/function.socket-connect.php
Yes, php can act as a HTTP-client with CURL, fsockopen and most easiest way to fetch URL - with file_get_contents()
I wonder how to make a status checker, checking about 500 addresses in a few minutes?
(it'll check a certain port if its listening).
But I care about the performance... so I don't know if it can be done with PHP. Waiting for your suggestions guys.
Also please give me some examples, if you think that the best way for this thing will be PHP or C#.
Ofc. I meant the TCP connection but not http, since I need to check open port for example: 11740
Edit:
Added third bounty for this question! Please post some better answer than those already posted.
This is very doable in PHP and you could check 500 IP in a few seconds. Use mutli-curl to send out many requests at once (i.e. 100 or all 500). It will take only as long as the slowest IP to respond. But you may want to set a reasonable curl connect timeout of a few seconds. Default network timeout is 2 minutes as I recall.
http://php.net/manual/en/function.curl-multi-exec.php
Note that I'm not saying PHP is your best choice for something like this. But it can be done fairly quickly and easily in PHP.
Here is a full code example. I tested it with real URLs and it all worked. The $results array will contain just about all the stats you can get from a curl request. In your case, since you just care if the port is "open" you do a HEAD request by setting CURLOPT_NOBODY to true.
$urls = array(
'http://url1.com'=>'8080',
'http://url2'=>'80',
);
$mh = curl_multi_init();
$url_count = count($urls);
$i = 0;
foreach ($urls as $url=>$port) {
$ch[$i] = curl_init();
curl_setopt($ch[$i], CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch[$i], CURLOPT_NOBODY, true);
curl_setopt($ch[$i], CURLOPT_URL, $url);
curl_setopt($ch[$i], CURLOPT_PORT, $port);
curl_multi_add_handle($mh, $ch[$i]);
$i++;
}
$running = null;
do {
$status = curl_multi_exec($mh,$running);
$info = curl_multi_info_read($mh);
} while ($status == CURLM_CALL_MULTI_PERFORM || $running);
$results= array();
for($i = 0; $i < $url_count; $i++) {
$results[$i] = curl_getinfo($ch[$i]);
// append port number request to URL
$results[$i]['url'] .= ':'.$urls[$results[$i]['url']];
if ($results[$i]['http_code']==200) {
echo $results[$i]['url']. " is ok\n";
} else {
echo $results[$i]['url']. " is not ok\n";
}
curl_multi_remove_handle($mh, $ch[$i]);
}
curl_multi_close($mh);
print_r($results);
Your best bet might be to use a dedicated port scanner like nmap. I don't know the command-line options off the top of my head, but it should be possible to output a results file and just parse it from PHP.
Here is a way to do this very quickly in PHP using the sockets extension, by setting all the sockets to non blocking. From a purely networking point of view, this is the most efficient way, since this simply tests the TCP connectivity and does not exchange any actual data. Tested on PHP/5.2.17-Win32.
<?php
// An array of hosts to check
$addresses = array(
'192.168.40.40',
'192.168.5.150',
'192.168.5.152',
'google.com',
'192.168.5.155',
'192.168.5.20'
);
// The TCP port to test
$testport = 80;
// The length of time in seconds to allow host to respond
$waitTimeout = 5;
// Loop addresses and create a socket for each
$socks = array();
foreach ($addresses as $address) {
if (!$sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) {
echo "Could not create socket for $address\n";
continue;
} else echo "Created socket for $address\n";
socket_set_nonblock($sock);
// Suppress the error here, it will always throw a warning because the
// socket is in non blocking mode
#socket_connect($sock, $address, $testport);
$socks[$address] = $sock;
}
// Sleep to allow sockets to respond
// In theory you could just pass $waitTimeout to socket_select() but this can
// be buggy with non blocking sockets
sleep($waitTimeout);
// Check the sockets that have connected
$w = $socks;
$r = $e = NULL;
$count = socket_select($r, $w, $e, 0);
echo "$count sockets connected successfully\n";
// Loop connected sockets and retrieve the addresses that connected
foreach ($w as $sock) {
$address = array_search($sock, $socks);
echo "$address connected successfully\n";
#socket_close($sock);
}
/* Output something like:
Created socket for 192.168.40.40
Created socket for 192.168.5.150
Created socket for 192.168.5.152
Created socket for google.com
Created socket for 192.168.5.155
Created socket for 192.168.5.20
4 sockets connected successfully
192.168.40.40 connected successfully
192.168.5.150 connected successfully
google.com connected successfully
192.168.5.20 connected successfully
*/
The best way to this would be nmap, as mentioned in other answers.
You'd want to run it like this (-PN is don't ping, -sP means to skip the port scan and just check if the host is up, -PS80 means to check port 80, -n is not to do reverse DNS lookup, -oG - is to output in machine readable format, and the other arguments are IP addresses or hostnames):
nmap -PN -sP -PS80 -n -oG - --send-ip IP1 IP2 ...
And it would look like this:
$ nmap -n -PN -sP -PS80 -oG - 209.85.147.104 87.248.122.122 4.4.4.4
# Nmap 5.21 scan initiated Tue Feb 21 01:07:20 2012 as: nmap -n -PN -sP -PS80 -oG - 209.85.147.104 87.248.122.122 4.4.4.4
Host: 209.85.147.104 () Status: Up
Host: 87.248.122.122 () Status: Up
Host: 4.4.4.4 () Status: Down
# Nmap done at Tue Feb 21 01:07:21 2012 -- 3 IP addresses (2 hosts up) scanned in 0.95 seconds
You could run and parse this from PHP with no trouble. I'm not very experienced in PHP, and haven't tested this, but here's some example code:
<?php
$output = shell_exec('nmap -n -PN -sP -PS80 -oG - --send-ip ' . implode(" ", $ips));
$result = array();
foreach(preg_split("/\r?\n/", $output) as $line) {
if (!(substr($line, 0, 1) === "#")) {
$info = preg_split("[\t ]", $line);
$result[$info[2]] = ($info[5] === "Up");
}
}
?>
Mind you, writing PHP code or C# code or whatever that does this isn't a big deal, it's just that nmap is very very good at what it does, and extremely versatile, that writing code that does this is reinventing the wheel. If you do decide to go that route, make sure you make your code asynchronous, otherwise one slow server would slow down your entire sweep.
As mentioned by kz26, nmap from command-line would be your best option. With PHP functions like system, exec, shell_exec, etc to capture the results for processing.
This guide should help you to get started http://www.cyberciti.biz/tips/linux-scanning-network-for-open-ports.html
C# would be a better option as you can use threads to speed up the process.
In PHP, you can essentially check if a TCP port is open by using fsockopen().
$host = 'example.com';
$port = 80;
$timeout = 30;
$fp = #fsockopen($host, $port, $errno, $errstr, $timeout);
if (!$fp) {
echo "Port $port appears to be closed on $host Reason: $errno: $errstr.\n";
} else {
echo "Port $port is open on $host\n";
fclose($fp);
}
As kz26 said, you could also get something like nmap to check the ports on a bunch of hosts and use php to call it and process the results as well.
PHP should be able to check 500 ips in pretty short amount of time, but it really depends on your internet connection and other specs. Other tools written in lower languages would be a little faster, but I think that php is good for the job. You must just set php execution limit to a suitable value before trying
They keyword in this is non-blocking. You would want to have a certain callback when an attempt is succesful and be able to run more calls in the meantime.
Some functions like sockets from DaveRandom's answer allow for a non-blocking mode to do this in regular php installations. You can also use different programming languages such as node.js to do this very efficiently because they are designed to be non-blocking.
The by far most efficient way to do this is to use raw sockets, however this requires administrative privileges and some boilerplate coding. You choose a local port as the source, send a SYN packet to port 80 of each target address, and collect the return packets on the source port. If they have an ACK flag, the port is open for connections. If they have RST or they don't return, the port isn't open/the host is dead.
Obviously you will need to manually wait for whatever your "timeout" of choice is as this method goes around the OS network stack. This also requires you to construct the TCP and IP headers manually, though, and I doubt it can be done from PHP. It can certainly be done in C, and I believe C# also supports raw sockets (haven't done it in C# myself).
This is extremely fast and doesn't pollute the system with a bunch of open connections or threads.
The best thing you can do is start a number of threads (you decide the number; probably more than 10 and less than a 100). Doing scanning on different threads will speed up your check. I am not sure if you can do multi-threading in php. If not, then c# would be better.