VirtualBox: hosting LAMP Server on the guest OS and making it available to the host 1

I have been guilty of not reporting my findings at work on this blog as regularly as I had intend to. This can be attributed to various reasons more notably due to the change in place of work (more on that to come in the next weeks, need some time to put my thoughts together on that one).

This week, since I no longer have access to VMWare Fusion (where things just worked out of the box), i had to consider setting up my vms on the one of the popular open source alternatives VirtualBox.
VirtualBox
Its pretty neat and easy to setup and getting a vm installed and running on it, however the first thing that struck me was that the VM are setup to use NAT which means that the VM can ping the host and the internet, but cannot be contacted by the outside world, not even the host. This being a great idea in case you need it just to check your emails or surf the internet in a safe manner, turns out to be a limitation is you are like me, interested in hosting your servers on the vm to be used as a dev box.

It turns out that virtual machine receives its network address and configuration on the private network from a DHCP server integrated into VirtualBox. The IP address thus assigned to the virtual machine is usually on a completely different network than the host. As more than one card of a virtual machine can be set up to use NAT, the first card is connected to the private network 10.0.2.0, the second card to the network 10.0.3.0 and so on. If you need to change the guest-assigned IP range for some reason, please refer to the section called “Configuring the address of a NAT network interface”.

Pinging this ip adress from the host doesnt work as its on a different subnet than the host (as its usually the case). The documentation for virtualbox states if you need to access a server on the guest on the host, you would need to setup Port Forwarding on the host so that the traffic on the host is directed to a port on the vm.

This turns out to be a pretty handy feature, especially since it can be used to protected your server from OS specific exploitable vulnerabilities, as the actual OS hosting the service can not be contacted. Obviously its assumed that in this case the host/guest OS are not the same :) .

So here’s my sample setup. I am running a LAMP server on my guest os an image of JeOS and for now i am only concerned about accessing the webserver on my host machine and also from other machines on the network (something that you cant do out of the box on VMWare Fusion, though i am sure it can be done on it by one means or the other).

I run the following commands:

  # VBoxManage setextradata "JeOS" "VBoxInternal/Devices/pcnet/0/LUN#0/Config/guesthttp/Protocol" TCP
  # VBoxManage setextradata "JeOS" "VBoxInternal/Devices/pcnet/0/LUN#0/Config/guesthttp/GuestPort" 80
  # VBoxManage setextradata "JeOS" "VBoxInternal/Devices/pcnet/0/LUN#0/Config/guesthttp/HostPort" 8080

The above example assumes a PCNet virtual network card; if you have configured the guest to use the Intel PRO/1000, replace “pcnet” with “e1000″ in the above commands. Similarly, if you want to configure a different interface instance replace the /0/ with the appropriate index. pcnet and e1000 are counted separately in this respect, and counting starts at 0 for both types.

The name guesthttp is an arbitrary one chosen for this particular forwarding configuration. With that configuration in place, all TCP connections to port 8080 on the host will be forwarded to port 80 on the guest. Protocol can be either of TCP or UDP (these are case insensitive). To remove a mapping again, use the same commands, but leaving out the values (in this case TCP, 80 and 8080).

It is not possible to configure incoming NAT connections while the VM is running. However you can change the settings for a VM which is currently saved (or powered off at a snapshot).

Share:
  • Digg
  • del.icio.us
  • Google Bookmarks
  • Sphinn
  • Facebook
  • Mixx
  • LinkedIn
  • Ma.gnolia
  • StumbleUpon
  • TwitThis
  • Yahoo! Buzz

Disable textmate from creating ._* files over the network 0

I have this problem every so often when I setup a new work env, this time is running a vm and accessing the share via sshfs.

1
defaults write com.macromates.textmate OakDocumentDisableFSMetaData 1
Share:
  • Digg
  • del.icio.us
  • Google Bookmarks
  • Sphinn
  • Facebook
  • Mixx
  • LinkedIn
  • Ma.gnolia
  • StumbleUpon
  • TwitThis
  • Yahoo! Buzz

Setting hostname on Leopard permanently 1

One of the annoying things about Leopard is that it keeps changing the hosting to whatever the DNS server dishes out and in my case its something like 12-32-145-23.config, not the most pretty/useful naming convention.

Also means that it looks really ugly on the terminal. So here are the commands to reset it permanently so that it doesn’t change again after a reboot.

1
2
3
$ sudo hostname foobox.local
$ sudo scutil --set HostName foobox.local
$ sudo scutil --set LocalHostName foobox
Share:
  • Digg
  • del.icio.us
  • Google Bookmarks
  • Sphinn
  • Facebook
  • Mixx
  • LinkedIn
  • Ma.gnolia
  • StumbleUpon
  • TwitThis
  • Yahoo! Buzz

Writing a Criteria statement for the IN Operator 0

This is going to be a quick post as I needed to write this done as its quite useful for anyone who either doesnt like or doesnt understand how the complex criteria objects work.

If you want to write code for a criteria object for the SQL statement which is something like this.

1
SELECT field1, field2 FROM table1 WHERE field1 IN (5,30,23)

The corresponding PHP for that would be as follows

1
2
3
4
$values = array(5,30,23);
$criteria_for_select = new Criteria();
$c = new Criteria();
$criteria_for_select = $c->getNewCriterion(table1::field1, $values, Criteria::IN);

That’s pretty much it, now this criteria object $criteria_for_select can now be used in your doSelectXXX calls.

Another really cool app that automates the task of writing criteria object is availabile here.
http://propel.jondh.me.uk/

The cool thing about this utility is you drop in your selection condition and it will write the code for the criteria object for you, now that’s really cool.

Share:
  • Digg
  • del.icio.us
  • Google Bookmarks
  • Sphinn
  • Facebook
  • Mixx
  • LinkedIn
  • Ma.gnolia
  • StumbleUpon
  • TwitThis
  • Yahoo! Buzz

IE6 and Webdevelopers 0

I havent been posting for a while and I guess I should be doing that a little more often, however in the meantime I found this post really funny. An IE6 voodo doll. This goes how out to show the extent to which developers hate IE6 and frankly I dont blame them for that.
IE6 Voodo Doll.
Link: http://www.chigarden.com/2007/10/tutorial-making-the-ie-voodoo-doll/

Share:
  • Digg
  • del.icio.us
  • Google Bookmarks
  • Sphinn
  • Facebook
  • Mixx
  • LinkedIn
  • Ma.gnolia
  • StumbleUpon
  • TwitThis
  • Yahoo! Buzz

Enabling HTTPS support in curl installed through MacPorts on OSX 0

While doing development just noticed that if you have installed php with curl support using macports it does’nt install ssl support in curl by default which is quite frustrating. Especially I just spent 30mins of my life trying to debugging what had gone wrong.

This is what you would get if you have a similar problem:

1
2
% curl -k https://www.yahoo.com
curl: (1) Protocol https not supported or disabled in libcurl

The problem is that you would usually have something that depends on curl so you cant install the version of curl with its variant straightaway, so you will first need to remove the dependent first, then remove curl and clean up the install and then finally install curl with its ssl variant followed by its dependents.

The steps are something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
busybox:web rp$ sudo port uninstall curl @7.19.3_0 curl @7.19.3_0+ssl
--->  Unable to uninstall curl 7.19.3_0, the following ports depend on it:
--->  	php5
Error: port uninstall failed: Please uninstall the ports that depend on curl first.
busybox:web rp$ sudo port uninstall curl @7.19.3_0 curl @7.19.3_0+ssl
busybox:web rp$ sudo port uninstall php5
--->  Deactivating php5 @5.2.9_0+apache2+macosx+mysql5+pear+sqlite
--->  Uninstalling php5 @5.2.9_0+apache2+macosx+mysql5+pear+sqlite
busybox:web rp$ sudo port uninstall curl @7.19.3_0 curl @7.19.3_0+ssl
--->  Deactivating curl @7.19.3_0
--->  Uninstalling curl @7.19.3_0
--->  Uninstalling curl @7.19.3_0+ssl
busybox:web rp$ sudo port install php5 @5.2.9_0+apache2+macosx+mysql5+pear+sqlite
Error: Requested variants do not match original selection.
Please perform 'port clean curl' or specify the force option.
Error: The following dependencies failed to build: curl
Error: Status 1 encountered during processing.
busybox:web rp$ sudo port clean curl
--->  Cleaning curl
busybox:web rp$ sudo port clean php5
--->  Cleaning php5
busybox:web rp$ sudo port clean php5
--->  Cleaning php5
busybox:web rp$ sudo port clean curl
--->  Cleaning curl
busybox:web rp$ sudo port clean php5
busybox:web rp$ sudo port install curl +ssl
--->  Fetching curl
--->  Verifying checksum(s) for curl
--->  Extracting curl
--->  Configuring curl
--->  Building curl
--->  Staging curl into destroot
--->  Installing curl @7.19.3_0+ssl
--->  Activating curl @7.19.3_0+ssl
--->  Cleaning curl
busybox:web rp$ sudo port install php5 @5.2.9_0+apache2+macosx+mysql5+pear+sqlite
--->  Fetching php5
--->  Verifying checksum(s) for php5
--->  Extracting php5
--->  Applying patches to php5
--->  Configuring php5
--->  Building php5
--->  Staging php5 into destroot
Warning: php5 requests to install files outside the common directory structure!
--->  Installing php5 @5.2.9_0+apache2+macosx+mysql5+pear+sqlite
 
If this is your first install, you might want
cd /opt/local/apache2/modules
/opt/local/apache2/bin/apxs -a -e -n "php5" libphp5.so
 
* copy  /opt/local/etc/php.ini-dist to  /opt/local/etc/php.ini
--->  Activating php5 @5.2.9_0+apache2+macosx+mysql5+pear+sqlite
--->  Cleaning php5
Share:
  • Digg
  • del.icio.us
  • Google Bookmarks
  • Sphinn
  • Facebook
  • Mixx
  • LinkedIn
  • Ma.gnolia
  • StumbleUpon
  • TwitThis
  • Yahoo! Buzz

PHP, Mail and OSX Leopard 3

I have been trying to get my old apps to send emails, but for some wierd reason I couldnt get it working out of the fox. If you have had similar problems, you can try out this.
Step 1: Update the hostconfig file.
Add the following line to /etc/hostconfig
MAILSERVER=-YES-

Step 2: Update variable myhostname in the file /etc/postfix/main.cf
Set the variable to your hostname, you might need to uncomment the default value.

Step 3: Find your php.ini file and update the sendmail_path and make it
/your/path/sendmail -t -i

Now open another terminal window and do a tail on the log file to see if you have any further errors.
tail -f /var/log/mail.log

You can start the server by running the following command:

1
sudo postfix start

The above changes worked for me, however you might need to investigate this a little more if you still have trouble.

Share:
  • Digg
  • del.icio.us
  • Google Bookmarks
  • Sphinn
  • Facebook
  • Mixx
  • LinkedIn
  • Ma.gnolia
  • StumbleUpon
  • TwitThis
  • Yahoo! Buzz

Using macport to setup php5 / apache2 on Leopard 2

As you can tell I got myself a new macbook and its pretty much ritualistic to install apache/php5 on it for me. I agree it comes with both of them pre-installed but really I just like to do it for the easy of configuration. I have written earlier how I compiled everything on Leopard in the past. This time I plan on trying something different.
I am using mac ports (possibly coz I am getting lazier). Here are a couple of quick start guides of port.

# Selfupdate
$sudo port selfupdate
 
# selfupdate, if you want to see what's going on.
$sudo port -d selfupdate
 
#search for a particular package
$sudo port search apache2
 
#search for variants like for instance, mysql and its server
$sudo port install mysql 
 
#search information about package
$sudo port info php5
 
#get info about dependencies for a package
$sudo port deps php5
 
#install package
$sudo port install apache2
 
#install package with variant like mysql and its server
$sudo port install mysql +server
 
#clean all the guff
$sudo port clean --all
 
#get the contents of a package
$sudo port contents apache2
 
#get installed packages
$sudo port installed
 
#upgrade package
$sudo port upgrade apache2
 
#update all outdated packages
$sudo port upgrade outdated

So back to setting up apache2 and php5

$sudo port install apache2

It does its standard business and then confirms the installation, similarly for installing php5, it has the following variants available that might interest you.

rp@busybox:~ rp$ sudo port variants php5
Password:
php5 has the variants:
	darwin_6: Platform variant, do not select manually
	darwin_7: Platform variant, do not select manually
	macosx: Platform variant, do not select manually
	no_web: Don't include any web server support
	apache: Add Apache 1 web server module
	apache2: Add Apache 2.2 web server module (default)
	fastcgi: Add FastCGI web server binary
	gmp: Add GNU MP functions
	dbase: Add dBase file format support
	imap: enable operation with IMAP protocol
	pspell: Add pspell spell-checking functions
	tidy: add Tidy support
	mssql: add support for MS-SQL server
	snmp: use Apple snmp
	macports_snmp: use MacPorts snmp
	mysql3: build MySQL 3 support
	mysql4: build MySQL 4 support
	mysql5: build MySQL 5 support
	oracle: Add Oracle oci8 database functions with the Oracle Instant Client
	postgresql82: provide postgresql82 support
	postgresql83: provide postgresql83 support
	sqlite: build sqlite support
	ipc: build IPC support
	pcntl: provide process control
	pear: add pear stuff
	readline: Add GNU readline functions
	sockets: Add socket communication functions
	t1lib: Add PostScript Type 1 font support with t1lib
	universal: Build for multiple architectures

I would go with just the basics.

$sudo port install php5 +apache2 +mysql5 +pear

With that done, now you can create your own copy of apaches httpd.conf

sudo cp /opt/local/apache2/conf/httpd.conf.sample /opt/local/apache2/conf/httpd.conf

Activate the php5 module.

cd /opt/local/apache2/modules
sudo /opt/local/apache2/bin/apxs -a -e -n "php5" libphp5.so
[activating module 'php5' in /opt/local/apache2/conf/httpd.conf]

and then you can play around with the config files as much as you like to set it up the way you prefer and then fire up the server using the following command:

apache2ctl start

and it should all work fine in your browsers. try out the config with the standard php testing function.

phpinfo();

Have fun, port is easy and simple, lets you get to the point where you can do something productive and creative.

Photo credit to my esteemed collegue: Neil Crosby.

Share:
  • Digg
  • del.icio.us
  • Google Bookmarks
  • Sphinn
  • Facebook
  • Mixx
  • LinkedIn
  • Ma.gnolia
  • StumbleUpon
  • TwitThis
  • Yahoo! Buzz

Conditional Validator in Symfony 1

I recently had to work on a signup form where the user was present different set of fields based on where the user came from. Lets take a sample scenario, I have a signup form where users get to from the “Plans” page.
If the user chooses to go with the Free Plan, he gets to a page which asks for his username and password only where as if the user chooses the “Paid” plan, he is presented with the full form including his username, password, credit card info and expiry date.

I shall cover writing the Credit Card Validator for Symony in one of the next few posts potentially for now, just documenting what I did for implementing the conditional validator.

So the standard RegisterForm.class logged like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
  public function configure() {
      // Remove all widgets we don't want to show
      unset(
        $this['is_active'],
        $this['is_super_admin'],
        $this['updated_at'],
        $this['groups_list'],
        $this['permissions_list'],
        $this['last_login'],
        $this['created_at'],
        $this['salt'],
        $this['algorithm']
      );
 
    // Setup proper password validation with confirmation
    $this->widgetSchema['password']                          = new sfWidgetFormInputPassword();
    $this->widgetSchema['password_confirmation']    = new sfWidgetFormInputPassword();
 
    $this->widgetSchema['cc']                = new sfWidgetFormInput();
    $this->widgetSchema['toc']               = new sfWidgetFormInputCheckbox();
 
    // assuming someone would have a card which 
    // expires as far as 10years from today
    $years = range(date('Y'), date('Y') + 10);
 
    $this->widgetSchema['cc_expiry_date']    = new sfWidgetFormI18nDate(
                                                    array(
                                                      'can_be_empty' => 'false',
                                                      'years'=> array_combine($years, $years),
                                                      'culture'=>'en', 
                                                      'month_format'=>'name', 
                                                      'format'=> '%month% %year%')
                                                    );
 
    $this->widgetSchema->setLabel('username', 'Email');
    $this->widgetSchema->setLabel('password_confirmation', 'Confirm Password');
    $this->widgetSchema->setLabel('cc', 'Credit Card Number');
    $this->widgetSchema->setLabel('cc_expiry_date', 'Credit Card Expiry Date');
    $this->widgetSchema->setLabel('toc', 'I agree to the Terms of Service, Privacy, & Refund policies');
 
    $this->validatorSchema['username'] 	= new sfValidatorEmail();
    $this->validatorSchema['cc'] 		    = new sfValidatorCreditCard();
    $this->validatorSchema['toc']       = new sfValidatorBoolean(
                                            array('required' => true), 
                                            array('required'=> 'You need to accept the terms and conditions to proceed')
                                          );
 
 
    $this->validatorSchema['password_confirmation'] = clone $this->validatorSchema['password'];
    $this->validatorSchema['password']->setOption('required', true);
    $this->validatorSchema['cc_expiry_date'] = new sfValidateCCExpiryDate(array('min' => time()), 
                                                              array('invalid' => 'Please enter a valid expiry date'));
 
    $this->widgetSchema->moveField('password_confirmation', 'after', 'password');
    $this->mergePostValidator(new sfValidatorSchemaCompare('password', 
                                    sfValidatorSchemaCompare::EQUAL, 'password_confirmation', 
                                    array(), 
                                    array('invalid' => 'The two passwords must be the same.')));

as you can see credit card and expiry date are a required field, however i don’t want to use that validation when it comes to doing a signup for a basic plan which will not have credit card and expiry date fields. So, this is implemented by overriding the bind method to change the validation rules based on the input provided. In the code snippet below the field validations change based on the hidden value price_id passed.

1
2
3
4
5
6
7
8
9
10
11
12
13
  public function bind(array $taintedValues = null, array $taintedFiles = null)
  {
    $price = PricePeer::retrieveByPK(@$taintedValues['price_id']);
    if (!$price) {
      return false;
    }
    if(0 == $price->getPrice()) {
      // turn off all the other validations
      $this->validatorSchema['cc_expiry_date']->setOption('required',false);
      $this->validatorSchema['cc']->setOption('required',false);
   }
    return parent::bind($taintedValues,$taintedFiles);
  }

I would be interested in knowing how you worked around this problem. Do leave a comment below.

Share:
  • Digg
  • del.icio.us
  • Google Bookmarks
  • Sphinn
  • Facebook
  • Mixx
  • LinkedIn
  • Ma.gnolia
  • StumbleUpon
  • TwitThis
  • Yahoo! Buzz

PING using php 0

I have been playing around with CURL and its awesomeness for a potential idea and had to use some data retrieved by sending a ICMP packet to the host. This was required to check to check stuff like host availability, packet loss etc. The standard stuff. Doing this would be fairly straightforward if you wanted to use the exec function. However getting the data back as a data structure can be a pain.
Pear has an interesting packge Net/Ping does does all that very neatly for you. Here is the code snippet for that.

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
     require_once "Net/Ping.php";
     $ping = Net_Ping::factory();
     if(PEAR::isError($ping)) {
      echo $ping->getMessage();
    } else {
      /* Number of packets to send */
      $ping->setArgs(array('count' => 4));
      $rawData = $ping->ping('rajatpandit.com');
      print_r($rawData);
    }
 
?>

and the data that you get back, is a pretty useful structured array.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
Net_Ping_Result Object
(
    [_icmp_sequence] => Array
        (
            [1] => 310
            [2] => 300
            [3] => 318
            [4] => 301
        )
 
    [_target_ip] => 67.205.0.93
    [_bytes_per_request] => 32
    [_bytes_total] => 128
    [_ttl] => 238
    [_raw_data] => Array
        (
            [0] => 
            [1] => Pinging rajatpandit.com [67.205.0.93] with 32 bytes of data:
            [2] => 
            [3] => Reply from 67.205.0.93: bytes=32 time=310ms TTL=238
            [4] => Reply from 67.205.0.93: bytes=32 time=300ms TTL=238
            [5] => Reply from 67.205.0.93: bytes=32 time=318ms TTL=238
            [6] => Reply from 67.205.0.93: bytes=32 time=301ms TTL=238
            [7] => 
            [8] => Ping statistics for 67.205.0.93:
            [9] =>     Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
            [10] => Approximate round trip times in milli-seconds:
            [11] =>     Minimum = 300ms, Maximum = 318ms, Average = 307ms
        )
 
    [_sysname] => windows
    [_round_trip] => Array
        (
            [min] => 300
            [max] => 318
            [avg] => 307
        )
 
    [_transmitted] => 4
    [_received] => 4
    [_loss] => 0
)

Sweet!

Share:
  • Digg
  • del.icio.us
  • Google Bookmarks
  • Sphinn
  • Facebook
  • Mixx
  • LinkedIn
  • Ma.gnolia
  • StumbleUpon
  • TwitThis
  • Yahoo! Buzz

Next Page »