如何在PHP上将上传的图像存储到AWS S3

时间:2015-04-05 12:41:37

标签: amazon-web-services amazon-s3 s3fs

我正在使用EC2实例,我希望将我的PHP网站与我的Amazon S3存储桶连接起来,我已经在这里看到了PHP的API:http://aws.amazon.com/sdkforphp/但是还不清楚。

这是我需要在控制器中编辑的代码行:

thisFu['original_img']='/uploads/fufu/'.$_POST['cat'].'/original_'.uniqid('fu_').'.jpg';

我需要连接到Amazon S3并能够像这样更改代码:

$thisFu['original_img']='my_s3_bucket/uploads/fufu/'.$_POST['cat'].'/original_'.uniqid('fu_').'.jpg';

我已经为此目的配置了一个IAM用户,但我不知道完成这项工作所需的所有步骤。

我如何连接Amazon S3并与之交互以上传和检索公共图像?

更新

我决定尝试按照建议使用s3fs,所以我按照here所述安装了它(我的操作系统是Ubuntu 14.04)

我从控制台运行:

sudo apt-get install build-essential git libfuse-dev libcurl4-openssl-dev libxml2-dev mime-support automake libtool
sudo apt-get install pkg-config libssl-dev
git clone https://github.com/s3fs-fuse/s3fs-fuse
cd s3fs-fuse/
./autogen.sh
./configure --prefix=/usr --with-openssl
make
sudo make install

一切都已正确安装,但下一步是什么?我应该在哪里申报凭证,我如何在项目中使用此集成?

第二次更新

我使用单个代码行创建了一个名为.passwd-s3fs的文件,其中包含我的IAM凭据accessKeyId:secretAccessKey

我将其放入我的home/ubuntu目录,并使用chmod 600 ~/.passwd-s3fs

授予其600权限

接下来从控制台我运行/usr/bin/s3fs My_S3bucket /uploads/fufu

/uploads/fufu内,现在有我所有的桶文件夹。但是当我尝试这个命令时:

s3fs -o nonempty allow_other My_S3bucket /uploads/fufu

我收到此错误消息:

s3fs: unable to access MOUNTPOINT My_S3bucket : No such file or directory

第三次更新

根据建议我运行此fusermount -u /uploads/fufu,之后我检查了fufu文件夹,并且按预期为空。 之后我又尝试了这个命令(还有一个-o):

s3fs -o nonempty -o allow_other My_S3bucket /uploads/fufu

并收到此错误消息:

fusermount: failed to open /etc/fuse.conf: Permission denied
fusermount: option allow_other only allowed if 'user_allow_other' is set in /etc/fuse.conf

还有其他建议吗?

第4次更新 18/04/15

根据控制台的建议我运行sudo usermod -a -G fuse ubuntusudo vim /etc/fuse.conf我取消注释mount_max = 1000和user_allow_other

比我运行s3fs -o nonempty -o allow_other My_S3bucket / uploads / fufu

乍一看没有错误,所以我认为一切都很好,但恰恰相反。

我现在有点沮丧,因为我不知道发生了什么,但我的文件夹/uploads/fufu被隐藏并使用ls -Al我只看到了这个

d????????? ? ?        ?              ?            ? fufu

我不能sudo rm -r-rfmv -r它说/uploads/fufu is a directory

我尝试reboot exit and mount -a,但没有尝试。

我尝试使用fusermount卸载,错误消息为fusermount: entry for /uploads/fufu not found in /etc/mtab

但我尝试了sudo vim / etc / mtab,我找到了这一行:s3fs /uploads/fufu fuse.s3fs rw,nosuid,nodev,allow_other 0 0

有人可以告诉我如何卸载并最终删除此文件夹/uploads/fufu

4 个答案:

答案 0 :(得分:1)

我同意该链接上的文档有点难以挖掘,并留下了很多要连接的点。

但是,我在这里找到了更好的东西:http://docs.aws.amazon.com/aws-sdk-php/v2/guide/service-s3.html

它包含几乎所有S3操作的示例代码和说明。

答案 1 :(得分:1)

为了让您更加清晰,因为您是初学者:通过此Installation Guide下载AWS SDK

然后使用此位

在PHP网络服务器上设置您的AWS账户客户端
use Aws\S3\S3Client;

$client = S3Client::factory(array('profile' => '<profile in your aws credentials file>'
));

如果您想了解有关如何使用AWS凭据文件的更多信息,请head here.

然后上传您自己的PHP服务器上的文件:

$result = $client->putObject(array(
'Bucket'     => $bucket,
'Key'        => 'data_from_file.txt',
'SourceFile' => $pathToFile,
'Metadata'   => array(
    'Foo' => 'abc',
    'Baz' => '123'
)
));

如果您有兴趣学习如何将图像上传到php文件,我建议您查看this W3 schools tutorial.本教程可帮助您开始在服务器本地保存文件之前的临时目录它会上传到您的S3存储桶。

答案 2 :(得分:1)

您的应用程序设置更容易和透明,只需使用s3fs

安装s3分区即可

https://github.com/s3fs-fuse/s3fs-fuse

(使用选项allow_other) 您的s3fs然后表现得像普通文件夹只会将文件移动到该文件夹​​。 S3fs然后上传

S3fs在最近的版本中非常可靠

你也可以用这种方式阅读图片,但是松散了AWS CDN的任何影响,虽然上次我试过它并没有太大的区别

你需要一个s3fspassword文件

格式 accessKeyId:secretAccessKey

它可以在这些地方中的任何一个

using the passwd_file command line option
setting the AWSACCESSKEYID and AWSSECRETACCESSKEY environment variables
using a .passwd-s3fs file in your home directory
using the system-wide /etc/passwd-s3fs file

该文件需要600个权限

https://github.com/s3fs-fuse/s3fs-fuse/wiki/Fuse-Over-Amazon

有一些信息。

完成后,命令为s3fs bucket_name mnt_dir

你可以在这里找到钥匙

https://console.aws.amazon.com/iam/home?#security_credential

从示例中我将假设您的mnt_dir/uploads/fufu

所以s3fs bucket /uploads/fufu

到你的第二个问题

s3fs -o nonempty allow_other My_S3bucket /uploads/fufu

错误,您需要再次指定-o

s3fs -o nonempty -o allow_other My_S3bucket /uploads/fufu

您正在安装的用户需要位于保险丝组中

sudo usermod -a -G fuse your_user

或     sudo addgroup your_user fuse

答案 3 :(得分:1)

尽管“S3fs在最近的版本中非常可靠”,但我可以分享自己的经验与s3fs和info,我们将写操作从直接的s3fs挂载文件夹访问到aws控制台(SDK api可能的方式)也定期随机系统崩溃。

你可能不会对像图像这样的小尺寸文件有任何问题,但是当我们尝试编写mp4文件时它肯定会出现问题。所以在系统崩溃之前的日志中的最后一条消息是:

kernel: [ 9180.212990] s3fs[29994]: segfault at 0 ip 000000000042b503 sp 00007f09b4abf530 error 4 in s3fs[400000+52000]

并且这是罕见的随机情况,但这使得系统不稳定。

所以我们决定继续安装s3fs,但仅将其用于读取访问

下面我将展示如何在没有密码文件的情况下使用AIM凭据挂载s3fs

#!/bin/bash -x
S3_MOUNT_DIR=/media/s3
CACHE_DIR=/var/cache/s3cache

wget http://s3fs.googlecode.com/files/s3fs-1.74.tar.gz
tar xvfz s3fs-1.74.tar.gz
cd s3fs-1.74
./configure
make
make install

mkdir $S3_MOUNT_DIR
mkdir $CACHE_DIR

chmod 0755 $S3_MOUNT_DIR
chmod 0755 $CACHE_DIR

export IAMROLE=`curl http://169.254.169.254/latest/meta-data/iam/security-credentials/`

/usr/local/bin/s3fs $S3_BUCKET $S3_MOUNT_DIR  -o iam_role=$IAMROLE,rw,allow_other,use_cache=$CACHE_DIR,uid=222,gid=500

此外,您还需要创建分配给具有附加策略的实例的IAM角色:

{"Statement":[{"Resource":"*","Action":["s3:*"],"Sid":"S3","Effect":"Allow"}],"Version":"2012-10-17"}

在你的情况下,似乎使用php sdk是合理的(其他答案已经有用法示例),但你也可以用aws控制台将图像写入s3:

aws s3 cp /path_to_image/image.jpg s3://your_bucket/path

如果您将创建IAM角色并将其分配给您的实例,则无需提供任何其他凭据

更新 - 回答您的问题:

  • 我不需要包含声明我的IAM凭证的工厂方法吗?

是的,如果你将IAM分配给ec2实例,那么在代码中你只需要创建客户端:

     $s3Client = S3Client::factory();
     $bucket = 'my_s3_bucket';
     $keyname = $_POST['cat'].'/original_'‌​.uniqid('fu_').'.jpg';
     $localFilePath = '/local_path/some_image.jpg';

 $result = $s3Client->putObject(array(
        'Bucket' => $bucket,
        'Key'    => $keyname,
        'SourceFile'   => $filePath,
        'ACL'    => 'public-read',
        'ContentType' => 'image/jpeg'
    ));
    unlink($localFilePath);

选项2:如果您不需要文件本地存储阶段,但会从上传表单中放置direclt:

 $s3Client = S3Client::factory();
 $bucket = 'my_s3_bucket';
 $keyname = $_POST['cat'].'/original_'‌​.uniqid('fu_').'.jpg';
 $dataFromFile = file_get_contents($_FILES['uploadedfile']['tmp_name']); 

$result = $s3Client->putObject(array(
    'Bucket' => $bucket,
    'Key'    => $keyname,
    'Body' => $dataFromFile,
    'ACL'    => 'public-read',
));

如果您有公共访问权限,则获取s3链接

$publicUrl = $s3Client->getObjectUrl($bucket, $keyname);

或者为私人内容生成签名网址:

$validTime = '+10 minutes';
$signedUrl = $s3Client->getObjectUrl($bucket, $keyname, $validTime);