Files
portal-api/app/Support/SslBundleExtractor.php
T
baodev0andClaude Sonnet 5.5 b44a88bb52 feat(service): huỷ dịch vụ, SSL, đổi mật khẩu hosting, lịch sử thanh toán theo hình thức
- Lịch sử thanh toán hoá đơn trả thêm `method` (tự động gia hạn / số dư / admin / chuyển khoản / hoàn tiền), bỏ đuôi `(method)` khỏi ghi chú
- `DnsServer::panelUrl()` = https://<domain>/ dùng cho email cấp hosting và nút Plesk của khách
- Order item trả thêm `uuid`/`type` của dịch vụ để FE dẫn tới trang quản lý
- Yêu cầu huỷ dịch vụ, chứng chỉ SSL, lịch sử gia hạn, đổi mật khẩu hosting cho khách

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-28 16:40:24 +07:00

68 lines
2.0 KiB
PHP

<?php
namespace App\Support;
use App\Models\ServiceSslCertificate;
use Illuminate\Http\UploadedFile;
use InvalidArgumentException;
use ZipArchive;
class SslBundleExtractor
{
private const MAX_TOTAL_BYTES = 2097152;
public static function extract(UploadedFile $archive): array
{
$zip = new ZipArchive();
if ($zip->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');
}
}