I was curious whether it will work with PHP 7 the latest version of Magento Community Edition. When I write this article the latest released version is 1.9.2.1. As I expected, Magento has crashed with an ugly error message like:
Fatal error: Uncaught Error: Function name must be a string in ... app\code\core\Mage\Core\Model\Layout.php:555 ...
This error was easy to fix because the problem was in the following line:
$out .= $this->getBlock($callback[0])->$callback[1]();
Instead it should be:
$out .= $this->getBlock($callback[0])->{$callback[1]}();
Since it is not recommended to edit the core files, we will override them, which means that we will create the very similar structure of the core files in app/code/local. Example if we want to override app/code/core/Mage/Core/Model/Layout.php, then we will copy this file into app/code/local/Mage/Core/Model/Layout.php. Magento will automatically include what is in the app/code/local folder. Despite this solution works, this can be considered only a temporary solution until a fixed Magento / PHP 7 will be released. Overriding core files could be dangerous, problems could occur especially after upgrading Magento to a newer version.
This small change seemed to fix Magento, but I was wrong. While the frontend worked well, the backend did not log me in. In the meantime I had a lot of problems getting PHP and Apache configuration files ready. So I didn’t know whether my configuration is bad or simply the new PHP 7 RC1 does not like Magento.
Finally I found out the main reason why the login doesn’t work: despite the authentication of the backend user has happened and I was redirected back to the admin index, the user object was not saved into the session. Investigation was very difficult because currently there is no Xdebug for the unreleased PHP7. After another couple of hours of digging I’ve found out that in one of Magento’s abstract classes it was specified something like:
$this->_data = &$_SESSION;
So Magento just sets $this->_data as a reference to the $_SESSION. Hmm, maybe that thing does not work… And yes. First I just tried to use in the admin/session class instead of
$this->setUser($user);
this:
$_SESSION['admin']['user'] = $user;
then suddenly Magento logged me in. The next step was to make the session related functionality work all over Magento. For this I had to override Mage_Core_Model_Session_Abstract_Varien and had to change getData from:
public function getData($key='', $clear = false) { $data = parent::getData($key); if ($clear && isset($this->_data[$key])) { unset($this->_data[$key]); } return $data; }
to
public function getData($key='', $clear = false) { $data = $this->getSessionData($key); if ($clear && isset($_SESSION[$key])) { unset($_SESSION[$key]); } return $data; } public function getSessionData($key='', $index=null) { if (''===$key) { return $_SESSION; } $default = null; // accept a/b/c as ['a']['b']['c'] if (strpos($key,'/')) { $keyArr = explode('/', $key); $data = $_SESSION; foreach ($keyArr as $i=>$k) { if ($k==='') { return $default; } if (is_array($data)) { if (!isset($data[$k])) { return $default; } $data = $data[$k]; } elseif ($data instanceof Varien_Object) { $data = $data->getData($k); } else { return $default; } } return $data; } // legacy functionality for $index if (isset($_SESSION[$key])) { if (is_null($index)) { return $_SESSION[$key]; } $value = $_SESSION[$key]; if (is_array($value)) { //if (isset($value[$index]) && (!empty($value[$index]) || strlen($value[$index]) > 0)) { /** * If we have any data, even if it empty - we should use it, anyway */ if (isset($value[$index])) { return $value[$index]; } return null; } elseif (is_string($value)) { $arr = explode("\n", $value); return (isset($arr[$index]) && (!empty($arr[$index]) || strlen($arr[$index]) > 0)) ? $arr[$index] : null; } elseif ($value instanceof Varien_Object) { return $value->getData($index); } return $default; } return $default; }
then I had to create the __call magic method to override the parent class’ behavior:
public function __call($method, $args) { if (substr($method, 0, 3) == "has") { $key = $this->_underscore(substr($method,3)); return isset($_SESSION[$key]); } return parent::__call($method, $args); }
and then I’ve added the modified setData, unsetData and _addFullNames methods:
public function setData($key, $value=null) { $this->_hasDataChanges = true; if(is_array($key)) { $_SESSION = $key; $this->_addFullNames(); } else { $_SESSION[$key] = $value; if (isset($this->_syncFieldsMap[$key])) { $fullFieldName = $this->_syncFieldsMap[$key]; $_SESSION[$fullFieldName] = $value; } } return $this; } public function unsetData($key=null) { $this->_hasDataChanges = true; if (is_null($key)) { $_SESSION = array(); } else { unset($_SESSION[$key]); if (isset($this->_syncFieldsMap[$key])) { $fullFieldName = $this->_syncFieldsMap[$key]; unset($_SESSION[$fullFieldName]); } } return $this; } protected function _addFullNames() { $existedShortKeys = array_intersect($this->_syncFieldsMap, array_keys($_SESSION)); if (!empty($existedShortKeys)) { foreach ($existedShortKeys as $key) { $fullFieldName = array_search($key, $this->_syncFieldsMap); $_SESSION[$fullFieldName] = $_SESSION[$key]; } } }
It has worked for me. Maybe it can be fixed with some php.ini setting also, but I really don’t see a reason to disable passing variables by reference. We will find out shortly if PHP 7 RC2 solves this problem.
So, to sum it up:
– the problem with the “fatal error. function name must be a string” can be fixed by overriding Mage_Core_Model_Layout
– the other problem: getData / setData / unsetData methods does not write into the session, which causes the admin login problem. It can be fixed by overriding Mage_Core_Model_Session_Abstract_Varien.
Happy patching!
p.s. In the meantime the PHP team released the PHP 7 RC2, which has the same behavior as the RC1. It seems that the problem is already reported and it is under discussion by the PHP team.
p.s.2 In PHP 7 RC3 the session-related problem has been solved, so the only thing you need is to fix Layout.php.
p.s.3 If you override Varien.php with this fix, while using the final version of PHP 7, you will meet some serious problems in the frontend, the customers not being able to log in. So I repeat: don’t use it with the final releases of PHP 7!
Is there already any information available regarding php 7.0 RC5 compatibility?
I didn’t test it yet, but I expect a behavior similar with RC3.
Getting the following issue with PHP 7.0 RC5 and Magento EE 1.14.2.2 with unable to login to the admin!
2015-10-28T11:58:28+00:00 ERR (admin): /index.php/admin/index/index/key/98a41a7863640caeffed2dac80ca517200fd55b44a79ae3219f25db01fc1b990/
REQUEST: POST|{“form_key”:”aB95vknHQsxFsIBn”,”login”:{“username”:”xxx”,”password”:”xxx”},”dummy”:””}
TIME: 0.597522s
ADDRESS: 127.0.0.1
USER AGENT: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:41.0) Gecko/20100101 Firefox/41.0
FILE: vax-uk/app/code/core/Mage/Core/functions.php:247
Recoverable Error: session_regenerate_id(): Failed to create session ID: user (path: ) in /Users/xxx/Sites/xxx/app/code/core/Mage/Core/Model/Session/Abstract/Varien.php on line 493
I’ve met these days a similar problem while trying to save the session into the database instead of the file system. Try to change this setting in local.xml and see if it works.
A PHP 7 incompatibility in Zend_XmlRpc_Server has been fixed in Zend Framework 1.12.12
All versions prior CE 1.9.2.2 / EE 1.14.2.2 use an older version of Zend Framework
https://magento.stackexchange.com/questions/74008/is-magento-ready-for-php-7/
Here’s a patch for that core file edit, might be easier:
…or an extension if you don’t want to edit core files:
On my install the totals are incorrect in PHP 7 compared to PHP 5. I had the same issue with HHVM which was eventually fixed through zend compatibility flag.
Hey php 7.0 final is out!
https://secure.php.net/archive/2015.php
together with some new promising looking benchmarks:
http://talks.php.net/froscon15#/magentobench
(use concurrent client links at the bottom)
=> Are there already any experiences regarding “things to do for compatibility” of PHP 7.0 final in combination with magento 1.9.2.2 ?
I didn’t have time to test it yet. What I tried until now is PHP 7 final with Magento 2. And it works! I’ll try also with 1.9.x later and will come back with a reply.
7 more places identified to have a look at https://magento.stackexchange.com/questions/74008/is-magento-ready-for-php-7/
this one should fix all known problems regarding compatibility of 1.9.2.2 and PHP 7.0 final
https://github.com/Inchoo/Inchoo_PHP7