PHP 프로그래밍 언어를 사용하여 SFTP에 연결하고, 파일을 리스트업하며, 업로드 및 다운로드하는 방법을 배웁니다.
SFTP는 데이터 및 파일의 안전한 전송 및 공유를 위한 표준적이고 안전한 프로토콜입니다. 어떤 경우라도, 프로그래밍 방식으로 SFTP 서버에 연결하는 것은 쉽지 않습니다. 이 기사에서는 본격적인 PHP 기반의 SFTP 클라이언트를 만드는 법을 단계별로 알려드리며, 이 가이드의 마지막에는 스스로 설정을 문제없이 할 수 있게 될 것입니다.
필수사항
먼저 연결할 SFTP 서버가 필요합니다. 아직 가지고 있지 않으시다면 SFTP To Go에서 30초 만에 SFTP 엔드포인트를 취득하실 수 있습니다.

PHP는 처음부터 SFTP 라이브러리와 함께 번들로 제공되지 않으므로 필요한 라이브러리인 phpseclib를 설치해야 합니다.
$ composer require phpseclib/phpseclib
12 factor-app 클라우드 개발 기술에 따라 다음 composer.json과 같이 앱 종속성을 명확하게 정의해야 합니다.
{
"require": {
"phpseclib/phpseclib": "^3.0"
}
}
정말 재미있는 것은 지금부터입니다!
SFTP 연결 생성 및 삭제
우선 첫 단계는 새 클래스를 만드는 것부터입니다. 여기에는 SFTP 클라이언트에 필요한 기능이 들어 있습니다. 최초로 추가하는 public 메소드는, 패스워드 인증 또는 키 인증 중에 하나를 사용하여 서버에 접속한 후에, 기존의 세션을 끊는 방법을 제공합니다.
<?php
class SFTPClient
{
private $sftp;
public function __construct($host, $port=22)
{
$this->sftp = new SFTP($host, $port);
if (!$this->sftp->isConnected())
throw new Exception("Failed to connect to ${host} on port ${port}.");
}
// Login with user and password
public function auth_password($username, $password)
{
if (!$this->sftp->login($username, $password))
throw new Exception("Failed to authenticate with username $username " .
"and password.");
}
// Login with SSH agent
public function auth_agent($username)
{
if (!$this->sftp->login($username))
throw new Exception("Failed to authenticate with username $username " .
"and public key.");
}
// Disconnect session
public function disconnect()
{
$this->sftp->disconnect();
}
}
?>
새로운 메소드를 사용하려면 메인 함수에서 클래스를 인스턴스화하고 auth_password
함수를 호출하여 연결을 시작하고 즉시 disconnect
함수로 연결을 닫습니다. 다음과 같은 URI 형식의 환경 변수 SFTPTOGO_URL
을 사용하여 SFTP 서버에 연결하는 데 필요한 모든 정보를 검색합니다: sftp://user:password@host
. 해당 변수는 함수 내에서 분석(파싱)되고 사용자 이름, 암호, 호스트 및 포트가 추출됩니다.
<?php
function main()
{
$raw_url = getenv('SFTPTOGO_URL');
// Parse URL
$parsed_url = parse_url($raw_url);
if ($parsed_url === false)
{
fwrite(STDERR, "Failed to parse SFTP To Go URL.\n");
exit(1);
}
// Get user name and password
$user = isset($parsed_url['user']) ? $parsed_url['user'] : null;
$pass = isset($parsed_url['pass']) ? $parsed_url['pass'] : null;
// Parse Host and Port
$host = isset($parsed_url['host']) ? $parsed_url['host'] : null;
// Port is always 22
$port = isset($parsed_url['port']) ? $parsed_url['port'] : 22;
fwrite(STDOUT, "Connecting to [${host}] ...\n");
}
main();
?>
파일 리스트 표시
연결이 성공하면 클래스에 원격 SFTP 서버의 파일을 나열하는 데 사용되는 함수를 추가합니다. listFiles
함수는 $remote_dir
인수를 취해 파일명의 배열과 그 사이즈, 갱신 시각을 돌려줍니다. 이 함수를 호출하려면, 단순히 패스를 건네주고 ( .
로 현재 디렉토리의 내용을 모두 열람할 수 있습니다), 취득한 배열을 처리합니다.
<?php
// List remote directory files
function listFiles($remote_dir) {
$tempArray = array();
fwrite(STDOUT, "Listing [${remote_dir}] ...\n\n");
$files = $this->sftp->nlist($remote_dir);
foreach ($files as $file) {
$filetype = $this->sftp->is_dir($file) ? 'dir' : 'file';
$modTime = '';
$size = sprintf("%.2f", $this->sftp->size($file));
if ($filetype == "dir") {
$file .= '/';
$modTime = '';
$size = "PRE";
}
$tempArray[] = $file;
printf("%19s %12s %s\n", $modTime, $size, $file);
}
return $tempArray;
}
?>
파일 업로드
이제 파일을 업로드 해봅시다. uploadFile
함수를 사용하여 두 개의 인수를 전달합니다. 그리고 함수 호출은 다음과 같습니다: $client->uploadFile("./local.txt", "./remote.txt");
<?php
// Upload local file to remote file
public function uploadFile($local_file, $remote_file)
{
fwrite(STDOUT, "Uploading [${local_file}] to [${remote_file}] ...\n");
$data_to_send = file_get_contents($local_file);
if ($data_to_send === false)
throw new Exception("Could not open local file: $local_file.");
if (!$this->sftp->put($remote_file, $data_to_send))
throw new Exception("Could not send data from file: $local_file.");
}
?>
파일 다운로드
마지막으로 중요한 한 가지, 파일을 다운로드하려면 downloadFile
함수를 사용합니다. 리모트 파일에 대한 경로와 다운로드한 파일을 저장하는 로컬 경로를 함수에 전달합니다. 이 함수는 다음을 통해 호출하게 됩니다: $client->downloadFile("./remote.txt", "./download.txt");
<?php
// Download remote file to local file
public function downloadFile($remote_file, $local_file)
{
fwrite(STDOUT, "Downloading [${remote_file}] to [${local_file}] ...\n");
$contents = $this->sftp->get($remote_file);
if ($contents === false)
throw new Exception("Could not open remote file: $remote_file.");
file_put_contents($local_file, $contents);
}
?>

마무리
이제 끝입니다! 이 프로그램을 처음부터 끝까지 실행하고 싶다면 아래 코드를 복사하여 main.php
로 저장하십시오:
<?php
use phpseclib3\Net\SFTP;
class SFTPClient
{
private $sftp;
public function __construct($host, $port=22)
{
$this->sftp = new SFTP($host, $port);
if (!$this->sftp->isConnected())
throw new Exception("Failed to connect to ${host} on port ${port}.");
}
// Login with user and password
public function auth_password($username, $password)
{
if (!$this->sftp->login($username, $password))
throw new Exception("Failed to authenticate with username $username " .
"and password.");
}
// Login with SSH agent
public function auth_agent($username)
{
if (!$this->sftp->login($username))
throw new Exception("Failed to authenticate with username $username " .
"and public key.");
}
// Disconnect session
public function disconnect()
{
$this->sftp->disconnect();
}
// List remote directory files
function listFiles($remote_dir) {
$tempArray = array();
fwrite(STDOUT, "Listing [${remote_dir}] ...\n\n");
$files = $this->sftp->nlist($remote_dir);
foreach ($files as $file) {
$filetype = $this->sftp->is_dir($file) ? 'dir' : 'file';
$modTime = '';
$size = sprintf("%.2f", $this->sftp->size($file));
if ($filetype == "dir") {
$file .= '/';
$modTime = '';
$size = "PRE";
}
$tempArray[] = $file;
printf("%19s %12s %s\n", $modTime, $size, $file);
}
return $tempArray;
}
// Upload local file to remote file
public function uploadFile($local_file, $remote_file)
{
fwrite(STDOUT, "Uploading [${local_file}] to [${remote_file}] ...\n");
$data_to_send = file_get_contents($local_file);
if ($data_to_send === false)
throw new Exception("Could not open local file: $local_file.");
if (!$this->sftp->put($remote_file, $data_to_send))
throw new Exception("Could not send data from file: $local_file.");
}
// Download remote file to local file
public function downloadFile($remote_file, $local_file)
{
fwrite(STDOUT, "Downloading [${remote_file}] to [${local_file}] ...\n");
$contents = $this->sftp->get($remote_file);
if ($contents === false)
throw new Exception("Could not open remote file: $remote_file.");
file_put_contents($local_file, $contents);
}
// Delete remote file
public function deleteFile($remote_file){
fwrite(STDOUT, "Deleting [${remote_file}] ...\n");
$this->sftp->delete($remote_file);
}
}
function main()
{
$raw_url = getenv('SFTPTOGO_URL');
// Parse URL
$parsed_url = parse_url($raw_url);
if ($parsed_url === false)
{
fwrite(STDERR, "Failed to parse SFTP To Go URL.\n");
exit(1);
}
// Get user name and password
$user = isset($parsed_url['user']) ? $parsed_url['user'] : null;
$pass = isset($parsed_url['pass']) ? $parsed_url['pass'] : null;
// Parse Host and Port
$host = isset($parsed_url['host']) ? $parsed_url['host'] : null;
// Port is always 22
$port = isset($parsed_url['port']) ? $parsed_url['port'] : 22;
fwrite(STDOUT, "Connecting to [${host}] ...\n");
try
{
$client = new SFTPClient($host, $port);
$client->auth_password($user, $pass);
//*
//* List working directory files
//*
$client->listFiles(".");
//*
//* Upload local file to remote file
//*
$client->uploadFile("./local.txt", "./remote.txt");
//*
//* Download remote file to local file
//*
$client->downloadFile("./remote.txt", "./download.txt");
//*
//* Delete remote file
//*
$client->deleteFile("./remote.txt");
}
catch (Exception $e)
{
echo $e->getMessage() . "\n";
}
}
main();
?>
코드를 실행하기 위해서는, 아래의 명령을 이용하세요:
php main.php
또한, Github에 있는 저희 리포지토리를 복제해서 활용하거나, 다른 샘플들을 체크해 보세요.