1<?php
2// this corrupt zip maker uses portions of Vincent Lascaux's File_Archive to create
3// specifically corrupted zip archives for unit-testing zip support in the phar extension
4// and was modified by Greg Beaver
5/**
6 * ZIP archive writer
7 *
8 * PHP versions 4 and 5
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18 * Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330,Boston,MA 02111-1307 USA
23 *
24 * @category   File Formats
25 * @package    File_Archive
26 * @author     Vincent Lascaux <vincentlascaux@php.net>
27 * @copyright  1997-2005 The PHP Group
28 * @license    http://www.gnu.org/copyleft/lesser.html  LGPL
29 * @version    CVS: $Id$
30 * @link       http://pear.php.net/package/File_Archive
31 */
32
33/**
34 * ZIP archive writer
35 */
36class corrupt_zipmaker
37{
38	/**
39	* @var int Current position in the writer
40	* @access private
41	*/
42	var $offset = 0;
43
44	/**
45	* @var string Optionnal comment to add to the zip
46	* @access private
47	*/
48	var $comment = "";
49
50	/**
51	* @var string Data written at the end of the ZIP file
52	* @access private
53	*/
54	var $central = "";
55
56	/**
57	* @var string Data written at the start of the ZIP file
58	* @access private
59	*/
60	var $start = "";
61
62	/**
63	* Set a comment on the ZIP file
64	*/
65	function setComment($comment) { $this->comment = $comment; }
66
67	/**
68	* @param int $time Unix timestamp of the date to convert
69	* @return the date formated as a ZIP date
70	*/
71	function getMTime($time)
72	{
73		$mtime = ($time !== null ? getdate($time) : getdate());
74		$mtime = preg_replace(
75				"/(..){1}(..){1}(..){1}(..){1}/",
76				"\\x\\4\\x\\3\\x\\2\\x\\1",
77				dechex(($mtime['year']-1980<<25)|
78					($mtime['mon'    ]<<21)|
79					($mtime['mday'   ]<<16)|
80					($mtime['hours'  ]<<11)|
81					($mtime['minutes']<<5)|
82					($mtime['seconds']>>1)));
83		eval('$mtime = "'.$mtime.'";');
84		return $mtime;
85	}
86
87	private function getFileEntry($compmethod, $mtime, $crc32, $complength, $uncomplength, $filename, $data, $corrupt, $fakecomp)
88	{
89		switch ($corrupt) {
90			case null :
91				$file = "PK\x03\x04\x14\x00\x00\x00" . pack('v', $compmethod) .
92						$mtime .
93						pack("VVVvv", $crc32, $complength, $uncomplength, strlen($filename), 0x00) .
94						$filename .
95						$data;
96				break;
97			case 'compress' :
98				$file = "PK\x03\x04\x14\x00\x00\x00" . pack('v', $fakecomp) .
99						$mtime .
100						pack("VVVvv", $crc32, $complength, $uncomplength, strlen($filename), 0x00) .
101						$filename .
102						$data;
103				break;
104			case 'encrypt' :
105				$file = "PK\x03\x04\x14\x00\x01\x00" . pack('v', $compmethod) .
106						$mtime .
107						pack("VVVvv", $crc32, $complength, $uncomplength, strlen($filename), 0x00) .
108						$filename .
109						$data;
110				break;
111			case 'crc32' :
112				$file = "PK\x03\x04\x14\x00\x00\x00" . pack('v', $compmethod) .
113						$mtime .
114						pack("VVVvv", $crc32 + 1, $complength, $uncomplength, strlen($filename), 0x00) .
115						$filename .
116						$data;
117				break;
118			case 'complength' :
119				$file = "PK\x03\x04\x14\x00\x00\x00" . pack('v', $compmethod) .
120						$mtime .
121						pack("VVVvv", $crc32, $complength + 1, $uncomplength, strlen($filename), 0x00) .
122						$filename .
123						$data;
124				break;
125			case 'uncomplength' :
126				$file = "PK\x03\x04\x14\x00\x00\x00" . pack('v', $compmethod) .
127						$mtime .
128						pack("VVVvv", $crc32, $complength, $uncomplength - 1, strlen($filename), 0x00) .
129						$filename .
130						$data;
131				break;
132			case 'filename_len' :
133				$file = "PK\x03\x04\x14\x00\x00\x00" . pack('v', $compmethod) .
134						$mtime .
135						pack("VVVvv", $crc32, $complength, $uncomplength, strlen($filename) - 1, 0x00) .
136						$filename .
137						$data;
138				break;
139			case 'extra_len' :
140				$file = "PK\x03\x04\x14\x00\x00\x00" . pack('v', $compmethod) .
141						$mtime .
142						pack("VVVvv", $crc32, $complength, $uncomplength, strlen($filename), 1) .
143						$filename .
144						$data;
145				break;
146			case 'filename' :
147				$file = "PK\x03\x04\x14\x00\x00\x00" . pack('v', $compmethod) .
148						$mtime .
149						pack("VVVvv", $crc32, $complength, $uncomplength, strlen($filename), 0x00) .
150						substr($filename, 1) .
151						$data;
152				break;
153			case 'data' :
154				$file = "PK\x03\x04\x14\x00\x00\x00" . pack('v', $compmethod) .
155						$mtime .
156						pack("VVVvv", $crc32, $complength, $uncomplength, strlen($filename), 0x00) .
157						$filename .
158						substr($data, 1);
159				break;
160		}
161		return $file;
162	}
163
164	private function getCentralEntry($compmethod, $mtime, $crc32, $complength, $uncomplength, $filename, $comment, $corrupt, &$offset, $fakecomp)
165	{
166		settype($comment, 'string');
167		switch ($corrupt) {
168			case null :
169				$central = "PK\x01\x02\x00\x00\x14\x00\x00\x00" . pack('v', $compmethod) .
170						$mtime .
171						pack("VVVvvvvvVV", $crc32, $complength, $uncomplength, strlen($filename), 0x00,strlen($comment),0x00,0x00,
172							0x0000, $this->offset).
173						$filename . $comment;
174				$offset = strlen($central);
175				break;
176			case 'encrypt' :
177				$central = "PK\x01\x02\x00\x00\x14\x00\x01\x00" . pack('v', $compmethod) .
178						$mtime .
179						pack("VVVvvvvvVV", $crc32, $complength, $uncomplength, strlen($filename), 0x00,strlen($comment),0x00,0x00,
180							0x0000, $this->offset).
181						$filename . $comment;
182				$offset = strlen($central);
183				break;
184			case 'compress' :
185				$central = "PK\x01\x02\x00\x00\x14\x00\x00\x00" . pack('v', $fakecomp) .
186						$mtime .
187						pack("VVVvvvvvVV", $crc32, $complength, $uncomplength, strlen($filename), 0x00,strlen($comment),0x00,0x00,
188							0x0000, $this->offset).
189						$filename . $comment;
190				$offset = strlen($central);
191				break;
192			case 'crc32' :
193				$central = "PK\x01\x02\x00\x00\x14\x00\x00\x00" . pack('v', $compmethod) .
194						$mtime .
195						pack("VVVvvvvvVV", $crc32 + 1, $complength, $uncomplength, strlen($filename), 0x00,strlen($comment),0x00,0x00,
196							0x0000, $this->offset).
197						$filename . $comment;
198				$offset = strlen($central);
199				break;
200			case 'complength' :
201				$central = "PK\x01\x02\x00\x00\x14\x00\x00\x00" . pack('v', $compmethod) .
202						$mtime .
203						pack("VVVvvvvvVV", $crc32, $complength - 1, $uncomplength, strlen($filename), 0x00,strlen($comment),0x00,0x00,
204							0x0000, $this->offset).
205						$filename . $comment;
206				$offset = strlen($central);
207				break;
208			case 'uncomplength' :
209				$central = "PK\x01\x02\x00\x00\x14\x00\x00\x00" . pack('v', $compmethod) .
210						$mtime .
211						pack("VVVvvvvvVV", $crc32, $complength, $uncomplength - 1, strlen($filename), 0x00,strlen($comment),0x00,0x00,
212							0x0000, $this->offset).
213						$filename . $comment;
214				$offset = strlen($central);
215				break;
216			case 'filename_len' :
217				$central = "PK\x01\x02\x00\x00\x14\x00\x00\x00" . pack('v', $compmethod) .
218						$mtime .
219						pack("VVVvvvvvVV", $crc32, $complength, $uncomplength, strlen($filename) - 1, 0x00,strlen($comment),0x00,0x00,
220							0x0000, $this->offset).
221						$filename . $comment;
222				$offset = strlen($central);
223				break;
224			case 'offset' :
225				$central = "PK\x01\x02\x00\x00\x14\x00\x00\x00" . pack('v', $compmethod) .
226						$mtime .
227						pack("VVVvvvvvVV", $crc32, $complength, $uncomplength, strlen($filename), 0x00,strlen($comment),0x00,0x00,
228							0x0000, $this->offset - 1).
229						$filename . $comment;
230				$offset = strlen($central) - 1;
231				break;
232			case 'comment' :
233				$central = "PK\x01\x02\x00\x00\x14\x00\x00\x00" . pack('v', $compmethod) .
234						$mtime .
235						pack("VVVvvvvvVV", $crc32, $complength, $uncomplength, strlen($filename), 0x00,strlen($comment) + 1,0x00,0x00,
236							0x0000, $this->offset).
237						$filename . $comment;
238				$offset = strlen($central);
239				break;
240			case 'extralen1' :
241				$extra = 'nu' . 0xffff; // way huge size
242				$central = "PK\x01\x02\x00\x00\x14\x00\x00\x00" . pack('v', $compmethod) .
243						$mtime .
244						pack("VVVvvvvvVV", $crc32, $complength, $uncomplength, strlen($filename), strlen($extra),strlen($comment),0x00,0x00,
245							0x0000, $this->offset).
246						$filename . $extra . $comment;
247				$offset = strlen($central);
248				break;
249		}
250		return $central;
251	}
252
253	function addFile($filename, $mtime, $data, $comment = null, $compress = null, $filecorrupt = null, $centralcorrupt = null, $fakecomp = 1)
254	{
255		$mtime = $this->getMTime($mtime ? $mtime : null);
256
257		$uncomplength = strlen($data);
258		$crc32 = crc32($data) & 0xFFFFFFFF;
259		$compmethod = 0;
260		switch ($compress) {
261			case 'gz' :
262				$data = gzcompress($data);
263				$compmethod = 8;
264				break;
265			case 'bz2' :
266				$data = bzcompress($data);
267				$compmethod = 12;
268				break;
269		}
270		$complength = strlen($data);
271
272		$this->start .= ($file = $this->getFileEntry($compmethod, $mtime, $crc32, $complength, $uncomplength, $filename, $data, $filecorrupt, $fakecomp));
273
274		$offset = 0;
275		$this->central .= $this->getCentralEntry($compmethod, $mtime, $crc32, $complength, $uncomplength, $filename, $comment, $centralcorrupt, $offset, $fakecomp);
276
277		$this->offset += $offset;
278		$this->count++;
279	}
280
281	function writeZip($zipfile, $corrupt = null)
282	{
283		$write = $this->start . $this->central;
284		switch ($corrupt) {
285			case null :
286				$write .= "PK\x05\x06\x00\x00\x00\x00" .
287					pack("vvVVv", $this->count, $this->count,
288					$this->offset, strlen($this->start),
289					strlen($this->comment)) . $this->comment;
290				break;
291			case 'disknumber' :
292				$write .= "PK\x05\x06\x01\x00\x01\x00" .
293					pack("vvVVv", $this->count, $this->count,
294					$this->offset, strlen($this->start),
295					strlen($this->comment)) . $this->comment;
296				break;
297			case 'count1' :
298				$write .= "PK\x05\x06\x00\x00\x00\x00" .
299					pack("vvVVv", $this->count + 1, $this->count,
300					$this->offset, strlen($this->start),
301					strlen($this->comment)) . $this->comment;
302				break;
303			case 'count2' :
304				$write .= "PK\x05\x06\x00\x00\x00\x00" .
305					pack("vvVVv", $this->count, $this->count + 1,
306					$this->offset, strlen($this->start),
307					strlen($this->comment)) . $this->comment;
308				break;
309			case 'cdir_offset' :
310				$write .= "PK\x05\x06\x00\x00\x00\x00" .
311					pack("vvVVv", $this->count, $this->count,
312					$this->offset, strlen($this->start) - 3,
313					strlen($this->comment)) . $this->comment;
314				break;
315			case 'cdir_len' :
316				$write .= "PK\x05\x06\x00\x00\x00\x00" .
317					pack("vvVVv", $this->count, $this->count,
318					$this->offset - 5, strlen($this->start),
319					strlen($this->comment)) . $this->comment;
320				break;
321			case 'comment' :
322				$write .= "PK\x05\x06\x00\x00\x00\x00" .
323					pack("vvVVv", $this->count, $this->count,
324					strlen($this->start), $this->offset + 1,
325					strlen($this->comment) + 1) . $this->comment;
326				break;
327			case 'none' :
328		}
329		file_put_contents($zipfile, $write);
330	}
331}
332?>