基于MongoDb的S3實現
原理是利用MongoDb的GridFS,伸展性方面交由MongoDb的auto sharding去實現,這里用PHP給MongoDb綁了個S3出來,支持選擇文件存儲節點,支持文件分目錄存儲,這樣的好處是對于一些受時間影響比較 明顯的文件,可以按照年月的形式存儲,減輕歷史包袱。
首先,配置MongoDb GridFS節點信息:
<?php
$s3Config = array(
'foo' => array(
'server' => '127.0.0.1',
'database' => 'test',
'user' => 'test',
'password' => 'foobar',
'domain' => 'http://s3.foobar.com'
),
'bar' => array(
'server' => '127.0.0.1',
'database' => 'test',
'user' => 'test',
'password' => 'foobar',
'domain' => 'http://s3.foobar.com'
),
);
MongoDb的S3綁定:
<?php
/**
* 統一文件存儲
*
*/
class Api_S3
{
protected $_node;
protected $_dir;
protected $_config;
/**
* 構造函數
*
* @param string $node
* @param string $dir
* @param array $config
*/
public function __construct($node, $dir = null, $config = null)
{
$this->_config = $config;
$this->path($node, $dir, false);
}
/**
* 設置文件路徑
*
* @param string $node
* @param string $dir
* @return Api_S3
*/
public function path($node, $dir, $connect = true)
{
$this->_node = $node;
$this->_dir = empty($dir) ? 'fs' : $dir;
if (empty($this->_config[$this->_node])) {
throw new Cola_Exception('Api_S3: invalidate node');
}
if ($connect) {
$this->_gridFS = $this->_gridFS();
}
return $this;
}
/**
* GridFS
*
* @return MongDbGridFS
*/
protected function _gridFS()
{
$mongo = new Cola_Com_Mongo($this->_config[$this->_node]);
return $mongo->gridFS($this->_dir);
}
/**
* 獲得文件句柄
*
* @param string $name
* @return MongoGridFSFile
*/
public function file($name)
{
if (empty($this->_gridFS)) {
$this->_gridFS = $this->_gridFS();
}
return $this->_gridFS->findOne(array('filename' => $name));
}
/**
* 獲得文件內容
*
* @param string $name
*/
public function read($name)
{
$file = $this->file($name);
return $file->getBytes();
}
/**
* 寫入文件
*
* @param string $name
* @param string $data
* @param array $extra
* @param boolean $overWrite
* @return boolean
*/
public function write($name, $data, $extra = array(), $overWrite = false)
{
$extra = (array)$extra + array('filename' => basename($name));
if ($filetype = $this->_type($name)) {
$extra['filetype'] = $filetype;
}
if ($this->file($extra['filename'])) {
if ($overWrite) {
$this->delete($extra['filename']);
} else {
throw new Cola_Exception('Api_S3: file exists');
}
}
return $this->_gridFS->storeBytes($data, $extra);
}
/**
* 復制系統文件
*
* @param string $file
* @param array $extra
* @param boolean $overWrite
* @return boolean
*/
public function copy($file, $extra = array(), $overWrite = false)
{
$extra = (array)$extra + array('filename' => basename($file));
if ($filetype = $this->_type($file)) {
$extra['filetype'] = $filetype;
}
if ($this->file($extra['filename'])) {
if ($overWrite) {
$this->delete($extra['filename']);
} else {
throw new Cola_Exception('Api_S3: file exists');
}
}
return $this->_gridFS->storeFile($file, $extra);
}
/**
* 刪除文件
*
* @param string $name
* @return boolean
*/
public function delete($name)
{
if (empty($this->_gridFS)) {
$this->_gridFS = $this->_gridFS();
}
return $this->_gridFS->remove(array('filename' => $name));
}
/**
* 獲得文件地址
*
* @param string $name
* @param string $default
* @return string
*/
public function getUrl($name, $default = false)
{
$data = array(
'domain' => rtrim($this->_config[$this->_node]['domain'], '/'),
'path' => $this->_node . (('fs' == $this->_dir) ? '' : $this->_dir),
'name' => $name
);
return implode('/', $data);
}
/**
* 設置文件屬性
*
* @param string $name
* @param array $attr
* @return boolean
*/
public function setAttr($name, $attr)
{
if (!$file = $this->file($name)) {
throw new Cola_Exception('Api_S3: file not exists');
}
$file->file = $attr + $file->file;
return $this->_gridFS->save($file->file);
}
/**
* 獲得文件屬性
*
* @param string $name
* @return array
*/
public function getAttr($name)
{
$file = $this->file($name);
return $file->file;
}
/**
* 獲得文件類型
*
* @param string $file
* @return string
*/
protected function _type($file)
{
return mime_content_type($file);
}
}
文件存入,支持自選節點,自定義目錄,自定義文件名,可以自動添加文件類型:
<?php
$s3 = new Api_S3($node, $dir, $s3Config);
$s3->copy($file, array('filename' => $name, 'filetype' => $type));
文件讀取,以”http://s3.foobar.com/foo/201005/foobar.jpg”為例,foo映射到節點名,201005映射到目錄名,foobar.jpg映射到文件名:
<?php
$s3 = new Api_S3($node, $dir, $s3Config);
$file = $s3->file($name);
Cola_Response::lastModified($file->file['uploadDate']->sec);
Cola_Response::etag($file->file['md5']);
if (isset($file->file['filetype'])) {
header("Content-Type: {$file->file['filetype']}");
}
echo $file->getBytes();
注意到我們利用了文件的修改時間設置http頭的last modified,以及用文件的md5信息設置etag值,這樣的好處是可以大大減少帶寬使用,當然,你也可以設置expire時間來減少重復請求。
關于性能問題,可以在PHP讀取的上一層,加一個Squid之類的反向代理服務,基本上就不會有問題。
轉自:http://www.fuchaoqun.com/2010/05/s3-on-mongodb-with-php/
本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!