<?php // 定义一个处理CSV文件的类 class csv { private $_name = ""; // 定义CSV文件名称 private $_split = ","; // 定义分隔符,默认为逗号 private $_fp = null; // 文件句柄 // 构造函数,用于初始化类 public function __construct($name = "", $split = ",") { if ($name == "") { $this->_name = time() . ".csv"; // 设置CSV文件的新名称为时间戳+扩展名 } else { $this->_name = $name; // 使用类实例化时用户提供的文件名 } $this->_split = $split; // 设置用于切分CSV文件的字符,默认为逗号 } // 根据用户提交的数据,生成一个CSV格式的文件 public function create($data) { if (is_array($data)) { // 使用is_array()检查函数的参数是否为数组 // 使用类中的connect()函数,取得文件句柄 if ($this->connect($this->_name, "wb")) { foreach ($data as $line) { // 遍历数组 // 使用fputcsv()函数,把用户提交的数据写入文件 fputcsv($this->_fp, $line, $this->_split); } // 使用类中的close()函数,关闭文件句柄 $this->close(); return true; } } return false; } /** * 以表格的形式,显示CSV文件的数据 * $header(true/false):是否显示表头 * $lineNumber(true/false):是否显示行数 */ public function showTable($header = true, $lineNumber = true) { // 打开CSV文件 if (!$this->connect($this->_name, "rb")) { return "<p>无法打开文件: {$this->_name}</p>"; } $table = "<table border='1' class='csv-table'>"; $row = 0; // 使用fgetcsv()函数读取CSV文件并以数组的形式返回 while (($data = fgetcsv($this->_fp, 0, $this->_split)) !== false) { $table .= "<tr>"; if ($header && $row == 0) { // 当标头参数值为true时,显示标头数据 if ($lineNumber) { $table .= "<th>编号</th>"; } foreach ($data as $tk => $tv) { $table .= "<th>" . htmlspecialchars($tv) . "</th>"; // 遍历保存标头数据的数组 } } else { if ($lineNumber) { $table .= "<td>" . ($row) . "</td>"; // 当行号参数为true时,显示行号 } foreach ($data as $tk => $tv) { // 遍历CSV内容数组 $table .= "<td>" . htmlspecialchars($tv) . "</td>"; } } $table .= "</tr>"; $row++; } $table .= "</table>"; $this->close(); return $table; } // 私有方法:根据参数,返回一个文件句柄供类中的其他函数使用 private function connect($file, $mode) { if (empty($file)) { return false; // 当文件参数值为空时,返回false值 } else { // 文件存在时,打开CSV文件,并将文件句柄保存在类变量$_fp中 $this->_fp = fopen($file, $mode); return ($this->_fp !== false); } } // 关闭文件句柄 public function close() { if (is_resource($this->_fp)) { fclose($this->_fp); // 关闭文件句柄 $this->_fp = null; // 重置文件句柄 } } // 获取CSV文件的一行内容(辅助方法) private function getRow($rowNum) { if (!$this->connect($this->_name, "rb")) { return ""; } $currentRow = 0; $content = ""; while (($data = fgetcsv($this->_fp, 0, $this->_split)) !== false) { if ($currentRow == $rowNum) { $content = implode($this->_split, $data); break; } $currentRow++; } $this->close(); return $content; } } ?>
<?php class excel { private $_name = ""; private $_delimiter = "\t"; // 默认使用制表符,生成TSV格式(Excel兼容) // 构造函数 public function __construct($name) { $this->_name = $this->sanitizeFilename($name); } // 设置分隔符(可选) public function setDelimiter($delimiter) { $this->_delimiter = $delimiter; } // 创建Excel文件(实际生成TSV格式) public function create($data, $title = "") { // 安全检查:确保数据是数组 if (!is_array($data)) { return false; } // 设置响应头 header("Pragma: public"); header("Expires: 0"); header("Cache-Control: must-revalidate, post-check=0, pre-check=0"); header("Content-Type: text/tab-separated-values; charset=utf-8"); // TSV格式,Excel兼容 header("Content-Disposition: attachment; filename=\"{$this->_name}.tsv\""); // 添加.tsv扩展名 // 输出BOM标记,确保Excel正确解析UTF-8编码 echo "\xEF\xBB\xBF"; // 输出表头(如果有) if (!empty($title)) { $this->outputRow($title); } // 输出数据 foreach ($data as $row) { $this->outputRow($row); } return true; } // 安全处理文件名 private function sanitizeFilename($filename) { // 移除非法字符 $filename = preg_replace('/[^a-zA-Z0-9_\-\.]/', '_', $filename); // 确保有扩展名 if (!preg_match('/\.(tsv|xls|xlsx)$/i', $filename)) { $filename .= '.tsv'; } return $filename; } // 输出一行数据 private function outputRow($data) { // 处理关联数组,保持列顺序一致 if (is_array($data)) { // 转义特殊字符并使用分隔符连接 $escapedData = array_map(function($value) { // 如果值包含分隔符、引号或换行符,则用引号包裹并转义内部引号 if (strpos($value, $this->_delimiter) !== false || strpos($value, '"') !== false || strpos($value, "\n") !== false) { return '"' . str_replace('"', '""', $value) . '"'; } return $value; }, $data); echo implode($this->_delimiter, $escapedData) . "\n"; } else { // 如果不是数组,直接输出(可能需要调整) echo $data . "\n"; } } } ?>