Десериализация с ограничениями памяти / размера - PullRequest
4 голосов
/ 16 июня 2020

Есть ли способ использовать unserialize с ограничением памяти / размера?

В настоящее время у нас есть:

$data = unserialize($_SESSION['visits']);

, и мы иногда получаем:

PHP Неустранимая ошибка: разрешенный объем памяти 134217728 байт исчерпан (попытка выделить 17645568 байт) в Неизвестном в строке 0

, когда посетитель посетил много раз за короткий период время (значение сеанса хранит информацию о каждой посещенной странице).

Если длина $_SESSION['visits'] превышает миллион символов, это вызывает проблему, поэтому я могу выполнить простую проверку, но есть ли лучшее решение, чем это:

 if(strlen($_SESSION['visits']) <= 1000000) {
    $data = unserialize($_SESSION['visits']);
} else {
    $data = array();
}

Я думал, что try catch может вести себя лучше, но его не поймали:

try{
    $data = unserialize($_SESSION['vists']);
} catch(\Exception $exception){
    error_log('Caught memory limit');
}

Ответ на этот вопрос - не увеличивать размер памяти.

Ответы [ 2 ]

4 голосов
/ 04 июля 2020

Есть два варианта:

a) десериализация в другом phpprocess

Что может дать сбой с ошибкой ограничения памяти и, возможно, вернуть обратно только те данные, которые вас интересуют.

Как?

  1. создать собственный php скрипт / файл, который:
    1. вызывает автозагрузчик / приложение инициализации
    2. десериализует переданное значение через файл или $argv
  2. вызовите этот сценарий, используя exec()

, чтобы ответить на вопрос, вы можете:

  • либо вернуть использование памяти из настраиваемого сценария (и проверьте, будет ли эта память доступна в родительском сценарии)
  • ИЛИ вернуть только те данные, которые вас интересуют в обратном файле или стандартный вывод

b) используйте пользовательский парсер

Like https://github.com/xKerman/restricted-unserialize, который позволяет:

  • десериализовать по отдельным значениям и проверять, достаточно ли у вас памяти раньше (та же проблема, но с небольшими данные вы можете проверить намного лучше)
  • просматривать данные без unser их полная инициализация (без использования дополнительной памяти)

c) использование базы данных

Два указанных выше варианта являются решением ваших требований. Однако я настоятельно рекомендую хранить данные сеанса / посещений в базе данных, а затем сохранять для них только уникальный идентификатор.

2 голосов
/ 04 июля 2020

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

Различия в использовании памяти

$a = memory_get_usage();
$data = serialize(array(1 => 1, 0 => 2, 3 => 3));
$b = memory_get_usage();
$c = $b - $a;
echo $c; //Outputs 296

И когда одни и те же данные упакованы в виде двоичной строки.

$a = memory_get_usage();
$data = pack("C*",array(1 => 1, 0 => 2, 3 => 3));
$b = memory_get_usage();
$c = $b - $a;
echo $c; //Outputs 72

Экономит вашу память намного больше, чем ожидалось, и очень эффективный.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...