scan-files: silence open_basedir warnings during walk
All checks were successful
cpanel-importer Build and Push / Build-and-Push (push) Successful in 53s

Container run on darkside completed end-to-end successfully (170,753
files scanned, 78 symlinks skipped via filter, 65 quarantined, walk
errors = 0) — but the import log was flooded with PHP Warnings on
every cpmove-internal symlink whose absolute target points outside
the container's open_basedir allow-list:

  PHP Warning:  is_link(): open_basedir restriction in effect.
  File(/host/sanitized/.../cybercoveconsulting.com/wp-content/db.php)
  is not within the allowed path(s): (/host:/tmp:...)

The actual code path was correct — is_link() still returns true when
warning, so the filter callback properly skipped these. But the noise
made the streamed [container] log on the panel side unreadable
(hundreds of warning lines per real signal line).

Root cause: PHP's open_basedir check normalizes via realpath() even
for is_link/is_file. cpmove symlinks like:
  db.php -> /home/<user>/<addon>.com/wp-content/db.php
  access-logs -> /usr/local/apache/domlogs/<user>
  cpanel-styled -> /usr/local/cpanel/base/frontend/.../glass
have absolute targets that don't exist anywhere in the container
(no /home, no /usr/local), so realpath() can't normalize them under
any allow-list entry. PHP fires Warning, returns the lstat answer
anyway, and our filter handles the skip correctly.

Fix: a scoped set_error_handler around the walk that suppresses ONLY
E_WARNINGs containing 'open_basedir restriction'. Non-open_basedir
warnings still surface. The handler is restored immediately after the
file-count loop, so subsequent stages (clamscan output parsing,
quarantine actions) keep the default error reporting.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Claude (bootstrap)
2026-05-31 12:08:40 -07:00
parent 9652a71816
commit 4888f85b54

View File

@@ -128,6 +128,30 @@ $filesScanned = 0;
$skippedLinks = 0; $skippedLinks = 0;
$walkErrors = 0; $walkErrors = 0;
// Silence open_basedir E_WARNINGs during the walk. cPanel cpmove tarballs
// frequently contain symlinks pointing at the SOURCE server's absolute
// paths (db.php -> /home/<user>/<addon>/wp-content/db.php, access-logs ->
// /usr/local/apache/domlogs/<user>, etc.). PHP's open_basedir check
// normalizes via realpath() even for is_link/is_file; when the symlink
// target lies outside the container's allow-list (it does — there's no
// /home or /usr/local in the container), PHP emits a Warning per call.
// Our filter callback STILL returns the right answer (is_link returns
// true even when warning), so the skip-symlink logic works regardless
// of the noise — but the noise floods 100k+ lines into the import log
// for a typical customer account, drowning the actually-useful
// quarantine actions.
//
// set_error_handler limited to E_WARNING with a needle filter is
// narrower than `error_reporting(0)` (we still surface non-open_basedir
// warnings) and narrower than `@`-prefixing every call site (covers
// PHP-internal callbacks invoked deep inside the iterator).
$prevHandler = set_error_handler(function ($errno, $errstr) {
if ($errno === E_WARNING && strpos($errstr, 'open_basedir restriction') !== false) {
return true; // suppress
}
return false; // let PHP handle (or chain to previous handler)
}, E_WARNING);
$rdi = new RecursiveDirectoryIterator( $rdi = new RecursiveDirectoryIterator(
$extractDir, $extractDir,
FilesystemIterator::SKIP_DOTS | FilesystemIterator::CURRENT_AS_PATHNAME FilesystemIterator::SKIP_DOTS | FilesystemIterator::CURRENT_AS_PATHNAME
@@ -154,6 +178,8 @@ foreach ($it as $pathname) {
$walkErrors++; $walkErrors++;
} }
} }
restore_error_handler();
fwrite(STDERR, sprintf( fwrite(STDERR, sprintf(
"scan-files: file walk: counted=%d, symlinks-skipped=%d, walk-errors=%d\n", "scan-files: file walk: counted=%d, symlinks-skipped=%d, walk-errors=%d\n",
$filesScanned, $skippedLinks, $walkErrors $filesScanned, $skippedLinks, $walkErrors