Author: Tom Freund
Viewers: 119
Last month viewers: 2
Categories: PHP Tutorials
Read this article to learn how to implement PHP software agents that can process actions using sequences of actions defined in JSON.
Contents
Introduction
What Are Software Agents?
Defining Process Agents using JSON
Brief Introduction to the JSON syntax
PHP Functions Relevant to Agents
A Software Agent as a JSON Document
Enabling the JSON Agent Documents
The Need for Securing JSON Process Agent Documents
Conclusion
Introduction
What Are Software Agents?
Agent-oriented software is about enabling a series of actions based on sensed conditions or the context of a process.
For example, an agent is embedded in a processor, monitoring the space around an unmanned vehicle. If there is an object present, the agent can query its movement, static or moving. If moving, it can acquire its current location, speed and direction.
Defining Process Agents using JSON
Process agents can be defined through JSON documents. A process document contains the sequence of operations and physical objects used in the process. And, PHP has the constructs needed to enable agent operation through such JSON documents.
Brief Introduction to the JSON syntax
To start with, the structure of a JSON document, or object, begins with { and ends with }. Between these brackets is a list of name/value pairs with the format
<label>: <value>
<label> is a string delimited by double quotes and is the name of an attribute. Name and value pairs are separated by commas, except for the last pair in the list.
<value> can be a string, a number, true, false, or null. A number can be an integer, float, or double value. A string is any number of Unicode characters, except double quotes ("") backslash (\) or a control character delimited by double quotes. As an example, "model": "XYZ" is an attribute of a product object describing the product's model number.
<value> can also be full JSON document delimited by brackets ({,}) or an array (a list of values delimited by square brackets ([, ]) and separated by commas).
An example of a JSON document is the following description of a product,
{ "model_number": "X-6754", "design_specs": "https://acme.com/specs/X-6754.pdf", "mfg_plant": "TN", "version": 14, "distributors": ["Acme", "United", "Paramount"] }
Note that numbers are are not delimited by any character. Also, the distributors attribute is an example of an array value.
PHP Functions Relevant to Agents
To begin with, we make use of the popen and pclose functions. popen enables an executable, refered to as a session, residing in the host. It takes 2 arguments:
popen( <command>, <mode>)
where,
<command> = a full path description of an executable program as a string,
<mode> = same as the mode used for the function fopen and indicating direction of the data flow (read, write, append, etc.)
The executable is contained in the host running the PHP environment. pclose simply closes the session opened through popen and has no arguments.
In addition, we also have the function json_decode that can convert a standard JSON document into a PHP object or array. When converting to an array, it is defined as follows:
json_decode(<json_doc>, true)
where,
<json_doc> = a string representing a full JSON document as per above syntax
The second parameter is either true or false and lets the decoder know the output format; true for an array or false for an object.
A Software Agent as a JSON Document
JSON documents, as was shown in the example above, tend to be used passive structures that carry data. In effect, they act like rows in a database. But, JSON documents can be more.
As in the case of the popen function, invocation of a host resident executable can be stated as a string. So, one of the attributes in a JSON document describing a process or workflow is a physical object used in the process and associated with the invocation of that executable.
Take, for example, a JSON document that describes a process that fills a tank with a fluid, heats the fluid, and releases it from the tank once it reaches a certain temperature. So, there is:
a tank inlet valve that can be turned on or off in order to fill the tank
a tank heater that can be set to one of many levels including off
a tank outlet valve that can be turned on or off in order to drain the tank
a fluid temperature sensor acquiring the current temperature of the fluid in the tank
a fluid level sensor acquiring the current level of the fluid within the tank
The structure of the JSON document describing tank structure and operation, in effect the tank agent can be:
{ "inlet_valve" : "/home/tank/SetValve inlet", "outlet_valve": "/home/tank/SetValve outlet", "heater": "/home/tank/SetHeat" "fluid_temp": "/home/tank/GetTemp", "fluid_level": "/home/tank/GetLevel", "sequence": [ "inlet_valve", "on", "fluid_level", "<top>", "inlet_valve", "off", "heater", "<level>", "fluid_temp", "<setpoint>", "heater", "off", "outlet_valve", "on", "fluid_level", "<empty>", "outlet_valve", "off" ] }
In this JSON process agent document, the attribute sequence is standard regardless of the process specifics. In effect, it is like a reserved label in his type of document.
In this example, the sequence starts by opening the inlet valve, filling the tank with fluid, heating the fluid to pre-set temperature, and opening the outlet valve to release the heated fluid. The other attributes are physical objects used in the process defined as follows:
attribute label describing a physical object that is part of the process, and
a value that is a string containing the full path description of an executable enabling a specific physical process associated with this object.
In this example, the value of inlet_valve is an executable (SetValve) that handles the details of activating or deactivating a valve. Its parameters are:
the type of valve (inlet, outlet), and
the state of the valve (on, off).
Now, how is the executable paired with its parameters ? That takes us back to sequence. Note that the value of sequence is a JSON array.
The values in this array are pairs consisting of an attribute label and an executable parameter that is attached (concantenated) to the value associated with the attributed value. So, in the first pair, the value of the inlet_valve attrribute is attached to the next entry, on, and so on.
Following the array in the order shown provides the flow of the process: open the inlet valve until the tank is full, shut the inlet valve, heat the tank until it reaches a set point temperature, open the outlet valve until the tank reaches the empty level, close the outlet valve.
The values enclosed by "<" and ">" are parameters supplied through a JSON process configuration document. The labels between the "<" and ">" are attribute labels in the configuration document. An associated configuration document to the above example process agent document is:
{ "top": 100, "level": "mid", "setpoint": 350, "empty": 0.01 }
In this way, activating a process description starts with a JSON agent document and a JSON process configuration document.
Enabling the JSON Agent Documents
Now, what does it take to enable the process agent ? Here is a class used to load and enable a process agent description:
class ProcessCycle { public $Proc_Err; // error log for any method in this class private $Proc_Cycle; // description of the JSON process cycle document /* Load the process cycle definition. inputs: 1. The contents of a JSON process agent document 2. The contents of is associated JSON configuration document output: a configured process agent ready for use */ function __construct($Agent, $Config) { $this->Proc_Err = ""; // initialize the process error log $this->Proc_Cycle = null; // initialize the process cycle descriptor // convert the contents of the JSON process agent document to an array $this->Proc_Cycle = json_decode($Agent, true); // if there was any issue with the conversion .... if(is_null($this->Proc_Cycle)) { // issue a messsage in the error log and exit $this->Proc_Err = "\n1.The agent JSON process agent document cannot be decoded."; return; } // convert the contents of the JSON configuration document to an array $Cfg = json_decode($Config, true); // if there was any issue with the conversion .... if(is_null($Cfg)) { // issue a messsage in the error log and exit $this->Proc_Err = "\n2.The agent JSON configuration document cannot be decoded."; return; } // retrieve the cycle sequence $seq = $this->Proc_Cycle["sequence"]; // for each process object parameter .... for($i = 0; $i < count( $seq ); $i = $i + 2) { // if this is a configured value .... if(is_numeric( ereg( "<.+>", $seq[ $i + 1 ] ))) { // retrieve the label in the parameter value (between '<' and '>') $lbl = trim( substr( $seq[ $i + 1 ], 1, strlen( $seq[ $i + 1 ]) - 2)); // replace the parameter value with the configured value // using the retrieved label $seq[$i+1] = $Cfg[$lbl]; } } // replace the cycle sequence with the configured sequence $this->Proc_Cycle["sequence"] = $seq; // .... that's all, people !! } // Run the process sequence for a prescribed number of times function DoIt($CycleCount) { $RunMsgs = ""; // initialize the process runs log $this->Proc_Err = ""; // initialize the process error log $Seq = $this->Proc_Cycle["sequence"]; // get the configured process sequence for( $i = 0; $i < $CycleCount ; $i++) { $cnt = $i + 1; $RunMsgs .= "\n\n**** RUN [". $cnt ."] ****\n"; // for each sequence step .... for($j = 0; $j <count( $Seq ); $j = $j + 2) { // retrieve the executable for the process object, // attaching the configured parameter value to it // as a parameter for the executable $exec = $this->Proc_Cycle[$Seq[$j]]." ".$Seq[$j+1]; $ep = popen($exec,"r"); // enable the executable if($ep == false) // if the executable could not be enabled .... { // issue a message to the error log and exit $this->Proc_Err = "\n3. Run [".$i."]: "; $this->Proc_Err .= $exec." cannot be enabled."; return -3; } // retrieve the feedback message from the executable $msg = fgets($ep); if($msg == false) // if the feedback message failed to appear .... { // issue a message to the error log and exit $this->Proc_Err = "\n4. Run [".$i."]: "; $this->Proc_Err .= $exec." did not provide feedback."; return -4; } // add this feedback message to // the process runs log $RunMsgs .= "\n".$msg; // if the executable stream cannot be closed .... if(pclose($ep) == -1) { // issue a message to the error log and exit $this->Proc_Err = "\n5. Run [". $i. "]: "; $this->Proc_Err .= $exec." stream cannot be closed."; return -5; } } } // exit and transfer process runs log return $RunMsgs; } }
A PHP script utilizing this class passes the contents of a process agent document and associated configuration document as follows:
<?php include 'ProcessCycle.php'; $CycleCount = 3; // number of cycle runs requested // full path description of the JSON process agent and configuration documents $Docs = array("proc" => "/home/tank/tank.json", "config" => "/home/tank/tank.cfg"); // get the JSON process agent and configuration documents for the tank process $JSON = null; foreach($Docs as $key => $itm) { $fp = fopen($itm, "r") or exit("**** document ($itm) cannot be accessed"); $JSON[$key] = fread($fp,filesize($itm)) or exit("**** document ($itm) cannot be read"); fclose($fp) or exit("**** document ($itm) cannot be closed"); } // create an instance of a tank process $tank = new ProcessCycle($JSON["proc"], $JSON["config"]); if($tank->Proc_Err == "") { // run it for the prescribed number of cycles $tank_run = $tank->DoIt($CycleCount); if(!is_numeric($tank_run)) { // display the cycle runs log print("____ RUN LOG ____\n".$tank_run."\n"); } else { // display the error log during cycle run(s) print("____ RUN ERRORS ____\n".$tank->Proc_Err."\n"); } } else { // display the error log during instance creation print("____ LOAD ERRORS ____\n".$tank->Proc_Err."\n"); } ?>
In effect, a similar PHP script uses pre-defined JSON process and configuration documents in the host while the number of cycles to run can be provided via a CGI parameter.
The run log or error log can be also provided as an HTML process feedback page. The contents of the feedback for our example tank process agent document simply look like this:
**** RUN [1] **** inlet valve is open fluid level in tank now at 100 percent inlet valve is close heater set at mid fluid temperature now at 350 degrees heater set at off outlet valve is open fluid level in tank now at 0 percent outlet valve is close
These messages are supplied by the executable programs described in the example tank JSON process agent document above.
The Need for Securing JSON Process Agent Documents
A key element of enabling such process documents is maintaining a secure environment which minimizes risk of malicious or unintended use of a PHP script enabling a process.
Measures should be in place that secure access to PHP sctipts that manipulate a process via such documents; as well as control access to the JSON documents themselves.
Conclusion
A methodology for remotely enabling a process using JSON documents and PHP is to define a general process enabling class driving by a process agent document and associated configuration document in order to run a physical process.
The ProcessCycle class, along with the sample JSON documents, serves as a template that can be emulated and modified in order to illustrate the ability of PHP to manage and enable cyber-physical systems.
If you liked this article or have questions, post a comment here.
You need to be a registered user or login to post a comment
Login Immediately with your account on:
Comments:
1. But how do you read the sensors? - Dimitry Codreanu (2015-07-13 20:57)
Using PHP for many applications is something that makes it very... - 7 replies
Read the whole comment and replies
2. Doubts - Julio Villalba (2015-07-13 19:11)
questions... - 1 reply
Read the whole comment and replies