Nov 10, 2015

"Notice: Undefined index: und in eval() (line . . . . . /modules/php/php.module(80) : eval()'d code)"

On my local instance of a Drupal 7 site, I'd get warnings like the following on almost every page for a custom content type called Poem.

Notice: Undefined index: und in eval() (line 12 of /var/www/html/power-poetry/modules/php/php.module(80) : eval()'d code).

Although most probably innocuous, these warnings were also being logged numerous times in the system log, cluttering it up and making it harder to spot other, significant messages. It was enough of an annoyance that I decided to fix it.

I was able  to track this to a snippet of PHP code that is used in a Drupal block of ours. The code is part of the block's Visibility Settings. It determines if the current Poem being rendered satisfies certain criteria or not. If so, the block is made visible.

The offending line turned out to be

  $slam_id = $current_slam['und'][0]['target_id'];

The variable $current_slam was often an empty array. So by replacing the line with an additional check, the PHP warnings disappeared.

  if (!empty($current_slam)) {
    $slam_id = $current_slam['und'][0]['target_id'];
  }

The key to finding this quickly was remembering that we have this user-supplied snippet of code that needs to be evaluated at runtime

  - - - - -

While debugging, I wanted to see the type and the value of the variable $current_slam. The following worked to output it to the system log.

  watchdog('debug', print_r($current_slam, TRUE), array(),
           WATCHDOG_NOTICE);

The second parameter to print_r() determines what kind of return value the function passes back. By default, print_r() returns its status. But by setting the second param to TRUE, the return value is the output string instead.

  - - - - -

The site is hosted on Pantheon, which provides this status message:

  • PHP Filter: PHP Filter is enabled! Executable code should never be stored in the database, and support for this feature was removed in Drupal 8 - https://drupal.org/node/1203886
    Remove all executable code from your content and move it to your codebase.

Source:

Remove the PHP module from Drupal core
https://drupal.org/node/1203886

5 comments:

  1. A few points perhaps of value:
    - isset() rather than !empty() is the "standard" in the Drupal PHP community. For example:

    if (isset($current_slam['und'][0]['target_id'])) {
    $slam_id = $current_slam['und'][0]['target_id'];
    }

    - print_r is the "old school" way of getting debugging output from Drupal:

    echo '< pre >';
    print_r($some_var);
    echo('< /pre >);
    exit;

    The devel module's dsm() gives you the same kind of debugging output.

    I hope these are of value.

    ReplyDelete
  2. That's a great point about using isset().

    When I first read that, I thought it would still trigger a PHP warning since the parameter to isset() looks like an expression that needs to be evaluated.

    Not so! isset() is a language construct, not a function call. Its param can only be a variable.

    When I used isset() as Dee described, it also eliminated the warnings. Very nice, and it's a more robust approach since the param indexes all the way down to the actual variable of interest.

    ReplyDelete
  3. @Dee Unfortunately, for the particular use case of code that is evaluated for the purpose of determining the visibility of a block, the output from dsm()/dpm() disappears into the ether.

    Although not ideal, watchdog() writes to the system log and does work for this situation.

    Normally, I'd use a debugger. But I'm pretty skeptical it would kick in for code that is evaluated in this manner.

    ReplyDelete
  4. Thus the "exit()" in:

    echo '< pre >';
    print_r($some_var);
    echo('< /pre >);
    exit;

    ReplyDelete
    Replies
    1. Cool! print_r() followed by exit() does write its output to the page with nothing else after it. Good to know about this use of exit().

      Delete