Я использую Amazon s3, но здесь я столкнулся с двумя проблемами
1. Я не могу напрямую загружать файлы на сервер амазонки, когда я отправляю форму. Я имею в виду, что мне нужно загружать изображения для загрузки папки, а оттуда мне нужно загрузить и загрузить на s3 server
Есть ли способ загружать изображения напрямую, когда мы нажимаем на Отправить ?
2.if я передаю 'public'
в s3 put object
тогда только я могу получить доступ или просматривать файлы, но если я сделаю его общедоступным, каждый может просматривать файлы, но мне нужно защитить все файлы и просмотреть только для аутентифицированного пользователя. мне как решить эту проблему?
try { $s3 = \Storage::disk('s3'); $s3->put($strFileName, file_get_contents($img_path.$strFileName), 'public'); } catch (Aws\Exception\S3Exception $e) { echo "There was an error uploading the file.\n"+$e; }
Прежде чем задавать вопросы, я прочитал так много ответов от stackoverflow, но это не помогло мне исправить мою проблему. Спасибо.
Я недавно занялся этой проблемой. Сначала да, вы можете загрузить прямо на s3, вот что я использовал для некоторой информации об этом: http://docs.aws.amazon.com/AmazonS3/latest/dev/HTTPPOSTExamples.html
Во-первых, вам нужно создать сервер политики и подпись, чтобы добавить в html-форму для загрузки файлов.
$policy = base64_encode(json_encode([ "expiration" => "2100-01-01T00:00:00Z", "conditions" => [ ["bucket"=> "bucketname"], ["starts-with", '$key', "foldername"], ["acl" => "public-read"], ["starts-with", '$Content-Type', "image/"], ["success_action_status" => '201'], ] ])); $signature = base64_encode(hash_hmac('sha1',$policy,getenv('S3_SECRET_KEY'),true));
Теперь в интерфейсе моей формы я не использую кнопку отправки, вы можете использовать кнопку отправки, но вам нужно поймать отправку и не допустить, чтобы форма была отправлена до завершения загрузки.
Когда мы нажимаем «Сохранить», он генерирует имя файла md5 (использование npm для установки), чтобы имена файлов не могли быть предсказаны случайным образом, а затем использует ajax для загрузки файла до S3. После этого он помещает данные файла и возвращает данные aws в скрытый ввод и отправляет форму. Он должен выглядеть примерно так:
<form action="/post/url" method="POST" id="form"> <input type="text" name="other_field" /> <input type="file" class="form-control" id="image_uploader" name="file" accept="image/*" /> <input type="hidden" id="hidden_medias" name="medias" value="[]" /> </form> <input type="button" value="save" id="save" /> <script> $(document).ready(function(){ $('#save').click(function(){ uploadImage(function () { $('#form').submit(); }); }); }); var uploadImage = function(callback) { var file = $('#image_uploader')[0].files[0]; if(file !== undefined) { var data = new FormData(); var filename = md5(file.name + Math.floor(Date.now() / 1000)); var filenamePieces = file.name.split('.'); var extension = filenamePieces[filenamePieces.length - 1]; data.append('acl',"public-read"); data.append('policy',"{!! $policy !!}"); data.append('signature',"{!! $signature !!}"); data.append('Content-type',"image/"); data.append('success_action_status',"201"); data.append('AWSAccessKeyId',"{!! getenv('S3_KEY_ID') !!}"); data.append('key',filename + '.' + extension); data.append('file', file); var fileData = { type: file.type, name: file.name, size: file.size }; $.ajax({ url: 'https://{bucket_name}.s3.amazonaws.com/', type: 'POST', data: data, processData: false, contentType: false, success: function (awsData) { var xmlData = new XMLSerializer().serializeToString(awsData); var currentImages = JSON.parse($('#hidden_medias').val()); currentImages.push({ awsData: xmlData, fileData: fileData }); $('#hidden_medias').val(JSON.stringify(currentImages)); callback(); }, error: function (errorData) { console.log(errorData); } }); } }; </script>
Контроллер, прослушивающий подачу, затем анализирует JSON из этого поля ввода и создает экземпляр Media (модель, которую я создал), и он хранит awsData
и fileData
для каждого изображения.
Затем вместо указания html-тегов изображений в файл s3, например:
<img src="https://{bucketname}.s3.amazonaws.com/filename.jpg" />
Я делаю что-то вроде этого:
<img src="/medias/{id}" />
Затем маршрут может пройти через обычное промежуточное ПО и все, что вам нужно сделать в Laravel. Наконец, этот маршрут указывает на контроллер, который делает это:
public function getResponse($id) { $media = Media::find($id); return (new Response('',301,['Location' => $media->info['aws']['Location']])); }
Так что это просто использует 301 переадресацию и устанавливает местоположение заголовка в фактический файл aws. Поскольку мы генерируем имя файла md5, когда мы загружаем файл в aws, каждое имя файла является md5, чтобы люди не могли случайно искать aws-файлы в ведре.
Для первого вопроса можно напрямую загрузить изображения в AWS S3.
$s3 = \Storage::disk('s3')->getDriver(); $s3->put($filePath, file_get_contents($file), array('ContentDisposition' => 'attachment; filename=' . $file_name . '', 'ACL' => 'public-read'));
Вы должны указать путь к файлу и файл, который вы получаете из формы.
1. есть ли способ загружать изображения напрямую, когда мы нажимаем кнопку «Отправить»
да
Как:
Вам нужно сделать это, используя JavaScript (с AJAX) в двух частях;
а) когда пользователь нажимает «отправить», вы задерживаете это событие, сначала загрузите файл (см. http://docs.aws.amazon.com/AWSJavaScriptSDK/guide/browser-examples.html для примера), и b) затем отправьте формы через AJAX и обрабатывать ответ.
Однако:
Это позволяет пользователю загружать что угодно и может вызвать проблемы. Есть советы (чуть ниже примера) для создания аутентифицированных URL-адресов в течение 15 минут (переменная), но что происходит, если пользователь занимает более 15 минут или пытается загрузить 100 файлов за 15 минут или загружает что-то, отличное от файла изображений, или плохо отформатированный файл изображения и т. д.
Гораздо безопаснее подключиться к вашему серверу и убедиться, что это изображения и тип / размер, который вам нужен, а затем загрузить с сервера.
Конечно, если это простой инструмент администрирования, и вы контролируете, кто обращается к коду, то идите на него – надеюсь, вы будете загружать только то, что ожидаете.
2. Мне нужно защитить все файлы и просмотреть только аутентифицированного пользователя
Под «аутентифицированным пользователем»: если вы имеете в виду «пользователь, загрузивший изображение», тогда только s3 не предоставляет функциональные возможности, но CloudFront делает это. Вы можете опубликовать предварительно авторизированные URL-адреса или подписанные файлы cookie: http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-choosing-signed-urls-cookies.html
Если «аутентифицированный пользователь» означает человека, который загрузил файл, то, согласно документам, это невозможно в классе Laravel без доступа к базовому клиенту. public
и private
– это ваши единственные параметры видимости по умолчанию, которые переведены на public-read
, но вам необходимо пройти authenticated-read
bucket-owner-read
или одну из других консервированных грантов (ref: http: //docs.aws.amazon .com / AmazonS3 / latest / dev / acl-overview.html # canned-acl ) Если authenticated-read
или другие консервированные ACL-гранты не предоставляют профиль разрешений, который вам нужен, вы можете создать свой собственный (подробнее об этом на той же странице).
Решение состоит в том, чтобы захватить базового клиента, а затем непосредственно поставить объект. (И тогда, если вы заходите так далеко, вы можете также сорвать библиотеку Laravel и потянуть s3 и сделать все сами – тогда у вас есть полный контроль над всем).
$client = $disk->getDriver()->getAdapter()->getClient(); $client->putObject([ 'Bucket' => $bucket, 'Key' => $fileName, 'Body' => $fileBody, 'ACL' => 'authenticated-read' /* Or which ACL suits */ ]);
Решение вашего вопроса, который я использую, но без laravel.
1. Для загрузки любого файла непосредственно в Buzz Amazon AWS S3 в определенную папку вы можете сделать это следующим образом.
HTML
<form action="upload.php" enctype="multipart/form-data"> <input type="file" name="file" id="file" /> <button type="submit">Upload file</button> </form>
PHP – upload.php
Включить aws php sdk
require "vendor/autoload.php";
Инициализировать клиент S3
$credentials = new Aws\Credentials\Credentials( '<AWS ACCESS KEY>', '<AWS ACCESS SECRET>' ); $s3Client = Aws\S3\S3Client::factory( [ 'credentials' => credentials 'region' => 'us-east-1', 'version' => 'latest' ] );
Создать объект для загрузки файлов
$uploadEntity = array( 'Bucket' => <S3 Bucket Name>, 'Key' => '<Upload_Folder_If_Any>/<FileName>', 'Body' => fopen($_FILES['file']['tmp_name'], 'r+'), //'ContentDisposition' => 'attachment; filename="<FileName>"' <-- If need to allow downloading );
Загрузить в s3 Bucket
try { // $result will be Aws\Result object $result = $s3Client->putObject($uploadEntity); } catch (Aws\S3\Exception\S3Exception $exception) { // S3 Exception }
2. Теперь для загрузки загруженных файлов только для прошедших проверку подлинности пользователей
Во-первых, вам нужно будет создать политику private bucket для s3 Bucket.
Политика Bucket – для создания политики ведра вы можете использовать Generator Policy . Используя это, вы можете создать такую политику. Скопировано с сайта Improve.dk
{ "Id": "Policy1319566876317", "Statement": [ { "Sid": "Stmt1319566860498", "Action": [ "s3:GetObject" ], "Effect": "Allow", "Resource": "arn:aws:s3:::<BucketName>/*", "Principal": { "CanonicalUser": [ "<CannoicalUserId_of_OAI>" ] } } ] }
Во-вторых, вам нужно будет настроить частное веб-распределение облачной системы s3 Bucket. Только делая это, вы сможете обслуживать свое содержимое для аутентифицированных пользователей только через подписанный urs или подписанный файл cookie
В-третьих, для создания подписанного URL- кода вам понадобится файл pem, который вы получите только от консоли aws.
Создать подписанный URL
$cdnName = '<AWS CLOUDFRONT WEB DISTRIBUTION CDN>'; $assetName = '<UPLOAD_FOLDER_IF_ANY>/<FILENAME>'; $expiry = time() + 300; // 5 mins expiry time, ie. the signed url will be valid only for 5 mins $cloudfront = CloudFrontClient::factory(array( 'credentials' => $credentials, 'region' => 'us-east-1', 'version' => 'latest' )); // Use this for creating signed url $signedUrl = $cloudFront->getSignedUrl([ 'url' => $cdnName . '/' . $assetName, 'expires' => $expiry, 'private_key' => '/path/to/your/cloudfront-private-key.pem', 'key_pair_id' => '<cloudfront key pair id>' ]); // Use this for signed cookie $signedCookie = $cloudFront->getSignedCookie([ 'url' => $cdnName . '/' . $assetName, 'expires' => $expiry, 'private_key' => '/path/to/your/cloudfront-private-key.pem', 'key_pair_id' => '<cloudfront key pair id>' ]);