PostgreSQL中的bytea字段類型可以以二進制的形式存儲數據,這樣做的好處就是可以將原本存儲在網站目錄下的文件存儲到數據庫中,壞處就是如果文件過多、過大的話,就會導致數據庫的數據量大大增加,備份和恢復的時候就會浪費大量的時間,而且數據也有可能會出錯。個人覺得,在文件量小的情況下,使用這種存儲方式還是很方便的。
言歸正傳,下面介紹一下使用bytea字段存讀取文件的具體實現方法。首先是文件存儲於存儲於bytea字段的方法,主要用到的就是PHP中的pg_escape_bytea方法,代碼如下:
<?php $dbconn = pg_connect("host='localhost' dbname='dbname' user='user' password='password' port='port'") OR DIE('Could not connect:' . pg_last_error()); $fileUrl = iconv("utf-8", "gbk", $fileUrl);//$fileName為文件路徑地址,漢字可能會亂碼,此處處理一下 $fileContents = file_get_contents($fileUrl); $escapeBytea = pg_escape_bytea($fileContents);//轉義bytea數據類型的二進制字符串 $insertStr = "INSERT INTO tableName(id, contents) VALUES(DEFAULT, '{$escapeBytea}')"; pg_query($dbconn, $insertStr); ?>
從bytea字段中還原文件用到的是PHP中的pg_unescape_bytea方法,實現代碼如下:
<?php $dbconn = pg_connect("host='localhost' dbname='dbname' user='user' password='password' port='port'") OR DIE('Could not connect: ' . pg_last_error()); $selectStr = "SELECT contents FROM tableName WHERE id = " . $fileId;//$fileId為文件id $query = pg_query($dbconn, $selectStr); while($row = pg_fetch_array($query, null, PGSQL_ASSOC)){ $escapeBytea = $row['contents']; $fileContents = pg_unescape_bytea($escapeBytea); //獲得二進制數據 file_put_contents($fileName, $fileContents); //$fileName為帶有后綴名的文件名,如hello.pdf } ?>
導出文件后,如果二進制數據轉碼錯誤就會出現文件打不開的現象,比如錯誤的PDF文件打開時彈出錯誤如下圖:
這種錯誤在數據庫遷移時特別容易出現(本人是從PostgreSQL 8.4遷移到9.1),解決的方法是修改PostgreSQL的配置文件
postgresql.conf,將bytea_output的輸出類型設置為轉義類型(escape)輸出,即bytea_output = 'escape'(如果前面有#,刪除開啟配置),然后reload一下PostgreSQL的配置使修改生效,這樣二進制數據就可以正常解碼並輸出到文件。