Simpele PHP class en voorbeeld om een bestand op te halen van een ftps server via cURL. Of om een bestand te plaatsen op een ftps server. <?php
/*
* Copyright (c) 2023 Reynaert.be -- all rights reserved
*
* Reynaert.be BVBA. ("Reynaert.be") permits use of the
* accompanying software and documentation ("the Software") provided
* that the conditions of the Reynaert.be License
* ("the License") are met.
*
* This Software is provided "AS IS", without a warranty of any kind.
* ALL EXPRESS OR IMPLIED REPRESENTATIONS AND WARRANTIES, INCLUDING
* ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
*
* REYNAERT.BE AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES
* SUFFERED BY LICENSEE OR ANY THIRD PARTY AS A RESULT OF USING OR
* DISTRIBUTING SOFTWARE. IN NO EVENT WILL REYNAERT.BE OR ITS LICENSORS
* BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
* INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES,
* HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING
* OUT OF THE USE OF OR INABILITY TO USE SOFTWARE, EVEN IF HE HAS
* BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
/*
(new \Util\FTP('ftp.reynaert.be', 'gebruiker', 'paswoord'))
->setMethod(\Util\FTP::METHOD_CURLS) // connecteer via Curl -> TLSv1.2 ipv ftps
->connect()
->setStream("FTP via Curl - SSL TLSv1.2 - Dit is meer dan een test.")
->fput('/testomgeving/test.txt')
->close();
*/
//** Class FTP **/
namespace Util;
class FTP {
protected string $hostname = "";
protected string $username = "";
protected string $password = "";
protected int $port = 21;
protected int $timeout = 90;
protected $stream=null;
protected int $method = 1;
private $connection = null;
const METHOD_FTP = 0;
const METHOD_FTPS = 1;
const METHOD_CURLS = 2;
// const METHOD_SSH = 3;
function getHostname():string{
return $this->hostname;
}
function setHostname(string $hostname):self{
$this->hostname = $hostname;
return $this;
}
function getUsername():string{
return $this->username;
}
function setUsername(string $username):self{
$this->username = $username;
return $this;
}
function getPassword():string{
return $this->password;
}
function setPassword(string $password):self{
$this->password = $password;
return $this;
}
public function getPort(): int {
return $this->port;
}
public function setPort(int $port): self {
$this->port = $port;
return $this;
}
public function getTimeout(): int {
return $this->timeout;
}
public function setTimeout(int $timeout): self {
$this->timeout = $timeout;
return $this;
}
public function getMethod(): int {
return $this->method;
}
public function setMethod(int $method): self {
$this->method = $method;
return $this;
}
public function setStream($str) :self{
$this->stream = self::memStream($str);
return $this;
}
public function getStreamContent() :string {
if (is_null($this->stream)) return "";
else {
rewind($this->stream);
return stream_get_contents($this->stream);
}
}
public function __construct($hostname=null, $username=null, $password=null){
if (!is_null($hostname)) $this->hostname = $hostname;
if (!is_null($username)) $this->username = $username;
if (!is_null($password)) $this->password = $password;
return $this;
}
public function connect($hostname=null, int $port=null,int $timeout=null):self{
if (!is_null($hostname)) $this->hostname = $hostname;
if (!is_null($port)) $this->port = $port;
if (!is_null($timeout)) $this->timeout = $timeout;
switch ($this->method) {
case 1: $this->connection = $this->getFtpsConnection(); break;
case 2: $this->connection = $this->getCurlsConnection(); break;
case 3: break; // todo ssh
}
return $this;
}
public function close() {
switch ($this->method) {
case 1: $this->closeFtp(); break;
case 2: $this->closeCurl(); break;
case 3: break; // todo ssh
}
if (!is_null($this->stream)) fclose($this->stream);
}
public function fget($remote_filename):self{
switch ($this->method) {
case 1: $this->fgetFtp($remote_filename); break;
case 2: $this->fgetCurl($remote_filename); break;
case 3: break; // todo ssh
}
return $this;
}
public function fput($remote_filename):self{
switch ($this->method) {
case 1: $this->fputFtp($remote_filename); break;
case 2: $this->fputCurl($remote_filename); break;
case 3: break; // todo ssh
}
return $this;
}
public function exists($remote_filename) :bool {
switch ($this->method) {
case 1: return $this->isFileOnFtp($remote_filename); break;
case 2: return $this->isFileOnCurl($remote_filename); break;
case 3: break; // todo ssh
}
return false;
}
// ----------- private stuff
private function getFtpsConnection() {
$conn_id = ftp_ssl_connect($this->hostname);
ftp_set_option($conn_id, FTP_TIMEOUT_SEC, $this->timeout);
$login_result = ftp_login($conn_id, $this->username, $this->password);
ftp_pasv($conn_id, true);
return $conn_id;
}
private function getCurlsConnection() {
$ch = curl_init();
curl_setopt($ch, CURLOPT_VERBOSE, TRUE);
curl_setopt($ch, CURLOPT_URL, "ftp://".$this->hostname);
curl_setopt($ch, CURLOPT_PORT, $this->port);
curl_setopt($ch, CURLOPT_USERPWD, sprintf("%s:%s", $this->username, $this->password));
curl_setopt($ch, CURLOPT_USE_SSL, TRUE);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);
curl_setopt($ch, CURLOPT_FTP_SSL, CURLOPT_FTPSSLAUTH);
curl_setopt($ch, CURLOPT_FTPSSLAUTH, CURLFTPAUTH_TLS);
curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeout);
return $ch;
}
private function closeFtp(){
if (!is_null($this->connection)) {
ftp_close($this->connection);
$this->connection = null;
}
}
private function closeCurl(){
if (!is_null($this->connection)) {
curl_close($this->connection);
$this->connection = null;
}
}
private function fgetFtp($remote_filename) {
$this->stream = self::memStream();
// todo uitbreiden met $mode en $offset
return ftp_fget($this->connection, $this->stream,$remote_filename);
}
private function fgetCurl($remote_filename) {
$this->stream = self::memStream();
curl_setopt($this->connection, CURLOPT_URL, "ftp://".$this->hostname.'/'.ltrim($remote_filename,'/'));
curl_setopt($this->connection, CURLOPT_FILE, $this->stream);
curl_setopt($this->connection, CURLOPT_FOLLOWLOCATION, true);
return curl_exec($this->connection);
}
private function fputFtp($remote_filename) {
if (!is_null($this->stream)) {
// todo uitbreiden met $mode en $offset
return @ftp_fput($this->connection, $remote_filename, $this->stream); // Warning: ftp_fput(): Connection timed out
}
return false;
}
private function fputCurl($remote_filename) {
if (!is_null($this->stream)) {
curl_setopt($this->connection, CURLOPT_URL, "ftp://".$this->hostname.'/'.ltrim($remote_filename,'/'));
curl_setopt($this->connection, CURLOPT_UPLOAD, TRUE);
curl_setopt($this->connection, CURLOPT_INFILE, $this->stream);
curl_setopt($this->connection, CURLOPT_INFILESIZE, fstat($this->stream)['size'] ?? 0);
return curl_exec($this->connection);
}
return false;
}
private function isFileOnFtp($filename) : bool {
$dir = rtrim($filename,'/');
$dir = substr($dir, 0, strrpos($dir, '/'));
if (\Tekst::endsWith($filename,"/")) {
$filename = rtrim($filename,'/');
$filename = substr($filename, strrpos($filename, '/'))."/";
} else
$filename = substr($filename, strrpos($filename, '/'));
$pattern = (\Tekst::startsWith($filename,"/") && \Tekst::endsWith($filename,"/"));
$contents = ftp_nlist($this->connection, $dir);
if ($contents)
foreach ($contents as $c) {
if ($pattern && preg_match($filename,$c)) return true;
elseif ($c==$dir.$filename) return true;
}
return false;
}
private function isFileOnCurl($remote_filename) : bool {
curl_setopt($this->connection, CURLOPT_URL, "ftp://".$this->hostname.'/'.ltrim($remote_filename,'/'));
curl_setopt($this->connection, CURLOPT_RETURNTRANSFER, TRUE);
$result = curl_exec($this->connection);
$httpCode = curl_getinfo($this->connection, CURLINFO_HTTP_CODE);
return $httpCode>=200 && $httpCode<300;
}
private static function memStream($str=null) {
$stream = fopen('php://memory','w+');
if (!is_null($str)) {
fwrite($stream, $str);
rewind($stream);
}
return $stream;
}
}