[ Index ] |
PHP Cross Reference of Joomla 4.2.2 documentation |
[Summary view] [Print] [Text view]
1 <?php 2 3 /** 4 * Joomla! Content Management System 5 * 6 * @copyright (C) 2005 Open Source Matters, Inc. <https://www.joomla.org> 7 * @license GNU General Public License version 2 or later; see LICENSE.txt 8 */ 9 10 namespace Joomla\CMS\Client; 11 12 \defined('JPATH_PLATFORM') or die; 13 14 use Joomla\CMS\Language\Text; 15 use Joomla\CMS\Log\Log; 16 use Joomla\CMS\Utility\BufferStreamHandler; 17 18 /** Error Codes: 19 * - 30 : Unable to connect to host 20 * - 31 : Not connected 21 * - 32 : Unable to send command to server 22 * - 33 : Bad username 23 * - 34 : Bad password 24 * - 35 : Bad response 25 * - 36 : Passive mode failed 26 * - 37 : Data transfer error 27 * - 38 : Local filesystem error 28 */ 29 30 if (!\defined('CRLF')) { 31 /** 32 * Constant defining a line break 33 * 34 * @var string 35 * @since 1.5 36 */ 37 \define('CRLF', "\r\n"); 38 } 39 40 if (!\defined('FTP_AUTOASCII')) { 41 /** 42 * Constant defining whether the FTP connection type will automatically determine ASCII support based on a file extension 43 * 44 * @var integer 45 * @since 1.5 46 */ 47 \define('FTP_AUTOASCII', -1); 48 } 49 50 if (!\defined('FTP_BINARY')) { 51 /** 52 * Stub of the native FTP_BINARY constant if PHP is running without the ftp extension enabled 53 * 54 * @var integer 55 * @since 1.5 56 */ 57 \define('FTP_BINARY', 1); 58 } 59 60 if (!\defined('FTP_ASCII')) { 61 /** 62 * Stub of the native FTP_ASCII constant if PHP is running without the ftp extension enabled 63 * 64 * @var integer 65 * @since 1.5 66 */ 67 \define('FTP_ASCII', 0); 68 } 69 70 if (!\defined('FTP_NATIVE')) { 71 /** 72 * Constant defining whether native FTP support is available on the platform 73 * 74 * @var integer 75 * @since 1.5 76 */ 77 \define('FTP_NATIVE', \function_exists('ftp_connect') ? 1 : 0); 78 } 79 80 /** 81 * FTP client class 82 * 83 * @since 1.5 84 */ 85 class FtpClient 86 { 87 /** 88 * @var resource Socket resource 89 * @since 1.5 90 */ 91 protected $_conn = null; 92 93 /** 94 * @var resource Data port connection resource 95 * @since 1.5 96 */ 97 protected $_dataconn = null; 98 99 /** 100 * @var array Passive connection information 101 * @since 1.5 102 */ 103 protected $_pasv = null; 104 105 /** 106 * @var string Response Message 107 * @since 1.5 108 */ 109 protected $_response = null; 110 111 /** 112 * @var integer Timeout limit 113 * @since 1.5 114 */ 115 protected $_timeout = 15; 116 117 /** 118 * @var integer Transfer Type 119 * @since 1.5 120 */ 121 protected $_type = null; 122 123 /** 124 * @var array Array to hold ascii format file extensions 125 * @since 1.5 126 */ 127 protected $_autoAscii = array( 128 'asp', 129 'bat', 130 'c', 131 'cpp', 132 'csv', 133 'h', 134 'htm', 135 'html', 136 'shtml', 137 'ini', 138 'inc', 139 'log', 140 'php', 141 'php3', 142 'pl', 143 'perl', 144 'sh', 145 'sql', 146 'txt', 147 'xhtml', 148 'xml', 149 ); 150 151 /** 152 * Array to hold native line ending characters 153 * 154 * @var array 155 * @since 1.5 156 */ 157 protected $_lineEndings = array('UNIX' => "\n", 'WIN' => "\r\n"); 158 159 /** 160 * @var array FtpClient instances container. 161 * @since 2.5 162 */ 163 protected static $instances = array(); 164 165 /** 166 * FtpClient object constructor 167 * 168 * @param array $options Associative array of options to set 169 * 170 * @since 1.5 171 */ 172 public function __construct(array $options = array()) 173 { 174 // If default transfer type is not set, set it to autoascii detect 175 if (!isset($options['type'])) { 176 $options['type'] = FTP_BINARY; 177 } 178 179 $this->setOptions($options); 180 181 if (FTP_NATIVE) { 182 BufferStreamHandler::stream_register(); 183 } 184 } 185 186 /** 187 * FtpClient object destructor 188 * 189 * Closes an existing connection, if we have one 190 * 191 * @since 1.5 192 */ 193 public function __destruct() 194 { 195 if (\is_resource($this->_conn)) { 196 $this->quit(); 197 } 198 } 199 200 /** 201 * Returns the global FTP connector object, only creating it 202 * if it doesn't already exist. 203 * 204 * You may optionally specify a username and password in the parameters. If you do so, 205 * you may not login() again with different credentials using the same object. 206 * If you do not use this option, you must quit() the current connection when you 207 * are done, to free it for use by others. 208 * 209 * @param string $host Host to connect to 210 * @param string $port Port to connect to 211 * @param array $options Array with any of these options: type=>[FTP_AUTOASCII|FTP_ASCII|FTP_BINARY], timeout=>(int) 212 * @param string $user Username to use for a connection 213 * @param string $pass Password to use for a connection 214 * 215 * @return FtpClient The FTP Client object. 216 * 217 * @since 1.5 218 */ 219 public static function getInstance($host = '127.0.0.1', $port = '21', array $options = array(), $user = null, $pass = null) 220 { 221 $signature = $user . ':' . $pass . '@' . $host . ':' . $port; 222 223 // Create a new instance, or set the options of an existing one 224 if (!isset(static::$instances[$signature]) || !\is_object(static::$instances[$signature])) { 225 static::$instances[$signature] = new static($options); 226 } else { 227 static::$instances[$signature]->setOptions($options); 228 } 229 230 // Connect to the server, and login, if requested 231 if (!static::$instances[$signature]->isConnected()) { 232 $return = static::$instances[$signature]->connect($host, $port); 233 234 if ($return && $user !== null && $pass !== null) { 235 static::$instances[$signature]->login($user, $pass); 236 } 237 } 238 239 return static::$instances[$signature]; 240 } 241 242 /** 243 * Set client options 244 * 245 * @param array $options Associative array of options to set 246 * 247 * @return boolean True if successful 248 * 249 * @since 1.5 250 */ 251 public function setOptions(array $options) 252 { 253 if (isset($options['type'])) { 254 $this->_type = $options['type']; 255 } 256 257 if (isset($options['timeout'])) { 258 $this->_timeout = $options['timeout']; 259 } 260 261 return true; 262 } 263 264 /** 265 * Method to connect to a FTP server 266 * 267 * @param string $host Host to connect to [Default: 127.0.0.1] 268 * @param int $port Port to connect on [Default: port 21] 269 * 270 * @return boolean True if successful 271 * 272 * @since 3.0.0 273 */ 274 public function connect($host = '127.0.0.1', $port = 21) 275 { 276 $errno = null; 277 $err = null; 278 279 // If already connected, return 280 if (\is_resource($this->_conn)) { 281 return true; 282 } 283 284 // If native FTP support is enabled let's use it... 285 if (FTP_NATIVE) { 286 $this->_conn = @ftp_connect($host, $port, $this->_timeout); 287 288 if ($this->_conn === false) { 289 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_NO_CONNECT', __METHOD__, $host, $port), Log::WARNING, 'jerror'); 290 291 return false; 292 } 293 294 // Set the timeout for this connection 295 ftp_set_option($this->_conn, FTP_TIMEOUT_SEC, $this->_timeout); 296 297 return true; 298 } 299 300 // Connect to the FTP server. 301 $this->_conn = @ fsockopen($host, $port, $errno, $err, $this->_timeout); 302 303 if (!$this->_conn) { 304 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_NO_CONNECT_SOCKET', __METHOD__, $host, $port, $errno, $err), Log::WARNING, 'jerror'); 305 306 return false; 307 } 308 309 // Set the timeout for this connection 310 socket_set_timeout($this->_conn, $this->_timeout, 0); 311 312 // Check for welcome response code 313 if (!$this->_verifyResponse(220)) { 314 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_NOT_EXPECTED_RESPONSE', __METHOD__, $this->_response, 220), Log::WARNING, 'jerror'); 315 316 return false; 317 } 318 319 return true; 320 } 321 322 /** 323 * Method to determine if the object is connected to an FTP server 324 * 325 * @return boolean True if connected 326 * 327 * @since 1.5 328 */ 329 public function isConnected() 330 { 331 return \is_resource($this->_conn); 332 } 333 334 /** 335 * Method to login to a server once connected 336 * 337 * @param string $user Username to login to the server 338 * @param string $pass Password to login to the server 339 * 340 * @return boolean True if successful 341 * 342 * @since 1.5 343 */ 344 public function login($user = 'anonymous', $pass = '[email protected]') 345 { 346 // If native FTP support is enabled let's use it... 347 if (FTP_NATIVE) { 348 if (@ftp_login($this->_conn, $user, $pass) === false) { 349 Log::add('JFtp::login: Unable to login', Log::WARNING, 'jerror'); 350 351 return false; 352 } 353 354 return true; 355 } 356 357 // Send the username 358 if (!$this->_putCmd('USER ' . $user, array(331, 503))) { 359 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_BAD_USERNAME', __METHOD__, $this->_response, $user), Log::WARNING, 'jerror'); 360 361 return false; 362 } 363 364 // If we are already logged in, continue :) 365 if ($this->_responseCode == 503) { 366 return true; 367 } 368 369 // Send the password 370 if (!$this->_putCmd('PASS ' . $pass, 230)) { 371 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_BAD_PASSWORD', __METHOD__, $this->_response, str_repeat('*', \strlen($pass))), Log::WARNING, 'jerror'); 372 373 return false; 374 } 375 376 return true; 377 } 378 379 /** 380 * Method to quit and close the connection 381 * 382 * @return boolean True if successful 383 * 384 * @since 1.5 385 */ 386 public function quit() 387 { 388 // If native FTP support is enabled lets use it... 389 if (FTP_NATIVE) { 390 @ftp_close($this->_conn); 391 392 return true; 393 } 394 395 // Logout and close connection 396 @fwrite($this->_conn, "QUIT\r\n"); 397 @fclose($this->_conn); 398 399 return true; 400 } 401 402 /** 403 * Method to retrieve the current working directory on the FTP server 404 * 405 * @return string Current working directory 406 * 407 * @since 1.5 408 */ 409 public function pwd() 410 { 411 // If native FTP support is enabled let's use it... 412 if (FTP_NATIVE) { 413 if (($ret = @ftp_pwd($this->_conn)) === false) { 414 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_BAD_RESPONSE', __METHOD__), Log::WARNING, 'jerror'); 415 416 return false; 417 } 418 419 return $ret; 420 } 421 422 $match = array(null); 423 424 // Send print working directory command and verify success 425 if (!$this->_putCmd('PWD', 257)) { 426 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_NOT_EXPECTED_RESPONSE', __METHOD__, $this->_response, 257), Log::WARNING, 'jerror'); 427 428 return false; 429 } 430 431 // Match just the path 432 preg_match('/"[^"\r\n]*"/', $this->_response, $match); 433 434 // Return the cleaned path 435 return preg_replace("/\"/", '', $match[0]); 436 } 437 438 /** 439 * Method to system string from the FTP server 440 * 441 * @return string System identifier string 442 * 443 * @since 1.5 444 */ 445 public function syst() 446 { 447 // If native FTP support is enabled lets use it... 448 if (FTP_NATIVE) { 449 if (($ret = @ftp_systype($this->_conn)) === false) { 450 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_BAD_RESPONSE', __METHOD__), Log::WARNING, 'jerror'); 451 452 return false; 453 } 454 } else { 455 // Send print working directory command and verify success 456 if (!$this->_putCmd('SYST', 215)) { 457 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_NOT_EXPECTED_RESPONSE', __METHOD__, $this->_response, 215), Log::WARNING, 'jerror'); 458 459 return false; 460 } 461 462 $ret = $this->_response; 463 } 464 465 // Match the system string to an OS 466 if (strpos(strtoupper($ret), 'MAC') !== false) { 467 $ret = 'MAC'; 468 } elseif (strpos(strtoupper($ret), 'WIN') !== false) { 469 $ret = 'WIN'; 470 } else { 471 $ret = 'UNIX'; 472 } 473 474 // Return the os type 475 return $ret; 476 } 477 478 /** 479 * Method to change the current working directory on the FTP server 480 * 481 * @param string $path Path to change into on the server 482 * 483 * @return boolean True if successful 484 * 485 * @since 1.5 486 */ 487 public function chdir($path) 488 { 489 // If native FTP support is enabled lets use it... 490 if (FTP_NATIVE) { 491 if (@ftp_chdir($this->_conn, $path) === false) { 492 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_BAD_RESPONSE', __METHOD__), Log::WARNING, 'jerror'); 493 494 return false; 495 } 496 497 return true; 498 } 499 500 // Send change directory command and verify success 501 if (!$this->_putCmd('CWD ' . $path, 250)) { 502 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_NOT_EXPECTED_RESPONSE_PATH_SENT', __METHOD__, $this->_response, 250, $path), Log::WARNING, 'jerror'); 503 504 return false; 505 } 506 507 return true; 508 } 509 510 /** 511 * Method to reinitialise the server, ie. need to login again 512 * 513 * NOTE: This command not available on all servers 514 * 515 * @return boolean True if successful 516 * 517 * @since 1.5 518 */ 519 public function reinit() 520 { 521 // If native FTP support is enabled let's use it... 522 if (FTP_NATIVE) { 523 if (@ftp_site($this->_conn, 'REIN') === false) { 524 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_BAD_RESPONSE', __METHOD__), Log::WARNING, 'jerror'); 525 526 return false; 527 } 528 529 return true; 530 } 531 532 // Send reinitialise command to the server 533 if (!$this->_putCmd('REIN', 220)) { 534 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_NOT_EXPECTED_RESPONSE', __METHOD__, $this->_response, 220), Log::WARNING, 'jerror'); 535 536 return false; 537 } 538 539 return true; 540 } 541 542 /** 543 * Method to rename a file/folder on the FTP server 544 * 545 * @param string $from Path to change file/folder from 546 * @param string $to Path to change file/folder to 547 * 548 * @return boolean True if successful 549 * 550 * @since 1.5 551 */ 552 public function rename($from, $to) 553 { 554 // If native FTP support is enabled let's use it... 555 if (FTP_NATIVE) { 556 if (@ftp_rename($this->_conn, $from, $to) === false) { 557 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_BAD_RESPONSE', __METHOD__), Log::WARNING, 'jerror'); 558 559 return false; 560 } 561 562 return true; 563 } 564 565 // Send rename from command to the server 566 if (!$this->_putCmd('RNFR ' . $from, 350)) { 567 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_RENAME_BAD_RESPONSE_FROM', __METHOD__, $this->_response, $from), Log::WARNING, 'jerror'); 568 569 return false; 570 } 571 572 // Send rename to command to the server 573 if (!$this->_putCmd('RNTO ' . $to, 250)) { 574 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_RENAME_BAD_RESPONSE_TO', __METHOD__, $this->_response, $to), Log::WARNING, 'jerror'); 575 576 return false; 577 } 578 579 return true; 580 } 581 582 /** 583 * Method to change mode for a path on the FTP server 584 * 585 * @param string $path Path to change mode on 586 * @param mixed $mode Octal value to change mode to, e.g. '0777', 0777 or 511 (string or integer) 587 * 588 * @return boolean True if successful 589 * 590 * @since 1.5 591 */ 592 public function chmod($path, $mode) 593 { 594 // If no filename is given, we assume the current directory is the target 595 if ($path == '') { 596 $path = '.'; 597 } 598 599 // Convert the mode to a string 600 if (\is_int($mode)) { 601 $mode = decoct($mode); 602 } 603 604 // If native FTP support is enabled let's use it... 605 if (FTP_NATIVE) { 606 if (@ftp_site($this->_conn, 'CHMOD ' . $mode . ' ' . $path) === false) { 607 if (!IS_WIN) { 608 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_BAD_RESPONSE', __METHOD__), Log::WARNING, 'jerror'); 609 } 610 611 return false; 612 } 613 614 return true; 615 } 616 617 // Send change mode command and verify success [must convert mode from octal] 618 if (!$this->_putCmd('SITE CHMOD ' . $mode . ' ' . $path, array(200, 250))) { 619 if (!IS_WIN) { 620 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_CHMOD_BAD_RESPONSE', __METHOD__, $this->_response, $path, $mode), Log::WARNING, 'jerror'); 621 } 622 623 return false; 624 } 625 626 return true; 627 } 628 629 /** 630 * Method to delete a path [file/folder] on the FTP server 631 * 632 * @param string $path Path to delete 633 * 634 * @return boolean True if successful 635 * 636 * @since 1.5 637 */ 638 public function delete($path) 639 { 640 // If native FTP support is enabled let's use it... 641 if (FTP_NATIVE) { 642 if (@ftp_delete($this->_conn, $path) === false) { 643 if (@ftp_rmdir($this->_conn, $path) === false) { 644 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_BAD_RESPONSE', __METHOD__), Log::WARNING, 'jerror'); 645 646 return false; 647 } 648 } 649 650 return true; 651 } 652 653 // Send delete file command and if that doesn't work, try to remove a directory 654 if (!$this->_putCmd('DELE ' . $path, 250)) { 655 if (!$this->_putCmd('RMD ' . $path, 250)) { 656 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_NOT_EXPECTED_RESPONSE_PATH_SENT', __METHOD__, $this->_response, 250, $path), Log::WARNING, 'jerror'); 657 658 return false; 659 } 660 } 661 662 return true; 663 } 664 665 /** 666 * Method to create a directory on the FTP server 667 * 668 * @param string $path Directory to create 669 * 670 * @return boolean True if successful 671 * 672 * @since 1.5 673 */ 674 public function mkdir($path) 675 { 676 // If native FTP support is enabled let's use it... 677 if (FTP_NATIVE) { 678 if (@ftp_mkdir($this->_conn, $path) === false) { 679 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_BAD_RESPONSE', __METHOD__), Log::WARNING, 'jerror'); 680 681 return false; 682 } 683 684 return true; 685 } 686 687 // Send change directory command and verify success 688 if (!$this->_putCmd('MKD ' . $path, 257)) { 689 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_NOT_EXPECTED_RESPONSE_PATH_SENT', __METHOD__, $this->_response, 257, $path), Log::WARNING, 'jerror'); 690 691 return false; 692 } 693 694 return true; 695 } 696 697 /** 698 * Method to restart data transfer at a given byte 699 * 700 * @param integer $point Byte to restart transfer at 701 * 702 * @return boolean True if successful 703 * 704 * @since 1.5 705 */ 706 public function restart($point) 707 { 708 // If native FTP support is enabled let's use it... 709 if (FTP_NATIVE) { 710 if (@ftp_site($this->_conn, 'REST ' . $point) === false) { 711 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_BAD_RESPONSE', __METHOD__), Log::WARNING, 'jerror'); 712 713 return false; 714 } 715 716 return true; 717 } 718 719 // Send restart command and verify success 720 if (!$this->_putCmd('REST ' . $point, 350)) { 721 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_RESTART_BAD_RESPONSE', __METHOD__, $this->_response, $point), Log::WARNING, 'jerror'); 722 723 return false; 724 } 725 726 return true; 727 } 728 729 /** 730 * Method to create an empty file on the FTP server 731 * 732 * @param string $path Path local file to store on the FTP server 733 * 734 * @return boolean True if successful 735 * 736 * @since 1.5 737 */ 738 public function create($path) 739 { 740 // If native FTP support is enabled let's use it... 741 if (FTP_NATIVE) { 742 // Turn passive mode on 743 if (@ftp_pasv($this->_conn, true) === false) { 744 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_PASSIVE', __METHOD__), Log::WARNING, 'jerror'); 745 746 return false; 747 } 748 749 $buffer = fopen('buffer://tmp', 'r'); 750 751 if (@ftp_fput($this->_conn, $path, $buffer, FTP_ASCII) === false) { 752 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_BAD_RESPONSE', __METHOD__), Log::WARNING, 'jerror'); 753 fclose($buffer); 754 755 return false; 756 } 757 758 fclose($buffer); 759 760 return true; 761 } 762 763 // Start passive mode 764 if (!$this->_passive()) { 765 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_PASSIVE', __METHOD__), Log::WARNING, 'jerror'); 766 767 return false; 768 } 769 770 if (!$this->_putCmd('STOR ' . $path, array(150, 125))) { 771 @ fclose($this->_dataconn); 772 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_NOT_EXPECTED_RESPONSE_150_125', __METHOD__, $this->_response, $path), Log::WARNING, 'jerror'); 773 774 return false; 775 } 776 777 // To create a zero byte upload close the data port connection 778 fclose($this->_dataconn); 779 780 if (!$this->_verifyResponse(226)) { 781 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_TRANSFER_FAILED', __METHOD__, $this->_response, $path), Log::WARNING, 'jerror'); 782 783 return false; 784 } 785 786 return true; 787 } 788 789 /** 790 * Method to read a file from the FTP server's contents into a buffer 791 * 792 * @param string $remote Path to remote file to read on the FTP server 793 * @param string &$buffer Buffer variable to read file contents into 794 * 795 * @return boolean True if successful 796 * 797 * @since 1.5 798 */ 799 public function read($remote, &$buffer) 800 { 801 // Determine file type 802 $mode = $this->_findMode($remote); 803 804 // If native FTP support is enabled let's use it... 805 if (FTP_NATIVE) { 806 // Turn passive mode on 807 if (@ftp_pasv($this->_conn, true) === false) { 808 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_PASSIVE', __METHOD__), Log::WARNING, 'jerror'); 809 810 return false; 811 } 812 813 $tmp = fopen('buffer://tmp', 'br+'); 814 815 if (@ftp_fget($this->_conn, $tmp, $remote, $mode) === false) { 816 fclose($tmp); 817 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_BAD_RESPONSE', __METHOD__), Log::WARNING, 'jerror'); 818 819 return false; 820 } 821 822 // Read tmp buffer contents 823 rewind($tmp); 824 $buffer = ''; 825 826 while (!feof($tmp)) { 827 $buffer .= fread($tmp, 8192); 828 } 829 830 fclose($tmp); 831 832 return true; 833 } 834 835 $this->_mode($mode); 836 837 // Start passive mode 838 if (!$this->_passive()) { 839 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_PASSIVE', __METHOD__), Log::WARNING, 'jerror'); 840 841 return false; 842 } 843 844 if (!$this->_putCmd('RETR ' . $remote, array(150, 125))) { 845 @ fclose($this->_dataconn); 846 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_NOT_EXPECTED_RESPONSE_150_125', __METHOD__, $this->_response, $remote), Log::WARNING, 'jerror'); 847 848 return false; 849 } 850 851 // Read data from data port connection and add to the buffer 852 $buffer = ''; 853 854 while (!feof($this->_dataconn)) { 855 $buffer .= fread($this->_dataconn, 4096); 856 } 857 858 // Close the data port connection 859 fclose($this->_dataconn); 860 861 // Let's try to cleanup some line endings if it is ascii 862 if ($mode == FTP_ASCII) { 863 $os = 'UNIX'; 864 865 if (IS_WIN) { 866 $os = 'WIN'; 867 } 868 869 $buffer = preg_replace('/' . CRLF . '/', $this->_lineEndings[$os], $buffer); 870 } 871 872 if (!$this->_verifyResponse(226)) { 873 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_TRANSFER_FAILED', __METHOD__, $this->_response, $remote), Log::WARNING, 'jerror'); 874 875 return false; 876 } 877 878 return true; 879 } 880 881 /** 882 * Method to get a file from the FTP server and save it to a local file 883 * 884 * @param string $local Local path to save remote file to 885 * @param string $remote Path to remote file to get on the FTP server 886 * 887 * @return boolean True if successful 888 * 889 * @since 1.5 890 */ 891 public function get($local, $remote) 892 { 893 // Determine file type 894 $mode = $this->_findMode($remote); 895 896 // If native FTP support is enabled let's use it... 897 if (FTP_NATIVE) { 898 // Turn passive mode on 899 if (@ftp_pasv($this->_conn, true) === false) { 900 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_PASSIVE', __METHOD__), Log::WARNING, 'jerror'); 901 902 return false; 903 } 904 905 if (@ftp_get($this->_conn, $local, $remote, $mode) === false) { 906 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_BAD_RESPONSE', __METHOD__), Log::WARNING, 'jerror'); 907 908 return false; 909 } 910 911 return true; 912 } 913 914 $this->_mode($mode); 915 916 // Check to see if the local file can be opened for writing 917 $fp = fopen($local, 'wb'); 918 919 if (!$fp) { 920 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_LOCAL_FILE_OPEN_WRITING', __METHOD__, $local), Log::WARNING, 'jerror'); 921 922 return false; 923 } 924 925 // Start passive mode 926 if (!$this->_passive()) { 927 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_PASSIVE', __METHOD__), Log::WARNING, 'jerror'); 928 929 return false; 930 } 931 932 if (!$this->_putCmd('RETR ' . $remote, array(150, 125))) { 933 @ fclose($this->_dataconn); 934 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_NOT_EXPECTED_RESPONSE_150_125', __METHOD__, $this->_response, $remote), Log::WARNING, 'jerror'); 935 936 return false; 937 } 938 939 // Read data from data port connection and add to the buffer 940 while (!feof($this->_dataconn)) { 941 $buffer = fread($this->_dataconn, 4096); 942 fwrite($fp, $buffer, 4096); 943 } 944 945 // Close the data port connection and file pointer 946 fclose($this->_dataconn); 947 fclose($fp); 948 949 if (!$this->_verifyResponse(226)) { 950 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_TRANSFER_FAILED', __METHOD__, $this->_response, $remote), Log::WARNING, 'jerror'); 951 952 return false; 953 } 954 955 return true; 956 } 957 958 /** 959 * Method to store a file to the FTP server 960 * 961 * @param string $local Path to local file to store on the FTP server 962 * @param string $remote FTP path to file to create 963 * 964 * @return boolean True if successful 965 * 966 * @since 1.5 967 */ 968 public function store($local, $remote = null) 969 { 970 // If remote file is not given, use the filename of the local file in the current 971 // working directory. 972 if ($remote == null) { 973 $remote = basename($local); 974 } 975 976 // Determine file type 977 $mode = $this->_findMode($remote); 978 979 // If native FTP support is enabled let's use it... 980 if (FTP_NATIVE) { 981 // Turn passive mode on 982 if (@ftp_pasv($this->_conn, true) === false) { 983 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_PASSIVE', __METHOD__), Log::WARNING, 'jerror'); 984 985 return false; 986 } 987 988 if (@ftp_put($this->_conn, $remote, $local, $mode) === false) { 989 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_BAD_RESPONSE', __METHOD__), Log::WARNING, 'jerror'); 990 991 return false; 992 } 993 994 return true; 995 } 996 997 $this->_mode($mode); 998 999 // Check to see if the local file exists and if so open it for reading 1000 if (@ file_exists($local)) { 1001 $fp = fopen($local, 'rb'); 1002 1003 if (!$fp) { 1004 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_LOCAL_FILE_OPEN_READING', __METHOD__, $local), Log::WARNING, 'jerror'); 1005 1006 return false; 1007 } 1008 } else { 1009 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_LOCAL_FILE_FIND', __METHOD__, $local), Log::WARNING, 'jerror'); 1010 1011 return false; 1012 } 1013 1014 // Start passive mode 1015 if (!$this->_passive()) { 1016 @ fclose($fp); 1017 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_PASSIVE', __METHOD__), Log::WARNING, 'jerror'); 1018 1019 return false; 1020 } 1021 1022 // Send store command to the FTP server 1023 if (!$this->_putCmd('STOR ' . $remote, array(150, 125))) { 1024 @ fclose($fp); 1025 @ fclose($this->_dataconn); 1026 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_NOT_EXPECTED_RESPONSE_150_125', __METHOD__, $this->_response, $remote), Log::WARNING, 'jerror'); 1027 1028 return false; 1029 } 1030 1031 // Do actual file transfer, read local file and write to data port connection 1032 while (!feof($fp)) { 1033 $line = fread($fp, 4096); 1034 1035 do { 1036 if (($result = @ fwrite($this->_dataconn, $line)) === false) { 1037 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_DATA_PORT', __METHOD__), Log::WARNING, 'jerror'); 1038 1039 return false; 1040 } 1041 1042 $line = substr($line, $result); 1043 } while ($line != ''); 1044 } 1045 1046 fclose($fp); 1047 fclose($this->_dataconn); 1048 1049 if (!$this->_verifyResponse(226)) { 1050 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_TRANSFER_FAILED', __METHOD__, $this->_response, $remote), Log::WARNING, 'jerror'); 1051 1052 return false; 1053 } 1054 1055 return true; 1056 } 1057 1058 /** 1059 * Method to write a string to the FTP server 1060 * 1061 * @param string $remote FTP path to file to write to 1062 * @param string $buffer Contents to write to the FTP server 1063 * 1064 * @return boolean True if successful 1065 * 1066 * @since 1.5 1067 */ 1068 public function write($remote, $buffer) 1069 { 1070 // Determine file type 1071 $mode = $this->_findMode($remote); 1072 1073 // If native FTP support is enabled let's use it... 1074 if (FTP_NATIVE) { 1075 // Turn passive mode on 1076 if (@ftp_pasv($this->_conn, true) === false) { 1077 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_PASSIVE', __METHOD__), Log::WARNING, 'jerror'); 1078 1079 return false; 1080 } 1081 1082 $tmp = fopen('buffer://tmp', 'br+'); 1083 fwrite($tmp, $buffer); 1084 rewind($tmp); 1085 1086 if (@ftp_fput($this->_conn, $remote, $tmp, $mode) === false) { 1087 fclose($tmp); 1088 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_BAD_RESPONSE', __METHOD__), Log::WARNING, 'jerror'); 1089 1090 return false; 1091 } 1092 1093 fclose($tmp); 1094 1095 return true; 1096 } 1097 1098 // First we need to set the transfer mode 1099 $this->_mode($mode); 1100 1101 // Start passive mode 1102 if (!$this->_passive()) { 1103 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_PASSIVE', __METHOD__), Log::WARNING, 'jerror'); 1104 1105 return false; 1106 } 1107 1108 // Send store command to the FTP server 1109 if (!$this->_putCmd('STOR ' . $remote, array(150, 125))) { 1110 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_NOT_EXPECTED_RESPONSE_150_125', __METHOD__, $this->_response, $remote), Log::WARNING, 'jerror'); 1111 @ fclose($this->_dataconn); 1112 1113 return false; 1114 } 1115 1116 // Write buffer to the data connection port 1117 do { 1118 if (($result = @ fwrite($this->_dataconn, $buffer)) === false) { 1119 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_DATA_PORT', __METHOD__), Log::WARNING, 'jerror'); 1120 1121 return false; 1122 } 1123 1124 $buffer = substr($buffer, $result); 1125 } while ($buffer != ''); 1126 1127 // Close the data connection port [Data transfer complete] 1128 fclose($this->_dataconn); 1129 1130 // Verify that the server received the transfer 1131 if (!$this->_verifyResponse(226)) { 1132 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_TRANSFER_FAILED', __METHOD__, $this->_response, $remote), Log::WARNING, 'jerror'); 1133 1134 return false; 1135 } 1136 1137 return true; 1138 } 1139 1140 /** 1141 * Method to append a string to the FTP server 1142 * 1143 * @param string $remote FTP path to file to append to 1144 * @param string $buffer Contents to append to the FTP server 1145 * 1146 * @return boolean True if successful 1147 * 1148 * @since 3.6.0 1149 */ 1150 public function append($remote, $buffer) 1151 { 1152 // Determine file type 1153 $mode = $this->_findMode($remote); 1154 1155 // If native FTP support is enabled let's use it... 1156 if (FTP_NATIVE) { 1157 // Turn passive mode on 1158 if (@ftp_pasv($this->_conn, true) === false) { 1159 throw new \RuntimeException(Text::sprintf('JLIB_CLIENT_ERROR_FTP_PASSIVE', __METHOD__), 36); 1160 } 1161 1162 $tmp = fopen('buffer://tmp', 'bw+'); 1163 fwrite($tmp, $buffer); 1164 rewind($tmp); 1165 1166 $size = $this->size($remote); 1167 1168 if ($size === false) { 1169 } 1170 1171 if (@ftp_fput($this->_conn, $remote, $tmp, $mode, $size) === false) { 1172 fclose($tmp); 1173 1174 throw new \RuntimeException(Text::sprintf('JLIB_CLIENT_ERROR_FTP_BAD_RESPONSE', __METHOD__), 35); 1175 } 1176 1177 fclose($tmp); 1178 1179 return true; 1180 } 1181 1182 // First we need to set the transfer mode 1183 $this->_mode($mode); 1184 1185 // Start passive mode 1186 if (!$this->_passive()) { 1187 throw new \RuntimeException(Text::sprintf('JLIB_CLIENT_ERROR_FTP_PASSIVE', __METHOD__), 36); 1188 } 1189 1190 // Send store command to the FTP server 1191 if (!$this->_putCmd('APPE ' . $remote, array(150, 125))) { 1192 @fclose($this->_dataconn); 1193 1194 throw new \RuntimeException(Text::sprintf('JLIB_CLIENT_ERROR_FTP_NOT_EXPECTED_RESPONSE_150_125', __METHOD__, $this->_response, $remote), 35); 1195 } 1196 1197 // Write buffer to the data connection port 1198 do { 1199 if (($result = @ fwrite($this->_dataconn, $buffer)) === false) { 1200 throw new \RuntimeException(Text::sprintf('JLIB_CLIENT_ERROR_FTP_DATA_PORT', __METHOD__), 37); 1201 } 1202 1203 $buffer = substr($buffer, $result); 1204 } while ($buffer != ''); 1205 1206 // Close the data connection port [Data transfer complete] 1207 fclose($this->_dataconn); 1208 1209 // Verify that the server received the transfer 1210 if (!$this->_verifyResponse(226)) { 1211 throw new \RuntimeException(Text::sprintf('JLIB_CLIENT_ERROR_FTP_TRANSFER_FAILED', __METHOD__, $this->_response, $remote), 37); 1212 } 1213 1214 return true; 1215 } 1216 1217 /** 1218 * Get the size of the remote file. 1219 * 1220 * @param string $remote FTP path to file whose size to get 1221 * 1222 * @return mixed number of bytes or false on error 1223 * 1224 * @since 3.6.0 1225 */ 1226 public function size($remote) 1227 { 1228 if (FTP_NATIVE) { 1229 $size = ftp_size($this->_conn, $remote); 1230 1231 // In case ftp_size fails, try the SIZE command directly. 1232 if ($size === -1) { 1233 $response = ftp_raw($this->_conn, 'SIZE ' . $remote); 1234 $responseCode = substr($response[0], 0, 3); 1235 $responseMessage = substr($response[0], 4); 1236 1237 if ($responseCode != '213') { 1238 throw new \RuntimeException(Text::sprintf('JLIB_CLIENT_ERROR_FTP_BAD_RESPONSE', __METHOD__), 35); 1239 } 1240 1241 $size = (int) $responseMessage; 1242 } 1243 1244 return $size; 1245 } 1246 1247 // Start passive mode 1248 if (!$this->_passive()) { 1249 throw new \RuntimeException(Text::sprintf('JLIB_CLIENT_ERROR_FTP_PASSIVE', __METHOD__), 36); 1250 } 1251 1252 // Send size command to the FTP server 1253 if (!$this->_putCmd('SIZE ' . $remote, array(213))) { 1254 @fclose($this->_dataconn); 1255 1256 throw new \RuntimeException(Text::sprintf('JLIB_CLIENT_ERROR_FTP_NOT_EXPECTED_RESPONSE_PATH_SENT', __METHOD__, $this->_response, 213, $remote), 35); 1257 } 1258 1259 return (int) substr($this->_responseMsg, 4); 1260 } 1261 1262 /** 1263 * Method to list the filenames of the contents of a directory on the FTP server 1264 * 1265 * Note: Some servers also return folder names. However, to be sure to list folders on all 1266 * servers, you should use listDetails() instead if you also need to deal with folders 1267 * 1268 * @param string $path Path local file to store on the FTP server 1269 * 1270 * @return string Directory listing 1271 * 1272 * @since 1.5 1273 */ 1274 public function listNames($path = null) 1275 { 1276 $data = null; 1277 1278 // If native FTP support is enabled let's use it... 1279 if (FTP_NATIVE) { 1280 // Turn passive mode on 1281 if (@ftp_pasv($this->_conn, true) === false) { 1282 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_PASSIVE', __METHOD__), Log::WARNING, 'jerror'); 1283 1284 return false; 1285 } 1286 1287 if (($list = @ftp_nlist($this->_conn, $path)) === false) { 1288 // Workaround for empty directories on some servers 1289 if ($this->listDetails($path, 'files') === array()) { 1290 return array(); 1291 } 1292 1293 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_BAD_RESPONSE', __METHOD__), Log::WARNING, 'jerror'); 1294 1295 return false; 1296 } 1297 1298 $list = preg_replace('#^' . preg_quote($path, '#') . '[/\\\\]?#', '', $list); 1299 1300 if ($keys = array_merge(array_keys($list, '.'), array_keys($list, '..'))) { 1301 foreach ($keys as $key) { 1302 unset($list[$key]); 1303 } 1304 } 1305 1306 return $list; 1307 } 1308 1309 // If a path exists, prepend a space 1310 if ($path != null) { 1311 $path = ' ' . $path; 1312 } 1313 1314 // Start passive mode 1315 if (!$this->_passive()) { 1316 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_PASSIVE', __METHOD__), Log::WARNING, 'jerror'); 1317 1318 return false; 1319 } 1320 1321 if (!$this->_putCmd('NLST' . $path, array(150, 125))) { 1322 @ fclose($this->_dataconn); 1323 1324 // Workaround for empty directories on some servers 1325 if ($this->listDetails($path, 'files') === array()) { 1326 return array(); 1327 } 1328 1329 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_NOT_EXPECTED_RESPONSE_150_125', __METHOD__, $this->_response, $path), Log::WARNING, 'jerror'); 1330 1331 return false; 1332 } 1333 1334 // Read in the file listing. 1335 while (!feof($this->_dataconn)) { 1336 $data .= fread($this->_dataconn, 4096); 1337 } 1338 1339 fclose($this->_dataconn); 1340 1341 // Everything go okay? 1342 if (!$this->_verifyResponse(226)) { 1343 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_TRANSFER_FAILED', __METHOD__, $this->_response, $path), Log::WARNING, 'jerror'); 1344 1345 return false; 1346 } 1347 1348 $data = preg_split('/[' . CRLF . ']+/', $data, -1, PREG_SPLIT_NO_EMPTY); 1349 $data = preg_replace('#^' . preg_quote(substr($path, 1), '#') . '[/\\\\]?#', '', $data); 1350 1351 if ($keys = array_merge(array_keys($data, '.'), array_keys($data, '..'))) { 1352 foreach ($keys as $key) { 1353 unset($data[$key]); 1354 } 1355 } 1356 1357 return $data; 1358 } 1359 1360 /** 1361 * Method to list the contents of a directory on the FTP server 1362 * 1363 * @param string $path Path to the local file to be stored on the FTP server 1364 * @param string $type Return type [raw|all|folders|files] 1365 * 1366 * @return mixed If $type is raw: string Directory listing, otherwise array of string with file-names 1367 * 1368 * @since 1.5 1369 */ 1370 public function listDetails($path = null, $type = 'all') 1371 { 1372 $dir_list = array(); 1373 $data = null; 1374 $regs = null; 1375 1376 // @todo: Deal with recurse -- nightmare 1377 // For now we will just set it to false 1378 $recurse = false; 1379 1380 // If native FTP support is enabled let's use it... 1381 if (FTP_NATIVE) { 1382 // Turn passive mode on 1383 if (@ftp_pasv($this->_conn, true) === false) { 1384 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_PASSIVE', __METHOD__), Log::WARNING, 'jerror'); 1385 1386 return false; 1387 } 1388 1389 if (($contents = @ftp_rawlist($this->_conn, $path)) === false) { 1390 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_BAD_RESPONSE', __METHOD__), Log::WARNING, 'jerror'); 1391 1392 return false; 1393 } 1394 } else { 1395 // Non Native mode 1396 1397 // Start passive mode 1398 if (!$this->_passive()) { 1399 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_PASSIVE', __METHOD__), Log::WARNING, 'jerror'); 1400 1401 return false; 1402 } 1403 1404 // If a path exists, prepend a space 1405 if ($path != null) { 1406 $path = ' ' . $path; 1407 } 1408 1409 // Request the file listing 1410 if (!$this->_putCmd(($recurse == true) ? 'LIST -R' : 'LIST' . $path, array(150, 125))) { 1411 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_NOT_EXPECTED_RESPONSE_150_125', __METHOD__, $this->_response, $path), Log::WARNING, 'jerror'); 1412 @ fclose($this->_dataconn); 1413 1414 return false; 1415 } 1416 1417 // Read in the file listing. 1418 while (!feof($this->_dataconn)) { 1419 $data .= fread($this->_dataconn, 4096); 1420 } 1421 1422 fclose($this->_dataconn); 1423 1424 // Everything go okay? 1425 if (!$this->_verifyResponse(226)) { 1426 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_TRANSFER_FAILED', __METHOD__, $this->_response, $path), Log::WARNING, 'jerror'); 1427 1428 return false; 1429 } 1430 1431 $contents = explode(CRLF, $data); 1432 } 1433 1434 // If only raw output is requested we are done 1435 if ($type === 'raw') { 1436 return $data; 1437 } 1438 1439 // If we received the listing of an empty directory, we are done as well 1440 if (empty($contents[0])) { 1441 return $dir_list; 1442 } 1443 1444 // If the server returned the number of results in the first response, let's dump it 1445 if (strtolower(substr($contents[0], 0, 6)) === 'total ') { 1446 array_shift($contents); 1447 1448 if (!isset($contents[0]) || empty($contents[0])) { 1449 return $dir_list; 1450 } 1451 } 1452 1453 // Regular expressions for the directory listing parsing. 1454 $regexps = array( 1455 'UNIX' => '#([-dl][rwxstST-]+).* ([0-9]*) ([a-zA-Z0-9]+).* ([a-zA-Z0-9]+).* ([0-9]*)' 1456 . ' ([a-zA-Z]+[0-9: ]*[0-9])[ ]+(([0-9]{1,2}:[0-9]{2})|[0-9]{4}) (.+)#', 1457 'MAC' => '#([-dl][rwxstST-]+).* ?([0-9 ]*)?([a-zA-Z0-9]+).* ([a-zA-Z0-9]+).* ([0-9]*)' 1458 . ' ([a-zA-Z]+[0-9: ]*[0-9])[ ]+(([0-9]{2}:[0-9]{2})|[0-9]{4}) (.+)#', 1459 'WIN' => '#([0-9]{2})-([0-9]{2})-([0-9]{2}) +([0-9]{2}):([0-9]{2})(AM|PM) +([0-9]+|<DIR>) +(.+)#', 1460 ); 1461 1462 // Find out the format of the directory listing by matching one of the regexps 1463 $osType = null; 1464 1465 foreach ($regexps as $k => $v) { 1466 if (@preg_match($v, $contents[0])) { 1467 $osType = $k; 1468 $regexp = $v; 1469 break; 1470 } 1471 } 1472 1473 if (!$osType) { 1474 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_UNRECOGNISED_FOLDER_LISTING_FORMATJLIB_CLIENT_ERROR_JFTP_LISTDETAILS_UNRECOGNISED', __METHOD__), Log::WARNING, 'jerror'); 1475 1476 return false; 1477 } 1478 1479 // Here is where it is going to get dirty.... 1480 if ($osType === 'UNIX' || $osType === 'MAC') { 1481 foreach ($contents as $file) { 1482 $tmp_array = null; 1483 1484 if (@preg_match($regexp, $file, $regs)) { 1485 $fType = (int) strpos('-dl', $regs[1][0]); 1486 1487 // $tmp_array['line'] = $regs[0]; 1488 $tmp_array['type'] = $fType; 1489 $tmp_array['rights'] = $regs[1]; 1490 1491 // $tmp_array['number'] = $regs[2]; 1492 $tmp_array['user'] = $regs[3]; 1493 $tmp_array['group'] = $regs[4]; 1494 $tmp_array['size'] = $regs[5]; 1495 $tmp_array['date'] = @date('m-d', strtotime($regs[6])); 1496 $tmp_array['time'] = $regs[7]; 1497 $tmp_array['name'] = $regs[9]; 1498 } 1499 1500 // If we just want files, do not add a folder 1501 if ($type === 'files' && $tmp_array['type'] == 1) { 1502 continue; 1503 } 1504 1505 // If we just want folders, do not add a file 1506 if ($type === 'folders' && $tmp_array['type'] == 0) { 1507 continue; 1508 } 1509 1510 if (\is_array($tmp_array) && $tmp_array['name'] != '.' && $tmp_array['name'] != '..') { 1511 $dir_list[] = $tmp_array; 1512 } 1513 } 1514 } else { 1515 foreach ($contents as $file) { 1516 $tmp_array = null; 1517 1518 if (@preg_match($regexp, $file, $regs)) { 1519 $fType = (int) ($regs[7] === '<DIR>'); 1520 $timestamp = strtotime("$regs[3]-$regs[1]-$regs[2] $regs[4]:$regs[5]$regs[6]"); 1521 1522 // $tmp_array['line'] = $regs[0]; 1523 $tmp_array['type'] = $fType; 1524 $tmp_array['rights'] = ''; 1525 1526 // $tmp_array['number'] = 0; 1527 $tmp_array['user'] = ''; 1528 $tmp_array['group'] = ''; 1529 $tmp_array['size'] = (int) $regs[7]; 1530 $tmp_array['date'] = date('m-d', $timestamp); 1531 $tmp_array['time'] = date('H:i', $timestamp); 1532 $tmp_array['name'] = $regs[8]; 1533 } 1534 1535 // If we just want files, do not add a folder 1536 if ($type === 'files' && $tmp_array['type'] == 1) { 1537 continue; 1538 } 1539 1540 // If we just want folders, do not add a file 1541 if ($type === 'folders' && $tmp_array['type'] == 0) { 1542 continue; 1543 } 1544 1545 if (\is_array($tmp_array) && $tmp_array['name'] != '.' && $tmp_array['name'] != '..') { 1546 $dir_list[] = $tmp_array; 1547 } 1548 } 1549 } 1550 1551 return $dir_list; 1552 } 1553 1554 /** 1555 * Send command to the FTP server and validate an expected response code 1556 * 1557 * @param string $cmd Command to send to the FTP server 1558 * @param mixed $expectedResponse Integer response code or array of integer response codes 1559 * 1560 * @return boolean True if command executed successfully 1561 * 1562 * @since 1.5 1563 */ 1564 protected function _putCmd($cmd, $expectedResponse) 1565 { 1566 // Make sure we have a connection to the server 1567 if (!\is_resource($this->_conn)) { 1568 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_PUTCMD_UNCONNECTED', __METHOD__), Log::WARNING, 'jerror'); 1569 1570 return false; 1571 } 1572 1573 // Send the command to the server 1574 if (!fwrite($this->_conn, $cmd . "\r\n")) { 1575 Log::add(Text::sprintf('DDD', Text::sprintf('JLIB_CLIENT_ERROR_FTP_PUTCMD_SEND', __METHOD__, $cmd)), Log::WARNING, 'jerror'); 1576 } 1577 1578 return $this->_verifyResponse($expectedResponse); 1579 } 1580 1581 /** 1582 * Verify the response code from the server and log response if flag is set 1583 * 1584 * @param mixed $expected Integer response code or array of integer response codes 1585 * 1586 * @return boolean True if response code from the server is expected 1587 * 1588 * @since 1.5 1589 */ 1590 protected function _verifyResponse($expected) 1591 { 1592 $parts = null; 1593 1594 // Wait for a response from the server, but timeout after the set time limit 1595 $endTime = time() + $this->_timeout; 1596 $this->_response = ''; 1597 1598 do { 1599 $this->_response .= fgets($this->_conn, 4096); 1600 } while (!preg_match('/^([0-9]{3})(-(.*' . CRLF . ')+\1)? [^' . CRLF . ']+' . CRLF . "$/", $this->_response, $parts) && time() < $endTime); 1601 1602 // Catch a timeout or bad response 1603 if (!isset($parts[1])) { 1604 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_TIMEOUT', __METHOD__, $this->_response), Log::WARNING, 'jerror'); 1605 1606 return false; 1607 } 1608 1609 // Separate the code from the message 1610 $this->_responseCode = $parts[1]; 1611 $this->_responseMsg = $parts[0]; 1612 1613 // Did the server respond with the code we wanted? 1614 if (\is_array($expected)) { 1615 if (\in_array($this->_responseCode, $expected)) { 1616 $retval = true; 1617 } else { 1618 $retval = false; 1619 } 1620 } else { 1621 if ($this->_responseCode == $expected) { 1622 $retval = true; 1623 } else { 1624 $retval = false; 1625 } 1626 } 1627 1628 return $retval; 1629 } 1630 1631 /** 1632 * Set server to passive mode and open a data port connection 1633 * 1634 * @return boolean True if successful 1635 * 1636 * @since 1.5 1637 */ 1638 protected function _passive() 1639 { 1640 $match = array(); 1641 $parts = array(); 1642 $errno = null; 1643 $err = null; 1644 1645 // Make sure we have a connection to the server 1646 if (!\is_resource($this->_conn)) { 1647 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_NO_CONNECT', __METHOD__), Log::WARNING, 'jerror'); 1648 1649 return false; 1650 } 1651 1652 // Request a passive connection - this means, we'll talk to you, you don't talk to us. 1653 @ fwrite($this->_conn, "PASV\r\n"); 1654 1655 // Wait for a response from the server, but timeout after the set time limit 1656 $endTime = time() + $this->_timeout; 1657 $this->_response = ''; 1658 1659 do { 1660 $this->_response .= fgets($this->_conn, 4096); 1661 } while (!preg_match('/^([0-9]{3})(-(.*' . CRLF . ')+\1)? [^' . CRLF . ']+' . CRLF . "$/", $this->_response, $parts) && time() < $endTime); 1662 1663 // Catch a timeout or bad response 1664 if (!isset($parts[1])) { 1665 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_TIMEOUT', __METHOD__, $this->_response), Log::WARNING, 'jerror'); 1666 1667 return false; 1668 } 1669 1670 // Separate the code from the message 1671 $this->_responseCode = $parts[1]; 1672 $this->_responseMsg = $parts[0]; 1673 1674 // If it's not 227, we weren't given an IP and port, which means it failed. 1675 if ($this->_responseCode != '227') { 1676 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_PASSIVE_IP_OBTAIN', __METHOD__, $this->_responseMsg), Log::WARNING, 'jerror'); 1677 1678 return false; 1679 } 1680 1681 // Snatch the IP and port information, or die horribly trying... 1682 if (preg_match('~\((\d+),\s*(\d+),\s*(\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+))\)~', $this->_responseMsg, $match) == 0) { 1683 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_PASSIVE_IP_VALID', __METHOD__, $this->_responseMsg), Log::WARNING, 'jerror'); 1684 1685 return false; 1686 } 1687 1688 // This is pretty simple - store it for later use ;). 1689 $this->_pasv = array('ip' => $match[1] . '.' . $match[2] . '.' . $match[3] . '.' . $match[4], 'port' => $match[5] * 256 + $match[6]); 1690 1691 // Connect, assuming we've got a connection. 1692 $this->_dataconn = @fsockopen($this->_pasv['ip'], $this->_pasv['port'], $errno, $err, $this->_timeout); 1693 1694 if (!$this->_dataconn) { 1695 Log::add( 1696 Text::sprintf('JLIB_CLIENT_ERROR_FTP_NO_CONNECT', __METHOD__, $this->_pasv['ip'], $this->_pasv['port'], $errno, $err), 1697 Log::WARNING, 1698 'jerror' 1699 ); 1700 1701 return false; 1702 } 1703 1704 // Set the timeout for this connection 1705 socket_set_timeout($this->_conn, $this->_timeout, 0); 1706 1707 return true; 1708 } 1709 1710 /** 1711 * Method to find out the correct transfer mode for a specific file 1712 * 1713 * @param string $fileName Name of the file 1714 * 1715 * @return integer Transfer-mode for this filetype [FTP_ASCII|FTP_BINARY] 1716 * 1717 * @since 1.5 1718 */ 1719 protected function _findMode($fileName) 1720 { 1721 if ($this->_type == FTP_AUTOASCII) { 1722 $dot = strrpos($fileName, '.') + 1; 1723 $ext = substr($fileName, $dot); 1724 1725 if (\in_array($ext, $this->_autoAscii)) { 1726 $mode = FTP_ASCII; 1727 } else { 1728 $mode = FTP_BINARY; 1729 } 1730 } elseif ($this->_type == FTP_ASCII) { 1731 $mode = FTP_ASCII; 1732 } else { 1733 $mode = FTP_BINARY; 1734 } 1735 1736 return $mode; 1737 } 1738 1739 /** 1740 * Set transfer mode 1741 * 1742 * @param integer $mode Integer representation of data transfer mode [1:Binary|0:Ascii] 1743 * Defined constants can also be used [FTP_BINARY|FTP_ASCII] 1744 * 1745 * @return boolean True if successful 1746 * 1747 * @since 1.5 1748 */ 1749 protected function _mode($mode) 1750 { 1751 if ($mode == FTP_BINARY) { 1752 if (!$this->_putCmd('TYPE I', 200)) { 1753 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_MODE_BINARY', __METHOD__, $this->_response), Log::WARNING, 'jerror'); 1754 1755 return false; 1756 } 1757 } else { 1758 if (!$this->_putCmd('TYPE A', 200)) { 1759 Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_MODE_ASCII', __METHOD__, $this->_response), Log::WARNING, 'jerror'); 1760 1761 return false; 1762 } 1763 } 1764 1765 return true; 1766 } 1767 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Sep 7 05:41:13 2022 | Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer |