Задать вопрос
@Ex1st

Как инкрементировать число?

Мне нужно передать данные из формы и записать в файл. Пусть после первой отправки число будет 1, после второй 2, и так далее. Проблема в том, что если сделать
$a = 0
$a++;

то после следующей отправки я затру и будет снова 1. Как можно решить? Число из самой формы не передается, оно должно присваиваться автоматически. По сути это айди

P.S. Сори за нубский вопрос, но что-то я прям залип
  • Вопрос задан
  • 130 просмотров
Подписаться 1 Простой 10 комментариев
Решения вопроса 1
Compolomus
@Compolomus Куратор тега PHP
Комполом-быдлокодер
echo '<form action="" method="post">
        <input type="text" name="name" />
        <input type="submit" name="submit" />
        </form>';

$data = 'data.dat';

if (!file_exists($data)) {
    touch($data);
}

if (isset($_POST['submit'])) {
    $array = file($data, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
    $int = count($array) ? (int)end($array) : 0;
    $array[] = ++$int . ':' . ($_POST['name'] ?? 'Test') . PHP_EOL;
    $fp = fopen($data, 'r+b');
    if (flock($fp, LOCK_EX)) {
        ftruncate($fp, 0);
        fwrite($fp, implode(PHP_EOL, $array));
        fflush($fp);
        flock($fp, LOCK_UN);
    }
}
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
@rPman
В терминах базы данных это называется sequence, в каких то это специальный объект с этим именем, значение которого можно запросить и получить следующее, в каких то используется стратегия autoincrement, когда это значение вычисляется автоматически при добавлении в таблицу (например primary key) в каких то, а значит следующее значение можно получить только добавив запись, ну а в совсем уж слабых, пользователи заводят специальную таблицу, где одна запись - сиквенс, значение которого можно прочитать и увеличить на нужное число простым update (и использовать блокировки).

Самое главное, в базах данных за многопользовательский доступ (а значит конфликты, что делать если два пользователя одновременно затребуют следующее значение), отвечает механизм транзакций.

При попытке реализовать подобное на базе файлов возникнет необходимость реализовывать контроль за подобными коллизиями уже самому.
обожаю велосипеды, не надо так делать
Пишите в файл, добавляя символы < и > (смысл у каждого - транзакция начата и завершена соответственно), текущая позиция (размер файла) будет значением сиквенса (т.е. сначала вы определяете размер файла, и читаете его последний байт, если он < то ждете случайное время в миллисекундах и повторяете процесс, если он >, значит текущая позиция будет номером сиквенса, добавляете в файл символ <, отрабатываете генерацию формы, пишете >, это самый опасный момент, если нет сервера, смерть процесса до этого момента 'заблокирует' работу, так всегда бывает когда нет сервера, чтобы возобновить - достаточно добавить >), если нужен счетчик то считаете количество < во всем файле до текущей позиции.
Если счетчик должен считать долго, можно в начало файла записывать определенное число (выравнивая его по фиксированному количеству символов, например sprintf('%08u',$seq);) отдельным процессом на сервере запустить периодическое усечение этого файла, процесс так же ждет момента когда последний символ будет >, переименовывает файл, считает в нем количество, и обновляет запись в первоначальном файле, создав его если он не создался и после этого удаляет предыдущий переименованный.
В этом случае не важно, в какой последовательности будет происходить работа с файлом и сколько в него будут писать приложений, пока размер файла меньше размера сектора (4кб минимум чаще больше) то операции с ним атомарны (под вопросом сетевые FS типа nfs/samba но на них и так проблемы) а значит сам файл станет механизмом контроля и синхронизации.

p.s. Внимательно подумайте, вам нужен счетчик или нужно уникальное значение? Можно чтобы каждое следующее значение было ровно на единицы больше? может быть оно меньше предыдущего?

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

Самый простой алгоритм - который по правде говоря не дает гарантий, но значительно понижает вероятность коллизий - взять текущее время, в милли-/микро-/пико-секундах, при наличии кучи машин - добавить номер этой машины, можно добавить еще случайное число (чем больше его разрядность тем ниже вероятность коллизий)
sprintf("%u",microtime(true)*1000000);
еще есть метод uniqid, он делает примерно то же самое но возвращает hex строку.

p.s. время на машинах должно быть синхронизировано с точным, чтобы не было такого что в какой то момент оно откатится назад на достаточное значение чтобы метод дал сбой
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы