I am a newbie in Yii Framework and PHP Development.
I am trying to store a file in PostgreSQL Bytea column because the application needs to share resources with Java Web Services.
However, when I try to retrieve the data (the contents of the file) back, I cannot recreate the file.
The error message is Resource #92. I searched only online and people said that Resource #92 means I should not print the nonprintable contents. It seems to me that the file_put_contents() expects unpacked data.
Anybody has experiences in recreating file/image from bytea data stores in PostgreSQL.
Please point me out to the right direction.
Here are my PHP Codes
class Doc extends CApplicationComponent {
public function __construct() {
}
/**
* Build requested path using application root path and requested dir and file name
* @param string $dir the requested directory name
* @param string $filename the requested file name
* @return string the full path
*/
public function createPath($dir, $fileName=null) {
$basePath = Yii::app()->basePath;
$pos=strrpos($basePath,'/');
$path = substr($basePath, 0, $pos + 1);
if ($fileName != null)
return ($path . $dir . '/' . $fileName);
else
return ($path . $dir);
}
/**
* Create a directory in the root folder of the application
* @param string $dir for example 'files' or 'files/docs' or 'files/images' if 'files' already exists
* @return boolean true for success otherwise false
*/
public function createDir($dir) {
$flag=false;
$path = $this->createPath($dir);
if(file_exists($path) && is_dir($path))
return $flag;
else {
mkdir($path, '0755');
$flag=true;
}
return $flag;
}
/**
* Saves the document in binary format
* @param string $path the folter to be save. For exmample, files/docs
* @param string $name the document file name. For examplle, test.rtf
* @return integer 0 for failure of greater than 0 for success
*/
public function saveDocument($path, $name, $docTypeId) {
$id = 0;
$document = new Documents();
$contents = $this->getFileBin($path, $name);
if ($contents == null || strlen($contents) < 0) return $id;
$docPath = $this->createPath($path, $name);
$docExt = substr($docPath,strrpos($docPath,'.'));
$docSize = strlen($contents);
$document->setAttributes(
array(
'document_name' => $name,
'document_data' => $contents,
'document_path' => $docPath,
'document_ext' => $docExt,
'document_type_id' => $docTypeId,
'document_size' => $docSize,
'active' => true,
'modified_at' => new CDbExpression('NOW()'),
)
);
$document->save(false);
return ($id = $document->id);
}
/**
* Gets document by requested id
* @param integer $id the document id of requested record
* @return instance of Documents object if success otherwise null
*/
public function getDocumentById($id) {
if ($id < 1) return null;
return Documents::model()->findByPk($id);
}
/**
* Gets file contents in binary format given a full path and file name
* We can use file_get_contents() or fread() with 'rb' mode
* @param string $path the path to the folder that store the requested file
* @param string $name the requested file name
* @return the binary data prepared for bytea colunmn of postgresql
*/
public function getFileBin($path, $name) {
$contents = '';
$fullPath = $this->createPath($path);
$dir = opendir($fullPath);
while($file = readdir($dir)) {
if (strcasecmp($name, $file) == 0) {
$contents = file_get_contents($fullPath.'/'.$file);
$contents = pg_escape_bytea($contents);
break;
}
}
return $contents;
}
/**
* Creates file in original format given the binary file contents, the directory name, and the filename
* @param string $contents the contents of the document in binary format
* @param string $dir the directory name
* @param string $name the document or file name
* @return boolean true for success otherwise false
* pg_unescape_bytea()
*/
public function bin2File($contents, $dir, $name) {
$contents = pg_unescape_bytea($contents);
$fileName = $this->createPath($dir, $name);
$bytes = file_put_contents($fileName, $contents);
return (sizeof($bytes) > 0);
}
}
Here are my PHP codes for Unit Test
class DocTest extends CTestCase {
protected $doc;
protected function setUp() {
$this->doc = new Doc();
}
protected function tearDown() {
if (isset($this->doc)) unset($this->doc);
}
public function testGetFileBin() {
$path = 'files/docs';
$name = 'PartnershipAgreement.rtf';
$contents = $this->doc->getFileBin($path, $name);
echo "\ncontents = " . $contents . "\n";
$this->assertTrue(strlen($contents) > 0);
}
public function testGetDocumentById() {
$document = $this->doc->getDocumentById(2);
}
public function testBin2File() {
$contents =null;
$dir = "files/docs";
$name = "test.rtf";
$document = $this->doc->getDocumentById(2);
echo $this->doc->createPath($dir,$name);
$contents = $document->document_data;
$flag = $this->doc->bin2File($contents, $dir, $name);
$this->assertTrue($flag);
}
public function testSaveDocument() {
$docTypeId = 4;
$name = 'NonDisclosureAgreement.rtf';
$path = 'files/docs';
$contents = $this->doc->getFileBin($path, $name);
$id = $this->doc->saveDocument($path, $name, $docTypeId);
$this->assertTrue($id > 0);
}
public function testCreateDir() {
$flag = $this->doc->createDir('files/images');
$this->assertTrue($flag);
}
public function testCreatePath() {
$imgPath = $this->doc->createPath('images');
echo "\nimage path = " . $imgPath . "\n";
$imgFullPath = $this->doc->createpath('images', 'test.png');
echo "image full path = " . $imgFullPath . "\n";
$this->assertTrue(strlen($imgPath) > 0);
}
}