rkljw 1 deň pred
rodič
commit
90d9568f73
2 zmenil súbory, kde vykonal 129 pridanie a 24 odobranie
  1. 69 24
      app/Controller/PublicController.php
  2. 60 0
      app/Service/FileService.php

+ 69 - 24
app/Controller/PublicController.php

@@ -381,10 +381,8 @@ class PublicController extends AbstractController
         }
         $fileName = $requireData['fileName'] . time() . mt_rand(1, 1000000) . '.zip';
         $zipFileName = $allDir . DIRECTORY_SEPARATOR . $requireData['fileName'] . time() . mt_rand(1, 1000000) . '.zip';
-//        $zipFileName = 'public/zip/files.zip';
 
         if ($zip->open($zipFileName, ZipArchive::CREATE) === true) {
-            // 将要下载的文件逐个添加到zip文件中
             /** @var array<string> $files */
             $files = [];
             if (is_array($requireData['files'])) {
@@ -393,47 +391,94 @@ class PublicController extends AbstractController
                 $files = [$requireData['files']];
             }
             
+            // 使用协程并行处理文件
+            $fileService = \Hyperf\Support\make(\App\Service\FileService::class);
+            $promises = [];
+            
             foreach ($files as $key => $filePathu) {
                 if (!is_string($filePathu)) {
                     continue;
                 }
                 
-                // 生成文件名:key + 1
-                $fileName = $requireData['names'][$key]; //($key + 1) . $this->getFileExtension($filePathu);
+                $fileName = $requireData['names'][$key];
                 
                 // 处理远程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;
+                    // 检查缓存
+                    $cachedContent = $fileService->getCachedFile($filePathu);
+                    if ($cachedContent !== null) {
+                        $zip->addFromString($fileName, $cachedContent);
+                        continue;
                     }
                     
-                    // 确保文件存在且可读
-                    if (is_file($filePathu) && is_readable($filePathu)) {
-                        $zip->addFile($filePathu, $fileName);
-                    }
+                    // 添加到并行下载队列
+                    $promises[] = function() use ($fileService, $zip, $filePathu, $fileName) {
+                        $content = $fileService->downloadWithProgress($filePathu, function($ch, $downloadSize, $downloaded) {
+                            // 可以在这里添加下载进度记录
+                            if ($downloadSize > 0) {
+                                $progress = round($downloaded / $downloadSize * 100);
+                                // 记录进度...
+                            }
+                        });
+                        
+                        if ($content !== false) {
+                            // 缓存文件内容
+                            $fileService->cacheFile($filePathu, $content);
+                            // 添加到zip
+                            $zip->addFromString($fileName, $content);
+                        }
+                    };
+                } else {
+                    // 本地文件处理
+                    $this->addLocalFileToZip($zip, $filePathu, $fileName);
                 }
             }
-            // 关闭zip文件
+            
+            // 并行执行所有下载任务
+            if (!empty($promises)) {
+                // 使用协程并发执行所有下载任务
+                \Hyperf\Coroutine\parallel($promises);
+            }
+            
             $zip->close();
-            // 将zip文件提供给用户进行下载
             $fileUrlName = explode("public", $zipFileName);
             return Result::success(['fileUrl' => env('HOST') . $fileUrlName[1]]);
         } else {
             return Result::error('无法创建zip文件');
         }
     }
+
+    /**
+     * 处理本地文件添加到zip
+     */
+    private function addLocalFileToZip($zip, $filePath, $fileName): void
+    {
+        if (!file_exists($filePath)) {
+            // 尝试不同的路径组合
+            $paths = [
+                'public/' . $filePath,
+                BASE_PATH . '/public/' . $filePath
+            ];
+            
+            foreach ($paths as $path) {
+                if (file_exists($path)) {
+                    $filePath = $path;
+                    break;
+                }
+            }
+        }
+        
+        if (is_file($filePath) && is_readable($filePath)) {
+            // 对大文件使用流式处理
+            if (filesize($filePath) > 10 * 1024 * 1024) { // 10MB
+                $stream = fopen($filePath, 'r');
+                $zip->addFromStream($stream, $fileName);
+                fclose($stream);
+            } else {
+                $zip->addFile($filePath, $fileName);
+            }
+        }
+    }
     
     /**
      * 添加远程文件到zip

+ 60 - 0
app/Service/FileService.php

@@ -0,0 +1,60 @@
+<?php
+declare(strict_types=1);
+
+namespace App\Service;
+
+use Hyperf\Redis\Redis;
+
+class FileService
+{
+    private Redis $redis;
+    private string $cachePrefix = 'file_cache:';
+    private int $cacheExpire = 3600; // 1小时缓存
+
+    public function __construct(Redis $redis)
+    {
+        $this->redis = $redis;
+    }
+
+    public function getCachedFile(string $url): ?string
+    {
+        $cacheKey = $this->cachePrefix . md5($url);
+        $result = $this->redis->get($cacheKey);
+        return $result === false ? null : $result;
+    }
+
+    public function cacheFile(string $url, string $content): void
+    {
+        $cacheKey = $this->cachePrefix . md5($url);
+        $this->redis->setex($cacheKey, $this->cacheExpire, $content);
+    }
+
+    public function downloadWithProgress(string $url, callable $progressCallback = null): string|false
+    {
+        $ch = curl_init();
+        curl_setopt_array($ch, [
+            CURLOPT_URL => $url,
+            CURLOPT_RETURNTRANSFER => true,
+            CURLOPT_TIMEOUT => 120,
+            CURLOPT_CONNECTTIMEOUT => 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_NOPROGRESS => false,
+            CURLOPT_PROGRESSFUNCTION => $progressCallback
+        ]);
+
+        $content = curl_exec($ch);
+        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
+        curl_close($ch);
+
+        if ($content === false || $httpCode !== 200) {
+            return false;
+        }
+
+        return $content;
+    }
+}