Сериализация / несериализация массива PHP

#php #mysql #serialization

#php #mysql #сериализация

Вопрос:

У меня возникли некоторые проблемы при попытке рассериализовать массив в PHP.

У меня есть два метода в классе, один для обработки хранения сериализованного массива в таблице mysql, а другой для его извлечения.

Я получаю следующую ошибку при выполнении второго метода (при извлечении / несериализации):

Обратите внимание: unserialize(): ошибка при смещении 50623 на 50647 байт в /Users/benwaine/NetBeansProjects/SentimentEngineMk2/lib/TSE/Mapper/Filter.php в строке 39

Строка хранится в поле blob-объекта в MySQL. Массив является многомерным и состоит из токена с массивом значений типа float. Проблема возникает периодически, возможно, предполагая, что проблема связана с токенами?

// Структура

Ключевое слово - 0.234
 - 0.234
KeywordB - 0.23
 - 0.47


// Методы

 публичная функция insertFilterForKeyword($id, массив $filterProbs)
 {

 $sql = "ВСТАВИТЬ В фильтр (keyword_id, filter_probs, sample_size_pos, sample_size_neg)
 ЗНАЧЕНИЕ (:id, :filterProbs, :pos, :neg)";

 $stmt = $this->pdo-> подготовить($sql);

 $meta = array_shift($filterProbs);

 $stmt->bindParam(':id', $id);
 $stmt->bindParam(':filterProbs',сериализовать($filterProbs));
 $stmt->bindParam(':pos', $meta['sample_size_pos']);
 $stmt->bindParam(':neg', $meta['sample_size_neg']);

 $result = $stmt-> выполнить();

 возвращает $resu<
 }


 общедоступная функция getFilterByKeyword(ключевое слово $)
 {
 $sql = 'ВЫБРАТЬ f.id , например,keyword_id, например,filter_probs, например,sample_size_pos, например,sample_size_neg
 ИЗ фильтра f 
 Ключевое слово JOIN k НА k.id = f.keyword_id 
 ГДЕ k.ключевое слово = :ключевоеслово';

 $stmt = $this->pdo-> подготовить($sql);

 $stmt->bindParam(':ключевое слово', $keyword);

 $result = $stmt-> выполнить();

 $data = $stmt->выборка(PDO::FETCH_ASSOC);

 $probArray = несериализовать($data['filter_probs']);

 $filter = новый TSE_Filter($probArray);

 возвращает $filter; 
 }

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

После поиска в Google я попробовал использовать строку десериализации следующими способами, ни один из которых не сработал:

1) base64_encode / декодирование сериализованной строки.

 //для безопасной сериализации 
 $safe_string_to_store = base64_encode(сериализовать($multidimensional_array)); 

 //для несериализации... 
 $array_restored_from_db = несериализовать(base64_decode($encoded_serialized_string)); 

2) Используйте предварительное соответствие для изменения потенциально сложных символов:

 рассериализовать(preg_replace('/;n;/', ';N;', strtolower($data['filter_probs'])));
 

Любая помощь была бы высоко оценена!

Спасибо.

Комментарии:

1. Можете ли вы опубликовать пример того, как выглядят сериализованные данные, когда вы запрашиваете их из базы данных, не пытаясь их рассериализовать?

Ответ №1:

Я бы предположил, что проблема заключается в длине strin в db. Что произойдет, если вы повторите сериализованную строку после того, как извлекли ее из базы данных? Выглядит ли это как готовая строка или она прерывается? Я думаю, что большой двоичный объект содержит около 65 тысяч символов, вы могли бы попробовать изменить его на longblob, а затем повторно сохранить данные?

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

Комментарии:

1. Спасибо, Дуглас. Вы правы. После перехода на длинный большой двоичный объект несериализация прошла успешно. В итоге я записал строку в файл до и после сохранения базы данных, а затем я их разделил, и было легко увидеть упомянутое вами сокращение. Приветствия!

Ответ №2:

В вашем примере кода вы используете urlencode для сериализованной строки. Вы не декодируете urlencoding при отмене сериализации, что может привести к сбою отмены сериализации.

Возможно, в этом проблема?

(Вы должны иметь возможность хранить сериализованные данные без urlencoding)

Комментарии:

1. Спасибо за ответ, Джани. Я случайно оставил это в одном из решений, которые я пытался использовать перед публикацией. Я отредактировал его и удалил из вопроса сейчас.

Ответ №3:

Я предполагаю, что это как-то связано с кодировками столбцов, соединений или клиентов.

Из http://dev.mysql.com/doc/refman/5.1/en/charset-conversion.html:

Если столбец имеет двоичный тип данных (BINARY, VARBINARY, BLOB), все значения, которые он содержит, должны быть закодированы с использованием одного набора символов (набора символов, в который вы преобразуете столбец). Если вы используете двоичный столбец для хранения информации в нескольких наборах символов, MySQL не имеет способа узнать, какие значения используют какой набор символов, и не может преобразовать данные должным образом.

Итак, я бы попробовал сначала явно установить для столбца ДВОИЧНЫЙ НАБОР СИМВОЛОВ. Помните, что сериализованные строки содержат нулевые байты и другие странные вещи, если вы сериализуете объекты (я понимаю, что вы этого не делаете, но кто знает, что содержит ваш массив в виде ключей и значений).

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

 $stmt->bindParam(':filterProbs', serialize($filterProbs), PDO::PARAM_LOB);
  

И, возможно, используйте тот же подход и при выборке, только с PDOStatement::bindColumn() (и помните о выборке с PDOStatement::fetch(PDO::FETCH_BOUND) тогда).

Ответ №4:

Проверьте определение схемы базы данных для поля filter .filter_probs проверяет, достаточно ли он длинный для сохранения сериализованной строки.

Также вы можете проверить массив перед сериализацией и после несериализации, содержащий одно и то же значение.

Комментарии:

1. Привет, Энди, я проверил определение, это ‘blob’ без значения длины. Этого достаточно?

Ответ №5:

Соответствует ли комментарий getmequickhttp://php.net/manual/en/function.unserialize.php помочь? Найдите «ошибку при смещении»…