18

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

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

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

4

6 回答 6

27

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

问题的根源可以在 中找到Mage_Adminhtml_Catalog_CategoryController,该saveAction()方法检索一个大的 POST 字符串(category_products编码为查询字符串),该字符串由 PHP 函数处理parse_str()

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

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

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

一种解决方案是增加max_input_vars、 inphp.ini或 in的值.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_CategoryController,saveAction()方法中,替换:

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

来源

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

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

于 2013-02-13T10:11:41.340 回答
5

最好的解决方案是使用观察者事件“catalog_category_prepare_save”。因此,您需要更改模块的 config.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>

然后将函数添加到 app/code/local/Your/Module/Model/Observer.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);
        }
    }
}

来源

于 2014-02-26T11:39:33.233 回答
1

我找到了一个可行的解决方案,所以我在这里分享它!

php5.ini在您的文件夹中创建一个文件名,magento root并在第一行中放置此代码

[PHP]
max_input_vars = 5000

现在,如果它不起作用,您需要在 SERVER PHP,ini (/usr/local/lib/php.ini) 中添加这一行

max_input_vars = 5000

希望它的帮助。

于 2013-09-26T12:54:00.807 回答
0

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

为我做了诀窍,我遇到了与上述相同的问题,Magento 1.4.1.1 仅在类别中保存了 1001 个产品,但将上面的代码放入我的 .htaccess 后,错误就消失了。

于 2013-05-10T08:19:12.527 回答
0

.htaccess 中不允许 LocationMatch,它只能放在 Apache httpd.conf 中

首选方法是创建一个 Apache 包含而不是直接修改 httpd.conf,因为它会在下一次更新/重建时中断。

就我而言,我创建了一个包含文件pre_virtualhost_global.conf并将此代码放入其中:

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

之后当然需要重启apache。我使用了我的 WebHostManager,所以这是一个简单的过程。

更多信息可以在以下位置找到:

[http://docs.cpanel.net/twiki/bin/view/EasyApache3/WebHome#Custom Directives to http.conf][1]

我认为这是最优雅的解决方案,不涉及 Magento Core,适用于您服务器上的所有站点,还可以保护前端。

[1]:https ://web.archive.org/web/20140804033608/http://docs.cpanel.net:80/twiki/bin/view/EasyApache3/WebHome? #Custom Directives to http.conf

于 2013-09-12T22:57:13.847 回答
0

在 Magento 1.8.0.0 上,programurweb 的解决方案 2 有问题!

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

它应该是:

if (!empty($k)) {
    $products[$k] = $v;
}

$v 用于“位置”,而不是复选框值 = 1(将产品关联到当前类别复选框)。

我已经对此进行了测试。我错了吗 ?

这提醒了永远不要从网络复制和粘贴代码。

PS:我现在不能评论答案。

于 2014-04-24T20:38:43.780 回答