Cannot add more than 1000 products using Magento admin category management interface

Many people having a large catalog have faced a problem in Magento “Catalog Management” that they are not able to assign more than 1000  products under a category using the Magento admin category management interface.

Category Edit Form

The category management interface allows you to select as many products as you want.  If you have selected more than 1000 products and then you click on the “Save Category” button, the forms submits without any error displayed on the frontend. But if you see the products actually assigned to category in the grid displayed,  it may happen that all the ones you selected have not been assigned to the category but only the first 1000 selected are.

The issue is logged in Magento bug tracking list – Issue #27321 Can’t save categories with more than 1000 products [http://www.magentocommerce.com/bug-tracking/issue?issue=13203]

To locate the root cause of problem, lets check the “category_edit_form” action.  The form action is http://mymagentodomain/index.php/admin/catalog_category/save/.

According to the form action “saveAction()” method located in class Mage_Adminhtml_Catalog_CategoryController [file located at:{Magento_Root}\app\code\core\Mage\Adminhtml\controllers\Catalog\CategoryController.php] is called to assign the products to categories.

In “saveAction()” method the following piece of code is used to assign the products to categories


if (isset($data['category_products']) &&

!$category->getProductsReadonly()) {

$products = array();

parse_str($data['category_products'], $products);

$category->setPostedProducts($products);

}

The saveAction() method is using the parse_str() function.

Since PHP version 5.3.9, there is a new configuration setting “max_input_vars”  in php.ini file which is 1000 by default. It imposes a limit on the maximum number of “input variables” that may be accepted (the limit is applied to $_GET, $_POST and $_COOKIE superglobal separately). Use of this directive mitigates the possibility of denial of service attacks which use hash collisions.

The parse_str() function appears to be subject to the php.ini directive “max_input_vars”.

Following are the possible solutions that may be considered:

1. Modifying “max_input_vars” directive in php.ini file

Increase the “max_input_vars” value to a suitable value say 10000. The downside of this change is that it makes server more vulnerable to Denial of Service attacks(DoS).

2. Using .htaccess file

If you do not have access to php.ini file you may increase the value of “max_input_vars” using .htaccess file


<IfModule mod_php5.c>
php_value max_input_vars 10000
</IfModule>

A better suggested secure solution is to increase “max_input_vars” only for requests within the Magento admin URL space. It may be done as below:


<LocationMatch "eshop/(index\.php/)?admin/">
<IfModule mod_php5.c>
php_value max_input_vars 100000
</IfModule>
</LocationMatch>

3. Override the file saveAction() method in CategoryController.php file

Create a custom module to overrirde the saveAction() method located in file {Magento_Root}\app\code\core\Mage\Adminhtml\controllers\Catalog\CategoryController.phpReplace the code below [located around line no. 307] in saveAction() method


if (isset($data['category_products']) &&

!$category->getProductsReadonly()) {

$products = array();

parse_str($data['category_products'], $products);

$category->setPostedProducts($products);

}

with the following code in your custom module


if (isset($data['category_products']) &&
!$category->getProductsReadonly()) {
$products = array();

$cat_products_split = explode('&', $data['category_products']);

foreach($cat_products_split as $row) {
$arr = array();

// This will always work.
parse_str($row, $arr);

list($k, $v) = each($arr);
if (!empty($k) && !empty($v)) {
$products[$k] = $v;
}
}

if (!empty($products)) {
$category->setPostedProducts($products);
}
}

This soltion is posted on github at https://gist.github.com/mshmsh5000/3440260

Leave a Comment

Back to top