public
Last active

Magento fix for parse_str() bug in CategoryController

  • Download Gist
CategoryController.partial.php
PHP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
/**
* Addresses this bug: http://www.magentocommerce.com/bug-tracking/issue/?issue=13203
*
* See app/code/core/Mage/Adminhtml/controllers/Catalog/CategoryController.php
* Mage_Adminhtml_Catalog_CategoryController::saveAction(), starting around
* line 307
*/
if (isset($data['category_products']) &&
!$category->getProductsReadonly()) {
$products = array();
 
// This can be a massive request -- i.e., all product IDs in this category.
// So we need to step through this instead of calling parse_str(), which can
// run up against the max_input_vars limit.
// parse_str($data['category_products'], $products);
 
$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);
}
}

I'm not sure why but this chunk of code doesn't seem to work for me on Magento 1.7.0.2 ... I wish I could figure out how to debug it for you to get you further details.

Just a heads up this code worked

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

            $records = preg_split('/&/',$data['category_products'],-1,PREG_SPLIT_NO_EMPTY);
            if(count($records) > 0){
                foreach($records as $record){
                    $record = trim($record);
                    if(preg_match('/([0-9]*)=([0-9]*)/',$record,$matches)){
                        $products[$matches[1]] = $matches[2];
                    }
                }
            }

            $category->setPostedProducts($products);
        }

ts magento bug.in php.ini file, set
max_input_vars =10000

parse_str function can not parse an array above this number, and its "1000" at default configuration.

Better is to use observer event "catalog_category_prepare_save".

        /**
         * Fix bug with saving only first 1000 products in a category
         * It's related to default php config 'max_input_vars' = 1000
         *
         * @param Varien_Event_Observer $observer
         */
         public function onCatalogCategoryPrepareSave(Varien_Event_Observer $observer)
         {
             $phpDefaultMaxInputVars = (int)ini_get('max_input_vars');
            /** @var Mage_Core_Controller_Request_Http $request */
            $request = $observer->getRequest();
            $dataProducts = $request->getPost('category_products');
            $dataProducts = preg_split('/&/', $dataProducts, -1, PREG_SPLIT_NO_EMPTY);
            /** @var Mage_Catalog_Model_Category $category */
            $category = $observer->getCategory();

            if ($dataProducts && !$category->getProductsReadonly() && count($dataProducts) > $phpDefaultMaxInputVars) {
                $products = array();
                foreach ($dataProducts as $_product) {
                    $_product = trim($_product);
                    if (preg_match('/([0-9]*)=([\-]?[0-9]*)/', $_product, $matches)) {
                        $products[$matches[1]] = $matches[2];
                    }
                }
                $category->setPostedProducts($products);
            }
        }

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.