Сохранить массив PHP в MySQL?

88

Как хорошо сохранить массив данных в одном поле mysql?

Также, когда я запрашиваю этот массив в таблице mysql, как лучше вернуть его в форму массива?

Есть ли сериализация и десериализация ответа?

ДжейсонДэвис
источник

Ответы:

87

Нет хорошего способа хранить массив в одном поле.

Вам необходимо изучить ваши реляционные данные и внести соответствующие изменения в вашу схему. См. Пример ниже для ссылки на этот подход.

Если необходимо сохранить массив в одно поле то serialize()и unserialize()функции будут делать трюк. Но вы не можете выполнять запросы к фактическому контенту.

В качестве альтернативы функции сериализации также есть json_encode()и json_decode().

Рассмотрим следующий массив

$a = array(
    1 => array(
        'a' => 1,
        'b' => 2,
        'c' => 3
    ),
    2 => array(
        'a' => 1,
        'b' => 2,
        'c' => 3
    ),
);

Чтобы сохранить его в базе данных, вам нужно создать такую ​​таблицу

$c = mysql_connect($server, $username, $password);
mysql_select_db('test');
$r = mysql_query(
    'DROP TABLE IF EXISTS test');
$r = mysql_query(
    'CREATE TABLE test (
      id INTEGER UNSIGNED NOT NULL,
      a INTEGER UNSIGNED NOT NULL,
      b INTEGER UNSIGNED NOT NULL,
      c INTEGER UNSIGNED NOT NULL,
      PRIMARY KEY (id)
    )');

Для работы с записями вы можете выполнять такие запросы (и да, это пример, будьте осторожны!)

function getTest() {
    $ret = array();
    $c = connect();
    $query = 'SELECT * FROM test';
    $r = mysql_query($query,$c);
    while ($o = mysql_fetch_array($r,MYSQL_ASSOC)) {
        $ret[array_shift($o)] = $o;
    }
    mysql_close($c);
    return $ret;
}
function putTest($t) {
    $c = connect();
    foreach ($t as $k => $v) {
        $query = "INSERT INTO test (id,".
                implode(',',array_keys($v)).
                ") VALUES ($k,".
                implode(',',$v).
            ")";
        $r = mysql_query($query,$c);
    }
    mysql_close($c);
}

putTest($a);
$b = getTest();

connect()Функция возвращает ресурс соединения MySQL

function connect() {
    $c = mysql_connect($server, $username, $password);
    mysql_select_db('test');
    return $c;
}
Питер Линдквист
источник
26

Как правило, да, сериализация и десериализация - это лучший способ.

Однако, если ваши данные являются чем-то простым, сохранение в виде строки, разделенной запятыми, вероятно, будет лучше для места для хранения. Если вы знаете, что ваш массив будет, например, просто списком чисел, вам следует использовать implode / explode. В этом разница между 1,2,3и a:3:{i:0;i:1;i:1;i:2;i:2;i:3;}.

Если нет, то сериализация и десериализация работают для всех случаев.

Matchu
источник
23
Поскольку вы здесь, читатель, я просто собираюсь найти время, чтобы объявить, что с тех пор, благодаря многолетнему опыту, я обнаружил, что на самом деле это не тот путь. Принятый ответ - гораздо более сильный подход.
Matchu 01
4
Так как вы здесь, читатель, я поделюсь с вами, что это просто зависит от ваших требований. Если вам не нужно запрашивать значения вашего массива и вам нужно что-то очень БЫСТРО, вы можете безопасно хранить свои данные, как это, в одном поле (это то, что четко сформулировано в вопросе), нажмите на него первичный ключ и вперед . Если вам интересно, что это за приложение: помещает данные в очередь, которая обновляется каждые 5 минут. Другой cron создает массивы, что занимает гораздо больше времени. Que получает вычисленные данные и передает их стороннему API. Нет лучшего способа сделать это.
Rid Iculous 07
1
@RidIculous Я в замешательстве, вы говорите о своем личном приложении или о приложении, которое привело к заданному вопросу?
Питер Линдквист,
1
Хотя это не имеет отношения к исходной посылке моего заявления, префикс «Если вам интересно, что это за приложение» должен внести ясность.
Rid Iculous
10

Просто используйте функцию сериализации PHP:

<?php
$myArray = array('1', '2');
$seralizedArray = serialize($myArray);
?>

Однако, если вы используете такие простые массивы, вы также можете использовать implode и explode. Используйте пустой массив вместо нового.

KramerC
источник
9

Сериализовать / десериализовать массив для хранения в БД

Посетите http://php.net/manual/en/function.serialize.php

Из Руководства по PHP:

Посмотрите в разделе «Возврат» на странице

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

Обратите внимание, что это двоичная строка, которая может включать нулевые байты и должна храниться и обрабатываться как таковая. Например, вывод serialize () обычно должен храниться в поле BLOB в базе данных, а не в поле CHAR или TEXT.

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

Пример кодировки:

$YourSerializedData = base64_encode(serialize($theHTML));

$YourSerializedData теперь готов к хранению в blob.

После получения данных из большого двоичного объекта вам необходимо выполнить base64_decode, а затем выполнить десериализацию. Пример декодирования:

$theHTML = unserialize(base64_decode($YourSerializedData));
морской окунь
источник
8

Лучший способ, который я нашел для себя, - это сохранить массив как строку данных с символами-разделителями.

$array = array("value1", "value2", "value3", "...", "valuen");
$array_data = implode("array_separator", $array);

$query = "INSERT INTO my_tbl_name (id, array_data) VALUES(NULL,'" . $array_data . "');";

Затем вы можете искать данные, хранящиеся в вашем массиве, с помощью простого запроса

$query = "SELECT * FROM my_tbl_name WHERE array_data LIKE '%value3%'";

используйте функцию explode () для преобразования строки "array_data" в массив

$array = explode("array_separator", $array_data);

обратите внимание, что это не работает с многомерными массивами, и убедитесь, что ваш "array_separator" уникален и не существует в значениях массива.

Быть осторожен !!! если вы просто возьмете данные формы и поместите в базу данных, вы попадете в ловушку, потому что данные формы не являются безопасными для SQL! вы должны обрабатывать значение формы с помощью mysql_real_escape_string или если вы используете MySQLi mysqli :: real_escape_string, или если значение является целочисленным или логическим приведением (int) (boolean) для них

$number = (int)$_POST['number'];
$checked = (boolean) $_POST['checked'];

$name = mysql_real_escape_string($db_pt, $_POST['name']);
$email = mysqli_obj->real_escape_string($_POST['email']);
Гарри
источник
В моем случае, думаю, это лучший вариант для меня.
Имтиаз
6

Для этого довольно часто используются сериализация и десериализация. Вы также можете использовать JSON через json_encode и json_decode для менее специфичного для PHP формата.

Ceejayoz
источник
5

Как упоминалось ранее - если вам не нужно искать данные в массиве, вы можете использовать сериализацию, но это «только php». Поэтому я бы рекомендовал использовать json_decode / json_encode - не только для производительности, но также для удобства чтения и переносимости (другие языки, такие как javascript, могут обрабатывать данные с json_encoded).

Себастьян Лассе
источник
3

Ухх, я не знаю, почему все предлагают сериализовать массив.

Я говорю, что лучший способ - это вписать его в схему вашей базы данных. Я понятия не имею (и вы не догадались) о фактическом семантическом значении данных в вашем массиве, но обычно есть два способа хранения подобных последовательностей

create table mydata (
  id int not null auto_increment primary key,
  field1 int not null,
  field2 int not null,
  ...
  fieldN int not null
)

Таким образом, вы храните свой массив в одной строке.

create table mydata (
    id int not null auto_increment primary key,
    ...
)

create table myotherdata (
    id int not null auto_increment primary key,
    mydata_id int not null,
    sequence int not null,
    data int not null
)

Недостатком первого метода, очевидно, является то, что если у вас много элементов в вашем массиве, работа с этой таблицей будет не самым элегантным занятием. Также непрактично (возможно, но тоже довольно неэлегантно - просто сделайте столбцы обнуляемыми) работать с последовательностями переменной длины.

Для второго метода вы можете иметь последовательности любой длины, но только одного типа. Вы, конечно, можете создать этот тип varchar или что-то в этом роде и сериализовать элементы вашего массива. Не лучший вариант, но, безусловно, лучше, чем сериализация всего массива, верно?

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

Что касается возврата. Ну, получить соответствующую строку / последовательность строк с помощью запроса и, ну, использовать цикл .. верно?

хитрый
источник
Иногда действительно уместен массив. Если вы собираетесь обращаться к нему только как к атрибуту первого объекта, тогда это имеет смысл.
Matchu
1
Я должен не согласиться в самых строгих терминах - мне кажется довольно неуместным хранить случайные, неструктурированные (php «массивы» на самом деле вовсе не массивы, верно?) Нетипизированные капли данных в реляционной базе данных . Что вы собираетесь использовать в качестве разделителя, если в вашем массиве могут быть какие-то строки? Это просто вызывает проблемы разными способами. В 99,9% случаев есть другой, более естественный способ. Я сделаю безумное предположение и предположу, что довод опрашивающего не попадает в остальные 0,1%.
shylent
2
На самом деле, иногда очень уместно хранить массив в поле в БД. Примером могут служить метаданные, такие как глобальная таблица «переменных», в которой системные плагины и модули могут хранить свои различные настройки. Таблица, в которой хранятся произвольные «сеансовые» данные, может быть лучше всего реализована с использованием поля, содержащего ассоциативный массив ключей / значений. сериализовать и десериализовать (что является правильным ответом) позаботиться о разделителях. проверьте некоторые из нескольких успешных и популярных проектов с открытым исходным кодом, таких как WordPress или Drupal - и вы увидите, что массивы иногда хранятся в БД вот так
Скотт Эвернден
@ Скотт Эвернден: Думаю, ты все-таки прав. php не является моим «основным» языком, поэтому я оценивал решение с точки зрения дизайна базы данных. Если то, что вы описываете, действительно является обычным способом делать такие вещи (на php), пусть будет так. Но мне это не нравится :)
shylent
5
НИКОГДА не уместно хранить массив в поле в БД. Это нарушение не четвертой нормальной формы, третьей нормальной формы или даже не второй нормальной формы: это НАРУШЕНИЕ ПЕРВОЙ НОРМАЛЬНОЙ ФОРМЫ. Если вы не можете придерживаться даже первой нормальной формы, значит, с вашим заявлением что-то серьезно не так. Это касается Drupal и Wordpress; если они делают это, то определенно не потому, что этот аспект их приложений хорошо спроектирован ... У меня был этот аргумент на моей последней работе, и поскольку XCart делал эту ерунду, это сделало то, что должно было быть возможным, а вместо этого чрезвычайно трудным.
Dexygen
2

Вы можете сохранить свой массив как файл json.
есть документация для типа данных json: https://dev.mysql.com/doc/refman/5.7/en/json.html
Я думаю, что это лучшее решение, которое поможет вам сделать ваш код более читаемым, избегая сумасшедших функций .
Надеюсь, это будет вам полезно.

Роберто Мургуа
источник
0

Да, сериализация / десериализация - это то, что я видел больше всего во многих проектах с открытым исходным кодом.

Эдуардо
источник
0

Я бы предложил использовать implode / explode с символом, который, как вы знаете, не будет содержаться ни в одном из отдельных элементов массива. Затем сохраните его в SQL как строку.

user1478500
источник
3
Этот вопрос был задан 3 года назад, и на него есть принятый ответ. Возможно, вам будет полезнее отвечать на новые вопросы или вопросы, на которые нет ответов.
MDrollette,
0

проверьте функцию implode, поскольку значения находятся в массиве, вы хотите поместить значения массива в запрос mysql, который вставляет значения в таблицу.

$query = "INSERT INto hardware (specifications) VALUES (".implode(",",$specifications).")";

Если значения в массиве являются текстовыми значениями, вам нужно будет добавить кавычки

$query = "INSERT INto hardware (specifications) VALUES ("'.implode("','",$specifications)."')";

mysql_query($query);

Кроме того, если вы не хотите дублировать значения, переключите «INto» на «IGNORE», и в таблицу будут вставлены только уникальные значения.

j0k
источник
Если у вас есть первичный ключ, вы все равно не получите дубликатов с помощью INSERT INTO. Если у вас нет первичного ключа или индекса, IGNORE не имеет никакого значения.
Питер Линдквист,
0

вы можете вставить сериализованный объект (массив) в mysql, например, serialize($object)и вы можете unserize object exampleunserialize($object)

Вильдан Бина
источник
-5

Вместо того, чтобы сохранять его в базе данных, сохраните его в файл, а затем вызовите его позже.

Что делают многие приложения php (например, sugarcrm), так это просто использовать var_export для вывода всех данных массива в файл. Вот что я использую для сохранения данных моей конфигурации:

private function saveConfig() {
    file_put_contents($this->_data['pathtocompileddata'],'<?php' . PHP_EOL . '$acs_confdata = ' . var_export($this->_data,true) . ';');        
}

Думаю, это лучший способ сохранить ваши данные!

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