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

Шаг 1 — Базовый HTML
Давайте начнем. Первое, что нам нужно, это пустой 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>
|
Шаг 2 — Добавление формы загрузки файла
Хорошо, теперь, когда у нас есть базовый 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» пуст. Не беспокойтесь об этом прямо сейчас, так как мы заполним этот раздел файлами на сервере.
Шаг 3 — Добавить CSS и JS
Я использовал 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;
}
|
То, что мы теперь должны иметь, показано на следующем рисунке.

Шаг 4 — Обработка ввода файлов с помощью PHP
Давайте начнем с 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.
Шаг 5 — список загруженных файлов
|
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;
|
Шаг 6 — Вспомогательная функция
Функция 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, и все готово.
Шаг 7 — Касание 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 .
Теперь то, что мы должны иметь, это что-то вроде этого

Ах, намного лучше.
Шаг 8 — Переключение видимости файлов с помощью jQuery
В завершение добавим немного дополнительной функциональности с помощью 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 документа, как показано выше.
Теперь меню «кнопки» должно работать и при нажатии на них список файлов должен измениться.

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

- Подпишитесь на нас в Твиттере или подпишитесь на RSS-канал NETTUTS, чтобы получать ежедневные обзоры и статьи о веб-разработке.
