PHP + ssh2
大量のリモートサーバ上で何かの処理を一斉に実行したいとき、expect使ったりシェルで書くよりPHPに慣れた人ならPECLのssh2を使うと便利かも。
<?php class sshClass { function __construct(){ } function sshCls(){ if(PHP_VERSION < 5){ $this->__construct(); } } function _setAuthPassword($user, $pass){ if($user !== ''){ $this->user = $user; }else{ die("ユーザ名がありません。\\n"); } if($pass !== ''){ $this->pass = $pass; }else{ die("パスワードがありません。\\n"); } } function _connect($server){ $this->conn = ssh2_connect($server, '22'); } function execute($user, $pass, $server, $cmd){ $this->_setAuthPassword($user, $pass); if($cmd === ''){ die("コマンドを指定して下さい。\\n"); } $cmd .= "\\n"; $this->_connect($server); if(ssh2_auth_password($this->conn, $user, $pass)){ //echo "Authentication Successful!\\n"; }else{ die("認証に失敗しました。\\n"); } $fp = ssh2_shell($this->conn, 'xterm'); if($fp){ fwrite($fp, $cmd); //ココが肝心 sleep(1); do{ $data = fgets($fp, '1024'); if(strlen($data) == 0){ break; } $this->return .= $data; }while(true); }else{ die("接続に失敗しました。\\n"); } } function getResult(){ return $this->return; } } $obj = new sshClass(); $obj->execute('user', 'pass', 'example.com', "ls -l /home"); print($obj->getResult() . "\\n"); ?>
こんな感じ。PECLモジュールのビルドにはlibssh2が必要。
それから、いろいろ試していたらscpでファイルの送信がうまくいかなかったので下のようにSFTPと組み合わせるメソッドを追加したり。
function putFile($user, $pass, $server, $local, $remote, $perm='0644'){ $this->_setAuthPassword($user, $pass); $this->_connect($server); if(ssh2_auth_password($this->conn, $user, $pass)){ print("認証に成功しました。\\n"); }else{ die("認証に失敗しました。\\n"); } if(ssh2_scp_send($this->conn, $local, $remote, $perm)){ $this->return = "SCPでファイル".$local."を送信しました。\\n"; }else{ $this->return = "ファイルを送信できませんでした。SFTPに切り替えます。\\n"; $this->sftp = ssh2_sftp($this->conn); $fp = fopen("ssh2.sftp://" . $this->sftp . $remote, 'w'); if($fp){ $data = file_get_contents($local); fwrite($fp, $data); fclose($fp); $this->return .= "SFTPでファイル".$local."を送信しました。\\n"; }else{ $this->return .= "ファイルを送信できませんでした。\\n"; } } }
上の方、一度コマンド実行したら再接続しないといけないのでthis->connの使い回しはやめた。
コメントを残す