Почему Magento сохраняет только первые 1000 продуктов в категории после сохранения категории?

Используя бэк-офис Magento, после сохранения категории, связанной с множеством продуктов, сохраняются только первые 1000 продуктов (или 2000 или x000 в зависимости от конфигурации хоста).

Все другие ссылки категории / продукта удаляются из таблицы catalog_category_product в базе данных.
Это происходит, даже если флажки не отмечены в сетке продуктов (вкладка «Категория продуктов»).

Сообщение об ошибке не отображается или не регистрируется.
Данные трассировки, отправленные из браузера на сервер, не обнаруживают недостающих идентификаторов продуктов, но даже если вы проверяете больше продуктов в сетях бэк-офиса, при окончательном сохранении категории сервер сохраняет только первый x000 и удаляет другие идентификаторы. ..

Хотя некоторые ответы можно найти на других сайтах, я подумал, что стоит поделиться этим с StackOverflow …

Источник проблемы можно найти в Mage_Adminhtml_Catalog_CategoryController , где метод saveAction() извлекает большую строку POSTed ( category_products , закодированную как строка запроса), которая обрабатывается функцией PHP parse_str() :

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

Увы! Начиная с версии 5.3.9 PHP существует новый параметр конфигурации max_input_vars , который ограничивает количество входных переменных, которые могут быть приняты.
Этот предел в основном применяется к $_COOKIE $_GET , $_POST и $_COOKIE , но также используется внутри parse_str() !
(См. Руководство по PHP )

В зависимости от конфигурации php.ini вашего хоста количество продуктов, связанных с категорией, поэтому ограничено этим параметром …

Одним из решений является увеличение значения max_input_vars в php.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_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 …

Надеюсь, это все равно полезно, я боролся некоторое время, прежде чем я смог узнать, почему некоторые категории продолжают терять некоторые продукты!

Лучшим решением было бы использовать событие наблюдателя «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); } } } 

( Источник )

Я нашел рабочее решение, поэтому я делюсь им здесь!

Создайте имя файла php5.ini в magento root папке php5.ini и в первой строке просто поместите этот код

 [PHP] max_input_vars = 5000 

Теперь, если он не работает, вам нужно будет добавить эту строку в SERVER PHP, ini (/usr/local/lib/php.ini)

 max_input_vars = 5000 

Надеюсь, что это поможет.

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

сделал трюк для меня, у меня была такая же проблема, как описано выше, Magento 1.4.1.1 сохранил только 1001 продукт в категории, но после установки кода выше в моем .htaccess ошибка исчезла.

LocationMatch не разрешен в .htaccess, его можно разместить только в Apache httpd.conf

Предпочтительным способом является создание Apache, а не изменение httpd.conf напрямую, поскольку оно будет ломаться при следующем обновлении / восстановлении.

В моем случае я создал файл include 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#Пользовательски&#x435; директивы для http.conf

Я думаю, что это самое элегантное решение, не касающееся Magento Core, распространяется на все сайты вашего сервера, а также защищает интерфейс.

Решение 2 из programmeurweb прослушивается, на Magento 1.8.0.0!

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

Должен быть:

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

$ v используется для 'position' и не является флажком value = 1 (в качестве ассоциированного продукта с текущей категорией).

Я уже тестировал это. Я ошибаюсь ?

Это напоминает никогда не копировать и вставлять код из сети.

PS: Я не могу комментировать ответы сейчас.