Jump to content

problem with extract() using call from a class


monkeytooth

Recommended Posts

I don't know to much about the extract function, or what it does exactly. However in the name of trying to save time I went out and got myself a premade cart script. Ok fine, dandy. Ill work with it. Unfortunately it does not work out of the box. Like I anticipated and hoped it would.

 

The problem is the people who developed it are building it off of custom classes and functions, and I think the class:

class jcart {
var $total = 0;
var $itemcount = 0;
var $items = array();
var $itemprices = array();
var $itemqtys = array();
var $itemname = array();

the way it was laid out is incorrect. I could be wrong, I dont know. Anywho I need some eyes to help me out here Ive looked at it a couple times I know enough to diagnose usually what an issue is, but Im stumped maybe to stressed from my upcoming deadline I dont know. Im not necessarily looking for a full rewrite here or anything else of the sort. What I am looking for is some opinions on how I can patch this, maybe catch a glitch Im not catching anything.

 

Here are the 2 lines throwing errors in the script:

Line 1

extract($jcart);

Line 2

if ($_POST['jcart_update_item'] == $jcart['text']['update_button'])

 

One other thing I have noticed is that the class brackets wrap over all the other functions in the file below is the whole file.

 

<?php

// JCART v1.1
// http://conceptlogic.com/jcart/

// SESSION BASED SHOPPING CART CLASS FOR JCART

/**********************************************************************
Based on Webforce Cart v.1.5
(c) 2004-2005 Webforce Ltd, NZ
http://www.webforce.co.nz/cart/
**********************************************************************/

// USER CONFIG
include_once('jcart-config.php');

// DEFAULT CONFIG VALUES
include_once('jcart-defaults.php');

// JCART
class jcart {
var $total = 0;
var $itemcount = 0;
var $items = array();
var $itemprices = array();
var $itemqtys = array();
var $itemname = array();

// CONSTRUCTOR FUNCTION
function cart() {}

// GET CART CONTENTS
function get_contents()
	{
	$items = array();
	foreach($this->items as $tmp_item)
		{
		$item = FALSE;

		$item['id'] = $tmp_item;
		$item['qty'] = $this->itemqtys[$tmp_item];
		$item['price'] = $this->itemprices[$tmp_item];
		$item['name'] = $this->itemname[$tmp_item];
		$item['subtotal'] = $item['qty'] * $item['price'];
		$items[] = $item;
		}
	return $items;
	}


// ADD AN ITEM
function add_item($item_id, $item_qty=1, $item_price, $item_name)
	{
	// VALIDATION
	$valid_item_qty = $valid_item_price = false;

	// IF THE ITEM QTY IS AN INTEGER, OR ZERO
	if (preg_match("/^[0-9-]+$/i", $item_qty))
		{
		$valid_item_qty = true;
		}
	// IF THE ITEM PRICE IS A FLOATING POINT NUMBER
	if (is_numeric($item_price))
		{
		$valid_item_price = true;
		}

	// ADD THE ITEM
	if ($valid_item_qty !== false && $valid_item_price !== false)
		{
		// IF THE ITEM IS ALREADY IN THE CART, INCREASE THE QTY
		if($this->itemqtys[$item_id] > 0)
			{
			$this->itemqtys[$item_id] = $item_qty + $this->itemqtys[$item_id];
			$this->_update_total();
			}
		// THIS IS A NEW ITEM
		else
			{
			$this->items[] = $item_id;
			$this->itemqtys[$item_id] = $item_qty;
			$this->itemprices[$item_id] = $item_price;
			$this->itemname[$item_id] = $item_name;
			}
		$this->_update_total();
		return true;
		}

	else if	($valid_item_qty !== true)
		{
		$error_type = 'qty';
		return $error_type;
		}
	else if	($valid_item_price !== true)
		{
		$error_type = 'price';
		return $error_type;
		}
	}


// UPDATE AN ITEM
function update_item($item_id, $item_qty)
	{
	// IF THE ITEM QTY IS AN INTEGER, OR ZERO
	// UPDATE THE ITEM
	if (preg_match("/^[0-9-]+$/i", $item_qty))
		{
		if($item_qty < 1)
			{
			$this->del_item($item_id);
			}
		else
			{
			$this->itemqtys[$item_id] = $item_qty;
			}
		$this->_update_total();
		return true;
		}
	}


// UPDATE THE ENTIRE CART
// VISITOR MAY CHANGE MULTIPLE FIELDS BEFORE CLICKING UPDATE
// ONLY USED WHEN JAVASCRIPT IS DISABLED
// WHEN JAVASCRIPT IS ENABLED, THE CART IS UPDATED ONKEYUP
function update_cart()
	{
	// POST VALUE IS AN ARRAY OF ALL ITEM IDs IN THE CART
	if (is_array($_POST['jcart_item_ids']))
		{
		// TREAT VALUES AS A STRING FOR VALIDATION
		$item_ids = implode($_POST['jcart_item_ids']);
		}

	// POST VALUE IS AN ARRAY OF ALL ITEM QUANTITIES IN THE CART
	if (is_array($_POST['jcart_item_qty']))
		{
		// TREAT VALUES AS A STRING FOR VALIDATION
		$item_qtys = implode($_POST['jcart_item_qty']);
		}

	// IF NO ITEM IDs, THE CART IS EMPTY
	if ($_POST['jcart_item_id'])
		{
		// IF THE ITEM QTY IS AN INTEGER, OR ZERO, OR EMPTY
		// UPDATE THE ITEM
		if (preg_match("/^[0-9-]+$/i", $item_qtys) || $item_qtys == '')
			{
			// THE INDEX OF THE ITEM AND ITS QUANTITY IN THEIR RESPECTIVE ARRAYS
			$count = 0;

			// FOR EACH ITEM IN THE CART
			foreach ($_POST['jcart_item_id'] as $item_id)
				{
				// GET THE ITEM QTY AND DOUBLE-CHECK THAT THE VALUE IS AN INTEGER
				$update_item_qty = intval($_POST['jcart_item_qty'][$count]);

				if($update_item_qty < 1)
					{
					$this->del_item($item_id);
					}
				else
					{
					// UPDATE THE ITEM
					$this->update_item($item_id, $update_item_qty);
					}

				// INCREMENT INDEX FOR THE NEXT ITEM
				$count++;
				}
			return true;
			}
		}
	// IF NO ITEMS IN THE CART, RETURN TRUE TO PREVENT UNNECSSARY ERROR MESSAGE
	else if (!$_POST['jcart_item_id'])
		{
		return true;
		}
	}


// REMOVE AN ITEM
/*
GET VAR COMES FROM A LINK, WITH THE ITEM ID TO BE REMOVED IN ITS QUERY STRING
AFTER AN ITEM IS REMOVED ITS ID STAYS SET IN THE QUERY STRING, PREVENTING THE SAME ITEM FROM BEING ADDED BACK TO THE CART
SO WE CHECK TO MAKE SURE ONLY THE GET VAR IS SET, AND NOT THE POST VARS

USING POST VARS TO REMOVE ITEMS DOESN'T WORK BECAUSE WE HAVE TO PASS THE ID OF THE ITEM TO BE REMOVED AS THE VALUE OF THE BUTTON
IF USING AN INPUT WITH TYPE SUBMIT, ALL BROWSERS DISPLAY THE ITEM ID, INSTEAD OF ALLOWING FOR USER FRIENDLY TEXT SUCH AS 'remove'
IF USING AN INPUT WITH TYPE IMAGE, INTERNET EXPLORER DOES NOT SUBMIT THE VALUE, ONLY X AND Y COORDINATES WHERE BUTTON WAS CLICKED
CAN'T USE A HIDDEN INPUT EITHER SINCE THE CART FORM HAS TO ENCOMPASS ALL ITEMS TO RECALCULATE TOTAL WHEN A QUANTITY IS CHANGED, WHICH MEANS THERE ARE MULTIPLE REMOVE BUTTONS AND NO WAY TO ASSOCIATE THEM WITH THE CORRECT HIDDEN INPUT
*/
function del_item($item_id)
	{
	$ti = array();
	$this->itemqtys[$item_id] = 0;
	foreach($this->items as $item)
		{
		if($item != $item_id)
			{
			$ti[] = $item;
			}
		}
	$this->items = $ti;
	$this->_update_total();
	}


// EMPTY THE CART
function empty_cart()
	{
	$this->total = 0;
	$this->itemcount = 0;
	$this->items = array();
	$this->itemprices = array();
	$this->itemqtys = array();
	$this->itemname = array();
	}


// INTERNAL FUNCTION TO RECALCULATE TOTAL
function _update_total()
	{
	$this->itemcount = 0;
	$this->total = 0;
	if(sizeof($this->items > 0))
		{
		foreach($this->items as $item)
			{
			$this->total = $this->total + ($this->itemprices[$item] * $this->itemqtys[$item]);

			// TOTAL ITEMS IN CART (ORIGINAL wfCart COUNTED TOTAL NUMBER OF LINE ITEMS)
			$this->itemcount += $this->itemqtys[$item];
			}
		}
	}


// PROCESS AND DISPLAY CART
function display_cart($jcart)
	{
	// JCART ARRAY HOLDS USER CONFIG SETTINGS
	extract($jcart);

	// ASSIGN USER CONFIG VALUES AS POST VAR LITERAL INDICES
	// INDICES ARE THE HTML NAME ATTRIBUTES FROM THE USERS ADD-TO-CART FORM
	$item_id = $_POST[$item_id];
	$item_qty = $_POST[$item_qty];
	$item_price = $_POST[$item_price];
	$item_name = $_POST[$item_name];

	// ADD AN ITEM
	if ($_POST[$item_add])
		{
		$item_added = $this->add_item($item_id, $item_qty, $item_price, $item_name);
		// IF NOT TRUE THE ADD ITEM FUNCTION RETURNS THE ERROR TYPE
		if ($item_added !== true)
			{
			$error_type = $item_added;
			switch($error_type)
				{
				case 'qty':
					$error_message = $text['quantity_error'];
					break;
				case 'price':
					$error_message = $text['price_error'];
					break;
				}
			}
		}

	// UPDATE A SINGLE ITEM
	// CHECKING POST VALUE AGAINST $text ARRAY FAILS?? HAVE TO CHECK AGAINST $jcart ARRAY
	if ($_POST['jcart_update_item'] == $jcart['text']['update_button'])
		{
		$item_updated = $this->update_item($_POST['item_id'], $_POST['item_qty']);
		if ($item_updated !== true)
			{
			$error_message = $text['quantity_error'];
			}
		}

	// UPDATE ALL ITEMS IN THE CART
	if($_POST['jcart_update_cart'] || $_POST['jcart_checkout'])
		{
		$cart_updated = $this->update_cart();
		if ($cart_updated !== true)
			{
			$error_message = $text['quantity_error'];
			}
		}

	// REMOVE AN ITEM
	if($_GET['jcart_remove'] && !$_POST[$item_add] && !$_POST['jcart_update_cart'] && !$_POST['jcart_check_out'])
		{
		$this->del_item($_GET['jcart_remove']);
		}

	// EMPTY THE CART
	if($_POST['jcart_empty'])
		{
		$this->empty_cart();
		}

	// DETERMINE WHICH TEXT TO USE FOR THE NUMBER OF ITEMS IN THE CART
	if ($this->itemcount >= 0)
		{
		$text['items_in_cart'] = $text['multiple_items'];
		}
	if ($this->itemcount == 1)
		{
		$text['items_in_cart'] = $text['single_item'];
		}

	// DETERMINE IF THIS IS THE CHECKOUT PAGE
	// WE FIRST CHECK THE REQUEST URI AGAINST THE USER CONFIG CHECKOUT (SET WHEN THE VISITOR FIRST CLICKS CHECKOUT)
	// WE ALSO CHECK FOR THE REQUEST VAR SENT FROM HIDDEN INPUT SENT BY AJAX REQUEST (SET WHEN VISITOR HAS JAVASCRIPT ENABLED AND UPDATES AN ITEM QTY)
	$is_checkout = strpos($_SERVER['REQUEST_URI'], $form_action);
	if ($is_checkout !== false || $_REQUEST['jcart_is_checkout'] == 'true')
		{
		$is_checkout = true;
		}
	else
		{
		$is_checkout = false;
		}

	// OVERWRITE THE CONFIG FORM ACTION TO POST TO jcart-gateway.php INSTEAD OF POSTING BACK TO CHECKOUT PAGE
	// THIS ALSO ALLOWS US TO VALIDATE PRICES BEFORE SENDING CART CONTENTS TO PAYPAL
	if ($is_checkout == true)
		{
		$form_action = $path . 'jcart-gateway.php';
		}

	// DEFAULT INPUT TYPE
	// CAN BE OVERRIDDEN IF USER SETS PATHS FOR BUTTON IMAGES
	$input_type = 'submit';

	// IF THIS ERROR IS TRUE THE VISITOR UPDATED THE CART FROM THE CHECKOUT PAGE USING AN INVALID PRICE FORMAT
	// PASSED AS A SESSION VAR SINCE THE CHECKOUT PAGE USES A HEADER REDIRECT
	// IF PASSED VIA GET THE QUERY STRING STAYS SET EVEN AFTER SUBSEQUENT POST REQUESTS
	if ($_SESSION['quantity_error'] == true)
		{
		$error_message = $text['quantity_error'];
		unset($_SESSION['quantity_error']);
		}

	// OUTPUT THE CART

	// IF THERE'S AN ERROR MESSAGE WRAP IT IN SOME HTML
	if ($error_message)
		{
		$error_message = "<p class='jcart-error'>$error_message</p>";
		}

	// DISPLAY THE CART HEADER
	echo "<!-- BEGIN JCART -->\n<div id='jcart'>\n";
	echo "\t$error_message\n";
	echo "\t<form method='post' action='$form_action'>\n";
	echo "\t\t<fieldset>\n";
	echo "\t\t\t<table border='1'>\n";
	echo "\t\t\t\t<tr>\n";
	echo "\t\t\t\t\t<th id='jcart-header' colspan='3'>\n";
	echo "\t\t\t\t\t\t<strong id='jcart-title'>" . $text['cart_title'] . "</strong> (" . $this->itemcount . " " . $text['items_in_cart'] .")\n";
	echo "\t\t\t\t\t</th>\n";
	echo "\t\t\t\t</tr>". "\n";

	// IF ANY ITEMS IN THE CART
	if($this->itemcount > 0)
		{

		// DISPLAY LINE ITEMS
		foreach($this->get_contents() as $item)
			{
			echo "\t\t\t\t<tr>\n";

			// ADD THE ITEM ID AS THE INPUT ID ATTRIBUTE
			// THIS ALLOWS US TO ACCESS THE ITEM ID VIA JAVASCRIPT ON QTY CHANGE, AND THEREFORE UPDATE THE CORRECT ITEM
			// NOTE THAT THE ITEM ID IS ALSO PASSED AS A SEPARATE FIELD FOR PROCESSING VIA PHP
			echo "\t\t\t\t\t<td class='jcart-item-qty'>\n";
			echo "\t\t\t\t\t\t<input type='text' size='2' id='jcart-item-id-" . $item['id'] . "' name='jcart_item_qty[ ]' value='" . $item['qty'] . "' />\n";
			echo "\t\t\t\t\t</td>\n";
			echo "\t\t\t\t\t<td class='jcart-item-name'>\n";
			echo "\t\t\t\t\t\t" . $item['name'] . "<input type='hidden' name='jcart_item_name[ ]' value='" . $item['name'] . "' />\n";
			echo "\t\t\t\t\t\t<input type='hidden' name='jcart_item_id[ ]' value='" . $item['id'] . "' />\n";
			echo "\t\t\t\t\t</td>\n";
			echo "\t\t\t\t\t<td class='jcart-item-price'>\n";
			echo "\t\t\t\t\t\t<span>" . $text['currency_symbol'] . number_format($item['subtotal'],2) . "</span><input type='hidden' name='jcart_item_price[ ]' value='" . $item['price'] . "' />\n";
			echo "\t\t\t\t\t\t<a class='jcart-remove' href='?jcart_remove=" . $item['id'] . "'>" . $text['remove_link'] . "</a>\n";
			echo "\t\t\t\t\t</td>\n";
			echo "\t\t\t\t</tr>\n";
			}
		}

	// THE CART IS EMPTY
	else
		{
		echo "\t\t\t\t<tr><td colspan='3' class='empty'>" . $text['empty_message'] . "</td></tr>\n";
		}

	// DISPLAY THE CART FOOTER
	echo "\t\t\t\t<tr>\n";
	echo "\t\t\t\t\t<th id='jcart-footer' colspan='3'>\n";

	// IF THIS IS THE CHECKOUT HIDE THE CART CHECKOUT BUTTON
	if ($is_checkout !== true)
		{
		if ($button['checkout']) { $input_type = 'image'; $src = ' src="' . $button['checkout'] . '" alt="' . $text['checkout_button'] . '" title="" ';	}
		echo "\t\t\t\t\t\t<input type='" . $input_type . "' " . $src . "id='jcart-checkout' name='jcart_checkout' class='jcart-button' value='" . $text['checkout_button'] . "' />\n";
		}

	echo "\t\t\t\t\t\t<span id='jcart-subtotal'>" . $text['subtotal'] . ": <strong>" . $text['currency_symbol'] . number_format($this->total,2) . "</strong></span>\n";
	echo "\t\t\t\t\t</th>\n";
	echo "\t\t\t\t</tr>\n";
	echo "\t\t\t</table>\n\n";

	echo "\t\t\t<div class='jcart-hide'>\n";
	if ($button['update']) { $input_type = 'image'; $src = ' src="' . $button['update'] . '" alt="' . $text['update_button'] . '" title="" ';	}
	echo "\t\t\t\t<input type='" . $input_type . "' " . $src ."name='jcart_update_cart' value='" . $text['update_button'] . "' class='jcart-button' />\n";
	if ($button['empty']) { $input_type = 'image'; $src = ' src="' . $button['empty'] . '" alt="' . $text['empty_button'] . '" title="" ';	}
	echo "\t\t\t\t<input type='" . $input_type . "' " . $src ."name='jcart_empty' value='" . $text['empty_button'] . "' class='jcart-button' />\n";
	echo "\t\t\t</div>\n";

	// IF THIS IS THE CHECKOUT DISPLAY THE PAYPAL CHECKOUT BUTTON
	if ($is_checkout == true)
		{
		// HIDDEN INPUT ALLOWS US TO DETERMINE IF WE'RE ON THE CHECKOUT PAGE
		// WE NORMALLY CHECK AGAINST REQUEST URI BUT AJAX UPDATE SETS VALUE TO jcart-relay.php
		echo "\t\t\t<input type='hidden' id='jcart-is-checkout' name='jcart_is_checkout' value='true' />\n";

		// SEND THE URL OF THE CHECKOUT PAGE TO jcart-gateway.php
		// WHEN JAVASCRIPT IS DISABLED WE USE A HEADER REDIRECT AFTER THE UPDATE OR EMPTY BUTTONS ARE CLICKED
		$protocol = 'http://'; if (!empty($_SERVER['HTTPS'])) { $protocol = 'https://'; }
		echo "\t\t\t<input type='hidden' id='jcart-checkout-page' name='jcart_checkout_page' value='" . $protocol . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] . "' />\n";

		// PAYPAL CHECKOUT BUTTON
		if ($button['paypal_checkout'])	{ $input_type = 'image'; $src = ' src="' . $button['paypal_checkout'] . '" alt="' . $text['checkout_paypal_button'] . '" title="" '; }
		echo "\t\t\t<input type='" . $input_type . "' " . $src ."id='jcart-paypal-checkout' name='jcart_paypal_checkout' value='" . $text['checkout_paypal_button'] . "'" . $disable_paypal_checkout . " />\n";
		}
	echo "\t\t</fieldset>\n";
	echo "\t</form>\n";

	// IF UPDATING AN ITEM, FOCUS ON ITS QTY INPUT AFTER THE CART IS LOADED (DOESN'T SEEM TO WORK IN IE7)
	if ($_POST['jcart_update_item'])
		{
		echo "\t" . '<script type="text/javascript">$(function(){$("#jcart-item-id-' . $_POST['item_id'] . '").focus()});</script>' . "\n";
		}

	echo "</div>\n<!-- END JCART -->\n";
	}
}
?>

 

The Developers solution is turn register_globals off I don't know about the rest of you but last I knew, register globals off is a bad idea

Link to comment
Share on other sites

On is bad? Yea I can see that... more so after some more reading up on it.. the first few articles I read a while back some time ago made it seem like it was evil to put them off.. but after the recent reads I have been doing in the past couple hours, and after digging through the php.ini on my server I can say yes, I agree with keeping them on is bad.

 

I know this is silly question and the answers most likely right in my face.. but lets say I turn my globals off, are such things like $_GET $_SESSION and $_POST things that wont work any more, with it off? I assume turning it off will at the least make $_GET and $_POST variables pretty much the same exact thing in the script and rather than using $_GET/POST['var'] i can just use $var. But can I still use $_SESSION? With globals off, or do I have to use another method? If none of these work anymore would I be correct to assume I will have to do rewrites or some of my scripts removing $_GET/POST from my scripting, adjusting them accordingly?

 

As for the errors I have gotten they are,.

First argument should be an array in /home/campus/public_html/x/inc/jcart/jcart.php on line 244

Fatal error: Cannot use object of type jcart as array in /home/campus/public_html/x/inc/jcart/jcart.php on line 275

 

244 is the first line of 2 i mentioned earlier, and 275 is the second

Link to comment
Share on other sites

It is because your jcart::display_cart() method expects the argument passed to be an array, however, it is recieving an object. Have you tried casting the jcart object to an array before passing it to jcart::display_cart() as an argument.

 

//nvm

Link to comment
Share on other sites

you seem to have the wrong idea regarding register_globals.

 

The super global arrays GET/POST/COOKIE/SESSION/SERVER will ALWAYS work.

It is just that you have to address them using their array names. With register_globals on, their values are avalible in the general namespace.

so $_GET['fred'] is avalaible as $fred. This is what is a bad thing, and why register_globals should be off.

 

Regarding your errors, please indicate what is on the lines producing the errors.

Link to comment
Share on other sites

Here are the 2 lines throwing errors in the script:

Line 1 (244)

Code: [select]

extract($jcart);

Line 2 (275)

Code: [select]

if ($_POST['jcart_update_item'] == $jcart['text']['update_button'])

 

As far as superglobals go, I figured they would work.. just the handling of them is what i wasn't sure about meaning would i still code in essence of $var1 = $_POST['var1']; or $_SESSION['var2'] = "something";.. or would i have to handle that in another way.

 

example an if-else statment I might have in my script already...

if((isset($_SESSION) AND ($_SESSION == "Tacobell")){/*do something*/}else{ignore}

or another example:

if(empty($_POST['formdata'])){/*do nothing*/}else{preg_match([abc], $_POST['formdata']){/*good*/}

 

messy concept above but for the sake of example hopefully can convery what I am wondering about how things may or may not change upon globals off vs how (above code sample) i do things no with it on.

 

Link to comment
Share on other sites

Ok your problem is you are addressing an object as if it were an array, which you cannot do

 

you cannot extract() on an object, or use the $var['element'] syntax

 

you use the $obj->element syntax on an instance of the object.

 

Your code using $_POST and $_SESSION would work the same with register_globals on or off

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.