Yandex Metrika
sanches.free 1 просмотр

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 дней гарантии