Run the "second file" that does the work in the background on a web server, for example, through exec or cgi (depends on the OS / environment / settings / permissions, but is generally doable). There was a question on this topic , and most likely not one. The task is similar to yours.
Next, transfer the value of $ i from the "second file (script)" through the database, or through a text file (worse and stranger). For example, each cycle $ i will increase by 1 and written to the database (or file). When you need to find out the current value of $ i on the client and show it to the user - make a request to the database (via another php script) or to a file on the server. So you can get the current value of $ i on the client, without interfering with the work.
The display of progress can be done through javascript:setTimeout() through an interval acceptable for your task, 50-500 milliseconds, for example.
Separately, I want to add that the input parameters of work, intermediate results and the final result, as well as the unique number, are the easiest to combine into an object “task / task” and save the whole database. A working script (worker) will be run periodically and:
- Search for a job in the list of tasks not occupied
- If found, take one, block in the database
- Do some part of it
- Save intermediate / final result in the database
- Unlock task in db
- Terminate, or launch a new iteration of yourself
This is a very general algorithm)
UPD: Added a simple example code
The index.php file, in the example, displays the form for the start and the current status of the task:
<?php ob_start(); $html = ''; /* Структура БД -- -- Структура таблицы `tasks` -- CREATE TABLE IF NOT EXISTS `tasks` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'Первичный ключ, номер задачи', `lock` int(11) NOT NULL COMMENT 'Флаг блокировки задачи', `input` int(11) NOT NULL COMMENT 'Входные данные задачи', `output` int(11) NOT NULL COMMENT 'Выходные данные задачи', `current` int(11) NOT NULL COMMENT 'Текущие или промежуточные данные задачи', `progress` double NOT NULL COMMENT 'Поле прогресса задачи, будет полезно для сложных многоступенчатых задач', PRIMARY KEY (`id`), KEY `lock` (`lock`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; */ /* Подключаемся к БД */ $link = mysqli_connect('localhost', 'root', 'root', 'stackoverflow'); $task_id = isset($_GET['task_id']) ? intval($_GET['task_id']) : NULL; $progress = isset($_GET['progress']) && $_GET['progress'] ? true : false; if ($task_id) { /* Отображаем страницу данных по конкретной задаче */ $result = mysqli_query($link, "SELECT * FROM `tasks` WHERE `id` = ".mysqli_real_escape_string($link, $task_id)." LIMIT 1;"); if ($result && $task = mysqli_fetch_assoc($result)) { if ($progress) { /* Если был запрошен только прогресс, возвращаем его */ $html .= sprintf('%.1f', $task['progress']); } else { /* Иначе */ $html .= '<h3>Задача #'.$task_id.'</h3> <p>Прогресс: <span id="progress">'.sprintf('%.1f', $task['progress']).'</span> %</p> '; if (floatval($task['progress']) < 100.0) { /* Также добавляем скрипт для получения прогресса по AJAX */ $html .= ' <script src="http://code.jquery.com/jquery-3.2.1.min.js"></script> <script> var updateProgressIntervalId = null; $(function(){ updateProgressIntervalId = setInterval(function(){ /* Анонимная функция для обновления значения прогресса на странице клиента */ $.get("index.php", {task_id:'.$task_id.',progress:1},function(data, textStatus, jqXHR){ /* Callback для обработки результата ответа */ if (textStatus == "success" && data) { $("#progress").html(data); if (Number(data) == 100.0) { /* Останавливаем опрос прогресса по задаче */ clearInterval(updateProgressIntervalId); } } }); }, 200); }); </script> '; } } } else { $html .= '<p>Задача #'.$task_id.' не найдена</p>'; } } else { /* Отображаем страницу запуска задачи */ $html .= '<h3>Пример</h3> <form action="" method="post"> <input type="submit" name="start" value="Запустить новую задачу и запустить процесс работы"> </form> <form action="" method="post"> <input type="submit" name="worker" value="Запустить процесс работы"> </form> '; /* Проверяем, а не была ли запущена задача */ if (isset($_POST['start'])) { mysqli_query($link, "INSERT INTO `tasks` (`lock`,`input`,`output`,`current`,`progress`) VALUES (0,0,10000,0,0);"); $task_id = mysqli_insert_id($link); header('Location: index.php?task_id='.$task_id); } if (isset($_POST['start']) || isset($_POST['worker'])) { /* Запускаем воркер в фоне. Конкретная строка зависит от вашей ОС/сервера и настроек */ exec('/usr/bin/php -f '.__DIR__.'/worker.php > /dev/null 2>&1 &'); } } /* Отключаемся от БД */ mysqli_close($link); if ($progress) { print $html; } else { print '<html> <head> <title>ru.stackoverflow.com/questions/759003/</title> </head> <body> '.$html.' </body> </html> '; } ob_flush(); ?>


File worker.php , does work on tasks. It can be run in several instances, for example, one for each active task.
<?php /* Подключаемся к БД */ $link = mysqli_connect('localhost', 'root', 'root', 'stackoverflow'); /* Флаг наличия работы */ $need_to_restart = false; /* Ищем задачи, которые свободны и не завершены */ $result = mysqli_query($link, "SELECT * FROM `tasks` WHERE `lock` = 0 AND `progress` < 100 LIMIT 1;"); if ($result && $task = mysqli_fetch_assoc($result)) { /* Блокируем задачу */ mysqli_query($link, "UPDATE `tasks` SET `lock` = 1 WHERE `id` = ".mysqli_real_escape_string($link, $task['id']).";"); /* Выполняем некую работу (+1 к промежуточному значения в данном случае) */ $task['current'] += 1; $task['progress'] = 100.0 * $task['current'] / $task['output']; if ($task['progress'] > 100.0) { $task['progress'] = 100.0; } /* Обновляем и разблокируем задачу */ mysqli_query($link, "UPDATE `tasks` SET `lock` = 0, `current` = ".mysqli_real_escape_string($link, $task['current']).", `progress` = ".mysqli_real_escape_string($link, $task['progress'])." WHERE `id` = ".mysqli_real_escape_string($link, $task['id']).";"); /* Немного отладочного вывода */ print 'task #'.$task['id'].' '.sprintf('%.1f', $task['progress']).' %'; /* Проверяем наличие работы в очереди */ $result = mysqli_query($link, "SELECT * FROM `tasks` WHERE `lock` = 0 AND `progress` < 100 LIMIT 1;"); if ($result && $task = mysqli_fetch_assoc($result)) { $need_to_restart = true; } } /* Отключаемся от БД */ mysqli_close($link); if ($need_to_restart) { /* Запускаем воркер в фоне */ exec('/usr/bin/php -f '.__DIR__.'/worker.php > /dev/null 2>&1 &'); } ?>
The example was written by me, checked on CentOS 7 (kernel 3.10.0) + Apache / 2.4.6 + MariaDB / 5.5.56 + php / 5.4.16
