何がしたかったか
ユーザーからmultipart/form-dataでPOSTされてきたファイルをSFTPでストレージサーバに送る
ファイルのバリデーションは実装してるけど今回はSFTPする部分について。
実現方法
- 使っているフレームワークに頼る
- ssh2のライブラリを使う
- curlを使う
- systemやexecでコマンドを叩く
フレームワークを利用しているならフレームワークのライブラリを使うのが多分1番簡単です。
composerなどが使える環境ならさくっとライブラリを入れてしまうのも手だと思います。
systemやexecでコマンドを叩くのはエラーハンドリングも面倒だし、コマンドを直接発行するという怖さがあるのでオススメしません。
今回は僕が実装した環境がこれらの手段が使えなかったため、curlで実装してみたという話です。
実装
記事用なのでコメント多め。
アップロード
<?php
$curl = curl_init();
//プロトコルをSFTPに設定
curl_setopt($curl, CURLOPT_PROTOCOLS, CURLPROTO_SFTP);
// 認証方法の設定
curl_setopt($curl, CURLOPT_SSH_AUTH_TYPES, CURLSSH_AUTH_PUBLICKEY);
// ポートを指定する
curl_setopt($curl, CURLOPT_PORT, **);
// 実行ユーザーの公開鍵と秘密鍵のパスを指定する
curl_setopt($curl, CURLOPT_SSH_PUBLIC_KEYFILE, 'pub_key_path');
curl_setopt($curl, CURLOPT_SSH_PRIVATE_KEYFILE, 'pri_key_path');
// アップロードを指定
curl_setopt($curl, CURLOPT_UPLOAD, 1);
// URL設定
// パスワードを指定する場合は user:pass@~の形式にする
$url = "sftp://user@server/~/UploadPath";
curl_setopt($curl, CURLOPT_URL, $url);
// 送信するファイルをオープンして設定する
$fp = fopen($file, 'rb');
curl_setopt($curl, CURLOPT_INFILE, $fp);
curl_setopt($curl, CURLOPT_INFILESIZE, filesize($file));
//実行
$res = curl_exec($curl);
//エラーハンドリング
if(curl_errno($curl) !== 0) {
fclose($fp);
curl_close($curl);
//例外を投げるなりよしなにする
echo 'failed.';
exit;
}
//終わったら後処理
fclose($fp);
curl_close($curl);
echo 'success';
exit;
ファイルの削除
<?php
$curl = curl_init();
// アップロードと同じ設定
curl_setopt($curl, CURLOPT_PROTOCOLS, CURLPROTO_SFTP);
curl_setopt($curl, CURLOPT_SSH_AUTH_TYPES, CURLSSH_AUTH_PUBLICKEY);
curl_setopt($curl, CURLOPT_PORT, **);
curl_setopt($curl, CURLOPT_SSH_PUBLIC_KEYFILE, 'pub_key_path');
curl_setopt($curl, CURLOPT_SSH_PRIVATE_KEYFILE, 'pri_key_path');
// URL設定 削除のときは対象のファイルパスは不要
$url = "sftp://user@server";
curl_setopt($curl, CURLOPT_URL, $url);
// 削除コマンドを発行するように設定する
curl_setopt($curl, CURLOPT_QUOTE, array('rm deleteFilePath'));
//実行
$res = curl_exec($curl);
//エラーハンドリング
if(curl_errno($curl) !== 0) {
curl_close($curl);
//例外を投げるなりよしなにする
echo 'failed.';
exit;
}
//終わったら後処理
curl_close($curl);
echo 'success';
exit;
詰まった個所
curl_setopt($curl, CURLOPT_SSH_AUTH_TYPES, CURLSSH_AUTH_PUBLICKEY);
これがPHP5.2環境だとWarningを吐いて設定されなかった。
公式ドキュメントを見たがPHPのバージョン依存はなく、使っているcurlのバージョンにも問題なかったので結局理由が解らなかった。
今時PHP5.2なんて環境を使うのが悪い。
所感
やっぱフレームワーク無いとこういうのを自前で実装しないといけなくなって面倒なので、フレームワーク使いましょう。