IPv4 в INT, INSERT из массива и array_reduce в задачах 1С‑Битрикс
Зачем это в проекте на «1С‑Битрикс»
В кастомных таблицах голосований, антифрода, логов посещений и интеграций тот же PHP и тот же MySQL, что и у ядра. Ниже — переработанные приёмы из раздела «Решения PHP»: без копипасты устаревшего кода, с акцентом на то, что важно бэкенд‑разработчику на битриксовом стеке.
IPv4 как INT UNSIGNED и «минусовой» ip2long
Адрес удобно хранить в INT UNSIGNED NOT NULL: меньше места, быстрее индекс, родные битовые операции. Функция ip2long() в PHP возвращает подписанное целое; на 32‑битном PHP и для многих октетов значение уходит в отрицательную область, хотя в MySQL вы ожидали беззнаковое.
Для корректной строки представления беззнакового 32‑битного числа используйте спецификатор %u у sprintf / printf, чтобы не путать знаковое отображение с тем, что реально лежит в UNSIGNED‑колонке:
$packed = ip2long($_SERVER['REMOTE_ADDR']);
// $packed может быть отрицательным в var_dump — это норма для signed int.
$unsigned = sprintf('%u', $packed);
echo $unsigned;На 64‑битном PHP ip2long для валидного IPv4 часто даёт положительное число, но переносимый код всё равно проходит через sprintf('%u', …) или вообще опирается на MySQL (см. ниже).
MySQL: INET_ATON / INET_NTOA вместо ручного ip2long
На стороне БД типичный и устойчивый вариант — не тащить преобразование в PHP, а передать «человеческий» IP в SQL. В модуле голосований и аналогичных местах это снимает часть путаницы со знаковостью:
global $DB;
$addr = $DB->ForSql($_SERVER['REMOTE_ADDR'], 15);
$sql = "INSERT INTO my_vote_log (ip, item_id) VALUES (INET_ATON('" . $addr . "'), " . (int)$itemId . ")";
$DB->Query($sql);Чтение обратно: INET_NTOA(ip_col) в SELECT или хранить и число, и представление только на выдаче. Для новых модулей рассматривайте подготовленные запросы через API D7/SQL helper там, где они уместны; ForSql и приведение типов здесь иллюстрируют привычный уровень ядра.
Сбор INSERT из ассоциативного массива через array_map
Нужно вставить строку, ключи которой — имена колонок, значения — из бизнес‑массива. Идея: имена экранировать обратными кавычками, значения — через кавычки и экранирование строк (в ядре для запросов к собственным таблицам используется свой слой; для учебного примера оставлена классическая схема с addslashes — в бою для пользовательских данных лучше явная санитация или плейсхолдеры):
public function save(array $data): void
{
$wrapBacktick = static function ($name) {
return '`' . str_replace('`', '``', $name) . '`';
};
$wrapSqlString = static function ($value) {
return "'" . addslashes((string)$value) . "'";
};
$columns = implode(', ', array_map($wrapBacktick, array_keys($data)));
$values = implode(', ', array_map($wrapSqlString, array_values($data)));
$sql = "INSERT INTO `{$this->table}` ($columns) VALUES ($values)";
$this->connection->Query($sql);
}Такой приём удобен для простых служебных таблиц; для публичного ввода приоритет — параметризованные запросы и типобезопасные геттеры.
array_reduce: собрать производный список из массива строк
Нужно пройти список структур и накопить, например, все section_id (или уникализировать — добавьте свою логику в колбэке):
$rows = [
['id' => 1, 'section_id' => 1],
['id' => 2, 'section_id' => 2],
['id' => 3, 'section_id' => 2],
['id' => 3, 'section_id' => 3],
];
$sectionIds = array_reduce(
$rows,
static function (array $carry, array $item) {
$carry[] = (int)$item['section_id'];
return $carry;
},
[]
);
var_export($sectionIds);Для фильтрации дубликатов после цикла удобно array_unique или накопление в ключах ассоциативного массива.
Кратко
- Храните IPv4 как UNSIGNED; для отображения числа из
ip2longиспользуйтеsprintf('%u', …). - В SQL предпочтительны
INET_ATON/INET_NTOA, чтобы не воевать со знаковостью в PHP. array_map— практичный способ собрать списки колонок и значений дляINSERT; не забывайте про безопасность строк.array_reduce— гибкая свёртка для подготовки данных перед ORM или сырым запросом.
Не хотите копаться сами?
Починю за 1-3 дня. Без предоплаты — оплата по результату.
15+ лет опыта с 1С-Битрикс · Без предоплаты · 7 дней гарантии