Redirect outbound traffic over specific IP

Recently one of our clients decided to white label their product. With that we had to setup the server to use multiple IPs as the application requires you communicate over SSL and we needed a SSL per domain. We did not want to buy a UCC(a multiple domain) SSL certificate as right now it wasn’t required for the small number of white labels. After we added the additional IP we had the issue that the application which connects to off site MySQL servers, was sometimes going over the new IPs and then getting denied accessed.

We knew the solution was with iptables so after some digging and testing, we came up with the following command. This command we use will redirect all traffic that is not over port 443 (in this example) to go out over the ‘YYY.YYY.YYY.YYY’ address that is about to go out over the XXX.XXX.XXX.XXX ip.

iptables -t nat -A POSTROUTING -p tcp ! --dport 443 -s XXX.XXX.XXX.XXX -j SNAT --to-source YYY.YYY.YYY.YYY

We didn’t see any examples of this clearly defined (after a quick google that is), on the web, so hopefully this will save you time from having to read through the iptables documentation.

TrackYourImpact.com Launched!

Recently we’ve launched a new site for a client called Purpose Beverages: http://trackyourimpact.com . We’ve received great feedback from users so far. The site uses a wide range of technologies. It is built on http://symfony-project.org">symfony and uses the http://www.apostrophenow.com/">Apostrophe CMS to manage the main parts of the site. It integrates with a SMS provider to allow you text into it to find out more about your purchase.

Tēvolution is a new brand of tea on the market that does good with each purchase. Every time someone buys it they done a specific amount(for example 25 cents) to a specific charity. In order to find out how large of a donation and what charity your bottle goes to you can actually text the code found on the bottle to the website, or you can login in on your phone browser or regular browser and enter the code. You will find out how much and to whom you just donated money to!

Right now Tēvolution is just coming to the market so keep your eyes peeled for it! It’s a great product that does good!

Getting an extra 'Invalid' or other error on your symfony form?

On a project I’m working on I came across the following problem: we had a email field that we needed to be unique in our system, but we also made sure that it matched a confirm email field. A snippet of our form looks like this:

<?php

public function configure()
  {
     $this->setWidgets( array(
        'email'         => new sfWidgetFormInputText()
        'confirm_email' => new sfWidgetFormInputText()
      ));

      $this->setValidators(array(

      'email'=>         new sfValidatorAnd(
                          array(
                              new sfValidatorEmail( array('required' => true) ),
                              new sfValidatorDoctrineUnique(
                                  array('throw_global_error' => true, 'model' => 'sfGuardUser', 'column' => 'username'),
                                  array('invalid' => 'Sorry! A user with that email address already exists.')
                              )
                          )),
        'confirm_email' => new sfValidatorEmail( array('required' => true) )

      ));

      $this->validatorSchema->setPostValidator(
        new sfValidatorSchemaCompare('password', '==', 'confirm_password')
      );
  }

When we submitted an email that was already in the system we got back two errors:

  • Sorry! A user with that email address already exists.
  • Invalid.

For a while I thought is there some extra validator somewhere that I left on? Where is this invalid coming from? It ended up being due to the way the validators work. If a validator throws an error it doesn’t return that validator’s value. So by the time it gets to the sfValidatorSchemaCompare post validator the value of email is null and confirm_email has the value you input, thus the seemingly extra ‘Invalid’ message.

This can be fixed easily with a sfValidatorCallback instead of the sfValidatorSchemaCompare. Here is the fix:

<?php

 public function validateConfirmEmail( $validator, $values ){

    if($values['email']&&$values['email']!=$values['confirm_email'])
    {
      throw new sfValidatorError($validator, 'Please confirm your email, currently they do not match!.');
    }

    return $values;
  }

This way if the email is blank it doesn’t both making sure that the email matches the confirm_email. You don’t need to worry about a person just passing two blank emails as the earlier validator(the sfValidatorEmail requires it to be there and valid).

If you are getting an extra validation error, check your postValidators and how the values get to them.

Changing a Doctrine connection with the same name in single instance

On one of our projects that we use multiple connections that are defined at run time we recently were generating reports that required us to change a specific connection multiple times in a single run. We noticed that even though we would define a new connection, it would not throw any errors but just continue to use the originally defined connection. Here is how we were doing the connections:

<?php
$databaseManager = sfContext::getInstance()->getDatabaseManager();
$manager=Doctrine_Manager::getInstance();
$newConn = new sfDoctrineDatabase(array('dsn'=>'XXX','name'=> 'ExampleName'));
$newConn->connect();
$databaseManager->setDatabase('ExampleName',$newConn);

If you called the code above once, it would connect properly to the given DSN. However if you then called it a second time with a new DSN, it would not error and would simply just remain connected to the first DSN. After hunting around a bit it was the problem that Doctrine wasn’t assigning the new connection as the old connection was still open. To get around this we updated the code to the following:

<?php

$databaseManager = sfContext::getInstance()->getDatabaseManager();
$manager=Doctrine_Manager::getInstance();

// If the Doctrine Manager has the connection already close it so the new connection can be established
if($manager->contains('ExampleName'))
        $manager->closeConnection($manager->getConnection('ExampleName'));
$newConn = new sfDoctrineDatabase(array('dsn'=>'XXX','name'=> 'ExampleName'));
$newConn->connect();
$databaseManager->setDatabase('ExampleName',$newConn);

You need to first check to see if the Doctrine Manager has the connection, as if you try to get a connection that doesn’t exist, it will throw an exception.

Hope this saves you some time!

ahDoctrineEasyEmbeddedRelationsPlugin and Composite Primary Keys

We’ve been working on a project in which a bunch of the tables had composite primary keys. Often we wanted to embed these tables in other forms. ahDoctrineEasyEmbeddedRelationsPlugin is a great plugin for managing embedded forms with Doctrine and Symfony. It lets you easily let users add multiple new relations and delete previous ones. However, it didn’t really support composite keys. We also wanted to be able to expose the primary keys rather than unsetting them from the form(so that the relation is automatically declared). This was a problem as we needed to be able to select at least one of the primary keys. Here is an example where we wanted to let the user pick one of the primary keys:

User:
  columns:
     first_name:
        type: string(16)
Product:
   columns:
      name:
         type: string(32)
UserProduct:
   columns:
      user_id:
         type: integer
      product_id:
         type: integer
        price:
          type: decimal
    relations:
       User:
          local: user_id
          foreign: id
       Product:
         local: product_id
         foreign: id

In this case there are Products and Users. A Users can have a products and specify how much each costs. When you are adding products to a user, you would want to be able to select which product you are adding in the embedded form. This is where our problem was, with the plugin as of version 1.4.4 you couldn’t tell it not to unset the primary keys when it embedded the form. We did a checkout of the plugin from SVN and modified it a bit. It now has and additional parameter: newFormUnsetPrimaryKeys . This will make it so the plugin will not unset the primary keys on a new form if you set it to true (it defaults to false).

We also found that the plugin had hard coded a couple of places findOneById which required the primary key to be called id. We’ve updated this to use the Doctrine method getIdentifierColumnNames() to get the primary keys.

We only applied to be developers on this script, so are currently waiting on it to be packaged and released, however if you want our updated just do a svn checkout of the plugin and you will be all set!

Let us know if you have any questions on it!