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