Introducing the bane of my existence – PHP’s magic_quotes_gpc.

I won’t bore you with the details suffice to say that this is one of PHP’s greatest failings and I cannot wait until the world adopts PHP6 and this awful blight is removed forever. Until then, we’ll just have to deal with it.

Now, there are various ways of disabling this “feature” as outlined here but what if that isn’t an option? My particular host of choice, while being excellent in every other regard, has this little blighter enabled and runs PHP as a CGI via the suExec module. This means no php_flag or php_value entries in the .htaccess file and the current implementation of allowing custom php.ini files is totally broken (server php.ini items do not cascade through to the custom one, meaning paths are wrong, extensions aren’t loaded, etc). This prompted me to implement something in code which is what I’ll be sharing with you today.

The code solution to magic quotes is to use stripslashes(). The simplest way of getting this into the Zend Framework is to create a filter.

class MoreCowbell_Filter_StripSlashes implements Zend_Filter_Interface
{
    public function filter($value)
    {
        return get_magic_quotes_gpc() ? $this->_clean($value) : $value;
    }
 
    protected function _clean($value)
    {
        return is_array($value) ? array_map(array($this, '_clean'), $value) : stripslashes($value);
    }
}

This filter allows us to process not only strings but array values as well. Note that the filter only activates if magic quotes is enabled.

All my forms extend my own custom Zend_Form extension which simply provides some shortcuts to my preferred decorator scheme. I’ll add some extra shortcuts for the new filter.

class MoreCowbell_Form extends Zend_Form
{
    public $elementDecorators = array(
        'ViewHelper',
        'Description',
        array('Label',   array('requiredSuffix' => ' *')),
        array('Errors',  array('placement' => 'PREPEND')),
        array('HtmlTag', array('tag' => 'li'))
    );
 
    public $buttonDecorators = array(
        'ViewHelper',
        array('HtmlTag', array('tag' => 'li'))
    );
 
    public $groupDecorators = array(
        'FormElements',
        array('HtmlTag', array('tag' => 'ol')),
        'Fieldset'
    );
 
    // Configure path to custom plugins
    public $elementPrefixPaths = array('filter' => array(
        'prefix' => 'MoreCowbell_Filter',
        'path'   => 'MoreCowbell/Filter'
    ));
 
    // Shortcut to default element filters
    public $elementFilters = array(
        'StripSlashes'
    );
 
    public function loadDefaultDecorators()
    {
        $this->setDecorators(array(
            'FormElements',
            'Form'
        ));
    }
}

All that’s left to do is assign the appropriate configuration settings in your forms and all your input data will be purged of the magic quotes evil. Here’s an overly simple example of a blog entry form.

class My_Blog_Form extends MoreCowbell_Form
{
    public function init()
    {
        $this->addElement('text', 'blog_title', array(
            'label'      => 'Title',
            'required'   => true,
            'prefixPath' => $this->elementPrefixPaths,
            'decorators' => $this->elementDecorators,
            'filters'    => $this->elementFilters
        ))->addElement('textarea', 'blog_post', array(
            'label'      => 'Post',
            'required'   => true,
            'rows'       => 5,
            'cols'       => 10,
            'prefixPath' => $this->elementPrefixPaths,
            'decorators' => $this->elementDecorators,
            'filters'    => $this->elementFilters
        ))->addElement('submit', 'submit_btn', array(
            'label'      => 'Submit',
            'decorators' => $this->buttonDecorators
        ))->addDisplayGroup(
            array('blog_title', 'blog_post', 'submit_btn'),
            'blog',
            array(
                'legend'     => 'Blog Entry',
                'decorators' => $this->groupDecorators
            )
        );
    }
}