Статьи

Интернет-хранилище файлов с PHP

В этом уроке я покажу вам, как легко создать онлайн систему хранения файлов с помощью PHP. Вы узнаете, как загружать файлы с помощью PHP и перечислять их путем сканирования папки «uploads».

Вы когда-нибудь хотели, чтобы у вас было место для загрузки файлов в дороге? Что если вы используете общедоступный терминал или чужой компьютер и не можете установить какое-либо стороннее программное обеспечение для передачи файлов?
Разве не было бы просто открыть страницу в браузере и загрузить файл одним нажатием кнопки?

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

Давайте начнем. Первое, что нам нужно, это пустой HTML-документ. Я использую XHTML 1.0 Transitional с набором символов ISO-8859-1. Если вы предпочитаете и не нуждаетесь в специальных символах, вы можете заменить это на набор символов UTF-8.

01
02
03
04
05
06
07
08
09
10
<!DOCTYPE html PUBLIC «-//W3C//DTD XHTML 1.0 Transitional//EN» «http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd»>
<html xmlns=»http://www.w3.org/1999/xhtml»>
<head>
<meta http-equiv=»Content-Type» content=»text/html; charset=ISO-8859-1″ />
<title>Online file storage</title>
</head>
<body>
 
</body>
</html>

Хорошо, теперь, когда у нас есть базовый HTML-файл, у нас практически ничего нет 🙂 Итак, давайте добавим немного контента. Я оберну все содержимое в элементе DIV, чтобы помочь стилизовать страницу с помощью CSS. Теги Fieldset и Legend, возможно, встречаются довольно редко, но они представляют собой определенную разметку для организации контента в группы.

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

Обратите внимание, что в отличие от стандартного повседневного элемента Form этот элемент имеет тип multipart / form-data.
Это необходимо для размещения файлов POSTing и должно быть здесь. Я установил модификатор действия, чтобы он указывал на тот же файл.
Это означает, что после отправки формы данные формы будут отправлены обратно на ту же страницу.

Скрытое поле MAX_FILE_SIZE предназначено для PHP и определяет максимальный размер (в байтах), который мы можем отправить. Это, однако, не переопределит параметр MAX_FILE_SIZE в файле php.ini, поэтому он всегда будет тем, который определяет максимальный размер.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
<div id=»container»>
    <h1>Online File Storage</h1>
     
    <fieldset>
        <legend>Add a new file to the storage</legend>
        <form method=»post» action=»index.php» enctype=»multipart/form-data»>
        <input type=»hidden» name=»MAX_FILE_SIZE» value=»100000″ />
        <p><label for=»name»>Select file</label><br />
        <input type=»file» name=»file» /></p>
        <p><label for=»password»>Password for upload</label><br />
        <input type=»password» name=»password» /></p>
        <p><input type=»submit» name=»submit» value=»Start upload» /></p>
        </form>
    </fieldset>
</div>

Если мы откроем файл в браузере, теперь у нас будет скучная и простая HTML-форма. Он будет отправлять контент самому себе, но не будет знать, что с ним делать.

Нам нужно место для отображения файлов, которые мы уже загрузили; поэтому добавьте следующий HTML-код внутри контейнера div под первым набором полей.

01
02
03
04
05
06
07
08
09
10
11
12
<fieldset>
    <legend>Previousely uploaded files</legend>
    <ul id=»menu»>
        <li><a href=»»>All files</a></li>
        <li><a href=»»>Documents</a></li>
        <li><a href=»»>Images</a></li>
        <li><a href=»»>Applications</a></li>
    </ul>
     
    <ul id=»files»>
    </ul>
</fieldset>

Обратите внимание, что неупорядоченный список с идентификатором «files» пуст. Не беспокойтесь об этом прямо сейчас, так как мы заполним этот раздел файлами на сервере.

Я использовал jQuery, чтобы создать возможность переключать видимость файлов определенных типов без обновления страницы.
Это совершенно необязательно, и удаление JS несколько ускорит загрузку страницы. Итак, давайте добавим следующие строки в заголовок HTML-файла.

1
2
3
4
<style type=»text/css» media=»all»>
    @import url(«style/style.css»);
</style>
<script src=»http://code.jquery.com/jquery-latest.js»></script>

Я загружаю jQuery из внешнего источника во время выполнения. Опять же, если вы предпочитаете, вы можете изменить это так, чтобы файл загружался из локального источника с этой строкой.

1
<script type=»text/javascript» src=»js/jquery-1.3.2.min.js»></script>

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

Создайте новую папку с именем style и создайте в ней новый CSS-файл с именем style.css. Это будет файл, который сообщает браузеру, как мы хотим, чтобы страница выглядела. Здесь довольно много CSS, но это достаточно просто для всех.

Теперь страница должна выглядеть примерно так:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
@CHARSET «ISO-8859-1»;
 
body
{
    background-color: #cddcec;
    font-family: «Arial»;
    font-size: 11px;
}
 
div#container
{
    width: 600px;
    margin: 0px auto;
    border: 1px solid #e6eef6;
    background-color: #ffffff;
}
 
div#container h1
{
    background-color: #4b75b3;
    margin: 0px;
    padding: 8px;
    font-family: «Arial»;
    font-weight: normal;
    border: 1px solid #3564a9;
}
 
div#container fieldset
{
    margin: 20px;
    border: 1px solid #98b9d0;
}
 
ul#menu
{
    list-style-type: none;
    margin: 4px;
    padding: 0px;
}
 
ul#menu li
{
    float: left;
    margin: 4px;
}
 
ul#menu li.active
{
    background-color: #98b9d0;
    border-left: 1px solid #3564a9;
    border-top: 1px solid #3564a9;
    border-bottom: 1px solid #e6eef6;
    border-right: 1px solid #e6eef6;
}
 
ul#menu li a
{
    text-decoration: none;
    font-size: 10px;
    padding: 2px;
    color: #3564a9;
}
 
ul#files
{
    list-style-type: none;
    margin: 40px 0px 0px 0px;
    padding: 0px;
}
 
ul#files li
{
    background-color: #fff7c0;
    border-bottom: 1px solid #efefef;
    padding: 2px;
    margin-bottom: 1px;
}

То, что мы теперь должны иметь, показано на следующем рисунке.

Давайте начнем с PHP-части урока, создав класс Settings. В этом классе мы можем сохранить пароль для загрузки, а также путь к файлу для папки загрузки.
Затем мы можем включить класс на нашу страницу и использовать его значения при необходимости.
Вы можете писать файлы PHP практически с теми же инструментами, которые используете для написания HTML и CSS, просто не забудьте сохранить файл с суффиксом .php.

01
02
03
04
05
06
07
08
09
10
11
<?php
/**
 * Class Settings holds the upload settings
 *
 */
class Settings
{
    static $password = «mypassword»;
    static $uploadFolder = «uploads/»;
}
?>

Не углубляясь в объектно-ориентированное программирование (ООП), код создает новый класс со значениями, к которым можно обращаться без создания экземпляра класса.
Теперь мы можем получить доступ к его значениям, просто вызвав Settings :: $ password; и Настройки :: $ uploadFolder; Это также место, где вы можете изменить пароль, когда пожелаете.
<? Php и?> Отмечают начало и конец сегмента кода PHP. Эти сегменты могут быть записаны внутри обычных HTML-страниц, и сервер будет интерпретировать их при запросе страницы.

Хорошо, теперь мы приступаем к делу. В HTML-файле, с которым мы работали, давайте добавим следующее в самый верх файла. Да, перед тегом <head>.

1
2
3
4
5
<?php
//Load the settings
require_once(«settings.php»);
 
$message = «»;

Сначала мы говорим интерпретатору PHP включить наш файл настроек. Я также установил новую переменную $ message. Позже я запишу информацию о процессе в эту переменную и покажу ее пользователю.

1
2
3
//Has the user uploaded something?
if(isset($_FILES[‘file’]))
{

Если форма была отправлена ​​с файлом, массив $ _FILE должен иметь значение с ключом, который мы использовали в качестве имени поля ввода файла.

1
2
$target_path = Settings::$uploadFolder;
$target_path = $target_path .

Здесь мы получаем путь к папке загрузки, которую мы указали в настройках. В строке 2 мы добавляем (объединяем) имя загруженного файла в целевой путь.
Также обратите внимание, что я добавил текущую временную метку сервера в начало имени файла. Для этого есть две причины.
Во-первых, он используется для хранения даты, а во-вторых, он будет гарантировать, что все файлы имеют разные имена.
Если бы мы использовали базу данных позади этого приложения, время добавления было бы там, и мы могли бы сериализовать имена файлов и сохранить исходное имя только в таблице базы данных,
но поскольку нет базы данных, мы можем просто использовать этот обходной путь.

1
2
3
4
5
6
7
//Check the password to verify legal upload
if($_POST[‘password’] != Settings::$password)
{
    $message = «Invalid Password!»;
}
else
{

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

1
2
3
4
5
6
7
8
9
        //Try to move the uploaded file into the designated folder
        if(move_uploaded_file($_FILES[‘file’][‘tmp_name’], $target_path)) {
            $message = «The file «.
            » has been uploaded»;
        } else{
            $message = «There was an error uploading the file, please try again!»;
        }
    }
}

Итак, пароль был верен, что теперь? Теперь мы «сохраняем» файл. Я говорю сохранить в скобках, так как файл на самом деле уже находится на сервере; это просто во временной папке.
Таким образом, чтобы сделать файл доступным и убедиться, что сервер не удалит его после очистки временного пространства, мы должны переместить его в какое-то безопасное место. Я использовал функцию move_uploaded_file.
Функция принимает два аргумента. Первый — это временное имя файла, автоматически назначаемое сервером, а второй — целевой путь, который мы указали ранее.
Функция возвращает логическое значение, указывающее на успешную операцию. Мы снова устанавливаем значение сообщения, чтобы сообщить пользователю, что произошло.

1
2
3
4
if(strlen($message) > 0)
{
    $message = ‘<p class=»error»>’ .
}

И вот как легко загружать файлы на сервер с помощью PHP! Здесь я только что проверил, было ли что-либо записано в переменную сообщения (длина больше 0) и отформатировал его, чтобы мы могли стилизовать его с помощью CSS.

1
2
3
4
5
/** LIST UPLOADED FILES **/
$uploaded_files = «»;
 
//Open directory for reading
$dh = opendir(Settings::$uploadFolder);

Первое, что нужно сделать, это создать дескриптор папки. Все, что нужно, это одна команда. Переменная uploaded_files — это место, где мы будем записывать имена папок в формате HTML.

1
2
3
//LOOP through the files
while (($file = readdir($dh)) !== false)
{

Здесь мы перебираем файлы в папке. Пока мы можем читать следующий файл в папке в файловой переменной, мы делаем это и идем дальше. Как только мы проверим все файлы, функция вернет false и завершит цикл.

1
2
if($file != ‘.’ && $file != ‘..’)
{

«.» и ‘..’ также возвращаются этой функцией, поэтому мы должны убедиться, что мы не пытаемся ничего с ними сделать.

1
2
$filename = Settings::$uploadFolder .
$parts = explode(«_», $file);

Мы добавляем имя файла в путь к папке загрузки и сохраняем его как переменную имени файла. Затем мы взрываем имя файла с символом ‘_’.
Эта функция возвращает массив строк, разделяющих исходную строку каждый раз, когда есть ‘_’.
Поскольку есть один из этих символов, мы получим массив с частью метки времени в качестве ячейки 1 и исходным именем файла в качестве ячейки 2.

1
2
3
$size = formatBytes(filesize($filename));
$added = date(«m/d/Y», $parts[0]);
$origName = $parts[1];

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

1
2
$filetype = getFileType(substr($file, strlen($file) — 3));
$uploaded_files .= «<li class=\»$filetype\»><a href=\»$filename\»>$origName</a> $size — $added</li>\n»;

При загрузке файла на сервер PHP предоставляет нам информацию о типе файла, но, поскольку у нас нет места для хранения этой информации, нам придется попытаться получить тип файла с помощью пользовательской функции.
Я даю три последних символа имени файла в качестве параметра функции getFileType (будет показано позже). Я использую переменную filetype для стилизации различных файлов с помощью CSS.
Теперь осталось только сгенерировать строку HTML и добавить ее в переменную uploaded_files и закрыть дескриптор папки.

1
2
3
    }
}
closedir($dh);
1
2
3
4
if(strlen($uploaded_files) == 0)
{
    $uploaded_files = «<li><em>No files found</em></li>»;
}

Если файлы не найдены, установите переменную uploaded_files для отображения сообщения.

Мы также должны где-то показать строку uploaded_files; поэтому добавьте эту строку внутри <ul> с идентификатором ‘files’.

1
<?php echo $uploaded_files;

Функция getFileType пытается угадать, к какому типу относится файл, читая последние символы его имени. Это не будет работать с расширениями, такими как .jpeg и .tiff.
Чтобы сделать его более универсальным, нам нужно прочитать подстроку, начинающуюся с точки и заканчивающуюся до конца имени файла.
Но тогда, если имя будет что-то вроде my.new.car.pic, мы получим new.car.pic в качестве расширений.
Таким образом, чтобы это действительно работало, нам нужно найти последний период в имени и взять с него подстроку.
Но для целей этого урока это достаточно близко.

01
02
03
04
05
06
07
08
09
10
11
function getFileType($extension)
{
    $images = array(‘jpg’, ‘gif’, ‘png’, ‘bmp’);
    $docs = array(‘txt’, ‘rtf’, ‘doc’);
    $apps = array(‘zip’, ‘rar’, ‘exe’);
     
    if(in_array($extension, $images)) return «Images»;
    if(in_array($extension, $docs)) return «Documents»;
    if(in_array($extension, $apps)) return «Applications»;
    return «»;
}

Эта следующая функция форматирует байты в более читаемый формат. Просто базовая математика — больше ничего. Сама функция взята из комментариев к функции PHP.net.

01
02
03
04
05
06
07
08
09
10
11
12
function formatBytes($bytes, $precision = 2) {
    $units = array(‘B’, ‘KB’, ‘MB’, ‘GB’, ‘TB’);
    
    $bytes = max($bytes, 0);
    $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
    $pow = min($pow, count($units) — 1);
    
    $bytes /= pow(1024, $pow);
    
    return round($bytes, $precision) .
}
?>

И это все, что касается PHP. Просто еще немного JS и CSS, и все готово.

То, что у нас так далеко, должно выглядеть так:

Но чтобы эффективно использовать функцию getFileType и имя класса, которое она возвращает, я добавил следующие строки CSS в файл style.css.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
ul#files li a
{
    text-decoration: none;
    color: #3564a9;
    padding: 2px 25px;
    background-position: left;
    background-repeat: no-repeat;
}
 
ul#files li.Documents a
{
    background-image: url(‘../images/text.jpg’);
}
 
ul#files li.Images a
{
    background-image: url(‘../images/picture.jpg’);
}
 
ul#files li.Applications a
{
    background-image: url(‘../images/zip.jpg’);
}
 
p.error
{
    background-color: #fff7c0;
    border-bottom: 1px solid #efefef;
    font-weight: bold;
    color: #ff0000;
    padding: 6px;
}

Я назначаю значок для каждого типа файла. Иконы, которые я использовал, взяты из великолепной коллекции, найденной на http://www.famfamfam.com .
Теперь то, что мы должны иметь, это что-то вроде этого

Ах, намного лучше.

В завершение добавим немного дополнительной функциональности с помощью JavaScript. Создайте новую папку с именем «js» и в этой папке создайте новый файл filestorage.js.
Затем добавьте следующую строку в конец страницы HTML прямо перед тегом </ body>.

1
<script src=»js/filestorage.js» />

Рекомендуется включать js-файлы такого рода в самый конец страницы, чтобы сначала загрузить объектную модель документа (DOM).

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
function HideFiles(selector)
{
    //show all files
    if(selector === «All files»)
    {
        $(«#files > li»).show();
        return true;
    }
    else
    {
        //show only the selected filetype
        $(«#files > li»).hide();
        $(«#files > li.» + selector).show();
        return true;
    }
}

Функция HideFiles делает две вещи. Если селектор параметров равен «Все файлы», функция просматривает все элементы <li> внутри файлов <ul> и делает их видимыми.
Однако, если был задан какой-то другой параметр, функция скрывает все, а затем показывает только те, у которых имя класса совпадает с параметром.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
function prepareMenu()
{
    $(«#menu li»).click(
        function () {
            $(«#menu li»).each(
                function(){
                    $(this).removeClass(«active»);
                }
            );
            $(this).addClass(«active»);
            HideFiles($(this).children().html());
        return false;
    });
 
    //Select the first as default
    $(«#menu li:first»).click();
}

Функция prepareMenu добавляет функцию к событию onClick в меню <li>.
После щелчка удалите класс ‘active’ из всех них, а затем добавьте его к тому, который был нажат, и вызовите функцию HideFiles с текстом внутри элемента внутри <li>, по которому щелкнули.
Наконец, мы вызываем событие onClick в первом элементе меню, чтобы убедиться, что оно выбрано по умолчанию при загрузке страницы.

1
2
3
4
$(document).ready(function()
{
    prepareMenu();
});

Не забудьте вызвать функцию prepareMenu при загрузке страницы. Это можно легко сделать, вызвав его внутри события ready документа, как показано выше.
Теперь меню «кнопки» должно работать и при нажатии на них список файлов должен измениться.

Это оно! Теперь у вас должно быть рабочее онлайн-хранилище файлов.
Просто не забудьте создать «uploadFolder» и изменить его CHMOD для внесения изменений. Инструкции для этого можно найти по всему Интернету и непосредственно от вашего хостинг-провайдера.

Это был учебник для начинающих. Надеюсь, это было достаточно подробно, не будучи слишком объяснительным.

Спасибо за прочтение и оставьте комментарий, если у вас есть какие-либо вопросы.