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.
Related
Ok, so I've created a project where a client can drag and drop files onto our server and all works great! Now I've been asked to have the files that are being uploaded/transferred by our clients over a specific port range (let's say between 10000 and 11000 for argument sake). I do not know how to accomplish this. My current uploading function looks something like this:
File's name: test/upload.php
$dir = "path/to/directory/";
$tempFile = $_FILE['file']['tmp_name'];
$tagetFile = $dir.$_FILE['file']['name'];
move_uploaded_file($tempFile, $targetFile);
Where $_FILE is a file being uploaded.
Please disregard any syntax or spelling error in the code above, it works perfect at the moment. I have removed a lot of code to give a simplistic idea of what my code is currently doing.
If any configuration changes to PHP are to be made, they need to target this directory specifically as the rest of our website needs to stay on the current port. I am not exactly sure where to begin with specifying the ports to be used for file transfers. The file transfers are purely client to server and will never be vice-versa. We do have an FTP server setup however if possible, we'd like to remain off of it. I am not sure if what I am asking is possible otherwise.
I am using the Dropzone.js plugin (from here: http://www.dropzonejs.com/), however all the PHP code is mine.
I am not sure if something like the code below (from here) is the way to go, I've never used the fsockopen function before.
$fp = fsockopen($host, $port, $errno, $errstr, $timeout);
$responding = 1;
if (!$fp) { $responding = 0; }
$tend = microtime(true);
fclose($fp);
All answers are welcome. Thank you.
Since you want the client to upload the file on a different port, you will need to stand up a web server on that port. You could tell your current server to listen on that port, but that would do nothing to reduce load on your main website, so a separate machine is necessary. The new machine will have to be set up to listen to only the file upload port, but will need to contain your server (Apache, etc), PHP, and have access to the network storage location for your files.
If you have one, you may need to configure your firewall so traffic comes in to the correct machine depending on which port it is sent to.
The actual PHP code you use will not really be any different from what you have working now. Your JS code will need to be updated to it posts to the server using port 10000 or whatever you choose.
Here's a simple diagram that may help.
I would like to make a web interface in PHP to see the FreeSWITCH activities (calls, etc), possibly hosted on a different server than the one where FS is running.
I've seen the server status on the FS server using command line (php single_command.php status), but now I would like to see this status from another server.
When I try to copy ESL.php file to this remote server and try to check the status, I get this error message:
Fatal error: Call to undefined function new_ESLconnection() in
/var/www/freeswitch/ESL.php on line 127
This is my index.php file:
<?php
ini_set('display_errors', 1);
$password = "ClueCon";
$port = "8021";
$host = "192.168.2.12";
require_once('ESL.php');
set_time_limit(0); // Remove the PHP time limit of 30 seconds for completion due to loop watching events
// Connect to FreeSWITCH
$sock = new ESLconnection($host, $port, $password);
// We want all Events (probably will want to change this depending on your needs)
$sock->sendRecv("status");
// Grab Events until process is killed
while($sock->connected()){
$event = $sock->recvEvent();
print_r($event->serialize());
}
?>
I undestand that the webserver doesn't have FreeSWITCH installed, so the error message is obvious, but i don't see how to access to this information from this webserver.
Thank you for your help.
Depending upon your need you can use either Inbound or Outbound socket. I do not know much about PHP and FS Event Socket but yeah tried enough with python. I highly recommended to go through thislink.
So if you just want to do small task like initiating a call, bridging any two given number etc i think you should go with Inbound socket(making cli command from your web server to freeswitch server) or mod_xml_rpc.
And if you want to have full control of everything that happens on FS server like showing live call status and modifying their states or say a complete interactive telephony dashboard then you should go with Outbound socket.(Your FS server will send all events to your web server.)
However in your case problem is I think you did not properly build the php ESL module.
this link might help you installing ESL
Rather than using ESL, you might want to consider using the XMLRPC. The connection is very straight forward:
https://wiki.freeswitch.org/wiki/Freeswitch_XML-RPC
The credentials for the XMLRPC are in your autoloads_configs/xml_rpc.conf.xml
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
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)
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.