32
$ser = 'a:2:{i:0;s:5:"héllö";i:1;s:5:"wörld";}'; // fails
$ser2 = 'a:2:{i:0;s:5:"hello";i:1;s:5:"world";}'; // works
$out = unserialize($ser);
$out2 = unserialize($ser2);
print_r($out);
print_r($out2);
echo "<hr>";

しかし、なぜ?
シリアル化する前にエンコードする必要がありますか?どのように?

PHPの$_POSTよりもJavascriptを使用して、シリアル化された文字列を非表示フィールドに書き込みます。JSでは次の
ようなものがあります。

function writeImgData() {
    var caption_arr = new Array();
    $('.album img').each(function(index) {
         caption_arr.push($(this).attr('alt'));
    });
    $("#hidden-field").attr("value", serializeArray(caption_arr));
};
4

14 に答える 14

56

unserialize()失敗する理由:

$ser = 'a:2:{i:0;s:5:"héllö";i:1;s:5:"wörld";}';

PHPはマルチバイト文字列をネイティブに正しく処理しないため、との長さが間違っているhéllöためです。wörld

echo strlen('héllö'); // 7
echo strlen('wörld'); // 6

unserialize()ただし、次の正しい文字列を使用しようとすると、次のようになります。

$ser = 'a:2:{i:0;s:7:"héllö";i:1;s:6:"wörld";}';

echo '<pre>';
print_r(unserialize($ser));
echo '</pre>';

できます:

Array
(
    [0] => héllö
    [1] => wörld
)

PHPを使用する場合serialize()は、マルチバイト文字列インデックスの長さを正しく計算する必要があります。

一方、複数の(プログラミング)言語でシリアル化されたデータを操作する場合は、それを忘れて、はるかに標準化されたJSONのようなものに移行する必要があります。

于 2010-05-17T23:33:41.610 に答える
52

これが1年前のように投稿されたことは知っていますが、私はこの問題を抱えていてこれに遭遇し、実際に解決策を見つけました。このコードは魅力のように機能します!

背後にある考え方は簡単です。上記の@Alixによって投稿されたように、マルチバイト文字列の長さを再計算することで、あなたを助けているだけです。

いくつかの変更はあなたのコードに合うはずです:

/**
 * Mulit-byte Unserialize
 *
 * UTF-8 will screw up a serialized string
 *
 * @access private
 * @param string
 * @return string
 */
function mb_unserialize($string) {
    $string = preg_replace('!s:(\d+):"(.*?)";!se', "'s:'.strlen('$2').':\"$2\";'", $string);
    return unserialize($string);
}

ソース:http ://snippets.dzone.com/posts/show/6592

私のマシンでテストしました、そしてそれは魅力のように働きます!!

于 2011-04-28T02:50:49.960 に答える
33

Lionel Chanの回答は、PHP>=5.5で動作するように変更されました。

function mb_unserialize($string) {
    $string2 = preg_replace_callback(
        '!s:(\d+):"(.*?)";!s',
        function($m){
            $len = strlen($m[2]);
            $result = "s:$len:\"{$m[2]}\";";
            return $result;

        },
        $string);
    return unserialize($string2);
}    

このコードはpreg_replace_callbackを使用します。これは、/e修飾子を使用したpreg_replaceがPHP5.5以降で廃止されたためです。

于 2015-01-13T14:30:19.870 に答える
9

問題は、Alixが指摘しているように、エンコーディングに関連しています。

PHP 5.4まで、PHPの内部エンコーディングはISO-8859-1でしたが、このエンコーディングでは、Unicodeではマルチバイトである一部の文字に1バイトが使用されていました。その結果、UTF-8システムでシリアル化されたマルチバイト値はISO-8859-1システムでは読み取れなくなります。

このような問題を回避するには、すべてのシステムが同じエンコーディングを使用していることを確認してください。

mb_internal_encoding('utf-8');
$arr = array('foo' => 'bár');
$buf = serialize($arr);

utf8_(encode|decode)クリーンアップに使用できます:

// Set system encoding to iso-8859-1
mb_internal_encoding('iso-8859-1');
$arr = unserialize(utf8_encode($serialized));
print_r($arr);
于 2012-05-24T12:39:08.550 に答える
3

";上記の@Lionelへの返信として、実際には、シリアル化された文字列自体にcharシーケンス(引用符の後にセミコロンが続く)が含まれている場合、提案した関数mb_unserialize()は機能しません 。注意して使用してください。例えば:

$test = 'test";string'; 
// $test is now 's:12:"test";string";'
$string = preg_replace('!s:(\d+):"(.*?)";!se', "'s:'.strlen('$2').':\"$2\";'", $test);
print $string; 
// output: s:4:"test";string";  (Wrong!!)

他の人が言っているように、JSONは行く方法です、IMHO

注:直接返信する方法がわからないため、これを新しい回答として投稿します(ここでは新しい)。

于 2012-04-02T03:33:04.963 に答える
1

もう一方の端がPHPでない場合は、PHPのシリアル化/非シリアル化を使用しないでください。移植可能な形式を意図したものではありません。たとえば、保護されたキーのASCII1文字も含まれていますが、これはjavascriptでは処理したくないものです(完全に正常に機能しますが、非常に醜いです)。

代わりに、 JSONのような移植可能な形式を使用してください。XMLもその役割を果たしますが、JSONは、XPathやDOMツリーなどを処理する代わりに、単純なデータ構造に簡単に解析できるため、オーバーヘッドが少なく、プログラマーにとって使いやすいものです。

于 2010-05-17T23:11:34.443 に答える
1

ここでもう1つわずかなバリエーションがあり、誰かに役立つことを願っています...配列をシリアル化してから、データベースに書き込んでいました。データを取得すると、シリアル化解除操作が失敗していました。

私が書き込んでいたデータベースのロングテキストフィールドは、UTF8ではなくlatin1を使用していたことがわかりました。私がそれを切り替えたとき、すべてが計画通りに機能しました。

文字エンコードについて言及し、私を正しい軌道に乗せてくれた上記のすべてに感謝します!

于 2013-04-12T19:47:45.497 に答える
1

この解決策は私のために働いた:

$unserialized = unserialize(utf8_encode($st));
于 2020-09-17T12:31:01.193 に答える
0

javascriptを使用してjsonとしてエンコードしてから、json_decodeを使用してシリアル化を解除することをお勧めします。

于 2010-05-17T22:57:18.220 に答える
0
/**
 * MULIT-BYTE UNSERIALIZE
 *
 * UTF-8 will screw up a serialized string
 *
 * @param string
 * @return string
 */
function mb_unserialize($string) {
    $string = preg_replace_callback('/!s:(\d+):"(.*?)";!se/', function($matches) { return 's:'.strlen($matches[1]).':"'.$matches[1].'";'; }, $string);
    return unserialize($string);
}
于 2014-10-10T16:46:03.550 に答える
0

文字列を配列に分解できます。

$finalArray = array();
$nodeArr = explode('&', $_POST['formData']);

foreach($nodeArr as $value){
    $childArr = explode('=', $value);
    $finalArray[$childArr[0]] = $childArr[1];
}
于 2016-10-03T09:47:32.007 に答える
0

シリアライズ:

foreach ($income_data as $key => &$value)
{
    $value = urlencode($value);
}
$data_str = serialize($income_data);

シリアル化解除:

$data = unserialize($data_str);
foreach ($data as $key => &$value)
{
    $value = urldecode($value);
}
于 2016-10-17T11:16:44.833 に答える
0

これは私のために働いた。

function mb_unserialize($string) {
    $string = mb_convert_encoding($string, "UTF-8", mb_detect_encoding($string, "UTF-8, ISO-8859-1, ISO-8859-15", true));
    $string = preg_replace_callback(
        '/s:([0-9]+):"(.*?)";/',
        function ($match) {
            return "s:".strlen($match[2]).":\"".$match[2]."\";"; 
        },
        $string
    );
    return unserialize($string);
}
于 2017-10-12T13:15:52.227 に答える
0

私の場合、問題は行末にありました(おそらく、一部のエディターが私のファイルをDOSからUnixに変更しました)。

私はこれらのapadtiveラッパーをまとめました:

function unserialize_fetchError($original, &$unserialized, &$errorMsg) {
    $unserialized = @unserialize($original);
    $errorMsg = error_get_last()['message'];
    return ( $unserialized !== false || $original == 'b:0;' );  // "$original == serialize(false)" is a good serialization even if deserialization actually returns false
}

function unserialize_checkAllLineEndings($original, &$unserialized, &$errorMsg, &$lineEndings) {
    if ( unserialize_fetchError($original, $unserialized, $errorMsg) ) {
        $lineEndings = 'unchanged';
        return true;
    } elseif ( unserialize_fetchError(str_replace("\n", "\n\r", $original), $unserialized, $errorMsg) ) {
        $lineEndings = '\n to \n\r';
        return true;
    } elseif ( unserialize_fetchError(str_replace("\n\r", "\n", $original), $unserialized, $errorMsg) ) {
        $lineEndings = '\n\r to \n';
        return true;
    } elseif ( unserialize_fetchError(str_replace("\r\n", "\n", $original), $unserialized, $errorMsg) ) {
        $lineEndings = '\r\n to \n';
        return true;
    } //else
    return false;
}
于 2018-04-13T07:26:14.397 に答える