Wednesday, July 20, 2011

TIP: Importing your Project through SVN+SSH using a different port

1.) Edit your subversion config file
shell> sudo vim /etc/subversion/config

2.) Under "tunnels" add this
[tunnels]
ssh23 = ssh -p 23

3.) Now you can use it like this:
shell> svn import myproject svn+ssh23://username@192.100.100.100/usr/local/svn/test -m "initial import of files"

Tuesday, July 12, 2011

Setting up PHPUnit in Zend Framework

I haven't really done much unit testing but recently I have to mingle with it a little bit for this task that I was asked to do. I will walk through on how I set it up in ZF (Zend Framework) and share how I solve some problems I encountered.

I will assume you have already installed PHPUnit. If not go here to read the install documentation.

As you may noticed every time you create a new controller in ZF using zend tool a separate test controller is created in /tests/application/controllers but before we can use PHPUnit we need to setup our bootstrap.

1.) Go to and edit /tests/phpunit.xml and add this:
<phpunit bootstrap="./application/bootstrap.php" colors="true">
    <testsuite name="school">
       <directory>./</directory>
    </testsuite>
  
    <filter>
        <whitelist>
            <directory suffix=".php">../library/</directory>
            <directory suffix=".php">../application/</directory>
            <exclude>
                <directory suffix=".phtml">../application/</directory>
            </exclude>
        </whitelist>
    </filter>
</phpunit>

The above will tell PHPUnit where to find your bootstrap and what type of files to look for. You can use this if you are running test from the test parent directory.

2.) Now edit the /tests/application/bootstrap.php file and add this:
<?php
// Define path to application directory
defined('APPLICATION_PATH')
    || define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../../application'));

// Define application environment
defined('APPLICATION_ENV')
    || define('APPLICATION_ENV', (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV') : 'testing'));

// Ensure library/ is on include_path
set_include_path(implode(PATH_SEPARATOR, array(
    realpath(APPLICATION_PATH . '/../library'),
    get_include_path(),
)));

require_once 'ControllerTestCase.php';

The part you want to take a note on the above script is:
set_include_path(implode(PATH_SEPARATOR, array(
    realpath(APPLICATION_PATH . '/../library'),
    get_include_path(),
)));

This is important because if you do not include the ZF library in your PHP's include path, PHPUnit will not be able to find your library without you explicitly specifying the location.

2.) Now let's create an abstract class for our test cases to extend from. Go to /tests/application and create a file called ControllerTestCase.php and add:
<?php
require_once 'Zend/Application.php';
require_once 'Zend/Test/PHPUnit/ControllerTestCase.php';

abstract class ControllerTestCase extends Zend_Test_PHPUnit_ControllerTestCase
{
    public function setUp()
    {
        $this->bootstrap = new Zend_Application(
            APPLICATION_ENV,
            APPLICATION_PATH . '/configs/application.ini'
        );
        parent::setUp();
    }

    public function tearDown()
    {
        $this->resetRequest()->resetResponse();
        $this->request->setPost(array());
        $this->request->setQuery(array());
    }
}

NOTE: The above class is the class that you will need to extend when writing the actual tests.

3.) Edit your main application bootstrap and add the following:
/application/bootstrap.php

    protected function _initLogger()
    {
        $this->bootstrap('frontController');
       
        if ($this->getEnvironment() == "testing") {
            $writer = new Zend_Log_Writer_Stream(APPLICATION_PATH . "/../data/logs/app.log");
            $filter = new Zend_Log_Filter_Priority(Zend_Log::CRIT);
        }
       
        // register the Zend_Application_Resource_Log plugin first if you havent done so
        $this->registerPluginResource('log', array('writer' => $writer));
       
        // make sure to bootstrap
        $this->bootstrap('log');
       
        // retrieve Zend_Log and add the filter
        $this->_logger = $this->getResource('log')
                              ->addFilter($filter);
    }

Then edit your ErrorController.php and change/append the part in your error action where it says "// Log exception, if logger available" and change it to the following. This is if you happen to be using the default Error Controller:
        // Log exception, if logger available
        $log = $this->getLog();
        if ($log) {
            $message = $this->view->message . PHP_EOL;
            $message .= $errors->exception . PHP_EOL;
            $message .= '---------------------------';
            $log->crit($message);
        }

The above script will attempt to log error messages in the stream location that you set. This is so that if there is an error within your application itself unrelated to the test error such as "Application Error" or "Page Not Found Error", you will be able to debug the test. I realize that I need to do this because PHPUnit does not really report any information when you get these types of error. One example is if you $this->dispatch('/notexist') to a non existing action you will get an error in PHPUnit saying:

Failed asserting last action used <"error"> was "notexist";

That error in PHPUnit will not say much to you to debug from but it will log something in app.log.

4.) Now we can write a sample test script. Edit /tests/application/controller/IndexControllerTest.php if you have one and replace it to:

<?php

file_exists('../bootstrap.php') ? require_once '../bootstrap.php' : '';
require_once 'PHPUnit/Framework/TestCase.php';

class IndexControllerTest extends ControllerTestCase
{
    public function testShouldCallStudentSearch()
    {
        $this->dispatch('/');
        $this->assertAction('index');
        $this->assertController('index');
        $this->assertModule('MyModule');
    }
}

One last thing to note here is the line: file_exists('../bootstrap.php') ? require_once '../bootstrap.php' : ''; that I manually added. I did this so I can test the IndexController.php directly within the controller directory:
shell> cd test/application/controllers
shell> phpunit IndexControllerTest.php

Also notice that our class extends ControllerTestCase instead.

If you want to test every test controller that you created, make sure to test from the test directory:

shell> cd /test
shell> phpunit

Saturday, July 9, 2011

Notes: Zend Framework - Invalid Controller Specified Error in Controller Prefix

If you created a new module manually without zend tool make sure to add:
resources.frontController.params.prefixDefaultModule = "1"

Or the prefix in your controllers under your new module will not work! you'll get errors such as:
Fatal error: Uncaught exception 'Zend_Controller_Dispatcher_Exception' with message 'Invalid controller specified (error)'

This is all because of the prefix... (and also the error controller/view not present)

shell> zf create module newmodulename
shell> zf create controller index 1 newmodulename

This will create something like:

/modules/newmodulename/controllers
indexController.php
class Newmodulename_IndexController extends Zend_Controller_Action
{
}

The highlighted prefix that you will see above is the reason the controllers will generate an error. Now to fix it just add like what I noted earlier:
resources.frontController.params.prefixDefaultModule = "1"

Another fix is you can also edit your bootstrap instead. Just add this:
Bootstrap.php
$this->bootstrap('frontController');
$front = $this->getResource('frontController');
$front->setParam('prefixDefaultModule', 1);

Friday, July 1, 2011

Installing Apache 2.2.19 with SSL from source in Ubuntu

Before installing Apache 2, we need to install OpenSSL.

1.) Download OpenSSL from http://www.openssl.org/source/openssl-1.0.0d.tar.gz:
shell> wget http://www.openssl.org/source/openssl-1.0.0d.tar.gz

2.) You want to at least verify the md5 checksum of the openssl tar source and compare the md5 hash string with the one provided in the Apache web site (for this version: http://www.openssl.org/source/openssl-1.0.0d.tar.gz.md5) OR better yet use GnuPG:
shell> md5sum openssl-1.0.0d.tar.gz
shell> 40b6ea380cc8a5bf9734c2f8bf7e701e  openssl-1.0.0d.tar.gz ;: now compare the md5

3.) If everything is well, untar and install:
shell> tar xzvf openssl-1.0.0d.tar.gz
shell> cd openssl-1.0.0d
shell> ./config --prefix=/usr/local/lib/openssl -fPIC

NOTES: I have to use -fPIC for some reason or the configure will keep generating an error but try first without it.

4.) Make a soft link of the bin/openssl
shell> sudo ln -s /usr/local/lib/openssl/bin/openssl /usr/local/bin/

Now we need to create a private key and a certificate.
5.) Lets create our server's private key:
shell> openssl genrsa -des3 -out server.key 1024

6.) Now lets create a Certificate Signing Request (CSR) and sign it using our private key (server.key):
shell> openssl req -new -key server.key -out server.csr

NOTE: You usually send the CSR to a CA or Certificate Authority such as Verisign (Im clueless, never done it) but for now we cannot wait and we want to test! We can act as our OWN Certificate Authority and sign our CSR. This will not be valid for browsers and will tell you the Certificate is not from a valid authority.

7.) Lets use our server's private key (server.key) to sign our Certificate Signing Request (CSR) or you can create another private key acting as a Certificate Authority (CA). From there we can sign and create our own CRT (Certificate):
shell> openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt

Now we have a Private key (server.key) and a signed certificate (server.crt)

8.) Lets add this public key and certificate to a location we can remember:
shell> mv server.key /usr/local/ssl/privatekeys/
shell> mv server.crt /usr/local/ssl/certificates/

We can start installing Apache 2.

9.) Download Apache 2.
shell> wget http://www.takeyellow.com/apachemirror//httpd/httpd-2.2.19.tar.gz
shell> tar xzvf httpd-2.2.19.tar.gz

10.) Before installing, lets compare the md5 checksum of our package to the ones from Apache.org so we can have a little peace of mind that the integrity of the source files has not been compromised:
shell> md5sum httpd-2.2.19.tar.gz
shell> e9f5453e1e4d7aeb0e7ec7184c6784b5 httpd-2.2.19.tar.gz
 *Compare that md5 with this: http://www.apache.org/dist/httpd/httpd-2.2.19.tar.gz.md5

If everything seems to look right, lets proceed with the installation

11.)  Install Apache 2 and enable SSL support:
shell> cd httpd-2.2.19
shell>sudo ./configure --prefix=/usr/local/lib/apache2 --enable-mods-shared=most --enable-ssl --with-ssl=/usr/local/lib/openssl
shell> sudo make
shell> sudo make install

12.) If everything went smooth, lets add our private key and certificate to Apache:
shell> sudo vim /usr/local/lib/apache2/conf/extra/httpd-ssl.conf

13.) Look for the line SSLCertificateFile "/usr/local/ssl/server.crt" and SSLCertificateKeyFile "/usr/local/ssl/server.key" and replace it with your proper certificate and key location

Mine will be:
SSLCertificateFile "/usr/local/ssl/certificates/server.crt"
SSLCertificateKeyFile "/usr/local/ssl/privatekey/server.key"

14.) Go to your Apache's httpd.conf and uncomment the include for httpd-ssl.conf
shell> sudo vim /usr/local/lib/apache2/conf/httpd.conf

15.) Make a soft link of apachectl then start Apache:
shell> sudo ln -s /usr/local/lib/apache2/bin/apachectl /usr/local/bin/
shell> sudo apachectl start

IMPORTANT: The above steps are just fast walk through and did not consider any security concerns in setting up Apache. Please research further on how to secure your web server efficiently.