Показать Меню
falbar Загрузка файлов

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

Загрузка файлов

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

<script type="text/javascript">
	$(function(){

		/*

			Весь JavaScript
			добавляем сюда

		*/
	});
</script>

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

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 на сервер.

Источник
valums

Подписаться на обновления

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