Интерактивная загрузка файлов на HTML5 и jQuery
Сегодня мы сделаем небольшое веб-приложение, которое позволит пользователям загружать фотографии со своего компьютера, просто перетаскивая их в окно браузера. Это возможно благодаря новым возможностям HTML5.
У фото в нашем приложении будут небольшие иконки и индикатор загрузки, которые будут создаваться на стороне клиента. Пока изображения просто хранятся в папке на сервере, но вы можете расширить функционал.
HTML5 загрузка файлов
Для начала разберемся что такое загрузка с помощью HTML5. На самом деле это комбинация трех новых технологий: File Reader API, Drag & Drop API и AJAX. Рассмотрим процесс загрузки:
- Пользователь перетаскивает один или несколько файлов в окно браузера. Браузер, поддерживающий Drag & Drop API генерирует событие, которое наряду с другой информацией содержит список файлов.
- Используя File Reader API, мы считываем файлы и запоминаем их.
- Используя новый метод sendAsBinary объекта XMLHttpRequest, мы отправляем файлы на сервер.
Все эти шаги сделает за нас jQuery плагин Filedrop. Плагин позволяет нам задавать максимальный размер файлов и определять функции обратного вызова, что очень полезно для встраивания в ваше веб приложение.
Минус данного метода в том, что он работает не во всех браузерах. Хотя последние версии поддерживают данные функции, сделать стандартную форму загрузки не будет лишним. В нашем примере мы не будем уделять этому внимания.
HTML
Начнем с разметки нашего приложения. Это простая html5 страница, мы подключаем стили, script.js, Filedrop plugin и jQuery.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>HTML5 File Drag and Drop Upload with jQuery and PHP | Tutorialzine Demo</title>
<!-- стили -->
<link rel="stylesheet" href="assets/css/styles.css" />
<!--[if lt IE 9]>
<script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
</head>
<body>
<header>
<h1>HTML5 File Upload with jQuery and PHP</h1>
</header>
<div id="dropbox">
<span>Drop images here to upload. <br /><i>(they will only be visible to you)</i></span>
</div>
<!--jQuery-->
<script src="http://code.jquery.com/jquery-1.6.3.min.js"></script>
<!-- библиотека для загрузки файлов -->
<script src="assets/js/jquery.filedrop.js"></script>
<!-- главный скрипт -->
<script src="assets/js/script.js"></script>
</body>
</html>
Единственный элемент div #dropbox будет содержать список файлов, которые на него перетащили.
Когда пользователь перетащит файл, jQuery добавит на страницу следующий html код, который будет отображать уменьшенное изображение:
<div class="preview done"> <span class="imageHolder"> <img src="" /> <span class="uploaded"></span> </span> <div class="progressHolder"> <div class="progress"></div> </div> </div>
Данный фрагмент содержит иконку изображения и линию загрузки файла. Элемент, содержащий миниатюру может иметь класс .done, он означает, span.uploaded должен стать видимым(по-умолчанию скрыт). Этот элемент содержит зеленую галку, которая появляется после полной загрузки файла.
jQuery
Загрузкой файла будет заниматься плагин Filedrop нам надо только вызвать его и передать несколько колбеков для нужд нашего приложения. Также мы напишем небольшой PHP скрипт, который будет управлять загрузкой на стороне сервера.
Сначала напишем вспомогательную функцию, которая принимает объект, содержащий информацию о файле (специальный объект, созданный браузером и содержащий некоторые параметры, например, имя, путь, размер файла). Эта функция будет создавать разметку для миниатюры.
var template = '<div class="preview">'+
'<span class="imageHolder">'+
'<img />'+
'<span class="uploaded"></span>'+
'</span>'+
'<div class="progressHolder">'+
'<div class="progress"></div>'+
'</div>'+
'</div>';
function createImage(file){
var preview = $(template),
image = $('img', preview);
var reader = new FileReader();
image.width = 100;
image.height = 100;
reader.onload = function(e){
// e.target.result содержит путь к изображению
image.attr('src',e.target.result);
};
// считываем файл, при завершении будет вызвана функция onload (выше)
reader.readAsDataURL(file);
message.hide();
preview.appendTo(dropbox);
$.data(file,preview);
}
Теперь перейдем к вызову плагина.
$(function(){
var dropbox = $('#dropbox'),
message = $('.message', dropbox);
dropbox.filedrop({
// имя поля в $_FILES:
paramname:'pic',
maxfiles: 5,
maxfilesize: 2, // в Мб
url: 'post_file.php',
uploadFinished:function(i,file,response){
$.data(file).addClass('done');
// ответ сервера - это JSON объект, котоорый вернет post_file.php
},
error: function(err, file) {
switch(err) {
case 'BrowserNotSupported':
showMessage('Your browser does not support HTML5 file uploads!');
break;
case 'TooManyFiles':
alert('Too many files! Please select 5 at most!');
break;
case 'FileTooLarge':
alert(file.name+' is too large! Please upload files up to 2mb.');
break;
default:
break;
}
},
// вызывается перед загрузкой
beforeEach: function(file){
if(!file.type.match(/^image\//)){
alert('Only images are allowed!');
return false;
}
},
uploadStarted:function(i, file, len){
createImage(file);
},
progressUpdated: function(i, file, progress) {
$.data(file).find('.progress').width(progress);
}
});
var template = '...';
function createImage(file){
// ... выше ...
}
function showMessage(msg){
message.html(msg);
}
});
Все корректные файлы, будут переданы в post_file.php, код которого вы увидите ниже.
PHP
Серверная часть кода ничем не отличается от обычной загрузки. Поэтому вы можете менять её на свое усмотрение.
// если вы не хотите загружать файлы присвойте $demo_mode значение true;
$demo_mode = false;
$upload_dir = 'uploads/';
$allowed_ext = array('jpg','jpeg','png','gif');
if(strtolower($_SERVER['REQUEST_METHOD']) != 'post'){
exit_status('Error! Wrong HTTP method!');
}
if(array_key_exists('pic',$_FILES) && $_FILES['pic']['error'] == 0 ){
$pic = $_FILES['pic'];
if(!in_array(get_extension($pic['name']),$allowed_ext)){
exit_status('Only '.implode(',',$allowed_ext).' files are allowed!');
}
if($demo_mode){
// загрузка не происходит
$line = implode(' ', array( date('r'), $_SERVER['REMOTE_ADDR'], $pic['size'], $pic['name']));
file_put_contents('log.txt', $line.PHP_EOL, FILE_APPEND);
exit_status('Uploads are ignored in demo mode.');
}
// перемещаем файл из временной папки в папку хранения на сервере
if(move_uploaded_file($pic['tmp_name'], $upload_dir.$pic['name'])){
exit_status('File was uploaded successfuly!');
}
}
exit_status('Something went wrong with your upload!');
// вспомогательные функции
function exit_status($str){
echo json_encode(array('status'=>$str));
exit;
}
function get_extension($file_name){
$ext = explode('.', $file_name);
$ext = array_pop($ext);
return strtolower($ext);
}
Код проверяет HTTP метод запроса и формат переданного файла. Переменная $demo_mode нужна только для демонстрации приложения, мы не вызываем move_uploaded_file, поэтому файл автоматически удаляется после обработки запроса.
CSS
Рассмотрим только часть кода CSS. Весь код доступен в исходниках.
/*-------------------------
Dropbox Element
--------------------------*/
#dropbox{
background:url('../img/background_tile_3.jpg');
border-radius:3px;
position: relative;
margin:80px auto 90px;
min-height: 290px;
overflow: hidden;
padding-bottom: 40px;
width: 990px;
box-shadow:0 0 4px rgba(0,0,0,0.3) inset,0 -3px 2px rgba(0,0,0,0.1);
}
#dropbox .message{
font-size: 11px;
text-align: center;
padding-top:160px;
display: block;
}
#dropbox .message i{
color:#ccc;
font-size:10px;
}
#dropbox:before{
border-radius:3px 3px 0 0;
}
/*-------------------------
Image Previews
--------------------------*/
#dropbox .preview{
width:245px;
height: 215px;
float:left;
margin: 55px 0 0 60px;
position: relative;
text-align: center;
}
#dropbox .preview img{
max-width: 240px;
max-height:180px;
border:3px solid #fff;
display: block;
box-shadow:0 0 2px #000;
}
#dropbox .imageHolder{
display: inline-block;
position:relative;
}
#dropbox .uploaded{
position: absolute;
top:0;
left:0;
height:100%;
width:100%;
background: url('../img/done.png') no-repeat center center rgba(255,255,255,0.5);
display: none;
}
#dropbox .preview.done .uploaded{
display: block;
}
/*-------------------------
Progress Bars
--------------------------*/
#dropbox .progressHolder{
position: absolute;
background-color:#252f38;
height:12px;
width:100%;
left:0;
bottom: 0;
box-shadow:0 0 2px #000;
}
#dropbox .progress{
background-color:#2586d0;
position: absolute;
height:100%;
left:0;
width:0;
box-shadow: 0 0 1px rgba(255, 255, 255, 0.4) inset;
-moz-transition:0.25s;
-webkit-transition:0.25s;
-o-transition:0.25s;
transition:0.25s;
}
#dropbox .preview.done .progress{
width:100% !important;
}
Меняя ширину .progress мы получим интерактивный индикатор загрузки.
На этом всё! 🙂








Здравствуйте! Спасибо большое за урок! Хотел бы спросить, есть ли возможность приделать удаления фотографий, после того как их перетащили и они видны в виде миниатюр?
Вот пример кода:
// перемещаем файл из временной папки в папку хранения на сервере
if(move_uploaded_file($pic[‘tmp_name’], $upload_dir.$pic[‘name’])){
exit_status(‘File was uploaded successfuly!’);
}
Вот эта функция предполагает вывод всех статусов на экран пользователя. Однако плагин этого не делает.
Уважаемый автор, Почему? Как мне сделать так, чтобы JS у пользователя получал сообщения как в стандартных Ajax запросах.
function exit_status($str){
echo json_encode(array(‘status’=>$str));
exit;
}
статья супер. еще бы добавить сжатие картинки на стороне клиента.