shane           Tue Mar 25 02:45:18 2003 EDT

  Added files:                 
    /php4       README.TESTING2 run-tests-config.php 
    /php4/sapi/tests    test001.phpt test002.phpt test003.phpt 
                        test004.phpt test005.phpt test006.phpt 
                        test007.phpt 

  Modified files:              
    /php4       run-tests2.php 
  Log:
  many new enhancements to run-tests that allow for testing cgi and other
  sapi modules via http.  see README.TESTING2 for more details
  several sapi tests added
  
  
Index: php4/run-tests2.php
diff -u php4/run-tests2.php:1.7 php4/run-tests2.php:1.8
--- php4/run-tests2.php:1.7     Tue Mar 18 07:05:58 2003
+++ php4/run-tests2.php Tue Mar 25 02:45:18 2003
@@ -16,31 +16,429 @@
    | Authors: Ilia Alshanetsky <[EMAIL PROTECTED]>                             |
    |          Preston L. Bannister <[EMAIL PROTECTED]>                   |
    |          Marcus Boerger <[EMAIL PROTECTED]>                              |
+   |          Shane Caraveo <[EMAIL PROTECTED]>                               |
    |          Derick Rethans <[EMAIL PROTECTED]>                             |
    |          Sander Roobol <[EMAIL PROTECTED]>                              |
-   |          John Coggeshall <[EMAIL PROTECTED]>                              |
    | (based on version by: Stig Bakken <[EMAIL PROTECTED]>)                     |
    | (based on the PHP 3 test framework by Rasmus Lerdorf)                |
    +----------------------------------------------------------------------+
  */
+
 set_time_limit(0);
-ob_implicit_flush();
+while(@ob_end_clean());
+if (ob_get_level()) echo "Not all buffers were deleted.\n";
 error_reporting(E_ALL);
-define('PHP_QA_EMAIL', '[EMAIL PROTECTED]');
+
+/**********************************************************************
+ * QA configuration
+ */
+
+define('PHP_QA_EMAIL', '[EMAIL PROTECTED]');
 define('QA_SUBMISSION_PAGE', 'http://qa.php.net/buildtest-process.php');
 
+/**********************************************************************
+ * error messages
+ */
+
+define('PCRE_MISSING_ERROR',
+'+-----------------------------------------------------------+
+|                       ! ERROR !                           |
+| The test-suite requires that you have pcre extension      |
+| enabled. To enable this extension either compile your PHP |
+| with --with-pcre-regex or if you have compiled pcre as a  |
+| shared module load it via php.ini.                        |
++-----------------------------------------------------------+');
+define('SAFE_MODE_WARNING',
+'+-----------------------------------------------------------+
+|                       ! WARNING !                         |
+| You are running the test-suite with "safe_mode" ENABLED ! |
+|                                                           |
+| Chances are high that no test will work at all,           |
+| depending on how you configured "safe_mode" !             |
++-----------------------------------------------------------+');
+define('TMP_MISSING',
+'+-----------------------------------------------------------+
+|                       ! ERROR   !                         |
+| You must create /tmp for session tests to work!           |
+|                                                           |
++-----------------------------------------------------------+');
+define('PROC_OPEN_MISSING',
+'+-----------------------------------------------------------+
+|                       ! ERROR !                           |
+| The test-suite requires that proc_open() is available.    |
+| Please check if you disabled it in php.ini.               |
++-----------------------------------------------------------+');
+define('REQ_PHP_VERSION',
+'+-----------------------------------------------------------+
+|                       ! ERROR !                           |
+| The test-suite must be run with PHP 5 or later.           |
+| You can still test older extecutables by setting          |
+| TEST_PHP_EXECUTABLE and running this script with PHP 5.   |
++-----------------------------------------------------------+');
+/**********************************************************************
+ * information scripts
+ */
+define('PHP_INFO_SCRIPT','<?php echo "
+PHP_SAPI=" . PHP_SAPI . "
+PHP_VERSION=" . phpversion() . "
+ZEND_VERSION=" . zend_version() . "
+PHP_OS=" . PHP_OS . "
+INCLUDE_PATH=" . get_cfg_var("include_path") . "
+INI=" . realpath(get_cfg_var("cfg_file_path")) . "
+SCANNED_INI=" . (function_exists(\'php_ini_scanned_files\') ?
+                                       str_replace("\n","", php_ini_scanned_files()) :
+                                       "** not determined **") . "
+SERVER_SOFTWARE=" . $_ENV[\'SERVER_SOFTWARE\'];
+?>');
+
+define('PHP_EXTENSIONS_SCRIPT','<?php print join(get_loaded_extensions(),":"); ?>');
+define('PHP_INI_SETTINGS_SCRIPT','<?php echo serialize(ini_get_all()); ?>');
+
+/**********************************************************************
+ * various utility functions
+ */
+
+function save_to_file($filename,$text)
+{
+       $fp = @fopen($filename,'w')
+               or die("Cannot open file '" . $filename . "' (save_to_file)");
+       fwrite($fp,$text);
+       fclose($fp);
+}
+
+function settings2array($settings, &$ini_settings)
+{
+       foreach($settings as $setting) {
+               if (strpos($setting, '=')!==false) {
+                       $setting = explode("=", $setting, 2);
+                       $name = trim($setting[0]);
+                       $value = trim($setting[1]);
+                       $ini_settings[$name] = $value;
+               }
+       }
+}
+
+function settings2params(&$ini_settings)
+{
+       $settings = '';
+       if (count($ini_settings)) {
+               foreach($ini_settings as $name => $value) {
+                       $value = addslashes($value);
+                       $settings .= " -d \"".strtolower($name)."=$value\"";
+               }
+       }
+       return $settings;
+}
+
+function generate_diff($wanted,$output)
+{
+       $w = explode("\n", $wanted);
+       $o = explode("\n", $output);
+       $w1 = array_diff_assoc($w,$o);
+       $o1 = array_diff_assoc($o,$w);
+       $w2 = array();
+       $o2 = array();
+       foreach($w1 as $idx => $val) $w2[sprintf("%03d<",$idx)] = sprintf("%03d- ", 
$idx+1).$val;
+       foreach($o1 as $idx => $val) $o2[sprintf("%03d>",$idx)] = sprintf("%03d+ ", 
$idx+1).$val;
+       $diff = array_merge($w2, $o2);
+       ksort($diff);
+       return implode("\r\n", $diff);
+}
+
+function mkpath($path,$mode = 0700) {
+       $dirs = split('[\\|/]',realpath($path));
+       $path = $dirs[0];
+       for($i = 1;$i < count($dirs);$i++) {
+               $path .= '/'.$dirs[$i];
+               @mkdir($path,$mode);
+       }
+}
+
+function copyfiles($src,$new) {
+       $d = dir($src);
+       while (($entry = $d->read())) {
+               if (is_file("$src/$entry"))
+                       copy("$src/$entry","$new/$entry");
+       }
+       $d->close();
+}
+
+function post_result_data($query,$data)
+{
+       $url = QA_SUBMISSION_PAGE.'?'.$query;
+       $post = "php_test_data=" . urlencode(base64_encode(preg_replace("/[\\x00]/", 
"[0x0]", $data)));
+       $r = new HTTPRequest($url,NULL,NULL,$post);
+       return $this->response_headers['Status']=='200';
+} 
+
+
+function execute($command, $args=NULL, $input=NULL, $cwd=NULL, $env=NULL)
+{
+       $data = "";
+       
+       if (gettype($args)=='array') {
+               $args = join($args,' ');
+       }
+       $commandline = "$command $args";
+       $proc = proc_open($commandline, array(
+                               0 => array('pipe', 'r'),
+                               1 => array('pipe', 'w')),
+                               $pipes, $cwd, $env);
+
+       if (!$proc)
+               return false;
+
+       if ($input) {
+               $out = fwrite($pipes[0],$input);
+               if ($out != strlen($input)) {
+                       return NULL;
+               }
+       }
+       
+       fclose($pipes[0]);
+
+       while (true) {
+               /* hide errors from interrupted syscalls */
+               $r = $pipes;
+               $w = null;
+               $e = null;
+               $n = @stream_select($r, $w, $e, 60);
+
+               if ($n == 0) {
+                       /* timed out */
+                       $data .= "\n ** ERROR: process timed out **\n";
+                       proc_terminate($proc);
+                       return $data;
+               } else if ($n) {
+                       $line = fread($pipes[1], 8192);
+                       if (strlen($line) == 0) {
+                               /* EOF */
+                               break;
+                       }
+                       $data .= $line;
+               }
+       }
+       $code = proc_close($proc);
+       return $data;
+}
+
+function executeCode($php, $ini_overwrites, $code, $remove_headers=true, $cwd=NULL, 
$env=NULL)
+{
+       $params = NULL;
+       if ($ini_overwrites) {
+               $info_params = array();
+               settings2array($ini_overwrites,$info_params);
+               $params = settings2params($info_params);
+       }
+       $out = execute($php, $params, $code, $cwd, $env);
+       // kill the headers
+       if ($remove_headers && preg_match("/^(.*?)\r?\n\r?\n(.*)/s", $out, $match)) {
+               $out = $match[2];
+       }
+       return $out;
+}
+
+
+/**********************************************************************
+ * a simple request class that lets us handle http based tests
+ */
+
+class HTTPRequest
+{
+    var $headers = array();
+    var $timeout = 4;
+    var $urlparts = NULL;
+    var $url = '';
+    var $userAgent = 'PHP-Test-Harness';
+    var $options = array();
+    var $postdata = NULL;
+    var $errmsg = '';
+    var $errno = 0;
+    var $response;
+    var $response_headers;
+    var $outgoing_payload;
+    var $incoming_payload = '';
+
+    /*
+    URL is the full url
+    headers is assoc array of outgoing http headers
+    
+    options may include
+    timeout
+    proxy_host
+    proxy_port
+    proxy_user
+    proxy_pass
+    method (GET|POST)
+    
+    post data is, well, post data.  It is not processed so
+        multipart stuff must be prepared before calling this
+        (or add it to class)
+    */
+    function HTTPRequest($URL, $headers=array(), $options=array(), $postdata=NULL)
+    {
+        $this->urlparts = @parse_url($URL);
+        $this->url = $URL;
+        $this->options = $options;
+        $this->headers = $headers;
+        $this->postdata = &$postdata;
+        $this->doRequest();
+    }
+    
+    function doRequest()
+    {
+        if (!$this->_validateUrl()) return;
+        
+        if (isset($this->options['timeout'])) 
+            $this->timeout = (int)$this->options['timeout'];
+    
+        $this->_sendHTTP();
+    }
+
+    function _validateUrl()
+    {
+        if ( ! is_array($this->urlparts) ) {
+            return FALSE;
+        }
+        if (!isset($this->urlparts['host'])) {
+            $this->urlparts['host']='127.0.0.1';
+        }
+        if (!isset($this->urlparts['port'])) {
+            $this->urlparts['port'] = 80;
+        }
+        if (!isset($this->urlparts['path']) || !$this->urlparts['path'])
+            $this->urlparts['path'] = '/';
+        return TRUE;
+    }
+    
+    function _parseResponse()
+    {
+        if (preg_match("/^(.*?)\r?\n\r?\n(.*)/s", $this->incoming_payload, $match)) {
+            $this->response = $match[2];
+            if (preg_match("/^HTTP\/1\.. (\d+).*/s",$match[1],$status) && 
!$status[1]) {
+                    $this->errmsg = "HTTP Response $status[1] Not Found";
+                    return FALSE;
+            }
+            $rh = preg_split("/[\n\r]+/",$match[1]);
+            $this->response_headers = array();
+            foreach ($rh as $line) {
+                if (strpos($line, ':')!==false) {
+                    $line = explode(":", $line, 2);
+                    $this->response_headers[trim($line[0])] = trim($line[1]);
+                }
+            }
+            $this->response_headers['Status']=$status[1];
+            // if no content, return false
+            if(strlen($this->response) > 0) return TRUE;
+        }
+        $this->errmsg = 'Invalid HTTP Response';
+        return FALSE;
+    }
+    
+    function &_getRequest()
+    {
+        $fullpath = $this->urlparts['path'].
+                    (isset($this->urlparts['query'])?'?'.$this->urlparts['query']:'').
+                    
(isset($this->urlparts['fragment'])?'#'.$this->urlparts['fragment']:'');
+        if (isset($this->options['proxy_host'])) {
+            $fullpath = 
'http://'.$this->urlparts['host'].':'.$this->urlparts['port'].$fullpath;
+        }
+        if (isset($this->options['proxy_user'])) {
+            $headers['Proxy-Authorization'] = 'Basic ' . 
base64_encode($this->options['proxy_user'].":".$this->options['proxy_pass']);
+        }
+        $headers['User-Agent'] = $this->userAgent;
+        $headers['Host'] = $this->urlparts['host'];
+        $headers['Content-Length'] = strlen($this->postdata);
+        $headers['Content-Type'] = 'application/x-www-form-urlencoded';
+        if (isset($this->headers)) {
+            $headers = array_merge($headers, $this->headers);
+        }
+        $headertext = '';
+        foreach ($headers as $k => $v) {
+            $headertext .= "$k: $v\r\n";
+        }
+        $method = 
trim($this->options['method'])?strtoupper(trim($this->options['method'])):'GET';
+        $this->outgoing_payload = 
+                "$method $fullpath HTTP/1.0\r\n".
+                $headertext."\r\n".
+                $this->postdata;
+        return $this->outgoing_payload;
+    }
+    
+    function &_sendHTTP()
+    {
+        $this->_getRequest();
+        $host = $this->urlparts['host'];
+        $port = $this->urlparts['port'];
+        if (isset($this->options['proxy_host'])) {
+            $host = $this->options['proxy_host'];
+            $port = 
isset($this->options['proxy_port'])?$this->options['proxy_port']:8080;
+        }
+        // send
+        if ($this->timeout > 0) {
+            $fp = fsockopen($host, $port, $this->errno, $this->errmsg, 
$this->timeout);
+        } else {
+            $fp = fsockopen($host, $port, $this->errno, $this->errmsg);
+        }
+        if (!$fp) {
+            $this->errmsg = "Connect Error to $host:$port";
+            return NULL;
+        }
+        if ($this->timeout > 0) {
+            // some builds of php do not support this, silence
+            // the warning
+            @socket_set_timeout($fp, $this->timeout);
+        }
+        if (!fputs($fp, $this->outgoing_payload, strlen($this->outgoing_payload))) {
+            $this->errmsg = "Error Sending Request Data to $host";
+            return NULL;
+        }
+        
+        while ($data = fread($fp, 32768)) {
+            $this->incoming_payload .= $data;
+        }
+
+        fclose($fp);
+
+        $this->_parseResponse();
+    }
+
+# a simple test case
+#$r = new HTTPRequest('http://localhost:81/info.php/path/info');
+#print_r($r->response_headers);
+#print $r->response;
+
+} // end HTTPRequest
+
+
+/**********************************************************************
+ * main test harness
+ */
 
 class testHarness {
        var $cwd;
-       var $TEST_PHP_SRCDIR;
-       var $TEST_PHP_EXECUTABLE;
-       var $TEST_PHP_LOG_FORMAT;
-       var $TEST_PHP_DETAILED;
-       var $TEST_PHP_ERROR_STYLE;
-       var $REPORT_EXIT_STATUS;
-       var $NO_PHPTEST_SUMMARY;
-       var $NO_INTERACTION;
+       var $xargs = array(
+               #arg         env var                value        default   description
+               'c' => array(''                    ,'file'       ,NULL    
,'configuration file, see run-tests-config.php for example'),
+               'd' => array('TEST_PATHS'          ,'paths'      ,NULL    ,'colon 
seperate path list'),
+               'e' => array('TEST_PHP_ERROR_STYLE','EMACS|MSVC' ,'EMACS' ,'editor 
error style'),
+               'h' => array(''                    ,''           ,NULL    ,'this 
help'),
+               'i' => array('PHPRC'               ,'path|file'  ,NULL    ,'ini file 
to use for tests (sets PHPRC)'),
+               'l' => array('TEST_PHP_LOG_FORMAT' ,'string'     ,'LEODC' ,'any 
combination of CDELO'),
+               'm' => array('TEST_BASE_PATH'      ,'path'       ,NULL    ,'copy tests 
to this path before testing'),
+               'n' => array('NO_PHPTEST_SUMMARY'  ,''           ,0       ,'do not 
print test summary'),
+               'p' => array('TEST_PHP_EXECUTABLE' ,'path'       ,NULL    ,'php 
executable to be tested'),
+               'q' => array('NO_INTERACTION'      ,''           ,0       ,'no console 
interaction (ie dont contact QA)'),
+               'r' => array('REPORT_EXIT_STATUS'  ,''           ,0       ,'exit with 
status at end of execution'),
+               's' => array('TEST_PHP_SRCDIR'     ,'path'       ,NULL    ,'path to 
php source code'),
+               't' => array('TEST_PHP_DETAILED'   ,'number'     ,0       ,'level of 
detail output to dump'),
+               'u' => array('TEST_WEB_BASE_URL'   ,'url'        ,''      ,'base url 
for http testing'),
+               'v' => array('TEST_CONTEXT_INFO'   ,''           ,0       ,'view text 
executable context info'),
+               'w' => array('TEST_WEB'            ,''           ,0       ,'run tests 
via http'),
+               'x' => array('TEST_WEB_EXT'        ,'file ext'   ,'php'   ,'http file 
extension to use')
+               );
        
+       var $conf = array();
        var $test_to_run = array();
        var $test_files = array();
        var $test_results = array();
@@ -49,9 +447,13 @@
        var $exts_tested = 0;
        var $exts_skipped = 0;
        var $ignored_by_ext = 0;
-       var $test_dirs = array('tests', 'pear', 'ext');
+       var $test_dirs = array('tests', 'pear', 'ext', 'sapi');
        var $start_time;
        var $end_time;
+       var $exec_info;
+       var $test_executable_iscgi = false;
+       var $inisettings; // the test executables settings, used for web tests
+       var $iswin32 = false;
        
        var $ddash = 
"=====================================================================";
        var $sdash = 
"---------------------------------------------------------------------";
@@ -79,36 +481,122 @@
                        'auto_append_file'=>'',
                        'magic_quotes_runtime'=>'0',
                );      
-       var $env = array(
-               'REDIRECT_STATUS'=>'',
-               'QUERY_STRING'=>'',
-               'PATH_TRANSLATED'=>'',
-               'SCRIPT_FILENAME'=>'',
-               'REQUEST_METHOD'=>'',
-               'CONTENT_TYPE'=>'',
-               'CONTENT_LENGTH'=>'',
-               );
+       var $env = array();
        var $info_params = array();
 
        function testHarness() {
-               $this->checkPCRE();
-               $this->checkSafeMode();
+               $this->iswin32 = substr(PHP_OS, 0, 3) == "WIN";
+               $this->checkRequirements();
+               $this->env = $_ENV;
                $this->removeSensitiveEnvVars();
+               
                $this->initializeConfiguration();
                $this->parseArgs();
+               $this->setTestPaths();
                # change to working directory
-               if ($this->TEST_PHP_SRCDIR) {
-                       @chdir($this->TEST_PHP_SRCDIR);
+               if ($this->conf['TEST_PHP_SRCDIR']) {
+                       @chdir($this->conf['TEST_PHP_SRCDIR']);
                }
                $this->cwd = getcwd();
-               $this->isExecutable();
+               
+               if (!$this->conf['TEST_PHP_SRCDIR'])
+                       $this->conf['TEST_PHP_SRCDIR'] = $this->cwd;
+               if (!$this->conf['TEST_BASE_PATH'] && $this->conf['TEST_PHP_SRCDIR'])
+                       $this->conf['TEST_BASE_PATH'] = $this->conf['TEST_PHP_SRCDIR'];
+               if ($this->iswin32) {
+                       $this->conf['TEST_PHP_SRCDIR'] = 
str_replace('/','\\',$this->conf['TEST_PHP_SRCDIR']);
+                       $this->conf['TEST_BASE_PATH'] = 
str_replace('/','\\',$this->conf['TEST_BASE_PATH']);
+               }
+               
+               if (!$this->conf['TEST_WEB'] && 
!is_executable($this->conf['TEST_PHP_EXECUTABLE'])) {
+                       $this->error("invalid PHP executable specified by 
TEST_PHP_EXECUTABLE  = " .
+                                       $this->conf['TEST_PHP_EXECUTABLE']);
+                       return false;
+               }
+               
                $this->getInstalledExtensions();
+               $this->getExecutableInfo();
+               $this->getExecutableIniSettings();
+               $this->test_executable_iscgi = 
strncmp($this->exec_info['PHP_SAPI'],'cgi',3)==0;
+               $this->calculateDocumentRoot();
+
+               // add TEST_PHP_SRCDIR to the include path, this facilitates
+               // tests including files from src/tests
+               //$this->ini_overwrites['include_path'] = 
$this->cwd.($this->iswin32?';.;':':.:').$this->exec_info['INCLUDE_PATH'];
+               
+               $params = array();
+               settings2array($this->ini_overwrites,$params);
+               $this->info_params = settings2params($params);
+               
                $this->contextHeader();
+               if ($this->conf['TEST_CONTEXT_INFO']) return;
                $this->loadFileList();
+               $this->moveTestFiles();
                $this->run();
                $this->summarizeResults();
        }
 
+       function getExecutableIniSettings()
+       {
+               $out = $this->runscript(PHP_INI_SETTINGS_SCRIPT,true);
+               $this->inisettings = unserialize($out);
+       }
+       
+       function getExecutableInfo()
+       {
+               $out = $this->runscript(PHP_INFO_SCRIPT,true);
+               $out = preg_split("/[\n\r]+/",$out);
+               $info = array();
+               foreach ($out as $line) {
+                       if (strpos($line, '=')!==false) {
+                               $line = explode("=", $line, 2);
+                               $name = trim($line[0]);
+                               $value = trim($line[1]);
+                               $info[$name] = $value;
+                       }
+               }
+               $this->exec_info = $info;
+       }
+       
+       function getInstalledExtensions()
+       {
+               // get the list of installed extensions
+               $out = $this->runscript(PHP_EXTENSIONS_SCRIPT,true);
+               $this->exts_to_test = split(":",$out);
+               sort($this->exts_to_test);
+               $this->exts_tested = count($this->exts_to_test);
+       }
+
+       // if running local, calls executeCode,
+       // otherwise does an http request
+       function runscript($script,$removeheaders=false,$cwd=NULL)
+       {
+               if ($this->conf['TEST_WEB']) {
+                       $pi = "/testscript.{$this->conf['TEST_WEB_EXT']}";
+                       if (!$cwd) $cwd = $this->conf['TEST_BASE_PATH'];
+                       $tmp_file = "$cwd$pi";
+                       $pi = substr($cwd,strlen($this->conf['TEST_BASE_PATH'])).$pi;
+                       $url = "{$this->conf['TEST_WEB_BASE_URL']}$pi";
+                       save_to_file($tmp_file,$script);
+                       $fd = fopen($url, "rb");
+                       $out = '';
+                       if ($fd) {
+                               while (!feof($fd))
+                                       $out .= fread($fd, 8192);
+                               fclose($fd);
+                       }
+                       #unlink($tmp_file);
+                       if ($removeheaders &&
+                               preg_match("/^(.*?)\r?\n\r?\n(.*)/s", 
$this->incoming_payload, $match)) {
+                                       return $match[2];
+                       }
+                       return $out;
+               } else {
+                       return 
executeCode($this->conf['TEST_PHP_EXECUTABLE'],$this->ini_overwrites, 
$script,$removeheaders,$cwd,$this->env);
+               }
+       }
+
+       
        // Use this function to do any displaying of text, so that
        // things can be over-written as necessary.
        
@@ -124,134 +612,130 @@
        function showstatus($item, $status, $reason = '') {
            
            switch($status) {
-               
                case 'PASSED':
-               
                    $this->writemsg("PASSED: $item ($reason)\n");
-                   
                    break;
-                   
                case 'FAILED':
-                   
                    $this->writemsg("FAILED: $item ($reason)\n");
-                   
                    break;
-                   
                case 'SKIPPED':
-               
                    $this->writemsg("SKIPPED: $item ($reason)\n");
                    break;
-                   
            }
-           
        }
        
+       
        function help()
        {
-               return "usage: php run-tests.php [options]\n".
-                               "  -d testpaths            colon seperate path list\n".
-                               "  -s path                 to php sources\n".
-                               "  -p path                 to php executable to be 
tested\n".
-                               "  -l logformat            LEOD\n".
-                               "  -t 0|1                  detailed reporting\n".
-                               "  -e string               error style\n".
-                               "  -r 0|1                  report exit status\n".
-                               "  -n 0|1                  print test summary\n".
-                               "  -i 0|1                  console interaction\n".
-                               "  -h                      this help\n";
+               $usage = "usage: php run-tests.php [options]\n";
+               foreach ($this->xargs as $arg=>$arg_info) {
+                       $usage .= sprintf(" -%s  %-12s 
%s\n",$arg,$arg_info[1],$arg_info[3]);
+               }
+               return $usage;
        }
        
        function parseArgs() {
                global $argc;
                global $argv;
+               global $_SERVER;
                
                if (!isset($argv)) {
                        $argv = $_SERVER['argv'];
                        $argc = $_SERVER['argc'];
                }
-               if (!isset($argc) || $argc < 2) return;
        
+               $conf = NULL;
                for ($i=1; $i<$argc;) {
                        if ($argv[$i][0] != '-') continue;
                        $opt = $argv[$i++][1];
-                       $value = 0;
+                       if (isset($value)) unset($value);
                        if (@$argv[$i][0] != '-') {
                                @$value = $argv[$i++];
                        }
                        switch($opt) {
-                               case 'd':
-                                       $this->test_dirs = array();
-                                       $paths = split(':|;',$value);
-                                       foreach($paths as $path) {
-                                               $this->test_dirs[] = realpath($path);
-                                       }
-                                       break;
-                               case 's':
-                                       $this->TEST_PHP_SRCDIR = $value;
-                                       break;
-                               case 'p':
-                                       $this->TEST_PHP_EXECUTABLE = $value;
-                                       break;
-                               case 'l':
-                                       $this->TEST_PHP_LOG_FORMAT = $value;
-                                       break;
-                               case 't':
-                                       $this->TEST_PHP_DETAILED = $value;
-                                       break;
-                               case 'e':
-                                       $this->TEST_PHP_ERROR_STYLE = 
strtoupper($value);
-                                       break;
-                               case 'r':
-                                       $this->REPORT_EXIT_STATUS = $value;
-                                       break;
-                               case 'n':
-                                       $this->NO_PHPTEST_SUMMARY = $value;
-                                       break;
-                               case 'i':
-                                       $this->NO_INTERACTION = $value;
-                                       break;
-                               case 'h':
-                                       print $this->help();
-                                       exit(0);
+                       case 'c':
+                               /* TODO: Implement configuraiton file */
+                               include($value);
+                               if (!isset($conf)) {
+                                       $this->writemsg("Invalid configuration 
file\n");
+                                       exit(1);
+                               }
+                               $this->conf = array_merge($this->conf,$conf);
+                               break;
+                       case 'e':
+                               $this->conf['TEST_PHP_ERROR_STYLE'] = 
strtoupper($value);
+                               break;
+                       case 'h':
+                               print $this->help();
+                               exit(0);
+                       default:
+                               if ($this->xargs[$opt][1] && isset($value))
+                                       $this->conf[$this->xargs[$opt][0]] = $value;
+                               else if (!$this->xargs[$opt][1])
+                                       $this->conf[$this->xargs[$opt][0]] = 
isset($value)?$value:1;
+                               else
+                                       $this->error("Invalid argument setting for 
argument $opt, should be [{$this->xargs[$opt][1]}]\n");
+                               break;
                        }
                }
+               
+               // set config into environment, this allows
+               // executed tests to find out about the test
+               // configurations.  config file or args overwrite
+               // env var config settings
+               $this->env = array_merge($this->env,$this->conf);
+               if (!$this->conf['TEST_WEB'] && !$this->conf['TEST_PHP_EXECUTABLE']) {
+                       $this->writemsg($this->help());
+                       exit(0);
+               }
        }
-       
+
        function removeSensitiveEnvVars()
        {
                # delete sensitive env vars
-               putenv('SSH_CLIENT=deleted');
-               putenv('SSH_AUTH_SOCK=deleted');
-               putenv('SSH_TTY=deleted');
+               $this->env['SSH_CLIENT']='deleted';
+               $this->env['SSH_AUTH_SOCK']='deleted';
+               $this->env['SSH_TTY']='deleted';
+       }
+       
+       function setEnvConfigVar($name)
+       {
+               if (isset($this->env[$name])) {
+                       $this->conf[$name] = $this->env[$name];
+               }
        }
        
        function initializeConfiguration()
        {
-               # get config from environment
-               $this->TEST_PHP_SRCDIR = getenv('TEST_PHP_SRCDIR');
-               $this->TEST_PHP_EXECUTABLE = getenv('TEST_PHP_EXECUTABLE');
-               $this->TEST_PHP_LOG_FORMAT = getenv('TEST_PHP_LOG_FORMAT');
-               if (!$this->TEST_PHP_LOG_FORMAT) $this->TEST_PHP_LOG_FORMAT = 'LEOD';
-               $this->TEST_PHP_DETAILED = getenv('TEST_PHP_DETAILED');
-               $this->TEST_PHP_ERROR_STYLE = 
strtoupper(getenv('TEST_PHP_ERROR_STYLE'));
-               $this->REPORT_EXIT_STATUS = getenv('REPORT_EXIT_STATUS');
-               $this->NO_PHPTEST_SUMMARY = getenv('NO_PHPTEST_SUMMARY');
-               $this->NO_INTERACTION = getenv('NO_INTERACTION');
+               foreach ($this->xargs as $arg=>$arg_info) {
+                       if ($arg_info[0]) {
+                               # initialize the default setting
+                               $this->conf[$arg_info[0]]=$arg_info[2];
+                               # get config from environment
+                               $this->setEnvConfigVar($arg_info[0]);
+                       }
+               }
        }
 
-       function getInstalledExtensions()
+       function setTestPaths()
        {
-               // get the list of installed extensions
-               $this->exts_to_test = get_loaded_extensions();
-               $this->exts_tested = count($this->exts_to_test);
-               sort($this->exts_to_test);
+               // configure test paths from config file or command line
+               if (@$this->conf['TEST_PATHS']) {
+                       $this->test_dirs = array();
+                       if ($this->iswin32) {
+                               $paths = split(';',$this->conf['TEST_PATHS']);
+                       } else {
+                               $paths = split(':|;',$this->conf['TEST_PATHS']);
+                       }
+                       foreach($paths as $path) {
+                               $this->test_dirs[] = realpath($path);
+                       }
+               }
        }
-
-       function test_sort($a, $b) {
-               global $cwd;
        
-               $ta = strpos($a, "{$cwd}/tests")===0 ? 1 + (strpos($a, 
"{$cwd}/tests/run-test")===0 ? 1 : 0) : 0;
-               $tb = strpos($b, "{$cwd}/tests")===0 ? 1 + (strpos($b, 
"{$cwd}/tests/run-test")===0 ? 1 : 0) : 0;
+       function test_sort($a, $b) {
+               $ta = strpos($a, "{$this->cwd}/tests")===0 ? 1 + (strpos($a, 
"{$this->cwd}/tests/run-test")===0 ? 1 : 0) : 0;
+               $tb = strpos($b, "{$this->cwd}/tests")===0 ? 1 + (strpos($b, 
"{$this->cwd}/tests/run-test")===0 ? 1 : 0) : 0;
                if ($ta == $tb) {
                        return strcmp($a, $b);
                } else {
@@ -259,71 +743,26 @@
                }
        }
 
-       function isExecutable() {
-               if (!$this->TEST_PHP_EXECUTABLE ||
-                       (function_exists('is_executable') &&
-                       [EMAIL PROTECTED]($this->TEST_PHP_EXECUTABLE))) {
-                       $this->error("invalid PHP executable specified by 
TEST_PHP_EXECUTABLE  = " .
-                                       $this->TEST_PHP_EXECUTABLE);
-                       return false;
+       function checkRequirements() {
+               if (version_compare(phpversion(), "5.0") < 0) {
+                       $this->writemsg(REQ_PHP_VERSION);
+                       exit;
+               }
+               if (!file_exists("/tmp")) {
+                       $this->writemsg(TMP_MISSING);
+                       exit;
+               }
+               if (!function_exists("proc_open")) {
+                       $this->writemsg(PROC_OPEN_MISSING);
+                       exit;
                }
-               return true;
-       }
-       
-       function checkPCRE() {
                if (!extension_loaded("pcre")) {
-                       echo <<<NO_PCRE_ERROR
-
-+-----------------------------------------------------------+
-|                       ! ERROR !                           |
-| The test-suite requires that you have pcre extension      |
-| enabled. To enable this extension either compile your PHP |
-| with --with-pcre-regex or if you have compiled pcre as a  |
-| shared module load it via php.ini.                        |
-+-----------------------------------------------------------+
-
-NO_PCRE_ERROR;
-               exit;
+                       $this->writemsg(PCRE_MISSING_ERROR);
+                       exit;
                }
-       }
-       
-       function checkSafeMode() {
                if (ini_get('safe_mode')) {
-                       $safewarn =  <<< SAFE_MODE_WARNING
-
-+-----------------------------------------------------------+
-|                       ! WARNING !                         |
-| You are running the test-suite with "safe_mode" ENABLED ! |
-|                                                           |
-| Chances are high that no test will work at all,           |
-| depending on how you configured "safe_mode" !             |
-+-----------------------------------------------------------+
-
-
-SAFE_MODE_WARNING;
-                       writemsg($safewarn);
-                       return true;
+                       $this->writemsg(SAFE_MODE_WARNING);
                }
-               return false;
-       }
-       
-       function getExecutableInfo()
-       {
-               $info_file = realpath(dirname(__FILE__)) . '/run-test-info.php';
-               @unlink($info_file);
-               $php_info = '<?php echo "
-PHP_SAPI    : " . PHP_SAPI . "
-PHP_VERSION : " . phpversion() . "
-ZEND_VERSION: " . zend_version() . "
-PHP_OS      : " . PHP_OS . "
-INI actual  : " . realpath(get_cfg_var("cfg_file_path")) . "
-More .INIs  : " . (function_exists(\'php_ini_scanned_files\') ? str_replace("\n","", 
php_ini_scanned_files()) : "** not determined **"); ?>';
-               $this->save_text($info_file, $php_info);
-               $this->settings2array($this->ini_overwrites,$this->info_params);
-               $this->settings2params($this->info_params);
-               $php_info = `{$this->TEST_PHP_EXECUTABLE} {$this->info_params} -f 
$info_file`;
-               @unlink($info_file);
-               return $php_info;
        }
        
        //
@@ -331,34 +770,75 @@
        //
        function contextHeader()
        {
-               $ini='';
-               if (function_exists('php_ini_scanned_files')) {
-                       $ini=php_ini_scanned_files();
+               $info = '';
+               foreach ($this->exec_info as $k=>$v) {
+                       $info .= sprintf("%-20.s: %s\n",$k,$v);
+               }
+               $exts = '';
+               foreach ($this->exts_to_test as $ext) {
+                       $exts .="$ext\n              ";
                }
-
-               $info = $this->getExecutableInfo();
-               
-               $this->writemsg("\n$this->ddash\n".
-                       "CWD         : {$this->cwd}\n".
-                       "PHP         : {$this->TEST_PHP_EXECUTABLE} $info\n".
-                       "Test Dirs   : ");
+               $dirs = '';
                foreach ($this->test_dirs as $test_dir) {
-                       $this->writemsg("$test_dir\n              ");
+                       $dirs .= "$test_dir\n              ";
                }
-               $this->writemsg("\n$this->ddash\n");
+               $conf = '';
+               foreach ($this->conf as $k=>$v) {
+                       $conf .= sprintf("%-20.s: %s\n",$k,$v);
+               }
+               
+               $exeinfo = '';
+               if (!$this->conf['TEST_WEB'])
+                       $exeinfo = "CWD                 : {$this->cwd}\n".
+                                       "PHP                 : 
{$this->conf['TEST_PHP_EXECUTABLE']}\n";
+               
+               $this->writemsg("\n$this->ddash\n".
+                       "$exeinfo$info\n".
+                       "Test Harness Configuration:\n$conf\n".
+                       "Extensions  : $exts\n".
+                       "Test Dirs   : $dirs\n".
+                       "$this->ddash\n");
        }
        
        function loadFileList()
        {
                foreach ($this->test_dirs as $dir) {
-                       print "searching {$this->cwd}/{$dir}\n";
-                       $this->findFilesInDir("{$this->cwd}/$dir", ($dir == 'ext'));
-                       #$this->findFilesInDir($dir, ($dir == 'ext'));
+                       if (is_dir($dir)) {
+                               $this->findFilesInDir($dir, ($dir == 'ext'));
+                       } else {
+                               $this->test_files[] = $dir;
+                       }
                }
                usort($this->test_files,array($this,"test_sort"));
                $this->writemsg("found ".count($this->test_files)." files\n");
        }
        
+       function moveTestFiles()
+       {
+               if (!$this->conf['TEST_BASE_PATH'] ||
+                       $this->conf['TEST_BASE_PATH'] == 
$this->conf['TEST_PHP_SRCDIR']) return;
+               $this->writemsg("moving files from {$this->conf['TEST_PHP_SRCDIR']} to 
{$this->conf['TEST_BASE_PATH']}\n");
+               $l = strlen($this->conf['TEST_PHP_SRCDIR']);
+               $files = array();
+               $dirs = array();
+               foreach ($this->test_files as $file) {
+                       if (strpos($file,$this->conf['TEST_PHP_SRCDIR'])==0) {
+                               $newlocation = 
$this->conf['TEST_BASE_PATH'].substr($file,$l);
+                               $files[] = $newlocation;
+                               $dirs[dirname($file)] = dirname($newlocation);
+                       } else {
+                               // XXX what to do with test files outside the
+                               // php source directory?  Need to map them into
+                               // the new directory somehow.
+                       }
+               }
+               foreach ($dirs as $src=>$new) {
+                       mkpath($new);
+                       copyfiles($src,$new);
+               }
+               $this->test_files = $files;
+       }
+       
        function findFilesInDir($dir,$is_ext_dir=FALSE,$ignore=FALSE)
        {
                $skip = array('.', '..', 'CVS');
@@ -402,14 +882,6 @@
                }
        }
        
-       // Probably unnecessary for CLI, but used when overloading a
-       // web-based test class
-       
-       function runFooter()
-       {
-           
-       }
-       
        function run()
        {
                $this->start_time = time();
@@ -430,7 +902,6 @@
                        }
                }
                $this->end_time = time();
-               $this->runFooter();
        }
 
        function summarizeResults()
@@ -479,12 +950,12 @@
                        $failed_test_summary .=  $this->ddash."\n";
                }
                
-               if ($failed_test_summary && !$this->NO_PHPTEST_SUMMARY) {
+               if ($failed_test_summary && !$this->conf['NO_PHPTEST_SUMMARY']) {
                        $this->writemsg($failed_test_summary);
                }
 
                /* We got failed Tests, offer the user to send and e-mail to QA team, 
unless NO_INTERACTION is set */
-               if ($sum_results['FAILED'] && !$this->NO_INTERACTION) {
+               if ($sum_results['FAILED'] && !$this->conf['NO_INTERACTION']) {
                        $fp = fopen("php://stdin", "r+");
                        $this->writemsg("\nPlease allow this report to be send to the 
PHP QA\nteam. This will give us a better understanding in how\n");
                        $this->writemsg("PHP's test cases are doing.\n");
@@ -514,13 +985,12 @@
                                $sep = "\n" . str_repeat('=', 80) . "\n";
                                
                                $failed_tests_data .= $failed_test_summary . "\n";
-                               $failed_tests_data .= $summary . "\n";
                                
-                               if (sum($this->failed_tests)) {
+                               if (array_sum($this->failed_tests)) {
                                        foreach ($this->failed_tests as $test_info) {
                                                $failed_tests_data .= $sep . 
$test_info['name'];
-                                               $failed_tests_data .= $sep . 
$this->getFileContents($test_info['output']);
-                                               $failed_tests_data .= $sep . 
$this->getFileContents($test_info['diff']);
+                                               $failed_tests_data .= $sep . 
file_get_contents(realpath($test_info['output']));
+                                               $failed_tests_data .= $sep . 
file_get_contents(realpath($test_info['diff']));
                                                $failed_tests_data .= $sep . "\n\n";
                                        }
                                        $status = "failed";
@@ -532,7 +1002,7 @@
                                $failed_tests_data .= "OS:\n". PHP_OS. "\n\n";
                                $automake = $autoconf = $libtool = $compiler = 'N/A';
 
-                               if (substr(PHP_OS, 0, 3) != "WIN") {
+                               if (!$this->iswin32) {
                                        $automake = shell_exec('automake --version');
                                        $autoconf = shell_exec('autoconf --version');
                                        /* Always use the generated libtool - Mac OSX 
uses 'glibtool' */
@@ -541,9 +1011,9 @@
                                        $flags = array('-v', '-V', '--version');
                                        $cc_status=0;
                                        foreach($flags AS $flag) {
-                                               system(getenv('CC')." $flag >/dev/null 
2>&1", $cc_status);
+                                               system($this->env['CC']." $flag 
>/dev/null 2>&1", $cc_status);
                                                if($cc_status == 0) {
-                                                       $compiler = 
shell_exec(getenv('CC')." $flag 2>&1");
+                                                       $compiler = 
shell_exec($this->env['CC']." $flag 2>&1");
                                                        break;
                                                }
                                        }
@@ -561,11 +1031,12 @@
                                }
 
                                $failed_tests_data .= $sep . "PHPINFO" . $sep;
-                               $failed_tests_data .= 
shell_exec($this->TEST_PHP_EXECUTABLE.' -dhtml_errors=0 -i');
+                               $failed_tests_data .= 
shell_exec($this->conf['TEST_PHP_EXECUTABLE'].' -dhtml_errors=0 -i');
                                
                                $compression = 0;
 
-                               if ($just_save_results || 
!$this->mail_qa_team($failed_tests_data, $compression, $status)) {
+                               if ($just_save_results ||
+                                       
!post_result_data("status=$status&version=".urlencode(TESTED_PHP_VERSION),$failed_tests_data))
 {
                                        $output_file = 'php_test_results_' . 
date('Ymd_Hi') . ( $compression ? '.txt.gz' : '.txt' );
                                        $fp = fopen($output_file, "w");
                                        fwrite($fp, $failed_tests_data);
@@ -581,62 +1052,88 @@
                        }
                }
                 
-               if($this->REPORT_EXIT_STATUS == 1 and $sum_results['FAILED']) {
+               if($this->conf['REPORT_EXIT_STATUS'] and $sum_results['FAILED']) {
                        exit(1);
                }
        }
 
-       function getFileContents($filename)
+       function getINISettings(&$section_text)
        {
-               $real_filename = realpath($filename);
-               if (function_exists('file_get_contents')) {
-                       return file_get_contents($real_filename);
-               }
-               
-               $fd = fopen($real_filename, "rb");
-               if ($fd) {
-                       $contents = fread($fd, filesize($real_filename));
-                       fclose($fd);
-                       return $contents;
+               $ini_settings = $this->ini_overwrites;
+               // Any special ini settings 
+               // these may overwrite the test defaults...
+               if (array_key_exists('INI', $section_text)) {
+                       settings2array(preg_split( "/[\n\r]+/", $section_text['INI']), 
$ini_settings);
                }
-               return NULL;
+               return $ini_settings;
        }
 
-       function settings2array($settings, &$ini_settings)
+       function getINIParams(&$section_text)
        {
-               foreach($settings as $setting) {
-                       if (strpos($setting, '=')!==false) {
-                               $setting = explode("=", $setting, 2);
-                               $name = trim(strtolower($setting[0]));
-                               $value = trim($setting[1]);
-                               $ini_settings[$name] = $value;
-                       }
+               if (!$section_text) return '';
+               // XXX php5 current has a problem doing this in one line
+               // it fails with Only variables can be passed by reference
+               // on test ext\calendar\tests\jdtojewish.phpt
+               // return settings2params($this->getINISettings($section_text));
+               $ini = $this->getINISettings($section_text);
+               return settings2params($ini);
+       }
+
+       function calculateDocumentRoot()
+       {
+               if ($this->conf['TEST_WEB'] || $this->test_executable_iscgi) {
+                       // configure DOCUMENT_ROOT for web tests
+                       // this assumes that directories from the base url
+                       // matches directory depth from the base path
+                       $parts = parse_url($this->conf['TEST_WEB_BASE_URL']);
+                       $depth = substr_count($parts['path'],'/');
+                       $docroot = $this->conf['TEST_BASE_PATH'];
+                       for ($i=0 ; $i < $depth; $i++) $docroot = dirname($docroot);
+                       $this->conf['TEST_DOCUMENT_ROOT']=$docroot;
+                       $this->conf['TEST_BASE_SCRIPT_NAME']=$parts['path'];
+                       
$this->conf['TEST_SERVER_URL']=substr($this->conf['TEST_WEB_BASE_URL'],0,strlen($this->conf['TEST_WEB_BASE_URL'])-strlen($parts['path']));
+               } else {
+                       $this->conf['TEST_DOCUMENT_ROOT']='';
+                       $this->conf['TEST_BASE_SCRIPT_NAME']='';
+                       $this->conf['TEST_SERVER_URL']='';
                }
        }
 
-       function settings2params(&$ini_settings)
+       function evalSettings($filename,$data) {
+               // we eval the section so we can allow dynamic env vars
+               // for cgi testing
+               $filename = str_replace('\\','/',$filename);
+               $cwd = str_replace('\\','/',$this->cwd);
+               $filepath = dirname($filename);
+               $scriptname = 
substr($filename,strlen($this->conf['TEST_DOCUMENT_ROOT']));
+               // eval fails if no newline
+               return eval("$data\n");
+       }
+       
+       function getENVSettings(&$section_text,$testfile)
        {
-               if (count($ini_settings)) {
-                       $settings = '';
-                       foreach($ini_settings as $name => $value) {
-                               $value = addslashes($value);
-                               $settings .= " -d \"$name=$value\"";
-                       }
-                       $ini_settings = $settings;
-               } else {
-                       $ini_settings = '';
+               $env = $this->env;
+               // Any special environment settings 
+               // these may overwrite the test defaults...
+               if (array_key_exists('ENV', $section_text)) {
+                       $sect = $this->evalSettings($testfile,$section_text['ENV']);
+                       //print "data evaled:\n$sect\n";
+                       settings2array(preg_split( "/[\n\r]+/", $sect), $env);
                }
+               return $env;
        }
 
-       function getINISettings(&$section_text)
+       function getEvalTestSettings($section_text,$testfile)
        {
-               $ini_settings = $this->ini_overwrites;
-               // Any special ini settings 
+               $rq = array();
+               // Any special environment settings 
                // these may overwrite the test defaults...
-               if (array_key_exists('INI', $section_text)) {
-                       $this->settings2array(preg_split( "/[\n\r]+/", 
$section_text['INI']), $ini_settings);
+               if ($section_text) {
+                       $sect = $this->evalSettings($testfile,$section_text);
+                       //print "data evaled:\n$sect\n";
+                       settings2array(preg_split( "/[\n\r]+/", $sect), $rq);
                }
-               return $this->settings2params($ini_settings);
+               return $rq;
        }
        
        //
@@ -660,7 +1157,6 @@
                $section = '';
                while (!feof($fp)) {
                        $line = fgets($fp);
-       
                        // Match the beginning of a section.
                        if (ereg('^--([A-Z]+)--',$line,$r)) {
                                $section = $r[1];
@@ -672,83 +1168,69 @@
                        $section_text[$section] .= $line;
                }
                fclose($fp);
-               return $section_text;
-       }
-       
-       function setEnvironment($env)
-       {
-               foreach ($env as $name=>$value) {
-                       putenv("$name=$value");
+               foreach ($section_text as $k=>$v) {
+                       // for POST data ,we only want to trim the last new line!
+                       if ($k == 'POST' && 
preg_match('/^(.*?)\r?\n$/Ds',$v,$matches)) {
+                               $section_text[$k]=$matches[1];
+                       } else {
+                               $section_text[$k]=trim($v);
+                       }
                }
+               return $section_text;
        }
-       
+
        //
        // Check if test should be skipped.
        //
-       function getSkipReason(&$section_text)
+       function getSkipReason($file,&$section_text,$docgi=false)
        {
-               if (array_key_exists('SKIPIF', $section_text)) {
-                       $tmp_skipif = $section_text['_DIR'] . uniqid('/phpt.');
-                       @unlink($tmp_skipif);
-                       if (trim($section_text['SKIPIF'])) {
-                               $this->save_text($tmp_skipif, $section_text['SKIPIF']);
-                               $output = `{$this->TEST_PHP_EXECUTABLE} 
{$this->info_params} $tmp_skipif`;
-                               @unlink($tmp_skipif);
-                               if (eregi("^skip", trim($output))){
-                               
-                                       $reason = (ereg("^skip[[:space:]]*(.+)\$", 
trim($output))) ? ereg_replace("^skip[[:space:]]*(.+)\$", "\\1", trim($output)) : 
FALSE;
-                                       $this->showstatus($section_text['TEST'], 
'SKIPPED', $reason);
-       
-                                       return 'SKIPPED';
+               // if the test uses POST or GET, and it's not the cgi
+               // executable, skip
+               if ($docgi && !$this->conf['TEST_WEB'] && 
!$this->test_executable_iscgi) {
+                       $this->showstatus($section_text['TEST'], 'SKIPPED', 'CGI Test 
needs CGI Binary');
+                       return "SKIPPED";
+               }
+               // if we're doing web testing, then we wont be able to set
+               // ini setting on the command line.  be sure the executables
+               // ini settings are compatible with the test, or skip
+               if (($docgi || $this->conf['TEST_WEB']) &&
+                       isset($section_text['INI']) && $section_text['INI']) {
+                       $settings = $this->getINISettings($section_text);
+                       foreach ($settings as $k=>$v) {
+                               if (strcasecmp($v,'off')==0 || !$v) $v='';
+                               $haveval = 
isset($this->inisettings[$k]['local_value']);
+                               if ($k == 'include_path') {
+                                       // we only want to know that src directory
+                                       // is in the include path
+                                       if 
(strpos($this->inisettings[$k]['local_value'],$this->cwd))
+                                               continue;
                                }
-                               if (eregi("^info", trim($output))) {
-                                       $reason = (ereg("^info[[:space:]]*(.+)\$", 
trim($output))) ? ereg_replace("^info[[:space:]]*(.+)\$", "\\1", trim($output)) : 
FALSE;
-                                       if ($reason) {
-                                               $tested .= " (info: $reason)";
-                                       }
+                               if (($haveval && $this->inisettings[$k]['local_value'] 
!= $v) || (!$haveval && $v)) {
+                                       $this->showstatus($section_text['TEST'], 
'SKIPPED', "Test requires ini setting $k=[$v], not 
[".($haveval?$this->inisettings[$k]['local_value']:'')."]");
+                                       return "SKIPPED";
                                }
                        }
                }
-               return NULL;
-       }
-
-       function execute($commandline)
-       {
-               $data = "";
-               
-               $proc = proc_open($commandline, array(
-                  0 => array('pipe', 'r'),
-                  1 => array('pipe', 'w'),
-                  2 => array('pipe', 'w')
-                  ), $pipes);
-               
-               if (!$proc)
-                return false;
-          fclose($pipes[0]);
-       
-               while (true) {
-                       /* hide errors from interrupted syscalls */
-                       $r = $pipes;
-                       $w = null;
-                       $e = null;
-                       $n = @stream_select($r, $w, $e, 60);
-       
-                       if ($n == 0) {
-                               /* timed out */
-                               $data .= "\n ** ERROR: process timed out **\n";
-                               proc_terminate($proc);
-                               return $data;
-                       } else if ($n) {
-                               $line = fread($pipes[1], 8192);
-                               if (strlen($line) == 0) {
-                                       /* EOF */
-                                       break;
+               // now handle a SKIPIF section
+               if ($section_text['SKIPIF']) {
+                       $output = 
trim($this->runscript($section_text['SKIPIF'],$this->test_executable_iscgi,realpath(dirname($file))),true);
+                       if (!$output) return NULL;
+                       if ($this->conf['TEST_PHP_DETAILED'] > 2)
+                               print "SKIPIF: [$output]\n";
+                       if (eregi("^skip", $output)){
+                       
+                               $reason = (ereg("^skip[[:space:]]*(.+)\$", $output)) ? 
ereg_replace("^skip[[:space:]]*(.+)\$", "\\1", $output) : FALSE;
+                               $this->showstatus($section_text['TEST'], 'SKIPPED', 
$reason);
+                               return 'SKIPPED';
+                       }
+                       if (eregi("^info", $output)) {
+                               $reason = (ereg("^info[[:space:]]*(.+)\$", $output)) ? 
ereg_replace("^info[[:space:]]*(.+)\$", "\\1", $output) : FALSE;
+                               if ($reason) {
+                                       $tested .= " (info: $reason)";
                                }
-                               $data .= $line;
                        }
                }
-               $code = proc_close($proc);
-               return $data;
+               return NULL;
        }
 
        //
@@ -756,19 +1238,25 @@
        //
        function run_test($file)
        {
-               if ($this->TEST_PHP_DETAILED)
+               if ($this->conf['TEST_PHP_DETAILED'])
                        $this->writemsg("\n=================\nTEST $file\n");
        
                $section_text = $this->getSectionText($file);
        
-               $shortname = str_replace($this->cwd.'/', '', $file);
-               $tested = trim($section_text['TEST'])." [$shortname]";
-       
-               $tmp_file   = ereg_replace('\.phpt$','.php',$file);
-               $tmp_post   = $section_text['_DIR'] . uniqid('/phpt.');
-       
+               if ($this->iswin32)
+                       $shortname = str_replace($this->conf['TEST_BASE_PATH'].'\\', 
'', $file);
+               else
+                       $shortname = str_replace($this->conf['TEST_BASE_PATH'].'/', 
'', $file);
+               $tested = $section_text['TEST']." [$shortname]";
+       
+               if ($this->conf['TEST_WEB']) {
+                       $tmp_file   = 
ereg_replace('\.phpt$','.'.$this->conf['TEST_WEB_EXT'],$file);
+                       $uri = 
$this->conf['TEST_BASE_SCRIPT_NAME'].str_replace($this->conf['TEST_BASE_PATH'], '', 
$tmp_file);
+                       $uri = str_replace('\\', '/', $uri);
+               } else {
+                       $tmp_file   = ereg_replace('\.phpt$','.php',$file);
+               }
                @unlink($tmp_file);
-               @unlink($tmp_post);
        
                // unlink old test results      
                @unlink(ereg_replace('\.phpt$','.diff',$file));
@@ -776,76 +1264,169 @@
                @unlink(ereg_replace('\.phpt$','.exp',$file));
                @unlink(ereg_replace('\.phpt$','.out',$file));
        
-               // Reset environment from any previous test.
-               $env = $this->env;
-               $this->setEnvironment($env);
+               if (!$this->conf['TEST_WEB']) {
+                       // Reset environment from any previous test.
+                       $env = $this->getENVSettings($section_text,$tmp_file);
+                       $ini_overwrites = $this->getINIParams($section_text);
+               }
+               
+               // if this is a cgi test, prepare for it
+               $query_string = '';
+               $havepost = array_key_exists('POST', $section_text) && 
!empty($section_text['POST']);
+               // allow empty query_string requests
+               $haveget = array_key_exists('GET', $section_text) && 
!empty($section_text['GET']);
+               $do_cgi = array_key_exists('CGI', $section_text) || $haveget || 
$havepost;
+
+               $skipreason = $this->getSkipReason($file,$section_text,$do_cgi);
+               if ($skipreason == 'SKIPPED') {
+                       return $skipreason;
+               }
 
-               $skipreason = $this->getSkipReason($section_text);
-               if ($skipreason == 'SKIPPED') return $skipreason;
-               
-               $ini_overwrites = $this->getINISettings($section_text);
-       
                // We've satisfied the preconditions - run the test!
-               $this->save_text($tmp_file,$section_text['FILE']);
-               if (array_key_exists('GET', $section_text)) {
-                       $query_string = trim($section_text['GET']);
+               save_to_file($tmp_file,$section_text['FILE']);
+
+               $post = NULL;
+               $args = "";
+
+               $headers = array();
+               if ($this->conf['TEST_WEB']) {
+                       $request = 
$this->getEvalTestSettings(@$section_text['REQUEST'],$tmp_file);
+                       $headers = 
$this->getEvalTestSettings(@$section_text['HEADERS'],$tmp_file);
+
+                       $method = 
isset($request['method'])?$request['method']:$havepost?'POST':'GET';
+                       $query_string = $haveget?$section_text['GET']:'';
+               
+                       $options = array();
+                       $options['method']=$method;
+                       if (isset($this->conf['timeout']))    $options['timeout']    = 
$this->conf['timeout'];
+                       if (isset($this->conf['proxy_host'])) $options['proxy_host'] = 
$this->conf['proxy_host'];
+                       if (isset($this->conf['proxy_port'])) $options['proxy_port'] = 
$this->conf['proxy_port'];
+                       if (isset($this->conf['proxy_user'])) $options['proxy_user'] = 
$this->conf['proxy_user'];
+                       if (isset($this->conf['proxy_pass'])) $options['proxy_pass'] = 
$this->conf['proxy_pass'];
+                       
+                       $post = $havepost?$section_text['POST']:NULL;
+                       $url = $this->conf['TEST_SERVER_URL'];
+                       if (isset($request['SCRIPT_NAME']))
+                               $url .= $request['SCRIPT_NAME'];
+                       else
+                               $url .= $uri;
+                       if (isset($request['PATH_INFO']))
+                               $url .= $request['PATH_INFO'];
+                       if (isset($request['FRAGMENT']))
+                               $url .= '#'.$request['FRAGMENT'];
+                       if (isset($request['QUERY_STRING']))
+                               $query_string = $request['QUERY_STRING'];
+                       if ($query_string)
+                               $url .= '?'.$query_string;
+                       if ($this->conf['TEST_PHP_DETAILED'])
+                               $this->writemsg("\nURL  = $url\n");
+               } else if ($do_cgi) {
+                       $query_string = $haveget?$section_text['GET']:'';
+                       
+                       if (!array_key_exists('GATEWAY_INTERFACE', $env))
+                               $env['GATEWAY_INTERFACE']='CGI/1.1';
+                       if (!array_key_exists('SERVER_SOFTWARE', $env))
+                               $env['SERVER_SOFTWARE']='PHP Test Harness';
+                       if (!array_key_exists('SERVER_SOFTWARE', $env))
+                               $env['SERVER_NAME']='127.0.0.1';
+                       if (!array_key_exists('REDIRECT_STATUS', $env))
+                               $env['REDIRECT_STATUS']='200';
+                       if (!array_key_exists('SERVER_NAME', $env))
+                               $env['QUERY_STRING']=$query_string;
+                       if (!array_key_exists('PATH_TRANSLATED', $env) &&
+                               !array_key_exists('SCRIPT_FILENAME', $env)) {
+                               $env['PATH_TRANSLATED']=$tmp_file;
+                               $env['SCRIPT_FILENAME']=$tmp_file;
+                       }
+                       if (!array_key_exists('PATH_TRANSLATED', $env))
+                               $env['PATH_TRANSLATED']='';
+                       if (!array_key_exists('PATH_INFO', $env))
+                               $env['PATH_INFO']='';
+                       if (!array_key_exists('SCRIPT_NAME', $env))
+                               $env['SCRIPT_NAME']='';
+                       if (!array_key_exists('SCRIPT_FILENAME', $env))
+                               $env['SCRIPT_FILENAME']='';
+               
+                       if (array_key_exists('POST', $section_text) && (!$haveget || 
!empty($section_text['POST']))) {
+                               $post = $section_text['POST'];
+                               $content_length = strlen($post);
+                               if (!array_key_exists('REQUEST_METHOD', $env))
+                                       $env['REQUEST_METHOD']='POST';
+                               if (!array_key_exists('CONTENT_TYPE', $env))
+                                       
$env['CONTENT_TYPE']='application/x-www-form-urlencoded';
+                               if (!array_key_exists('CONTENT_LENGTH', $env))
+                                       $env['CONTENT_LENGTH']=$content_length;
+                       } else {
+                               if (!array_key_exists('REQUEST_METHOD', $env))
+                                       $env['REQUEST_METHOD']='GET';
+                               if (!array_key_exists('CONTENT_TYPE', $env))
+                                       $env['CONTENT_TYPE']='';
+                               if (!array_key_exists('CONTENT_LENGTH', $env))
+                                       $env['CONTENT_LENGTH']='';
+                       }
+                       if ($this->conf['TEST_PHP_DETAILED'] > 1)
+                               $this->writemsg("\nCONTENT_LENGTH  = " . 
$env['CONTENT_LENGTH'] . 
+                                               "\nCONTENT_TYPE    = " . 
$env['CONTENT_TYPE'] . 
+                                               "\nPATH_TRANSLATED = " . 
$env['PATH_TRANSLATED'] . 
+                                               "\nPATH_INFO       = " . 
$env['PATH_INFO'] . 
+                                               "\nQUERY_STRING    = " . 
$env['QUERY_STRING'] . 
+                                               "\nREDIRECT_STATUS = " . 
$env['REDIRECT_STATUS'] . 
+                                               "\nREQUEST_METHOD  = " . 
$env['REQUEST_METHOD'] . 
+                                               "\nSCRIPT_NAME     = " . 
$env['SCRIPT_NAME'] . 
+                                               "\nSCRIPT_FILENAME = " . 
$env['SCRIPT_FILENAME'] . "\n");
+                       /* not cgi spec to put query string on command line,
+                          but used by a couple tests to catch a security hole
+                          in older php versions.  At least IIS can be configured
+                          to do this. */
+                       $args = $env['QUERY_STRING'];
                } else {
-                       $query_string = '';
+                       $args = $section_text['ARGS'] ? $section_text['ARGS'] : '';
+                       $args = "$ini_overwrites $tmp_file $args 2>&1";
                }
-       
-               $env['REDIRECT_STATUS']='1';
-               $env['QUERY_STRING']=$query_string;
-               $env['PATH_TRANSLATED']=$tmp_file;
-               $env['SCRIPT_FILENAME']=$tmp_file;
-       
-               $args = $section_text['ARGS'] ? ' -- '.$section_text['ARGS'] : '';
-       
-               if (array_key_exists('POST', $section_text) && 
!empty($section_text['POST'])) {
-       
-                       $post = trim($section_text['POST']);
-                       $this->save_text($tmp_post,$post);
-                       $content_length = strlen($post);
-       
-                       $env['REQUEST_METHOD']='POST';
-                       $env['CONTENT_TYPE']='application/x-www-form-urlencoded';
-                       $env['CONTENT_LENGTH']=$content_length;
-       
-                       $cmd = "{$this->TEST_PHP_EXECUTABLE} $ini_overwrites -f 
$tmp_file 2>&1 < $tmp_post";
-       
+
+               if ($this->conf['TEST_WEB']) {
+                       // we want headers also, so fopen
+                       $r = new HTTPRequest($url,$headers,$options,$post);
+                       //$out = preg_replace("/\r\n/","\n",$r->response);
+                       $out = $r->response;
+                       $headers = $r->response_headers;
+                       //print $r->outgoing_payload."\n";
+                       //print $r->incoming_payload."\n";
                } else {
-       
-                       $env['REQUEST_METHOD']='GET';
-                       $env['CONTENT_TYPE']='';
-                       $env['CONTENT_LENGTH']='';
-       
-                       $cmd = "{$this->TEST_PHP_EXECUTABLE} $ini_overwrites -f 
$tmp_file$args 2>&1";
+                       $out = 
execute($this->conf['TEST_PHP_EXECUTABLE'],$args,$post,$this->cwd,$env);
+                       // if this is a cgi, remove the headers first
+                       if ($this->test_executable_iscgi
+                                && preg_match("/^(.*?)\r?\n\r?\n(.*)/s", $out, 
$match)) {
+                               $out = $match[2];
+                               $rh = preg_split("/[\n\r]+/",$match[1]);
+                               $headers = array();
+                               foreach ($rh as $line) {
+                                       if (strpos($line, ':')!==false) {
+                                               $line = explode(":", $line, 2);
+                                               $headers[trim($line[0])] = 
trim($line[1]);
+                                       }
+                               }
+                       }
                }
-       
-               if ($this->TEST_PHP_DETAILED)
-                       $this->writemsg("\nCONTENT_LENGTH  = " . 
$env['CONTENT_LENGTH'] . 
-                                       "\nCONTENT_TYPE    = " . $env['CONTENT_TYPE'] 
. 
-                                       "\nPATH_TRANSLATED = " . 
$env['PATH_TRANSLATED'] . 
-                                       "\nQUERY_STRING    = " . $env['QUERY_STRING'] 
. 
-                                       "\nREDIRECT_STATUS = " . 
$env['REDIRECT_STATUS'] . 
-                                       "\nREQUEST_METHOD  = " . 
$env['REQUEST_METHOD'] . 
-                                       "\nSCRIPT_FILENAME = " . 
$env['SCRIPT_FILENAME'] . 
-                                       "\nCOMMAND $cmd\n");
-       
-               $this->setEnvironment($env);
                
-               $out = $this->execute($cmd);
-       
-               @unlink($tmp_post);
-       
+               if ($this->conf['TEST_PHP_DETAILED'] > 2) {
+                       echo "HEADERS: ";
+                       print_r($headers);
+                       echo "OUTPUT: \n$out\n";
+                       
+               }
+                       
                // Does the output match what is expected?
                $output = trim($out);
                $output = preg_replace('/\r\n/',"\n",$output);
-       
+
+               $failed = FALSE;
+
                if (isset($section_text['EXPECTF']) || 
isset($section_text['EXPECTREGEX'])) {
                        if (isset($section_text['EXPECTF'])) {
-                               $wanted = trim($section_text['EXPECTF']);
+                               $wanted = $section_text['EXPECTF'];
                        } else {
-                               $wanted = trim($section_text['EXPECTREGEX']);
+                               $wanted = $section_text['EXPECTREGEX'];
                        }
                        $wanted_re = preg_replace('/\r\n/',"\n",$wanted);
                        if (isset($section_text['EXPECTF'])) {
@@ -860,28 +1441,53 @@
                                // %f allows two points "-.0.0" but that is the best 
*simple* expression
                        }
        /* DEBUG YOUR REGEX HERE
-                       var_dump($wanted);
+                       var_dump($wanted_re);
                        print(str_repeat('=', 80) . "\n");
                        var_dump($output);
        */
-                       if (preg_match("/^$wanted_re\$/s", $output)) {
-                               @unlink($tmp_file);
-                               $this->showstatus($tested, 'PASSED');
-                               return 'PASSED';
+                       $failed = !preg_match("/^$wanted_re\$/s", $output);
+               }
+               
+               $skipexpect = false;
+               if (!$failed && $this->conf['TEST_WEB'] && 
isset($section_text['EXPECTHEADERS'])) {
+                       $want = array();
+                       $lines = 
preg_split("/[\n\r]+/",$section_text['EXPECTHEADERS']);
+                       $wanted='';
+            foreach ($lines as $line) {
+                if (strpos($line, ':')!==false) {
+                    $line = explode(":", $line, 2);
+                    $want[trim($line[0])] = trim($line[1]);
+                                       $wanted .= trim($line[0]).': 
'.trim($line[1])."\n";
+                }
+            }
+                       $output='';
+                       foreach ($want as $k=>$v) {
+                               $output .= "$k: {$headers[$k]}\n";
+                               if (!isset($headers[$k]) || $headers[$k] != $v) {
+                                       $failed = TRUE;
+                               }
                        }
-       
-               } else {
-                       $wanted = trim($section_text['EXPECT']);
+                       
+                       // different servers may do different things on non-200 results
+                       // for instance, IIS will deliver it's own error pages, so we
+                       // cannot expect to match up the EXPECT section.  We may 
however,
+                       // want to match EXPECT on more than 200 results, so this may
+                       // need to change later.
+                       $skipexpect = isset($headers['Status']) && $headers['Status'] 
!= 200;
+               }
+                       
+               if (!$failed && !$skipexpect && isset($section_text['EXPECT'])) {
+                       $wanted = $section_text['EXPECT'];
                        $wanted = preg_replace('/\r\n/',"\n",$wanted);
-               // compare and leave on success
-                       $ok = (0 == strcmp($output,$wanted));
-                       if ($ok) {
-                               @unlink($tmp_file);
-                               $this->showstatus($tested, 'PASSED');
-                               return 'PASSED';
-                       }
+                       $failed = (0 != strcmp($output,$wanted));
                }
-       
+               
+               if (!$failed) {
+                       @unlink($tmp_file);
+                       $this->showstatus($tested, 'PASSED');
+                       return 'PASSED';
+               }
+                       
                // Test failed so we need to report details.
                $this->showstatus($tested, 'FAILED');
        
@@ -892,88 +1498,50 @@
                                                        'diff'   => 
ereg_replace('\.phpt$','.diff', $file)
                                                        );
        
+               if ($this->conf['TEST_PHP_DETAILED'])
+                       $this->writemsg(generate_diff($wanted,$output)."\n");
+                       
                // write .exp
-               if (strpos($this->TEST_PHP_LOG_FORMAT,'E') !== FALSE) {
+               if (strpos($this->conf['TEST_PHP_LOG_FORMAT'],'E') !== FALSE) {
                        $logname = ereg_replace('\.phpt$','.exp',$file);
-                       $this->save_text($logname,$wanted);
+                       save_to_file($logname,$wanted);
                }
        
                // write .out
-               if (strpos($this->TEST_PHP_LOG_FORMAT,'O') !== FALSE) {
+               if (strpos($this->conf['TEST_PHP_LOG_FORMAT'],'O') !== FALSE) {
                        $logname = ereg_replace('\.phpt$','.out',$file);
-                       $this->save_text($logname,$output);
+                       save_to_file($logname,$output);
                }
        
                // write .diff
-               if (strpos($this->TEST_PHP_LOG_FORMAT,'D') !== FALSE) {
+               if (strpos($this->conf['TEST_PHP_LOG_FORMAT'],'D') !== FALSE) {
                        $logname = ereg_replace('\.phpt$','.diff',$file);
-                       
$this->save_text($logname,$this->generate_diff($wanted,$output));
+                       save_to_file($logname,generate_diff($wanted,$output));
                }
        
                // write .log
-               if (strpos($this->TEST_PHP_LOG_FORMAT,'L') !== FALSE) {
+               if (strpos($this->conf['TEST_PHP_LOG_FORMAT'],'L') !== FALSE) {
                        $logname = ereg_replace('\.phpt$','.log',$file);
-                       $this->save_text($logname,
+                       save_to_file($logname,
                                                "\n---- EXPECTED OUTPUT\n$wanted\n".
                                                "---- ACTUAL OUTPUT\n$output\n".
                                                "---- FAILED\n");
-                       $this->error_report($file,$logname,$tested);
+                       // display emacs/msvc error output
+                       if (strpos($this->conf['TEST_PHP_LOG_FORMAT'],'C') !== FALSE) {
+                               $this->error_report($file,$logname,$tested);
+                       }
                }
-       
                return 'FAILED';
        }
 
        //
-       // Send Email to QA Team
-       //
-       function mail_qa_team($data, $compression)
-       {
-               $url_bits = parse_url(QA_SUBMISSION_PAGE);
-               if (empty($url_bits['port'])) $url_bits['port'] = 80;
-               
-               $data = "php_test_data=" . 
urlencode(base64_encode(preg_replace("/[\\x00]/", "[0x0]", $data)));
-               $data_length = strlen($data);
-               
-               $fs = fsockopen($url_bits['host'], $url_bits['port'], $errno, $errstr, 
10);
-               if (!$fs) {
-                       return FALSE;
-               }
-       
-               $this->writemsg("Posting to {$url_bits['host']} 
{$url_bits['path']}\n");
-               fwrite($fs, "POST ".$url_bits['path']." HTTP/1.1\r\n");
-               fwrite($fs, "Host: ".$url_bits['host']."\r\n");
-               fwrite($fs, "User-Agent: QA Browser 0.1\r\n");
-               fwrite($fs, "Content-Type: application/x-www-form-urlencoded\r\n");
-               fwrite($fs, "Content-Length: ".$data_length."\r\n\r\n");
-               fwrite($fs, $data);
-               fwrite($fs, "\r\n\r\n");
-               fclose($fs);
-       
-               return TRUE;
-       } 
-
-       //
-       //  Write the given text to a temporary file, and return the filename.
-       //
-       function save_text($filename,$text)
-       {
-               $fp = @fopen($filename,'w')
-                       or $this->error("Cannot open file '" . $filename . "' 
(save_text)");
-               fwrite($fp,$text);
-               fclose($fp);
-               if (1 < $this->TEST_PHP_DETAILED) {
-                       $this->writemsg("\nFILE $filename {{{\n$text\n}}}\n");
-               }
-       }
-
-       //
        //  Write an error in a format recognizable to Emacs or MSVC.
        //
        function error_report($testname,$logname,$tested) 
        {
                $testname = realpath($testname);
                $logname  = realpath($logname);
-               switch ($this->TEST_PHP_ERROR_STYLE) {
+               switch ($this->conf['TEST_PHP_ERROR_STYLE']) {
                default:
                case 'MSVC':
                        $this->writemsg($testname . "(1) : $tested\n");
@@ -986,152 +1554,10 @@
                }
        }
 
-       function generate_diff($wanted,$output)
-       {
-               $w = explode("\n", $wanted);
-               $o = explode("\n", $output);
-               $w1 = array_diff_assoc($w,$o);
-               $o1 = array_diff_assoc($o,$w);
-               $w2 = array();
-               $o2 = array();
-               foreach($w1 as $idx => $val) $w2[sprintf("%03d<",$idx)] = 
sprintf("%03d- ", $idx+1).$val;
-               foreach($o1 as $idx => $val) $o2[sprintf("%03d>",$idx)] = 
sprintf("%03d+ ", $idx+1).$val;
-               $diff = array_merge($w2, $o2);
-               ksort($diff);
-               return implode("\r\n", $diff);
-       }
-
-       function error($message)
-       {
-               $this->writemsg("ERROR: {$message}\n");
-               exit(1);
-       }
-}
-
-class webHarness extends testHarness {
-       
-       var $textdata;
-       
-       function checkSafeMode() {
-               if (ini_get('safe_mode')) {
-               
-?>
-<CENTER>
-<TABLE CELLPADDING=5 CELLSPACING=0 BORDER=1>
-<TR>
-<TD BGCOLOR="#FE8C97" ALIGN=CENTER><B>WARNING</B>
-<HR NOSHADE COLOR=#000000>
-You are running this test-suite with "safe_mode" <B>ENABLED</B>!<BR><BR>
-Chances are high that none of the tests will work at all, depending on
-how you configured "safe_mode".
-</TD>
-</TR>
-</TABLE>
-</CENTER>
-<?php
-               return true;
-       }
-       return false;
-       }
-       
-       function runHeader() {
-?>
-<TABLE CELLPADDING=3 CELLSPACING=0 BORDER=0 STYLE="border: thin solid black;">
-<TR>
-       <TD>TESTED FUNCTIONALITY</TD>
-       <TD>RESULT</TD>
-</TR>
-<?php
-
-       }
-
-       function runFooter() {
-
-
-?>
-<TR>
-<TD COLSPAN=2 ALIGN=CENTER><FONT SIZE=3>Additional Notes</FONT><HR><?php 
$this->displaymsg(); ?></TD>
-</TR>
-</TABLE><BR><BR>
-<?php 
-       }
-       
        function error($message)
        {
                $this->writemsg("ERROR: {$message}\n");
                exit(1);
-       }
-       
-       // Use this function to do any displaying of text, so that
-       // things can be over-written as necessary.
-       
-       function writemsg($msg) {
-               
-               $this->textdata = $this->textdata . $msg;
-               
-       }
-       
-       function displaymsg() {
-       
-?>
-<TEXTAREA ROWS=10 COLS=80><?=$this->textdata?></TEXTAREA>
-<?php
-       }
-       
-       // Another wrapper function, this one should be used any time
-       // a particular test passes or fails
-       
-       function showstatus($item, $status, $reason = '') 
-       {
-               static $color = "#FAE998";
-               
-               $color = ($color == "#FAE998") ? "#FFFFFF" : "#FAE998";
-               
-               switch($status) {
-               
-                       case 'PASSED':
-                       
-?>
-<TR>
-<TD BGCOLOR=<?=$color?>><?=$item?></TD>
-<TD VALIGN=CENTER ALIGN=CENTER BGCOLOR=<?=$color?> ROWSPAN=2><FONT 
COLOR=#00FF00>PASSED</FONT></TD>
-</TR>
-<TR>
-<TD BGCOLOR=<?=$color?>>Notes: <?=htmlentities($reason)?></TD>
-</TR>
-<?php
-                               
-                               break;
-                               
-                       case 'FAILED':
-                               
-?>
-<TR>
-<TD BGCOLOR=<?=$color?>><?=$item?></TD>
-<TD VALIGN=CENTER ALIGN=CENTER BGCOLOR=<?=$color?> ROWSPAN=2><FONT 
COLOR=#FF0000>FAILED</FONT></TD>
-</TR>
-<TR>
-<TD BGCOLOR=<?=$color?>>Notes: <?=htmlentities($reason)?></TD>
-</TR>
-<?php
-                               
-                               break;
-                               
-                       case 'SKIPPED':
-                       
-?>
-<TR>
-<TD BGCOLOR=<?=$color?>><?=$item?></TD>
-<TD VALIGN=CENTER ALIGN=CENTER BGCOLOR=<?=$color?> ROWSPAN=2><FONT 
COLOR=#000000>SKIPPED</FONT></TD>
-</TR>
-<TR>
-<TD BGCOLOR=<?=$color?>>Notes: <?=htmlentities($reason)?></TD>
-</TR>
-<?php
-                               break;
-                       
-               }
-       
        }
 }
 

Index: php4/README.TESTING2
+++ php4/README.TESTING2
[IMPORTANT NOTICE]
------------------
This is an addendum to README.TESTING with additional information 
specific to run-tests2.php.

run-tests2.php is backward compatible with tests developed for
the original run-tests.php script.  run-tests2 is *not* used by
'make test'.  run-tests2 was developed to provide support for
testing PHP under it's primary environment, HTTP, and can run the
PHP tests under any of the SAPI modules that are direct executables, 
or are accessable via HTTP.

[New features]
----------------
* Command line interface:
  You can run 'php run-tests2.php -h' to get all the possible options.
* Configuration file:
  the -c argument will allow you to use a configuration file.  This is
  handy if you are testing multiple environments and need various options
  depending on the environment.
  see run-tests-config.php for details.
* CGI Emulation:
  Will emulate a CGI environment when testing with the cgi sapi executable.
* HTTP testing:
  can be configured to run test scripts through an HTTP server running
  on localhost.  localhost is required since either the web server must
  alias a directory to the php source directory, or the test scripts
  must be copied to a directory under the web server 
  (see config options TEST_WEB_BASE_URL, TEST_BASE_PATH, and TEST_WEB_EXT)
* New sections supported for test files (see below)

When running tests over http, tests that require ini settings different that what
the web server runs under will be skipped.  Since the test harness defines a number
of ini settings by default, the web server may require special configuration to
make testing work.

[Example Usage]
----------------
Some (but not all!) examples of usage:

1. run tests from the php source directory
    php run-tests2.php -p /path/to/php-cli

2. run tests using cgi emulation
    php run-tests2.php -p /path/to/php-cgi

3. run tests over http, copying test files into document root
    php run-tests2.php -w -u http://localhost/test -m /path/to/htdocs/test

4. run tests over http, php sources have been aliased in web server
    php run-tests2.php -w -u http://localhost/test
    
5. run tests using configuration file
    php run-tests2.php -c /path/to/run-tests-config.php

6. run tests using configuration file, but overriding some settings:
   (config file must be first)
    php run-tests2.php -c /path/to/run-tests-config.php -w -t 3 -d /path/to/testdir

NOTE: configuration as described in README.TESTING still works.

[New Test Sections] 
----------------
In addition to the traditional test sections 
(see http://qa.php.net/write-test.php), several new sections are available 
under run-tests2.

--POST--
This is not a new section, but not multipart posts are supported for testing
file uploads, or other types of POST data.

--CGI--
This section takes no value.  It merely provides a simple marker for tests
that MUST be run as CGI, even if there is no --POST-- or --GET-- sections
in the test file.

--DESCRIPTION--
Not used for anything, just a section for documenting the test

--ENV--
This section get's eval()'d to help build an environment for the 
execution of the test.  This can be used to change environment
vars that are used for CGI emulation, or simply to set env vars
for cli testing.  A full example looks like:

  --ENV--
  return <<<END
  PATH_TRANSLATED=$filename
  PATH_INFO=$scriptname
  SCRIPT_NAME=$scriptname
  END;

Some variables are made easily available for use in this section, they
include:
  $filename     full native path to file, will become PATH_TRANSLATED
  $filepath     =dirname($filename)
  $scriptname   this is what will become SCRIPT_NAME unless you override it
  $docroot      the equivelant of DOCUMENT_ROOT under Apache
  $cwd          the directory that the test is being initiated from
  $this->conf   all run-tests2 configuration vars
  $this->env    all environment variables that will get passed to the test


--REQUEST--
This section is also eval'd, and is similar in nature to --ENV--.  However,
this section is used to build the url used in an HTTP request.  Valid values
to set in this section would include:
  SCRIPT_NAME   The inital part of the request url
  PATH_INFO     The pathinfo part of a request url
  FRAGMENT      The fragment section of a url (after #)
  QUERY_STRING  The query part of a url (after ?)

  --REQUEST--
  return <<<END
  PATH_INFO=/path/info
  END;

--HEADERS--
This section is also eval'd.  It is used to provide additional headers sent
in an HTTP request, such as content type for multipart posts, cookies, etc.

  --HEADERS--
  return <<<END
  Content-Type=multipart/form-data; boundary=---------------------------240723202011929
  Content-Length=100
  END;

--EXPECTHEADERS--
This section can be used to define what headers are required to be
received back from a request, and is checked in addition to the
regular expect sections.  For example:

  --EXPECTHEADERS--
  Status: 404




Index: php4/run-tests-config.php
+++ php4/run-tests-config.php
<?php
/* this file may be duplicated to provide testing for
   multiple php binaries or configurations.  It is used
   with the -c option on run_tests2.php.  All these
   settings will also go into the environment for tests
   that are directly executed, so you can also set things
   like PHPRC here to force an executable to use a
   specific php.ini file. */
   
$conf = array(
/* path to the php source tree */
'TEST_PHP_SRCDIR'      =>    NULL,

/* executable that will be tested.  Not used for
   web based tests */
'TEST_PHP_EXECUTABLE'  =>    NULL,

/* php.ini to use when executing php */
'PHPRC'                =>    NULL,

/* log format */
'TEST_PHP_LOG_FORMAT'  =>    'LEODC',

/* debugging detail in output. */
'TEST_PHP_DETAILED'    =>    0,

/* error style for editors or IDE's */
'TEST_PHP_ERROR_STYLE' =>    'EMACS',

'REPORT_EXIT_STATUS'   =>    0,
'NO_PHPTEST_SUMMARY'   =>    0,

/* don't ask, and don't send results to QA if true */
'NO_INTERACTION'       =>    true,

/* base url prefixed to any requests */
'TEST_WEB_BASE_URL'    =>    NULL,

/* if set, copy phpt files into this directory,
   which should be accessable via an http server.  The
   TEST_WEB_BASE_URL setting should be the base url
   to access this path.  If this is not used,
   TEST_WEB_BASE_URL should be the base url pointing
   to TEST_PHP_SRCDIR, which should then be accessable via
   an http server.
   
   An example would be:
   TEST_WEB_BASE_URL=http://localhost/test
   TEST_BASE_PATH=/path/to/htdocs/test
*/
'TEST_BASE_PATH'   =>    NULL,

/* file extension of pages requested via http
   this allows for php to be configured to parse
   extensions other than php, usefull for multiple
   configurations under a single webserver */
'TEST_WEB_EXT'         =>    'php',

/* if true doesn't run tests, just outputs executable info */
'TEST_CONTEXT_INFO'    =>    false,

/* : or ; seperated list of paths */
'TEST_PATHS'           =>    NULL
/* additional configuration items that may be set
   to provide proxy support for testes:
  timeout
  proxy_host
  proxy_port
  proxy_user
  proxy_pass
*/
);

?>
Index: php4/sapi/tests/test001.phpt
+++ php4/sapi/tests/test001.phpt
--TEST--
IIS style CGI missing SCRIPT_FILENAME
--DESCRIPTION--
This would be similar to what IIS produces for a simple query.
--ENV--
return <<<END
PATH_TRANSLATED=$filename
PATH_INFO=$scriptname
SCRIPT_NAME=$scriptname
END;
--CGI--
--FILE--
<?php
    echo "HELLO";
?>
--EXPECT--
HELLO
Index: php4/sapi/tests/test002.phpt
+++ php4/sapi/tests/test002.phpt
--TEST--
Apache style CGI
--DESCRIPTION--
Apache likes to set SCRIPT_FILENAME to the php executable
if you use ScriptAlias configurations, and the proper
path is in PATH_TRANSLATED.  SCRIPT_NAME in this is faked,
but that is ok, Apache sets SCRIPT_NAME to the ScriptAlias
of the executable.
--ENV--
return <<<END
REDIRECT_URL=$scriptname
PATH_TRANSLATED=$filename
PATH_INFO=$scriptname
SCRIPT_NAME=/scriptalias/php
SCRIPT_FILENAME=$this->conf['TEST_PHP_EXECUTABLE']
END;
--CGI--
--FILE--
<?php
    echo "HELLO";
?>
--EXPECT--
HELLO
Index: php4/sapi/tests/test003.phpt
+++ php4/sapi/tests/test003.phpt
--TEST--
IIS style CGI missing SCRIPT_FILENAME, has PATH_INFO
--DESCRIPTION--
This would be similar to what IIS produces for a simple query
that also has PATH_INFO.
--REQUEST--
return <<<END
PATH_INFO=/path/info
END;
--ENV--
return <<<END
PATH_TRANSLATED=$filename/path/info
PATH_INFO=$scriptname/path/info
SCRIPT_NAME=$scriptname
END;
--CGI--
--FILE--
<?php
    echo $_SERVER['PATH_INFO'];
?>
--EXPECT--
/path/info
Index: php4/sapi/tests/test004.phpt
+++ php4/sapi/tests/test004.phpt
--TEST--
Apache style CGI with PATH_INFO
--DESCRIPTION--
Apache likes to set SCRIPT_FILENAME to the php executable
if you use ScriptAlias configurations, and the proper
path is in PATH_TRANSLATED.  SCRIPT_NAME in this is faked,
but that is ok, Apache sets SCRIPT_NAME to the ScriptAlias
of the executable.
--REQUEST--
return <<<END
PATH_INFO=/path/info
END;
--ENV--
return <<<END
REDIRECT_URL=$scriptname
PATH_TRANSLATED=$filename/path/info
PATH_INFO=$scriptname/path/info
SCRIPT_NAME=/scriptalias/php
SCRIPT_FILENAME=$this->conf['TEST_PHP_EXECUTABLE']
END;
--CGI--
--FILE--
<?php
    echo $_SERVER['PATH_INFO'];
?>
--EXPECT--
/path/info
Index: php4/sapi/tests/test005.phpt
+++ php4/sapi/tests/test005.phpt
--TEST--
QUERY_STRING Security Bug
--DESCRIPTION--
This bug was present in PHP 4.3.0 only.
A failure should print HELLO.
--REQUEST--
return <<<END
SCRIPT_NAME=/nothing.php
QUERY_STRING=$filename
END;
--ENV--
return <<<END
REDIRECT_URL=$scriptname
PATH_TRANSLATED=c:\apache\1.3.27\htdocs\nothing.php
QUERY_STRING=$filename
PATH_INFO=/nothing.php
SCRIPT_NAME=/phpexe/php.exe/nothing.php
SCRIPT_FILENAME=c:\apache\1.3.27\htdocs\nothing.php
END;
--CGI--
--FILE--
<?php
    echo "HELLO";
?>
--EXPECTHEADERS--
Status: 404
--EXPECT--
No input file specified.
Index: php4/sapi/tests/test006.phpt
+++ php4/sapi/tests/test006.phpt
--TEST--
Multipart Form POST Data
--CGI--
--HEADERS--
return <<<END
Content-Type=multipart/form-data; boundary=---------------------------240723202011929
Content-Length=862
END;
--ENV--
return <<<END
CONTENT_TYPE=multipart/form-data; boundary=---------------------------240723202011929
CONTENT_LENGTH=862
END;
--POST--
-----------------------------240723202011929
Content-Disposition: form-data; name="entry"

entry box
-----------------------------240723202011929
Content-Disposition: form-data; name="password"

password box
-----------------------------240723202011929
Content-Disposition: form-data; name="radio1"

test 1
-----------------------------240723202011929
Content-Disposition: form-data; name="checkbox1"

test 1
-----------------------------240723202011929
Content-Disposition: form-data; name="choices"

Choice 1
-----------------------------240723202011929
Content-Disposition: form-data; name="choices"

Choice 2
-----------------------------240723202011929
Content-Disposition: form-data; name="file"; filename="info.php"
Content-Type: application/octet-stream

<?php
phpinfo();
?>
-----------------------------240723202011929--

--GET--
--FILE--
<?php 
error_reporting(0);
print_r($_POST);
print_r($_FILES);
?>
--EXPECTF--
Array
(
    [entry] => entry box
    [password] => password box
    [radio1] => test 1
    [checkbox1] => test 1
    [choices] => Choice 2
)
Array
(
    [file] => Array
        (
            [name] => info.php
            [type] => application/octet-stream
            [tmp_name] => %s
            [error] => 0
            [size] => 21
        )

)

Index: php4/sapi/tests/test007.phpt
+++ php4/sapi/tests/test007.phpt
--TEST--
Multipart Form POST Data, incorrect content length
--CGI--
--HEADERS--
return <<<END
Content-Type=multipart/form-data; boundary=---------------------------240723202011929
Content-Length=100
END;
--POST--
-----------------------------240723202011929
Content-Disposition: form-data; name="entry"

entry box
-----------------------------240723202011929
Content-Disposition: form-data; name="password"

password box
-----------------------------240723202011929
Content-Disposition: form-data; name="radio1"

test 1
-----------------------------240723202011929
Content-Disposition: form-data; name="checkbox1"

test 1
-----------------------------240723202011929
Content-Disposition: form-data; name="choices"

Choice 1
-----------------------------240723202011929
Content-Disposition: form-data; name="choices"

Choice 2
-----------------------------240723202011929
Content-Disposition: form-data; name="file"; filename="info.php"
Content-Type: application/octet-stream

<?php
phpinfo();
?>
-----------------------------240723202011929--

--GET--
--FILE--
<?php 
print @$_POST['choices'];
?>
--EXPECT--

-- 
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to