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 のわずかにコンパクトな 16 進表現ですbytea
。pg_unescape_bytea
それをうまく処理し、出力と同じ生バイトを生成します...最新のPHPとlibpq
. 古いバージョンではガベージが発生し、それを処理するには forを設定bytea_output
する必要があります。escape
pg_unescape_bytea
代わりにすべきこと
PDO を使用します。
の健全な(ish)サポートがあり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();
見る:
また、PostgreSQL の lob (ラージ オブジェクト) サポートを調べることもできます。これは、完全にトランザクション対応でありながら、ストリーミングでシーク可能なインターフェイスを提供します。
さて、私の石鹸箱に
PHP が「バイト文字列」タイプと「テキスト文字列」タイプを実際に区別している場合pg_escape_bytea
、データベース ドライバーがそれを行うことができるので、その必要はありません。この醜さは必要ありません。残念ながら、PHP には別個の文字列型とバイト型はありません。
できるだけパラメータ化されたステートメントで PDO を使用してください。
できない場合は、少なくともpg_query_params
パラメーター化されたステートメントを使用してください。PHPaddslashes
は代替手段ではありません。非効率的で醜く、データベース固有のエスケープ規則を理解していません。bytea
厄介な歴史的理由で PDO を使用していない場合でも、手動でエスケープする必要がありますが、それ以外はすべてパラメーター化されたステートメントを使用する必要があります。
に関するガイダンスpg_query_params
: