Showing posts with label php. Show all posts
Showing posts with label php. Show all posts

Tuesday, July 10, 2012

Using Phpseclib Read/Write to Manage the Terminal


About Phpseclib


Managing terminal commands with php can be a tricky business.  You have several built-in php commands, such as exec(), system() and passthru().  The issue with these commands is that you will be running all of these commands as the www-data user (or equivalent).  No sudo commands can be run, and you cannot log on as another user.  As well, commands are "one-offs", no interaction with the shell is possible.

You could install the PHP SSH2 library, and run shell commands that way... however, if anyone else would like to use the software, they will have to add that php library as well, since it is not a default library.  The other option you have is phpseclib. Phpseclib is a pure php implementation of SSH2 (and tons others).

In this tutorial we will be covering the SSH2 features of phpseclib, specifically read()/write(), since they can be slightly complicated.

Setting up phpseclib


Extremely simple to do:  download either the stable version (currently 0.3.0) or (as I recommend) pulling the latest version from git: https://github.com/phpseclib/phpseclib.git.  The latest version seems to work much better for me.

Place the folder in your php project folder.  Next, in your php page, include the following code.

set_include_path(get_include_path() . PATH_SEPARATOR . 'phpseclib');

include('Net/SSH2.php');


Next, you need to actually set up an ssh connection to your server in your php script.  Usually this would be localhost.  This is done like so:

$ssh = new Net_SSH2('localhost'); //starting the ssh connection to localhost
if (!$ssh->login($username, $password)) { //if you can't log on...
    exit('Login Failed');
}

If you don't receive an error message, congratulations, you are logged in, that simple.  The $username and $password are actual PHP variables that can be collected from user input (Be careful!  That is sensitive information...)

Phpseclib exec() vs read()/write()


Phpseclib has two different ways to execute shell commands.  The first is exec(), which is simple and effective, and looks like so:

$ssh->exec('killall -v apt-get');

Just make sure that whatever variable you named your connection (in this case $ssh) you use when you execute the command. If you want, you can also store the output of the command like so:

$output = $ssh->exec('killall -v apt-get');

Then you can echo or search the output, which is very useful. Essentially, the exec() command logs on, executes command, then exits. For example, the following command DOES NOT output the contents of "/etc/test":

$ssh->exec('cd /etc/test');
$ssh->exec('ls');

This is because the second command does not follow the first. The connection at the end of the exec command is closed, then reopened for the next command. The ls command will list the contents of the default logon folder (Usually the home folder).


However, the read command could accomplish this... and much more.

Using read() and write() together


IMPORTANT NOTE:  The write() command must simulate the enter key, so end all of your command with "\n".
The read() and write() commands must be used together... the best way to show you is with an example....

$ssh->read('/.*@.*[$|#]/', NET_SSH2_READ_REGEX); //start by reading for the command prompt using regex.. we COULD use our username variable in here to make it even better..
$ssh->write("sudo sed -i 's/KEY_PROVINCE=.*/KEY_PROVINCE=\"$key_province\"/g' $var_file\n");
$ssh->setTimeout(10); //right before the read set timeout so php don't crash/timeout on unexpected output
$output = $ssh->read('/.*@.*[$|#]|.*[P|p]assword.*/', NET_SSH2_READ_REGEX); //reading for either the password or the command prompt
echo "$output
";
if (preg_match('/.*[P|p]assword.*/', $output)) { //if we read a prompt asking for the sudo password
 $ssh->write($password."\n"); //write our password (Stored in $_SESSION) to the prompt and "hit" enter (\n)
 $sed_output = $ssh->read('/.*@.*[$|#]/', NET_SSH2_READ_REGEX); //make sure our password worked, read for the command prompt.....
 echo "
Entering SUDO Password... Check for errors....: $sed_output
"; //echo the output of the command... this usually will print errors/output of command... } $ssh->read('/.*@.*[$|#]/', NET_SSH2_READ_REGEX);//Both reads' appear to be required! $ssh->read('/.*@.*[$|#]/', NET_SSH2_READ_REGEX);//Both reads' appear to be required! echo str_repeat(' ',1024*64);//purging output to the browser


Lets go through the steps involved:
Line 1.  The first $ssh->read is using the REGEX flag, which means it accepts regex commands.  What we are doing here is "reading" what the SSH terminal says currently.  Since we have just logged on, it should be at a command prompt.  So I am using a regex that says "Any number of characters, followed by an "@" symbol, followed by any number of characters, follow by either a "$ or #".  For those of you familiar with the command prompt, you will realize that the regex should work for recognizing almost all command prompts. Once we have read the command prompt, we know it is ready to accept commands.
Line 2.  Now we will write our command, a simple sudo sed command.  You can put php variables in the command as needed.
Line 3.  Set the timeout, so we don't have to wait for php to time out if something goes wrong.
Line 4.  Now we are going to "read" the output from the command, so we save the next ssh->read command to "$output".
Line 5. Just echoing the result of the last write command (this has to be done after the "read" because phpseclib needs to read the result of the last command)
Line 7.  Now we are going to search/read the resulting output to see what we find.  We will once again use a regex, except this time we will test for two outputs.  A) The regular command promt OR B) Password.  As you know, since this is a sudo command, we might get prompted for our sudo password.  If that happens, we need to handle that.
Line 8.  We will reach this command IF either A) or B) happened.  Then we will do a preg_match, to see if the output contains the word "Password". If so, we will write the password to the command line, then read for the command prompt again.

We finally reach the end of the password loop, and next we do a final $ssh->read to get the final results.

IMPORTANT NOTE:  Before launching directly into another $ssh->write command, make sure you add ONE MORE $ssh->read command before doing so, both appear to be required.

Phpseclib Logging


You can view the complete phpseclib log by adding the following lines:

define('NET_SSH2_LOGGING', NET_SSH2_LOG_COMPLEX); //add near include lines

echo $ssh->getLog();//add after the command you want to see the log for....


This will output the log to your browser.

Good luck!




Monday, October 24, 2011

PHP Real-Time Search Using MySQL and AJAX

Recently I decided that instead of posting all of my links directly on my homepage (It was becoming a long list, and annoying to have to edit the HTML every time to add a link) I would create a php based search engine, that used AJAX for real-time results.

After using Google for an extended period of time, finally found my first link: http://woork.blogspot.com/2007/11/simple-search-engine-in-ajax-and-php.html  (I DON'T recommend this unless you know what you are doing, it is full of errors/missing syntax/db connections).  After following this guide (and fixing mistakes) I realized this did not work as I had hoped.  When I searched for my keyword, it did not appear to matter what keyword I searched it pulled all the results up.  Since I am not a php expert, went back to Google and found the following article: http://blogs.nightglass.com/jeremy/2008/07/23/realtime-search-with-php-mysql-and-prototype/

The second article was a much better guide on how to set up real time search, now I just had to edit it to my needs... here is what I wanted.

A search engine that would search my MySQL database of internal website links based on 3 keywords that I specify upon creation of the link.  So I created a MySQL database, lets take a look at the layout.  (Please note I am not even close to proficient with MySQL, which is why I'm using phpmysql).

MySQL Database Setup



The first field is the Index, a simple auto-increment field just to make my links have a unique number.  The next field is "link_text" which is just the html link.  Then I have my three tag fields, the next is the current timestamp, if for example I wanted to show the latest links that were added.


Form.html - The search box setup

The "Form.html" sets up the basic search box, and calls the javascript file, lets take a look:

 
  Live Search!
  
 
 
  Keyword Search:
  


Fairly simple, ignore the first half, that just is styling for the search box.  The part we need starts at "from id="searchform"".  That creates the search box.  Notice "onkeyup" this updates the results every time a key is let up.  The "name=searchq" is also tied to our next php script, so remember that name.

Prototype.js is the javascript that creates the search results, which can be found here.


Search.php - Where the magic happens

Lets take a look at our "search.php" document, which is the main part we need to know.

 


"; //this div is used to contain the results. Mostly used for styling.
   
 //This query searches the name field for whatever the input is.
 $sql = "SELECT link_text FROM Links WHERE link_tag_1 LIKE '%$searchq%' OR link_tag_2 LIKE '%$searchq%' OR link_tag_3 LIKE '%$searchq%' ";
   
 $result = mysql_query($sql);
 while($row = mysql_fetch_assoc($result)) {
  $id = $row['link_text'];
  echo "$id";
                echo "br"; 
  }   
  echo "div";
 }
?>


*Note: I have not yet cleaned the input, so make sure you do that to avoid MySQL injection. Also, because blogger hates me, had to remove the formatting from the last div tag, and there is some odd formatting at the very top.

The first lines are standard, you are connecting to your MySQL server, connecting to your link database and table.

The interesting part is when you grab your search query from form.html "$searchq = $_POST['searchq'];". If it is empty, you will display nothing. Else, you will start getting search results. Next is your sql command. You are selecting the link_text that matches any of your tags for that link. The "%" signs specify any characters before or after the search term, so you don't have to type out the entire tag to get a match, you can type one letter and it will match any of the letters in all of the search terms, and will narrow it down as you type.

Next, we set $id to equal row "link_text" which is just the fully formatted html link, so this displays in your popup box. If you don't like the popup box, go ahead and delete or reformat it in Form.html, I did not like the look so changed it to a simple blue link that appears below search results.

EDIT: The files how now been uploaded to google docs, link to download here. Let me know if you have any problems.

Okay, you should be ready to go, happy searching. Next time I hope to post about adding/changing entries in your mysql database from a web page.