PHP:获取文件扩展名不能上传到S3

jQu*_*ast 9 php file-extension file-upload amazon-s3

我使用Amazon S3 API上传文件,每次上传时我都会更改文件名.

例如:

Dog.png> 3Sf5f.png

现在我得到了随机部分:

function rand_string( $length ) {
            $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";  

            $size = strlen( $chars );
            for( $i = 0; $i < $length; $i++ ) {
                $str .= $chars[ rand( 0, $size - 1 ) ];
            }

            return $str;
        }   
Run Code Online (Sandbox Code Playgroud)

所以我将random_string设置为name参数:

$params->key = rand_string(5);
Run Code Online (Sandbox Code Playgroud)

现在我的问题是,这不会显示任何扩展.所以文件将上传3Sf5f而不是3Sf5f.png.

变量$ filename为我提供了文件的全名及其扩展名.

如果我使用$params->key = rand_string(5).'${filename}';我得到:

3Sf5fDog.png
Run Code Online (Sandbox Code Playgroud)

所以我试图检索$ filename扩展并应用它.我尝试了30多种方法而没有任何积极的方法.

例如,我尝试了$ path_info(),我尝试了substr(strrchr($ file_name,'.'),1); 还有更多.所有这些都给了我3Sf5fDog.png或者只是3Sf5f.

我试过的一个例子:

// As @jcinacio pointed out. Change this to: 
//
//   $file_name = "${filename}";
//
$file_name = '${filename}'  // Is is wrong, since '..' does not evaluate 

$params->key = rand_string(5).$file_name;
=
3Sf5fDog.png
Run Code Online (Sandbox Code Playgroud)

.

$file_name = substr(strrchr('${filename}', '.'), 1);

$params->key = rand_string(5).$file_name;
=
3Sf5f
Run Code Online (Sandbox Code Playgroud)

.

$filename = "example.png"   // If I declare my own the filename it works.
$file_name = substr(strrchr('${filename}', '.'), 1);

$params->key = rand_string(5).$file_name;
=
3Sf5f.png
Run Code Online (Sandbox Code Playgroud)

整个类文件:http://pastebin.com/QAwJphmW(整个脚本没有其他文件).

我做错了什么?这真令人沮丧.

Rob*_*bie 8

变量$ filename(以及因此"$ {filename}")在代码的第1053行不在范围内(基于来自pastebin的原始粘贴的行编号).

所以,无论你做什么,你都永远找不到不存在的变量的扩展.


我终于找到了你正在做的事情.我认为这是PHP的扩展:在上传之前重命名文件

简单的回答:你不能按照你设想的那样去做.为什么 - 在创建URL时不解析'$ filename',但是变量被传递到Amazon S3并在那里处理.

解决方案

因此,我能想到的唯一选择是使用"successRedirect"参数指向另一个URL.该URL将从Amazon(http://doc.s3.amazonaws.com/proposals/post.html#Dealing_with_Success)接收"bucket"和"key"作为查询参数.指向在Amazon S3上重命名文件的PHP脚本(复制+删除),然后将用户重定向到另一个成功屏幕.

所以,

在你的代码中,第34行,

  1. 将一个完全限定的URL添加到您要编写的新PHP脚本文件中.
  2. php脚本将获取桶和密钥传递给它
  3. 从"密钥"创建新文件名
  4. 使用函数"public static function copyObject($ srcBucket,$ srcUri,$ bucket,$ uri)"将上传的文件复制到新名称
  5. 然后删除原始文件(使用deleteObject($ bucket,$ uri))
  6. 然后将用户重定向到您要发送它们的位置

这将完全符合你的要求.


回应您的意见"这是唯一的方式 - 亚马逊每次请求的费用是多少?"

删除请求是免费的.在同一个桶(甚至是同一个区域)上移动时没有数据传输成本.所以这个解决方案(这是没有你转移到中间服务器,重命名和上传的唯一方法)它将上传a的成本从每1000上传1c上传到每1000上传2c的成本加倍.我花了10分钟@ 200美元/小时来找到它并回复= $ 33 = 1,666,666上传!当你做数学时,成本有点苍白:)

与其他解决方案比较:对网络服务器发帖,重命名文件,然后从网络服务器上传:你将所有带宽从clinet直接移动到你自己 - 两次.这也会带来风险并增加可能的失败点.


响应"不工作.我上传文件然后删除旧文件"

我会认为这不是问题,因为你上传文件然后在一两秒内重命名它.但是如果你想要保证每个文件都被上传,那么你需要做的不仅仅是创建一个随机文件名:

  1. 拥有你的"最终"桶
  2. 对于每次上传,创建一个临时存储桶(如果您担心成本,则每1000个存储桶1c)
  3. 上传到临时存储桶
  4. 创建随机名称,检查最终存储桶中是否不存在(每1000次检查1c)
  5. 将文件复制到最终存储桶(使用新名称)
  6. 删除上传的文件以及存储桶.
  7. 定期清理文件上传未完成的存储桶.


小智 3

$fileSplit = explode('.',$filename);
$extension = '.'.$fileSplit[count($fileSplit) - 1];
Run Code Online (Sandbox Code Playgroud)

这个explode()将文件名分成一个以句点作为分隔符的数组,然后抓取数组的最后一部分(如果文件名是foo.bar.jpg),并在它前面放一个句点。这应该会为您提供所需的扩展名,并将其附加到 rand_string(5) 中。

$params->key = rand_string(5).$extension;
Run Code Online (Sandbox Code Playgroud)