|
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
define("SERIAL_DEVICE_NOTSET", 0);
|
|
|
|
|
define("SERIAL_DEVICE_SET", 1);
|
|
|
|
|
define("SERIAL_DEVICE_OPENED", 2);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Serial port control class
|
|
|
|
|
*
|
|
|
|
|
* THIS PROGRAM COMES WITH ABSOLUTELY NO WARANTIES !
|
|
|
|
|
* USE IT AT YOUR OWN RISKS !
|
|
|
|
|
*
|
|
|
|
|
* @author R<EFBFBD>my Sanchez <thenux@gmail.com>
|
|
|
|
|
* @thanks Aur<EFBFBD>lien Derouineau for finding how to open serial ports with windows
|
|
|
|
|
* @thanks Alec Avedisyan for help and testing with reading
|
|
|
|
|
* @copyright under GPL 2 licence
|
|
|
|
|
*/
|
|
|
|
|
class phpSerial {
|
|
|
|
|
|
|
|
|
|
var $_device = null;
|
|
|
|
|
var $_windevice = null;
|
|
|
|
|
var $_dHandle = null;
|
|
|
|
|
var $_dState = SERIAL_DEVICE_NOTSET;
|
|
|
|
|
var $_buffer = "";
|
|
|
|
|
var $_os = "";
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* This var says if buffer should be flushed by sendMessage (true) or manualy (false)
|
|
|
|
|
*
|
|
|
|
|
* @var bool
|
|
|
|
|
*/
|
|
|
|
|
var $autoflush = true;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Constructor. Perform some checks about the OS and setserial
|
|
|
|
|
*
|
|
|
|
|
* @return phpSerial
|
|
|
|
|
*/
|
|
|
|
|
function phpSerial() {
|
|
|
|
|
setlocale(LC_ALL, "en_US");
|
|
|
|
|
|
|
|
|
|
$sysname = php_uname();
|
|
|
|
|
|
|
|
|
|
if (substr($sysname, 0, 5) === "Linux") {
|
|
|
|
|
$this->_os = "linux";
|
|
|
|
|
|
|
|
|
|
if ($this->_exec("stty --version") === 0) {
|
|
|
|
|
register_shutdown_function(array($this, "deviceClose"));
|
|
|
|
|
} else {
|
|
|
|
|
trigger_error("No stty availible, unable to run.", E_USER_ERROR);
|
|
|
|
|
}
|
|
|
|
|
} elseif (substr($sysname, 0, 7) === "Windows") {
|
|
|
|
|
$this->_os = "windows";
|
|
|
|
|
register_shutdown_function(array($this, "deviceClose"));
|
|
|
|
|
} else {
|
|
|
|
|
trigger_error("Host OS is neither linux nor windows, unable tu run.", E_USER_ERROR);
|
|
|
|
|
exit();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// OPEN/CLOSE DEVICE SECTION -- {START}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Device set function : used to set the device name/address.
|
|
|
|
|
* -> linux : use the device address, like /dev/ttyS0
|
|
|
|
|
* -> windows : use the COMxx device name, like COM1 (can also be used
|
|
|
|
|
* with linux)
|
|
|
|
|
*
|
|
|
|
|
* @param string $device the name of the device to be used
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
|
|
|
|
function deviceSet($device) {
|
|
|
|
|
if ($this->_dState !== SERIAL_DEVICE_OPENED) {
|
|
|
|
|
if ($this->_os === "linux") {
|
|
|
|
|
if (preg_match("@^COM(\d+):?$@i", $device, $matches)) {
|
|
|
|
|
$device = "/dev/ttyS" . ($matches[1] - 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($this->_exec("stty -F " . $device) === 0) {
|
|
|
|
|
$this->_device = $device;
|
|
|
|
|
$this->_dState = SERIAL_DEVICE_SET;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
} elseif ($this->_os === "windows") {
|
|
|
|
|
if (preg_match("@^COM(\d+):?$@i", $device, $matches) and $this->_exec(exec("mode " . $device)) === 0) {
|
|
|
|
|
$this->_windevice = "COM" . $matches[1];
|
|
|
|
|
$this->_device = "\\.\com" . $matches[1];
|
|
|
|
|
$this->_dState = SERIAL_DEVICE_SET;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
trigger_error("Specified serial port is not valid", E_USER_WARNING);
|
|
|
|
|
return false;
|
|
|
|
|
} else {
|
|
|
|
|
trigger_error("You must close your device before to set an other one", E_USER_WARNING);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Opens the device for reading and/or writing.
|
|
|
|
|
*
|
|
|
|
|
* @param string $mode Opening mode : same parameter as fopen()
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
|
|
|
|
function deviceOpen($mode = "r+b") {
|
|
|
|
|
if ($this->_dState === SERIAL_DEVICE_OPENED) {
|
|
|
|
|
trigger_error("The device is already opened", E_USER_NOTICE);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($this->_dState === SERIAL_DEVICE_NOTSET) {
|
|
|
|
|
//trigger_error("The device must be set before to be open", E_USER_WARNING);
|
|
|
|
|
trigger_error("<EFBFBD> necess<EFBFBD>rio conectar um dispositivo a porta serial!", E_USER_WARNING);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!preg_match("@^[raw]\+?b?$@", $mode)) {
|
|
|
|
|
trigger_error("Invalid opening mode : " . $mode . ". Use fopen() modes.", E_USER_WARNING);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$this->_dHandle = @fopen($this->_device, $mode);
|
|
|
|
|
|
|
|
|
|
if ($this->_dHandle !== false) {
|
|
|
|
|
stream_set_blocking($this->_dHandle, 0);
|
|
|
|
|
$this->_dState = SERIAL_DEVICE_OPENED;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$this->_dHandle = null;
|
|
|
|
|
trigger_error("Unable to open the device", E_USER_WARNING);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Closes the device
|
|
|
|
|
*
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
|
|
|
|
function deviceClose() {
|
|
|
|
|
if ($this->_dState !== SERIAL_DEVICE_OPENED) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (fclose($this->_dHandle)) {
|
|
|
|
|
$this->_dHandle = null;
|
|
|
|
|
$this->_dState = SERIAL_DEVICE_SET;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
trigger_error("Unable to close the device", E_USER_ERROR);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// OPEN/CLOSE DEVICE SECTION -- {STOP}
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// CONFIGURE SECTION -- {START}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Configure the Baud Rate
|
|
|
|
|
* Possible rates : 110, 150, 300, 600, 1200, 2400, 4800, 9600, 38400,
|
|
|
|
|
* 57600 and 115200.
|
|
|
|
|
*
|
|
|
|
|
* @param int $rate the rate to set the port in
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
|
|
|
|
function confBaudRate($rate) {
|
|
|
|
|
if ($this->_dState !== SERIAL_DEVICE_SET) {
|
|
|
|
|
trigger_error("Unable to set the baud rate : the device is either not set or opened", E_USER_WARNING);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$validBauds = array(
|
|
|
|
|
110 => 11,
|
|
|
|
|
150 => 15,
|
|
|
|
|
300 => 30,
|
|
|
|
|
600 => 60,
|
|
|
|
|
1200 => 12,
|
|
|
|
|
2400 => 24,
|
|
|
|
|
4800 => 48,
|
|
|
|
|
9600 => 96,
|
|
|
|
|
19200 => 19,
|
|
|
|
|
38400 => 38400,
|
|
|
|
|
57600 => 57600,
|
|
|
|
|
115200 => 115200
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (isset($validBauds[$rate])) {
|
|
|
|
|
if ($this->_os === "linux") {
|
|
|
|
|
$ret = $this->_exec("stty -F " . $this->_device . " " . (int) $rate, $out);
|
|
|
|
|
} elseif ($this->_os === "windows") {
|
|
|
|
|
$ret = $this->_exec("mode " . $this->_windevice . " BAUD=" . $validBauds[$rate], $out);
|
|
|
|
|
} else
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if ($ret !== 0) {
|
|
|
|
|
trigger_error("Unable to set baud rate: " . $out[1], E_USER_WARNING);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Configure parity.
|
|
|
|
|
* Modes : odd, even, none
|
|
|
|
|
*
|
|
|
|
|
* @param string $parity one of the modes
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
|
|
|
|
function confParity($parity) {
|
|
|
|
|
if ($this->_dState !== SERIAL_DEVICE_SET) {
|
|
|
|
|
trigger_error("Unable to set parity : the device is either not set or opened", E_USER_WARNING);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$args = array(
|
|
|
|
|
"none" => "-parenb",
|
|
|
|
|
"odd" => "parenb parodd",
|
|
|
|
|
"even" => "parenb -parodd",
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (!isset($args[$parity])) {
|
|
|
|
|
trigger_error("Parity mode not supported", E_USER_WARNING);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($this->_os === "linux") {
|
|
|
|
|
$ret = $this->_exec("stty -F " . $this->_device . " " . $args[$parity], $out);
|
|
|
|
|
} else {
|
|
|
|
|
$ret = $this->_exec("mode " . $this->_windevice . " PARITY=" . $parity[0], $out );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($ret === 0) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
trigger_error("Unable to set parity : " . $out[1], E_USER_WARNING);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Sets the length of a character.
|
|
|
|
|
*
|
|
|
|
|
* @param int $int length of a character (5 <= length <= 8)
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
|
|
|
|
function confCharacterLength($int) {
|
|
|
|
|
if ($this->_dState !== SERIAL_DEVICE_SET) {
|
|
|
|
|
trigger_error("Unable to set length of a character : the device is either not set or opened", E_USER_WARNING);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$int = (int) $int;
|
|
|
|
|
if ($int < 5)
|
|
|
|
|
$int = 5;
|
|
|
|
|
elseif ($int > 8)
|
|
|
|
|
$int = 8;
|
|
|
|
|
|
|
|
|
|
if ($this->_os === "linux") {
|
|
|
|
|
$ret = $this->_exec("stty -F " . $this->_device . " cs" . $int, $out);
|
|
|
|
|
} else {
|
|
|
|
|
$ret = $this->_exec("mode " . $this->_windevice . " DATA=" . $int, $out);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($ret === 0) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
trigger_error("Unable to set character length : " . $out[1], E_USER_WARNING);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Sets the length of stop bits.
|
|
|
|
|
*
|
|
|
|
|
* @param float $length the length of a stop bit. It must be either 1,
|
|
|
|
|
* 1.5 or 2. 1.5 is not supported under linux and on some computers.
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
|
|
|
|
function confStopBits($length) {
|
|
|
|
|
if ($this->_dState !== SERIAL_DEVICE_SET) {
|
|
|
|
|
trigger_error("Unable to set the length of a stop bit : the device is either not set or opened", E_USER_WARNING);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($length != 1 and $length != 2 and $length != 1.5 and ! ($length == 1.5 and $this->_os === "linux")) {
|
|
|
|
|
trigger_error("Specified stop bit length is invalid", E_USER_WARNING);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($this->_os === "linux") {
|
|
|
|
|
$ret = $this->_exec("stty -F " . $this->_device . " " . (($length == 1) ? "-" : "") . "cstopb", $out);
|
|
|
|
|
} else {
|
|
|
|
|
$ret = $this->_exec("mode " . $this->_windevice . " STOP=" . $length, $out);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($ret === 0) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
trigger_error("Unable to set stop bit length : " . $out[1], E_USER_WARNING);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Configures the flow control
|
|
|
|
|
*
|
|
|
|
|
* @param string $mode Set the flow control mode. Availible modes :
|
|
|
|
|
* -> "none" : no flow control
|
|
|
|
|
* -> "rts/cts" : use RTS/CTS handshaking
|
|
|
|
|
* -> "xon/xoff" : use XON/XOFF protocol
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
|
|
|
|
function confFlowControl($mode) {
|
|
|
|
|
if ($this->_dState !== SERIAL_DEVICE_SET) {
|
|
|
|
|
trigger_error("Unable to set flow control mode : the device is either not set or opened", E_USER_WARNING);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$linuxModes = array(
|
|
|
|
|
"none" => "clocal -crtscts -ixon -ixoff",
|
|
|
|
|
"rts/cts" => "-clocal crtscts -ixon -ixoff",
|
|
|
|
|
"xon/xoff" => "-clocal -crtscts ixon ixoff"
|
|
|
|
|
);
|
|
|
|
|
$windowsModes = array(
|
|
|
|
|
"none" => "xon=off octs=off rts=on",
|
|
|
|
|
"rts/cts" => "xon=off octs=on rts=hs",
|
|
|
|
|
"xon/xoff" => "xon=on octs=off rts=on",
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if ($mode !== "none" and $mode !== "rts/cts" and $mode !== "xon/xoff") {
|
|
|
|
|
trigger_error("Invalid flow control mode specified", E_USER_ERROR);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($this->_os === "linux")
|
|
|
|
|
$ret = $this->_exec("stty -F " . $this->_device . " " . $linuxModes[$mode], $out);
|
|
|
|
|
else
|
|
|
|
|
$ret = $this->_exec("mode " . $this->_windevice . " " . $windowsModes[$mode], $out);
|
|
|
|
|
|
|
|
|
|
if ($ret === 0)
|
|
|
|
|
return true;
|
|
|
|
|
else {
|
|
|
|
|
trigger_error("Unable to set flow control : " . $out[1], E_USER_ERROR);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Sets a setserial parameter (cf man setserial)
|
|
|
|
|
* NO MORE USEFUL !
|
|
|
|
|
* -> No longer supported
|
|
|
|
|
* -> Only use it if you need it
|
|
|
|
|
*
|
|
|
|
|
* @param string $param parameter name
|
|
|
|
|
* @param string $arg parameter value
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
|
|
|
|
function setSetserialFlag($param, $arg = "") {
|
|
|
|
|
if (!$this->_ckOpened())
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
$return = exec("setserial " . $this->_device . " " . $param . " " . $arg . " 2>&1");
|
|
|
|
|
|
|
|
|
|
if ($return[0] === "I") {
|
|
|
|
|
trigger_error("setserial: Invalid flag", E_USER_WARNING);
|
|
|
|
|
return false;
|
|
|
|
|
} elseif ($return[0] === "/") {
|
|
|
|
|
trigger_error("setserial: Error with device file", E_USER_WARNING);
|
|
|
|
|
return false;
|
|
|
|
|
} else {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// CONFIGURE SECTION -- {STOP}
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// I/O SECTION -- {START}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Sends a string to the device
|
|
|
|
|
*
|
|
|
|
|
* @param string $str string to be sent to the device
|
|
|
|
|
* @param float $waitForReply time to wait for the reply (in seconds)
|
|
|
|
|
*/
|
|
|
|
|
function sendMessage($str, $waitForReply = 0.1) {
|
|
|
|
|
$this->_buffer .= $str;
|
|
|
|
|
|
|
|
|
|
if ($this->autoflush === true)
|
|
|
|
|
$this->flush();
|
|
|
|
|
|
|
|
|
|
usleep((int) ($waitForReply * 1000000));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Reads the port until no new datas are availible, then return the content.
|
|
|
|
|
*
|
|
|
|
|
* @pararm int $count number of characters to be read (will stop before
|
|
|
|
|
* if less characters are in the buffer)
|
|
|
|
|
* @return string
|
|
|
|
|
*/
|
|
|
|
|
function readPort($count = 0) {
|
|
|
|
|
if ($this->_dState !== SERIAL_DEVICE_OPENED) {
|
|
|
|
|
trigger_error("Device must be opened to read it", E_USER_WARNING);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($this->_os === "linux") {
|
|
|
|
|
$content = "";
|
|
|
|
|
$i = 0;
|
|
|
|
|
|
|
|
|
|
if ($count !== 0) {
|
|
|
|
|
do {
|
|
|
|
|
if ($i > $count)
|
|
|
|
|
$content .= fread($this->_dHandle, ($count - $i));
|
|
|
|
|
else
|
|
|
|
|
$content .= fread($this->_dHandle, 128);
|
|
|
|
|
} while (($i += 128) === strlen($content));
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
do {
|
|
|
|
|
$content .= fread($this->_dHandle, 128);
|
|
|
|
|
} while (($i += 128) === strlen($content));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $content;
|
|
|
|
|
} elseif ($this->_os === "windows") {
|
|
|
|
|
/* Do nohting : not implented yet */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
trigger_error("Reading serial port is not implemented for Windows", E_USER_WARNING);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Flushes the output buffer
|
|
|
|
|
*
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
|
|
|
|
function flush() {
|
|
|
|
|
if (!$this->_ckOpened())
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (fwrite($this->_dHandle, $this->_buffer) !== false) {
|
|
|
|
|
$this->_buffer = "";
|
|
|
|
|
return true;
|
|
|
|
|
} else {
|
|
|
|
|
$this->_buffer = "";
|
|
|
|
|
trigger_error("Error while sending message", E_USER_WARNING);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// I/O SECTION -- {STOP}
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// INTERNAL TOOLKIT -- {START}
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
function _ckOpened() {
|
|
|
|
|
if ($this->_dState !== SERIAL_DEVICE_OPENED) {
|
|
|
|
|
trigger_error("Device must be opened", E_USER_WARNING);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function _ckClosed() {
|
|
|
|
|
if ($this->_dState !== SERIAL_DEVICE_CLOSED) {
|
|
|
|
|
trigger_error("Device must be closed", E_USER_WARNING);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function _exec($cmd, &$out = null) {
|
|
|
|
|
$desc = array(
|
|
|
|
|
1 => array("pipe", "w"),
|
|
|
|
|
2 => array("pipe", "w")
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$proc = proc_open($cmd, $desc, $pipes);
|
|
|
|
|
|
|
|
|
|
$ret = stream_get_contents($pipes[1]);
|
|
|
|
|
$err = stream_get_contents($pipes[2]);
|
|
|
|
|
|
|
|
|
|
fclose($pipes[1]);
|
|
|
|
|
fclose($pipes[2]);
|
|
|
|
|
|
|
|
|
|
$retVal = proc_close($proc);
|
|
|
|
|
|
|
|
|
|
if (func_num_args() == 2)
|
|
|
|
|
$out = array($ret, $err);
|
|
|
|
|
return $retVal;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// INTERNAL TOOLKIT -- {STOP}
|
|
|
|
|
//
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
?>
|