У меня есть простое веб-приложение PHP, которое принимает изображения значков через загрузку файлов и сохраняет их в столбце MEDIUMBLOB.
На моей машине (Windows) плюс два Linux-сервера это прекрасно работает. На третьем сервере Linux вставленное изображение повреждено: нечитабельно после SELECT, а длина данных столбца, о котором сообщает функция length () MySQL, примерно на 40% больше, чем размер загруженного файла.
(Каждый сервер подключается к отдельному экземпляру MySQL.)
Конечно, это заставляет меня думать о проблемах с кодировкой и набором символов. В столбцах BLOB нет связанных кодировок, поэтому, скорее всего, наиболее вероятным виновником является PDO и его интерпретация значения параметра для этого столбца.
Код вставки в основном выглядит следующим образом:
$imagedata = file_get_contents($_FILES["icon"]["tmp_name"]); $stmt = $pdo->prepare('insert into foo (theimage) values (:theimage)'); $stmt->bindValue(':theimage', $imagedata, PDO::PARAM_LOB); $stmt->execute();
Любая помощь будет действительно оценена.
ОБНОВЛЕНИЕ : кодировка MySQL по умолчанию на проблемном сервере – utf8; это latin1 на других.
Проблема «решена» путем добавления PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES latin1 COLLATE latin1_general_ci"
в конструктор PDO.
Это похоже на плохой дизайн для меня: почему кодировка соединения влияет на данные для двоичного столбца, особенно когда она была идентифицирована как двоичная для самого PDO с PARAM_LOB?
Обратите внимание, что таблицы БД во всех случаях определяются как latin1: это противоречивые кодировки серверов по умолчанию.
Это кажется ошибкой для меня: почему кодировка соединения влияет на данные для двоичного столбца, особенно когда она была идентифицирована как двоичная для самого PDO с PARAM_LOB?
Я не думаю, что это должно быть ошибкой. Я могу себе представить, что всякий раз, когда клиент разговаривает с сервером и говорит, что следующая команда находится в UTF-8, а серверу требуется его в латинском-1, тогда запрос может быть повторно закодирован перед разбором и исполнением. Таким образом, это проблема кодирования для транспортировки данных. Так как весь запрос до синтаксического анализа будет зависеть от этого повторного кодирования, бинарные данные для столбца BLOB также будут изменены.
Из руководства Mysql:
Какой набор символов должен сервер перевести инструкцию после получения?
Для этого сервер использует системные переменные character_set_connection и collation_connection. Он преобразует утверждения, отправленные клиентом от character_set_client к character_set_connection (за исключением строковых литералов, у которых есть интродуктор, такой как _latin1 или _utf8). collation_connection важна для сравнения литеральных строк. Для сравнения строк со значениями столбцов объединение collation_connection не имеет значения, поскольку столбцы имеют собственную сортировку, которая имеет более высокий приоритет сортировки.
Или на обратном пути: данные Latin1 из магазина будут преобразованы в UTF-8, потому что клиент сказал серверу, что он предпочитает UTF-8 для транспортировки.
Идентификатор самого PDO, который вы называете, выглядит как нечто совершенно другое:
PDO :: PARAM_LOB сообщает PDO для сопоставления данных как потока, так что вы можете манипулировать им с помощью PHP Streams API. ( Ref )
Я не эксперт по MySQL, но я бы объяснил это так. Клиенту и серверу необходимо обсудить, какие кодировки они используют, и я предполагаю, что они делают это по какой-то причине.