* Extracts archive files from the specified folder. * Supports ZIP via ZipArchive and other formats via 7z (RAR extraction prefers unar when available). * * @param string $folder The folder from which archives will be extracted (e.g., "root" or a subfolder). * @param array $files An array of archive file names to extract. * @return array An associative array with keys "suc
($folder, $files)
| 1653 | * @return array An associative array with keys "success" (boolean), and either "extractedFiles" (array) on success or "error" (string) on failure. |
| 1654 | */ |
| 1655 | public static function extractZipArchive($folder, $files) |
| 1656 | { |
| 1657 | // Block ZIP extraction inside encrypted folders (v1). |
| 1658 | try { |
| 1659 | if (FolderCrypto::isEncryptedOrAncestor((string)$folder)) { |
| 1660 | return ["error" => "ZIP operations are disabled inside encrypted folders."]; |
| 1661 | } |
| 1662 | } catch (\Throwable $e) { |
| 1663 | /* ignore */ |
| 1664 | } |
| 1665 | |
| 1666 | $errors = []; |
| 1667 | $warnings = []; |
| 1668 | $allSuccess = true; |
| 1669 | $extractedFiles = []; |
| 1670 | |
| 1671 | // Config toggles |
| 1672 | $SKIP_DOTFILES = defined('SKIP_DOTFILES_ON_EXTRACT') ? (bool)SKIP_DOTFILES_ON_EXTRACT : true; |
| 1673 | |
| 1674 | // Hard limits to mitigate zip-bombs (tweak via defines if you like) |
| 1675 | $MAX_UNZIP_BYTES = defined('MAX_UNZIP_BYTES') ? (int)MAX_UNZIP_BYTES : (200 * 1024 * 1024 * 1024); // 200 GiB |
| 1676 | $MAX_UNZIP_FILES = defined('MAX_UNZIP_FILES') ? (int)MAX_UNZIP_FILES : 20000; |
| 1677 | $formatBytes = function (int $bytes): string { |
| 1678 | $bytes = max(0, $bytes); |
| 1679 | $units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB']; |
| 1680 | $value = (float)$bytes; |
| 1681 | $i = 0; |
| 1682 | while ($value >= 1024 && $i < count($units) - 1) { |
| 1683 | $value /= 1024; |
| 1684 | $i++; |
| 1685 | } |
| 1686 | $dec = ($value >= 10 || $i === 0) ? 0 : 1; |
| 1687 | return number_format($value, $dec) . ' ' . $units[$i]; |
| 1688 | }; |
| 1689 | |
| 1690 | $baseDir = realpath(self::uploadRoot()); |
| 1691 | if ($baseDir === false) { |
| 1692 | return ["error" => "Uploads directory not configured correctly."]; |
| 1693 | } |
| 1694 | |
| 1695 | // Build target dir |
| 1696 | if (strtolower(trim($folder) ?: '') === "root") { |
| 1697 | $relativePath = ""; |
| 1698 | $folderNorm = "root"; |
| 1699 | } else { |
| 1700 | $parts = explode('/', trim($folder, "/\\")); |
| 1701 | foreach ($parts as $part) { |
| 1702 | if ($part === '' || $part === '.' || $part === '..' || !preg_match(REGEX_FOLDER_NAME, $part)) { |
| 1703 | return ["error" => "Invalid folder name."]; |
| 1704 | } |
| 1705 | } |
| 1706 | $relativePath = implode(DIRECTORY_SEPARATOR, $parts) . DIRECTORY_SEPARATOR; |
| 1707 | $folderNorm = implode('/', $parts); // normalized with forward slashes for metadata helpers |
| 1708 | } |
| 1709 | |
| 1710 | $folderPath = $baseDir . DIRECTORY_SEPARATOR . $relativePath; |
| 1711 | if (!is_dir($folderPath) && !mkdir($folderPath, 0775, true)) { |
| 1712 | return ["error" => "Folder not found and cannot be created."]; |
no test coverage detected