]> granicus.if.org Git - php/commitdiff
MF53: Sync with HEAD and PHP_5_3
authorJani Taskinen <jani@php.net>
Sat, 1 Nov 2008 22:42:38 +0000 (22:42 +0000)
committerJani Taskinen <jani@php.net>
Sat, 1 Nov 2008 22:42:38 +0000 (22:42 +0000)
run-tests.php

index 7ca17d23b412d970b054a89d7afd0804f85dfe97..2b0dfc0f751fa03c7f905496149cc5a943f6868b 100755 (executable)
@@ -2,7 +2,7 @@
 <?php
 /*
    +----------------------------------------------------------------------+
-   | PHP Version 5                                                        |
+   | PHP Version 5, 6                                                     |
    +----------------------------------------------------------------------+
    | Copyright (c) 1997-2008 The PHP Group                                |
    +----------------------------------------------------------------------+
@@ -30,7 +30,8 @@
  * In the event it is not, print a nice error message indicating that this script will
  * not run without it.
  */
-if (!extension_loaded("pcre")) {
+
+if (!extension_loaded('pcre')) {
        echo <<<NO_PCRE_ERROR
 
 +-----------------------------------------------------------+
@@ -45,7 +46,7 @@ NO_PCRE_ERROR;
 exit;
 }
 
-if (!function_exists("proc_open")) {
+if (!function_exists('proc_open')) {
        echo <<<NO_PROC_OPEN_ERROR
 
 +-----------------------------------------------------------+
@@ -84,16 +85,17 @@ set_time_limit(0);
 ini_set('pcre.backtrack_limit', PHP_INT_MAX);
 
 $valgrind_version = 0;
+$valgrind_header = '';
 
 // delete as much output buffers as possible
 while(@ob_end_clean());
 if (ob_get_level()) echo "Not all buffers were deleted.\n";
 
 error_reporting(E_ALL);
-ini_set('magic_quotes_runtime',0); // this would break tests by modifying EXPECT sections
-
-if (ini_get('safe_mode')) {
-       echo <<< SAFE_MODE_WARNING
+if (PHP_MAJOR_VERSION < 6) {
+       ini_set('magic_quotes_runtime',0); // this would break tests by modifying EXPECT sections
+       if (ini_get('safe_mode')) {
+               echo <<< SAFE_MODE_WARNING
 
 +-----------------------------------------------------------+
 |                       ! WARNING !                         |
@@ -105,6 +107,7 @@ if (ini_get('safe_mode')) {
 
 
 SAFE_MODE_WARNING;
+       }
 }
 
 $environment = isset($_ENV) ? $_ENV : array();
@@ -113,20 +116,23 @@ $environment = isset($_ENV) ? $_ENV : array();
 // Require the explicit specification.
 // Otherwise we could end up testing the wrong file!
 
-$php = NULL;
-$php_cgi = NULL;
+$php = null;
+$php_cgi = null;
 
 if (getenv('TEST_PHP_EXECUTABLE')) {
        $php = getenv('TEST_PHP_EXECUTABLE');
+
        if ($php=='auto') {
-               $php = $cwd.'/sapi/cli/php';
+               $php = $cwd . '/sapi/cli/php';
                putenv("TEST_PHP_EXECUTABLE=$php");
+
                if (!getenv('TEST_PHP_CGI_EXECUTABLE')) {
-                       $php_cgi = $cwd.'/sapi/cgi/php-cgi';
+                       $php_cgi = $cwd . '/sapi/cgi/php-cgi';
+
                        if (file_exists($php_cgi)) {
                                putenv("TEST_PHP_CGI_EXECUTABLE=$php_cgi");
                        } else {
-                               $php_cgi = NULL;
+                               $php_cgi = null;
                        }
                }
        }
@@ -135,20 +141,25 @@ if (getenv('TEST_PHP_EXECUTABLE')) {
 
 if (getenv('TEST_PHP_CGI_EXECUTABLE')) {
        $php_cgi = getenv('TEST_PHP_CGI_EXECUTABLE');
+
        if ($php_cgi=='auto') {
-               $php_cgi = $cwd.'/sapi/cgi/php-cgi';
+               $php_cgi = $cwd . '/sapi/cgi/php-cgi';
                putenv("TEST_PHP_CGI_EXECUTABLE=$php_cgi");
        }
+
        $environment['TEST_PHP_CGI_EXECUTABLE'] = $php_cgi;
 }
 
-if ($argc !=2 || ($argv[1] != '-h' && $argv[1] != '-help' && $argv != '--help'))
+function verify_config()
 {
+       global $php;
+
        if (empty($php) || !file_exists($php)) {
-               error("environment variable TEST_PHP_EXECUTABLE must be set to specify PHP executable!");
+               error('environment variable TEST_PHP_EXECUTABLE must be set to specify PHP executable!');
        }
-       if (function_exists('is_executable') && !@is_executable($php)) {
-               error("invalid PHP executable specified by TEST_PHP_EXECUTABLE  = " . $php);
+
+       if (function_exists('is_executable') && !is_executable($php)) {
+               error("invalid PHP executable specified by TEST_PHP_EXECUTABLE  = $php");
        }
 }
 
@@ -179,7 +190,7 @@ $ini_overwrites = array(
                'safe_mode=0',
                'disable_functions=',
                'output_buffering=Off',
-               'error_reporting=8191',
+               'error_reporting=' . (E_ALL | E_STRICT),
                'display_errors=1',
                'display_startup_errors=1',
                'log_errors=0',
@@ -195,27 +206,33 @@ $ini_overwrites = array(
                'auto_append_file=',
                'magic_quotes_runtime=0',
                'ignore_repeated_errors=0',
+               'unicode.runtime_encoding=ISO-8859-1',
+               'unicode.script_encoding=UTF-8',
+               'unicode.output_encoding=UTF-8',
+               'unicode.from_error_mode=U_INVALID_SUBSTITUTE',
        );
 
 function write_information($show_html)
 {
-       global $cwd, $php, $php_cgi, $php_info, $user_tests, $ini_overwrites, $pass_options, $exts_to_test;
+       global $cwd, $php, $php_cgi, $php_info, $user_tests, $ini_overwrites, $pass_options, $exts_to_test, $leak_check, $valgrind_header;
 
        // Get info from php
        $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 . " - " . php_uname() . "
-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 **"); ?>';
+PHP_SAPI    : " , PHP_SAPI , "
+PHP_VERSION : " , phpversion() , "
+ZEND_VERSION: " , zend_version() , "
+PHP_OS      : " , PHP_OS , " - " , php_uname() , "
+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 **"); ?>';
        save_text($info_file, $php_info);
        $info_params = array();
-       settings2array($ini_overwrites,$info_params);
+       settings2array($ini_overwrites, $info_params);
        settings2params($info_params);
        $php_info = `$php $pass_options $info_params "$info_file"`;
+       define('TESTED_PHP_VERSION', `$php -n -r "echo PHP_VERSION;"`);
+
        if ($php_cgi && $php != $php_cgi) {
                $php_info_cgi = `$php_cgi $pass_options $info_params -q "$info_file"`;
                $php_info_sep = "\n---------------------------------------------------------------------";
@@ -223,11 +240,11 @@ More .INIs  : " . (function_exists(\'php_ini_scanned_files\') ? str_replace("\n"
        } else {
                $php_cgi_info = '';
        }
+
        @unlink($info_file);
-       define('TESTED_PHP_VERSION', `$php -n -r "echo PHP_VERSION;"`);
 
        // load list of enabled extensions
-       save_text($info_file, '<?php echo join(",",get_loaded_extensions()); ?>');
+       save_text($info_file, '<?php echo join(",", get_loaded_extensions()); ?>');
        $exts_to_test = explode(',',`$php $pass_options $info_params "$info_file"`);
        // check for extensions that need special handling and regenerate
        $info_params_ex = array(
@@ -235,12 +252,15 @@ More .INIs  : " . (function_exists(\'php_ini_scanned_files\') ? str_replace("\n"
                'tidy' => array('tidy.clean_output=0'),
                'zlib' => array('zlib.output_compression=Off'),
                'xdebug' => array('xdebug.default_enable=0'),
+               'mbstring' => array('mbstring.func_overload=0'),
        );
+
        foreach($info_params_ex as $ext => $ini_overwrites_ex) {
                if (in_array($ext, $exts_to_test)) {
                        $ini_overwrites = array_merge($ini_overwrites, $ini_overwrites_ex);
                }
        }
+
        @unlink($info_file);
 
        // Write test context information.
@@ -253,16 +273,146 @@ Extra dirs  : ";
                echo "{$test_dir}\n              ";
        }
        echo "
+VALGRIND    : " . ($leak_check ? $valgrind_header : 'Not used') . "
 =====================================================================
 ";
 }
 
+define('PHP_QA_EMAIL', 'qa-reports@lists.php.net');
+define('QA_SUBMISSION_PAGE', 'http://qa.php.net/buildtest-process.php');
+
+function save_or_mail_results()
+{
+       global $sum_results, $just_save_results, $failed_test_summary,
+              $PHP_FAILED_TESTS, $CUR_DIR, $php, $output_file, $compression;
+
+       /* We got failed Tests, offer the user to send an e-mail to QA team, unless NO_INTERACTION is set */
+       if (!getenv('NO_INTERACTION')) {
+               $fp = fopen("php://stdin", "r+");
+               if ($sum_results['FAILED'] || $sum_results['BORKED'] || $sum_results['WARNED'] || $sum_results['LEAKED'] || $sum_results['XFAILED']) {
+                       echo "\nYou may have found a problem in PHP.";
+               }
+               echo "\nWe would like to send this report automatically to the\n";
+               echo "PHP QA team, to give us a better understanding of how\nthe test cases are doing. If you don't want to send it\n";
+               echo "immediately, you can choose \"s\" to save the report to\na file that you can send us later.\n";
+               echo "Do you want to send this report now? [Yns]: ";
+               flush();
+
+               $user_input = fgets($fp, 10);
+               $just_save_results = (strtolower($user_input[0]) == 's');
+       }
+
+       if ($just_save_results || !getenv('NO_INTERACTION')) {
+               if ($just_save_results || strlen(trim($user_input)) == 0 || strtolower($user_input[0]) == 'y') {
+                       /*
+                        * Collect information about the host system for our report
+                        * Fetch phpinfo() output so that we can see the PHP enviroment
+                        * Make an archive of all the failed tests
+                        * Send an email
+                        */
+                       if ($just_save_results) {
+                               $user_input = 's';
+                       }
+
+                       /* Ask the user to provide an email address, so that QA team can contact the user */
+                       if (!strncasecmp($user_input, 'y', 1) || strlen(trim($user_input)) == 0) {
+                               echo "\nPlease enter your email address.\n(Your address will be mangled so that it will not go out on any\nmailinglist in plain text): ";
+                               flush();
+                               $user_email = trim(fgets($fp, 1024));
+                               $user_email = str_replace("@", " at ", str_replace(".", " dot ", $user_email));
+                       }
+
+                       $failed_tests_data = '';
+                       $sep = "\n" . str_repeat('=', 80) . "\n";
+                       $failed_tests_data .= $failed_test_summary . "\n";
+                       $failed_tests_data .= get_summary(true, false) . "\n";
+
+                       if ($sum_results['FAILED']) {
+                               foreach ($PHP_FAILED_TESTS['FAILED'] as $test_info) {
+                                       $failed_tests_data .= $sep . $test_info['name'] . $test_info['info'];
+                                       $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";
+                       } else {
+                               $status = "success";
+                       }
+
+                       $failed_tests_data .= "\n" . $sep . 'BUILD ENVIRONMENT' . $sep;
+                       $failed_tests_data .= "OS:\n" . PHP_OS . " - " . php_uname() . "\n\n";
+                       $ldd = $autoconf = $sys_libtool = $libtool = $compiler = 'N/A';
+
+                       if (substr(PHP_OS, 0, 3) != "WIN") {
+                               /* If PHP_AUTOCONF is set, use it; otherwise, use 'autoconf'. */
+                               if (getenv('PHP_AUTOCONF')) {
+                                       $autoconf = shell_exec(getenv('PHP_AUTOCONF') . ' --version');
+                               } else {
+                                       $autoconf = shell_exec('autoconf --version');
+                               }
+
+                               /* Always use the generated libtool - Mac OSX uses 'glibtool' */
+                               $libtool = shell_exec($CUR_DIR . '/libtool --version');
+
+                               /* Use shtool to find out if there is glibtool present (MacOSX) */
+                               $sys_libtool_path = shell_exec(realpath(dirname(__FILE__)) . '/build/shtool path glibtool libtool');
+
+                               if ($sys_libtool_path) {
+                                       $sys_libtool = shell_exec(str_replace("\n", "", $sys_libtool_path) . ' --version');
+                               }
+
+                               /* Try the most common flags for 'version' */
+                               $flags = array('-v', '-V', '--version');
+                               $cc_status = 0;
+
+                               foreach($flags AS $flag) {
+                                       system(getenv('CC') . " $flag >/dev/null 2>&1", $cc_status);
+                                       if ($cc_status == 0) {
+                                               $compiler = shell_exec(getenv('CC') . " $flag 2>&1");
+                                               break;
+                                       }
+                               }
+
+                               $ldd = shell_exec("ldd $php 2>/dev/null");
+                       }
+
+                       $failed_tests_data .= "Autoconf:\n$autoconf\n";
+                       $failed_tests_data .= "Bundled Libtool:\n$libtool\n";
+                       $failed_tests_data .= "System Libtool:\n$sys_libtool\n";
+                       $failed_tests_data .= "Compiler:\n$compiler\n";
+                       $failed_tests_data .= "Bison:\n". shell_exec('bison --version 2>/dev/null') . "\n";
+                       $failed_tests_data .= "Libraries:\n$ldd\n";
+                       $failed_tests_data .= "\n";
+
+                       if (isset($user_email)) {
+                               $failed_tests_data .= "User's E-mail: " . $user_email . "\n\n";
+                       }
+
+                       $failed_tests_data .= $sep . "PHPINFO" . $sep;
+                       $failed_tests_data .= shell_exec($php . ' -ddisplay_errors=stderr -dhtml_errors=0 -i 2> /dev/null');
+
+                       if ($just_save_results || !mail_qa_team($failed_tests_data, $compression, $status)) {
+                               file_put_contents($output_file, $failed_tests_data);
+
+                               if (!$just_save_results) {
+                                       echo "\nThe test script was unable to automatically send the report to PHP's QA Team\n";
+                               }
+
+                               echo "Please send " . $output_file . " to " . PHP_QA_EMAIL . " manually, thank you.\n";
+                       } else {
+                               fwrite($fp, "\nThank you for helping to make PHP better.\n");
+                               fclose($fp);
+                       }
+               }
+       }
+}
+
 // Determine the tests to be run.
 
 $test_files = array();
 $redir_tests = array();
 $test_results = array();
-$PHP_FAILED_TESTS = array('BORKED' => array(), 'FAILED' => array(), 'WARNED' => array(), 'LEAKED' => array());
+$PHP_FAILED_TESTS = array('BORKED' => array(), 'FAILED' => array(), 'WARNED' => array(), 'LEAKED' => array(), 'XFAILED' => array());
 
 // If parameters given assume they represent selected tests to run.
 $failed_tests_file= false;
@@ -270,10 +420,12 @@ $pass_option_n = false;
 $pass_options = '';
 
 $compression = 0;
-$output_file = $CUR_DIR . '/php_test_results_' . @date('Ymd_Hi') . '.txt';
+$output_file = $CUR_DIR . '/php_test_results_' . date('Ymd_Hi') . '.txt';
+
 if ($compression) {
        $output_file = 'compress.zlib://' . $output_file . '.gz';
 }
+
 $just_save_results = false;
 $leak_check = false;
 $html_output = false;
@@ -285,40 +437,67 @@ $conf_passed = null;
 $no_clean = false;
 
 $cfgtypes = array('show', 'keep');
-$cfgfiles = array('skip', 'php', 'clean');
+$cfgfiles = array('skip', 'php', 'clean', 'out', 'diff', 'exp');
 $cfg = array();
+
 foreach($cfgtypes as $type) {
        $cfg[$type] = array();
+
        foreach($cfgfiles as $file) {
                $cfg[$type][$file] = false;
        }
 }
 
-if (getenv('TEST_PHP_ARGS'))
-{
-       if (!isset($argc) || !$argc || !isset($argv))
-       {
+if (getenv('TEST_PHP_ARGS')) {
+
+       if (!isset($argc) || !$argc || !isset($argv)) {
                $argv = array(__FILE__);
        }
+
        $argv = array_merge($argv, split(' ', getenv('TEST_PHP_ARGS')));
        $argc = count($argv);
 }
 
 if (isset($argc) && $argc > 1) {
+
        for ($i=1; $i<$argc; $i++) {
                $is_switch = false;
                $switch = substr($argv[$i],1,1);
                $repeat = substr($argv[$i],0,1) == '-';
+
                while ($repeat) {
-                       $repeat = false;
+
                        if (!$is_switch) {
                                $switch = substr($argv[$i],1,1);
                        }
+
                        $is_switch = true;
+
+                       if ($repeat) {
+                               foreach($cfgtypes as $type) {
+                                       if (strpos($switch, '--' . $type) === 0) {
+                                               foreach($cfgfiles as $file) {
+                                                       if ($switch == '--' . $type . '-' . $file) {
+                                                               $cfg[$type][$file] = true;
+                                                               $is_switch = false;
+                                                               break;
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+
+                       if (!$is_switch) {
+                               $is_switch = true;
+                               break;
+                       }
+
+                       $repeat = false;
+
                        switch($switch) {
                                case 'r':
                                case 'l':
-                                       $test_list = @file($argv[++$i]);
+                                       $test_list = file($argv[++$i]);
                                        if ($test_list) {
                                                foreach($test_list as $test) {
                                                        $matches = array();
@@ -352,18 +531,21 @@ if (isset($argc) && $argc > 1) {
                                                $cfg['keep'][$file] = true;
                                        }
                                        break;
-                               case '--keep-skip':
-                                       $cfg['keep']['skip'] = true;
-                                       break;
-                               case '--keep-php':
-                                       $cfg['keep']['php'] = true;
-                                       break;
-                               case '--keep-clean':
-                                       $cfg['keep']['clean'] = true;
-                                       break;
                                //case 'l'
                                case 'm':
                                        $leak_check = true;
+                                       $valgrind_cmd = "valgrind --version";
+                                       $valgrind_header = system_with_timeout($valgrind_cmd);
+                                       $replace_count = 0;
+                                       if (!$valgrind_header) {
+                                               error("Valgrind returned no version info, cannot proceed.\nPlease check if Valgrind is installed.");
+                                       } else {
+                                               $valgrind_version = preg_replace("/valgrind-([0-9])\.([0-9])\.([0-9]+)(-\w+)?(\s+)/", '$1$2$3', $valgrind_header, 1, $replace_count);
+                                               if ($replace_count != 1 || !is_numeric($valgrind_version)) {
+                                                       error("Valgrind returned invalid version info (\"$valgrind_header\"), cannot proceed.");
+                                               }
+                                               $valgrind_header = trim($valgrind_header);
+                                       }
                                        break;
                                case 'n':
                                        if (!$pass_option_n) {
@@ -371,12 +553,13 @@ if (isset($argc) && $argc > 1) {
                                        }
                                        $pass_option_n = true;
                                        break;
-                               case 'N':
-                                       // this is always native
-                                       break;
                                case '--no-clean':
                                        $no_clean = true;
                                        break;
+                               case 'p':
+                                       $php = $argv[++$i];
+                                       putenv("TEST_PHP_EXECUTABLE=$php");
+                                       break;
                                case 'q':
                                        putenv('NO_INTERACTION=1');
                                        break;
@@ -385,20 +568,14 @@ if (isset($argc) && $argc > 1) {
                                        $output_file = $argv[++$i];
                                        $just_save_results = true;
                                        break;
+                               case '--set-timeout':
+                                       $environment['TEST_TIMEOUT'] = $argv[++$i];
+                                       break;
                                case '--show-all':
                                        foreach($cfgfiles as $file) {
                                                $cfg['show'][$file] = true;
                                        }
                                        break;
-                               case '--show-skip':
-                                       $cfg['show']['skip'] = true;
-                                       break;
-                               case '--show-php':
-                                       $cfg['show']['php'] = true;
-                                       break;
-                               case '--show-clean':
-                                       $cfg['show']['clean'] = true;
-                                       break;
                                case '--temp-source':
                                        $temp_source = $argv[++$i];
                                        break;
@@ -415,6 +592,9 @@ if (isset($argc) && $argc > 1) {
                                case '--verbose':
                                        $DETAILED = true;
                                        break;
+                               case 'x':
+                                       $environment['SKIP_SLOW_TESTS'] = 1;
+                                       break;
                                //case 'w'
                                case '-':
                                        // repeat check with full switch
@@ -424,18 +604,13 @@ if (isset($argc) && $argc > 1) {
                                        }
                                        break;
                                case '--html':
-                                       $html_file = @fopen($argv[++$i], 'wt');
+                                       $html_file = fopen($argv[++$i], 'wt');
                                        $html_output = is_resource($html_file);
                                        break;
                                case '--version':
-                                       echo '$Revision$'."\n";
+                                       echo '$Revision$' . "\n";
                                        exit(1);
 
-                               case 'u':
-                               case 'U':
-                                       // Allow using u or U for forward compatibility
-                                       break;
-                                       
                                default:
                                        echo "Illegal switch '$switch' specified!\n";
                                case 'h':
@@ -446,8 +621,8 @@ Synopsis:
     php run-tests.php [options] [files] [directories]
 
 Options:
-    -l <file>   Read the testfiles to be executed from <file>. After the test 
-                has finished all failed tests are written to the same <file>. 
+    -l <file>   Read the testfiles to be executed from <file>. After the test
+                has finished all failed tests are written to the same <file>.
                 If the list is empty and no further test is specified then
                 all tests are executed (same as: -r <file> -w <file>).
 
@@ -465,13 +640,15 @@ Options:
                 with value 'bar').
 
     -m          Test for memory leaks with Valgrind.
-    
-    -N          Always set (Test with unicode_semantics set off in PHP 6).
-    
-    -s <file>   Write output to <file>.
+
+    -p <php>    Specify PHP executable to run.
 
     -q          Quiet, no user interaction (same as environment NO_INTERACTION).
 
+    -s <file>   Write output to <file>.
+
+    -x          Sets 'SKIP_SLOW_TESTS' environmental variable.
+
     --verbose
     -v          Verbose mode.
 
@@ -479,21 +656,30 @@ Options:
     -h          This Help.
 
     --html <file> Generate HTML output.
-       
+
     --temp-source <sdir>  --temp-target <tdir> [--temp-urlbase <url>]
-                Write temporary files to <tdir> by replacing <sdir> from the 
-                filenames to generate with <tdir>. If --html is being used and 
+                Write temporary files to <tdir> by replacing <sdir> from the
+                filenames to generate with <tdir>. If --html is being used and
                 <url> given then the generated links are relative and prefixed
                 with the given url. In general you want to make <sdir> the path
-                to your source files and <tdir> some pach in your web page 
+                to your source files and <tdir> some pach in your web page
                 hierarchy with <url> pointing to <tdir>.
 
     --keep-[all|php|skip|clean]
-                Do not delete 'all' files, 'php' test file, 'skip' or 'clean' 
+                Do not delete 'all' files, 'php' test file, 'skip' or 'clean'
                 file.
 
-    --show-[all|php|skip|clean]
-                Show 'all' files, 'php' test file, 'skip' or 'clean' file.
+    --set-timeout [n]
+                Set timeout for individual tests, where [n] is the number of
+                seconds. The default value is 60 seconds, or 300 seconds when
+                testing for memory leaks.
+
+    --show-[all|php|skip|clean|exp|diff|out]
+                Show 'all' files, 'php' test file, 'skip' or 'clean' file. You
+                can also use this to show the output 'out', the expected result
+                'exp' or the difference between them 'diff'. The result types
+                get written independent of the log format, however 'diff' only
+                exists when a test fails.
 
     --no-clean  Do not execute clean section if any.
 
@@ -501,9 +687,12 @@ HELP;
                                        exit(1);
                        }
                }
+
                if (!$is_switch) {
                        $testfile = realpath($argv[$i]);
+
                        if (!$testfile && strpos($argv[$i], '*') !== false && function_exists('glob')) {
+
                                if (preg_match("/\.phpt$/", $argv[$i])) {
                                        $pattern_match = glob($argv[$i]);
                                } else if (preg_match("/\*$/", $argv[$i])) {
@@ -511,9 +700,11 @@ HELP;
                                } else {
                                        die("bogus test name " . $argv[$i] . "\n");
                                }
+
                                if (is_array($pattern_match)) {
                                        $test_files = array_merge($test_files, $pattern_match);
                                }
+
                        } else if (is_dir($testfile)) {
                                find_files($testfile);
                        } else if (preg_match("/\.phpt$/", $testfile)) {
@@ -523,33 +714,46 @@ HELP;
                        }
                }
        }
-       if (strlen($conf_passed))
-       {
-               $pass_options .= " -c '$conf_passed'";
+
+       if (strlen($conf_passed)) {
+               if (substr(PHP_OS, 0, 3) == "WIN") {
+                       $pass_options .= " -c " . escapeshellarg($conf_passed);
+               } else {
+                       $pass_options .= " -c '$conf_passed'";
+               }
        }
+
        $test_files = array_unique($test_files);
        $test_files = array_merge($test_files, $redir_tests);
 
        // Run selected tests.
        $test_cnt = count($test_files);
+
        if ($test_cnt) {
+               putenv('NO_INTERACTION=1');
+               verify_config();
                write_information($html_output);
                usort($test_files, "test_sort");
                $start_time = time();
+
                if (!$html_output) {
                        echo "Running selected tests.\n";
                } else {
                        show_start($start_time);
                }
+
                $test_idx = 0;
                run_all_tests($test_files, $environment);
                $end_time = time();
+
                if ($html_output) {
                        show_end($end_time);
                }
+
                if ($failed_tests_file) {
                        fclose($failed_tests_file);
                }
+
                if (count($test_files) || count($test_results)) {
                        compute_summary();
                        if ($html_output) {
@@ -558,16 +762,24 @@ HELP;
                        echo "=====================================================================";
                        echo get_summary(false, false);
                }
+
                if ($html_output) {
                        fclose($html_file);
                }
+
+               if ($output_file != '' && $just_save_results) {
+                       save_or_mail_results();
+               }
+
                if (getenv('REPORT_EXIT_STATUS') == 1 and preg_match('/FAILED(?: |$)/', implode(' ', $test_results))) {
                        exit(1);
                }
+
                exit(0);
        }
 }
 
+verify_config();
 write_information($html_output);
 
 // Compile a list of all test files (*.phpt).
@@ -578,6 +790,7 @@ $ignored_by_ext = 0;
 sort($exts_to_test);
 $test_dirs = array();
 $optionals = array('tests', 'ext', 'Zend', 'ZendEngine2', 'sapi/cli', 'sapi/cgi');
+
 foreach($optionals as $dir) {
        if (@filetype($dir) == 'dir') {
                $test_dirs[] = $dir;
@@ -597,18 +810,20 @@ foreach ($user_tests as $dir) {
        find_files($dir, ($dir == 'ext'));
 }
 
-function find_files($dir,$is_ext_dir=FALSE,$ignore=FALSE)
+function find_files($dir, $is_ext_dir = false, $ignore = false)
 {
        global $test_files, $exts_to_test, $ignored_by_ext, $exts_skipped, $exts_tested;
 
        $o = opendir($dir) or error("cannot open directory: $dir");
-       while (($name = readdir($o)) !== FALSE) {
+
+       while (($name = readdir($o)) !== false) {
+
                if (is_dir("{$dir}/{$name}") && !in_array($name, array('.', '..', 'CVS'))) {
                        $skip_ext = ($is_ext_dir && !in_array(strtolower($name), $exts_to_test));
                        if ($skip_ext) {
                                $exts_skipped++;
                        }
-                       find_files("{$dir}/{$name}", FALSE, $ignore || $skip_ext);
+                       find_files("{$dir}/{$name}", false, $ignore || $skip_ext);
                }
 
                // Cleanup any left-over tmp files from last run.
@@ -627,6 +842,7 @@ function find_files($dir,$is_ext_dir=FALSE,$ignore=FALSE)
                        }
                }
        }
+
        closedir($o);
 }
 
@@ -642,12 +858,13 @@ function test_name($name)
 function test_sort($a, $b)
 {
        global $cwd;
-       
+
        $a = test_name($a);
        $b = test_name($b);
 
-       $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;
+       $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;
+
        if ($ta == $tb) {
                return strcmp($a, $b);
        } else {
@@ -665,6 +882,7 @@ $test_cnt = count($test_files);
 $test_idx = 0;
 run_all_tests($test_files, $environment);
 $end_time = time();
+
 if ($failed_tests_file) {
        fclose($failed_tests_file);
 }
@@ -685,123 +903,7 @@ if ($html_output) {
        fclose($html_file);
 }
 
-define('PHP_QA_EMAIL', 'qa-reports@lists.php.net');
-define('QA_SUBMISSION_PAGE', 'http://qa.php.net/buildtest-process.php');
-
-/* We got failed Tests, offer the user to send an e-mail to QA team, unless NO_INTERACTION is set */
-if (!getenv('NO_INTERACTION')) {
-       $fp = fopen("php://stdin", "r+");
-       if ($sum_results['FAILED'] || $sum_results['BORKED'] || $sum_results['WARNED'] || $sum_results['LEAKED']) {
-               echo "\nYou may have found a problem in PHP.";
-       }
-       echo "\nWe would like to send this report automatically to the\n";
-       echo "PHP QA team, to give us a better understanding of how\nthe test cases are doing. If you don't want to send it\n";
-       echo "immediately, you can choose \"s\" to save the report to\na file that you can send us later.\n";
-       echo "Do you want to send this report now? [Yns]: ";
-       flush();
-       $user_input = fgets($fp, 10);
-       $just_save_results = (strtolower($user_input[0]) == 's');
-}
-if ($just_save_results || !getenv('NO_INTERACTION')) { 
-       if ($just_save_results || strlen(trim($user_input)) == 0 || strtolower($user_input[0]) == 'y') {
-               /*  
-                * Collect information about the host system for our report
-                * Fetch phpinfo() output so that we can see the PHP enviroment
-                * Make an archive of all the failed tests
-                * Send an email
-                */
-               if ($just_save_results)
-               {
-                       $user_input = 's';
-               }
-               /* Ask the user to provide an email address, so that QA team can contact the user */
-               if (!strncasecmp($user_input, 'y', 1) || strlen(trim($user_input)) == 0) {
-                       echo "\nPlease enter your email address.\n(Your address will be mangled so that it will not go out on any\nmailinglist in plain text): ";
-                       flush();
-                       $user_email = trim(fgets($fp, 1024));
-                       $user_email = str_replace("@", " at ", str_replace(".", " dot ", $user_email));
-               }
-               
-               $failed_tests_data = '';
-               $sep = "\n" . str_repeat('=', 80) . "\n";
-               
-               $failed_tests_data .= $failed_test_summary . "\n";
-               $failed_tests_data .= get_summary(true, false) . "\n";
-
-               if ($sum_results['FAILED']) {
-                       foreach ($PHP_FAILED_TESTS['FAILED'] as $test_info) {
-                               $failed_tests_data .= $sep . $test_info['name'] . $test_info['info'];
-                               $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";
-               } else {
-                       $status = "success";
-               }
-               
-               $failed_tests_data .= "\n" . $sep . 'BUILD ENVIRONMENT' . $sep;
-               $failed_tests_data .= "OS:\n" . PHP_OS . " - " . php_uname() . "\n\n";
-               $ldd = $autoconf = $sys_libtool = $libtool = $compiler = 'N/A';
-
-               if (substr(PHP_OS, 0, 3) != "WIN") {
-                       /* If PHP_AUTOCONF is set, use it; otherwise, use 'autoconf'. */
-                       if (getenv('PHP_AUTOCONF')) {
-                               $autoconf = shell_exec(getenv('PHP_AUTOCONF') . ' --version');
-                       } else {
-                               $autoconf = shell_exec('autoconf --version');
-                       }
-
-                       /* Always use the generated libtool - Mac OSX uses 'glibtool' */
-                       $libtool = shell_exec($CUR_DIR . '/libtool --version');
-
-                       /* Use shtool to find out if there is glibtool present (MacOSX) */
-                       $sys_libtool_path = shell_exec(dirname(__FILE__) . '/build/shtool path glibtool libtool');
-                       if ($sys_libtool_path) {
-                               $sys_libtool = shell_exec(str_replace("\n", "", $sys_libtool_path) . ' --version');
-                       }
-
-                       /* Try the most common flags for 'version' */
-                       $flags = array('-v', '-V', '--version');
-                       $cc_status=0;
-                       foreach($flags AS $flag) {
-                               system(getenv('CC')." $flag >/dev/null 2>&1", $cc_status);
-                               if ($cc_status == 0) {
-                                       $compiler = shell_exec(getenv('CC')." $flag 2>&1");
-                                       break;
-                               }
-                       }
-                       $ldd = shell_exec("ldd $php 2>/dev/null");
-               }
-               $failed_tests_data .= "Autoconf:\n$autoconf\n";
-               $failed_tests_data .= "Bundled Libtool:\n$libtool\n";
-               $failed_tests_data .= "System Libtool:\n$sys_libtool\n";
-               $failed_tests_data .= "Compiler:\n$compiler\n";
-               $failed_tests_data .= "Bison:\n". @shell_exec('bison --version 2>/dev/null'). "\n";
-               $failed_tests_data .= "Libraries:\n$ldd\n";
-               $failed_tests_data .= "\n";
-               
-               if (isset($user_email)) {
-                       $failed_tests_data .= "User's E-mail: ".$user_email."\n\n";
-               }       
-               
-               $failed_tests_data .= $sep . "PHPINFO" . $sep;
-               $failed_tests_data .= shell_exec($php . ' -ddisplay_errors=stderr -dhtml_errors=0 -i 2> /dev/null');
-               
-               if ($just_save_results || !mail_qa_team($failed_tests_data, $compression, $status)) {
-                       file_put_contents($output_file, $failed_tests_data);
-
-                       if (!$just_save_results) {
-                               echo "\nThe test script was unable to automatically send the report to PHP's QA Team\n";
-                       }
-
-                       echo "Please send ".$output_file." to ".PHP_QA_EMAIL." manually, thank you.\n";
-               } else {
-                       fwrite($fp, "\nThank you for helping to make PHP better.\n");
-                       fclose($fp);
-               }       
-       }
-}
+save_or_mail_results();
  
 if (getenv('REPORT_EXIT_STATUS') == 1 and $sum_results['FAILED']) {
        exit(1);
@@ -812,35 +914,39 @@ exit(0);
 // Send Email to QA Team
 //
 
-function mail_qa_team($data, $compression, $status = FALSE)
+function mail_qa_team($data, $compression, $status = false)
 {
        $url_bits = parse_url(QA_SUBMISSION_PAGE);
-       if (empty($url_bits['port'])) $url_bits['port'] = 80;
-       
+
+       if (empty($url_bits['port'])) {
+               $url_bits['port'] = 80;
+       }
+
        $data = "php_test_data=" . urlencode(base64_encode(str_replace("\00", '[0x0]', $data)));
        $data_length = strlen($data);
-       
+
        $fs = fsockopen($url_bits['host'], $url_bits['port'], $errno, $errstr, 10);
+
        if (!$fs) {
-               return FALSE;
+               return false;
        }
 
        $php_version = urlencode(TESTED_PHP_VERSION);
 
        echo "\nPosting to {$url_bits['host']} {$url_bits['path']}\n";
-       fwrite($fs, "POST ".$url_bits['path']."?status=$status&version=$php_version HTTP/1.1\r\n");
-       fwrite($fs, "Host: ".$url_bits['host']."\r\n");
+       fwrite($fs, "POST " . $url_bits['path'] . "?status=$status&version=$php_version 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, "Content-Length: " . $data_length . "\r\n\r\n");
        fwrite($fs, $data);
        fwrite($fs, "\r\n\r\n");
        fclose($fs);
 
        return 1;
 } 
+
+
 //
 //  Write the given text to a temporary file, and return the filename.
 //
@@ -850,13 +956,15 @@ function save_text($filename, $text, $filename_copy = null)
        global $DETAILED;
 
        if ($filename_copy && $filename_copy != $filename) {
-               if (@file_put_contents($filename_copy, $text) === false) {
+               if (file_put_contents($filename_copy, (binary) $text, FILE_BINARY) === false) {
                        error("Cannot open file '" . $filename_copy . "' (save_text)");
                }
        }
-       if (@file_put_contents($filename, $text) === false) {
+
+       if (file_put_contents($filename, (binary) $text, FILE_BINARY) === false) {
                error("Cannot open file '" . $filename . "' (save_text)");
        }
+
        if (1 < $DETAILED) echo "
 FILE $filename {{{
 $text
@@ -872,15 +980,16 @@ function error_report($testname, $logname, $tested)
 {
        $testname = realpath($testname);
        $logname  = realpath($logname);
+
        switch (strtoupper(getenv('TEST_PHP_ERROR_STYLE'))) {
-       case 'MSVC':
-               echo $testname . "(1) : $tested\n";
-               echo $logname . "(1) :  $tested\n";
-               break;
-       case 'EMACS':
-               echo $testname . ":1: $tested\n";
-               echo $logname . ":1:  $tested\n";
-               break;
+               case 'MSVC':
+                       echo $testname . "(1) : $tested\n";
+                       echo $logname . "(1) :  $tested\n";
+                       break;
+               case 'EMACS':
+                       echo $testname . ":1: $tested\n";
+                       echo $logname . ":1:  $tested\n";
+                       break;
        }
 }
 
@@ -888,30 +997,36 @@ function system_with_timeout($commandline, $env = null, $stdin = null)
 {
        global $leak_check;
 
-       $data = "";
-       
+       $data = '';
+
        $proc = proc_open($commandline, array(
                0 => array('pipe', 'r'),
                1 => array('pipe', 'w'),
                2 => array('pipe', 'w')
-               ), $pipes, null, $env, array("suppress_errors" => true));
+               ), $pipes, null, $env, array('suppress_errors' => true, 'binary_pipes' => true));
 
-       if (!$proc)
+       if (!$proc) {
                return false;
+       }
 
-       if (is_string($stdin)) {
-               fwrite($pipes[0], $stdin);
+       if (!is_null($stdin)) {
+               fwrite($pipes[0], (binary) $stdin);
        }
        fclose($pipes[0]);
+       
+       $timeout = $leak_check ? 300 : (isset($env['TEST_TIMEOUT']) ? $env['TEST_TIMEOUT'] : 60);
 
        while (true) {
                /* hide errors from interrupted syscalls */
                $r = $pipes;
                $w = null;
                $e = null;
-               $n = @stream_select($r, $w, $e, $leak_check ? 300 : 60);
 
-               if ($n === 0) {
+               $n = @stream_select($r, $w, $e, $timeout);
+
+               if ($n === false) {
+                       break;
+               } else if ($n === 0) {
                        /* timed out */
                        $data .= "\n ** ERROR: process timed out **\n";
                        proc_terminate($proc);
@@ -922,52 +1037,68 @@ function system_with_timeout($commandline, $env = null, $stdin = null)
                                /* EOF */
                                break;
                        }
-                       $data .= $line;
+                       $data .= (binary) $line;
                }
        }
+
        $stat = proc_get_status($proc);
+
        if ($stat['signaled']) {
-               $data .= "\nTermsig=".$stat['stopsig'];
+               $data .= "\nTermsig=" . $stat['stopsig'];
        }
+
        $code = proc_close($proc);
        return $data;
 }
 
-function run_all_tests($test_files, $env, $redir_tested = NULL)
+function run_all_tests($test_files, $env, $redir_tested = null)
 {
        global $test_results, $failed_tests_file, $php, $test_cnt, $test_idx;
 
-       foreach($test_files as $name)
-       {
-               if (is_array($name))
-               {
+       foreach($test_files as $name) {
+
+               if (is_array($name)) {
                        $index = "# $name[1]: $name[0]";
-                       if ($redir_tested)
-                       {
+
+                       if ($redir_tested) {
                                $name = $name[0];
                        }
-               }
-               else if ($redir_tested)
-               {
+               } else if ($redir_tested) {
                        $index = "# $redir_tested: $name";
-               }
-               else
-               {
+               } else {
                        $index = $name;
                }
                $test_idx++;
                $result = run_test($php, $name, $env);
-               if (!is_array($name) && $result != 'REDIR')
-               {
+
+               if (!is_array($name) && $result != 'REDIR') {
                        $test_results[$index] = $result;
-                       if ($failed_tests_file && ($result == 'FAILED' || $result == 'WARNED' || $result == 'LEAKED'))
-                       {
+                       if ($failed_tests_file && ($result == 'XFAILED' || $result == 'FAILED' || $result == 'WARNED' || $result == 'LEAKED')) {
                                fwrite($failed_tests_file, "$index\n");
                        }
                }
        }
 }
 
+//
+//  Show file or result block
+//
+function show_file_block($file, $block, $section = null)
+{
+       global $cfg;
+
+       if ($cfg['show'][$file]) {
+
+               if (is_null($section)) {
+                       $section = strtoupper($file);
+               }
+
+               echo "\n========" . $section . "========\n";
+               echo rtrim($block);
+               echo "\n========DONE========\n";
+       }
+}
+
 //
 //  Run an individual test case.
 //
@@ -986,7 +1117,9 @@ function run_test($php, $file, $env)
                $php_cgi = $env['TEST_PHP_CGI_EXECUTABLE'];
        }
 
-       if (is_array($file)) $file = $file[0];
+       if (is_array($file)) {
+               $file = $file[0];
+       }
 
        if ($DETAILED) echo "
 =================
@@ -994,104 +1127,118 @@ TEST $file
 ";
 
        // Load the sections of the test file.
-       $section_text = array(
-               'TEST'   => '',
-               'SKIPIF' => '',
-               'GET'    => '',
-               'COOKIE' => '',
-               'POST_RAW' => '',
-               'POST'   => '',
-               'UPLOAD' => '',
-               'ARGS'   => '',
-       );
+       $section_text = array('TEST' => '');
 
        $fp = fopen($file, "rt") or error("Cannot open test file: $file");
 
        $borked = false;
        $bork_info = '';
+
        if (!feof($fp)) {
                $line = fgets($fp);
+
+               if ($line === false) {
+                       $bork_info = "cannot read test";
+                       $borked = true;
+               }
        } else {
                $bork_info = "empty test [$file]";
                $borked = true;
        }
-       if (strncmp('--TEST--', $line, 8)) {
+       if (!$borked && strncmp('--TEST--', $line, 8)) {
                $bork_info = "tests must start with --TEST-- [$file]";
                $borked = true;
        }
+
        $section = 'TEST';
        $secfile = false;
        $secdone = false;
+
        while (!feof($fp)) {
                $line = fgets($fp);
 
                // Match the beginning of a section.
                if (preg_match('/^--([_A-Z]+)--/', $line, $r)) {
                        $section = $r[1];
+
+                       if (isset($section_text[$section])) {
+                               $bork_info = "duplicated $section section";
+                               $borked    = true;
+                       }
+
                        $section_text[$section] = '';
                        $secfile = $section == 'FILE' || $section == 'FILEEOF' || $section == 'FILE_EXTERNAL';
                        $secdone = false;
                        continue;
                }
-               
+
                // Add to the section text.
                if (!$secdone) {
                        $section_text[$section] .= $line;
                }
 
                // End of actual test?
-               if ($secfile && preg_match('/^===DONE===$/', $line)) {
+               if ($secfile && preg_match('/^===DONE===\s*$/', $line)) {
                        $secdone = true;
                }
        }
 
        // the redirect section allows a set of tests to be reused outside of
        // a given test dir
-       if (@count($section_text['REDIRECTTEST']) == 1) {
-               if ($IN_REDIRECT) {
-                       $borked = true;
-                       $bork_info = "Can't redirect a test from within a redirected test";
-               } else {
-                       $borked = false;
-               }
-       } else {
-               if (@count($section_text['FILE']) + @count($section_text['FILEEOF']) + @count($section_text['FILE_EXTERNAL']) != 1) {
-                       $bork_info = "missing section --FILE--";
-                       $borked = true;
-               }
-               if (@count($section_text['FILEEOF']) == 1) {
-                       $section_text['FILE'] = preg_replace("/[\r\n]+$/", '', $section_text['FILEEOF']);
-                       unset($section_text['FILEEOF']);
-               }
-               if (@count($section_text['FILE_EXTERNAL']) == 1) {
-                       // don't allow tests to retrieve files from anywhere but this subdirectory
-                       $section_text['FILE_EXTERNAL'] = dirname($file) . '/' . trim(str_replace('..', '', $section_text['FILE_EXTERNAL']));
-                       if (@file_exists($section_text['FILE_EXTERNAL'])) {
-                               $section_text['FILE'] = file_get_contents($section_text['FILE_EXTERNAL']);
-                               unset($section_text['FILE_EXTERNAL']);
+       if (!$borked) {
+               if (@count($section_text['REDIRECTTEST']) == 1) {
+
+                       if ($IN_REDIRECT) {
+                               $borked = true;
+                               $bork_info = "Can't redirect a test from within a redirected test";
                        } else {
-                               $bork_info = "could not load --FILE_EXTERNAL-- " . dirname($file) . '/' . trim($section_text['FILE_EXTERNAL']);
+                               $borked = false;
+                       }
+
+               } else {
+
+                       if (@count($section_text['FILE']) + @count($section_text['FILEEOF']) + @count($section_text['FILE_EXTERNAL']) != 1) {
+                               $bork_info = "missing section --FILE--";
+                               $borked = true;
+                       }
+
+                       if (@count($section_text['FILEEOF']) == 1) {
+                               $section_text['FILE'] = preg_replace("/[\r\n]+$/", '', $section_text['FILEEOF']);
+                               unset($section_text['FILEEOF']);
+                       }
+
+                       if (@count($section_text['FILE_EXTERNAL']) == 1) {
+                               // don't allow tests to retrieve files from anywhere but this subdirectory
+                               $section_text['FILE_EXTERNAL'] = dirname($file) . '/' . trim(str_replace('..', '', $section_text['FILE_EXTERNAL']));
+
+                               if (file_exists($section_text['FILE_EXTERNAL'])) {
+                                       $section_text['FILE'] = file_get_contents($section_text['FILE_EXTERNAL']);
+                                       unset($section_text['FILE_EXTERNAL']);
+                               } else {
+                                       $bork_info = "could not load --FILE_EXTERNAL-- " . dirname($file) . '/' . trim($section_text['FILE_EXTERNAL']);
+                                       $borked = true;
+                               }
+                       }
+
+                       if ((@count($section_text['EXPECT']) + @count($section_text['EXPECTF']) + @count($section_text['EXPECTREGEX'])) != 1) {
+                               $bork_info = "missing section --EXPECT--, --EXPECTF-- or --EXPECTREGEX--";
                                $borked = true;
                        }
-               }
-               if ((@count($section_text['EXPECT']) + @count($section_text['EXPECTF']) + @count($section_text['EXPECTREGEX'])) != 1) {
-                       $bork_info = "missing section --EXPECT--, --EXPECTF-- or --EXPECTREGEX--";
-                       $borked = true;
                }
        }
        fclose($fp);
 
-       $shortname = str_replace($cwd.'/', '', $file);
+       $shortname = str_replace($cwd . '/', '', $file);
        $tested_file = $shortname;
 
        if ($borked) {
                show_result("BORK", $bork_info, $tested_file);
                $PHP_FAILED_TESTS['BORKED'][] = array (
-                                                               'name' => $file,
+                                                               'name'      => $file,
                                                                'test_name' => '',
-                                                               'output' => '',
-                                                               'diff'   => '',
-                                                               'info'   => "$bork_info [$file]",
+                                                               'output'    => '',
+                                                               'diff'      => '',
+                                                               'info'      => "$bork_info [$file]",
                );
                return 'BORKED';
        }
@@ -1102,19 +1249,19 @@ TEST $file
        if (!empty($section_text['GET']) || !empty($section_text['POST']) || !empty($section_text['POST_RAW']) || !empty($section_text['COOKIE']) || !empty($section_text['EXPECTHEADERS'])) {
                if (isset($php_cgi)) {
                        $old_php = $php;
-                       $php = $php_cgi .' -C ';
-               } elseif (!strncasecmp(PHP_OS, "win", 3) && file_exists(dirname($php) ."/php-cgi.exe")) {
+                       $php = $php_cgi . ' -C ';
+               } else if (!strncasecmp(PHP_OS, "win", 3) && file_exists(dirname($php) . "/php-cgi.exe")) {
                        $old_php = $php;
-                       $php = realpath(dirname($php) ."/php-cgi.exe") .' -C ';
+                       $php = realpath(dirname($php) . "/php-cgi.exe") . ' -C ';
                } else {
-                       if (file_exists(dirname($php)."/../../sapi/cgi/php-cgi")) {
+                       if (file_exists(dirname($php) . "/../../sapi/cgi/php-cgi")) {
                                $old_php = $php;
-                               $php = realpath(dirname($php)."/../../sapi/cgi/php-cgi") . ' -C ';
+                               $php = realpath(dirname($php) . "/../../sapi/cgi/php-cgi") . ' -C ';
                        } else if (file_exists("./sapi/cgi/php-cgi")) {
                                $old_php = $php;
                                $php = realpath("./sapi/cgi/php-cgi") . ' -C ';
                        } else {
-                               show_result("SKIP", $tested, $tested_file, "reason: CGI not available");
+                               show_result('SKIP', $tested, $tested_file, "reason: CGI not available");
                                return 'SKIPPED';
                        }
                }
@@ -1127,40 +1274,44 @@ TEST $file
        } else {
                $temp_dir = $test_dir = realpath(dirname($file));
        }
+
        if ($temp_source && $temp_target) {
                $temp_dir = str_replace($temp_source, $temp_target, $temp_dir);
        }
 
        $main_file_name = basename($file,'phpt');
 
-       $diff_filename     = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'diff';
-       $log_filename      = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'log';
-       $exp_filename      = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'exp';
-       $output_filename   = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'out';
-       $memcheck_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'mem';
-       $temp_file         = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'php';
-       $test_file         = $test_dir . DIRECTORY_SEPARATOR . $main_file_name.'php';
-       $temp_skipif       = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'skip.php';
-       $test_skipif       = $test_dir . DIRECTORY_SEPARATOR . $main_file_name.'skip.php';
-       $temp_clean        = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'clean.php';
-       $test_clean        = $test_dir . DIRECTORY_SEPARATOR . $main_file_name.'clean.php';
+       $diff_filename     = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'diff';
+       $log_filename      = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'log';
+       $exp_filename      = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'exp';
+       $output_filename   = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'out';
+       $memcheck_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'mem';
+       $temp_file         = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'php';
+       $test_file         = $test_dir . DIRECTORY_SEPARATOR . $main_file_name . 'php';
+       $temp_skipif       = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'skip.php';
+       $test_skipif       = $test_dir . DIRECTORY_SEPARATOR . $main_file_name . 'skip.php';
+       $temp_clean        = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'clean.php';
+       $test_clean        = $test_dir . DIRECTORY_SEPARATOR . $main_file_name . 'clean.php';
        $tmp_post          = $temp_dir . DIRECTORY_SEPARATOR . uniqid('/phpt.');
-       $tmp_relative_file = str_replace(dirname(__FILE__).DIRECTORY_SEPARATOR, '', $test_file) . 't';
+       $tmp_relative_file = str_replace(realpath(dirname(__FILE__)) . DIRECTORY_SEPARATOR, '', $test_file) . 't';
 
        if ($temp_source && $temp_target) {
                $temp_skipif  .= 's';
                $temp_file    .= 's';
                $temp_clean   .= 's';
-               $copy_file     = $temp_dir . DIRECTORY_SEPARATOR . basename(is_array($file) ? $file[1] : $file).'.phps';
+               $copy_file     = $temp_dir . DIRECTORY_SEPARATOR . basename(is_array($file) ? $file[1] : $file) . '.phps';
+
                if (!is_dir(dirname($copy_file))) {
-                       @mkdir(dirname($copy_file), 0777, true) or error("Cannot create output directory - " . dirname($copy_file));
+                       mkdir(dirname($copy_file), 0777, true) or error("Cannot create output directory - " . dirname($copy_file));
                }
+
                if (isset($section_text['FILE'])) {
                        save_text($copy_file, $section_text['FILE']);
                }
+
                $temp_filenames = array(
                        'file' => $copy_file,
-                       'diff' => $diff_filename, 
+                       'diff' => $diff_filename,
                        'log'  => $log_filename,
                        'exp'  => $exp_filename,
                        'out'  => $output_filename,
@@ -1176,7 +1327,7 @@ TEST $file
                $section_text['FILE'] = "# original source file: $shortname\n" . $section_text['FILE'];
        }
 
-       // unlink old test results      
+       // unlink old test results
        @unlink($diff_filename);
        @unlink($log_filename);
        @unlink($exp_filename);
@@ -1191,16 +1342,19 @@ TEST $file
        @unlink($test_clean);
 
        // Reset environment from any previous test.
-       $env['REDIRECT_STATUS']='';
-       $env['QUERY_STRING']='';
-       $env['PATH_TRANSLATED']='';
-       $env['SCRIPT_FILENAME']='';
-       $env['REQUEST_METHOD']='';
-       $env['CONTENT_TYPE']='';
-       $env['CONTENT_LENGTH']='';
+       $env['REDIRECT_STATUS'] = '';
+       $env['QUERY_STRING']    = '';
+       $env['PATH_TRANSLATED'] = '';
+       $env['SCRIPT_FILENAME'] = '';
+       $env['REQUEST_METHOD']  = '';
+       $env['CONTENT_TYPE']    = '';
+       $env['CONTENT_LENGTH']  = '';
+
        if (!empty($section_text['ENV'])) {
+
                foreach(explode("\n", trim($section_text['ENV'])) as $e) {
-                       $e = explode('=',trim($e),2);
+                       $e = explode('=', trim($e), 2);
+
                        if (!empty($e[0]) && isset($e[1])) {
                                $env[$e[0]] = $e[1];
                        }
@@ -1221,18 +1375,17 @@ TEST $file
                }
                settings2array(preg_split( "/[\n\r]+/", $section_text['INI']), $ini_settings);
        }
+
        settings2params($ini_settings);
 
        // Check if test should be skipped.
        $info = '';
        $warn = false;
+
        if (array_key_exists('SKIPIF', $section_text)) {
+
                if (trim($section_text['SKIPIF'])) {
-                       if ($cfg['show']['skip']) {
-                               echo "\n========SKIP========\n";
-                               echo $section_text['SKIPIF'];
-                               echo "========DONE========\n";
-                       }
+                       show_file_block('skip', $section_text['SKIPIF']);
                        save_text($test_skipif, $section_text['SKIPIF'], $temp_skipif);
                        $extra = substr(PHP_OS, 0, 3) !== "WIN" ?
                                "unset REQUEST_METHOD; unset QUERY_STRING; unset PATH_TRANSLATED; unset SCRIPT_FILENAME; unset REQUEST_METHOD;": "";
@@ -1242,29 +1395,38 @@ TEST $file
                        } else {
                                $env['USE_ZEND_ALLOC'] = '1';
                        }
+
                        $output = system_with_timeout("$extra $php $pass_options -q $ini_settings $test_skipif", $env);
+
                        if (!$cfg['keep']['skip']) {
                                @unlink($test_skipif);
                        }
+
                        if (!strncasecmp('skip', ltrim($output), 4)) {
+
                                if (preg_match('/^\s*skip\s*(.+)\s*/i', $output, $m)) {
-                                       show_result("SKIP", $tested, $tested_file, "reason: $m[1]", $temp_filenames);
+                                       show_result('SKIP', $tested, $tested_file, "reason: $m[1]", $temp_filenames);
                                } else {
-                                       show_result("SKIP", $tested, $tested_file, '', $temp_filenames);
+                                       show_result('SKIP', $tested, $tested_file, '', $temp_filenames);
                                }
+
                                if (isset($old_php)) {
                                        $php = $old_php;
                                }
+
                                if (!$cfg['keep']['skip']) {
                                        @unlink($test_skipif);
                                }
+
                                return 'SKIPPED';
                        }
+
                        if (!strncasecmp('info', ltrim($output), 4)) {
                                if (preg_match('/^\s*info\s*(.+)\s*/i', $output, $m)) {
                                        $info = " (info: $m[1])";
                                }
                        }
+
                        if (!strncasecmp('warn', ltrim($output), 4)) {
                                if (preg_match('/^\s*warn\s*(.+)\s*/i', $output, $m)) {
                                        $warn = true; /* only if there is a reason */
@@ -1282,17 +1444,19 @@ TEST $file
                $IN_REDIRECT['dir'] = realpath(dirname($file));
                $IN_REDIRECT['prefix'] = trim($section_text['TEST']);
 
-               if (@count($IN_REDIRECT['TESTS']) == 1) {
+               if (count($IN_REDIRECT['TESTS']) == 1) {
+
                        if (is_array($org_file)) {
                                $test_files[] = $org_file[1];
                        } else {
                                $GLOBALS['test_files'] = $test_files;
                                find_files($IN_REDIRECT['TESTS']);
+
                                foreach($GLOBALS['test_files'] as $f) {
                                        $test_files[] = array($f, $file);
                                }
                        }
-                       $test_cnt += count($test_files) - 1;
+                       $test_cnt += @count($test_files) - 1;
                        $test_idx--;
 
                        show_redirect_start($IN_REDIRECT['TESTS'], $tested, $tested_file);
@@ -1300,16 +1464,18 @@ TEST $file
                        // set up environment
                        $redirenv = array_merge($environment, $IN_REDIRECT['ENV']);
                        $redirenv['REDIR_TEST_DIR'] = realpath($IN_REDIRECT['TESTS']) . DIRECTORY_SEPARATOR;
-       
+
                        usort($test_files, "test_sort");
                        run_all_tests($test_files, $redirenv, $tested);
-       
+
                        show_redirect_ends($IN_REDIRECT['TESTS'], $tested, $tested_file);
-       
+
                        // a redirected test never fails
                        $IN_REDIRECT = false;
                        return 'REDIR';
+
                } else {
+
                        $bork_info = "Redirect info must contain exactly one TEST string to be used as redirect directory.";
                        show_result("BORK", $bork_info, '', $temp_filenames);
                        $PHP_FAILED_TESTS['BORKED'][] = array (
@@ -1318,12 +1484,16 @@ TEST $file
                                                                        'output' => '',
                                                                        'diff'   => '',
                                                                        'info'   => "$bork_info [$file]",
-                                                                       'unicode'=> $unicode_semantics,
                        );
                }
        }
+
        if (is_array($org_file) || @count($section_text['REDIRECTTEST']) == 1) {
-               if (is_array($org_file)) $file = $org_file[0];
+
+               if (is_array($org_file)) {
+                       $file = $org_file[0];
+               }
+
                $bork_info = "Redirected test did not contain redirection info";
                show_result("BORK", $bork_info, '', $temp_filenames);
                $PHP_FAILED_TESTS['BORKED'][] = array (
@@ -1333,18 +1503,13 @@ TEST $file
                                                                'diff'   => '',
                                                                'info'   => "$bork_info [$file]",
                );
-               //$test_cnt -= 1;  // Only if is_array($org_file) ?
-               //$test_idx--;
                return 'BORKED';
        }
-       
+
        // We've satisfied the preconditions - run the test!
-       if ($cfg['show']['php']) {
-               echo "\n========TEST========\n";
-               echo $section_text['FILE'];
-               echo "========DONE========\n";
-       }
+       show_file_block('php', $section_text['FILE'], 'TEST');
        save_text($test_file, $section_text['FILE'], $temp_file);
+
        if (array_key_exists('GET', $section_text)) {
                $query_string = trim($section_text['GET']);
        } else {
@@ -1362,20 +1527,27 @@ TEST $file
                $env['HTTP_COOKIE'] = '';
        }
 
-       $args = $section_text['ARGS'] ? ' -- '.$section_text['ARGS'] : '';
+       $args = isset($section_text['ARGS']) ? ' -- ' . $section_text['ARGS'] : '';
 
        if (array_key_exists('POST_RAW', $section_text) && !empty($section_text['POST_RAW'])) {
+
                $post = trim($section_text['POST_RAW']);
                $raw_lines = explode("\n", $post);
 
                $request = '';
                $started = false;
+
                foreach ($raw_lines as $line) {
+
                        if (empty($env['CONTENT_TYPE']) && preg_match('/^Content-Type:(.*)/i', $line, $res)) {
                                $env['CONTENT_TYPE'] = trim(str_replace("\r", '', $res[1]));
                                continue;
                        }
-                       if ($started) $request .= "\n";
+
+                       if ($started) {
+                               $request .= "\n";
+                       }
+
                        $started = true;
                        $request .= $line;
                }
@@ -1386,9 +1558,11 @@ TEST $file
                if (empty($request)) {
                        return 'BORKED';
                }
+
                save_text($tmp_post, $request);
                $cmd = "$php $pass_options $ini_settings -f \"$test_file\" 2>&1 < $tmp_post";
-       } elseif (array_key_exists('POST', $section_text) && !empty($section_text['POST'])) {
+
+       } else if (array_key_exists('POST', $section_text) && !empty($section_text['POST'])) {
 
                $post = trim($section_text['POST']);
 
@@ -1420,26 +1594,14 @@ TEST $file
 
        if ($leak_check) {
                $env['USE_ZEND_ALLOC'] = '0';
-               if (!$valgrind_version) {
-                       $valgrind_cmd = "valgrind --version";
-                       $out = system_with_timeout($valgrind_cmd);
-                       $replace_count = 0;
 
-                       if (!$out) {
-                               error("Valgrind returned no version info, cannot proceed.\nPlease check if Valgrind is installed.");
-                       } else {
-                               $valgrind_version = preg_replace("/valgrind-([0-9])\.([0-9])\.([0-9]+)(?:-\w+)?\s*/", '$1$2$3', $out, 1, $replace_count);
-                               if ($replace_count != 1 || !is_numeric($valgrind_version)) {
-                                       error("Valgrind returned invalid version info (\"$out\"), cannot proceed.");
-                               }
-                       }
-               }
-               if ($valgrind_version < 330) {
-                       $cmd = "valgrind -q --tool=memcheck --trace-children=yes --log-file-exactly=$memcheck_filename $cmd";
-               } else {
+               if ($valgrind_version >= 330) {
                        /* valgrind 3.3.0+ doesn't have --log-file-exactly option */
                        $cmd = "valgrind -q --tool=memcheck --trace-children=yes --log-file=$memcheck_filename $cmd";
+               } else {
+                       $cmd = "valgrind -q --tool=memcheck --trace-children=yes --log-file-exactly=$memcheck_filename $cmd";
                }
+
        } else {
                $env['USE_ZEND_ALLOC'] = '1';
        }
@@ -1459,21 +1621,20 @@ COMMAND $cmd
        $out = system_with_timeout($cmd, $env, isset($section_text['STDIN']) ? $section_text['STDIN'] : null);
 
        if (array_key_exists('CLEAN', $section_text) && (!$no_clean || $cfg['keep']['clean'])) {
+
                if (trim($section_text['CLEAN'])) {
-                       if ($cfg['show']['clean']) {
-                               echo "\n========CLEAN=======\n";
-                               echo $section_text['CLEAN'];
-                               echo "========DONE========\n";
-                       }
+                       show_file_block('clean', $section_text['CLEAN']);
                        save_text($test_clean, trim($section_text['CLEAN']), $temp_clean);
+
                        if (!$no_clean) {
                                $clean_params = array();
-                               settings2array($ini_overwrites,$clean_params);
+                               settings2array($ini_overwrites, $clean_params);
                                settings2params($clean_params);
                                $extra = substr(PHP_OS, 0, 3) !== "WIN" ?
                                        "unset REQUEST_METHOD; unset QUERY_STRING; unset PATH_TRANSLATED; unset SCRIPT_FILENAME; unset REQUEST_METHOD;": "";
                                system_with_timeout("$extra $php $pass_options -q $clean_params $test_clean", $env);
                        }
+
                        if (!$cfg['keep']['clean']) {
                                @unlink($test_clean);
                        }
@@ -1486,23 +1647,26 @@ COMMAND $cmd
        $passed = false;
 
        if ($leak_check) { // leak check
-               $leaked = @filesize($memcheck_filename) > 0;
+               $leaked = filesize($memcheck_filename) > 0;
+
                if (!$leaked) {
                        @unlink($memcheck_filename);
                }
        }
 
        // Does the output match what is expected?
-       $output = str_replace("\r\n", "\n", trim($out));
+       $output = preg_replace("/\r\n/", "\n", trim($out));
 
        /* when using CGI, strip the headers from the output */
        $headers = "";
+
        if (isset($old_php) && preg_match("/^(.*?)\r?\n\r?\n(.*)/s", $out, $match)) {
                $output = trim($match[2]);
-               $rh = preg_split("/[\n\r]+/",$match[1]);
+               $rh = preg_split("/[\n\r]+/", $match[1]);
                $headers = array();
+
                foreach ($rh as $line) {
-                       if (strpos($line, ':')!==false) {
+                       if (strpos($line, ':') !== false) {
                                $line = explode(':', $line, 2);
                                $headers[trim($line[0])] = trim($line[1]);
                        }
@@ -1510,10 +1674,12 @@ COMMAND $cmd
        }
 
        $failed_headers = false;
+
        if (isset($section_text['EXPECTHEADERS'])) {
                $want = array();
                $wanted_headers = array();
-               $lines = preg_split("/[\n\r]+/",$section_text['EXPECTHEADERS']);
+               $lines = preg_split("/[\n\r]+/", $section_text['EXPECTHEADERS']);
+
                foreach($lines as $line) {
                        if (strpos($line, ':') !== false) {
                                $line = explode(':', $line, 2);
@@ -1521,39 +1687,53 @@ COMMAND $cmd
                                $wanted_headers[] = trim($line[0]) . ': ' . trim($line[1]);
                        }
                }
+
                $org_headers = $headers;
                $headers = array();
                $output_headers = array();
+
                foreach($want as $k => $v) {
+
                        if (isset($org_headers[$k])) {
                                $headers = $org_headers[$k];
                                $output_headers[] = $k . ': ' . $org_headers[$k];
                        }
+
                        if (!isset($org_headers[$k]) || $org_headers[$k] != $v) {
                                $failed_headers = true;
                        }
                }
+
                ksort($wanted_headers);
                $wanted_headers = join("\n", $wanted_headers);
                ksort($output_headers);
                $output_headers = join("\n", $output_headers);
        }
 
+       show_file_block('out', $output);
+
        if (isset($section_text['EXPECTF']) || isset($section_text['EXPECTREGEX'])) {
+
                if (isset($section_text['EXPECTF'])) {
                        $wanted = trim($section_text['EXPECTF']);
                } else {
                        $wanted = trim($section_text['EXPECTREGEX']);
                }
-               $wanted_re = preg_replace('/\r\n/',"\n",$wanted);
+
+               show_file_block('exp', $wanted);
+               $wanted_re = preg_replace('/\r\n/', "\n", $wanted);
+
                if (isset($section_text['EXPECTF'])) {
                        $wanted_re = preg_quote($wanted_re, '/');
+                       $wanted_re = str_replace(
+                               array('%unicode\|string%', '%string\|unicode%'),
+                               version_compare(PHP_VERSION, '6.0.0-dev') == -1 ? 'string' : 'unicode',
+                               $wanted_re
+                       );
                        // Stick to basics
                        $wanted_re = str_replace('%e', '\\' . DIRECTORY_SEPARATOR, $wanted_re);
                        $wanted_re = str_replace('%s', '[^\r\n]+', $wanted_re);
-                       $wanted_re = str_replace('%S', '[^\r\n]*', $wanted_re);
                        $wanted_re = str_replace('%a', '.+', $wanted_re);
-                       $wanted_re = str_replace('%A', '.*', $wanted_re);
                        $wanted_re = str_replace('%w', '\s*', $wanted_re);
                        $wanted_re = str_replace('%i', '[+-]?\d+', $wanted_re);
                        $wanted_re = str_replace('%d', '\d+', $wanted_re);
@@ -1567,7 +1747,7 @@ COMMAND $cmd
                print(str_repeat('=', 80) . "\n");
                var_dump($output);
 */
-               if (preg_match("/^$wanted_re\$/s", $output)) {
+               if (preg_match((binary) "/^$wanted_re\$/s", $output)) {
                        $passed = true;
                        if (!$cfg['keep']['php']) {
                                @unlink($test_file);
@@ -1580,24 +1760,32 @@ COMMAND $cmd
                                return 'PASSED';
                        }
                }
+
        } else {
+
                $wanted = trim($section_text['EXPECT']);
-               $wanted = preg_replace('/\r\n/',"\n",$wanted);
+               $wanted = preg_replace('/\r\n/',"\n", $wanted);
+               show_file_block('exp', $wanted);
+
                // compare and leave on success
                if (!strcmp($output, $wanted)) {
                        $passed = true;
+
                        if (!$cfg['keep']['php']) {
                                @unlink($test_file);
                        }
+
                        if (isset($old_php)) {
                                $php = $old_php;
                        }
+
                        if (!$leaked && !$failed_headers) {
                                show_result("PASS", $tested, $tested_file, '', $temp_filenames);
                                return 'PASSED';
                        }
                }
-               $wanted_re = NULL;
+
+               $wanted_re = null;
        }
 
        // Test failed so we need to report details.
@@ -1605,6 +1793,7 @@ COMMAND $cmd
                $passed = false;
                $wanted = $wanted_headers . "\n--HEADERS--\n" . $wanted;
                $output = $output_headers . "\n--HEADERS--\n" . $output;
+
                if (isset($wanted_re)) {
                        $wanted_re = preg_quote($wanted_headers . "\n--HEADERS--\n", '/') . $wanted_re;
                }
@@ -1613,37 +1802,46 @@ COMMAND $cmd
        if ($leaked) {
                $restype[] = 'LEAK';
        }
+
        if ($warn) {
                $restype[] = 'WARN';
        }
+
        if (!$passed) {
-               $restype[] = 'FAIL';
+               if (isset($section_text['XFAIL'])) {
+                       $restype[] = 'XFAIL';
+               } else {
+                       $restype[] = 'FAIL';
+               }
        }
 
        if (!$passed) {
+
                // write .exp
-               if (strpos($log_format,'E') !== FALSE && file_put_contents($exp_filename, $wanted) === FALSE) {
+               if (strpos($log_format, 'E') !== false && file_put_contents($exp_filename, (binary) $wanted, FILE_BINARY) === false) {
                        error("Cannot create expected test output - $exp_filename");
                }
-       
+
                // write .out
-               if (strpos($log_format,'O') !== FALSE && file_put_contents($output_filename, $output) === FALSE) {
+               if (strpos($log_format, 'O') !== false && file_put_contents($output_filename, (binary) $output, FILE_BINARY) === false) {
                        error("Cannot create test output - $output_filename");
                }
-       
+
                // write .diff
-               if (strpos($log_format,'D') !== FALSE && file_put_contents($diff_filename, generate_diff($wanted,$wanted_re,$output)) === FALSE) {
+               $diff = generate_diff($wanted, $wanted_re, $output);
+               show_file_block('diff', $diff);
+               if (strpos($log_format, 'D') !== false && file_put_contents($diff_filename, (binary) $diff, FILE_BINARY) === false) {
                        error("Cannot create test diff - $diff_filename");
                }
-       
+
                // write .log
-               if (strpos($log_format,'L') !== FALSE && file_put_contents($log_filename, "
+               if (strpos($log_format, 'L') !== false && file_put_contents($log_filename, b"
 ---- EXPECTED OUTPUT
 $wanted
 ---- ACTUAL OUTPUT
 $output
 ---- FAILED
-") === FALSE) {
+", FILE_BINARY) === false) {
                        error("Cannot create test log - $log_filename");
                        error_report($file, $log_filename, $tested);
                }
@@ -1653,33 +1851,34 @@ $output
 
        foreach ($restype as $type) {
                $PHP_FAILED_TESTS[$type.'ED'][] = array (
-                                               'name' => $file,
-                                               'test_name' => (is_array($IN_REDIRECT) ? $IN_REDIRECT['via'] : '') . $tested . " [$tested_file]",
-                                               'output' => $output_filename,
-                                               'diff'   => $diff_filename,
-                                               'info'   => $info,
-                                               );
+                       'name'      => $file,
+                       'test_name' => (is_array($IN_REDIRECT) ? $IN_REDIRECT['via'] : '') . $tested . " [$tested_file]",
+                       'output'    => $output_filename,
+                       'diff'      => $diff_filename,
+                       'info'      => $info,
+               );
        }
 
        if (isset($old_php)) {
                $php = $old_php;
        }
 
-       return $restype[0].'ED';
+       return $restype[0] . 'ED';
 }
 
-function comp_line($l1,$l2,$is_reg)
+function comp_line($l1, $l2, $is_reg)
 {
        if ($is_reg) {
-               return preg_match('/^'.$l1.'$/s', $l2);
+               return preg_match((binary) "/^$l1$/s", (binary) $l2);
        } else {
-               return !strcmp($l1, $l2);
+               return !strcmp((binary) $l1, (binary) $l2);
        }
 }
 
-function count_array_diff($ar1,$ar2,$is_reg,$w,$idx1,$idx2,$cnt1,$cnt2,$steps)
+function count_array_diff($ar1, $ar2, $is_reg, $w, $idx1, $idx2, $cnt1, $cnt2, $steps)
 {
        $equal = 0;
+
        while ($idx1 < $cnt1 && $idx2 < $cnt2 && comp_line($ar1[$idx1], $ar2[$idx2], $is_reg)) {
                $idx1++;
                $idx2++;
@@ -1689,95 +1888,110 @@ function count_array_diff($ar1,$ar2,$is_reg,$w,$idx1,$idx2,$cnt1,$cnt2,$steps)
        if (--$steps > 0) {
                $eq1 = 0;
                $st = $steps / 2;
-               for ($ofs1 = $idx1+1; $ofs1 < $cnt1 && $st-- > 0; $ofs1++) {
-                       $eq = count_array_diff($ar1,$ar2,$is_reg,$w,$ofs1,$idx2,$cnt1,$cnt2,$st);
+
+               for ($ofs1 = $idx1 + 1; $ofs1 < $cnt1 && $st-- > 0; $ofs1++) {
+                       $eq = @count_array_diff($ar1, $ar2, $is_reg, $w, $ofs1, $idx2, $cnt1, $cnt2, $st);
+
                        if ($eq > $eq1) {
                                $eq1 = $eq;
                        }
                }
+
                $eq2 = 0;
                $st = $steps;
-               for ($ofs2 = $idx2+1; $ofs2 < $cnt2 && $st-- > 0; $ofs2++) {
-                       $eq = count_array_diff($ar1,$ar2,$is_reg,$w,$idx1,$ofs2,$cnt1,$cnt2,$st);
+
+               for ($ofs2 = $idx2 + 1; $ofs2 < $cnt2 && $st-- > 0; $ofs2++) {
+                       $eq = @count_array_diff($ar1, $ar2, $is_reg, $w, $idx1, $ofs2, $cnt1, $cnt2, $st);
                        if ($eq > $eq2) {
                                $eq2 = $eq;
                        }
                }
+
                if ($eq1 > $eq2) {
                        $equal += $eq1;
                } else if ($eq2 > 0) {
                        $equal += $eq2;
                }
        }
+
        return $equal;
 }
 
-function generate_array_diff($ar1,$ar2,$is_reg,$w)
+function generate_array_diff($ar1, $ar2, $is_reg, $w)
 {
-       $idx1 = 0; $ofs1 = 0; $cnt1 = count($ar1);
-       $idx2 = 0; $ofs2 = 0; $cnt2 = count($ar2);
+       $idx1 = 0; $ofs1 = 0; $cnt1 = @count($ar1);
+       $idx2 = 0; $ofs2 = 0; $cnt2 = @count($ar2);
        $diff = array();
        $old1 = array();
        $old2 = array();
-       
+
        while ($idx1 < $cnt1 && $idx2 < $cnt2) {
+
                if (comp_line($ar1[$idx1], $ar2[$idx2], $is_reg)) {
                        $idx1++;
                        $idx2++;
                        continue;
                } else {
-                       $c1 = count_array_diff($ar1,$ar2,$is_reg,$w,$idx1+1,$idx2,$cnt1,$cnt2,10);
-                       $c2 = count_array_diff($ar1,$ar2,$is_reg,$w,$idx1,$idx2+1,$cnt1,$cnt2,10);
+
+                       $c1 = @count_array_diff($ar1, $ar2, $is_reg, $w, $idx1+1, $idx2, $cnt1, $cnt2, 10);
+                       $c2 = @count_array_diff($ar1, $ar2, $is_reg, $w, $idx1, $idx2+1, $cnt1,  $cnt2, 10);
+
                        if ($c1 > $c2) {
-                               $old1[$idx1] = sprintf("%03d- ", $idx1+1).$w[$idx1++];
+                               $old1[$idx1] = (binary) sprintf("%03d- ", $idx1+1) . $w[$idx1++];
                                $last = 1;
                        } else if ($c2 > 0) {
-                               $old2[$idx2] = sprintf("%03d+ ", $idx2+1).$ar2[$idx2++];
+                               $old2[$idx2] = (binary) sprintf("%03d+ ", $idx2+1) . $ar2[$idx2++];
                                $last = 2;
                        } else {
-                               $old1[$idx1] = sprintf("%03d- ", $idx1+1).$w[$idx1++];
-                               $old2[$idx2] = sprintf("%03d+ ", $idx2+1).$ar2[$idx2++];
+                               $old1[$idx1] = (binary) sprintf("%03d- ", $idx1+1) . $w[$idx1++];
+                               $old2[$idx2] = (binary) sprintf("%03d+ ", $idx2+1) . $ar2[$idx2++];
                        }
                }
        }
-       
+
        reset($old1); $k1 = key($old1); $l1 = -2;
-       reset($old2); $k2 = key($old2); $l2 = -2;  
-       while ($k1 !== NULL || $k2 !== NULL) {
-               if ($k1 == $l1+1 || $k2 === NULL) {
+       reset($old2); $k2 = key($old2); $l2 = -2;
+
+       while ($k1 !== null || $k2 !== null) {
+
+               if ($k1 == $l1 + 1 || $k2 === null) {
                        $l1 = $k1;
                        $diff[] = current($old1);
-                       $k1 = next($old1) ? key($old1) : NULL;
-               } else if ($k2 == $l2+1 || $k1 === NULL) {
+                       $k1 = next($old1) ? key($old1) : null;
+               } else if ($k2 == $l2 + 1 || $k1 === null) {
                        $l2 = $k2;
                        $diff[] = current($old2);
-                       $k2 = next($old2) ? key($old2) : NULL;
+                       $k2 = next($old2) ? key($old2) : null;
                } else if ($k1 < $k2) {
                        $l1 = $k1;
                        $diff[] = current($old1);
-                       $k1 = next($old1) ? key($old1) : NULL;
+                       $k1 = next($old1) ? key($old1) : null;
                } else {
                        $l2 = $k2;
                        $diff[] = current($old2);
-                       $k2 = next($old2) ? key($old2) : NULL;
+                       $k2 = next($old2) ? key($old2) : null;
                }
        }
+
        while ($idx1 < $cnt1) {
-               $diff[] = sprintf("%03d- ", $idx1+1).$w[$idx1++];
+               $diff[] = (binary) sprintf("%03d- ", $idx1 + 1) . $w[$idx1++];
        }
+
        while ($idx2 < $cnt2) {
-               $diff[] = sprintf("%03d+ ", $idx2+1).$ar2[$idx2++];
+               $diff[] = (binary) sprintf("%03d+ ", $idx2 + 1) . $ar2[$idx2++];
        }
+
        return $diff;
 }
 
-function generate_diff($wanted,$wanted_re,$output)
+function generate_diff($wanted, $wanted_re, $output)
 {
-       $w = explode("\n", $wanted);
-       $o = explode("\n", $output);
-       $r = is_null($wanted_re) ? $w : explode("\n", $wanted_re);
-       $diff = generate_array_diff($r,$o,!is_null($wanted_re),$w);
-       return implode("\r\n", $diff);
+       $w = explode(b"\n", $wanted);
+       $o = explode(b"\n", $output);
+       $r = is_null($wanted_re) ? $w : explode(b"\n", $wanted_re);
+       $diff = generate_array_diff($r, $o, !is_null($wanted_re), $w);
+
+       return implode(b"\r\n", $diff);
 }
 
 function error($message)
@@ -1789,15 +2003,20 @@ function error($message)
 function settings2array($settings, &$ini_settings)
 {
        foreach($settings as $setting) {
-               if (strpos($setting, '=')!==false) {
+
+               if (strpos($setting, '=') !== false) {
                        $setting = explode("=", $setting, 2);
                        $name = trim(strtolower($setting[0]));
                        $value = trim($setting[1]);
+
                        if ($name == 'extension') {
+
                                if (!isset($ini_settings[$name])) {
                                        $ini_settings[$name] = array();
                                }
+
                                $ini_settings[$name][] = $value;
+
                        } else {
                                $ini_settings[$name] = $value;
                        }
@@ -1808,7 +2027,9 @@ function settings2array($settings, &$ini_settings)
 function settings2params(&$ini_settings)
 {
        $settings = '';
+
        foreach($ini_settings as $name => $value) {
+
                if (is_array($value)) {
                        foreach($value as $val) {
                                $val = addslashes($val);
@@ -1819,6 +2040,7 @@ function settings2params(&$ini_settings)
                        $settings .= " -d \"$name=$value\"";
                }
        }
+
        $ini_settings = $settings;
 }
 
@@ -1828,13 +2050,24 @@ function compute_summary()
 
        $n_total = count($test_results);
        $n_total += $ignored_by_ext;
-       $sum_results = array('PASSED'=>0, 'WARNED'=>0, 'SKIPPED'=>0, 'FAILED'=>0, 'BORKED'=>0, 'LEAKED'=>0);
+       $sum_results = array(
+               'PASSED'  => 0,
+               'WARNED'  => 0,
+               'SKIPPED' => 0,
+               'FAILED'  => 0,
+               'BORKED'  => 0,
+               'LEAKED'  => 0,
+               'XFAILED' => 0
+       );
+
        foreach ($test_results as $v) {
                $sum_results[$v]++;
        }
+
        $sum_results['SKIPPED'] += $ignored_by_ext;
        $percent_results = array();
-       while (list($v,$n) = each($sum_results)) {
+
+       while (list($v, $n) = each($sum_results)) {
                $percent_results[$v] = (100.0 * $n) / $n_total;
        }
 }
@@ -1844,89 +2077,117 @@ function get_summary($show_ext_summary, $show_html)
        global $exts_skipped, $exts_tested, $n_total, $sum_results, $percent_results, $end_time, $start_time, $failed_test_summary, $PHP_FAILED_TESTS, $leak_check;
 
        $x_total = $n_total - $sum_results['SKIPPED'] - $sum_results['BORKED'];
+
        if ($x_total) {
                $x_warned = (100.0 * $sum_results['WARNED']) / $x_total;
                $x_failed = (100.0 * $sum_results['FAILED']) / $x_total;
+               $x_xfailed = (100.0 * $sum_results['XFAILED']) / $x_total;
                $x_leaked = (100.0 * $sum_results['LEAKED']) / $x_total;
                $x_passed = (100.0 * $sum_results['PASSED']) / $x_total;
        } else {
-               $x_warned = $x_failed = $x_passed = $x_leaked = 0;
+               $x_warned = $x_failed = $x_passed = $x_leaked = $x_xfailed = 0;
        }
 
-       $summary = "";
-       if ($show_html) $summary .= "<pre>\n";
+       $summary = '';
+
+       if ($show_html) {
+               $summary .= "<pre>\n";
+       }
+       
        if ($show_ext_summary) {
-               $summary .= "
+               $summary .= '
 =====================================================================
 TEST RESULT SUMMARY
 ---------------------------------------------------------------------
-Exts skipped    : " . sprintf("%4d",$exts_skipped) . "
-Exts tested     : " . sprintf("%4d",$exts_tested) . "
+Exts skipped    : ' . sprintf('%4d', $exts_skipped) . '
+Exts tested     : ' . sprintf('%4d', $exts_tested) . '
 ---------------------------------------------------------------------
-";
+';
        }
-       $summary .= "
-Number of tests : " . sprintf("%4d",$n_total). "          " . sprintf("%8d",$x_total);
+
+       $summary .= '
+Number of tests : ' . sprintf('%4d', $n_total) . '          ' . sprintf('%8d', $x_total);
+
        if ($sum_results['BORKED']) {
-       $summary .= "
-Tests borked    : " . sprintf("%4d (%5.1f%%)",$sum_results['BORKED'],$percent_results['BORKED']) . " --------";
+               $summary .= '
+Tests borked    : ' . sprintf('%4d (%5.1f%%)', $sum_results['BORKED'], $percent_results['BORKED']) . ' --------';
        }
-       $summary .= "
-Tests skipped   : " . sprintf("%4d (%5.1f%%)",$sum_results['SKIPPED'],$percent_results['SKIPPED']) . " --------
-Tests warned    : " . sprintf("%4d (%5.1f%%)",$sum_results['WARNED'], $percent_results['WARNED']) . " " . sprintf("(%5.1f%%)",$x_warned) . "
-Tests failed    : " . sprintf("%4d (%5.1f%%)",$sum_results['FAILED'], $percent_results['FAILED']) . " " . sprintf("(%5.1f%%)",$x_failed);
+
+       $summary .= '
+Tests skipped   : ' . sprintf('%4d (%5.1f%%)', $sum_results['SKIPPED'], $percent_results['SKIPPED']) . ' --------
+Tests warned    : ' . sprintf('%4d (%5.1f%%)', $sum_results['WARNED'], $percent_results['WARNED']) . ' ' . sprintf('(%5.1f%%)', $x_warned) . '
+Tests failed    : ' . sprintf('%4d (%5.1f%%)', $sum_results['FAILED'], $percent_results['FAILED']) . ' ' . sprintf('(%5.1f%%)', $x_failed) . '
+Expected fail   : ' . sprintf('%4d (%5.1f%%)', $sum_results['XFAILED'], $percent_results['XFAILED']) . ' ' . sprintf('(%5.1f%%)', $x_xfailed);
+
        if ($leak_check) {
-               $summary .= "
-Tests leaked    : " . sprintf("%4d (%5.1f%%)",$sum_results['LEAKED'], $percent_results['LEAKED']) . " " . sprintf("(%5.1f%%)",$x_leaked);
+               $summary .= '
+Tests leaked    : ' . sprintf('%4d (%5.1f%%)', $sum_results['LEAKED'], $percent_results['LEAKED']) . ' ' . sprintf('(%5.1f%%)', $x_leaked);
        }
-       $summary .= "
-Tests passed    : " . sprintf("%4d (%5.1f%%)",$sum_results['PASSED'], $percent_results['PASSED']) . " " . sprintf("(%5.1f%%)",$x_passed) . "
+
+       $summary .= '
+Tests passed    : ' . sprintf('%4d (%5.1f%%)', $sum_results['PASSED'], $percent_results['PASSED']) . ' ' . sprintf('(%5.1f%%)', $x_passed) . '
 ---------------------------------------------------------------------
-Time taken      : " . sprintf("%4d seconds", $end_time - $start_time) . "
+Time taken      : ' . sprintf('%4d seconds', $end_time - $start_time) . '
 =====================================================================
-";
+';
        $failed_test_summary = '';
+
        if (count($PHP_FAILED_TESTS['BORKED'])) {
-               $failed_test_summary .= "
+               $failed_test_summary .= '
 =====================================================================
 BORKED TEST SUMMARY
 ---------------------------------------------------------------------
-";
+';
                foreach ($PHP_FAILED_TESTS['BORKED'] as $failed_test_data) {
                        $failed_test_summary .= $failed_test_data['info'] . "\n";
                }
+
                $failed_test_summary .=  "=====================================================================\n";
        }
-       
+
        if (count($PHP_FAILED_TESTS['FAILED'])) {
-               $failed_test_summary .= "
+               $failed_test_summary .= '
 =====================================================================
 FAILED TEST SUMMARY
 ---------------------------------------------------------------------
-";
+';
                foreach ($PHP_FAILED_TESTS['FAILED'] as $failed_test_data) {
                        $failed_test_summary .= $failed_test_data['test_name'] . $failed_test_data['info'] . "\n";
                }
                $failed_test_summary .=  "=====================================================================\n";
        }
-       
+       if (count($PHP_FAILED_TESTS['XFAILED'])) {
+               $failed_test_summary .= '
+=====================================================================
+EXPECTED FAILED TEST SUMMARY
+---------------------------------------------------------------------
+';
+               foreach ($PHP_FAILED_TESTS['XFAILED'] as $failed_test_data) {
+                       $failed_test_summary .= $failed_test_data['test_name'] . $failed_test_data['info'] . "\n";
+               }
+               $failed_test_summary .=  "=====================================================================\n";
+       }
+
        if (count($PHP_FAILED_TESTS['LEAKED'])) {
-               $failed_test_summary .= "
+               $failed_test_summary .= '
 =====================================================================
 LEAKED TEST SUMMARY
 ---------------------------------------------------------------------
-";
+';
                foreach ($PHP_FAILED_TESTS['LEAKED'] as $failed_test_data) {
                        $failed_test_summary .= $failed_test_data['test_name'] . $failed_test_data['info'] . "\n";
                }
+
                $failed_test_summary .=  "=====================================================================\n";
        }
-       
+
        if ($failed_test_summary && !getenv('NO_PHPTEST_SUMMARY')) {
                $summary .= $failed_test_summary;
        }
 
-       if ($show_html) $summary .= "</pre>";
+       if ($show_html) {
+               $summary .= "</pre>";
+       }
 
        return $summary;
 }
@@ -1935,34 +2196,34 @@ function show_start($start_time)
 {
        global $html_output, $html_file;
 
-       if ($html_output)
-       {
-               fwrite($html_file, "<h2>Time Start: " . @date('Y-m-d H:i:s', $start_time) . "</h2>\n");
+       if ($html_output) {
+               fwrite($html_file, "<h2>Time Start: " . date('Y-m-d H:i:s', $start_time) . "</h2>\n");
                fwrite($html_file, "<table>\n");
        }
-       echo "TIME START " . @date('Y-m-d H:i:s', $start_time) . "\n=====================================================================\n";
+
+       echo "TIME START " . date('Y-m-d H:i:s', $start_time) . "\n=====================================================================\n";
 }
 
 function show_end($end_time)
 {
        global $html_output, $html_file;
 
-       if ($html_output)
-       {
+       if ($html_output) {
                fwrite($html_file, "</table>\n");
-               fwrite($html_file, "<h2>Time End: " . @date('Y-m-d H:i:s', $end_time) . "</h2>\n");
+               fwrite($html_file, "<h2>Time End: " . date('Y-m-d H:i:s', $end_time) . "</h2>\n");
        }
-       echo "=====================================================================\nTIME END " . @date('Y-m-d H:i:s', $end_time) . "\n";
+
+       echo "=====================================================================\nTIME END " . date('Y-m-d H:i:s', $end_time) . "\n";
 }
 
 function show_summary()
 {
        global $html_output, $html_file;
 
-       if ($html_output)
-       {
+       if ($html_output) {
                fwrite($html_file, "<hr/>\n" . get_summary(true, true));
        }
+
        echo get_summary(true, false);
 }
 
@@ -1970,10 +2231,10 @@ function show_redirect_start($tests, $tested, $tested_file)
 {
        global $html_output, $html_file;
 
-       if ($html_output)
-       {
+       if ($html_output) {
                fwrite($html_file, "<tr><td colspan='3'>---&gt; $tests ($tested [$tested_file]) begin</td></tr>\n");
        }
+
        echo "---> $tests ($tested [$tested_file]) begin\n";
 }
 
@@ -1981,10 +2242,10 @@ function show_redirect_ends($tests, $tested, $tested_file)
 {
        global $html_output, $html_file;
 
-       if ($html_output)
-       {
+       if ($html_output) {
                fwrite($html_file, "<tr><td colspan='3'>---&gt; $tests ($tested [$tested_file]) done</td></tr>\n");
        }
+
        echo "---> $tests ($tested [$tested_file]) done\n";
 }
 
@@ -2002,33 +2263,40 @@ function show_result($result, $tested, $tested_file, $extra = '', $temp_filename
 
        echo "$result $tested [$tested_file] $extra\n";
 
-       if ($html_output)
-       {
-               if (isset($temp_filenames['file']) && @file_exists($temp_filenames['file'])) {
+       if ($html_output) {
+
+               if (isset($temp_filenames['file']) && file_exists($temp_filenames['file'])) {
                        $url = str_replace($temp_target, $temp_urlbase, $temp_filenames['file']);
                        $tested = "<a href='$url'>$tested</a>";
                }
-               if (isset($temp_filenames['skip']) && @file_exists($temp_filenames['skip'])) {
+
+               if (isset($temp_filenames['skip']) && file_exists($temp_filenames['skip'])) {
+
                        if (empty($extra)) {
                                $extra = "skipif";
                        }
+
                        $url = str_replace($temp_target, $temp_urlbase, $temp_filenames['skip']);
                        $extra = "<a href='$url'>$extra</a>";
+
                } else if (empty($extra)) {
                        $extra = "&nbsp;";
                }
-               if (isset($temp_filenames['diff']) && @file_exists($temp_filenames['diff'])) {
+
+               if (isset($temp_filenames['diff']) && file_exists($temp_filenames['diff'])) {
                        $url = str_replace($temp_target, $temp_urlbase, $temp_filenames['diff']);
                        $diff = "<a href='$url'>diff</a>";
                } else {
                        $diff = "&nbsp;";
                }
-               if (isset($temp_filenames['mem']) && @file_exists($temp_filenames['mem'])) {
+
+               if (isset($temp_filenames['mem']) && file_exists($temp_filenames['mem'])) {
                        $url = str_replace($temp_target, $temp_urlbase, $temp_filenames['mem']);
                        $mem = "<a href='$url'>leaks</a>";
                } else {
                        $mem = "&nbsp;";
                }
+
                fwrite($html_file, 
                        "<tr>" .
                        "<td>$result</td>" .