/**
* Set server to passive mode and open a data port connection
*
* @return boolean True if successful
*
* @since 1.5
*/
protected function _passive()
{
$match = array();
$parts = array();
$errno = null;
$err = null;
// Make sure we have a connection to the server
if (!\is_resource($this->_conn)) {
Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_NO_CONNECT', __METHOD__), Log::WARNING, 'jerror');
return false;
}
// Request a passive connection - this means, we'll talk to you, you don't talk to us.
@fwrite($this->_conn, "PASV\r\n");
// Wait for a response from the server, but timeout after the set time limit
$endTime = time() + $this->_timeout;
$this->_response = '';
do {
$this->_response .= fgets($this->_conn, 4096);
} while (!preg_match('/^([0-9]{3})(-(.*' . CRLF . ')+\\1)? [^' . CRLF . ']+' . CRLF . "\$/", $this->_response, $parts) && time() < $endTime);
// Catch a timeout or bad response
if (!isset($parts[1])) {
Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_TIMEOUT', __METHOD__, $this->_response), Log::WARNING, 'jerror');
return false;
}
// Separate the code from the message
$this->_responseCode = $parts[1];
$this->_responseMsg = $parts[0];
// If it's not 227, we weren't given an IP and port, which means it failed.
if ($this->_responseCode != '227') {
Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_PASSIVE_IP_OBTAIN', __METHOD__, $this->_responseMsg), Log::WARNING, 'jerror');
return false;
}
// Snatch the IP and port information, or die horribly trying...
if (preg_match('~\\((\\d+),\\s*(\\d+),\\s*(\\d+),\\s*(\\d+),\\s*(\\d+)(?:,\\s*(\\d+))\\)~', $this->_responseMsg, $match) == 0) {
Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_PASSIVE_IP_VALID', __METHOD__, $this->_responseMsg), Log::WARNING, 'jerror');
return false;
}
// This is pretty simple - store it for later use ;).
$this->_pasv = array('ip' => $match[1] . '.' . $match[2] . '.' . $match[3] . '.' . $match[4], 'port' => $match[5] * 256 + $match[6]);
// Connect, assuming we've got a connection.
$this->_dataconn = @fsockopen($this->_pasv['ip'], $this->_pasv['port'], $errno, $err, $this->_timeout);
if (!$this->_dataconn) {
Log::add(Text::sprintf('JLIB_CLIENT_ERROR_FTP_NO_CONNECT', __METHOD__, $this->_pasv['ip'], $this->_pasv['port'], $errno, $err), Log::WARNING, 'jerror');
return false;
}
// Set the timeout for this connection
socket_set_timeout($this->_conn, $this->_timeout, 0);
return true;
}