1. Code
  2. PHP

Сетевое хранилище файлов на PHP

Scroll to top

Russian (Pусский) translation by Anna Goorikova (you can also view the original English article)

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

Введение

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

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

Шаг 1 - Основной HTML

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

1
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2
<html xmlns="http://www.w3.org/1999/xhtml">
3
<head>
4
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
5
<title>Online file storage</title>
6
</head>
7
<body>
8
9
</body>
10
</html>

Шаг 2 - Добавление формы загрузки файла

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

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

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

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

1
<div id="container">
2
  <h1>Online File Storage</h1>
3
	
4
	<fieldset>
5
		<legend>Add a new file to the storage</legend>
6
		<form method="post" action="index.php" enctype="multipart/form-data">
7
		<input type="hidden" name="MAX_FILE_SIZE" value="100000" />
8
		<p><label for="name">Select file</label><br />
9
		<input type="file" name="file" /></p>
10
		<p><label for="password">Password for upload</label><br />
11
		<input type="password" name="password" /></p>
12
		<p><input type="submit" name="submit" value="Start upload" /></p>
13
		</form>	
14
	</fieldset>
15
</div>

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

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

1
<fieldset>
2
	<legend>Previousely uploaded files</legend>
3
	<ul id="menu">
4
		<li><a href="">All files</a></li>
5
		<li><a href="">Documents</a></li>
6
		<li><a href="">Images</a></li>
7
		<li><a href="">Applications</a></li>
8
	</ul>
9
	
10
	<ul id="files">
11
	</ul>
12
</fieldset>

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

Шаг 3 - Добавление CSS и JS

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

1
<style type="text/css" media="all"> 
2
	@import url("style/style.css");
3
</style>
4
<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, но для всех это достаточно просто.

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

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

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

Шаг 4 - Обработка переданных файлов с помощью PHP

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

1
<?php
2
/**

3
 * Class Settings holds the upload settings

4
 *

5
 */
6
class Settings
7
{
8
	static $password = "mypassword";
9
	static $uploadFolder = "uploads/";
10
}
11
?>

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

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

1
<?php 
2
//Load the settings

3
require_once("settings.php");
4
5
$message = "";

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

1
//Has the user uploaded something?

2
if(isset($_FILES['file']))
3
{

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

1
	$target_path = Settings::$uploadFolder;
2
	$target_path = $target_path . time() . '_' . basename( $_FILES['file']['name']);

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

1
	//Check the password to verify legal upload

2
	if($_POST['password'] != Settings::$password)
3
	{
4
		$message = "Invalid Password!";
5
	}
6
	else
7
	{

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

1
		//Try to move the uploaded file into the designated folder

2
		if(move_uploaded_file($_FILES['file']['tmp_name'], $target_path)) {
3
		    $message = "The file ".  basename( $_FILES['file']['name']). 
4
		    " has been uploaded";
5
		} else{
6
		    $message = "There was an error uploading the file, please try again!";
7
		}
8
	}
9
}

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

1
if(strlen($message) > 0)
2
{
3
	$message = '<p class="error">' . $message . '</p>';
4
}

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

Шаг 5 - Список загруженных файлов

1
/** LIST UPLOADED FILES **/
2
$uploaded_files = "";
3
4
//Open directory for reading

5
$dh = opendir(Settings::$uploadFolder);

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

1
//LOOP through the files

2
while (($file = readdir($dh)) !== false) 
3
{

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

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

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

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

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

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

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

1
		$filetype = getFileType(substr($file, strlen($file) - 3));
2
        $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
if(strlen($uploaded_files) == 0)
2
{
3
	$uploaded_files = "<li><em>No files found</em></li>";
4
}

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

Нам также нужно показать строку uploaded_files; поэтому добавьте эту строку внутри <ul> с id "files".

1
<?php echo $uploaded_files; ?>

Шаг 6 - Вспомогательная функция

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

1
function getFileType($extension)
2
{
3
	$images = array('jpg', 'gif', 'png', 'bmp');
4
	$docs 	= array('txt', 'rtf', 'doc');
5
	$apps 	= array('zip', 'rar', 'exe');
6
	
7
	if(in_array($extension, $images)) return "Images";
8
	if(in_array($extension, $docs)) return "Documents";
9
	if(in_array($extension, $apps)) return "Applications";
10
	return "";
11
}

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

1
function formatBytes($bytes, $precision = 2) { 
2
    $units = array('B', 'KB', 'MB', 'GB', 'TB'); 
3
   
4
    $bytes = max($bytes, 0); 
5
    $pow = floor(($bytes ? log($bytes) : 0) / log(1024)); 
6
    $pow = min($pow, count($units) - 1); 
7
   
8
    $bytes /= pow(1024, $pow); 
9
   
10
    return round($bytes, $precision) . ' ' . $units[$pow]; 
11
} 
12
?>

И это для части PHP. Еще немного JS и CSS, и мы все закончили.

Шаг 7 - Немного CSS для повышения удобочитаемости

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

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

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

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

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

Шаг 8 - Переключение видимости файла с помощью jQuery

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

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

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

1
function HideFiles(selector)
2
{
3
	//show all files

4
	if(selector === "All files")
5
	{
6
		$("#files > li").show();
7
		return true;
8
	}
9
	else
10
	{
11
		//show only the selected filetype

12
		$("#files > li").hide();
13
		$("#files > li." + selector).show();
14
		return true;
15
	}	
16
}

Функция HideFiles выполняет две функции. Если селектор параметров равен 'All files', функция проходит все элементы <li> внутри списка файлов <ul> и делает их видимыми.
Если, однако, был предоставлен какой-то другой параметр, функция скрывает все, а затем отображает только те, которые имеют такое же имя класса, что и параметр.

1
function prepareMenu()
2
{ 
3
	$("#menu li").click( 
4
		function () {            
5
			$("#menu li").each(
6
				function(){
7
					$(this).removeClass("active");
8
				}
9
			);
10
			$(this).addClass("active");
11
			HideFiles($(this).children().html());
12
	    return false;
13
	});
14
15
	//Select the first as default

16
	$("#menu li:first").click();
17
}

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

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

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

Шаг 9 - Поздравляем себя за работу.

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

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

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

  • Следуйте за нами в Твиттере или подпишитесь на RSS-канал NETTUTS для получения ежедневных веб-разработок и статей.