PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

Съхранение на изображения в bytea полета в PostgreSQL база данни

TL;DR:

Изтрийте addslashes($data) . Тук е излишно.

Двойно избягване .. два пъти

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

Вие четете данните, избягвате ги, сякаш са низови литерал, след което ги преобразувате в байт осмични или шестнадесетични екрани. Никога не би могло да работи по този начин, дори ако pg_escape_bytea беше разумен, което не е.

pg_escape_bytea на PHP изглежда двойно избягване изхода, така че да може да бъде вмъкнат в низов литерал. Това е невероятно грозно, но изглежда няма алтернатива, която да не прави това двойно избягване, така че изглежда не можете да използвате параметризирани изрази за bytea в PHP. Все пак трябва да го правите за всичко останало.

В този случай просто премахване на addslashes ред за прочетените данни от файла е достатъчен.

Тестов случай, показващ, че pg_escape_bytea двойно извеждане (и винаги използва и старите, неефективни осмични екрани):

<?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 . pg_unescape_bytea ще се справи добре и ще произведе същите сурови байтове като изхода ... ако имате модерен PHP и libpq . В по-старите версии ще получите боклук и ще трябва да зададете 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();

Вижте:

  • PHP:Големи обекти, който има пример за точно това, което искате;
  • PDOStatement::bindParam
  • как да съхранявате сериализиран обект с пространство от имена в база данни с помощта на pdo php
  • Свържете BYTEA към PGSQL PDO подготвена декларация в PHP5

Може също да искате да разгледате поддръжката за лоб (голям обект) на PostgreSQL, която осигурява поточно, търсещ интерфейс, който все още е напълно транзакционен.

Сега към моята кутия за сапун

Ако PHP имаше истинска разлика между типовете "байтов низ" и "текстов низ", дори нямаше да се нуждаете от pg_escape_bytea тъй като драйверът на базата данни може да го направи вместо вас. Нищо от тази грозота няма да се изисква. За съжаление, в PHP няма отделни типове низове и байтове.

Моля, използвайте PDO с параметризирани изрази колкото е възможно повече.

Където не можете, използвайте поне pg_query_params и параметризирани изявления. addslashes на PHP не е алтернатива, той е неефективен, грозен и не разбира специфичните за базата данни правила за избягване. Все още трябва ръчно да избягвате bytea ако не използвате PDO по гадни исторически причини, но всичко останало трябва да премине през параметризирани оператори.

За насоки относно pg_query_params :

  • Таблици Боби, PHP секция.
  • Ръководството за PHP за pg_query_params


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Вземете броя на дните в месеца в PostgreSQL

  2. Изберете тип данни на полето в postgres

  3. Rails:Няма пул за връзки за ActiveRecord::Base

  4. Еквивалент на PostgreSQL за TOP n WITH TIES:LIMIT с връзки?

  5. Пълнотекстово търсене на PostgreSQL и объркване на триграма