Как сохранить совместимый с IPv6 адрес в реляционной базе данных

Несколько рекомендаций по экранированию специальных символов в операторах SQL.

Не используйте MySQL , это расширение устарело, используйте MySQLi или PDO .

MySQLi

Для ручного экранирования специальных символов в строке вы можете использовать функцию mysqli_real_escape_string .

Пример:

$mysqli = new mysqli( 'host', 'user', 'password', 'database' );
$mysqli->set_charset( 'charset');

$string = $mysqli->real_escape_string( $string );
$mysqli->query( "INSERT INTO table (column) VALUES ('$string')" );

Для автоматического экранирования значений с помощью подготовленных операторов , используйте mysqli_prepare и mysqli_stmt_bind_param , где для соответствующего преобразования должны быть указаны типы для соответствующих переменных связывания:

Пример:

$stmt = $mysqli->prepare( "INSERT INTO table ( column1, column2 ) VALUES (?,?)" );

$stmt->bind_param( "is", $integer, $string );

$stmt->execute();

Независимо от того, используете ли вы подготовленные операторы или mysqli_real_escape_string, вам всегда нужно знать тип входных данных, с которыми вы работаете.

Итак, если вы используете подготовленный оператор, вы должны указать типы переменных для функции mysqli_stmt_bind_param.

И использование mysqli_real_escape_string для, как сказано в названии, означает экранирование специальных символов в строке, поэтому оно не сделает целые числа безопасными. Цель этой функции - предотвратить разрыв строк в операторах SQL и повреждение базы данных, которое она может вызвать. mysqli_real_escape_string - полезная функция при правильном использовании, особенно в сочетании с sprintf.

Пример:

$string = "x' OR name LIKE '%John%";
$integer = '5 OR id != 0';

$query = sprintf( "SELECT id, email, pass, name FROM members WHERE email ='%s' AND id = %d", $mysqli->real_escape_string( $string ), $integer );

echo $query;
// SELECT id, email, pass, name FROM members WHERE email ='x\' OR name LIKE \'%John%' AND id = 5

$integer = '99999999999999999999';
$query = sprintf( "SELECT id, email, pass, name FROM members WHERE email ='%s' AND id = %d", $mysqli->real_escape_string( $string ), $integer );

echo $query;
// SELECT id, email, pass, name FROM members WHERE email ='x\' OR name LIKE \'%John%' AND id = 2147483647

34
задан the Tin Man 19 October 2012 в 21:44
поделиться

6 ответов

Я не уверен, который является право ответ для MySQL, учитывая, что это еще не поддерживает форматы адреса IPv6 исходно (хотя, пока" WL#798: поддержка MySQL IPv6 " предполагает, что это было в MySQL v6.0, текущая документация не создает резервную копию этого).

Однако тех Вы предложили, чтобы я предложил бы идти для 2 * BIGINT, но удостоверился бы, что они НЕ ПОДПИСАНЫ. Существует своего рода, естественное разделение в/64 обращается к границе в IPv6 (так как/64 является самым маленьким netblock размером), который выровнялся бы приятно с этим.

21
ответ дан Mike 27 November 2019 в 17:08
поделиться

Если Вы склоняетесь к символу (16), определенно используйте двоичный файл (16) вместо этого. двоичный файл (n) не имеет понятия сопоставления или набора символов (или скорее это - символ (n) с набором символов/сопоставлением 'двоичного файла'). Значение по умолчанию для символа в mysql является latin1_swedish_ci, что означает, что это будет делать попытку нечувствительной к регистру сортировки и сравнений для значений байта, которые являются допустимыми кодовыми точками в latin1, который вызовет Вас всех способ неожиданных проблем.

Другая опция состоит в том, чтобы использовать десятичное число (39, 0) заполняют нулями неподписанный, не совсем столь же эффективный как два bigints (десятичное число будет использовать 4 байта на девять цифр в текущих версиях mysql), но позволит Вам сохранять все это в одном столбце и распечатывать приятно.

6
ответ дан dlamblin 27 November 2019 в 17:08
поделиться

Я пошел бы для полных 39 символов распечатанный format: "стандарта" -

"2001:0db8:85a3:0000:0000:8a2e:0370:7334"

40 с пустым разделителем.

Это - формат, используемый *, отклоняют инструменты командной строки, и, формат, в котором обычно(?) сообщают об адресе IPv6.

4
ответ дан dlamblin 27 November 2019 в 17:08
поделиться

IP-адрес идет в используемый программой, для которой двоичный файл имеет смысл? Или Вы были бы более обеспеченным хранением текстового представления? Кроме того, с IPv6 Вы, менее вероятно, будете использовать адрес в целом и более вероятно использовать имена хоста. Релевантно ли это, зависит от приложения, частично. CHAR (16) был бы плохим выбором; символ для символьных данных и не будет любить большие потоки нулевых байтов, которые распространены в адресах IPv6. 2 x BIGINT были бы неудобны - два поля, которые являются действительно одним (плюс значение, хранится или прямой порядок байтов с обратным порядком байтов?). Я использовал ДВОИЧНЫЙ тип фиксированного размера, или если это не доступно, тип блоба.

1
ответ дан Jonathan Leffler 27 November 2019 в 17:08
поделиться

Обратите внимание, что максимальная длина IPv6-адреса, включая идентификатор области, составляет 46 байтов, как определено INET6_ADDRSTRLEN в стандартных заголовках C. При использовании Интернета вы можете игнорировать идентификатор зоны (% 10, # eth0 и т. Д.), Но помните, когда getaddrinfo возвращает более длинный результат, чем ожидалось.

6
ответ дан 27 November 2019 в 17:08
поделиться

Я работаю над проектом сопоставления самого длинного префикса, поэтому я разделяю адрес на 4 целых числа для адресов IPv4. Это работает хорошо. Я бы расширил это до адресов IPv6.

1
ответ дан 27 November 2019 в 17:08
поделиться
Другие вопросы по тегам:

Похожие вопросы: