Blame view

sources/lib/private/files.php 7.79 KB
03e52840d   Kload   Init
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  <?php
  
  /**
   * ownCloud
   *
   * @author Frank Karlitschek
   * @copyright 2012 Frank Karlitschek frank@owncloud.org
   *
   * This library is free software; you can redistribute it and/or
   * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
   * License as published by the Free Software Foundation; either
   * version 3 of the License, or any later version.
   *
   * This library is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
   *
   * You should have received a copy of the GNU Affero General Public
   * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
   *
   */
6d9380f96   Cédric Dupont   Update sources OC...
23
24
25
26
27
28
29
30
  // TODO: get rid of this using proper composer packages
  require_once 'mcnetic/phpzipstreamer/ZipStreamer.php';
  
  class GET_TYPE {
  	const FILE = 1;
  	const ZIP_FILES = 2;
  	const ZIP_DIR = 3;
  }
03e52840d   Kload   Init
31
  /**
6d9380f96   Cédric Dupont   Update sources OC...
32
   * Class for file server access
03e52840d   Kload   Init
33
34
35
   *
   */
  class OC_Files {
03e52840d   Kload   Init
36

6d9380f96   Cédric Dupont   Update sources OC...
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
  	/**
  	 * @param string $filename
  	 * @param string $name
  	 * @param bool $zip
  	 */
  	private static function sendHeaders($filename, $name, $zip = false) {
  		OC_Response::setContentDispositionHeader($name, 'attachment');
  		header('Content-Transfer-Encoding: binary');
  		OC_Response::disableCaching();
  		if ($zip) {
  			header('Content-Type: application/zip');
  		} else {
  			$filesize = \OC\Files\Filesystem::filesize($filename);
  			header('Content-Type: '.\OC\Files\Filesystem::getMimeType($filename));
  			if ($filesize > -1) {
  				header("Content-Length: ".$filesize);
  			}
  		}
03e52840d   Kload   Init
55
56
57
58
59
60
  	}
  
  	/**
  	 * return the content of a file or return a zip file containing multiple files
  	 *
  	 * @param string $dir
6d9380f96   Cédric Dupont   Update sources OC...
61
  	 * @param string $files ; separated list of files to download
03e52840d   Kload   Init
62
63
64
65
66
  	 * @param boolean $only_header ; boolean to only send header of the request
  	 */
  	public static function get($dir, $files, $only_header = false) {
  		$xsendfile = false;
  		if (isset($_SERVER['MOD_X_SENDFILE_ENABLED']) ||
31b7f2792   Kload   Upgrade to ownclo...
67
  			isset($_SERVER['MOD_X_SENDFILE2_ENABLED']) ||
03e52840d   Kload   Init
68
69
70
  			isset($_SERVER['MOD_X_ACCEL_REDIRECT_ENABLED'])) {
  			$xsendfile = true;
  		}
6d9380f96   Cédric Dupont   Update sources OC...
71
  		if (is_array($files) && count($files) === 1) {
03e52840d   Kload   Init
72
73
74
75
  			$files = $files[0];
  		}
  
  		if (is_array($files)) {
6d9380f96   Cédric Dupont   Update sources OC...
76
  			$get_type = GET_TYPE::ZIP_FILES;
03e52840d   Kload   Init
77
78
79
80
  			$basename = basename($dir);
  			if ($basename) {
  				$name = $basename . '.zip';
  			} else {
a293d369c   Kload   Update sources to...
81
  				$name = 'download.zip';
03e52840d   Kload   Init
82
  			}
6d9380f96   Cédric Dupont   Update sources OC...
83
84
  
  			$filename = $dir . '/' . $name;
03e52840d   Kload   Init
85
  		} else {
03e52840d   Kload   Init
86
  			$filename = $dir . '/' . $files;
6d9380f96   Cédric Dupont   Update sources OC...
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
  			if (\OC\Files\Filesystem::is_dir($dir . '/' . $files)) {
  				$get_type = GET_TYPE::ZIP_DIR;
  				// downloading root ?
  				if ($files === '') {
  					$name = 'download.zip';
  				} else {
  					$name = $files . '.zip';
  				}
  
  			} else {
  				$get_type = GET_TYPE::FILE;
  				$name = $files;
  			}
  		}
  
  		if ($get_type === GET_TYPE::FILE) {
  			$zip = false;
31b7f2792   Kload   Upgrade to ownclo...
104
105
106
  			if ($xsendfile && OC_App::isEnabled('files_encryption')) {
  				$xsendfile = false;
  			}
6d9380f96   Cédric Dupont   Update sources OC...
107
108
  		} else {
  			$zip = new ZipStreamer(false);
03e52840d   Kload   Init
109
110
111
  		}
  		OC_Util::obEnd();
  		if ($zip or \OC\Files\Filesystem::isReadable($filename)) {
6d9380f96   Cédric Dupont   Update sources OC...
112
113
  			self::sendHeaders($filename, $name, $zip);
  		} elseif (!\OC\Files\Filesystem::file_exists($filename)) {
03e52840d   Kload   Init
114
115
116
117
118
119
120
121
122
123
124
125
  			header("HTTP/1.0 404 Not Found");
  			$tmpl = new OC_Template('', '404', 'guest');
  			$tmpl->assign('file', $name);
  			$tmpl->printPage();
  		} else {
  			header("HTTP/1.0 403 Forbidden");
  			die('403 Forbidden');
  		}
  		if($only_header) {
  			return ;
  		}
  		if ($zip) {
6d9380f96   Cédric Dupont   Update sources OC...
126
127
128
129
130
131
132
133
134
135
136
137
  			$executionTime = intval(ini_get('max_execution_time'));
  			set_time_limit(0);
  			if ($get_type === GET_TYPE::ZIP_FILES) {
  				foreach ($files as $file) {
  					$file = $dir . '/' . $file;
  					if (\OC\Files\Filesystem::is_file($file)) {
  						$fh = \OC\Files\Filesystem::fopen($file, 'r');
  						$zip->addFileFromStream($fh, basename($file));
  						fclose($fh);
  					} elseif (\OC\Files\Filesystem::is_dir($file)) {
  						self::zipAddDir($file, $zip);
  					}
03e52840d   Kload   Init
138
  				}
6d9380f96   Cédric Dupont   Update sources OC...
139
140
141
  			} elseif ($get_type === GET_TYPE::ZIP_DIR) {
  				$file = $dir . '/' . $files;
  				self::zipAddDir($file, $zip);
03e52840d   Kload   Init
142
  			}
6d9380f96   Cédric Dupont   Update sources OC...
143
144
145
146
147
148
149
150
151
152
153
154
155
156
  			$zip->finalize();
  			set_time_limit($executionTime);
  		} else {
  			if ($xsendfile) {
  				$view = \OC\Files\Filesystem::getView();
  				/** @var $storage \OC\Files\Storage\Storage */
  				list($storage) = $view->resolvePath($filename);
  				if ($storage->isLocal()) {
  					self::addSendfileHeader($filename);
  				} else {
  					\OC\Files\Filesystem::readfile($filename);
  				}
  			} else {
  				\OC\Files\Filesystem::readfile($filename);
03e52840d   Kload   Init
157
158
159
  			}
  		}
  	}
6d9380f96   Cédric Dupont   Update sources OC...
160
161
162
  	/**
  	 * @param false|string $filename
  	 */
03e52840d   Kload   Init
163
164
  	private static function addSendfileHeader($filename) {
  		if (isset($_SERVER['MOD_X_SENDFILE_ENABLED'])) {
6d9380f96   Cédric Dupont   Update sources OC...
165
  			$filename = \OC\Files\Filesystem::getLocalFile($filename);
03e52840d   Kload   Init
166
  			header("X-Sendfile: " . $filename);
31b7f2792   Kload   Upgrade to ownclo...
167
168
   		}
   		if (isset($_SERVER['MOD_X_SENDFILE2_ENABLED'])) {
6d9380f96   Cédric Dupont   Update sources OC...
169
170
  			$filename = \OC\Files\Filesystem::getLocalFile($filename);
  			if (isset($_SERVER['HTTP_RANGE']) &&
31b7f2792   Kload   Upgrade to ownclo...
171
172
  				preg_match("/^bytes=([0-9]+)-([0-9]*)$/", $_SERVER['HTTP_RANGE'], $range)) {
  				$filelength = filesize($filename);
6d9380f96   Cédric Dupont   Update sources OC...
173
   				if ($range[2] === "") {
31b7f2792   Kload   Upgrade to ownclo...
174
175
176
177
178
179
180
181
   					$range[2] = $filelength - 1;
   				}
   				header("Content-Range: bytes $range[1]-$range[2]/" . $filelength);
   				header("HTTP/1.1 206 Partial content");
   				header("X-Sendfile2: " . str_replace(",", "%2c", rawurlencode($filename)) . " $range[1]-$range[2]");
   			} else {
   				header("X-Sendfile: " . $filename);
   			}
03e52840d   Kload   Init
182
  		}
6d9380f96   Cédric Dupont   Update sources OC...
183

03e52840d   Kload   Init
184
  		if (isset($_SERVER['MOD_X_ACCEL_REDIRECT_ENABLED'])) {
6d9380f96   Cédric Dupont   Update sources OC...
185
  			$filename = \OC::$WEBROOT . '/data' . \OC\Files\Filesystem::getRoot() . $filename;
03e52840d   Kload   Init
186
187
188
  			header("X-Accel-Redirect: " . $filename);
  		}
  	}
6d9380f96   Cédric Dupont   Update sources OC...
189
190
191
192
193
  	/**
  	 * @param string $dir
  	 * @param ZipStreamer $zip
  	 * @param string $internalDir
  	 */
03e52840d   Kload   Init
194
195
  	public static function zipAddDir($dir, $zip, $internalDir='') {
  		$dirname=basename($dir);
6d9380f96   Cédric Dupont   Update sources OC...
196
197
198
199
  		$rootDir = $internalDir.$dirname;
  		if (!empty($rootDir)) {
  			$zip->addEmptyDir($rootDir);
  		}
03e52840d   Kload   Init
200
  		$internalDir.=$dirname.='/';
6d9380f96   Cédric Dupont   Update sources OC...
201
202
203
204
  		// prevent absolute dirs
  		$internalDir = ltrim($internalDir, '/');
  
  		$files=\OC\Files\Filesystem::getDirectoryContent($dir);
03e52840d   Kload   Init
205
206
207
208
  		foreach($files as $file) {
  			$filename=$file['name'];
  			$file=$dir.'/'.$filename;
  			if(\OC\Files\Filesystem::is_file($file)) {
6d9380f96   Cédric Dupont   Update sources OC...
209
210
211
  				$fh = \OC\Files\Filesystem::fopen($file, 'r');
  				$zip->addFileFromStream($fh, $internalDir.$filename);
  				fclose($fh);
03e52840d   Kload   Init
212
213
214
215
216
217
218
  			}elseif(\OC\Files\Filesystem::is_dir($file)) {
  				self::zipAddDir($file, $zip, $internalDir);
  			}
  		}
  	}
  
  	/**
03e52840d   Kload   Init
219
220
  	 * set the maximum upload size limit for apache hosts using .htaccess
  	 *
6d9380f96   Cédric Dupont   Update sources OC...
221
222
  	 * @param int $size file size in bytes
  	 * @return bool false on failure, size on success
03e52840d   Kload   Init
223
224
225
226
227
228
229
230
231
  	 */
  	static function setUploadLimit($size) {
  		//don't allow user to break his config -- upper boundary
  		if ($size > PHP_INT_MAX) {
  			//max size is always 1 byte lower than computerFileSize returns
  			if ($size > PHP_INT_MAX + 1)
  				return false;
  			$size -= 1;
  		} else {
6d9380f96   Cédric Dupont   Update sources OC...
232
  			$size = OC_Helper::phpFileSize($size);
03e52840d   Kload   Init
233
234
235
  		}
  
  		//don't allow user to break his config -- broken or malicious size input
6d9380f96   Cédric Dupont   Update sources OC...
236
  		if (intval($size) === 0) {
03e52840d   Kload   Init
237
238
  			return false;
  		}
6d9380f96   Cédric Dupont   Update sources OC...
239
240
  		//suppress errors in case we don't have permissions for
  		$htaccess = @file_get_contents(OC::$SERVERROOT . '/.htaccess');
03e52840d   Kload   Init
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
  		if (!$htaccess) {
  			return false;
  		}
  
  		$phpValueKeys = array(
  			'upload_max_filesize',
  			'post_max_size'
  		);
  
  		foreach ($phpValueKeys as $key) {
  			$pattern = '/php_value ' . $key . ' (\S)*/';
  			$setting = 'php_value ' . $key . ' ' . $size;
  			$hasReplaced = 0;
  			$content = preg_replace($pattern, $setting, $htaccess, 1, $hasReplaced);
  			if ($content !== null) {
  				$htaccess = $content;
  			}
6d9380f96   Cédric Dupont   Update sources OC...
258
  			if ($hasReplaced === 0) {
03e52840d   Kload   Init
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
  				$htaccess .= "
  " . $setting;
  			}
  		}
  
  		//check for write permissions
  		if (is_writable(OC::$SERVERROOT . '/.htaccess')) {
  			file_put_contents(OC::$SERVERROOT . '/.htaccess', $htaccess);
  			return OC_Helper::computerFileSize($size);
  		} else {
  			OC_Log::write('files',
  				'Can\'t write upload limit to ' . OC::$SERVERROOT . '/.htaccess. Please check the file permissions',
  				OC_Log::WARN);
  		}
  		return false;
  	}
  }