Implementing MySql View in CakePHP For Typeahead Search

View works like a table, but it is not a table. It never exists; it is only a prepared SQL statement that is run when you reference the view name. A programmer can write VIEWs that limit the dataset both horizontally and vertically, ensuring that only the data that is required is queried for. Recently I Had to implement a search option for one of my developed site. The requirement was to show typeahed results from 5 tables. I used jQuery Ui – Autocomplete‘s Remote with caching to fullfil this requirement. My ajax call back result must fast enough as user writes on the textbox and result is showing. So for my first query return I used MySql View. Then start I firedup my Cake Bake. When I go to model creation i dont see my view’s name. I thought I have made some mistake – So I start looking into my view creation sql, my database configuration. But all seems ok. Then I clear cache by deleting app/tmp/cahe/models/. Yet no luck. Then I start poking around codes on cake folder. Then i found what I have been dreading.

On cake/libs/model/datasources/datasource.php line 613

function listSources() {
    $cache = parent::listSources();
    if ($cache != null) {
        return $cache;
    }
    $result = $this->_execute('SHOW TABLES FROM ' . $this->name($this->config['database']) . ';');

    if (!$result) {
        return array();
    } else {
        $tables = array();

        while ($line = mysql_fetch_row($result)) {
            $tables[] = $line[0];
        }
        parent::listSources($tables);
        return $tables;
    }
}

So CakePHP does not support MySql view!? No it does. But views are not available for Bake :( . Anyway you have create model, controller and view files old fashioned manually.

So my view sql is

CREATE VIEW searches AS
select videos.id AS id,videos.video_title AS Name,'videos' AS TYPE from videos
union
select users.id AS id,concat(users.first_name,' ',users.last_name) AS Name, 'users' AS TYPE from users
union
select tag_sub_categories.id AS id,tag_sub_categories.name AS name,'tag_sub_categories' AS TYPE from tag_sub_categories
union
select shows.id AS id,shows.title AS title,'shows' AS TYPE from shows union select announcements.id AS id,announcements.title AS title,'announcements' AS TYPE from announcements;

Mysql UNION is used to combine the result from multiple SELECT statements into a single result set. UNION is quite handy as you can see I can have all the values from different table in one result set. I also used a virtual field TYPE for tracking were the values from.

Bow create a file app/models/search.php and add the following code

class Search extends AppModel {
	var $name = 'Search';
	var $useTable = 'searches';
	var $primaryKey = 'id';
	var $useDbConfig = 'default';
}

You have to use $primaryKey otherwise when you to use find(‘list’) as described Here.

Now lets create out controller file app/controllers/searches_controller.php

class SearchesController extends AppController {

	var $name = 'Searches';
	var $paginate = array(
		'limit' => 10,
	);	

	function search_json() {
		$search_keyword=$this->params['url']['term'];
		$results = $this->Search->find('all',array(
					'conditions'=>array('Name LIKE '=> "{$search_keyword}%"),
					'limit'=>8
				));
		$return_array=array();
		foreach	($results as $result):
			$temp['id']=$result['Search']['id'];
			$temp['label']= (strlen($result['Search']['Name']) > 30)? substr($result['Search']['Name'], 0, 30). '...' : $result['Search']['Name'];
			$temp['value']=$result['Search']['Name'];
			$return_array[]=$temp;
		endforeach;
		echo json_encode($return_array);
		exit;
	}
}

For our search function

<script>
$(function(){
$.ui.autocomplete.prototype._renderItem = function( ul, item){
  var term = this.term.split(' ').join('|');
  var re = new RegExp("(" + term + ")", "gi") ;
  var t = item.label.replace(re,"<strong>$1</strong>");
  return $( "<li></li>" )
     .data( "item.autocomplete", item )
     .append( "<a >" + t + "</a>" )
     .appendTo( ul );
};
	var cache = {},
		lastXhr;
	$( "#search_ahead" ).autocomplete({
		minLength: 2,
		source: function( request, response ) {
			var term = request.term;
			if ( term in cache ) {
				response( cache[ term ] );
				return;
			}

			lastXhr = $.getJSON( "<?php echo $html->url(array("controller" => "searches", "action" => "search_json"));?>", request, function( data, status, xhr ) {
				cache[ term ] = data;
				if ( xhr === lastXhr ) {
					response( data );
				}
			});
		}
	});
});
</script>
    	<?php echo $this->Form->create(null, array('url'=>"/searches/show_results.html", 'type'=>"file", 'id'=>'change_status', 'inputDefaults' => array('label' => false,'div' => false)));?>
        <table width="230" cellpadding="0" cellspacing="0" border="0">
            <tr>
                <td width="170"><input name="search_ahead" id="search_ahead" type="text" class="input-box2" style="width:160px; height:22px;" value="" /></td>
                <td width="60"><?php echo $this->Form->end('/css/images/frequency-search.gif');?></td>
            </tr>
        </table>
        <?php ?>

This function also highlight the search text on the result text.

afterSave: A Great Callback Method for Soft Deleting Related Model Data( hasOne, hasMany, belongsTo)

Update: Here is model file to download Download Code

I never like to “Hard Delete” data. Some one will make mistake deleting something. Then they will tell you retrive it. So “Soft Delete” can save you time telling you clients/boss why the data can not be retrieved. BTW “Soft Delete” means you keep a field in table name is_delete/delete. Setting it’s value 1(or any value you may use but using boolean 1 seems logical) means the item is deleted. “Hard Delete” means you delete the row from the table. Poof gone. When i say delete on this post means “Soft Delete”.

Now lest discuss the power of afterSave. Suppose you Relational database for products. You have categories, sub-categories and sub-categories. Their relation looks like this

Category hasMany SubCategories
SubCategory hasMany SubSubCategories
SubSubCategory hasMany Products

Category -> SubCategories -> SubSubCategories -> Products

As CakePHP naming convention your Category, SubCategory, SubSubCategory Model should have these fields

CREATE TABLE `categories ` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(550) NOT NULL,
  `is_delete` tinyint(1) NOT NULL DEFAULT '0',
  `created` datetime DEFAULT NULL,
  `modified` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB ;

CREATE TABLE `sub_categories` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `category_id` int(11) NOT NULL,
  `name` varchar(550) NOT NULL,
  `is_delete` tinyint(1) NOT NULL DEFAULT '0',
  `created` datetime DEFAULT NULL,
  `modified` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;

CREATE TABLE `sub_sub_categories` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `sub_category_id` int(11) NOT NULL,
  `name` varchar(550) NOT NULL,
  `is_delete` tinyint(1) NOT NULL DEFAULT '0',
  `created` datetime DEFAULT NULL,
  `modified` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;

CREATE TABLE `products` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` int(11) NOT NULL,
  `sub_sub_category_id` int(11) NOT NULL,
  `is_delete` tinyint(1) NOT NULL DEFAULT '0',
  `created` datetime DEFAULT NULL,
  `modified` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;

created, modified will be automatically updated by CakePHP. Its nice little feature. So on to our relation between tables. categories table is connected with sub_categories category_id. Its model will look like this

class Catagory extends AppModel {
	var $name = 'Catagory';
	var $displayField = 'name';
	//The Associations below have been created with all possible keys, those that are not needed can be removed
	var $hasMany = array(
		'SubCatagory' => array(
			'className' => 'SubCatagory',
			'foreignKey' => 'catagory_id',
			'dependent' => false,
		)
	);
}

Same with sub_categories, sub_sub_categories and products table.

class SubCatagory extends AppModel {
	var $name = 'SubCatagory';
	var $displayField = 'name';
	//The Associations below have been created with all possible keys, those that are not needed can be removed
	var $belongsTo = array(
		'Catagory' => array(
			'className' => 'Catagory',
			'foreignKey' => 'catagory_id',
		)
	);

	var $hasMany = array(
		'SubSubCatagory' => array(
			'className' => 'SubSubCatagory',
			'foreignKey' => 'sub_catagory_id',
			'dependent' => false,
		)
	);
}

class SubSubCatagory extends AppModel {
	var $name = 'SubSubCatagory';
	var $displayField = 'name';
	//The Associations below have been created with all possible keys, those that are not needed can be removed
	var $belongsTo = array(
		'SubCatagory' => array(
			'className' => 'SubCatagory',
			'foreignKey' => 'sub_catagory_id',
		)
	);

	var $hasMany = array(
		'Product' => array(
			'className' => 'Product',
			'foreignKey' => 'sub_sub_catagory_id',
			'dependent' => false,
		)
	);
}

class Product extends AppModel {
	var $name = 'Product';
	var $displayField = 'name';
	//The Associations below have been created with all possible keys, those that are not needed can be removed

	var $belongsTo = array(
		'SubSubCatagory' => array(
			'className' => 'SubSubCatagory',
			'foreignKey' => 'sub_sub_catagory_id',
			'conditions' => '',
			'fields' => '',
			'order' => ''
		)
	);
}

Now we will delete on category – so the row on the categories table will updated with 1. But all the rows on the sub_categories, sub_sub_categories, products for that category will not be deleted. Now comes CakePHP to rescue. It is actually quite beautiful. Lets add afterSave() function to Category model -category.php

	function afterSave()
	{
		if($this->data['Catagory']['is_delete']==1)
		{
			$this->SubCatagory->recursive=0;
			$sub_catagories = $this->SubCatagory->find('all', array(
								'conditions' => array('SubCatagory.catagory_id'=>$this->data['Catagory']['id'])
							));
			foreach($sub_catagories as $sub_catagory):
				unset($this->data['SubCatagory']);
				$this->data=$sub_catagory;
				$this->data['SubCatagory']['is_delete']=1;
			endforeach;
		}
	}

We first check for delete. The we found out all the sub_catagories. Then we delete it. But what about the sub_sub_categories and products. Lets first delete the sub_sub_categories.

	function afterSave()
	{
		if($this->data['SubCatagory']['is_delete']==1 )
		{
			$this->SubSubCatagory->recursive=0;
			$sub_sub_catagories = $this->SubSubCatagory->find('all', array(
								'conditions' => array('SubCatagory.catagory_id'=>$this->data['Catagory']['id'],'SubSubCatagory.sub_catagory_id'=>$this->data['SubCatagory']['id'])
							));
			foreach($sub_sub_catagories as $sub_sub_catagory):
				unset($this->data['SubSubCatagory']);
				$this->data=$sub_sub_catagory;
				$this->data['SubSubCatagory']['is_delete']=1;
				$this->SubSubCatagory->save($this->data);
			endforeach;
		}
	}

Wow all the sub_sub_catagories are deleted. Now delete all the products

	function afterSave($created)
	{
		if($this->data['SubSubCatagory']['is_delete']==1 or $this->data['SubSubCatagory']['is_hide']==1)
		{
			$this->Product->recursive=0;
			$products = $this->Product->find('all', array(
								'conditions' => array('Product.catagory_id'=>$this->data['SubCatagory']['catagory_id'], 'Product.sub_catagory_id'=>$this->data['SubCatagory']['id'], 'Product.sub_sub_catagory_id'=>$this->data['SubSubCatagory']['id'])
							));
			foreach($products as $product):
				unset($this->data['Product']);
				$this->data=$product;
				$this->data['Product']['is_delete']=1;
				$this->Product->save($this->data);
			endforeach;
		}
	}

Now all the records have been deleted. Now you can ask why i did not add the codes on the Category model because then deleting any sub_categories entry will not delete sub_sub_categories and products.

ISPConfig 3 setup on Ubuntu

There are number of Hosting Control Panel Softwares. The cPanel is best but it cost 10$ per month. Plesk also need licensing cost. Webmin is free but it interface is not user friendly. THe ISPConfig – Hosting Control Panel Software has user friendly interface with a lot of functions and it is totally free. They charge simple fee to download documentation pdf but They have very good documentation on line Here. Before you set up ISPConfig 3 you need to prepare you server. In this tutorial i will show how to set it up.

Update Repositories

We need to update the aptitude repository indexes.

 apt-get update

Installing Prerequisites

Next we need to install the prerequisite packages for ISPConfig. The following packages will be needed:

  • PostFix (postfix, postfix-mysql, postfix-doc)
  • MySQL (mysql-client, mysql-server)
  • Courier (courier-authdaemon, courier-authlib-mysql, courier-pop, courier-pop-ssl, courier-imap, courier-imap-ssl)
  • System Libraries (libsasl2-2, libsasl2-modules, libsasl2-modules-sql, sasl2-bin, libpam-mysql, binutils)
  • SSL (openssl)
  • Mail Programs (maildrop, getmail4)
  • Rootkit Hunter (rkhunter)
 apt-get install postfix postfix-mysql postfix-doc mysql-client mysql-server courier-authdaemon courier-authlib-mysql courier-pop courier-pop-ssl courier-imap courier-imap-ssl libsasl2-2 libsasl2-modules libsasl2-modules-sql sasl2-bin libpam-mysql openssl maildrop getmail4 rkhunter binutils

During the setup you will be presented the following screens:

- Enter a password you would like to use for the root user in MySQL.

- You will be required to enter the password again.

- Select No as we do not want to create the directories.

- Select Internet Site as the configuration type.

- Enter your server’s hostname here. Keep in mind that it MUST resolve in DNS.

- Select OK on this screen.

Customizing MySQL

Once the installation has completed we will need to modify the MySQL configuration to allow connections from all interfaces instead of localhost only. To open the MySQL configuration file type the following:

nano /etc/mysql/my.cnf

Find the line that starts with bind-address and comment it out by putting a # in front of it. Save the file and quit.

Now we need to restart MySQL:

service mysql restart

Next we will need to make sure that MySQL is answering properly:

netstat -tap | grep mysql

You should see something that looks like the following:

ttcp 0 0 *:mysql *:* LISTEN 10296/mysqld

Configuring Courier

During the installation, the SSL certificates for IMAP-SSL and POP3-SSL were created with the hostname localhost. To change this to the correct hostname (mail.contosso.com in this tutorial), delete the certificates.

cd /etc/courier
rm -f imapd.pem
rm -f pop3d.pem

Next modify the following two files replacing CN=localhost with CN=mail.contosso.com. You may modify the other values as necessary. Replace mail.contosso.com with your real domain.

nano /etc/courier/imapd.cnf

...

CN=mail.contosso.com
nano/etc/courier/pop3d.cnf

...

CN=mail.contosso.com

Next we need to recreate the certificates.

mkimapdcert
mkpop3dcert

Restart the Courier-IMAP-SSL and Courier-POP3-SSL services.

/etc/init.d/courier-imap-ssl restart
/etc/init.d/courier-pop-ssl restart

Install Amavisd-new, SpamAssassin, ClamAV

To install amavisd-new, SpamAssassin, and ClamAV type the following:

apt-get install amavisd-new spamassassin clamav clamav-daemon zoo unzip bzip2 arj nomarch lzop cabextract apt-listchanges libnet-ldap-perl libauthen-sasl-perl clamav-docs daemon libio-string-perl libio-socket-ssl-perl libnet-ident-perl zip libnet-dns-perl

Install Apache, PHP5, phpMyAdmin, FastCGI, suExec, Pear, and mcrypt

We need to install the following components:

  • Apache Web Server
  • PHP5
  • phpMyAdmin MySQL Admin Tool
  • FastCGI extensions for Apache
  • suExec
  • Pear
  • mcrypt extensions for PHP
apt-get install apache2 apache2.2-common apache2-doc apache2-mpm-prefork apache2-utils libexpat1 ssl-cert libapache2-mod-php5 php5 php5-common php5-gd php5-mysql php5-imap phpmyadmin php5-cli php5-cgi libapache2-mod-fcgid apache2-suexec php-pear php-auth php5-mcrypt mcrypt php5-imagick imagemagick libapache2-mod-suphp

You will be prompted with the following screen:

- Select apache2 by pressing the space-bar and select OK.

-Enter MySql root server and select OK.

-Enter password for phpMyAdmin and select OK.

-Enter same password for phpMyAdmin and select OK.

Activate Apache Modules

Next we will need to activate the following Apache modules: suexec, rewrite, ssl, actions, and include.

a2enmod suexec rewrite ssl actions include

Installing PureFTPd with Quotas

We need to allow FTP access with quota support. To accomplish this we will install PureFTPd. Use the following command:

apt-get install pure-ftpd-common pure-ftpd-mysql quota quotatool

Next we need to make a few changes to the configuration of PureFTPd. Edit /etc/default/pure-ftpd-common:

nano /etc/default/pure-ftpd-common

Make sure that STANDALONE_OR_INETD is set to standalone and VIRTUALCHROOT is set to true.

Save the file if you made any changes.

Restart PureFTPd:

nano /etc/init.d/pure-ftpd-mysql restart

Next we will enable quotas on our file system. First we need to modify our filesystem structure to support quotas. Let’s modify /etc/fstab to add support.

nano /etc/fstab

On the line that starts with either /dev/sda1 or /dev/xvda1 we need to add ,usrquota,grpquota right after noatime in the arguments. For example, it should look like the following when you’re done if the device is /dev/sda1:

/dev/sda1       /           ext3    defaults,errors=remount-ro,noatime,usrquota,grpquota    0 1

Next we need to enable quotas:

touch /quota.user /quota.group
chmod 600 /quota.*
mount -o remount /

We’ll run a few utilities to make sure quotas are setup correctly:

quotacheck -avugm
quotaon -avug

Installing MyDNS

Before we can install MyDNS we need to install a few prequisites:

# sudo aptitude install g++ libc6 gcc gawk make texinfo libmysqlclient15-dev

MyDNS is not available in the Ubuntu 8.10 repository so we will have to install it ourselves. It is assumed you have the URL to the current version from the MyDNS website.

cd /tmp
wget http://downloads.sourceforge.net/project/mydns/mydns/0.11.0/mydns-0.11.0.tar.gz
tar xvfz mydns-1.2.8.27.tar.gz
cd mydns-1.2.8
./configure
make
make install

Now we need to create a start/stop script for MyDNS:

To create the file:

nano /etc/init.d/mydns

Copy the following text into this file:

#! /bin/sh
#
# mydns         Start the MyDNS server
#
# Author:       Philipp Kern <phil@philkern.de>.
#               Based upon skeleton 1.9.4 by Miquel van Smoorenburg
#               <miquels@cistron.nl> and Ian Murdock <imurdock@gnu.ai.mit.edu>.
#

set -e

PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/usr/local/sbin/mydns
NAME=mydns
DESC="DNS server"

SCRIPTNAME=/etc/init.d/$NAME

# Gracefully exit if the package has been removed.
test -x $DAEMON || exit 0

case "$1" in
  start)
        echo -n "Starting $DESC: $NAME"

        start-stop-daemon --start --quiet \
                --exec $DAEMON -- -b
        echo "."
        ;;
  stop)
        echo -n "Stopping $DESC: $NAME"
        start-stop-daemon --stop --oknodo --quiet \
                --exec $DAEMON
        echo "."
        ;;
  reload|force-reload)
        echo -n "Reloading $DESC configuration..."
        start-stop-daemon --stop --signal HUP --quiet \
                --exec $DAEMON
        echo "done."

        ;;
  restart)
        echo -n "Restarting $DESC: $NAME"
        start-stop-daemon --stop --quiet --oknodo \
                --exec $DAEMON
        sleep 1
        start-stop-daemon --start --quiet \
                --exec $DAEMON -- -b
        echo "."
        ;;
  *)
        echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
        exit 1
        ;;
esac

exit 0

Next we need to make the file executable and add startup links for it.

chmod +x /etc/init.d/mydns
update-rc.d mydns defaults

Installing Vlogger and Webalizer

Use the following commands to install:

apt-get  install vlogger webalizer

Installing fail2ban

This is optional but recommended. ISPConfig monitor will attempt to show the fail2ban log.

apt-get install fail2ban

Installing SquirrelMail

To install the SquirrelMail webmail client use the following:

apt-get install squirrelmail

You should see a screen that looks like the following:

-select OK.

-select OK.
Now we need to create a symbolic link…

ln -s /usr/share/squirrelmail/ /var/www/webmail

Use the following to configure SquirrelMail:

squirrelmail-configure

You should see a screen that looks like the following:

- We need to tell SquirrelMail that we are using Courier-IMAP/POP3. At the prompt enter D and press Enter.

- Enter courier here to tell it to use Courier.

- Press any key at the screen to continue.

- Press S here to save the configuration. Press Q here to quit.

Now we need to test our Squirrel Mail configuration to make sure it loads. You can verify by sending your web browser to http://your_domain/webmail. Replace your_domain with your fully qualified domain name.

Installing ISPConfig 3

ISPConfig 3 is not available in the Ubuntu 8.10 repositories so we will have to install it manually. You must download the current version from the ISPConfig download page.

cd /tmp
wget http://prdownloads.sourceforge.net/ispconfig/ISPConfig-3.0.4.2.tar.gz
tar zxvf ISPConfig-3.0.4.2.tar.gz
cd ispconfig3_install/install/
php -q install.php


- Press enter to accept en.
- Press enter to accept the standard installation.
- Enter your fully qualified host name. The default value pulled from your server will be the default. Press enter if you would like to accept.
- Press enter because MySQL is installed on the same server.
- Press enter to use the default username of root for the MySQL connection.
- Press enter to use the default password for MySQL. It has not been configured yet.
- Press enter to accept the default MySQL database name.
- Press enter to accept the default MySQL character set.

- Type US for the country code.
- Enter your state name.
- Enter your city name.
- Enter your organization’s name.
- Enter your department, if applicable
- Enter a representative name for your company.
- Enter a primary contact e-mail for the certificate.

- Select the default port of 8080.

- Enter to use https for web interface
Use the same step for ssl set up previously.

- Upon successful completion you should have a screen that looks similar to the screen above.

Testing

You may now log into ISPConfig for the first time. Point your web browser to http://your_domain:8080 replacing your_domain with your domain name. You should see a window that looks similar to the one below.

Mail Server Installation on Ubuntu

As a beginner to linux it took about almost 10 days of goggling for me for proper installation of mail server and fixing necessary problems. Before you start this you should look into these posts Some Important Linux commands for Newbies and Setup LAMP With Ubuntu In 10 Minutes. We will setup Postfix (Mail Transfer Agent MTA), Dovecot (IMAP/POP3 Server), SASL Authentication with TLS (Authenticate before sending mail outside network in Outlook) and Squirrel Mail (Popular Web based Email).

Note: If you install Postfix/Dovecot mail server you will ONLY be able to send mail within your network. You can only send mail externally if you install SASL authentication with TLS. As otherwise you get nasty “Relay Access Denied” error.

Install Postfix MTA (Mail Transfer Agent)

apt-get install postfix postfix-tls  libsasl2-2 sasl2-bin libsasl2-modules popa3d

During installation, postfix will ask for few questions like name of server and answer those questions by entering your domain name and select Internet site for postfix.

Postfix configuration file is located at:/etc/postfix/main.cf. You can edit this file using popular text editor nano /etc/postfix/main.cf
Start or Restart Postfix Server:

/etc/init.d/postfix restart
/etc/init.d/postfix stop
/etc/init.d/postfix start

Install Dovecot

apt-get install dovecot-imapd dovecot-pop3d dovecot-common

Dovecot configuration file is located at: /etc/dovecot/dovecot.conf

Before we proceed we need to make some changes with dovecot configuration file. Double check the following entries in the file if the values are entered properly.

nano /etc/dovecot/dovecot.conf 

# specify protocols = imap imaps pop3 pop3s
protocols = pop3 imap
# uncomment this and change to no.
disable_plaintext_auth = no
pop3_uidl_format = %08Xu%08Xv

Now, create a user to test our pop3 mail with outlook:

adduser <user_name>

Restart Dovecot:

/etc/init.d/dovecot restart

Configure SASL Authentication with TLS
SASL Configuration + TLS (Simple authentication security layer with transport layer security) used mainly to authenticate users before sending email to external server, thus restricting relay access. If your relay server is kept open, then spammers could use your mail server to send spam. It is very essential to protect your mail server from misuse.

Let us set up SMTP authentication for our users with postfix and dovecot.

Edit the postfix configuration file /etc/postfix/main.cf and enter the few lines to enable authentication of our users

smtpd_sasl_auth_enable = yes
smtpd_sasl_local_domain = yourdomain.com
smtpd_recipient_restrictions = permit_mynetworks,permit_sasl_authenticated,reject_unauth_destination
smtpd_sasl_security_options = noanonymous

On the Dovecot side you also need to specify the dovecot authentication daemon socket. In this case we specify an absolute pathname. Refer to this postfix manual here

Edit /etc/dovecot/dovecot.conf

Look for the line that starts with auth default, before that insert the lines below.

auth default {
mechanisms = plain login
passdb pam {
}
userdb passwd {
}
socket listen {
client {
path = /var/spool/postfix/private/auth
mode = 0660
user = postfix
group = postfix
}
}
}

Now, rename previous auth default to auth default2. If you dont rename this then dovecot server will give you error like multiple instances of auth default.

Now restart all the components of mail server.

/etc/init.d/saslauthd restart
/etc/init.d/postfix restart
/etc/init.d/dovecot restart

NOTE:
1. If you dont enable My server requires authentication in outlook you cannot send emails to external recipients and you get relay access denied error.
2. Do not use root login to login to your mail server.
3. Dont forget to create a new user before you authenticate using outlook.

Installing Squirrel Web Mail
Squirrel mail is one of the most popular web based email with very friendly interface. Squirrel mail works without mysql database very easy to install and configure under apache2.

apt-get install squirrelmail

Squirrelmail configuration file is located in: /etc/squirrelmail/ folder. By default all settings are preloaded.

# Run squirrelmail configuration utility as ROOT
/usr/sbin/squirrelmail-configure

Now we want to setup to run under apache. Edit apache configuration file /etc/apache2/apache2.conf and insert the following line:

Include /etc/squirrelmail/apache.conf

Thats it. Your webmail is ready !!! Point your browser to: http://yourdomain/squirrelmail

Some Important Linux commands for Newbies

My first experience with Linux started when i setuped a server for one my client. It was monumental task for me at that time. I was very happy mouse driven windows user. When I came to the world of putty I was lost. So I had to search for certain commands. I recently written the Setup LAMP With Ubuntu In 10 Minutes. One of my colleague trie to setup LAMP following that post. He was also happy mouse driven windows user So he was having problem with commands. So in this post I am showing all the commands I need and used to use Linux server. I will post all the problems i faced using LAMP in next post. Be sure to subscribe my blog.

To create new directory

mkdir target_director

To copy an entire folder (directory tree) in Linux

cp -ap /var/lib/mysql /mnt/mysql -ap for same permission as source

For checking the size of current folder

du -ch | grep total

To find the size of the hdd

 just enter df

To find out the size of the folder in the folder

du
du -a to show all the file's size

See all files and their size

du -s * -h

To output the number of files in the current directory

ls | wc -l

See all the jobs

ps -aux

To find out RAM size on Linux machine

free

Rename folder/filename

mv test hope
mv *.rtf *.txt

To find which process is consuming how much RAM?

top

To see the free ram memory

free -m

To update yum using corn

0 21 *** usr/bin/yum -y update

Create tar.gz file

tar czvf myfolder.tar.gz abcfolder/

Untar a tar file
tar czvf myfolder.tar.gz abcfolder/
[/sourcecode]

Delete bash History
Try to delete the content of ~/.bash_history

To add new user
* Adding a new user (useradd)
* Modifying an existing user (usermod)

Options:
* -d home directory
* -s starting program (shell)
* -p password
* -g (primary group assigned to the users)
* -G (Other groups the user belongs to)
* -m (Create the user’s home directory

useradd -gusers -Gmgmt -s/bin/shell -pass -d/home/jambura -m jambura

User’s home directory should be 700. If you are operating a ~username type server, the public_html directory should be 777. You may also need to open up the home directory to 755.

 useradd -s/bin/bash -pass -d/imp/sysbsd -m sysbsd

For allowing sudo

 sudo adduser jambura admin

To delete user

userdel user

To display your crontab file

crontab -l

root can view any users crontab file by adding “-u username”

crontab -u bappy -l  # List bappy's crontab file.

* * * * * Command to be executed
- – – – -
| | | | |
| | | | +—– Day of week (0-6)
| | | +——- Month (1 – 12)
| | +——— Day of month (1 – 31)
| +———– Hour (0 – 23)
+————- Min (0 – 59)

Field Allowed values
—– ————–
minute 0-59
hour 0-23
day of month 1-31
month 1-12 (or names, see below)
day of week 0-7 (0 or 7 is Sun, or use names)

To edit crontab file

crontab -e

#change the editor used to edit file set the EDITOR environmental variable like this:

export EDITOR=/usr/bin/emacs

jQuery, JSON and jTemplates For Ajax driven Web app

jQuery is one best and easy JavaScript Library. There are thousand of plug-in to do endless thing to do on the web-page. The best thing is you don’t have to worry about will this code you written run on ie/opera etc. The Best way to make a web app or website is using Ajax. Obviously when you get a HTML using Ajax and replace or add in a HTML element – it consumes some time which does not look good. There is another solution – we can use JSON and template engine like jTemplates. jQuery has it own template engine but its beta version. jTemplates is quite easy to understand and develop. Its has conditional structure and also has foreach loop. So you can do a lot of things using this. I have develop many Facebook apps and website using jTemplates. Here is link of chat application show http://apps.facebook.com/chat-rooms/. In this tutorial i will show you multiple examples which you can download here. There are couple of functions are not described here – the main focus of this tutorial is show you the basic things.

Before we start, First download jQuery v1.6.2 and jTemplates from http://jtemplates.tpython.com/. I have used delegate so use jQuery v1.6.2 instead of latest version. In the latest version delegate is relace by on. All the JSON object is retrieved by $T. The template written like this

<script type="text/html" id="template">
</script>

The Conditional Statement
In this first example, We will see how the if-else / if-elseif-else work in jTemplates. First let see the php file which we will call in ajax.

$return_array['chk']=1;
echo json_encode($return_array);

The basic is always same. put all the data in an php array then json_encode the array. We echo the resulting json string.
Then we develop the template

<script type="text/html" id="template">
	{#if  $T.chk==0}
		The result is 0
	{#elseif $T.chk==1}
		The result is 1
	{#else}
		The result is not 0 or 1
	{#/if}
 </script>

The code is very simple. The main focus of This code is the $T.chk. As we set the php array like this $return_array['chk'] so chk json object will be available by $T.chk.

$(function() {
	$('body').delegate('#click_me', 'click', function (event){
		$.getJSON('/jquery-json-and-jtemplate-for-ajax-driven-web-app/demo-2-ajax.php',{}, function(data)
		{
			$container = $('#result');
			$container.setTemplate($("#template").html());
			$container.processTemplate(data);
			$('#result').html($container.html());
		});
	});
});

Here is the code where the magic happens :) . $(‘body’).delegate(‘#click_me’, ‘click’, function (event){ means when any one click the element which id is click_me then the code snippet will run. $.getJSON will load the json sting from the server and convert it to json object

.
$container = $('#result');
$container.setTemplate($("#template").html());
$container.processTemplate(data);
$('#result').html($container.html());

This the code where all the json datas are put on html template, then using html() function to put the html on result div.
You can see this on action http://fbapps.jambura.com/jquery-json-and-jtemplate-for-ajax-driven-web-app/demo-1.php

The Loop foreach
Let first see the php code

for($i=0;$i<20;$i++)
{
	$imgs[$i]['img']='http://blog.jambura.com/wp-content/uploads/2011/10/Ubuntu-logo.jpg';
	$imgs[$i]['name']='Ubuntu_'.$i;
}
$return_array['images']=$imgs;
echo json_encode($return_array);

The code is just add name and img in array. Then that array put in images key in $return_array array.

<table  width="261" cellpadding="0" cellspacing="0" border="0">
{#foreach $T.images as image}
    {#if $T.image$iteration == 0 || ($T.image$iteration%2)==0}
        <tr>
    {#/if}
    <td width="130" align="center">{$T.image.name}</td>
    <td width="130" align="center">
        <a href="{$T.image.img}"><img width="200" height="178" border="0" alt="image" src="{$T.image.img}"></a>
    </td>
    {#if ($T.image$iteration%2)==1}
        </tr>
    {#/if}
{#/for}
</table>

Here the foreach code is same as php’s foreach. $iteration – id of iteration (next number begin from 0). The delegate code is same

$(function() {
	$('body').delegate('#click_me', 'click', function (event){
		$.getJSON('/jquery-json-and-jtemplate-for-ajax-driven-web-app/demo-2-ajax.php',{}, function(data)
		{
			$container = $('#result');
			$container.setTemplate($("#template").html());
			$container.processTemplate(data);
			$('#result').html($container.html());
		});
	});
});

You can see this on action http://localhost:8888/jquery-json-and-jtemplate-for-ajax-driven-web-app/demo-2.php

You can get more details about the jTemplates here. You can download the code from jquery-json-and-jtemplate-for-ajax-driven-web-app.

Ubuntu Linux Setup and Configure a Domain Name Server Using BIND

Recently i had to setup a LAMP server for one of client. As usual I chose Ubuntu. I setup the The LAMP. You can view the Setup LAMP With Ubuntu In 10 Minutes. Then my client wanted to setup domain on that server. So start searching for easy to setup domain name on Ubuntu server.So i found out about BIND. Its pretty sweet DNS software. As I am using Ubuntu then setting it up will be one line code :) .








Step # 1: Install BIND
First you need to install BIND server.
Code:

$ sudo apt-get install bind9

Step # 2: Define foo.com domain
You need to add foo.com domain to bind configuration file /etc/bind/named.conf.local

Open this file and append following text (zone and reverse zone for foo.com):
Code:

$ sudo nano /etc/bind/named.conf.local

Add foo.com zone:
Code:

zone "foo.com" {
        type master;
        file "/etc/bind/zones/foo.com.zone";
        };

zone "1.55.202.in-addr.arpa" {
     type master;
     file "/etc/bind/zones/rev.1.55.202.in-addr.arpa";
};

Save the file.

Step # 3: Create a /etc/bind/zones/ directory
Code:

$ sudo mkdir /etc/bind/zones

Step # 4: Create a zone file for foo.com domain
Now create a zone file /etc/bind/zones/foo.com.zone
Code:

$ sudo nano /etc/bind/zones/foo.com.zone

Append following text:
Code:

foo.com. IN      SOA     ns1.foo.com. admin.foo.com. (
          2006071801
          28800
          3600
          604800
          38400 )
foo.com. IN      NS      ns1.foo.com.
foo.com. IN      MX     10 mta.foo.com.

www           IN      A       202.55.1.2
mta              IN      A       202.55.1.2
ns1               IN       A        202.55.1.2

Create the reverse zone file:
Code:

$ sudo nano /etc/bind/zones/rev.1.55.202.in-addr.arpa

Append following text
Code:

@ IN SOA ns1.foo.com. admin.foo.com. (
                        2006071801; serial
                        28800; refresh, seconds
                        604800; retry, seconds
                        604800; expire, seconds
                        86400 ); minimum, seconds

                     IN  NS ns1.foot.com.

2                  IN      PTR    foo.com

Save the file and restart the BIND server:
Code:

$ sudo /etc/init.d/bind9 restart

Test it:
Code:

$ nslookup foo.com

Server: 202.55.1.2
Address: 202.55.1.2#53

Name: foo.com
Address: 202.55.1.2

Add Your Own Validation in model On CakePHP

Update: Here is model file to download Download Code

CakePHP has many validation rules that can make model data validation much easier. There are 26 core validation rules. You can see here. These 26 rules almost covers all the validation. You can also add multiple validation to one field. But some time you need your own validation or you need to check a value dependent on other value then you need your own validation.

Lets build our scenario. We have a user table and we have user type table. There are two types of user one is admin and other is user i.e normal user. Now in user table we only save username only for admin. if we set validation notempty for username field then CakePHP will validate username even for normal user. This does not suit us. So we need custom validation. lets build our user model.

class User extends AppModel {
	var $name = 'User';
	var $validate = array(
		'name' => array(
			'notempty' => array(
				'rule' => array('notempty'),
				'message' => 'Please enter first name',
				//'allowEmpty' => false,
				//'required' => false,
				//'last' => false, // Stop validation after this rule
				//'on' => 'create', // Limit validation to 'create' or 'update' operations
			),
		),
	);
	//The Associations below have been created with all possible keys, those that are not needed can be removed

	var $belongsTo = array(
		'UserType' => array(
			'className' => 'UserType',
			'foreignKey' => 'user_type_id',
			'conditions' => '',
			'fields' => '',
			'order' => ''
		)
	);
}

Here a added a not empty validation for name field and also we made HABTM relation with user_type table. lets add username field in model.

class User extends AppModel {
	var $name = 'User';
	var $validate = array(
		'name' => array(
			'notempty' => array(
				'rule' => array('notempty'),
				'message' => 'Please enter first name',
				//'allowEmpty' => false,
				//'required' => false,
				//'last' => false, // Stop validation after this rule
				//'on' => 'create', // Limit validation to 'create' or 'update' operations
			),
		),
		'username' => array(
			'custom' => array(
				'rule' => array('validateDependentFields'),
				'message' => 'Please enter height',
				//'allowEmpty' => false,
				//'required' => false,
				//'last' => false, // Stop validation after this rule
				//'on' => 'create', // Limit validation to 'create' or 'update' operations
			),
		),
	);
}

Now lets build our custom function validateDependentFields. This function will have a parameter which will have the field name. One import thing to remember is that we will have all the post data in $this->data in this function. Lets think user_type_id=1 is for admin and user_type_id=2 is user.

function validateDependentFields($field){
	$passed=true;
	switch(true){
		case array_key_exists('username',$field):
			if(  $this->data['User']['user_type_id']==1 and (!isset($this->data['User']['username']) or empty($this->data['User']['username'])) ){
				$passed=false;
			}else{
				$passed=true;
			}
		break;
	}
	return $passed;
}

This function will now check for the user type and then decide about the username field. You can check for other validation here. We can use this function for multiple fields.

function validateDependentFields($field){
	$passed=true;
	switch(true){
		case array_key_exists('username',$field):
			if(  $this->data['User']['user_type_id']==1 and (!isset($this->data['User']['username']) or empty($this->data['User']['username'])) ){
				$passed=false;
			}else{
				$passed=true;
			}
		break;
		case array_key_exists('class_of',$field):
			if(  $this->data['User']['user_type_id']==1 and (!isset($this->data['User']['class_of']) or empty($this->data['User']['class_of'])) ){
				$passed=false;
			}else{
				$passed=true;
			}
		break;
	}
	return $passed;
}

Easy, simple and highly customizable.

Setup LAMP With Ubuntu In 10 Minutes

I love Debian/Ubuntu based Linux because of this command apt-get. As a starter knowing this one command, It is so easy to install packages and you dont need to worry about package dependency and configuration. I first come use Ubuntu when i start using Amazon’s ec2. I was amazed how easily i can build up a server. I am going to show how easy LAMP setup really is. I assume you have a Ubuntu setup-ed server and PuTTy.Note: Linux + Apache + MySQL + PHP/Perl together commonly known as LAMP Server.

Before proceeding to install, update the necessary packages with Debian with this command.

 apt-get update

1. Installing Apache + PHP
To install PHP5, just run the following on Linux shell. Note that if you dont specify packages with ’4′, PHP5 will be automatically installed.

apt-get install apache2 php5 libapache2-mod-php5

Apache configuration file is located at: /etc/apache2/apache2.conf and your web folder is /var/www

To check whether php is installed and running properly, just create a test.php in your /var/www folder with phpinfo() function exactly as shown below.

nano /var/www/test.php

And write this

<?php phpinfo(); ?>

Point your browser to http://ip.address/test.php or http://domain/test.php and this should show all your php configuration and default settings.
To enable GD Enter this

apt-get install php5-gd

To enabling mod rewrite with .htaccess

a2enmod rewrite

Then open the apache config

nano /etc/apache2/sites-enabled/000-default

Change AllowOverride none to AllowOverride All

<Directory /var/www/>
Options Indexes FollowSymLinks MultiViews
AllowOverride All
Order allow,deny
allow from all
# Uncomment this directive is you want to see apache2's
# default start page (in /apache2-default) when you go to /
#RedirectMatch ^/$ /apache2-default/
</Directory>

2. Installing MySQL Database Server
The following commands will install mysql 5 server and mysql 5 client.

apt-get install mysql-server mysql-client php5-mysql

To install PhpMyAdmin use the following code

apt-get install phpmyadmin

Then restart Apache

/etc/init.d/apache2 restart

Now When you develop web app or sites you need more packages then the default installation for that use the following command

apt-get install curl libcurl3 libcurl4-openssl-dev php5-curl php5-mcrypt php5-xmlrpc

To install pear use the following command

apt-get install php-pear

How much time did it take – less than 10 Minutes right.

How To Setup SSL On Ubuntu

This the second part of the SSL setup tutorial. Before reading this make sure you have followed the step shown How To Create A Certificate Signing Request (CSR) For SSL. In This tutorial i am assuming you have only one domain and no sub-domains on the server. By now you have domainname.com.key,domainname.com.csr and domainname.com.crt file. Another crt file is provided by SSL certificate issuer companies which is called Intermediate Certificate. If you dont have it ask your provider to give it to you.

Now put all the certificate files in ~/domainname.com.ssl/ folder. First we will check is the ssl port which is 443 is open or not.

 nano /etc/apache2/ports.conf

It should be like following command. If not then add the following code in the ports.conf file

Listen 80
<IfModule mod_ssl.c>
    Listen 443
</IfModule>

Now we are going to copy the default setting for the ssl .

cp /etc/apache2/sites-available/default /etc/apache2/sites-available/ssl

Now we going add some lines to the ssl file so that apache will know where to find the certificates for SSL.
First lets open the file

nano /etc/apache2/sites-available/ssl

Now the file looks like this

NameVirtualHost *
<VirtualHost *>
        ServerAdmin webmaster@localhost

        DocumentRoot /var/www/
        <Directory />

Now We going to make some changes so that the SSL file looks like the following

NameVirtualHost *:443
<VirtualHost *:443>
        ServerAdmin webmaster@localhost
        SSLEngine On
        SSLCertificateFile /root/domainname.com.ssl/domainname.com.crt
        SSLCertificateKeyFile /root/domainname.com.ssl/domainname.com.key
        SSLCertificateChainFile /root/domainname.com.ssl/PositiveSSLCA.crt
        DocumentRoot /var/www/

PositiveSSLCA.crt is the intermediate SSL certificate. Now we are going to enable the ssl and reload the apache server.

a2enmod ssl
/etc/init.d/apache2 force-reload
/etc/init.d/apache2 restart

See this so simple. But to implementing SSL with ip-based is quite a work. I will post about this next week. Be sure to subscribe the blog.