PHPでFTP/FTPS/SFTPを使ってアップロードする例
前回の記事「PHPでjson_encode/json_decodeする例」の続きみたいなものですが、PHPでFTPやFTPS (FTP over SSL) を使ってファイルをアップロードするサンプルの紹介です。
FTPでのアップロード
■PHPサンプル
$cfg['ftp_host'] = 'example.com'; //接続先サーバー
$cfg['ftp_user'] = '[ユーザー名]'; //ログイン情報
$cfg['ftp_pass'] = '[パスワード]'; //
function uploadFTP($local_filename, $remote_filename)
{
global $cfg;
//サーバーへ接続
$conn = ftp_connect($cfg['ftp_host']);
//ログイン試行
if (!ftp_login($conn, $cfg['ftp_user'], $cfg['ftp_pass'])) {
echo 'Login Failed';
return;
}
//PASVモードへ変更
ftp_pasv($conn, true);
//ファイルのアップロード
ftp_put($conn, $remote_filename, $local_filename, FTP_BINARY);
//切断
ftp_close($conn);
}
■解説
- ftp_connectでFTPサーバーへ接続
- ftp_loginでログイン
- ftp_pasvでPASVモードへ変更
- ftp_putでローカルファイルをリモートへアップロード
- ftp_closeで切断
とまぁ、コメントに書いたとおりですね。
■FTP使用時のトラブル事例
- 下記のようなエラーメッセージが出る場合
Fatal error: Uncaught Error: Call to undefined function ftp_connect()
Windowsの場合、php.iniで extension=php_ftp の記述を忘れている可能性があります。
ググると「PHPをコンパイルしなければ~」みたいな情報も出てくるかも知れませんが、Windows版のPHP 7以降ならばextension=php_ftp の記述だけで使えるようになるはずです。
- 下記のようなエラーメッセージが出る場合
Warning: ftp_put (): PORT command successful
ftp_pasvを実行し忘れている可能性があります。PHPのftp関数はデフォルトではアクティブモードでの接続のため、一般的なファイアウォールのある環境では普通エラーになります。(アクティブモードではサーバー側からポート要求が来るため)
FTPS (FTP over SSL) でのアップロード
■PHPサンプル
$cfg['ftp_host'] = 'example.com'; //接続先サーバー
$cfg['ftp_user'] = '[ユーザー名]'; //ログイン情報
$cfg['ftp_pass'] = '[パスワード]'; //
function uploadFTPS($local_filename, $remote_filename)
{
global $cfg;
//サーバーへ接続
$conn = ftp_ssl_connect($cfg['ftp_host']);
//ログイン試行
if (!ftp_login($conn, $cfg['ftp_user'], $cfg['ftp_pass'])) {
echo 'Login Failed';
return;
}
//PASVモードへ変更
ftp_pasv($conn, true);
//ファイルのアップロード
ftp_put($conn, $remote_filename, $local_filename, FTP_BINARY);
//切断
ftp_close($conn);
}
■解説
- ftp_connectをftp_ssl_connectに変更しただけ。簡単!素敵!
PHPマニュアルのftp_ssl_connectの項目にWindows版では使えない云々と書かれていますが、php.iniで extension=php_ftp を記述すれば ftp_connect のみならず ftp_ssl_connect も使えるようになるためご安心を。
■FTPS使用時のトラブル事例
- ftp_close実行時に下記のようなエラーが出る場合
Warning: ftp_close(): SSL_read on shutdown: Resource temporarily unavailable
PHPのバグなので @ftp_close($conn); とする等、無視してください。PHP 7.2.14 でも確認しましたが、このバグはまだ治っていませんでした。
参考資料:https://bugs.php.net/bug.php?id=77151
PHP 7.3.1では治っているというような情報も見かけましたが、こちらは未確認です。
SFTP(SSH2)でのアップロード
■PHPサンプル
$cfg['ftp_host'] = 'example.com'; //接続先サーバー
$cfg['ftp_user'] = '[ユーザー名]'; //ログイン情報
$cfg['ftp_pass'] = '[パスワード]'; //
function uploadSFTP($local_filename, $remote_filename)
{
global $cfg;
//SSHで接続
$conn = ssh2_connect($cfg['ftp_host'], 22);
if (!ssh2_auth_password($conn, $cfg['ftp_user'], $cfg['ftp_pass'])) {
echo 'Login Failed';
return;
}
//SFTP接続を行う
$sftp = ssh2_sftp($conn);
//ローカルファイルを読み込む
$file_data = file_get_contents($local_filename);
//アップロードする
file_put_contents('ssh2.sftp://'.$sftp.$remote_filename, $file_data);
//サーバーから切断
ssh2_disconnect($conn);
}
■解説
- ssh2_connectでSSHサーバーへ接続
- ssh2_auth_passwordでログイン処理
- ssh2_sftpでSFTPサブシステムを初期化
- file_get_contentsでローカルファイルを読み込み
- file_put_contentsでリモートへアップロード
- ssh2_disconnectで切断
FTPとFTPSはお仲間ですが、SFTPの中身はSSH2なので関数もガラっと変わります。やってることは同じようなことですけどね。
ただ、SSHの場合、レンタルサーバーによってはIPの登録が必要だったり、公開鍵/秘密鍵による接続しか許可していなかったりするので注意が必要です。前者はともかく、後者はこのサンプルでは動きません。
ssh2_auth_passwordの部分をssh2_auth_pubkey_fileに変更して、公開鍵/秘密鍵の両ファイルを指定してあげる必要があります。でもまぁ、それだけで動く…はずです。
まとめ
PHPのftp操作自体はconnect~login~pasv~put~closeと非常に簡単なのですが、環境まわりでハマることが多いので一応記事にしてみました。
- Windowsで使うときはphp.iniで extension=php_ftp の記述を忘れずに
- ftp_pasvでPASVモードにするのも忘れずに
- FTPSを使うときはftp_close時にWarningが出るかも知れませんが、PHP7.2の場合はPHPのバグなので無視する方向で
- WindowsでSFTPを使う場合はphp.iniで extension=ssh2 の記述も忘れずに
- SFTPで公開鍵/秘密鍵を使う場合はssh2_auth_passwordをssh2_auth_pubkey_fileへ変更
といったところですかね。
SFTPを使う場合はデフォルトでは php_ssh2.dll が同梱されていないと思うので、下記の記事を参考にDLLをダウンロードしてください。