Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Framework/Helpers.php
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ public static function errorTypeToString($type)
*/
public static function escapeArg($s)
{
if (preg_match('#^[a-z0-9._-]+\z#i', $s)) {
if (preg_match('#^[a-z0-9._=/:-]+\z#i', $s)) {
return $s;
}

Expand Down
44 changes: 8 additions & 36 deletions src/Runner/CliTester.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@

use Tester\CodeCoverage;
use Tester\Environment;
use Tester\Helpers;
use Tester\Dumper;


Expand Down Expand Up @@ -142,52 +141,25 @@ private function loadOptions()
/** @return void */
private function createPhpInterpreter()
{
$args = '';
$args = [];
if ($this->options['-c']) {
$args .= ' -c ' . Helpers::escapeArg($this->options['-c']);
array_push($args, '-c', $this->options['-c']);
} elseif (!$this->options['--info']) {
echo "Note: No php.ini is used.\n";
}

if (in_array($this->options['-o'], ['tap', 'junit'])) {
$args .= ' -d html_errors=off';
array_push($args, '-d', 'html_errors=off');
}

foreach ($this->options['-d'] as $item) {
$args .= ' -d ' . Helpers::escapeArg($item);
array_push($args, '-d', $item);
}

// Is the executable Zend PHP or HHVM?
$proc = @proc_open( // @ is escalated to exception
$this->options['-p'] . ' --version',
[['pipe', 'r'], ['pipe', 'w'], ['pipe', 'w']],
$pipes,
NULL,
NULL,
['bypass_shell' => TRUE]
);
if ($proc === FALSE) {
throw new \Exception('Cannot run PHP interpreter ' . $this->options['-p'] . '. Use -p option.');
}
$output = stream_get_contents($pipes[1]);
$error = stream_get_contents($pipes[2]);
if (proc_close($proc)) {
throw new \Exception("Unable to run '{$this->options['-p']}': " . preg_replace('#[\r\n ]+#', ' ', $error));
}

if (preg_match('#HipHop VM#', $output)) {
$this->interpreter = new HhvmPhpInterpreter($this->options['-p'], $args);
} elseif (strpos($output, 'phpdbg') !== FALSE) {
$this->interpreter = new ZendPhpDbgInterpreter($this->options['-p'], $args);
} else {
$this->interpreter = new ZendPhpInterpreter($this->options['-p'], $args);
}
$this->interpreter = new PhpInterpreter($this->options['-p'], $args);

if ($this->interpreter->getErrorOutput()) {
echo Dumper::color('red', 'PHP startup error: ' . $this->interpreter->getErrorOutput()) . "\n";
if ($this->interpreter->isCgi()) {
echo "(note that PHP CLI generates better error messages)\n";
}
if ($error = $this->interpreter->getStartupError()) {
echo Dumper::color('red', "PHP startup error: $error") . "\n";
}
}

Expand Down Expand Up @@ -230,7 +202,7 @@ private function createRunner()
/** @return string */
private function prepareCodeCoverage()
{
if (!$this->interpreter->hasXdebug()) {
if (!$this->interpreter->canMeasureCodeCoverage()) {
$alternative = PHP_VERSION_ID >= 70000 ? ' or phpdbg SAPI' : '';
throw new \Exception("Code coverage functionality requires Xdebug extension$alternative (used {$this->interpreter->getCommandLine()})");
}
Expand Down
106 changes: 0 additions & 106 deletions src/Runner/HhvmPhpInterpreter.php

This file was deleted.

3 changes: 2 additions & 1 deletion src/Runner/Job.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
namespace Tester\Runner;

use Tester\Environment;
use Tester\Helpers;


/**
Expand Down Expand Up @@ -83,7 +84,7 @@ public function run($flags = NULL)
putenv(Environment::COLORS . '=' . (int) Environment::$useColors);
$this->proc = proc_open(
$this->interpreter->getCommandLine()
. ' -n -d register_argc_argv=on ' . \Tester\Helpers::escapeArg($this->file) . ' ' . implode(' ', $this->args),
. ' -d register_argc_argv=on ' . Helpers::escapeArg($this->file) . ' ' . implode(' ', $this->args),
[
['pipe', 'r'],
['pipe', 'w'],
Expand Down
2 changes: 1 addition & 1 deletion src/Runner/Output/ConsolePrinter.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public function __construct(Runner $runner, $displaySkipped = FALSE)
public function begin()
{
$this->time = -microtime(TRUE);
echo 'PHP ' . $this->runner->getInterpreter()->getVersion()
echo $this->runner->getInterpreter()->getShortInfo()
. ' | ' . $this->runner->getInterpreter()->getCommandLine()
. " | {$this->runner->threadCount} thread" . ($this->runner->threadCount > 1 ? 's' : '') . "\n\n";
}
Expand Down
135 changes: 129 additions & 6 deletions src/Runner/PhpInterpreter.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,33 +7,156 @@

namespace Tester\Runner;

use Tester\Helpers;

interface PhpInterpreter

/**
* PHP command-line executable.
*/
class PhpInterpreter
{
/** @var string */
private $commandLine;

/** @var bool is CGI? */
private $cgi;

/** @var \stdClass created by info.php */
private $info;

/** @var string */
private $error;


public function __construct($path, array $args = [])
{
$this->commandLine = Helpers::escapeArg($path);
$proc = @proc_open( // @ is escalated to exception
$this->commandLine . ' --version',
[['pipe', 'r'], ['pipe', 'w'], ['pipe', 'w']],
$pipes,
NULL,
NULL,
['bypass_shell' => TRUE]
);
if ($proc === FALSE) {
throw new \Exception("Cannot run PHP interpreter $path. Use -p option.");
}
$output = stream_get_contents($pipes[1]);
proc_close($proc);

$args = ' -n ' . implode(' ', array_map(['Tester\Helpers', 'escapeArg'], $args));
if (preg_match('#HipHop VM#', $output)) {
$args = ' --php' . $args . ' -d hhvm.log.always_log_unhandled_exceptions=false'; // HHVM issue #3019
} elseif (strpos($output, 'phpdbg') !== FALSE) {
$args = ' -qrrb -S cli' . $args;
}
$this->commandLine .= $args;

$proc = proc_open(
$this->commandLine . ' ' . Helpers::escapeArg(__DIR__ . '/info.php') . ' serialized',
[['pipe', 'r'], ['pipe', 'w'], ['pipe', 'w']],
$pipes,
NULL,
NULL,
['bypass_shell' => TRUE]
);
$output = stream_get_contents($pipes[1]);
$this->error = trim(stream_get_contents($pipes[2]));
if (proc_close($proc)) {
throw new \Exception("Unable to run $path: " . preg_replace('#[\r\n ]+#', ' ', $this->error));
}

$parts = explode("\r\n\r\n", $output, 2);
$this->cgi = count($parts) === 2;
if (!($this->info = @unserialize($parts[$this->cgi]))) {
throw new \Exception("Unable to detect PHP version (output: $output).");

} elseif ($this->info->hhvmVersion && version_compare($this->info->hhvmVersion, '3.3.0', '<')) {
throw new \Exception('HHVM below version 3.3.0 is not supported.');

} elseif ($this->info->phpDbgVersion && version_compare($this->info->version, '7.0.0', '<')) {
throw new \Exception('Unable to use phpdbg on PHP < 7.0.0.');

} elseif ($this->cgi && $this->error) {
$this->error .= "\n(note that PHP CLI generates better error messages)";
}
}


/**
* @param string
* @param string
*/
public function addPhpIniOption($name, $value = NULL)
{
$this->commandLine .= ' -d ' . Helpers::escapeArg($name . ($value === NULL ? '' : "=$value"));
}


/**
* @return string
*/
function getCommandLine();
public function getCommandLine()
{
return $this->commandLine;
}


/**
* @return string
*/
function getVersion();
public function getVersion()
{
return $this->info->version;
}


/**
* @return bool
*/
function hasXdebug();
public function canMeasureCodeCoverage()
{
return $this->info->canMeasureCodeCoverage;
}


/**
* @return bool
*/
function isCgi();
public function isCgi()
{
return $this->cgi;
}


/**
* @return string
*/
public function getStartupError()
{
return $this->error;
}


/**
* @return string
*/
function getErrorOutput();
public function getShortInfo()
{
return "PHP {$this->info->version} ({$this->info->sapi})"
. ($this->info->phpDbgVersion ? "; PHPDBG {$this->info->phpDbgVersion}" : '')
. ($this->info->hhvmVersion ? "; HHVM {$this->info->hhvmVersion}" : '');
}


/**
* @param string
* @return bool
*/
public function hasExtension($name)
{
return in_array(strtolower($name), array_map('strtolower', $this->info->extensions), TRUE);
}

}
3 changes: 2 additions & 1 deletion src/Runner/TestHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,8 @@ private function initiatePhpVersion($version, PhpInterpreter $interpreter)

private function initiatePhpIni($value, PhpInterpreter $interpreter)
{
$interpreter->arguments .= ' -d ' . Helpers::escapeArg($value);
list($name, $value) = explode('=', $value, 2) + [1 => NULL];
$interpreter->addPhpIniOption($name, $value);
}


Expand Down
Loading