Jacek Kowalski
2019-06-30 75471ecd99d1b3583a2c87dd71b56a72358de4f2
Reuse FTP connection if possible
1 files added
1 files modified
91 ■■■■ changed files
lib/FtpConnection.php 55 ●●●●● patch | view | raw | blame | history
lib/fetch.php 36 ●●●● patch | view | raw | blame | history
lib/FtpConnection.php
New file
@@ -0,0 +1,55 @@
<?php
class FtpConnection {
    private static $instances = [];
    private $connection;
    static function create(string $host, int $port=21, string $user='anonymous', string $pass='anonymous') : FtpConnection {
        $key = $host."\0".$port."\0".$user."\0".$pass;
        if(!isset(self::$instances[$key])) {
            self::$instances[$key] = new FtpConnection($host, $port, $user, $pass);
        }
        return self::$instances[$key];
    }
    private function __construct(string $host, int $port=21, string $user, string $pass) {
        $this->connection = ftp_connect($host, $port, 10);
        if($this->connection === FALSE) {
            throw new Exception('FTP connection failed');
        }
        if(!ftp_login($this->connection, $user, $pass)) {
            throw new Exception('FTP login failed');
        }
        if(!ftp_pasv($this->connection, TRUE)) {
            throw new Exception('Passive FTP request failed');
        }
    }
    public function __destruct() {
        ftp_close($this->connection);
    }
    public function size(string $file) : int {
        $remoteSize = ftp_size($this->connection, $file);
        if($remoteSize < 0) {
            throw new Exception('FTP file size fetch failed');
        }
        return $remoteSize;
    }
    public function mdtm(string $file) : int {
        $remoteTime = ftp_mdtm($this->connection, $file);
        if($remoteTime < 0) {
            throw new Exception('FTP modification time fetch failed');
        }
        return $remoteTime;
    }
    public function get(string $local_file, string $remote_file, int $mode = FTP_BINARY, int $resumepos = 0) : bool {
        $result = ftp_get($this->connection, $local_file, $remote_file, $mode, $resumepos);
        if($result === FALSE) {
            throw new Exception('FTP file get failed');
        }
        return $result;
    }
}
lib/fetch.php
@@ -1,4 +1,6 @@
<?php
require_once(__DIR__.'/FtpConnection.php');
function ftp_fetch_if_newer($url, $file = NULL) {
    $url = parse_url($url);
    if(!isset($url['scheme']) || $url['scheme'] != 'ftp') {
@@ -30,24 +32,9 @@
        $localSize = filesize($file);
    }
    
    $ftp = ftp_connect($url['host'], $url['port'], 10);
    if($ftp === FALSE) {
        throw new Exception('FTP connection failed');
    }
    if(!ftp_login($ftp, $url['user'], $url['pass'])) {
        throw new Exception('FTP login failed');
    }
    if(!ftp_pasv($ftp, TRUE)) {
        throw new Exception('Passive FTP request failed');
    }
    $remoteSize = ftp_size($ftp, $url['path']);
    if($remoteSize < 0) {
        throw new Exception('FTP file size fetch failed');
    }
    $remoteTime = ftp_mdtm($ftp, $url['path']);
    if($remoteTime < 0) {
        throw new Exception('FTP modification time fetch failed');
    }
    $ftp = FtpConnection::create($url['host'], $url['port'], $url['user'], $url['pass']);
    $remoteSize = $ftp->size($url['path']);
    $remoteTime = $ftp->mdtm($url['path']);
    
    $updated = FALSE;
    
@@ -55,16 +42,13 @@
        if(file_exists($file.'.tmp')) {
            unlink($file.'.tmp');
        }
        if(ftp_get($ftp, $file.'.tmp', $url['path'], FTP_BINARY)) {
            touch($file.'.tmp', $remoteTime);
            if(!rename($file.'.tmp', $file)) {
                throw new Exception('Temporary file rename failed');
            }
            $updated = TRUE;
        $ftp->get($file.'.tmp', $url['path'], FTP_BINARY);
        touch($file.'.tmp', $remoteTime);
        if(!rename($file.'.tmp', $file)) {
            throw new Exception('Temporary file rename failed');
        }
        $updated = TRUE;
    }
    ftp_close($ftp);
    
    return $updated;
}