Query DHT Server - php

I'm trying to make a simple query to a DHT server.
I'm trying to make a simple simple example to test queries to the servers, but I don't get a response from the server in any form...
Little example:
$socket = fsockopen("udp://router.bittorrent.com", 6881, $errno, $errstr, 3);
fwrite($socket, 'p'); $Head = fread($socket, 4);
$CheckStatus = socket_get_status($socket);
if($CheckStatus["unread_bytes"] == 0)
{
return 0;
}
$do = 1;
while($do)
{
$str = fread($socket,1);
$stats .= $str;
$status = socket_get_status($socket);
if($status["unread_bytes"] == 0)
{
$do = 0;
}
}
fclose($socket);
The info about the queries in DHT server is here: http://www.bittorrent.org/beps/bep_0005.html#dht-queries
But I don't understand how make this with PHP.
Is this possible? What's the problem with my code?

As the8472 mentions, your client is sending p, which is not a valid query. To see valid query formats, look here: bep 005

Related

Need help in PHP with non-blocking sockets for IRC bot

I've been learning to write an IRC bot in PHP and it's been working great but the blocking has become an issue because I want certain actions to happen based on a timer. I've been trying to learn about non-blocking but im struggling to get it working correctly. Can anyone have a look at my code and let me know where im going wrong?
<?php
$ircPort = 6667;
$ircBotNick = "CaveBot";
$ircBotPrefix = "!";
$ircBotPass = "";
$ircBotIdent = "CaveBot";
$ircBotRealName = "Cavemans Bot Script";
$ircDefaultChannel = "#CaveDen";
$ircServer = "localhost";
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
$error = socket_connect($socket, $ircServer, $ircPort);
socket_set_nonblock($socket);
while (1) {
$read = array($socket);
$write = NULL;
$except = NULL;
$num_changed_sockets = socket_select($read, $write, $except, 0);
if ($num_changed_sockets === false) {
// Error handling
} else if ($num_changed_sockets > 0) {
$data = socket_read($socket, 1024, PHP_NORMAL_READ);
echo $n . " - ";
$d = explode(' ', $data);
$d = array_pad($d, 10, '');
if ($d[0] === 'PING') {
socket_write($socket, "PONG $d[1]");
}
print_r($data);
}
}
I think i'm not handling the read/incoming data correctly. It starts to connect but freezes up after a message from the server about looking up hostname. When I use similar code that has blocking, i get a ping and welcome message after the lookup.

How to do an IMAP search based on "Delivered-To" header (or how to use the gmail imap extension?)

I need to search gmail messages (google apps for work) via imap/php. However, imap_search criterias are not enough to catch the messages in question.
The code I use looks like this:
$imap = imap_open("{imap.gmail.com:993/imap/ssl}Label1/label2", $user_email, $user_passwd);
$msg_list = imap_search($imap, 'TEXT "Delivered-To: username+label#gmail.com"');
imap_close($imap);
The imap_search call didn't return anything.
I did some research, it seems I can filter messages based on "Delivered-To" header field via the gmail search syntax X-GM-RAW, but I just couldn't achieve this, I tried all these calls (and more):
$msg_list = imap_search($imap, 'UID SEARCH X-GM-RAW "deliveredto:username+label#gmail.com"');
$msg_list = imap_search($imap, 'SEARCH X-GM-RAW "deliveredto:username+label#gmail.com"');
$msg_list = imap_search($imap, 'X-GM-RAW "deliveredto:username+label#gmail.com"');
But it didn't work, anyone knows what's wrong with my code?
OK, either I don't know how to ask questions, SOers are busy, or I'm asking difficult questions.
Anyway, now I know the imap_* functions built-into PHP don't handle direct IMAP commands, so I had to either use the zend framework (too heavy for my needs), or directly connect to imap via sockets.
I chose the second option, the code is as follow (code stolen from here and adapted for my own needs), in case someone needs it:
<?php
// Open a socket
if (!($fp = fsockopen('ssl://imap.gmail.com', 993, $errno, $errstr, 15))) die("Could not connect to host");
// Set timout to 1 second
if (!stream_set_timeout($fp, 1)) die("Could not set timeout");
// Fetch first line of response and echo it
echo fgets($fp);
// =========================================
fwrite($fp, "0001 LOGIN user.name#gmail.com YOUR_PASSWORD_HERE_WITHOUT_QUOTES\r\n");
// ie. fwrite($fp, "0001 LOGIN super.dude#gmail.com pass123\r\n");
// Keep fetching lines until response code is correct
while ($line = trim(fgets($fp)))
{
echo "Line = [$line]\n";
$line = preg_split('/\s+/', $line, 0, PREG_SPLIT_NO_EMPTY);
$code = $line[0];
if (strtoupper($code) == '0001') {
break;
}
}
// =========================================
fwrite($fp, "0002 SELECT Inbox\r\n");
// Keep fetching lines until response code is correct
while ($line = trim(fgets($fp)))
{
echo "Line = [$line]\n";
$line = preg_split('/\s+/', $line, 0, PREG_SPLIT_NO_EMPTY);
$code = $line[0];
if (strtoupper($code) == '0002') {
break;
}
}
// =========================================
fwrite($fp, "0003 SEARCH X-GM-RAW \"deliveredto:user.name+someLabel#gmail.com\"\r\n");
// Keep fetching lines until response code is correct
while ($line = fgets($fp))
{
echo "Line = [$line]\n";
$line = preg_split('/\s+/', $line, 0, PREG_SPLIT_NO_EMPTY);
$code = $line[0];
if (strtoupper($code) == '0003') {
break;
}
}
fclose($fp);
echo "I've finished!";
?>
Voila! Just copy and paste and now you have access to the gmail syntax right from PHP! (Hey vote if you like :p)

How to read multiple lines from socket stream?

I want to retrieve email from gmails' imap server but the problem is that the responses from the server are multiple lines long (as demonstrated here) and fgets only retrieves one line.
I've tried using fgets, fread, socket_read but none of them work so either i'm using the wrong method or using the methods incorrectly. I also tried this tutorial but it didn't work either. I would appreciate if someone could help me with this.
Thanks and i'm really sorry if this is an amateur question.
Code:
<?php
$stuff = fsockopen('ssl://imap.gmail.com',993);
$reply = fgets($stuff,4096);
echo 'connection: '.$reply.'<br/>';
$request = fputs($stuff,"a1 LOGIN MyUserName Password\r\n");
$receive = socket_read($stuff, 4096);
echo 'login: '.$receive.'<br/>';
$request = fputs($stuff,"a2 EXAMINE INBOX\r\n");
$reply = '';
while(!feof($stuff))
$reply .= fread($stuff, 4096);
echo $reply;
/*
$request = fputs($stuff,'a3 FETCH 1 BODY[]\r\n');
$reply = fgets($stuff);
echo $reply;
*/
?>
Max's answer below works. This is my implementation of it.
private function Response($instructionNumber)
{
$end_of_response = false;
while (!$end_of_response)
{
$line = fgets($this->connection,self::responseSize);
$response .= $line.'<br/>';
if(preg_match("/$instructionNumber (OK|NO|BAD)/", $response,$responseCode))
$end_of_response = true;
}
return array('code' => $responseCode[1],
'response'=>$response);
}
Generally, you know to stop reading when you get the OK/BAD/NO response for the tag you sent. If you send a1 LOGIN ... you stop when you get a1 OK/BAD/NO ....
It's been a while since I wrote PHP, and I don't know that much about IMAP, but if it's anything like NNTP, your code would look a bit like this (wrote it in the SO editor, might be bugged) :
$buffer = '';
function read_line($socket) {
global $buffer;
while (strpos($buffer, "\n") === false)
$buffer .= fread($socket, 1024);
$lineEnd = strpos($buffer, "\n");
$line = substr($buffer, 0, $lineEnd-1);
$buffer = substr($buffer, $lineEnd);
return $line;
}
function send_line($socket, $line) {
fwrite($socket, $line);
}
$socket = fsockopen('ssl://imap.gmail.com',993);
$welcome = read_line($socket);
send_line("a1 LOGIN MyUserName Password\r\n");
$reply = read_line($socket);
send_line("a2 EXAMINE INBOX\r\n");
while (($reply = trim(read_line($socket))) != '.') {
echo $reply.PHP_EOL;
}
echo "Done";
The basic concepts are :
Always buffer all incoming data. PHP doesn't handle lines very well, so do the splitting yourself.
Don't randomly read everything, but know what to expect. You expect one welcome line, LOGIN has one reply, and EXAMINE INBOX keeps outputting data until there's a single dot, so immediately stop reading once you see that.
You'll most likely want a simple function to take care of the reading. You could even write another function to make it easy:
function read_block($socket) {
$block = '';
while ('.' != trim($reply = read_line($socket)) {
$block .= $reply;
}
return $block;
}

PHP sockets stdin appending to data received

I am using sockets in PHP to create a simple command line based chat. It works ok, but there is one main issue that is making it almost unusable. When there are multiple people in the chat and one person is typing a message and the other sends a message the person typing the message gets the message received appended to what they are typing. Is there anyway around this? I'm using stdin and stream select. Here is a piece from the client:
$uin = fopen("php://stdin", "r");
while (true) {
$r = array($socket, $uin);
$w = NULL;
$e = NULL;
if (0 < stream_select($r, $w, $e, 0)) {
foreach ($r as $i => $fd) {
if ($fd == $uin) {
$text = (fgets($uin));
fwrite($socket, $text);
} else {
$text = fgets($socket);
print $text;
}
}
}
}
All help is appreciated! Thanks!
The code outputs a message to stdout everytime a full string is waiting in $socket.
The only way to get around that is to put the text to a variable ($outtext) in stead of printing it. Then you can display it whenever you are ready to read it, such as before writing to the outgoing socket...
$uin = fopen("php://stdin", "r");
while (true) {
$r = array($socket, $uin);
$w = NULL;
$e = NULL;
$outtext = '';
if (0 < stream_select($r, $w, $e, 0)) {
foreach ($r as $i => $fd) {
if ($fd == $uin) {
$text = (fgets($uin));
print $outtext;
$outtext = '';
fwrite($socket, $text);
} else {
$text = fgets($socket);
$outtext .= $text;
}
}
}
}
The downside being that it will only display incoming text when you press enter. The only way around that would be to use something other than fgets().
I'm assuming this is just an experiment - event driven programming with Node.js or similar would be much better for this type of thing.

PHP: Want fsockopen to retrieve portion only of remote xml file

I need to retrieve a small amount of data from a very large remote XML file that I access via http. I only need a portion of the file at the beginning, but the files I am accessing can often be so large that downloading them all will cause a timeout. It seems like it should be possible with fsockopen to pull only as much as needed before closing the connection, but nothing I have tried has worked.
Below is a simplified version of what I have been trying. Can anyone tell me what I need to do differently?
<?php
$k = 0;
function socketopen($funcsite, $funcheader){
$fp = fsockopen ($funcsite, 80, $errno, $errstr, 5);
$buffer = NULL;
if ($fp) {
fwrite($fp, "GET " . $funcheader . " HTTP/1.0\r\nHost: " . $funcsite. "\r\n\r\n");
while (!feof($fp)) {
$buffer = fgets($fp, 4096);
echo $buffer;
if($k == 200){
break;
}
$k++;
}
fclose ($fp);
} else {
print "No Response:";
}
return ( html_entity_decode($buffer));
}
$site = "www.remotesite.com";
$header = "/bigdatafile.xml";
$data = socketopen($site, $header);
?>
This works fine, but always opens and downloads the entire remote file. (I actually use a different conditional than the if($k = x), but that shouldn't matter).
Any help greatly appreciated. -Jim
Any reason not to use file_get_contents() instead?
$buffer = html_entity_decode(file_get_contents('http://www.remotesite.com/bigdatafile.xml', 0, null, $offsetBytes, $maxlenBytes));
You just need to specify $offsetBytes and $maxlenBytes.
Try this:
set_time_limit(0);
echo $buffer = html_entity_decode(file_get_contents('http://www.remotesite.com/bigdatafile.xml', 0, null, 1024, 4096));
with this code you could download the entire rss
if (!$xml = simplexml_load_file("http://remotesite.com/bigrss.rss))
{
throw new RuntimeException('Unable to load or parse feed');
}
else
{
file_put_contents($xml,'mybigrss.rss');
}
but if you want to get just some parts then do the following;
$limit = 512000; // set here a limit
$sourceData = fread($s_handle,$limit);
// your code ect..
Or with eof
$source='';
while (!feof($s_handle))
$source.=fread($s_handle,1024); // set limit

Categories