|
@@ -381,23 +381,219 @@ class PublicController extends AbstractController
|
|
|
|
|
|
if ($zip->open($zipFileName, ZipArchive::CREATE) === true) {
|
|
|
// 将要下载的文件逐个添加到zip文件中
|
|
|
-// $string = trim($requireData['files'], "[]'"); // 去掉最外层的方括号和单引号(注意:这里假设了单引号,如果是双引号则替换为 ")
|
|
|
-// $string = str_replace("'", '', $string); // 去掉所有剩余的单引号(如果原字符串中使用的是双引号,则替换为双引号)
|
|
|
-// $filePaths = explode(',', $string);
|
|
|
- foreach ($requireData['files'] as $filePathu) {
|
|
|
- // $attachmentItem = 'public/' . $filePathu;
|
|
|
- $zip->addFile($filePathu, pathinfo($filePathu, PATHINFO_BASENAME));
|
|
|
+ /** @var array<string> $files */
|
|
|
+ $files = [];
|
|
|
+ if (is_array($requireData['files'])) {
|
|
|
+ $files = $requireData['files'];
|
|
|
+ } elseif (is_string($requireData['files'])) {
|
|
|
+ $files = [$requireData['files']];
|
|
|
+ }
|
|
|
+
|
|
|
+ foreach ($files as $key => $filePathu) {
|
|
|
+ if (!is_string($filePathu)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 生成文件名:key + 1
|
|
|
+ $fileName = ($key + 1) . $this->getFileExtension($filePathu);
|
|
|
+
|
|
|
+ // 处理base64数据
|
|
|
+ if ($this->isBase64Data($filePathu)) {
|
|
|
+ $this->addBase64FileToZip($zip, $filePathu, $fileName);
|
|
|
+ }
|
|
|
+ // 处理远程URL文件
|
|
|
+ if (filter_var($filePathu, FILTER_VALIDATE_URL)) {
|
|
|
+ $this->addRemoteFileToZip($zip, $filePathu, $fileName);
|
|
|
+ } else {
|
|
|
+ // 处理本地文件
|
|
|
+ if (!file_exists($filePathu)) {
|
|
|
+ // 尝试添加public前缀
|
|
|
+ $fullPath = 'public/' . $filePathu;
|
|
|
+ if (!file_exists($fullPath)) {
|
|
|
+ // 尝试使用绝对路径
|
|
|
+ $fullPath = BASE_PATH . '/public/' . $filePathu;
|
|
|
+ if (!file_exists($fullPath)) {
|
|
|
+ continue; // 跳过不存在的文件
|
|
|
+ }
|
|
|
+ }
|
|
|
+ $filePathu = $fullPath;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 确保文件存在且可读
|
|
|
+ if (is_file($filePathu) && is_readable($filePathu)) {
|
|
|
+ $zip->addFile($filePathu, $fileName);
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
// 关闭zip文件
|
|
|
$zip->close();
|
|
|
// 将zip文件提供给用户进行下载
|
|
|
-// readfile($zipFileName);
|
|
|
$fileUrlName = explode("public", $zipFileName);
|
|
|
return Result::success(['fileUrl' => env('HOST') . $fileUrlName[1]]);
|
|
|
} else {
|
|
|
return Result::error('无法创建zip文件');
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 添加远程文件到zip
|
|
|
+ */
|
|
|
+ private function addRemoteFileToZip($zip, $url, $fileName = null): void
|
|
|
+ {
|
|
|
+ try {
|
|
|
+ // 创建临时文件
|
|
|
+ $tempFile = tempnam(sys_get_temp_dir(), 'remote_file_');
|
|
|
+
|
|
|
+ // 设置更长的超时时间和更好的下载参数
|
|
|
+ $context = stream_context_create([
|
|
|
+ 'http' => [
|
|
|
+ 'timeout' => 120, // 增加到120秒
|
|
|
+ 'user_agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
|
|
|
+ 'follow_location' => true, // 允许重定向
|
|
|
+ 'max_redirects' => 5,
|
|
|
+ 'protocol_version' => 1.1,
|
|
|
+ 'header' => [
|
|
|
+ 'Accept: */*',
|
|
|
+ 'Accept-Encoding: gzip, deflate',
|
|
|
+ 'Connection: keep-alive'
|
|
|
+ ]
|
|
|
+ ],
|
|
|
+ 'ssl' => [
|
|
|
+ 'verify_peer' => false,
|
|
|
+ 'verify_peer_name' => false,
|
|
|
+ 'allow_self_signed' => true
|
|
|
+ ]
|
|
|
+ ]);
|
|
|
+
|
|
|
+ // 使用cURL作为备选方案
|
|
|
+ $fileContent = $this->downloadFileWithCurl($url);
|
|
|
+ if ($fileContent === false) {
|
|
|
+ // 如果cURL失败,尝试file_get_contents
|
|
|
+ $fileContent = file_get_contents($url, false, $context);
|
|
|
+ }
|
|
|
+
|
|
|
+ if ($fileContent === false) {
|
|
|
+ error_log("Failed to download remote file: " . $url);
|
|
|
+ return; // 下载失败,跳过
|
|
|
+ }
|
|
|
+
|
|
|
+ // 验证文件内容
|
|
|
+ if (empty($fileContent) || strlen($fileContent) < 100) {
|
|
|
+ error_log("Downloaded file is too small or empty: " . $url);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 写入临时文件并验证
|
|
|
+ $bytesWritten = file_put_contents($tempFile, $fileContent);
|
|
|
+ if ($bytesWritten === false || $bytesWritten !== strlen($fileContent)) {
|
|
|
+ error_log("Failed to write file content: " . $url);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 验证文件是否可读
|
|
|
+ if (!is_readable($tempFile) || filesize($tempFile) < 100) {
|
|
|
+ error_log("Temporary file is not readable or too small: " . $tempFile);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取文件名
|
|
|
+ if ($fileName === null) {
|
|
|
+ $fileName = basename(parse_url($url, PHP_URL_PATH));
|
|
|
+ if (empty($fileName)) {
|
|
|
+ $fileName = 'remote_file_' . time() . '.jpg';
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 添加到zip并验证
|
|
|
+ if (!$zip->addFile($tempFile, $fileName)) {
|
|
|
+ error_log("Failed to add file to zip: " . $fileName);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ // 记录错误但继续处理其他文件
|
|
|
+ error_log("Failed to download remote file: " . $url . " - " . $e->getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 使用cURL下载文件
|
|
|
+ */
|
|
|
+ private function downloadFileWithCurl($url): string|false
|
|
|
+ {
|
|
|
+ if (!function_exists('curl_init')) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ $ch = curl_init();
|
|
|
+ curl_setopt_array($ch, [
|
|
|
+ CURLOPT_URL => $url,
|
|
|
+ CURLOPT_RETURNTRANSFER => true,
|
|
|
+ CURLOPT_TIMEOUT => 120, // 120秒超时
|
|
|
+ CURLOPT_CONNECTTIMEOUT => 30, // 连接超时30秒
|
|
|
+ CURLOPT_FOLLOWLOCATION => true,
|
|
|
+ CURLOPT_MAXREDIRS => 5,
|
|
|
+ CURLOPT_USERAGENT => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
|
|
|
+ CURLOPT_SSL_VERIFYPEER => false,
|
|
|
+ CURLOPT_SSL_VERIFYHOST => false,
|
|
|
+ CURLOPT_ENCODING => '', // 自动处理编码
|
|
|
+ CURLOPT_HTTPHEADER => [
|
|
|
+ 'Accept: image/*, */*',
|
|
|
+ 'Accept-Encoding: gzip, deflate',
|
|
|
+ 'Connection: keep-alive',
|
|
|
+ 'Cache-Control: no-cache'
|
|
|
+ ]
|
|
|
+ ]);
|
|
|
+
|
|
|
+ $content = curl_exec($ch);
|
|
|
+ $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
|
+ $contentLength = curl_getinfo($ch, CURLINFO_CONTENT_LENGTH_DOWNLOAD);
|
|
|
+ $actualLength = strlen($content);
|
|
|
+ curl_close($ch);
|
|
|
+
|
|
|
+ // 检查HTTP状态码和内容长度
|
|
|
+ if ($content === false || $httpCode !== 200) {
|
|
|
+ error_log("cURL download failed for URL: $url, HTTP Code: $httpCode");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查内容长度是否匹配
|
|
|
+ if ($contentLength > 0 && $actualLength !== $contentLength) {
|
|
|
+ error_log("Content length mismatch for URL: $url, Expected: $contentLength, Actual: $actualLength");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查文件是否为空或太小
|
|
|
+ if (empty($content) || $actualLength < 100) {
|
|
|
+ error_log("File too small or empty for URL: $url, Size: $actualLength");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ return $content;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取文件扩展名
|
|
|
+ */
|
|
|
+ private function getFileExtension($filePath): string
|
|
|
+ {
|
|
|
+ $extension = pathinfo($filePath, PATHINFO_EXTENSION);
|
|
|
+ if (empty($extension)) {
|
|
|
+ // 如果是URL,尝试从URL中获取扩展名
|
|
|
+ if (filter_var($filePath, FILTER_VALIDATE_URL)) {
|
|
|
+ $parsedUrl = parse_url($filePath, PHP_URL_PATH);
|
|
|
+ $extension = pathinfo($parsedUrl, PATHINFO_EXTENSION);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果还是没有扩展名,默认为jpg
|
|
|
+ if (empty($extension)) {
|
|
|
+ $extension = 'jpg';
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return '.' . $extension;
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 检测是否被处理
|
|
|
* @return array
|