[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
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 // Try to find out whether we have a IPv4 or IPv6 (control) connection 812 if (function_exists('stream_socket_get_name')) 813 { 814 $socket_name = stream_socket_get_name($this->connection, true); 815 $server_ip = substr($socket_name, 0, strrpos($socket_name, ':')); 816 } 817 818 if (!isset($server_ip) || preg_match(get_preg_expression('ipv4'), $server_ip)) 819 { 820 // Passive mode 821 $this->_send_command('PASV', '', false); 822 823 if (!$ip_port = $this->_check_command(true)) 824 { 825 return false; 826 } 827 828 // open the connection to start sending the file 829 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)) 830 { 831 // bad ip and port 832 return false; 833 } 834 835 $temp = explode(',', $temp[0]); 836 $server_ip = $temp[0] . '.' . $temp[1] . '.' . $temp[2] . '.' . $temp[3]; 837 $server_port = $temp[4] * 256 + $temp[5]; 838 } 839 else 840 { 841 // Extended Passive Mode - RFC2428 842 $this->_send_command('EPSV', '', false); 843 844 if (!$epsv_response = $this->_check_command(true)) 845 { 846 return false; 847 } 848 849 // Response looks like "229 Entering Extended Passive Mode (|||12345|)" 850 // where 12345 is the tcp port for the data connection 851 if (!preg_match('#\(\|\|\|([0-9]+)\|\)#', $epsv_response, $match)) 852 { 853 return false; 854 } 855 $server_port = (int) $match[1]; 856 857 // fsockopen expects IPv6 address in square brackets 858 $server_ip = "[$server_ip]"; 859 } 860 861 $errno = 0; 862 $errstr = ''; 863 864 if (!$this->data_connection = @fsockopen($server_ip, $server_port, $errno, $errstr, $this->timeout)) 865 { 866 return false; 867 } 868 @stream_set_timeout($this->data_connection, $this->timeout); 869 870 return true; 871 } 872 873 /** 874 * Closes a connection used to send data 875 * @access private 876 */ 877 function _close_data_connection() 878 { 879 return @fclose($this->data_connection); 880 } 881 882 /** 883 * Check to make sure command was successful (FTP fsock only function) 884 * @access private 885 */ 886 function _check_command($return = false) 887 { 888 $response = ''; 889 890 do 891 { 892 $result = @fgets($this->connection, 512); 893 $response .= $result; 894 } 895 while (substr($result, 3, 1) !== ' '); 896 897 if (!preg_match('#^[123]#', $response)) 898 { 899 return false; 900 } 901 902 return ($return) ? $response : true; 903 } 904 } 905 906 ?>
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Oct 2 15:03:47 2013 | Cross-referenced by PHPXref 0.7.1 |