Хранение изображений в базе данных MySQL
Для хранения изображений в базе данных MySQL необходимо определить одно из полей таблицы как производное от типа BLOB. Сокращение BLOB означает большой двоичный объект. Тип хранения данных BLOB обладает несколькими вариантами:
- TINYBLOB - может хранить до 255 байт
- BLOB - может хранить до 64 килобайт информации
- MEDIUMBLOB - до 16 мегабайт
- LONGBLOB - до 4 гигабайт
Соответсвенно, для хранения изображений нам надо создать таблицу images с двумя полями:
- id - уникальный ID изображения
- content - поле для хранения изображения
Для сохранения файла изображения в базе данных необходимо прочитать файл в переменную и создать запрос на добавление данных в таблицу. Допустим у нас есть форма для загрузки файла изображения на сервер:
Изображение: <input type="file" name="image" />
<input type="submit" value="Загрузить" />
</form>
Обработчик формы - файл putimage.php:
// Проверяем пришел ли файл
if( !empty( $_FILES['image']['name'] ) ) {
// Проверяем, что при загрузке не произошло ошибок
if ( $_FILES['image']['error'] == 0 ) {
// Если файл загружен успешно, то проверяем - графический ли он
if( substr($_FILES['image']['type'], 0, 5)=='image' ) {
// Читаем содержимое файла
$image = file_get_contents( $_FILES['image']['tmp_name'] );
// Экранируем специальные символы в содержимом файла
$image = mysql_escape_string( $image );
// Формируем запрос на добавление файла в базу данных
$query="INSERT INTO `images` VALUES(NULL, '".$image."')";
// После чего остается только выполнить данный запрос к базе данных
mysql_query( $query );
}
}
}
?>
Извлечь сохраненный файл изображения можно следующим образом (файл image.php):
if ( isset( $_GET['id'] ) ) {
// Здесь $id номер изображения
$id = (int)$_GET['id'];
if ( $id > 0 ) {
$query = "SELECT `content` FROM `images` WHERE `id`=".$id;
// Выполняем запрос и получаем файл
$res = mysql_query($query);
if ( mysql_num_rows( $res ) == 1 ) {
$image = mysql_fetch_array($res);
// Отсылаем браузеру заголовок, сообщающий о том, что сейчас будет передаваться файл изображения
header("Content-type: image/*");
// И передаем сам файл
echo $image['content'];
}
}
}
?>
Чтобы вывести изображение в HTML-документе, делаем так:
И последнее: графические файлы иногда имеют довольно большой размер, убедитесь, что настройки сервера позволяют работать с таким объемом данных. В файле php.ini это директивы post_max_size - определяет максимальный объем данных передаваемых методом POST, и upload_max_filesize - определяет максимальный размер загружаемого файла. Так же проверьте, позволяют ли настройки MySQL обрабатывать запросы с большим объемом данных (директива max_allowed_packet файла my.ini).
art:
еще бы примеры, когда хранить картинки в базе лучше чем просто на диске
21 Сентябрь 2008, 10:57admin:
art, хранить графические файлы в базе данных - не самое удачное решение. Ведь это создает дополнительную нагрузку на сервер БД.
Когда мы сохраняем в базе данных каталог продукции, заказы в Интернет-магазине - то это вполне оправдано. Потому как альтернативный вариант - сохранять всю информацию в файлах. И работать с файлами напрямую. Но базы данных для того и созданы, чтобы избавить нас от этой рутины. Ведь в конечном итоге, все данные все равно сохраняются в файлах, хотя мы и говорим, что “данные хранятся в БД”. БД - это некий уровень абстракции, который здорово облегчает жизнь.
Почему тогда хранят файлы в базе данных? Дело в том, что на некоторых хостингах на объем дискового пространства есть ограничения, в то время как на размер БД - нет. Подчеркиваю - на некоторых. В этом случае, чтобы не выйти за пределы дисковой квоты прибегают к такой хитрости - хранят файлы в БД. В противном случае смысла в этом нет.
21 Сентябрь 2008, 12:14Владимир Лапшин:
“SELECT *” в реально работающем приложении не самая хорошая идея.
Лучше все-таки перечислять нужные поля. Точно помогает, когда в таблицу приходится добавить еще какое-то поле. 
21 Сентябрь 2008, 18:06admin:
Согласен, сам читал об этом, но частенько забываю. Здесь это тем более актуально - нам нужно выбрать всего одно поле. Исправил.
21 Сентябрь 2008, 21:57Анатолий:
Здравствуйте. Помогите начинающему. Загрузка картинки в базу идет нормально (вроде бы), т.е. объем загруженного файла (8кб) соответствует объему картинки, но плучить изображение обратно я не могу. В приведенном вами файле image.php - $_GET - не существует. Я малость его изменил - убрал лишние пока проверки - в результате, файл выводится, но не в виде картинки, а в виде текста-абракадабры.
Привожу свой вар. подскажите где ошибка, если знаете.
// Отсылаем браузеру заголовок, сообщающий о том,
//что сейчас будет передаваться файл изображения
header("Content-type: image/*");
include_once 'conf4b.php';//подключаем базу
//Вывод изображения из БАЗЫ, загруженного из формы
$query = "SELECT content FROM image ";
// Выполняем запрос и получаем файл
$res = mysql_query($query);
$image = mysql_fetch_array($res);
echo $image['content'];
//выводится пустой квадратик
mysql_close($connect)or die("not razriva");
print "соединение разорвано";
?>
admin:
Анатолий, вы посылаете заголовок, сообщающий браузеру, что дальше идет изображение. Поэтому нельзя выводить в браузер ничего, кроме содержимого картинки. Т.е. факт наличия в скрипте оператора
уже является ошибкой. Браузер считает строку “соединение разорвано” частью изображения.
8 Октябрь 2008, 19:16Анатолий:
Я полагал, что перед header нельзя делать какой-либо вывод.
8 Октябрь 2008, 20:10Впрочем, я убрал принт, оставил только одно echo - результат тот же.
admin:
Перед заголовками, разумеется, не должно быть вывода. Сервер и браузер общаются между собой при помощи заголовков. В данном случае ты отправляешь браузеру заголовок “Content-type: image/*”, сообщающий браузеру, что ВСЕ ДАЛЕЕ будет картинка. Но вместе с картинкой отправляешь еще и текст. По поводу того, почему не работает - причин может быть воз и маленькая тележка:
1. скрипт для коннекта к БД содержит после закрывающего тега ?> какой-нибудь вывод (например, пробел или перевод строки)
2. пробел или пустая строка перед открывающим тегом <?php в файле image.php - опять вывод в браузер информации
3. блокнот Windows при использовании кодировки Unicode добавляет в начало файла служебный символ Byte Order Mark - а это тоже вывод в браузер
4. в базу данных был записан поврежденный файл изображения
P.S. Такие вопросы лучше обсуждать на форуме.
8 Октябрь 2008, 23:08Анатолий CMX:
Спасибо! То что нужно! Все работает без правок и добавлений. Как семпл очень полезно и информативно!
От себя могу добавить, что хранение изображений в базе данных актуально например когда:
1) используются каталоги изображений для шаблонов (например наборы иконок)
2) когда есть много мелких изображений, файлы которых “весят” очень мало, но самих файлов очень много. В базе будет занято ровно столько места сколько требуется, а не сектора диска под нефактический объем файла.
НО:
Если вы собрались делать фото галерею или каталог “крупных” изображений, то целесообразнее организовать каталог в виде папок и подпапок на диске, а уже ссылки на файлы можно хранить в базе! Т.к. при достаточно большом объеме файлов и их количестве, если хранить данные в базе, возрастет нагрузка на ресурсы сервера при обращении и получениии данных из базы.
Влад:
Мне понравилось про () , люблю изощренные решения. но всё таки мне не понятно почему тот же пхп не сделал стандартную функцию для чтения бинарных изображений из БД. явно напрашивается такая штука.
13 Ноябрь 2008, 19:09victor:
Хранить изображения в базе очень удобно. Насчёт загрузки сервера - это миф. Использую MSSQL 2005 и RAID 5, база около 20Г.
19 Ноябрь 2008, 19:33admin:
victor, а в чем удобство-то? Какое реальное преимущество мы получаем, если изображение у нас в таблице БД, а не просто в директории?
19 Ноябрь 2008, 20:46victor:
В администрировании, бекап, безопасность, механизм построения галереи простой. То есть я имею введу необходимые действия удаления, изменение, добавления галерей и фото. Всё это элементарно организуется посредствам самой ДБ (cascade) и требует минимального кода. В случае хранения фото “на диске” алгоритм сильно усложняется, нужно выполнять множество проверок при выполнении операций с диском… MSSQL сильно отличается от MySQL , а именно структура хранения данных, не рискнул бы хранить в ней большое количество фото.
20 Ноябрь 2008, 13:28Дмитрий:
Убогое какое-то описание, а где в скрипте соединение с базой данных, выбор таблицы. Уж если описываете, так сделайте чтобы даже военным было понятно
13 Декабрь 2008, 22:17Сергей:
при переходе с MSSQL на MySQL столкнулся с проблемой, select count(*) from image; (посчитать количество картинок в базе) на MySQL выполняется 25 сек, на MSSQL MySQL меньше секунды. в таблице 50000 картинок, 300MB.
23 Декабрь 2008, 20:16это нормально для mysql? или я что-то не так делаю?
admin:
Сергей, здесь явно что-то не так. Не может быть, чтобы разница во времени выполнения была такой большой. Попробуйте задать свой вопрос на форумах
23 Декабрь 2008, 22:01SQL.RU
SQLINFO.RU
Mujeek:
Преимущества хранения изображений в базе - на лицо… когда есть необходимость каскадного удаления данных, а изображения находится, например, на 3 уровне подчинённости удаляемой записи..
24 Декабрь 2008, 11:45Mujeek:
вдобавок не нужны проверки существования в каталоге одноименного файла…
24 Декабрь 2008, 11:49Mujeek:
Будут ли кэшироваться на клиенте изображения, полученные из базы данных,или при каждом открытии страницы все изображения закачиваются заново?
25 Декабрь 2008, 7:05admin:
Mujeek, вообще, дело обстоит так
25 Декабрь 2008, 12:00* Страницы передаваемые по POST никогда не сохраняются в кэш.
* Страницы запрашиваемые по GET и содержащие параметры (в URL присутствует ‘?’) не сохраняются в кэш, если не указано обратное.
Наш вызов скрипта картинки выглядит так
http://server.com/image.php?id=17
а значит по правилам изображение не будет сохраняться в кэш (присутствуют параметры), но через заголовок можно управлять этим. Подробности здесь:
PHP и Web. Кэширование
Ренат:
Здравствуйте, хочу спросить, а средствами PHP можно вывести на экран вместе с картинкой ещё, к примеру, оформление сайта? Ну не только картинку на экран? Или это уже к JavaScript’y?
7 Январь 2009, 23:06Mujeek:
И как получить увеличенную картинку в отдельном окне при клике на изображении?
12 Январь 2009, 18:16hannibal:
Очень нужно!!!! Подскажите как вывести несколько изображений из базы???
15 Февраль 2009, 23:12Максим:
Сделал, подобие примера. Точнее повторил все точно точно также но вот вывода картинки я не вижу.
Загружаеться но вывода нет.
В чем может быть проблема? картика 64кб, поле(блоб).
qip 439_810-757 Мучаюсь 2 день, прошу помощи.
1 Апрель 2009, 2:32admin:
И как получить увеличенную картинку в отдельном окне при клике на изображении?
1 Апрель 2009, 9:22<a href=”/images/big.jpg” target=”_blank”
onClick=”popupWin = window.open(this.href, ”, ‘location,width=500,height=200,left=200,top=200′); popupWin.focus(); return false;”>
<img src=”/images/small.jpg” alt=”" />
</a>
А если красиво - использовать готовое решение:
Плагин FancyBox для библиотеки jQuery
admin:
Максим, давайте обсудим это на форуме. Выкладывайте свой скрипт, посмотрим, в чем там проблема.
1 Апрель 2009, 9:25Евгений:
> при переходе с MSSQL на MySQL столкнулся с проблемой,
> select count(*) from image; (посчитать количество
> картинок в базе) на MySQL выполняется 25 сек, на
> MSSQL MySQL меньше секунды. в таблице 50000 картинок, 300MB.
> это нормально для mysql? или я что-то не так делаю?
Не так делаете. Зачем запрашивать все поля *?
13 Апрель 2009, 19:08Проще и быстрее будет SELECT COUNT(`id`) FROM `image`;
Sancho:
printf ("Ф.И.О. - %s %s Дата визита: %s",
$myrow['id'],$myrow['username'], $myrow['username'],$myrow['namelastname'],$myrow['lastvisit']);
} while ($myrow = mysql_fetch_array($result,$db));
Sancho:
не пойму почему не передает полный текст
18 Май 2009, 22:38admin:
Sancho, а Вы о чем вообще говорите?
19 Май 2009, 9:12Ольга:
Скажите, что делать с хедером, если изображение мне нужно вывести в середине страницы и, естественно, заголовок уже выведен.
20 Май 2009, 17:30При инклюде image.php, вылезает ошибка - Warning: Cannot modify header information - headers already sent by (output started at Z:\home\localhost\www\xyxa\index.php:17) in Z:\home\localhost\www\xyxa\image.php on line 13
Как мне всё же вывести изображение из БД в index.php?
(И, мало ли у кого есть готовый пример для ресайза изображения ДО добавления его в БД - буду очень признательна. Хотелось бы из одной загружаемой человеком фотографии сделать превью и фото, к примеру 600х400 и поместить их в БД, причем учитывая, что просто уменьшение может оказаться не пропорциональным, если, к примеру, фото было 1200х1000)Спасибо.
admin:
если изображение мне нужно вывести в середине страницы и, естественно, заголовок уже выведен. При инклюде image.php, вылезает ошибка - Warning: Cannot modify header information
По-моему, в заметке четко написано: чтобы вывести изображение в HTML-документе, делаем так
Включать изображение на страницу с помощью include?! Даже не комментирую…
у кого есть готовый пример для ресайза изображения ДО добавления его в БД
21 Май 2009, 9:28Масштабирование изображений
Ольга:
Включать изображение на страницу с помощью include?! Даже не комментирую…
Спасибо за быстрый ответ, но Вы не поняли, я не изображение же вставляю include, а файл image.php, а в самом html коде, конечно же.
Мне не понятна вот эта часть Вашего кода:
// Отсылаем браузеру заголовок, сообщающий о том, что сейчас будет передаваться файл изображения
header(”Content-type: image/*”);
Это же получается второй header и выдается ошибка ( Если не сложно, пожалуйста, объясните? Я все сделала так, как Вы указали в коде, затем весь пхп в отдельном файле image.php я добавила в индексную страницу в то место, где планируется вывод картинки. (Пробовала и не отдельным файлом image.php делать, а втавлять код сразу в страницу, где оно выводится), но результат один и тот же:
21 Май 2009, 11:40Cannot modify header information - headers already sent by (output started at …
Заранее спасибо.
admin:
но Вы не поняли, я не изображение же вставляю include, а файл image.php, а в самом html коде, конечно же
Я прекрасно понял, что с помощью include вставляется файл image.php. И именно поэтому сказал “Даже не комментирую…”. Еще раз для особо сообразительных - файл index.html (или index.php), где надо вывести изображение:
// здесь какой-то код
?>
<html>
<head>
.....
</head>
<body>
<?php
// здесь еще какой-то код
?>
Изображение:<br/>
<img src="image.php?id=17" alt="" />
<?php
// и еще немного
?>
</body>
</html>
Ольга:
Не злитесь, пожалуйста, я только учусь (( Я поняла свою ошибку, спасибо. Правда изображение все равно не выходит, но уже нет того, что было )) Буду разбираться дальше. СПАСИБО!!!
21 Май 2009, 14:59admin:
Правда изображение все равно не выходит
21 Май 2009, 15:22Что, Данила-мастер, не выходит каменный цветок?
Вывод картинок из БД - там есть рабочий пример.
Ольга:
))) С таким огромным трудом!!!
21 Май 2009, 15:38Но, благодаря Вам - легче! ))
Алексей:
А у меня такой вопрос - при выводе изобажения указываю хедеры, но вместо отображения изображения, происходит вывод диалога на сохранение или открытие файла, что с этим делать?
5 Июнь 2009, 1:39admin:
Алексей, чтобы появился диалог на сохранение или открытие файла, надо в скрипте отправить заголовок
header('Content-disposition: attachment; filename="image.jpg"');
Если Вы не отправляли такой заголовок - для меня полная загадка, откуда взялся диалог.
5 Июнь 2009, 11:33Sancho:
Подскажите пожалуйста - в форму вставки изображения можно добавить текстовые поля, чтобы их передать одновременно в фаил обработчик?
24 Июнь 2009, 9:49Sancho:
Да с изображением все работает отлично огромное спасибо!!!!
24 Июнь 2009, 10:04admin:
в форму вставки можно добавить текстовые поля
24 Июнь 2009, 10:08Почему нет? Вот здесь можно посмотреть рабочий пример: Вывод картинок из БД
Sancho:
Тогда прости за наглость есче вопрос как ограничить на размер загружаемой картинки
24 Июнь 2009, 10:27admin:
как ограничить на размер загружаемой картинки
24 Июнь 2009, 10:40На стороне клиента - никак. А на сервере, после того, как изображение будет загружено во временную директорию, мы можем узнать его размер из переменной $_FILES['uploadfile']['size'].
Загрузка файлов на сервер
Если этот размер больше допустимого, мы просто выдаем сообщение пользователю “Ошибка: mах размер файла - …”, а файл во временной директории будет удален автоматически после завершения работы обработчика формы. Кроме того, есть ограничения на max размер POST-данных и размер загружаемого файла:
Загрузка больших файлов на сайт
Sancho:
Огромное человеческое СПАСИБО!!!
24 Июнь 2009, 10:59Sancho:
Можно еще один вопрос. Можно ли дать пользователю, просмотреть в браузере, загружаемое изображение до отправки на сервер! Чтобы он увидел сразу как оно будет выглядеть
24 Июнь 2009, 16:50admin:
Можно ли дать пользователю, просмотреть в браузере, загружаемое изображение до отправки на сервер
25 Июнь 2009, 9:20Нет.
Sancho:
Ответ исчерпываюше но и нато большое спасибо не будем питатся и тратит время отсутсвие результата ето тоже результат!
25 Июнь 2009, 9:35lake:
А что надо поменять, если нужно загрузить в БД не картинку, а файл xls?
8 Июль 2009, 12:12admin:
А что надо поменять, если нужно загрузить в БД не картинку, а файл xls
9 Июль 2009, 15:06Поле BLOB предназначено для хранения бинарных данных; не имеет значения, что это будет - изображение, PDF-документ или таблица Excel.
Андрей:
здравствуйте!
28 Июль 2009, 16:59Подскажите пожалуйста, почему то фото не добавляется в БД. Вручную вставил фото в БД 250 кб, при этом БД жутко тормозит (страница грузилась с минуту, хотя выполнение запроса пишет 0.3 сек), и фото не выводит. Код image.php в точности как у Вас, а в файле индекс, где должно вывестись фото одна строчка
Андрей:
прошу прощения. Одна проблемма снялсь, фото вывелось. Может, подождать чуток надо было). А вот закачки в БД так и не происходит. Нажимаю “загрузить”, начинается загрузка, и ничего не пишет. Ни ошибок, ни что загружено. Так и должно быть?
28 Июль 2009, 17:05И подскажите пжл, какие значения полей в табл. имагес должны быть?
admin:
Андрей, рабочий пример можно взять здесь: Вывод картинок из БД. Если что-то не работает, давайте обсудим на форуме.
29 Июль 2009, 9:07Света:
Здравствуйте. Подскажите пожалуйста,
как после запроса
$query = “INSERT INTO `images` VALUES(NULL, ‘”.$image.”‘)”;
определить автоматически присвоенный ID?
Хочу вывести изображение добавленное только что пользователем вместе с другими (текстовыми) полями, т.е пользователь должен увидеть загруженные им данные включая изображение (только его данные и изображение)
Короче вместо id=17 хочу использовать переменную $id
30 Август 2009, 21:09admin:
как определить автоматически присвоенный ID?
31 Август 2009, 9:48Функция mysql_insert_id().
Александр:
а как узнать ширину и высоту загруженной картинки в базе?
19 Ноябрь 2009, 14:18slogic:
Пример записи в базу не очень удачный. Картинка, не смотря на то, что исходно находится на диске, грузится полностью в память, и лишь потом в базу. Это не проблема, когда кратинка равна 250КБ, однако она может быть и 4МБ и больше. Тогда вы столкнетесь с нехваткой памяти на дешевых хостингах. Поэтому неплохо было бы дополнить пример загрузкой бинарных данных прямо с диска. Возможно такое на MySQL?
14 Май 2011, 16:48Ольга:
Здравствуйте! Я новичок, и что-то не совсем поняла как мне создать таблицу в базе, напишите пример пожалуйста!
Вот так или возможно я ошибаюсь:
CREATE TABLE `ad_e_mail` (
4 Июнь 2011, 0:44`id` int(5) NOT NULL auto_increment,
`content` varchar(255) NOT NULL default ”,
PRIMARY KEY (`id`)
) TYPE=MyISAM ;
Антон:
1. Это непроизводительно - дополнительная нагрузка на БД.
5 Июль 2012, 4:422. Картинки отдаются клиенту как файлы - пусть хранятся как файлы на диске. Это намного быстрее, чем вынимать картинки из базы.
3. Кэширование.
4. Хочется попробовать - попробуйте, но вот серьезные вещи так не делают подробнее тут http://digger3d.com/webmaster/mysql-php-drupal-shell-tips/replace-image-in-mysql-database.html