I’m still working in my filesystem with CouchDb. After creating a library to enable working with PHP and CouchDB (see the post here), and after using Monkey Patching to override standard PHP’s filesystem functions. I’ve created another solution now. Thanks to a comment in my last post (many thanks Benjamin) I’ve discovered that it’s possible to create a stream wrapper in PHP (I thought it was only available with a C extension).
It’s pretty straightforward to create the wrapper. Of course it’s only an approach. We can create more functionality to our stram wrapper but at least this example meets my needs.
[sourcecode language=”php”]
namespace Nov\CouchDb\Fs;
class StreamWrapper {
var $position;
var $varname;
/**
* @var \Nov\CouchDb\Fs\Resource
*/
var $fs;
/**
* @param string $path
* @return \Nov\CouchDb\Fs
*/
private static function _getFs($path, $_url)
{
return \Nov\CouchDb\Fs::factory(FSCDB, $_url[‘host’]);
}
function stream_open($path, $mode, $options, &$opened_path)
{
$_url = parse_url($path);
$_path = $_url[‘path’];
$fs = self::_getFs($path, $_url);
$_type = strtolower(substr($mode, 0, 1));
switch ($_type) {
case ‘r’:
$this->fs = $fs->open($_path);
break;
case ‘w’:
$this->fs = $fs->open($_path, true, true);
break;
}
return true;
}
function stream_read($count=null)
{
if (is_null($count)) {
return $this->fs->raw();
} else {
return $this->fs->raw(0, $count);
}
}
function stream_write($data, $lenght=null)
{
if (is_null($lenght)) {
$this->fs->write($data);
} else {
$this->fs->write(mb_substr($data, 0, $lenght));
}
return strlen($data);
}
public function unlink($path)
{
$_url = parse_url($path);
$_path = $_url[‘path’];
$fs = self::_getFs($path, $_url)->open($_path);
$fs->delete();
}
public function url_stat($path , $flags)
{
$_url = parse_url($path);
$_path = $_url[‘path’];
$fs = self::_getFs($path, $_url)->open($_path);
//tamaño en bytes
$size = $fs->getLenght();
$out[7] = $size;
$out[‘size’] = $size;
return $out;
}
[/sourcecode]
That’s very simple. It’s almost the same code than the Monkey Patching example.
And now if we want to use it:
[sourcecode language=”php”]
use Nov\CouchDb;
use Nov\CouchDb\Fs;
require_once ("Nov/Loader.php");
Nov\Loader::init();
// I use FSCDB to set up the connection parameters to our couchDb database
define(‘FSCDB’, \NovConf::CDB1);
stream_wrapper_register("novCouchDb", "Nov\CouchDb\Fs\StreamWrapper") or die("Failed to register protocol");
$file = "novCouchDb://fs/home/gonzalo/new.txt";
$f = fopen($file, ‘w+’);
fwrite($f, "***12345dkkydd678901");
fclose($f);
$f = fopen($file, ‘r’);
$a = fread($f, filesize($file));
fclose($f);
unlink($file);
echo $a;
[/sourcecode]
As we can see the URI is:
novCouchDb://fs/home/gonzalo/new.txt.
That’s mean [protocol]://[database]/[path]
The behaviour of this example is exactly the same than Monkey Patching one but I preffer this one. It looks like more “clean” than Monkey Patching approach.
The full source code is available here. And the example: document_root/tests/couchdb/test7.php
2 thoughts on “Using a stream wrapper to access CouchDb attachments with PHP”