{"id":1620,"date":"2014-01-21T20:37:15","date_gmt":"2014-01-21T14:37:15","guid":{"rendered":"http:\/\/notes.norfolks.org\/?p=1620"},"modified":"2014-01-21T20:43:18","modified_gmt":"2014-01-21T14:43:18","slug":"make-ssh-connections-with-php","status":"publish","type":"post","link":"https:\/\/notes.norfolks.fun\/?p=1620","title":{"rendered":"Make SSH connections with PHP"},"content":{"rendered":"<p><strong>kvz.io <\/strong><br \/>\n<em>24 Jul 2007 <\/em><\/p>\n<p>Not everyone knows about PHP&#8217;s capabilities of making SSH connections and executing remote commands, but it can be very useful. I&#8217;ve been using it a lot in PHP CLI applications that I run from cronjobs, but initially it was a pain to get it to work. The PHP manual on Secure Shell2 Functions is not very practicle or thorough for that matter, so I would like to share my knowledge in this how to, to make it a little less time consuming setting this up.<\/p>\n<p>In this article I&#8217;m going to assume that:<\/p>\n<ul>\n<li>You&#8217;re running Debian \/ Ubuntu If not, you will have to substitute the package manager aptitude with whatever your distribution provides<\/li>\n<li>You&#8217;re running PHP 5 If not, just replace php5 with php4 everywhere<\/li>\n<li>You have basic knowledge of PHP &#038; server administration<\/li>\n<li>You already have PHP installed<\/li>\n<\/ul>\n<p><strong>Update<\/strong><\/p>\n<p>On recent Ubuntu machines, there&#8217;s no need to do any compiling anymore:<\/p>\n<pre lang=\"bash\">$ aptitude install libssh2-1-dev libssh2-php<\/pre>\n<p>You can now test if PHP recognizes it&#8217;s new ssh2 extension by running:<\/p>\n<pre lang=\"bash\">$ php -m |grep ssh2<\/pre>\n<p>It should return: <code>ssh2<\/code><\/p>\n<p>If the above works for you (you should see also: &#171;Build process completed successfully&#187;), you can skip to: <strong>Great! PHP supports SSH &#8212; time to code.<\/strong><\/p>\n<p>Otherwise we need to compile manually, continue reading here.<br \/>\n<strong>Prerequisites<\/strong><br \/>\n<strong>Packages<\/strong><\/p>\n<p>First let&#8217;s install the following packages:<\/p>\n<pre lang=\"bash\">$ aptitude install php5-dev php5-cli php-pear build-essential openssl-dev zlib1g-dev<\/pre>\n<p>That should set us up alright.<br \/>\n<strong>libssh2<\/strong><\/p>\n<p>We need libssh2 from sourcefourge. We have to compile this, but no worries, this is all you need to do:<\/p>\n<pre lang=\"bash\">$ cd \/usr\/src \\\r\n && wget http:\/\/surfnet.dl.sourceforge.net\/sourceforge\/libssh2\/libssh2-0.14.tar.gz \\\r\n && tar -zxvf libssh2-0.14.tar.gz \\\r\n && cd libssh2-0.14\/ \\\r\n && .\/configure \\\r\n && make all install<\/pre>\n<p>\u0412\u043e\u0442 \u0438 \u0432\u0441\u0435! \u041b\u0435\u0433\u043a\u043e, \u043d\u0435 \u0442\u0430\u043a \u043b\u0438?<\/p>\n<ul>\n<li>Update: since December 26th 2008, libssh2 has reached version 1.0. Though I have not tested it: it has been reported to work. So you may want to check sf.net and download the latest stable version.<\/li>\n<\/ul>\n<p><strong>Installation<\/strong><br \/>\n<strong>ssh2.so<\/strong><\/p>\n<p>Next we need to link libssh &#038; PHP together. There&#8217;s a PECL module for this so let&#8217;s install using:<\/p>\n<pre lang=\"bash\">$ pecl install -f ssh2<\/pre>\n<p>The -f makes sure ssh2 is installed even though there&#8217;s not a stable candidate. You could also use the package name: ssh2-beta to overrule this.<\/p>\n<p>Now you need to make sure our new <code>ssh2.so<\/code> module is loaded by PHP. Edit a php.ini file (I&#8217;d recommend a separate one: <code>\/etc\/php5\/conf.d\/ssh2.ini<\/code>). Make sure it reads:<\/p>\n<pre lang=\"bash\">extension=ssh2.so<\/pre>\n<p><strong>Great! PHP supports SSH &#8212; time to code<\/strong><\/p>\n<p>You&#8217;ve just enabled ssh2 support in PHP. Now how can we make use of this? There are 2 options. SSH supports the:<\/p>\n<ul>\n<li>Execute method This tells the server&#8217;s operating system to execute something and pipe the output back to your script. (recommended)<\/li>\n<li>Shell method This opens an actual shell to the operating system, just as you would normally when logging in with your terminal application. Some routers that don&#8217;t have a full POSIX compliant implementation, but run their own application as soon as you login, require this. (advanced)<\/li>\n<\/ul>\n<p><strong>\u041c\u0435\u0442\u043e\u0434 1: Execute<\/strong><\/p>\n<p>Best would be to create functions or even a class for the following code, but this is the basic idea and will definitely get you started:<\/p>\n<pre lang=\"php\"><?php\r\nif (!function_exists(\"ssh2_connect\")) die(\"function ssh2_connect doesn't exist\");\r\n\/\/ log in at server1.example.com on port 22\r\nif(!($con = ssh2_connect(\"server1.example.com\", 22))){\r\n    echo \"fail: unable to establish connection\\n\";\r\n} else {\r\n    \/\/ try to authenticate with username root, password secretpassword\r\n    if(!ssh2_auth_password($con, \"root\", \"secretpassword\")) {\r\n        echo \"fail: unable to authenticate\\n\";\r\n    } else {\r\n        \/\/ allright, we're in!\r\n        echo \"okay: logged in...\\n\";\r\n\r\n        \/\/ execute a command\r\n        if (!($stream = ssh2_exec($con, \"ls -al\" ))) {\r\n            echo \"fail: unable to execute command\\n\";\r\n        } else {\r\n            \/\/ collect returning data from command\r\n            stream_set_blocking($stream, true);\r\n            $data = \"\";\r\n            while ($buf = fread($stream,4096)) {\r\n                $data .= $buf;\r\n            }\r\n            fclose($stream);\r\n        }\r\n    }\r\n}\r\n?><\/pre>\n<p><strong>\u041c\u0435\u0442\u043e\u0434 2: Shell<\/strong><\/p>\n<p>Best would be to create functions or even a class for the following code, but this is the basic idea and will definitely get you started:<\/p>\n<pre lang=\"php\"><?php\r\nif (!function_exists(\"ssh2_connect\")) die(\"function ssh2_connect doesn't exist\");\r\n\/\/ log in at server1.example.com on port 22\r\nif (!($con = ssh2_connect(\"server1.example.com\", 22))) {\r\n    echo \"fail: unable to establish connection\\n\";\r\n} else {\r\n    \/\/ try to authenticate with username root, password secretpassword\r\n    if (!ssh2_auth_password($con, \"root\", \"secretpassword\")) {\r\n        echo \"fail: unable to authenticate\\n\";\r\n    } else {\r\n        \/\/ allright, we're in!\r\n        echo \"okay: logged in...\\n\";\r\n\r\n        \/\/ create a shell\r\n        if (!($shell = ssh2_shell($con, 'vt102', null, 80, 40, SSH2_TERM_UNIT_CHARS))) {\r\n            echo \"fail: unable to establish shell\\n\";\r\n        } else {\r\n            stream_set_blocking($shell, true);\r\n            \/\/ send a command\r\n            fwrite($shell, \"ls -al\\n\");\r\n            sleep(1);\r\n\r\n            \/\/ &#038; collect returning data\r\n            $data = \"\";\r\n            while ($buf = fread($shell,4096)) {\r\n                $data .= $buf;\r\n            }\r\n            fclose($shell);\r\n        }\r\n    }\r\n}\r\n?><\/pre>\n<p><strong>Tips<\/strong><\/p>\n<p>Sometimes when a server is busy, or a connection is buggy, the buffer may run dry, and the PHP script stops collecting data from a command output (even though the command hasn&#8217;t completed yet!). There are a couple of things you could do about that:<\/p>\n<pre lang=\"php\"><?php\r\nssh2_exec($con, 'ls -al; echo \"__COMMAND_FINISHED__\"' );\r\n?>\r\n<\/pre>\n<p>Now, in the loop where you keep checking for the buffer, just see if the COMMAND_FINISHED line is coming by. Because then you know you have all the data. To avoid infinite loops, just limit the loop with a timeout of 10 seconds or so:<\/p>\n<pre lang=\"php\"><?php\r\n$time_start = time();\r\n$data       = \"\";\r\nwhile (true){\r\n    $data .= fread($stream, 4096);\r\n    if (strpos($data,\"__COMMAND_FINISHED__\") !== false) {\r\n        echo \"okay: command finished\\n\";\r\n        break;\r\n    }\r\n    if ((time()-$time_start) > 10 ) {\r\n        echo \"fail: timeout of 10 seconds has been reached\\n\";\r\n        break;\r\n    }\r\n}\r\n?><\/pre>\n<p>In the example above, you&#8217;d better set streamsetblocking to false.<\/p>\n<p><strong>Can&#8217;t get enough?<\/strong><\/p>\n<p>PHP can send files over ssh!<\/p>\n<pre lang=\"php\"><?php\r\nssh2_scp_send($con, \"\/tmp\/source.dat\", \"\/tmp\/dest.dat\", 0644);\r\n?><\/pre>\n<p><strong>\u041d\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442?<\/strong><\/p>\n<p>Check the following:<\/p>\n<ul>\n<li>Did you follow every step of the prerequisites &#038; installation how to in this article?<\/li>\n<li>On the serverside, &#8216;PasswordAuthentication yes&#8217; must be enabled in the sshd_config. Default is yes on most servers, but in some cases you will have to turn this on yourself by making sure the following line is in place in the file: <code>\/etc\/ssh\/sshd_config: PasswordAuthentication yes<\/code><\/li>\n<\/ul>\n<p>If you&#8217;ve made any changes, ssh needs a restart<\/p>\n<pre lang=\"bash\">$ \/etc\/init.d\/ssh restart<\/pre>\n<p>Post a comment here if it&#8217;s still failing. Don&#8217;t forget to paste the error that you&#8217;re getting.<\/p>\n<p><strong>make: *** [ssh2.lo] Error 1<\/strong><\/p>\n<p>If you get the error:<\/p>\n<pre lang=\"text\">\/usr\/include\/php5\/Zend\/zend_API.h:361: note: expected char * but argument is of type const unsigned char *\r\nmake: *** [ssh2.lo] Error 1<\/pre>\n<p>that&#8217;s because of PHP 5.3 incompatibility. Try this patch:<\/p>\n<pre lang=\"bash\">$ mkdir -p \/usr\/src \\\r\n && cd \/usr\/src \\\r\n && wget http:\/\/pecl.php.net\/get\/ssh2-0.11.0.tgz \\\r\n && tar xvfz ssh2-0.11.0.tgz \\\r\n && cd ssh2-0.11.0 \\\r\n && wget http:\/\/remi.fedorapeople.org\/ssh2-php53.patch \\\r\n && patch -p0 < ssh2-php53.patch \\\r\n &#038;&#038; phpize &#038;&#038; .\/configure --with-ssh2 \\\r\n &#038;&#038; make<\/pre>\n<p><strong>make: *** [ssh2fopenwrappers.lo] Error 1<\/strong><\/p>\n<p>If you get the error:<\/p>\n<pre lang=\"text\">\/tmp\/pear\/download\/ssh2-0.11.0\/ssh2_fopen_wrappers.c:49: error: for each function it appears IN.)\r\nmake: *** [ssh2_fopen_wrappers.lo] Error 1\r\nERROR: `make' failed<\/pre>\n<p>This is the <a href=\"http:\/\/cvs.php.net\/viewvc.cgi\/pecl\/ssh2\/ssh2-fopen-wrappers.c?r1=1.15&#038;r2=1.16&#038;diff-format=u\">reported fix<\/a> (thanks to BuNker).<\/p>\n<p><strong>\u0410\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u044b<\/strong><\/p>\n<p>There have been some additional developments since the writing of this article. Checkout:<br \/>\nNet_SSH2, PEAR's SSH wrapper (driver based to support multiple ways of establishing the connection)<br \/>\nSSH2, another wrapper by Jaimie Sirovich<br \/>\nphpseclib, a pure PHP implementation - no additional libraries, binaries, bindings required (against all odds, still pretty fast with mcrypt installed)<\/p>\n<p><a href=\"http:\/\/kvz.io\/blog\/2007\/07\/24\/make-ssh-connections-with-php\/\">http:\/\/kvz.io\/blog\/2007\/07\/24\/make-ssh-connections-with-php\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>kvz.io 24 Jul 2007 Not everyone knows about PHP&#8217;s capabilities of making SSH connections and executing remote commands, but it can be very useful. I&#8217;ve been using it a lot in PHP CLI applications that I run from cronjobs, but &hellip; <a href=\"https:\/\/notes.norfolks.fun\/?p=1620\">\u0427\u0438\u0442\u0430\u0442\u044c \u0434\u0430\u043b\u0435\u0435 <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[14,15],"tags":[],"class_list":["post-1620","post","type-post","status-publish","format-standard","hentry","category-linux","category-php"],"_links":{"self":[{"href":"https:\/\/notes.norfolks.fun\/index.php?rest_route=\/wp\/v2\/posts\/1620","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/notes.norfolks.fun\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/notes.norfolks.fun\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/notes.norfolks.fun\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/notes.norfolks.fun\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1620"}],"version-history":[{"count":6,"href":"https:\/\/notes.norfolks.fun\/index.php?rest_route=\/wp\/v2\/posts\/1620\/revisions"}],"predecessor-version":[{"id":1626,"href":"https:\/\/notes.norfolks.fun\/index.php?rest_route=\/wp\/v2\/posts\/1620\/revisions\/1626"}],"wp:attachment":[{"href":"https:\/\/notes.norfolks.fun\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1620"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/notes.norfolks.fun\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1620"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/notes.norfolks.fun\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1620"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}