PHP

PHP에서 Excel 생성

PHP에서 바이너리 Excel 파일을 어떻게 생성할 까? 고민하던 중 PHPExcel이란 프로젝트를 찾았다.

게다가 Excel 2007을 지원한다는 점이 매력적이었다.

바이너리 Excel 파일을 생성하는 이유는 호환성이 가장 좋기 때문이다.

특히 Mac OS X에서 Pages로 HTML이나 XML로 된 Excel 파일을 열면 그냥 텍스트로 출력된다.

구현

데이터 1000개를 가지는 시트를 만들고 1000개가 넘으면 다른 시트를 추가하는 Excel 파일 생성 예:

require_once "PHPExcel.php";
require_once "PHPExcel/IOFactory.php";

$maxRow = 10001;
$excelFile = PROJECT_PATH."/tmp/data_export_".date("Ymd_Hi").".xlsx";

$excel = new PHPExcel();
$excel->getProperties()->setTitle("데이터 내보내기");
$excel->getProperties()->setSubject($excel->getProperties()->getTitle());

if($webList->getTotal() > $maxRow) {
    $totalSheet = $webList->getTotal() / $maxRow;
    for($i = 1; $i < $totalSheet; $i++) {
        $excel->createSheet();
    }
}

$sheetNo = 0;
$rowNo = 1;
foreach($webList->getList() as $item) {
    if($rowNo == 1) {
        $excel->setActiveSheetIndex($sheetNo);
        $excel->getActiveSheet()->setTitle("예제 데이터");
        $excel->getActiveSheet()->getDefaultStyle()->getFont()->setName("Arial");
        $excel->getActiveSheet()->getDefaultStyle()->getFont()->setSize(10);

        $excel->getActiveSheet()->setCellValue("A$cellNo", "번호");
        $excel->getActiveSheet()->setCellValue("B$cellNo", "보내는 사람");
        $excel->getActiveSheet()->setCellValue("C$cellNo", "받는 사람");
        ..
        $rowNo++;
    }
    $excel->getActiveSheet()->setCellValue("A$cellNo", $item["no"]);
    $excel->getActiveSheet()->setCellValue("B$cellNo", $item["sender"]);
    $excel->getActiveSheet()->setCellValue("C$cellNo", $item["receiver"]);
    ...
    $rowNo++;

    if($rowNo > $maxRow) {
        $rowNo = 1;
        $sheetNo++;
    }
}
$excel->setActiveSheetIndex(0);

$writer = PHPExcel_IOFactory::createWriter($excel, "Excel2007");
$writer->save($excelFile);

참고

Smarty

최근에 PHP를 사용해야 할 경우가 생겼다.

개인적으로 지난 수 년 동안 PHP는 개인적으로 선호하는 환경이 아니었다.

따라서 그동안 PHP 변화에 별 다른 관심을 가지지 않았었는데, 지난 번 Piwik를 설치하면서 살펴본 소스는 그동안 내가 알고 있던 PHP와 많이 달리 Java와 비슷하게 친숙한 느낌을 받았다.

Piwik로 알게된 Smarty를 소형 프로젝트에 적용해 보기로 했다.

만약 어느정도 목표를 달성하게 되면 향후 PHP 개발을 해야하는 경우 Smarty를 이용할  것이다.

Smarty

Smarty는 소위 컨트롤러와 뷰를 분리시킬 수 있는 템플릿 엔진이다.

스크립트 언어기반에서 가장 싫은 점이 바로 어플리케이션 로직과 컨텐츠가 혼합된 페이지인데 Smarty를 사용하면 이것이 분리가 가능하다.

Java를 예를 들면 서블릿으로 구성된 컨트롤러와 JSP로 구성된 뷰와 같이 별도의 파일로 분리가 가능하다.

이를 통해 프로그램 개발자와 UI 개발자 모두 좀 더 쉽게 개발하고 유지보수가 가능할 것이다.

1. 컨트롤러

Spring Framework를 사용하게 되면 다음과 같이 사용하는 경우가 있다.

someAction.java

public ModelAndView showSample(HttpServletRequest request,
		HttpServletResponse response)
	throws Exception
{
	// 일부 로직

	// 뷰 출력
	ModelAndView mav = new ModelAndView("sample/view");
	mav.addObject("sample", someSrvice.getSample());
	mav.addObject("name", "Barney Kim");
	return mav;
}

이 것은 Smarty를 사용하는 PHP에서 다음과 같이 바꿀 수 있다.

someAction.php

<?php
	// 뷰 출력
	$smarty->assign("sample", $service->getSample());
	$smarty->assign("name", "Barney Kim");
	$smarty->display("view.tpl");
?>

2. 뷰

JSTL을 사용한 JSP는 다음과 같다면

some.jsp

<table>
<tbody>
<tr>
<td>${sample.sampleNo}</td>
<td>${sample.name}</td>
<td><fmt:formatDate value="${sample.regDate}" pattern="yyyy.MM.dd"/></td>
</tr>
</tbody>
</table>

이 것을 Smarty를 사용한 템플릿은 다음과 같이 바꿀 수 있다.

some.tpl

<tr>
<td>{$sample.no}</td>
<td>{$sample.name}</td>
<td>{$sample.regdate|date_format:"%Y.%m.%d"}</td>
</tr>

3. 참고

Piwik 설치

또 다른 Google Analytics라는 거대한 목표를 잡고 있는 Open Source Web Analytics 툴 Piwik !

아직 버전이 0.2.32지만 동작 방식이 궁금하여 MacBook에 Piwik를 설치하여 테스트를 해보았다.

처음 다운로드 받아보니 설치 단계를 진행하려고 보니 MacBook에는 PHP용 GD, PDO_MySQL이 설치되어 있지 않았다.

GD, PDO_MySQL을 컴파일하여 실행해보았으나

Piwik 설치 단계 중 데이터베이스 설정하는 부분에서 빈 페이지가 출력되었다.

Crash 로그 파일을 보니 다음과 같다

Process:         httpd [468]
Path:            /usr/sbin/httpd
Identifier:      httpd
Version:         ??? (???)
Code Type:       X86-64 (Native)
Parent Process:  httpd [467]

Date/Time:       2009-03-20 00:31:41.986 +0900
OS Version:      Mac OS X 10.5.6 (9G55)
Report Version:  6

Exception Type:  EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x0000000000000008
Crashed Thread:  0

Application Specific Information:
*** single-threaded process forked ***

Thread 0 Crashed:
0   libphp5.so                    	0x00000001012e27df mysql_send_query + 95
1   libmysqlclient.16.dylib       	0x0000000101f3a1bc mysql_real_query + 17
2   pdo_mysql.so                  	0x0000000101f0cc82 pdo_mysql_stmt_execute + 1852
3   libphp5.so                    	0x00000001010d383c zim_PDOStatement_execute + 593

PHP와 MySQL, PDO_MySQL에서 문제가 발생되는 상태였다.

여러가지를 해보아도 동일한 상태였기 때문에 i386 (32-bit) 모드 재구성을 해보기로 했다.

다행하게도(?) 32-bit에서는 정상적으로 동작을 했다.

테스트된 환경은 다음과 같다.

Mac OS X 10.5.6

Apache 2.2.6 (OS 번들)

PHP 5.2.6 (번들)

MySQL 5.0.67 (별도 설치한 binary tar)

1. 컴파일 및 설치

MySQL 32-bit를 받아서 /usr/local/mysql에 설치했다.

그리고 GD 라이브러리를 32-bit 모드로 컴파일하고 설치했다.

barney-macbook: barney$ sudo -i
barney-macbook: root# mkdir source
barney-macbook: root# wget http://www.ijg.org/files/jpegsrc.v6b.tar.gz
barney-macbook: root# wget http://www.libgd.org/releases/gd-2.0.35.tar.gz
barney-macbook: root# cd source
barney-macbook: root# tar xzpf ../jpegsrc.v6b.tar.gz
barney-macbook: root# tar xzpf ../gd-2.0.35.tar.gz
barney-macbook: root# cd jpeg-6b
barney-macbook: root# ./configure --enable-shared
barney-macbook: root# make
barney-macbook: root# make test
barney-macbook: root# make install
barney-macbook: root# cd ../gd-2.0.35
barney-macbook: root# ./configure --disable-dependency-tracking
barney-macbook: root# make
barney-macbook: root# make test
barney-macbook: root# make install

PHP용 GD, PDO_MySQL 확장 모듈을 컴파일하기 위해 해당 소스를 받아 컴파일 했다.

barney-macbook: root# cd ..
barney-macbook: root# wget http://www.opensource.apple.com/darwinsource/10.5.6/apache_mod_php-44.1/php-5.2.6.tar.bz2
barney-macbook: root# tar xjf php-5.2.6.tar.bz2
barney-macbook: root# cd php-5.2.6/ext/gd
barney-macbook: root# phpize
barney-macbook: root# ./configure --with-zlib-dir=/usr --with-jpeg-dir=/usr/local/bin --with-png-dir=/usr/X11R6 --with-freetypedir=/usr/X11R6 --with-xpm-dir=/usr/X11R6
barney-macbook: root# make
barney-macbook: root# make test
barney-macbook: root# make install
barney-macbook: root# cd ../pdo_mysql
barney-macbook: root# ./configure --with-zlib-dir=/usr --with-pdo-mysql=/usr/local/mysql
barney-macbook: root# make
barney-macbook: root# make test
barney-macbook: root# make install
barney-macbook: root# ls `php-config --extension-dir`
gd.so pdo_mysql.so phpcups.so

이제 만들어진 PHP 확장 모듈을 사용하기 위해서 php.ini을 설정한다.

barney-macbook: root# cp /etc/php.ini.default /etc/php.ini
barney-macbook: root# vi /etc/php.ini
; 확장 모듈 디렉토리 주석 처리
;extension_dir = "./"
; 확장 모듈 활성화
extension=gd.so
extension=pdo_mysql.so

2. Apache 32-bit용 생성

이제 PHP는 준비가 되었으므로 Apache를 32-bit로 동작시키기 위해 변경작업을 한다

barney-macbook: root# apachectl stop
barney-macbook: root# mv /usr/sbin/httpd /usr/sbin/httpd.x86_64
barney-macbook: root# lipo -thin i386 /usr/sbin/httpd.x86_64 -output /usr/sbin/httpd.i386
barney-macbook: root# ln -s /usr/sbin/httpd.i386 /usr/sbin/httpd
barney-macbook: root# apachectl start

3. 참고