Now I have my bot to send message when the bot joins. However how do I make a form that would post data so that the bot will say the message to the channel?
Here is my script (Rewamped):
<?php
set_time_limit(0);
$socket = fsockopen("//", 6667) or die();
$msg = $_POST['message'];
$pr = $_POST['percentage'];
$pr /= 100;
fputs($socket,"USER BOT 0 zo :ZH bot\n");
// Set the bots nickname
fputs($socket,"NICK BOT1\n");
fputs($socket,"JOIN #bots\n");
while(1) {
while($data = fgets($socket, 128)) {
// echo the data received to page
echo nl2br($data);
// flush old data, it isn't needed any longer.
flush();
$ex = explode(' ', $data);
if($ex[0] == "PING") fputs($socket, "PONG ".$ex[1]."\n");
$search_string = "/^:([A-Za-z0-9_\-]+)[#!~a-zA-Z0-9#\.\-]+\s*([A-Z]+)\s*[:]*([\#a-zA-Z0-9\-]+)*\s*[:]*([!\#\-\.A-Za-z0-9 ]+)*/";
$do = preg_match($search_string, $data, $matches);
// check that there is a command received
if(isset($matches['2'])) {
switch($matches['2']) {
case "PRIVMSG":
$user = $matches['1'];
$channel = $matches['3'];
$chat_text = isset($matches['4']) ? $matches['4'] : "";
// check chat for !time
if(strtolower($chat_text) == "!time") {
$output = "::::: " . date('l jS \of F Y h:i:s A') . " :::::";
fputs($socket, "PRIVMSG " . $channel . " :" . $output . "\n");
} elseif(strtolower($chat_text) == "!hello") {
fputs($socket, "PRIVMSG " . $channel . " :Hello!\n");
}
break;
case "JOIN":
$user = $matches['1'];
$channel = $matches['3'];
fputs($socket, "PRIVMSG " . $channel . " :Welcome " . $user . " to " . $channel . "\n");
break;
}
}
}
}
?>
E.g. Making a form that would send the data to the IRC channel. The output would be "wget file info port" <-- That would be the text sent to the IRC channel.
Here are parts related:
fputs($socket, "PRIVMSG " . $channel . " :Welcome " . $user . " to " . $channel ."\n");
Hope someone can help out.
Okay here's a better answer. The first section still stands. A new PHP process is called every time you want to initiate a new script. Thus, you need some way to do IPC.
Here's how it's done on *nix (but not windows) in PHP:
Receiver:
<?php
$queueKey = 123321;
$queue = false;
if(msg_queue_exists($queueKey)) {
echo "Queue Exists.\n";
}
// Join the queue
$queue = msg_get_queue($queueKey);
while(!($queue == false)) {
// Note: This function could block if you feel like threading
$msgRec = msg_receive(
$queue, // I: Queue to get messages from
0, // I: Message type (0 = first on queue)
$msgType, // O: Type of message received
1024, // I: Max message size
$msgData, // O: Data in the message
true, // I: Unserialize data
MSG_IPC_NOWAIT // I: Don't block
);
if($msgRec) {
echo "Message received:\n";
echo "Type = $msgType\n";
echo "Data = \n";
print_r($msgData);
}
}
?>
Sender:
<?php
$queueKey = 123321;
$queue = false;
if(msg_queue_exists($queueKey)) {
echo "Queue Exists.\n";
} else {
echo "WARNING: Queue does not exist. Maybe no listeners?\n";
}
$queue = msg_get_queue($queueKey);
$abc["something"] = "something value";
$abc["hello"] = "world";
$abc["fu"] = "bar";
msg_send(
$queue, // Queue to send on
1, // Message type
$abc, // Data to send
true, // Serialize data?
true // Block
);
?>
This should produce (in the receiver loop) something similar to this:
Message received:
Type = 1
Data =
Array
(
[something] => something value
[hello] => world
[fu] => bar
)
Your script might look something like this
postToMe.php:
<?php
$queueKey = 123321;
$queue = false;
if(msg_queue_exists($queueKey)) {
echo "Queue Exists.\n";
} else {
echo "WARNING: Queue does not exist. Maybe no listeners?\n";
}
$queue = msg_get_queue($queueKey);
msg_send(
$queue, // Queue to send on
1, // Message type
$_POST, // Data to send
true, // Serialize data?
true // Block
);
?>
bot.php:
<?php
set_time_limit(0);
$socket = fsockopen("//", 6667) or die();
$msg = $_POST['message'];
$pr = $_POST['percentage'];
$pr /= 100;
fputs($socket,"USER BOT 0 zo :ZH bot\n");
// Set the bots nickname
fputs($socket,"NICK BOT1\n");
fputs($socket,"JOIN #bots\n");
$queueKey = 123321;
$queue = false;
// Join the IPC queue
$queue = msg_get_queue($queueKey);
if(!$queue) echo "ERROR: Could not join IPC queue. Form data will not be received";
while(1) {
// Handle new post info
// You may want to increase the message size from 1024 if post data is large
if(msg_receive($queue, 0, $msgType, 1024, $msgData, true, MSG_IPC_NOWAIT)) {
// Handle data here. Post data is stored in $msgData
}
while($data = fgets($socket, 128)) {
// echo the data received to page
echo nl2br($data);
// flush old data, it isn't needed any longer.
flush();
$ex = explode(' ', $data);
if($ex[0] == "PING") fputs($socket, "PONG ".$ex[1]."\n");
$search_string = "/^:([A-Za-z0-9_\-]+)[#!~a-zA-Z0-9#\.\-]+\s*([A-Z]+)\s*[:]*([\#a-zA-Z0-9\-]+)*\s*[:]*([!\#\-\.A-Za-z0-9 ]+)*/";
$do = preg_match($search_string, $data, $matches);
// check that there is a command received
if(isset($matches['2'])) {
switch($matches['2']) {
case "PRIVMSG":
$user = $matches['1'];
$channel = $matches['3'];
$chat_text = isset($matches['4']) ? $matches['4'] : "";
// check chat for !time
if(strtolower($chat_text) == "!time") {
$output = "::::: " . date('l jS \of F Y h:i:s A') . " :::::";
fputs($socket, "PRIVMSG " . $channel . " :" . $output . "\n");
} elseif(strtolower($chat_text) == "!hello") {
fputs($socket, "PRIVMSG " . $channel . " :Hello!\n");
}
break;
case "JOIN":
$user = $matches['1'];
$channel = $matches['3'];
fputs($socket, "PRIVMSG " . $channel . " :Welcome " . $user . " to " . $channel . "\n");
break;
}
}
}
}
?>
Basically, this script will be running all the time. The way PHP works is that for each script that is being run, a new PHP process is created. Scripts can be run multiple times simultaneously, however they will not be able to directly communicate.
You will need to create enother script (or at least a whole new function of this one) to accept the post variables, and then send them to the running version of this script.
(Note: I will provide 2 solutions, since 1 is significantly more difficult. Also, there's Semaphore that I've just found, however I am unsure exactly if this suits our needs because I know next to nothing about it http://php.net/manual/en/book.sem.php)
Best (But Advanced)
The best way I can think of doing this would be to use sockets (particularly on *nix, since sockets are fantastic for IPC [inter process communication]). It's a little difficult, since you're basically create a client/server just to communicate details, then you need to come up with some sort of a protocol for your IPC.
I won't code anything up here, but the links that are relevant to this are
http://www.php.net/manual/en/function.socket-create.php
http://www.php.net/manual/en/function.socket-bind.php
http://www.php.net/manual/en/function.socket-listen.php
http://www.php.net/manual/en/function.socket-accept.php
http://www.php.net/manual/en/function.socket-connect.php
If using this on *nix, I would highly recommend using AF_UNIX as the domain. It's very efficient, and quite a number of applications use it for IPC.
Pros:
Very robust solution
- Highly efficient
- Instant (or as close as we can get) communication
Cons:
- Quite difficult to implement
Not As Great (But Still Good)
Just use files to communicate the information. Have your bot script check the file every 15 seconds for changes. I would suggest using XML for the data (since simple xml makes xml processing in php well... simple)
Things you need to consider would be:
How would it react when receiving 2 posts at the same time? (If you just use a flat file or don't account for having multiple entries, this will become a problem).
How you find out if a message is new (I'd delete/blank the file right after reading. Note: Not after processing, as someone could post to the form script while you are processing/sending the message)
Links:
How to use simple xml
http://php.net/manual/en/simplexml.examples-basic.php
http://au2.php.net/manual/en/book.simplexml.php
File related
http://au2.php.net/manual/en/function.file-put-contents.php
http://au2.php.net/manual/en/function.file-get-contents.php
With that being said, you could also use MySQL/Postgres or some other database back end to deal with the flow of data between scripts.
Pros:
- Easy to implement
Cons:
- Slow to transfer data (checks files at given intervals)
- Uses external files, which can be deleted/modified my external applications/users
Related
I am working with a client API (master API) that does not have a bulk feature.
I have taken data from 2 different API's (client API's) and merged it into one JSON file that is properly formatted. Checked in online JSON Validator.
The JSON File is 1100 records of merged customer data. Taking one record at a time, I have built a function that submits the data successfully to the master API.
I have now built a PHP script that loops through the JSON File and takes the row data (each client record) and submits it to the master API successfully. After about 90 rows, the PHP script times out.
I have set the following code on the page
#ini_set('zlib.output_compression', 0);
#ini_set('implicit_flush', 1);
set_time_limit(600);
#ob_end_clean();
And am buffering each update to return a JSON status code returned from the master API.
What should I be doing to get the PHP to not time out after about 100 records and keep updating the buffer response on the page.?
Thanks in advance.
Jason
I've taken a few of different approached to this kind of problem in the past. The only quick fix for this is if you can change the php.ini settings on the server to increase the timeout enough to allow your batch to complete. This is not a great solution, but it is a solution.
The next option (in ascending order of effort) is to set up a loop between the browser and your server where your browser makes a request, the server sends a portion of the records, then returns to the browser with a cursor indicating where the process left off, the browser makes another request to the server, sending the cursor back as a parameter, and this continues until the batch finishes. This is nice because you can display a progress bar to the user.
Finally, you could have an agent running on the server that waits for batch jobs to be submitted and runs them completely outside of the HTTP request lifecycle. So your browser makes a request to kick off a batch job, which results in some sort of record in a database that can keep track of the status of the job. The agent picks up the job and sets it to a pending state while it works, then sets the completion status when it finishes. You can set set something up that allows you to poll the server from the browser periodically so you can alert the user when the process finishes. Of you can just have the agent send an email report to the user when the batch completes. This is the most solid option with the least risk of something interrupting the processing, and it can leave an audit trail without any effort at all. But it's clearly more complicated to set up.
Thanks Rob.
Your response sent me in the right direction.
I sort of used your backend idea on the frontend. I just looped through 20 records at a time and then refreshed the page via javascript and started at 21 to 40 etc. Threw in a progress bar for fun as well.
Thanks for helping me get my head around the idea. Not the right way to do it, but my Python is just as bad as my PHP.
<?php
#ini_set('zlib.output_compression', 0);
#ini_set('implicit_flush', 1);
set_time_limit(600);
#ob_end_clean();
require("header.php");
require_once('nav.php');
function sync_systems($sfData){
$dataPost = $sfData;
$postID = $dataPost['ID'];
$epcall = update_profile($dataPost);
$epResult = json_decode($epcall, true);
if($epResult['status'] != 404){
$sfStatus = updateSFOpportunity($epResult['client_id'], $epResult['ep_id'] );
if($sfStatus == 1){
$datamsg = " Success! The sync was a success in both Salesforce and other system. OtherSystem Record " . $epResult['ep_id'] . " was created or updated.<br/>";
} else {
$datamsg = " Success! The sync was a success in other system, but failed in Salesforce<br/>";
}
echo json_encode(['code'=>200, 'msg'=>$datamsg]);
} else {
$datamsg = " Failure! The sync did not work.<br/>";
echo json_encode(['code'=>404, 'msg'=>$datamsg]);
} // end epResult
}
function sync_ep($sfData){
$dataPost = $sfData;
$postID = $dataPost['ID'];
$epcall = update_profile($dataPost);
$epResult = json_decode($epcall, true);
if($epResult['status'] != 404){
// $sfStatus = updateSFOpportunity($epResult['client_id'], $epResult['ep_id'] );
if($sfStatus == 1){
$datamsg = " Success! The sync was a success in both Salesforce and other system. Other System Record " . $epResult['ep_id'] . " was created or updated.<br/>";
} else {
$datamsg = " Success! The sync was a success in other system, but failed in Salesforce<br/>";
}
echo json_encode(['code'=>200, 'msg'=>$datamsg]);
} else {
$datamsg = " Failure! The sync did not work.<br/>";
echo json_encode(['code'=>404, 'msg'=>$datamsg]);
} // end epResult
}
$ju = "CustomerData20Fall.json";
//read json file from url in php
$readJSONFile = file_get_contents($ju);
//convert json to array in php
$jfile = json_decode($readJSONFile);
//print_r($jfile);
//convert json to array in php
$epSync = array();
$oldValue = 0;
$total = count($jfile );
?>
<!-- Progress bar holder -->
<div id="progress" style="width:500px;border:1px solid #ccc;"></div>
<!-- Progress information -->
<div id="information" style="width"></div>
<?php
if(isset($_REQUEST["NEXTVALUE"])){
$nextValue = $_REQUEST["NEXTVALUE"];
} else {
$nextValue = 1;
}
$refreshValue = $nextValue + 20;
$displaycounter = $nextValue;
$timeRemaining = 0;
$updatedRecords = 0;
foreach ($jfile as $key => $jsons) {
$newKey = $key;
if($oldValue != $newKey){
if($newKey >= $nextValue && $newKey < $refreshValue){
// echo "Updated: " . [$oldValue]['EPID'] . "<br/>";
// echo "<hr>" . $nextValue . " >= " . $newKey . " < " . $refreshValue;
print_r($epSync[$oldValue]);
$displaycounter = $newKey;
echo sync_systems($epSync[$oldValue]);
usleep(30000);
flush();
} else {
if($key == ($refreshValue)){
$theURL = "sf-ep-sync.php?NEXTVALUE=" . $refreshValue . "&RAND=" . rand();
// echo "<hr>" . $newKey . " = " . $refreshValue . " " . $theURL ."<br/>";
echo "<script>location.href = '" . $theURL . "';</script>";
exit;
}
}
$oldValue = $newKey;
$i = $nextValue + 1;
if(($i + 1) == $total ){
$percent = intval($i/$total * 100)."%";
$timeRemaining = 0;
} else {
$percent = intval($i/$total * 100)."%";
$timeRemaining = (($total - $displaycounter)/60);
}
usleep(30000);
echo '<script language="javascript">
document.getElementById("progress").innerHTML="<div style=\"width:'.$percent.';background-color:#ddd;\"> </div>";
document.getElementById("information").innerHTML="'.$displaycounter.' row(s) of '. $total . ' processed. About ' . round($timeRemaining, 2) . ' minutes remaining.";
</script>';
// This is for the buffer achieve the minimum size in order to flush data
echo str_repeat(' ',1024*64);
}
foreach($jsons as $key => $value) {
$epSync[$newKey][$key] = $value;
}
}
Thanks,
Jason
I've been reading up on multi-threading with PHP, but I'm having a tough time integrating it into my command line php script.
I read multithreading
and multithread foreach.
But I'm really not sure. Any thoughts how to apply multi-threading here? The reason I need multi-threading here is that Telnet takes forever (see shell script). But I can't write to my DB concurrently ($stmt2). I'm looping through my list of devices with $stmt->fetch.
Maybe I should do something like run task specifically, with just the telnet/shell script call in the task, like that example:
$task = new class extends Thread {
private $response;
public function run()
{
$content = file_get_contents("http://google.com");
preg_match("~<title>(.+)</title>~", $content, $matches);
$this->response = $matches[1];
}
};
$task->start() && $task->join();
var_dump($task->response); // string(6) "Google"
But, I'm getting the error when I try to add this to my code below:
PHP Parse error: syntax error, unexpected T_CLASS in /opt/IBM/custom/NAC_Dslam/calix_swVerThreaded.php on line 100
this is the line:
$task = new class ...
My script looks like this:
$stmt =$mysqli->prepare("SELECT ip, model FROM TableD WHERE vendor = 'Calix' AND model in ('C7','E7') AND sw_ver IS NULL LIMIT 6000"); //AND ping_reply IS NULL AND software_version IS NULL
$stmt->bind_result($ip, $model); //list of ip's
if(!$stmt->execute())
{
//err
}
$stmt2 = $mysqli2->prepare("UPDATE TableD SET sw_ver = ?
WHERE vendor = 'Calix'
AND ip = ? ");
$stmt2->bind_param("ss", $software, $ip);
while($stmt->fetch()) {
//initializing var's
if(pingAddress($ip)=="alive") { //Ones that don't ping are dead to us.
///////this is the part that takes forever and should be multi-threaded/////
//Call shell script to telnet to calix dslam and get version for that ip
if($model == "C7"){
$task = new class extends Thread {
private $itsOutput;
public function run()
{
exec ("./calix_C7_swVer.sh $ip", $itsOutput);//takes forever/telnet
//in shell script. Can't
//be fixed. Each time I
//call this script it's a
//different ip
}
};
$task->start() && $task->join();
var_dump($task->itsOutput); //should be returned output above //takes forever to telnet
//$output = $task->itsOutput;
$output2=array_reverse($output,true);
if (!(preg_grep("/DENY/", $output2))){
$found = preg_grep("/COMPLD/", $output2);
$ind = key($found);
$version = explode(",", $output[$ind+1]);
if(strlen($version[3])>=1) { //if sw ver came back in an acceptable size
$software = $version[3];
$software = trim($software,'"'); //trim double quote (usually is there)
print "sw ver after trim: " . $software . "\n";
if(!$stmt2->execute()) { //write sw version to netcool db
$tempErr = "Failed to insert into dslam_elements_nac: " . $stmt2->error;
printf($tempErr . "\n"); //show mysql execute error if exists
$err->logThis($tempErr);
}
if(!$stmtX->execute()) { //commit it
$tempErr = "Failed to commit dslam_elements_nac: " . $stmtX->error;
printf($tempErr . "\n"); //show mysql execute error if exists
$err->logThis($tempErr);
}
} //we got a version back
else { //version not retrieved
//error processing
} //didn't get sw ver
} //not deny
} //c7
else if($model == "E7") {
exec ("./calix_E7_swVer.sh $ip", $output);
$output2=array_reverse($output,true);
if (!(preg_grep("/DENY/", $output2))){
$found = preg_grep("/yes/", $output2);
$ind = key($found);
$version = explode(" ", $output[$ind]);
if(strlen($version[5])>=1) { //if sw ver came back in an acceptable size
$software = $version[5];
print "sw ver after trim: " . $software . "\n";
if(!$stmt2->execute()) { //write sw version to netcool db
$tempErr = "Failed to insert into dslam_elements_nac: " . $stmt2->error;
printf($tempErr . "\n"); //show mysql execute error if exists
$err->logThis($tempErr);
}
if(!$stmtX->execute()) { //commit it
//err processing
}
} //we got a version back
else { //version not retrieved
//handle it
} //didn't get sw ver
} //not deny
}
} //while
update
I'm trying this (pcntl_fork), but it doesn't seem to be quite what I need because when I sleep(30), which I think is similar to my shell script call, other processes don't continue and do the next one.
<?php
declare(ticks = 1);
$max=10;
$child=0;
$res = array("aabc", "bcd", "cde", "eft", "ggg", "hhh", "iii", "jjj", "kkk", "lll", "mmm", "nnn", "ooo", "ppp", "qqq", "aabc", "bcd", "cde", "eft", "ggg", "hhh", "iii", "jjj", "kkk", "lll", "mmm", "nnn", "ooo", "ppp", "qqq");
function sig_handler($signo) {
global $child;
switch ($signo) {
case SIGCHLD:
//echo "SIGCHLD receivedn";
// clean up zombies
$pid = pcntl_waitpid(-1, $status, WNOHANG);
$child -= 1;
//exit;
}
}
pcntl_signal(SIGCHLD, "sig_handler");
//$website_scraper = new scraper();
foreach($res as $r){
while ($child >= $max) {
sleep(5); //echo " - sleep $child n";
//pcntl_waitpid(0,$status);
}
$child++;
$pid=pcntl_fork();
if ($pid==-1) {
die("Could not fork:n");
}
elseif ($pid) {
// we're in the parent fork, dont do anything
}
else {
//example of what a child process could do:
print "child process stuff \n";
sleep(30);
//$website_scraper -> scraper("http://foo.com");
exit;
}
while(pcntl_waitpid(0, $status) != -1) { //////???
$status = pcntl_wexitstatus($status);
echo "child $status completed \n";
}
print "did stuff \n";
}
?>
I've been reading up on multi-threading with PHP
Don't. PHP threading has very limited utility, as it cannot be used in a web server environment. It can only be used in command-line scripts.
The author of the PHP pthreads extension has written:
pthreads v3 is restricted to operating in CLI only: I have spent many years trying to explain that threads in a web server just don't make sense, after 1,111 commits to pthreads I have realised that, my advice is going unheeded.
So I'm promoting the advice to hard and fast fact: you can't use pthreads safely and sensibly anywhere but CLI.
If you need to communicate with multiple network devices in parallel, consider using stream_select to perform asynchronous I/O, or running multiple PHP processes as part of a worker queue to manage the connections.
I'm running a php server based on the one provided by a tutorial by Raymond Fain on kirupa:
http://www.kirupa.com/developer/flash8/php5sockets_flash8_3.htm
It works great, up to a point. The thing is that when it receives certain messages, it then does some stuff to that message then sends it out to all connected clients. The problem here is that once the number of clients reaches the atmospheric heights of around 12, the loop that sends the message to all clients can take a while (like 4 seconds), and any subsequent messages sent during that 4 second period get queued up and eventually we get timeouts.
This is the loop that sends a message to all clients:
function send_Message($allclient, $socket, $buf)
{
$now = microtime(true);
echo 'sending message to '.count($allclient).' clients ';
$msg = "<mbFeed>$buf</mbFeed>\n\0";
foreach($allclient as $client)
{
socket_write($client, $msg, strlen($msg));
}
$end = microtime(true);
echo 'time was '.($end - $now);
}
You'll notice I've been echoing the time it takes by comparing microtimes. The thing is that the echo claims that the whole process takes a tiny amount of time, like 0.003 seconds, which is what I would have expected, but when I have this script running in the terminal, I see the little spinning icon going for the four seconds, during which everything gets unresponsive.
My questions are as follows: does anyone know what the script is doing during that time? Is there anything I can do it to stop it doing that? Is there a more efficient way to send a message to all connected sockets?
Here's the code for the whole socket file, if you need it, but I'm hoping this is something that might be familiar to somebody...
#!/usr/bin/php -q
<?php
/*
Raymond Fain
Used for PHP5 Sockets with Flash 8 Tutorial for Kirupa.com
For any questions or concerns, email me at ray#obi-graphics.com
or simply visit the site, www.php.net, to see if you can find an answer.
*/
//ini_set('display_errors',1);
ini_set('display_startup_errors',1);
error_reporting(E_ALL);
//ini_set('error_log', 'socket_errors.log');
ini_set('log_errors', 'On');
ini_set('display_errors', '1');
error_log('testing');
stream_set_timeout(1,0);
set_time_limit(0);
ob_implicit_flush();
$address = 'xxx.xxx.x.xxx';
$port = xxxx;
function send_Message($allclient, $socket, $buf)
{
$now = microtime(true);
echo 'sending message to '.count($allclient).' clients ';
$msg = "<mbFeed>$buf</mbFeed>\n\0";
foreach($allclient as $client)
{
socket_write($client, $msg, strlen($msg));
}
$end = microtime(true);
echo 'time was '.($end - $now);
}
echo "connecting...
";
//---- Start Socket creation for PHP 5 Socket Server -------------------------------------
if (($master = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) < 0)
{
echo "socket_create() failed, reason: " . socket_strerror($master) . "\n";
}
socket_set_option($master, SOL_SOCKET,SO_REUSEADDR, 1);
socket_set_nonblock($master);
if (($ret = socket_bind($master, $address, $port)) < 0)
{
echo "socket_bind() failed, reason: " . socket_strerror($ret) . "\n";
}
echo 'socket bind successfull.
';
if (($ret = socket_listen($master, 5)) < 0)
{
echo "socket_listen() failed, reason: " . socket_strerror($ret) . "\n";
}
$read_sockets = array($master);
echo "connected.";
//---- Create Persistent Loop to continuously handle incoming socket messages ---------------------
while (true)
{
$changed_sockets = $read_sockets;
$num_changed_sockets = socket_select($changed_sockets, $write = NULL, $except = NULL, NULL);
echo 'changed sockets length: '.(count($changed_sockets));
foreach($changed_sockets as $key => $socket)
{
if ($socket == $master)
{
if (($client = socket_accept($master)) < 0)
{
echo "socket_accept() failed: reason: " . socket_strerror($msgsock) . "\n";
continue;
}
else
{
socket_set_nonblock($client);
array_push($read_sockets, $client);
}
}
else
{
$bytes = socket_recv($socket, $buffer, 8192, 0);
if ($bytes == 0)
{
unset($read_sockets[$key]);
unset($changed_sockets[$key]);
socket_close($socket);
}
else
{
if (substr($buffer, 0, 3) == "<->")
{
unset($read_sockets[$key]);
unset($changed_sockets[$key]);
socket_close($socket);
$buffer = substr($buffer, 3);
}
$allclients = $read_sockets;
array_shift($allclients);
if (substr($buffer, 0, 3) == ":::") handleSpecial(substr($buffer, 3));
else
{
echo 'allclients length: '.(count($allclients));
send_Message($allclients, $socket, str_replace("\0","",$buffer));
}
}
}
}
}
?>
I would like to recommend you to look at ZeroMQ its like sockets on steroids
ØMQ in a Hundred Words
ØMQ (also seen as ZeroMQ, 0MQ, zmq) looks like an embeddable networking library but acts like a concurrency framework. It gives you sockets that carry atomic messages across various transports like in-process, inter-process, TCP, and multicast. You can connect sockets N-to-N with patterns like fanout, pub-sub, task distribution, and request-reply. It's fast enough to be the fabric for clustered products. Its asynchronous I/O model gives you scalable multicore applications, built as asynchronous message-processing tasks. It has a score of language APIs and runs on most operating systems. ØMQ is from iMatix and is LGPLv3 open source.
using ZMQ::SOCKET_PUB and ZMQ::SOCKET_PULL the same chat server can be as simple as
$ctx = new ZMQContext();
$pub = $ctx->getSocket(ZMQ::SOCKET_PUB);
$pub->bind('tcp://*:5566');
$pull = $ctx->getSocket(ZMQ::SOCKET_PULL);
$pull->bind('tcp://*:5567');
echo "Chat Server Start ", PHP_EOL;
while(true) {
$message = $pull->recv();
echo "Got ", $message, PHP_EOL;
$pub->send($message);
}
This can easily handle10,000 push request per min on a simple system as oppose to your current server implementation.
With ZmqSocket you can talk to zmq sockets from your JavaScript code. You can connect, send and receive string messages. As JavaScript does not support raw TCP connections, it uses Flash as a bridge
Simple JavaScript Bridge Example you can also look at zmqsocket-as which allows you to talk to zmq-sockets from ActionScript code.
How can you mimic a command line run of a script with arguements inside a PHP script? Or is that not possible?
In other words, let's say you have the following script:
#!/usr/bin/php
<?php
require "../src/php/whatsprot.class.php";
function fgets_u($pStdn) {
$pArr = array($pStdn);
if (false === ($num_changed_streams = stream_select($pArr, $write = NULL, $except = NULL, 0))) {
print("\$ 001 Socket Error : UNABLE TO WATCH STDIN.\n");
return FALSE;
} elseif ($num_changed_streams > 0) {
return trim(fgets($pStdn, 1024));
}
}
$nickname = "WhatsAPI Test";
$sender = ""; // Mobile number with country code (but without + or 00)
$imei = ""; // MAC Address for iOS IMEI for other platform (Android/etc)
$countrycode = substr($sender, 0, 2);
$phonenumber=substr($sender, 2);
if ($argc < 2) {
echo "USAGE: ".$_SERVER['argv'][0]." [-l] [-s <phone> <message>] [-i <phone>]\n";
echo "\tphone: full number including country code, without '+' or '00'\n";
echo "\t-s: send message\n";
echo "\t-l: listen for new messages\n";
echo "\t-i: interactive conversation with <phone>\n";
exit(1);
}
$dst=$_SERVER['argv'][2];
$msg = "";
for ($i=3; $i<$argc; $i++) {
$msg .= $_SERVER['argv'][$i]." ";
}
echo "[] Logging in as '$nickname' ($sender)\n";
$wa = new WhatsProt($sender, $imei, $nickname, true);
$url = "https://r.whatsapp.net/v1/exist.php?cc=".$countrycode."&in=".$phonenumber."&udid=".$wa->encryptPassword();
$content = file_get_contents($url);
if(stristr($content,'status="ok"') === false){
echo "Wrong Password\n";
exit(0);
}
$wa->Connect();
$wa->Login();
if ($_SERVER['argv'][1] == "-i") {
echo "\n[] Interactive conversation with $dst:\n";
stream_set_timeout(STDIN,1);
while(TRUE) {
$wa->PollMessages();
$buff = $wa->GetMessages();
if(!empty($buff)){
print_r($buff);
}
$line = fgets_u(STDIN);
if ($line != "") {
if (strrchr($line, " ")) {
// needs PHP >= 5.3.0
$command = trim(strstr($line, ' ', TRUE));
} else {
$command = $line;
}
switch ($command) {
case "/query":
$dst = trim(strstr($line, ' ', FALSE));
echo "[] Interactive conversation with $dst:\n";
break;
case "/accountinfo":
echo "[] Account Info: ";
$wa->accountInfo();
break;
case "/lastseen":
echo "[] Request last seen $dst: ";
$wa->RequestLastSeen("$dst");
break;
default:
echo "[] Send message to $dst: $line\n";
$wa->Message(time()."-1", $dst , $line);
break;
}
}
}
exit(0);
}
if ($_SERVER['argv'][1] == "-l") {
echo "\n[] Listen mode:\n";
while (TRUE) {
$wa->PollMessages();
$data = $wa->GetMessages();
if(!empty($data)) print_r($data);
sleep(1);
}
exit(0);
}
echo "\n[] Request last seen $dst: ";
$wa->RequestLastSeen($dst);
echo "\n[] Send message to $dst: $msg\n";
$wa->Message(time()."-1", $dst , $msg);
echo "\n";
?>
To run this script, you are meant to go to the Command Line, down to the directory the file is in, and then type in something like php -s "whatsapp.php" "Number" "Message".
But what if I wanted to bypass the Command Line altogether and do that directly inside the script so that I can run it at any time from my Web Server, how would I do that?
First off, you should be using getopt.
In PHP it supports both short and long formats.
Usage demos are documented at the page I've linked to. In your case, I suspect you'll have difficulty detecting whether a <message> was included as your -s tag's second parameter. It will probably be easier to make the message a parameter for its own option.
$options = getopt("ls:m:i:");
if (isset($options["s"] && !isset($options["m"])) {
die("-s needs -m");
}
As for running things from a web server ... well, you pass variables to a command line PHP script using getopt() and $argv, but you pass variables from a web server using $_GET and $_POST. If you can figure out a sensible way to map $_GET variables your command line options, you should be good to go.
Note that a variety of other considerations exist when taking a command line script and running it through a web server. Permission and security go hand in hand, usually as inverse functions of each other. That is, if you open up permissions so that it's allowed to do what it needs, you may expose or even create vulnerabilities on your server. I don't recommend you do this unless you'll more experienced, or you don't mind if things break or get attacked by script kiddies out to 0wn your server.
You're looking for backticks, see
http://php.net/manual/en/language.operators.execution.php
Or you can use shell_exec()
http://www.php.net/manual/en/function.shell-exec.php
I am having problem with my IRC Bot script, I have implemented it into my Curl transfer method.
I have a problem, once the IRC bot sends a message to the IRC channel, all of the "echo" at the end of the script does not show and the page hangs. The whole Apache hangs.
<?php
$ircServer = "///";
$ircPort = "6667";
$ircChannel = "#bots";
set_time_limit(0);
$msg = $_POST['msg'];
$paper = $_POST['paper'];
$sizzor = $_POST['sizzor'];
$hand = $_POST['hand'];
$ircSocket = fsockopen($ircServer, $ircPort, $eN, $eS);
if ($ircSocket)
{
fwrite($ircSocket, "USER Lost rawr.test lol :code\n");
fwrite($ircSocket, "NICK Rawr" . rand() . "\n");
fwrite($ircSocket, "JOIN " . $ircChannel . "\n");
ignore_user_abort(TRUE); // Noob Close down page
fwrite($ircSocket, "PRIVMSG " . $ircChannel . " :" . $msg . "\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");
}
}
echo $eS . ": " . $eN;
}
}
?>
if ($bootcontents == 'success') {
echo '<center><marquee behavior="alternate" direction="left">Spinning xxx at ' . $power . '% power.</marquee></center>';
This part does not show during the script:
if ($bootcontents == 'success') {
echo '<center><marquee behavior="alternate" direction="left">Spinning xxx at ' . $power . '% power.</marquee></center>';
The page just hangs, if I add the exit(); function onto near the top the whole "echo" info does not show.
Please can someone help.
You are creating an infinite loop:
while (1)
// ...
This loop can never finish, since you did not use an exit statement (like break). Therefore the code after the infinite loop is never executed.
Furthermore is it a busy loop (using a lot of CPU resources), so the whole apache (and computer) will hang.
You're leaving some lines out of the <?php ?> tags, so whatever is outside them will be treated as plain text. You fix it moving the closing ?> tags further down:
[this is the while(1) closing bracket]
}
// code past this line will never run, see below for details
echo $eS . ": " . $eN;
}
}
if ($bootcontents == 'success') {
echo '<center><marquee behavior="alternate" direction="left">Spinning xxx at ' . $power . '% power.</marquee></center>';
}
?> <!-- closing tag goes here -->
The page would anyway not work properly because the while(1) loop is missing an exit condition:
while(1) {
while($data = fgets($ircSocket, 128)) {
// ...
}
}
After the inner while finishes, your script keeps looping, ending up trapped in an empty, infinite loop (which would hang the server up, if it's not configured to detect and kill this kind of loophole).
On a final notice, PHP isn't probably the best tool for the job: you would be much better off with a stand-alone application.
while($data = fgets($ircSocket, 128))
This part blocks the script running until it receives data, and if somehow you're not getting data through that socket... well you're stuck there... forever... lol ok, stuck until the PHP script times out.
If that part doesn't catch, you're still stuck inside the while loop and so there is no way of ever running the part of your code that echos stuff out... so both apfelbox and Alex are correct, just not explained fully...
In order to have a infinite loop but also be able to run code outside, you would need to catch the "event" in which you want to capture and run code. All the events you want to capture would need to sit inside the while loop, or at least dispatched from the while loop to a function that would parse the input from server and respond correctly.
An even better way to do this is to utilise the observer pattern.
I really wouldn't make an IRC bot with PHP, even if you run it via commandline... PHP isn't meant to run as a long-running application.