|
1
|
|
|
<?php |
|
2
|
|
|
/** |
|
3
|
|
|
* @copyright Copyright (c) 2016, ownCloud, Inc. |
|
4
|
|
|
* |
|
5
|
|
|
* @author Arthur Schiwon <[email protected]> |
|
6
|
|
|
* @author Bart Visscher <[email protected]> |
|
7
|
|
|
* @author Björn Schießle <[email protected]> |
|
8
|
|
|
* @author Clark Tomlinson <[email protected]> |
|
9
|
|
|
* @author Frank Karlitschek <[email protected]> |
|
10
|
|
|
* @author Jakob Sack <[email protected]> |
|
11
|
|
|
* @author Joas Schilling <[email protected]> |
|
12
|
|
|
* @author Jörn Friedrich Dreyer <[email protected]> |
|
13
|
|
|
* @author Ko- <[email protected]> |
|
14
|
|
|
* @author Lukas Reschke <[email protected]> |
|
15
|
|
|
* @author Michael Gapczynski <[email protected]> |
|
16
|
|
|
* @author Nicolai Ehemann <[email protected]> |
|
17
|
|
|
* @author noveens <[email protected]> |
|
18
|
|
|
* @author Piotr Filiciak <[email protected]> |
|
19
|
|
|
* @author Robin Appelman <[email protected]> |
|
20
|
|
|
* @author Robin McCorkell <[email protected]> |
|
21
|
|
|
* @author Thibaut GRIDEL <[email protected]> |
|
22
|
|
|
* @author Thomas Müller <[email protected]> |
|
23
|
|
|
* @author Victor Dubiniuk <[email protected]> |
|
24
|
|
|
* @author Vincent Petry <[email protected]> |
|
25
|
|
|
* |
|
26
|
|
|
* @license AGPL-3.0 |
|
27
|
|
|
* |
|
28
|
|
|
* This code is free software: you can redistribute it and/or modify |
|
29
|
|
|
* it under the terms of the GNU Affero General Public License, version 3, |
|
30
|
|
|
* as published by the Free Software Foundation. |
|
31
|
|
|
* |
|
32
|
|
|
* This program is distributed in the hope that it will be useful, |
|
33
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
34
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
35
|
|
|
* GNU Affero General Public License for more details. |
|
36
|
|
|
* |
|
37
|
|
|
* You should have received a copy of the GNU Affero General Public License, version 3, |
|
38
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/> |
|
39
|
|
|
* |
|
40
|
|
|
*/ |
|
41
|
|
|
|
|
42
|
|
|
use OC\Files\View; |
|
43
|
|
|
use OC\Streamer; |
|
44
|
|
|
use OCP\ILogger; |
|
45
|
|
|
use OCP\Lock\ILockingProvider; |
|
46
|
|
|
|
|
47
|
|
|
/** |
|
48
|
|
|
* Class for file server access |
|
49
|
|
|
* |
|
50
|
|
|
*/ |
|
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) { |
|
363
|
|
|
if (!is_array($files)) { |
|
364
|
|
|
$file = $dir . '/' . $files; |
|
365
|
|
|
$files = [$file]; |
|
366
|
|
|
} |
|
367
|
|
|
foreach ($files as $file) { |
|
368
|
|
|
$file = $dir . '/' . $file; |
|
369
|
|
|
$view->lockFile($file, ILockingProvider::LOCK_SHARED); |
|
370
|
|
|
if ($view->is_dir($file)) { |
|
371
|
|
|
$contents = $view->getDirectoryContent($file); |
|
372
|
|
|
$contents = array_map(function($fileInfo) use ($file) { |
|
373
|
|
|
/** @var \OCP\Files\FileInfo $fileInfo */ |
|
374
|
|
|
return $file . '/' . $fileInfo->getName(); |
|
375
|
|
|
}, $contents); |
|
376
|
|
|
self::lockFiles($view, $dir, $contents); |
|
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 = []) { |
|
389
|
|
|
//don't allow user to break his config |
|
390
|
|
|
$size = (int)$size; |
|
391
|
|
|
if ($size < self::UPLOAD_MIN_LIMIT_BYTES) { |
|
392
|
|
|
return false; |
|
393
|
|
|
} |
|
394
|
|
|
$size = OC_Helper::phpFileSize($size); |
|
395
|
|
|
|
|
396
|
|
|
$phpValueKeys = array( |
|
397
|
|
|
'upload_max_filesize', |
|
398
|
|
|
'post_max_size' |
|
399
|
|
|
); |
|
400
|
|
|
|
|
401
|
|
|
// default locations if not overridden by $files |
|
402
|
|
|
$files = array_merge([ |
|
403
|
|
|
'.htaccess' => OC::$SERVERROOT . '/.htaccess', |
|
404
|
|
|
'.user.ini' => OC::$SERVERROOT . '/.user.ini' |
|
405
|
|
|
], $files); |
|
406
|
|
|
|
|
407
|
|
|
$updateFiles = [ |
|
408
|
|
|
$files['.htaccess'] => [ |
|
409
|
|
|
'pattern' => '/php_value %1$s (\S)*/', |
|
410
|
|
|
'setting' => 'php_value %1$s %2$s' |
|
411
|
|
|
], |
|
412
|
|
|
$files['.user.ini'] => [ |
|
413
|
|
|
'pattern' => '/%1$s=(\S)*/', |
|
414
|
|
|
'setting' => '%1$s=%2$s' |
|
415
|
|
|
] |
|
416
|
|
|
]; |
|
417
|
|
|
|
|
418
|
|
|
$success = true; |
|
419
|
|
|
|
|
420
|
|
|
foreach ($updateFiles as $filename => $patternMap) { |
|
421
|
|
|
// suppress warnings from fopen() |
|
422
|
|
|
$handle = @fopen($filename, 'r+'); |
|
423
|
|
|
if (!$handle) { |
|
424
|
|
|
\OCP\Util::writeLog('files', |
|
|
|
|
|
|
425
|
|
|
'Can\'t write upload limit to ' . $filename . '. Please check the file permissions', |
|
426
|
|
|
ILogger::WARN); |
|
427
|
|
|
$success = false; |
|
428
|
|
|
continue; // try to update as many files as possible |
|
429
|
|
|
} |
|
430
|
|
|
|
|
431
|
|
|
$content = ''; |
|
432
|
|
|
while (!feof($handle)) { |
|
433
|
|
|
$content .= fread($handle, 1000); |
|
434
|
|
|
} |
|
435
|
|
|
|
|
436
|
|
|
foreach ($phpValueKeys as $key) { |
|
437
|
|
|
$pattern = vsprintf($patternMap['pattern'], [$key]); |
|
438
|
|
|
$setting = vsprintf($patternMap['setting'], [$key, $size]); |
|
439
|
|
|
$hasReplaced = 0; |
|
440
|
|
|
$newContent = preg_replace($pattern, $setting, $content, 2, $hasReplaced); |
|
441
|
|
|
if ($newContent !== null) { |
|
442
|
|
|
$content = $newContent; |
|
443
|
|
|
} |
|
444
|
|
|
if ($hasReplaced === 0) { |
|
445
|
|
|
$content .= "\n" . $setting; |
|
446
|
|
|
} |
|
447
|
|
|
} |
|
448
|
|
|
|
|
449
|
|
|
// write file back |
|
450
|
|
|
ftruncate($handle, 0); |
|
451
|
|
|
rewind($handle); |
|
452
|
|
|
fwrite($handle, $content); |
|
453
|
|
|
|
|
454
|
|
|
fclose($handle); |
|
455
|
|
|
} |
|
456
|
|
|
|
|
457
|
|
|
if ($success) { |
|
458
|
|
|
return OC_Helper::computerFileSize($size); |
|
459
|
|
|
} |
|
460
|
|
|
return false; |
|
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) { |
|
471
|
|
|
if ($getType === self::FILE) { |
|
472
|
|
|
$view->unlockFile($filename, ILockingProvider::LOCK_SHARED); |
|
473
|
|
|
} |
|
474
|
|
|
if ($getType === self::ZIP_FILES) { |
|
475
|
|
|
foreach ($files as $file) { |
|
476
|
|
|
$file = $dir . '/' . $file; |
|
477
|
|
|
$view->unlockFile($file, ILockingProvider::LOCK_SHARED); |
|
478
|
|
|
} |
|
479
|
|
|
} |
|
480
|
|
|
if ($getType === self::ZIP_DIR) { |
|
481
|
|
|
$file = $dir . '/' . $files; |
|
482
|
|
|
$view->unlockFile($file, ILockingProvider::LOCK_SHARED); |
|
483
|
|
|
} |
|
484
|
|
|
} |
|
485
|
|
|
|
|
486
|
|
|
} |
|
487
|
|
|
|