Hello Support,
I have joomla 3.6.5 virtuemart 3.0.18.
I have upgraded my php version to 7 and since upgradation when I click on product on product listing page to get detail page I have got the following error.
0 - Cannot access property started with '\0'
Please help me to solve this issue. I have tried jumbo! solution on following post
http://forum.virtuemart.net/index.php?topic=133607.0
But its not work for me.
Please help.
Thanks
you can try VM3.2 -- test first!!
HI
I am having the same issue when update to php 7 on one site joomla 3.71 VM 3.22
The only workaround seems to be staying on php 5.6 which is not a good option
Does anyone have any fix for this yet or even a clue?
Thanks and Regards
Stuart
opn365.com
Does your site has products with multi-variants or child products?
Quote from: Jumbo! on May 18, 2017, 10:48:49 AM
Does your site has products with multi-variants or child products?
Yes - does that make a difference some way?
Quote from: opn365 on May 18, 2017, 04:37:41 AM
The only workaround seems to be staying on php 5.6 which is not a good option
PHP5.6 will receive security support until 31 Dec 2018
PHP7.0 will receive security support until 3 Dec 2018
So having to use 5.6 for longer while you solve the issue is a reasonable option.
See https://forum.virtuemart.net/index.php?topic=133607.0 I have had no issues with PHP7 and latest versions.
Try this.
Open - administrator/components/com_virtuemart/models/product.php
Find the following codes between lines 998 to 1006:
foreach ($attribs as $k=> $v) {
if (strpos($k, "\0")===0) continue;
if ('product_in_stock' != $k and 'product_ordered' != $k) {// Do not copy parent stock into child
if (strpos ($k, '_') !== 0 and empty($child->$k)) {
$child->$k = $v;
// vmdebug($child->product_parent_id.' $child->$k',$child->$k);
}
}
}
Replace above by:
foreach ($attribs as $k=> $v) {
if (strpos($k, "\0")===0) continue;
if ('product_in_stock' != $k and 'product_ordered' != $k) {// Do not copy parent stock into child
if (isset($parentProduct->$k) && strpos ($k, '_') !== 0 && empty($child->$k)) {
$child->$k = $v;
// vmdebug($child->product_parent_id.' $child->$k',$child->$k);
}
}
}
Save the file. Now check again.
I wonder that the problem is not catched by the
if (strpos($k, "\0")===0) continue;
above
Milbo, I might be wrong but, in my understanding you're checking for NULL character and you must have a strlen of 1 for this at least.
I don't believe it being reliable (in no language).
Checking via isset and empty checks variable set and empty checks for an empty string.
In some languages one can do if (strlen(var) + 0) to overcome some nasty hurdles being imposed by is NULL, is empty and the like.
It is a key, retrived before by get_object_vars, so it must be set. I wonder how to set an empty property to a class, I doubt that can work. The check for "\0" is for php7 to check if it is a protected or private property.
hm.
give such a construct a try, please:
$a = "";
$b = "\0";
echo "strlen a: " . strlen($a);
echo "strlen b: " . strlen($b);
Over here I get strlen a = 0, strlen b= 1.
edit:
C handles strings with \0 per automatic (NULL termination), PHP does not (AFAIR).
edit2:
You can find "mysterious" results with SQL in same relation as well when you don't use COALESCE.
The array which is used for the foreach is created by "get_object_vars". Try to create a attribute for an object, which is is an empty string. Imagine the code
$myObject->{}="TEST";
I doubt that can work.
But we could extend and write
if (empty($k) or strpos($k, "\0")===0) continue;
are you using a debian/linux server? If so, list the packages you have installed for php7.x.
dpkg -l | grep php7
Here is the list of my packages...
I remember when i moved to php7 i had issues, and i solved them by adding more packages (upgrade didnt install all the ones that were needed...
php7.0
php7.0-bz2
php7.0-cgi
php7.0-cli
php7.0-common
php7.0-curl
php7.0-fpm
php7.0-gd
php7.0-json
php7.0-mbstring
php7.0-mcrypt
php7.0-mysql
php7.0-opcache
php7.0-readline
php7.0-xml
just in case it helps...
There's something I "like" since very first days of PHP:
No version has reliable and complete documentation and with no version one can trust on it's compatibility to it's predecessor ... :'(
Any update can be an adventure forcing you to dive very deep. Therefore I'm happy to have Perl available most time.
Ah, forum works again (it had some 502 hickups)...
Ok, i fear there's a basic problem with $var is either null, empty or 0. ISSET seems to have nothing to do with it at first glance.
Didn't check in real detail now, but (if memory serves well) EMPTY should not return an error in case you try to access a private variable. It returns "true" in such a case. If it's a public string variable with value 0 it returns true as well.
There are some pitfalls with isset in PHP because i.e. in case get_object_vars returns a value instead of a var and __get is used internal by PHP isset returns false.
In my humble oppinion this behaviour is reason for working combination of empty and comparison of variable ($k in this case).
I doubt it's working reliable because when there is a private var you don't have anything to compare and current (not extended) implementation works correct like being designed:
No var -> no comparison.
Quote from: Milbo on May 25, 2017, 09:50:53 AM
But we could extend and write
if (empty($k) or strpos($k, "\0")===0) continue;
I just need to know if this construction removes the bug in php7. Your explanation support my idea :-) I like it more than the other. Jumbos idea has the disadvantage, that you cannot inherit values to children, which do not exist for the parent.
You can not inherit private and protected properties of parent products to children using get_object_vars() in any PHP version.
strpos($k, "\0")===0 check looks bit odd and hard coded to me.
It is better to ensure that we are inheriting to the public properties of the parent.
if(!property_exists($parentProduct, $k)) continue;
Here is a function which ensure correct conversions of object to array if you need to inherit every properties of the object.
function object_to_array($object)
{
$reflectionClass = new ReflectionClass(get_class($object));
$array = array();
foreach ($reflectionClass->getProperties() as $property)
{
$property->setAccessible(true);
$array[$property->getName()] = $property->getValue($object);
$property->setAccessible(false);
}
return $array;
}
But this is probably little too much considering the requirement we have here.
Quote from: Jumbo! on May 26, 2017, 10:09:32 AM
You can not inherit private and protected properties of parent products to children using get_object_vars() in any PHP version.
It is anyway not intended. The version below php7 handles it different. There was no problem before.
Quote from: Jumbo! on May 26, 2017, 10:09:32 AM
strpos($k, "\0")===0 check looks bit odd and hard coded to me.
Imho the way you suggest yourself a time ago and I think I used it, because I found it on some php official page.
Quote from: Jumbo! on May 26, 2017, 10:09:32 AM
It is better to ensure that we are inheriting to the public properties of the parent.
if(!property_exists($parentProduct, $k)) continue;
Here is a function which ensure correct conversions of object to array if you need to inherit every properties of the object.
function object_to_array($object)
{
$reflectionClass = new ReflectionClass(get_class($object));
$array = array();
foreach ($reflectionClass->getProperties() as $property)
{
$property->setAccessible(true);
$array[$property->getName()] = $property->getValue($object);
$property->setAccessible(false);
}
return $array;
}
But this is probably little too much considering the requirement we have here.
Maybe not bad as general function, but I wonder about the $property->setAccessible(true); I would do a check if it is accessible, or?
Quote from: Jumbo! on May 26, 2017, 10:09:32 AM
You can not inherit private and protected properties of parent products to children using get_object_vars() in any PHP version.
strpos($k, "\0")===0 check looks bit odd and hard coded to me.
It is better to ensure that we are inheriting to the public properties of the parent.
if(!property_exists($parentProduct, $k)) continue;
foreach ($attribs as $k=> $v) {
if (!property_exists($parentProduct, $k)) continue;
if ('product_in_stock' != $k and 'product_ordered' != $k) {// Do not copy parent stock into child
if (strpos ($k, '_') !== 0 and empty($child->$k)) {
$child->$k = $v;
// vmdebug($child->product_parent_id.' $child->$k',$child->$k);
}
}
}