Archive for the ‘miscellaneous’ Category

Fixing mysqldump on Zend Server CE on OS X

Tibo BeijenTuesday, March 1st, 2011
fixing-mysqldump-on-zend-server-ce-on-os-x

A while ago I installed Zend Server Community Edition on OS X which was pretty straightforward. It was only recently that I found out that, as opposed to mysql which worked fine, mysqldump didn’t work correctly and terminated with the error:

mysqldump: Got error: 2002: Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2) when trying to connect

Inspecting the mysql configuration contained in /usr/local/zend/mysql/data/my.cnf confirmed that the section [client] showed the socket as returned by executing SHOW VARIABLES; from the mysql client: /usr/local/zend/mysql/tmp/mysql.sock

Although it is possible to specify the socket by using mysqldump’s --socket switch, that doesn’t really seem a ‘solution’.

Apparently mysqldump, as opposed to the mysql client does not use the server-specific settings contained in /usr/local/zend/mysql/data/my.cnf. The comments in my.cnf state:

# You can copy this file to
# /etc/my.cnf to set global options,
# mysql-data-dir/my.cnf to set server-specific options (in this
# installation this directory is /usr/local/zend/mysql/data) or
# ~/.my.cnf to set user-specific options.

After copying /usr/local/zend/mysql/data/my.cnf to /etc/my.cnf mysqldump worked as expected.

In /etc/my.cnf I have included only the setting needed to get mysqldump running:

# Specifying socket to use for mysql/mysqldump
# For other settings refer to /usr/local/zend/mysql/data/my.cnf
[client]
socket      = /usr/local/zend/mysql/tmp/mysql.sock

Hope this saves anyone running into the same issue some time.

Update (alternative solutions):
As Joel Clermont pointed out it is also possible to create a symlink on the socket location expected by mysqldump to the real socket location. This can be done by executing:

ln -s /usr/local/zend/mysql/tmp/mysql.sock /tmp/mysql.sock

Another possible approach is to create a symlink at /etc/my.cnf to /usr/local/zend/mysql/data/my.cnf. This has the downside that it requires loosening the default permissions (drwxr-x---) on the data folder by allowing ‘others’ to enter it. Commands to execute:

sudo chmod o+x /usr/local/zend/mysql/data
sudo ln -s /usr/local/zend/mysql/data/my.cnf my.cnf

Granting more permissions can be a security consideration but on most development setups this probably won’t be an issue.

Additional info about Zend Server CE on OS X:

Zend_Form: Building dynamic forms

Tibo BeijenMonday, December 21st, 2009
zend_form-building-dynamic-forms

In my previous post about Zend_Form I showed how, using Zend_Form, a form’s structure can be separated from it’s presentation and how to use custom Decorators and Validators. The example used showed a form that is tightly coupled to a record in a database: One form edits one record. There are however numerous occasions where no ‘one to one’ connection exists and where the fields that need to be shown are not predetermined. Take for example a shopping cart that shows the amounts of each product. In this article I’ll take a look at how to:

  • dynamically construct a form based on the data being edited
  • use subforms to reuse common parts and group related values
  • create composite ‘elements’ by using the default Zend_Form_Element in combination with a custom decorator
  • create additional elements with Javascript and have them processed by the form when submitted

Like previous article the case examined assumes a situation where Zend_Form is used in an existing project that doesn’t use the Zend Framework MVC stack. The Form can be viewed online and all of the sample code can be found on GitHub.

Case outline

In this example I construct a form where a user can view and edit a task list for a week’s working days. Every task can be edited in one single form and new tasks can be added at will. When viewing the page the application fetches the tasks already entered for that week. The assumed codebase is able to generate and consume an array as shown below:

// array format used to supply data of multiple tasks to form
$tasks[$timestampDay1]['current'][$taskId1]['desc'] = 'Gotta do this';
$tasks[$timestampDay1]['current'][$taskId1]['completed'] = true;
$tasks[$timestampDay2]['current'][$taskId2]['desc'] = 'Gotta do that';
$tasks[$timestampDay2]['current'][$taskId2]['completed'] = false;

The ‘current’ part will later help to distinguish between new and allready stored tasks.

Dynamically building a Zend_Form

Using Zend_Form typically follows these steps:

$Form = new My_Form(); // My_Form::init() will define elements
$Form->setDefaults($myData);
if ($Form->isValid($_POST)) {
    $submittedValues = $Form->getValues();
    // process values and redirect to same or other page
}
echo $Form->render();

When a form’s elements need to be defined based on the data being edited, Zend_Form::init() is not suitable as at that point the data is not known yet. Providing data through the constructor to have it available in the init() method ‘could’ work but is not a really nice solution as it means changing the parameter scheme of the constructor. Furthermore, it would ignore the method that exists specifically for adding initial data: setDefaults(). As that will be the first point at which the form ‘knows’ what data needs to be edited, that will be the point to add elements. Or, as in this case, subforms.

My_Form_TaskWeek

The setDefaults() method of the week-form is changed as displayed below:

class My_Form_TaskWeek extends Zend_Form
{
    // ...
    public function setDefaults($defaults)
    {
        // first add the subforms
        $this->clearSubForms();
        $dates = array_keys($defaults);
        foreach ($dates as $day) {
            $dayForm = new My_SubForm_TaskDay();
            $this->addSubForm($dayForm, (string) $day);
        }
        // set defaults, which will propagate to newly created subforms
        parent::setDefaults($defaults);
    }
    // ...
}

For every day in $defaults (in this example the key is a timestamp, but it could be anything) a subform is added. This is done before calling parent::setDefaults(). With the subforms in place the call to the parent method will propagate to the subforms we’ve just created.

My_Form_TaskDay

In the form that shows one single day, some actions are performed in the init() method: A subform for both ‘current’ and ‘new’ elements is added. Also a ‘template’ element is added. The subforms have just one decorator: FormElements. The template element will be used as source for new elements that are added by javascript. When setDefaults() is called, elements are added to the current subform.

 class My_SubForm_TaskDay extends Zend_Form_SubForm
{
    // ...
   public function init() {
        // create subforms having nothing but element decorator
        $this->addSubForm(new Zend_Form_SubForm, 'current');
        $this->addSubForm(new Zend_Form_SubForm, 'new');
        $this->getSubForm('current')->setDecorators(array('FormElements'));
        $this->getSubForm('new')->setDecorators(array('FormElements'));
 
        // add template element
        $templateElement = $this->createTaskElement('__template__', array(), true);
        $this->getSubForm('new')->addElement($templateElement);
    }
 
    public function setDefaults($defaults)
    {
        $subform = $this->getSubForm('current');
        foreach ($defaults['current'] as $id => $values) {
            $subform->addElement($this->createTaskElement($id, $values));
        }
        // set defaults, which will propagate to newly created subforms & elements
        parent::setDefaults($defaults);
    }

The method that creates an element:

    protected function createTaskElement($id, $values, $isNew = false)
    {
        $elm = new Zend_Form_Element((string) $id);
        $elm->clearDecorators();
        $elm->addDecorator(new My_Decorator_TaskElement());
        $elm->addDecorator('Errors', array('placement'=>'prepend'));
 
        // add configured validator
        $validator = new My_Validator_TaskElement();
        $validator->setIsNew($isNew);
        $elm->addValidator($validator);
 
        return $elm;
    }

Creating composite elements by using custom decorator

As the code above shows, creating a task element consists of three steps:

Zend_Form_Element

A basic Zend_Form_Element is created. This is the ‘root’ class of which specific element-types (like Zend_Form_Element_Text) are descendants. The Form will supply each element with the element’s value which in this case will be an associative array with the keys ‘desc’ and ‘completed’.

My_Decorator_TaskElement

A custom decorator is added: My_Decorator_TaskElement. This decorator replaces what would normally be the ViewRenderer decorator. It is responsible for rendering both the text and checkbox input elements and wraps them in a div. For the template element (based on the element name) the containing div will be given a classname ‘template’ which will be of use when creating the javascript behaviour.

    public function render($content)
    {
        // get element details
        $elm = $this->getElement();
        $value = $elm->getValue();
        $elmName = $elm->getFullyQualifiedName();
 
        // construct inputs
        $isCompleted = isset($value['completed']) && $value['completed'];
        $descValue = (isset($value['desc'])) ? htmlspecialchars($value['desc']) : '';
 
        $inputDesc = sprintf(
            '<input type="text" name="%s" value="%s" />',
            $elmName . '[desc]',
            $descValue
        );
        $inputCompleted = sprintf(
            '<input type="checkbox" name="%s" value="1" %s />',
            $elmName . '[completed]',
            ($isCompleted) ? 'checked="checked"' : ''
        );
 
        // wrap in div, optionally adding attribute class
        $elmHtml = sprintf(
            '<div class="task %s">%s%s</div>',
            ($elm->getName() == '__template__') ? 'template' : '',
            $inputDesc,
            $inputCompleted
        );
 
        // this should be the first decorator but add the content for
        // consistency's sake
        return $content . $elmHtml;
    }

My_Validator_TaskElement

A custom validator is added: My_Validator_TaskElement (see code on GitHub). This validator will check if the description is empty but treats new elements differently from existing ones: For existing elements it is not allowed to have an empty description. For new elements this is only allowed if the ‘completed’ checkbox isn’t checked. (This way a user can still submit the form if he’d accidentally added a new field).

Using jQuery to let the user add new elements

The javascript that lets a user add a new element is implemented as a jQuery plugin. The code having the javascript initiate looks as follows:

$(document).ready(function() {
    $('form .taskDay').dynamicForm();
});

As can be seen each of the ‘day’ subforms outer elements is selected and applied upon a jQuery plugin. This plugin (on GitHub)performs the following tasks:

  • Within the element it operates on it searches for an element with classname ‘add’ and attaches a ‘click’ event handler to it.
  • It searches for an element ‘template’ and stores a reference to it.
  • Whenever the user clicks the ‘add’ button, the template element is cloned
  • Within the template element the ‘name’ attribute of any input element is altered: The string ‘__template__’ is replaced by a timestamp. This makes sure that multiple new tasks can be added within a day without them interfering with each other.
  • The new element is placed after the last found element with classname ‘task’

By referring to classnames, the javascript’s dependencies on the exact HTML are kept to a minimum. This way, if needed, the HTML structure of the form elements can be changed without the need to update the javascript.

Having the form process the new elements

When the task form is submitted, newly added tasks will be in the $_POST array as shown below:

// is assoc. array having 'desc' and 'completed' keys
$_POST[$dayTimestamp]['new'][$uniqueJSCreatedValue];

The form object needs to be able to validate the input for both the existing and the new tasks, so the $_POST array is passed to the isValid() method. At this point the form doesn’t yet contain the ‘new’ elements. Adding those is done in a similar fashion to how the existing elements are added in setDefaults(), only this time it is done in isValid(). That is the first point where the form is able to determine what the new elements are. Dynamically adding the new elements happens in the ‘day’ subform:

class My_SubForm_TaskDay extends Zend_Form_SubForm
{
    // ...
    public function isValid($data) {
        $subform = $this->getSubForm('new');
        // make sure new is array (won't be in $data if nothing submitted)
        if (!isset($data['new'])) {
            $data['new'] = array();
        }
        foreach ($data['new'] as $idx => $values) {
            // Don't add element with idx = __template__. SetIgnore works on
            // getValues. Template elements are submitted so this would otherwise
            // override the previously added template element, thereby losing the
            // setIgnore setting...
            if ($idx !== '__template__') {
                $subform->addElement($this->createTaskElement($idx, $data, true));
            }
        }
        // call parent, which will populate newly created elements.
        return parent::isValid($data);
    }
    //...
}

Here the aforementioned createTaskElement() method pops up again. Notice the third parameter (true) that will make the validator treat the element as a ‘new’ one.

All done, except for …

In theory now everything works. But practice tends to have those little things that go wrong which you hardly ever read about in code examples. When working on this example I noticed that getValues() doesn’t preserve the per-day timestamp keys in the array returned. Instead, it returns an indexed array like this:

$getValues = array(
    // this '0' should have been a timestamp, like: 1261350000
    '0' => array(
        'current' => array(), // etc. etc.
        'new' => array() // etc. etc.
    ),
    // ...
);

Bummer. As it appears, Zend_Form ‘requires’ elements, subforms and display groups to have valid variable names (See ZF-4204). One of the reasons is problably that the names also end up in HTML id attributes which are not allowed to start with a number. The name attribute is though (you can run the demo form through the W3C validator). Remarkably, the task elements, having a name consisting of the database id, are processed just fine.

Two possible solutions for this:

  • Avoid numeric names. Downside is that this also involves changing the existing code generating and processing the array. The day-form header decorator which uses the form’s name to display the date needs to be changed as well.
  • Add an implementation of getValues() in My_Form_TaskWeek that checks for numeric keys and changes them back to their original timestamp

I choose the latter (for now) because it allows to leave almost all existing code unaltered and the resulting behaviour is unit testable (supply defaults, test what is rendered, test what is returned, etc.).

Conclusion

The above shows that:

  • Subforms are very useful to repeat similar blocks within a form and to group related values in the returned value array.
  • Dynamically adding initial and newly submitted elements follows a similar pattern: Add elements based on the passed in array and then call the parent’s method. This is done in setDefaults() and isValid() respectively.

The question might arise ‘is Zend_Form the best solution for this type of customized form?’. The default ViewHelper decorator is ignored, no default validator is used. I can’t tell if Zend_Form is the best solution but fact is that it provides a lot of functionallity and flexibility: The Form, Errors and HtmlTag decorators are used ‘as is’. Furthermore, the option to reuse parts comes almost naturally because of Zend_Form’s design.

Regarding the last point I’ll conclude with following example: What if, some time after having created this form, the idea is born to have some sort of per-day dashboard page where a user can view and edit things like calendar, messages and tasks? (This is the kind of stuff that happens in agile projects). Reusing My_SubForm_TaskDay would be very useful. And luckily that is easily accomplished. All that is needed is wrapping the subform in a class that will additionally:

  • Set a view object
  • Add a submit button
  • Add a Form decorator

See the code of My_Form_TaskDay on GitHub or see it in action online.

Taming the Javascript event scope: Closures

Tibo BeijenMonday, July 27th, 2009
taming-the-javascript-event-scope-closures

When doing client-side developing there are times that jQuery’s get-this-do-that nature doesn’t provide all that is needed. For more complex applications I usually find myself creating javascript objects that ‘control’ a specific part of the page’s interaction. In the objects the application’s state is tracked, references to other objects (could be relevant DOM nodes) are stored and event handlers are set.

One of the problems typically encountered when dealing with javascript event handlers is that they have their own take on the ‘this’ keyword. Closures to the rescue.
(more…)

Zend_Test, Zend_Layout and the need to reset

Tibo BeijenMonday, June 1st, 2009
zend_test-zend_layout-and-the-need-to-reset

In a recent Zend Framework project I’ve used Zend_Test to test the functioning of the website ‘as a whole’. So besides testing the separate (authorization) components, the website was tested in the same way a visitor would use it. This is especially useful for testing login scenarios, so I added the test below:

public function testLogoutShouldDenyAccess()
{
    $this->login();
 
         // verify that profile page now doesn't contain login form
    $this->dispatch('/profile');
    $this->assertQueryCount('form#login', 0);
 
        // dispatch logout page
    $this->dispatch('/login/logout');
 
        // verify that profile now holds login form
    $this->dispatch('/profile');
    $this->assertQueryCount('form#login', 1);
    $this->assertNotController('profile');
}

This failed on the last assertQueryCount() which left me puzzled. Performing above steps manually seemed to work fine so I was overlooking something either in my app-code or the test-code.
(more…)

Installing PHPUnit on XAMPP Lite (Windows)

Tibo BeijenSunday, May 17th, 2009
installing-phpunit-on-xampp-lite-windows

At my work PHPUnit is ‘just there’ but it’s not on my home machine where I’m running an out of the box XAMPP Lite setup. So I visited the PHPUnit installation manual and all looked easy:

pear channel-discover pear.phpunit.de
pear install phpunit/PHPUnit

But what I got was a message saying my pear installer was out of date, 1.7.1 was needed. Running ‘pear -V’ showed:

E:\Xampplite\php>pear -V
PEAR Version: 1.4.5
PHP Version: 5.2.5
Zend Engine Version: 2.2.0
Running on: Windows NT T1720 6.0 build 6000

Allright, upgrading PEAR it is. That was not as straightforward as hoped.
(more…)

Fixing Netbeans after Ubuntu 9 upgrade

Tibo BeijenFriday, May 1st, 2009
fixing-netbeans-after-ubuntu-9-upgrade

This morning I upgraded my Ubuntu machine using the auto-update. As I just recently started using Ubuntu I’m very pleased at how some features work compared to Vista. (Vista users will probably be familiar with the auto-update restart that has a terrific feel for timing by always presenting you the choice for postponing the restart when you have several documents opened and are away for a coffee break.) After my self initiated restart everything worked like a charm, OpenOffice is updated to version 3 (nice for the docx workflow) but… Netbeans didn’t start. Now that’s bad for productivity. Running from the console showed the following:

Cannot find java. Please use the --jdkhome switch.

a After a little bit of googling I learned there is a netbeans.conf somewhere. On my system it’s location is:

~/netbeans-6.7-m2/etc/netbeans.conf

In there, look for a line like

netbeans_jdkhome="/usr/lib/jvm/java-6-sun-1.6.0.13/jre"

and change the version number to the correct version. For me it worked like a charm, I hope it helps someone.

Annoying banners: A plea for quality

Tibo BeijenMonday, April 27th, 2009
annoying-banners-a-plea-for-quality

Banners play an essential role in many site’s business models so they are an inevitable price paid for all the free content that is available on the internet. To get a user’s attention a lot of practices are employed like animation, placement or sound (horrible). Today I stumbled on a T-mobile advert on the site nu.nl that indeed attracts a lot of attention but does so in a questionable way: It makes using the visited site almost impossible. (Not a new phenomenon and it’s certainly not the first time I encounter such a banner).

The T-mobile banner is positioned at the bottom of the viewport and is kept in place by javascript or actionscript. This means that during scrolling the banner shakes because the script reacts to the scroll event. No awards won but not a real problem either. But what is bad is the fact that in the orange area (note the little pun there) no link can be clicked. Something I didn’t notice at first resulting in rapid agitated clicking. See screenshot below:

T-Mobile banner on nu.nl

T-Mobile banner on nu.nl

As a ‘normal’ visitor that is just annoying but as a web-professional it irritates me to a great extend that there seems to be no technical need for this misbehaviour whatsoever. So what goes wrong? On a first glance there seem to be four roles involved:

  • Nu.nl: They need adds but it seems unlikely they want banners to block parts of their site and thereby cause user frustration.
  • The banner merchant. Doubleclick, adclick or whatever their names are. I’m not really into the advertisement business but I wouldn’t be surprised if different advertisement programs exist that site publishers can use: flashy or not, type of products promoted, sound or not, full page mayhem or not. That sort of differentiations. Normally adds on nu.nl aren’t this annoying so something might have gone wrong there.
  • The developer or company developing the banner. Perhaps there’s a tight deadline. Perhaps technical knowledge is lacking. Maybe they just don’t care…
  • The advertiser, in this case T-Mobile. Bottom line is: they want to get visitors to their site. But perhaps reputation might be a consideration. I think in most cases that the people reviewing a banner proposol don’t have the knowledge to determine that a banner has these unwanted technical side-effects. Or the prototype presented doesn’t show the problems.

So somewhere in the process things go wrong, be it a lack of knowledge or a lack of interest for the end-user. Sadly the result is a lack of quality having bad usability as a consequence.

To conclude this criticism in a more positive and constructive fashion I’ve made a quick css proof of concept showing that it’s perfectly possible to achieve the layout while preserving click access to the underlying site.

Bottom aligned banner proof of concept

It’s positioning is now done by using css position:absolute but could just as well have been javascript. The demo took about 15 minutes to make while watching tv. I haven’t tested it on IE6 so expect about 2 hours needed for that but even then development time seems reasonable. The advertisment html part is displayed below.

<div id="banner" style="background-color:purple;position:fixed;bottom:0;width:100%;height:80px;">
	<div id="bannerCenter" style="width:760px;height:80px;position:relative;margin:0 auto;background-color:red;">
		<div id="phone" style="position:absolute;width:100px;height:160px;left:660px;top:-100px;background-color:#666;z-index"100;">
		</div>
	</div>
</div>
</body>

Of course the real world is more complicated than can be described in a short article but it’s obvious that the examined banner is sub-par. In my opinion it would be wise, or at least nice, to take the user a bit more seriously.

Jumping in and out of jQuery land

Tibo BeijenThursday, April 2nd, 2009
jumping-in-and-out-of-jquery-land

Recently I started using jQuery in some projects. In past projects I have mainly been using Prototype and the fact that jQuery also has a $() function made me feel at home right away. That same fact put me a bit off-guard as both functions are in fact quite different:

  • Prototype extends the selected HTML node with added functionality and returns it. Argument should be a HTML node or element id.
  • jQuery selects the HTML node (or nodes) and stores the selection in a jQuery object, which then is returned. Argument should be a css-like selector.

So, as opposed to Prototype, jQuery’s $() method can select a single element as well as a collection of elements. The existence of Prototype’s $$() function also kind of suggests that Prototype’s $() doesn’t do that. And… when passing just an id to jQuery’s $() (e.g. $(‘myDiv’)) it is discovered soon enough that nothing is selected but air.

By using jQuery’s $() functionwe’re leaving the DOM-zone and enter jQuery land. Although jQuery can do a lot, situations might occur where one needs to get the ‘real’ DOM elements. For instance, to pass them as argument to components that don’t talk jQuery. Luckily it’s just as easy to go back, by using the get() accessor.

Some simplified HTML code example boxes:

<div class="codeBox">
    <a href="#">copy to clipboard</a>
    <code>Some code</code>
</div>
<div class="codeBox">
    <a href="#">copy to clipboard</a>
    <code>More code</code>
</div>

Accompanied by the following javascript:

$(document).ready(function(){
    initCodeBox();
});
 
function initCodeBox()
{
    $('.codeBox a').bind('click',function() {
        var htmlNode = $(this).siblings('code').get(0);
        if (htmlNode) copyContentsToClipboard(htmlNode);
        return false;
    });
}
 
function copyContentsToClipboard(htmlNode)
{
        // js selecting the text contents of a DOM node, simplified to: 
    alert(htmlNode.innerHTML);
}

It’s clear that, as long as existing code doesn’t conflict with the $() function, it’s very easy to start using jQuery in existing projects.

Internet Explorer 8

Tibo BeijenFriday, March 20th, 2009
internet-explorer-8

Yesterday Internet Explorer 8 is released. I consider that a good things as it will move more people farther away from the severe case of release abuse called IE6. Improvements include integrated developer tools for css analysis and script profiling and debugging.

And there is ‘Compatibility View’. Developers can specify, by adding a specific meta tag, that IE7 rendering should be used. There seem to be some tricky aspects related to Compatibility View:

  • It’s not 100% compatible with the ‘real’ IE7
  • For intranets IE8 will behave differently, using smart defaults based on zone evaluation. That by itself sounds alarming. What it means is that Microsoft (and sadly they’re right) assumes that a lot of intranets, also called line of business applications, will malfunction when confronted with a new browser.

The latter will be something to take into account when developing and testing intranets. Another concern I heard about (and share) is that if a lot of developers will start using Compatibility View, a lot of bad practices will stick around and development for IE as a whole will ‘freeze’. Instead of move forward to a more standards compliant level.

As IE6 isn’t dead yet there are now three IE versions to test for. Microsoft offers free downloadable virtual machines with IEx installed as a solution. Virtualization is ‘hot’ but some might find Microsoft’s solution a bit of a hassle. IETester looks like a nice alternative (haven’t tried it yet) altough it seems to require Vista.

SQL injection & the Kaspersky hack

Tibo BeijenWednesday, February 11th, 2009
sql-injection-the-kaspersky-hack

Last week I read an article on webwereld titled ‘2008 was year of the SQL injection attack‘. It was based on an article with the same title on networkworld.com. Apparently SQL injection has taken over the lead from XSS. Not surprisingly the first user-comment stated that almost 100% of the exploits were certainly in PHP applications written by would-be programmers. With things so obvious it’s of course unneccessary to provide factual data backing up such a statement. So, nothing to win in that discussion. Three days ago news came that a customer database of Kaspersky was hacked. By using SQL injection. On a PHP website. Could commenter X be right?
(more…)