"phpoffice/phpspreadsheet": "*"
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
use PhpOffice\PhpSpreadsheet\Cell\DataType;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Style\Alignment;
use PhpOffice\PhpSpreadsheet\Style\Border;
use PhpOffice\PhpSpreadsheet\Style\Color;
use PhpOffice\PhpSpreadsheet\Style\Fill;
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
use PhpOffice\PhpSpreadsheet\Worksheet\PageSetup;
use PhpOffice\PhpSpreadsheet\Reader\Xlsx;
use PhpOffice\PhpSpreadsheet\Reader\Xls;
class Php_spread_sheet_lib
{
/**
* 使用PHPEXECL导入
*
* @param string $file 文件地址
* @param int $sheet 工作表sheet(传0则获取第一个sheet)
* @param int $columnCnt 列数(传0则自动获取最大列)
* @param array $options 操作选项
* array mergeCells 合并单元格数组
* array formula 公式数组
* array format 单元格格式数组
*
* @return array
* @throws Exception
*/
public function importExecl(string $file = '', int $sheet = 0, int $columnCnt = 0, &$options = [])
{
try {
/* 转码 */
$file = iconv("utf-8", "gb2312", $file);
if (empty($file) OR !file_exists($file)) {
throw new \Exception('文件不存在!');
}
/** @var Xlsx $objRead */
$objRead = IOFactory::createReader('Xlsx');
if (!$objRead->canRead($file)) {
/** @var Xls $objRead */
$objRead = IOFactory::createReader('Xls');
if (!$objRead->canRead($file)) {
throw new \Exception('只支持导入Excel文件!');
}
}
/* 如果不需要获取特殊操作,则只读内容,可以大幅度提升读取Excel效率 */
empty($options) && $objRead->setReadDataOnly(true);
/* 建立excel对象 */
$obj = $objRead->load($file);
/* 获取指定的sheet表 */
$currSheet = $obj->getSheet($sheet);
if (isset($options['mergeCells'])) {
/* 读取合并行列 */
$options['mergeCells'] = $currSheet->getMergeCells();
}
if (0 == $columnCnt) {
/* 取得最大的列号 */
$columnH = $currSheet->getHighestColumn();
/* 兼容原逻辑,循环时使用的是小于等于 */
$columnCnt = Coordinate::columnIndexFromString($columnH);
}
/* 获取总行数 */
$rowCnt = $currSheet->getHighestRow();
$data = [];
/* 读取内容 */
for ($_row = 1; $_row <= $rowCnt; $_row++) {
$isNull = true;
for ($_column = 1; $_column <= $columnCnt; $_column++) {
$cellName = Coordinate::stringFromColumnIndex($_column);
$cellId = $cellName . $_row;
$cell = $currSheet->getCell($cellId);
if (isset($options['format'])) {
/* 获取格式 */
$format = $cell->getStyle()->getNumberFormat()->getFormatCode();
/* 记录格式 */
$options['format'][$_row][$cellName] = $format;
}
if (isset($options['formula'])) {
/* 获取公式,公式均为=号开头数据 */
$formula = $currSheet->getCell($cellId)->getValue();
if (0 === strpos($formula, '=')) {
$options['formula'][$cellName . $_row] = $formula;
}
}
if (isset($format) && 'm/d/yyyy' == $format) {
/* 日期格式翻转处理 */
$cell->getStyle()->getNumberFormat()->setFormatCode('yyyy/mm/dd');
}
$data[$_row][$cellName] = trim($currSheet->getCell($cellId)->getFormattedValue());
if (!empty($data[$_row][$cellName])) {
$isNull = false;
}
}
/* 判断是否整行数据为空,是的话删除该行数据 */
if ($isNull) {
unset($data[$_row]);
}
}
return $data;
} catch (\Exception $e) {
throw $e;
}
}
/**
* Excel导出,TODO 可继续优化
*
* @param array $datas 导出数据,格式['A1' => 'XXXX公司报表', 'B1' => '序号']
* @param string $fileName 导出文件名称
* @param array $options 操作选项,例如:
* bool print 设置打印格式
* string freezePane 锁定行数,例如表头为第一行,则锁定表头输入A2
* array setARGB 设置背景色,例如['FFc0c0c0'=>'A1', 'FF000000'=>['C1', 'C2']]
键为FF开头的颜色值,值为单元格可以为单个字符串或多个组成的数组,说明多个单元格都适用同一种颜色背景
* array setWidth 设置宽度,例如['A' => 30, 'C' => 20]
* array setHeight 设置高度,例如['1' => 300, '10' => 200]//键为行号,值为行高
* array setWrap 设置换行,例如['A1', 'C2']
* 要实现单元格换行,包括两部分:首先,需要换行的内容之间必需包括换行符,可以用PHP_EOL或者\r\n;其次,必需激活单元格的“自动换行”属性
* bool setBorder 设置单元格边框
* array mergeCells 设置合并单元格,例如['A1:J1' => 'A1:J1']
* array formula 设置公式,例如['F2' => '=IF(D2>0,E42/D2,0)']
* array format 设置格式,整列设置,例如['A' => 'General']
* array alignCenter 设置居中样式,例如['A1', 'A2']
* array bold 设置加粗样式,例如['A1', 'A2']
* string savePath 保存路径,设置后则文件保存到服务器,不通过浏览器下载
* @param string $excelType 导出文件格式类型,默认xlsx,可选xls和xlsx
*
* @return bool 成返回true,失败返回false
* @throws Exception
*/
function exportExcel(array $datas, string $fileName = '', array $options = [], string $excelType='xlsx'): bool
{
try {
if (empty($datas)) {
return false;
}
set_time_limit(0);
/** @var Spreadsheet $objSpreadsheet */
//$objSpreadsheet = app(Spreadsheet::class);//laravel写法
$objSpreadsheet = new Spreadsheet();
/* 设置默认文字居左,上下居中 */
$styleArray = [
'alignment' => [
'horizontal' => Alignment::HORIZONTAL_LEFT,
'vertical' => Alignment::VERTICAL_CENTER,
],
];
$objSpreadsheet->getDefaultStyle()->applyFromArray($styleArray);
/* 设置Excel Sheet */
$activeSheet = $objSpreadsheet->setActiveSheetIndex(0);
/* 打印设置 */
if (isset($options['print']) && $options['print']) {
/* 设置打印为A4效果 */
$activeSheet->getPageSetup()->setPaperSize(PageSetup:: PAPERSIZE_A4);
/* 设置打印时边距 */
$pValue = 1 / 2.54;
$activeSheet->getPageMargins()->setTop($pValue / 2);
$activeSheet->getPageMargins()->setBottom($pValue * 2);
$activeSheet->getPageMargins()->setLeft($pValue / 2);
$activeSheet->getPageMargins()->setRight($pValue / 2);
}
/* 行数据处理 */
foreach ($datas as $sKey => $sItem) {
/* 默认文本格式 */
$pDataType = DataType::TYPE_STRING;
/* 设置单元格格式 */
if (isset($options['format']) && !empty($options['format'])) {
$colRow = Coordinate::coordinateFromString($sKey);
/* 存在该列格式并且有特殊格式 */
if (isset($options['format'][$colRow[0]]) &&
NumberFormat::FORMAT_GENERAL != $options['format'][$colRow[0]]) {
$activeSheet->getStyle($sKey)->getNumberFormat()
->setFormatCode($options['format'][$colRow[0]]);
if (false !== strpos($options['format'][$colRow[0]], '0.00') &&
is_numeric(str_replace(['¥', ','], '', $sItem))) {
/* 数字格式转换为数字单元格 */
$pDataType = DataType::TYPE_NUMERIC;
$sItem = str_replace(['¥', ','], '', $sItem);
}
} elseif (is_int($sItem)) {
$pDataType = DataType::TYPE_NUMERIC;
}
}
$activeSheet->setCellValueExplicit($sKey, $sItem, $pDataType);
/* 存在:形式的合并行列,列入A1:B2,则对应合并 */
if (false !== strstr($sKey, ":")) {
$options['mergeCells'][$sKey] = $sKey;
}
}
unset($datas);
/* 设置锁定行 */
if (isset($options['freezePane']) && !empty($options['freezePane'])) {
$activeSheet->freezePane($options['freezePane']);
unset($options['freezePane']);
}
/* 设置宽度 */
if (isset($options['setWidth']) && !empty($options['setWidth'])) {
foreach ($options['setWidth'] as $swKey => $swItem) {
if(is_numeric($swItem)){//设置宽度
$activeSheet->getColumnDimension($swKey)->setWidth($swItem);
}else{//自动宽度
$activeSheet->getColumnDimension($swKey)->setAutoSize($swItem);
}
}
unset($options['setWidth']);
}
/* 设置行高度 */
if (isset($options['setHeight']) && !empty($options['setHeight'])) {
foreach ($options['setHeight'] as $shKey => $shItem) {
if(is_numeric($shItem)){//设置宽度
$activeSheet->getRowDimension($shKey)->setRowHeight($shItem);
}else{//默认高度15
$activeSheet->getDefaultRowDimension()->setRowHeight(15);
}
}
unset($options['setHeight']);
}
/* 设置换行 */
if (isset($options['setWrap']) && !empty($options['setWrap'])) {
foreach ($options['setWrap'] as $swItem) {
$activeSheet->getStyle($swItem)->getAlignment()->setWrapText(true);
}
unset($options['setWrap']);
}
/* 设置背景色 */
if (isset($options['setARGB']) && !empty($options['setARGB'])) {
/*foreach ($options['setARGB'] as $sItem) {
$activeSheet->getStyle($sItem)
->getFill()->setFillType(Fill::FILL_SOLID)
->getStartColor()->setARGB(Color::COLOR_YELLOW);
}*/
foreach ($options['setARGB'] as $sKey => $sItem) {
if(!is_array($sItem)){//不是数组
$activeSheet->getStyle($sItem)
->getFill()->setFillType(Fill::FILL_SOLID)
->getStartColor()->setARGB($sKey);
}else{//是数组
foreach($sItem as $item){
$activeSheet->getStyle($item)
->getFill()->setFillType(Fill::FILL_SOLID)
->getStartColor()->setARGB($sKey);
}
}
}
unset($options['setARGB']);
}
/* 设置公式 */
if (isset($options['formula']) && !empty($options['formula'])) {
foreach ($options['formula'] as $fKey => $fItem) {
$activeSheet->setCellValue($fKey, $fItem);
}
unset($options['formula']);
}
/* 合并行列处理 */
if (isset($options['mergeCells']) && !empty($options['mergeCells'])) {
$activeSheet->setMergeCells($options['mergeCells']);
unset($options['mergeCells']);
}
/* 设置居中 */
if (isset($options['alignCenter']) && !empty($options['alignCenter'])) {
$styleArray = [
'alignment' => [
'horizontal' => Alignment::HORIZONTAL_CENTER,
'vertical' => Alignment::VERTICAL_CENTER,
],
];
foreach ($options['alignCenter'] as $acItem) {
$activeSheet->getStyle($acItem)->applyFromArray($styleArray);
}
unset($options['alignCenter']);
}
/* 设置加粗 */
if (isset($options['bold']) && !empty($options['bold'])) {
foreach ($options['bold'] as $bItem) {
$activeSheet->getStyle($bItem)->getFont()->setBold(true);
}
unset($options['bold']);
}
/* 设置单元格边框,整个表格设置即可,必须在数据填充后才可以获取到最大行列 */
if (isset($options['setBorder']) && $options['setBorder']) {
$border = [
'borders' => [
'allBorders' => [
'borderStyle' => Border::BORDER_THIN, // 设置border样式
'color' => ['argb' => 'FF000000'], // 设置border颜色
],
],
];
$setBorder = 'A1:' . $activeSheet->getHighestColumn() . $activeSheet->getHighestRow();
$activeSheet->getStyle($setBorder)->applyFromArray($border);
unset($options['setBorder']);
}
$fileName = !empty($fileName) ? $fileName.'.'.strtolower($excelType) : (date('YmdHis').'.'.strtolower($excelType));
if (!isset($options['savePath'])) {
if($excelType == 'xlsx'){
/* 直接导出Excel,无需保存到本地,输出07Excel文件 */
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
}else{
header('Content-Type: application/vnd.ms-excel');
}
header(
"Content-Disposition:attachment;filename=" . iconv(
"utf-8", "GB2312//TRANSLIT", $fileName
)
);
header('Cache-Control: max-age=0');//禁止缓存
$savePath = 'php://output';
} else {
$savePath = $options['savePath'].$fileName;
}
ob_clean();
ob_start();
$objWriter = IOFactory::createWriter($objSpreadsheet, ucfirst($excelType));
$objWriter->save($savePath);
/* 释放内存 */
$objSpreadsheet->disconnectWorksheets();
unset($objSpreadsheet);
ob_end_flush();
return true;
} catch (Exception $e) {
return false;
}
}
}
/**
* 方法 export_project_apply_detail_as_excel_serv,导出项目抽检申请详情数据到excel
*
* @param array $params 参数数组
*
* @return mixed 成功返回true,失败返回false
*/
public function export_project_apply_detail_as_excel_serv(array $params){
//获取项目抽检申请详情(包含项目地址所属公司等信息)
$project_apply_department = $this->get_project_apply_department_detail_serv($params);
//获取项目抽检申请检查项列表
$resolve_item_list = $this->deal_get_project_apply_item_list_serv($params);
//处理成可写入excel的数据格式
$data = [
'A1' => '公司名称', 'B1' => '项目名称', 'C1' => '立项时间', 'D1' => '项目地址', 'E1' => '技术负责人', 'F1' => '手机号',
'A2' => $project_apply_department['company_name'], 'B2' => $project_apply_department['project_name'],
'C2' => $project_apply_department['create_time'], 'D2' => $project_apply_department['address'],
'E2' => $project_apply_department['tec_leader_name'], 'F2' => $project_apply_department['tec_leader_phone'],
'A4' => '项目状态', 'B4' => '抽签时间', 'C4' => '预计抽检时间', 'D4' => '抽检人员', 'E4' => '职务', 'F4' => '手机号',
'A5' => $project_apply_department['status_name'], 'B5' => $project_apply_department['draw_date'],
'C5' => $project_apply_department['plan_samp_date'], 'D5' => $project_apply_department['samp_user_name'],
'E5' => $project_apply_department['samp_user_job'], 'F5' => $project_apply_department['samp_user_phone'],
'A7' => '分数', 'B7' => '检查时间',
'A8' => $project_apply_department['score'], 'B8' => $project_apply_department['samp_date'] ?? '暂无',
'A10' => '检查项', 'B10' => '检查楼层',
];
//处理抽检的检查项楼层数据
static $row = 11;
foreach($project_apply_department['project_apply_wbs_item'] as $k => $v){
if($v['plaster']){
$tmp = ['A'.$row => $v['plaster_name'], 'B'.$row => $v['build_name'].$v['floor_name'].'层',];
$data = array_merge($data, $tmp);
$row ++;
continue;
}
if($v['concrete']){
$tmp = ['A'.$row => $v['concrete_name'], 'B'.$row => $v['build_name'].$v['floor_name'].'层',];
$data = array_merge($data, $tmp);
$row ++;
}
if($v['masonry']){
$tmp = ['A'.$row => $v['masonry_name'], 'B'.$row => $v['build_name'].$v['floor_name'].'层',];
$data = array_merge($data, $tmp);
$row ++;
}
}
//处理检查项楼层列表数据
$row ++;
$bold_row2 = $row;//设置加粗的行号
$tmp2 = ['A'.$row => '楼号', 'B'.$row => '层号', 'C'.$row => '形象进度', 'D'.$row => '检查项', 'E'.$row => '检查项', 'F'.$row => '检查项'];
$data = array_merge($data, $tmp2);
$row ++;
foreach($resolve_item_list as $r_i_l_k => $r_i_l_v){
/*if($r_i_l_v['plaster']){
unset($r_i_l_v['concrete_name'], $r_i_l_v['masonry_name']);
}else{
unset($r_i_l_v['plaster_name']);
}*/
$tmp3 = [
'A'.$row => $r_i_l_v['build_name'], 'B'.$row => $r_i_l_v['floor_name'], 'C'.$row => $project_apply_department['appearance_name'],
'D'.$row => $r_i_l_v['concrete_name'] ?? '', 'E'.$row => $r_i_l_v['plaster_name'] ?? '', 'F'.$row => $r_i_l_v['masonry_name'] ?? '',
];
$data = array_merge($data, $tmp3);
$row ++;
}
//设置导出excel单元格格式(居中、加粗等)
$oss_path = 's_c_s_l/excel/';
$save_path = getcwd().'/'.$oss_path;
$file_name = $project_apply_department['project_name'].'-项目抽检申请详情资料';
$file_ext = 'xls';
$options = [
'print' => true,//打印格式
'alignCenter' => array_keys($data),//居中
'setWidth' => ['A'=>true, 'B'=>true, 'C'=>true, 'D'=>true, 'E'=>true, 'F'=>true],
'bold' => [
'A1', 'B1', 'C1', 'D1', 'E1', 'F1', 'A4', 'B4', 'C4', 'D4', 'E4', 'F4', 'A7', 'B7', 'C7', 'D7', 'E7', 'F7', 'A10', 'B10',
'A'.$bold_row2, 'B'.$bold_row2, 'C'.$bold_row2, 'D'.$bold_row2, 'E'.$bold_row2, 'F'.$bold_row2,
],//加粗
'savePath' => $save_path,//存储路径
];
//导出,在浏览器输出二进制流主动生成excel文件
$this->load->library('php_spread_sheet_lib');
$export_res = $this->php_spread_sheet_lib->exportExcel($data, $file_name, $options, $file_ext);
if($export_res){
$export_res = [
'oss_path' => $oss_path.$file_name.'.'.$file_ext,
'local_full_path' => $save_path.$file_name.'.'.$file_ext,
];
}
return $export_res;
}
参考(基于并扩展导出excel的方法):使用PhpSpreadsheet导入&导出Excel(适用各种Excel操作场景)