| Total Complexity | 77 | 
| Total Lines | 432 | 
| Duplicated Lines | 0 % | 
| Changes | 0 | ||
Complex classes like OC_Files often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use OC_Files, and based on these observations, apply Extract Interface, too.
| 1 | <?php  | 
            ||
| 51 | class OC_Files { | 
            ||
| 52 | const FILE = 1;  | 
            ||
| 53 | const ZIP_FILES = 2;  | 
            ||
| 54 | const ZIP_DIR = 3;  | 
            ||
| 55 | |||
| 56 | const UPLOAD_MIN_LIMIT_BYTES = 1048576; // 1 MiB  | 
            ||
| 57 | |||
| 58 | |||
| 59 | private static $multipartBoundary = '';  | 
            ||
| 60 | |||
| 61 | /**  | 
            ||
| 62 | * @return string  | 
            ||
| 63 | */  | 
            ||
| 64 | 	private static function getBoundary() { | 
            ||
| 65 | 		if (empty(self::$multipartBoundary)) { | 
            ||
| 66 | self::$multipartBoundary = md5(mt_rand());  | 
            ||
| 67 | }  | 
            ||
| 68 | return self::$multipartBoundary;  | 
            ||
| 69 | }  | 
            ||
| 70 | |||
| 71 | /**  | 
            ||
| 72 | * @param string $filename  | 
            ||
| 73 | * @param string $name  | 
            ||
| 74 | 	 * @param array $rangeArray ('from'=>int,'to'=>int), ... | 
            ||
| 75 | */  | 
            ||
| 76 | 	private static function sendHeaders($filename, $name, array $rangeArray) { | 
            ||
| 77 | OC_Response::setContentDispositionHeader($name, 'attachment');  | 
            ||
| 78 | 		header('Content-Transfer-Encoding: binary', true); | 
            ||
| 79 | 		header('Pragma: public');// enable caching in IE | 
            ||
| 80 | 		header('Expires: 0'); | 
            ||
| 81 | 		header("Cache-Control: must-revalidate, post-check=0, pre-check=0"); | 
            ||
| 82 | $fileSize = \OC\Files\Filesystem::filesize($filename);  | 
            ||
| 83 | $type = \OC::$server->getMimeTypeDetector()->getSecureMimeType(\OC\Files\Filesystem::getMimeType($filename));  | 
            ||
| 
                                                                                                    
                        
                         | 
                |||
| 84 | 		if ($fileSize > -1) { | 
            ||
| 85 | 			if (!empty($rangeArray)) { | 
            ||
| 86 | http_response_code(206);  | 
            ||
| 87 | 			    header('Accept-Ranges: bytes', true); | 
            ||
| 88 | 			    if (count($rangeArray) > 1) { | 
            ||
| 89 | $type = 'multipart/byteranges; boundary='.self::getBoundary();  | 
            ||
| 90 | // no Content-Length header here  | 
            ||
| 91 | }  | 
            ||
| 92 | 			    else { | 
            ||
| 93 | 				header(sprintf('Content-Range: bytes %d-%d/%d', $rangeArray[0]['from'], $rangeArray[0]['to'], $fileSize), true); | 
            ||
| 94 | OC_Response::setContentLengthHeader($rangeArray[0]['to'] - $rangeArray[0]['from'] + 1);  | 
            ||
| 95 | }  | 
            ||
| 96 | }  | 
            ||
| 97 | 			else { | 
            ||
| 98 | OC_Response::setContentLengthHeader($fileSize);  | 
            ||
| 99 | }  | 
            ||
| 100 | }  | 
            ||
| 101 | 		header('Content-Type: '.$type, true); | 
            ||
| 102 | }  | 
            ||
| 103 | |||
| 104 | /**  | 
            ||
| 105 | * return the content of a file or return a zip file containing multiple files  | 
            ||
| 106 | *  | 
            ||
| 107 | * @param string $dir  | 
            ||
| 108 | * @param string $files ; separated list of files to download  | 
            ||
| 109 | * @param array $params ; 'head' boolean to only send header of the request ; 'range' http range header  | 
            ||
| 110 | */  | 
            ||
| 111 | 	public static function get($dir, $files, $params = null) { | 
            ||
| 112 | |||
| 113 | $view = \OC\Files\Filesystem::getView();  | 
            ||
| 114 | $getType = self::FILE;  | 
            ||
| 115 | $filename = $dir;  | 
            ||
| 116 | 		try { | 
            ||
| 117 | |||
| 118 | 			if (is_array($files) && count($files) === 1) { | 
            ||
| 119 | $files = $files[0];  | 
            ||
| 120 | }  | 
            ||
| 121 | |||
| 122 | 			if (!is_array($files)) { | 
            ||
| 123 | $filename = $dir . '/' . $files;  | 
            ||
| 124 | 				if (!$view->is_dir($filename)) { | 
            ||
| 125 | self::getSingleFile($view, $dir, $files, is_null($params) ? array() : $params);  | 
            ||
| 126 | return;  | 
            ||
| 127 | }  | 
            ||
| 128 | }  | 
            ||
| 129 | |||
| 130 | $name = 'download';  | 
            ||
| 131 | 			if (is_array($files)) { | 
            ||
| 132 | $getType = self::ZIP_FILES;  | 
            ||
| 133 | $basename = basename($dir);  | 
            ||
| 134 | 				if ($basename) { | 
            ||
| 135 | $name = $basename;  | 
            ||
| 136 | }  | 
            ||
| 137 | |||
| 138 | $filename = $dir . '/' . $name;  | 
            ||
| 139 | 			} else { | 
            ||
| 140 | $filename = $dir . '/' . $files;  | 
            ||
| 141 | $getType = self::ZIP_DIR;  | 
            ||
| 142 | // downloading root ?  | 
            ||
| 143 | 				if ($files !== '') { | 
            ||
| 144 | $name = $files;  | 
            ||
| 145 | }  | 
            ||
| 146 | }  | 
            ||
| 147 | |||
| 148 | self::lockFiles($view, $dir, $files);  | 
            ||
| 149 | |||
| 150 | /* Calculate filesize and number of files */  | 
            ||
| 151 | 			if ($getType === self::ZIP_FILES) { | 
            ||
| 152 | $fileInfos = array();  | 
            ||
| 153 | $fileSize = 0;  | 
            ||
| 154 | 				foreach ($files as $file) { | 
            ||
| 155 | $fileInfo = \OC\Files\Filesystem::getFileInfo($dir . '/' . $file);  | 
            ||
| 156 | $fileSize += $fileInfo->getSize();  | 
            ||
| 157 | $fileInfos[] = $fileInfo;  | 
            ||
| 158 | }  | 
            ||
| 159 | $numberOfFiles = self::getNumberOfFiles($fileInfos);  | 
            ||
| 160 | 			} elseif ($getType === self::ZIP_DIR) { | 
            ||
| 161 | $fileInfo = \OC\Files\Filesystem::getFileInfo($dir . '/' . $files);  | 
            ||
| 162 | $fileSize = $fileInfo->getSize();  | 
            ||
| 163 | $numberOfFiles = self::getNumberOfFiles(array($fileInfo));  | 
            ||
| 164 | }  | 
            ||
| 165 | |||
| 166 | $streamer = new Streamer(\OC::$server->getRequest(), $fileSize, $numberOfFiles);  | 
            ||
| 167 | OC_Util::obEnd();  | 
            ||
| 168 | |||
| 169 | $streamer->sendHeaders($name);  | 
            ||
| 170 | 			$executionTime = (int)OC::$server->getIniWrapper()->getNumeric('max_execution_time'); | 
            ||
| 171 | 			if (strpos(@ini_get('disable_functions'), 'set_time_limit') === false) { | 
            ||
| 172 | @set_time_limit(0);  | 
            ||
| 173 | }  | 
            ||
| 174 | ignore_user_abort(true);  | 
            ||
| 175 | |||
| 176 | 			if ($getType === self::ZIP_FILES) { | 
            ||
| 177 | 				foreach ($files as $file) { | 
            ||
| 178 | $file = $dir . '/' . $file;  | 
            ||
| 179 | 					if (\OC\Files\Filesystem::is_file($file)) { | 
            ||
| 180 | $fileSize = \OC\Files\Filesystem::filesize($file);  | 
            ||
| 181 | $fileTime = \OC\Files\Filesystem::filemtime($file);  | 
            ||
| 182 | $fh = \OC\Files\Filesystem::fopen($file, 'r');  | 
            ||
| 183 | $streamer->addFileFromStream($fh, basename($file), $fileSize, $fileTime);  | 
            ||
| 184 | fclose($fh);  | 
            ||
| 185 | 					} elseif (\OC\Files\Filesystem::is_dir($file)) { | 
            ||
| 186 | $streamer->addDirRecursive($file);  | 
            ||
| 187 | }  | 
            ||
| 188 | }  | 
            ||
| 189 | 			} elseif ($getType === self::ZIP_DIR) { | 
            ||
| 190 | $file = $dir . '/' . $files;  | 
            ||
| 191 | $streamer->addDirRecursive($file);  | 
            ||
| 192 | }  | 
            ||
| 193 | $streamer->finalize();  | 
            ||
| 194 | set_time_limit($executionTime);  | 
            ||
| 195 | self::unlockAllTheFiles($dir, $files, $getType, $view, $filename);  | 
            ||
| 196 | 		} catch (\OCP\Lock\LockedException $ex) { | 
            ||
| 197 | self::unlockAllTheFiles($dir, $files, $getType, $view, $filename);  | 
            ||
| 198 | OC::$server->getLogger()->logException($ex);  | 
            ||
| 199 | 			$l = \OC::$server->getL10N('core'); | 
            ||
| 200 | $hint = method_exists($ex, 'getHint') ? $ex->getHint() : '';  | 
            ||
| 201 | 			\OC_Template::printErrorPage($l->t('File is currently busy, please try again later'), $hint, 200); | 
            ||
| 202 | 		} catch (\OCP\Files\ForbiddenException $ex) { | 
            ||
| 203 | self::unlockAllTheFiles($dir, $files, $getType, $view, $filename);  | 
            ||
| 204 | OC::$server->getLogger()->logException($ex);  | 
            ||
| 205 | 			$l = \OC::$server->getL10N('core'); | 
            ||
| 206 | 			\OC_Template::printErrorPage($l->t('Can\'t read file'), $ex->getMessage(), 200); | 
            ||
| 207 | 		} catch (\Exception $ex) { | 
            ||
| 208 | self::unlockAllTheFiles($dir, $files, $getType, $view, $filename);  | 
            ||
| 209 | OC::$server->getLogger()->logException($ex);  | 
            ||
| 210 | 			$l = \OC::$server->getL10N('core'); | 
            ||
| 211 | $hint = method_exists($ex, 'getHint') ? $ex->getHint() : '';  | 
            ||
| 212 | 			\OC_Template::printErrorPage($l->t('Can\'t read file'), $hint, 200); | 
            ||
| 213 | }  | 
            ||
| 214 | }  | 
            ||
| 215 | |||
| 216 | /**  | 
            ||
| 217 | * @param string $rangeHeaderPos  | 
            ||
| 218 | * @param int $fileSize  | 
            ||
| 219 | 	 * @return array $rangeArray ('from'=>int,'to'=>int), ... | 
            ||
| 220 | */  | 
            ||
| 221 | 	private static function parseHttpRangeHeader($rangeHeaderPos, $fileSize) { | 
            ||
| 222 | 		$rArray=explode(',', $rangeHeaderPos); | 
            ||
| 223 | $minOffset = 0;  | 
            ||
| 224 | $ind = 0;  | 
            ||
| 225 | |||
| 226 | $rangeArray = array();  | 
            ||
| 227 | |||
| 228 | 		foreach ($rArray as $value) { | 
            ||
| 229 | 			$ranges = explode('-', $value); | 
            ||
| 230 | 			if (is_numeric($ranges[0])) { | 
            ||
| 231 | 				if ($ranges[0] < $minOffset) { // case: bytes=500-700,601-999 | 
            ||
| 232 | $ranges[0] = $minOffset;  | 
            ||
| 233 | }  | 
            ||
| 234 | 				if ($ind > 0 && $rangeArray[$ind-1]['to']+1 == $ranges[0]) { // case: bytes=500-600,601-999 | 
            ||
| 235 | $ind--;  | 
            ||
| 236 | $ranges[0] = $rangeArray[$ind]['from'];  | 
            ||
| 237 | }  | 
            ||
| 238 | }  | 
            ||
| 239 | |||
| 240 | 			if (is_numeric($ranges[0]) && is_numeric($ranges[1]) && $ranges[0] < $fileSize && $ranges[0] <= $ranges[1]) { | 
            ||
| 241 | // case: x-x  | 
            ||
| 242 | 				if ($ranges[1] >= $fileSize) { | 
            ||
| 243 | $ranges[1] = $fileSize-1;  | 
            ||
| 244 | }  | 
            ||
| 245 | $rangeArray[$ind++] = array( 'from' => $ranges[0], 'to' => $ranges[1], 'size' => $fileSize );  | 
            ||
| 246 | $minOffset = $ranges[1] + 1;  | 
            ||
| 247 | 				if ($minOffset >= $fileSize) { | 
            ||
| 248 | break;  | 
            ||
| 249 | }  | 
            ||
| 250 | }  | 
            ||
| 251 | 			elseif (is_numeric($ranges[0]) && $ranges[0] < $fileSize) { | 
            ||
| 252 | // case: x-  | 
            ||
| 253 | $rangeArray[$ind++] = array( 'from' => $ranges[0], 'to' => $fileSize-1, 'size' => $fileSize );  | 
            ||
| 254 | break;  | 
            ||
| 255 | }  | 
            ||
| 256 | 			elseif (is_numeric($ranges[1])) { | 
            ||
| 257 | // case: -x  | 
            ||
| 258 | 				if ($ranges[1] > $fileSize) { | 
            ||
| 259 | $ranges[1] = $fileSize;  | 
            ||
| 260 | }  | 
            ||
| 261 | $rangeArray[$ind++] = array( 'from' => $fileSize-$ranges[1], 'to' => $fileSize-1, 'size' => $fileSize );  | 
            ||
| 262 | break;  | 
            ||
| 263 | }  | 
            ||
| 264 | }  | 
            ||
| 265 | return $rangeArray;  | 
            ||
| 266 | }  | 
            ||
| 267 | |||
| 268 | /**  | 
            ||
| 269 | * @param View $view  | 
            ||
| 270 | * @param string $name  | 
            ||
| 271 | * @param string $dir  | 
            ||
| 272 | * @param array $params ; 'head' boolean to only send header of the request ; 'range' http range header  | 
            ||
| 273 | */  | 
            ||
| 274 | 	private static function getSingleFile($view, $dir, $name, $params) { | 
            ||
| 275 | $filename = $dir . '/' . $name;  | 
            ||
| 276 | OC_Util::obEnd();  | 
            ||
| 277 | $view->lockFile($filename, ILockingProvider::LOCK_SHARED);  | 
            ||
| 278 | |||
| 279 | $rangeArray = array();  | 
            ||
| 280 | |||
| 281 | 		if (isset($params['range']) && substr($params['range'], 0, 6) === 'bytes=') { | 
            ||
| 282 | $rangeArray = self::parseHttpRangeHeader(substr($params['range'], 6),  | 
            ||
| 283 | \OC\Files\Filesystem::filesize($filename));  | 
            ||
| 284 | }  | 
            ||
| 285 | |||
| 286 | 		if (\OC\Files\Filesystem::isReadable($filename)) { | 
            ||
| 287 | self::sendHeaders($filename, $name, $rangeArray);  | 
            ||
| 288 | 		} elseif (!\OC\Files\Filesystem::file_exists($filename)) { | 
            ||
| 289 | http_response_code(404);  | 
            ||
| 290 | 			$tmpl = new OC_Template('', '404', 'guest'); | 
            ||
| 291 | $tmpl->printPage();  | 
            ||
| 292 | exit();  | 
            ||
| 293 | 		} else { | 
            ||
| 294 | http_response_code(403);  | 
            ||
| 295 | 			die('403 Forbidden'); | 
            ||
| 296 | }  | 
            ||
| 297 | 		if (isset($params['head']) && $params['head']) { | 
            ||
| 298 | return;  | 
            ||
| 299 | }  | 
            ||
| 300 | 		if (!empty($rangeArray)) { | 
            ||
| 301 | 			try { | 
            ||
| 302 | 			    if (count($rangeArray) == 1) { | 
            ||
| 303 | $view->readfilePart($filename, $rangeArray[0]['from'], $rangeArray[0]['to']);  | 
            ||
| 304 | }  | 
            ||
| 305 | 			    else { | 
            ||
| 306 | // check if file is seekable (if not throw UnseekableException)  | 
            ||
| 307 | // we have to check it before body contents  | 
            ||
| 308 | $view->readfilePart($filename, $rangeArray[0]['size'], $rangeArray[0]['size']);  | 
            ||
| 309 | |||
| 310 | $type = \OC::$server->getMimeTypeDetector()->getSecureMimeType(\OC\Files\Filesystem::getMimeType($filename));  | 
            ||
| 311 | |||
| 312 | 				foreach ($rangeArray as $range) { | 
            ||
| 313 | echo "\r\n--".self::getBoundary()."\r\n".  | 
            ||
| 314 | "Content-type: ".$type."\r\n".  | 
            ||
| 315 | "Content-range: bytes ".$range['from']."-".$range['to']."/".$range['size']."\r\n\r\n";  | 
            ||
| 316 | $view->readfilePart($filename, $range['from'], $range['to']);  | 
            ||
| 317 | }  | 
            ||
| 318 | echo "\r\n--".self::getBoundary()."--\r\n";  | 
            ||
| 319 | }  | 
            ||
| 320 | 			} catch (\OCP\Files\UnseekableException $ex) { | 
            ||
| 321 | // file is unseekable  | 
            ||
| 322 | 			    header_remove('Accept-Ranges'); | 
            ||
| 323 | 			    header_remove('Content-Range'); | 
            ||
| 324 | http_response_code(200);  | 
            ||
| 325 | self::sendHeaders($filename, $name, array());  | 
            ||
| 326 | $view->readfile($filename);  | 
            ||
| 327 | }  | 
            ||
| 328 | }  | 
            ||
| 329 | 		else { | 
            ||
| 330 | $view->readfile($filename);  | 
            ||
| 331 | }  | 
            ||
| 332 | }  | 
            ||
| 333 | |||
| 334 | /**  | 
            ||
| 335 | * Returns the total (recursive) number of files and folders in the given  | 
            ||
| 336 | * FileInfos.  | 
            ||
| 337 | *  | 
            ||
| 338 | * @param \OCP\Files\FileInfo[] $fileInfos the FileInfos to count  | 
            ||
| 339 | * @return int the total number of files and folders  | 
            ||
| 340 | */  | 
            ||
| 341 | 	private static function getNumberOfFiles($fileInfos) { | 
            ||
| 342 | $numberOfFiles = 0;  | 
            ||
| 343 | |||
| 344 | $view = new View();  | 
            ||
| 345 | |||
| 346 | 		while ($fileInfo = array_pop($fileInfos)) { | 
            ||
| 347 | $numberOfFiles++;  | 
            ||
| 348 | |||
| 349 | 			if ($fileInfo->getType() === \OCP\Files\FileInfo::TYPE_FOLDER) { | 
            ||
| 350 | $fileInfos = array_merge($fileInfos, $view->getDirectoryContent($fileInfo->getPath()));  | 
            ||
| 351 | }  | 
            ||
| 352 | }  | 
            ||
| 353 | |||
| 354 | return $numberOfFiles;  | 
            ||
| 355 | }  | 
            ||
| 356 | |||
| 357 | /**  | 
            ||
| 358 | * @param View $view  | 
            ||
| 359 | * @param string $dir  | 
            ||
| 360 | * @param string[]|string $files  | 
            ||
| 361 | */  | 
            ||
| 362 | 	public static function lockFiles($view, $dir, $files) { | 
            ||
| 377 | }  | 
            ||
| 378 | }  | 
            ||
| 379 | }  | 
            ||
| 380 | |||
| 381 | /**  | 
            ||
| 382 | * set the maximum upload size limit for apache hosts using .htaccess  | 
            ||
| 383 | *  | 
            ||
| 384 | * @param int $size file size in bytes  | 
            ||
| 385 | * @param array $files override '.htaccess' and '.user.ini' locations  | 
            ||
| 386 | * @return bool|int false on failure, size on success  | 
            ||
| 387 | */  | 
            ||
| 388 | 	public static function setUploadLimit($size, $files = []) { | 
            ||
| 461 | }  | 
            ||
| 462 | |||
| 463 | /**  | 
            ||
| 464 | * @param string $dir  | 
            ||
| 465 | * @param $files  | 
            ||
| 466 | * @param integer $getType  | 
            ||
| 467 | * @param View $view  | 
            ||
| 468 | * @param string $filename  | 
            ||
| 469 | */  | 
            ||
| 470 | 	private static function unlockAllTheFiles($dir, $files, $getType, $view, $filename) { | 
            ||
| 483 | }  | 
            ||
| 484 | }  | 
            ||
| 485 | |||
| 486 | }  | 
            ||
| 487 |