Пошаговая отправка информации с помощью PHP exec()

#php #ajax #bash #composer-php #command-line-interface

#php #ajax #bash #композитор-php #интерфейс командной строки

Вопрос:

Я использую PHP exec() для установки зависимостей Composer:

exec('php composer.phar install -d ' . dirname(__DIR__), $out);

Это запускается с помощью запроса ajax post. Все работает нормально, и возврат из exec() выводится на экран.

exit(json_encode($out));

Однако мне нужен способ периодической отправки данных обратно в обратный вызов ajax, чтобы я мог отображать каждый бит информации, а не весь блок сразу.

Хотя не уверен, возможно ли это.

Я должен упомянуть, что серверы, на которых это будет выполняться, не будут иметь ничего похожего на NodeJS и, скорее всего, будут общедоступным хостингом.

Комментарии:

1. Я думаю, WebSocket s может помочь.

2. Я бы предпочел не использовать websockets, поскольку мне нужно поддерживать некоторые старые браузеры (IE)

3. Как? Основная проблема заключается в том, что Carl создает поток данных, но затем передает его в виде дейтаграммы.

4. После открытия соединения он мог передавать фрагменты данных на другую сторону. Чтобы реализовать это только с помощью Ajax, вам нужно будет создать конечный автомат, но это может легко усложниться.

5. Существуют решения для websockets в IE6 с использованием flash github.com/arahaya/FlashSocket

Ответ №1:

Если оставить в стороне проблемы безопасности выполнения по требованию, если вы можете записать / протоколировать статус выходных данных в файл, вы можете написать простой AJAX-опросник (поскольку вы предпочитаете не использовать WebSockets).

В вашем exec попробуйте:

add-task.php

 $jobId = uniqid();
$outfile = $jobId . "-results.txt";
exec('php composer.phar install -d ' . dirname(__DIR__) . " > $outfile amp;", $out);
$result = array("jobId" => $jobId);
echo json_encode($result);
  

Хорошо, теперь отправьте это $jobId клиенту, чтобы он мог опрашивать обновления. Я использую вариант концептуального проекта на github:https://github.com/panique/php-long-polling

server.php

 $jobid = isset($_GET['jobid']) ? $_GET['jobid'] : null;
$outputfile = $jobid . "-results.txt";
$lastTimestamp = isset($_GET['timestamp']) ? (int)$_GET['timestamp'] : null;

// get timestamp of when file has been changed the last time
clearstatcache();
$lastModified = filemtime($outputfile);

// if no timestamp delivered via ajax 
// or data.txt has been changed SINCE last ajax timestamp
if ($lastTimestamp == null || $lastModified > $lastTimestamp) {

    // get content of data.txt
    $data = file_get_contents($outputfile);

    // put data.txt's content and timestamp of 
    // last data.txt change into array
    $result = array(
        'data' => $data,
        'timestamp' => $lastTimestamp
    );

    // encode to JSON, render the result (for AJAX)
    $json = json_encode($result);

} else {

    // No updates in the file, just kick back the current time
    // and the client will check back later
    $result = array(
        'timestamp' => time()
    );

    $json = json_encode($result);
}

header("Content-Type: application/json");
echo $json;
  

Затем в браузере у вас просто есть крошечный клиент, который запрашивает ‘jobid’ для проверки статуса.

client.js

 $(function () {

  var jobid = '12345';
  function checkForUpdates(timestamp) {
    $.ajax({
      type: 'GET',
      url: 'http://localhost/server.php',
      data: {
        'timestamp': timestamp,
        'jobid': jobid
      },
      success: function (data) {
        var obj = jQuery.parseJSON(data);
        if (obj.data) {
          // Update status content
          $('#response').text(obj.data);
        }
        // Check again in a second
        setTimeout(function () {
          checkForUpdates(obj.timestamp);
        }, 1000);
      }
    });
  }

  checkForUpdates();
});
  

index.html

 <html>
    <head>
        <script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
        <script type="text/javascript" src="client.js"></script>
    </head>
    <body>
        <h1>Status:</h1>
        <div><pre id="response"></pre></div>
    </body>
</html>