標籤:

nodejs和php實現圖片訪問實時處理

我在訪問時光網、網易雲音樂等網站時,發現將它們頁面中的一些圖片URL修改一下就可以得到不同尺寸的圖片,於是思考了其實現方案,我的思路是:URL Rewrite + 實時處理 + 緩存,對用戶請求的URL進行重寫,然後利用圖片處理類庫對圖片進行處理,接著緩存該尺寸圖片並輸出到瀏覽器。使用PHP和Node.js實現了一遍,基本達到了需要的效果。

1、Nginx+Node.js(express)實現

URL重寫 這裡Nginx主要是做一個URL重寫和反向代理的功能,配置如下所示:

location ~ /upload/{ n if ($request_uri ~* ^/upload/(.+)_(d+)x(d+).(jpg|png|gif)$) { n set $src $1; n set $w $2; n set $h $3; n set $t $4; n rewrite . /resize?src=$src&w=$w&h=$h&type=$t break; n } n proxy_pass http://127.0.0.1:3000; n} n

這裡說明一下:Nginx監聽本地的80埠,Node.js監聽的是3000埠。當用戶訪問類似http://127.0.0.1/upload/147332819224704_400x300.jpg的地址時,便會被代理到127.0.0.1:3000/resize?訪問,看起來像是訪問一張圖片,其實不然。 圖片實時處理 我們在Node.js中實時處理圖片,進行縮放、模糊、水印等操作,之後將其緩存起來並輸出到瀏覽器。Node.js自身API並不擅長圖片的處理,我們可以藉助第三方類庫來實現,這裡推薦GraphicsMagick或ImageMagick,使用它們之前先安裝gm模塊: npm install gm --save 接著便可以使用GraphicsMagick了,該模塊的API可以參考GM模塊API介紹。

圖片處理的實現如下:

app.get(/resize,function(req,res){ n var src = req.query.src, n width = req.query.w, n height = req.query.h, n type = req.query.type; n var imgFile = uploadDir+src+.+type; n var notFound = 不好意思,該圖片不存在或已被刪除!; n var thumb = getThumbImg(src,width,height,type); n if(isFileExists(imgFile)){ n if(isFileExists(thumb)){ n res.type(type).sendFile(__dirname+/+thumb); n }else{ n imgResize(imgFile,thumb,width,height,type,res); n } n }else{ n res.status(404).send(notFound); n } n}); nfunction imgResize(f,th,w,h,t,r){ n var imgSize = sizeOf(f); n if(!w||!h||w>=imgSize.width||h>=imgSize.height){ n r.type(t).sendFile(__dirname+/+f); n }else{ n imageMagick(f) n .resize(w,h,!) n .stream(function(err, stdout, stderr) { n if (err) { n console.log(err); n res.end(); n } n var ws = fs.createWriteStream(th); n stdout.pipe(ws); n r.type(t); n stdout.pipe(r); n }); n } n} nfunction isFileExists(filePath){ n var bool = !0; n try{ n fs.accessSync(filePath,fs.constants.F_OK); n }catch(err){ n bool = !1; n } n return bool; n} n

如上代碼所示,當用戶訪問http://127.0.0.1/upload/147332819224704_400x300.jpg時,如果147332819224704這張圖片存在,且400x300這個尺寸也存在,則直接輸出這張圖片,如不存在,則生成一張該尺寸的圖片保存並輸出到瀏覽器。如果提供的尺寸超出了圖片的原始尺寸,則直接輸出原圖。我們不僅可以修改尺寸,也可以進行模糊、打水印等操作,這裡就不多介紹了。

如果不用Nginx反向代理也是可以的,使用express的正則路由實現,如下所示:

app.get(/^/upload/(.+)_(d+)x(d+).(jpg|png|gif)$/,function(req,res){ n var src = RegExp.$1, n width = RegExp.$2, n height = RegExp.$3, n type = RegExp.$4; n var imgFile = uploadDir+src+.+type; n var notFound = 不好意思,該圖片不存在或已被刪除!; n var thumb = getThumbImg(src,width,height,type); n if(isFileExists(imgFile)){ n if(isFileExists(thumb)){ n res.type(type).sendFile(__dirname+/+thumb); n }else{ n imgResize(imgFile,thumb,width,height,type,res); n } n }else{ n res.status(404).send(notFound); n } n}); n

2、Apache+PHP實現 首先得搭建windows下php開發環境,我本人用的是apache2+php5.6,具體的搭建步驟網上一大堆,便不再累述。開啟apache rewrite功能 首先我們得開啟Apache rewrite模塊功能,去掉配置文件http.conf中LoadModule rewritemodule modules/modrewrite.so前面的注釋,然後設置Directory塊下AllowOverride All,可能有多處,接著重啟Apache服務。 配置.htaccess文件 在DocumentRoot目錄下,新建.htaccess文件,如果創建不了,可以先創建一個文本,然後另存為,在彈出的對話框文件名處填寫".htaccess"即可。

之後,編寫URL重寫規則,如下所示:

RewriteEngine on RewriteCond %{REQUEST_FILENAME} !-f nRewriteRule ^upload/(.+)_([0-9]+)x([0-9]+).(jpg|png|gif)$ resize.php?src=$1&w=$2&h=$3&type=$4 [L] n

將類似http://127.0.0.1/upload/147332819224704_400x300.jpg地址重寫為http://127.0.0.1/resize.php/src=147332819224704&w=400&h=300&type=jpg。

功能實現 接下來便是功能的實現,邏輯和nodejs版邏輯一致,代碼如下:

<?phpnfunction getThumbImg($src,$w,$h,$type) { n global $thumbs; n return $_SERVER[DOCUMENT_ROOT].$thumbs.$src._.$w._.$h...$type; n} nfunction imgResize($f,$th,$w,$h,$t) { n $imagick = new Imagick(); n $imagick->readImage($_SERVER[DOCUMENT_ROOT]..$f); n $width = $imagick->getImageWidth(); n $height = $imagick->getImageHeight(); n if(!$w||!$h||$w>=$width||$h>=$height){ n header(Content-Type:image/.$t); n echo file_get_contents($_SERVER[DOCUMENT_ROOT]..$f); n }else{ n $imagick->stripImage(); n $imagick->cropThumbnailImage($w, $h); n $imagick->writeImage($th); n header(Content-Type:image/.$t); n echo $imagick->getImageBlob(); n $imagick->clear(); n $imagick->destroy(); n } n} n$uploadDir = "uploads/images/"; n$thumbs = "uploads/thumbs/"; n$src = $_GET[src]; n$width = $_GET[w]; n$height = $_GET[h]; n$type = $_GET[type]; n$imgFile = $uploadDir.$src...$type; n$notFound = 不好意思,該圖片不存在或已被刪除!; n$thumb = getThumbImg($src,$width,$height,$type); nif(file_exists($imgFile)){ n if(file_exists($thumb)){ n header(Content-Type:image/.$type); n echo file_get_contents($thumb); n }else{ n imgResize($imgFile,$thumb,$width,$height,$type); n } n}else{ n header("HTTP/1.0 404 Not Found"); n header("status: 404"); n echo $notFound; n} n

至此,圖片訪問實時處理也就完成了。其實大部分圖片伺服器都需要這樣的功能,而不是事先生成好幾套尺寸的圖片。

推薦閱讀:

php為什麼弄點號連接字元串?
如何給會員群發廣告郵件而又不被當垃圾郵件?
為什麼shopex和ecshop都停止更新了?
微軟.Net架構現在被不少人吐槽「老掉牙」,相比其它技術(如php)它是否真的失去優勢?
PHP7 出來之後,HHVM 還有什麼優勢嗎?

TAG:PHP | Nodejs |