---
# System prepended metadata

title: 如何讓CodeIgniter4能即時輸出
tags: [ci4, ' 即時']

---

---
tags: ci4, 即時
---
# 如何讓CodeIgniter4能即時輸出

2022/05/08

CI4的回應請求都是等全部任務都完成後再一次輸出
有時希望能看到即時進度狀況的情況下會很不方便
因此本為來解決這個問題

分成兩種狀況，CLI、網頁(後台與前台)

## CLI
CLI有兩種方法可以即時輸出
1. (推薦)透過CLI::print() / CLI::write() 直接輸出
CLI::print與CLI::write差別插在CLI::print不會換行，CLI::write會換行
1. 透過ob_end_flush()將緩衝區的資料送出去

```php=
<?php
namespace App\Controllers\CLI; 
use CodeIgniter\Controller;
use CodeIgniter\CLI\CLI;
class demo extends Controller
{
  public function test()
  {
    echo '方法一:';
    for ($i = 0; $i < 10; $i++) {
      CLI::print($i . ' ');
      sleep(1);
    }
    
    CLI::print('方法二:');
    for ($i = 0; $i < 10; $i++) {
      echo $i . ' ';
      $this->output();
      sleep(1);
    }
  }
  
  function output()
  {
    while (ob_get_level() > 0)
      ob_end_flush();
  }
}
```

![](https://i.imgur.com/TjWrNoW.gif)


## 網頁後台

如果不使用CI4的話，
可透過ob_flush(); flush();將當前緩衝區資料輸出
依照參考[1]的執行結果
![[開發與維護/網站前端/attachments/動畫 1.gif]]

但套用到CI4就還是會等全部任務都完成後再一次輸出，
所以要進行調整

GOOGLE爬文沒找不到相關資料，  
透過一陣子的自己摸索亂試中於試出來了~

但我不清楚為啥這樣可以...
所以發文 [iT邦幫忙](https://ithelp.ithome.com.tw/questions/10208446) 詢問

```php
namespace App\Controllers;
use App\Controllers\BaseController;

class demo extends BaseController
{
    public function index()
    {
        $this->response->send(); // 送出預設表頭
        ob_end_flush(); // 從緩衝區輸出並結束當前緩衝區
        flush(); // 顯示到畫面

        for ($i = 0; $i < 10; $i++) {
            echo $i . ' ';

            ob_flush(); // 從緩衝區輸出
            flush(); // 顯示到畫面

            sleep(1);
        }
        return $this->response->setJSON('');
    }
}
```

第一個$this->response->send();主要是送出表頭用
ob_end_flush(); : 從緩衝區輸出並結束當前緩衝區，避免因當前被CI4設定過的換衝區影響，導致還是全部工作完成才一次輸出

return $this->response->setJSON('');
透過空字串的setJson()，使開發模式下不會產生多餘的debug資訊

結果
![](https://i.imgur.com/WoQFr9h.gif)

## 網頁前台
網頁前台的部分就直接參考參考連結[1]
```html
<!DOCTYPE html>
<html>
<head>
  <title></title>
  <meta charset="utf-8">
</head>
<body>
  <div><button id="ontimeoutputBtn">及時輸出</button></div>
  <div id="ontimeoutputArea" style="border: 1px solid red"></div>
</body>
<script src="//ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script type="text/javascript">
// readyState總共有5個狀態值，分別為0~4
// 0  未初始化狀態：此時，已經建立了一個XMLHttpRequest物件
// 1  準備傳送狀態：此時，已經呼叫了XMLHttpRequest物件的open方法，並且XMLHttpRequest物件已經準備好將一個請求傳送到伺服器端
// 2  已經發送狀態：此時，已經通過send方法把一個請求傳送到伺服器端，但是還沒有收到一個響應
// 3  正在接收狀態：此時，已經接收到HTTP響應頭部資訊，但是訊息體部分還沒有完全接收到
// 4  完成響應狀態：此時，已經完成了HTTP響應的接收
  $('#ontimeoutputBtn').click(function(){
    $.ajax({
      // url :'demo.php',
      url: 'https://soc.localhost.tw:8007/demo/index',
      type:'get'
      ,data:{}
      ,success:function(res){
        console.log('這裡用jq提供的方法處理');
        console.log(res);
      }
      ,xhr:function(){//返回一個更強大的XMLHttpRequest的物件
        if (window.XMLHttpRequest) {
          //主流瀏覽器提供了XMLHttpRequest物件
          var xhr = new XMLHttpRequest();
        }else if (window.ActiveXObject) {
          //低版本的IE瀏覽器沒有提供XMLHttpRequest物件
          //所以必須使用IE瀏覽器的特定實現ActiveXObject
          var xhr = new ActiveXObject("Microsoft.XMLHTTP");
        }
        //繫結事件
        xhr.onreadystatechange = function () {
          if (xhr.readyState === 4 && xhr.status === 200) {
            //獲取成功後執行操作
            //資料在xhr.responseText
            //這裡使用js原生的處理方式
            // console.log('success');
          }
          if(xhr.readyState === 3){
            var html = "<p style='border:1px solid red;'>"+xhr.responseText+"</p>";
            $('#ontimeoutputArea').html(html);
          }
        }
        return xhr;
      }
    });
  });
</script>
</html>
```


## 參考連結
- [1]PHP+jquery ajax 實現實時的輸出顯示
https://www.796t.com/content/1542836826.html
- [2]解決 CodeIgniter 4 Command line 輸出緩衝/不即時的問題 (ob_start / ob_end_flush)
http://blog.changyy.org/2020/06/php-codeigniter-4-command-line-obstart.html

