Статьи

Как создать собственный загрузчик S3

Задумывались ли вы, как создать форму, которая может загружать несколько файлов непосредственно в желаемое ведро S3? Несмотря на то, что такие инструменты, как S3Fox и Transmit, безусловно, справляются со своей задачей достаточно хорошо, иногда нам нужен более простой интерфейс в один клик для наших клиентов. Мы построим один сегодня!




Давайте сначала выясним наши цели.

Мы хотим создать простую страницу загрузки, которая предоставит нашим клиентам / членам команды возможность загружать несколько файлов (ресурсов) в нашу учетную запись S3 одним щелчком мыши. Это сделает процесс максимально простым для них, а также дополнит бонус ограничением полного доступа к нашей учетной записи S3.


При работе с API всегда помните, что может быть гораздо выгоднее использовать существующие классы, чем тратить часы на изучение собственной документации API. Ваше время лучше провести в другом месте. Кроме того, с другой стороны, протестированный класс-обертка для вашего желаемого API будет иметь гораздо больше преимуществ от тестирования и отладки.

Имея это в виду, мы будем использовать превосходный класс Amazon S3 PHP . Скачайте zip-файл и перетащите папку в корень вашего проекта.


Давайте начнем строить наш простой контроллер. Создайте новый файл index.php и добавьте:

1
2
3
4
5
6
7
// Display errors during production
ini_set(‘display_errors’, 1);
  
//include the S3 class
if ( !class_exists(‘S3’) ) {
  require_once ‘s3/S3.php’;
}

Сначала мы гарантируем, что все ошибки отображаются на странице во время производства.

Далее нам нужно включить класс Amazon S3, который мы скачали на первом этапе. Конкретный файл, который нам требуется, называется S3.php . Теперь он должен быть включен в наш проект, только если класс S3 еще не существует. Технически, поскольку у нас есть полный контроль над этими файлами, вы можете удалить эту проверку, но это все же лучший метод.



Следующим шагом будет передача учетных данных Amazon S3. В этом руководстве предполагается, что вы уже зарегистрировали учетную запись и эти ключи доступны для вас. Поскольку эти значения не должны изменяться в течение всего цикла нашего приложения, они должны быть соответствующим образом объявлены как constants .

1
2
3
//AWS access info
if ( !defined(‘awsAccessKey’) ) define(‘awsAccessKey’, ‘your-access-key’);
if ( !defined(‘awsSecretKey’) ) define(‘awsSecretKey’, ‘your-secret-key’);

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

1
2
//instantiate the class
$S3 = new S3( awsAccessKey, awsSecretKey );

Этот класс первоначально будет принимать два параметра: ключ доступа и секретный ключ соответственно. Выше мы передаем константы, которые мы объявили на третьем шаге.


Хорошо, это будет делать сейчас. Давайте двигаться вперед и строить нашу точку зрения — или форму. Вместо того, чтобы объединять все эти PHP и HTML, вместо этого мы создадим файл шаблона и включим его. Внизу index.php добавьте:

1
include ‘index.tmpl.php’;

Создайте этот новый файл и не стесняйтесь хранить его в корневом каталоге вашего проекта. Давайте добавим нашу начальную разметку и саму форму.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<!DOCTYPE html>
<html lang=»en» class=»no-js»>
<head>
    <meta charset=»UTF-8″ />
    <script>document.documentElement.className = ‘js’;
  
    <title>Upload to S3</title>
      
    <meta http-equiv=»X-UA-Compatible» content=»IE=edge,chrome=1″>
      
    <link rel=»shortcut icon» href=»favicon.ico»>
</head>
<body>
  
    <div id=»container»>
  
        <h1>Upload a File </h1>
      
        <form action=»index.php?uploads=complete» method=»post» enctype=»multipart/form-data»>
          <input name=»theFile» type=»file» id=»file_upload» />
        </form>
      
        <noscript> Please enable JavaScript to upload multiple files.
      
    </div>
  
</body>
</html>

Все это должно выглядеть в основном знакомым для вас. Чтобы указать на некоторые особенности, хотя:

  • Метатег X-UA-Compatible гарантирует, что Internet Explorer, несмотря ни на что, использует свой новейший механизм рендеринга, а не возвращается в режим IE7.
  • Мы будем использовать JavaScript для многократной загрузки файлов, поэтому нам нужна ловушка в нашей разметке. Наиболее распространенное решение — применить класс no-js к элементу html , а затем переопределить его с помощью JavaScript для js . Это простое решение!
  • Наша простая форма содержит только file ввода. Обратите внимание, что мы установили для enctype multipart/form-data . Это необходимо для всех загрузок файлов. Кнопка отправки будет добавлена ​​позже в этом руководстве, когда мы интегрируем плагин Uploadify.
  • В настоящее время мы установили action формы для текущей страницы, но мы также передали значение «uploads» в строке запроса.


Итак, что происходит, когда пользователь выбирает файл? Ну, за исключением того факта, что мы еще не интегрировали кнопку submit , данные файла будут храниться во временной памяти. Мы рассмотрим процесс фактического сохранения файлов в нашей локальной папке на следующем шаге. А сейчас давайте продолжим, предполагая, что файлы были сохранены в нашей папке «uploads».

Давайте послушаем загрузку с помощью PHP. Вернитесь к контроллеру index.php . Сразу после того, как вы создали новый экземпляр класса S3:

1
2
3
4
5
6
7
//instantiate the class
$s3 = new S3(awsAccessKey, awsSecretKey);
  
//check whether a form was submitted.
if ( isset($_GET[‘uploads’]) ) {
  
}

Помните, как мы устанавливаем атрибут действия формы для передачи ?uploads=complete в строке запроса? Это значение будет затем доступно нам через: $_GET['uploads'] . Итак, когда страница загружается, если это значение существует, то мы знаем, что форма была отправлена. Отлично!

Далее мы должны объявить некоторые переменные, которые указывают, как и где мы хотим поддерживать представленные файлы. Следующий код должен быть помещен в оператор if выше.

1
2
3
$bucketName = ‘myUploadr’;
$uploadsDir = ‘uploads/’;
$refused_types = array(‘application/exe’);

Когда вы читаете «ведро» , думайте «папка».

S3 использует термин « корзина» , но по сути относится к имени папки в вашей учетной записи. Не стесняйтесь назвать это, как вы хотите. Я назвал свое ведро, myUploadr .

Далее нам нужно знать, где хранятся загруженные файлы. Затем мы будем использовать этот путь для последовательной загрузки файлов из этой папки в корзину S3. Создайте папку с именем uploads и поместите ее в корневой каталог вашего проекта.

Наконец, мы должны указать, какие типы файлов могут быть загружены, или наоборот. Эта опция будет зависеть от конкретных потребностей вашего проекта. В этом случае, для простоты, мы будем запрещать все exe файлы, но не стесняйтесь изменять это так, как вы пожелаете.

Обратите внимание, что массив $refused_types ничего не делает сам по себе. Это просто массив, к которому мы подключимся позже.


Чтобы определить, с какими файлами нам нужно работать, нам нужно просканировать каталог закачек. PHP предлагает полезную функцию scandir чтобы учесть это.

1
2
3
$files = scandir($uploadsDir);
array_shift($files);
array_shift($files);

Вы когда-нибудь замечали, что функция scanDir всегда возвращает два элемента: ‘.’ и ‘..’? Они относятся к папкам, и, хотя мы могли бы быть немного более техническими в этом, давайте будем ленивы и выделим эти два из нашего списка, используя функцию array_shift . Это оставит нас с:

1
2
3
4
Array
(
    [0] => some-file.jpg
)

Хорошо, теперь, когда у нас есть массив всех файлов, которые нужно загрузить, давайте воспользуемся классом S3! Давайте разберемся с этим. Мы должны:

  1. Создать ведро S3
  2. Отфильтруйте все файлы в каталоге «uploads»
  3. Измените имя файла на что-то уникальное. Может быть, мы можем использовать функцию time PHP для этого. В противном случае мы рискуем перезаписать файлы с одинаковыми именами.
  4. Загрузить файл на S3
  5. Удалите файл из нашей временной папки «uploads», потому что он теперь хранится на S3.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//create a new bucket
$S3->putBucket(«$bucketName», S3::ACL_PUBLIC_READ);
  
// filter through items in the «uploads/» folder
for ( $i = 0; $i < count($files); $i++ ) {
            // Determine what type of file it is.
            $mt = mime_content_type(‘uploads/’ . $files[$i]);
      
            // If the file type is in our refused_types array, delete it, and continue…
    if ( in_array($mt, $refused_types) ) {
        // can’t accept this file type.
        // You could also reverse this to only accepted allowed-types.
        unlink($uploadsDir . $fils[$i]);
        continue;
    }
    //Prefix a unique sequence of characters to the file name
    $fileName = time() .
 
    // path to file we want to move, the desired bucket, the desired file name, when it is added to the bucket, Access control list
    if ($S3->putObjectFile($uploadsDir . $files[$i], «$bucketName», $fileName, S3::ACL_PUBLIC_READ)) {
        // delete file
        unlink($uploadsDir . $files[$i]);
          
        //update filesArr
        $filesArr[$files[$i]] = «http://$bucketName.s3.amazonaws.com/$fileName»;
    }

Хорошо, давайте возьмем этот код построчно, для максимальной ясности.

1
$S3->putBucket(«$bucketName», S3::ACL_PUBLIC_READ);

Этот метод класса $ S3 позволяет нам добавить новый сегмент в нашу учетную запись S3. Он принимает два параметра: имя сегмента и права доступа. Здесь мы перешли в «myUploadr» и установили права на публичное чтение всех.

1
for ( $i = 0; $i < count($files); $i++ ) {

Это утверждение позволяет нам циклически перебирать все изображения в папке загрузки .

1
$fileName = time() .

Эта строка гарантирует, что имя файла уникально и не конфликтует с существующими файлами в корзине на S3. Функция time() добавит к нашему имени файла уникальную строку символов.

1
if ($S3->putObjectFile($uploadsDir . $files[$i], «$bucketName», $fileName, S3::ACL_PUBLIC_READ)) {

Эта строка обрабатывает процесс загрузки файла в S3 благодаря putObjectFile методу putObjectFile класса S3. Этот метод будет принимать четыре основных параметра.

  • Путь к файлу, который мы хотим загрузить на S3
  • Название корзины (папки), в которую мы загружаем
  • Желаемое имя файла
  • Ваши назначенные права доступа
1
unlink($uploadsDir . $files[$i]);

Если файл был успешно загружен, нам больше не нужно хранить его локально. Мы можем удалить файл, используя PHP-функцию unlink и передав путь к файлу, который должен быть удален.

А что если мы загрузим несколько файлов на S3, что вполне вероятно? Нам нужно место для хранения путей ко всем этим файлам, верно? Имея это в виду, давайте создадим новый массив, названный $filesArr .

1
2
// an array containing links to all of the uploaded images
$filesArr = array();

Вы можете поместить это наверху своего заявления if . С этим массивом, который мы создали, нам нужно только указать путь к каждому загруженному файлу.

1
2
//update filesArr
$filesArr[ $files[$i] ] = «http://$bucketName.s3.amazonaws.com/$fileName»;

После завершения оператора for $fileArr , следовательно, будет содержать список путей к каждому загруженному файлу. Presto!

Ниже приведен полный исходный код нашего простого «контроллера».



Мы написали все функции на стороне сервера для нашего маленького веб-приложения. Но теперь нам нужно обработать внешний интерфейс загрузки нескольких файлов в наш каталог uploads / . Для этого мы воспользуемся удобной Uploadify .

«Uploadify — это плагин jQuery, который интегрирует полностью настраиваемую утилиту загрузки нескольких файлов на ваш сайт. Он использует смесь Javascript, ActionScript и любого серверного языка для динамического создания экземпляра поверх любого элемента DOM на странице».

Первым шагом при интеграции Uploadify является загрузка необходимых файлов. Их можно получить здесь. Переименуйте загруженную папку в «uploadify» и поместите ее в корневой каталог вашего проекта.

Далее нам нужно ссылаться на необходимые файлы с нашей точки зрения. Вернитесь к index.tmpl.php и, непосредственно перед закрывающим тегом body , добавьте:

1
2
3
4
<script src=»http://ajax.googleapis.com/ajax/libs/jquery/1.5.0/jquery.min.js»></script>
<script src=»uploadify/swfobject.js»></script>
<script src=»uploadify/jquery.uploadify.v2.1.4.min.js»></script>
<script src=»js/scripts.js»></script>

Здесь мы ссылаемся на последнюю версию jQuery, swfobject, основной скрипт Uploadify и наш собственный файл scripts.js (вы можете создать этот файл сейчас).

Давайте теперь активировать Uploadify.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
(function() {
  
var myUploadr = {
  
  uploadify : function() {
    $(‘#file_upload’).uploadify({
        ‘uploader’ : ‘uploadify/uploadify.swf’,
        ‘script’ : ‘uploadify/uploadify.php’,
        ‘cancelImg’ : ‘uploadify/cancel.png’,
        ‘folder’ : ‘uploads/’,
        ‘auto’ : true,
        ‘multi’ : true,
        ‘wmode’ : ‘transparent’,
        ‘buttonText’: ‘Send to S3’,
        ‘sizeLimit’ : 10485760, // 10 megs
        ‘onAllComplete’ : function() {
            // all files finished uploading
            location = «index.php?uploads=complete»;
        }
    });
  }
  
}
  
})();

Активировать Uploadify так же просто, как вызвать метод. Помните, Uploadify — это просто потрясающий плагин jQuery. Этот метод принимает множество дополнительных параметров. Я призываю вас просмотреть их здесь. Для наших конкретных потребностей нам требуется всего лишь горстка.

  • Uploader: путь к swf файлу, который обрабатывает кнопку отправки
  • скрипт: путь к uploadify.php
  • cancelImg: путь к кнопке отмены. (Один предоставляется по умолчанию)
  • папка: путь к папке, где будут храниться загруженные файлы
  • auto: логическое значение, которое указывает, должны ли загрузки выполняться автоматически.
  • multi: допускается ли загрузка нескольких файлов?
  • wmode: установите этот параметр transparent чтобы гарантировать отсутствие проблем с типом «z-index», когда кнопка отображается в раскрывающемся меню или что-то подобное.
  • buttonTxt: Что должна сказать кнопка отправки?
  • sizeLimit: Какой максимальный размер файла мы примем?
  • onAllComplete: этот метод будет запущен после завершения загрузки всех файлов. В нашем случае мы перезагружаем страницу и передаем параметр uploads=complete в строку запроса.

Это должно сделать это! Просто убедитесь, что вы вызываете нашу функцию uploadify внизу scripts.js .

1
myUploadr.uploadify();

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





На данный момент мы написали основную часть нашей логики. Но есть еще одно задание, которое нам нужно выполнить. Помните, когда мы писали логику обработки загрузок на наш аккаунт S3? Мы сохранили ссылки в array , называемом $filesArr .

Когда наша форма загружается, мы должны определить, существует ли этот array и не является ли он пустым. Если это так, файлы уже были загружены, и в этом случае нам нужно только отображать ссылки на каждый загруженный ресурс.

Вернитесь к index.tmpl.php и чуть ниже основной формы добавьте следующее:

01
02
03
04
05
06
07
08
09
10
11
12
13
<?php if ( !empty($filesArr) ) : ?>
  <div class=»overlay»>
     <hr />
<h2> Links to Uploaded Files</h2>
     <ul>
        <?php foreach( $files_arr as $name => $path ) : ?>
        <li>
           <a target=»_blank» href=»<?php echo $path; ?>»> <?php echo $name;
        </li>
        <?php endforeach;
     </ul>
  </div>
<?php endif;

Этот бит кода сначала определяет, существует ли $filesArr . Если это так, то он содержит как имя, так и ссылку на каждый загруженный файл. Чтобы отобразить эти ссылки, процесс так же прост, как и фильтрация каждого элемента в массиве, и отображение тега привязки, который ссылается на связанный файл.



Это должно сделать это! Теперь, когда все функциональные возможности отсутствуют, ваш следующий шаг — настроить страницу под ваши конкретные потребности. Мы могли бы охватить это, но это определенно выходит за рамки этого урока. Используйте свое воображение — вот что я закончил.


Спасибо за чтение, и дайте мне знать, если у вас есть какие-либо вопросы! Если части письменного руководства вас смутили, обязательно посмотрите также и скринкаст!