Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ftp_ssl_connect with implicit ftp over tls

Tags:

php

ssl

ftp

ftps

Can ftp_ssl_connect handle Implicit FTP over TLS? By default it uses explicit.

I'm trying to upload to a server that accepts only Implicit ftp over tls on port 990; has anybody run into this as of yet? How did you fix it?

like image 247
Rasiel Avatar asked Jul 05 '11 22:07

Rasiel


People also ask

What is implicit FTP over TLS?

FTP over TLS (Implicit) - Deprecated Implicit security is a mechanism by which security is automatically turned on as soon as the FTP client makes a connection to an FTP server. In this case, the FTP server defines a specific port for the client (990) to be used for secure connections.

Is implicit FTP over SSL secure?

With Implicit FTPS, an SSL handshake must be negotiated before any FTP commands can be sent by the client. In addition, even though Explicit FTPS allows the client to arbitrarily decide whether to use SSL, Implicit FTPS requires that the entire FTP session must be encrypted.

What is implicit FTP?

What is Implicit FTPS? Implicit FTPS is a method of FTPS that allows clients to connect to an implicit port (Port 990) which already has secure connections baked in without requesting for there to be one. Implicit FTPS makes use of a dedicated port in order to allow for port 21 to be left open.


2 Answers

ftp_ssl_connect is only explicit

if you need implicit, use curl

$fp = fopen($path, 'r');
$ftp_server = 'ftps://'.$server.'/'.$filename; 
$ch = curl_init(); 
curl_setopt($ch, CURLOPT_URL, $ftp_server);
curl_setopt($ch, CURLOPT_USERPWD,$user.':'.$pass);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($ch, CURLOPT_FTP_SSL, CURLFTPSSL_TRY);
curl_setopt($ch, CURLOPT_FTPSSLAUTH, CURLFTPAUTH_TLS);
curl_setopt($ch, CURLOPT_UPLOAD, 1);
curl_setopt($ch, CURLOPT_INFILE, $fp);

$output = curl_exec($ch);
$error_no = curl_errno($ch);
//var_dump(curl_error($ch));
curl_close($ch);
like image 73
frustrum Avatar answered Oct 07 '22 03:10

frustrum


Based on frustrum and Steven Jeffries's answers I've extended it further. This reuses the curl connection and has some directory listing functions, including one to sort files by last modified.

This is for PHP 7, for lower you will have to rewrite the <=> operator line.

<?php
/**
 * Implicit FTP 
 * @author Nico
 * Based on
 * http://stackoverflow.com/questions/6589730/ftp-ssl-connect-with-implicit-ftp-over-tls
 * http://stackoverflow.com/questions/845220/get-the-last-modified-date-of-a-remote-file
 */
class ImplicitFtp {

    private $server;
    private $username;
    private $password;
    private $curlhandle;

    public function __construct($server, $username, $password) {
        $this->server = $server;
        $this->username = $username;
        $this->password = $password;
        $this->curlhandle = curl_init();
    }

    public function __destruct() {
        if (!empty($this->curlhandle))
            @curl_close($this->curlhandle);
    }

    /**
     * @param string $remote remote path
     * @return resource a cURL handle on success, false on errors.
     */
    private function common($remote) {
        curl_reset($this->curlhandle);
        curl_setopt($this->curlhandle, CURLOPT_URL, 'ftps://' . $this->server . '/' . $remote);
        curl_setopt($this->curlhandle, CURLOPT_USERPWD, $this->username . ':' . $this->password);
        curl_setopt($this->curlhandle, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($this->curlhandle, CURLOPT_SSL_VERIFYHOST, FALSE);
        curl_setopt($this->curlhandle, CURLOPT_FTP_SSL, CURLFTPSSL_TRY);
        curl_setopt($this->curlhandle, CURLOPT_FTPSSLAUTH, CURLFTPAUTH_TLS);
        return $this->curlhandle;
    }

    public function download($remote, $local = null) {
        if ($local === null) {
            $local = tempnam('/tmp', 'implicit_ftp');
        }

        if ($fp = fopen($local, 'w')) {
            $this->curlhandle = self::common($remote);
            curl_setopt($this->curlhandle, CURLOPT_UPLOAD, 0);
            curl_setopt($this->curlhandle, CURLOPT_FILE, $fp);

            curl_exec($this->curlhandle);

            if (curl_error($this->curlhandle)) {
                return false;
            } else {
                return $local;
            }
        }
        return false;
    }

    public function upload($local, $remote) {
        if ($fp = fopen($local, 'r')) {
            $this->curlhandle = self::common($remote);
            curl_setopt($this->curlhandle, CURLOPT_UPLOAD, 1);
            curl_setopt($this->curlhandle, CURLOPT_INFILE, $fp);

            curl_exec($this->curlhandle);
            $err = curl_error($this->curlhandle);

            return !$err;
        }
        return false;
    }

    /**
     * Get file/folder names
     * @param string $remote
     * @return string[]
     */
    public function listnames($remote) {
        if (substr($remote, -1) != '/')
            $remote .= '/';
        $this->curlhandle = self::common($remote);
        curl_setopt($this->curlhandle, CURLOPT_UPLOAD, 0);
        curl_setopt($this->curlhandle, CURLOPT_FTPLISTONLY, 1);
        curl_setopt($this->curlhandle, CURLOPT_RETURNTRANSFER, 1);

        $result = curl_exec($this->curlhandle);

        if (curl_error($this->curlhandle)) {
            return false;
        } else {
            $files = explode("\r\n", trim($result));
            return $files;
            return $local;
        }
    }

    /**
     * Get file/folder names ordered by modified date
     * @param string $remote
     * @return string[]
     */
    public function listbydate($remote) {
        $files = $this->listnames($remote);
        if (empty($files))
            return null;
        $filedata = array();
        foreach ($files as $file) {

            $this->curlhandle = self::common($remote . '/' . $file);
            curl_setopt($this->curlhandle, CURLOPT_NOBODY, 1);
            curl_setopt($this->curlhandle, CURLOPT_FILETIME, 1);
            curl_setopt($this->curlhandle, CURLOPT_RETURNTRANSFER, 1);
            $result = curl_exec($this->curlhandle);

            if ($result) {
                $timestamp = curl_getinfo($this->curlhandle, CURLINFO_FILETIME);
                $fileobj = array();
                $fileobj['name'] = $file;
                $fileobj['lastmodified'] = ($timestamp != -1) ? date("Y-m-d H:i:s", $timestamp) : null;
                $filedata[] = $fileobj;
            }
        }

        usort($filedata, function ($item1, $item2) {
            return date($item2['lastmodified']) <=> date($item1['lastmodified']);
        });

        return $filedata;
    }



    /**
     * Get file/folder raw data
     * @param string $remote
     * @return string[]
     */
    public function rawlist($remote) {
        if (substr($remote, -1) != '/')
            $remote .= '/';
        $this->curlhandle = self::common($remote);
        curl_setopt($this->curlhandle, CURLOPT_UPLOAD, 0);
        curl_setopt($this->curlhandle, CURLOPT_RETURNTRANSFER, 1);

        $result = curl_exec($this->curlhandle);

        if (curl_error($this->curlhandle)) {
            return false;
        } else {
            $files = explode("\n", trim($result));
            return $files;
            return $local;
        }
    }

    /**
     * Get file/folder parsed data into an array
     * @param string $remote
     * @return array[]
     */
    public function list($remote) {
        $this->curlhandleildren = $this->rawlist($remote);
        if (!empty($this->curlhandleildren)) {
            $items = array();
            foreach ($this->curlhandleildren as $this->curlhandleild) {
                $chunks = preg_split("/\s+/", $this->curlhandleild);
                list($item['rights'], $item['number'], $item['user'], $item['group'], $item['size'], $item['month'], $item['day'], $item['time']) = $chunks;
                array_splice($chunks, 0, 8);
                $item['name'] = trim(implode(" ", $chunks));
                $item['type'] = $chunks[0]{0} === 'd' ? 'directory' : 'file';
                $items[] = $item;
            }
            return $items;
        }
        return false;
    }

}
?>
like image 31
Nico Westerdale Avatar answered Oct 07 '22 04:10

Nico Westerdale