Can PHP ping a remote system without ICMP and without external programs? - php

I want to check if another machine is generally responding with PHP.
Most approaches are to ping some service running on the target machine, but I want to check if the machine is online generally.
I've found http://birk-jensen.dk/2010/09/php-ping/ which supposedly sends an ICMP Ping package. The problem is, somehow one is required to be root to perform a socket_create(AF_INET, SOCK_RAW, 1). The workaround via posix_seteuid(0) doesn't work either, since elevated permissions are required for that too.
Any functions that would let me run the ping program are not available in my scenario either.
So how do I check if a server is online using php?

You can always use Net_Ping to ping from php
http://pear.php.net/package/Net_Ping/redirected

for this you might want to try, this is highly unlikely to give meaningful data, but is something to grok over.
if you open a tcp socket to a random port and instead of timing out it closes immediately. then the machine is "up", however this does not mean much more then that. it could be in a kernel panic.
and a timeout does not mean that the machine is down. just that instead of rejecting the tcp handshake it dropped it.
you wont be able to get any kind of meaningful timing data with this, but will give more of an educated guess if the machine in question is on or off.
<?php
$sock = socket_create(AF_INET,SOCK_STREAM,SOL_TCP);
socket_connect ( $sock , string $address,22 ) === true) {
switch(socket_last_error($sock)) {
case 110:
case 112:
case 113:
echo 'Machine may be down';
break;
case 111:
echo 'Machine may be up';
break;
case 115:
echo 'Machine is up';
break;
default:
echo 'Machine in unknown state.';
break;
}
you already stated that you can't use the ping command so Net_Ping will not work as it is just a fancy interface to the ping command in the operating system

Related

PHP exec is blocked by ISP

I am trying to implement the following chat-html5 from git hub:
https://github.com/ivanph/Chat-HTML5
I have uploaded everything to my ISP but I have found that the ISP blocks exec for security reasons.
The file I am calling is :
<?php
/**
* Main Script of phpWebSockets
*
* Run this file in a shell or windows cmd to start the socket server.
* Sorry for calling this daemon but the goal is that this server run
* as daemon in near future.
*
* #author Moritz Wutz <moritzwutz#gmail.com>
* #version 0.1
* #package phpWebSockets
*/
ob_implicit_flush(true);
require 'socket.class.php';
require 'socketWebSocket.class.php';
require 'socketWebSocketTrigger.class.php';
$ip = exec ("ifconfig|grep 'inet:'|grep -v '127.0.0.1' |cut -d: -f2 |awk '{ print $1}'");
$WebSocket = new socketWebSocket($ip,8000);
?>
Is there an alternative way to do this ? Do all Isp's block this ?
What can I do?
Hi Guys
thanks for the responses.
I got a response from the script developer.
I have changed the $ip to the ip address of our web site. I now get the following error:
--2013-08-13 12:07:01-- http://www.wilsea.com/websockets2/startDaemon.php
Resolving www.wilsea.com... 188.64.188.21
Connecting to www.wilsea.com|188.64.188.21|:80... connected.
HTTP request sent, awaiting response... 500 Internal Server Error
2013-08-13 12:07:12 ERROR 500: Internal Server Error.
The developer says this means that the port (8000) is in use so I tried 80 - 443 - 8080 but got the same error.
I have emailed the ISP and asked if websockets are blocked or if I need a port opening.
Anyone else had this issue or any insights into this problem?
Is there an alternative way to do this ?
There also are system and shell_exec, but I'd assume this to be disabled for the same reasons.
Like pointed out in the comments, you could also just provide your server's static IP instead of having the script determine it. However, chances are sockets are disabled as well, so don't put your hopes too high.
Do all Isp's block this ?
Most Hosting Providers do. Obviously a hosting service doesn't want you to run arbitrary commands on the shell that could potentially reconfigure the machine.
What can I do?
Get paid hosting that allows you to exec. A VPS or a dedicated server comes to mind.
I could try to find a way to detect a good listening address in PHP to avoid this monstrosity. (The workaround would probably be $ip = '0';) Your next question would be: Fatal error: Call to undefined function socket_create() why is my ISP so mean?. exec() is blocked for good reasons on a shared hosting and you won't be allowed to create a socket with create_socket().
No hoster will want something like this on their shared server. You'll have to get your own system but then you wouldn't want this code to run on it. This is because you don't want to run this code anywhere unless you were trying to improve on it. But then you'd be improving on a solution which builds on the sand that is PHP. And that would be sad.
Get a cheap virtual server if you really want to use this. I don't recommend it. Looks like somebody is trying to use PHP for a task it's not designed to do. If you've gotten this far without understanding the issues involved I recommend you to stay far away from it. Try it on localhost if you must, so you're not harming other people.
The issue was the ISP blocks all port. They have now opened the port for me.
Cheers
SteveW

PHP / JS / Bash script for receiving GPS data over UDP

I want to write my own, small website for controlling my own GPS localizers. The problem is, that they are sending data (over GPRS) using UDP, not HTTP protocol. Can anyone give me any advice on how to receive such data and put it into MySQL database?
I'm looking for something exactly as written in this answer to that question. The only problem is that site mentioned in this answer has expired and script is unavailable.
All I need is an advice or example on how can I receive UDP packet/datagram containing coordinates, speed, date etc. and put this data into MySQL database. How to write a gateway as easiest as possible? All the rest I can handle myself.
I could do this without problems on Windows, as I'm former Delphi developer and writing a gateway between UDP and MySQL isn't a hard job to do there. But I need to run this solution (gateway) on a small, week Linux-based server, which isn't able to run Kylix (Delphi for Linux) programs, so this way is a dead-end.
Can this be done using PHP, JavaScript or by writing Bash script? I was thinking about node.js, which has similar example on home webpage (and probably many more out in the Internet). But I'm not to familiar with node.js, therefore I don't know, if there aren't better/easiers ways to do this.
It's possible to read data from UDP port using PHP. I am posting a example code which reads data from udp port.
<?php
error_reporting(E_ALL | E_STRICT);
$socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
socket_bind($socket, '127.0.0.1', 1223);
$from = '';
$port = 0;
socket_recvfrom($socket, $buf, 12, 0, $from, $port);
echo "Received $buf from remote address $from and remote port $port" . PHP_EOL;
?>
and to insert that data into MySQL database may be you need to use a daemon, go through this link
http://phpdaemon.net/
Maybe socket_recvfrom might interest you?
Here is, what I found myself.
General
As Venkat wrote, you can write a simple listner in pure PHP. You only have to run it via SSH, in PHP in CLI SAPI mode, not via browser, as it will fail on timeout after about 3-5 minutes.
For running in CLI mode, you need to know a full path to PHP and you have to call it with proper switch. For example:
/mnt/ext/opt/apache/bin/php -f /share/Web/projects/gps/gateway.php
PHP CLI does not use stdout for echo (don't know, what it uses). So, replace any echo with storing values to file or database, to see actual effects of your listner working.
You may need to use set_time_limit(0) function for endless, uninterrupted execution; but it was reported (see user contributed notes here), it is hardcoded to 0 for CLI SAPI, so setting this may not be mandatory.
After running your script in CLI mode, you can break it, by using Ctrl+C.
Listner example
Here is an example of a listner, that drops everything, it receives into 'drop.txt' file in the same directory, where script file is placed:
error_reporting(E_ALL | E_STRICT);
$file = './dump.txt';
$socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
socket_bind($socket, '0.0.0.0', 12345);
while(TRUE)
{
$buf = '';
$from = '';
$port = 0;
socket_recvfrom($socket, $buf, 1024, 0, $from, $port);
$momentum = time();
$entry = $momentum.' -- received "'.trim($buf).'" from '.$from.' on port '.$port.PHP_EOL;
file_put_contents($file, $entry, FILE_APPEND | LOCK_EX);
}
Things, you should keep in mind:
This script uses infinite loop, so the only way to break it after running is to cast Ctrl+C.
Use 0.0.0.0 IP address in socket_bind to listen from all sources (IP addresses) or 127.0.0.1 to limit it to localhost only.
Carefully select third parameter in socket_recvfrom -- a maximum number of bytes that will be received -- to make sure that the data you're waiting for will not be truncated.
You must use full path to files, you're using -- that is why there is $file = './dump.txt', not $file = 'dump.txt' in the code. Without full path, it can only work via webbrowser.
Using database
If you decide to drop recevied UDP packets into database and you choose SQLite for this purpose, you not only have to provide full path to database file, but also an absolute path! So:
$dbhandle = new SQLiteDatabase('/share/Web/projects/gps/data.db');
not:
$dbhandle = new SQLiteDatabase('data.db');
or even:
$dbhandle = new SQLiteDatabase('./data.db');
Second and third attempt will fail on some systems (depending on PHP configuration) and in this case, you'll see warning, that there is no such table, you're looking for, in database file.
Logoff problem fix
If you don't have direct access to the machine, on which you'll be running that listener, and you're connecting via SSH, keep in mind, that your listener will be problably turned off, once you logoff.
To fix this problem, you have to either run your PHP script in daemon mode (by adding & at the end):
/mnt/ext/opt/apache/bin/php -f /share/Web/gps/gateway.php&
Or make use of screen command in run non-daemon version of your listener in "wirtual" terminal.

Is it possible to re-use deliberately left open sockets?

I'm using the PHP sockets extension (basically a wrapper around the socket(2)-related linux syscalls) and would like to re-use sockets I open while serving one request in the subsequent ones. Performance is a critical factor.
The sockets I open are all to the same IP, which makes the use of other functions like pfsockopen() impossible (because it reuses same single socket every time) and I need several at a time.
The question
If I leave the sockets I open serving one request deliberately open, (I don't call socket_close() or socket_shutdown()) and connect a socket with the exact same parameters to the same IP serving the next request; will linux re-use the previously opened socket / file-descriptor?
What I want to do in the end is to avoid TCP-handshakes on every request.
Additional information:
I use the apache worker MPM - which means that different request can be but are not necessarily served from different processes. For the sake of simplicity let's assume that all requests are served from the same process.
I can get the file-descriptor ID of a open and connected socket in PHP. I can open and read and write to /dev/fd/{$id}, yet to no purpose - it's not communicating with the remote server (maybe this is a naïve approach). If anybody knew how to make this work I'd consider that to be an acceptable answer too.
If you want to reuse the socket in the same process, simply leave the connection open. That is actually your only option of avoiding TCP handshakes. Make sure keepalives are on:
s.setsockopt( socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
If you want to spawn new processes and pass the connection to them, yes, they will be able to write to /dev/fd/{$id} and this will send the data over network. Just make sure that the sockets are not closed during exec (learn about SOCK_CLOEXEC).
Passing the socket to an unrelated process is not possible. You would have to use some form of interprocess communication to accomplish that, and I am not sure that the overhead of TCP handshake in intranet or internet conditions would be enough to justify the complexity and other overhead associated with that.
If I leave the sockets I open serving one request deliberately open,
(I don't call socket_close() or socket_shutdown()) and connect a
socket with the exact same parameters to the same IP serving the next
request; will linux re-use the previously opened socket /
file-descriptor?
No, but you could always keep using the original one, if you are in the same process. What you are talking about is really connection pooling.
While the answer given by Jirka Hanika is correct for most systems, I have come to the conclusion that it regretfully does not apply to PHP; the re-use of sockets using the PHP sockets extension is impossible to achieve from user space.
The code that led to this conclusion is:
function statDescriptors() {
foreach (glob('/proc/self/fd/*') as $sFile) {
$r = realpath($sFile);
// ignore local file descriptors
if($r === false) {
echo `stat {$sFile}`, "\n";
}
}
}
header('Content-Type: text/plain');
statDescriptors();
$oSocket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_option($oSocket, SOL_SOCKET, SO_KEEPALIVE, 1);
socket_set_option($oSocket, SOL_SOCKET, SO_REUSEADDR, 1);
socket_connect($oSocket, '173.194.35.33', 80); // Google IP
socket_write($oSocket, 'GET / HTTP/1.0' . "\r\n");
socket_write($oSocket, 'Connection: Keep-Alive' . "\r\n\r\n");
socket_read($oSocket, 1024 * 8);
// socket_close($oSocket); // toggle this line comment during test
echo 'PID is: ', getmypid(), "\n";
statDescriptors();
This code will stat() the current process' open socket file descriptors at the start and end of its' execution. In between it will open a socket with SO_KEEPALIVE set, write a request to it and read a response. Then it will optionally close the socket (toggle line comment) and echo the current process' PID (to make sure you're in the same process).
You will see that regardless if you close the socket or not, the file descriptor created serving the previous request will not exist anymore at the beginning of this cycle's execution and a completely new socket will be created and connected.
I was unable to test SOCK_CLOEXEC since it's not (yet?) implemented in the extension.
(This was tested using PHP 5.4.0)

Check if host computer is online with PHP?

I've been having some issues with my Internet connection and I was wondering what is the fastest, error-less and most reliable way to check if the host computer is connected to the Internet.
I'm looking for something like is_online() that returns true when online and false when not.
I've benchmarked some solutions: file_get_contents with HEAD request, gethostbynamel, checkdnsrr and the following solution seems to be more than 100 faster than all the others:
function is_online()
{
return (checkdnsrr('google.com', 'ANY') && checkdnsrr('yahoo.com', 'ANY') && checkdnsrr('microsoft.com', 'ANY'));
}
Takes about one microsecond per each host, while file_get_contents for instance takes more than one second per each host (when offline).
You could send a ping to a host that is probably up (e.g. Google).
There seems to be no PHP built-in for this, so you'd have to resort to shell commands. The return value of ping on *nix can tell you whether a reply was received.
Update: ping -c1 -q -w1 should be the right command on Linux. This will give you exit code 0 if a reply was received, something else otherwise, and it times out after one second.
Hence, something like this (warning, my PHP is rusty) should do the trick:
function is_online() {
$retval = 0;
system("ping -c1 -q -w1", $retval);
return $retval == 0;
}
Why don't you do a number of HTTP GET (or better still HTTP HEAD for speed) requests on popular web sites? Use majority voting to decide on the answer.
You can sometimes rely on ping too (through a system call in PHP) but note that not all web sites respond to ICMP (ping) requests.
Note that by increasing the number of ping/http requests you make before drawing a conclusion helps with the confidence level of the answer but can't be error free in the worst of cases.
Don't forget this assumes that your server will respond to ICMP requests. If that's the case then I agree, Net_Ping is probably the way to go. Failing that you could use the Net_Socket package, also on PEAR, to attempt a connection to some port that you know will get a response from - perhaps port 7 or port 80 depending on what services you have running.

Ping from Dynamic Language without using 'ping'

I'm on a Linux system where I am not allowed to use the 'ping' application (ping: icmp open socket: Operation not permitted). However, the script that I am writing (PHP, but I can use an exec() call to any script/program if needed) needs to determine if a host is 'alive'. How can I go about this without using 'ping'?
If ping can't do it, you can't do it in a different language. Here is an analogy that may help you understand why. Let's say there is a file on the file system and you want to its contents. You run cat filename and it says cat: filename: Permission denied. Do you think Perl (or any other language) will fair better than C did here? Let's try:
#!/usr/bin/perl
use strict;
use warnings;
die "usage: $0 filename" unless #ARGV == 1;
my $filename = shift;
open my $fh, "<", $filename
or die "could not open $filename: $!\n";
print while <$fh>;
When run against the file it says could not open filename: Permission denied. No matter what language you try to use, you are going to get Operation not permitted.
That said, there are other methods of determining if a machine is alive. If there is a server that is known to always be running on the machine, you could try to connect to it. Note that you don't need to finish the connection (e.g. log in), just the fact that you can successfully initiate the connection is enough to know that box is up.
To do a ping (ICMP) you need root access.
The only way you have is to do a TCP or UDP ping.
If you want an example check the code of Cacti or you can use hping to do it for you
Or you can set SUID bit on "ping" program on unix ;)
http://us2.php.net/manual-lookup.php?pattern=socket
But if you can't open a socket with ping, it's unlikely that you can use any of these. Talk to your hosting provider.
The PHP Manual gives user supplied code for an implementation of a ping in PHP. Unfortunately, it requires root access so it's not likely you'll be able to use that either. One alternative is to use curl and look at the values returned by curl_getinfo():
c = curl_init('http://www.site.com/');
curl_exec($c);
$info = curl_getinfo($ch);
It is nowhere near being equivalent to ping, but still maybe suitable for your needs.

Categories