GridFS是MongoDB的一個内置功能, 它提供一組檔案操作的API以利用MongoDB存儲檔案, GridFS的基本原理是将檔案儲存在兩個Collection中, 一個儲存檔案索引, 一個儲存檔案内容, 檔案内容按一定大小分成若幹塊,
每一塊存在一個Document中, 這種方法不僅提供了檔案存儲, 還提供了對檔案相關的一些附加屬性(比如MD5值, 檔案名等等)的存儲。
http://www.mongodb.org/display/DOCS/GridFS
http://www.mongodb.org/display/DOCS/GridFS+Specification
安裝文檔
https://docs.mongodb.com/manual/installation/
環境搭建
1.安裝mongoDb
vim /etc/yum.repos.d/mongodb.repo
如果是64bit的
[mongodb]
name=MongoDB Repository
baseurl=http://downloads-distro.mongodb.org/repo/redhat/os/x86_64/
gpgcheck=0
enabled=1
32bit的系統:
[mongodb]
name=MongoDB Repository
baseurl=http://downloads-distro.mongodb.org/repo/redhat/os/i686/
gpgcheck=0
enabled=1
然後安裝, 會提示Y/N:
yum install mongo-10gen mongo-10gen-server # 此時在安裝之前會自動更新yum源 mongodb-org與mongo-10gen 10gen 是 MongoDB 原來的名字, 在源裡還留着 10gen 隻是為了舊包的維護, 現在就不要用 10gen 了
啟動:
service mongod start
檢視狀态
service mongod status
停止
service mongod stop
2.安裝nginx及nginx-gridfs
依賴庫、工具
# yum -y install pcre-devel openssl-devel zlib-devel
# yum -y install gcc gcc-c++
下載下傳nginx-gridfs源碼
# git clone https://github.com/mdirolf/nginx-gridfs.git
# cd nginx-gridfs
# git checkout v0.8
# git submodule init
# git submodule update
下載下傳nginx源碼,編譯安裝。(高版本支援不好)
# wget http://nginx.org/download/nginx-1.4.7.tar.gz
# tar zxvf nginx-1.4.7.tar.gz
# cd nginx-1.4.7
# ./configure --with-openssl=/usr/include/openssl --add-module=../nginx-gridfs/
# make -j8 && make install –j8
解釋: make -j4 作業數是在編譯的時候指定主機的CPU個數
../nginx-gridfs/ 配置成對應nginx-gridfs的路徑
3. 配置nginx-gridfs
vim /usr/local/nginx/conf/nginx.conf
在 server 節點中添加 location 節點
location /img/ {
gridfs testdb
field=filename
type=string;
mongo 192.168.0.159:27017;
}
location /files/ {
gridfs testdb
field=_id
type=objectid;
mongo 192.168.0.159:27017;
}
這裡我們的mongo服務在IP 192.168.0.159。
如果不指定 field, 預設為 MongoDB 的自增ID, 且type為int
配置參數介紹:
gridfs:nginx識别插件的關鍵字
testdb:db名
[root_collection]: 選擇collection, 如root_collection=blog, mongod就會去找blog.files與blog.chunks兩個塊, 預設是fs
[field]: 查詢字段, 保證mongdb裡有這個字段名, 支援_id, filename, 可省略, 預設是_id
[type]: 解釋field的資料類型, 支援objectid, int, string, 可省略, 預設是int
[user]: 使用者名, 可省略
[pass]: 密碼, 可省略
mongo: mongodb url
啟動nginx服務
# /usr/local/nginx/sbin/nginx
可能出現:
Nginx [emerg]: bind() to 0.0.0.0:80 failed (98: Address already in use)
這時可用使用指令關閉占用80端口的程式
sudo fuser -k 80/tcp
GridFS使用
MongoDB提供了一個指令行工具mongofiles可以來處理GridFS, 在bin目錄下。
列出所有檔案:
mongofiles list
上傳一個檔案:
mongofiles put xxx.txt
下載下傳一個檔案:
mongofiles get xxx.txt
查找檔案:
mongofiles search xxx //會查找所有檔案名中包含“xxx”的檔案
mongofiles list xxx //會查找所有檔案名以“xxx”為字首的檔案
參數說明:
–d 指定資料庫, 預設是fs, Mongofiles list –d testGridfs
-u –p 指定使用者名, 密碼
-h 指定主機
-port 指定主機端口
-c 指定集合名, 預設是fs
-t 指定檔案的MIME類型, 預設會忽略
使用MongoVUE來檢視,管理GridFS
MongoVUE位址:http://www.mongovue.com/
MongoVUE是個免費軟體, 但超過15天後功能受限。可以通過删除以下系統資料庫項來解除限制:
[HKEY_CURRENT_USER\Software\Classes\CLSID\{B1159E65-821C3-21C5-CE21-34A484D54444}\4FF78130]
把這個項下的值全删掉就可以了。
<?php
// 初始化gridfs
$conn = new Mongo(); // 連接配接MongoDB
$db = $conn->photos; // 選擇資料庫
$collection = $db->getGridFS(); // 取得gridfs對象
// gridfs有三種方式存儲檔案
// 第一種直接存儲檔案
$id = $collection->storeFile("./logo.png");
// 第二種存儲檔案二進制流
$data = file_get_contents("./logo.png");
$id = $collection->storeBytes($data,array("param" => '附加參數将随圖檔一起存入'));
// 第三種儲存直接表單送出的檔案$_FILES
$id = $collection->storeUpload('upfile');
// 相當于
$id = $collection->storeFile($_FILES['upfile']['tmp_name']);
//--------------以上是儲存圖檔--下面開始讀取圖檔----------------
// 儲存成功後傳回$id = md5字元串
$logo = $collection->findOne(array('_id'=>$id)); // 以_id為索引取得檔案
header('Content-type: image/png'); // 輸出圖檔頭
echo $logo ->getBytes(); // 輸出資料流
?>
特别備注:
通過 $id = $collection->storeFile($_FILES['upfile']['tmp_name']); 産生的ID, 是MongoDB的 ID對象, 而不是一個 字元串! 如以下格式:
{
"_id": ObjectId("525418525ba8a18c1b000001"),
"filename": "D:\\php\\xampp\\tmp\\php8116.tmp",
"uploadDate": ISODate("2013-10-08T14:36:02.0Z"),
"length": NumberInt(55862),
"chunkSize": NumberInt(262144),
"md5": "a6f19f3434f0b36bb2611cd4c6d82b35"
}
不過, 我們可以通過 $id = strval($id), 把上述 ID對象字元串化, 如可得到上述的 525418525ba8a18c1b000001 值, 再把這個值存到MySQL資料庫中, 到時候可通過這個字元串ID 作為條件, 找到相應的MongoDB資源。
參考代碼如下:
$conn = new Mongo(C('127.0.0.1:27017')); //如果設定了密碼自己配置DSN
$db=$conn->selectDB('edu_sns'); // 選擇資料庫
$collection = $db->getGridFS('zk_attach'); // 選擇集合,相等于選擇資料表
$id=$_GET['id'];
$object=$collection->findOne(array('_id'=>new MongoId($id)));
header('Content-type: image/png');
echo $object->getBytes();
完整流程
1、前端上傳檔案html index.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Mongo Gridfs</title>
</head>
<body>
<form action="upload.php" method="post" enctype="multipart/form-data">
<label for="upfile" >上傳圖檔</label>
<input type="file" id="upfile" name="upfile" />
<input type="submit" />
</form>
</body>
</html>
2、上傳檔案進入MongoDB資料庫并傳回圖檔的索引ID upload.php
<?php
//上傳圖檔到
header("Content-type:text/html;charset=utf-8");
// 連接配接Mongo并初始化GFS
// 資料庫命名 picDB;集合命名pic_userid
$conn = new MongoClient();
$db = $conn->picDB;
// 取得gridfs對象
$prefix = 'pic';
$collection = $db->getGridFS($prefix);
// 上傳圖檔
if(isset($_FILES['upfile'])){
$id = $collection->storeUpload('upfile');
$id = strval($id);
echo "<p>圖檔路徑為:<font color=red>http://{$_SERVER['HTTP_HOST']}/image.php?id={$id}</font></p>";
}
?>
3、根據圖檔ID直接從MongoDB裡面擷取圖檔資源并顯示 image.php
<?php
// 根據ID索引值将圖檔資源取出來,即圖檔二進制資料
$conn = new Mongo();
$db = $conn->picDB;
// 取得gridfs對象
$prefix = 'pic';
$collection = $db->getGridFS($prefix);
$id = $_GET['id'];
$object = $collection->findOne(array('_id' => new MongoId($id)));
header('Content-type:image/jpg');
echo $object->getBytes();
?>
在upload.php裡面萬一根據ID無法取出資料! 應該做出提示。
在image.php裡面應該添加異常處理, 如果取出的資料格式不是image而是其他格式! 要提前判斷type。
最後, 要在MongoDB的使用中添加授權使用! 因為mongo預設是非授權使用的, 也就是通路資料庫時不需要提供使用者名和密碼。
參考類庫:
https://github.com/crodas/MongoFS