[ Index ]

PHP Cross Reference of phpBB-3.2.0-deutsch

title

Body

[close]

/includes/ -> functions_transfer.php (source)

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


Generated: Sun Feb 19 19:47:08 2017 Cross-referenced by PHPXref 0.7.1