Форум программистов, компьютерный форум, киберфорум
PHP
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
1 / 1 / 0
Регистрация: 06.03.2024
Сообщений: 113

Найти строку в файле, и если нет, то добавить новую

13.10.2025, 22:38. Показов 1198. Ответов 10
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте уважаемые специалисты.

В файле

$file = "db/list";

нужно найти строку

$_POST['walletnumber'] = trim($_POST['walletnumber']);

и если такая строка не найдена, то добавить новую. Вот код:

PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// читаем содержимое файла
$lines = file($file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
 
// запоминаем сколько строк в файле было изначально
$countLines = count($lines);
 
// проверяем каждую строку
foreach ($lines as $key => $line) {
 
    // если нет такой строки ($_POST['walletnumber']) в файле, то добавляем новую
    if (!strstr($line, $_POST['walletnumber'])) {
 
        $rec = "$_POST[walletnumber]\r\n";
        file_put_contents($file, $rec, FILE_APPEND | LOCK_EX);
    }
}
 
// записываем обновленный массив обратно
if ($countLines !== count($lines)) {
 
    file_put_contents($file, implode(PHP_EOL, $lines) . "\n");
}
В итоге у меня получается так, что:

- если файл пустой, то совсем ничего не добавляется;

- если файл не пустой, то строка добавляется в любом случае, если даже такая строка в файле уже существует;

Пожалуйста, поправьте меня, что я делаю не так?
0
Лучшие ответы (1)
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
13.10.2025, 22:38
Ответы с готовыми решениями:

Дана строка. Если она представляет собой запись целого числа, то вывести 1; если вещественного (с дробной частью), то вывести 2; если строку нельзя
Дана строка. Если она представляет собой запись целого числа, то вывести 1; если вещественного (с...

Если элемент массива больше А, то добавить перед элементом число А, иначе добавить после элемента число Б
Дан целочисленный массив и два числа А и Б. Если элемент массива больше А то добавить перед...

PHPExcel: Данные из формы добавить в новую строку файла
Помогите, у меня есть форма, из которой данные должны добавиться в уже существующий файл в новую...

10
3011 / 1444 / 262
Регистрация: 16.03.2008
Сообщений: 6,441
Записей в блоге: 2
13.10.2025, 23:06
Так попробуйте прочитать текущий код "по русски"

1. Входим в цикл по строкам
2. Если в текущей строке не содержится значение параметра walletnumber то дописываем строку
3. По выходу из цикла (если количество элементов изменилось) то полностью перезаписываем файл массивом


Наводящие вопросы:
1 не замечаете в том алгоритме что я озвучил не состыковок?
2. в какой момент времени может измениться массив в принципе (где вы в него что либо добавляете)?
3. Если в файле нет ни одной записи, какая строка должна записать нужное в файл?
4. Условие проверки (предположим все остальное кроме условия вы исправили): что будет если мы сначала записали Apple а потом app.
5. Зачем вам strstr вам разве нужно знать часть строки начиная с заданной ведь если вам нужно знать входит ли введенная строка в считанную есть более подходящая функция. Не говоря уж, что озвученное над кодом условие вообще другое
2
 Аватар для sad67man
2590 / 1495 / 688
Регистрация: 23.08.2015
Сообщений: 3,775
14.10.2025, 13:01
Лучший ответ Сообщение было отмечено Kuzma92 как решение

Решение

Цитата Сообщение от Kuzma92 Посмотреть сообщение
- если файл пустой, то совсем ничего не добавляется;
Если файл пустой, то тело цикла foreach не выполнится.

Цитата Сообщение от Kuzma92 Посмотреть сообщение
- если файл не пустой, то строка добавляется в любом случае, если даже такая строка в файле уже существует;
PHP
1
2
// если нет такой строки ($_POST['walletnumber']) в файле
    if (!strstr($line, $_POST['walletnumber'])) {
Комментарии не соответствуют коду, вы тут сравниваете построчно, получается, что условие будет выполняться на каждую строку, где нет вхождений.

А вам нужно сначала обойти весь массив целиком, и только потом делать какие-то выводы. Для этого можно добавить отдельную переменную-флаг.

PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$isFind = false;
 
// проверяем каждую строку
foreach ($lines as $key => $line) {
    if (strstr($line, $_POST['walletnumber'])) {
         $isFind = true;
         break;
    }
}
 
// если нет такой строки ($_POST['walletnumber']) в файле, то добавляем новую
if (!$isFind) {
    $rec = "$_POST[walletnumber]\r\n";
    file_put_contents($file, $rec, FILE_APPEND | LOCK_EX);
}
Цитата Сообщение от Kuzma92 Посмотреть сообщение
PHP
1
// записываем обновленный массив обратно
вы нигде массив не обновляли, а записывали сразу в файл.. поэтому этот блок кода никогда не будет выполняться.
1
1 / 1 / 0
Регистрация: 06.03.2024
Сообщений: 113
14.10.2025, 14:41  [ТС]
sad67man, спасибо вам за развернутый ответ. Увидел свои ошибки, понял как должно быть правильно.
voral, вам спасибо за наводящие вопросы. Постарался во всем разобраться.
В силу своих знаний, сделал вот так:

PHP
1
2
3
4
5
6
7
8
9
    $path_list = "db/list";
        $list = file_get_contents($path_list);
        $add = $_POST['walletnumber'];
        if (strpos($list, $add) !== false) {
        }
        else {
 
            file_put_contents($path_list, $add."\r\n", FILE_APPEND | LOCK_EX);
        }
Конечно, все работает. Но хотелось бы, услышать комментарии от профи, можно ли так делать и правильно ли это. Всем благодарен.
0
 Аватар для sad67man
2590 / 1495 / 688
Регистрация: 23.08.2015
Сообщений: 3,775
14.10.2025, 16:22
Цитата Сообщение от Kuzma92 Посмотреть сообщение
Но хотелось бы, услышать комментарии от профи, можно ли так делать и правильно ли это. Всем благодарен.
1) Ну первая мысль возникает, что может быть частичное совпадение по части слова.. А у вас вроде по условию задачи нужно искать строку целиком.. Вам уже об этом писали.
2) Если файл огромный, то может не хватить памяти, чтоб его содержимое загнать в переменную. В этом случае построчное чтение выгоднее, но в таком случае и функция file() тоже не подойдет.

3)
Цитата Сообщение от Kuzma92 Посмотреть сообщение
PHP
1
2
3
4
if (strpos($list, $add) !== false) {
} else {
    file_put_contents($path_list, $add."\r\n", FILE_APPEND | LOCK_EX);
}
Тут лучше все-таки инвертировать условие
PHP
1
2
3
if (strpos($list, $add) === false) {
    file_put_contents($path_list, $add."\r\n", FILE_APPEND | LOCK_EX);
}
Чтоб не было пустого блока - это выглядит странно.
1
1 / 1 / 0
Регистрация: 06.03.2024
Сообщений: 113
14.10.2025, 21:20  [ТС]
sad67man, всё наконец-то, до меня дошло, как до жирафа правда)) Теперь в этом моменте полностью разобрался и буду знать. Спасибо вам огромное за помощь, уделенное время, и главное за полезную для меня информацию.
0
3011 / 1444 / 262
Регистрация: 16.03.2008
Сообщений: 6,441
Записей в блоге: 2
15.10.2025, 07:51
Ну я бы все же проверил условие на соответствие исходной задачи. вы либо условия в начале топика описали не верные либо у вас не верное условие

Цитата Сообщение от Kuzma92 Посмотреть сообщение
В файле
$file = "db/list";
нужно найти строку
$_POST['walletnumber'] = trim($_POST['walletnumber']);
и если такая строка не найдена, то добавить новую. Вот код:
Здесь у вас во первых есть обработка при помощи trim. а в конечном коде ее нет. соответственно, если:
пользователь введет первый раз c пробелом в конце, а второй раз без пробелом - строки будет две. (а если в другой последовательности - то одна)
пользователь введет первый раз строку с переносом строки, а второй раз с без - строки будет три!. (а ввести так может легко. например он значение скопирует через буфер обмена из файлика открытого в текстовом редакторе и захватит переносы)
Порядок ломающий логику будет воспроизводиться наоборот если поменять параметры местами в функции strpos - но суть одна


Т.е. полагаю стоит "нормализовать" полученное значение. И, кстати, вы поступили правильно что завели до цикла переменную add (только название придумали не логичное. а если не надо добавлять ? ).

Кроме того, уже зависит от вашей задачи. Я так понимаю речь идет о номерах кошельков. Если там могут быть буквы, то пользователь может один раз ввести заглавными буквами (или в разнобой) а во второй раз все маленькими... И у вас будут две записи. Если регистр в реальности не имеет значение - необходимо приводить к единому.


Далее поговорим об условии.
strpos($list, $add) Это поиск строки в подстроке. отсюда: если сначала будет передано app а потом apple - будет только одна строка. Это точно то, что вам нужно?

Если да - ок. (кстати в php 8 есть более "правильная" функция str_contains)


Если мы тут видим весь код и к скрипту будет обращение пустое - без переданого параметра или с пустым значением - будет добавляться пустая строка - каждый раз.

Далее строка
PHP
1
$rec = "$_POST[walletnumber]\r\n";
будет работать не корректно в версиях php 8+
надо либо
PHP
1
$rec = "{$_POST['walletnumber']}\r\n";
Либо. (тут в добавок от себя - я обычно завершение строки ставлю при помощи константы, чтобы ставилось в зависимости от ОС - не везде два символа)
PHP
1
$rec = $add.PHP_EOL;

На уровне "микрооптимизаций" (или даже нано-) я обычно стараюсь избегать лишних (не нужных по логике) инверсий булевых значений. т.е. !isFind лишнее я бы сделал обратную переменную. но это конечно мелочи

Так же я бы разложил на функции. Просто чтобы алгоритм стал более очевидным. в данном случае выделил бы определение надо ли производить запись. Т.е. чтобы был виден отдельно "общий алгоритм" и не мешался при взгляде с алгоритмом принятия решения о записи. Но это уже дело вкуса - можно и вынести из функции

Так же хорошо бы добавить проверку наличия файла иначе у вас скрипт упадет с ошибкой

Т.е. с учетом вышесказанного (если у вас старая версия PHP без типизации - просто уберите типы из сигнатуры функции)
PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?php
 
$file = "db/list";
 
// Нормализация
$walletNumber = strtolower(trim($_POST['walletnumber']));
// Добавили проверку исключающую запись пустого
if ($walletNumber !== '') {
    if (file_exists($file)) {
        $lines = file($file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
        $needSave = needSave($walletNumber, $lines);
    } else {
        $needSave = true;
    }
    if ($needSave) {
        file_put_contents($file, $walletNumber . PHP_EOL, FILE_APPEND | LOCK_EX);
    }
}
 
function needSave(string $walletNumber, array $lines): bool
{
    foreach ($lines as $line) {
        if ($line === $walletNumber) {
            return false;
        }
    }
    return true;
}
Ну и под конец. все это вообще можно схлопнуть (если алгоритм определения необходимости записи именно такой) используя in_array

Добавлено через 10 секунд
PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$file = "db/list";
 
// Нормализация
$walletNumber = strtolower(trim($_POST['walletnumber']));
// Добавили проверку исключающую запись пустого
if ($walletNumber !== '') {
    if (file_exists($file)) {
        $lines = file($file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
        $needSave = !in_array($walletNumber, $lines);
    } else {
        $needSave = true;
    }
    if ($needSave) {
        file_put_contents($file, $walletNumber . PHP_EOL, FILE_APPEND | LOCK_EX);
    }
}
Добавлено через 3 минуты
Забыл еще один момент. Ведь параметр может быть и не передан. Предусмотрим и это (для php 7.4+)
добавим значение по умолчанию(??'')
PHP
1
$walletNumber = strtolower(trim($_POST['walletnumber']??''));
0
 Аватар для sad67man
2590 / 1495 / 688
Регистрация: 23.08.2015
Сообщений: 3,775
15.10.2025, 10:45
Цитата Сообщение от voral Посмотреть сообщение
PHP
1
$needSave = needSave($walletNumber, $lines);
Функция веселая получилась.

PHP
1
2
3
4
5
public function addNumber($number) {
    if ($this->repository->needSave($number)) {
        $this->repository->save($number)
    }
}
Если надо сохранить - сохраняем) Какие вопросы?
0
3011 / 1444 / 262
Регистрация: 16.03.2008
Сообщений: 6,441
Записей в блоге: 2
15.10.2025, 11:13
Цитата Сообщение от sad67man Посмотреть сообщение
Функция веселая получилась.
Ну тут она скорее для демонстрации.

Цитата Сообщение от sad67man Посмотреть сообщение
Если надо сохранить - сохраняем) Какие вопросы?
Да тут вокруг этого примера можно вообще на целую полнометражную лекцию развернуть. Ведь тут и на функциях сначала можно привести к примерно такому виду, и на ООП переключиться и еще ряд сопутствующих тем упомянуть... главное во время остановиться.

По большому счету тут правильно и чтение файла убрать в needSave т.к. условие записи "отсутствует запись в файле" )


в общем (оставаясь в фукнционале можно и так)

PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
$fileName = 'db/log';
 
// Нормализация
$walletNumber = strtolower(trim($_POST['walletnumber'] ?? ''));
try {
// а еще добавить проверку на формат, корректность и т.п, которая бросит исключение
 
    if ($walletNumber !== '' && needSave($fileName, $walletNumber)) {
        save($fileName, $walletNumber);
    }
} catch (Exception $e) {
    echo $e->getMessage(), PHP_EOL;
}
 
function save(string $fileName, string $walletNumber): void
{
    if (!file_put_contents($fileName, $walletNumber . PHP_EOL, FILE_APPEND | LOCK_EX)) {
        $error = error_get_last();
        throw new Exception($error['message']);
    };
}
 
function needSave(string $fileName, string $walletNumber): bool
{
    if (file_exists($fileName)) {
        // И тут действительно, если универсально делать, лучше построчное чтение
        $lines = file($fileName, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
        return !in_array($walletNumber, $lines);
    }
    return true;
}
0
 Аватар для sad67man
2590 / 1495 / 688
Регистрация: 23.08.2015
Сообщений: 3,775
15.10.2025, 12:35
Цитата Сообщение от voral Посмотреть сообщение
Да тут вокруг этого примера можно вообще на целую полнометражную лекцию развернуть. Ведь тут и на функциях сначала можно привести к примерно такому виду, и на ООП переключиться и еще ряд сопутствующих тем упомянуть... главное во время остановиться.
Я хотел показать, что название функции не очень удачное. Мне это показалось забавным.
0
 Аватар для Серибериешка
3 / 3 / 0
Регистрация: 19.10.2025
Сообщений: 55
20.10.2025, 12:34
Цитата Сообщение от Kuzma92 Посмотреть сообщение
strpos($list, $add) !== false
этот костыль давно решён - вот тут
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
20.10.2025, 12:34
Помогаю со студенческими работами здесь

При записи в лог файл - не переносит новые записи на новые строки
foreach( $_FILES as $file ) { $format=pathinfo($file, PATHINFO_EXTENSION);...

Если $i делится на 2 то выделяем строку цветом aqua, а если на 3 - то курсивом
Как сделать так, чтобы 6 тоже был курсив?Так как он делится на 2 и на 3. Условие: если $i делится...

Дана строка. Если она представляет собой запись целого числа, то вывести 1; если вещественного (с дробной частью), то вывести 2
Помогите пожалуйста! Дана строка. Если она представляет собой запись целого числа, то вывести 1;...

Добавить в начале каждой новой строки текст
Сабж.Извиняюсь, может это проще сделать и не на php с помощью рег. выражений...В общем нужно...

Как можно одним запросом редактировать предыдущую строку и добавить новый?
Как можно одним запросом редактировать предыдущую строку и добавить новый? Если можно на...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
11
Ответ Создать тему
Новые блоги и статьи
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
Фото: Daniel Greenwood
kumehtar 13.11.2025
Расскажи мне о Мире, бродяга
kumehtar 12.11.2025
— Расскажи мне о Мире, бродяга, Ты же видел моря и метели. Как сменялись короны и стяги, Как эпохи стрелою летели. - Этот мир — это крылья и горы, Снег и пламя, любовь и тревоги, И бескрайние. . .
PowerShell Snippets
iNNOKENTIY21 11.11.2025
Модуль PowerShell 5. 1+ : Snippets. psm1 У меня модуль расположен в пользовательской папке модулей, по умолчанию: \Documents\WindowsPowerShell\Modules\Snippets\ А в самом низу файла-профиля. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru