web-dev-qa-db-ja.com

テキストエディタでMySQLデータベースを編集したために壊れたシリアル化されたデータを修正しますか?

背景:WordPress)の*。sqlバックアップをダウンロードしました=サイトのデータベース、および古いデータベーステーブルプレフィックスのすべてのインスタンスを新しいものに置き換えました(たとえば、デフォルトのwp_からasdfghjkl_)。

WordPressはデータベース内のシリアル化されたPHP文字列を使用することを学びました。私がしたことは、シリアル化された文字列の長さの整合性を台無しにするでしょう。

問題は、これを知る直前にバックアップファイルを削除し(私のWebサイトはまだ正常に機能していたため)、それ以降、いくつかのプラグインをインストールしたことです。したがって、元に戻す方法はありません。したがって、次の2つのことを知りたいと思います。

  1. 可能であれば、どうすればこれを修正できますか?

  2. これはどのような問題を引き起こす可能性がありますか?

この記事 は、たとえば、WordPressブログは、設定とウィジェットを失う可能性があると述べています。しかし、これはすべての設定として私には起こっていないようです。私のブログはまだ無傷ですが、内部で何が壊れているのか、将来どのような問題が発生するのかについてはわかりません。したがって、この質問です。)

15
its_me

このページにアクセスしてください: http://unserialize.onlinephpfunctions.com/

そのページに、次のシリアル化された文字列のサンプルが表示されます。a:1:{s:4:"Test";s:17:"unserialize here!";}。それの一部を取る--s:4:"Test";。つまり、「文字列」、4文字、そして実際の文字列を意味します。あなたがしたことにより、数字の文字数が文字列と同期しなくなったと確信しています。上記のサイトでツールを試してみると、たとえば「テスト」を「テス」に変更するとエラーが発生することがわかります。

あなたがする必要があるのは、それらの文字数をあなたの新しい文字列と一致させることです。他のエンコーディングを破損していない場合(コロンなどを削除した場合)、問題は解決するはずです。

16
s_ha_dum

ドメインをローカルホストから実際のURLに変更しようとした後、同じ問題が発生しました。いくつか検索した後、私はWordpressドキュメント:

https://codex.wordpress.org/Moving_WordPress

そこに書かれていることを引用します:

このシリアル化の問題を回避するには、次の3つのオプションがあります。

  • >ダッシュボードにアクセスできる場合は、Better SearchReplaceまたはVelvetBlues UpdateURLsプラグインを使用してください。
  • ホスティングプロバイダー(またはユーザー)がWP-CLIをインストールしている場合は、WP-CLIの検索置換を使用します。
  • データベースで検索と置換クエリを手動で実行します。注:wp_postsテーブルでのみ検索と置換を実行してください。

シリアル化を中断せずにデータベース内のものを置き換えることができるWP-CLIを使用することになりました: http://wp-cli.org/commands/search-replace/

11
carlosvini

私はこれが古い質問であることを知っていますが、決して遅くなるよりはましだと思います。シリアル化されたデータに対して検索/置換が実行されたデータベースを継承した後、最近この問題に遭遇しました。何時間も調査した結果、これは文字列のカウントがオフになっていることが原因であることがわかりました。残念ながら、エスケープや改行がたくさんあるデータが多すぎて、場合によってはカウント方法がわからず、データが多すぎて自動化されたものが必要でした。

途中で、私はこの質問に出くわし、Benubirdの投稿は私を正しい道に導くのに役立ちました。彼のサンプルコードは、非常に深いレベルのネストを伴う、多数の特殊文字とHTMLを含む複雑なデータでの本番環境での使用では機能せず、特定のエスケープ文字とエンコーディングを適切に処理しませんでした。それで私はそれを少し修正し、シリアル化されたデータを「修正」するために私のバージョンを取得するために追加のバグを処理するために数え切れないほどの時間を費やしました。

// do some DB query here
while($res = db_fetch($qry)){
    $str = $res->data;
    $sCount=1; // don't try to count manually, which can be inaccurate; let serialize do its thing
    $newstring = unserialize($str);
    if(!$newstring) {
        preg_match_all('/s:([0-9]+):"(.*?)"(?=;)/su',$str,$m);
#           preg_match_all("/s:([0-9]+):(\"[^\"\\\\]*(?:\\\\.[^\"\\\\]*)*\")(?=;)/u",$str,$m); // alternate: almost works but leave quotes in $m[2] output
#           print_r($m); exit;
        foreach($m[1] as $k => $len) {
            /*** Possibly specific to my case: Spyropress Builder in WordPress ***/
            $m_clean = str_replace('\"','"',$m[2][$k]); // convert escaped double quotes so that HTML will render properly
            // if newline is present, it will output directly in the HTML
            // nl2br won't work here (must find literally; not with double quotes!)
            $m_clean = str_replace('\n', '<br />', $m_clean); 
            $m_clean = nl2br($m_clean);  // but we DO need to convert actual newlines also
            /*********************************************************************/
            if($sCount){
                $m_new = $m[0][$k].';'; // we must account for the missing semi-colon not captured in regex!
                // NOTE: If we don't flush the buffers, things like <img src="http://whatever" can be replaced with <img src="//whatever" and break the serialize count!!!                  
                ob_end_flush(); // not sure why this is necessary but cost me 5 hours!!
                $m_ser = serialize($m_clean);
                if($m_new != $m_ser) {
                    print "Replacing: $m_new\n";
                    print "With: $m_ser\n";
                    $str = str_replace($m_new, $m_ser, $str);
                }
            }
            else{
                $m_len = (strlen($m[2][$k]) - substr_count($m[2][$k],'\n'));
                if($len != $m_len) {
                    $newstr='s:'.$m_len.':"'.$m[2][$k].'"';
                    echo "Replacing: {$m[0][$k]}\n";
                    echo "With: $newstr\n\n";
                    $str = str_replace($m_new, $newstr, $str);
                }
            }
        }
        print_r($str); // this is your FIXED serialized data!! Yay!
    }
}

私の変更についてのちょっとオタクな説明:

  • Benubirdのコードをベースとしてカウントしようとすると、大規模なデータセットには不正確であることがわかったため、カウントが正確であることを確認するためにシリアル化を使用することになりました。
  • 私の場合、tryは成功しましたが、空の文字列が返されたため、try/catchを回避しました。そこで、代わりに空のデータをチェックします。
  • 私は多数の正規表現を試しましたが、Benubirdのmodだけがすべてのケースを正確に処理しました。具体的には、「;」をチェックした部分を変更する必要がありました。 「width:100%; height:25px;」のようにCSSで一致するためです。そして出力を壊しました。そのため、ポジティブルックアヘッドを使用して、「;」の場合にのみ一致させました。二重引用符のセットの外にありました。
  • 私のケースには多くの改行、HTML、およびエスケープされた二重引用符が含まれていたため、それをクリーンアップするためにブロックを追加する必要がありました。
  • データが正規表現によって誤って置き換えられ、シリアル化によってデータが誤ってカウントされるという奇妙な状況がいくつかありました。私はこれを助けるためにどのサイトでも何も見つけませんでした、そして最終的にそれがキャッシングまたはそのような何かに関連しているかもしれないと思い、そしてうまくいった出力バッファ(ob_end_flush())をフラッシュしようとしました、よかったです!

これが誰かに役立つことを願っています...調査と奇妙な問題への対処を含めて、私はほぼ20時間かかりました! :)

3
Brandon Elliott

このスクリプト( https://interconnectit.com/products/search-and-replace-for-wordpress-databases/ )は、シリアル化されたデータの問題に遭遇することなく、どこでも適切なURLでSQLデータベースを更新するのに役立ちます、シリアル化されたデータが発生するたびにURLが同期しなくなる可能性がある「文字数」が更新されるためです。

手順は次のとおりです。

  1. 混乱したデータベース(ウィジェットが機能しない、テーマオプションがないなど)を既にインポートしている場合は、PhpMyAdminを使用してそのデータベースを削除するだけです。つまり、その上のすべてを削除します。次に、エクスポートして、古いデータベースの編集されていないダンプを手元に用意します。

  2. 次に、(編集されていない)古いデータベースを新しく作成されたデータベースにインポートする必要があります。これは、インポート、またはPhpMyAdminからデータベースをコピーすることで実行できます。これまでのところ、検索と置換はまだ行っていないことに注意してください。古いデータベースのコンテンツと構造が、独自のユーザーとパスワードを持つ新しいデータベースになっているだけです。この時点では、おそらくサイトにアクセスできなくなります。

  3. WordPressファイルがサーバー上の適切なフォルダーに新たにアップロードされていることを確認し、wp-config.phpを編集して新しいデータベースに接続します。
  4. スクリプトを、セキュリティ上の理由から、wp-admin、wp-content、およびwp-includesと同じレベルの「シークレット」フォルダーにアップロードします。 DBの詳細をインターネット全体に公開するリスクがあるため、検索と置換が行われたら、すべてを削除することを忘れないでください。
  5. 次に、ブラウザでシークレットフォルダを指定し、スクリプトの優れたインターフェイスを使用します。それは非常に自明です。使用後は、サーバーから完全に削除します。

これにより、データベースが適切に更新され、シリアル化されたデータの問題が発生することはありません。新しいURLがどこにでも設定され、それに応じてシリアル化されたデータの文字数が更新されます。

ウィジェットが渡され、テーマ設定も渡されます-WordPressでシリアル化されたデータを使用する2つの典型的な場所です。

完了し、テスト済みのソリューション!

2
Peanuts

私は個人的に、PHPで作業したり、DB資格情報を公開ファイルに配置したりするのが好きではありません。ローカルで実行できるシリアル化を修正するために、Rubyスクリプトを作成しました:

https://github.com/wsizoo/wordpress-fix-serialization

コンテキスト編集:最初に正規表現を介してシリアル化を識別し、次に含まれているデータ文字列のバイトサイズを再計算することで、シリアル化の修正に取り組みました。

$content_to_fix.gsub!(/s:([0-9]+):\"((.|\n)*?)\";/) {"s:#{$2.bytesize}:\"#{$2}\";"}

次に、エスケープされたSQL更新クエリを介して指定されたデータを更新します。

escaped_fix_content = client.escape($fixed_content)

query = client.query("UPDATE #{$table} SET #{$column} = '#{escaped_fix_content}' WHERE #{$column_identifier} LIKE '#{$column_identifier_value}'")
1
wsizoo

エラーが文字列の長さが正しくないことが原因である場合(私が頻繁に見たもの)、このスクリプトを適応させて修正できるはずです:

foreach($strings as $key => $str)
{
    try {
        unserialize($str);
    } catch(exception $e) {
        preg_match_all('#s:([0-9]+):"([^;]+)"#',$str,$m);
        foreach($m[1] as $k => $len) {
            if($len != strlen($m[2][$k])) {
                $newstr='s:'.strlen($m[2][$k]).':"'.$m[2][$k].'"';
                echo "len mismatch: {$m[0][$k]}\n";
                echo "should be:    $newstr\n\n";
                $strings[$key] = str_replace($m[0][$k], $newstr, $str);
            }
        }
    }
}
1
Benubird