<?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";
}
}
}
?>
|