Как я могу хранить загруженные изображения в AWS S3 на PHP

Я использую инстанс EC2 и хочу связать свой веб-сайт PHP с корзиной Amazon S3. Я уже видел API для PHP здесь: 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, как было предложено, поэтому я установил его, как описано здесь (у меня ОС 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

Все правильно установилось, но что дальше? Где я должен объявить учетные данные и как я могу использовать эту интеграцию в своем проекте?

2-е ОБНОВЛЕНИЕ

Я создал файл с именем .passwd-s3fs с одной строкой кода с моими учетными данными IAM accessKeyId:secretAccessKey.

Я помещаю его в свой каталог home/ubuntu и даю ему разрешение 600 с помощью chmod 600 ~/.passwd-s3fs

Далее из консоли я запускаю /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

3-е ОБНОВЛЕНИЕ

Как и было предложено, я запускаю этот 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 апреля 2015 г.

По предложению из консоли я запускаю sudo usermod -a -G fuse ubuntu и sudo 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 или -rf или mv -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?


person NineCattoRules    schedule 05.04.2015    source источник


Ответы (4)


Несмотря на то, что «S3fs очень надежен в последних сборках», я могу поделиться своим собственным опытом работы с s3fs и информацией о том, что мы перенесли операцию записи из прямого доступа к смонтированной папке s3fs в консоль aws (также возможен способ SDK API) после периодических случайных сбоев системы.

Возможно, у вас не будет проблем с файлами небольшого размера, такими как изображения, но это, безусловно, создало проблему, когда мы пытались записать файлы mp4. Итак, последнее сообщение в журнале перед сбоем системы было:

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

и это были редкие случайные случаи, но это делало систему нестабильной.

Поэтому мы решили оставить s3fs смонтированным, но использовать его только для чтения.

Ниже я покажу, как смонтировать s3fs с учетными данными AIM без файла пароля.

#!/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 (в другом ответе уже есть пример использования), но вы также можете записывать изображения в s3 с помощью консоли aws:

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: Если вам не нужен этап локального хранения файлов, но вы поставите прямо из формы загрузки:

 $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);

Или создайте подписанный URL-адрес для частного контента:

$validTime = '+10 minutes';
$signedUrl = $s3Client->getObjectUrl($bucket, $keyname, $validTime);
person Evgeniy Kuzmin    schedule 17.04.2015
comment
спасибо за предложение ... Мне нравится использовать php sdk, но я не знаю, как это сделать, вы говорите, что мне не нужно включать фабричный метод для объявления моих учетных данных IAM? Можно ли создать переменную для URL-адреса корзины и использовать ее как: my_s3_bucket='http://link/to/my/s3, а затем $thisFu['original_img']='my_s3_bucket/uploads/fufu/'.$_POST['cat'].'/original_'.uniqid('fu_').'.jpg';? - person NineCattoRules; 18.04.2015
comment
Извините за задержку, но я не получаю уведомления о новом обновлении. Вау, спасибо за ваше отличное и подробное объяснение, это кажется таким простым ... вместо этого несколько дней назад я попробовал с s3fs, и теперь моя папка для загрузки скрыта и недоступна каким-либо образом (вы можете прочитать мое 4-е обновление выше). Я хочу попробовать этот метод, но пока у меня не возникнет проблема с моей папкой для загрузки, я даже не могу попробовать. - person NineCattoRules; 19.04.2015
comment
Я думаю, что если я просто отредактирую пост, то уведомление не придет... Я был рад, что информация была полезной для вас :) о вашей проблеме в обновлении 4: я немного потерял, в чем именно ваша проблема? Отключить s3fs? Почему вы не можете просто зайти в исходную папку и сделать: sudo make uninstall? Кстати, я вижу, вы упомянули некоторые проблемы с разрешениями, вы делали команды от root или sudo? - person Evgeniy Kuzmin; 19.04.2015
comment
Я запускал команды из sudo ... теперь я вошел в папку s3fs-fuse и запускаю sudo make uninstall, но, похоже, ничего не изменилось, папка есть, но скрыта, и я не могу ее удалить, действительно, я пытался удалить, и я получил sudo rm -R rm: cannot remove ‘fufu’: Is a directory, чем я попытался также изменить владельца папки, и я получил Transport endpoint is not connected - person NineCattoRules; 19.04.2015
comment
Я пытался sudo service apache2 restart... как вы думаете, стоит ли перезагружать экземпляр? - person NineCattoRules; 19.04.2015
comment
apache ничего не знает о s3fs, перезагрузите свой экземпляр - person Evgeniy Kuzmin; 19.04.2015
comment
Вы просто восхитительны! Грустно, что ты пришел сюда слишком поздно для моей щедрости - person NineCattoRules; 19.04.2015

Я согласен, что документация по этой ссылке немного сложна для понимания и оставляет много точек для связи.

Однако здесь я нашел кое-что получше: http://docs.aws.amazon.com/aws-sdk-php/v2/guide/service-s3.html

В нем есть примеры кода и инструкции почти для всех операций S3.

person Noman Ur Rehman    schedule 05.04.2015
comment
Привет, после подключения, как я могу автоматически загружать в корзину картинки, которые загружают пользователи? Мой код выглядит так: $this['original_img'] = '/uploads/img/'.$_POST['cat'].'/original_'.uniqid('my_').'.jpg'; Спасибо. - person NineCattoRules; 05.04.2015
comment
@Simone Вы видели раздел загрузки файла на этой странице? - person Noman Ur Rehman; 05.04.2015
comment
@Simone Что вы подразумеваете под константой для использования в URL-адресе? Вы можете указать параметры функции, чтобы сделать файл общедоступным или частным. - person Noman Ur Rehman; 05.04.2015
comment
Как я уже писал, я новичок, я не знаю, какой правильный путь для загрузки изображений в s3... что я должен кодировать перед /upload/img/? - person NineCattoRules; 05.04.2015
comment
Привет, я изменил свой вопрос, не могли бы вы изменить свой голос? Спасибо - person NineCattoRules; 06.04.2015

Чтобы дать вам немного больше ясности, так как вы новичок: загрузите SDK AWS через этот Руководство по установке

Затем настройте клиент своей учетной записи AWS на своем веб-сервере PHP, используя этот бит.

use Aws\S3\S3Client;

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

Если вам нужна дополнительная информация об использовании файлов учетных данных AWS, идите сюда.

Затем, чтобы загрузить файл, который у вас есть на вашем собственном PHP-сервере:

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

Если вам интересно узнать, как загружать изображения в php-файл, я бы порекомендовал посмотреть эту школу W3. учебник. Этот учебник может помочь вам приступить к сохранению файла локально на вашем сервере во временном каталоге, прежде чем он будет загружен в корзину S3.

person Erik    schedule 15.04.2015
comment
Наконец кто-то! Спасибо за ответ, однако я не могу установить ничего подобного, ведь я на Amazon EC2... это так сложно вручную? Я подумал, что достаточно взять все папки и поместить в корень :) - person NineCattoRules; 16.04.2015
comment
В первой ссылке для установки SDK перейдите к инструкции Install from zip и вместо строки use Aws\S3\S3Client; используйте require '/path/to/aws-autoloader.php'; - person Erik; 16.04.2015
comment
Это понятно, но где я должен разместить в своем проекте? У меня есть собственный фреймворк, поместить ли его в корневую папку? или папка администратора возможно? Какая разница, если есть - person NineCattoRules; 16.04.2015
comment
Разместите его там, где вы хотите, внутри вашего каталога с кодом PHP, который вы используете! - person Erik; 16.04.2015
comment
:D ок, это здорово... Я спросил только из соображений безопасности - person NineCattoRules; 16.04.2015
comment
извините, почему бы не ввести напрямую, как показано здесь: docs.aws.amazon.com/aws-sdk-php/v2/guide/ - person NineCattoRules; 16.04.2015
comment
я не знаю, что ты имеешь в виду - person Erik; 16.04.2015
comment
Давайте продолжим обсуждение в чате. - person Erik; 16.04.2015

Гораздо проще и прозрачнее для настройки вашего приложения просто смонтировать раздел s3 с помощью s3fs.

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

из примера about я бы предположил, что ваш mnt_dir будет /uploads/fufu

so 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

person exussum    schedule 17.04.2015
comment
Спасибо, значит, таким образом я не могу использовать Cloudfront в качестве CDN? Я активировал Cloudfront и для происхождения я поместил свое ведро - person NineCattoRules; 17.04.2015
comment
Если единственное изменение, которое вы делаете, это использование s3fs, то да, вы можете записать образ на s3 с помощью s3fs, а затем использовать ссылки Cloudfront с API. Но потребуются изменения кода - person exussum; 17.04.2015
comment
Хорошо, я на последнем шаге, так что мне нужно добавить фиксированную точку монтирования в /etc/fstab? Мне нужно сделать ведро общедоступным, правильно ли это? s3fs#mybucket /uploads/fufu fuse allow_other 0 0 - person NineCattoRules; 17.04.2015
comment
Я попробовал из консоли команду, которую я разместил здесь выше, я получил эту ошибку: s3fs#elasticbeanstalk-eu-west-1-(my number): command not found - person NineCattoRules; 17.04.2015
comment
нет хеша, просто s3fs -o allow_other mybucket /ubloads/fufu убедитесь, что он работает из командной строки перед добавлением в fstab - person exussum; 17.04.2015
comment
хорошо, я получил это сообщение: s3fs: MOUNTPOINT directory /uploads/fufu is not empty. s3fs: if you are sure this is safe, can use the 'nonempty' mount option. Что я могу сделать? - person NineCattoRules; 17.04.2015
comment
Я нашел это решение - person NineCattoRules; 17.04.2015
comment
Я попытался с -o nonempty и получил другую ошибку: s3fs: unable to access MOUNTPOINT elasticbeanstalk-eu-west-1-(my number): No such file or directory - person NineCattoRules; 17.04.2015
comment
в каталоге уже есть файлы? попробуйте mv /uploads/fufu /uploads/fufu.old; mkdir /uploads/fufu;, затем повторите команду s3fs - person exussum; 17.04.2015
comment
Я забыл проверить папку... теперь все мои папки ведра находятся в /uploads/fufu, но когда я запускаю команду s3fs, я снова получаю это сообщение об ошибке. - person NineCattoRules; 17.04.2015
comment
непустая команда, вероятно, не помогла. попробуйте размонтировать s3fs (fusermount -u /uploads/fufu), подтвердите, что он больше не смонтирован (не отображается в выводе df), убедитесь, что в папке ничего не существует. (ls -la) нет ничего, повторите команду s3fs. После этого все должно работать. Ивед отредактировал мой ответ. с пустым каталогом вам не нужна непустая опция - person exussum; 17.04.2015
comment
Давайте продолжим обсуждение в чате. - person exussum; 17.04.2015
comment
Кажется, отсутствует аргумент (ковш для монтирования). Удалите все записи, которые автоматически монтируют его. Монтируйте с помощью командной строки, пока ваш gaooy не заработает. - person exussum; 19.04.2015
comment
Извините, но что вы имели в виду под всеми входами? Вы говорите об удалении строки внутри mtab? Я пробовал, но ничего не изменилось - person NineCattoRules; 19.04.2015