mirror of
https://github.com/php/php-src.git
synced 2025-08-16 05:58:45 +02:00
Implement GH-10024: support linting multiple files at once using php -l
This is supported in both the CLI and CGI modes. For CLI this required little changes. For CGI, the tricky part was that the options parsing happens inside the loop. This means that options passed after the -l flag were previously simply ignored. As we now re-enter the loop we would parse the options again, and if they are handled but don't set the script name, then CGI will think you want to read from standard in. To keep the same "don't parse options" behaviour I simply wrapped the options handling inside an if. Closes GH-10024. Closes GH-10710.
This commit is contained in:
parent
dde1d9e102
commit
f16b34f1d0
6 changed files with 249 additions and 2 deletions
3
NEWS
3
NEWS
|
@ -2,6 +2,9 @@ PHP NEWS
|
||||||
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||
?? ??? ????, PHP 8.3.0alpha4
|
?? ??? ????, PHP 8.3.0alpha4
|
||||||
|
|
||||||
|
- CLI:
|
||||||
|
. Implement GH-10024 (support linting multiple files at once using php -l).
|
||||||
|
(nielsdos)
|
||||||
|
|
||||||
06 Jul 2023, PHP 8.3.0alpha3
|
06 Jul 2023, PHP 8.3.0alpha3
|
||||||
|
|
||||||
|
|
|
@ -87,6 +87,9 @@ PHP 8.3 UPGRADE NOTES
|
||||||
in a parent class or implemented interface.
|
in a parent class or implemented interface.
|
||||||
RFC: https://wiki.php.net/rfc/marking_overriden_methods
|
RFC: https://wiki.php.net/rfc/marking_overriden_methods
|
||||||
|
|
||||||
|
- CLI
|
||||||
|
. It is now possible to lint multiple files.
|
||||||
|
|
||||||
- Posix
|
- Posix
|
||||||
. posix_getrlimit() now takes an optional $res parameter to allow fetching a
|
. posix_getrlimit() now takes an optional $res parameter to allow fetching a
|
||||||
single resource limit.
|
single resource limit.
|
||||||
|
|
|
@ -2372,6 +2372,7 @@ parent_loop_end:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
do_repeat:
|
||||||
if (script_file) {
|
if (script_file) {
|
||||||
/* override path_translated if -f on command line */
|
/* override path_translated if -f on command line */
|
||||||
if (SG(request_info).path_translated) efree(SG(request_info).path_translated);
|
if (SG(request_info).path_translated) efree(SG(request_info).path_translated);
|
||||||
|
@ -2512,7 +2513,6 @@ parent_loop_end:
|
||||||
PG(during_request_startup) = 0;
|
PG(during_request_startup) = 0;
|
||||||
if (php_lint_script(&file_handle) == SUCCESS) {
|
if (php_lint_script(&file_handle) == SUCCESS) {
|
||||||
zend_printf("No syntax errors detected in %s\n", ZSTR_VAL(file_handle.filename));
|
zend_printf("No syntax errors detected in %s\n", ZSTR_VAL(file_handle.filename));
|
||||||
exit_status = 0;
|
|
||||||
} else {
|
} else {
|
||||||
zend_printf("Errors parsing %s\n", ZSTR_VAL(file_handle.filename));
|
zend_printf("Errors parsing %s\n", ZSTR_VAL(file_handle.filename));
|
||||||
exit_status = -1;
|
exit_status = -1;
|
||||||
|
@ -2581,6 +2581,11 @@ fastcgi_request_done:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (behavior == PHP_MODE_LINT && argc - 1 > php_optind) {
|
||||||
|
php_optind++;
|
||||||
|
script_file = NULL;
|
||||||
|
goto do_repeat;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
117
sapi/cgi/tests/012.phpt
Normal file
117
sapi/cgi/tests/012.phpt
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
--TEST--
|
||||||
|
multiple files syntax check
|
||||||
|
--SKIPIF--
|
||||||
|
<?php include "skipif.inc"; ?>
|
||||||
|
--INI--
|
||||||
|
display_errors=stdout
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
include "include.inc";
|
||||||
|
|
||||||
|
function run_and_output($cmd) {
|
||||||
|
if (!defined("PHP_WINDOWS_VERSION_MAJOR")) {
|
||||||
|
$cmd .= " 2>/dev/null";
|
||||||
|
}
|
||||||
|
exec($cmd, $output, $exit_code);
|
||||||
|
print_r($output);
|
||||||
|
// Normalize Windows vs Linux exit codes. On Windows exit code -1 is actually -1 instead of 255.
|
||||||
|
if ($exit_code < 0) {
|
||||||
|
$exit_code += 256;
|
||||||
|
}
|
||||||
|
var_dump($exit_code);
|
||||||
|
}
|
||||||
|
|
||||||
|
$php = get_cgi_path();
|
||||||
|
reset_env_vars();
|
||||||
|
|
||||||
|
$filename_good = __DIR__."/012_good.test.php";
|
||||||
|
$filename_good_escaped = escapeshellarg($filename_good);
|
||||||
|
$filename_bad = __DIR__."/012_bad.test.php";
|
||||||
|
$filename_bad_escaped = escapeshellarg($filename_bad);
|
||||||
|
|
||||||
|
$code = '
|
||||||
|
<?php
|
||||||
|
|
||||||
|
echo "hi";
|
||||||
|
';
|
||||||
|
|
||||||
|
file_put_contents($filename_good, $code);
|
||||||
|
|
||||||
|
$code = '
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class test
|
||||||
|
private $var;
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
';
|
||||||
|
|
||||||
|
file_put_contents($filename_bad, $code);
|
||||||
|
|
||||||
|
run_and_output("$php -n -l $filename_good_escaped $filename_good_escaped");
|
||||||
|
run_and_output("$php -n -l $filename_good_escaped some.unknown $filename_good_escaped");
|
||||||
|
run_and_output("$php -n -l $filename_good_escaped $filename_bad_escaped $filename_good_escaped");
|
||||||
|
run_and_output("$php -n -l $filename_bad_escaped $filename_bad_escaped");
|
||||||
|
run_and_output("$php -n -l $filename_bad_escaped some.unknown $filename_bad_escaped");
|
||||||
|
run_and_output("$php -n -l $filename_bad_escaped $filename_bad_escaped some.unknown");
|
||||||
|
|
||||||
|
echo "Done\n";
|
||||||
|
?>
|
||||||
|
--CLEAN--
|
||||||
|
<?php
|
||||||
|
@unlink($filename_good);
|
||||||
|
@unlink($filename_bad);
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
Array
|
||||||
|
(
|
||||||
|
[0] => No syntax errors detected in %s012_good.test.php
|
||||||
|
[1] => No syntax errors detected in %s012_good.test.php
|
||||||
|
)
|
||||||
|
int(0)
|
||||||
|
Array
|
||||||
|
(
|
||||||
|
[0] => No syntax errors detected in %s012_good.test.php
|
||||||
|
[1] => No input file specified.
|
||||||
|
)
|
||||||
|
int(255)
|
||||||
|
Array
|
||||||
|
(
|
||||||
|
[0] => No syntax errors detected in %s012_good.test.php
|
||||||
|
[1] => <br />
|
||||||
|
[2] => <b>Parse error</b>: syntax error, unexpected token "private", expecting "{" in <b>%s012_bad.test.php</b> on line <b>5</b><br />
|
||||||
|
[3] => Errors parsing %s012_bad.test.php
|
||||||
|
[4] => No syntax errors detected in %s012_good.test.php
|
||||||
|
)
|
||||||
|
int(255)
|
||||||
|
Array
|
||||||
|
(
|
||||||
|
[0] => <br />
|
||||||
|
[1] => <b>Parse error</b>: syntax error, unexpected token "private", expecting "{" in <b>%s012_bad.test.php</b> on line <b>5</b><br />
|
||||||
|
[2] => Errors parsing %s012_bad.test.php
|
||||||
|
[3] => <br />
|
||||||
|
[4] => <b>Parse error</b>: syntax error, unexpected token "private", expecting "{" in <b>%s012_bad.test.php</b> on line <b>5</b><br />
|
||||||
|
[5] => Errors parsing %s012_bad.test.php
|
||||||
|
)
|
||||||
|
int(255)
|
||||||
|
Array
|
||||||
|
(
|
||||||
|
[0] => <br />
|
||||||
|
[1] => <b>Parse error</b>: syntax error, unexpected token "private", expecting "{" in <b>%s012_bad.test.php</b> on line <b>5</b><br />
|
||||||
|
[2] => Errors parsing %s012_bad.test.php
|
||||||
|
[3] => No input file specified.
|
||||||
|
)
|
||||||
|
int(255)
|
||||||
|
Array
|
||||||
|
(
|
||||||
|
[0] => <br />
|
||||||
|
[1] => <b>Parse error</b>: syntax error, unexpected token "private", expecting "{" in <b>%s012_bad.test.php</b> on line <b>5</b><br />
|
||||||
|
[2] => Errors parsing %s012_bad.test.php
|
||||||
|
[3] => <br />
|
||||||
|
[4] => <b>Parse error</b>: syntax error, unexpected token "private", expecting "{" in <b>%s012_bad.test.php</b> on line <b>5</b><br />
|
||||||
|
[5] => Errors parsing %s012_bad.test.php
|
||||||
|
[6] => No input file specified.
|
||||||
|
)
|
||||||
|
int(255)
|
||||||
|
Done
|
|
@ -734,6 +734,10 @@ static int do_cli(int argc, char **argv) /* {{{ */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
behavior=PHP_MODE_LINT;
|
behavior=PHP_MODE_LINT;
|
||||||
|
/* We want to set the error exit status if at least one lint failed.
|
||||||
|
* If all were successful we set the exit status to 0.
|
||||||
|
* We already set EG(exit_status) here such that only failures set the exit status. */
|
||||||
|
EG(exit_status) = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'q': /* do not generate HTTP headers */
|
case 'q': /* do not generate HTTP headers */
|
||||||
|
@ -962,7 +966,6 @@ do_repeat:
|
||||||
case PHP_MODE_LINT:
|
case PHP_MODE_LINT:
|
||||||
if (php_lint_script(&file_handle) == SUCCESS) {
|
if (php_lint_script(&file_handle) == SUCCESS) {
|
||||||
zend_printf("No syntax errors detected in %s\n", php_self);
|
zend_printf("No syntax errors detected in %s\n", php_self);
|
||||||
EG(exit_status) = 0;
|
|
||||||
} else {
|
} else {
|
||||||
zend_printf("Errors parsing %s\n", php_self);
|
zend_printf("Errors parsing %s\n", php_self);
|
||||||
EG(exit_status) = 255;
|
EG(exit_status) = 255;
|
||||||
|
@ -1128,9 +1131,15 @@ out:
|
||||||
}
|
}
|
||||||
if (request_started) {
|
if (request_started) {
|
||||||
php_request_shutdown((void *) 0);
|
php_request_shutdown((void *) 0);
|
||||||
|
request_started = 0;
|
||||||
}
|
}
|
||||||
if (translated_path) {
|
if (translated_path) {
|
||||||
free(translated_path);
|
free(translated_path);
|
||||||
|
translated_path = NULL;
|
||||||
|
}
|
||||||
|
if (behavior == PHP_MODE_LINT && argc > php_optind && strcmp(argv[php_optind],"--")) {
|
||||||
|
script_file = NULL;
|
||||||
|
goto do_repeat;
|
||||||
}
|
}
|
||||||
/* Don't repeat fork()ed processes. */
|
/* Don't repeat fork()ed processes. */
|
||||||
if (--num_repeats && pid == getpid()) {
|
if (--num_repeats && pid == getpid()) {
|
||||||
|
|
110
sapi/cli/tests/024.phpt
Normal file
110
sapi/cli/tests/024.phpt
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
--TEST--
|
||||||
|
multiple files syntax check
|
||||||
|
--SKIPIF--
|
||||||
|
<?php include "skipif.inc"; ?>
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
function run_and_output($cmd) {
|
||||||
|
exec($cmd, $output, $exit_code);
|
||||||
|
print_r($output);
|
||||||
|
var_dump($exit_code);
|
||||||
|
}
|
||||||
|
|
||||||
|
$php = getenv('TEST_PHP_EXECUTABLE_ESCAPED');
|
||||||
|
|
||||||
|
$filename_good = __DIR__."/024_good.test.php";
|
||||||
|
$filename_good_escaped = escapeshellarg($filename_good);
|
||||||
|
$filename_bad = __DIR__."/024_bad.test.php";
|
||||||
|
$filename_bad_escaped = escapeshellarg($filename_bad);
|
||||||
|
|
||||||
|
$code = '
|
||||||
|
<?php
|
||||||
|
|
||||||
|
echo "hi";
|
||||||
|
';
|
||||||
|
|
||||||
|
file_put_contents($filename_good, $code);
|
||||||
|
|
||||||
|
$code = '
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class test
|
||||||
|
private $var;
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
';
|
||||||
|
|
||||||
|
file_put_contents($filename_bad, $code);
|
||||||
|
|
||||||
|
run_and_output("$php -n -l $filename_good_escaped $filename_good_escaped 2>&1");
|
||||||
|
run_and_output("$php -n -l $filename_good_escaped some.unknown $filename_good_escaped 2>&1");
|
||||||
|
run_and_output("$php -n -l $filename_good_escaped $filename_bad_escaped $filename_good_escaped 2>&1");
|
||||||
|
run_and_output("$php -n -l $filename_bad_escaped $filename_bad_escaped 2>&1");
|
||||||
|
run_and_output("$php -n -l $filename_bad_escaped some.unknown $filename_bad_escaped 2>&1");
|
||||||
|
run_and_output("$php -n -l $filename_bad_escaped $filename_bad_escaped some.unknown 2>&1");
|
||||||
|
|
||||||
|
echo "Done\n";
|
||||||
|
?>
|
||||||
|
--CLEAN--
|
||||||
|
<?php
|
||||||
|
@unlink($filename_good);
|
||||||
|
@unlink($filename_bad);
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
Array
|
||||||
|
(
|
||||||
|
[0] => No syntax errors detected in %s024_good.test.php
|
||||||
|
[1] => No syntax errors detected in %s024_good.test.php
|
||||||
|
)
|
||||||
|
int(0)
|
||||||
|
Array
|
||||||
|
(
|
||||||
|
[0] => No syntax errors detected in %s024_good.test.php
|
||||||
|
[1] => Could not open input file: some.unknown
|
||||||
|
[2] => No syntax errors detected in %s024_good.test.php
|
||||||
|
)
|
||||||
|
int(1)
|
||||||
|
Array
|
||||||
|
(
|
||||||
|
[0] => No syntax errors detected in %s024_good.test.php
|
||||||
|
[1] =>
|
||||||
|
[2] => Parse error: syntax error, unexpected token "private", expecting "{" in %s on line %d
|
||||||
|
[3] => Errors parsing %s024_bad.test.php
|
||||||
|
[4] => No syntax errors detected in %s024_good.test.php
|
||||||
|
)
|
||||||
|
int(255)
|
||||||
|
Array
|
||||||
|
(
|
||||||
|
[0] =>
|
||||||
|
[1] => Parse error: syntax error, unexpected token "private", expecting "{" in %s on line %d
|
||||||
|
[2] => Errors parsing %s024_bad.test.php
|
||||||
|
[3] =>
|
||||||
|
[4] => Parse error: syntax error, unexpected token "private", expecting "{" in %s on line %d
|
||||||
|
[5] => Errors parsing %s024_bad.test.php
|
||||||
|
)
|
||||||
|
int(255)
|
||||||
|
Array
|
||||||
|
(
|
||||||
|
[0] =>
|
||||||
|
[1] => Parse error: syntax error, unexpected token "private", expecting "{" in %s on line %d
|
||||||
|
[2] => Errors parsing %s024_bad.test.php
|
||||||
|
[3] => Could not open input file: some.unknown
|
||||||
|
[4] =>
|
||||||
|
[5] => Parse error: syntax error, unexpected token "private", expecting "{" in %s on line %d
|
||||||
|
[6] => Errors parsing %s024_bad.test.php
|
||||||
|
)
|
||||||
|
int(255)
|
||||||
|
Array
|
||||||
|
(
|
||||||
|
[0] =>
|
||||||
|
[1] => Parse error: syntax error, unexpected token "private", expecting "{" in %s on line %d
|
||||||
|
[2] => Errors parsing %s024_bad.test.php
|
||||||
|
[3] =>
|
||||||
|
[4] => Parse error: syntax error, unexpected token "private", expecting "{" in %s on line %d
|
||||||
|
[5] => Errors parsing %s024_bad.test.php
|
||||||
|
[6] => Could not open input file: some.unknown
|
||||||
|
)
|
||||||
|
int(1)
|
||||||
|
Done
|
Loading…
Add table
Add a link
Reference in a new issue