Уроки PHP - урок 3.5 - Работа с БД MySQL. Оператор JOIN. Загрузка файлов на сервер.
Прежде чем начать писать этот урок, я долго думал как лучше преподать запросы с операторами 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.