개발 꿀팁/PHP

php CSV 추상화 내보내기

Jammie 2022. 8. 10. 12:27
반응형

php CSV 추상 클래스를 내보내며, 총 레코드 수와 로트당 레코드 수에 따라 총 로트를 계산하여 순환 내보냅니다.메모리 부족 문제를 피한다.



ExportCSV.class.php

<?php
/** php Export CSV abstract class,총 기록 수와 로트당 기록 수에 따라 총 로트를 계산하여 순환적으로 내보냅니다。
*   Date:   2014-05-16
*   Author: fdipzone
*   Ver:    1.0
*
*   Func:
*   public  setPageSize      로트당 내보낼 레코드 개수 설정
*   public  setExportName    내보낸 파일 이름 설정
*   public  setSeparator     구분 기호 설정
*   public  setDelimiter     구분 기호 설정
*   public  export           내보내기 실행
*   private getPageCount     총 내보내기 로트 계산
*   private setHeader        내보내기 파일 header 설정
*   private formatCSV        데이터를 csv 형식으로 변환
*   private escape           이스케이프 문자열
*   abstract getExportTotal  총 기록 건수, 추상적인 방법을 얻으려면 클래스를 계승하여 실현해야 한다
*   abstract getExportFields 내보낸 열 이름, 추상 방법을 가져오려면 클래스 구현을 상속해야 합니다
*   abstract getExportData   각 페이지의 기록, 추상적인 방법을 얻으려면 클래스를 계승하여 실현해야 한다
*/
 
abstract class ExportCSV{ // class start
 
    // 서브클래스가 반드시 실현되어야 할 방법을 정의하다
    
    /** 총 레코드 개수 가져오기
    * @return int
    */
    abstract protected function getExportTotal();
 
    /** 내보낸 열 이름 가져오기
    * @return Array
    */
    abstract protected function getExportFields();
 
    /** 로트당 데이터 가져오기
    * @param  int $offset 오프셋
    * @param  int $limit  가져온 레코드 개수
    * @return Array
    */
    abstract protected function getExportData($offset, $limit);
 
 
    // 클래스 속성 정의
    protected $total = 0;                 // 총기록수
    protected $pagesize = 500;            // 로트당 내보낸 레코드 수
    protected $exportName = 'export.csv'; // 내보낸 파일 이름
    protected $separator = ',';           // 구분 기호 설정
    protected $delimiter = '"';           // 구분 기호 설정
 
 
    /** 내보낼 때마다 레코드 개수 설정
    * @param int $pagesize 내보낼 때마다 레코드 개수
    */
    public function setPageSize($pagesize=0){
        if(is_numeric($pagesize) && $pagesize>0){
            $this->pagesize = $pagesize;
        }
    }
 
 
    /** 내보낸 파일 이름 설정
    * @param String $filename 내보낸 파일 이름
    */
    public function setExportName($filename){
        if($filename!=''){
            $this->exportName = $filename;
        }
    }
 
 
    /** 구분 기호 설정
    * @param String $separator 구분 기호
    */
    public function setSeparator($separator){
        if($separator!=''){
            $this->separator = $separator;
        }
    }
 
 
    /** 구분 기호 설정
    * @param String $delimiter 구분 기호
    */
    public function setDelimiter($delimiter){
        if($delimiter!=''){
            $this->delimiter = $delimiter;
        }
    }
 
 
    /** csv 내보내기 */
    public function export(){
 
        // 총 레코드 수 가져오기
        $this->total = $this->getExportTotal();
 
        // 기록이 없다
        if(!$this->total){
            return false;
        }
 
        // 총 내보내기 로트 계산
        $pagecount = $this->getPageCount();
 
        //내보낸 열 이름 가져오기
        $fields = $this->getExportFields();
 
        // 내보내기 파일 header 설정
        $this->setHeader();
 
        // 순환 내보내기
        for($i=0; $i<$pagecount; $i++){
 
            $exportData = '';
 
            if($i==0){ // 제1조 기록 전에 먼저 이름을 열거하다
                $exportData .= $this->formatCSV($fields);
            }
 
            // 오프셋 값 설정
            $offset = $i*$this->pagesize;
 
            // 페이지당 데이터 가져오기
            $data = $this->getExportData($offset, $this->pagesize);
 
            // 모든 페이지를 csv 형식으로 변환
            if($data){
                foreach($data as $row){
                    $exportData .= $this->formatCSV($row);
                }
            }
 
            //데이터 내보내기
            echo $exportData;
        }
 
    }
 
 
    /** 총 로트를 계산하다 */
    private function getPageCount(){
        $pagecount = (int)(($this->total-1)/$this->pagesize)+1;
        return $pagecount;
    }
 
 
    /** 내보내기 파일 header 설정 */
    private function setHeader(){
        header('content-type:application/x-msexcel');
 
        $ua = $_SERVER['HTTP_USER_AGENT'];
 
        if(preg_match("/MSIE/", $ua)){
            header('content-disposition:attachment; filename="'.rawurlencode($this->exportName).'"');
        }elseif(preg_match("/Firefox/", $ua)){
            header("content-disposition:attachment; filename*=\"utf8''".$this->exportName.'"');
        }else{
            header('content-disposition:attachment; filename="'.$this->exportName.'"');
        }
 
        ob_end_flush();
        ob_implicit_flush(true);
    }
 
 
    /** csv 형식으로 데이터 형식 지정
    * @param Array $data csv 형식으로 변환할 배열
    */
    private function formatCSV($data=array()){
        // 배열의 각 원소에 대한 전의를 진행하다
        $data = array_map(array($this,'escape'), $data);
        return $this->delimiter.implode($this->delimiter.$this->separator.$this->delimiter, $data).$this->delimiter."\r\n";
    }
 
 
    /** 이스케이프 문자열
    * @param  String $str
    * @return String
    */
    private function escape($str){
        return str_replace($this->delimiter, $this->delimiter.$this->delimiter, $str);
    }
 
} // class end
 
?>

demo

<?php
 
// ExportCSV abstract class
require "ExportCSV.class.php";
 
// 상속 클래스 정의
class myexport extends ExportCSV{
 
    // 내보내려는 데이터는 실제 상황은 db에서 읽어낸다
    protected $data = array(
        array('1','오설성 단풍"','남자'),
        array('2','오설성 단풍","','남자'),
        array('3','오설성 단풍","','남자'),
        array('4',"오설성 단풍\"\"\r\n행을 바꾸다",'남자'),
        array('5','오설성 단풍,,','남자'),
        array('6','오설성 단풍"','남자'),
        array('7','오설성 단풍','남자'),
        array('8','오설성 단풍','남자'),
        array('9','오설성 단풍','남자'),
        array('10','오설성 단풍','남자')
    );
 
    /* 총 내보내기 레코드 수를 반환합니다
    * @return int
    */
    protected function getExportTotal(){
        return count($this->data);
    }
 
    /** 내보낸 열 이름을 되돌려줍니다
    * @return Array
    */
    protected function getExportFields(){
        $title = array('id','name','gender');
        return $title;
    }
 
    /* 각 로트의 레코드를 되돌립니다
    * @param  int $offset 오프셋
    * @param  int $limit  가져온 레코드 개수
    * @return Array
    */
    protected function getExportData($offset, $limit){
        return array_slice($this->data, $offset, $limit);
    }
 
}
 
// 내보내기
$obj = new myexport();
$obj->setPageSize(1);
$obj->setExportName('myexport.csv');
$obj->setSeparator(',');
$obj->setDelimiter('"');
$obj->export();
 
?>

 

반응형