From 75471ecd99d1b3583a2c87dd71b56a72358de4f2 Mon Sep 17 00:00:00 2001
From: Jacek Kowalski <Jacek@jacekk.info>
Date: Sun, 30 Jun 2019 20:41:08 +0000
Subject: [PATCH] Reuse FTP connection if possible

---
 lib/fetch.php         |   36 +++++-------------
 lib/FtpConnection.php |   55 +++++++++++++++++++++++++++
 2 files changed, 65 insertions(+), 26 deletions(-)

diff --git a/lib/FtpConnection.php b/lib/FtpConnection.php
new file mode 100644
index 0000000..94f9ebd
--- /dev/null
+++ b/lib/FtpConnection.php
@@ -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;
+	}
+}
diff --git a/lib/fetch.php b/lib/fetch.php
index bb36a1a..57ffaaa 100644
--- a/lib/fetch.php
+++ b/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;
 }

--
Gitblit v1.9.1