Aaron Saray

open source programmer,
web developer

entrepreneur, author
and musician

My Blog

contains PHP, Web and business/entrepreneurial related content. Please join in the conversation!

Creating a custom Zend Framework Body Script helper

It drives me nuts that the best practices with javascript that is not required for the initial rendering of your application is to be placed at the bottom of the document, yet frameworks (like Zend Framework) do not support that out of the box. (I recently found out that Joomla also shares this problem.)

By default, in Zend Framework, the Zend View Helper of HeadScript allows additions to the header of the document (now, technically you could just call the headScript() output in the body of your layout, and this would fix it, but that’s not very semantic, is it?).

I’ve created my own solution. Now, I put headScript() items only in the head when necessary, and I add everything else to my new custom bodyScript() handler. This is simply extending the headScript() handler for a different position.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Application_View_Helper_BodyScript extends Zend_View_Helper_HeadScript
{
    /**
     * @var string The key to store this in the registry
     */

    protected $_regKey = 'Application_View_Helper_BodyScript';
       
    /**
     * Proxy for the different named head script
     */

    public function bodyScript()
    {
        $args = func_get_args();
        return call_user_func_array(array($this, 'headScript'), $args);
    }
}

You’ll notice it simply is simply extending the headScript item and calling it the bodyScript. The only other thing to note is that the regKey variable is different from the headScript() version. This is to keep them separate when building the registered entities for this helper.

And of course, this is simply called just like HeadScript

1
2
    <?php echo $this->bodyScript(); ?>
</body>
Posted in javascript, zend framework | Tagged , | Leave a comment

Split Read/Write Connections in Zend Framework Database on the Application Level

I’m no sys admin, so I can’t be sure, but I’ve seen lots of issues with using things like MySQL Proxy to fully separate the write and read queries in an application. Maybe it works, I don’t know… but I do know that if I can separate the connections in my code, that saves my Admin time… it doesn’t appear to give that much of a hit to performance either! Do keep in mind that this is only working at the table level in Zend Framework. If you use their database system, this should do the trick. If you do a lot of getting the adapter yourself, this won’t help you at all!

First thing to know, when you define your database settings in the application.ini file, the default settings that the bootstrap would read in … you know:

resources.db.adapter = "pdo_mysql"
resources.db.params.host = "localhost"
resources.db.params.username = "xx"
resources.db.params.password = "xx"
resources.db.params.dbname = "xx"

Let that be the read connection.

Next, create a method in your bootstrap called _initWriteConnection() or something like that. Create the write connection in there (a separate instance of the Zend_Db connection…). Store that into the Zend_Registry.

Finally, time to extend the Zend_Db_Table_Abstract

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
class Application_Model_SplitReadWriteDatabaseConnection extends Zend_Db_Table_Abstract
{
    /**
         * temporary storage of the read only adapter
     */

    protected $_readDB = null;
   
    /**
     * invokes the read/write connection
     * @see Db/Table/Zend_Db_Table_Abstract::insert()
     */

    public function insert(array $data)
    {
        $this->_preWrite();
        $return = parent::insert($data);
        $this->_postWrite();
        return $return;
    }
   
    /**
     * Invokes the read/write connection
     * @see Db/Table/Zend_Db_Table_Abstract::update()
     */

    public function update(array $data, $where)
    {
        $this->_preWrite();
        $return = parent::update($data, $where);
        $this->_postWrite();
        return $return;
    }
   
    /**
     * Stores the read adapter and sets the write adapter
     */

    protected function _preWrite()
    {
        $this->_readDB = $this->getAdapter();
        $this->_setAdapter(Zend_Registry::get('DbWriteConnection'));
    }
   
    /**
     * Sets the read adapter back and clears the temporary storage
     */

    public function _postWrite()
    {
        $this->_setAdapter($this->_readDB);
        $this->_readDB = null;
    }
}

This is pretty simple. It overrides the insert and update commands of the Zend_Db_Table_Abstract class. With that, it calls preWrite to set the adapter to the write version, and store the ‘current’ one (the read one). After the parent is called, it restores the database connection.

This isn’t fully tested or complete!

I’m trying to find ways to make this better. Here are things/problems (err… Opportunities?) I see…

  • If you use the getAdapter() method against a table, it will return the read connection. You have to use the Zend_Db_Table methods only for this to work.
  • If an exception happens during the write methods, it may not return the connection to the read database. I believe it will exit this code and continue using the write connection (even if more read queries are called).

Any other ways that I can make this better?

PS, if you’d like to test this, but don’t actually have two different database credential connections (but want to be ready for later), make the _initWriteConnection() method contain the following code:

1
2
3
4
        $this->bootstrap('db');
        $db = $this->getResource('db');
        Zend_Registry::set('DbWriteConnection', $db);
        return $db;

This way, it gets the existing read connection and stores it as the ‘write’ version as well. Remember, only do this until you have both connections.

Posted in mysql, zend framework | Tagged , | Leave a comment

Zend Framework Static Router URLs Not Found in Zend Navigation

For a CMS I’ve been working on, there are a number of custom routes that are added statically in a loop. These point to specific ID’s of articles on on the default module’s page viewing controller/action. Sometimes these routes need to appear in the Zend_Navigation output. As you can probably guess, the logic used for this is similar to what you might experience when using the URL view helper. But, for some reason, I could never get the URL’s to be marked as active.

Here is an example of the code that was being executed in the setup plugin:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$route = new Zend_Controller_Router_Route_Static(
   'custom-url-1',
   array(
       'module'=>'default',
       'controller'=>'page',
       'action'=>'view',
       'id'=>101,
   )
);
               
$router->addRoute('custom1', $route);

$route = new Zend_Controller_Router_Route_Static(
   'custom-url-2',
   array(
       'module'=>'default',
       'controller'=>'page',
       'action'=>'view',
       'id'=>102,
   )
);
               
$router->addRoute('custom2', $route);

Well, it turns out that its impossible for the URL handler to know which route to use. It can match it, sure, but it doesn’t know how to recompile it (that’s my best guess at least…). So, in order to tell it to form it in the default way, I added the ‘route’=>’default’ attribute to the arrays and this seemed to work.

So now, for example, this is what you’ll find:

1
2
3
4
5
6
7
   array(
       'module'=>'default',
       'controller'=>'page',
       'action'=>'view',
       'id'=>102,
       'route'=>'default'
   )

Hope this helps someone else out! If you know exactly why this works, feel free to comment.

Posted in zend framework | Tagged | 1 Comment

How to Quickly Mask a Credit Card Number

So, often I have to show a masked credit card on the screen. However, I really want to go the extra mile and show the user a secure, fully masked credit card number that still reflects their original card. For example, if their credit card number is only 15 numbers long, I shouldn’t show a 16 character long string. So, I’ve developed this code snippet:

1
2
$cc='1234123412341234';
$masked = str_pad(substr($cc, -4), strlen($cc), '*', STR_PAD_LEFT);

This simply takes the credit card, substr() the last 4 digit into the str_pad() method as the input. Then, says the length of the output string should be strlen() of the actual input. The pad character is a *. Finally, pad everything on the left. This way, no matter what, the output length will be the same as the input string, and it will be padded correctly.

Posted in PHP, programming | Tagged , | Leave a comment

Running PHPUnit on Remote System from Command Line

If I need to run PHPUnit on a remote system against a code suite, I will write a simple shell script like the following to do it for me. (Bonus points, you can even include this as an External Tool in eclipse to do it right from your project).

1
2
3
#!/bin/bash

ssh developmentserver "cd /var/www/tests && phpunit $1"

So, two things you should know: I’m using shared keys and have my .ssh/config file set up to have developmentserver as a name for the connection.

Bonus:

To add this as an external tool in Eclipse, do the following:

  1. Open Eclipse
  2. Click Run -> External Tools -> External Tools Configurations
  3. Double click ‘Program’ to create a new program.
  4. Name it to reflect the unit test you’re going to be running.
  5. In the location box, put the full location to your bash script
  6. In the arguments box, click Variables. Choose ‘selected resource location’
  7. Click Apply/Close

Now, assuming that your workspace is matched up to your file system on the remote system, you can run the external tool for PHP Unit on any selected test or folder. The output will appear in your console tab.

Posted in Eclipse PDT, phpunit | Tagged , | 1 Comment

Mod Rewrite to index.php file, the easy way

How many of you have written this before (or something very much like it):

?View Code APACHE
1
2
3
4
5
6
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ index.php [NC,L]

You might recognize something like this from the Zend Framework .htaccess file. Basically, the point is to say if something doesn’t exist, point it to the index.php file. Well, there is a simpler way to do this – I can’t believe I didn’t know this till now…

Apache Fallback Resource

All of that configuration now becomes this:

?View Code APACHE
1
FallbackResource /index.php
Posted in apache | Tagged | 1 Comment

Add PHPUnit Listeners to Watch for Long Running Tests

One of the under-utilized features of PHPUnit probably is the listeners interface. You can see the configuration options here: http://www.phpunit.de/manual/current/en/appendixes.configuration.html. So, I decided that I want to use this to know if a Unit Test takes longer than 2 seconds to run. That’s super over-kill in my opinion, but that’s my hard limit. If it takes longer than 2 seconds to run, something is wrong! So, I added the following to my configuration:

excerpt from phpunit.xml

1
2
3
    <listeners>
        <listener file="scripts/TestTimesLimitListener.php" class="Application_Test_TestTimesListener" />
    </listeners>

This simply says to invoke the listener from TestTimesLimitListener.php – which class name is Application_test_TestTimesListener. Here is the code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
/**
 * Listener Class for test times
 *
 * @package Tests
 */

class Application_Test_TestTimesListener implements PHPUnit_Framework_TestListener
{
    /**
     * Number of seconds that this test can run
     * @var integer
     */

    const TEST_LIMIT_TIME = 2;
   
    /**
     * called when test is ended - determines if it was long and prints
     * @param PHUnit_Framework_Test $test
     * @param float $length the length of time for the test
     */

    public function endTest(PHPUnit_Framework_Test $test, $length)
    {
        if ($length > self::TEST_LIMIT_TIME) {
            $this->_printError($test->getName() . " ran for {$length} seconds");
        }
    }
   
    /**
     * Used to print error in error colors
     * @param string $error
     */

    protected function _printError($error)
    {
        print "\n\033[41m" . $error . "\033[0m\n";
    }
   
    /**
     * Required for Interface
     * (non-PHPdoc)
     * @see PHPUnit_Framework_TestListener::startTest()
     */

    public function startTest(PHPUnit_Framework_Test $test) {}

    /**
     * Required for Interface
     * (non-PHPdoc)
     * @see PHPUnit_Framework_TestListener::addError()
     */

    public function addError(PHPUnit_Framework_Test $test, Exception $e, $time) {}

    /**
     * Required for Interface
     * (non-PHPdoc)
     * @see PHPUnit_Framework_TestListener::addFailure()
     */

    public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time) {}

    /**
     * Required for Interface
     * (non-PHPdoc)
     * @see PHPUnit_Framework_TestListener::addError()
     */

    public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time){}

    /**
     * Required for Interface
     * (non-PHPdoc)
     * @see PHPUnit_Framework_TestListener::addSkippedTest()
     */

    public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time) {}
   
    /**
     * Required for Interface
     * (non-PHPdoc)
     * @see PHPUnit_Framework_TestListener::startTestSuite()
     */

    public function startTestSuite(PHPUnit_Framework_TestSuite $suite) {}
   
    /**
     * Required for Interface
     * (non-PHPdoc)
     * @see PHPUnit_Framework_TestListener::endTestSuite()
     */

    public function endTestSuite(PHPUnit_Framework_TestSuite $suite) {}
}

First of all, the class must implement the PHPUnit_Framework_TestListener interface. That’s why at the end you’ll see all the extra empty methods piled on. Let’s dive into the code:

Define a constant of the number of whole seconds. Next, define the endTest method which will receive a float of how many seconds/milliseconds that test took to run. If it takes longer than our limit, print an error using the test name. The _printError() method uses some control characters to change the font color red.

There you go! Now, during your normal execution of unit tests, you may see a few warnings for long running tests in red. Go and correct those to keep your tests running smooth and fast.

Please note: a while ago, I ran into a blog entry about this. It wasn’t clear to me at the time, so I didn’t book mark it. However, I wanted to mention that this isn’t 100% only my work. Credit to where credit is due.

Posted in phpunit, testing | Tagged , | Leave a comment

Setting PHP Command Line Colors

I’m not entirely certain why this escaped me for so long, but it’s remarkably easy to set terminal colors with PHP. Simply echo the escape/color character \033, followed by the bash color definition and your output. For reference, here is a listing of bash colors. So, for example, if we want to make something blue text, do the following:

1
echo "\033[34m" . 'here is blue text' . "\033[0m\n";

This simply sets the blue color, adds the blue text, and then resets the color to default, and makes a new line.

Posted in PHP | Tagged | Leave a comment

When you Create Your Account, Please log in.

I’ve always found it annoying when programmers create systems where you create your account and then you’re not logged in. Maybe I’m lazy? I decided to do a poll on a popular social networking site. The poll went like this:

When signing up for a new web site, do you mind logging in after signing up?

The two options were:

  • If I create an account, it should already log me in.
  • I don’t mind logging in after I create my account (it proves I know my password)

Overwhelmingly (ok only 78% but still…) response has been in favor of creating an account and logging in automatically. I think that we should take the extra step when creating applications to make this process streamlined for users.

Posted in Misc Web Design | Tagged | 2 Comments

Zend Framework Authentication: Let the user know if it is their fault

One of the things that is irritating is logging into a website with credentials that you know are right, only to have it fail. Then, later, you find that the site was malfunctioning. By then, maybe you requested a new password, or had to at least waste time looking up your old password. With Zend_Auth, however, we can prevent user’s from having that issue.

Side note: some schools of thought want to go the extra mile for security and never give the visitor any extra information than what is required. I believe this to some extent. I will say the username or password is wrong (I won’t say that the username exists, but the password is wrong.) However, I don’t think it’s out of line to alert the user if your system is having authentication issues.

So, with Zend_Auth, the authenticate() method returns a Zend_Auth_Result. This, of course, has the isValid() method which everyone is familiar with. However, there are a number of reasons why this could return false. Whatever reason generated the invalid response will be returned by the getCode() method. These include:

    const FAILURE                        =  0;
    const FAILURE_IDENTITY_NOT_FOUND     = -1;
    const FAILURE_IDENTITY_AMBIGUOUS     = -2;
    const FAILURE_CREDENTIAL_INVALID     = -3;
    const FAILURE_UNCATEGORIZED          = -4;

The user is really only concerned with the FAILURE_IDENTITY_NOT_FOUND and FAILURE_CREDENTIAL_INVALID conditions. The rest are more-than-likely our own failures. (For example, your data has become corrupted? FAILURE_IDENTITY_AMBIGUOUS).

When I generate error messages for the user, I tend to make a method called isFailureUserBased() which will determine the type of error I return. If it is user based, I’ll return a string saying incorrect username or password. If it is not user based, the message will be to contact support or wait it out (I might even send an automated note to the support staff at this time).

This is usually a very simple method:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
 * Used to determine if this is a user failure or an internal failure on our part
 *
 * @return boolean if its a user failure
 */

public function isFailureUserBased()
{
    $result = $this->_authResult->getCode(); //stored internal Zend_Auth_Result instance
   
    switch ($result) {
        case Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND:
        case Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID:
            return true;
    }
   
    return false;
}
Posted in zend framework | Tagged | Leave a comment