'/path/to/lib', * 'error_reporting' => E_ALL | E_STRICT, * 'error_display' => 1, * 'html_errors' => 0, * ); * * $php = Solar::factory('Solar_Php'); * * $php->setIniFile(false) * ->setIniArray($ini) * ->runSolarCode('echo "hello world!\n"'); * * Solar::stop(); * }} * * @category Solar * * @package Solar * * @author Paul M. Jones * * @license http://opensource.org/licenses/bsd-license.php BSD * * @version $Id$ * */ class Solar_Php extends Solar_Base { /** * * Default configuration values. * * @config string php Command to invoke the PHP binary. * * @config string ini_file Which php.ini file to use; if null, use the * default php.ini file. * * @config array ini_set Override php.ini settings with these settings * instead. The element key is the .ini setting name, and the element * value is the .ini value to use. * * @config mixed solar_config When calling Solar::start(), use this as the * config value. * * @config bool echo Whether or not to echo the process output as it goes. * * @var array * */ protected $_Solar_Php = array( 'php' => 'php', 'ini_file' => null, 'ini_set' => null, 'solar_config' => null, 'echo' => null, ); /** * * Command to invoke the PHP binary. * * @var string * */ protected $_php = 'php'; /** * * Which php.ini file to use. * * Null means to use the default php.ini file, but false means to use *no* * php.ini file. * * @var string * */ protected $_ini_file = null; /** * * Override php.ini file settings with these settings. * * Format is an array of key-value pairs, where the key is the setting * name and the value is the setting value. * * @var array * */ protected $_ini_set = array(); /** * * When calling Solar::start() in the new process, use this as the $config * value. * * @var mixed * */ protected $_solar_config = null; /** * * Whether or not to echo the process output as it goes. * * @var bool * */ protected $_echo = true; /** * * After the code runs, each line of output (if any). * * @var array * */ protected $_output; /** * * After the code runs, the last line of output (if any). * * @var array * */ protected $_last_line; /** * * After the code runs, the exit status code (if any). * * Note that null is *not* the same as zero; zero is normally an "OK" * exit code, whereas null means "no exit code given". * * @var array * */ protected $_exit_code; /** * * Command-line arguments to pass to the code. * * @var array * */ protected $_argv = array(); /** * * Post-construction tasks to complete object construction. * * @return void * */ protected function _postConstruct() { parent::_postConstruct(); // populate each of these properties with its config value ... $list = array_keys($this->_Solar_Php); foreach ($list as $key) { // ... but only if not null. if ($this->_config[$key] !== null) { $var = "_$key"; $this->$var = $this->_config[$key]; } } } /** * * Sets the PHP command to call at the command line. * * @param string $php The PHP command; e.g., "/usr/local/php". * * @return Solar_Php * */ public function setPhp($php) { $this->_php = $php; return $this; } /** * * Sets the location of the php.ini file to use. * * If null, uses the default php.ini file location. * * If false, uses *no* php.ini file (the `--no-php-ini` switch). * * @param string $file The php.ini file location. * * @return Solar_Php * */ public function setIniFile($file) { if ($file !== null && $file !== false) { $file = (string) $file; } $this->_ini_file = $file; return $this; } /** * * Sets one php.ini value, overriding the php.ini file. * * @param string $key The php.ini setting name. * * @param string $val The php.ini setting value. * * @return Solar_Php * */ public function setIniVal($key, $val) { $this->_ini_set[$key] = $val; return $this; } /** * * Sets an array of php.ini values, overriding the php.ini file. * * Each key in the array is a php.ini setting name, and each value is the * corresponding php.ini value. * * @param string $list The array of php.ini key-value pairs. * * @return Solar_Php * */ public function setIniArray($list) { foreach ($list as $key => $val) { $this->_ini_set[$key] = $val; } return $this; } /** * * Add a command-line argument for the code. * * @param mixed $val The command-line argument value. * * @return Solar_Php * */ public function addArgv($val) { $this->_argv[] = $val; return $this; } /** * * Set all command-line arguments for the code at one time; clears all * previous argument values. * * @param array $array A sequential array of command-line arguments. * * @return Solar_Php * */ public function setArgv($array) { $this->_argv = (array) $array; return $this; } /** * * When calling Solar::start() in the new process, use this as the $config * value. * * @param mixed $solar_config The value to use for Solar::start(). * * @return Solar_Php * */ public function setSolarConfig($solar_config) { $this->_solar_config = $solar_config; return $this; } /** * * Turns execution process output on and off. * * @param bool $echo True to echo the process as it runs, or false to * suppress output. * * @return Solar_Php * */ public function setEcho($echo) { $this->_echo = (bool) $echo; return $this; } /** * * Runs a file as a Solar script. * * @param string $file The file to load as a Solar script. * * @return Solar_Php * */ public function runSolar($file) { $code = file_get_contents($file); return $this->runSolarCode($code); } /** * * Runs a code string as a Solar script. * * @param string $code The code to run as a Solar script. * * @return Solar_Php * */ public function runSolarCode($code) { $code = $this->_buildSolarCode($code); return $this->_run($code); } /** * * Runs the named file as the PHP code for the process. * * @param string $file The script file name. * * @return Solar_Php * */ public function run($file) { $code = file_get_contents($file); return $this->runCode($code); } /** * * Runs the given string as the PHP code for the process. * * @param string $code The script code. * * @return Solar_Php * */ public function runCode($code) { $code = $this->_buildCode($code); return $this->_run($code); } /** * * Support method to actually run the code and retain information about * the run. * * @param string $code The code to execute. * * @return Solar_Php * */ protected function _run($code) { // clean up from last run $this->_output = null; $this->_last_line = null; $this->_exit_code = null; // build the full command with PHP code $cmd = $this->_buildCommand($code); // open a process handle and send the command $handle = popen($cmd, 'rb'); // read from the handle while (! feof($handle)) { $read = fread($handle, 4096); if ($this->_echo) { echo $read; } $this->_output .= $read; } // close the handle and retain the exit code $this->_exit_code = pclose($handle); // get the last line of output. $tmp = $this->_output; $len = strlen(PHP_EOL) * -1; if (substr($tmp, $len) == PHP_EOL) { $tmp = substr($tmp, 0, $len); } $tmp = explode(PHP_EOL, $tmp); $this->_last_line = end($tmp); // done! return $this; } /** * * Gets the exit code from the separate process. * * @return int * */ public function getExitCode() { return $this->_exit_code; } /** * * Gets all lines of output from the separate process. * * @return array * */ public function getOutput() { return $this->_output; } /** * * Gets the last line of output from the separate process. * * @return string * */ public function getLastLine() { return $this->_last_line; } /** * * Builds a code string appropriate for the PHP command-line call. * * @param string $code The code to run. * * @return string The "fixed" code. * */ protected function _buildCode($code) { // trim leading and trailing space so as not to mess up the removal of // opening and closing tags. $code = trim($code); // strip long opening tag if (substr($code, 0, 5) == '') { $code = substr($code, 0, -2); } return $code; } /** * * Wraps the given code string in extra code to load, start, and stop * Solar. * * @param string $code The code to run in the separate process. * * @return string * */ protected function _buildSolarCode($code) { // the core code $code = $this->_buildCode($code); // get the solar config as a variable $solar_config = var_export($this->_solar_config, true); // wrap the code in Solar::start() and Solar::stop() $code = "require 'Solar.php'; " . "Solar::start($solar_config); " . "$code; " . "Solar::stop();"; // done! return $code; } /** * * Builds the command-line invocation of PHP. * * @param string $code The code to execute. * * @return string The PHP command with the necessary switches. * */ protected function _buildCommand($code) { // the PHP binary $cmd = $this->_php; // using a php.ini file? if ($this->_ini_file) { // non-default file or path $cmd .= " --php-ini " . escapeshellarg($this->_ini_file); } elseif ($this->_ini_file === false) { // explicitly *no* file to be used $cmd .= " --no-php-ini"; } // override php.ini values foreach ((array) $this->_ini_set as $key => $val) { $key = escapeshellarg($key); $val = escapeshellarg($val); $cmd .= " --define $key=$val"; } // add the code $cmd .= " --run " . escapeshellarg($code); foreach ($this->_argv as $val) { $cmd .= " $val"; } // done return $cmd; } }