I have process on server which acts as WebSocket server (not written in Ratchet). I want to be able to send data to this process using PHP (as client).
I found a lot of examples to send as TCP like this:
<?php
$addr = gethostbyname("localhost");
$client = stream_socket_client("tcp://$addr:8887", $errno, $errorMessage);
if ($client === false) {
throw new UnexpectedValueException("Failed to connect: $errorMessage");
}
fwrite($client, "GET / HTTP/1.0\r\nHost: localhost\r\nAccept: */*\r\n\r\n");
echo stream_get_contents($client);
?>
All I need I to send message to the process and close the connection. The result that I expect is the result from the webSocket will be later printed or "echo" to the PHP page.
Is there a way to make it work with curl in php?
I have found this code on github, (I can't find the exact repo where I got it from because I have looked and tried a lot of them)
<?php
class WebsocketClient {
private $_Socket = null;
public function __construct($host, $port) {
$this->_connect($host, $port);
}
public function __destruct() {
$this->_disconnect();
}
public function sendData($data) {
// send actual data:
fwrite($this->_Socket, "\x00" . $data . "\xff") or die('Error:' . $errno . ':' . $errstr);
$wsData = fread($this->_Socket, 2000);
$retData = trim($wsData, "\x00\xff");
return $retData;
}
private function _connect($host, $port) {
$key1 = $this->_generateRandomString(32);
$key2 = $this->_generateRandomString(32);
$key3 = $this->_generateRandomString(8, false, true);
$header = "GET /echo HTTP/1.1\r\n";
$header.= "Upgrade: WebSocket\r\n";
$header.= "Connection: Upgrade\r\n";
$header.= "Host: " . $host . ":" . $port . "\r\n";
$header.= "Origin: http://localhost\r\n";
$header.= "Sec-WebSocket-Key1: " . $key1 . "\r\n";
$header.= "Sec-WebSocket-Key2: " . $key2 . "\r\n";
$header.= "\r\n";
$header.= $key3;
$this->_Socket = fsockopen($host, $port, $errno, $errstr, 2);
fwrite($this->_Socket, $header) or die('Error: ' . $errno . ':' . $errstr);
$response = fread($this->_Socket, 2000);
/**
* #todo: check response here. Currently not implemented cause "2 key handshake" is already deprecated.
* See: http://en.wikipedia.org/wiki/WebSocket#WebSocket_Protocol_Handshake
*/
return true;
}
private function _disconnect() {
fclose($this->_Socket);
}
private function _generateRandomString($length = 10, $addSpaces = true, $addNumbers = true) {
$characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"§$%&/()=[]{}';
$useChars = array();
// select some random chars:
for ($i = 0; $i < $length; $i++) {
$useChars[] = $characters[mt_rand(0, strlen($characters) - 1)];
}
// add spaces and numbers:
if ($addSpaces === true) {
array_push($useChars, ' ', ' ', ' ', ' ', ' ', ' ');
}
if ($addNumbers === true) {
array_push($useChars, rand(0, 9), rand(0, 9), rand(0, 9));
}
shuffle($useChars);
$randomString = trim(implode('', $useChars));
$randomString = substr($randomString, 0, $length);
return $randomString;
}
}
$WebSocketClient = new WebsocketClient('localhost', 8887);
echo $WebSocketClient->sendData("MyUserNameFromPHP");
unset($WebSocketClient);
?>
Out of 7 php websocket clients that I tried, this is the only one that I was able to work with.
It doesn't requires any external files or frameworks.
This is simple implementation for executing short command that doesn't require persistent connection to webSocket server.
I hope it helps you guys , and you will save some time !!!
Related
I connect to the Minecraft server via tcp, how do I use a proxy server
I know how to use a proxy for HTTP requests, but I don’t really understand how to do it for TCP
$data = "\x00";
$data .= makeVarInt($proto);
$data .= pack('c', strlen($ip)) . $ip;
$data .= pack('n', $port);
$data .= "\x02";
$handshake = pack('c', strlen($data)) . $data;
$nick = generateRandomString(5)."_RAGE_". generateRandomString(5);
//Create TCP socket
$socket = #stream_socket_client("tcp://$ip:$port", $errno, $errstr, 10);
//Check for errors
if ($errno > 0) {
echo "ERROR: " . $errstr . PHP_EOL;
continue;
}
//Send login handshake packet
fwrite($socket, $handshake);
//Make login start packet
$data = "\x00";
$data .= pack('c', strlen($nick)) . $nick;
$data = pack('c', strlen($data)) . $data;
//Send login start packet
fwrite($socket, $data);
I am using Mailchimp api 1.3 php wrapper. The problem is that a server where my customer hosts a site will cache response, it won't even make api call. The exact the same code works with me and other customers:
$api = new MCAPI($apiKey);
$doubleOptin = false;
$mergeVar = array(
'FNAME' => '',
'LNAME' => ''
);
$api->listSubscribe($listId, $email, $mergeVar, 'html', $doubleOptin);
print_r($api);
method listSubscribe() calls method callServer where I guess is the problem:
$payload = "POST " . $this->apiUrl["path"] . "?" . $this->apiUrl["query"] . "&method=" . $method . " HTTP/1.0\r\n";
$payload .= "Host: " . $host . "\r\n";
$payload .= "User-Agent: MCAPI/" . $this->version ."\r\n";
$payload .= "Content-type: application/x-www-form-urlencoded\r\n";
$payload .= "Content-length: " . strlen($post_vars) . "\r\n";
$payload .= "Connection: close \r\n\r\n";
$payload .= $post_vars;
ob_start();
if ($this->secure){
$sock = fsockopen("ssl://".$host, 443, $errno, $errstr, 30);
} else {
$sock = fsockopen($host, 80, $errno, $errstr, 30);
}
if(!$sock) {
$this->errorMessage = "Could not connect (ERR $errno: $errstr)";
$this->errorCode = "-99";
ob_end_clean();
return false;
}
$response = "";
fwrite($sock, $payload);
stream_set_timeout($sock, $this->timeout);
$info = stream_get_meta_data($sock);
while ((!feof($sock)) && (!$info["timed_out"])) {
$response .= fread($sock, $this->chunkSize);
$info = stream_get_meta_data($sock);
}
var_dump($response); exit;
Does anybody have any idea why fsockopen and fwrite never sends call to Mailchimp? Weird thing is that I can actually read $response, but it is always the same from cache.
If the code works for you and there is some query caching then you could try to add a timestamp to the request.
"&time=".time()
This way you always have a "fresh" request.
This is my code and I am using as external file include in my code as external file. When new user post this code is run but not sent message on all numbers that stored in database:
Error is:
Warning: fsockopen() [function.fsockopen]: unable to connect to :0
(Failed to parse address "") in C:\xampp\htdocs\funsmss\location\sendsms.php
Failed to parse address "" (0)
Here's the code:
<?php
$sql = "select * from subscribe where type ='$cat' and city ='$city'";
$query = mysql_query($sql);
if ($query != null) {
while ($row = mysql_fetch_array($query)) {
$name = $row['name'];
$phoneNum = $row['fone'];
$message = "Hi ".$name.", now you can buy your product.";
ozekiSend($phoneNum, $message);
// for debugging, try the following line
//echo ozekiSend($phoneNum, $message, true);
}
}
########################################################
# Login information for the SMS Gateway
########################################################
$ozeki_user = "admin";
$ozeki_password = "abc123";
$ozeki_url = "http://127.0.0.1:9501/api?";
########################################################
# Functions used to send the SMS message
########################################################
function httpRequest($url)
{
$pattern = "/http...([0-9a-zA-Z-.]*).([0-9]*).(.*)/";
preg_match($pattern, $url, $args);
$in = "";
$fp = fsockopen("$args[1]", $args[2], $errno, $errstr, 30);
if (!$fp) {
return("$errstr ($errno)");
} else {
$out = "GET /$args[3] HTTP/1.1\r\n";
$out .= "Host: $args[1]:$args[2]\r\n";
$out .= "User-agent: Ozeki PHP client\r\n";
$out .= "Accept: */*\r\n";
$out .= "Connection: Close\r\n\r\n";
fwrite($fp, $out);
while (!feof($fp)) {
$in.=fgets($fp, 128);
}
}
fclose($fp);
return($in);
}
function ozekiSend($phone, $msg, $debug = false)
{
global $ozeki_user, $ozeki_password, $ozeki_url;
$url = 'username=' . $ozeki_user;
$url.= '&password=' . $ozeki_password;
$url.= '&action=sendmessage';
$url.= '&messagetype=SMS:TEXT';
$url.= '&recipient=' . urlencode($phone);
$url.= '&messagedata=' . urlencode($msg);
$urltouse = $ozeki_url . $url;
if ($debug === true) {
echo "Request: <br>$urltouse<br><br>";
}
//Open the URL to send the message
$response = httpRequest($urltouse);
if ($debug === true) {
echo "Response: <br><pre>" .
str_replace(array("<", ">"), array("<", ">"), $response) .
"</pre><br>";
}
return($response);
}
?>
basically I am trying to get peers in php from a udp torrent tracker.
Purpose is analyzing traffic in different regions.
So I don't need to download the torrent just get the peer list and announce again to get a different set. I tried to use PHP
I have picked a open-source code that scrapes udp torrents and modified it.
here's the code
require_once(dirname(__FILE__) . '/tscraper.php');
class udptscraper extends tscraper{
/* $url: Tracker url like: udp://tracker.tld:port or udp://tracker.tld:port/announce
$infohash: Infohash string or array (max 74 items). 40 char long infohash.
*/
public function scrape($url,$infohash){
if(!is_array($infohash)){ $infohash = array($infohash); }
foreach($infohash as $hash){
if(!preg_match('#^[a-f0-9]{40}$#i',$hash)){ throw new ScraperException('Invalid infohash: ' . $hash . '.'); }
}
if(count($infohash) > 74){ throw new ScraperException('Too many infohashes provided.'); }
if(!preg_match('%udp://([^:/]*)(?::([0-9]*))?(?:/)?%si', $url, $m)){ throw new ScraperException('Invalid tracker url.'); }
$tracker = 'udp://' . $m[1];
$port = isset($m[2]) ? $m[2] : 80;
$transaction_id = mt_rand(0,65535);
$fp = fsockopen($tracker, $port, $errno, $errstr);
if(!$fp){ throw new ScraperException('Could not open UDP connection: ' . $errno . ' - ' . $errstr,0,true); }
stream_set_timeout($fp, $this->timeout);
$current_connid = "\x00\x00\x04\x17\x27\x10\x19\x80";
//Connection request
$packet = $current_connid . pack("N", 0) . pack("N", $transaction_id);
fwrite($fp,$packet);
//Connection response
$ret = fread($fp, 16);
if(strlen($ret) < 1){ throw new ScraperException('No connection response.',0,true); }
if(strlen($ret) < 16){ throw new ScraperException('Too short connection response.'); }
$retd = unpack("Naction/Ntransid",$ret);
if($retd['action'] != 0 || $retd['transid'] != $transaction_id){
throw new ScraperException('Invalid connection response.');
}
$current_connid = substr($ret,8,8);
//ANNOUNCE request
$hashes = '';
$pid ='O5214m2Y0z6178K1z090';
$key = mt_rand(0,65535);
$down =mt_rand(0,12345);
$left =mt_rand(0,12345);
$upped =mt_rand(0,12345);
$transaction_id = mt_rand(0,65535);
$event = 2;
$socket = socket_create_listen (19624);
foreach($infohash as $hash){ $hashes .= pack('H*', $hash); }
$packet = $current_connid . pack("N", 1) . pack("N", $transaction_id) . $hashes . pack("N", $pid) . pack("N", $down) . pack("N", $left) . pack("N", $upped) . pack("N", 0) . pack("N", 0) . pack("N", $key) . pack("N", -1) . pack("N", 19624);
fwrite($fp,$packet);
//ANNOUNCE response
$readlength = 20 + (6 * count($infohash));
$ret = fread($fp, $readlength);
echo $ret;
if(strlen($ret) < 1){ throw new ScraperException('No .',0,true); }
if(strlen($ret) < 8){ throw new ScraperException('Too short response.'); }
$retd = unpack("Naction/Ntransid",$ret);
// Todo check for error string if response = 3
if($retd['action'] != 1 || $retd['transid'] != $transaction_id){
throw new ScraperException('Invalid scrape response.');
}
if(strlen($ret) < $readlength){ throw new ScraperException('Too short scrape response.'); }
$torrents = array();
$index = 8;
foreach($infohash as $hash){
$retd = unpack("Ninterval/Nleechers/Nseeders/Nipaddr/NTCP",substr($ret,$index));
print_r($retd);
$retd['infohash'] = $hash;
$torrents[$hash] = $retd;
$index = $index + 12;
}
return($torrents);
}
}
try{
$timeout = 2;
$scraper = new udptscraper($timeout);
$ret = $scraper->scrape('udp://tracker.openbittorrent.com:80/announce',array('8B60D5838A2CE34294AF9E49FF990C5BEC6C61B1'));
//print_r($ret);
}catch(ScraperException $e){
echo('Error: ' . $e->getMessage() . "<br />\n");
echo('Connection error: ' . ($e->isConnectionError() ? 'yes' : 'no') . "<br />\n");
}
?>
I am using only 1 HASH value
Some help please.
EDIT : The tracker server sometimes send the response message with peer list of peers replaced by a 6 bytes per peer. The first 4 bytes are the host IP, and the last 2bytes are port number. You should parse them to communicate with peers for pieces.
I think theory(specs) is probably not a fact. all specs about Bittorent from Internet become outdated. It might be impossible to check whether announce request is correct by just following the spec.
I recommend you to try using Wireshark. Capture packets that common Bittorent-client sends, and then check how common Bittornet client works. Compare announce request that your php code send, to one common client sends.
Actually, I'm trying to implement Bittorent client in C. I had a hard time communicating with a tracker server, since not specifying compact field in request message. But most specs says compact field in announce request is optional.
Try using wireshark. then compare two requests(your request and the other that common bittorent sends.)
I am trying to develop a websocket server in php.
Here is what I have done so far :
(server part)
$server = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_option($server, SOL_SOCKET, SO_REUSEADDR, 1);
socket_bind($server, "localhost", 10000);
socket_listen($server);
$client = socket_accept($server);
$message = socket_read($client, 5000);
$matches = array();
preg_match('#Sec-WebSocket-Key: (.*)\r\n#', $message, $matches);
$new_key = new_key($matches[1]);
$new_message = "HTTP/1.1 101 Switching Protocols\r\n";
$new_message .= "Upgrade: websocket\r\n";
$new_message .= "Connection: Upgrade\r\n";
$new_message .= "Sec-WebSocket-Accept: " . $new_key . "\r\n\r\n";
socket_write($client, $new_message, strlen($new_message));
$new_message = "Test message !";
socket_write($client, $new_message, strlen($new_message));
function new_key($key)
{
$key .= "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
$key = sha1($key);
$new_key = '';
for ($i = 0; $i < strlen($key); $i+=2)
{
$new_key .= chr(intval($key[$i] . $key[$i+1], 16));
}
$new_key = base64_encode($new_key);
return $new_key;
}
/* End of file server.php */
(client part)
window.onload = function() {
var ws = new WebSocket('ws://localhost:10000');
ws.onopen = function() {
alert('Connection open !');
setInterval(function() {
ws.send('lol');
}, 1000);
}
ws.onclose = function() {
alert('WebSocket close !');
}
ws.onmessage = function(e) {
alert(e.data);
}
ws.onerror = function(e) {
alert('Error');
}
};
The first socket_write works perfectly (for the handshake) and the open event is triggered correctly. But the second socket_write doesn't work. I tried to do a ws.send on the open event with a second socket_read in server part, it doesn't work neither.
Thank you if you have an idea !
I think it is a INVALID_STATE_ERR: DOM Exception 11 meaning a sync problem. Try this in your client:
var test = function(){
var myWebSocket = new WebSocket('ws://localhost:10000');
myWebSocket.onopen = function(e){
alert('connection open');
this.send('test1');
this.send('test2');
}
myWebSocket.onmessage = function(e){ alert('message ' + e.data) };
myWebSocket.onclose = function(e){ alert('connection closed'); this.close(); };
myWebSocket.send('test3');
};
test3 will fail because it is an asynchronous websocket.
I had a similar issue. After checking out this project over here https://github.com/srchea/PHP-Push-WebSocket I noticed a function called "encode" in this file https://github.com/srchea/PHP-Push-WebSocket/blob/master/lib/Server.class.php before sending the message.
So try to change this
socket_write($client, $new_message, strlen($new_message));
$new_message = "Test message !";
socket_write($client, $new_message, strlen($new_message));
to this
socket_write($client, $new_message, strlen($new_message));
$new_message = "Test message !";
socket_write($client, chr(129) . chr(strlen($new_message)) ."". $new_message);