rkljw 10 saat önce
ebeveyn
işleme
b09eeebd92
7 değiştirilmiş dosya ile 457 ekleme ve 57 silme
  1. 4 4
      .env
  2. 13 0
      .idea/admin_consumer.iml
  3. 8 0
      .idea/modules.xml
  4. 187 0
      .idea/php.xml
  5. 6 0
      .idea/vcs.xml
  6. 23 5
      .idea/workspace.xml
  7. 216 48
      app/Controller/PublicController.php

+ 4 - 4
.env

@@ -13,7 +13,7 @@ APP_ENV=dev
 
 
 
-HOST = http://192.168.1.123:13306/
+HOST = http://192.168.1.201:9501/
 
 
 DB_DRIVER=mysql
@@ -48,10 +48,10 @@ REDIS_DB=0
 
 
 
-AMQP_HOST=192.168.1.234
-AMQP_PORT=5672
+AMQP_HOST=192.168.1.201
+AMQP_PORT=25672
 AMQP_USER=rabbitmq
-AMQP_PASSWORD=zxt_mq_dev
+AMQP_PASSWORD=zxt_mq_pre
 
 
 

+ 13 - 0
.idea/admin_consumer.iml

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="JAVA_MODULE" version="4">
+  <component name="NewModuleRootManager" inherit-compiler-output="true">
+    <exclude-output />
+    <content url="file://$MODULE_DIR$">
+      <sourceFolder url="file://$MODULE_DIR$/./test" isTestSource="true" packagePrefix="HyperfTest\" />
+      <sourceFolder url="file://$MODULE_DIR$/app" isTestSource="false" packagePrefix="App\" />
+      <excludeFolder url="file://$MODULE_DIR$/vendor/hyperf/crontab" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+  </component>
+</module>

+ 8 - 0
.idea/modules.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectModuleManager">
+    <modules>
+      <module fileurl="file://$PROJECT_DIR$/.idea/admin_consumer.iml" filepath="$PROJECT_DIR$/.idea/admin_consumer.iml" />
+    </modules>
+  </component>
+</project>

+ 187 - 0
.idea/php.xml

@@ -0,0 +1,187 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="PhpIncludePathManager">
+    <include_path>
+      <path value="$PROJECT_DIR$/vendor/hyperf/engine-contract" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/code-parser" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/snowflake" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/redis" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/engine" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/memory" />
+      <path value="$PROJECT_DIR$/vendor/myclabs/deep-copy" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/watcher" />
+      <path value="$PROJECT_DIR$/vendor/symfony/http-foundation" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/collection" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/testing" />
+      <path value="$PROJECT_DIR$/vendor/symfony/console" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/nacos" />
+      <path value="$PROJECT_DIR$/vendor/evenement/evenement" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/json-rpc" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/cache" />
+      <path value="$PROJECT_DIR$/vendor/phar-io/version" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/event" />
+      <path value="$PROJECT_DIR$/vendor/phar-io/manifest" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/service-governance-consul" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/codec" />
+      <path value="$PROJECT_DIR$/vendor/php-di/phpdoc-reader" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/config-nacos" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/config-center" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/dispatcher" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/model-listener" />
+      <path value="$PROJECT_DIR$/vendor/php-amqplib/php-amqplib" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/pool" />
+      <path value="$PROJECT_DIR$/vendor/jetbrains/phpstorm-attributes" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/translation" />
+      <path value="$PROJECT_DIR$/vendor/easyswoole/spl" />
+      <path value="$PROJECT_DIR$/vendor/clue/ndjson-react" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/logger" />
+      <path value="$PROJECT_DIR$/vendor/easyswoole/verifycode" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/contract" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/consul" />
+      <path value="$PROJECT_DIR$/vendor/swoole/ide-helper" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/utils" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/constants" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/load-balancer" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/command" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/support" />
+      <path value="$PROJECT_DIR$/vendor/paragonie/constant_time_encoding" />
+      <path value="$PROJECT_DIR$/vendor/paragonie/random_compat" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/context" />
+      <path value="$PROJECT_DIR$/vendor/vlucas/phpdotenv" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/server" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/service-governance-nacos" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/config" />
+      <path value="$PROJECT_DIR$/vendor/friendsofphp/php-cs-fixer" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/rpc" />
+      <path value="$PROJECT_DIR$/vendor/swow/psr7-plus" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/stringable" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/devtool" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/pipeline" />
+      <path value="$PROJECT_DIR$/vendor/fidry/cpu-core-counter" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/coroutine" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/http-server" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/amqp" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/http-message" />
+      <path value="$PROJECT_DIR$/vendor/composer" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/macroable" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/di" />
+      <path value="$PROJECT_DIR$/vendor/egulias/email-validator" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/coordinator" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/db-connection" />
+      <path value="$PROJECT_DIR$/vendor/symfony/polyfill-php83" />
+      <path value="$PROJECT_DIR$/vendor/symfony/polyfill-intl-grapheme" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/validation" />
+      <path value="$PROJECT_DIR$/vendor/symfony/stopwatch" />
+      <path value="$PROJECT_DIR$/vendor/symfony/options-resolver" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/guzzle" />
+      <path value="$PROJECT_DIR$/vendor/symfony/deprecation-contracts" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/rpc-client" />
+      <path value="$PROJECT_DIR$/vendor/symfony/finder" />
+      <path value="$PROJECT_DIR$/vendor/symfony/polyfill-ctype" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/websocket-server" />
+      <path value="$PROJECT_DIR$/vendor/symfony/service-contracts" />
+      <path value="$PROJECT_DIR$/vendor/symfony/polyfill-php81" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/tappable" />
+      <path value="$PROJECT_DIR$/vendor/symfony/translation-contracts" />
+      <path value="$PROJECT_DIR$/vendor/friendsofhyperf/openai-client" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/service-governance" />
+      <path value="$PROJECT_DIR$/vendor/symfony/polyfill-php80" />
+      <path value="$PROJECT_DIR$/vendor/hamcrest/hamcrest-php" />
+      <path value="$PROJECT_DIR$/vendor/nikic/php-parser" />
+      <path value="$PROJECT_DIR$/vendor/symfony/event-dispatcher" />
+      <path value="$PROJECT_DIR$/vendor/nikic/fast-route" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/conditionable" />
+      <path value="$PROJECT_DIR$/vendor/symfony/polyfill-intl-normalizer" />
+      <path value="$PROJECT_DIR$/vendor/symfony/process" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/stdlib" />
+      <path value="$PROJECT_DIR$/vendor/symfony/translation" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/serializer" />
+      <path value="$PROJECT_DIR$/vendor/symfony/polyfill-intl-idn" />
+      <path value="$PROJECT_DIR$/vendor/guzzlehttp/guzzle" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/rpc-server" />
+      <path value="$PROJECT_DIR$/vendor/phpstan/phpstan" />
+      <path value="$PROJECT_DIR$/vendor/symfony/event-dispatcher-contracts" />
+      <path value="$PROJECT_DIR$/vendor/theseer/tokenizer" />
+      <path value="$PROJECT_DIR$/vendor/symfony/string" />
+      <path value="$PROJECT_DIR$/vendor/guzzlehttp/promises" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/framework" />
+      <path value="$PROJECT_DIR$/vendor/symfony/filesystem" />
+      <path value="$PROJECT_DIR$/vendor/guzzlehttp/psr7" />
+      <path value="$PROJECT_DIR$/vendor/phpunit/php-code-coverage" />
+      <path value="$PROJECT_DIR$/vendor/phpunit/php-file-iterator" />
+      <path value="$PROJECT_DIR$/vendor/laminas/laminas-mime" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/exception-handler" />
+      <path value="$PROJECT_DIR$/vendor/laminas/laminas-stdlib" />
+      <path value="$PROJECT_DIR$/vendor/symfony/polyfill-mbstring" />
+      <path value="$PROJECT_DIR$/vendor/php-http/multipart-stream-builder" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/process" />
+      <path value="$PROJECT_DIR$/vendor/php-http/discovery" />
+      <path value="$PROJECT_DIR$/vendor/phpunit/phpunit" />
+      <path value="$PROJECT_DIR$/vendor/phpunit/php-timer" />
+      <path value="$PROJECT_DIR$/vendor/zx/php-tools" />
+      <path value="$PROJECT_DIR$/vendor/phpunit/php-invoker" />
+      <path value="$PROJECT_DIR$/vendor/phpunit/php-text-template" />
+      <path value="$PROJECT_DIR$/vendor/monolog/monolog" />
+      <path value="$PROJECT_DIR$/vendor/phpoption/phpoption" />
+      <path value="$PROJECT_DIR$/vendor/fig/http-message-util" />
+      <path value="$PROJECT_DIR$/vendor/markrogoyski/math-php" />
+      <path value="$PROJECT_DIR$/vendor/psr/simple-cache" />
+      <path value="$PROJECT_DIR$/vendor/psr/clock" />
+      <path value="$PROJECT_DIR$/vendor/psr/http-server-middleware" />
+      <path value="$PROJECT_DIR$/vendor/psr/cache" />
+      <path value="$PROJECT_DIR$/vendor/psr/http-message" />
+      <path value="$PROJECT_DIR$/vendor/psr/event-dispatcher" />
+      <path value="$PROJECT_DIR$/vendor/psr/container" />
+      <path value="$PROJECT_DIR$/vendor/psr/http-client" />
+      <path value="$PROJECT_DIR$/vendor/psr/http-server-handler" />
+      <path value="$PROJECT_DIR$/vendor/psr/http-factory" />
+      <path value="$PROJECT_DIR$/vendor/react/child-process" />
+      <path value="$PROJECT_DIR$/vendor/react/event-loop" />
+      <path value="$PROJECT_DIR$/vendor/react/stream" />
+      <path value="$PROJECT_DIR$/vendor/react/cache" />
+      <path value="$PROJECT_DIR$/vendor/openai-php/client" />
+      <path value="$PROJECT_DIR$/vendor/react/promise" />
+      <path value="$PROJECT_DIR$/vendor/react/socket" />
+      <path value="$PROJECT_DIR$/vendor/psr/log" />
+      <path value="$PROJECT_DIR$/vendor/lcobucci/jwt" />
+      <path value="$PROJECT_DIR$/vendor/react/dns" />
+      <path value="$PROJECT_DIR$/vendor/lcobucci/clock" />
+      <path value="$PROJECT_DIR$/vendor/phpseclib/phpseclib" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/database" />
+      <path value="$PROJECT_DIR$/vendor/mockery/mockery" />
+      <path value="$PROJECT_DIR$/vendor/ralouphie/getallheaders" />
+      <path value="$PROJECT_DIR$/vendor/phper666/jwt-auth" />
+      <path value="$PROJECT_DIR$/vendor/sebastian/lines-of-code" />
+      <path value="$PROJECT_DIR$/vendor/sebastian/object-enumerator" />
+      <path value="$PROJECT_DIR$/vendor/sebastian/type" />
+      <path value="$PROJECT_DIR$/vendor/sebastian/diff" />
+      <path value="$PROJECT_DIR$/vendor/sebastian/recursion-context" />
+      <path value="$PROJECT_DIR$/vendor/sebastian/environment" />
+      <path value="$PROJECT_DIR$/vendor/sebastian/version" />
+      <path value="$PROJECT_DIR$/vendor/death_satan/hyperf-validate" />
+      <path value="$PROJECT_DIR$/vendor/sebastian/complexity" />
+      <path value="$PROJECT_DIR$/vendor/sebastian/exporter" />
+      <path value="$PROJECT_DIR$/vendor/sebastian/cli-parser" />
+      <path value="$PROJECT_DIR$/vendor/sebastian/comparator" />
+      <path value="$PROJECT_DIR$/vendor/sebastian/code-unit" />
+      <path value="$PROJECT_DIR$/vendor/doctrine/deprecations" />
+      <path value="$PROJECT_DIR$/vendor/doctrine/annotations" />
+      <path value="$PROJECT_DIR$/vendor/doctrine/lexer" />
+      <path value="$PROJECT_DIR$/vendor/sebastian/object-reflector" />
+      <path value="$PROJECT_DIR$/vendor/stella-maris/clock" />
+      <path value="$PROJECT_DIR$/vendor/sebastian/global-state" />
+      <path value="$PROJECT_DIR$/vendor/sebastian/code-unit-reverse-lookup" />
+      <path value="$PROJECT_DIR$/vendor/graham-campbell/result-type" />
+      <path value="$PROJECT_DIR$/vendor/doctrine/instantiator" />
+      <path value="$PROJECT_DIR$/vendor/doctrine/inflector" />
+      <path value="$PROJECT_DIR$/vendor/nesbot/carbon" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/async-queue" />
+      <path value="$PROJECT_DIR$/vendor/carbonphp/carbon-doctrine-types" />
+      <path value="$PROJECT_DIR$/vendor/aws/aws-crt-php" />
+      <path value="$PROJECT_DIR$/vendor/aws/aws-sdk-php" />
+      <path value="$PROJECT_DIR$/vendor/mtdowling/jmespath.php" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/crontab" />
+    </include_path>
+  </component>
+  <component name="PhpProjectSharedConfiguration" php_language_level="8.1" />
+</project>

+ 6 - 0
.idea/vcs.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="VcsDirectoryMappings">
+    <mapping directory="" vcs="Git" />
+  </component>
+</project>

+ 23 - 5
.idea/workspace.xml

@@ -4,7 +4,11 @@
     <option name="autoReloadType" value="SELECTIVE" />
   </component>
   <component name="ChangeListManager">
-    <list default="true" id="f943e179-929c-4d98-8619-4423423ee73e" name="更改" comment="" />
+    <list default="true" id="f943e179-929c-4d98-8619-4423423ee73e" name="更改" comment="">
+      <change beforePath="$PROJECT_DIR$/.env" beforeDir="false" afterPath="$PROJECT_DIR$/.env" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/app/Controller/PublicController.php" beforeDir="false" afterPath="$PROJECT_DIR$/app/Controller/PublicController.php" afterDir="false" />
+    </list>
     <option name="SHOW_DIALOG" value="false" />
     <option name="HIGHLIGHT_CONFLICTS" value="true" />
     <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
@@ -200,11 +204,12 @@
       <path value="$PROJECT_DIR$/vendor/aws/aws-crt-php" />
       <path value="$PROJECT_DIR$/vendor/aws/aws-sdk-php" />
       <path value="$PROJECT_DIR$/vendor/mtdowling/jmespath.php" />
+      <path value="$PROJECT_DIR$/vendor/hyperf/crontab" />
     </include_path>
   </component>
-  <component name="ProjectColorInfo"><![CDATA[{
-  "associatedIndex": 3
-}]]></component>
+  <component name="ProjectColorInfo">{
+  &quot;associatedIndex&quot;: 3
+}</component>
   <component name="ProjectId" id="2qujtr8hxgPzTXMJ7F15U9bBHUB" />
   <component name="ProjectViewState">
     <option name="hideEmptyMiddlePackages" value="true" />
@@ -214,7 +219,7 @@
   "keyToString": {
     "RunOnceActivity.OpenProjectViewOnStart": "true",
     "RunOnceActivity.ShowReadmeOnStart": "true",
-    "git-widget-placeholder": "正在合并 dev",
+    "git-widget-placeholder": "master",
     "kotlin-language-version-configured": "true",
     "last_opened_file_path": "D:/wwwroot/zxt",
     "node.js.detected.package.eslint": "true",
@@ -245,10 +250,23 @@
       <option name="presentableId" value="Default" />
       <updated>1735519571105</updated>
       <workItem from="1735519572141" duration="10106000" />
+      <workItem from="1753958077075" duration="746000" />
+      <workItem from="1753960600078" duration="3129000" />
     </task>
     <servers />
   </component>
   <component name="TypeScriptGeneratedFilesManager">
     <option name="version" value="3" />
   </component>
+  <component name="Vcs.Log.Tabs.Properties">
+    <option name="TAB_STATES">
+      <map>
+        <entry key="MAIN">
+          <value>
+            <State />
+          </value>
+        </entry>
+      </map>
+    </option>
+  </component>
 </project>

+ 216 - 48
app/Controller/PublicController.php

@@ -10,6 +10,7 @@ use App\Tools\CommonService;
 use App\Tools\PublicData;
 use App\Tools\Result;
 use function Hyperf\Support\env;
+use function Hyperf\Coroutine\parallel;
 use Hyperf\Context\Context;
 use Hyperf\Di\Annotation\Inject;
 use Hyperf\HttpServer\Contract\RequestInterface;
@@ -348,7 +349,11 @@ class PublicController extends AbstractController
 
     public function downloadFile(RequestInterface $request, ResponseInterface $response)
     {
-        //验证是否有传参数
+        // 放开执行时限,避免大量文件导致的超时
+        ignore_user_abort(true);
+        @set_time_limit(0);
+
+        // 验证参数
         $requireData = $this->request->all();
         $validator = $this->validationFactory->make(
             $requireData,
@@ -363,72 +368,156 @@ class PublicController extends AbstractController
             $errorMessage = $validator->errors()->first();
             return Result::error($errorMessage);
         }
+
         $requireData['fileName'] = $requireData['fileName'] ?? '政讯通';
-        //打包文件
+
+        // 归一化文件与名称
+        /** @var array<int|string, string> $files */
+        $files = [];
+        if (is_array($requireData['files'])) {
+            // 保留原有索引,避免与 names 对应关系错位
+            $files = array_filter($requireData['files'], fn($v) => is_string($v) && $v !== '');
+        } elseif (is_string($requireData['files'])) {
+            $files = [$requireData['files']];
+        }
+        $names = [];
+        if (isset($requireData['names']) && is_array($requireData['names'])) {
+            $names = $requireData['names'];
+        }
+
+        if (count($files) === 0) {
+            return Result::error('文件不能为空');
+        }
+
+        // 预下载远程文件(并发)
+        $remoteIndexes = [];
+        foreach ($files as $index => $path) {
+            if (is_string($path) && filter_var($path, FILTER_VALIDATE_URL)) {
+                $remoteIndexes[] = $index;
+            }
+        }
+
+        $tempFiles = [];
+        if (!empty($remoteIndexes)) {
+            $concurrency = (int) env('ZIP_DOWNLOAD_CONCURRENCY', 5);
+            $tasks = [];
+            foreach ($remoteIndexes as $idx) {
+                $url = $files[$idx];
+                $tasks[] = function () use ($idx, $url) {
+                    $temp = $this->downloadRemoteToTemp($url);
+                    return [$idx, $temp];
+                };
+            }
+            try {
+                $results = parallel($concurrency, $tasks);
+                foreach ($results as $result) {
+                    if (is_array($result) && count($result) === 2) {
+                        [$i, $temp] = $result;
+                        if (is_string($temp) && $temp !== '' && is_file($temp)) {
+                            $tempFiles[$i] = $temp;
+                        }
+                    }
+                }
+            } catch (\Throwable $e) {
+                // 并发下载异常不终止,尽量继续处理其他文件
+            }
+        }
+
+        // 创建 ZIP 目录与文件
         $zip = new ZipArchive();
         $fileType = 'zip';
         $date = date('Ymd');
         $filePath = $fileType . DIRECTORY_SEPARATOR . $date;
         $allDir = 'public' . DIRECTORY_SEPARATOR . $filePath;
-        if (!is_dir($allDir)) {
-            if (!mkdir($allDir, 0755, true)) {
-                return Result::error('创建文件夹失败');
+        if (!is_dir($allDir) && !mkdir($allDir, 0755, true) && !is_dir($allDir)) {
+            // 清理已下载的临时文件
+            foreach ($tempFiles as $temp) {
+                @unlink($temp);
             }
+            return Result::error('创建文件夹失败');
         }
-        $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'])) {
-                $files = $requireData['files'];
-            } elseif (is_string($requireData['files'])) {
-                $files = [$requireData['files']];
+
+        $addedAny = false;
+        $zipOpened = false;
+        try {
+            if ($zip->open($zipFileName, ZipArchive::CREATE) !== true) {
+                return Result::error('无法创建zip文件');
             }
-            
-            foreach ($files as $key => $filePathu) {
-                if (!is_string($filePathu)) {
+            $zipOpened = true;
+
+            foreach ($files as $index => $originalPath) {
+                if (!is_string($originalPath) || $originalPath === '') {
                     continue;
                 }
-                
-                // 生成文件名:key + 1
-                $fileName = $requireData['names'][$key]; //($key + 1) . $this->getFileExtension($filePathu);
-                
-                // 处理远程URL文件
-                if (filter_var($filePathu, FILTER_VALIDATE_URL)) {
-                    $this->addRemoteFileToZip($zip, $filePathu, $fileName);
-                } else {
-                    // 处理本地文件
-                    if (!file_exists($filePathu)) {
-                        // 尝试添加public前缀
-                        $fullPath = 'public/' . $filePathu;
+
+                // 决定压缩包内的文件名
+                $zipInnerName = $names[$index] ?? '';
+                if (!is_string($zipInnerName) || $zipInnerName === '') {
+                    if (filter_var($originalPath, FILTER_VALIDATE_URL)) {
+                        $zipInnerName = basename(parse_url($originalPath, PHP_URL_PATH) ?: ('file_' . ($index + 1) . $this->getFileExtension($originalPath)));
+                    } else {
+                        $zipInnerName = basename($originalPath);
+                        if ($zipInnerName === '' || $zipInnerName === '.' || $zipInnerName === '..') {
+                            $zipInnerName = 'file_' . ($index + 1) . $this->getFileExtension($originalPath);
+                        }
+                    }
+                }
+
+                // 远程:使用预下载的临时文件
+                if (array_key_exists($index, $tempFiles)) {
+                    $tempPath = $tempFiles[$index];
+                    if (is_file($tempPath) && is_readable($tempPath)) {
+                        if ($zip->addFile($tempPath, $zipInnerName)) {
+                            $addedAny = true;
+                        }
+                    }
+                    continue;
+                }
+
+                // 本地文件处理
+                $localPath = $originalPath;
+                if (!file_exists($localPath)) {
+                    // 尝试添加 public 前缀
+                    $fullPath = 'public/' . ltrim($localPath, '/');
+                    if (!file_exists($fullPath)) {
+                        // 尝试使用绝对路径
+                        $fullPath = BASE_PATH . '/public/' . ltrim($localPath, '/');
                         if (!file_exists($fullPath)) {
-                            // 尝试使用绝对路径
-                            $fullPath = BASE_PATH . '/public/' . $filePathu;
-                            if (!file_exists($fullPath)) {
-                                continue; // 跳过不存在的文件
-                            }
+                            continue; // 跳过不存在的文件
                         }
-                        $filePathu = $fullPath;
                     }
-                    
-                    // 确保文件存在且可读
-                    if (is_file($filePathu) && is_readable($filePathu)) {
-                        $zip->addFile($filePathu, $fileName);
+                    $localPath = $fullPath;
+                }
+
+                if (is_file($localPath) && is_readable($localPath)) {
+                    if ($zip->addFile($localPath, $zipInnerName)) {
+                        $addedAny = true;
                     }
                 }
             }
-            // 关闭zip文件
-            $zip->close();
-            // 将zip文件提供给用户进行下载
-            $fileUrlName = explode("public", $zipFileName);
-            return Result::success(['fileUrl' => env('HOST') . $fileUrlName[1]]);
-        } else {
-            return Result::error('无法创建zip文件');
+        } finally {
+            // 关闭 zip
+            if ($zipOpened) {
+                $zip->close();
+            } elseif (file_exists($zipFileName) && filesize($zipFileName) === 0) {
+                // 若未成功打开或写入,确保不会遗留空文件
+                @unlink($zipFileName);
+            }
+            // 清理临时文件
+            foreach ($tempFiles as $temp) {
+                @unlink($temp);
+            }
+        }
+
+        if (!$addedAny || !file_exists($zipFileName)) {
+            return Result::error('打包失败或没有可用的文件');
         }
+
+        // 返回可下载地址
+        $fileUrlName = explode('public', $zipFileName);
+        return Result::success(['fileUrl' => env('HOST') . $fileUrlName[1]]);
     }
     
     /**
@@ -568,6 +657,85 @@ class PublicController extends AbstractController
         return $content;
     }
     
+    /**
+     * 下载远程文件到临时文件(流式写入,节省内存),成功返回临时文件路径,失败返回 null
+     */
+    private function downloadRemoteToTemp(string $url, int $timeoutSeconds = 120): ?string
+    {
+        // 优先使用 cURL 流式写入
+        if (function_exists('curl_init')) {
+            $tempFile = tempnam(sys_get_temp_dir(), 'remote_file_');
+            if ($tempFile === false) {
+                return null;
+            }
+            $fp = @fopen($tempFile, 'wb');
+            if ($fp === false) {
+                @unlink($tempFile);
+                return null;
+            }
+            $ch = curl_init();
+            curl_setopt_array($ch, [
+                CURLOPT_URL => $url,
+                CURLOPT_FILE => $fp, // 直接写文件
+                CURLOPT_FOLLOWLOCATION => true,
+                CURLOPT_MAXREDIRS => 5,
+                CURLOPT_CONNECTTIMEOUT => 30,
+                CURLOPT_TIMEOUT => $timeoutSeconds,
+                CURLOPT_SSL_VERIFYPEER => false,
+                CURLOPT_SSL_VERIFYHOST => false,
+                CURLOPT_USERAGENT => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
+                CURLOPT_HTTPHEADER => [
+                    'Accept: */*',
+                    'Connection: keep-alive',
+                    'Cache-Control: no-cache',
+                ],
+            ]);
+            $ok = curl_exec($ch);
+            $httpCode = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
+            curl_close($ch);
+            fclose($fp);
+
+            if ($ok !== false && $httpCode === 200 && is_file($tempFile) && filesize($tempFile) >= 100) {
+                return $tempFile;
+            }
+            @unlink($tempFile);
+        }
+
+        // 退化为 stream_context + file_get_contents 方案
+        $context = stream_context_create([
+            'http' => [
+                'timeout' => $timeoutSeconds,
+                '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: */*',
+                    'Connection: keep-alive'
+                ],
+            ],
+            'ssl' => [
+                'verify_peer' => false,
+                'verify_peer_name' => false,
+                'allow_self_signed' => true,
+            ],
+        ]);
+        $content = @file_get_contents($url, false, $context);
+        if ($content === false || strlen((string) $content) < 100) {
+            return null;
+        }
+        $tempFile = tempnam(sys_get_temp_dir(), 'remote_file_');
+        if ($tempFile === false) {
+            return null;
+        }
+        $bytes = @file_put_contents($tempFile, $content);
+        if ($bytes === false || $bytes < 100) {
+            @unlink($tempFile);
+            return null;
+        }
+        return $tempFile;
+    }
+    
     /**
      * 获取文件扩展名
      */