I have pretty basic knowledge of PHP sockets and the FIX protocol altogether. I have an account that allows me to connect to a server and retrieve currency prices.
I adapted this code to connect and figure out what I receive back from the remote server:
$host = "the-server.com";
$port = "2xxxx";
$fixv = "8=FIX.4.2";
$clid = "client-name";
$tid = "target-name";
$fp = fsockopen($host, $port, $errno, $errstr, 30);
if (!$fp) {
echo "$errstr ($errno)<br />\n";
} else {
$out = "$fixv|9=70|35=A|49=$clid|56=$tid|34=1|52=20000426-12:05:06|98=0|108=30|10=185|";
echo "\n".$out."\n";
fwrite($fp, $out);
while (!feof($fp)) {
echo ".";
echo fgets($fp, 1024);
}
fclose($fp);
}
and I get nothing back. The host is good because I'm getting an error when I use a random one.
Is the message I'm sending not generating a reply ?
I might not be very good at finding things in Google but I could not find any simple tutorial on how to do this with php (at least nothing that puts together fix and php).
Any help is greatly appreciated.
FIX separator character is actually '\001' not '|', so you have to replace that when sending.
Some links for you:
FIX protocol - formal specs
Onixs FIX dictionary - very useful site for tag lookup
Edit 0:
From that same wikipedia article you mention:
The message fields are delimited using the ASCII 01 character.
...
Example of a FIX message : Execution Report (Pipe character is used to represent SOH character) ...
Edit 1:
Couple more points:
Tag 9 holds message length without tags 8 (type), 9 (length), and 10 (checksum).
Tag 10, checksum, has to be a modulo 256 sum of ASCII values of all message characters including all SOH separators, but not including the tag 10 itself (I know, it's stupid to have checksums on top of TCP, but ...)
The issue is the use of fgets(...), it is expecting a \n which does not exists in this FIX protocol.
On top of that, an expected length of 1024 is specified, which is a length that the response is unlikely to exceed.
To cap it off, since the server doesn't terminate the connection, fgets(...) hangs there "forever"
Related
Im connecting to a DMX controller using fsockopen. (Or even telnet via putty)#
And it sends the following CHAR at the end of a command. I cannot for the life of me figure out what it is...
Their documentation doesnt say annoyingly and i need to use it as the "end of stream" as the return byte count varies.
Putty shows : ▒
Web browser shows as : ?
Hex editor shows as (FF) ÿ
What one earth could it be?
My code:
<?php
$fp = fsockopen("localhost", "3333");
fputs($fp,"FSBC017000");
$content = stream_get_line($fp, 10000, "**<Whatever that char is?>**");
echo $content;
?>
Thanks to anyone in advance. Brain is broken.
Three days ago I started making a simple app to send SMS. I already tested it and it works in GSM CSCS mode, but when I switch it to UCS2 it doesn't show the Cyrillic letters
<?php
error_reporting(E_ALL);
$fp = fopen("/dev/ttyUSB0", 'w+');
$msg = strtoupper(bin2hex(mb_convert_encoding("Тест", "UCS-2", "UTF-8")));
$number_raw = "+359000000000";
$number = bin2hex(mb_convert_encoding($number_raw, "UCS-2", "UTF-8"));
echo $number."<br>";
echo $msg;
$debug = false;
if(!$fp || $debug){
//echo "Can not open!";
}else{
fwrite($fp, "AT+CMGF=1".chr(13)); // OK
sleep(5);
fwrite($fp, 'AT+CSCS="UCS2"'.chr(13)); // OK
sleep(5);
fwrite($fp, 'AT+CMGS="'.$number.'"'.chr(13)); // OK
sleep(5);
fwrite($fp, $msg.chr(26)); // ERROR 500
echo "<br>Sent";
}
?>
Number and message are encoded properly according to this source: http://www.columbia.edu/kermit/ucs2.html
When the message is sent, I receive it (so the encoding of the number is correct) but the content isn't shown properly.
https://imgur.com/a/cCaTU
What are possible causes for this behaviour and could it be my PHP file encoding? Also why is linux finding 3 GSM tty devices?
After you have removed all the horrible sleep calls and implemented proper final response parsing, then you need fix the parsing for waiting for the "\r\n> " response of AT+CMGS.
Without any of that fixed, character set encoding trouble is a very minor problem. When you run AT+CSCS="UCS2" every single string will be encoded by the modem that way and must be encoded that way by you until eternity (or another character set is selected), so for instance to switch from UCS2 to UTF-8 would be AT+CSCS="005500540046002D0038" and not AT+CSCS="UTF-8".
I'm using fsockopen on a small cronjob to read and parse feeds on different servers. For the most past, this works very well. Yet on some servers, I get very weird lines in the response, like this:
<language>en</language>
<sy:updatePeriod>hourly</sy:updatePeriod>
<sy:updateFrequency>1</sy:updateFrequency>
11
<item>
<title>
1f
July 8th, 2010</title>
<link>
32
http://darkencomic.com/?p=2406</link>
<comments>
3e
But when I open the feed in e.g. notepad++, it works just fine, showing:
<language>en</language>
<sy:updatePeriod>hourly</sy:updatePeriod>
<sy:updateFrequency>1</sy:updateFrequency>
<item>
<title>July 8th, 2010</title>
<link>http://darkencomic.com/?p=2406</link>
<comments>
...just to show an excerpt. So, am I doing anything wrong here or is this beyond my control? I'm grateful for any idea to fix this.
Here's part of the code I'm using to retrieve the feeds:
$fp = #fsockopen($url["host"], 80, $errno, $errstr, 5);
if (!$fp) {
throw new UrlException("($errno) $errstr ~~~ on opening ".$url["host"]."");
} else {
$out = "GET ".$path." HTTP/1.1\r\n"
."Host: ".$url["host"]."\r\n"
."Connection: Close\r\n\r\n";
fwrite($fp, $out);
$contents = '';
while (!feof($fp)) {
$contents .= stream_get_contents($fp,128);
}
fclose($fp);
This looks like HTTP Chunked transfer encoding -- which is a way HTTP has of segmenting a response into several small parts ; quoting :
Each non-empty chunk starts with the
number of octets of the data it embeds
(size written in hexadecimal) followed
by a CRLF (carriage return and line
feed), and the data itself. The chunk
is then closed with a CRLF. In some
implementations, white space
characters (0x20) are padded between
chunk-size and the CRLF.
When working with fsockopen and the like, you have to deal with the HTTP Protocol yourself... Which is not always as easy as one might think ;-)
A solution to avoid having to deal with such stuff would be to use something like curl : it already knows the HTTP Protocol -- which means you won't have to re-invent the whell ;-)
I don't see anything strange that could cause that kind of behaviour. Is there any way you can use cURL to do this for you? It might solve the problem altogether :)
I read some URL with fsockopen() and fread(), and i get this kind of data:
<li
10
></li>
<li
9f
>asd</li>
d
<li
92
Which is totally messed up O_O
--
While using file _ get _ contents() function i get this kind of data:
<li></li>
<li>asd</li>
Which is correct! So, what the HELL is wrong? i tried on my windows server and linux server, both behaves same. And they dont even have the same PHP version.
--
My PHP code is:
$fp = #fsockopen($hostname, 80, $errno, $errstr, 30);
if(!$fp){
return false;
}else{
$out = "GET /$path HTTP/1.1\r\n";
$out .= "Host: $hostname\r\n";
$out .= "Accept-language: en\r\n";
$out .= "Connection: Close\r\n\r\n";
fwrite($fp, $out);
$data = "";
while(!feof($fp)){
$data .= fread($fp, 1024);
}
fclose($fp);
Any help/tips is appreciated, been wondering this whole day now :/
Oh, and i cant use fopen() or file _ get _ contents() because the server where my script runs doesnt have fopen wrappers enabled > __ <
I really want to know how to fix this, just for curiousity. and i dont think i can use any extra libraries on this server anyways.
About your "strange data" problem, this might be because the server you are requesting data from is transferring it in chunked mode.
You can take a look at the HTTP headers, when calling the same URL in your browser ; one of those headers might be like this :
Transfer-encoding: chunked
Quoting wikipedia's article on that matter :
Each non-empty chunk starts with the
number of octets of the data it embeds
(size written in hexadecimal) followed
by a CRLF (carriage return and line
feed), and the data itself. The chunk
is then closed with a CRLF. In some
implementations, white space
characters (0x20) are padded between
chunk-size and the CRLF.
The last chunk is a single line,
simply made of the chunk-size (0),
some optional padding white spaces and
the terminating CRLF. It is not
followed by any data, but optional
trailers can be sent using the same
syntax as the message headers.
The message is finally closed by a
final CRLF combination.
This looks close to what you are getting... So I'm guessing this is the problem.
As far as I remember, curl knows how to deal with that -- so, the easy way would be to use curl instead of fsockopen and the like
And using curl is often a better idea that using sockets : it will deal with many problems you might encounter ; like this one ;-)
Anoter idea, if you don't have curl enabled on your server, would be to use some already existing library based on fsockopen -- hoping it would take care of those kind of things for you already.
For instance, I've worked with Snoopy a couple of times ; maybe it ealready knows how to deal with that ?
(Not sure : you'll have to test by yourself -- or take a look at the documentation to know if this is OK)
Still, if you want to deal with the mysteries of the HTTP protocol by yourself... Well, I wish you luck !
You probably want to use cURL.
<?php
// create a new cURL resource
$ch = curl_init();
// set URL and other appropriate options
curl_setopt($ch, CURLOPT_URL, "http://www.example.com/");
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// grab URL and pass it to the browser
$output = curl_exec($ch);
// close cURL resource, and free up system resources
curl_close($ch);
?>
With fsockopen(), you get the raw TCP data, not the HTTP contents. I assume you also see the HTTP headers, right? If it's in chunked encoding, you will get all the chunk headers.
This is a known issue. Someone posted a solution here on how to remove chunk headers.
I am receiving packets sent to my server through UDP. I am using socket_read to read the data and it is coming along just fine. I have run into an error however. The length parameter to socket_read in my case is NOT always the same. The length of the data can range anywhere from 50-150 bytes. One thing that remains constant is that the data set is ended with a \x00 byte. How would I get the read function to always read until encountering this byte? I have already tried PHP_NORMAL_READ flag, but the docs say it only ends at \n or \r which really isn't what I want (tried it it doesn't work for my data). At the same time, the php page for socket_read states in the length parameter description that,
The maximum number of bytes read is
specified by the length parameter.
Otherwise you can use \r, \n, or \0 to
end reading (depending on the type
parameter, see below).
The type says nothing about the /0 byte. Its like a piece of documentation is missing. What I need is a function that will either let me specify a delimiter for my data, will automatically read all the data from the socket that is available. There might be a solution in the socket_recv function but its undocumented and I don't know how it works.
Thanks in advance.
If I understand correctly, you want to read data from a socket until there is no more data to read, with the problem being that the amount of data is variable and you don't know when to stop.
According to the relevant manual page (http://php.net/socket_read):
Note: socket_read() returns a zero
length string ("") when there is no
more data to read.
You should be able to deal with variable-length data by reading byte-by-byte until you hit a zero-length string:
while (($currentByte = socket_read($socket, 1)) != "") {
// Do whatever you wish with the current byte
}
Hav you tried something like this:
do {
echo socket_read($handle,1024);
$status = socket_get_status($handle);
} while($status['unread_bytes']);
Application dealing with the read payload will need to recognize when you have reached "end of record" for whatever application message you are passing. Expect arbitrary length on read.
Careful with use of UDP, as you can not guarantee order of packets read are order sent by peer either, if you are trying to stream several reads into a message. Recommend use of TCP socket in this case.
Came across another approach that might just work in your case:
<?php
function tftp_fetch($host, $filename)
{
$socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
// create the request packet
$packet = chr(0) . chr(1) . $filename . chr(0) . 'octet' . chr(0);
// UDP is connectionless, so we just send on it.
socket_sendto($socket, $packet, strlen($packet), 0x100, $host, 69);
$buffer = '';
$port = '';
$ret = '';
do
{
// $buffer and $port both come back with information for the ack
// 516 = 4 bytes for the header + 512 bytes of data
socket_recvfrom($socket, $buffer, 516, 0, $host, $port);
// add the block number from the data packet to the ack packet
$packet = chr(0) . chr(4) . substr($buffer, 2, 2);
// send ack
socket_sendto($socket, $packet, strlen($packet), 0, $host, $port);
// append the data to the return variable
// for large files this function should take a file handle as an arg
$ret .= substr($buffer, 4);
}
while(strlen($buffer) == 516); // the first non-full packet is the last.
return $ret;
}
?>
The most interesting part about this approach is the:
do
...
while(strlen($buffer) == 516); // the first non-full packet is the last.