Completed
Push — master ( a72e6a...adf7e7 )
by Lukas
08:39
created

ZIP   A

Complexity

Total Complexity 35

Size/Duplication

Total Lines 199
Duplicated Lines 2.01 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 35
c 1
b 0
f 0
lcom 1
cbo 4
dl 4
loc 199
rs 9

16 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 8 2
A addFolder() 0 3 1
B addFile() 0 12 5
A rename() 0 5 1
A filesize() 0 4 1
A mtime() 0 3 1
B getFolder() 0 13 5
A getFiles() 0 8 2
A getFile() 0 3 1
A extractFile() 0 4 1
A extract() 0 3 1
A fileExists() 0 3 2
A remove() 0 7 2
B getStream() 0 21 5
A writeBack() 4 6 2
A stripPath() 0 7 3

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
/**
3
 * @author Bart Visscher <[email protected]>
4
 * @author Christopher Schäpers <[email protected]>
5
 * @author Felix Moeller <[email protected]>
6
 * @author Frank Karlitschek <[email protected]>
7
 * @author Joas Schilling <[email protected]>
8
 * @author Jörn Friedrich Dreyer <[email protected]>
9
 * @author Morris Jobke <[email protected]>
10
 * @author Robin Appelman <[email protected]>
11
 * @author Thomas Müller <[email protected]>
12
 *
13
 * @copyright Copyright (c) 2016, ownCloud, Inc.
14
 * @license AGPL-3.0
15
 *
16
 * This code is free software: you can redistribute it and/or modify
17
 * it under the terms of the GNU Affero General Public License, version 3,
18
 * as published by the Free Software Foundation.
19
 *
20
 * This program is distributed in the hope that it will be useful,
21
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23
 * GNU Affero General Public License for more details.
24
 *
25
 * You should have received a copy of the GNU Affero General Public License, version 3,
26
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
27
 *
28
 */
29
30
namespace OC\Archive;
31
32
class ZIP extends Archive{
33
	/**
34
	 * @var \ZipArchive zip
35
	 */
36
	private $zip=null;
37
	private $path;
38
39
	/**
40
	 * @param string $source
41
	 */
42
	function __construct($source) {
43
		$this->path=$source;
44
		$this->zip=new \ZipArchive();
45
		if($this->zip->open($source, \ZipArchive::CREATE)) {
46
		}else{
47
			\OCP\Util::writeLog('files_archive', 'Error while opening archive '.$source, \OCP\Util::WARN);
48
		}
49
	}
50
	/**
51
	 * add an empty folder to the archive
52
	 * @param string $path
53
	 * @return bool
54
	 */
55
	function addFolder($path) {
56
		return $this->zip->addEmptyDir($path);
57
	}
58
	/**
59
	 * add a file to the archive
60
	 * @param string $path
61
	 * @param string $source either a local file or string data
62
	 * @return bool
63
	 */
64
	function addFile($path, $source='') {
65
		if($source and $source[0]=='/' and file_exists($source)) {
66
			$result=$this->zip->addFile($source, $path);
67
		}else{
68
			$result=$this->zip->addFromString($path, $source);
69
		}
70
		if($result) {
71
			$this->zip->close();//close and reopen to save the zip
72
			$this->zip->open($this->path);
73
		}
74
		return $result;
75
	}
76
	/**
77
	 * rename a file or folder in the archive
78
	 * @param string $source
79
	 * @param string $dest
80
	 * @return boolean|null
81
	 */
82
	function rename($source, $dest) {
83
		$source=$this->stripPath($source);
84
		$dest=$this->stripPath($dest);
85
		$this->zip->renameName($source, $dest);
86
	}
87
	/**
88
	 * get the uncompressed size of a file in the archive
89
	 * @param string $path
90
	 * @return int
91
	 */
92
	function filesize($path) {
93
		$stat=$this->zip->statName($path);
94
		return $stat['size'];
95
	}
96
	/**
97
	 * get the last modified time of a file in the archive
98
	 * @param string $path
99
	 * @return int
100
	 */
101
	function mtime($path) {
102
		return filemtime($this->path);
103
	}
104
	/**
105
	 * get the files in a folder
106
	 * @param string $path
107
	 * @return array
108
	 */
109
	function getFolder($path) {
110
		$files=$this->getFiles();
111
		$folderContent=array();
112
		$pathLength=strlen($path);
113
		foreach($files as $file) {
114
			if(substr($file, 0, $pathLength)==$path and $file!=$path) {
115
				if(strrpos(substr($file, 0, -1), '/')<=$pathLength) {
116
					$folderContent[]=substr($file, $pathLength);
117
				}
118
			}
119
		}
120
		return $folderContent;
121
	}
122
	/**
123
	 * get all files in the archive
124
	 * @return array
125
	 */
126
	function getFiles() {
127
		$fileCount=$this->zip->numFiles;
128
		$files=array();
129
		for($i=0;$i<$fileCount;$i++) {
130
			$files[]=$this->zip->getNameIndex($i);
131
		}
132
		return $files;
133
	}
134
	/**
135
	 * get the content of a file
136
	 * @param string $path
137
	 * @return string
138
	 */
139
	function getFile($path) {
140
		return $this->zip->getFromName($path);
141
	}
142
	/**
143
	 * extract a single file from the archive
144
	 * @param string $path
145
	 * @param string $dest
146
	 * @return boolean|null
147
	 */
148
	function extractFile($path, $dest) {
149
		$fp = $this->zip->getStream($path);
150
		file_put_contents($dest, $fp);
151
	}
152
	/**
153
	 * extract the archive
154
	 * @param string $dest
155
	 * @return bool
156
	 */
157
	function extract($dest) {
158
		return $this->zip->extractTo($dest);
159
	}
160
	/**
161
	 * check if a file or folder exists in the archive
162
	 * @param string $path
163
	 * @return bool
164
	 */
165
	function fileExists($path) {
166
		return ($this->zip->locateName($path)!==false) or ($this->zip->locateName($path.'/')!==false);
167
	}
168
	/**
169
	 * remove a file or folder from the archive
170
	 * @param string $path
171
	 * @return bool
172
	 */
173
	function remove($path) {
174
		if($this->fileExists($path.'/')) {
175
			return $this->zip->deleteName($path.'/');
176
		}else{
177
			return $this->zip->deleteName($path);
178
		}
179
	}
180
	/**
181
	 * get a file handler
182
	 * @param string $path
183
	 * @param string $mode
184
	 * @return resource
185
	 */
186
	function getStream($path, $mode) {
187
		if($mode=='r' or $mode=='rb') {
188
			return $this->zip->getStream($path);
189
		} else {
190
			//since we can't directly get a writable stream,
191
			//make a temp copy of the file and put it back
192
			//in the archive when the stream is closed
193
			if(strrpos($path, '.')!==false) {
194
				$ext=substr($path, strrpos($path, '.'));
195
			}else{
196
				$ext='';
197
			}
198
			$tmpFile=\OCP\Files::tmpFile($ext);
199
			\OC\Files\Stream\Close::registerCallback($tmpFile, array($this, 'writeBack'));
200
			if($this->fileExists($path)) {
201
				$this->extractFile($path, $tmpFile);
202
			}
203
			self::$tempFiles[$tmpFile]=$path;
204
			return fopen('close://'.$tmpFile, $mode);
205
		}
206
	}
207
208
	private static $tempFiles=array();
209
	/**
210
	 * write back temporary files
211
	 */
212
	function writeBack($tmpFile) {
213 View Code Duplication
		if(isset(self::$tempFiles[$tmpFile])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
214
			$this->addFile(self::$tempFiles[$tmpFile], $tmpFile);
215
			unlink($tmpFile);
216
		}
217
	}
218
219
	/**
220
	 * @param string $path
221
	 * @return string
222
	 */
223
	private function stripPath($path) {
224
		if(!$path || $path[0]=='/') {
225
			return substr($path, 1);
226
		}else{
227
			return $path;
228
		}
229
	}
230
}
231