| <?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); |
| } |
| } |
| ?> |
인터넷 검색하다가 이 글을 발견하고 올레를 외쳤는데...php5.4 이상의 환경이라니...
저는 php5.3 이거든요 T.T
위 소스로 zip파일 생성도 되고, 다운도 되고, 다운 받은 걸 압축해제도 됩니다.
근데, 압축 해제 시에 '압축파일이 손상되었습니다.(CRC에러)' 메세지가 떠요.
혹시 관련해서 해결 방법을 아시면 조언 좀 부탁드립니다 T.T
list(, $this->crc) = unpack('N', hash_file('crc32b', $filename, true));
복 받으실 거예요 T.T
전 반디집을 사용해서 zip파일 해제에 문제가 없었는데요.
윈도우의 기본 zip파일 해제도 문제 없습니다.
그런데, 알집을 사용하는 컴에서는 zip파일 해제 시에 '압축파일의 헤더가 손상되었습니다'란 오류메세지가 떠요.
이 부분 관련해서는 해결 방법이 없을까요?
조언 부탁드리겠습니다...
기본설정으로 했을 때 timezone관련 에러가 떴던 걸로...
해결하기 귀찮으면 error_reporting(0);을 파일 제일 처음에 넣는 방법도 있습니다.
PHP 5.3.3에서 테스트 했을경우 153라인($this->crc = unpack('N', hash_file('crc32b', $filename, true))[1];)에서 오류가 발생하였는데, 댓글에 남겨주신 코드로 변경하였더니 잘 됩니다.
파일 다운로드까지 남은시간 및 총 파일 용량은 아래의 코드추가로 해결하였습니다.
07라인 public function open($filename) -> public function open($filename, $filesize)
16라인에 추가 header("Content-Length: $filesize");
그리고 괜찮으시다면 출처 남기고 블로그에 퍼가도 될까요?
아니라면 브라우저가 받는 도중에 끊을 것 같은데, 잘 된다 하시니 걱정은 안 해도 되겠네요.
퍼가는 건 마음대로~
사용 안하는게 좋을 것 같습니다... ㅠㅠ
답변 감사합니다.
동적으로 생성할 파일의 최종 크기를 생성 전에 알 수 없기 때문이죠..
실례가 되지 않는다면 http://blog.terrorboy.net 으로 스크랩 해가도 될까요?
문론, 내용 하단에 원본 출처를 남긴다는 조건으로요^^
너무 좋은 소스 담아갈께요~~~~
잘 만드셨네요^^
좋은내용 감사합니다^^
문제는 압축하일에서 addFile 함수로 보낸 파일이 압축파일내로 안들어가집니다
$zip->open('아리아워크룸(신경욱).zip');
$zip->addEmptyDir('아리아워크룸(신경욱)');
$zip->addFile('/attach/20160215/1455506575.jpg', '아리아워크룸(신경욱)/1.jpg');
$zip->addFromString('아리아워크룸(신경욱)/바로 글쓰기.txt', '파일 내용');
이렇게 넣었는데요
텍스트파일은 압축해제하니 저대로 뜹니다
폴더도 생성되고요
이미지파일만 생성이 안되는데 이유가 뭘까요?
1455506575.jpg 파일은 실제 웹 서버에 올라가 있는 파일입니다
문제는 압축하일에서 addFile 함수로 보낸 파일이 압축파일내로 안들어가집니다
텍스트파일은 압축해제하니 제대로 뜹니다
폴더도 생성되고요
이미지파일만 생성이 안되는데 이유가 뭘까요?
파일은 실제 웹 서버에 올라가 있는 파일로 경로 설정도 root를 / 로 시작했습니다
www
-.php
-attach
--20160215
---1455506575.jpg
폴더 구성이 이렇게 돼있다면 '/attach'에서 '/'를 빼야 합니다.
추가로, ftp에서 볼 때 root와 웹서버의 root는 같지 않을 수 있으므로 조심하세요.
저도 알집과 윈집에서 파일열기 및 압축해제에서 손상된 파일이라는 오류메세지가 나타납니다.
이 있는 줄을 수정하면 됩니다.
다운로드는 되는것 같은데 알집에서 헤더가 손상되었다고 나옵니다. 파일은 잘들어 오는것 같습니다,.
언제 date 함수를 안 쓰게 바꿔야겠네요..
보내주신 소스로 만들어보니 파일 압축과 다운은 잘되는데 다운받은 압축파일을 열어보면 압축되어진 이미지 파일들의 크기가 0으로 나오고 있습니다. 이미지는 당연히 비어있구요ㅠㅠ 내용이 왜 안들어가지는지 알수 있을까요?
EUC-KR (PHP5.2, MySQL5.x)
소스코드에 골뱅이(@)를 다 지워보시고 출력되는 에러 로그를 첨부해주실레요?
제일 의심가는 게 BUFFER_SIZE const 선언부이긴 한데, BUFFER_SIZE 값을 75번째 줄에 바로 입력하는 거도 고려해주세요.