Location: PHPKode > scripts > FSM Chat > fsm-chat/fsmchatclass.inc.php
<?
/*

Final State Machine Chat class.

Runs a FSM on a line-oriented stream.

*/

//Run() result codes
define("FSMSTOP_OK",0);		//FSM stopped because of stream stop.
define("FSMSTOP_UNHANDLED",1);	//FSM stopped because some state is unhandled.
define("FSMSTOP_STOP",2);	//FSM stopped by a handler.

class FSMChat {

 var $FSM=array();

/*
 FSM programming method.
 $expect	- Match an input line against this regex. If match...
 $execute	- ...execute this PHP code. $STRING is an input string, $STATE is current state.
  Result can be an array:
   "REPLY" will be passed to a stream,
   "NEWSTATE" (optional) sets the new FSM state.
   "STOP" if nonzero stops FSM.
   "CONTINUE" if nonzero continues FSM search.
  If not - its result is immediately passed to a stream.
 $defaultstate	- if function did not return any state, assume this state.
 $state		- Before all, check if FSM is in this state.
*/
 function FSM($expect,$execute,$defaultstate,$state=NULL){
  $this->FSM[]=array("ex"=>$expect,"do"=>$execute,"ds"=>$defaultstate,"cs"=>$state);
 }

/*
 FSM loading function. Syntax described in README.
*/
 function LoadFSM($data){
   $dataset=explode("\n",$data);
   foreach($dataset as $line){
    if(strlen(trim($line))){
     if($line{0}=="#") continue;
     if($line{0}=="\t") { $do.=trim($line); continue; }
     $comp=explode(" ",$line);
     $cs=($comp[0]=="*")?NULL:trim($comp[0]);
     $ex=trim($comp[1]);
     $ds=trim($comp[2]);
    }elseif(strlen($ex)){
     $this->FSM($ex,$do,$ds,$cs);
     unset($ex);
     unset($do);
     unset($ds);
     unset($cs);
    }
   }
 }

/*
 FSM loading function - file wrapper.
*/
 function LoadFSMFile($file){
  $this->LoadFSM(file_get_contents($file));
 }


/*
Main loop method.
Accepts stream resource for chatting (i.e. from fopen() or fsockopen()) and initial state.
Optional debugging flag.
Returns FSMSTOP_*

Packet-oriented algorithm (best for telnet sessions)
*/ 
 function RunPacket($stream,$state,$debug=false){
  $RET=FSMSTOP_OK;
  $STATE=$state;
  if($debug)echo "Init: ".$STATE."\n--------------\n";
  while(!feof($stream)){
   $str=fread($stream,16384);
   unset($pstr);
   do{
    $pp=strpos($str,"\n");
    if($pp!==false){
     $pstr[]=substr($str,0,$pp+1);
     $str=substr($str,$pp+1);
    }elseif(strlen($str))$pstr[]=$str;
   }while($pp!==false);
   foreach($pstr as $STRING){
    if($debug)echo "Got string: ".$STRING."\n";
    $found=0;
    foreach($this->FSM as $line){
     if($debug)echo "Checking FSM record: ".print_r($line,1)."\n";
     if((!$line["cs"])or($line["cs"]==$STATE)){
      if($debug)echo "State check passed: ".$STATE." (".$line["cs"].")"."\n";
      if(preg_match($line["ex"],$STRING)){
       if($debug)echo "Line matches ".$line["ex"]."\n";
       $found=1;
       $result=eval($line["do"]);
       if(is_array($result)){
        $UP=$result["REPLY"];
        $STATE=$result["NEWSTATE"]?$result["NEWSTATE"]:($line["ds"]?$line["ds"]:$STATE);
       }else{
        $UP=$result;
        $STATE=$line["ds"]?$line["ds"]:$STATE;
       }
       if($debug)echo "Sending: ".$UP."\nNew state: ".$STATE."\n--------------\n";
       fputs($stream,$UP);
       if(is_array($result)){
        if($result["STOP"]){$RET=FSMSTOP_STOP;break 3;}
        if($result["CONTINUE"])continue;
       }
       break;
      }
     }
    }
    if(!$found){$RET=FSMSTOP_UNHANDLED;break 2;}
   }
  }
  return $RET;
 }
 
/*
Main loop method.
Accepts stream resource for chatting (i.e. from fopen() or fsockopen()) and initial state.
Optional debugging flag.
Returns FSMSTOP_*

String-oriented algorithm (will work on ttys, but doesn't catch prompts without "\n")
*/ 
 function RunString($stream,$state,$debug=false){
  $RET=FSMSTOP_OK;
  $STATE=$state;
  if($debug)echo "Init: ".$STATE."\n--------------\n";
  while(!feof($stream)){
   $STRING=fgets($stream);
    if($debug)echo "Got string: ".$STRING."\n";
    $found=0;
    foreach($this->FSM as $line){
     if($debug)echo "Checking FSM record: ".print_r($line,1)."\n";
     if((!$line["cs"])or($line["cs"]==$STATE)){
      if($debug)echo "State check passed: ".$STATE." (".$line["cs"].")"."\n";
      if(preg_match($line["ex"],$STRING)){
       if($debug)echo "Line matches ".$line["ex"]."\n";
       $found=1;
       $result=eval($line["do"]);
       if(is_array($result)){
        $UP=$result["REPLY"];
        $STATE=$result["NEWSTATE"]?$result["NEWSTATE"]:($line["ds"]?$line["ds"]:$STATE);
       }else{
        $UP=$result;
        $STATE=$line["ds"]?$line["ds"]:$STATE;
       }
       if($debug)echo "Sending: ".$UP."\nNew state: ".$STATE."\n--------------\n";
       fputs($stream,$UP);
       if(is_array($result)){
        if($result["STOP"]){$RET=FSMSTOP_STOP;break 2;}
        if($result["CONTINUE"])continue;
       }
       break;
      }
     }
    }
    if(!$found){$RET=FSMSTOP_UNHANDLED;break;}
   }
  return $RET;
 }
 
}
?>
Return current item: FSM Chat