$additionalPaths Absolute paths; missing ones are skipped but stated. * @return string The requested zip path, or an empty string when ZipArchive is unavailable. */ public function build(string $zipPath, string $debugFilePath, string $oldDebugFilePath, array $additionalPaths = array()): string { if (file_exists($zipPath)) { ABJ_404_Solution_FileSystemService::safeUnlink($zipPath); } if (!class_exists('ZipArchive')) { return ''; } $zipDirectory = dirname($zipPath); if (!is_dir($zipDirectory)) { abj404_logPhpFallback('logger-internal', 'debug log zip directory does not exist: ' . $zipDirectory); return $zipPath; } $zip = new ZipArchive; $openResult = $zip->open($zipPath, ZipArchive::CREATE); if ($openResult === true) { if (file_exists($debugFilePath)) { $zip->addFile($debugFilePath, basename($debugFilePath)); } if (file_exists($oldDebugFilePath)) { $zip->addFile($oldDebugFilePath, basename($oldDebugFilePath)); } foreach ($additionalPaths as $additionalPath) { if (is_string($additionalPath) && $additionalPath !== '' && file_exists($additionalPath)) { $zip->addFile($additionalPath, basename($additionalPath)); } } $zip->addFromString(self::MANIFEST_ENTRY, $this->manifest(array_merge(array($debugFilePath, $oldDebugFilePath), $additionalPaths))); if (!$zip->close()) { abj404_logPhpFallback('logger-internal', 'debug log zip close failed for ' . $zipPath); } } else { abj404_logPhpFallback( 'logger-internal', 'debug log zip open failed for ' . $zipPath . ' (status ' . (string)$openResult . ')' ); } return $zipPath; } /** * One line per requested path: whether it was there, how big it was, and * when it last changed. Requested paths, not added ones, because the * question this answers is "what did the collector look for", and the * absent ones are the interesting half of the answer. * * @param array $requestedPaths */ private function manifest(array $requestedPaths): string { $hostname = ABJ_404_Solution_PhpRuntimeCapabilityAdapter::hostname(); $pid = ABJ_404_Solution_PhpRuntimeCapabilityAdapter::processId(); $processIdentity = $pid !== null ? 'pid ' . $pid : 'synthetic process ' . ABJ_404_Solution_PhpRuntimeCapabilityAdapter::processToken(); $lines = array( 'Files this archive was asked to carry, and whether they were found.', 'Collected by ' . ($hostname !== null ? $hostname : 'unknown-host') . ' ' . $processIdentity . ' (' . PHP_SAPI . ').', '', ); foreach ($requestedPaths as $path) { if (!is_string($path) || $path === '') { continue; } if (!file_exists($path)) { $lines[] = 'absent ' . $path; continue; } $size = @filesize($path); $modified = @filemtime($path); $lines[] = 'present ' . $path . ' (' . (is_int($size) ? $size . ' bytes' : 'size unreadable') . ', modified ' . (is_int($modified) ? gmdate('Y-m-d H:i:s', $modified) . ' UTC' : 'unknown') . ')'; } return implode("\n", $lines) . "\n"; } }