open($archive->getRealPath(), ZipArchive::RDONLY) !== true) { throw new InvalidArgumentException('Không đọc được file zip.'); } $files = []; $total = 0; for ($index = 0; $index < $zip->numFiles; $index++) { $name = self::cleanName($zip->getNameIndex($index)); if ($name === null) { continue; } $content = $zip->getFromIndex($index, ServiceSslCertificate::MAX_FILE_BYTES + 1); if ($content === false || strlen($content) > ServiceSslCertificate::MAX_FILE_BYTES || ! self::isText($content)) { continue; } $total += strlen($content); if ($total > self::MAX_TOTAL_BYTES || count($files) >= ServiceSslCertificate::MAX_ENTRIES) { throw new InvalidArgumentException('File zip chứa quá nhiều dữ liệu.'); } $files[$name] = ['name' => $name, 'content' => $content]; } $zip->close(); if ($files === []) { throw new InvalidArgumentException('File zip không có tệp văn bản nào (pem, crt, key, txt...).'); } return array_values($files); } private static function cleanName(string $entry): ?string { if (str_ends_with($entry, '/') || str_contains($entry, '__MACOSX/')) { return null; } $name = trim(basename($entry)); return $name === '' || str_starts_with($name, '.') ? null : mb_substr($name, 0, 150); } private static function isText(string $content): bool { return ! str_contains($content, "\0") && mb_check_encoding($content, 'UTF-8'); } }