Extra Block Types (EBT) - New Layout Builder experience❗

Extra Block Types (EBT) - styled, customizable block types: Slideshows, Tabs, Cards, Accordions and many others. Built-in settings for background, DOM Box, javascript plugins. Experience the future of layout building today.

Demo EBT modules Download EBT modules

❗Extra Paragraph Types (EPT) - New Paragraphs experience

Extra Paragraph Types (EPT) - analogical paragraph based set of modules.

Demo EPT modules Download EPT modules

Scroll

Уроки PHP - урок 3.5 - Работа с БД MySQL. Оператор JOIN. Загрузка файлов на сервер.

08/12/2019, by Ivan

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

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

$content .=	'<form action="' . $_SERVER['PHP_SELF'] . '" method="post" enctype="multipart/form-data">'; 

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

  public function display_admin() { // метод ввода сообщения
	$content = '';
	
	$content .=	'<form action="' . $_SERVER['PHP_SELF'] . '" method="post" enctype="multipart/form-data">'; 
	$content .=	  '<label for="title">Имя:</label><br />';
	$content .=	  '<input name="title" id="title" type="text" maxlength="150" />';
	$content .=	  '<div class="clear"></div>';
	$content .=	  '<label for="bodytext">Сообщение:</label><br />';
	$content .=	  '<textarea name="bodytext" id="bodytext"></textarea>';
	$content .=        '<input type="file" name="filename">'; // поле загрузки файла
	$content .=	  '<div class="clear"></div>';
	$content .=	  '<input type="submit" value="Добавить сообщение" />';
	$content .=	'</form>';	
	$content .=	'<p><a href="/index.php">Вернуться на главную</a></p>';

    return $content;
  }

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

Теперь давайте посмотрим каким образом передается файл в запросе POST.

  public function write($p) { 
	print_r($p); // распечатаем массив формы
	print_r($_FILES); // распечатываем массив файлов
    $sql = 'INSERT INTO Messages (title, bodytext, created) VALUES ("'. $p["title"] . '", "' . $p["bodytext"] . '", ' . time() . ')';
    return mysql_query($sql);
  } 

Теперь поставим на загрузку какой-нибудь файл и сохраним сообщение. Все файлы которые будут загружены через форму, будут доступны в суперглобальной переменной $_FILES. Я загрузил файл и получил вот такие массивы:

Array ( 
  [title] => asfasdf 
  [bodytext] => asfasdf 
) 
Array ( 
  [filename] => Array ( 
    [name] => ip.txt 
    [type] => text/plain 
    [tmp_name] => Y:\tmp\phpAA.tmp 
    [error] => 0 
    [size] => 13 
   ) 
) 

Теперь когда у нас есть массив данных и файла, давайте создадим таблицу файлов, чтобы сохранять загруженные файлы. Начнем с того что создадим папку files в корне нашего сайта и если у вас ОС семейства linux или вы работаете на хостинге, то дайте права на эту папку 777, чтобы наш скрипт мог сохранять файлы в эту папку.

Изменим запрос создания таблиц для метода buildDB():

$sql = "CREATE TABLE Messages
(
mid int NOT NULL AUTO_INCREMENT,
PRIMARY KEY(mid),
title varchar(15),
bodytext text,
created  int(11),
file int(11),
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;
CREATE TABLE Files
(
fid int NOT NULL AUTO_INCREMENT,
PRIMARY KEY(fid),
filename varchar(255),
filepath varchar(255),
filemime varchar(255),
filesize int(10),
timestamp int(10),
)ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;";

Помимо добавления новой таблицы, мы еще добавим поле fid, которое будет внешним ключом для таблицы файлов. Для новой таблицы файлов у нас будут следующие поля:

fid - это первичный ключ нашей таблицы, номер нашего файла.

filename - имя файла.

filepath - путь к файлу от корня сайта.

filemime - тип файла, чтобы определять расширение файла и для чего его можно использовать (например у текстовых файлов это text/plain, у картинок может быть image/jpg, image/png).

filesize - размер файла в байтах.

timestamp - время загрузки файла.

Теперь давайте напишем сохраним файл и напишем запрос на добавление файла в БД. Можете создать нужные поля через phpMyAdmin.

 if($_FILES["filename"]["size"] > 1024*3*1024)
   {
     echo ("Размер файла превышает три мегабайта");
     exit;
   }
   // Проверяем загружен ли файл
   if(is_uploaded_file($_FILES["filename"]["tmp_name"]))
   {
     // Если файл загружен успешно, перемещаем его
     // из временной директории в конечную
     move_uploaded_file($_FILES["filename"]["tmp_name"], "/files/".$_FILES["filename"]["name"]);
   } else {
      echo("Ошибка загрузки файла");
   }

Таким образом мы сохраняем файл в папку files. Теперь после успешной загрузки файла, вставляем запрос в БД на добавление в таблицу Files:

$sql = 'INSERT INTO Files (filename, filepath, filemime, filesize, timestamp) 
VALUES ("'. $_FILES['filename']['name'] . '",
"files/' . $_FILES['filename']['name'] . '",
"'. $_FILES['filename']['type'] .'",
'. $_FILES['filename']['size'] .',
'. time() . ')';  

mysql_query($sql);   

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

   $sql = 'INSERT INTO Messages (title, bodytext, created, fid) VALUES ("'. $p["title"] . '", "' . $p["bodytext"] . '", ' . time() . ',LAST_INSERT_ID())';

Обратите внимание на функцию last_insert_id(), эта функция mysql, она выводит последний ID который был вставлен в любую из таблиц БД, в нашем случае последний запрос вставлял запись в таблицу файлов, поэтому и ID выводиться из таблиц файлов.

Теперь записи вставляются в таблицы, осталось выводить их с помощью оператора JOIN. Давайте изменим запрос на вывод сообщений, так чтобы выводить и имя файла:

  public function display_public() { // метод вывода сообщений
    $content = '';
	$sql = 'SELECT * FROM Messages LEFT JOIN Files ON Messages.fid=Files.fid ORDER BY mid DESC';
	$result = mysql_query($sql) or die(mysql_error());  
...

Оператор JOIN в данном случае я использовал вместе с LEFT. Дело в том что объединение таблиц для выборки можно производить разными способами, в одном из следующих уроков мы рассмотрим подробнее использование JOIN. А пока условимся на том что LEFT JOIN выводит все записи, в том числе где нет поля fid.

Теперь если распечатаем массив запроса:

  public function display_public() { // метод вывода сообщений
    $content = '';
	$sql = 'SELECT * FROM Messages LEFT JOIN Files ON Messages.fid=Files.fid ORDER BY mid DESC';
	$result = mysql_query($sql) or die(mysql_error());  
	while($row = mysql_fetch_array($result)){ // переменную запроса выборки необходимо обработать специальной функцией mysql_fetch_array()
	  print_r($row);

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

	  if(!empty($row['filename'])){
	    $content .= '<p>Приложение: <a target="_blank" href="/'. $row['filepath'] .'">'. $row['filename'] .'</a></p>';
	  }

Теперь вместе с сообщением будет выводиться и приложение в виде ссылки на загруженный нами файл. В следующем уроке мы более подробно разберем замечательный оператор JOIN позволяющий выводить данные сразу с нескольких таблиц. В приложение я теперь буду добавлять актуальный дамп БД, сделанный через phpMyAdmin.