0

I appreciate there are similar questions, but I can't get any of the solutions to work with my (inherited) code, so would be grateful for any help you can offer.

We use the Sage Pay / Opayo payment gateway via form integration. On completion/failure the customer is redirected to a URL on our site with an encrypted _GET string. After decryption, the getToken function is called ( $values = getToken($Decoded); ) to get the values from the array.

Not all the tokens are always populated though, and I suspect these null values may be the source of the problem.

The code works fine on PHP 7.1, but PHP 8.1 throws:

[03-May-2023 15:12:15 Europe/London] PHP Fatal error: Uncaught Error: Attempt to assign property "start" on null in /home/sitename/public_html/ch_functions.php:166 Stack trace: #0 /home/sitename/public_html/not_completed.php(32): getToken('VendorTxCode=AP...') #1 {main} thrown in /home/sitename/public_html/ch_functions.php on line 166

The code is, which fails on $resultArray[$i]->start = $start; is:

function getToken($thisString) {

    // List the possible tokens
    $Tokens = array("Status","StatusDetail","VendorTxCode","VPSTxId","TxAuthNo","Amount","AVSCV2","AddressResult","PostCodeResult","CV2Result","GiftAid","3DSecureStatus","CAVV", "AddressStatus", "PayerStatus", "CardType", "Last4Digits","BankAuthCode","DeclineCode");

    // Initialise arrays
    $output = array();
    $resultArray = array();
    
    // Get the next token in the sequence
    for ($i = count($Tokens)-1; $i >= 0 ; $i--){
        // Find the position in the string
        $start = strpos($thisString, $Tokens[$i]);
        // If it's present
        if ($start !== false){
            // Record position and token name
            $resultArray[$i]->start = $start;
            $resultArray[$i]->token = $Tokens[$i];
        }
    }
    
    // Sort in order of position
    sort($resultArray);

    // Go through the result array, getting the token values
    for ($i = 0; $i<count($resultArray); $i++){
        // Get the start point of the value
        $valueStart = $resultArray[$i]->start + strlen($resultArray[$i]->token) + 1;
        // Get the length of the value
        if ($i==(count($resultArray)-1)) {
            $output[$resultArray[$i]->token] = substr($thisString, $valueStart);
        } else {
            $valueLength = $resultArray[$i+1]->start - $resultArray[$i]->start - strlen($resultArray[$i]->token) - 2;
            $output[$resultArray[$i]->token] = substr($thisString, $valueStart, $valueLength);
        }           

    }

    // Return the ouput array
    return $output;

}
Mike West
  • 15
  • 5
  • 1
    You're assuming that `$resultArray[$i]` is an object, but it's not. Use `var_dump()` to see what's actually in that array. – Alex Howansky May 03 '23 at 15:12
  • @AlexHowansky - At which point in the code? Is it not failing while populating the array? – Mike West May 03 '23 at 15:25
  • `$resultArray` is an array, `$result[$i]` doesn't exist inside your loop until you create it. You're using object accessors on something that hasn't been created. Either initialize the array key as an object at the top of the loop, or use array accessors. – aynber May 03 '23 at 15:32
  • Aha! Thank you! ``` $resultArray[$i] = (object)[]; $resultArray[$i]->start = $start; $resultArray[$i]->token = $Tokens[$i]; ``` seems to work ok – Mike West May 03 '23 at 15:44

1 Answers1

0

You're referencing $resultArray[$i] as an object but the array is empty, so there's no object there to reference. In PHP 7.4 and prior, you could do this:

$x = [];
$x[0]->foo = 1;

And PHP would dynamically create a stdClass object at $x[0] and then dynamically create the foo attribute, but issue a warning:

Warning: Creating default object from empty value in ... on line ...

You're currently suppressing or ignoring this warning. In PHP 8.0, this now generates a fatal error. So just create an empty object before you try to set its values:

if ($start !== false) {
    $resultArray[$i] = new stdClass();
    $resultArray[$i]->start = $start;
    $resultArray[$i]->token = $Tokens[$i];
}

Or:

if ($start !== false) {
    $resultArray[$i] = (object) [
        'start' => $start,
        'token' => $Tokens[$i],
    ];
}
Alex Howansky
  • 50,515
  • 8
  • 78
  • 98