I'm trying to connect my PHP script to IRC, but it keeps timing out. I'm on the server, so I know it's up and running, I can't tell what the problem is.
Could it be an error in my code?
<?php
/**
* Configuration.
* Pretty self-explanatory
*/
$ircServer = "hub.malvager.com";
$ircPort = "6667";
$ircChannel = "#hackforums";
set_time_limit(0);
$ircSocket = fsockopen($ircServer, $ircPort, $eN, $eS);
if ($ircSocket)
{
fwrite($ircSocket, "USER Orgy orgy.test hfcoder :twBooter\n");
fwrite($ircSocket, "NICK OrgyBot|" . rand() . "\n");
fwrite($ircSocket, "JOIN " . $ircChannel . "\n");
while(1)
{
while($data = fgets($ircSocket, 128))
{
echo nl2br($data);
flush();
// Separate all data
$exData = explode(' ', $data);
// Send PONG back to the server
if($exData[0] == "PING")
{
fwrite($ircSocket, "PONG ".$exData[1]."\n");
}
}
}
}
else
{
echo $eS . ": " . $eN;
}
?>
UPDATE: Apparently, it's successfully working on SOME servers, but not others. fsockopen is allowed, as is set_time_limit. I can't figure out what the problem is.
UPDATE: Here's a trace route:
traceroute to hub.malvager.com (69.164.201.185), 30 hops max, 40 byte packets
1 rtr-1.bluehost.com (69.89.16.1) 0.406 ms 0.418 ms 0.438 ms
2 ge-6-8.car2.SaltLakeCity1.Level3.net (4.53.42.5) 1.484 ms 1.515 ms 1.590 ms
3 ae-5-5.ebr1.Denver1.Level3.net (4.69.133.126) 35.117 ms 35.119 ms 35.270 ms
4 ae-2-2.ebr2.Dallas1.Level3.net (4.69.132.106) 39.978 ms 39.938 ms 39.939 ms
5 ae-3-80.edge4.Dallas3.Level3.net (4.69.145.141) 40.070 ms 40.046 ms ae-4-90.edge4.Dallas3.Level3.net (4.69.145.205) 40.040 ms
6 THE-PLANET.edge4.Dallas3.Level3.net (4.59.32.30) 40.171 ms 41.407 ms 40.698 ms
7 te7-2.dsr02.dllstx3.theplanet.com (70.87.253.26) 40.653 ms te9-2.dsr02.dllstx3.theplanet.com (70.87.253.30) 40.454 ms te7-2.dsr02.dllstx3.theplanet.com (70.87.253.26) 40.593 ms
8 * * 6e.ff.5746.static.theplanet.com (70.87.255.110) 40.537 ms
9 52.ff.5746.static.theplanet.com (70.87.255.82) 40.481 ms 40.472 ms 40.459 ms
10 li115-185.members.linode.com (69.164.201.185) 40.450 ms 40.171 ms 40.582 ms
And the dig:
; <<>> DiG 9.6.2-RedHat-9.6.2-0.BH <<>> hub.malvager.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 34815
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 5, ADDITIONAL: 5
;; QUESTION SECTION:
;hub.malvager.com. IN A
;; ANSWER SECTION:
hub.malvager.com. 85419 IN A 69.164.201.185
;; AUTHORITY SECTION:
malvager.com. 85419 IN NS ns1.linode.com.
malvager.com. 85419 IN NS ns3.linode.com.
malvager.com. 85419 IN NS ns2.linode.com.
malvager.com. 85419 IN NS ns4.linode.com.
malvager.com. 85419 IN NS ns5.linode.com.
;; ADDITIONAL SECTION:
ns1.linode.com. 54252 IN A 69.93.127.10
ns2.linode.com. 51679 IN A 65.19.178.10
ns3.linode.com. 41439 IN A 75.127.96.10
ns4.linode.com. 26259 IN A 207.192.70.10
ns5.linode.com. 54441 IN A 109.74.194.10
;; Query time: 4 msec
;; SERVER: 74.220.195.27#53(74.220.195.27)
;; WHEN: Thu Sep 23 16:32:21 2010
;; MSG SIZE rcvd: 227
NETCAT:
nc: connect to hub.malvager.com port 6667 (tcp) failed: Connection timed out
You have some errors.
Is buggy, because checking strictly first explode result, you exploding by space character and in IRC implementation protocol all commands must be terminated by newline character then server send to you "PING\n"
not "PING"
then your $exData
array is in this state.
array(1) {
[0]=>
string(5) "PING
"
}
Then your $exData[0] == "PING"
is false because "PING"
is not equal to "PING\n"
.
Good solution is not add "\n"
to the end of command in parser because "\n"
is not only newline marker (for poor IRC Protocol implementation i recommend this, you never know what newline marker IRC protocol developer may use, think about Delphi INDY Buggy IRC Server Control), better solution is not checking her.
if (strstr(strtolower($exData[0]), "ping"))
{
$cmd = "PONG";
if (sizeof($exData) == 1)
{
$cmd .= "\n";
}
else for ($Index=1; $Index < sizeof($exData); $Index++)
{
$cmd .= " " . $exData[$Index];
}
/*
* Not adding newline marker, because is.
* already exists in last element of $exData
* array at last position if for was executed
*/
fwrite($ircSocket, $cmd);
}
I will change the while($data = fgets($ircSocket, 128))
, to the while ($data = fgets($ircSocket))
, because in long server names you can simply overflow 128 bytes.
And your fwrite($ircSocket, "JOIN " . $ircChannel . "\n");
line don't doing exactly what you want, because your JOIN
command was sended after the USER
and NICK
command then server parse your request before user was registered and if user is not registered you can JOIN
to channel, IRC servers don't QUEUE failed command because this don't have any sense. The best practice of this is send JOIN
command after the MOTD
command was received from the server and after the left from channel command was received too if you want implement some functionality like AUTOJOIN
.
// End of /MOTD command.
if (sizeof($exData) > 1) if (strstr($exData[1], "376"))
{
fwrite($ircSocket, "JOIN " . $ircChannel . "\n");
}
About your script design, if you writing simple bot then i don't have any thing to say in this topic, but if you plan write some big piece of code you should design your script in other way. You must separate some layers like IRC Protocol implementation and your IRC Bot actions. You should use some class to move responsibility of IRC Protocol into her, because in bigger piece of code mixing IRC Protocol control with your bot actions code is nice Technical debt.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With