开发者社区> ghost丶桃子> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

基于MongoDb的S3实现

简介:
+关注继续查看
【原文】
http://www.fuchaoqun.com/2010/05/s3-on-mongodb-with-php/


原理是利用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之类的反向代理服务,基本上就不会有问题.

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
windows上mongoDB的安装和简单使用
windows上mongoDB的安装和简单使用http://www.bieryun.com/3369.html 我是按照菜鸟教程上的来安装的 mongoDB下载地址:https://www.mongodb.
1346 0
Windows 平台安装 MongoDB教程
1.MongoDB下载 链接: https://pan.baidu.com/s/1dRZw748Lui_r9kE5aYwZFA 密码: 9yj6 此文件只适用于64位系统安装,32位系统请自己上官网下载。
1170 0
MongoDB之旅:MongDB安装和使用(后台运行)
初识MongDB 随时都要保持求知欲! 一、什么是MongDB MongDB的官网 什么是MongoDB? MongoDB是一个文档数据库,具有您想要的查询和索引所需的可扩展性和灵活性。
1832 0
windows安装mongodb
一、资源 mongo下载地址: https://www.mongodb.com/download-center#community romongo下载: https://robomongo.org/  如下三个文件,(mongodb-compass可以不用下在,这是管理mongo用的图形化界面,习惯...
1047 0
MongoDB系列七(Linux 安装 MongoDB).
一、下载 Linux:CentOS 7.3 64位 MongoDB:3.6.4 安装目录:/usr/local cd /usr/local wget https://fastdl.mongodb.
1180 0
windows上mongoDB的安装和简单使用
windows上mongoDB的安装和简单使用 我是按照菜鸟教程上的来安装的 mongoDB下载地址:https://www.mongodb.com/download-center#community windows上安装网址:http://www.
2026 0
Mongodb安装启动详解
最近在倒腾node+mongodb,安装mongodb的时候开始遇到很多问题,然后折腾了好几次,直到可以很顺利完成安装 ,所以把安装的过程记录下来。 线上系统基本上都是linux的,所以只安装了linux的,mac本地的跟linux的几乎一样,下载的时候选择mac版本的 下来我们就一步步的在linux系统上安装下载和启动mongodb 1.
1107 0
MongoDB安装
非关系性数据库 NoSQL,泛指非关系型的数据库。随着互联网web2.0网站的兴起,传统的关系数据库在应付web2.0网站,特别是超大规模和高并发的SNS类型的web2.0纯动态网站已经显得力不从心,暴露了很多难以克服的问题,而非关系型的数据库则由于其本身的特点得到了非常迅速的发展。
777 0
文章
问答
文章排行榜
最热
最新
相关电子书
更多
ApsaraDB for MongoDB
立即下载
MongoDB在性能监控领域的应用
立即下载
《阿里云数据库 MongoDB 专属集群版》
立即下载