unserialize

(PHP 4, PHP 5, PHP 7, PHP 8)

unserialize β€” Π‘ΠΎΠ·Π΄Π°Ρ‘Ρ‚ PHP-Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ ΠΈΠ· Ρ…Ρ€Π°Π½ΠΈΠΌΠΎΠ³ΠΎ прСдставлСния

ОписаниС

function unserialize(string $data, array $options = []): mixed

Ѐункция unserialize() ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Π΅Ρ‚ ΠΎΠ΄Π½Ρƒ ΡΠ΅Ρ€ΠΈΠ°Π»ΠΈΠ·ΠΎΠ²Π°Π½Π½ΡƒΡŽ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΡƒΡŽ ΠΈ ΠΊΠΎΠ½Π²Π΅Ρ€Ρ‚ΠΈΡ€ΡƒΠ΅Ρ‚ Π΅Ρ‘ ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎ Π² PHP-Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅.

Π’Π½ΠΈΠΌΠ°Π½ΠΈΠ΅

НСльзя ΠΏΠ΅Ρ€Π΅Π΄Π°Π²Π°Ρ‚ΡŒ Π² Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ unserialize() Π½Π΅Π½Π°Π΄Ρ‘ΠΆΠ½Ρ‹Π΅ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΈΠ΅ Π²Ρ…ΠΎΠ΄Π½Ρ‹Π΅ Π΄Π°Π½Π½Ρ‹Π΅ нСзависимо ΠΎΡ‚ значСния ΠΎΠΏΡ†ΠΈΠΈ allowed_classes Π² ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Π΅ options. ΠŸΡ€ΠΈ дСсСриализации функция воссоздаёт ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹ ΠΈ автоматичСски Π·Π°Π³Ρ€ΡƒΠΆΠ°Π΅Ρ‚ классы, Ρ‡Ρ‚ΠΎ Π²Π΅Π΄Ρ‘Ρ‚ ΠΊ риску Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ ΠΈ выполнСния ΠΊΠΎΠ΄Π°, Ρ‡Π΅ΠΌ ΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚ΡΡ Π·Π»ΠΎΡƒΠΌΡ‹ΡˆΠ»Π΅Π½Π½ΠΈΠΊΠΈ. ВмСсто этого ΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚ΡΡ бСзопасным стандартным Ρ„ΠΎΡ€ΠΌΠ°Ρ‚ΠΎΠΌ ΠΎΠ±ΠΌΠ΅Π½Π° Π΄Π°Π½Π½Ρ‹ΠΌΠΈ Π½Π°ΠΏΠΎΠ΄ΠΎΠ±ΠΈΠ΅ JSON, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°ΡŽΡ‚ функциями json_decode() ΠΈ json_encode(), Ссли сСриализованныС Π΄Π°Π½Π½Ρ‹Π΅ трСбуСтся ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‚ΡŒ ΠΊΠ»ΠΈΠ΅Π½Ρ‚Ρƒ.

Π”Π°Π½Π½Ρ‹Π΅ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΡΡŽΡ‚ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠ΅ΠΉ hash_hmac(), ΠΊΠΎΠ³Π΄Π° трСбуСтся Π΄Π΅ΡΠ΅Ρ€ΠΈΠ°Π»ΠΈΠ·ΠΎΠ²Π°Ρ‚ΡŒ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ хранится Π²ΠΎ внСшнСм источникС. Π Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΈ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΡΡŽΡ‚, Ρ‡Ρ‚ΠΎ Π΄Π°Π½Π½Ρ‹Π΅ Π½ΠΈΠΊΡ‚ΠΎ Π½Π΅ ΠΈΠ·ΠΌΠ΅Π½ΠΈΠ», ΠΊΡ€ΠΎΠΌΠ΅ Π½ΠΈΡ… самих.

Бписок ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΎΠ²

data

БСриализованная строка.

ПослС восстановлСния ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π°, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Ρ…Ρ€Π°Π½ΠΈΡ‚ пСрСмСнная, PHP автоматичСски Π²Ρ‹Π·ΠΎΠ²Π΅Ρ‚ магичСскиС ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹ __unserialize() ΠΈ __wakeup(), Ссли эти ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹ ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΠ»ΠΈ Π² классС ΠΈ ΠΏΡ€ΠΈ дСсСриализации Π½Π΅ Π²ΠΎΠ·Π½ΠΈΠΊΠ»ΠΎ ошибок.

Π—Π°ΠΌΠ΅Ρ‡Π°Π½ΠΈΠ΅: Π”ΠΈΡ€Π΅ΠΊΡ‚ΠΈΠ²Π° unserialize_callback_func

Callback-функция, ΠΊΠΎΡ‚ΠΎΡ€ΡƒΡŽ ΡƒΠΊΠ°Π·Π°Π»ΠΈ Π² Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΈΠ²Π΅ unserialize_callback_func, вызываСтся ΠΏΡ€ΠΈ дСсСриализации Π½Π΅ΠΎΠΏΡ€Π΅Π΄Π΅Π»Ρ‘Π½Π½ΠΎΠ³ΠΎ класса. PHP создаст ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ класса __PHP_Incomplete_Class, Ссли callback-Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ Π½Π΅ ΡƒΠΊΠ°Π·Π°Π»ΠΈ.

options

Ассоциативный массив ΠΎΠΏΡ†ΠΈΠΉ для Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ unserialize().

ДопустимыС ΠΎΠΏΡ†ΠΈΠΈ
Имя Вип ОписаниС
allowed_classes array|bool ΠžΠΏΡ†ΠΈΡ ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Π΅Ρ‚ Π»ΠΈΠ±ΠΎ массив (array) с названиями классов, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΏΡ€ΠΈΠΌΠ΅Ρ‚ функция, Π»ΠΈΠ±ΠΎ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ false, Ρ‡Ρ‚ΠΎΠ±Ρ‹ функция Π½Π΅ ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Π»Π° Π½ΠΈΠΊΠ°ΠΊΠΈΠ΅ классы, Π»ΠΈΠ±ΠΎ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ true, Ρ‡Ρ‚ΠΎΠ±Ρ‹ функция ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Π»Π° всС классы. ВмСсто ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π°, класс ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ³ΠΎ Π½Π΅ Ρ€Π°Π·Ρ€Π΅ΡˆΠ°Π»ΠΈ ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Ρ‚ΡŒ, функция unserialize() создаст ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ класса __PHP_Incomplete_Class, Ссли ΠΎΠΏΡ†ΠΈΡŽ ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΠ»ΠΈ ΠΈ функция встрСтит Π½Π΅Ρ€Π°Π·Ρ€Π΅ΡˆΡ‘Π½Π½Ρ‹ΠΉ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ класса. ΠŸΡ€ΠΎΠΏΡƒΡΠΊ ΠΎΠΏΡ†ΠΈΠΈ равносилСн ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½ΠΈΡŽ значСния true: PHP попытаСтся ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹ любого класса. ΠžΠΏΡ†ΠΈΡ Π½Π΅ влияСт Π½Π° пСрСчислСния.
max_depth int ΠžΠΏΡ†ΠΈΡ устанавливаСт Π³Π»ΡƒΠ±ΠΈΠ½Ρƒ структур, ΠΊΠΎΡ‚ΠΎΡ€ΡƒΡŽ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ Ρ€Π°Π·Ρ€Π΅ΡˆΠ°Π΅Ρ‚ΡΡ Π΄Π΅ΡΠ΅Ρ€ΠΈΠ°Π»ΠΈΠ·ΠΎΠ²Π°Ρ‚ΡŒ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΡ€Π΅Π΄ΠΎΡ‚Π²Ρ€Π°Ρ‚ΠΈΡ‚ΡŒ ΠΏΠ΅Ρ€Π΅ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ стСка. По ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ ΠΎΠ³Ρ€Π°Π½ΠΈΡ‡Π΅Π½ΠΈΠ΅ Π³Π»ΡƒΠ±ΠΈΠ½Ρ‹ составляСт 4096 ΡƒΡ€ΠΎΠ²Π½Π΅ΠΉ ΠΈ ΠΎΡ‚ΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ΡΡ ΠΏΡƒΡ‚Ρ‘ΠΌ установки для ΠΎΠΏΡ†ΠΈΠΈ max_depth значСния 0.

Π’ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅ΠΌΡ‹Π΅ значСния

Ѐункция Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ прСобразования Π² Π²ΠΈΠ΄Π΅ значСния bool, int, float, string, array ΠΈΠ»ΠΈ object.

Ѐункция Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ false ΠΈ Π²Ρ‹Π΄Π°Ρ‘Ρ‚ ΠΎΡˆΠΈΠ±ΠΊΡƒ уровня E_WARNING, Ссли строка Π½Π΅ поддаётся дСсСриализации.

Ошибки

Π›ΡƒΡ‡ΡˆΠ΅ ΠΏΡ€Π΅Π΄ΡƒΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΡƒ ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠΉ Throwable, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹ ΠΈΠ½ΠΎΠ³Π΄Π° Π²Ρ‹Π±Ρ€Π°ΡΡ‹Π²Π°ΡŽΡ‚ Π² своих ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠ°Ρ… дСсСриализации.

Начиная с PHP 8.4.0 функция unserialize() выбрасываСт ΠΎΡˆΠΈΠ±ΠΊΡƒ TypeError ΠΈΠ»ΠΈ ValueError, Ссли Π² элСмСнтС allowed_classes ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Π° options ΠΏΠ΅Ρ€Π΅Π΄Π°Π»ΠΈ Π½Π΅ массив (array) с названиями классов ΠΈ Π½Π΅ логичСскоС Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ (bool).

Бписок измСнСний

ВСрсия ОписаниС
8.4.0 Π’Π΅ΠΏΠ΅Ρ€ΡŒ выбрасываСт ΠΎΡˆΠΈΠ±ΠΊΡƒ TypeError ΠΈΠ»ΠΈ ValueError, Ссли элСмСнт allowed_classes ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Π° options Π½Π΅ являСтся Π½ΠΈ массивом ΠΈΠΌΡ‘Π½ классов, Π½ΠΈ логичСским Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ΠΌ (bool).
8.4.0 ДСсСриализация строк с использованиСм Ρ‚Π΅Π³Π° Π² Π²Π΅Ρ€Ρ…Π½Π΅ΠΌ рСгистрС "S" Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ объявлСна ΡƒΡΡ‚Π°Ρ€Π΅Π²ΡˆΠ΅ΠΉ; вмСсто Π½Π΅Π³ΠΎ ΠΏΡ€ΠΈΠΌΠ΅Π½ΡΡŽΡ‚ Ρ‚Π΅Π³ Π² Π½ΠΈΠΆΠ½Π΅ΠΌ рСгистрС "s".
8.3.0 Ѐункция Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ Π²Ρ‹Π΄Π°Ρ‘Ρ‚ ΠΎΡˆΠΈΠ±ΠΊΡƒ уровня E_WARNING, ΠΊΠΎΠ³Π΄Π° входная строка содСрТит Π½Π΅ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Π½Π½Ρ‹Π΅ Π΄Π°Π½Π½Ρ‹Π΅.
8.3.0 Ѐункция Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ Π²Ρ‹Π΄Π°Ρ‘Ρ‚ ΠΎΡˆΠΈΠ±ΠΊΡƒ уровня E_WARNING, Ссли строку Π½Π΅Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ Π΄Π΅ΡΠ΅Ρ€ΠΈΠ°Π»ΠΈΠ·ΠΎΠ²Π°Ρ‚ΡŒ; Ρ€Π°Π½ΡŒΡˆΠ΅ Π²Ρ‹Π΄Π°Π²Π°Π»Π°ΡΡŒ ошибка уровня E_NOTICE.
7.4.0 Π’ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ options Π΄ΠΎΠ±Π°Π²ΠΈΠ»ΠΈ элСмСнт max_depth, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ устанавливаСт ΠΌΠ°ΠΊΡΠΈΠΌΠ°Π»ΡŒΠ½ΡƒΡŽ Π³Π»ΡƒΠ±ΠΈΠ½Ρƒ дСсСриализации структур.
7.1.0 Для элСмСнта allowed_classes Π² ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Π΅ options ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΠ»ΠΈ строгий Ρ‚ΠΈΠΏ, поэтому функция unserialize() Π²Π΅Ρ€Π½Ρ‘Ρ‚ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ false ΠΈ Π²Ρ‹Π·ΠΎΠ²Π΅Ρ‚ ΠΎΡˆΠΈΠ±ΠΊΡƒ уровня E_WARNING, Ссли Π² элСмСнтС ΠΏΠ΅Ρ€Π΅Π΄Π°Π»ΠΈ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ Π½Π΅ с Ρ‚ΠΈΠΏΠΎΠΌ array ΠΈΠ»ΠΈ bool.

ΠŸΡ€ΠΈΠΌΠ΅Ρ€Ρ‹

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ #1 ΠŸΡ€ΠΈΠΌΠ΅Ρ€ воссоздания PHP-значСния ΠΈΡ… Ρ…Ρ€Π°Π½ΠΈΠΌΠΎΠ³ΠΎ прСдставлСния Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠ΅ΠΉ unserialize()

<?php

// Π’Ρ‹Π·ΠΎΠ²Π΅ΠΌ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ unserialize(), Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π·Π°Π³Ρ€ΡƒΠ·ΠΈΡ‚ΡŒ Π΄Π°Π½Π½Ρ‹Π΅ сСссии Π² массив
// $session_data ΠΈΠ· строки, ΠΊΠΎΡ‚ΠΎΡ€ΡƒΡŽ ΠΈΠ·Π²Π»Π΅ΠΊΠ»ΠΈ ΠΈΠ· Π±Π°Π·Ρ‹ Π΄Π°Π½Π½Ρ‹Ρ….
// Π­Ρ‚ΠΈΠΌ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ΠΎΠΌ дополняСтся ΠΏΡ€ΠΈΠΌΠ΅Ρ€, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ описываСт докумСнтация Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ serialize()

$conn = odbc_connect("webdb", "php", "chicken");
$stmt = odbc_prepare($conn, "SELECT data FROM sessions WHERE id = ?");
$sqldata = array($_SERVER['PHP_AUTH_USER']);

if (!odbc_execute($stmt, $sqldata) || !odbc_fetch_into($stmt, $tmp)) {
    // Π˜Π½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΡƒΠ΅ΠΌ пустой массив, Ссли Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ запроса ΠΈΠ»ΠΈ ΠΈΠ·Π²Π»Π΅Ρ‡Π΅Π½ΠΈΠ΅ Π΄Π°Π½Π½Ρ‹Ρ… Π·Π°Π²Π΅Ρ€ΡˆΠΈΠ»ΠΎΡΡŒ ошибкой
    $session_data = array();
} else {
    // Π­Π»Π΅ΠΌΠ΅Π½Ρ‚ $tmp[0] Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ содСрТит сСриализованныС Π΄Π°Π½Π½Ρ‹Π΅
    $session_data = unserialize($tmp[0]);

    if (!is_array($session_data)) {
        // Π§Ρ‚ΠΎ-Ρ‚ΠΎ пошло Π½Π΅ Ρ‚Π°ΠΊ, ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΡƒΠ΅ΠΌ пустой массив
        $session_data = array();
    }
}

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ #2 ΠŸΡ€ΠΈΠΌΠ΅Ρ€ установки callback-Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ Ρ‡Π΅Ρ€Π΅Π· Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΈΠ²Ρƒ unserialize_callback_func

<?php

$serialized_object='O:1:"a":1:{s:5:"value";s:3:"100";}';

ini_set('unserialize_callback_func', 'mycallback'); // УстанавливаСм свою callback-Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ

function mycallback($classname)
{
    // ΠŸΡ€ΠΎΡΡ‚ΠΎ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ Ρ„Π°ΠΉΠ» с ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½ΠΈΠ΅ΠΌ класса;
    // пСрСмСнная $classname ΡƒΠΊΠ°Π·Ρ‹Π²Π°Π΅Ρ‚, ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½ΠΈΠ΅ ΠΊΠ°ΠΊΠΎΠ³ΠΎ класса трСбуСтся
    var_dump($classname);
}

unserialize($serialized_object);

ΠŸΡ€ΠΈΠΌΠ΅Ρ‡Π°Π½ΠΈΡ

Π’Π½ΠΈΠΌΠ°Π½ΠΈΠ΅

Π—Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ false возвращаСтся ΠΊΠ°ΠΊ ΠΏΡ€ΠΈ ошибкС, Ρ‚Π°ΠΊ ΠΈ ΠΏΡ€ΠΈ дСсСриализации сСриализованного значСния false. Π­Ρ‚ΠΎΡ‚ случай ΠΎΡ‚Π»Π°Π²Π»ΠΈΠ²Π°ΡŽΡ‚ ΠΏΡƒΡ‚Ρ‘ΠΌ сравнСния значСния Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Π° data со Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ΠΌ, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ Π²Ρ‹Π·ΠΎΠ² serialize(false), ΠΈΠ»ΠΈ ΠΏΡƒΡ‚Ρ‘ΠΌ ΠΏΠ΅Ρ€Π΅Ρ…Π²Π°Ρ‚Π° ошибки уровня E_WARNING.

Π‘ΠΌΠΎΡ‚Ρ€ΠΈΡ‚Π΅ Ρ‚Π°ΠΊΠΆΠ΅

οΌ‹Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ

ΠŸΡ€ΠΈΠΌΠ΅Ρ‡Π°Π½ΠΈΡ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΉ 24 notes

up
105
me+phpnet at unreal4u dot com ΒΆ
8 years ago
Just some reminder which may save somebody some time regarding the `$options` array: 

Say you want to be on the safe side and not allow any objects to be unserialized... My first thought was doing the following:

<?php
$lol = unserialize($string, false);
// This will generate:
// Warning: unserialize() expects parameter 2 to be array, boolean given
?>

The correct way of doing this is the following:
<?php
$lol = unserialize($string, ['allowed_classes' => false]);
?>

Hope it helps somebody!
up
13
karsten at dambekalns dot de ΒΆ
5 years ago
Keep in mind that the allowed_classes does not use inheritance, i.e. allowing an interface is not possible and sub-classes won't pass the check. See https://3v4l.org/tdHfl
up
34
ErnestV ΒΆ
13 years ago
Just a note - if the serialized string contains a reference to a class that cannot be instantiated (e.g. being abstract) PHP will immediately die with a fatal error. If the unserialize() statement is preceded with a '@' to avoid cluttering the logs with warns or notices there will be absolutely no clue as to why the script stopped working. Cost me a couple of hours...
up
12
daniel at fourstaples dot com ΒΆ
16 years ago
Here's a simple function to get the class of a serialized string (that is, the type of object that will be returned if it's unserialized):

<?php
function get_serial_class($serial) {
    $types = array('s' => 'string', 'a' => 'array', 'b' => 'bool', 'i' => 'int', 'd' => 'float', 'N;' => 'NULL');
    
    $parts = explode(':', $serial, 4);
    return isset($types[$parts[0]]) ? $types[$parts[0]] : trim($parts[2], '"'); 
}
?>

I use this when saving a serialized object to a cookie, to make sure it is the right type when I go to unserialize it.

The type names are the same format/case as you would see if you did a var_dump().
up
12
hadley8899 at gmail dot com ΒΆ
6 years ago
For the people who are getting the error 

PHP Notice:  unserialize(): Error at offset 191 of 285 bytes in ...

and are getting the data from a database, Make sure that you have the database set the the correct encoding, I had the database set as latin1_swedish_ci and all of the data looked perfect, Infact when i copied it into a online unserialize it worked fine. I changed the collation to utf8mb4_unicode_ci and all worked fine.
up
7
bjd ΒΆ
9 years ago
Talk on Exploiting PHP7 Unserialize here: https://media.ccc.de/v/33c3-7858-exploiting_php7_unserialize
up
10
Ray.Paseur often uses Gmail ΒΆ
13 years ago
In the Classes and Objects docs, there is this: In order to be able to unserialize() an object, the class of that object needs to be defined.

Prior to PHP 5.3, this was not an issue.  But after PHP 5.3 an object made by SimpleXML_Load_String() cannot be serialized.  An attempt to do so will result in a run-time failure, throwing an exception.  If you store such an object in $_SESSION, you will get a post-execution error that says this:

Fatal error: Uncaught exception 'Exception' with message 'Serialization of 'SimpleXMLElement' is not allowed' in [no active file]:0 Stack trace: #0 {main} thrown in [no active file] on line 0

The entire contents of the session will be lost.  Hope this saves someone some time!

<?php // RAY_temp_ser.php
error_reporting(E_ALL);
session_start();
var_dump($_SESSION);
$_SESSION['hello'] = 'World';
var_dump($_SESSION);

// AN XML STRING FOR TEST DATA
$xml = '<?xml version="1.0"?>
<families>
  <parent>
    <child index="1" value="Category 1">Child One</child>
  </parent>
</families>';

// MAKE AN OBJECT (GIVES SimpleXMLElement)
$obj = SimpleXML_Load_String($xml);

// STORE THE OBJECT IN THE SESSION
$_SESSION['obj'] = $obj;
up
9
arbie samong ΒΆ
17 years ago
__PHP_Incomplete_Class Object Demystified

1. First take note of the output. A simple example:

__PHP_Incomplete_Class Object (
[__PHP_Incomplete_Class_Name] => SomeObject1
[obj1property1] => somevalue1 [obj1property2] => __PHP_Incomplete_Class Object ( [__PHP_Incomplete_Class_Name] => SomeObject2 [obj2property1] => somevalue1 [obj2property2] => Array (
['key1'] => somevalue3, ['key2'] => somevalue4 ) ) )

2. We analyze this and break it down. 
__PHP_Incomplete_Class Object tells you there is an object that needs to be declared somehow. 
__PHP_Incomplete_Class_Name simply tells you the expected class name. It is just one of the properties for now.

So we have:
a) an unknown object that has a class name SomeObject1 (first class)
b) it has 2 properties, namely obj1property1 and obj2property2
c) obj2property2 is itself an object whose class name is SomeObject2 (the second class)
d) SomeObject2 has two properties, obj2property1 and obj2property2
e) obj2property2 is an array that contains two elements

3. Now that we have an idea of the structure, we shall create class definitions based from it. We will just create properties for now, methods are not required as a minimum.

<?php
class SomeObject1 {
        public $obj1property1;
        public $obj1property2;
}
class SomeObject2 {
        public $obj2property1;
        public $obj2property2;
}
?>

4. Have that accessible to your script and it will solve the __PHP_Incomplete_Class Object problem as far as the output is concerned. Now you will have:

SomeObject1 ( [obj1property1] => somevalue1 [obj1property2] => SomeObject2 ( [obj2property1] => somevalue1 [obj2property2] => Array ( ['key1'] => somevalue3, ['key2'] => somevalue4 ) ) )

As you will notice, __PHP_Incomplete_Class Object is gone and replaced by the class name. The property __PHP_Incomplete_Class_Name is also removed.

5. As for the array property obj2property2, we can directly access that and just assume that it is an array and loop through it:

<?php

// this will be SomeObject1 
$data = unserialize($serialized_data);

// this will be SomeObject2
$data2 = $data->obj1property2();

foreach($data2->obj2property2 as $key => $value):
         print $key.' : '. $value .'<br>'; 
endforeach;

?>

Outputs:
key1 : somevalue3
key2 : somevalue4

That's it. You can add more methods on the class declarations for the given properties, provided you keep your original output as basis for the data types.
up
4
chris at pollett dot org ΒΆ
11 years ago
When you serialize an object of a class from a particular namespace, the namespace is recorded as part of the serialization. If you decide to change this namespace's name, it can be hard to read in old serialized objects. I.e., suppose you had serialized an object of type foo\A, you change the namespace of your project to goo but otherwise leave the class definition of A unchanged. You would like to be able to unserialize the object as goo\A, instead unserialization will only create a partial object. To fix this in the case where you don't have nested objects in your class definition, you can use the following simple rename function:
/**
 * Used to change the namespace of a serialized php object (assumes doesn't
 * have nested subobjects)
 *
 * @param string $class_name new fully qualified name with namespace
 * @param string $object_string serialized object
 *
 * @return string serialized object with new name
 */
function renameSerializedObject($class_name, $object_string)
{
    /*  number of digits in the length of name of the object needs to be 
        less than 12 digits (probably more like 4) for this to work.
    */
    $name_length = intval(substr($object_string, 2, 14));
    $name_space_info_length = strlen("O:".$name_length.":") +
        $name_length + 2; // 2 for quotes;
    $object_string = 'O:' .
        strlen($class_name) . ':"'. $class_name.'"' .
        substr($object_string, $name_space_info_length);
    return $object_string;
}
up
9
chris AT cmbuckley DOT co DOT uk ΒΆ
18 years ago
As mentioned in the notes, unserialize returns false in the event of an error and for boolean false. Here is the first solution mentioned, without using error handling:

<?php
function isSerialized($str) {
    return ($str == serialize(false) || @unserialize($str) !== false);
}

var_dump(isSerialized('s:6:"foobar";')); // bool(true)
var_dump(isSerialized('foobar'));        // bool(false)
var_dump(isSerialized('b:0;'));          // bool(true)
?>
up
5
BenBE at omorphia dot de ΒΆ
19 years ago
When trying to serialize or unserialize recursive arrays or otherwise linked data you might find the undocumented R data type quite useful.

If you want a array like the one produced with
<?
$a = array();
$a[0] =& $a;
?>
serialized you can store it using a string simular to this one:
<?
$a = unserialize("a:1:{i:0;R:1;}");
?>

Both sources will make $a hold an array that self-references itself in index 0.

The argument for R is the index of the created sub-variable of the serialize-string beginning with 1.
up
2
w dot laurencine at teknoa dot net ΒΆ
17 years ago
When dealing with a string which contain "\r", it seems that the length is not evaluated correctly. The following solves the problem for me :

<?php
// remove the \r caracters from the $unserialized string
$unserialized = str_replace("\r","",$unserialized);

// and then unserialize()
unserialize($unserialized);
?>
up
3
Are Pedersen ΒΆ
20 years ago
Be aware that if useing serialize/unserialize in a serverfarm with both 32bit and 64bit servers you can get unexpected results.

Ex: if you serialize an integer with value of 2147483648 on a 64bit system and then unserialize it on a 32bit system you will get the value -2147483648 instead. This is because an integer on 32bit cannot be above 2147483647 so it wraps.
up
2
Chris Hayes (chris at hypersites dot com) ΒΆ
21 years ago
In reply to the earlier post about having to include object definitions *before* using unserialize.  There is a workaround for this.

When an object is serialized, the first bit of the string is actually the name of the class.  When an unknown object is unserialized, this is maintained as a property.  So if you serialize it again, you get back the exact same string as if you'd serialized the original object.  Basically, to cut to the point...

If you use

$_SESSION['my_object'] = unserialize(serialize($_SESSION['my_object']))

then you get back an object of the correct type, even if the session had originally loaded it as an object of type stdClass.
up
1
m.m.j.kronenburg ΒΆ
10 years ago
You can use the following code to use the php 7 unserialize function in php 5.3 and upwards. This adds the $option argument.

<?php

namespace
{

/**
 * PHP 7 unserialize function for PHP 5.3 upwards.
 * Added the $option argument (allowed_classes).
 * See php unserialize manual for more detail.
 **/
function php7_unserialize($str, $options = array())
{
  if(version_compare(PHP_VERSION, '7.0.0', '>='))
  { return unserialize($str, $options); }

  $allowed_classes = isset($options['allowed_classes']) ? 
    $options['allowed_classes'] : true;
  if(is_array($allowed_classes) || !$allowed_classes)
  {
    $str = preg_replace_callback(
      '/(?=^|:)(O|C):\d+:"([^"]*)":(\d+):{/', 
      function($matches) use ($allowed_classes)
      {
        if(is_array($allowed_classes) && 
          in_array($matches[2], $allowed_classes))
        { return $matches[0]; }
        else
        {
          return $matches[1].':22:"__PHP_Incomplete_Class":'.
            ($matches[3] + 1).
            ':{s:27:"__PHP_Incomplete_Class_Name";'.
            serialize($matches[2]);
        }
      },
      $str
    );
  }
  unset($allowed_classes);
  return unserialize($str);
}

} // namespace

namespace my_name_space
{
  /**
   * Use the new php7 unserialize in your namespace without
   * renaming all unserialize(...) function calls to 
   * php7_unserialize(...).
   **/
  function unserialize($str, $options = array())
  { return php7_unserialize($str, $options); }
}

?>
up
2
Anonymous ΒΆ
1 year ago
Please note there is a minor difference in how unserializa() works between PHP 7 and 8.

Under PHP 8, strings that are not trimmed of whitespace will emit a warning in the likes of:

PHP Warning:  unserialize(): Extra data starting at offset 721 of 722 bytes in /tmp/a.php on line 4

so something like:

$s = 's:3:"bar";'."\n"
unserialize($s);    # warning emitted
unserialize(trim($s));  # no warning
up
2
suman dot jis at gmail dot com ΒΆ
14 years ago
I was getting unserialize()  Error at offset error.

If you face similar problem  then use the following procedure

$auctionDetails = preg_replace('!s:(\d+):"(.*?)";!se', "'s:'.strlen('$2').':\"$2\";'", $dataArr[$i]['auction_details'] ); 
$auctionDetails = unserialize($auctionDetails);
up
1
chris at colourlovers dot com ΒΆ
15 years ago
Anyone having trouble serializing data with SimpleXMLElement objects stored within it, check this out:

This will traverse $data looking for any children which are instances of SimpleXMLElement, and will run ->asXML() on them, turning them into a string and making them serializable. Other data will be left alone.

<?php
function exportNestedSimpleXML($data) {
    if (is_scalar($data) === false) {
        foreach ($data as $k => $v) {
            if ($v instanceof SimpleXMLElement) {
                $v = str_replace("&#13;","\r",$v->asXML());
            } else {
                $v = exportNestedSimpleXML($v);
            }

            if (is_array($data)) {
                $data[$k] = $v;
            } else if (is_object($data)) {
                $data->$k = $v;
            }
        }
    }

    return $data;
}

$data = array (
    "baz" => array (
        "foo" => new stdClass(),
        "int" => 123,
        "str" => "asdf",
        "bar" => new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?><foo>bar</foo>'),
    )
);

var_dump($data);
/*array(1) {
  ["baz"]=>
  array(4) {
    ["foo"]=>
    object(stdClass)#3 (0) {
    }
    ["int"]=>
    int(123)
    ["str"]=>
    string(4) "asdf"
    ["bar"]=>
    object(SimpleXMLElement)#4 (1) {
      [0]=>
      string(3) "bar"
    }
  }
}*/

var_dump(exportNestedSimpleXML($data));
/*array(1) {
  ["baz"]=>
  array(4) {
    ["foo"]=>
    object(stdClass)#3 (0) {
    }
    ["int"]=>
    int(123)
    ["str"]=>
    string(4) "asdf"
    ["bar"]=>
    string(54) "<?xml version="1.0" encoding="UTF-8"?>
<foo>bar</foo>
"
  }
}
*/
?>
up
2
double at dumpit dot com ΒΆ
19 years ago
This little function will check whether the serialized string is well formed. 

PHP < 6 because i'd heard changes will be made in this php-intern function, 
maybe it could be edited easy for it.

<?php

function wd_check_serialization( $string, &$errmsg ) 
{

    $str = 's';
    $array = 'a';
    $integer = 'i';
    $any = '[^}]*?';
    $count = '\d+';
    $content = '"(?:\\\";|.)*?";';
    $open_tag = '\{';
    $close_tag = '\}';
    $parameter = "($str|$array|$integer|$any):($count)" . "(?:[:]($open_tag|$content)|[;])";            
    $preg = "/$parameter|($close_tag)/";
    if( !preg_match_all( $preg, $string, $matches ) ) 
    {            
        $errmsg = 'not a serialized string';
        return false;
    }    
    $open_arrays = 0;
    foreach( $matches[1] AS $key => $value )
    {
        if( !empty( $value ) && ( $value != $array xor $value != $str xor $value != $integer ) ) 
        {
            $errmsg = 'undefined datatype';
            return false;
        }
        if( $value == $array )
        {
            $open_arrays++;                                
            if( $matches[3][$key] != '{' ) 
            {
                $errmsg = 'open tag expected';
                return false;
            }
        }
        if( $value == '' )
        {
            if( $matches[4][$key] != '}' ) 
            {
                $errmsg = 'close tag expected';
                return false;
            }
            $open_arrays--;
        }
        if( $value == $str )
        {
            $aVar = ltrim( $matches[3][$key], '"' );
            $aVar = rtrim( $aVar, '";' );
            if( strlen( $aVar ) != $matches[2][$key] ) 
            {
                $errmsg = 'stringlen for string not match';
                return false;
            }
        }
        if( $value == $integer )
        {
            if( !empty( $matches[3][$key] ) ) 
            {
                $errmsg = 'unexpected data';
                return false;
            }
            if( !is_integer( (int)$matches[2][$key] ) ) 
            {
                $errmsg = 'integer expected';
                return false;
            }
        }
    }        
    if( $open_arrays != 0 ) 
    {
        $errmsg = 'wrong setted arrays';
        return false;
    }
    return true;
}

?>
up
0
mikko dot rantalainen at peda dot net ΒΆ
11 months ago
Beware: file_put_contents() is racy by design and if you use it to write serialize()d data, you may end up having error such as

    unserialize(): Extra data starting at offset 1000 of 1002 bytes

For details, see https://github.com/php/php-src/issues/20108
up
-1
aderyn at nowhere dot tld ΒΆ
22 years ago
A quick note:
If you store a serialized object in a session, you have to include the class _before_ you initialize (session_start()) the session.
up
-2
Anonymous ΒΆ
7 years ago
If serialize() is the answer, you're almost certainly asking the wrong question.

JSON is widely available. The only thing it does not do, is the very thing that makes serialization immensely dangerous. All it takes is a crafty hacker to pass a crafted payload to a supposedly 'secured' serialize call, for a database driver to be overwritten with malicious code, for example.

Recreate the object. Normally. With actual data, and a source file, not with serialize. To do otherwise is laziness bordering on malice.
up
-4
MBa ΒΆ
15 years ago
To check if a string is serialized:

$blSerialized=(@unserialize($sText)||$sText=='b:0;');
up
-1
OscarZarrus ΒΆ
3 years ago
For those who are looking for an efficient solution for handling controversial "FALSE", they can use this function which in case of non-unserializable string, instead of a "FALSE", throws an Exception. Vice versa it returns the unserialized variable.
<?php
    /**
     * @param string $serializedString
     * @param array $options
     * @return mixed
     * @throws Exception
     */
    function UnSerialize(string $serializedString, array $options = []) {
        $_unserialized = @unserialize($serializedString, $options);
        if ($serializedString === serialize(false) || $_unserialized !== false){
            return $_unserialized;
        }
        throw new Exception("Non-unserializable string");

    }

?>