Cry Havoc and Release the Dogs of War — PHP 7.1.5 Upgrade Gotchas

Login

Blog History

So just doing a Joomla 3.7.1 to PHP7.1.5 upgrade.

I have Chronoforms v5 installed (https://www.chronoengine.com/downloads/chronoforms) which works brilliantly btw.

However on upgrade to PHP 7.1.5 and trying to save a form I got "0 Cannot use string offset as an array" in the chronoforms admin area and in the apache logs:

[Wed Jun 07 12:51:31.685533 2017] [php7:warn] [pid 29833] [client 10.11.12.8] PHP Warning: Illegal string offset 'html_4' in /home/website/libraries/cegcore/libs/arr.php(61) : eval()'d code on line 1, referer: http://www.example.com/administrator/index.php?option=com_chronoforms5&act=edit&id=2
[Wed Jun 07 12:51:31.685539 2017] [php7:warn] [pid 29833] [client 10.11.12.8] PHP Warning: Cannot assign an empty string to a string offset in /home/website/libraries/cegcore/libs/arr.php(61) : eval()'d code on line 1, referer: http://www.example.com/administrator/index.php?option=com_chronoforms5&act=edit&id=2

So the pertinent thing from the logs is as follows. Notice that it is referring to eval()'d code. Apparently eval() is evil if you use it with user input as it can allow malicious code to be run. Not sure if it is bad in the case

Illegal string offset 'html_4' in /home/website/libraries/cegcore/libs/arr.php(61) : eval()'d code on line 1

Cannot assign an empty string to a string offset in /home/website/libraries/cegcore/libs/arr.php(61) : eval()'d code on line 1

The fix for this is to avoid using eval and use a function to assign the value as follows:

function assign(&$array, $keys, $value) {
    $last_key = array_pop($keys);
    $tmp = &$array;
    foreach($keys as $key) {
        if(!isset($tmp[$key]) || !is_array($tmp[$key])) {
            $tmp[$key] = array();
        }
        $tmp = &$tmp[$key];
    }
    $tmp[$last_key] = $value;
    unset($tmp);
}

assign($start_array, $indexes, $value);

 

The fix within ChronoForms is edit arr.php on line ~60 follows:

public static function setVal($array, $indexes, $value) {
    if (is_array($array)) {
      // eval('$array["'.implode('"]["', $indexes).'"] = $value;');
      self::assign($array, $indexes, $value);
    }
    return $array;
}


private static function assign(&$array, $keys, $value) {
    $last_key = array_pop($keys);
    $tmp = &$array;
    foreach ($keys as $key) {
        if (!isset($tmp[$key]) || !is_array($tmp[$key])) {
            $tmp[$key] = array();
        }
        $tmp = &$tmp[$key];
    }
    $tmp[$last_key] = $value;
    unset($tmp);
}

 

This is the stuff I wrote to test the bug:

<?php

$start_array = [
  "Form" => [
  "extras" => [
    "DNA" => [
      'submit' => '',
      'load' => '']
  ]]];

print_r ($start_array);

$value = "hi";


$first_array = $start_array;

print "This will assign the remaining array values and works\n";
$first_array["Form"]["extras"]["DNA"]["submit"] = [];
$first_array["Form"]["extras"]["DNA"]["submit"]["check_honeypot_8"]["success"] = $value;

print_r($first_array);


$second_array = $start_array;

print "This will throw an error because submit = '' (is an empty string not an array)\n";

$second_array["Form"]["extras"]["DNA"]["submit"]["check_honeypot_8"]["success"] = $value;


Credit where credit is due I found the fix here https://stackoverflow.com/questions/7465043/how-to-dynamically-access-values-in-a-variably-multidimensional-array

I also posted this on the Chronoforms Forums https://www.chronoengine.com/forums/posts/t102271/cannot-use-string-offset-as-an-array.html but that has been deleted as I think they are wanting people to upgrade

0 Comments

Submit a Comment

Your email address will not be published. Required fields are marked *

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

The reCAPTCHA verification period has expired. Please reload the page.