多个图像上传到 s3 在 heroku 故障时使用 laravel



我正在尝试循环访问多个输入文件选择元素

<label class="btn btn-success btn-md rounded-1" for="galleryFile">Create Album</label>
<input type="file" name="galleryFile[]" id="galleryFile" class="d-none" multiple accept="image/*">

并将所有选定的映像保存到 AWS s3

public function sendToCloud($file, $folder, $prefix) {
$filePath = Auth::user()->userid . '/' .$folder.'/' . $prefix;
$extension = $file->getClientOriginalExtension();
$filename  = $filePath . time() . '.' . $extension;
Storage::disk('s3')->put($filename, fopen($file, 'r+'), 'public');
return Storage::disk('s3')->url($filename);
}
$unikPath = uniqid();
foreach ($request->file('galleryFile') as $key => $file) {
if ($key == array_key_last($request->file('galleryFile'))) {
$galleryUrl .= $this->sendToCloud($file, $unikPath . '/gallery', 'img_');
} else {
$galleryUrl .= $this->sendToCloud($file, $unikPath . '/gallery', 'img_') . ' | ';
}
}

在我的本地机器上,它工作得很好,让我相信这不是我的代码或 laravel 单独的问题,但是当我部署到 heroku 时,上传行为发生了变化。它在 heroku 上的作用是

如果我选择要上传的 10 张图像,它会随机选择其中 2 张图像并将其保存到 S3 中,并返回这 3 张图像的 S10 URL。

我感谢任何关于如何解决此问题的正确方向的帮助。

提前谢谢。

在我发布这个答案时,你已经写了一个答案来解释你的解决方案。 然而,更好的解决方案是——

  1. 使用random_bytes(连同bin2hex(而不是uniqid生成随机文件名,以及
  2. 检查您是否使用fopen($file, ...)打开了现有文件,如果是,请生成不同的文件名以避免覆盖现有文件名。

此外,您在答案中给出的解决方案是脆弱的 - 它假设在应用程序运行时系统时间永远不会更改,由于许多原因,情况可能并不总是如此,包括服务器时钟同步。另请参阅uniqid的文档。

更新的答案

听从 @Peter O 的建议,我使用bin2hex(random_bytes(7))为每个文件生成唯一的名称。这可以防止图像被下一个图像覆盖,而无需sleep(1)

public function sendToCloud($file, $folder, $prefix) {
$filePath = Auth::user()->userid . '/' .$folder.'/' . $prefix;
$extension = $file->getClientOriginalExtension();
$filename  = $filePath . bin2hex(random_bytes(7)) . '.' . $extension;
Storage::disk('s3')->put($filename, fopen($file, 'r+'), 'public');
return Storage::disk('s3')->url($filename);
}

以前的答案

所以我能够解决这个问题。经过多次试验,我意识到所有图像实际上都在处理并发送到 s3,但我只能看到两个,因为处理速度使图像覆盖了以前具有相同名称的图像。

如何?

PHPuniqid()函数根据微时间生成一个唯一的 ID,三个图像可以同时处理,这意味着它们都将基于 uniqid(( 函数具有相同的值。

我是如何解决的

我在foreach循环中添加了一个 sleep 函数,将执行延迟 1 秒,让程序有时间生成新的唯一名称。

foreach ($request->file('galleryFile') as $key => $file) {
if ($key == array_key_last($request->file('galleryFile'))) {
$galleryUrl .= $this->sendToCloud($file, $unikPath . '/gallery', 'img_');
} else {
$galleryUrl .= $this->sendToCloud($file, $unikPath . '/gallery', 'img_') . ' | ';
sleep(1);
}
}

我希望有一天这对某人有所帮助。

最新更新