18

Magentoのバックオフィスを使用して、多くの製品にリンクされたカテゴリを保存した後、最初の1000製品(またはホスト構成によっては2000、またはx000)のみが保持されます。

他のすべてのカテゴリ/製品リンクはcatalog_category_product、データベースのテーブルから削除されます。
これは、製品グリッド([カテゴリ製品]タブ)でチェックボックスがオフになっていない場合でも発生します。

エラーメッセージは表示または記録されません。
ブラウザからサーバーに投稿されたデータをトレースしても、不足している製品IDは明らかになりませんが、バックオフィスグリッドでさらに多くの製品をチェックしても、最終的にカテゴリを保存すると、サーバーは最初のx000のみを保持し、他のIDを削除します。 ..

4

6 に答える 6

27

他のウェブサイトでいくつかの答えを見つけることができますが、StackOverflowでこれを共有する価値があると思いました...

問題の原因はにありますMage_Adminhtml_Catalog_CategoryController。ここで、メソッドは、PHP関数によって処理されるsaveAction()大きなPOST文字列(クエリ文字列のようにエンコードされた)を取得します。category_productsparse_str()

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

ああ!max_input_varsPHPのバージョン5.3.9以降、受け入れることができる入力変数の数を制限する、と呼ばれる新しい構成設定があります。
この制限は主に$_GET$_POSTおよびスーパーグローバルに適用されますが、関数$_COOKIEによって内部的にも使用されます。 (PHPマニュアルを参照)parse_str()

php.iniしたがって、ホストの構成に応じて、カテゴリにリンクされる製品の数はこの設定によって制限されます...

1つの解決策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>

出典

これは、カテゴリの1つが新しい最大数の製品に達するまで問題を解決するだけです...

別の解決策は、この時点でparse_str()関数を使用しないようにMagentoのコードを修正することです。
たとえば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;
    }
}

出典

最初のソリューションはサーバーを攻撃に対してより脆弱にするため(max_input_varsハッシュ衝突を使用するサービス拒否攻撃の可能性を軽減するため)、2番目のソリューションは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

LocationMatch は .htaccess では許可されていません。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#http.conf へのカスタム ディレクティブ][1]

これは最も洗練されたソリューションだと思います。Magento Core には触れず、サーバー上のすべてのサイトに適用され、フロントエンドも保護されます。

[1]: https://web.archive.org/web/20140804033608/http://docs.cpanel.net:80/twiki/bin/view/EasyApache3/WebHome?#http.confへのカスタム ディレクティブ

于 2013-09-12T22:57:13.847 に答える
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 に答える