sending a binary message using stream_socket_client and php strings - php

I am using php to connect to a socket server to send binary data - ie not standard ascii (or printable) strings. For example a message may contain ascii 0 or any number from 0 - 255.
I have functions for example like this:
function append_uint16($str, $num) {
$str += chr($num % 256);
$num /= 256;
$str += chr($num);
return $str;
}
It is called like this:
$msg = "\xA7\xA7";
$payload_size = 9 + 1 + strlen($param1) + 1 + strlen($param2);
$msg += append_uint16($msg, $payload_size);
Then I am sending to a socket server like this:
function send_msg($host, $port, $msg) {
$fp = stream_socket_client("tcp://" . $host . ":" . $port, $errno, $errstr, 30);
if (!$fp) {
echo "$errstr ($errno)<br />\n";
} else {
fwrite($fp, $msg);
}
}
But the messages are not correctly formed. I suspect that my string processing is not quite correct. Or maybe I can't use strings in php in this way? Any ideas?

Related

Convert python script to php for dht22 sensor data reading

I would convert this Python code to read DHT22 sensor data in php. I don't know python so I can't convert all functions in the php corrispondent.
The python script is from here (I add numpy library because I was an error without it)
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import socket
import numpy
TCP_ADDR = 'MYIP'
TCP_PORT = 8899
PACK_LEN = 11
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(30)
s.connect((TCP_ADDR, TCP_PORT))
bytes_data = numpy.zeros(PACK_LEN,int)
str_data = s.recv(PACK_LEN) #this should probably have a timeout
hex_data = str_data.encode('hex')
for n in range(0,PACK_LEN): #convert to array of bytes
lower = 2*n
upper = lower + 2
bytes_data[n] = int(hex_data[lower:upper],16)
humid = (((bytes_data[6])<<8)+(bytes_data[7]))/10.0
temp = (((((bytes_data[8])&0x7F)<<8)+(bytes_data[9]))/10.0)
if int(bytes_data[8]) & 0x80: #invert temp if sign bit is set
temp = -1.0* temp
checksum = (int(sum(bytes_data[0:10])) & 0xFF)+1
if checksum == bytes_data[10]:
print "T" + str(temp) + " H" + str(humid)
else:
print "Invalid. :("
It was just a test in php
$fp = fsockopen("192.168.0.12", 8899, $errno, $errstr, 20);
if (!$fp) {
echo "$errstr ($errno)<br />\n";
} else {
fwrite($fp, "\n");
$code = fread($fp, 26);
fclose($fp);
$code = array_shift( unpack('H*', $code) );
echo $code;
}

Cannot get required headers from some IPs and ports to parse song title using ShoutCast protocol

I'm trying to extract song title from live mp3 streams using SC protocol. The php script works fine with some IPs and ports, however with some IPs and ports I cannot get required headers from the response to determine the meta-block frequency, therefore I cannot find the location of the song title in the stream. Here's my code:
<?php
while(true)
{
//close warning messages (re-open for debugging)
error_reporting(E_ERROR | E_PARSE);
//create and connect socket with the parameters entered by the user
$sock = socket_create(AF_INET,SOCK_STREAM,SOL_TCP);
echo "Establishing connection to the given adress...\n";
$fp = fsockopen($argv[1], $argv[2], $errno, $errstr, 10);
if($fp)
{
echo "Connection established.\n";
$result = socket_connect($sock, $argv[1], $argv[2]);
//prepare request
$request = "GET / HTTP/1.1\r\n";
$request .= "Icy-MetaData: 1\r\n\r\n";
//send request
socket_write($sock,$request,strlen($request));
//set sentinel boolean value's initial value
$headers = true;
//put the segment to be parsed into a string variable
$l = socket_read($sock,2048);
$meta = "";
$streamurl = "";
$checkContentType = false;
//Parsing metadata frequency and streamurl from response's headers.
foreach(preg_split("/((\r?\n)|(\r\n?))/", $l) as $line)
{
if(!(strpos($line, "metaint:") === false))
{
$meta = $line;
}
if(!(strpos($line, "icy-url:") === false))
{
$streamurl = $line;
}
if(!strpos($line, "audio/mpeg") === false)
{
$checkContentType = true;
}
}
echo $l;
//Checking if the content of the stream is mpeg or not
if($checkContentType)
{
$pos = strpos($meta, ":");
$interval = intval(substr($meta,$pos+1));
$pos = strpos($streamurl, ":");
$streamurl = substr($streamurl, $pos+1);
$flag = false;
//initialize bytecount to 0
$bytecount = 0;
//Extracting song title using SC protocol
while($headers)
{
$l = socket_read($sock,PHP_NORMAL_READ);
$bytecount++;
if($bytecount == $interval )
{
$headers = false;
$flag = true;
}
if($flag)
{
$len = ord($l);
}
}
//Determining length variable
$len = $len * 16;
$string = socket_read($sock,$len);
$pos2 = strpos($string, "'") + 1;
$pos3 = strpos($string, ";",$pos2) -1;
$songtitle = substr($string, $pos2, ($pos3-$pos2));
//Formatting the log entry
$finalstr = "[".date("c")."]"."[".$streamurl."]".$songtitle."\n";
echo "logged".$finalstr;
//finalize connection
socket_close($sock);
//Writing the requested info to a log file
file_put_contents("log.txt", $finalstr,FILE_APPEND | LOCK_EX);
//waiting 5 minutes
echo "Logging next entry in five minutes. \n";
sleep(300);
}
else
{
echo "Content of the stream is not suitable.\n";
exit;
}
}
else
{
echo "Unable to connect to the given ip and port.\n Exiting...\n";
socket_close($sock);
exit;
}
}
?>
I've never tried to access shoutcast programatically but I've run streaming audio servers in the past. There are actually two different flavours of shoutcast server and I would guess your program is trying to talk to one and these broken servers are the other type.
From the post READING SHOUTCAST METADATA FROM A STREAM:
Turns out that SHOUTcast and Icecast (two of the most popular server
applications for streaming radio) are supposed to be compatible, but
the response message from each server is slightly different.
Full details about the shoutcast protocol: Shoutcast Metadata Protocol

Whois Arin and php

I have a problem with php and whois.arin.net
$whois="whois.arin.net";
$ip="xx.xx.xx.xx";
$sk=fsockopen($whois, 43, $errno, $errstr, 30) or die('Connessione impossibile');
fputs ($sk, $ip."\r\n") or die('Request impossibile');
while (!feof($sk)) {
$info.= fgets ($sk, 2048);
}
$i=explode("\n",$info);
foreach($i as $val){
$descr=explode("\n",$val);
echo $descr[0];
}
The error that appears is
ARIN WHOIS data and services are subject to the Terms of Use
Query terms are ambiguous. The query is assumed to be: n xx-xx-xx-xx
What is the problem?
A very simple PHP whois function that supports ARIN would look like this:
function whois($domain, $server) {
// format input for the specific server
if($server == 'whois.arin.net') {
$domain = "n + $domain";
}
// connect and send whois query
$connection = fsockopen($server, 43, $errno, $errstr, 30);
$request = fputs($connection, $domain . "\r\n");
if(!$connection OR !$request){
return "Error $errno: $errstr.";
}
// get the whois data
$data = '';
while(!feof($connection)){
$data .= fgets($connection);
}
fclose($connection);
return trim($data);
}
Then you can call the function like so:
echo whois('8.8.8.8', 'whois.arin.net');

UDP Streaming transfer from C# application to PHP webpage

I'm trying to code a C# UDP server. It receives a specific ID from the client, and return the song associated with it. The client is a PHP webpage, and stocks the bytes received into a file. Right now I'm doing some tests, trying to simply start a fake lecture of the song (just a javascript alert) when the transfer is at 2048 bytes. But I have plenty of bugs... The PHP page seems to finish the transfer into the file BEFORE having received all the data... The server continue to send bytes but the file is complete, with the good weight and all...
I know I don't have a very good english, so if you don't undersood something, just ask !
Here is the C# code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.IO;
using System.Net.Sockets;
using System.Net;
using System.Data.SQLite;
namespace cdCollector
{
public partial class Streaming : Form
{
private static List<IPAddress> clients_ = new List<IPAddress>();
public Streaming()
{
InitializeComponent();
listen();
}
public class ThreadClient
{
private static UdpClient socket_;
private static IPEndPoint ipepClient_;
private static int noChanson_;
private static SQLiteConnection connexion_;
public void setSocket(ref UdpClient socket) { socket_ = socket; }
public void setIpepClient(ref IPEndPoint ipepClient) { ipepClient_ = ipepClient; }
public void setNoChanson(int noChanson) { noChanson_ = noChanson; }
public void setConnexion(ref SQLiteConnection connexion) { connexion_ = connexion; }
public static void send()
{
try
{
while (Thread.CurrentThread.IsAlive)
{
Chanson uneChanson;
FileStream stream;
byte[] buffer = new byte[1024];
int read;
uneChanson = new Chanson(noChanson_);
uneChanson.load(ref connexion_);
stream = new FileStream("C:\\Users\\Julie\\Documents\\toune.flac", FileMode.Open, FileAccess.Read);
socket_.Send(Encoding.ASCII.GetBytes(stream.Length.ToString()), stream.Length.ToString().Length, ipepClient_);
while ((read = stream.Read(buffer, 0, buffer.Length)) > 0)
socket_.Send(buffer, buffer.Length, ipepClient_);
Console.WriteLine("finished");
}
}
catch (ThreadAbortException tae)
{ }
catch (Exception)
{
Thread.CurrentThread.Abort();
}
}
}
public static void listen()
{
byte[] data = new byte[1024];
IPEndPoint ipepServer = new IPEndPoint(IPAddress.Any, 7575); // IP du serveur
IPEndPoint ipepClient = new IPEndPoint(IPAddress.Any, 0); // IP du client;
UdpClient socket = new UdpClient(ipepServer); // socket serveur
int noChanson;
SQLiteConnection connexion = new SQLiteConnection("Data Source=" + Application.StartupPath + "\\cdCollector.db");
SQLiteCommand command = new SQLiteCommand(connexion);
SQLiteDataReader dr;
Thread thread;
connexion.Open();
while (true)
{
try
{
Console.WriteLine("Waiting for a client...");
data = socket.Receive(ref ipepClient);
Console.WriteLine("Message received from {0}:", ipepClient.ToString());
Console.WriteLine(Encoding.ASCII.GetString(data, 0, data.Length));
command.CommandText = "SELECT KeyLocale FROM AssocKeys WHERE NomTable = 'Chanson' AND KeyWeb = "
+ int.Parse(Encoding.ASCII.GetString(data, 0, data.Length));
dr = command.ExecuteReader();
if (dr.HasRows)
{
dr.Read();
noChanson = dr.GetInt32(0);
dr.Close();
ThreadClient client = new ThreadClient();
client.setConnexion(ref connexion);
client.setIpepClient(ref ipepClient);
client.setNoChanson(noChanson);
client.setSocket(ref socket);
thread = new Thread(new ThreadStart(ThreadClient.send));
thread.Start();
}
else
socket.Send(Encoding.ASCII.GetBytes("Erreur: Chanson introuvable"), ("Erreur: Chanson introuvable").Length, ipepClient);
}
catch (SocketException se)
{
Console.WriteLine("Erreur Socket:" + se.Message);
}
catch (Exception ex)
{
Console.WriteLine("Erreur: " + ex.Message);
}
}
connexion.Close();
}
}
}
And the PHP code:
<?php
session_start();
$address="192.168.2.2";
$read = false;
$port = 7575;
$length = 0;
$started = false;
if (isset($port) and
($socket=socket_create(AF_INET, SOCK_DGRAM, SOL_UDP)) and
(socket_connect($socket, $address, $port)))
{
$text = "Connection successful on IP $address, port $port <br />";
$from = '';
$port = 0;
$length = 0;
socket_send( $socket, $_GET['no'], 1024, MSG_EOR );
socket_recvfrom( $socket, $buf, 1024, 12, $from, $port);
$lengthTotal = $buf;
echo "Taille prévue du fichier: " . $lengthTotal . "<br />";
if( file_exists( "temp" . $_SESSION['ID_Membre'] . ".flac" ) )
unlink("temp" . $_SESSION['ID_Membre'] . ".flac");
$file = fopen("temp" . $_SESSION['ID_Membre'] . ".flac", 'a');
$buf = null;
while( $length < $lengthTotal )
{
$length += socket_recvfrom( $socket, $buf, 1024, 12, $from, $port );
if( $length > 2048 && !$started )
{
?>
<script type="text/javascript">
<!--
alert("Lecture...");
//->
</script>
<?php
$started = true;
}
fputs($file, $buf);
flush();
}
echo "<br />" . $length . "<br />";
fclose($file);
}
else
$text="Unable to connect<pre>".socket_strerror(socket_last_error())."</pre>";
echo $text;
?>
Thanks a lot !
UDP is an inherently unreliable transport. You will need to implement acknowledgements, timeouts, retransmissions and sequence numbers on top of UDP in order to guarantee transmission of all of your data in the expected order, unless your client application can live with dropped packets. I would advise you to consider using TCP sockets instead if you need guaranteed transmission of data between server and client and don't want to have to implement all of this stuff yourself (which might need to include client-side buffering to rearrange out-of-order datagrams). If you want reliability on top of UDP, I would advise you to read a good textbook on the subject (e.g. "Unix Network Programming" by W. Richard Stevens etc.).
Pointers on TCP:
You should take a look at System.Net.Sockets.TcpClient and System.Net.Sockets.TcpListener for the C# side of things and consult the PHP documentation for info on the PHP side of things.
Using TCP sockets isn't really that much different except you'll be using send and recv (or C#/PHP equivalents) instead of send_to and recv_from. Setting up the server side of things is a little more complicated since you need to bind and listen etc. but there are plenty of resources, e.g.:
http://www.switchonthecode.com/tutorials/csharp-tutorial-simple-threaded-tcp-server
Thanks for your help. I changed what you told me, except adding 'b' to the fopen mode because my web server is on Ubuntu. I still receive plenty of errors to tell me that the client connection had to close... It seems like PHP think the download is finished and exit the loop, so it closes the connection of the socket. Also, many minutes after the page have load, the server is still sending data... I never did streaming before so I have difficulties to see where the problem is ...
Here's the new PHP code:
<?php
session_start();
$address="192.168.2.2";
$read = false;
$port = 7575;
$length = 0;
$started = false;
if (isset($port) and
($socket=socket_create(AF_INET, SOCK_DGRAM, SOL_UDP)) and
(socket_connect($socket, $address, $port)))
{
$text = "Connection successful on IP $address, port $port <br />";
$from = '';
$port = 0;
$length = 0;
socket_send( $socket, $_GET['no'], 1024, MSG_EOR );
socket_recvfrom( $socket, $buf, 1024, MSG_WAITALL, $from, $port);
$lengthTotal = $buf;
echo "Taille prévue du fichier: " . $lengthTotal . "<br />";
if( file_exists( "temp" . $_SESSION['ID_Membre'] . ".flac" ) )
unlink("temp" . $_SESSION['ID_Membre'] . ".flac");
$file = fopen("temp" . $_SESSION['ID_Membre'] . ".flac", 'a');
$buf = null;
while( $length !== FALSE && $length < $lengthTotal )
{
$length += socket_recvfrom( $socket, $buf, 1024, 12, $from, $port );
if( $length > 2048 && !$started )
{
?>
<script type="text/javascript">
<!--
alert("Lecture...");
//->
</script>
<?php
$started = true;
}
if( $length == FALSE )
echo "ERREUR";
fputs($file, $buf, $length);
flush();
}
echo "<br />" . $length . "<br />";
fclose($file);
}
else
$text="Unable to connect<pre>".socket_strerror(socket_last_error())."</pre>";
echo $text;
?>
Some points:
1.- socket_recvfrom could return FALSE if there is any error, you can check the error with false === socket_recvfrom.
2.- If you are using a windows server add b to the open mode: $file = fopen("temp" . $_SESSION['ID_Membre'] . ".flac", 'ab'); (you are writing a binary file).
3.- Use as third argument of the fputs function the value returned by the socket_recvfrom function (if this value !== FALSE).
4.- You are using the value 12 (MSG_DONTROUTE | MSG_EOR), try to use 0 or MSG_WAITALL (of course socket_recvfrom is going to wait to receive 1024 bytes).
Your reception loop must be:
$reclen = 0;
while( ($reclen !== FALSE) && ($length < $lengthTotal) )
{
$reclen = socket_recvfrom( $socket, $buf, 1024, 12, $from, $port );
if ($reclen === FALSE)
{
echo "ERREUR";
break;
}
$length += $reclen;
if( $length > 2048 && !$started )
{
?>
<script type="text/javascript">
<!--
alert("Lecture...");
//->
</script>
<?php
$started = true;
}
fputs($file, $buf, $length);
flush();
}
The problem is that you are adding the value returned by socket_recvfrom to $length if the return value is FALSE is going to add 0 to $length, that is the reason why you have to add an additional variable ($reclength).

Using PHP to read a web page with fsockopen(), but fgets is not working

Im using this code here: http://www.digiways.com/articles/php/httpredirects/
public function ReadHttpFile($strUrl, $iHttpRedirectMaxRecursiveCalls = 5)
{
// parsing the url getting web server name/IP, path and port.
$url = parse_url($strUrl);
// setting path to '/' if not present in $strUrl
if (isset($url['path']) === false)
$url['path'] = '/';
// setting port to default HTTP server port 80
if (isset($url['port']) === false)
$url['port'] = 80;
// connecting to the server]
// reseting class data
$this->success = false;
unset($this->strFile);
unset($this->aHeaderLines);
$this->strLocation = $strUrl;
$fp = fsockopen ($url['host'], $url['port'], $errno, $errstr, 30);
// Return if the socket was not open $this->success is set to false.
if (!$fp)
return;
$header = 'GET / HTTP/1.1\r\n';
$header .= 'Host: '.$url['host'].$url['path'];
if (isset($url['query']))
$header .= '?'.$url['query'];
$header .= '\r\n';
$header .= 'Connection: Close\r\n\r\n';
// sending the request to the server
echo "Header is: <br />".str_replace('\n', '\n<br />', $header)."<br />";
$length = strlen($header);
if($length != fwrite($fp, $header, $length))
{
echo 'error writing to header, exiting<br />';
return;
}
// $bHeader is set to true while we receive the HTTP header
// and after the empty line (end of HTTP header) it's set to false.
$bHeader = true;
// continuing untill there's no more text to read from the socket
while (!feof($fp))
{
echo "in loop";
// reading a line of text from the socket
// not more than 8192 symbols.
$good = $strLine = fgets($fp, 128);
if(!$good)
{
echo 'bad';
return;
}
// removing trailing \n and \r characters.
$strLine = ereg_replace('[\r\n]', '', $strLine);
if ($bHeader == false)
$this->strFile .= $strLine.'\n';
else
$this->aHeaderLines[] = trim($strLine);
if (strlen($strLine) == 0)
$bHeader = false;
echo "read: $strLine<br />";
return;
}
echo "<br />after loop<br />";
fclose ($fp);
}
This is all I get:
Header is:
GET / HTTP/1.1\r\n
Host: www.google.com/\r\n
Connection: Close\r\n\r\n
in loopbad
So it fails the fgets($fp, 128);
Is there a reason you aren't using PHP's built-in, enabled-by-default ability to fetch remote files using fopen?
$remote_page = file_get_contents('http://www.google.com/'); // <- Works!
There are also plenty of high-quality third-party libraries, if you need to do something like fetch headers without thinking too hard. Try Zend_Http_Client on for size.
The flaw is here:
$good = $strLine = fgets($fp, 128);
if(!$good)
{
echo 'bad';
return;
}
fgets() returns either a string on success, or FALSE on failure. However, if there was no more data to be returned, fgets() will return the empty string (''). So, both $good and $strLine are set to the empty string, which PHP will happily cast to FALSE in the if() test. You should rewrite as follows:
$strLine = fgets($fp, 128);
if ($strLine === FALSE) { // strict comparison - types and values must match
echo 'bad';
return;
}
There's no need for the double assignment, as you can test $strLine directly.

Categories