SPF record

September 30th, 2013

The sender policy framework is not new. It’s been out there for quite long. However for the past week it has been a serious issue at the office.
The company I work for right now has contact with lots of important transport companies and email is a very important communication tool.
For some reason about a month ago some of our clients started complaining that our emails were being marked as spam. The easiest solution was to ask them to mark us as not spam, which some of them did. However there were a few of our customer that didn’t wanted to do that. First thing I did was call with my email service provider to ask them to check the issue for me.
They came back to me with the solution to request our customers to add us to their safe lists and start marking our emails as Not Spam… I told them that some of our customers didn’t wanted to do that and my provider said they couldn’t do anything else because everything seemed to be working fine.
My company’s CEO was pissed at me because of this issue. He suggested us to create a new domain from which he could send emails which were not being marked as spam. After discussing the pros and cons he decided we did as he said…
Anyway, time went by and I forgot about the issue till a couple of days ago when he came back to me complaining that the issue was repeating with the new domain and that the initial problem hadn’t been solved.
Of course this was partly my fault and I was pissed because the email service provider was stating it wasn’t our fault and everything was ok. So I started searching on Google to see if other people ever experienced something similar and I did found a lot of similar situations but one fought my attention, it said something about SPF… what is that?
To make the story short SPF is a DNS record. It was created as a mean to validate the origin of an email sender so it would make it a little more difficult for a spammer to reach anyone.
It works in a very simple way. You send an email from your_account@yourDomain.com to recipient@hisDomain.com. Your message travels through the internet and arrives to the email server at hisDomain.com. When the message arrives the server queries the DNS records for yourDomain.com. If it founds the SPF record it will read the confs to validate wether the message you just sent comes from an authorised server, the SPF policy will even tell other servers what to do with unauthorized messages. They can be rejected, marked as spam or accepted cleanly.
So I started reading about SPF thoroughly here.
It’s really interesting and a good first step to protect your email domain from being used as spam.
At the end I added the SPF record authorising both exchange IP addresses, email domains and an additional IP6 IP to send valid emails on behalf of my company.
A great tool to start making the SPF record can be found in Microsoft’s domain here here (Thanks to Debra Peterson for her follow up on this broken link).
I tested the configurations against these great tools:
SPF Query tools
They worked great. Next I did a test sending email to a gmail account. Once I received the email I opened the message and checked out the headers which read like this:

Received-SPF: pass (google.com: domain of noreply@[MYDOMAIN.COM] designates [IP6_ADDRESS] as permitted sender) client-ip=[IP6_ADDRESS];
Authentication-Results: mx.google.com;
spf=pass (google.com: domain of noreply@[MYDOMAIN.COM] designates [IP6_ADDRESS] as permitted sender) smtp.mail=noreply@[MYDOMAIN.COM]

So there it is, my confs are working great and my emails are no longer arriving as spam.
I’m just a little disappointed that my email provider wasn’t aware of this until I brought it up after a followup call.

When saying NO can be healthy

July 29th, 2013

After years of coding, learning languages and improving my programming skills I’ve finally made it to a manager position.
I must say I’ve been looking after this for a long time and to be honest it’s been quite a learning experience. Dealing with programmers, clients, resources management and a whole bunch of administrative tasks are now how I spend my days.
The deal is I get payed by an american company to be the IT manager for a mexican company.
After so many years I’ve come to my little theory of why american software products are almost always better than latin ones. We latinos don’t know when to say no. We always say yes to keep the job, making customers believe we will get the job done. Actually we do get the job done but there’s a catch.
For most latins a NO implies losing a customer (and money) and since the customer is always right they must do as the customer wants, even if the customer is asking for something clearly out of scope from the very beginning. The good thing is that they get the job done and the customer gets immediate satisfaction, the bad thing is that while trying to get the job done they loose quality, code gets hardcoded, coding coherence gets lost and little by little the product starts to become unstable and difficult to enhance. The customer sometimes will take long time to realize this and then will become dependant on a low quality software and will eventually drop it and go for a commercial license of some other company. That’s when the latin company will wonder how come another company that was way behind a few years ago is now providing the same functionality and adding more features so quickly while they are struggling a lot to add those same features.
I’ve seen this a lot. Why do this happen?
Simple, it’s all about knowing when to say NO and what a NO implies.
As a mexican if you say NO, that’s it, there’s no action taken, no responsibility is taken and any intention cease to exist. Thus, in order for something to happen they need to say Yes, take a rushed decision and develop a quick poor quality solution that will earn them a client, however as the client request upgrades, changes and new features, the code will become unstable, insecure and as time goes by it will keep getting more and more difficult to maintain causing failures and eventually loosing the customer.
In other cultures (like the american culture) if you say NO it triggers a complete different response. NO triggers a big event where the company identifies an area of opportunity, plans accordingly and develop a stable and upgradeable solution. They might have lost a couple of clients in the road but they will eventually get them back.
The other big catch involves the human resources. Bad planing results in the need for workers to stay overtime, frustrating efforts to satisfy ridiculous promises and a number of employees losing faith and loyalty in the company.
This is the case where a Yes actually can harm you more than a No.
We latins need to learn to do things right. Time spent on planing will result in greater benefits than the time spent in a quick mediocre solution.

Strlen issue for numbers

March 9th, 2013

There is an issue you must keep in mind when dealing with PHP numeric types.

I was trying to validate a credit card number today, in order to apply Luhn’s algorithm I needed to know the number of digits in the credit card number string.

Let me give you an example:

Credit card number: 4415121641207182

Let’s say I’m using a function.

function luhnsFunc ($ccn){
    return strlen($ccn);
}

And call it like this:

$ccn = '4415121641207182';
echo luhnsFunc($ccn);

The returned value is: 16

But see what happens when the credit card number is not declared as a string.

$ccn = 4415121641207182; //No quotes
echo luhnsFunc($ccn);

The returned value is: 19

So what’s happening here?!

I did a var dump to each case and found out something pretty interesting.

For the first case I got:

string(16) "4415410012107183"

Which is ok, but let’s see the second case.

float(4.4154100121072E+15)

So it’s storing a float on scientific notation. Why?

Take a look at this:

http://www.php.net/manual/en/language.types.integer.php

Just above the warning you’ll read the following:

The size of an integer is platform-dependent, although a maximum value of about two billion is the usual value (that’s 32 bits signed). 64-bit platforms usually have a maximum value of about 9E18. PHP does not support unsigned integers. Integer size can be determined using the constant PHP_INT_SIZE, and maximum value using the constant PHP_INT_MAX since PHP 4.4.0 and PHP 5.0.5.

The purpose of creating the function is that no matter what I pass it as an argument it will always bring the correct result. Applying the Luhn’s algorithm to a 16 char length string is very different than applying it to a 19 chars length string.

So how do I solve this?

function luhnsFunc ($ccn){
    $type = gettype($ccn);
    switch($type){
        case 'string':
            break;
        default:
            $ccn = number_format($ccn,0,'',''); //The second parameter is a zero
            break;
    }
    return strlen($ccn);
}

An finally the length is correct

Credit card Number validation

March 9th, 2013

Credit card validations are very important when it comes to E-commerce.

Most of the time your clearing house will validate the number and return an error message if something went wrong. If your clearing house does the validation it means that the order has already been closed and if your user typed the wrong credit card number he might have to go through the whole sale process again (choose items, fill out credit the card form, perhaps fill out the wrong credit card number again).

If the user is not aware of the error, perhaps after two attempts he’ll quit trying and the sale will be lost.

Let’s think in USABILITY.

If your user realizes he’s typing the wrong credit card number from the moment he’s filling the form, he won’t have to deal with the clearing house coming back with a rejected transaction.

How do you validate a credit card number?

You’ll have to check 2 thing:

  1. Credit card number type 
  2. Luhn’s algorithm

Both of them are important to get a correct validation for you credit card number. Both will help you give great hints to your user in case he’s typing an incorrect credit card number.

Credit Card Type

Most of credit card numbers are built with 4 blocks of information:

  • MII (Major Industry Identifier)
  • IIN (Issuer Identification Number)
  • Person’s account number
  • Check digit

So basically you can start your validations from the very first typed digit and by the time your user has typed the first six digits you can clearly identify the credit card’s issuer. For more information go to:

http://en.wikipedia.org/wiki/Credit_card_numbers

You’ll see that different industries have a specific IIN assigned to them.

Luhn’s Algorithm

The Luhn’s Algorithm is used to verify that the numbers sequence is valid by doing a checksum of the credit card’s number.

The details of the algorithm can be found here:

http://en.wikipedia.org/wiki/Luhn_algorithm

The best credit card validation would check both type and check digit to be correct. This is great because perhaps the user types a CCN for a Maestro card while his card is VISA; by means of switching an image the customer may realize something is wrong.

This validations can be done both in client and server side scripts before sending data to the clearing house.

Plugins in Zend Framework

September 1st, 2011

There is no way you haven’t noticed that the Zend Framework documentation is pure garbage, almost every example they have is useless, there is no context, lacks of more in depth case of use and the quickstart makes you wonder if you really need to use something so complex to create something so simple.

I visit the crappy documentation for a quick reference, then I search for a more detailed explanation on google and 90% of the time there will be a link to a page that clearly explains the functionality I’m searching for and even goes deeper into some subjects.

Ok, enough of my complaints, let’s get to business.

One project I worked recently used the following approach for reusable constructor methods.

It creates a base controller with most common methods and all other controllers inherit from that base controller.

This looks like a good idea. Pretty simple and functional but then I came across this page.

As you can read it encourages others to use the helpers and plugins instead of a base controller. Even though at first it sounds like the base controller approach is justifiable you’ll later realize that helpers or plugins are a better option.

In my case there is a part of the app reserved for logged users so I needed to check the permissions to see if the controller should show something or ask a user to log in.

I read Matthew’s post and decided to go along with this approach. The whole explanation is right there, nevertheless it’s missing a little bit of info regarding the plugins/helpers folder location and how to make them available for your application.

I wanted my app folder schema to be consistent so I decided I’ll have my helpers and plugins folders under the application one.

Next thing to do is make them available; I did this in the bootstrap by adding the following method:

<?php
    protected function _initAutoloader(){
        $moduleLoader = new Zend_Application_Module_Autoloader(array('namespace' => '', 'basePath' => APPLICATION_PATH));
        $moduleLoader->addResourceType('Plugin', 'plugins', 'Plugin');
        $moduleLoader->addResourceType('Helper', 'helpers', 'Helper');
        return $moduleLoader;
    }
?>

Ok, so now both paths are available so every plugin or helper class will be found under those directories.

The following step is to create a plugin and a helper.

My plugin is quite simple: if a session namespace exists it would mean my user is registered and then I would like to set a couple of view variables like the user’s email.

Please note the event I used. This took me to figure out why.

The file is called: registered.php under plugins folder as formerly stated.

<?php
class Plugin_Registered extends Zend_Controller_Plugin_Abstract{
    public static $doNotValidate = false;
    public function postDispatch(Zend_Controller_Request_Abstract $request){
        if(!self::$doNotValidate){
            if(!Zend_Session::namespaceIsset('credentials')){
                //Oops! user isn't logged in, get them somewhere else!
                $redirector = Zend_Controller_Action_HelperBroker::getStaticHelper('redirector');
                $redirector->gotoUrl('/');
            }
            else{
                //Nice! Proceed but set some variables first
                $namespace = new Zend_Session_Namespace('Credentials');
                //Get the view
                $viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
                if (null === $viewRenderer->view) {
                    $viewRenderer->initView();
                }
                $view = $viewRenderer->view;
                $view->email = $namespace->email;
                //Use the following line when view resource is given in application.ini (resources.view[]...)
                //Zend_Controller_Front::getInstance()->getParam('bootstrap')->getResource('view')->email = $namespace->email;
            }
        }
    }
}
?>

You’ll need to register the plugin and this is really easy.
Again get to the bootstrap. I typed the following code as pointed out by Matthew (it’s within the bootstrap).

<?php
    protected function _initPlugins(){
        $front = Zend_Controller_Front::getInstance();
        //Check if user is logged in
        $front->registerPlugin(new Plugin_Registered());
    }
?>

Now your plugin is registered.
Some static and public available pages won’t need to do this validation, so the controller body would look something like this:

<?php
class IndexController extends Zend_Controller_Action{
    public function preDispatch(){
        Plugin_Registered::$doNotValidate = true;
    }

    public function indexAction(){
        $this->view->headLink()->appendStylesheet($this->view->baseUrl('css/index.css'));
        $this->view->headScript()->appendFile($this->view->baseUrl('js/jquery.js'));
    }

    public function logoutAction(){
        Zend_Session::destroy();
        $this->_redirect('/');
    }
}
?>

The trick here is the preDispatch method. What happens is that it sets the flag before the plugin executes and so the plugin works as expected. If you need a controller to validate a user then you don’t have to set that flag.

Matthew’s post was enlightening. I’m starting to feel more comfortable with ZF now.

Helpers work pretty much the same. I’ll post it later.

Logic questions 1

August 29th, 2011

A couple of days ago I received a call from a south american country.

They are searching for web developers to work with them in some projects involving Google. They read my profile on Linkedin and decided to contact me. It was a very interesting interview due to the fact that it was focused both in evaluating my technical and logic skills.

One of the questions that were made was quite simple but I liked it:

Given a random integer ¿how would you code a function that returns the mirrored integer?

It might sound simple, but I’ve been working with PHP for years and it’s not a strong typed language so my first answer was to deal with it as a string:

<?php
function mirror($number){
    return strrev($number);
}
?>

But then the interviewer told me that I should’t treat data as a string but as a number… ok… so I started thinking and came up with this:

<?php
function mirror0($number){
    $ret = 0;
    $prev = 0;
    $go = true;
    do{
        $quotient = (int) floor($number/10);
        $rest = $number - ($quotient * 10);
        $ret = ($prev * 10) + $rest;
        $prev = $ret;
        if($quotient===0){
            $go = false;
        }
        $number = $quotient;
    }while($go);
    return $ret;
}
?>

He liked my answer but told me that perhaps I could do it simpler by using a logarithm… this stuck into my mind so after the call ended I wrote a piece of code:

<?php
function mirror1($number){
    $ret = 0;
    $quotient = floor($number/10);
    $rest = $number - ($quotient * 10);
    if($quotient == 0){
        $ret = $rest;
    }
    else{
        $ret = ($rest * (pow(10,floor(log($number,10))))) + mirror1($quotient);
    }
    return $ret;
}
?>

I wrote a small benchmark code and the difference is unnoticeable.

Anyway, I’m just posting this 3 even though there might be a lot of different ways.

Zend Framework – View – $this->url()

August 11th, 2011

Been using ZF a lot. It hasn’t amazed me because even though it’s really powerful it’s still very complicated to achieve simple task and the official documentation is very very messy.

Anyway, I have this layout for a project with a main menu.

Each of the menu options link to a different controller, instead of hard coding the menu links I used ZF url helper so for every link I was using something like this:

$this->url(array('controller'=>'console','action'=>'index'));

Which when ran gave me the following link

/[project_folder]/public/console

This looked just fine. Later on I created a product’s catalogue and from there a link to see a product’s detail. The link was:

$this->url(array('controller'=>'catalogue','action'=>'details','pid'=>[product_id]));

Everything worked just fine so I clicked the products details link. Everything looked fine. Then I clicked one of the main menu links to get to another section of the web page and then a bug popped.

For some reason all the links where appended with the GET parameters so when I clicked on the info link it took me to

/[project_folder]/public/info/pid/[product_id]

And obviously I was getting an error because there was no ‘pid’ action for the ‘info’ controller.

I searched and read a couple of google results, give the documentation a try (it sucks) and after a while I ended up in a simple blog entry with the solution.

I only needed to change my code to this:

$this->url(array('controller'=>'console','action'=>'index'),null,true);

Now GET params are not appended to the URL’s and everything works fine 😀

Imagick – Postscript delegate failed

August 10th, 2011

This new project I’m working on requires me to extract an image from a PDF file and show a preview on the web page. I knew this was possible but I didn’t knew how.

After googling it for a while I ended with some interesting results that pointed me to ImageMagick. It’s a nice tool to transform/extract images from one format to another. It is supported by many languages as C, Perl, Python and PHP. Since I am coding with PHP I went for it and activated the imagick extension for PHP on my Zend Server CE.

I’m using a Mac with Lion OS X.

I found a really good blog that has a whole section for Imagick with pretty neat results here.

After reading for a while I was ready to do my first test, so I used a code similar to this one:

<?php
/* Read page 1 */
$im = new imagick( 'test.pdf[0]' );
/* Convert to png */
$im->setImageFormat( "png" );
/* Send out */
header( "Content-Type: image/png" );
echo $im;
?>

And then ran it on my browser but to my surprise it was throwing an exception:

Postscript delegate failed `test.pdf': No such file or directory

The path was fine, I tested it with a jpg and a png image and it worked so I was really confused and started to dig into the issue. After a while I ended up reading ImageMagick documentation and somewhere I read that it uses third party commands to accomplish format transformations from vector images (like the ones stored within a pdf). Lastly I went to the server error logs and found this:

sh: gs: command not found

I guessed from previous experience that this message meant the following:

sh -> execute a shell command
gs -> ghostscript command
[text] -> error message

So it meant that the server was not being able to execute the ghostscript command, ¿really?
I went to a console and typed in:

which gs

It returned the command path so I knew I had ghostscript installed so the problem should be that the server user didn’t had the path set properly.
To check if my assumption was correct I typed the following in the console:

echo $PATH

And I got the PATH env variable.
On my PHP script I added the following line:

echo getenv('PATH');

And my script displays the PATH env variable being used by my web server. The result was different and the path where the ghostscript executable was not being included.
Now I was able to solve the issue and it was really simple. It required for me to provide the correct path for my server.
Now my script look like this:

<?php
putenv('PATH=' . getenv() . ':[absolute_path_where_the_ghostscript_executable_is]');
/* Read page 1 */
$im = new imagick( 'test.pdf[0]' );
/* Convert to png */
$im->setImageFormat( "png" );
/* Send out */
header( "Content-Type: image/png" );
echo $im;
?>

And finally everything works fine.

PHP classes autoload (namespaces) in Zend Framework

June 9th, 2011

On previous posts I created a function to dynamically load namespace classes.
Now that I’m using Zend Framework I was wondering how can I use the same namespaces in combination with Zend’s. Following the logic I only needed to register my autoload function so that everything starts working as I wish.
Having read through the documentation I was starting to think it would be very difficult but turned out to be quite simple so I’m posting my learning experience here hoping it would be useful for others.

Background

I have a bunch of namespaces being used for several applications. I have them stored in a specific folder. I use Mac OS.
Let’s suppose I have the namespaces folder located under /var so the namespaces folder path is: /var/namespaces/
Also I have a folder with several non namespaced classes on the following path: /var/classes/

I can’t change paths because several other non ZF applications use that, and I won’t be copying and pasting them into the ZF library path cause if code needs to change I have them all in just one single place.

My ZF application is stored in the following path: /Users/spiro79/web/sites/ZFapp/

ZF must work and be able to load the classes from the different namespaces.

Making it work

I will be using the same logic used in previous posts regarding the autload. Believe it or not is pretty simple.
All changes are done within the bootstrap so open it.
First of all we need to create the autoload function. I wrote this code as a Bootstrap public static function.

    /**
     * Autoload function for PHP namespaces
     * @param string $class
     */
    public static function getMoreNamespaces($class){
        $class = strtolower($class);
        if(strpos($class,'\\')!==false){
            $class = preg_replace('/\\\/',DIRECTORY_SEPARATOR,$class);
        }
        $possibilities = explode(PATH_SEPARATOR, get_include_path());
        $found = false;
        foreach($possibilities as $path){
            if(file_exists($path . DIRECTORY_SEPARATOR . $class . ".php")){
                $found = true;
                require_once $path . DIRECTORY_SEPARATOR . $class . ".php";
                break;
            }
        }
    }

What this code does is that it searches for the namespace folder within all paths set on the include path.
The autoloader will call this function to try to load the namespaces classes.
Now let’s set the namespaces and classes folders in the application.ini file, just add these lines and make them match your own path.

nmspcspth = "/var/namespaces"
clssspth = "/var/classes"

The third and last step is to add my autoload function to the default autoloader. I did this by typing the following code also within the Bootstrap.

    /**
     * Init the autoloader for PHP namespaces
     */
    protected function _initMoreNamespace(){
        $namespacesPath = $this->getOption('nmspcspth');
        $classesPath = $this->getOption('clssspth');
        define('PHP_CLASSES_PATH',$classesPath);
        define('PHP_NAMESPACES_PATH',$namespacesPath);
        set_include_path(get_include_path() . PATH_SEPARATOR . PHP_CLASSES_PATH . PATH_SEPARATOR . PHP_NAMESPACES_PATH);
        $autoloader = Zend_Loader_Autoloader::getInstance();
        $autoloader->unshiftAutoloader(array('Bootstrap','getMoreNamespaces'));
    }

Done! Now you can use natural namespace syntax like:

Use Utils\Config as MyConfig;
$configObj = new MyConfig;
$otherNs = new Utils\Tool();

My problem has been solved and now I can proceed with development 😀

Multiple databases support on ZF

June 8th, 2011

Zend Framework is nice but learning it is very confusing and time demanding. Official doc isn’t that clear, lacks of good examples and sometimes is outdated. Whenever I want something to be done I read the official documentation and then google it so I can get a good picture of what everyone did.

One thing that I recently needed was to enable multiple schema support for a specific project. One schema stores client info, the other stores products. One very interesting thing is that the products schema depends on the account so clients for region 1 should use a schema called reg1, while clients from region 2 a schema called reg2.

So the products schema kind of switches dynamically according to users setup.

The first thing to do is setup the config file. This is the easy part, I added some lines that looked like this:

resources.multidb.maindb.adapter = oracle
resources.multidb.maindb.persistent = true
resources.multidb.maindb.host =
resources.multidb.maindb.username = usr
resources.multidb.maindb.password = usr123
resources.multidb.maindb.dbname = "(DESCRIPTION= (ADDRESS= (PROTOCOL=TCP)(HOST=oracle.host.com)(PORT=1521)) (ADDRESS= (PROTOCOL=TCP)(HOST=oracle2.host.com)(PORT=1521)) (LOAD_BALANCE=yes) (CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=srvcnm)))"

resources.multidb.seconddb.adapter = oracle
resources.multidb.seconddb.persistent = true
resources.multidb.seconddb.host =
resources.multidb.seconddb.username = usr2
resources.multidb.seconddb.password = usr2123
resources.multidb.seconddb.dbname = "(DESCRIPTION= (ADDRESS= (PROTOCOL=TCP)(HOST=soracle.host.com)(PORT=1521)) (ADDRESS= (PROTOCOL=TCP)(HOST=soracle2.host.com)(PORT=1521)) (LOAD_BALANCE=yes) (CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=srvcnm2)))"

resources.multidb.thirddb.adapter = oracle
resources.multidb.thirddb.persistent = true
resources.multidb.thirddb.host =
resources.multidb.thirddb.username = usr3
resources.multidb.thirddb.password = usr3123
resources.multidb.thirddb.dbname = "(DESCRIPTION= (ADDRESS= (PROTOCOL=TCP)(HOST=toracle.host.com)(PORT=1521)) (ADDRESS= (PROTOCOL=TCP)(HOST=toracle2.host.com)(PORT=1521)) (LOAD_BALANCE=yes) (CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=srvcnm3)))"

Notice I’m storing everything in a multidb array with three different elements: maindb, seconddb and thirddb. Let’s consider the maindb to be the users schema, for products I’ll be switching between seconddb and thirddb.

First of all the main connection needs to be set so we can login, update, delete and o more stuff with a user account. Alo this connection will be set as the default adapter. I did this in the bootstrap. Here is the code:

/**
* Init the main database connection.
*/
protected function _initDatabase(){
    $applicationConfig = new Zend_Config_Ini(APPLICATION_PATH . '/configs/application.ini', APPLICATION_ENV);
    $config = $applicationConfig->toArray();
    $dbIni = $config['resources']['multidb']['maindb'];
    $db = Zend_Db::factory($dbIni['adapter'], $dbIni);
    Model_DbTable_Db::setDefaultAdapter($db);
}

So now we have the main connection up and working as a default adapter. This works the same as a basic database configuration. Now to the interesting part… set up the other database connection according to the user region. In my case the user’s account has a field/property that stores the correct products schema name so one of the things I’ll be doing is reading that property to know which schema I need to connect to for the products details. I won’t explain the account part because it’s quite simple.

We use a baseController from which we inherit all other controllers so we can easily concentrate most of the common methods in one single place. Within that baseController I added the following method:

/**
* Depending on the account we set up the adapter for the products tables
* @param Account A valid account object
*/
private function setProductsSchema(Account $account){
    if(!Zend_Registry::isRegistered('erpdb')){
        $applicationConfig = new Zend_Config_Ini(APPLICATION_PATH . '/configs/application.ini', APPLICATION_ENV);
        $config = $applicationConfig->toArray();
        $dbIni = $config['resources']['multidb'][strtolower($account->getSchemaName())]; // In this case $account->getSchemaName() may return 'seconddb' or 'thirddb' 😀
        $erpdb = Zend_Db::factory($dbIni['adapter'], $dbIni);
        Zend_Registry::set('erpdb',$erpdb);
    }
}

Now the application is able to dynamically choose the proper schema for products according to the account. It’s important to add it to the registry with a name, in this case is erpdb. This is necessary in order to let the DbTable objects know which schema they’ll use. Be sure to call this method before making a query to the secondary schema.

Now let’s set up the DbTable objects so they know which connection they’ll be using. Right now all DbTable objects are using the default adapter set in the bootstrap, for those objects that refer to products we need to make them aware that they’ll be using the secondary connection. doing this is pretty straightforward.

Go to your DbTable object and add the following method:

/**
* Set the default adapter for this object
*/
public function init(){
    $this->_setAdapter('erpdb');
}

That’s it! Notice that we set the adapter name the same as the db registry added before.

And that’s basically all we need to do to make the connection dynamic 😀

Hope it helps.