PHP导出基类(PHPExcel,PhpSpreadsheet)

PHP导出常用的导出类(PHPExcel,PhpSpreadsheet -->通过composer自行拉取到对应的项目下)

1:PHPExcel基类


namespace LYJ\Leyangjun;

use PHPExcel;
use PHPExcel_Writer_Excel5;
use PHPExcel_Writer_Excel2007;
use PHPExcel_IOFactory;
use PHPExcel_Reader_IReadFilter;
use PHPExcel_Cell_DataType;

/**
 * excel导出
 *
 * Class Excel
 * @package Mt\Lib
 *
 * 使用方式
 * use Mt\Lib\Excel;
 * $Excel = Excel::getInstance(['is_xlsx'=>true]);
 * $data = [['name'=>'cbs'],['name' => 'cbss']];
 * $Excel->export('cbstest.xlsx', $data, ['name'=>'名字']);
 */
class Excel
{
    private static $instances;
    private $objExcel;
    private $objWriter;
    private $is_xlsx = false;//是否要用Excel2007,默认为Excel5

    public function __contruct() {
    }

    // 单例模式,不能用系统自带的因为权限问题。
    public static function getInstance()
    {
        $className = get_called_class();
        $args = func_get_args();
        //若$args中有resource类型的参数,则无法区分同一个类的不同实例
        $key = md5($className . ':' . serialize($args));
        if (!isset(self::$instances[$key])) {
            //PHP_VERSION >= 5.6.0
            self::$instances[$key] = new $className(...$args);
        }
        return self::$instances[$key];
    }

    public function __construct($config=null){
        if(isset($config['is_xlsx']) && $config['is_xlsx']){
            $this->is_xlsx = true;
        }
    }

    /**
     * 把数据格式化为指定的格式
     * @param $obj_sheet 'PHPExcel_Worksheet'
     * @param $column
     * @param $row
     * @param $item
     * @param $format
     * @param $row_data
     */
    private function format_item(&$obj_sheet,$column,$row,$item,$format,$row_data){
        $format_arr = explode(':',$format);
        $format = $format_arr[0];
        switch($format){
            //把时间戳转成日期时间格式
            case 'datetime':
                $result = date('Y-m-d H:i:s',$item);
                $obj_sheet->setCellValueExplicitByColumnAndRow($column,$row,$result,PHPExcel_Cell_DataType::TYPE_STRING2);
                break;
            //把时间戳转成日期格式
            case 'date':
                $result = date('Y-m-d',$item);
                $obj_sheet->setCellValueExplicitByColumnAndRow($column,$row,$result,PHPExcel_Cell_DataType::TYPE_STRING2);
                break;
            //把秒数转成'N天N时N分N秒'时长格式
            case 'duration':
                $result = '';
                $day = (int)($item/86400);
                $hour = (int)(($item%86400)/3600);
                $minute = (int)(($item%3600)/60);
                $sec = (int)($item%60);
                if($day > 0){
                    $result .= $day.'天';
                }
                if($day > 0 || $hour > 0){
                    $result .= $hour.'时';
                }
                if($day > 0 || $hour > 0 || $minute > 0){
                    $result .= $minute.'分';
                }
                $result .= $sec.'秒';
                $obj_sheet->setCellValueExplicitByColumnAndRow($column,$row,$result,PHPExcel_Cell_DataType::TYPE_STRING2);
                break;
            //把数据转成超链接,格式:text_item@url:link_item_key:tooltip_item_key
            case 'url':
                $result = $item;
                $link_item_key = isset($format_arr[1]) ? $format_arr[1] : '';
                $link_item = isset($row_data[$link_item_key]) ? $row_data[$link_item_key] : '';
                $tooltip_item_key = isset($format_arr[2]) ? $format_arr[2] : '';
                $tooltip_item = isset($row_data[$tooltip_item_key]) ? $row_data[$tooltip_item_key] : '';
                $obj_sheet->setCellValueExplicitByColumnAndRow($column,$row,$result,PHPExcel_Cell_DataType::TYPE_STRING2);
                if($result && $link_item){
                    $obj_sheet->getCellByColumnAndRow($column,$row)->getHyperlink()->setUrl($link_item);
                }
                if($result && $link_item && $tooltip_item){
                    $obj_sheet->getCellByColumnAndRow($column,$row)->getHyperlink()->setTooltip($tooltip_item);
                }
                break;
            //不管是数字还是字符串都转为字符串格式
            case 'string':
                $result = $item;
                $obj_sheet->setCellValueExplicitByColumnAndRow($column,$row,$result,PHPExcel_Cell_DataType::TYPE_STRING2);
                break;
            default:
                $result = $item;
                $data_type = is_numeric($item) && $item <= 4294967295 ? PHPExcel_Cell_DataType::TYPE_NUMERIC
                    : PHPExcel_Cell_DataType::TYPE_STRING2;
                $obj_sheet->setCellValueExplicitByColumnAndRow($column,$row,$result,$data_type);
                break;
        }
        return $result;
    }

    /**
     * 导出为Excel文件
     * 若有指定$header,且$header元素没指定key则$data列的顺序要与$header对应;
     * 若有指定$header,且$header元素有指定key,则key要与数据库表字段一致
     * @param $filename
     * @param $data
     * @param array $header
     * @param string $dir 导出到目录(默认是导出到标准输出流)
     */
    public function export($filename,$data,$header=array(),$dir = null){
        $this->objExcel = new PHPExcel();
        $this->objWriter = $this->is_xlsx ? new \PHPExcel_Writer_Excel2007($this->objExcel) : new \PHPExcel_Writer_Excel5($this->objExcel);
        $this->objExcel->setActiveSheetIndex(0);
        $objActSheet = $this->objExcel->getActiveSheet();
        $row = 1;
        if($header){
            $column = 0;
            foreach($header as $item){
                $objActSheet->setCellValueExplicitByColumnAndRow($column,$row,$item);
                $objActSheet->getStyleByColumnAndRow($column,$row)->getFont()->setBold(true);
                $column++;
            }
            $row++;
        }
        if($data){
            $header_keys = array_keys($header);
            foreach($data as $row_data){
                $column = 0;
                if($header){
                    reset($row_data);
                    foreach($header_keys as $key){
                        $item = '';
                        $format = '';
                        if(is_numeric($key)){
                            $current_row = each($row_data);
                            $item = $current_row['value'];
                        }
                        else{
                            list($row_key,$format) = explode('@',$key);
                            $item = $row_data[$row_key];
                        }
                        $this->format_item($objActSheet,$column,$row,$item,$format,$row_data);
                        $column++;
                    }
                }
                else{
                    foreach($row_data as $item){
                        $data_type = is_numeric($item) && $item <= 4294967295 ? PHPExcel_Cell_DataType::TYPE_NUMERIC
                            : PHPExcel_Cell_DataType::TYPE_STRING2;
                        $objActSheet->setCellValueExplicitByColumnAndRow($column,$row,$item,$data_type);
                        $column++;
                    }
                }
                $row++;
            }
        }
        if ($dir) {
            if (is_writable($dir)) {
                $filename = $dir . $filename;
                $this->objWriter->save($filename);
            }
            return;
        }

        header('Content-Type: application/force-download');
        header('Content-Type: application/octet-stream');
        header('Content-Type: application/download');
        header('Content-Disposition:inline;filename="'.$filename.'"');
        header('Content-Transfer-Encoding: binary');
        header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
        header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
        header('Pragma: no-cache');
        $this->objWriter->save('php://output');
    }

    public function import($filename){
        $this->objExcel = \PHPExcel_IOFactory::load($filename);
        $worksheet = $this->objExcel->getActiveSheet()->toArray();
        return $worksheet;
    }

    /**
     * 读取excel转换成数组,和import方法不同,该方法会读取指定的行数,避免占用内存过大
     * @param string $excelFile 文件路径
     * @param string $excelType excel后缀格式: CSV,
     * @param int $startRow 开始读取的行数
     * @param int $endRow 结束读取的行数
     * @param array $columns 读取列
     * @return array
     */
    public function readFromExcel($excelFile, $excelType = null, $startRow = 1, $endRow = null, $columns = array())
    {
        if ($excelType == 'CSV') {
            return $this->readFromCsv($excelFile, $startRow, $endRow, $columns);
        }

        $excelReader = \PHPExcel_IOFactory::createReader($excelType);

        // 设置过滤器
        $perf = new PHPExcelReadFilter();
        $perf->startRow = $startRow;
        $perf->endRow = $endRow;
        $perf->columns = $columns;
        $excelReader->setReadFilter($perf);

        $phpexcel = $excelReader->load($excelFile);
        $activeSheet = $phpexcel->getActiveSheet();
        if (!$endRow) {
            $endRow = $activeSheet->getHighestRow(); //总行数
        }

        $highestColumn = $activeSheet->getHighestColumn(); //最后列数所对应的字母,例如第2行就是B
        $highestColumnIndex = \PHPExcel_Cell::columnIndexFromString($highestColumn); //总列数
        $columnNums = array();
        foreach ($columns as $c) {
            $columnNums[] = \PHPExcel_Cell::columnIndexFromString($c);
        }

        $data = array();
        for ($row = $startRow; $row <= $endRow; $row++) {
            for ($col = 0; $col < $highestColumnIndex; $col++) {
                if ($columnNums && !in_array(($col + 1), $columnNums)) {
                    continue;
                }
                $data[$row][] = (string)$activeSheet->getCellByColumnAndRow($col, $row)->getValue();
            }
        }

        return $data;
    }

    /**
     * 读取excel转换成数组,和import方法不同,该方法会读取指定的行数,避免占用内存过大
     * @param string $excelFile 文件路径
     * @param int $startRow 开始读取的行数
     * @param int $endRow 结束读取的行数
     * @param array $columns 读取列
     * @return array
     */
    private function readFromCsv($excelFile, $startRow = 1, $endRow = null, $columns = array())
    {
        $columnNums = array();
        foreach ($columns as $c) {
            $columnNums[] = \PHPExcel_Cell::columnIndexFromString($c);
        }

        $result = array();
        $f = fopen($excelFile, "r");
        $row = 0;
        while ($line = fgets($f)) {
            $row++;
            if ($row < $startRow) {
                continue;
            }
            if ($endRow && $row > $endRow) {
                continue;
            }
            $line = mb_convert_encoding($line, 'UTF-8', 'GBK');
            $content = explode(',', $line);
            if (!$columnNums) {
                $result[] = $content;
                continue;
            }
            $tmp = array();
            foreach ($columnNums as $columnNum) {
                $tmp[] = $content[$columnNum - 1];
            }
            $result[] = $tmp;
        }
        return $result;
    }

}

/**
 * 读取excel过滤器
 */
class PHPExcelReadFilter implements PHPExcel_Reader_IReadFilter
{
    public $startRow = 1;
    public $endRow = null;
    public $columns = array();

    public function readCell($column, $row, $worksheetName = '')
    {
        if ($row < $this->startRow) {
            return false;
        }
        if ($this->endRow && $row > $this->endRow) {
            return false;
        }
        if ($this->columns && !in_array($column, $this->columns)) {
            return false;
        }
        return true;
    }
}

## 2:PhpSpreadsheet基类
```php

namespace LYJ\Leyangjun;

use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use PhpOffice\PhpSpreadsheet\Reader\Xls;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Worksheet\PageSetup;
use PhpOffice\PhpSpreadsheet\Cell\DataType;
use PhpOffice\PhpSpreadsheet\Style\Fill;
use PhpOffice\PhpSpreadsheet\Style\Color;
use PhpOffice\PhpSpreadsheet\Style\Alignment;
use PhpOffice\PhpSpreadsheet\Style\Border;
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;

class PhpSpreadsheetExcel
{
    /**
     * 导出Excel
     * @param  string $fileName 文件名称
     * @param  array  $headArr  Excel标题头数组 [['name'=>'标题1', 'width'=>20]] width默认可以没有
     * @param  array  $data     数据内容
     * @param  array  $options  自定义配置信息 ['width'=>15] 目前只有宽度,后续可以增加,可以设置默认宽度
     * @param  string $suffix   文件后缀,xlsx 和 xls
     * @return bool
     */
    static function exportExcel($fileName = '', $headArr = [], $data = [], $options = [], $suffix = 'xlsx')
    {
        @ini_set('memory_limit', '2048M');
        @set_time_limit(0);

        if (!$headArr || !$data || !is_array($data)) {
            return false;
        }

        $fileName   .= "_" . date("YmdHis");
        $spreadsheet = new Spreadsheet();
        $objPHPExcel = $spreadsheet->getActiveSheet();

        // 设置表头
        $colum = 'A';
        foreach ($headArr as $v) {
            $objPHPExcel->setCellValue($colum . '1', $v);
            $colum++;
        }

        $column = 2;
        // 行写入
        foreach ($data as $key => $rows) {
            $span = 'A';
            // 列写入
            foreach ($rows as $keyName => $value) {
                $objPHPExcel->setCellValue($span . $column, $value);
                $span++;
            }
            $column++;
        }

        // 重命名表(UTF8编码不需要这一步)
        if (mb_detect_encoding($fileName) != "UTF-8") {
            $fileName = iconv("utf-8", "gbk//IGNORE", $fileName);
        }

        // 清理缓存
        ob_end_clean();

        if ($suffix == 'xlsx') {
            header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
            $class = "\PhpOffice\PhpSpreadsheet\Writer\Xlsx";
        } elseif ($suffix == 'xls') {
            header('Content-Type:application/vnd.ms-excel');
            $class = "\PhpOffice\PhpSpreadsheet\Writer\Xls";
        }
        header('Content-Disposition: attachment;filename="' . $fileName . '.' . $suffix . '"');
        header('Cache-Control: max-age=0');

        $writer = new $class($spreadsheet);
        $writer->save('php://output');

        // 删除清空 释放内存
        $spreadsheet->disconnectWorksheets();
        unset($spreadsheet);

        exit;
    }

    /**
     * 导出csv文件
     * @param  string $fileName 文件名称
     * @param  array  $headArr  Excel标题头数组
     * @param  array  $data     数据内容
     * @return mixed
     */
    public function exportCsv($fileName = '', $headArr = [], $data = [])
    {
        @ini_set('memory_limit', '2048M');
        @set_time_limit(0);
        if (!$headArr || !$data || !is_array($data)) {
            return false;
        }
        try {
            setlocale(LC_ALL, 'en_US.UTF-8');
            // 输出 Excel 文件头
            $fileName = empty($fileName) ? date('YmdHis') : $fileName . '_' . date('YmdHis');
            $fileName = $fileName . ".csv";
            $string   = "";
            $string  .= implode(',', $headArr) . "\n";//首先写入表格标题栏
            foreach ($data as $key => $value) {
                foreach ($value as $k => $val) {
                    $value[$k] = $val;
                }
                $string .= implode(",", $value) . "\n"; //用英文逗号分开
            }
            ob_end_clean();
            header("Content-type:text/csv");
            header("Content-Disposition:attachment;filename=" . $fileName);
            header('Cache-Control:must-revalidate,post-check=0,pre-check=0');
            header('Expires:0');
            header('Pragma:public');
            echo iconv('UTF-8', 'GBK//IGNORE', $string);

            exit;
        } catch (\Exception $e) {
            return $e->getMessage();
        }
    }

    /**
     * 使用PHPEXECL导入
     *
     * @param string $file      文件地址
     * @param int    $sheet     工作表sheet(传0则获取第一个sheet)
     * @param int    $columnCnt 列数(传0则自动获取最大列)
     * @param array  $options   操作选项
     *  array mergeCells 合并单元格数组
     *  array formula    公式数组
     *  array format     单元格格式数组
     *
     * @return mixed
     */
    static function importExcel($file = '', $sheet = 0, $columnCnt = 0, &$options = ['format'])
    {
        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) {
            return $e->getMessage();
        }
    }
}

你可能感兴趣的:(PHP)