Question

I have an array that contains ip addresses and their respective subnet information. In a first time, I have to add the subnets informations into my database but I'm trying to do so without any duplicate, with this code

#Note that this is pseudo-code
foreach ($subnets as $subnet)
{
    $query = 'INSERT INTO subnets (field1, field2) 
              VALUES ($subnet['subnet'], $subnet['netmask']);'

    $database->executeQuery($query);

    $query  = 'SELECT id FROM subnets 
               WHERE subnet = $subnet['subnet'] 
               AND mask = $subnet['netmask'];'
    $subnet_id = $database->getRow($query);

    foreach ($subnets as $key => $subnet_check)
    {
        if (($subnet['subnet'] == $subnet_check['subnet']) AND ($subnet['netmask'] == $subnet_check['netmask']))
        {
            $ip_to_add = array_merge($ip_to_add,array(array("subnet_id" => $subnet_id[0], "ip" => $subnet['ip'], "name" => $subnet['name'])));
            unset($subnets[$key]);
        }
    }
}

The first foreach will add every subnet and retrieve each of their id. The second foreach will scan every subnet and try to find a duplicate (including itself). If it does, it should add the ip addresse information an array and then, unset this element since we don't want to re-insert the subnet in another loop.

Yet, this does not seem to unset it correctly since in the end, every subnets and ip addresses are inserted (inserting all the subnet brings a lot of duplicates).

Could anyone explain to me why the unset is not working correctly? Is it because I'm into a 2 level foreach?

Thank you.

Was it helpful?

Solution

The foreach() statement in PHP secretly makes a copy of the array and iterates that copy. This doesn't have any performance impact because it uses Copy-on-Write semantics so the array is only truly copied in memory if you write to it inside the foreach loop. Which you are doing here. So your two loops are actually iterating over 2 different copies of the $subnets array. When you unset from one array, that is not going to have any affect on the other.

The easiest way to do fix this will be to instruct PHP to NOT make the copy. Make this change in both your loops:

foreach(array() as &$row) {} 

or

foreach(array() as $key => &$row) {}

That said, I do think your algorithm here could be improved. So what it seems like you're doing is:

  1. Iterate each subnet
  2. Insert
  3. Query for the ID of the inserted row
  4. Re-iterate the array and add an item to $ip_to_add that includes the ID.

My question is, what do you want the $ip_to_add to look like in the end? It seems like, right now, if there are duplicates you'll only have one insert into the table but $ip_to_add will have duplicate rows? It seems like $ip_to_add will have the same number of items as your original $subnets array? Is that what you need?

If not, what I would do is:

  1. De-dupe the array
  2. Iterate it, insert it, use mysql_insert_id() to get the ID, and add that to the array.
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top