Ban proc_open() and exec() entirely - replace with shell_exec() and file redirection
🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -19,7 +19,7 @@ class StreamBlockingMode_CodeQualityRule extends CodeQualityRule_Abstract
|
||||
|
||||
public function get_description(): string
|
||||
{
|
||||
return 'Streams from proc_open() and network sockets must set blocking mode before reading to prevent data truncation';
|
||||
return 'Streams from fsockopen() and network sockets must set blocking mode before reading to prevent data truncation (note: proc_open() is banned - see PHP-PROC-01)';
|
||||
}
|
||||
|
||||
public function get_file_patterns(): array
|
||||
@@ -36,9 +36,11 @@ class StreamBlockingMode_CodeQualityRule extends CodeQualityRule_Abstract
|
||||
* Check PHP file for stream operations without explicit blocking mode
|
||||
* and dangerous read patterns that truncate data
|
||||
*
|
||||
* PHP streams from proc_open(), fsockopen(), popen(), and stream_socket_client()
|
||||
* PHP streams from fsockopen(), popen(), and stream_socket_client()
|
||||
* default to non-blocking mode in some contexts, which causes incomplete reads
|
||||
* and silent data truncation.
|
||||
*
|
||||
* Note: proc_open() is completely banned by PHP-PROC-01 rule, so it's excluded here.
|
||||
*/
|
||||
public function check(string $file_path, string $contents, array $metadata = []): void
|
||||
{
|
||||
@@ -56,8 +58,8 @@ class StreamBlockingMode_CodeQualityRule extends CodeQualityRule_Abstract
|
||||
$sanitized_data = FileSanitizer::sanitize_php($contents);
|
||||
$sanitized_code = $sanitized_data['content'];
|
||||
|
||||
// Check for stream sources
|
||||
$stream_sources_pattern = '/\b(proc_open|fsockopen|stream_socket_client|popen)\s*\(/i';
|
||||
// Check for stream sources (proc_open excluded - it's banned by PHP-PROC-01)
|
||||
$stream_sources_pattern = '/\b(fsockopen|stream_socket_client|popen)\s*\(/i';
|
||||
if (!preg_match($stream_sources_pattern, $sanitized_code)) {
|
||||
return; // No stream sources, skip
|
||||
}
|
||||
@@ -140,14 +142,16 @@ class StreamBlockingMode_CodeQualityRule extends CodeQualityRule_Abstract
|
||||
{
|
||||
return "Stream operations without explicit blocking mode
|
||||
|
||||
File uses stream sources (proc_open/fsockopen/popen/stream_socket_client) with
|
||||
File uses stream sources (fsockopen/popen/stream_socket_client) with
|
||||
read operations but does not call stream_set_blocking().
|
||||
|
||||
Note: proc_open() is banned entirely - see PHP-PROC-01 rule.
|
||||
|
||||
PHP streams default to non-blocking mode in some contexts, which causes:
|
||||
- Incomplete reads with partial data
|
||||
- Silent data truncation (no errors or warnings)
|
||||
- Race conditions depending on when data arrives
|
||||
- Data integrity issues for command output and file transfers";
|
||||
- Data integrity issues for network transfers and command output";
|
||||
}
|
||||
|
||||
private function get_missing_blocking_resolution(): string
|
||||
@@ -156,30 +160,23 @@ PHP streams default to non-blocking mode in some contexts, which causes:
|
||||
|
||||
Add stream_set_blocking(\$stream, true) before reading AND use proper read loop:
|
||||
|
||||
CORRECT PATTERN:
|
||||
\$process = proc_open(\$command, \$descriptors, \$pipes);
|
||||
fclose(\$pipes[0]);
|
||||
CORRECT PATTERN (for network sockets):
|
||||
\$socket = fsockopen('example.com', 80);
|
||||
|
||||
stream_set_blocking(\$pipes[1], true);
|
||||
stream_set_blocking(\$pipes[2], true);
|
||||
stream_set_blocking(\$socket, true);
|
||||
|
||||
// Read stdout until EOF
|
||||
// Read until EOF
|
||||
\$output = '';
|
||||
while (!feof(\$pipes[1])) {
|
||||
\$chunk = fread(\$pipes[1], 8192);
|
||||
while (!feof(\$socket)) {
|
||||
\$chunk = fread(\$socket, 8192);
|
||||
if (\$chunk !== false) {
|
||||
\$output .= \$chunk;
|
||||
}
|
||||
}
|
||||
|
||||
// Read stderr until EOF
|
||||
\$error = '';
|
||||
while (!feof(\$pipes[2])) {
|
||||
\$chunk = fread(\$pipes[2], 8192);
|
||||
if (\$chunk !== false) {
|
||||
\$error .= \$chunk;
|
||||
}
|
||||
}";
|
||||
fclose(\$socket);
|
||||
|
||||
Note: If you're using proc_open(), replace it with file redirection (see PHP-PROC-01).";
|
||||
}
|
||||
|
||||
private function get_dangerous_break_message(): string
|
||||
|
||||
Reference in New Issue
Block a user