sql >> データベース >  >> RDS >> PostgreSQL

PostgreSQLデータベースのbyteaフィールドに画像を保存する

    TL; DR:

    addslashes($data)を削除します 。ここでは冗長です。

    ダブルエスケープ..2回

    $data=fread($p,filesize($fi));
    $data=addslashes($data);
    $dat= pg_escape_bytea($data); 
    

    データを読み込んで、文字列リテラルであるかのようにエスケープしてから、8進数または16進数のエスケープに変換します。 pg_escape_byteaであっても、そのように機能することはありません。 正気でしたが、そうではありません。

    PHPのpg_escape_bytea 二重エスケープのように見える 文字列リテラルに挿入できるように出力します。これは信じられないほど醜いですが、この二重エスケープを行わない代替手段はないようです。そのため、PHPでbyteaのパラメーター化されたステートメントを使用することはできないようです。それでも、他のすべてについてはそうする必要があります。

    この場合、addslashesを削除するだけです。 ファイルから読み込まれたデータの行で十分です。

    pg_escape_byteaを示すテストケース ダブルエスケープ(そして常に古くて非効率的な8進数エスケープも使用します):

    <?php
    # oh-the-horror.php
    print pg_escape_bytea("Blah binary\x00\x01\x02\x03\x04 blah");
    ?>
    

    実行:

    php oh-the-horror.php
    

    結果:

    Blah binary\\000\\001\\002\\003\\004 blah
    

    二重の円記号が表示されますか?これは、SQLに文字列として補間することを想定しているためです。これは、メモリ効率が非常に低く、醜く、非常に悪い習慣です。ただし、代替手段はないようです。

    とりわけ、これは次のことを意味します:

    pg_unescape_bytea(pg_escape_bytea("\x01\x02\x03"));
    

    ...間違った結果が生成されます 、pg_unescape_bytea以降 実際にはpg_escape_byteaの逆ではありません 。また、pg_escape_byteaの出力をフィードすることもできなくなります。 pg_query_paramsに パラメータとして、それを補間する必要があります。

    デコード

    最新のPostgreSQLを使用している場合は、おそらくbytea_outputが設定されます。 hexへ デフォルトでは。つまり、データをbyteaに書き込むと フィールドをフェッチして戻すと、次のようになります。

    craig=> CREATE TABLE byteademo(x bytea);
    CREATE TABLE
    craig=> INSERT INTO byteademo(x) VALUES ('Blah binary\\000\\001\\002\\003\\004 blah');
    INSERT 0 1
    craig=> SELECT * FROM byteademo ;
                                         x                                      
    ----------------------------------------------------------------------------
     \x426c61682062696e6172795c3030305c3030315c3030325c3030335c30303420626c6168
    (1 row)
    

    「ええと、何」と言うかもしれませんか?それは問題ありません。PostgreSQLのbyteaのわずかにコンパクトな16進表現です。 。 pg_unescape_bytea それをうまく処理し、出力と同じ生のバイトを生成します...最新のPHPとlibpqを使用している場合 。古いバージョンではゴミが出て、bytea_outputを設定する必要があります escapeする pg_unescape_byteaの場合 それを処理します。

    代わりにすべきこと

    PDOを使用します。

    byteaを適切にサポートしています 。

    $sth = $pdo->prepare('INSERT INTO mytable(somecol, byteacol) VALUES (:somecol, :byteacol)');
    $sth->bindParam(':somecol', 'bork bork bork');
    $sth->bindParam(':byteacol', $thebytes, PDO::PARAM_LOB);
    $sth->execute();
    

    参照:

    • PHP:ラージオブジェクト。必要なものの正確な例があります。
    • PDOStatement ::bindParam
    • pdophpを使用して名前空間を持つシリアル化されたオブジェクトをデータベースに保存する方法
    • BYTEAをPHP5のPGSQLPDOプリペアドステートメントにバインドする

    また、PostgreSQLのlob(ラージオブジェクト)サポートを調べることもできます。これは、完全にトランザクションであるストリーミングのシーク可能なインターフェイスを提供します。

    さて、私の石鹸箱に行きましょう

    PHPで「バイト文字列」タイプと「テキスト文字列」タイプが実際に区別されている場合は、pg_escape_byteaも必要ありません。 データベースドライバがあなたのためにそれをすることができるので。この醜さは必要ありません。残念ながら、PHPには個別の文字列とバイトのタイプはありません。

    可能な限り、パラメータ化されたステートメントでPDOを使用してください。

    できない場合は、少なくともpg_query_paramsを使用してください およびパラメータ化されたステートメント。 PHPのaddslashes 代替手段ではなく、非効率的で醜く、データベース固有のエスケープルールを理解していません。 byteaを手動でエスケープする必要があります 歴史的な理由でPDOを使用していないが、それ以外はすべてパラメーター化されたステートメントを実行する必要がある場合。

    pg_query_paramsのガイダンス :

    • ボビーテーブル、PHPセクション。
    • pg_query_paramsに関するPHPマニュアル


    1. OracleStreamsで伝搬を常に有効に保つ

    2. SQL、テーブルの作成

    3. 列の序数位置を使用してSQLサーバーデータを選択することは可能ですか?

    4. ASYNC_NETWORK_IO待機に対する実行プランの影響–パート1