为什么Magento在保存类别后只保留类别中的前1000种产品?

2022-08-30 22:01:57

使用Magento的后台,在保存链接到许多产品的类别后,仅保留前1000个产品(或2000,或x000,取决于主机配置)。

所有其他类别/产品链接将从数据库的表中删除。
即使未在产品网格(“类别产品”选项卡)中取消选中任何复选框,也会发生这种情况。catalog_category_product

不显示或记录任何错误消息。
从浏览器发布到服务器的跟踪数据不会显示任何丢失的产品ID,但即使您在后台网格上检查了更多产品,当最终保存类别时,服务器也只保留第一个x000并删除其他ID...


答案 1

虽然可以在其他网站上找到一些答案,但我认为值得在StackOverflow上分享这个...

问题的根源可以在 中找到,其中该方法检索一个大的POSTed字符串(编码为查询字符串),该字符串由PHP函数处理:Mage_Adminhtml_Catalog_CategoryControllersaveAction()category_productsparse_str()

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

唉!从 PHP 的 5.3.9 版开始,有一个名为 的新配置设置,它限制了可以接受的输入变量的数量。
此限制主要应用于 和 超全局,但也由函数内部使用!
(参见 PHP 手册max_input_vars$_GET$_POST$_COOKIEparse_str())

因此,根据主机的配置,链接到某个类别的产品数量受此设置的限制...php.ini

一种解决方案是增加 的值,在 或 在 中:max_input_varsphp.ini.htaccess

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

通过仅更改管理页面的此设置,甚至可以更安全地完成此操作(将LocationMatch模式调整为您自己的后台URL样式):

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

()

这只能解决问题,直到您的一个类别达到新的最大产品数量...

另一种解决方案是修复Magento的代码,以便此时不使用parse_str()函数。
例如,在 中,方法中,替换:Mage_Adminhtml_Catalog_CategoryControllersaveAction()

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

跟:

$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) && !empty($v)) {
        $products[$k] = $v;
    }
}

()

很难确定哪种解决方案是最好的,因为第一个解决方案使您的服务器更容易受到攻击(因为该解决方案旨在减轻使用哈希冲突的拒绝服务攻击的可能性),而第二个解决方案使您修改Magento核心类,这可能导致将来Magento升级中的进一步问题...max_input_vars

希望这无论如何都是有用的,在我找出为什么某些类别不断失去某些产品之前,我挣扎了一段时间!


答案 2

最好的解决方案是使用观察者事件“catalog_category_prepare_save”。所以你需要改变配置.xml你的模块:

<config>
    <global>
        <events>
            ...
            <catalog_category_prepare_save>
                <observers>
                    <your_module>
                         <class>your_module/observer</class>
                         <method>onCatalogCategoryPrepareSave</method>
                    </your_module>
                </observers>
            </catalog_category_prepare_save>

然后向应用/代码/本地/您的/模块/模型/观察者添加函数.php

<?php
class Your_Module_Model_Observer
{
    /**
     * 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);
        }
    }
}

()


推荐