Register
phpBB.com Wiki · Home Projects Help

root / trunk / phpBB / includes / functions_transfer.php

1 5375 acydburn
<?php
2 5375 acydburn
/**
3 5375 acydburn
*
4 5375 acydburn
* @package phpBB3
5 5375 acydburn
* @version $Id$
6 5375 acydburn
* @copyright (c) 2005 phpBB Group
7 5375 acydburn
* @license http://opensource.org/licenses/gpl-license.php GNU Public License
8 5375 acydburn
*
9 5375 acydburn
*/
10 5375 acydburn
11 5375 acydburn
/**
12 8146 acydburn
* @ignore
13 8146 acydburn
*/
14 8146 acydburn
if (!defined('IN_PHPBB'))
15 8146 acydburn
{
16 8146 acydburn
	exit;
17 8146 acydburn
}
18 8146 acydburn
19 8146 acydburn
/**
20 6058 acydburn
* Transfer class, wrapper for ftp/sftp/ssh
21 5375 acydburn
* @package phpBB3
22 5375 acydburn
*/
23 5375 acydburn
class transfer
24 5375 acydburn
{
25 5375 acydburn
	var $connection;
26 5375 acydburn
	var $host;
27 5375 acydburn
	var $port;
28 5375 acydburn
	var $username;
29 5375 acydburn
	var $password;
30 5375 acydburn
	var $timeout;
31 5375 acydburn
	var $root_path;
32 5375 acydburn
	var $tmp_path;
33 5375 acydburn
	var $file_perms;
34 5375 acydburn
	var $dir_perms;
35 5375 acydburn
36 5375 acydburn
	/**
37 5375 acydburn
	* Constructor - init some basic values
38 5375 acydburn
	*/
39 8295 davidmj
	function __construct()
40 5375 acydburn
	{
41 7241 acydburn
		$this->file_perms	= 0644;
42 7241 acydburn
		$this->dir_perms	= 0777;
43 5375 acydburn
44 5375 acydburn
		// We use the store directory as temporary path to circumvent open basedir restrictions
45 8572 acydburn
		$this->tmp_path = PHPBB_ROOT_PATH . 'store/';
46 5375 acydburn
	}
47 6048 acydburn
48 5375 acydburn
	/**
49 5375 acydburn
	* Write file to location
50 5375 acydburn
	*/
51 8295 davidmj
	public function write_file($destination_file = '', $contents = '')
52 5375 acydburn
	{
53 8572 acydburn
		$destination_file = $this->root_path . str_replace(PHPBB_ROOT_PATH, '', $destination_file);
54 5375 acydburn
55 5375 acydburn
		// need to create a temp file and then move that temp file.
56 5375 acydburn
		// ftp functions can only move files around and can't create.
57 5375 acydburn
		// This means that the users will need to have access to write
58 5375 acydburn
		// temporary files or have write access on a folder within phpBB
59 6930 acydburn
		// like the cache folder. If the user can't do either, then
60 5375 acydburn
		// he/she needs to use the fsock ftp method
61 5388 acydburn
		$temp_name = tempnam($this->tmp_path, 'transfer_');
62 5375 acydburn
		@unlink($temp_name);
63 5375 acydburn
64 5375 acydburn
		$fp = @fopen($temp_name, 'w');
65 5375 acydburn
66 5375 acydburn
		if (!$fp)
67 5375 acydburn
		{
68 6048 acydburn
			trigger_error('Unable to create temporary file ' . $temp_name, E_USER_ERROR);
69 5375 acydburn
		}
70 6048 acydburn
71 5375 acydburn
		@fwrite($fp, $contents);
72 5375 acydburn
		@fclose($fp);
73 5375 acydburn
74 5375 acydburn
		$result = $this->overwrite_file($temp_name, $destination_file);
75 5375 acydburn
76 5375 acydburn
		// remove temporary file now
77 5375 acydburn
		@unlink($temp_name);
78 5375 acydburn
79 5375 acydburn
		return $result;
80 5375 acydburn
	}
81 5375 acydburn
82 5375 acydburn
	/**
83 5375 acydburn
	* Moving file into location. If the destination file already exists it gets overwritten
84 5375 acydburn
	*/
85 8295 davidmj
	public function overwrite_file($source_file, $destination_file)
86 5375 acydburn
	{
87 5375 acydburn
		/**
88 5375 acydburn
		* @todo generally think about overwriting files in another way, by creating a temporary file and then renaming it
89 5375 acydburn
		* @todo check for the destination file existance too
90 5375 acydburn
		*/
91 5375 acydburn
		$this->_delete($destination_file);
92 5375 acydburn
		$result = $this->_put($source_file, $destination_file);
93 5375 acydburn
		$this->_chmod($destination_file, $this->file_perms);
94 6048 acydburn
95 5375 acydburn
		return $result;
96 5375 acydburn
	}
97 5375 acydburn
98 5375 acydburn
	/**
99 5375 acydburn
	* Create directory structure
100 5375 acydburn
	*/
101 8295 davidmj
	public function make_dir($dir)
102 5375 acydburn
	{
103 8572 acydburn
		$dir = str_replace(PHPBB_ROOT_PATH, '', $dir);
104 5375 acydburn
		$dir = explode('/', $dir);
105 5375 acydburn
		$dirs = '';
106 5375 acydburn
107 5375 acydburn
		for ($i = 0, $total = sizeof($dir); $i < $total; $i++)
108 5375 acydburn
		{
109 5375 acydburn
			$result = true;
110 5375 acydburn
111 6048 acydburn
			if (strpos($dir[$i], '.') === 0)
112 5375 acydburn
			{
113 5375 acydburn
				continue;
114 5375 acydburn
			}
115 5375 acydburn
			$cur_dir = $dir[$i] . '/';
116 5375 acydburn
117 8572 acydburn
			if (!file_exists(PHPBB_ROOT_PATH . $dirs . $cur_dir))
118 5375 acydburn
			{
119 6048 acydburn
				// create the directory
120 5375 acydburn
				$result = $this->_mkdir($dir[$i]);
121 5375 acydburn
				$this->_chmod($dir[$i], $this->dir_perms);
122 5375 acydburn
			}
123 5375 acydburn
124 6015 acydburn
			$this->_chdir($this->root_path . $dirs . $dir[$i]);
125 5375 acydburn
			$dirs .= $cur_dir;
126 5375 acydburn
		}
127 5375 acydburn
128 5375 acydburn
		$this->_chdir($this->root_path);
129 5375 acydburn
130 5375 acydburn
		/**
131 5375 acydburn
		* @todo stack result into array to make sure every path creation has been taken care of
132 5375 acydburn
		*/
133 5375 acydburn
		return $result;
134 5375 acydburn
	}
135 5375 acydburn
136 5375 acydburn
	/**
137 5375 acydburn
	* Copy file from source location to destination location
138 5375 acydburn
	*/
139 8295 davidmj
	public function copy_file($from_loc, $to_loc)
140 5375 acydburn
	{
141 8572 acydburn
		$from_loc = ((strpos($from_loc, PHPBB_ROOT_PATH) !== 0) ? PHPBB_ROOT_PATH : '') . $from_loc;
142 8572 acydburn
		$to_loc = $this->root_path . str_replace(PHPBB_ROOT_PATH, '', $to_loc);
143 5375 acydburn
144 5375 acydburn
		if (!file_exists($from_loc))
145 5375 acydburn
		{
146 5375 acydburn
			return false;
147 5375 acydburn
		}
148 6048 acydburn
149 5375 acydburn
		$result = $this->overwrite_file($from_loc, $to_loc);
150 5375 acydburn
151 5375 acydburn
		return $result;
152 5375 acydburn
	}
153 5375 acydburn
154 5375 acydburn
	/**
155 5375 acydburn
	* Remove file
156 5375 acydburn
	*/
157 8295 davidmj
	public function delete_file($file)
158 5375 acydburn
	{
159 8572 acydburn
		$file = $this->root_path . str_replace(PHPBB_ROOT_PATH, '', $file);
160 6048 acydburn
161 5375 acydburn
		return $this->_delete($file);
162 5375 acydburn
	}
163 6048 acydburn
164 5375 acydburn
	/**
165 5375 acydburn
	* Remove directory
166 5375 acydburn
	* @todo remove child directories?
167 5375 acydburn
	*/
168 8295 davidmj
	public function remove_dir($dir)
169 5375 acydburn
	{
170 8572 acydburn
		$dir = $this->root_path . str_replace(PHPBB_ROOT_PATH, '', $dir);
171 6048 acydburn
172 5375 acydburn
		return $this->_rmdir($dir);
173 5375 acydburn
	}
174 5375 acydburn
175 5375 acydburn
	/**
176 5562 davidmj
	* Rename a file or folder
177 5562 davidmj
	*/
178 8295 davidmj
	public function rename($old_handle, $new_handle)
179 5562 davidmj
	{
180 8572 acydburn
		$old_handle = $this->root_path . str_replace(PHPBB_ROOT_PATH, '', $old_handle);
181 5562 davidmj
182 5562 davidmj
		return $this->_rename($old_handle, $new_handle);
183 5562 davidmj
	}
184 5562 davidmj
185 5562 davidmj
	/**
186 6312 acydburn
	* Check if a specified file exist...
187 6312 acydburn
	*/
188 8295 davidmj
	public function file_exists($directory, $filename)
189 6312 acydburn
	{
190 8572 acydburn
		$directory = $this->root_path . str_replace(PHPBB_ROOT_PATH, '', $directory);
191 6312 acydburn
192 6689 acydburn
		$this->_chdir($directory);
193 6689 acydburn
		$result = $this->_ls('');
194 6689 acydburn
195 6312 acydburn
		if ($result !== false && is_array($result))
196 6312 acydburn
		{
197 6312 acydburn
			return (in_array($filename, $result)) ? true : false;
198 6312 acydburn
		}
199 6312 acydburn
200 6312 acydburn
		return false;
201 6312 acydburn
	}
202 6312 acydburn
203 6312 acydburn
	/**
204 5416 acydburn
	* Open session
205 5416 acydburn
	*/
206 8295 davidmj
	public function open_session()
207 5416 acydburn
	{
208 5416 acydburn
		return $this->_init();
209 5416 acydburn
	}
210 5416 acydburn
211 5416 acydburn
	/**
212 5375 acydburn
	* Close current session
213 5375 acydburn
	*/
214 8295 davidmj
	public function close_session()
215 5375 acydburn
	{
216 5375 acydburn
		return $this->_close();
217 5375 acydburn
	}
218 5388 acydburn
219 5388 acydburn
	/**
220 5388 acydburn
	* Determine methods able to be used
221 5388 acydburn
	*/
222 8295 davidmj
	public static function methods()
223 5388 acydburn
	{
224 5388 acydburn
		$methods = array();
225 5870 acydburn
		$disabled_functions = explode(',', @ini_get('disable_functions'));
226 5388 acydburn
227 5388 acydburn
		if (@extension_loaded('ftp'))
228 5388 acydburn
		{
229 5388 acydburn
			$methods[] = 'ftp';
230 5388 acydburn
		}
231 5388 acydburn
232 5870 acydburn
		if (!in_array('fsockopen', $disabled_functions))
233 5870 acydburn
		{
234 5870 acydburn
			$methods[] = 'ftp_fsock';
235 5870 acydburn
		}
236 5870 acydburn
237 5388 acydburn
		return $methods;
238 5388 acydburn
	}
239 5375 acydburn
}
240 5375 acydburn
241 5375 acydburn
/**
242 6058 acydburn
* FTP transfer class
243 5375 acydburn
* @package phpBB3
244 5375 acydburn
*/
245 5375 acydburn
class ftp extends transfer
246 5375 acydburn
{
247 5375 acydburn
	/**
248 5375 acydburn
	* Standard parameters for FTP session
249 5375 acydburn
	*/
250 8295 davidmj
	function __construct($host, $username, $password, $root_path, $port = 21, $timeout = 10)
251 5375 acydburn
	{
252 5375 acydburn
		$this->host			= $host;
253 5375 acydburn
		$this->port			= $port;
254 5375 acydburn
		$this->username		= $username;
255 5375 acydburn
		$this->password		= $password;
256 5375 acydburn
		$this->timeout		= $timeout;
257 5595 acydburn
258 6015 acydburn
		// Make sure $this->root_path is layed out the same way as the $user->page['root_script_path'] value (/ at the end)
259 5595 acydburn
		$this->root_path	= str_replace('\\', '/', $this->root_path);
260 5375 acydburn
261 6698 acydburn
		if (!empty($root_path))
262 6698 acydburn
		{
263 6698 acydburn
			$this->root_path = (($root_path[0] != '/' ) ? '/' : '') . $root_path . ((substr($root_path, -1, 1) == '/') ? '' : '/');
264 6698 acydburn
		}
265 6698 acydburn
266 5562 davidmj
		// Init some needed values
267 8295 davidmj
		parent::__construct();
268 5562 davidmj
269 5375 acydburn
		return;
270 5375 acydburn
	}
271 5375 acydburn
272 5375 acydburn
	/**
273 5562 davidmj
	* Requests data
274 5562 davidmj
	*/
275 8295 davidmj
	private function data()
276 5562 davidmj
	{
277 5595 acydburn
		global $user;
278 5595 acydburn
279 6048 acydburn
		return array(
280 6048 acydburn
			'host'		=> 'localhost',
281 6048 acydburn
			'username'	=> 'anonymous',
282 6048 acydburn
			'password'	=> '',
283 6048 acydburn
			'root_path'	=> $user->page['root_script_path'],
284 6048 acydburn
			'port'		=> 21,
285 6048 acydburn
			'timeout'	=> 10
286 6048 acydburn
		);
287 5562 davidmj
	}
288 5562 davidmj
289 5562 davidmj
	/**
290 5375 acydburn
	* Init FTP Session
291 6312 acydburn
	* @access private
292 5375 acydburn
	*/
293 8295 davidmj
	private function _init()
294 5375 acydburn
	{
295 5375 acydburn
		// connect to the server
296 5375 acydburn
		$this->connection = @ftp_connect($this->host, $this->port, $this->timeout);
297 5375 acydburn
298 5375 acydburn
		if (!$this->connection)
299 5375 acydburn
		{
300 6048 acydburn
			return 'ERR_CONNECTING_SERVER';
301 5375 acydburn
		}
302 5375 acydburn
303 5375 acydburn
		// attempt to turn pasv mode on
304 5375 acydburn
		@ftp_pasv($this->connection, true);
305 5375 acydburn
306 5375 acydburn
		// login to the server
307 5375 acydburn
		if (!@ftp_login($this->connection, $this->username, $this->password))
308 5375 acydburn
		{
309 6048 acydburn
			return 'ERR_UNABLE_TO_LOGIN';
310 5375 acydburn
		}
311 5375 acydburn
312 5375 acydburn
		// change to the root directory
313 5375 acydburn
		if (!$this->_chdir($this->root_path))
314 5375 acydburn
		{
315 6048 acydburn
			return 'ERR_CHANGING_DIRECTORY';
316 5375 acydburn
		}
317 5375 acydburn
318 5375 acydburn
		return true;
319 5375 acydburn
	}
320 5375 acydburn
321 5375 acydburn
	/**
322 5375 acydburn
	* Create Directory (MKDIR)
323 6312 acydburn
	* @access private
324 5375 acydburn
	*/
325 8295 davidmj
	private function _mkdir($dir)
326 5375 acydburn
	{
327 5375 acydburn
		return @ftp_mkdir($this->connection, $dir);
328 5375 acydburn
	}
329 5375 acydburn
330 5375 acydburn
	/**
331 5375 acydburn
	* Remove directory (RMDIR)
332 6312 acydburn
	* @access private
333 5375 acydburn
	*/
334 8295 davidmj
	private function _rmdir($dir)
335 5375 acydburn
	{
336 5375 acydburn
		return @ftp_rmdir($this->connection, $dir);
337 5375 acydburn
	}
338 5375 acydburn
339 5375 acydburn
	/**
340 6139 acydburn
	* Rename file
341 6312 acydburn
	* @access private
342 5562 davidmj
	*/
343 8295 davidmj
	private function _rename($old_handle, $new_handle)
344 5562 davidmj
	{
345 5562 davidmj
		return @ftp_rename($this->connection, $old_handle, $new_handle);
346 5562 davidmj
	}
347 5562 davidmj
348 5562 davidmj
	/**
349 5375 acydburn
	* Change current working directory (CHDIR)
350 6312 acydburn
	* @access private
351 5375 acydburn
	*/
352 8295 davidmj
	private function _chdir($dir = '')
353 5375 acydburn
	{
354 6730 acydburn
		if ($dir && $dir !== '/')
355 5375 acydburn
		{
356 6730 acydburn
			if (substr($dir, -1, 1) == '/')
357 6730 acydburn
			{
358 6730 acydburn
				$dir = substr($dir, 0, -1);
359 6730 acydburn
			}
360 5375 acydburn
		}
361 5375 acydburn
362 5375 acydburn
		return @ftp_chdir($this->connection, $dir);
363 5375 acydburn
	}
364 5375 acydburn
365 5375 acydburn
	/**
366 5375 acydburn
	* change file permissions (CHMOD)
367 6312 acydburn
	* @access private
368 5375 acydburn
	*/
369 8295 davidmj
	private function _chmod($file, $perms)
370 5375 acydburn
	{
371 5562 davidmj
		if (function_exists('ftp_chmod'))
372 5562 davidmj
		{
373 5562 davidmj
			$err = @ftp_chmod($this->connection, $perms, $file);
374 5562 davidmj
		}
375 5562 davidmj
		else
376 5562 davidmj
		{
377 7782 acydburn
			// Unfortunatly CHMOD is not expecting an octal value...
378 7782 acydburn
			// We need to transform the integer (which was an octal) to an octal representation (to get the int) and then pass as is. ;)
379 7782 acydburn
			$chmod_cmd = 'CHMOD ' . base_convert($perms, 10, 8) . ' ' . $file;
380 5562 davidmj
			$err = $this->_site($chmod_cmd);
381 5562 davidmj
		}
382 6048 acydburn
383 5375 acydburn
		return $err;
384 5375 acydburn
	}
385 5375 acydburn
386 5375 acydburn
	/**
387 5375 acydburn
	* Upload file to location (PUT)
388 6312 acydburn
	* @access private
389 5375 acydburn
	*/
390 8295 davidmj
	private function _put($from_file, $to_file)
391 5375 acydburn
	{
392 5375 acydburn
		// get the file extension
393 5375 acydburn
		$file_extension = strtolower(substr(strrchr($to_file, '.'), 1));
394 5375 acydburn
395 5416 acydburn
		// We only use the BINARY file mode to cicumvent rewrite actions from ftp server (mostly linefeeds being replaced)
396 5416 acydburn
		$mode = FTP_BINARY;
397 5416 acydburn
398 5375 acydburn
		$to_dir = dirname($to_file);
399 5375 acydburn
		$to_file = basename($to_file);
400 5375 acydburn
		$this->_chdir($to_dir);
401 5375 acydburn
402 5375 acydburn
		$result = @ftp_put($this->connection, $to_file, $from_file, $mode);
403 5375 acydburn
		$this->_chdir($this->root_path);
404 5375 acydburn
405 5375 acydburn
		return $result;
406 5375 acydburn
	}
407 5375 acydburn
408 5375 acydburn
	/**
409 5375 acydburn
	* Delete file (DELETE)
410 6312 acydburn
	* @access private
411 5375 acydburn
	*/
412 8295 davidmj
	private function _delete($file)
413 5375 acydburn
	{
414 5375 acydburn
		return @ftp_delete($this->connection, $file);
415 5375 acydburn
	}
416 6048 acydburn
417 5375 acydburn
	/**
418 5375 acydburn
	* Close ftp session (CLOSE)
419 6312 acydburn
	* @access private
420 5375 acydburn
	*/
421 8295 davidmj
	private function _close()
422 5375 acydburn
	{
423 5416 acydburn
		if (!$this->connection)
424 5416 acydburn
		{
425 5416 acydburn
			return false;
426 5416 acydburn
		}
427 5416 acydburn
428 5375 acydburn
		return @ftp_quit($this->connection);
429 5375 acydburn
	}
430 5375 acydburn
431 5375 acydburn
	/**
432 5375 acydburn
	* Return current working directory (CWD)
433 5375 acydburn
	* At the moment not used by parent class
434 6312 acydburn
	* @access private
435 5375 acydburn
	*/
436 8295 davidmj
	private function _cwd()
437 5375 acydburn
	{
438 5375 acydburn
		return @ftp_pwd($this->connection);
439 5375 acydburn
	}
440 5375 acydburn
441 5375 acydburn
	/**
442 5375 acydburn
	* Return list of files in a given directory (LS)
443 6312 acydburn
	* @access private
444 5375 acydburn
	*/
445 8295 davidmj
	private function _ls($dir = './')
446 5375 acydburn
	{
447 5375 acydburn
		return @ftp_nlist($this->connection, $dir);
448 5375 acydburn
	}
449 5375 acydburn
450 5375 acydburn
	/**
451 5375 acydburn
	* FTP SITE command (ftp-only function)
452 6312 acydburn
	* @access private
453 5375