Intereting Posts
Библиотека PHP для создания удобных относительных временных меток Как установить первый день недели в понедельник при использовании Week (Date) в PHP / MySQL? php / mysql добавить строки вместе, чтобы получить общее количество Замените цвет другим изображением с помощью PHP Выделение слов в Javascript – Почему они не будут выделены после полной загрузки страницы? Создание функции для захвата данных из базы данных Oracle (массив по идентификатору) Выполнение урока Laravel, получение «Базовой таблицы или представления не найдено: 1146 Таблица« sdbd_todo.migrations »не существует» Проблема с PHP: mysqli_error () ожидает ровно 1 параметр, 0 cURL get_data ($ url) с абсолютным URL-адресом Использование Hook_form_alter для переданных значений веб-формы Задача Cron Job $ _SERVER Построить запрос MySQL (таблица meta_key / meta_value) Отображать эхо PHP в текстовом поле, используя AJAX / jQuery? unserialize () : ошибка при смещении как обрабатывать большой размер запроса на обновление в mysql с laravel

«безопасный» json_decode (,,,) для предотвращения исчерпания памяти

В моем приложении я часто вызываю внешний api, который возвращает строку json.

$url = 'api.example.com/xyz'; $blah = json_decode( file_get_contents( $url ) ); 

Но в некоторых случаях я получаю

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

Я не могу контролировать внешний API, и, конечно, я мог бы увеличить память для php, но это имеет некоторые недостатки.

1- Какой бы размер я ни устанавливал, все равно было бы слишком мало. 2- Если я установил размер памяти «бесконечно», я мог бы рискнуть убить мой сервер.

В идеале я хотел бы «проверить», прежде чем я вызову json_decode (…), что строка приведет к исчерпанию памяти.

Это возможно?

Solutions Collecting From Web of "«безопасный» json_decode (,,,) для предотвращения исчерпания памяти"

Вы должны получать некоторые массивные ответы JSON, если им удастся исчерпать память вашего сервера. Вот некоторые показатели с файлом 1 МБ, содержащим многомерный связанный массив (содержащий данные, подготовленные для ввода в три таблицы MySQL с различными типами данных).

Когда я include и файл загружается в память в виде массива, использование моей памяти составляет 9 МБ. Если я получаю необработанные данные с помощью file_get_contents() , он занимает 1 МБ памяти, как ожидалось. Затем массив PHP имеет приблизительное отношение 1: 9 к strlen() данных (первоначально выводится с помощью var_export() ).

Когда я запускаю json_encode() , пиковое использование памяти не увеличивается. (PHP выделяет память в блоках, поэтому часто приходится немного накладных расходов, в этом случае достаточно включить строковые данные JSON, но это может увеличить число вас на один блок.) Полученные данные JSON в виде строки занимают 670 КБ.

Когда я загружаю данные JSON с помощью file_get_contents в строку, она занимает ожидаемую 0,75 МБ памяти. Когда я запускаю json_decode() на нем, он занимает 7 МБ памяти. Тогда я бы определил минимальное соотношение 1:10 для JSON-data-bytesize, декодированное для собственного массива PHP-объекта для требований к RAM.

Чтобы выполнить проверку данных JSON перед ее расшифровкой, вы можете сделать что-то вроде этого:

 if (strlen($my_json) * 10 > ($my_mb_memory * 1024 * 1024)) { die ('Decoding this would exhaust the server memory. Sorry!'); } 

… где $my_json – это сырой ответ JSON, а $my_mb_memory – ваша выделенная ОЗУ, которая преобразуется в байты для сравнения с входящими данными. (Конечно, вы также можете использовать intval(ini_get('memory_limit')) чтобы получить ограничение на память как целое.)

Как указано ниже, использование ОЗУ также будет зависеть от вашей структуры данных. Для сравнения, несколько более быстрых тестов, потому что мне любопытно:

    1. Если я создаю одномерный массив с целыми числами 1-60000, размер сохраненного массива PHP составляет 1 МБ, но пиковое использование ОЗУ составляет от 10,5 до 12,5 МБ (любопытное колебание) или соотношение 1: 12-иш.
    1. Если я создам данные достоинства 1 МБ как 12000 случайных строк в качестве базового ассоциативного массива, использование памяти составляет всего 5 МБ при загрузке; соотношение 1: 5.
    1. Если я создаю ценность 1 МБ в качестве аналогичного ассоциативного массива, где половина записей представляет собой массивы в виде строк с числовым индексом, использование памяти составляет 7 МБ, соотношение 1: 7.

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

Чтобы отлаживать использование памяти, вы можете использовать memory_get_usage() и / или memory_get_peak_usage() с большими интервалами в вашем коде для регистрации или вывода памяти, используемой в разных частях вашего кода.

Мой первый ответ выше – это чистое ограничение памяти. Теперь, как вы можете справиться с данными, если вы ненавидите их отбрасывать , но если они постоянно становятся громоздкими за пределы вашей памяти?

Предполагая, что вам не нужно, чтобы ответ обрабатывался одним выстрелом и абсолютным в реальном времени. Затем вы можете просто разделить ответ на куски подходящего размера, например, с помощью explode() или preg_split() и сохранить их во временном каталоге и обработать позже в пакетной операции.

Я полагаю, что большие ответы API возвращают сразу несколько наборов данных; если нет, вы можете также объединить одну многомерную запись в более управляемые куски, которые позже воссоединились, хотя для этого потребуется гораздо более оперативная точность в создании функции разметки JSON-строки.

Если несколько наборов данных необходимо связать в последующей обработке (например, запись в базу данных), вы также захотите иметь файл агрегатора, содержащий метаданные для пакетной операции. (Или иначе вставьте все это в базу данных.) Разумеется, вы должны убедиться, что упорядоченные данные хорошо сформированы. Это не идеальный вариант, но не наличие концертов с памятью также не является идеальным. Пакетирование – это один из способов борьбы с ним.

Вместо того, чтобы просто выйти, если файл JSON слишком велик, вы можете обрабатывать файлы JSON произвольного размера, используя парсер JSON на основе событий, такой как https://github.com/salsify/jsonstreamingparser . За один раз в память будет загружен только небольшой фрагмент объекта / массива.