| 1 | <?php
|
|---|
| 2 | /**
|
|---|
| 3 | *
|
|---|
| 4 | * @package phpBB3
|
|---|
| 5 | * @version $Id$
|
|---|
| 6 | * @copyright (c) 2005 phpBB Group
|
|---|
| 7 | * @license http://opensource.org/licenses/gpl-license.php GNU Public License
|
|---|
| 8 | *
|
|---|
| 9 | */
|
|---|
| 10 |
|
|---|
| 11 | /**
|
|---|
| 12 | * @ignore
|
|---|
| 13 | */
|
|---|
| 14 | if (!defined('IN_PHPBB'))
|
|---|
| 15 | {
|
|---|
| 16 | exit;
|
|---|
| 17 | }
|
|---|
| 18 |
|
|---|
| 19 | /**
|
|---|
| 20 | * Transfer class, wrapper for ftp/sftp/ssh
|
|---|
| 21 | * @package phpBB3
|
|---|
| 22 | */
|
|---|
| 23 | class transfer
|
|---|
| 24 | {
|
|---|
| 25 | var $connection;
|
|---|
| 26 | var $host;
|
|---|
| 27 | var $port;
|
|---|
| 28 | var $username;
|
|---|
| 29 | var $password;
|
|---|
| 30 | var $timeout;
|
|---|
| 31 | var $root_path;
|
|---|
| 32 | var $tmp_path;
|
|---|
| 33 | var $file_perms;
|
|---|
| 34 | var $dir_perms;
|
|---|
| 35 |
|
|---|
| 36 | /**
|
|---|
| 37 | * Constructor - init some basic values
|
|---|
| 38 | */
|
|---|
| 39 | function transfer()
|
|---|
| 40 | {
|
|---|
| 41 | global $phpbb_root_path;
|
|---|
| 42 |
|
|---|
| 43 | $this->file_perms = 0644;
|
|---|
| 44 | $this->dir_perms = 0777;
|
|---|
| 45 |
|
|---|
| 46 | // We use the store directory as temporary path to circumvent open basedir restrictions
|
|---|
| 47 | $this->tmp_path = $phpbb_root_path . 'store/';
|
|---|
| 48 | }
|
|---|
| 49 |
|
|---|
| 50 | /**
|
|---|
| 51 | * Write file to location
|
|---|
| 52 | */
|
|---|
| 53 | function write_file($destination_file = '', $contents = '')
|
|---|
| 54 | {
|
|---|
| 55 | global $phpbb_root_path;
|
|---|
| 56 |
|
|---|
| 57 | $destination_file = $this->root_path . str_replace($phpbb_root_path, '', $destination_file);
|
|---|
| 58 |
|
|---|
| 59 | // need to create a temp file and then move that temp file.
|
|---|
| 60 | // ftp functions can only move files around and can't create.
|
|---|
| 61 | // This means that the users will need to have access to write
|
|---|
| 62 | // temporary files or have write access on a folder within phpBB
|
|---|
| 63 | // like the cache folder. If the user can't do either, then
|
|---|
| 64 | // he/she needs to use the fsock ftp method
|
|---|
| 65 | $temp_name = tempnam($this->tmp_path, 'transfer_');
|
|---|
| 66 | @unlink($temp_name);
|
|---|
| 67 |
|
|---|
| 68 | $fp = @fopen($temp_name, 'w');
|
|---|
| 69 |
|
|---|
| 70 | if (!$fp)
|
|---|
| 71 | {
|
|---|
| 72 | trigger_error('Unable to create temporary file ' . $temp_name, E_USER_ERROR);
|
|---|
| 73 | }
|
|---|
| 74 |
|
|---|
| 75 | @fwrite($fp, $contents);
|
|---|
| 76 | @fclose($fp);
|
|---|
| 77 |
|
|---|
| 78 | $result = $this->overwrite_file($temp_name, $destination_file);
|
|---|
| 79 |
|
|---|
| 80 | // remove temporary file now
|
|---|
| 81 | @unlink($temp_name);
|
|---|
| 82 |
|
|---|
| 83 | return $result;
|
|---|
| 84 | }
|
|---|
| 85 |
|
|---|
| 86 | /**
|
|---|
| 87 | * Moving file into location. If the destination file already exists it gets overwritten
|
|---|
| 88 | */
|
|---|
| 89 | function overwrite_file($source_file, $destination_file)
|
|---|
| 90 | {
|
|---|
| 91 | /**
|
|---|
| 92 | * @todo generally think about overwriting files in another way, by creating a temporary file and then renaming it
|
|---|
| 93 | * @todo check for the destination file existance too
|
|---|
| 94 | */
|
|---|
| 95 | $this->_delete($destination_file);
|
|---|
| 96 | $result = $this->_put($source_file, $destination_file);
|
|---|
| 97 | $this->_chmod($destination_file, $this->file_perms);
|
|---|
| 98 |
|
|---|
| 99 | return $result;
|
|---|
| 100 | }
|
|---|
| 101 |
|
|---|
| 102 | /**
|
|---|
| 103 | * Create directory structure
|
|---|
| 104 | */
|
|---|
| 105 | function make_dir($dir)
|
|---|
| 106 | {
|
|---|
| 107 | global $phpbb_root_path;
|
|---|
| 108 |
|
|---|
| 109 | $dir = str_replace($phpbb_root_path, '', $dir);
|
|---|
| 110 | $dir = explode('/', $dir);
|
|---|
| 111 | $dirs = '';
|
|---|
| 112 |
|
|---|
| 113 | for ($i = 0, $total = sizeof($dir); $i < $total; $i++)
|
|---|
| 114 | {
|
|---|
| 115 | $result = true;
|
|---|
| 116 |
|
|---|
| 117 | if (strpos($dir[$i], '.') === 0)
|
|---|
| 118 | {
|
|---|
| 119 | continue;
|
|---|
| 120 | }
|
|---|
| 121 | $cur_dir = $dir[$i] . '/';
|
|---|
| 122 |
|
|---|
| 123 | if (!file_exists($phpbb_root_path . $dirs . $cur_dir))
|
|---|
| 124 | {
|
|---|
| 125 | // create the directory
|
|---|
| 126 | $result = $this->_mkdir($dir[$i]);
|
|---|
| 127 | $this->_chmod($dir[$i], $this->dir_perms);
|
|---|
| 128 | }
|
|---|
| 129 |
|
|---|
| 130 | $this->_chdir($this->root_path . $dirs . $dir[$i]);
|
|---|
| 131 | $dirs .= $cur_dir;
|
|---|
| 132 | }
|
|---|
| 133 |
|
|---|
| 134 | $this->_chdir($this->root_path);
|
|---|
| 135 |
|
|---|
| 136 | /**
|
|---|
| 137 | * @todo stack result into array to make sure every path creation has been taken care of
|
|---|
| 138 | */
|
|---|
| 139 | return $result;
|
|---|
| 140 | }
|
|---|
| 141 |
|
|---|
| 142 | /**
|
|---|
| 143 | * Copy file from source location to destination location
|
|---|
| 144 | */
|
|---|
| 145 | function copy_file($from_loc, $to_loc)
|
|---|
| 146 | {
|
|---|
| 147 | global $phpbb_root_path;
|
|---|
| 148 |
|
|---|
| 149 | $from_loc = ((strpos($from_loc, $phpbb_root_path) !== 0) ? $phpbb_root_path : '') . $from_loc;
|
|---|
| 150 | $to_loc = $this->root_path . str_replace($phpbb_root_path, '', $to_loc);
|
|---|
| 151 |
|
|---|
| 152 | if (!file_exists($from_loc))
|
|---|
| 153 | {
|
|---|
| 154 | return false;
|
|---|
| 155 | }
|
|---|
| 156 |
|
|---|
| 157 | $result = $this->overwrite_file($from_loc, $to_loc);
|
|---|
| 158 |
|
|---|
| 159 | return $result;
|
|---|
| 160 | }
|
|---|
| 161 |
|
|---|
| 162 | /**
|
|---|
| 163 | * Remove file
|
|---|
| 164 | */
|
|---|
| 165 | function delete_file($file)
|
|---|
| 166 | {
|
|---|
| 167 | global $phpbb_root_path;
|
|---|
| 168 |
|
|---|
| 169 | $file = $this->root_path . str_replace($phpbb_root_path, '', $file);
|
|---|
| 170 |
|
|---|
| 171 | return $this->_delete($file);
|
|---|
| 172 | }
|
|---|
| 173 |
|
|---|
| 174 | /**
|
|---|
| 175 | * Remove directory
|
|---|
| 176 | * @todo remove child directories?
|
|---|
| 177 | */
|
|---|
| 178 | function remove_dir($dir)
|
|---|
| 179 | {
|
|---|
| 180 | global $phpbb_root_path;
|
|---|
| 181 |
|
|---|
| 182 | $dir = $this->root_path . str_replace($phpbb_root_path, '', $dir);
|
|---|
| 183 |
|
|---|
| 184 | return $this->_rmdir($dir);
|
|---|
| 185 | }
|
|---|
| 186 |
|
|---|
| 187 | /**
|
|---|
| 188 | * Rename a file or folder
|
|---|
| 189 | */
|
|---|
| 190 | function rename($old_handle, $new_handle)
|
|---|
| 191 | {
|
|---|
| 192 | global $phpbb_root_path;
|
|---|
| 193 |
|
|---|
| 194 | $old_handle = $this->root_path . str_replace($phpbb_root_path, '', $old_handle);
|
|---|
| 195 |
|
|---|
| 196 | return $this->_rename($old_handle, $new_handle);
|
|---|
| 197 | }
|
|---|
| 198 |
|
|---|
| 199 | /**
|
|---|
| 200 | * Check if a specified file exist...
|
|---|
| 201 | */
|
|---|
| 202 | function file_exists($directory, $filename)
|
|---|
| 203 | {
|
|---|
| 204 | global $phpbb_root_path;
|
|---|
| 205 |
|
|---|
| 206 | $directory = $this->root_path . str_replace($phpbb_root_path, '', $directory);
|
|---|
| 207 |
|
|---|
| 208 | $this->_chdir($directory);
|
|---|
| 209 | $result = $this->_ls();
|
|---|
| 210 |
|
|---|
| 211 | if ($result !== false && is_array($result))
|
|---|
| 212 | {
|
|---|
| 213 | return (in_array($filename, $result)) ? true : false;
|
|---|
| 214 | }
|
|---|
| 215 |
|
|---|
| 216 | return false;
|
|---|
| 217 | }
|
|---|
| 218 |
|
|---|
| 219 | /**
|
|---|
| 220 | * Open session
|
|---|
| 221 | */
|
|---|
| 222 | function open_session()
|
|---|
| 223 | {
|
|---|
| 224 | return $this->_init();
|
|---|
| 225 | }
|
|---|
| 226 |
|
|---|
| 227 | /**
|
|---|
| 228 | * Close current session
|
|---|
| 229 | */
|
|---|
| 230 | function close_session()
|
|---|
| 231 | {
|
|---|
| 232 | return $this->_close();
|
|---|
| 233 | }
|
|---|
| 234 |
|
|---|
| 235 | /**
|
|---|
| 236 | * Determine methods able to be used
|
|---|
| 237 | */
|
|---|
| 238 | function methods()
|
|---|
| 239 | {
|
|---|
| 240 | $methods = array();
|
|---|
| 241 | $disabled_functions = explode(',', @ini_get('disable_functions'));
|
|---|
| 242 |
|
|---|
| 243 | if (@extension_loaded('ftp'))
|
|---|
| 244 | {
|
|---|
| 245 | $methods[] = 'ftp';
|
|---|
| 246 | }
|
|---|
| 247 |
|
|---|
| 248 | if (!in_array('fsockopen', $disabled_functions))
|
|---|
| 249 | {
|
|---|
| 250 | $methods[] = 'ftp_fsock';
|
|---|
| 251 | }
|
|---|
| 252 |
|
|---|
| 253 | return $methods;
|
|---|
| 254 | }
|
|---|
| 255 | }
|
|---|
| 256 |
|
|---|
| 257 | /**
|
|---|
| 258 | * FTP transfer class
|
|---|
| 259 | * @package phpBB3
|
|---|
| 260 | */
|
|---|
| 261 | class ftp extends transfer
|
|---|
| 262 | {
|
|---|
| 263 | /**
|
|---|
| 264 | * Standard parameters for FTP session
|
|---|
| 265 | */
|
|---|
| 266 | function ftp($host, $username, $password, $root_path, $port = 21, $timeout = 10)
|
|---|
| 267 | {
|
|---|
| 268 | $this->host = $host;
|
|---|
| 269 | $this->port = $port;
|
|---|
| 270 | $this->username = $username;
|
|---|
| 271 | $this->password = $password;
|
|---|
| 272 | $this->timeout = $timeout;
|
|---|
| 273 |
|
|---|
| 274 | // Make sure $this->root_path is layed out the same way as the $user->page['root_script_path'] value (/ at the end)
|
|---|
| 275 | $this->root_path = str_replace('\\', '/', $this->root_path);
|
|---|
| 276 |
|
|---|
| 277 | if (!empty($root_path))
|
|---|
| 278 | {
|
|---|
| 279 | $this->root_path = (($root_path[0] != '/' ) ? '/' : '') . $root_path . ((substr($root_path, -1, 1) == '/') ? '' : '/');
|
|---|
| 280 | }
|
|---|
| 281 |
|
|---|
| 282 | // Init some needed values
|
|---|
| 283 | transfer::transfer();
|
|---|
| 284 |
|
|---|
| 285 | return;
|
|---|
| 286 | }
|
|---|
| 287 |
|
|---|
| 288 | /**
|
|---|
| 289 | * Requests data
|
|---|
| 290 | */
|
|---|
| 291 | function data()
|
|---|
| 292 | {
|
|---|
| 293 | global $user;
|
|---|
| 294 |
|
|---|
| 295 | return array(
|
|---|
| 296 | 'host' => 'localhost',
|
|---|
| 297 | 'username' => 'anonymous',
|
|---|
| 298 | 'password' => '',
|
|---|
| 299 | 'root_path' => $user->page['root_script_path'],
|
|---|
| 300 | 'port' => 21,
|
|---|
| 301 | 'timeout' => 10
|
|---|
| 302 | );
|
|---|
| 303 | }
|
|---|
| 304 |
|
|---|
| 305 | /**
|
|---|
| 306 | * Init FTP Session
|
|---|
| 307 | * @access private
|
|---|
| 308 | */
|
|---|
| 309 | function _init()
|
|---|
| 310 | {
|
|---|
| 311 | // connect to the server
|
|---|
| 312 | $this->connection = @ftp_connect($this->host, $this->port, $this->timeout);
|
|---|
| 313 |
|
|---|
| 314 | if (!$this->connection)
|
|---|
| 315 | {
|
|---|
| 316 | return 'ERR_CONNECTING_SERVER';
|
|---|
| 317 | }
|
|---|
| 318 |
|
|---|
| 319 | // login to the server
|
|---|
| 320 | if (!@ftp_login($this->connection, $this->username, $this->password))
|
|---|
| 321 | {
|
|---|
| 322 | return 'ERR_UNABLE_TO_LOGIN';
|
|---|
| 323 | }
|
|---|
| 324 |
|
|---|
| 325 | // attempt to turn pasv mode on
|
|---|
| 326 | @ftp_pasv($this->connection, true);
|
|---|
| 327 |
|
|---|
| 328 | // change to the root directory
|
|---|
| 329 | if (!$this->_chdir($this->root_path))
|
|---|
| 330 | {
|
|---|
| 331 | return 'ERR_CHANGING_DIRECTORY';
|
|---|
| 332 | }
|
|---|
| 333 |
|
|---|
| 334 | return true;
|
|---|
| 335 | }
|
|---|
| 336 |
|
|---|
| 337 | /**
|
|---|
| 338 | * Create Directory (MKDIR)
|
|---|
| 339 | * @access private
|
|---|
| 340 | */
|
|---|
| 341 | function _mkdir($dir)
|
|---|
| 342 | {
|
|---|
| 343 | return @ftp_mkdir($this->connection, $dir);
|
|---|
| 344 | }
|
|---|
| 345 |
|
|---|
| 346 | /**
|
|---|
| 347 | * Remove directory (RMDIR)
|
|---|
| 348 | * @access private
|
|---|
| 349 | */
|
|---|
| 350 | function _rmdir($dir)
|
|---|
| 351 | {
|
|---|
| 352 | return @ftp_rmdir($this->connection, $dir);
|
|---|
| 353 | }
|
|---|
| 354 |
|
|---|
| 355 | /**
|
|---|
| 356 | * Rename file
|
|---|
| 357 | * @access private
|
|---|
| 358 | */
|
|---|
| 359 | function _rename($old_handle, $new_handle)
|
|---|
| 360 | {
|
|---|
| 361 | return @ftp_rename($this->connection, $old_handle, $new_handle);
|
|---|
| 362 | }
|
|---|
| 363 |
|
|---|
| 364 | /**
|
|---|
| 365 | * Change current working directory (CHDIR)
|
|---|
| 366 | * @access private
|
|---|
| 367 | */
|
|---|
| 368 | function _chdir($dir = '')
|
|---|
| 369 | {
|
|---|
| 370 | if ($dir && $dir !== '/')
|
|---|
| 371 | {
|
|---|
| 372 | if (substr($dir, -1, 1) == '/')
|
|---|
| 373 | {
|
|---|
| 374 | $dir = substr($dir, 0, -1);
|
|---|
| 375 | }
|
|---|
| 376 | }
|
|---|
| 377 |
|
|---|
| 378 | return @ftp_chdir($this->connection, $dir);
|
|---|
| 379 | }
|
|---|
| 380 |
|
|---|
| 381 | /**
|
|---|
| 382 | * change file permissions (CHMOD)
|
|---|
| 383 | * @access private
|
|---|
| 384 | */
|
|---|
| 385 | function _chmod($file, $perms)
|
|---|
| 386 | {
|
|---|
| 387 | if (function_exists('ftp_chmod'))
|
|---|
| 388 | {
|
|---|
| 389 | $err = @ftp_chmod($this->connection, $perms, $file);
|
|---|
| 390 | }
|
|---|
| 391 | else
|
|---|
| 392 | {
|
|---|
| 393 | // Unfortunatly CHMOD is not expecting an octal value...
|
|---|
| 394 | // We need to transform the integer (which was an octal) to an octal representation (to get the int) and then pass as is. ;)
|
|---|
| 395 | $chmod_cmd = 'CHMOD ' . base_convert($perms, 10, 8) . ' ' . $file;
|
|---|
| 396 | $err = $this->_site($chmod_cmd);
|
|---|
| 397 | }
|
|---|
| 398 |
|
|---|
| 399 | return $err;
|
|---|
| 400 | }
|
|---|
| 401 |
|
|---|
| 402 | /**
|
|---|
| 403 | * Upload file to location (PUT)
|
|---|
| 404 | * @access private
|
|---|
| 405 | */
|
|---|
| 406 | function _put($from_file, $to_file)
|
|---|
| 407 | {
|
|---|
| 408 | // get the file extension
|
|---|
| 409 | $file_extension = strtolower(substr(strrchr($to_file, '.'), 1));
|
|---|
| 410 |
|
|---|
| 411 | // We only use the BINARY file mode to cicumvent rewrite actions from ftp server (mostly linefeeds being replaced)
|
|---|
| 412 | $mode = FTP_BINARY;
|
|---|
| 413 |
|
|---|
| 414 | $to_dir = dirname($to_file);
|
|---|
| 415 | $to_file = basename($to_file);
|
|---|
| 416 | $this->_chdir($to_dir);
|
|---|
| 417 |
|
|---|
| 418 | $result = @ftp_put($this->connection, $to_file, $from_file, $mode);
|
|---|
| 419 | $this->_chdir($this->root_path);
|
|---|
| 420 |
|
|---|
| 421 | return $result;
|
|---|
| 422 | }
|
|---|
| 423 |
|
|---|
| 424 | /**
|
|---|
| 425 | * Delete file (DELETE)
|
|---|
| 426 | * @access private
|
|---|
| 427 | */
|
|---|
| 428 | function _delete($file)
|
|---|
| 429 | {
|
|---|
| 430 | return @ftp_delete($this->connection, $file);
|
|---|
| 431 | }
|
|---|
| 432 |
|
|---|
| 433 | /**
|
|---|
| 434 | * Close ftp session (CLOSE)
|
|---|
| 435 | * @access private
|
|---|
| 436 | */
|
|---|
| 437 | function _close()
|
|---|
| 438 | {
|
|---|
| 439 | if (!$this->connection)
|
|---|
| 440 | {
|
|---|
| 441 | return false;
|
|---|
| 442 | }
|
|---|
| 443 |
|
|---|
| 444 | return @ftp_quit($this->connection);
|
|---|
| 445 | }
|
|---|
| 446 |
|
|---|
| 447 | /**
|
|---|
| 448 | * Return current working directory (CWD)
|
|---|
| 449 | * At the moment not used by parent class
|
|---|
| 450 | * @access private
|
|---|
| 451 | */
|
|---|
| 452 | function _cwd()
|
|---|
| 453 | {
|
|---|
| 454 | return @ftp_pwd($this->connection);
|
|---|
| 455 | }
|
|---|
| 456 |
|
|---|
| 457 | /**
|
|---|
| 458 | * Return list of files in a given directory (LS)
|
|---|
| 459 | * @access private
|
|---|
| 460 | */
|
|---|
| 461 | function _ls($dir = './')
|
|---|
| 462 | {
|
|---|
| 463 | $list = @ftp_nlist($this->connection, $dir);
|
|---|
| 464 |
|
|---|
| 465 | // See bug #46295 - Some FTP daemons don't like './'
|
|---|
| 466 | if ($dir === './')
|
|---|
| 467 | {
|
|---|
| 468 | // Let's try some alternatives
|
|---|
| 469 | $list = (empty($list)) ? @ftp_nlist($this->connection, '.') : $list;
|
|---|
| 470 | $list = (empty($list)) ? @ftp_nlist($this->connection, '') : $list;
|
|---|
| 471 | }
|
|---|
| 472 |
|
|---|
| 473 | // Return on error
|
|---|
| 474 | if ($list === false)
|
|---|
| 475 | {
|
|---|
| 476 | return false;
|
|---|
| 477 | }
|
|---|
| 478 |
|
|---|
| 479 | // Remove path if prepended
|
|---|
| 480 | foreach ($list as $key => $item)
|
|---|
| 481 | {
|
|---|
| 482 | // Use same separator for item and dir
|
|---|
| 483 | $item = str_replace('\\', '/', $item);
|
|---|
| 484 | $dir = str_replace('\\', '/', $dir);
|
|---|
| 485 |
|
|---|
| 486 | if (!empty($dir) && strpos($item, $dir) === 0)
|
|---|
| 487 | {
|
|---|
| 488 | $item = substr($item, strlen($dir));
|
|---|
| 489 | }
|
|---|
| 490 |
|
|---|
| 491 | $list[$key] = $item;
|
|---|
| 492 | }
|
|---|
| 493 |
|
|---|
| 494 | return $list;
|
|---|
| 495 | }
|
|---|
| 496 |
|
|---|
| 497 | /**
|
|---|
| 498 | * FTP SITE command (ftp-only function)
|
|---|
| 499 | * @access private
|
|---|
| 500 | */
|
|---|
| 501 | function _site($command)
|
|---|
| 502 | {
|
|---|
| 503 | return @ftp_site($this->connection, $command);
|
|---|
| 504 | }
|
|---|
| 505 | }
|
|---|
| 506 |
|
|---|
| 507 | /**
|
|---|
| 508 | * FTP fsock transfer class
|
|---|
| 509 | *
|
|---|
| 510 | * @author wGEric
|
|---|
| 511 | * @package phpBB3
|
|---|
| 512 | */
|
|---|
| 513 | class ftp_fsock extends transfer
|
|---|
| 514 | {
|
|---|
| 515 | var $data_connection;
|
|---|
| 516 |
|
|---|
| 517 | /**
|
|---|
| 518 | * Standard parameters for FTP session
|
|---|
| 519 | */
|
|---|
| 520 | function ftp_fsock($host, $username, $password, $root_path, $port = 21, $timeout = 10)
|
|---|
| 521 | {
|
|---|
| 522 | $this->host = $host;
|
|---|
| 523 | $this->port = $port;
|
|---|
| 524 | $this->username = $username;
|
|---|
| 525 | $this->password = $password;
|
|---|
| 526 | $this->timeout = $timeout;
|
|---|
| 527 |
|
|---|
| 528 | // Make sure $this->root_path is layed out the same way as the $user->page['root_script_path'] value (/ at the end)
|
|---|
| 529 | $this->root_path = str_replace('\\', '/', $this->root_path);
|
|---|
| 530 |
|
|---|
| 531 | if (!empty($root_path))
|
|---|
| 532 | {
|
|---|
| 533 | $this->root_path = (($root_path[0] != '/' ) ? '/' : '') . $root_path . ((substr($root_path, -1, 1) == '/') ? '' : '/');
|
|---|
| 534 | }
|
|---|
| 535 |
|
|---|
| 536 | // Init some needed values
|
|---|
| 537 | transfer::transfer();
|
|---|
| 538 |
|
|---|
| 539 | return;
|
|---|
| 540 | }
|
|---|
| 541 |
|
|---|
| 542 | /**
|
|---|
| 543 | * Requests data
|
|---|
| 544 | */
|
|---|
| 545 | function data()
|
|---|
| 546 | {
|
|---|
| 547 | global $user;
|
|---|
| 548 |
|
|---|
| 549 | return array(
|
|---|
| 550 | 'host' => 'localhost',
|
|---|
| 551 | 'username' => 'anonymous',
|
|---|
| 552 | 'password' => '',
|
|---|
| 553 | 'root_path' => $user->page['root_script_path'],
|
|---|
| 554 | 'port' => 21,
|
|---|
| 555 | 'timeout' => 10
|
|---|
| 556 | );
|
|---|
| 557 | }
|
|---|
| 558 |
|
|---|
| 559 | /**
|
|---|
| 560 | * Init FTP Session
|
|---|
| 561 | * @access private
|
|---|
| 562 | */
|
|---|
| 563 | function _init()
|
|---|
| 564 | {
|
|---|
| 565 | $errno = 0;
|
|---|
| 566 | $errstr = '';
|
|---|
| 567 |
|
|---|
| 568 | // connect to the server
|
|---|
| 569 | $this->connection = @fsockopen($this->host, $this->port, $errno, $errstr, $this->timeout);
|
|---|
| 570 |
|
|---|
| 571 | if (!$this->connection || !$this->_check_command())
|
|---|
| 572 | {
|
|---|
| 573 | return 'ERR_CONNECTING_SERVER';
|
|---|
| 574 | }
|
|---|
| 575 |
|
|---|
| 576 | @stream_set_timeout($this->connection, $this->timeout);
|
|---|
| 577 |
|
|---|
| 578 | // login
|
|---|
| 579 | if (!$this->_send_command('USER', $this->username))
|
|---|
| 580 | {
|
|---|
| 581 | return 'ERR_UNABLE_TO_LOGIN';
|
|---|
| 582 | }
|
|---|
| 583 |
|
|---|
| 584 | if (!$this->_send_command('PASS', $this->password))
|
|---|
| 585 | {
|
|---|
| 586 | return 'ERR_UNABLE_TO_LOGIN';
|
|---|
| 587 | }
|
|---|
| 588 |
|
|---|
| 589 | // change to the root directory
|
|---|
| 590 | if (!$this->_chdir($this->root_path))
|
|---|
| 591 | {
|
|---|
| 592 | return 'ERR_CHANGING_DIRECTORY';
|
|---|
| 593 | }
|
|---|
| 594 |
|
|---|
| 595 | return true;
|
|---|
| 596 | }
|
|---|
| 597 |
|
|---|
| 598 | /**
|
|---|
| 599 | * Create Directory (MKDIR)
|
|---|
| 600 | * @access private
|
|---|
| 601 | */
|
|---|
| 602 | function _mkdir($dir)
|
|---|
| 603 | {
|
|---|
| 604 | return $this->_send_command('MKD', $dir);
|
|---|
| 605 | }
|
|---|
| 606 |
|
|---|
| 607 | /**
|
|---|
| 608 | * Remove directory (RMDIR)
|
|---|
| 609 | * @access private
|
|---|
| 610 | */
|
|---|
| 611 | function _rmdir($dir)
|
|---|
| 612 | {
|
|---|
| 613 | return $this->_send_command('RMD', $dir);
|
|---|
| 614 | }
|
|---|
| 615 |
|
|---|
| 616 | /**
|
|---|
| 617 | * Rename File
|
|---|
| 618 | * @access private
|
|---|
| 619 | */
|
|---|
| 620 | function _rename($old_handle, $new_handle)
|
|---|
| 621 | {
|
|---|
| 622 | $this->_send_command('RNFR', $old_handle);
|
|---|
| 623 | return $this->_send_command('RNTO', $new_handle);
|
|---|
| 624 | }
|
|---|
| 625 |
|
|---|
| 626 | /**
|
|---|
| 627 | * Change current working directory (CHDIR)
|
|---|
| 628 | * @access private
|
|---|
| 629 | */
|
|---|
| 630 | function _chdir($dir = '')
|
|---|
| 631 | {
|
|---|
| 632 | if ($dir && $dir !== '/')
|
|---|
| 633 | {
|
|---|
| 634 | if (substr($dir, -1, 1) == '/')
|
|---|
| 635 | {
|
|---|
| 636 | $dir = substr($dir, 0, -1);
|
|---|
| 637 | }
|
|---|
| 638 | }
|
|---|
| 639 |
|
|---|
| 640 | return $this->_send_command('CWD', $dir);
|
|---|
| 641 | }
|
|---|
| 642 |
|
|---|
| 643 | /**
|
|---|
| 644 | * change file permissions (CHMOD)
|
|---|
| 645 | * @access private
|
|---|
| 646 | */
|
|---|
| 647 | function _chmod($file, $perms)
|
|---|
| 648 | {
|
|---|
| 649 | // Unfortunatly CHMOD is not expecting an octal value...
|
|---|
| 650 | // We need to transform the integer (which was an octal) to an octal representation (to get the int) and then pass as is. ;)
|
|---|
| 651 | return $this->_send_command('SITE CHMOD', base_convert($perms, 10, 8) . ' ' . $file);
|
|---|
| 652 | }
|
|---|
| 653 |
|
|---|
| 654 | /**
|
|---|
| 655 | * Upload file to location (PUT)
|
|---|
| 656 | * @access private
|
|---|
| 657 | */
|
|---|
| 658 | function _put($from_file, $to_file)
|
|---|
| 659 | {
|
|---|
| 660 | // We only use the BINARY file mode to cicumvent rewrite actions from ftp server (mostly linefeeds being replaced)
|
|---|
| 661 | // 'I' == BINARY
|
|---|
| 662 | // 'A' == ASCII
|
|---|
| 663 | if (!$this->_send_command('TYPE', 'I'))
|
|---|
| 664 | {
|
|---|
| 665 | return false;
|
|---|
| 666 | }
|
|---|
| 667 |
|
|---|
| 668 | // open the connection to send file over
|
|---|
| 669 | if (!$this->_open_data_connection())
|
|---|
| 670 | {
|
|---|
| 671 | return false;
|
|---|
| 672 | }
|
|---|
| 673 |
|
|---|
| 674 | $this->_send_command('STOR', $to_file, false);
|
|---|
| 675 |
|
|---|
| 676 | // send the file
|
|---|
| 677 | $fp = @fopen($from_file, 'rb');
|
|---|
| 678 | while (!@feof($fp))
|
|---|
| 679 | {
|
|---|
| 680 | @fwrite($this->data_connection, @fread($fp, 4096));
|
|---|
| 681 | }
|
|---|
| 682 | @fclose($fp);
|
|---|
| 683 |
|
|---|
| 684 | // close connection
|
|---|
| 685 | $this->_close_data_connection();
|
|---|
| 686 |
|
|---|
| 687 | return $this->_check_command();
|
|---|
| 688 | }
|
|---|
| 689 |
|
|---|
| 690 | /**
|
|---|
| 691 | * Delete file (DELETE)
|
|---|
| 692 | * @access private
|
|---|
| 693 | */
|
|---|
| 694 | function _delete($file)
|
|---|
| 695 | {
|
|---|
| 696 | return $this->_send_command('DELE', $file);
|
|---|
| 697 | }
|
|---|
| 698 |
|
|---|
| 699 | /**
|
|---|
| 700 | * Close ftp session (CLOSE)
|
|---|
| 701 | * @access private
|
|---|
| 702 | */
|
|---|
| 703 | function _close()
|
|---|
| 704 | {
|
|---|
| 705 | if (!$this->connection)
|
|---|
| 706 | {
|
|---|
| 707 | return false;
|
|---|
| 708 | }
|
|---|
| 709 |
|
|---|
| 710 | return $this->_send_command('QUIT');
|
|---|
| 711 | }
|
|---|
| 712 |
|
|---|
| 713 | /**
|
|---|
| 714 | * Return current working directory (CWD)
|
|---|
| 715 | * At the moment not used by parent class
|
|---|
| 716 | * @access private
|
|---|
| 717 | */
|
|---|
| 718 | function _cwd()
|
|---|
| 719 | {
|
|---|
| 720 | $this->_send_command('PWD', '', false);
|
|---|
| 721 | return preg_replace('#^[0-9]{3} "(.+)" .+\r\n#', '\\1', $this->_check_command(true));
|
|---|
| 722 | }
|
|---|
| 723 |
|
|---|
| 724 | /**
|
|---|
| 725 | * Return list of files in a given directory (LS)
|
|---|
| 726 | * @access private
|
|---|
| 727 | */
|
|---|
| 728 | function _ls($dir = './')
|
|---|
| 729 | {
|
|---|
| 730 | if (!$this->_open_data_connection())
|
|---|
| 731 | {
|
|---|
| 732 | return false;
|
|---|
| 733 | }
|
|---|
| 734 |
|
|---|
| 735 | $this->_send_command('NLST', $dir);
|
|---|
| 736 |
|
|---|
| 737 | $list = array();
|
|---|
| 738 | while (!@feof($this->data_connection))
|
|---|
| 739 | {
|
|---|
| 740 | $filename = preg_replace('#[\r\n]#', '', @fgets($this->data_connection, 512));
|
|---|
| 741 |
|
|---|
| 742 | if ($filename !== '')
|
|---|
| 743 | {
|
|---|
| 744 | $list[] = $filename;
|
|---|
| 745 | }
|
|---|
| 746 | }
|
|---|
| 747 | $this->_close_data_connection();
|
|---|
| 748 |
|
|---|
| 749 | // Clear buffer
|
|---|
| 750 | $this->_check_command();
|
|---|
| 751 |
|
|---|
| 752 | // See bug #46295 - Some FTP daemons don't like './'
|
|---|
| 753 | if ($dir === './' && empty($list))
|
|---|
| 754 | {
|
|---|
| 755 | // Let's try some alternatives
|
|---|
| 756 | $list = $this->_ls('.');
|
|---|
| 757 |
|
|---|
| 758 | if (empty($list))
|
|---|
| 759 | {
|
|---|
| 760 | $list = $this->_ls('');
|
|---|
| 761 | }
|
|---|
| 762 |
|
|---|
| 763 | return $list;
|
|---|
| 764 | }
|
|---|
| 765 |
|
|---|
| 766 | // Remove path if prepended
|
|---|
| 767 | foreach ($list as $key => $item)
|
|---|
| 768 | {
|
|---|
| 769 | // Use same separator for item and dir
|
|---|
| 770 | $item = str_replace('\\', '/', $item);
|
|---|
| 771 | $dir = str_replace('\\', '/', $dir);
|
|---|
| 772 |
|
|---|
| 773 | if (!empty($dir) && strpos($item, $dir) === 0)
|
|---|
| 774 | {
|
|---|
| 775 | $item = substr($item, strlen($dir));
|
|---|
| 776 | }
|
|---|
| 777 |
|
|---|
| 778 | $list[$key] = $item;
|
|---|
| 779 | }
|
|---|
| 780 |
|
|---|
| 781 | return $list;
|
|---|
| 782 | }
|
|---|
| 783 |
|
|---|
| 784 | /**
|
|---|
| 785 | * Send a command to server (FTP fsock only function)
|
|---|
| 786 | * @access private
|
|---|
| 787 | */
|
|---|
| 788 | function _send_command($command, $args = '', $check = true)
|
|---|
| 789 | {
|
|---|
| 790 | if (!empty($args))
|
|---|
| 791 | {
|
|---|
| 792 | $command = "$command $args";
|
|---|
| 793 | }
|
|---|
| 794 |
|
|---|
| 795 | fwrite($this->connection, $command . "\r\n");
|
|---|
| 796 |
|
|---|
| 797 | if ($check === true && !$this->_check_command())
|
|---|
| 798 | {
|
|---|
| 799 | return false;
|
|---|
| 800 | }
|
|---|
| 801 |
|
|---|
| 802 | return true;
|
|---|
| 803 | }
|
|---|
| 804 |
|
|---|
| 805 | /**
|
|---|
| 806 | * Opens a connection to send data (FTP fosck only function)
|
|---|
| 807 | * @access private
|
|---|
| 808 | */
|
|---|
| 809 | function _open_data_connection()
|
|---|
| 810 | {
|
|---|
| 811 | $this->_send_command('PASV', '', false);
|
|---|
| 812 |
|
|---|
| 813 | if (!$ip_port = $this->_check_command(true))
|
|---|
| 814 | {
|
|---|
| 815 | return false;
|
|---|
| 816 | }
|
|---|
| 817 |
|
|---|
| 818 | // open the connection to start sending the file
|
|---|
| 819 | if (!preg_match('#[0-9]{1,3},[0-9]{1,3},[0-9]{1,3},[0-9]{1,3},[0-9]+,[0-9]+#', $ip_port, $temp))
|
|---|
| 820 | {
|
|---|
| 821 | // bad ip and port
|
|---|
| 822 | return false;
|
|---|
| 823 | }
|
|---|
| 824 |
|
|---|
| 825 | $temp = explode(',', $temp[0]);
|
|---|
| 826 | $server_ip = $temp[0] . '.' . $temp[1] . '.' . $temp[2] . '.' . $temp[3];
|
|---|
| 827 | $server_port = $temp[4] * 256 + $temp[5];
|
|---|
| 828 | $errno = 0;
|
|---|
| 829 | $errstr = '';
|
|---|
| 830 |
|
|---|
| 831 | if (!$this->data_connection = @fsockopen($server_ip, $server_port, $errno, $errstr, $this->timeout))
|
|---|
| 832 | {
|
|---|
| 833 | return false;
|
|---|
| 834 | }
|
|---|
| 835 | @stream_set_timeout($this->data_connection, $this->timeout);
|
|---|
| 836 |
|
|---|
| 837 | return true;
|
|---|
| 838 | }
|
|---|
| 839 |
|
|---|
| 840 | /**
|
|---|
| 841 | * Closes a connection used to send data
|
|---|
| 842 | * @access private
|
|---|
| 843 | */
|
|---|
| 844 | function _close_data_connection()
|
|---|
| 845 | {
|
|---|
| 846 | return @fclose($this->data_connection);
|
|---|
| 847 | }
|
|---|
| 848 |
|
|---|
| 849 | /**
|
|---|
| 850 | * Check to make sure command was successful (FTP fsock only function)
|
|---|
| 851 | * @access private
|
|---|
| 852 | */
|
|---|
| 853 | function _check_command($return = false)
|
|---|
| 854 | {
|
|---|
| 855 | $response = '';
|
|---|
| 856 |
|
|---|
| 857 | do
|
|---|
| 858 | {
|
|---|
| 859 | $result = @fgets($this->connection, 512);
|
|---|
| 860 | $response .= $result;
|
|---|
| 861 | }
|
|---|
| 862 | while (substr($result, 3, 1) !== ' ');
|
|---|
| 863 |
|
|---|
| 864 | if (!preg_match('#^[123]#', $response))
|
|---|
| 865 | {
|
|---|
| 866 | return false;
|
|---|
| 867 | }
|
|---|
| 868 |
|
|---|
| 869 | return ($return) ? $response : true;
|
|---|
| 870 | }
|
|---|
| 871 | }
|
|---|
| 872 |
|
|---|
| 873 | ?>
|
|---|