Thursday, February 28, 2008

How to delete all files and subfolders in a directory with PHP

If you have access to the shell or SSH, you can type in:

rm -fr /path/to/dir/
to delete all files and folders in a directory. However, if you don't have shell access, you may want to try running a system command via php.
echo exec('rm -fr /path/to/dir/');
If your PHP is not allowed to execute system commands, then you'll have to suffice to the PHP functions for directory and file traversal and manipulation.

In my last post I talked about installing Joomla on a remote server. Sometimes you make a few mistakes, and want to remove a whole directory and all files in it. If you don't have the benefit of a shell or shell command execution with PHP, you have to write your own functions to delete the non empty directory.

Deletes all subfolders and files in a directory recursively

/**
 * Deletes a directory and all files and folders under it
 * @return Null
 * @param $dir String Directory Path
 */
function rmdir_files($dir) {
 $dh = opendir($dir);
 if ($dh) {
  while($file = readdir($dh)) {
   if (!in_array($file, array('.', '..'))) {
    if (is_file($dir.$file)) {
     unlink($dir.$file);
    }
    else if (is_dir($dir.$file)) {
     rmdir_files($dir.$file);
    }
   }
  }
  rmdir($dir);
 }
}

This is quite a nasty function. You want to handle it with care. Make sure you don't delete any directories that you do not intend to delete. It will attempt to remove the whole directory, and all files in it. It does no error checking apart from making sure a directory handle was opened successfully for reading.

Remote Installation of Joomla

Working mainly with the Joomla CMS as our base for building websites, I have to install at least one Joomla site a week. Sometimes, 2-3 a day. This can become quite tedious. Here is a few tricks to help you out.

What this applies to

This article does not apply to Joomla alone. It can be used to install any web application on a remote server.

What to avoid when doing a remote install

If you have a T3 connection, then you probably don't mind downloading the full Joomla installation package. However, in if you have a relatively slow connection like I do, you want to avoid having to download anything to your local computer. What you want is to have all downloads go between the remote computer, and the remote site you are downloading Joomla from.

Uploading uncompressed folders, apart from being slow, is more error prone. Some FTP clients are known to lose a few files here and there. Your files will inherit the privileges set by your local system, or the ftp client. You don't want this. What you want is to upload a compressed archive, then uncompress it on your server, letting it create the privileges.

Installing Joomla with remote Shell Access

If you have SSH privileges on the remote host, then installing Joomla should be a breeze.

First fire up your SSH client, such as Putty. Then make your way to the folder you will be installing Joomla.

eg: cd /var/www/html/joomla1/
or
eg: cd /user/root/public_html/joomla1/
The filesystem structure will depend on your system.

Go to Joomla website and find the download page for the latest Joomla version you want to install. As the time of this writing, there are two forks of the Joomla CMS, the 1.0.x and 1.5 versions.

Regardless of which version you choose, make sure its the latest update, and the full package.

Now, instead of downloading Joomla to your computer, right click the download link and copy the URL.

In your SSH client, use wget to retrieve the remote file to the folder you will be installing Joomla. eg:

wget 'http://joomlacode.org/gf/download/frsrelease/6828/22537/Joomla_1.0.15-Stable-Full_Package.tar.gz'
I do this by typing in wget and then right clicking in the putty screen to paste the Joomla download URL.

Now you should have the file:

/var/www/html/joomla1/Joomla_1.0.15-Stable-Full_Package.tar.gz

Now you need to uncompress the file.

gunzip 'Joomla_1.0.15-Stable-Full_Package.tar.gz'
tar -xvf 'Joomla_1.0.15-Stable-Full_Package.tar'

gunzip will uncompress the Gzip archive. This will leave you with the Tar achive: Joomla_1.0.15-Stable-Full_Package.tar. You want to uncompress this too so so you use tar -xvf. Regarding -xvf: x if for extract, v is for verbose, and f is for file.

Now you should have the uncompressed Joomla Installation in your folder. So you will just have to go to your browser, type in the URL of the installation folder, and you can start with the web based installation.

Before you do that, you will need to set up your database.

This is quick and easy from the shell.

mysql -u username -p 
Assuming you have the user root with full privileges, you can log into mysql with that user and create your database:
mysql -u root -p 
You will be prompted for the password, which you fill in and hit enter.

Now you should be logged into mysql, so you can create your database.

create database `joomla_joomla1`;
I usually prefix all Joomla databases with joomla_. You can name it anything you want.

Now that you have your database table, you can associate a user with that table. Its good to have a user that only has access to that table.

GRANT ALL PRIVILEGES ON joomla_joomla1.* TO joomla@localhost IDENTIFIED BY 'abc123xyz';
where 'abc123xyz' is of course the password. This will create the user joomla, with full privileges to the joomla_joomla1 database. In joomla_joomla1.*, the asterisk matches any table in the joomla_joomla1 database. joomla@localhost means the user has to be on the host, localhost and not a different domain.

Now you can continue with the online installer, fill in the database installation, and complete the installation of Joomla.

Installing Joomla with PHP shell execution

If you don't have shell access, then it may not be so simple. However, you can still achieve something similar to shell access by using PHP to execute your commands.

If you at least have access to a remote server which as a faster internet connection then your local internet connection, you may want to use that speed to your benefit. You can log into a different server with SSH, then open an FTP session between your SSH server and the server you will be installing Joomla on. Then you can transfer the Joomla installation package from Joomla.org to your SSH server with wget, then FTP it to the Joomla Install server.

Another method is to open an FTP session to the server you will install Joomla on, and create a PHP file on the directory you will be installing Joomla on. Then you place commands in the PHP file and execute them. For example, to download Joomla.

<?php
echo exec("wget 'http://joomlacode.org/gf/download/frsrelease/6828/22537/Joomla_1.0.15-Stable-Full_Package.tar.gz'");
?>
exec() executes system commands from within PHP. You can also use system() or an equivalent function if system commands execution is allowed in your PHP installation.

If you're able to execute shell commands from within PHP, you can follow the steps in "installing Joomla with Remote Shell Access" but each time you will have to write the shell command into PHP and then execute it from visiting the page in the browser.

Installing Joomla with just PHP

Now on some servers, you're just stuck with no shell access, and shell calls disabled in PHP. This give you no choice but to install Joomla with just PHP, or FTP. Still, I prefer using PHP to uploading each file via FTP.

Here's how to quickly download the Joomla Installation package:

<?php

/**
 * Copy a remote URL to local file
 * @return Bool Success or Failure
 * @param $url String URL
 * @param $file String Local File
 */
function copy_url($url, $file, $len = 2028) {
 $len = intval($len ? $len : 2028);
 $ur = fopen($url, 'rb');
 $fw = fopen($file, 'wb');
 if ($ur && $fw) {
  while($buf = fread($ur, $len)) {
   if (!fwrite($fw, $buf, $len)) {
    return false;
   }
  }
  fclose($ur);
  fclose($fw);
  return true;
 }
 return false;
 
}

// download the Joomla install archive
$url = 'http://joomlacode.org/gf/download/frsrelease/6828/22537/Joomla_1.0.15-Stable-Full_Package.tar.gz';
$file = 'joomla.tar.gz';
copy_url($url, $file);

?>

Now you have to uncompress this archive. If you have access to Cpanel, you can easily do this using the Cpanel File Manager. Otherwise, you'll have to PHP functions. (I will update a function for this here). Update: See comments for the unzip function.

To create the MySQL database using PHP, you still need a user with database creation privileges. You can also use PHPMyAdmin if you have that installed on the server.

<?php

error_reporting(E_ALL);

echo 'connect to db
'; $link = mysql_connect('localhost', 'root', 'abc123xyz'); if (!$link) die('Could not connect to db'); echo 'create table
'; $query = 'create database joomla_joomla1'; $result = mysql_query($query); if (!$result) { echo('Invalid query: ' . mysql_error()); } echo 'close link
'; mysql_close($link); ?>
Save the PHP code to a PHP file and execute it by visiting the URL in the browser.

If all went well, you should have a joomla installation and a database ready. So now you can visit the Joomla folder via the browser and start with your Installation of Joomla.

Security Precautions while installing Joomla

A good idea, is to always secure the directory you are going to install Joomla in, with a .htaccess file. You can easily set up HTTP Basic Authentication just for the duration of your install. Otherwise, the installation is open to the public. So if you went out for tea and came back to finish the install, you could have ABC Hacker from XYZ has defaced your Server printed on your screen.

After installing Joomla, always delete the installation directory, as well as the INSTALL.php file.

Conclusion

I hope this bit has helped you make your installations of Joomla, or any other PHP application a bit more efficient.

Tuesday, February 26, 2008

Secure HTTP over SSH proxy with Putty

This articles explains how to set up your own SSH proxy for browsing the internet. It will allow you to encrypt your browser session, as well as hide your local IP from outsiders, which is more secure.

Please note that it is your responsibility to use the information in this article within the legal laws of your country. Some countries do not allow encryption of internet traffic, therefore you SHOULD NOT use this resource if you live in such a country. I live in Fiji and not one of those countries, therefore, I provide this information openly for those living in such countries.

Benefits of an HTTP over SSH Proxy

Once you've set up your proxy, all HTTP Requests from your country, to your remote server will be encrypted over SSH.

Your IP address as seen from the remote HTTP server you are connecting to (remote website) will be that of your remote SSH server, not your local computer. So to the remote site, it looks like you're in the country of your remote SSH server.

What would I use this for?

I use it every time I need pass over any sensitive information over an unsecured network, such wireless network, or internet cafe.

How Do I set up an HTTP over SSH Proxy

You will require a remote SSH server. If you purchase web hosting online, normally it will come with SSH access. If you purchase a shared hosting account, then you may have to ask for SSH access. Having a dedicated or VPS server will definitely come with SSH access.

You will also require an SSH client on your local computer. The one I use is Putty.

Setting up Putty to create an SSH tunnel

Once you have Putty installed, open it and under the session category, type in the IP address or Domain name of your remote server into the "Host Name" field.

In the Category open up the Connection Tree. Connection -> SSH -> Tunnels. Under Tunnels you will have "Add new forward port". For source port, type in a free port number. eg: 3000.

Choose the dynamic option under Destination, and click the Add button. You should have D3000 listed under the Forwarded ports list.

Now go back to the Session category and click the open button to start the SSH session. You should now have port 3000 on your local machine bound to the putty session. It will listen for any incoming traffic and forward it on.

Setting up your browser to use the SSH tunnel as its proxy

I use Firefox, but this could easily be done with IE6 or IE7 also. In Firefox click on the Tools Tab.

  • Tools -> Options -> Advanced -> Network
  • Under Connection click on the Settings button
  • Choose Manual Proxy configuration, and SOCKS v5
  • Fill in localhost for the host, and 3000 for the port
  • Click OK and reload the page

Now you should be browsing the internet through your SSH proxy. To confirm this you can visit http://whatismyip.com/ and view your IP. It should change when you switch between using the Socks Proxy and using a direct connection to the internet.

You can also type 'whois IP', into your SSH console to view the details for your IP. Where IP is your IP seen by whatismyip.com.

Now you can worry a bit less about your online privacy.

Thursday, February 14, 2008

Hacking Google Suggest (complete) with JavaScript Remoting

Google Suggest is an feature of the Google Search Engine User Interface and Server that creates suggestions (auto-completes) your search keywords.

This is performed using AJAX. Google will send the first few letters or word(s) you type into the Search Input back to the Google Server using the XMLHttpRequest Object (or a similar AJAX method)

When I type in the search keywords "javascript". I can watch the XMLHttpRequests created by Google Search using Firefox's Firebug extension. Google creates 5 XMLHttpRequests, each one a few letters more then the previous.

The Google Suggest XMLHttpRequests

  • http://www.google.com/complete/search?hl=en&client=suggest&js=true&q=ja - does not complete
  • http://www.google.com/complete/search?hl=en&client=suggest&js=true&q=java - completes and returns:
    window.google.ac.Suggest_apply(frameElement, "java", new Array(2, "java download", "21,600,000 results"
    
    , "java api", "9,000,000 results", "java runtime", "2,510,000 results", "java.com", "1,350,000 results"
    
    , "java update", "11,500,000 results", "javascript tutorial", "1,490,000 results", "java string", "3
    
    ,920,000 results", "java runtime environment", "894,000 results", "javanoid", "71,000 results", "java
    
     virtual machine", "2,050,000 results"), new Array(""));
  • http://www.google.com/complete/search?hl=en&client=suggest&js=true&q=javasc - completes and returns:
    window.google.ac.Suggest_apply(frameElement, "javasc", new Array(2, "javascript tutorial", "1,490,000
    
     results", "javascript substring", "120,000 results", "javascript redirect", "291,000 results", "javascript
    
     download", "20,300,000 results", "javascript replace", "283,000 results", "javascript settimeout", "198
    
    ,000 results", "javascript split", "251,000 results", "javascript indexof", "130,000 results", "javascript
    
     switch", "1,150,000 results", "javascript string replace", "153,000 results"), new Array(""));
    
  • http://www.google.com/complete/search?hl=en&client=suggest&js=true&q=javascri - does not complete
  • http://www.google.com/complete/search?hl=en&client=suggest&js=true&q=javascript - completes and returns:
    window.google.ac.Suggest_apply(frameElement, "javascript", new Array(2, "javascript tutorial", "1,490
    
    ,000 results", "javascript substring", "120,000 results", "javascript redirect", "291,000 results", "javascript
    
     download", "20,300,000 results", "javascript replace", "283,000 results", "javascript settimeout", "198
    
    ,000 results", "javascript split", "251,000 results", "javascript indexof", "130,000 results", "javascript
    
     switch", "1,150,000 results", "javascript string replace", "153,000 results"), new Array(""));
    

As you can see, each response is a JavaScript function call. Google Search makes the XMLHttpRequest call asynchronously as you type your search query, and aborts the last XMLHTTPRequest if you type more than 2 to 3 letters. Each XMLHttpRequest result is a call to the method: window.google.ac.Suggest_apply(). What what can do is create this method in our JavaScript, and wait for Google Suggest to call it with the suggested keywords and their "weight" as parameters.

Hacking Google Suggest for our own use

Now the fun part. What we do is make a HTTP request to the Google URL http://www.google.com/complete/search?hl=en&client=suggest&js=true&q={q}, where q is our keyword. Google will then return the Google Search Suggestions for that keyword.

Try it by clicking: http://www.google.com/complete/search?hl=en&client=suggest&js=true&q=javascript

Now that we know how to get Google Suggest results from the Google server, we can implement it with JavaScript. Due to the XMLHttpRequest Same Domain Policy, we cannot use the XMLHttpRequest Object. However, the results of each Google Suggest query is javascript, so we can use JavaScript Remoting.

Here is an example:

Try our Google Suggest Hack yourself. View source to see how it works.

Saturday, February 9, 2008

Native (W3C) XMLHttpRequest for IE6 and earlier browsers

With IE7 implementing XMLHttpRequest as a native JavaScript Object, the need to fork JavaScript for XMLHttpRequest is now limited to IE6 and earlier major browsers.

Here is my wrapper for IE6 and lower browsers so you can use the XMLHttpRequest syntax in those browsers also.

/**
* Emulate window.XMLHttpRequest in IE6-
*/
if (!window.XMLHttpRequest) {
 var ms_xhr_ver = false;
 window.XMLHttpRequest = function() {
  if (ms_xhr_ver) return new ActiveXObject(ms_xhr_ver);
  var xhr = false;
  var versions = [
  "Msxml2.XMLHTTP.7.0", 
  "Msxml2.XMLHTTP.6.0", 
  "Msxml2.XMLHTTP.5.0", 
  "Msxml2.XMLHTTP.4.0", 
  "MSXML2.XMLHTTP.3.0", 
  "MSXML2.XMLHTTP",
  "Microsoft.XMLHTTP"];
  var n = versions.length;
  for (var i = 0; i <  n; i++) {
   try {
    if (xhr = new ActiveXObject(versions[i])) {
     ms_xhr_ver = versions[i];
     break;
    }
   } catch (e) { /* try next */ }
  }
  return xhr;
 };
}

Here is some example usage:

/**
* Example usage of native XHR in IE6
*/
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() { 
 if (xhr.readyState == 4) {
  if (xhr.status == 200) {
   alert(xhr.responseText);
  }
 }
};
xhr.open('get', '/2008/02/native-w3c-xmlhttprequest-for-ie6-and.html');
xhr.send('');

Try It

You'll notice that you can use the same syntax in all major browsers, Firefox, IE6, IE7, Safari etc. There is not branching of code once you have emulated native XMLHttpRequest for IE6 and earlier browsers. This can be a good base to either make XMLHttpRequest requests directly, or to build your XMLHttpRequest library.

While I'm on the topic, I'd like to point out a major flaw in some popular XMLHttpRequest libraries. They wrap the ActiveX based XHR of IE6 and earlier before wrapping the native XMLHttpRequest. This will make IE7 use the older version of XMLHttpRequest.

Next I think I'll blog about cross-domain XMLHttpRequest.