• 0

Breaking my head on a multi-dimensional array


Question

Hi people! I've been trying to get a receipt # from a database and building up an array with it.

I've modified the code, at least 5 times to make it work, but I need a last push, and I can't seem to get it:


private function array_key_exists_r($needle, $haystack)
{
$result = array_key_exists($needle, $haystack);
if ($result) return $result;
foreach ($haystack as $v) {
if (is_array($v)) {
$result = $this->array_key_exists_r($needle, $v);
}
if ($result) return $result;
}
return $result;
}


while($row = $this->stmt->fetch())
{

$factura = $row['factura']; /*This is how I get the receipt's number*/
print($factura);
$result = $this->array_key_exists_r($factura,$this->factura);
if(!$result)
{
if(!in_array($factura,$this->trigger)) $this->trigger[] = $factura;
$this->factura = array($factura => array('producto_id' => array($row['producto_id']),
'producto' => array($row['producto']),
'cantidad' => array($row['cantidad']),
'price_i' => array($row['price_i']),
'tax' => array($row['tax'])
)
);

}

else
{

$this->factura[$factura]['producto_id'][] =$row['producto_id'];
$this->factura[$factura]['producto'][] =$row['producto'];
$this->factura[$factura]['cantidad'][]= $row['cantidad'];
$this->factura[$factura]['price_i'][] =$row['price_i'];
$this->factura[$factura]['tax'][] = $row['tax'];
}

}
[/CODE]

Explaining:

The code is trying to do the following:

Create an array which first keys are the receipt number, and to that receipt number add all the products that were fetched from the database.

What I'm getting:

The array is being currently overwrote by the last receipt #. I know that the root of all this evil is this portion of the code:

[CODE]
if(!in_array($factura,$this->trigger)) $this->trigger[] = $factura;
[b] $this->factura = [/b]array($factura => array('producto_id' => array($row['producto_id']),
'producto' => array($row['producto']),
'cantidad' => array($row['cantidad']),
'price_i' => array($row['price_i']),
'tax' => array($row['tax'])
)
);

[/CODE]

The bold part should actually be:

[CODE]
$this->factura[] =
[/CODE]

But by doing so, the whole schema breaks, and the receipts are not appended in order.

Now, in English:

The result I'm getting without any mods:

[CODE]
Array
(
[4] => Array
(
[producto_id] => Array
(
[0] => E5030
[1] => E5060
[2] => E0094
[3] => E7485
)

[producto] => Array
(
[0] => Product # 1
[1] => Product # 2
[2] => Product # 3
[3] => Product # 4
)

[cantidad] => Array
(
[0] => 1
[1] => 1
[2] => 1
[3] => 1
)

[price_i] => Array
(
[0] => 286.62
[1] => 301.92
[2] => 153
[3] => 481
)

[tax] => Array
(
[0] => 1
[1] => 1
[2] => 1
[3] => 1
)

)

)

[/CODE]

WHICH IS GOOD, but the other receipts are overwritten.

But if I made the change I was talking about before, I'd get:

[CODE]
Array
(
[0] => Array
(
[1] => Array
(
[producto_id] => Array
(
[0] => A4318
)

[producto] => Array
(
[0] => Product name
)

[cantidad] => Array
(
[0] => 1
)

[price_i] => Array
(
[0] => 771.12
)

[tax] => Array
(
[0] => 0
)

)

)

[1] => Array
(
[producto_id] => Array
(
[0] => 102992
)

[producto] => Array
(
[0] =>Product name
)

[cantidad] => Array
(
[0] => 1
)

[price_i] => Array
(
[0] => 1128.12
)

[tax] => Array
(
[0] => 0
)

)

[2] => Array
(
[2] => Array
(
[producto_id] => Array
(
[0] => A5816
)

[producto] => Array
(
[0] => Product name
)

[cantidad] => Array
(
[0] => 1
)

[price_i] => Array
(
[0] => 630.36
)

[tax] => Array
(
[0] => 0
)

)

)

[3] => Array
(
[4] => Array
(
[producto_id] => Array
(
[0] => E5030
)

[producto] => Array
(
[0] => Product name
)

[cantidad] => Array
(
[0] => 1
)

[price_i] => Array
(
[0] => 286.62
)

[tax] => Array
(
[0] => 1
)

)

)

[4] => Array
(
[producto_id] => Array
(
[0] => E5060
[1] => E0094
[2] => E7485
)

[producto] => Array
(
[0] => Product name
[1] => Product name
[2] => Product name
)

[cantidad] => Array
(
[0] => 1
[1] => 1
[2] => 1
)

[price_i] => Array
(
[0] => 301.92
[1] => 153
[2] => 481
)

[tax] => Array
(
[0] => 1
[1] => 1
[2] => 1
)

)

)
Array

[/CODE]

What I'm really after:

[CODE]
Array
(
[1] => Array
(
[producto_id] => Array
(
[0] => E5030

)

[producto] => Array
(
[0] => Product # 1

)

[cantidad] => Array
(
[0] => 1

)

[price_i] => Array
(
[0] => 286.62

)

[tax] => Array
(
[0] => 1

)

)

)

Array
(
[2] => Array
(
[producto_id] => Array
(
[0] => E5030
[1] => E5060
)

[producto] => Array
(
[0] => Product # 1
[1] => Product # 2
)

[cantidad] => Array
(
[0] => 1
[1] => 1
)

[price_i] => Array
(
[0] => 286.62
[1] => 301.92
)

[tax] => Array
(
[0] => 1
[1] => 1
)

)

)

Array
(
[4] => Array
(
[producto_id] => Array
(
[0] => E5030
[1] => E5060
[2] => E0094
[3] => E7485
)

[producto] => Array
(
[0] => Product # 1
[1] => Product # 2
[2] => Product # 3
[3] => Product # 4
)

[cantidad] => Array
(
[0] => 1
[1] => 1
[2] => 1
[3] => 1
)

[price_i] => Array
(
[0] => 286.62
[1] => 301.92
[2] => 153
[3] => 481
)

[tax] => Array
(
[0] => 1
[1] => 1
[2] => 1
[3] => 1
)

)

)
[/CODE]

**Note that the 3 is missing on purpose because the receipt's number does not belong to the user I'm currently fetching on the database.

I know this post is looooooooooooooooooooooooooooooooooooong, but if someone could give me a little help I'd appreciate it a lot! Thanks :D

2 answers to this question

Recommended Posts

  • 0

The array is being currently overwrote by the last receipt #. I know that the root of all this evil is this portion of the code:

>
if(!in_array($factura,$this->trigger)) $this->trigger[] = $factura;
[b] $this->factura = [/b]array($factura => array('producto_id' => array($row['producto_id']),
'producto' => array($row['producto']),
'cantidad' => array($row['cantidad']),
'price_i' => array($row['price_i']),
'tax' => array($row['tax'])
)
);

[/CODE]

The bold part should actually be:
[CODE]
$this->factura[] =
[/CODE]

But by doing so, the whole schema breaks, and the receipts are not appended in order.

Its broken (with the above fix implemented) primarily because of your array_key_exists_r() function. I'm assuming that you do understand what that function does... When processing a new row from the database, you're scanning recursively through all nested arrays within $this->factura looking for [b][u]any[/u][/b] existence of a key with a value matching the receipt number! I.e. it's checking for the existence of the receipt number amongst all existing receipt number keys, and all item number keys!!
Let me walk you through the incorrect output you printed having made your suggested fix (from the perspective of processing each row in the result set returned by the database):</pre>
<ul>Row#1: The array is empty, so array_key_exists_r() returns false and the if statement passes. You therefore create a new array containing the receipt number, and the details of the first item, which is stored in a new array entry in the format of $this-&gt;factura[0][1][itemdata], where key [0] was automatically created and [1] is the receipt number.
Row#2: A second item for receipt 1 is being processed. array_key_exists_r() finds an existing array key with a value of 1, so attempts to add the new item data to the receipt, but the receipt is at $this-factura[0][1] not $this-&gt;factura[1], so inadvertently makes a new top level array entry.
Row#3: We are now processing the first item of receipt 2. There is no array entry anywhere in $this-&gt;factura, so array_key_exists_r() returns false, and as with row #1, a new array entry is to be created. The next numerical array key is [2], which coincidentally happens to be the same as the receipt number. We end up creating $this-&gt;factura[2][2][itemdata], with the first [2] being automatically created and the second representing the receipt number.
Row#4: We are now processing receipt 4. An array key with value 4 does not exist anywhere in $this-&gt;factura (as a key representing a receipt number, and item number, or anything else), so same situation as the previous row, we create the new entry $this-&gt;factura[3][4][itemdata].
Row#5: Still on receipt 4, an array key with value 4 does now exist, so we therefore do an update as with row #2. But similarly, since receipt 4 is at $this-&gt;factura[3][4] not $this-&gt;factura[4] we inadvertently create $this-&gt;factura[4].
</ul>
<p></p>
<p>Now, try this:</p>
<div>[code]while($row = $this-&gt;stmt-&gt;fetch())
{
	$factura = $row['factura']; /*Receipt number*/
	print($factura);
	if(! array_key_exists($factura, $this-&gt;factura))
	{
		if(! in_array($factura, $this-&gt;trigger)) $this-&gt;trigger[] = $factura;
		$this-&gt;factura[$factura] = array(
			'producto_id' =&gt; array($row['producto_id']),
			'producto' =&gt; array($row['producto']),
			'cantidad' =&gt; array($row['cantidad']),
			'price_i' =&gt; array($row['price_i']),
			'tax' =&gt; array($row['tax'])
		);
	}
	else
	{
		$this-&gt;factura[$factura]['producto_id'][] =$row['producto_id'];
		$this-&gt;factura[$factura]['producto'][] =$row['producto'];
		$this-&gt;factura[$factura]['cantidad'][]= $row['cantidad'];
		$this-&gt;factura[$factura]['price_i'][] =$row['price_i'];
		$this-&gt;factura[$factura]['tax'][] = $row['tax'];
	}
}<

  • 0

Its broken (with the above fix implemented) primarily because of your array_key_exists_r() function. I'm assuming that you do understand what that function does... When processing a new row from the database, you're scanning recursively through all nested arrays within $this->factura looking for any existence of a key with a value matching the receipt number! I.e. it's checking for the existence of the receipt number amongst all existing receipt number keys, and all item number keys!!

First of all, thank you... thank you thank you...! It did the trick!!!!!!!!! :D :D :D :D:D

Before using the array_keys_r function, which I got from stackoverflow, I was using array_key_exists to verify the array, but it wasn't working as I wanted since the last receipt overwrote the previous one. I thought it was a multi-dimensional array problem so I looked up on Google and thought using that custom function. In the end it yielded the previous results I was having!

But clearly, the main problem was this little row:

$this-&gt;factura = array($factura =&gt; array('producto_id' =&gt; array($row['producto_id']),

Which you change to:

$this->factura[$factura] = array(

And through the explanation it does make a lot of sense...

I'm kind of slapping my face right now...

Really, really, really, thanks a million!

(Y)

This topic is now closed to further replies.
  • Recently Browsing   0 members

    • No registered users viewing this page.
  • Posts

    • Nice, hope they *finally* fixed the issue with the NTFS driver where the system would completely brick during large file copies using the built in driver. It's been broken for years requiring me to use the older, slower, NTFS-3G FUSE driver.
    • Windows 11 KB5094126 BSODing, freezing, forcing BitLocker lockout, breaks OneDrive, and more by Sayan Sen Microsoft released Windows 11 KB5094126 and KB5093998 last week as the latest Patch Tuesday updates. Following that the company also published the accompanying dynamic updates under KB5094149, KB5095971, and KB5094156. While Microsoft has so far not acknowledged any major problems with the release, some users online are running into problems. These range from OneDrive and Dropbox access issues, BitLocker recovery lockouts, to blue screens and BSODs. The most common one seems to be happening with HP systems wherein affected users say they hit 0xc0430001 BSOD (blue screen of death) error code after the KB5094126 update. We wonder if this could be related to the recent bug we covered on HP devices wherein the ongoing Secure Boot certificate updates are leading to similar issues. While we are not certain, users affected by this issue likely need to ensure that the boot.stl file is included on the installation media (such as a USB installer or ISO), if the above-mentioned dynamic updates are deployed. If this file is missing, computers may fail to boot from the installation media and could display the error 0xc0430001. This STL file is used by Secure Boot to verify that the boot files are trusted, so it must match the same Windows version and system architecture. To ensure the file is included, Microsoft recommends using the Update WinPE script, which automatically updates the image and handles the required files. Alternatively, you can manually copy the boot.stl file from the Windows\Boot\EFI folder on a Windows device and place it in the matching folder on your installation media before deploying the updated image. Aside from blue screening some users also note their systems have been freezing following the update. This could be happening to Lenovo PCs specifically. In the case of the OneDrive and Dropbox access issues, a user figured out that there could be a conflict with UAC. He explained: "Okay, so I did some digging, and in our environment KB5094126 breaks OneDrive and Dropbox in Explorer. I went through all our GPOs and found out that the combination of disabling UAC and having my user being a local admin breaks OneDrive in Explorer. ... If I enable UAC again, then it works, even with KB5094126 still installed." Hopefully, Microsoft will look into these issues. Source: Microsoft forum (link1, link2, link3, link4), Reddit (link1, link2, link3, link4)
    • It is when it's a desktop in my house though for a PC that's lightly used and not really important when it is. If it was a laptop, it would be a different story. The real solution is varied and begins starting at post #22 in that thread.
    • Win11Debloat 2026.06.14 by Razvan Serea Win11Debloat is a lightweight, easy to use PowerShell script that allows you to quickly declutter and customize your Windows experience. It can remove pre-installed bloatware apps, disable telemetry, remove intrusive interface elements and much more. The script also includes many features that system administrators and power users will enjoy. Such as a powerful command-line interface, support for Windows Audit mode and the option to make changes to other Windows users. All changes made by Win11Debloat can be easily reversed, and most removed apps can be restored via the Microsoft Store. A full guide on how to undo the changes is available here. Win11Debloat features: Below is an overview of the key features and functionality offered by Win11Debloat. Please refer to the wiki for more information about the default settings preset. Remove a wide variety of preinstalled apps. Click here for more info. Disable telemetry, diagnostic data, activity history, app-launch tracking & targeted ads. Disable tips, tricks, suggestions & ads across Windows. Disable Windows location services & app location access. Disable Find My Device location tracking. Disable 'Windows Spotlight' and tips & tricks on the lock screen. Disable 'Windows Spotlight' desktop background option. Disable ads, suggestions and the MSN news feed in Microsoft Edge. Hide Microsoft 365 ads on the Settings 'Home' page, or hide the 'Home' page entirely. Disable & remove Microsoft Copilot. Disable Windows Recall. Disable Click to Do, AI text & image analysis tool. Prevent AI service (WSAIFabricSvc) from starting automatically. Disable AI Features in Edge. Disable AI Features in Paint. Disable AI Features in Notepad. Disable the Drag Tray for sharing & moving files. Restore the old Windows 10 style context menu. Turn off Enhance Pointer Precision, also known as mouse acceleration. Disable the Sticky Keys keyboard shortcut. Disable Storage Sense automatic disk cleanup. Disable fast start-up to ensure a full shutdown. ...and more. Once you’ve downloaded the Win11Debloat file (Get.ps1), just follow these quick steps: Locate the Get.ps1 script file. Right-click the file and select Run with PowerShell from the context menu. If prompted by User Account Control (UAC), select Yes to grant the script the necessary administrative permissions. Win11Debloat 2026.06.14 changes: This is a minor release that hopefully addresses the false positives in Windows Defender and Bitdefender that prevented users from downloading and/or running Win11Debloat. Refactor Get-RegFileOperations.ps1 to address false positives by @Raphire in #626 Add logging around WinGet app retrieval and increase timeout to 20s by @Raphire Download: Win11Debloat 2026.06.14 | Open Source View: Win11Debloat Home Page | Screenshots 1| 2 Get alerted to all of our Software updates on Twitter at @NeowinSoftware
  • Recent Achievements

    • Week One Done
      Jeroen Wilms earned a badge
      Week One Done
    • Week One Done
      rolfus earned a badge
      Week One Done
    • One Month Later
      Leroy Jethro Gibbs earned a badge
      One Month Later
    • Conversation Starter
      flexorcist earned a badge
      Conversation Starter
    • One Month Later
      AndreaB earned a badge
      One Month Later
  • Popular Contributors

    1. 1
      +primortal
      508
    2. 2
      +Edouard
      198
    3. 3
      PsYcHoKiLLa
      138
    4. 4
      ATLien_0
      90
    5. 5
      Steven P.
      81
  • Tell a friend

    Love Neowin? Tell a friend!