ssh.php 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. <?
  2. ##############################################################################################################
  3. #
  4. # SSH
  5. #
  6. # Developer(s): swiNg
  7. #
  8. # Handles communication through SSH.
  9. #
  10. # I recommended that you pass a fingerprint hash when connecting to host. That will verify the host before
  11. # sending your credentials to it. Get fingerprint from the fingerprint property when connected if you don't
  12. # already have it.
  13. #
  14. # If a shell is opened, the stream is kept alive until disconnected. Commands executed while shell is open
  15. # is written to the existing stream rather than trying to execute the command directly.
  16. #
  17. # The destructor takes care of disconnecting if you don't run disconnect yourself.
  18. #
  19. # Disconnecting will try to make a clean exit before closing the connection by running the command stored in
  20. # the cmd_exit property.
  21. #
  22. ##############################################################################################################
  23. ##############################################################################################################
  24. # CLASS: SSH
  25. ##############################################################################################################
  26. class SSH {
  27. // set variables
  28. public $authed = false; // is set to true if authed
  29. public $fingerprint; // server hostkey hash
  30. public $cmd_delay = 1; // default delay before reading stream after executing a command
  31. public $cmd_exit = "exit"; // command to execute on disconnect
  32. public $cmd_exit_echo = true; // echo response after exit command
  33. private $connection; // variable that holds ssh connection
  34. private $stream; // variable that holds opened shell stream
  35. #*************************************************************************************************************
  36. # FUNCTION: __destruct() //
  37. #*************************************************************************************************************
  38. public function __destruct() {
  39. // always disconnect
  40. $this->Disconnect();
  41. }
  42. #*************************************************************************************************************
  43. # FUNCTION: Connect() // Open SSH connection.
  44. #*************************************************************************************************************
  45. public function Connect($host, $port, $fingerprint = "", $username = "", $password = "", $public_key_path = "", $private_key_path = "") {
  46. $this->Authed = false;
  47. // establish connection
  48. if (!($this->connection = @ssh2_connect($host, $port))) {
  49. throw new Exception("Could not connect to server.");
  50. }
  51. // get/verify fingerprint
  52. $this->fingerprint = ssh2_fingerprint($this->connection, SSH2_FINGERPRINT_MD5 | SSH2_FINGERPRINT_HEX);
  53. if ($fingerprint) {
  54. if (strcmp($this->fingerprint, $fingerprint) !== 0) {
  55. throw new Exception("Unable to verify server identity.");
  56. }
  57. }
  58. // authenticate by key or password if credentials are given
  59. if ($username && $public_key_path && $private_key_path) {
  60. $this->Authed = $this->AuthByKey($username, $public_key_path, $private_key_path);
  61. }
  62. elseif ($username && $password) {
  63. $this->Authed = $this->AuthByPassword($username, $password);
  64. }
  65. }
  66. #*************************************************************************************************************
  67. # FUNCTION: Disconnect() // Close SSH connection.
  68. #*************************************************************************************************************
  69. public function Disconnect($run_exit_cmd = true) {
  70. // set variables
  71. $response = "";
  72. // execute exit command if defined and close shell stream
  73. if ($this->stream) {
  74. if ($run_exit_cmd && $this->cmd_exit) {
  75. $response = $this->Exec($this->cmd_exit, 1);
  76. }
  77. fclose($this->stream);
  78. }
  79. elseif ($run_exit_cmd && $this->authed) {
  80. $response = $this->Exec($this->cmd_exit);
  81. }
  82. // echo response
  83. if ($this->cmd_exit_echo) {
  84. echo $response;
  85. }
  86. // clean up
  87. $this->authed = false;
  88. $this->stream = null;
  89. $this->connection = null;
  90. }
  91. #*************************************************************************************************************
  92. # FUNCTION: AuthByPassword() // Authenticate using password.
  93. #*************************************************************************************************************
  94. public function AuthByPassword($username, $password) {
  95. if ($this->connection) {
  96. if(!$this->authed = @ssh2_auth_password($this->connection, $username, $password)) {
  97. throw new Exception("Autentication rejected by server.");
  98. }
  99. }
  100. }
  101. #*************************************************************************************************************
  102. # FUNCTION: AuthByKey() // Authenticate using key files.
  103. #*************************************************************************************************************
  104. public function AuthByKey($username, $public_key_path, $private_key_path) {
  105. // password protected public keys are not supported becase of a bug in the libssh2 build
  106. if ($this->connection) {
  107. if (!file_exists($public_key_path)) {
  108. throw new Exception("Failed to find public key.");
  109. }
  110. elseif (!file_exists($private_key_path)) {
  111. throw new Exception("Failed to find private key.");
  112. }
  113. elseif (!is_readable($public_key_path)) {
  114. throw new Exception("Failed to read public key.");
  115. }
  116. elseif (!is_readable($private_key_path)) {
  117. throw new Exception("Failed to read private key.");
  118. }
  119. elseif (!$this->authed = @ssh2_auth_pubkey_file($this->connection, $username, $public_key_path, $private_key_path)) {
  120. throw new Exception("Autentication rejected by server.");
  121. }
  122. }
  123. }
  124. #*************************************************************************************************************
  125. # FUNCTION: ReadStream() //
  126. #*************************************************************************************************************
  127. public function ReadStream($buffer_size = 4096) {
  128. // read stream
  129. if ($this->stream) {
  130. $data = fread($this->stream, $buffer_size);
  131. }
  132. else {
  133. $data = false;
  134. }
  135. // return response
  136. return $data;
  137. }
  138. #*************************************************************************************************************
  139. # FUNCTION: Exec() // Execute a command and retrieve the response.
  140. #*************************************************************************************************************
  141. public function Exec($cmd, $delay = -1) {
  142. // set variables
  143. $data = "";
  144. // use existing shell stream if aviable
  145. if ($this->stream) {
  146. // write to stream
  147. fwrite($this->stream, $cmd.PHP_EOL);
  148. // issue delay
  149. if ($delay != 0) {
  150. sleep(($delay == -1 ? $this->cmd_delay : $delay));
  151. }
  152. // read stream
  153. while ($buf = fread($this->stream, 4096)) {
  154. $data .= $buf;
  155. }
  156. }
  157. else {
  158. if (!($stream = @ssh2_exec($this->connection, $cmd))) {
  159. throw new exception("Command failed.");
  160. }
  161. // fetch streams
  162. $err_stream = ssh2_fetch_stream($stream, SSH2_STREAM_STDERR);
  163. $io_stream = ssh2_fetch_stream($stream, SSH2_STREAM_STDIO);
  164. stream_set_blocking($err_stream, true);
  165. stream_set_blocking($io_stream, true);
  166. // read stream (stderr)
  167. while ($buf = fread($err_stream, 4096)) {
  168. $data .= $buf;
  169. }
  170. // read stream (dio)
  171. while ($buf = fread($io_stream, 4096)) {
  172. $data .= $buf;
  173. }
  174. fclose($stream);
  175. }
  176. // return response
  177. return $data;
  178. }
  179. #*************************************************************************************************************
  180. # FUNCTION: Shell() // Request shell and keep stream open.
  181. #*************************************************************************************************************
  182. public function Shell($term_type = "vt102", $delay = -1) {
  183. // set variables
  184. $data = "";
  185. // request shell
  186. if (!($this->stream = @ssh2_shell($this->connection, $term_type))) {
  187. throw new exception("Shell failed.");
  188. }
  189. // issue delay
  190. if ($delay != 0) {
  191. sleep(($delay == -1 ? $this->cmd_delay : $delay));
  192. }
  193. // read stream
  194. while ($buf = fread($this->stream, 4096)) {
  195. $data .= $buf;
  196. }
  197. // return response
  198. return $data;
  199. }
  200. }
  201. ?>