Как на MVC с помощью PHP правильно загружать файлы на сервер. Часть Первая


X

Как на MVC с помощью PHP правильно загружать файлы на сервер. Часть Первая

Заходим в корень MVC и открываем файл .htaccess. В него нам потребуется добавить следующие параметры:

php_value upload_max_filesize 200M
php_value post_max_size 200M
php_value max_execution_time 1000000
php_value max_input_time 1000000

 

Первыми двумя строками мы задаем максимально допустимый размер файла, который может быть загружен на сервер. Третья и четвертая строки будут отвечать за максимальное время загрузки.

Теперь создадим HTML форму, в которой мы будем выбирать файл на загрузку. Создавать мы его будем в директории views/site. Создаем новый файл, даем ему название download_file.php. Он будет содержать следующий код:

<html>
<head></head>
<body>
<script>
    function CopyTxt() {
        function strtr(str, repl) {
            for (var i = 0; i < str.length; i++) {
                var f = str.charAt(i),
                   r = repl[f];
                if (r) {
                    str = str.replace(new RegExp(f, 'g'), r);
                }
            }
            return str;
        }

        var trans = {
            'А':'A', 'Б':'B', 'В':'V', 'Г':'G', 'Д':'D', 'Е':'E', 'Ё':'E', 'Ж':'Gh', 'З':'Z', 'И':'I', 'Й':'Y', 'К':'K', 'Л':'L', 'М':'M', 'Н':'N', 'О':'O', 'П':'P', 'Р':'R', 'С':'S', 'Т':'T', 'У':'U', 'Ф':'F', 'Х':'H', 'Ц':'C', 'Ч':'Ch', 'Ш':'Sh', 'Щ':'Sch', 'Ъ':'Y', 'Ы':'Y', 'Ь':'Y', 'Э':'E', 'Ю':'Yu', 'Я':'Ya', 'а':'a', 'б':'b', 'в':'v', 'г':'g', 'д':'d', 'е':'e', 'ё':'e', 'ж':'gh', 'з':'z', 'и':'i', 'й':'y', 'к':'k', 'л':'l', 'м':'m', 'н':'n', 'о':'o', 'п':'p', 'р':'r', 'с':'s', 'т':'t', 'у':'u', 'ф':'f', 'х':'h', 'ц':'c', 'ч':'ch', 'ш':'sh', 'щ':'sch', 'ъ':'y', 'ы':'y', 'ь':'y', 'э':'e', 'ю':'yu', 'я':'ya', ' ':'_'
        };

        var txt = strtr(document.getElementById('id1').value, trans);
        document.getElementById('id2').value = txt;
    }
</script>

 

В целях безопасности файлы на сервере рекомендуем хранить с названием на латинской раскладке. Чтобы избежать загрузки файла на кириллице  мы написали функцию CopyTxt. Функция берет строку из текстового поля id1 и с помощью функции strtr посимвольно заменяет кириллицу на латиницу, а затем возвращает строку в текстовое поле id2.

<h4>Загрузить файл</h4>
<br/>
Занятое место: <b><?= $hranilishe ?></b><br>
Свободное место: <b><?
    $svobod = 200 - $svobod;
    echo $svobod.' MB';
    ?></b><br>

Разрешеные форматы файлов: <b>*.PDF, *.TXT, *.DOC, *.DOCX, *.XLS, *.XLSX, *.ZIP, *.RAR, *.JPG, *.JPEG, *.PNG</b>
<br>
<?php if (isset($er_z) && is_array($er_z)): ?>
    <div style="padding:20px 20px 20px 20px; margin: 20px; background:#f1f1f1;">
        <ul style="color:red; width:100%;">
            <?php foreach ($er_z as $er_z): ?>
                <li style="line-height: 27px;"> - <?php echo $er_z; ?></li>
            <?php endforeach; ?>
        </ul>
    </div>
<?php endif; ?>

<?php if (isset($errors) && is_array($errors)): ?>
    <div style="padding:20px 20px 20px 20px; margin: 20px; background:#f1f1f1;">
        <ul style="color:red; width:100%;">
            <?php foreach ($errors as $error): ?>
                <li style="line-height: 27px;"> - <?php echo $error; ?></li>
            <?php endforeach; ?>
        </ul>
    </div>
<?php endif; ?>

<?php if (isset($true) && is_array($true)): ?>
    <div style="padding:20px 20px 20px 20px; margin: 20px; background:#f1f1f1;">
        <ul style="color:green; width:100%;">
            <?php foreach ($true as $true): ?>
                <li style="line-height: 27px;"> - <?php echo $true; ?></li>
           <?php endforeach; ?>
        </ul>
    </div>
<?php endif; ?>

 

Мы выделяем пользователю под файлы 200мб. Поэтому пользователю важно знать, какое количество памяти у него занято, а какое свободно. Для этого мы выводим ему переменную  $hranilishe в которой считается размер всех загруженных пользователем файлов (сам расчет будет ниже). И переменную $svobod в которой считается свободное место.

В процессе загрузки файла или в момент отправки формы могут возникнуть ошибки (они будут описаны далее), они записываются в массивы er_z и error, а также будут выводиться сообщения об успешной загрузке, они записываются в массив true. Далее все эти массивы выводятся с помощью цикла foreach красным и зеленым цветом, для ошибок и сообщений соответственно.

 

<form method="post" action=""  enctype="multipart/form-data" style="width:100%; ">
    <table class="admin_table">
        <tr>
            <td>Заголовок*</td>
            <td><input id="id1" onkeyup="CopyTxt()" type="text" name="title" size="80" value="<?=$_POST['title']?>"></td>
        </tr>
        <tr>
            <td>Дата*</td>
            <td><input type="date" name="date" size="10" value="<?=$_POST['date']?>"></td>
        </tr>
        <tr>
            <td>Указать файл*</td>
            <td><input name="img_url" type="file" /></td>
        </tr>
        <tr>
            <td>Автоматический Url*</td>
            <td><input id="id2" type="text" name="url" size="80" value="<?=$_POST['url']?>" style="background: #ececec; color:#777;"></td>
        </tr>
    </table>
    <input class="button" type="submit" name="submit" value="Сохранить"><br><br><br><br>
</form>
</body>
</html>

 

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

Загрузка фалов будем осуществлять в формате добавления файла. Создаем таблицу files в базе данных, там будут храниться данные о загруженных файлах и параметры.

 

 

После создания файла необходимо прописать маршрут для него в файле routes.php, он находится в папке config. После добавления пути файл routes.php будет выглядеть так:

<?php
return array(
    'download' => 'site/download',
    '' => 'site/index', // actionIndex в SiteController
);
?>

 

Теперь  заходим в папку controllers и открываем файл SiteController.php. Создаем метод actionDownload, в нем будет описана загрузка файлов с отображением самой страницы с формой.

<?
public function actionDownload()
{
    function HumanBytes($size)
    {
        $filesizename = array(" Bytes", " KB", " MB", " GB", " TB", " PB", " EB", " ZB", " YB");
        return $size ? round($size / pow(1024, ($i = floor(log($size, 1024)))), 2) . $filesizename[$i] : '0 Bytes';
    }
    $sum = Page::checkDisk();
    $hranilishe = HumanBytes($sum);
    $svobod = explode(' ', $hranilishe);
    if ((trim($svobod[0])) == 0) {
        $svobod = 0;
    } else {
        if ($svobod[1] !== 'MB') {
            $svobod = 1;
        } else {
            $svobod = (real)trim($svobod[0]);
        }
    }
?>

 

Размер файлов находящихся на сервере у нас хранится в байтах. Чтобы не путать пользователя мы написали метод HumanBytes, который возвращает размер файла мегабайтах и других единицах измерения. Делает это он с помощью функции round и добавления нужного расширения в конец.

Переменная $hranilishe, которая была использована на странице с формой, формируется здесь. С помощью функции checkDisk,(которую мы напишем позже в модели Page) . Она считает размер загруженных на сервер файлов и возвращает его в байтах. После этого мы применяем функцию HumanBytes и получаем размер в мегабайтах и других единицах измерения.

Далее формируем массив $svobod путем разбиения переменной $hranilishe через пробел. Далее если первый элемент полученного массива  равен нулю, что переменную $svobod  делаем равную нулю. Иначе проверяем вторую часть массива, если она равна МВ, то переменной $svobod присеваем  1, иначе присваиваем  переменной $svobod первую часть массива из которой убраны пробелы.

<?
    if ($svobod > 200) {
        $errors[] = 'Нет места в хранилище, свяжитесь с разработчиками!';
    } else {
        if (isset($_POST['submit'])) {
            $title = $_POST['title'];
            $date = $_POST['date'];
            $size = $_FILES['img_url']['size'];
            $url = $_POST['url'];
            $name = $_FILES['img_url']['name'];
            $tmp_name = $_FILES['img_url']['tmp_name'];

            // Флаг ошибок
            $errors = false;
            $true = false;
            $er_z = false;

            $inf = pathinfo($name);
            if (!$date) { $er_z[] = 'Укажите дату'; }
            if (!$url) {
                $er_z[] = 'Введите название новости вручную т.к. автоматический урл не может сгенирироваться';
            }
            if ($er_z == false) {
                $rash = $inf['extension'];
                if (Page::checkNameFile($url, $rash)) {
                    if ($rash === 'pdf') {
                        $true[] = 'Формат файла PDF';
                        $errors = true;
                    }

                    if ($rash === 'PDF') {
                        $true[] = 'Формат файла PDF';
                        $errors = true;
                    }

                    if ($rash === 'txt') {
                        $true[] = 'Формат файла TXT';
                        $errors = true;
                    }

                    if ($rash === 'doc') {
                        $true[] = 'Формат файла DOC';
                        $errors = true;
                    }

                    if ($rash === 'xls') {
                        $true[] = 'Формат файла XLS';
                        $errors = true;
                    }

                    if ($rash === 'docx') {
                        $true[] = 'Формат файла DOCX';
                        $errors = true;
                    }

                    if ($rash === 'xlsx') {
                        $true[] = 'Формат файла XLSX';
                        $errors = true;
                    }

                    if ($rash === 'zip') {
                        $true[] = 'Формат файла ZIP';
                        $errors = true;

                    }

                    if ($rash === 'rar') {
                        $true[] = 'Формат файла RAR';
                        $errors = true;
                    }

                    if ($rash === 'jpg') {
                        $true[] = 'Формат файла JPG';
                        $errors = true;
                    }

                    if ($rash === 'jpeg') {
                        $true[] = 'Формат файла JPG';
                        $errors = true;
                    }

                    if ($rash === 'png') {
                        $true[] = 'Формат файла PNG';
                        $errors = true;
                    }

?>

 

Методом POST получаем введенные в поля данные и сведения о файле. Записываем их в переменные. С помощью функции pathinfo() получаем массив $inf, который содержит информацию о пути загружаемого файла. Проверяем, все ли поля заполнены и выбран ли файл, если нет, то на странице отобразятся ошибки по неправильным полям. Если же все хорошо, то мы проходим дальше.

Из массива $inf передаем расширение загружаемого файла в переменную $rash.  Также проверяем, нет ли файла с таким именем среди загруженных ранее файлов, для этого используется функция checkNameFile, находящиеся в модели Page.

Проверяем расширение файла. Если расширение файла совпало с одним из «разрешенных», то переменной $errors присваиваем true.

<?

                    if ($errors == true) {
                        Page::downloadFile($url, $tmp_name, $rash);
                        $result = Page::add_news($title, $date, $url, $rash, $size);
                        if ($result == true) {
                            $true[] = 'Файл загружен.';
                        } else {
                            $errors[] = 'Ошибка загрузки!';
                        }

                    } else {
                        $errors[] = 'Загружаемые файлы могут быть в формате *.PDF, *.TXT, *.DOC, *.DOCX, *.XLS, *.XLSX, *.ZIP, *.RAR, *.JPG, *.JPEG, *.PNG';
                    }
                } else {
                    $errors[] = 'Такой файл уже есть в хранилище, измените Заголовок файла, и повторно выберите файл';
                }
            }
        }
    }

    require_once(ROOT . '/views/site/download_file.php');
    return true;
}
?> 

 

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

В конце подключаем вид страницы с формой.

Теперь опишем используемые функции в модели Page. Переходим в папку models и открываем файл Page.php. Добавляем в него следующие функции:

<?

public static function checkDisk(){
    $db = Db::getConnection();
    $query = "SELECT sum(size) FROM  `files`";
    $sum = $db->query($query)->fetchColumn();
    return $sum;
}

?>

 

checkDisk, эта функция возвращает сумму всех загруженных на сервер файлов.

 

<?

public static function checkNameFile($url, $rash){
    $filename = 'img/'.$url.'.'.$rash;
    if (file_exists($filename)) {
        return false; //"Файл $filename существует";
    } else {
        return true;//"Файл $filename несуществует";
    }

}

?>

 

checkNameFile, проверяет нет ли на сервере файла с таким же именем. Делается это с помощью функции file_exists, она проверяет, существует ли файл в указанном каталоге.

 

<?

public static function downloadFile($name, $tmp_name, $rash)
    {
        if ($rash == 'zip') {
            // Имя файла
            $filename = $tmp_name;
// Разбиваем файл на части по 10 Kb
            $piece = 250000;
// Открываем исходный файл для чтения
            $fp = fopen($filename, "r");
// Читаем содержимое файла в буфер
            $bufer = fread($fp, filesize($filename));
// Закрываем файл
            fclose($fp);
// Подсчитываем число частей, на которые необходимо разбить файл
            $count = (int)filesize($filename)/$piece;
            if((float)(filesize($filename)/$piece) - $count != 0) $count++;
// В цикле разбиваем содержимое файла в переменной
// $bufer на части
            for($i=0; $i<$count; ++$i)
            {
                $part = substr($bufer,$i*$piece,$piece);
// Сохраняем текущую часть в отдельном файле
                $fp = fopen("part/big_file.part".$i,"w");
                fwrite($fp,$part);
                fclose($fp);
            }
            $buffer = "";
            for($i=0; $i<$count; ++$i)
            {
                // Генерируем имя файла
                $filename = "part/big_file.part".$i;
                // Если такой файл существует,
                // добавляем его содержимое к $buffer
                if(file_exists($filename))
                {
                    $fp = fopen($filename,"r");
                    $buffer .= fread($fp,filesize($filename));
                    fclose($fp);
                }
                else
                {
                    // Если файла с таким именем не
                    // существует, выходим из цикла
                    break;
                }
                // Склеенные в переменной $bufer
                // части помещаем в конечный файл

                $fp = fopen('files/'.$name.'.'.$rash,"w");
                fwrite($fp, $buffer);
                fclose($fp);
                unlink($filename);
            }

        } else {
           $uploaddir = 'files/';
            $uploadfile = $uploaddir . basename($name . '.' . $rash);
            if (move_uploaded_file($tmp_name, $uploadfile)) {
                $true[] = 'Pагрузки!';
            } else {
                $errors[] = 'Ошибка загрузки!';
            }
        }
}

?>

 

downloadFile, функция загружает файл на сервер. Если файл имеет расширение .zip то он разбивает его на части и затем сохраняет. Остальные файлы мы напрямую сохраняем в папке files.

 

<?
public static function add_news($title, $date, $url, $rash, $size)
    {
       // Соединение с БД
        $db = Db::getConnection();
        // Текст запроса к БД
        $sql = 'INSERT INTO files (title, date, url, rash, size) VALUES (:title, :date, :url, :rash, :size)';
        // Получение и возврат результатов. Используется подготовленный запрос
        $result = $db->prepare($sql);
        $result->bindParam(':title', $title, PDO::PARAM_STR);
        $result->bindParam(':date', $date, PDO::PARAM_STR);
        $result->bindParam(':url', $url, PDO::PARAM_STR);
        $result->bindParam(':rash', $rash, PDO::PARAM_STR);
        $result->bindParam(':size', $size, PDO::PARAM_STR);
        return $result->execute();
    }
}

?>

 

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

Grai Просмотров сегодня +1 16 июня 2017 команда сайта
Создание сайтов и мобильных приложений от 5 500 руб. Любой сложности!
Реклама Собственный фреймворк. Большие и сложные проекты. ТОП 100 разработчиков РФ.
Создание сайтов от 5 500 руб.
Мобильные приложения от 50 000 руб.
irogex.ru
Наши проекты Инстаграм от 6 500 руб.
Конструкторы Ugears купить в Иркутске от 690 руб. с Доставкой!
Реклама UGEARS это путешествие в удивительную атмосферу гармонии природы и совершенства конструкторской мысли
Конструктор Навигатор дат - 690 руб.
Конструктор Комбайн - 2990 руб.
ugears-irk.ru
Оплата и Доставка Контакты
Стоматология в Улан-Удэ | ДентаВита | Шок цены от 100 руб!
Реклама От всей нашей семьи хотим выразить огромную благодарность стоматологической клинике
Осмотр, консультация от 150 руб.
Рентгеновский снимок от 100 руб.
dentavita03.ru
Наши цены Отзывы
Реклама помогает поддерживать
и развивать наш сервис.


Подробнее
(ссылка откроется в новой вкладке)
  Реклама