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 * @link       http://pear.php.net/package/File_Archive
30 */
31
32/**
33 * ZIP archive writer
34 */
35class corrupt_zipmaker
36{
37	/**
38	* @var int Current position in the writer
39	* @access private
40	*/
41	var $offset = 0;
42
43	/**
44	* @var string Optional comment to add to the zip
45	* @access private
46	*/
47	var $comment = "";
48
49	/**
50	* @var string Data written at the end of the ZIP file
51	* @access private
52	*/
53	var $central = "";
54
55	/**
56	* @var string Data written at the start of the ZIP file
57	* @access private
58	*/
59	var $start = "";
60
61	/**
62	* Set a comment on the ZIP file
63	*/
64	function setComment($comment) { $this->comment = $comment; }
65
66	/**
67	* @param int $time Unix timestamp of the date to convert
68	* @return the date formatted as a ZIP date
69	*/
70	function getMTime($time)
71	{
72		$mtime = ($time !== null ? getdate($time) : getdate());
73		$mtime = preg_replace(
74				"/(..){1}(..){1}(..){1}(..){1}/",
75				"\\x\\4\\x\\3\\x\\2\\x\\1",
76				dechex(($mtime['year']-1980<<25)|
77					($mtime['mon'    ]<<21)|
78					($mtime['mday'   ]<<16)|
79					($mtime['hours'  ]<<11)|
80					($mtime['minutes']<<5)|
81					($mtime['seconds']>>1)));
82		eval('$mtime = "'.$mtime.'";');
83		return $mtime;
84	}
85
86	private function getFileEntry($compmethod, $mtime, $crc32, $complength, $uncomplength, $filename, $data, $corrupt, $fakecomp)
87	{
88		switch ($corrupt) {
89			case null :
90				$file = "PK\x03\x04\x14\x00\x00\x00" . pack('v', $compmethod) .
91						$mtime .
92						pack("VVVvv", $crc32, $complength, $uncomplength, strlen($filename), 0x00) .
93						$filename .
94						$data;
95				break;
96			case 'compress' :
97				$file = "PK\x03\x04\x14\x00\x00\x00" . pack('v', $fakecomp) .
98						$mtime .
99						pack("VVVvv", $crc32, $complength, $uncomplength, strlen($filename), 0x00) .
100						$filename .
101						$data;
102				break;
103			case 'encrypt' :
104				$file = "PK\x03\x04\x14\x00\x01\x00" . pack('v', $compmethod) .
105						$mtime .
106						pack("VVVvv", $crc32, $complength, $uncomplength, strlen($filename), 0x00) .
107						$filename .
108						$data;
109				break;
110			case 'crc32' :
111				$file = "PK\x03\x04\x14\x00\x00\x00" . pack('v', $compmethod) .
112						$mtime .
113						pack("VVVvv", $crc32 + 1, $complength, $uncomplength, strlen($filename), 0x00) .
114						$filename .
115						$data;
116				break;
117			case 'complength' :
118				$file = "PK\x03\x04\x14\x00\x00\x00" . pack('v', $compmethod) .
119						$mtime .
120						pack("VVVvv", $crc32, $complength + 1, $uncomplength, strlen($filename), 0x00) .
121						$filename .
122						$data;
123				break;
124			case 'uncomplength' :
125				$file = "PK\x03\x04\x14\x00\x00\x00" . pack('v', $compmethod) .
126						$mtime .
127						pack("VVVvv", $crc32, $complength, $uncomplength - 1, strlen($filename), 0x00) .
128						$filename .
129						$data;
130				break;
131			case 'filename_len' :
132				$file = "PK\x03\x04\x14\x00\x00\x00" . pack('v', $compmethod) .
133						$mtime .
134						pack("VVVvv", $crc32, $complength, $uncomplength, strlen($filename) - 1, 0x00) .
135						$filename .
136						$data;
137				break;
138			case 'extra_len' :
139				$file = "PK\x03\x04\x14\x00\x00\x00" . pack('v', $compmethod) .
140						$mtime .
141						pack("VVVvv", $crc32, $complength, $uncomplength, strlen($filename), 1) .
142						$filename .
143						$data;
144				break;
145			case 'filename' :
146				$file = "PK\x03\x04\x14\x00\x00\x00" . pack('v', $compmethod) .
147						$mtime .
148						pack("VVVvv", $crc32, $complength, $uncomplength, strlen($filename), 0x00) .
149						substr($filename, 1) .
150						$data;
151				break;
152			case 'data' :
153				$file = "PK\x03\x04\x14\x00\x00\x00" . pack('v', $compmethod) .
154						$mtime .
155						pack("VVVvv", $crc32, $complength, $uncomplength, strlen($filename), 0x00) .
156						$filename .
157						substr($data, 1);
158				break;
159		}
160		return $file;
161	}
162
163	private function getCentralEntry($compmethod, $mtime, $crc32, $complength, $uncomplength, $filename, $comment, $corrupt, &$offset, $fakecomp)
164	{
165		settype($comment, 'string');
166		switch ($corrupt) {
167			case null :
168				$central = "PK\x01\x02\x00\x00\x14\x00\x00\x00" . pack('v', $compmethod) .
169						$mtime .
170						pack("VVVvvvvvVV", $crc32, $complength, $uncomplength, strlen($filename), 0x00,strlen($comment),0x00,0x00,
171							0x0000, $this->offset).
172						$filename . $comment;
173				$offset = strlen($central);
174				break;
175			case 'encrypt' :
176				$central = "PK\x01\x02\x00\x00\x14\x00\x01\x00" . pack('v', $compmethod) .
177						$mtime .
178						pack("VVVvvvvvVV", $crc32, $complength, $uncomplength, strlen($filename), 0x00,strlen($comment),0x00,0x00,
179							0x0000, $this->offset).
180						$filename . $comment;
181				$offset = strlen($central);
182				break;
183			case 'compress' :
184				$central = "PK\x01\x02\x00\x00\x14\x00\x00\x00" . pack('v', $fakecomp) .
185						$mtime .
186						pack("VVVvvvvvVV", $crc32, $complength, $uncomplength, strlen($filename), 0x00,strlen($comment),0x00,0x00,
187							0x0000, $this->offset).
188						$filename . $comment;
189				$offset = strlen($central);
190				break;
191			case 'crc32' :
192				$central = "PK\x01\x02\x00\x00\x14\x00\x00\x00" . pack('v', $compmethod) .
193						$mtime .
194						pack("VVVvvvvvVV", $crc32 + 1, $complength, $uncomplength, strlen($filename), 0x00,strlen($comment),0x00,0x00,
195							0x0000, $this->offset).
196						$filename . $comment;
197				$offset = strlen($central);
198				break;
199			case 'complength' :
200				$central = "PK\x01\x02\x00\x00\x14\x00\x00\x00" . pack('v', $compmethod) .
201						$mtime .
202						pack("VVVvvvvvVV", $crc32, $complength - 1, $uncomplength, strlen($filename), 0x00,strlen($comment),0x00,0x00,
203							0x0000, $this->offset).
204						$filename . $comment;
205				$offset = strlen($central);
206				break;
207			case 'uncomplength' :
208				$central = "PK\x01\x02\x00\x00\x14\x00\x00\x00" . pack('v', $compmethod) .
209						$mtime .
210						pack("VVVvvvvvVV", $crc32, $complength, $uncomplength - 1, strlen($filename), 0x00,strlen($comment),0x00,0x00,
211							0x0000, $this->offset).
212						$filename . $comment;
213				$offset = strlen($central);
214				break;
215			case 'filename_len' :
216				$central = "PK\x01\x02\x00\x00\x14\x00\x00\x00" . pack('v', $compmethod) .
217						$mtime .
218						pack("VVVvvvvvVV", $crc32, $complength, $uncomplength, strlen($filename) - 1, 0x00,strlen($comment),0x00,0x00,
219							0x0000, $this->offset).
220						$filename . $comment;
221				$offset = strlen($central);
222				break;
223			case 'offset' :
224				$central = "PK\x01\x02\x00\x00\x14\x00\x00\x00" . pack('v', $compmethod) .
225						$mtime .
226						pack("VVVvvvvvVV", $crc32, $complength, $uncomplength, strlen($filename), 0x00,strlen($comment),0x00,0x00,
227							0x0000, $this->offset - 1).
228						$filename . $comment;
229				$offset = strlen($central) - 1;
230				break;
231			case 'comment' :
232				$central = "PK\x01\x02\x00\x00\x14\x00\x00\x00" . pack('v', $compmethod) .
233						$mtime .
234						pack("VVVvvvvvVV", $crc32, $complength, $uncomplength, strlen($filename), 0x00,strlen($comment) + 1,0x00,0x00,
235							0x0000, $this->offset).
236						$filename . $comment;
237				$offset = strlen($central);
238				break;
239			case 'extralen1' :
240				$extra = 'nu' . 0xffff; // way huge size
241				$central = "PK\x01\x02\x00\x00\x14\x00\x00\x00" . pack('v', $compmethod) .
242						$mtime .
243						pack("VVVvvvvvVV", $crc32, $complength, $uncomplength, strlen($filename), strlen($extra),strlen($comment),0x00,0x00,
244							0x0000, $this->offset).
245						$filename . $extra . $comment;
246				$offset = strlen($central);
247				break;
248		}
249		return $central;
250	}
251
252	function addFile($filename, $mtime, $data, $comment = null, $compress = null, $filecorrupt = null, $centralcorrupt = null, $fakecomp = 1)
253	{
254		$mtime = $this->getMTime($mtime ? $mtime : null);
255
256		$uncomplength = strlen($data);
257		$crc32 = crc32($data) & 0xFFFFFFFF;
258		$compmethod = 0;
259		switch ($compress) {
260			case 'gz' :
261				$data = gzcompress($data);
262				$compmethod = 8;
263				break;
264			case 'bz2' :
265				$data = bzcompress($data);
266				$compmethod = 12;
267				break;
268		}
269		$complength = strlen($data);
270
271		$this->start .= ($file = $this->getFileEntry($compmethod, $mtime, $crc32, $complength, $uncomplength, $filename, $data, $filecorrupt, $fakecomp));
272
273		$offset = 0;
274		$this->central .= $this->getCentralEntry($compmethod, $mtime, $crc32, $complength, $uncomplength, $filename, $comment, $centralcorrupt, $offset, $fakecomp);
275
276		$this->offset += $offset;
277		$this->count++;
278	}
279
280	function writeZip($zipfile, $corrupt = null)
281	{
282		$write = $this->start . $this->central;
283		switch ($corrupt) {
284			case null :
285				$write .= "PK\x05\x06\x00\x00\x00\x00" .
286					pack("vvVVv", $this->count, $this->count,
287					$this->offset, strlen($this->start),
288					strlen($this->comment)) . $this->comment;
289				break;
290			case 'disknumber' :
291				$write .= "PK\x05\x06\x01\x00\x01\x00" .
292					pack("vvVVv", $this->count, $this->count,
293					$this->offset, strlen($this->start),
294					strlen($this->comment)) . $this->comment;
295				break;
296			case 'count1' :
297				$write .= "PK\x05\x06\x00\x00\x00\x00" .
298					pack("vvVVv", $this->count + 1, $this->count,
299					$this->offset, strlen($this->start),
300					strlen($this->comment)) . $this->comment;
301				break;
302			case 'count2' :
303				$write .= "PK\x05\x06\x00\x00\x00\x00" .
304					pack("vvVVv", $this->count, $this->count + 1,
305					$this->offset, strlen($this->start),
306					strlen($this->comment)) . $this->comment;
307				break;
308			case 'cdir_offset' :
309				$write .= "PK\x05\x06\x00\x00\x00\x00" .
310					pack("vvVVv", $this->count, $this->count,
311					$this->offset, strlen($this->start) - 3,
312					strlen($this->comment)) . $this->comment;
313				break;
314			case 'cdir_len' :
315				$write .= "PK\x05\x06\x00\x00\x00\x00" .
316					pack("vvVVv", $this->count, $this->count,
317					$this->offset - 5, strlen($this->start),
318					strlen($this->comment)) . $this->comment;
319				break;
320			case 'comment' :
321				$write .= "PK\x05\x06\x00\x00\x00\x00" .
322					pack("vvVVv", $this->count, $this->count,
323					strlen($this->start), $this->offset + 1,
324					strlen($this->comment) + 1) . $this->comment;
325				break;
326			case 'none' :
327		}
328		file_put_contents($zipfile, $write);
329	}
330}
331?>
332