Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Magento fix for parse_str() bug in CategoryController
/**
* 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);
}
}
@bannostookaylo

This comment has been minimized.

Show comment Hide comment
@bannostookaylo

bannostookaylo Aug 22, 2013

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.

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.

@bannostookaylo

This comment has been minimized.

Show comment Hide comment
@bannostookaylo

bannostookaylo Aug 22, 2013

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);
        }

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);
        }
@emrahuyanik

This comment has been minimized.

Show comment Hide comment
@emrahuyanik

emrahuyanik Nov 20, 2013

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.

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.

@Maksold

This comment has been minimized.

Show comment Hide comment
@Maksold

Maksold Feb 26, 2014

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);
            }
        }

Maksold commented Feb 26, 2014

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);
            }
        }
@profago

This comment has been minimized.

Show comment Hide comment
@profago

profago Jul 18, 2014

I'm using Magento 1.8 and I have solved the problem with a modification in

app/code/core/Mage/Adminhtml/controllers/Catalog/CategoryController.php

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

to:

            $cat_products_split = explode('&', $data['category_products']);
            foreach($cat_products_split as $row) {
            $arr = array();
            parse_str($row, $arr); //This will always work
            list($k, $v) = each($arr);
            if (!empty($k)) {
            $products[$k] = $v;
            }
            }

now it works fine.

profago commented Jul 18, 2014

I'm using Magento 1.8 and I have solved the problem with a modification in

app/code/core/Mage/Adminhtml/controllers/Catalog/CategoryController.php

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

to:

            $cat_products_split = explode('&', $data['category_products']);
            foreach($cat_products_split as $row) {
            $arr = array();
            parse_str($row, $arr); //This will always work
            list($k, $v) = each($arr);
            if (!empty($k)) {
            $products[$k] = $v;
            }
            }

now it works fine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment