简体   繁体   中英

PHP incorrect variable value stored in database

Okay, so I have a basket which has a $iEmployeeNumbers variable which by default is set to 10.

When constructed this is over written to 23.

When dying before the insert statement the variable is 23 and when dying after the insert statement the variable is 23.

If I die after the insert statement the value in the database is correct however if I let the function run until it hits the return and goes back to the main code the value stored in the database is set to 10.

class basket
{
    // Basket ID
    private $id = 0;
    // Session ID
    private $sessionId = null;
    // client id
    private $iClientId = 0;
    // array with the index of the deck product and the value of array('product', 'status')
    private $aryItems = array();
    // array of deck products
    private $aryCurrentSubscrition = array();
    // employee numbers
    private $iEmployeeNumbers = 10;

    /**
     * Set up the basket with the current subscribed decks passed in
     * @param $iCurrentEmployeeNumbers An int of the current employee numbers from the system
     * @param $aryCurrentDeckProducts An array of currently subscribed to deck products
     */
    function __construct($api, $sessionId, $iCurrentEmployeeNumbers, $aryCurrentDecks = null)
    {
        $this->sessionId = $sessionId;
        $this->setEmployeeNumbers($iCurrentEmployeeNumbers);
        //die('shizzle:'.$this->iEmployeeNumbers);
        // check if $aryCurrentDeckProducts is not null
        if ($aryCurrentDecks !== null)
        {
            // loop through deck products adding them to the arrays
            foreach ($aryCurrentDecks as $objDeck)
            {
                // set the current subscribed decks to the ones passed in the construct.
                $this->aryCurrentSubscription[$objDeck->id] = $objDeck;
            }
        }
    }

    /**
     * Add an item to the basket
     * @param $objDeck The deck to add.
     * @param $sStatus The status of the item ('added', 'changed', 'removed', 'existing')
     */
    public function addItem($objDeck)
    {
        // check if the deck product exists in the basket already
        if (!empty($this->aryItems) && array_key_exists($objDeck->id, $this->aryItems))
        {
            // check if the deck product was part of the existing subscription
            if (!empty($this->aryCurrentSubscription) && array_key_exists($objDeck->id, $this->aryCurrentSubscription) && $this->aryCurrentSubscription[$objDeck->id]['deck']->compare($objDeck))
            {
                // the product was in the basket at the start of the shop and has been re-added
                // so set it to existing and avoid double charging them for the initial setup
                $this->aryItems[$objDeck->id]['status'] = 'existing';
            }
            else
            {
                if ($this->aryItems[$objDeck->id]['product']->compare($objDeck))
                {
                    // the product was added then removed from the basket but was not
                    // in the current subscription so set its status back to added
                    $this->aryItems[$objDeck->id]['status'] = 'added';
                }
                else
                {
                    // the product was added but does exist in the basket as a different
                    // set of addons
                    $this->aryItems[$objDeck->id]['status'] = 'changed';
                }
            }
        }
        else
        {
            // the product is not in the cart so add it as a new one
            $this->aryItems[$objDeck->id] = array('product' => $objDeck, 'status' => 'added');
        }
    }

    /**
     * Remove an item from the basket
     * @param $objDeckProduct The deck product to remove
     * @return bool true|false
     */
    public function removeItem($objDeck)
    {
        // Check if the product is in the basket
        if (array_key_exists($objDeck->id, $this->aryItems))
        {
            // Set the status of the product to removed
            $this->aryItems[$objDeck->id]['status'] = 'removed';
            return true;
        }

        // the item does not exist in the basket
        return false;
    }

    /**
     * Get the totals from the basket
     * @return array ('setup', 'monthly', 'equivalent', 'setup_formatted', 'monthly_formatted', 'equivalent_formatted')
     */
    public function getTotals()
    {
        // set up a running total for adding up all the costs involved
        $runningTotal = array('setup' => 0, 'monthly' => 0, 'equivalent' => 0);

        // loop through all items and process them based on status
        foreach ($this->aryItems as $aryItem)
        {
            // only process items that are NOT removed
            if ($aryItem['status'] !== 'removed')
            {
                // get the calcualate the deck prices
                $deckPrices = $this->calculatePrices($aryItem['product']);
                // because the setup check is done at addon level inside the get deck prices
                // we can just add the setup cost
                $runningTotal['setup'] += $deckPrices['setup'];
                $runningTotal['monthly'] += $deckPrices['monthly'];
                $runningTotal['equivalent'] += $deckPrices['equivalent'];
            }
        }

        // format all the numbers
        $runningTotal['setup_formatted'] = $this->stringNumberFormat(bcdiv($runningTotal["setup"], 100, 2));
        $runningTotal['monthly_formatted'] = $this->stringNumberFormat(bcdiv($runningTotal["monthly"], 100, 2));
        $runningTotal['equivalent_formatted'] = $this->stringNumberFormat(bcdiv($runningTotal["equivalent"], 100, 2));

        return $runningTotal;
    }

    /**
     * Calculate the prices for any given deck
     * @param $objDeck The deck to process
     * @param $iEmployees The number of employees to calculate against
     * @return array ('setup', 'monthly', 'equivalent', 'setup_formatted', 'monthly_formatted', 'equivalent_formatted')
     */
    function calculatePrices($objDeck, $iEmployees = null)
    {
        if ($iEmployees === null)
        {
            $iEmployees = $this->iEmployeeNumbers;
        }

        $prices = array();
        // calculate the monthly total with the support cost
        // FIXME need to implement discount for the deck price
        $iMonthlyPrice = $objDeck->price * $iEmployees;
        $iSetupPrice = 0;

        $deckIsInBasket = false;
        if (!empty($this->aryCurrentItems) && array_key_exists($objDeck->id, $this->aryCurrentItems))
        {
            $deckIsInBasket = true;
        }

        foreach ($objDeck->addons as $addon)
        {
            // if the deck is in the current subscription do the other two checks else skip to adding the setup cost
            if (($deckIsInBasket && (empty($this->aryCurrentItems[$objDeck->id]->addons) || !array_key_exists($addon->id, $this->aryCurrentItems[$objDeck->id]->addons))) || !$deckIsInBasket)
            {
                $iSetupPrice += $addon->setup_price;
            }

            $iMonthlyPrice += $addon->price * $iEmployees;
        }


        // set up the returned array
        $prices["setup"] = $iSetupPrice;
        $prices["monthly"] = $iMonthlyPrice;
        $prices["equivalent"] = (int) round($iMonthlyPrice / $iEmployees, 0);
        $prices["setup_formatted"] = $this->stringNumberFormat(bcdiv($prices["setup"], 100, 2));
        $prices["monthly_formatted"] = $this->stringNumberFormat(bcdiv($prices["monthly"], 100, 2));
        $prices["equivalent_formatted"] = $this->stringNumberFormat(bcdiv($prices["equivalent"], 100, 2));

        return $prices;
    }

    /**
     * Format a string number to currency format
     * @param $sNumber The number to be formatted as currency
     * @return string The formatted number
     */
    function stringNumberFormat($sNumber)
    {
        // check for any existing decimal places
        $parts = explode(".", $sNumber);

        // if there was no decimal place set the pennies to 00
        if (count($parts) === 1)
        {
            $parts[1] = "00";
        }

        // if the number has less then 3 digits e.g. less than 1000 then return
        // the formatted parts with a decimal place
        if (strlen($parts[0]) <= 3)
        {
            return implode(".", $parts);;
        }

        // prepare the formatted string
        $formattedString = $parts[0];
        // set the added characters to empty
        $added = "";
        // set the thousands to an empty array
        $thousands = array();
        // calculate the remainder of dividing the string length by 3
        // this tells us how many 0's to add at the start of the string
        // we add the 0's to make it easy to step through every thousand
        $remainder = (int) bcmod(strlen($formattedString), 3);

        // if the remainder is 1 add two 0's (e.g. 1000 now looks like 001000)
        if ($remainder === 1)
        {
            $added = "00";
        }
        // if the remainder is 2 add one 0 (e.g. 10000 now looks like 010000)
        elseif ($remainder === 2)
        {
            $added = "0";
        }
        // if it divided by three with no remainder then there is no need to add any

        // add the prefix to the start
        $formattedString = $added . $formattedString;

        // for the length of the string step through every 3 characters
        for ($x = 3; $x <= strlen($formattedString); $x += 3)
        {
            // minus this many off the start of the string
            $minus = 0;

            // for the first step only
            if ($x === 3)
            {
                // set minus to the number of 0's added
                $minus = strlen($added);
            }

            // set each set of thousands to a new part
            $thousands[] = substr($formattedString, $x - 3 + $minus, 3 - $minus);
        }

        // put all the groups of 3 characters back together with the
        // seperator of ,
        $parts[0] = implode(",", $thousands);

        // add the decimal places back on and return
        return implode(".", $parts);
    }

    /**
     * Get the number of employees
     * @return int Number of employees
     */
    public function getEmployeeNumbers()
    {
        return $this->iEmployeeNumbers;
    }

    /**
     * Sets the number of employees
     * @param $iNewEmployeeNumbers
     * @return bool successful
     */
    public function setEmployeeNumbers($iNewEmployeeNumbers)
    {
        if (is_numeric($iNewEmployeeNumbers) && (int) $iNewEmployeeNumbers >= 10)
        {
            echo 'iem:'.$this->iEmployeeNumbers.' inew:'.$iNewEmployeeNumbers;
            $this->iEmployeeNumbers = (int) $iNewEmployeeNumbers;
            echo 'iemnew:'.$this->iEmployeeNumbers;
            //die('in this if');
            return true;
        }
        else
        {
            return false;
        }
    }

    /**
     * Get the client id
     * @return int client id
     */
    public function getClientId()
    {
        return $this->iClientId;
    }

    /**
     * Sets the client id, can only be called if client id is not already set
     * @param $iNewClientId
     * @return bool successful
     */
    public function setClientId($iNewClientId)
    {
        if (is_numeric($iNewClientId) && (int) $iNewClientId > 0 && $this->iClientId == 0)
        {
            $this->iClientId = (int) $iNewClientId;
            return true;
        }
        else
        {
            return false;
        }
    }

    /**
     * Gets an array of items for displaying on the basket page.
     * @return array of deck products.
     */
    public function getDecks()
    {
        $activeItems = array();

        foreach($this->aryItems as $aryItem)
        {
            // only process items that are added
            if ($aryItem['status'] !== 'removed')
            {
                $activeItems[$aryItem['product']->id] = $aryItem['product'];
            }
        }

        return $activeItems;
    }

    /**
     * Sets the aryItems
     * @params array $aryDecks an array of decks to be set
     */
    public function setDecks($aryItems)
    {
        foreach($aryItems as $objDeck)
        {
            $this->addItem($objDeck);
        }
    }

    /**
     * Gets 'true' or 'false' if the client had decks at the start of the process
     * @return string 'true' or 'false'
     */
    public function hasDecks()
    {
        if (count($this->aryCurrentSubscription) > 0)
        {
            return 'true';
        }
        else
        {
            return 'false';
        }
    }

    /**
     * Builds the billing agreement description
     * @return string The billing agreement description
     */
    public function getBillingAgreementDescription($sResellerName)
    {
        $description = "Your subscription with " . $sResellerName . ".";

        return $description;
    }

    /**
     * FIXME Add a function for calculating revenue splits and amounts.
     *
     */

    /**
     * Saves the added items to the database for checkout resumption
     * @return bool successful?
     */
    public function save()
    {
        $db = database::getDBO();

        $id = $this->basketExists();

        if (!$id)
        {
            $db->beginTransaction();
            $query = $db->prepare("INSERT INTO `baskets` (`session_id`, `employee_numbers`) VALUES (?, ?)");
            $query->bindParam(1, $this->sessionId, PDO::PARAM_STR);
            $query->bindValue(2, $this->iEmployeeNumbers, PDO::PARAM_INT);
            $query->execute();

            $this->id = $db->lastInsertId();

            if ($this->id != 0)
            {
                $query = $db->prepare("INSERT INTO `basket_items` (`basket_id`, `deck_addon_id`, `status`) VALUES (?, ?, ?)");
                $query->bindParam(1, $this->id, PDO::PARAM_INT);

                foreach ($this->aryItems as $aryItem)
                {
                    foreach ($aryItem['product']->addons as $addon)
                    {
                        $query->bindParam(2, $addon->id, PDO::PARAM_INT);
                        $query->bindParam(3, $aryItem['status'], PDO::PARAM_STR);
                        if (!$query->execute())
                        {
                            $db->rollBack();
                            return false;
                        }
                    }
                }

                return $db->commit();
            }
            else
            {
                $db->rollBack();
                return false;
            }
        }
        else
        {
            $this->id = $id;
//          $db->beginTransaction();
            $iEmps = $this->iEmployeeNumbers;
            $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
//          $this->iEmployeeNumbers = $this->iEmployeeNumbers + 1;
            $query = $db->prepare("UPDATE `baskets` SET `session_id` = ?, `employee_numbers` = ? WHERE `id` = ?");
            $query->bindParam(1, $this->sessionId, PDO::PARAM_STR);
            //die(print_r($this->iEmployeeNumbers,1));
            $query->bindValue(2, $this->iEmployeeNumbers, PDO::PARAM_INT);
            $query->bindParam(3, $this->id, PDO::PARAM_INT);
            $query->execute();

            /*foreach ($this->aryItems as $aryItem)
            {
                foreach ($aryItem['product']->addons as $addon)
                {
                    $iBasketItemId = $this->basketItemExists($addon->id);
                    if ($iBasketItemId > 0)
                    {
                        $query = $db->prepare("UPDATE `basket_items` SET `basket_id` = ?, `deck_addon_id` = ?, `status` = ? WHERE `id` = ?");
                        $query->bindParam(4, $iBasketItemId, PDO::PARAM_INT);
                    }
                    else
                    {
                        $query = $db->prepare("INSERT INTO `basket_items` (`basket_id`, `deck_addon_id`, `status`) VALUES (?, ?, ?)");
                    }

                    $query->bindParam(1, $this->id, PDO::PARAM_INT);
                    $query->bindParam(2, $addon->id, PDO::PARAM_INT);
                    $query->bindParam(3, $aryItem['status'], PDO::PARAM_STR);

                    if (!$query->execute())
                    {
                        $db->rollBack();
                        return false;
                    }
                }
            }*/

            return true;
//          return $db->commit();
//          die('shizzle2:'.$this->iEmployeeNumbers);
        }
    }

    /**
     * Loads a basket from the database
     * @return bool sucess
     */
    public function load($api)
    {
        if ($this->basketExists())
        {
            $db = database::getDBO();
            // Get decks & addons for invites
            $query = $db->prepare("SELECT b.id, a.deck_id, bi.deck_addon_id, bi.status, b.employee_numbers FROM baskets AS b JOIN basket_items AS bi ON b.id = bi.basket_id JOIN addons AS a ON bi.deck_addon_id = a.id WHERE b.session_id = ?");
            $query->bindParam(1, $this->sessionId, PDO::PARAM_STR);
            $query->execute();

            while ($aryRes = $query->fetch(PDO::FETCH_ASSOC))
            {
                // Populate basket
                if (empty($this->aryitems) || !array_key_exists($aryRes['deck_id'], $this->aryItems))
                {
                    $this->aryItems[$aryRes['deck_id']]['product'] = $api->getDeckById($iResellerId, $aryRes['deck_id']);
                    $this->aryItems[$aryRes['deck_id']]['status'] = $aryRes['status'];
                }

                $this->aryItems[$aryRes['deck_id']]['product']->addAddon($api->getDeckAddonById($aryRes['deck_addon_id']));

                $this->setEmployeeNumbers($aryRes['employee_numbers']);
                $this->id = $aryRes['id'];
            }

            return true;
        }

        return false;
    }

    /**
     * function for checking if there is a basket saved against the session id
     * @return mixed basket id if one exists else false
     */
    public function basketExists()
    {
        $db = database::getDBO();
        $query = $db->prepare("SELECT id FROM baskets WHERE session_id = ? ORDER BY id DESC");
        $query->bindParam(1, $this->sessionId, PDO::PARAM_STR);
        $query->execute();

        $basket = $query->fetch(PDO::FETCH_ASSOC);

        if (!empty($basket) && $basket !== false)
        {
            return $basket['id'];
        }

        return false;
    }

    /**
     * Checks if the basket item exists
     * @param int $iDeckAddonId
     * @return int Basket id
     */
    public function basketItemExists($iDeckAddonId)
    {
        $db = database::getDBO();
        $query = $db->prepare("SELECT id FROM basket_items WHERE basket_id = ? AND deck_addon_id = ?");
        $query->bindParam(1, $this->id, PDO::PARAM_INT);
        $query->bindParam(2, $iDeckAddonId, PDO::PARAM_INT);
        $query->execute();

        $basket_item = $query->fetch(PDO::FETCH_ASSOC);

        if (!empty($basket_item) && $basket_item !== false)
        {
            return $basket_item['id'];
        }

        return false;
    }
}

And the construct call looks like this.

$basket = new basket($api, session_id(), $aryInvite['employees']);

Followed shortly by $basket->save();

The question is why does this inconsistency happen?

Why does dying inside the function make the database store 23 but if the script is left to hit the return and then dies the value is stored as 10?

Thanks for your help.

The framework being used was routing an image on the page back through to the same php script causing the basket to be initialised and saved with the default settings instead of with the correct ones.

/invites/(invite_id)

page loads and process correct data.

/invites/image-title.png

caused php script to run rather then getting the image and because the invite did not exist it caused the script to save the default employee numbers!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM