2021年3月2日 星期二

jQuery Mobile 學習筆記 (十七) : 疫苗登記表專案 (下)

這幾天回頭整理 jQuery Mobile 未完成部分, 這個項目終於接近尾聲了, 就剩下上次幫水某寫的疫苗登記小專案還有一個資料表匯出功能尚未實作, 趁 228 連假待在鄉下就繼續來把它收尾做個 happy ending, 此專案之前的兩篇參考 : 


全部 jQuery Mobile 測試筆記參考 :



6. 匯出資料表 : 

受試者於網頁表單中輸入的資料會被後端 PHP 程式儲存於 MySQL 資料庫的 vaccine 資料表中, 為了資料統計方便最好將其匯出為 EXCEL 試算表, 下載到本機進行資料統計. 匯出資料表為 EXCEL 試算表的方法參考 : 



匯出為 CSV 檔是最簡單的一種方式, 速度快且較不占記憶體. CSV 檔為純文字檔, 既可用一般文字處理軟體開啟, 也可以用 EXCEL 軟體開啟, 一舉兩得.

首先修改 vaccine_subject_admin.php 檔, 為匯出資料表的超連結按鈕加上 href="vaccine_subject_export_csv.php" 屬性值, 注意, 同樣要把預設的 Ajax 功能關掉 : 

# vaccine_subject_admin.php
<?php
//啟動 session 功能
session_start();
//設定台北時間
date_default_timezone_set("Asia/Taipei");
if (!isset($_SESSION["vaccine_admin_account"])) { //未登入回首頁
  header("Location: index.htm");
  }
?>
<!DOCTYPE html>
<html>
  <head>
    <title></title>
    <meta charset="utf-8">
    <meta http-equiv="cache-control" content="no-cache">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <script src="https://code.jquery.com/jquery-1.11.1.min.js"></script>
    <script src="https://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.js"></script>
    <link href="https://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.css" rel="stylesheet">
  </head>
  <body>
    <!-- 第一頁頁面 -->
    <section data-role="page" id="page1">
      <header data-role="header">
        <a href="index.htm" data-icon="home" data-ajax="false">回首頁</a>
        <h1>系統管理</h1>
        <a href="logout.php" class="ui-btn-right" data-icon="power" data-ajax="false">登出</a>
      </header>
      <article data-role="content">
        <a href="vaccine_subject_list.php" data-role="button" data-icon="user" data-ajax="false">受試者列表</a>
        <a href="vaccine_subject_export_csv.php" data-role="button" data-icon="action" data-ajax="false">匯出受試者 (CSV)</a>
        <a href="#" data-role="button" data-icon="gear" data-ajax="false">系統設定</a>
      </article>
      <footer data-role="footer" data-position="fixed">
        <h3>小狐狸事務所 07-1234567</h3>
      </footer>
    </section>
    <script>
      $(document).ready(function() {
        });
    </script>
  </body>
</html>

匯出程式 vaccine_subject_export_csv.php 主要任務就是讀取 vaccine 資料表, 然後走訪每一筆紀錄, 並將各欄位值輸出到檔案 vaccine.csv 內, 其內容如下 : 

# vaccine_subject_export_csv.php
<?php
//啟動 session 功能
session_start();
//設定台北時間
date_default_timezone_set("Asia/Taipei");
if (!isset($_SESSION["vaccine_admin_account"])) { //未登入回首頁
  header("Location: index.htm");
  }
?>
<!DOCTYPE html>
<html>
  <head>
    <title></title>
    <meta charset="utf-8">
    <meta http-equiv="cache-control" content="no-cache">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <script src="https://code.jquery.com/jquery-1.11.1.min.js"></script>
    <script src="https://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.js"></script>
    <link href="https://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.css" rel="stylesheet">
  </head>
  <body>
    <!-- 第一頁頁面 -->
    <section data-role="page" id="page1">
      <header data-role="header" data-position="fixed">
        <a href="vaccine_admin.php" data-role="button" data-icon="back" data-mini="true"  data-ajax="false">返回</a>
        <h1>匯出受試者資料</h1>
      </header>
      <article data-role="content">
<?php
//設定 CSV 欄位標題
$csv_header=['序號','姓名','年齡','電話','性別','登記日期'];  //CSV 欄位標題
$csv_content=chr(0xEF).chr(0xBB).chr(0xBF);  //UTF-8 BOM 開頭字元 (避免亂碼)
$csv_content .= join(',',$csv_header)."\n";  //合併 BOM 開頭與欄位標題
//建立 PDO 連線物件
$dsn="mysql:host=localhost;port=3306;dbname=test"; 
$username="root"; 
$password="mysql";
try {$conn=new PDO($dsn, $username, $password);}
catch (PDOException $e) {
  echo "資料庫連線錯誤!";
  die();
  }
//設定資料編碼
$conn->exec("SET CHARACTER SET utf8"); 
//讀取受試者資料表
$SQL="SELECT * FROM `vaccine` ORDER BY rdate DESC"; 
$RS=$conn->query($SQL);
$row=$RS->fetch(); 
//迭代整個資料集
while(!empty($row)) {
  $csv_content .= $row["id"].",".$row["name"].",".$row["age"].",".
                  $row["phone"].",".$row["gender"].",".$row["rdate"]."\n";
  $row=$RS->fetch();
  }
$conn=NULL;
file_put_contents('vaccine.csv', $csv_content);
?>
        <h3>資料表匯出成功!</h3>
        <a data-role="button" href="vaccine_subject_download_csv.php" data-ajax="false">下載 vaccine.csv</a>
      </article>
      <footer data-role="footer" data-position="fixed">
        <h3>小狐狸事務所 07-1234567</h3>
      </footer>
    </section>
  </body>
</html>

此程式須注意的是要在 CSV 檔案開頭加上 chr(0xEF).chr(0xBB).chr(0xBF) 這三個 BOM 開頭字元, 否則產生的 utf-8 檔案會出現亂碼, 參考 :


接著讀取 vaccine 資列表,於走訪整個紀錄集時製作 CSV 檔的各列, 結束後呼叫 file_put_contents() 函數將 CSV 內容寫入 vaccine.csv 檔案中, 並輸出匯出成功訊息, 結果如下 : 





按 "下載 vaccine.csv" 鈕即轉至 vaccine_subject_download_csv.php 執行下載, 其內容為 :

#vaccine_subject_download_csv.php
<?php
//啟動 session 功能
session_start();
//設定台北時間
date_default_timezone_set("Asia/Taipei");
if (!isset($_SESSION["vaccine_admin_account"])) { //未登入回首頁
  header("Location: index.htm");
  }
//設定檔案下載標頭
header('Content-Encoding: UTF-8');
header('Content-type: text/csv; charset=UTF-8');
header('Content-Disposition: attachment; filename=vaccine.csv');
readfile("vaccine.csv"); //讀取檔案內容並下載
?>  

用純文字編輯軟體例如記事本或 EditPlus 開啟下載的 vaccine.csv 發現內容正常無亂碼 :



 
用 Office 365 的 EXCEL 開啟也 OK (登記日期欄要拉開, 否則顯示 "######") :




但如果用 Office 2003 中的 EXCEL 開啟則出現亂碼 : 




用另存新檔檢查檔案編碼格式, 確定是 UTF-8 + BOM :




其實也可以將 CSV 文字檔偽裝成 XLS 檔案直接下載, 不需要做匯出檔案的動作 (其實上面的 CSV 也可以這樣做), 參考下面這篇的做法 :


修改 vaccine_admin.php, 添加一個 "下載受試者 (XLS)" 按鈕, 導向 vaccine_subject_download_xls.php 程式直接下載 (不需先匯出) :

#vaccine_admin.php
<?php
//啟動 session 功能
session_start();
//設定台北時間
date_default_timezone_set("Asia/Taipei");
if (!isset($_SESSION["vaccine_admin_account"])) { //未登入回首頁
  header("Location: index.htm");
  }
?>
<!DOCTYPE html>
<html>
  <head>
    <title></title>
    <meta charset="utf-8">
    <meta http-equiv="cache-control" content="no-cache">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <script src="https://code.jquery.com/jquery-1.11.1.min.js"></script>
    <script src="https://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.js"></script>
    <link href="https://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.css" rel="stylesheet">
  </head>
  <body>
    <!-- 第一頁頁面 -->
    <section data-role="page" id="page1">
      <header data-role="header">
        <a href="index.htm" data-icon="home" data-ajax="false">回首頁</a>
        <h1>系統管理</h1>
        <a href="logout.php" class="ui-btn-right" data-icon="power" data-ajax="false">登出</a>
      </header>
      <article data-role="content">
        <a href="vaccine_subject_list.php" data-role="button" data-icon="user" data-ajax="false">受試者列表</a>
        <a href="vaccine_subject_export_csv.php" data-role="button" data-icon="action" data-ajax="false">匯出受試者 (CSV)</a>
        <a href="vaccine_subject_download_xls.php" data-role="button" data-icon="action" data-ajax="false">下載受試者 (XLS)</a>
        <a href="#" data-role="button" data-icon="gear" data-ajax="false">系統設定</a>
      </article>
      <footer data-role="footer" data-position="fixed">
        <h3>小狐狸事務所 07-1234567</h3>
      </footer>
    </section>
    <script>
      $(document).ready(function() {
        });
    </script>
  </body>
</html>

頁面如下 : 




按 "下載受試者 (XLS)" 按鈕即由 vaccine_subject_download_xls.php 程式下載 XLS 檔案, 程式內容如下 :

#vaccine_subject_download_xls.php
<?php
//啟動 session 功能
session_start();
//設定台北時間
date_default_timezone_set("Asia/Taipei");
if (!isset($_SESSION["vaccine_admin_account"])) { //未登入回首頁
  header("Location: index.htm");
  }
//設定檔案下載標頭
header('Content-type: text/html; charset=utf-8');
header("Content-type:application/vnd.ms-excel;charset=UTF-8"); 
header("Content-Disposition:filename=vaccine.xls");
//建立 PDO 連線物件
$dsn="mysql:host=localhost;port=3306;dbname=test"; 
$username="root"; 
$password="mysql";
try {$conn=new PDO($dsn, $username, $password);}
catch (PDOException $e) {
  echo "資料庫連線錯誤!";
  die();
  }
//設定資料編碼
$conn->exec("SET CHARACTER SET utf8"); 
//讀取受試者資料表
$SQL="SELECT * FROM `vaccine` ORDER BY rdate DESC"; 
$RS=$conn->query($SQL);
$row=$RS->fetch();
echo chr(0xEF).chr(0xBB).chr(0xBF); //UTF-8 BOM
echo "序號,姓名,年齡,電話,性別,登記日期\n"; //輸出表頭
//迭代整個資料集
while(!empty($row)) {
  echo $row["id"].",".$row["name"].",".$row["age"].",".
       $row["phone"].",".$row["gender"].",".$row["rdate"]."\n";
  $row=$RS->fetch();
  }
$conn=NULL;
?>

注意, 基於避免亂碼問題, 同樣要在輸出標頭前先輸出 UTF-8 的 BOM 字元. 其次, 所下載的 vaccine.xls 其實內部檔案格式還是純文字檔 (可用記事本開啟), 使用 Office 365 開啟時會出現格式不符警語, 但不理會它直接開啟即可, 內容正確 (用 Office 2003 開啟則有亂碼):





如果要用 PHP 匯出真正的 XSLX 格式檔案需借助 PHP 的 EXCEL 函式庫, 參考 : 


OK, 終於搞定此專案了, 雖然沒派上用場, 但卻藉此大致寫完 jQuery Mobile 筆記了 (剩下用 Cordova 將行動網頁轉成 App, 但這部分嚴格來說算 Cordova, 不算在 jQuery Mobile 這分類裡). 以上整個系統各網頁程式互動流程更新如下 :




整個專案 zip 壓縮檔先封存在 GitHub :


參考 : 


沒有留言 :