Forums / Bug Reports / PHP 5.3.1 - Changing Quantity in Cart - Error in zen_get_prid

PHP 5.3.1 - Changing Quantity in Cart - Error in zen_get_prid

Views: 3,847

Results 1 to 8 of 8
7 Jan 2010, 7:00 PM
#1
decartwr avatar

decartwr

New Zenner

Join Date:
Feb 2005
Location:
Syracuse, New York, USA
Posts:
39
Plugin Contributions:
0

PHP 5.3.1 - Changing Quantity in Cart - Error in zen_get_prid

After upgrading to PHP 5.3.1 and installing the recommended 5.3 patches (on a 1.3.8a ZC), I am getting an error "explode() expects parameter 2 to be string" in function "zen_get_prid" in functions/functions_general.php.

This happens when I go into my shopping cart and change the quantity on an item and click "update".

The offending line of code is:

$pieces = explode(':', $uprid);

The problem is that $uprid is an array, not a string. $uprid is a parameter to the function, which is being called from the "in_cart_mixed" function in classes/shopping_cart, which in turn is called from function "actionUpdateProduct" in classes/shopping_cart.

Inspecting the code, the source of the array is $_POST['products_id']. I haven't worked back any farther than this.

I applied the following work-around:

Just before the above-shown line of code, I added:

  	if ( is_array( $uprid ) && (count( $uprid ) === 1) )
  		$uprid = $uprid[ 0 ];

This has the effect of liberating the string from within the array. This works because $uprid in fact contains a single string, it's just stuffed inside an array. So I check for that precise case, and liberate the string from within the array.

This eliminates the error and seems to function correctly, but I consider this a very temporary work-around. The right solution surely lies in the functions that call "zen_get_prid".

22 Jan 2010, 6:43 PM
#2
hephaestus avatar

hephaestus

New Zenner

Join Date:
Nov 2009
Posts:
20
Plugin Contributions:
0

Re: PHP 5.3.1 - Changing Quantity in Cart - Error in zen_get_prid

decartwr:

The problem is that $uprid is an array, not a string. $uprid is a parameter to the function, which is being called from the "in_cart_mixed" function in classes/shopping_cart, which in turn is called from function "actionUpdateProduct" in classes/shopping_cart.

Inspecting the code, the source of the array is $_POST['products_id']. I haven't worked back any farther than this.

Interesting. I started looking at "actionUpdateProduct" because I was seeing inconsistencies between the way it handles product quantity maxima for "mixed" products, and the way those maxima are handled by "actionAddProduct."

If you look at all the other occurrences of $_POST['products_id'] in "actionUpdateProduct," you'll see that they have an additional array subscript ("[$i]") attached to them, because "actionUpdateProduct" is iterating through all the line-items in the shopping cart. That "[$i]" subscript is missing from the line of code you've identified, and so the whole (sub-)array is being passed to in_cart_mixed(), rather than it's $i'th element (which is the string).

The upshot of this for me (and I think for anyone running an earlier version of PHP than you) is that this call to in_cart_mixed() always returns 0, and so up to the maximum number of any variant of the product can be added to the cart (as though "mixed" were off).

I had thought that simply adding the missing subscript would fix things (i.e., cause "actionUpdateProduct" to start treating quantity maxima consistently with "actionAddProduct."

But no! The behavior is even nuttier after that "fix." For example, if my product quantity maximum for a given product is 10, and I have in the cart 3 units with attribute mix "A", and 4 units with attribute mix "B", I can't add another unit of either flavor via the quantity boxes on the cart page.

The problem is that there's some "double-counting" going on:

First we have:

$add_max = zen_get_products_quantity_order_max($_POST['products_id'][$i]);  // product quantity maximum
$cart_qty = $this->in_cart_mixed($_POST['products_id'][$i]); // how many (of the current flavor) currently in the cart
$new_qty = $_POST['cart_quantity'][$i]; // number requested (i.e., the number in the quantity box) 

Then farther down we have:

if (($new_qty + $cart_qty > $add_max) and $add_max != 0) {
    $adjust_max= 'true';
    $new_qty = $add_max - $cart_qty;
}

which is just wrong. Why are $new_qty and $cart_qty being added together? The number requested is $new_qty, not the sum of the two. The reason this appeared to "work" in the past is because $cart_qty was always 0!

My first instinct on how to fix this was simply to change the test to:

if (($new_qty > $add_max) and $add_max != 0) {
   // ...

but that doesn't quite solve it either, and I've run out of time today to continue futzing with it.

I'll come back to this over the weekend and try to figure it out, but if anyone else can see what the right answer is before then, please post it!

Best,

Michael

22 Jan 2010, 6:58 PM
#3
gjh42 avatar

gjh42

Black Belt

Join Date:
Jul 2005
Location:
Upstate NY
Posts:
21,876
Plugin Contributions:
8

Re: PHP 5.3.1 - Changing Quantity in Cart - Error in zen_get_prid

The intention of the ($new_qty + $cart_qty > $add_max) test is to not allow the customer to add more than the stipulated quantity to their cart in total. If the new request would bring the total to more than that maximum, the request is reduced to keep within the max.

22 Jan 2010, 7:21 PM
#4
hephaestus avatar

hephaestus

New Zenner

Join Date:
Nov 2009
Posts:
20
Plugin Contributions:
0

Re: PHP 5.3.1 - Changing Quantity in Cart - Error in zen_get_prid

gjh42:

The intention of the ($new_qty + $cart_qty > $add_max) test is to not allow the customer to add more than the stipulated quantity to their cart in total. If the new request would bring the total to more than that maximum, the request is reduced to keep within the max.

But if $cart_qty is the quantity already in the cart (gotten from the call to in_count_mixed()) and $new_qty is the numeric value appearing in the quantity box (i.e., the number of units requested), why is it correct to add them together?

I can see how this could be right if $new_qty were an incremental value (i.e., the number of additional units to add to the cart), but its value is taken directly from $_POST['cart_quantity'][$i], which is just the number in the quantity box.

From the generated HTML:

<input type="text" name="cart_quantity[]" ... />

I don't see any mechanism by which the value provided by this text box gets transformed from a count to an increment...

What am I missing?

23 Jan 2010, 6:46 PM
#5
gjh42 avatar

gjh42

Black Belt

Join Date:
Jul 2005
Location:
Upstate NY
Posts:
21,876
Plugin Contributions:
8

Re: PHP 5.3.1 - Changing Quantity in Cart - Error in zen_get_prid

I haven't studied the code there so I can't say how it does work, but it is clearly intended to work as I described:

$cart_qty = $this->in_cart_mixed($_POST['products_id'][$i]); // how many (of the current flavor) currently in the cart

$_POST['cart_quantity'][$i]

is not the same as

$_POST['products_id'][$i]

and $cart_qty is not the same as $cart_quantity.

24 Jan 2010, 3:57 AM
#6
hephaestus avatar

hephaestus

New Zenner

Join Date:
Nov 2009
Posts:
20
Plugin Contributions:
0

Re: PHP 5.3.1 - Changing Quantity in Cart - Error in zen_get_prid

gjh42:

I haven't studied the code there so I can't say how it does work, but it is clearly intended to work as I described

Oh, no doubt. But good intentions don't necessarily imply correct code! :wink:

The code as currently written only works (or rather, appears to work) because, for PHP version < 5.3.1, $cart_qty is always 0, which happens because a bad argument is being passed to in_cart_mixed() on the right-hand-side of the assignment. As long as $cart_qty is 0, the test:

($new_qty + $cart_qty > $add_max)

is equivalent to the test:

($new_qty > $add_max)

which turns out to be right for products without attributes, or for products that have attributes and for which "mixed" is false.

But once we start passing a proper product ID to in_cart_mixed(), and getting back a meaningful value for $cart_qty, the test that actually appears in the code is always wrong. Always. It would be right (again, for non-"mixed" products), if $new_qty represented the number of units to be added to the cart, but that's not what it represents. It represents the numeric value that appears in the quantity box at the moment the user clicks the "update" button.

Consider the case in which there's one product (ID) in the cart, and the user makes no change whatsoever to the number in the quantity box. It was n when the shopping cart page was initially rendered, and it's n when the user clicks the button. But the test will end up comparing 2**n* (i.e., n+n) to $add_max. And if n > $add_max/2, the user gets an error message even though the quantity wasn't altered!

The upshot of all this is that the correct calculation really does depend on knowing the number of units being added to the cart, and not just the value of the quantity box at the time the button was clicked. And to determine that value, for a "mixed" product having a particular combination of attribute values, we need to know how many units having that particular combination are currently in the cart, as well as the total number of units of that product (irrespective of attribute combinations).

So here's my latest whack at addressing these issues (new/changed code in red):

$add_max = zen_get_products_quantity_order_max($_POST['products_id'][$i]);
$cart_qty = $this->in_cart_mixed($_POST['products_id'][$i]); // How many of all flavors of this product already in the cart
$item_qty = $this->get_quantity($_POST['products_id'][$i]); // How many of just this flavor of this product already in the cart
$new_qty = $_POST['cart_quantity'][$i]; // Number in quantity box at click time
$add_qty = $new_qty - $item_qty; // Number of units of the current flavor to add

// ...

if (($add_max == 1 and $cart_qty == 1)) {

// do not add
$adjust_max= 'true';

} else {
// adjust quantity if needed
if ($add_qty > 0 and ($cart_qty + $add_qty > $add_max) and $add_max != 0) {
$adjust_max= 'true';
$new_qty = $new_qty - ($cart_qty + $add_qty - $add_max);

}
// ...

The main test has now been rewritten to explicitly use $add_qty in place of $new_qty. The additional conjunct, $add_qty > 0, is in there to keep the code from delivering surprises to the user by trying to adjust quantities that the user didn't change. There's another outstanding, related issue that these modifications don't address: because the overall logic of actionUpdateCart() works by iterating through the cart's line items, it gets fooled by quantity modifications that transiently violate the quantity constraints, even if the net change would satisfy the constraints.

Sorry. Don't try to parse that. Here's an example:

Let's say there's a "mixed" product with a quantity max of 10. In the first line-item of the cart we have 4 units of that product with attribute-combination "A," and in the second line-item we have 6 units with attribute-combination "B." Now, say we switch the values in the quantity boxes to indicate that we want 6 of flavor "A" and 4 of flavor "B." We want to still end up with a total of 10, which would satisfy the constraint. But because the function processes the line-items in order, it rejects the request to set the quantity of flavor "A" to 6, because that would lead to a (transient) total of 12 units, in violation of the constraint. In the second line-item, dialing the quantity back from 6 to 4 is okay, so we end up with 4 of "A" and 4 of "B."

I will probably end up fixing this outstanding issue at some point as well, but not likely very soon.

Cheers,

Michael

28 Dec 2010, 2:28 PM
#7
neekfenwick avatar

neekfenwick

New Zenner

Join Date:
Feb 2009
Posts:
101
Plugin Contributions:
0

Re: PHP 5.3.1 - Changing Quantity in Cart - Error in zen_get_prid

hephaestus:

So here's my latest whack at addressing these issues (new/changed code in red):
I'm using 1.3.8a and the code in red above seems to work well for me. I just wanted to say thanks for the above and offer one slight tweak. In order to leave entries in the cart alone when their quantity hasn't been touched, I added this if around the call to $this->add_cart():

if ($new_qty != $cart_qty) {

My situation is that I have an observer and some custom cart_actions that decorate $cart->contents entries, so as well as the old 'qty' attribute they hold special attributes that my observer code uses:

$contents[product_id] => array( 'qty' => 1, 'magic' => 'foobar')

If, while updating the cart contents, you allow the add_cart() call to go ahead, the 'magic' attribute is lost. I disallow changing the quantity for my decorated product entries, so I don't care that the decoration would be lost were the quantity to change, as that never happens for me.

This probably isn't good for people whose products may have changed in some other way, for example changing attributes, but I never have understood product attributes (damn, those docs and the GUI just make no sense at all) so all I care about it changing quantity.

7 Mar 2011, 8:55 AM
#8
huntman avatar

huntman

New Zenner

Join Date:
Mar 2011
Posts:
1
Plugin Contributions:
0

Re: PHP 5.3.1 - Changing Quantity in Cart - Error in zen_get_prid

Did the quantity update button stop working in the shopping cart when you installed the 'Checkout By Amazon' add-on?

Mine stopped working in version 1.3.9h. However, when I reinstalled the original Includes/Templates/Templates_Default/Templates/tpl_shopping_cart_default.php the quantity update button started working again. Hmmm.

So I compared the original tpl_shopping_cart_default.php with the replacement file for 'Checkout By Amazon'. I found a bug. I fixed it by replacing some code from the original tpl_shopping_cart_default.php to the same file from the 'Checkout By Amazon' add-on.

I copied this code from line 32 (or so) of the original:

<?php echo zen_draw_form('cart_quantity', zen_href_link(FILENAME_SHOPPING_CART, 'action=update_product', $request_type)); ?> <div id="cartInstructionsDisplay" class="content"><?php echo TEXT_INFORMATION; ?></div>

Then I replaced the similar code (also about line 32) in the tpl_shopping_cart_default.php replacement file for 'Checkout By Amazon' with that code from the original file.

My shopping cart quantity update button works now with the 'Checkout By Amazon' add-on.:clap:

The difference is the ', $request_type' snippet that appears in the original code but was omitted from the 'Checkout By Amazon' add-on file.

I hope it works for you also.