Всем привет! Сегодня будет рассмотрено как сделать простенький индикатор для отображения процесса загрузки файлов на сервер. Итак, поехали!
Иногда бывает просто необходимо чем то заполнить возникшую паузу в процессе загрузки файла(ов) на сервер чтобы пользователь ясно понимал что процесс идет.
Причинами долгой загрузки может быть:
1. Плохое(медленное) соединение с интернетом
2. Большой вес загружаемых файлов
Для решения этой задачи идеально подойдет технология ajax в инструментариях которой есть механизм отслеживания передачи байтов на сервер.
Для начала создадим серверную часть в файле server.php
<?php
define('EXT', array('mp4', 'mp3'));
define('SIZE_MB', 100);
if(count($_FILES) === 0 || count($_POST) === 0){
echo json_encode(array('message'=> 'Переданы не все данные'), true);
die();
}
if(!isset($_POST['name']) || !isset($_POST['email']) || trim($_POST['name']) === "" || trim($_POST['email']) === ""){
echo json_encode(array('message'=> 'Не передано имя и/или email'), true);
die();
}
if(!isset($_FILES['media'])){
echo json_encode(array('message'=> 'Не удалось получить загруженный файл'), true);
die();
}
$count_file = 0;
for($i = 0; $i < count($_FILES['media']['tmp_name']); $i++){
if(trim($_FILES['media']['name'][$i]) === ''){
continue;
}
if(trim($_FILES['media']['type'][$i]) === ''){
continue;
}
if(trim($_FILES['media']['tmp_name'][$i]) === ''){
continue;
}
$ext = pathinfo($_FILES['media']['name'][$i], PATHINFO_EXTENSION);
if(!in_array($ext, EXT)){
continue;
}
$size = $_FILES['media']['size'][$i] / 1000000;
if($size >= SIZE_MB){
continue;
}
$path = $_SERVER['DOCUMENT_ROOT'].'upload/'.base64_encode(openssl_random_pseudo_bytes(10)).'.'.$ext;
if(!@move_uploaded_file($_FILES['media']['tmp_name'][$i], $path)){
continue;
}
$count_file++;
}
if($count_file === 0){
echo json_encode(array('message'=> 'Файлы не были загружены'), true);
die();
}
echo json_encode(array('message'=> 'Данные успешно отправлены'), true);
Весь механизм мы взяли из статьи посвященной загрузке файлов на сервер. Здесь идут несколько ограничений по общему весу файлов (не более 100 мб) и расширению (допускаются только файлы с расширением mp3, mp4). С этим я думаю все понятно!
Теперь рассмотрим клиентскую часть в index.html
<style>
#progress{
position:fixed;
top:0%;
left:0%;
width:100%;
height:100%;
z-index:1000000;
background:rgba(0, 0, 0, 0.7);
display:none;
}
#progress div{
position:absolute;
top:50%;
left:50%;
transform:translate(-50%, -50%);
background:white;
padding:20px;
text-align:center;
}
</style>
<div id="progress" >
<div>
<h4>Загружено</h4>
<p id="load-progress">0%</p>
<progress id="progressbar" value="0" max="100"></progress>
<p id="size-progress"></p>
</div>
</div>
<form method="post" action="server.php" enctype="multipart/form-data">
<input name="name" placeholder="Введите имя" type="text" required/>
<input name="email" placeholder="Введите email" type="email" required/>
<label>Загрузите медиафайл(mp3, mp4)</label>
<input type="file" name="media[]" multiple/>
<button>Отправить</button>
</form>
<script>
function loadProcess(a, len){
var one = len / 100;
var proc = (a / one).toFixed(1);
document.querySelector('#progressbar').value = (a / one);
document.querySelector('#load-progress').innerText = proc + '%';
document.querySelector('#size-progress').innerText = "Загружено: " + a.toFixed(2) + "МБ из " + len.toFixed(2) + "МБ";
}
document.querySelector('form').addEventListener('submit', function(e){
e.preventDefault();
var data = new FormData(this);
var receivedLength = 0, print = 0;
var xhr = new XMLHttpRequest();
xhr.open("POST", '/server.php');
xhr.responseType = 'json';
if (xhr.upload) {
document.querySelector('#progress').style.display = "block";
xhr.upload.addEventListener('progress', function(e) {
if (e.lengthComputable) {
loadProcess((e.loaded / 1000000), (e.total / 1000000));
}
},false);
xhr.onload = function(){
if(this.status === 200){
var res = this.response;
alert(res['message']);
if(res['message'] === 'Данные успешно отправлены'){
document.querySelector('form').reset();
}
}else{
alert('Страница не найдена!');
}
document.querySelector('#progress').style.display = "none";
};
xhr.onerror = function(){
alert('Проверьте соединение с интернетом!');
document.querySelector('#progress').style.display = "block";
};
xhr.send(data);
}
});
</script>
Здесь при отправке формы с заполненными полями и прикрепленном файле мы можем наблюдать процесс загрузки в виде бегущей дорожки(индикатора) + отображении сколько из скольки МБ загружено.
За вывод информации загрузки отвечает функция loadProcess() которая принимает два параметра: количество МБ загруженных в определенную единицу времену и общее количество загружаемых МБ. Эти параметры мы получаем из события 'progress' объекта xhr(ajax).
xhr.upload.addEventListener('progress', function(e) {
if (e.lengthComputable) {
loadProcess((e.loaded / 1000000), (e.total / 1000000));
}
},false);
e.lengthComputable - возвращает true при загрузке определенной части данных
e.loaded - количество загруженных байтов за определенную единицу времени
e.total - общее количество байтов которые будут загружены по завершению загрузки
Этот же механизм для отображения процесса загрузки можно использовать в обратном направлении. То есть когда мы что то скачиваем с сервера.
Пример:
<style>
#progress{
position:fixed;
top:0%;
left:0%;
width:100%;
height:100%;
z-index:1000000;
background:rgba(0, 0, 0, 0.7);
display:none;
}
#progress div{
position:absolute;
top:50%;
left:50%;
transform:translate(-50%, -50%);
background:white;
padding:20px;
text-align:center;
}
</style>
<div id="progress" >
<div>
<h4>Загружено</h4>
<p id="load-progress">0%</p>
<progress id="progressbar" value="0" max="100"></progress>
<p id="size-progress"></p>
</div>
</div>
<button id="load">Скачать файл с сервера</button>
<script>
function loadProcess(a, len){
var one = len / 100;
var proc = (a / one).toFixed(1);
document.querySelector('#progressbar').value = (a / one);
document.querySelector('#load-progress').innerText = proc + '%';
document.querySelector('#size-progress').innerText = "Загружено: " + a.toFixed(2) + "МБ из " + len.toFixed(2) + "МБ";
}
document.querySelector('#load').addEventListener('click', function(){
var xhr = new XMLHttpRequest();
xhr.open('GET', '/video.mp4');
xhr.responseType = 'blob';
if(xhr.upload){
document.querySelector('#progress').style.display = "block";
xhr.addEventListener('progress', function(e) {
if (e.lengthComputable) {
loadProcess((e.loaded / 1000000), (e.total / 1000000));
}
},false);
xhr.onload = function(){
var url = URL.createObjectURL(this.response),
a = document.createElement('a');
a.href = url;
a.setAttribute('download', 'video.mp4');
a.click();
document.querySelector('#progress').style.display = "none";
};
xhr.send();
}
});
</script>
В данном примере мы с сервера скачиваем некий файл video.mp4. Обратите внимание что здесь немного по другому вызывается событие 'progress'.
xhr.addEventListener('progress', function(e) {
if (e.lengthComputable) {
loadProcess((e.loaded / 1000000), (e.total / 1000000));
}
},false);
При загрузке файлом мы вызывали событие через свойство upload(xhr.upload) здесь же мы вызываем событие напрямую. Для тех кто еще не понял вот сравнительный пример с комментариями:
//Процесс загрузки на сервер(используется свойство upload)
xhr.upload.addEventListener('progress', function(e) {
if (e.lengthComputable) {
loadProcess((e.loaded / 1000000), (e.total / 1000000));
}
},false);
// процесс загрузки с сервера
xhr.addEventListener('progress', function(e) {
if (e.lengthComputable) {
loadProcess((e.loaded / 1000000), (e.total / 1000000));
}
},false);
По сути с помощью xhr.upload мы отображаем процесс передачи байтов на сервер(запрос), а при использовании просто xhr процесс приема байтов с сервера(ответ).
Вот в принципе и все что я хотел вам рассказать про отображение процесса загрузки данных. Конечно данный механизм лучше использовать когда вы осуществляете процесс обмена большими данными, так как в ином случае особой необходимости его использовать нет, вы просто не увидите процесса(из за малого объема данных).
Надеюсь данная статья была для вас полезной! Не забывайте подписываться на группу Вконтакте и переходите на мой канал Youtube.
Желаю успехов и удачи! Пока.