falbar Ajax-загрузка данных на сервер

Ajax-загрузка данных на сервер

16 июля 2015 8333 0

Хороший скрипт – это инструмент, который сэкономит вам массу времени и нервных клеток при разработке веб-приложения. По своему опыту создания сайтов знаю, что значительную часть времени приходиться тратить именно на поиск готовых «велосипедов» и решений, которые упрощают нашу работу. Сегодня мы затронем одну из важнейших тем – загрузка файлов или картинок на сервер при помощи ajax. И, хотя есть множество статьей и скриптов, я расскажу своё видение данной проблемы и её решения у себя в проекте.

Реклама

Речь пойдёт об одном из готовых инструментов под названием AJAX File-Uploader версии 2.0, которое если и не использовать при возникновении необходимости загрузки файлов, то уж точно добавить к себе в закладки. Почему именно этот плагин? Я, наверно, перебрал уже немало вариантов и сохранил столько же ссылок у себя на ПК, где рассматриваются различные решения, и каждое из них имеет право на существование, но этот плагин после подробного его исследования мне показался максимально удобным и универсальным.

Что же он может делать?

С одной стороны смешной вопрос, естественно загружать файлы! Но давайте рассмотрим отличительные его черты и возможности:

  • Плагин поддерживает Multiple функционал;
  • Есть собственный прогрессбар из коробки;
  • Поддерживает возможность Drag-and-drop;
  • Процесс загрузки отменяемый;
  • Довольно важная особенность – не использует Flash;
  • Работает во всех современных браузерах, а, что касается IE, то сам лично проверял – поддерживает начиная с 7 версии.

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

Если у вас медиаресурс или вы просто захотели добавить возможность пользователям загружать файлы, то, как это в основном происходит: пользователь кликает по кнопке загрузить, выбрав картинку, и ожидает какого-то результата -> в это время его картинка попадает на сервер, где что-то с ней делаем уже мы. Да это очень-очень упрощённая схема загрузки, но, тут важно, что весь процесс можно разделить на два этапа: визуальная часть и серверная часть. В этой статье мы и рассмотрим эту цепочку на примере, который вы можете изучить в демо, прикреплённом к этой статье.

В самом начале работы с плагином нам необходимо подключить следующие файлы:

<link href="main.css" type="text/css" rel="stylesheet" />
<link href="fileuploader.css" type="text/css" rel="stylesheet" />
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script src="fileuploader.js" type="text/javascript"></script>

Данное решение написано на JavaScript и не использует сторонних библиотек. jQuery я подключил для собственного удобства, а в файле стилей main – мы будем добавлять свои CSS правела, чтобы не затронуть стили которые нам предоставляют разработчики.

Теперь мы добавим HTML разметку:

<div id="file-uploader">
   <noscript>
        <p>
           Пожалуйста, включите JavaScript, чтобы использовать загрузчик файлов.
       </p>
  </noscript>
</div>

Если вы не ориентируетесь на людей, которые не используют JavaScript, то элемент noscript и его содержимое можно не писать.

Добавим ещё блок, в котором мы будем выводить состояния загрузки файлов:

<div id="file-logs">
</div>

Закончив с подготовительными делами, переходим непосредственно к работе со скриптом, который поместим в стандартную jQuery обёртку.

$(function(){

 /*
      Весь JavaScript
     добавляем сюда
  */
});

Теперь добавим функцию, при помощи которой мы будем формировать шаблон для вывода состояний при загрузке файла и событий, которые могут возникнуть:

function templateLogsHtml(element, title, type, args){

 var templateHtml = "",
        argsHtml     = "";

    for(var key in args){

       if(typeof(args[key]) == "object"){

            for(var k in args[key]){

                argsHtml += "<b>" + k + " - " + args[key][k] + "</b>";
            };
      }else{
          argsHtml += key + " - " + args[key] + "<br />";
       };
  };

  templateHtml  = "<p class='" + type + "'>";
 templateHtml    += "<span>" + title + ":</span>";
   templateHtml    += argsHtml;
    templateHtml += "</p>";

 element.prepend(templateHtml);

  return false;
};

Функция templateLogsHtml() представляет собой простейший шаблонизатор для вывода наших логов для различных событий. Рассмотрим принимаемые ею параметры:

  • element – блок в который мы будем выводить логи;
  • title – заголовок события;
  • type – тип события;
  • args – аргументы события.

Теперь я добавлю сам код уже настроенного загрузчика, а ниже под ним опишу все его составляющие:

var fileLogs = $("#file-logs");

var uploader = new qq.FileUploader({
   element: $("#file-uploader")[0],
  action: "server.php",
 allowedExtensions: ["jpg", "jpeg", "png", "gif", "ico"],
  sizeLimit: 51200,
   multiple: 5,
    inputName: "qqFile",
  onSubmit: function(fileId, fileName){

       templateLogsHtml(fileLogs, "Нажатие на кнопку", "onSubmit", {

           ID: fileId,
         NAME: fileName
      });
 },
  onCancel: function(fileId, fileName){

       templateLogsHtml(fileLogs, "Отмена загрузки", "onCancel", {

         ID: fileId,
         NAME: fileName
      });
 },
  onComplete: function(fileId, fileName, responseJSON){

       templateLogsHtml(fileLogs, "Ответ сервера", "onComplete", {

         ID: fileId,
         NAME: fileName,
         RESPONSE: responseJSON
      });
 },
  messages: {

     typeError: "Допустимые форматы для загрузки: {extensions}",
       sizeError: "Файл {file} слишком большой, Вы превысили допустимый размер {sizeLimit}"
  },
  showMessage: function(message){

     templateLogsHtml(fileLogs, "Вывод сообщения об ошибке", "showMessage", {

            MESSAGE: message
        });
 },
  dragText: "Переместите файл сюда чтобы загрузить",
    uploadButtonText: "Загрузить файл",
   cancelButtonText: "Отмена",
   failUploadText: "Файл не загрузился"
});

Из этого кода уже можно понять, что настройка довольно проста и понятна, теперь давайте рассмотрим все методы и свойства загрузчика, использованные для примера из демо:

  • element – узел DOM дерева в нашем случае <div id="file-uploader">;
  • action – путь до скрипта обработчика;
  • allowedExtensions – массив с форматами файлов допускаемых для загрузки;
  • sizeLimit – минимальный размер файла в байтах;
  • multiple – число файлов загружаемых за раз, если нужен только один указываем в значении !1;
  • inputName – значение параметра name у input через который будет осуществляться загрузка;
  • onSubmit – callback функция которая вызывается при нажатии на кнопку загрузки;
  • onCancel – callback функция вызываемая при отмене;
  • onComplete – callback функция при вызываемая при удачном завершении загрузки файла;
  • messages – сообщения ошибок;
  • showMessage – callback функция при помощи которой мы можем вывести ошибки на экран;
  • dragText – текст на области Drag-and-drop;
  • uploadButtonText – текст на кнопке загрузки;
  • cancelButtonText – текст кнопки отмены;
  • failUploadText – текст при не удачной загрузке.

Но это далеко не все параметры, которые можно использовать - их гораздо больше! С другими вы можете ознакомиться, воспользовавшись поиском по самой библиотеке.

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

Теперь давайте перейдём к серверу и разберемся, как мы будем обрабатывать данные. Если перейти на сайт разработчиков, ссылку вы найдёте в низу страницы и скачать там архив с плагином, то в нём будет готовый PHP сервер. Из себя он представляет файл с тремя классами. После его рассмотрения, я его немного подправил под себя. Конечно изменения не существенные, но есть, поэтому я буду отталкиваться от моего варианта.

Чтобы добиться большей кроссбраузерности разработчики AJAX File-Uploader версии 2.0 воспользовались двумя способами загрузки, а именно через ajax и через форму. Зависимости от поддерживаемого метода браузером подключается тот или иной способ. Такая же ситуация и на сервере, у нас - три класса UploaderFileByXhr, UploaderFileByForm, Uploader. Первый и второй отвечают каждый за свой способ загрузки, а третий используется для подключения одного из вариантов, а также обработки принимаемых параметров и проверки загрузки файла.

class UploaderFileByXhr{

 private $name;

  public function __construct($name){

     $this->name = $name;

     return false;
   }

   public function save($path){

        $input = fopen("php://input", "r");
     $temp = tmpfile();
      $real_size = stream_copy_to_stream($input, $temp);
      fclose($input);

     if($real_size != $this->get_size()){

         return false;
       }

       $target = fopen($path, "w");
      fseek($temp, 0, SEEK_SET);
      stream_copy_to_stream($temp, $target);
      fclose($target);

        return true;
    }

   public function get_size(){

     if(isset($_SERVER["CONTENT_LENGTH"])){

            return (int)$_SERVER["CONTENT_LENGTH"];
       }

       return false;
   }

   public function get_name(){

     return $_GET[$this->name];
   }
}
class UploaderFileByForm{

  private $name;

  public function __construct($name){

     $this->name = $name;

     return false;
   }

   public function save($path){

        if(!move_uploaded_file($_FILES[$this->name]["tmp_name"], $path)){

          return false;
       }

       return true;
    }

   public function get_size(){

     return $_FILES[$this->name]["size"];
   }

   public function get_name(){

     return $_FILES[$this->name]["name"];
   }
}
class Uploader{

    private $file;
  private $formats;
   private $max_size;

  public function __construct($params = array()){

     if(isset($params["file"]) && $params["file"]){

          if(isset($_GET[$params["file"]])){
                $this->file = new UploaderFileByXhr(
                 $params["file"]
               );
          }elseif(isset($_FILES[$params["file"]])){
             $this->file = new UploaderFileByForm(
                    $params["file"]
               );
          }else{
              $this->file = false;
         }
       }

       if(isset($params["formats"]) && $params["formats"]){

            $this->formats = strtolower($params["formats"]);
       }

       if(isset($params["max_size"]) && $params["max_size"]){

          $this->max_size = (int)$params["max_size"];
        }

       return false;
   }

   public function upload_file($path, $file_name){

     if(!is_writable($path)){

            return array(
               "error" => "Ошибка сервера, невозможно загрузить в папку"
            );
      }

       if(!$this->file){

            return array(
               "error" => "Файл не был загружен"
            );
      }

       $size = $this->file->get_size();
      if($size == 0){

         return array(
               "error" => "Файл пуст"
           );
      }
       if($size > $this->max_size){

          return array(
               "error" => "Файл слишком большой"
            );
      }

       $path_info = pathinfo($this->file->get_name());
       $ext       = @strtolower($path_info["extension"]);
        $valid_ext = explode("|", $this->formats);
     if($this->formats && !in_array($ext, $valid_ext)){

           $these = implode(", ", $valid_ext);
           return array(
               "error" => "Допустимые форматы для загрузки: ".$these
            );
      }

       if($this->file->save($path.$file_name.".".$ext)){

           return array(
               "success" => true
          );
      }

       return array(
           "error" => "Файл не был загружен или отменён"
        );
  }
}

Для загрузки файла на сервер необходимо создать экземпляр объекта Uploader с переданными в него параметрами:

  • file – название атрибута name, который был рассмотрен выше;
  • formats – форматы файлов допускаемые для загрузки;
  • max_size – максимальный размер файла.
$obj = new Uploader(array(
    "file"       => "qqFile",
    "formats"  => "jpg|jpeg|png|gif|ico",
    "max_size" => 51200
));

А теперь останется воспользоваться методом upload_file():

echo(json_encode(
 $obj->upload_file("uploads/", "newName")
));

Данный метод принимает два параметра:

  • Папка, в которую нужно сохранить файл;
  • Имя добавленного файла.
Напоследок: после того, как вы скачаете архив, строки, отвечающие за загрузку, будут закомментированы, для использования их стоит раскомментировать.

И так, подведём итог разбора плагина AJAX File-Uploader версии 2.0: это довольно хорошие и удобное решение для загрузки файлов, которое универсально и кроссбраузерно, в большинстве случаев оно будет лучшим выбором для загрузки файлов и картинок, но недостаток – обладает значительным размером.

Надеюсь, эта статья помогла вам разобраться с принципом загрузки файлов при помощи ajax на сервер.

Реклама
Комментариев еще не оставлено
no_avatar