Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
Tags
- MySQL
- virsualhost
- .htaccess
- JS
- 글자수제한
- iframe
- Ajax
- 정규식
- selinux
- 우분투 서버세팅
- 보안인증서
- 애니메이트
- JavaScript
- 날짜변환
- 배열
- ip직접접근차단
- 리사이즈
- SSL
- 301 리다이렉트
- 정부 서비스 가이드라인
- 비동기호출
- 자바스크립트
- 날짜비교
- Vanilla JS
- 디지털 정부서비스ui/ux
- 글자 수 제한
- post_type
- 구글뷰어
- php8.3
- krds
Archives
- Today
- Total
더 나은 프로그래머가 되자
다중 파일을 zip으로 묶어받기 본문
php로 여러 개의 파일을 묶는 방법은 여러가지가 있다. exec()으로 압축 프로그램을 실행시켜서 묶거나 , ZipArchive로 묶거나, 직접 묶거나. 이 글은 다 묶어질 때까지 기다릴 필요가 없는 직접 묶는 방법으로 코딩한 소스를 공유하고자 작성하였다!
소스와 사용법
PKZip의 구조를 정리해놓은 문서와 PHP ZipArchive 클래스를 참고해서 직접 코딩했다. 이 소스는 zip 관리용이 아니라 묶어받기용이다.
<?php | |
class DirectZip | |
{ | |
const BUFFER_SIZE = 4194304; // 4MiB | |
private $currentOffset; | |
private $entries; | |
public function open($filename) | |
{ | |
set_time_limit(0); | |
ini_set('zlib.output_compression', 'Off'); | |
header('Pragma: no-cache'); | |
header('Expires: Thu, 01 Jan 1970 00:00:00 GMT'); | |
header('Cache-Control: no-store'); | |
header('Content-Type: application/zip'); | |
header('Content-Disposition: attachment; ' . | |
'filename="' . $filename . '"; ' . | |
'filename*=UTF-8\'\'' . rawurlencode($filename)); | |
$this->currentOffset = 0; | |
$this->entries = array(); | |
} | |
public function addEmptyDir($dirname) | |
{ | |
if ($this->addFile('php://temp', $dirname.'/') === false) | |
{ | |
return false; | |
} | |
} | |
public function addFromString($localname, $contents) | |
{ | |
$tmp = tempnam(sys_get_temp_dir(), __CLASS__); | |
$pointer = @fopen($tmp, 'wb'); | |
if ($pointer === false) | |
{ | |
@unlink($tmp); | |
return false; | |
} | |
fwrite($pointer, $contents); | |
$result = $this->addFile($tmp, $localname); | |
fclose($pointer); | |
@unlink($tmp); | |
if ($result === false) | |
{ | |
return false; | |
} | |
} | |
public function addFile($filename, $localname = null) | |
{ | |
$entry = new DirectZipEntry(empty($localname) ? basename($filename) : $localname, $this->currentOffset); | |
if ($entry->open($filename) === false) | |
{ | |
return false; | |
} | |
$this->entries[] = $entry; | |
ob_start(); | |
self::write(0x504B0304, 'N'); // sig entry | |
self::writeEntryStat($entry); | |
echo $entry->name; | |
$this->currentOffset += strlen(ob_get_flush()); | |
while (!feof($entry->pointer)) | |
{ | |
$buffer = @fread($entry->pointer, self::BUFFER_SIZE); | |
echo $buffer; | |
flush(); | |
$this->currentOffset += strlen($buffer); | |
} | |
$entry->close(); | |
} | |
public function close() | |
{ | |
ob_start(); | |
foreach ($this->entries as $entry) | |
{ | |
self::write(0x504B0102, 'N'); // sig index | |
self::write(0); // os: fat | |
self::writeEntryStat($entry); | |
self::write(0); // comment len | |
self::write(0); // disk # start | |
self::write(0); // internal attr | |
self::write(0, 'V'); // external attr | |
self::write($entry->offset, 'V'); | |
echo $entry->name; | |
} | |
$length = strlen(ob_get_flush()); | |
self::write(0x504B0506, 'N'); // sig end | |
self::write(0); // disk number | |
self::write(0); // disk # index start | |
self::write(count($this->entries)); // disk entries | |
self::write(count($this->entries)); // total entries | |
self::write($length, 'V'); | |
self::write($this->currentOffset, 'V'); | |
self::write(0); // comment len | |
flush(); | |
} | |
private static function writeEntryStat($entry) | |
{ | |
self::write(substr($entry->name, -1) == '/' ? 20 : 10); | |
self::write(2048); // flags: unicode filename | |
self::write(0); // compression: store | |
self::write($entry->mtime, 'V'); | |
self::write($entry->crc, 'V'); | |
self::write($entry->size, 'V'); // compressed size | |
self::write($entry->size, 'V'); // uncompressed size | |
self::write(strlen($entry->name)); | |
self::write(0); // extra field len | |
} | |
private static function write($binary, $format = 'v') | |
{ | |
echo pack($format, $binary); | |
} | |
} | |
class DirectZipEntry | |
{ | |
public $offset; | |
public $pointer; | |
public $name; | |
public $crc; | |
public $size; | |
public $mtime; | |
public function __construct($name, $offset) | |
{ | |
$this->offset = $offset; | |
$this->name = $name; | |
} | |
public function open($filename) | |
{ | |
$this->pointer = @fopen($filename, 'rb'); | |
if ($this->pointer === false) | |
{ | |
return false; | |
} | |
list(, $this->crc) = unpack('N', hash_file('crc32b', $filename, true)); | |
$fstat = fstat($this->pointer); | |
$this->size = $fstat['size']; | |
$mtime = $filename == 'php://temp' ? time() : $fstat['mtime']; | |
$this->mtime = (date('Y', $mtime) - 1980) << 25 | date('m', $mtime) << 21 | date('d', $mtime) << 16 | | |
date('H', $mtime) << 11 | date('i', $mtime) << 5 | date('s', $mtime) >> 1; | |
} | |
public function close() | |
{ | |
fclose($this->pointer); | |
} | |
} | |
?> |
<?php | |
require 'cla_directzip.php'; | |
$zip = new DirectZip(); | |
$zip->open('브라우저로 보낼 압축파일 이름.zip'); | |
$zip->addFile('/tmp/추가할 파일.jpg', '압축파일 내 파일 이름.jpg'); | |
$zip->addEmptyDir('압축파일 내 폴더 이름'); // 안 해도 상관없음. | |
$zip->addFile('/tmp/추가할 파일2.png', '압축파일 내 폴더 이름/압축파일 내 파일 이름.png'); | |
$zip->addFile('/tmp/추가할 파일3.jpg'); // 압축파일에 파일을 '추가할 파일3.jpg'로 추가 | |
$zip->addFromString('바로 글쓰기.txt', '파일 내용'); // 압축파일에 '파일 내용'을 '바로 글쓰기.txt'로 추가 | |
$zip->close(); | |
/* | |
브라우저로 보낼 압축파일 이름.zip | |
│ 바로 글쓰기.txt | |
│ 압축파일 내 파일 이름.jpg | |
│ 추가할 파일3.jpg | |
│ | |
└─압축파일 내 폴더 이름 | |
압축파일 내 파일 이름.png | |
*/ | |
?> |
php 5.3 이상의 환경에서 위와 같이 코딩하면 한 주소에서 파일 여러 개를 묶어서 내려받을 수 있다.
단점
다 묶일 때까지 기다리거나 임시파일 만들 필요가 없는 이 소스에도 단점이 있다. 파일 이어받기가 안 되고 언제 다 받을지 모른다는 것인데, 다 받아질 때까지 느긋하게 기다리라고 클라이언트에 알려두면 좋을 것 같다.
최대한 간단하게 코딩해서 그런지 파일의 만든 날짜, 엑세스한 날짜 등이 지워진다는 것을 단점이라고 해야 되나 모르겠다. 난 좋은데.
출처 : http://blog.bloodcat.com/277
'언어 > PHP' 카테고리의 다른 글
xe 외부 페이지를 include 시켰을때 xe 코어 적용시키는법 (0) | 2016.01.06 |
---|---|
class,object 객체지향(oop) 관련 도큐먼트 (0) | 2015.12.30 |
그누보드5 게시판 포인트 하루 적립 제한 방법 (0) | 2015.10.13 |
그누보드5에 cheditor5 적용시키기 (0) | 2015.09.25 |
geoip 국가코드 식별 (0) | 2015.09.03 |
Comments