Skip to content

Modified Simpla Scheme class

On one of the Simpla projects, we encountered a customization that failed with error 500: Allowed memory size of 67108864 bytes exhausted (tried to allocate 72 bytes) in /var/www/domain.com/api/Database.php

We investigated and found the cause. Conclusions:

An entity called "Node" was added; it includes N products. The class is named Scheme.

When working with images of child products, the _products->get\_images_ function is used.

The call looks like this:

# SchemeView.php
# (one example)
foreach($related_ids as $key=>$id_product)
            {
                //$p->position
                $p = $this->products->get_products(array('id'=>$id_product,  'visible'=>1, 'whith_related_custom'=>1));
                $p=reset($p);
                $p->position = array_shift($positions[$key]);
                $p->custom_number = array_shift($custom_numbe[$key]);

# HERE IT IS !!!
                $related_products_images = $this->products->get_images(array('product_id'=>array($id_product)));

#

                foreach($related_products_images as $related_product_image)
                    $p->images[] = $related_product_image;

                $related_products_variants = $this->variants->get_variants(array('product_id'=>array($id_product), 'instock'=>true));
                foreach($related_products_variants as $related_product_variant)
                {
                        $p->variants[] = $related_product_variant;
                }

                $related_products[] = $p;
            }

The products->get\_images implementation checks that the passed parameter is non-empty as follows:

if(!empty($filter['product_id'])) {
  $product_id_filter = $this->db->placehold('AND i.product_id in(?@)', (array)$filter['product_id'] );
}

Because the Scheme class developers pass the parameter as an array—array('product\_id'=>array($id\_product))—the check above does not work. Consequently, the query in the get\_image function may be formed as follows:

SELECT i.id, i.product_id, i.name, i.filename, i.position FROM __images AS i WHERE 1 AND i.product_id in('0')  ORDER BY i.product_id, i.position;

It may seem harmless, since there should not be products with an ID of 0. However, the developers of this class also "contributed." The __images table has this structure, and it contains exactly as many records with product_id = 0 as there are images for the Scheme entity—in this case, almost 65 thousand.

image

The third component of the problem: where does "0" come from?

It is found in the table that contains relationships between the Node and Product entities: image

As a result, when all conditions match, the Node view page attempts to display 65 thousand images. The code was not designed for this, and PHP runs out of memory to hold the data.

The main question: where did the "0" in the s\_related\_products table records come from? Let us leave it unanswered. :)