July 22, 2013

How to prevent Zend Framework 1 from resolving a controller name with a dot on its end?

Artem Gordinsky’s Question:

I have a website that runs on Zend Framework 1.12. It has a controller named ‘users’. When I enter its name incorrectly — http://mywebsite/userss — I rightfully get an error saying that such controller does not exist. When I add a dot to the end of its name, however:
http://mywebsite/users., an error says that a viewscript called users./index.phtml does not exist. Interesting thing is, it still gets the controller (users) correctly.

I have two questions regarding this matter:

  1. How and why does it ignore a dot at the end, and still gets a controller correctly?
  2. Is there a way to reject such controller names, without any modifications to the framework’s core?

Excellent question, but to answer this we have dig the source of Zend Framework and initially back To 2007, a function _formatName() was specially designed to remove such anomalies from the URL name. May be it was earlier than this but I don’t know that.

This particular piece is from Zend Framework 0.1.4 (Historic Right??) 🙂

protected function _formatName($unformatted)
{
    $unformatted = str_replace(array('-', '_', '.'), ' ', strtolower($unformatted));
    $unformatted = preg_replace('[^a-z0-9 ]', '', $unformatted);
    return str_replace(' ', '', ucwords($unformatted));
}

Here you see -, _, and . removed on the very first step.

Even today, this function is set to remove - and . but not the _

Here is current Zend Framework 1.x version of that function

protected function _formatName($unformatted, $isAction = false)
{
    // preserve directories
    if (!$isAction) {
        $segments = explode($this->getPathDelimiter(), $unformatted);
    } else {
        $segments = (array) $unformatted;
    }

    foreach ($segments as $key => $segment) {
        $segment = str_replace($this->getWordDelimiter(), ' ', strtolower($segment));
        $segment = preg_replace('/[^a-z0-9 ]/', '', $segment);
        $segments[$key] = str_replace(' ', '', ucwords($segment));
    }

    return implode('_', $segments);
}

Just like before the URI Segment is clean out in this line

$segment = str_replace($this->getWordDelimiter(), ' ', strtolower($segment));

The function getWordDelimeter() returns an array of array('-', '.');[line] thus removing them first thing in the URL, which answers your first question. About the second question, you can modify this line and remove the . from it.

protected $_wordDelimiter = array('-', '.');

After this the Despatcher will no longer find the controller or any URI component with . on it.

...

Please fill the form - I will response as fast as I can!