Решил-таки составить нормальное регулярное выражение для вычленение IP-адреса из заголовков и прочего. Задача достаточно простая: нужно найти 4 октета, разделённых точкой, которые при этом могут принимать значение от 0 до 255.
Сначала придумаем выражение для одного октета, это будет (25[0-5]|2[0-4]\d|1\d{2}|\d{1,2}).
Дальше в коде, в зависимости от задач нужно будет его применить. Я придерживаюсь такой стратегии: в базе в MySQL адрес хранить в виде целого, конвертируя значение через php-функцию ip2long() на входе и long2ip() на выходе. В PostgreSQL для этого есть тип данных CIDR.
Получается примерно так:
$octet = '(25[0-5]|2[0-4]\d|1\d{2}|\d{1,2})';
$cutPattern = "/^{$octet}\.{$octet}\.{$octet}\.{$octet}.*/";
$matchPattern = "/({$octet}\.){3}{$octet}/";
Для записи в базу берём результат preg_replace($cutPattern, '$1.$2.$3.$4', $remote_addr); тогда у нас возьмётся только начальный кусок (иногда бывает, что в заголовок попадает несколько адресов через запятую).
Для простого соответствия достаточно будет preg_match($matchPattern, $temote_addr);
В $remote_addr у нас хранится, соответственно, адрес. Обычно это $_SERVER['REMOTE_ADDR'], но это частный случай.
В общем виде шаблон такой: ((25[0-5]|2[0-4]\d|1\d{2}|\d{1,2})\.){3}(25[0-5]|2[0-4]\d|1\d{2}|\d{1,2})
Для случаев особой паранойи можно в начале добавить ^ (признак начала строки).
Обязательным является только текст комментария. Он не может превышать 4кБ. Остальные поля служат для обратной связи. Имя всё же рекомендуется указать.