php перебор массива, и сравнение с частью переменной через regexp
Подскажите пожалуйста как перебрать массив и сравнить его значения с частью переменной?
Я сам не программист, сильно не пинайте, комплектую код из разных кусочков)
Этот код судя по всему не работает)
$cli = $result. " " .$client. " " .$userAgent. " " .$rf;
$file = file("ip.txt");
foreach ($file as $value) {
if (preg_match("/($value)/", $cli)) {
{$nume=3;}
}
Сначала беру данные о посетителе. Ip, юзерагент, провайдер.
Но этой части кода тут нет.Эти данные объединяю в
$cli = $result. " " .$client. " " .$userAgent. " " .$rf;
- В файле
ip.txt- есть список ip и провайдеров которые я хочу найти у посетителя. Беру в виде массива
$file = file("ip.txt");
- Далее массив перебираю в переменную
$value:
foreach ($file as $value){ /** ... */ }
- А потом пытаюсь сравнить через
regex, есть ли в данных пользователя$cliхотя бы одно значение из массива$file
if (preg_match("/($value)/", $cli)){ /** ... */ }
- Если значение есть то
$nume=3;
Ответы (1 шт):
Далее я буду комментировать весь код построчно сверху вниз:
Неразрывный пробел
- это спецсимвол, который называется "Неразрывный пробел"
Как следует из названия, данный символ запрещает разделять "слова", соединённые данным символом и используется он в HTML, для того чтобы устойчивые сочетания слов нельзя было разделить на несколько строк.
Использовать данный символ в других случаях не рекомендуется.
Данный символ не является заменой обычному пробелу (" ").
Более того, иногда могут возникать путаница и проблемы с поиском, заменой и разделением строк.
Поэтому если Вы, не намеревались добиться неразрывной строки в HTML, в данном случае лучше заменить на обычный пробел:
$cli = $result. " " .$client. " " .$userAgent. " " .$rf;
Это выглядит, читается и распознаётся лучше, чем оригинальный вариант.
Также можно избежать конкатенацию(соединение строк), просто поместив переменные внутрь строки(между кавычками)
$cli = "{$result} {$client} {$userAgent} {$rf}";
или
$cli = "$result $client $userAgent $rf";
Однако, стоит помнить, что замена переменных значениями внутри строк работает только с двойными кавычками. С одинарными замена работать не будет.
Относительный путь
$file = file("ip.txt");
Стоит отдавать себе отчёт в том, что данный код будет работать только тогда, когда файл ip.txt находится в одной папке с запущенным скриптом, потому что Вы передали относительный путь.
Во избежание ошибок, желательно передавать полный путь к файлу, начиная с корня файловой системы.Например:
// для Linux
$file = file("/var/www/test/ip.txt");
// для Windows
$file = file("C:\Users\Michael\www\test\ip.txt");
Иногда на хостинге Вы не имеете доступа ко всей файловой системе и даже не знаете точно в какой именно папке будет расположен скрипт, но Вы знаете относительное положение скрипта и требуемых ресурсов.
В этом случае может помочь:
- константа
__DIR__, которая хранит в себе полный путь к директории, в которой находится запущенный скрипт. - символические ссылки на текущую
.и родительскую..директории - функция realpath(), которая, возвращает абсолютный канонизированный путь к файлу
Например:
$filename = realpath(__DIR__."/../../config/ip_list.txt");
Фигурные скобки
Рассмотрим код
if (/**condition */) {
{$nume=3;}
}
Данные вложенные фигурные скобки ({$nume=3;}) не несут никакой пользы и не имеют никакого смысла.
Данный участок лучше переписать так:
if (/**condition */) {
$nume = 3;
}
Проверка наличия подстроки в строке
Я иногда и сам грешу этим, тем не менее я не рекомендую использовать функцию preg_match() для проверки наличия определенной подстроки в строке.
preg_match() отвечает за то, соответствует ли строка регулярному выражению.
И это не совсем одно и тоже.
- Во-первых: вы немного усложняете код составлением регулярного выражения.
- Во-вторых: вы можете получить результаты, которые будут отличаться от ваших ожиданий из-за попадания символов, используемых в регулярных выражениях (например: точка может обозначать любой символ и т.д.)
- В-третьих: проверка регулярного выражения будет требовать больших ресурсов, что может дать знать о себе на большом объеме.
Вместо этого для проверки наличия подстроки в строке обычно используют функцию strpos() или её аналог для мультибайтовых строк mb_strpos()
Данные функции возвращают позицию первого вхождения подстроки в строке или false при её отсутствии.
Например:
echo strpos("abcdefg", "d");
// output: 3
// обратите внимание на то, что отчёт начинается с нуля
// если мы будем искать букву "a", функция вернёт 0 и это будет ее верной позицией в строке
echo strpos("abcdefg", "a");
// output: 0
// пытаемся найти подстроку, которой нет
echo strpos("abcdefg", "z");
// output: false
При отсутствии же функция вернёт false и таким образом можно будет проверять наличие подстроки в строке.
if (strpos($mystring, $findme) === false) {
echo "Строка '$findme' не найдена в строке '$mystring'";
} else {
echo "Строка '$findme' найдена в строке '$mystring'";
echo " в позиции $pos";
}
Обратите внимание на то, что в данном случае для сравнения используется не ==, а ===.
=== - это строгое сравнение, которое сравнивает не только значение но и тип переменной.
php это динамично-типизируемый язык программирования и переменные могут автоматически приводиться от одного типа к другому.
И в частности: false может автоматически приводиться к 0 и наоборот.
Для того чтобы исключить путаницу и возможную ошибку лучше использовать строгое сравнение.
if ( 0 == false ){
echo "0 равен false";
} else {
echo "0 НЕ равен false";
}
// output: 0 равен false
if ( 0 === false ){
echo "0 равен false";
} else {
echo "0 НЕ равен false";
}
// output: 0 НЕ равен false
Соответственно, при проверке наличия подстроки "a" в строке "abcdefg", может возникнуть проблема, потому что strpos("abcdefg","a") вернёт 0, который может автоматически привестись к false.
Поэтому в данном случае важно использовать строгое сравнение с учетом типов переменных.
Также есть оператор сравнения !== (строго не равно).
И именно его стоит использовать для проверки наличия подстроки в строке следующим образом.
if(strpos("abcdefg","a") !== false){
echo "Подстрока 'а' есть в строке 'abcdefg'";
}
// output: Подстрока 'а' есть в строке 'abcdefg'
Таким образом вашу проверку можно написать следующим образом:
if (strpos($cli, $value) !== false) {
// ...
}
Замечание:
Не прошло и ста лет, как в языке php восьмой версии появилась функцияstr_contains(), которая проверяет наличия подстроки в строке, однако, я не рекомендую пока её использовать, потому что php версии 8, вы еще не скоро встретите на серверах хостингов и пока что эта функция имеется чуть более чем нигде
str_contains: https://www.php.net/manual/ru/function.str-contains.php
Результат работы функции file()
Скорее всего именно данный пункт был причиной ошибочной работы вашего скрипта.
Дело в том, что функция file() возвращает вам содержимое файла в виде массива строк.
Подвох состоит в том, что в конце каждой строки есть символ перехода строки(\n).
А это значит, что символ перехода строки также присутствует в условии поиска.
Т.е. по сути:
Вы думаете что ищите строку 192.168.1.1
Но на самом деле вы ищите строку 192.168.1.1\n
которой вы закономерно не находите.
Более того регулярные выражения по умолчанию выполняют поиск в строке, а не во всем тексте и для поиска соответствия регулярному выражению в многострочном тексте нужно указывать специальные ключи. Что в очередной раз говорит о том, что лучше данную функцию(preg_match) использовать только по прямому назначению.
Соответственно, перед тем как выполнять поиск Вам желательно очистить строку от символа конца строки.
Сделать это можно с помощью функции trim(), передав в нее символ конца строки в качестве дополнительного параметра.
Символ конца строки можно указать как "\n" или с помощью константы PHP_EOL (EOL = End Of Line)
foreach ($file as $value) {
$line = trim($value, PHP_EOL);
// ...
}
В итоге:
$cli = "$result $client $userAgent $rf";
// при условии что ip.txt находится в той же папке
// в противном случае используйте ссылки на родительские директории
// для позиционирования файла ip.txt относительно запущенного скрипта
$file = file(__DIR__."/ip.txt");
foreach ($file as $value) {
$line = trim($value, PHP_EOL);
if (strpos($cli, $line) !== false) {
$nume = 3;
}
// ...
}
Проверка:
Я создал файл ip.txt со следующим содержимым:
192.168.1.1
192.168.1.2
192.168.1.3
192.168.1.4
192.168.1.5
192.168.1.6
192.168.1.7
192.168.1.8
192.168.1.9
И выполнил данный скрипт для проверки:
$result = "192.168.1.3";
$client = "some client code";
$userAgent = "user-agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36";
$rf = "https://ru.stackoverflow.com";
$cli = "$result $client $userAgent $rf";
$file = file(__DIR__."/ip.txt");
echo $cli."\n";
foreach ($file as $value) {
$line = trim($value, PHP_EOL);
if (strpos($cli, $line) !== false) {
echo "Данный клиент ($line) имеется в списке\n";
}
}
Вывод:
192.168.1.3 some client code Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36 https://ru.stackoverflow.com
Данный клиент (192.168.1.3) имеется в списке
Что значит, что данный код работает и он находит IP адрес из списка в файле.