首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 生成 TXT/CSV/HTML 等格式文件的通用類實現

     編輯:PHP 相關知識

業務中常需導出報表、備份數據、生成靜態頁。本文封裝一個 FileExporter 類,支援 TXT、CSV、HTML、JSON、XML 多格式,統一入口、自動編碼轉換、流式寫入大數據不佔記憶體。

核心類實現

<?php
class FileExporter {
    private string $dir;
    private string $defaultEncoding = 'UTF-8';

    public function __construct(string $dir) {
        $this->dir = rtrim($dir, '/\\') . DIRECTORY_SEPARATOR;
        if (!is_dir($this->dir)) {
            mkdir($this->dir, 0755, true);
        }
    }

    /**
     * 統一導出入口
     *
     * @param string $filename   不含副檔名
     * @param string $type       txt/csv/html/json/xml
     * @param array  $header     標題行 (關聯陣列 key=>label 或索引陣列)
     * @param iterable $rows     數據行 (生成器/陣列/PDOStatement)
     * @param array  $options    格式專用選項
     * @return string|false      完整文件路徑或 false
     */
    public function export(string $filename, string $type, array $header, iterable $rows, array $options = []) {
        $method = 'export' . ucfirst(strtolower($type));
        if (!method_exists($this, $method)) {
            throw new InvalidArgumentException("不支援的導出格式: $type");
        }
        $filepath = $this->dir . $filename . '.' . $type;
        return $this->$method($filepath, $header, $rows, $options);
    }

    // ===== TXT: 固定寬度/分隔符 =====
    private function exportTxt(string $path, array $header, iterable $rows, array $opt): string {
        $delimiter = $opt['delimiter'] ?? "\t";
        $encoding  = $opt['encoding'] ?? 'GBK'; // 中文環境常用 GBK 兼容 Excel
        $newline   = $opt['newline'] ?? PHP_EOL;

        $fp = fopen($path, 'wb');
        if (!$fp) throw new RuntimeException("無法創建文件: $path");

        // 寫入 BOM (GBK/UTF-8 可選)
        if ($encoding === 'UTF-8') fwrite($fp, "\xEF\xBB\xBF");

        // 標題行
        if ($header) {
            fputcsv($fp, array_values($header), $delimiter, '"', '\\');
            // fputcsv 會自動處理換行/引號轉義,但輸出編碼需手動轉換
            // 這裡簡化:實際建議逐行 iconv
        }

        // 數據行 (流式寫入)
        foreach ($rows as $row) {
            $line = array_map(function($v) use ($encoding) {
                return is_scalar($v) ? @iconv('UTF-8', $encoding . '//IGNORE', (string)$v) : '';
            }, array_values((array)$row));
            fwrite($fp, implode($delimiter, $line) . $newline);
        }
        fclose($fp);
        return $path;
    }

    // ===== CSV: 標準 RFC 4180 =====
    private function exportCsv(string $path, array $header, iterable $rows, array $opt): string {
        $encoding = $opt['encoding'] ?? 'UTF-8';
        $delimiter = $opt['delimiter'] ?? ',';
        $enclosure = $opt['enclosure'] ?? '"';

        $fp = fopen($path, 'wb');
        if ($encoding === 'UTF-8') fwrite($fp, "\xEF\xBB\xBF"); // UTF-8 BOM

        if ($header) {
            fputcsv($fp, array_values($header), $delimiter, $enclosure);
        }
        foreach ($rows as $row) {
            $vals = array_map(function($v) {
                return is_scalar($v) ? (string)$v : '';
            }, array_values((array)$row));
            fputcsv($fp, $vals, $delimiter, $enclosure);
        }
        fclose($fp);
        return $path;
    }

    // ===== HTML: 簡易表格 =====
    private function exportHtml(string $path, array $header, iterable $rows, array $opt): string {
        $title = $opt['title'] ?? 'Data Export';
        $fp = fopen($path, 'wb');
        fwrite($fp, <<
$title


HTML);
        foreach ($header as $col) {
            fwrite($fp, '');
        }
        fwrite($fp, '');
        foreach ($rows as $row) {
            fwrite($fp, '');
            foreach ((array)$row as $cell) {
                fwrite($fp, '');
            }
            fwrite($fp, '');
        }
        fwrite($fp, '
' . htmlspecialchars((string)$col, ENT_QUOTES, 'UTF-8') . '
' . htmlspecialchars((string)$cell, ENT_QUOTES, 'UTF-8') . '
'); fclose($fp); return $path; } // ===== JSON: 逐行 JSON Lines (大數據友好) ===== private function exportJson(string $path, array $header, iterable $rows, array $opt): string { $pretty = $opt['pretty'] ?? false; $fp = fopen($path, 'wb'); if ($pretty) fwrite($fp, "[\n"); $first = true; foreach ($rows as $row) { $assoc = array_combine($header, array_values((array)$row)); $json = json_encode($assoc, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | ($pretty ? JSON_PRETTY_PRINT : 0)); if (!$first && $pretty) fwrite($fp, ",\n"); elseif (!$first) fwrite($fp, "\n"); fwrite($fp, $json); $first = false; } if ($pretty) fwrite($fp, "\n]"); fclose($fp); return $path; } // ===== XML: 簡單結構 ===== private function exportXml(string $path, array $header, iterable $rows, array $opt): string { $root = $opt['root'] ?? 'data'; $item = $opt['item'] ?? 'row'; $fp = fopen($path, 'wb'); fwrite($fp, '' . "\n<$root>\n"); foreach ($rows as $row) { fwrite($fp, " <$item>\n"); foreach (array_combine($header, array_values((array)$row)) as $k => $v) { $k = preg_replace('/[^a-zA-Z0-9_-]/', '_', $k); // 合法標籤名 fwrite($fp, " <$k>" . htmlspecialchars((string)$v, ENT_QUOTES, 'UTF-8') . "\n"); } fwrite($fp, " \n"); } fwrite($fp, "\n"); fclose($fp); return $path; } } ?>

使用範例

<?php
require 'FileExporter.php';

$exporter = new FileExporter(__DIR__ . '/exports');

// 模擬大數據源 (生成器,不佔記憶體)
function dataSource(): Generator {
    for ($i = 1; $i <= 100000; $i++) {
        yield [
            'id' => $i,
            'name' => "用戶$i",
            'email' => "user$i@example.com",
            'created_at' => date('Y-m-d H:i:s', strtotime("-$i days")),
        ];
    }
}

$header = ['id' => 'ID', 'name' => '姓名', 'email' => '郵箱', 'created_at' => '註冊時間'];

// 導出 CSV (流式,常駐記憶體 < 2MB)
$exporter->export('users_2024', 'csv', $header, dataSource(), [
    'encoding' => 'UTF-8',
    'delimiter' => ',',
]);

// 導出 HTML (帶標題)
$exporter->export('users_report', 'html', $header, dataSource(), [
    'title' => '用戶註冊報表 2024',
]);

// 導出 JSON Lines (每行一個 JSON,適合日誌/大數據入湖)
$exporter->export('users_dump', 'json', $header, dataSource(), [
    'pretty' => false,
]);
?>

關鍵設計亮點

  1. 流式寫入:使用 fopen('wb') + fwrite,配合 Generator 數據源,百萬行導出常駐記憶體 < 5MB。
  2. 編碼自適應:CSV/JSON 強制 UTF-8 + BOM;TXT 可選 GBK 兼容國產 Excel。
  3. 統一入口:export() 分發具體格式方法,新增格式只需加私有方法,符合開閉原則。
  4. 標題映射:支援關聯陣列 ['field' => '顯示名'],自動對齊數據鍵名。
  5. 安全轉義:HTML/XML 使用 htmlspecialchars,CSV 依賴 fputcsv 內建轉義。

擴展建議

  • 新增 exportXlsx():引入 PhpSpreadsheet 僅在調用時 require_once,避免常駐大型庫。
  • 新增 exportPdf():HTML 轉 PDF (wkhtmltopdf/Headless Chrome)。
  • 壓縮輸出:導出後自動 ZipArchive 打包,返回 .zip 下載鏈接。
  • 異步導出:大文件導出推入隊列,前端輪詢/下載鏈接通知。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved