質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.45%

  • PHP

    24602questions

    PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

  • CakePHP

    2556questions

    CakePHPは、PHPで書かれたWebアプリケーション開発用のフレームワークです。 Ruby on Railsの考え方を多く取り入れており、Railsの高速性とPHPの機動性を兼ね備えています。 MVCやORMなどを「規約優先の考え方」で利用するため、コードを書く手間を省くことができます。 外部のライブラリに依存しないので、単体での利用が可能です。

  • sh

    352questions

    shは、UNIX系OSのシェル操作の1つであり、最も基本的なシェルのことです。

PHPでシェルスクリプトの実行

解決済

回答 2

投稿

  • 評価
  • クリップ 1
  • VIEW 1,986

ToshY

score 15

前提・実現したいこと

MacOS上でCakePHP3を使用し、アプリケーションを作成中なのですが、
あるページに遷移した際、シェルコマンドを実行し、
その実行結果を随時ブラウザに表示するという処理を行いたいのですがうまくいきません。

発生している問題・エラーメッセージ

現状の問題としては、先にシェルコマンドの実行と随時echoのメッセージ表示が行われ、
最後にレイアウトが出力される状況です。

理想としては、先にページをレンダーし、
シェルコマンドの実行結果が随時HTML上で更新されるようにしたいと思っています。

ご助言頂戴できれば幸いです。
よろしくお願いします。

ソースコード

# src/Template/Test/index.ctp

<p>ok</p>

<?php
    echo '<div id="progress"></div>';
    echo str_pad(" ",4096)."<br />\n";

    $proc = popen($cmd, 'r');
    while (!feof($proc))
    {
        # echo '<pre>'. fread($proc, 4096) .'</pre>';
        echo "<script>document.getElementById( 'progress' ).appendChild(document.createTextNode('" . str_replace(array("\r", "\n"),"", fread($proc, 4096)) . "'));</script>";
        echo "<script>document.getElementById( 'progress' ).appendChild(document.createElement('br'));</script>";
        echo str_pad(" ",4096);

        flush();
        ob_flush();
        sleep(1);
    }
?>
# src/Controller/TestController.php

class TestController extends AppController
{

    public function index()
    {
        $cmd = <<< EOF
echo ディレクトリを作成中;
cd ~/Documents/develop;
mkdir ~/Documents/develop/test;
echo ディレクトリ作成完了;
EOF;

        $this->set(compact(
            "cmd"
        ));
    }
}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+1

Transfer-Encoding: chunked なレスポンスを生成して, JavaScriptのXMLHttpRequestの状態変更イベントでリアルタイムに反映するのが一番綺麗だと思います. iframeでやるとずっと読み込み中の状態みたいになってしまうので…

 /api/execute_shellcommand.php

<?php

// こういうMIMEタイプを指定しておくと,str_padで先頭を埋めたりしなくても
// ブラウザのバッファリングを防げる
header('Content-Type: text/event-stream; charset=UTF-8');

// レスポンスをチャンクで分割する宣言
header('Transfer-Encoding: chunked');

// バッファリングを完全に無効化
// (ob_flushのコールが不要になる)
while (ob_get_level()) ob_end_clean();

// 1行ごとにレスポンスを返す
$pr = popen('for i in {1..10}; do sleep 1; echo $i; done', 'rb');
while (false !== $line = fgets($pr)) {
    // "16進数表記のサイズ\r\n"
    echo base_convert(strlen($line), 10, 16) . "\r\n";
    // "データ\r\n"
    echo $line . "\r\n";
    flush();
}
// 最後はサイズ0のチャンクで締めくくり,Webブラウザに終わりを知らせる
echo "0\r\n";
echo "\r\n";
flush();

 example.html

<!DOCTYPE html>
<meta charset="UTF-8">
<title>Example</title>
<p>
  <textarea id="response" rows="5" cols="20"></textarea><br>
  <button id="start">コマンド実行</button>
</p>
<script>

  /* 手抜きしてますが,ここのコードは DOMContentLoaded のイベント時実行にしたほうがいいです */

  var area = document.querySelector('#response');
  var start = document.querySelector('#start');

  // ボタンのクリックイベントを登録
  start.addEventListener('click', function () {

    // 実行中は2回目のクリックを防ぐ
    start.disabled = true;

    // Ajax通信を行うためにXMLHttpRequestオブジェクトを生成
    var xhr = new XMLHttpRequest;
    xhr.open('get', '/api/execute_shellcommand.php', true);
    xhr.onreadystatechange = function () {
      if (this.status === 200 && this.readyState === 3) {
        // chunkの一部分が返ってきたときテキストエリアを更新
        area.textContent = this.responseText;
        return;
      }
      if (this.status === 200 && this.readyState === 4) {
        // 終了時
        start.disabled = false;
        return;
      }
      if (this.status !== 200 && this.readyState === 4) {
        // エラー時
        alert('エラー!');
        start.disabled = false;
        return;
      }
    };

    // HTTPリクエストを実行
    xhr.send();

  });
</script>

Apacheとかphp -Sに頼らず全てWebサーバまでPHPで実装した例があるのでこちらに貼っておきますw
(あんまり参考にならないかも)
https://github.com/mpyw/http-tutorial-with-php

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/03/15 10:26

    ご丁寧にご説明いただき、本当にありがとうございます。
    大変参考になりました。

    昨日iframeでの実装は完了していたのですが、おっしゃられるとおり、
    iframeでの実装では、常にローディングが行なわれている表示になっておりました。

    ご教授いただいたように実装を進めてみます。

    キャンセル

0

ob_flushをご覧ください。
http://php.net/manual/ja/function.ob-flush.php

と思ったのですが、CakePHPの場合、いろいろやっているので、バッファをフラッシュしてしまうと期待通りに動かないと思います。
別の方法を考えてみることをお勧めします。
(シェル部分をiframeで素のphpでやるとか)

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/03/14 22:02

    ご回答ありがとうございます。
    おっしゃる通り、CakePHPでの実行環境がよろしくないのではと考えておりました。

    シェル部分をiframeでPHPで行う方法について、
    参考文献などございましたらご連絡いただけますと幸いです。

    どうもありがとうございました。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.45%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る

  • PHP

    24602questions

    PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

  • CakePHP

    2556questions

    CakePHPは、PHPで書かれたWebアプリケーション開発用のフレームワークです。 Ruby on Railsの考え方を多く取り入れており、Railsの高速性とPHPの機動性を兼ね備えています。 MVCやORMなどを「規約優先の考え方」で利用するため、コードを書く手間を省くことができます。 外部のライブラリに依存しないので、単体での利用が可能です。

  • sh

    352questions

    shは、UNIX系OSのシェル操作の1つであり、最も基本的なシェルのことです。