ZF-6869: `Zend_Application::mergeOptions` can fail to merge sub-arrays of options with differing cases of keys

Description

Zend Framework version: 1.8.4-minimal PHP version: 5.2.10 OS: Windows 2000 Service Pack 4

This concerns the options-retrieval part of constructing a {{Zend_Application}} object.

It is important to be able to specify options both in the {{application.ini}} file as well as in the second argument to the {{Zend_Application}} constructor. This is because the INI file can contain just the options, such as paths, that potentially depend on server configuration, and the options array can contain the options that do not (like the file extension of layout scripts).

Currently, however, one has to be careful to use the capitalization on keys as they appear the INI file, or else {{mergeOptions}} can fail to merge the INI options into the options array properly. This is a bug because option keys are mostly processed case-insensitively, so {{mergeOptions}} should be able to merge INI options into the options array regardless of key case.

I will attach a minimal test case which demonstrates this. {{index.php}} constructs a {{Zend_Application}}, and {{echo}} s its options. With the buggy behavior, you should see:


Array
(
    [config] => C:\Program Files\Apache Software Foundation\HTTPD\htdocs\mintest\application/configs/application.ini
    [resources] => Array
        (
            [Layout] => Array
                (
                    [viewSuffix] => tpl
                )

            [frontController] => Array
                (
                    [controllerDirectory] => C:\Program Files\Apache Software Foundation\HTTPD\htdocs\mintest\application/controllers
                    [throwExceptions] => 1
                )

            [layout] => Array
                (
                    [layoutPath] => C:\Program Files\Apache Software Foundation\HTTPD\htdocs\mintest\application/layouts
                )

        )

    [phpSettings] => Array
        (
            [display_startup_errors] => 1
            [display_errors] => 1
        )

    [includePaths] => Array
        (
            [library] => C:\Program Files\Apache Software Foundation\HTTPD\htdocs\mintest\application/../library
        )

    [bootstrap] => Array
        (
            [path] => C:\Program Files\Apache Software Foundation\HTTPD\htdocs\mintest\application/Bootstrap.php
            [class] => Bootstrap
        )

)

Notice that the 'resources' option has a 'Layout' and 'layout' key. Commenting out the {{echo}} line, and uncommenting the "run" line results in a Fatal Error due to the 'layout' array being ignored.

If you change the 'L' in 'Layout' on line 22 of {{index.php}} to 'l', then the {{echo}} line shows:


Array
(
    [config] => C:\Program Files\Apache Software Foundation\HTTPD\htdocs\mintest\application/configs/application.ini
    [resources] => Array
        (
            [layout] => Array
                (
                    [viewSuffix] => tpl
                    [layoutPath] => C:\Program Files\Apache Software Foundation\HTTPD\htdocs\mintest\application/layouts
                )

            [frontController] => Array
                (
                    [controllerDirectory] => C:\Program Files\Apache Software Foundation\HTTPD\htdocs\mintest\application/controllers
                    [throwExceptions] => 1
                )

        )

    [phpSettings] => Array
        (
            [display_startup_errors] => 1
            [display_errors] => 1
        )

    [includePaths] => Array
        (
            [library] => C:\Program Files\Apache Software Foundation\HTTPD\htdocs\mintest\application/../library
        )

    [bootstrap] => Array
        (
            [path] => C:\Program Files\Apache Software Foundation\HTTPD\htdocs\mintest\application/Bootstrap.php
            [class] => Bootstrap
        )

)

{{index.php}} with the "run" line shows: h1. index

(as expected)

After applying the patch (that I will also attach), using either 'Layout' or 'layout' as they key in the options array produces the expected output.

{{Zend_Application_Resource_ResourceAbstract}} and {{Zend_Application_Bootstrap_BootstrapAbstract}} need similar modifications, and a patch for each of the corresponding files will also be attached.

Note that the new implementation of {{mergeOptions}} that I have provided is somewhat inefficient, but it is the most compatible with code that is in the Zend Framework, as well as code that has already been written which relies on the case of options. For example, {{Zend_Application_Resource_View}} blindly passes the options that it receives to {{Zend_View::__construct}}, which requires that some option keys have capital letters (eg.: {{scriptPath}}). A filter could be created that would translate the lower-cased version to the expected form, but, again, code for application resources that has already been written, that relies on the fact that {{mergeOptions}} does not lower-case all option keys, will break.

Comments

The syntax of code blocks is not PHP.

Can you please test against 1.8.2? I believe this may have been fixed already.

This is still a bug in 1.8.2. I downloaded ZF 1.8.2, and there are no changes in {{Application.php}} from 1.8.1.

Update: Tried in ZF 1.8.4

Actually... closing this as "won't fix".

Currently, most classes have case-sensitive keys (but will often ignore the first character of the key, particularly if a setter for the key exists). As a result, this makes merging keys that do not have matching case difficult at best, and problematic at worst (if we flatten the key to make it easier to merge, which version do we keep? and if we keep the wrong version, will the functionality continue to work?)

It's up to the developer to ensure that the keys between configuration files and/or options arrays are consistent.