搭建图片服务(一)

软件列表

  • nginx-1.12.0.tar.gz
  • LuaJIT-2.0.5.zip
  • lua-nginx-module-0.10.10.zip
  • ngx_devel_kit-0.3.0.zip
  • lua-resty-upload-0.10.zip
  • lua-resty-string-0.10.zip
  • lua-cjson-2.1.0.tar.gz
  • luarocks-2.4.3.tar.gz
  • lua-stringy-0.4-1.zip
  • gd-devel-2.0.35-11.el6.x86_64.rpm (centos 6.x)
  • gd-devel-2.0.35-26.el7.x86_64.rpm (centos 7.x)

安装步骤

安装luajit

  1. 解压 unzip LuaJIT-2.0.5.zip
  2. 修改Makefile export PREFIX= /usr/local/luajit
  3. 编译安装 make && make install
  4. 配置环境变量
   vi /etc/profile
   export LUAJIT_LIB=/usr/local/luajit/lib
   export LUAJIT_INC=/usr/local/luajit/include/luajit-2.0 
   source /etc/profile

nginx安装

  1. 创建用户
useradd -M -s /sbin/nologin nginx

  1. 安装依赖
yum install gcc pcre pcre-devel zlib zlib-devel openssl openssl-devel libxml2 libxml2-devel libxslt libxslt-devel gd-devel geoip geoip-devel -y

yum install gd fontconfig-devel freetype-devel libX11-devel libXpm-devel libjpeg-devel libpng-devel -y

rpm -ivh gd-devel-2.0.35-11.el6.x86_64.rpm

  1. 编译安装
./configure \
 --prefix=/usr/local/nginx \
 --user=nginx \
 --group=nginx \
 --with-pcre \
 --with-http_ssl_module \
 --with-http_v2_module \
 --with-http_realip_module \
 --with-http_addition_module \
 --with-http_sub_module \
 --with-http_dav_module \
 --with-http_flv_module \
 --with-http_mp4_module \
 --with-http_gunzip_module \
 --with-http_gzip_static_module \
 --with-http_random_index_module \
 --with-http_secure_link_module \
 --with-http_stub_status_module \
 --with-http_auth_request_module \
 --with-http_image_filter_module \
 --with-mail \
 --with-mail_ssl_module \
 --with-stream_ssl_module \
 --add-module=/root/ngx_devel_kit-0.3.0 \
 --add-module=/root/lua-nginx-module-0.10.10

 make && make install

  1. 启动测试

./nginx: error while loading shared libraries: libluajit-5.1.so.2: cannot open shared object file: No such file or directory

执行 ln -s /usr/local/lib/libluajit-5.1.so.2 /lib64/libluajit-5.1.so.2

配置lua

  1. 修改nginx.conf

server前面增加

 lua_package_path "/usr/local/luajit/lib/lua/?.lua;/usr/local/nginx/lua_lib/?.lua;;";
 lua_package_cpath "/usr/local/luajit/lib/lua/5.1/?.so;;";

http里面增加

location /hello {
    default_type text/html;
    content_by_lua_file lua_lib/hello.lua
}

创建hello.lua

mkdir /usr/local/nginx/lua_lib/
cd /usr/local/nginx/lua_lib/
touch hello.lua
vi hello.lua

ngx.say('hello lua!')

测试访问 http://127.0.0.1/hello

配置图片上传

  1. 安装lua-cjson-2.1.0.tar.gz
  • tar -zxf lua-cjson-2.1.0.tar.gz
  • cd lua-cjson-2.1.0
  • 修改Makefile PREFIX = /usr/local/luajit
  • 修改Makefile LUA_INCLUDE_DIR = $(PREFIX)/include/luajit-2.0
  • make && make install
  1. 安装lua-resty-string-0.10.zip
  • unzip lua-resty-string-0.10.zip
  • cd lua-resty-string-0.10
  • 修改Makefile PREFIX ?= /usr/local/luajit
  • 修改Makefile LUA_INCLUDE_DIR ?= $(PREFIX)/include/luajit-2.0
  • make install
  1. 安装lua-resty-upload-0.10.zip
  • unzip lua-resty-upload-0.10.zip
  • cd lua-resty-upload-0.10
  • 修改Makefile PREFIX ?= /usr/local/luajit
  • 修改Makefile LUA_INCLUDE_DIR ?= $(PREFIX)/include/luajit-2.0
  • make install

4.安装luarocks

  • tar -zxf luarocks-2.4.3.tar.gz
  • cd luarocks-2.4.3
  • ./configure --with-lua-include=/usr/local/luajit/include/luajit-2.0 --prefix=/usr/local/luajit
  • make && make install
  • 将/usr/local/luajit/bin加入path
  1. 安装lua-stringy-0.4-1.zip
  • unzip lua-stringy-0.4-1.zip
  • cd lua-stringy-0.4-1
  • ln -s /usr/local/luajit/share/lua/5.1/luarocks /usr/share/lua/5.1/luarocks
  • luarocks make stringy/stringy-0.4-1.rockspec

上传nginx_upload.lua脚本

  1. 脚本内容
string.split = function(line, sep)

    sep = sep or ' '
    local retval = {}
    local pos = 1
    while true do
        local from, to = string.find(line, sep, pos)
        if from then
            local item = string.sub(line, pos, from-1)
            table.insert( retval, item )
            pos = to + 1
        else
            local item = string.sub(line, pos)
            table.insert( retval, item )
            break
        end
    end
    return retval
end    

string.trim = function (s)
  return (s:gsub("^%s*(.-)%s*$", "%1"))
end

--获取扩展名  
function getExtension(filename)  
    return filename:match(".+%.(%w+)$")  
end

local stringy = require "stringy"
local resty_sha1 = require "resty.sha1"
local upload = require "resty.upload"
local cjson = require "cjson"
local chunk_size = 4096
local form = upload:new(chunk_size)
local sha1 = resty_sha1:new()
local file
local extnames={"png","jpg","jpeg","gif"}
local msg = {success=false,msg='上传失败',data=nil}


function extExists(ext)
    for _, value in pairs(extnames) do
        if value == ext then
            return true
        end
    end

    return false
end

local fileNames={}
local fileRes={}
local part_name, part_value
local params={}
while true do
    local typ, res, err = form:read()

    if not typ then
        ngx.say("failed to read: ", err)
        return
    end

    if typ == "header" then
        local key=res[1]
        local value=res[2]
        
        if stringy.startswith(string.lower(res[1]), "content-disposition") then
                local parts = stringy.split(res[3], ";")
                local current_parts = stringy.split(stringy.strip(parts[2]), "=")
                if string.lower(table.remove(current_parts, 1)) == "name" then
                    local current_value = stringy.strip(table.remove(current_parts, 1))
                    part_name = string.sub(current_value, 2, string.len(current_value) - 1)
                end
        end

        if key =="Content-Disposition" then
             local kvlist=string.split(value,';')

             for _, kv in ipairs(kvlist) do
                    local seg = string.trim(kv)
                    --ngx.log(ngx.ERR,seg)
                    if seg:find("filename") then
                        local kvfile = string.split(seg, "=")
                        filename = string.sub(kvfile[2], 2, -2)
                        if filename then
                            --获取文件后缀名字
                            fileExtension=getExtension(filename)
                            --ngx.log(ngx.ERR,fileExtension)
                            if extExists(fileExtension) == false then
                               msg['msg'] = '文件类型错误'
                               ngx.say(cjson.encode(msg))
                               return 1
                            end
                            local linuxTime=tostring(os.time())
                            local filename = linuxTime..filename
                            filePath= "/tmp/attachment/image/"..filename
                            file,errmsg = io.open(filePath, "w+")
                            --存储的文件路径                    
                            --ngx.say("failed to open file ", filePath)
                            if not file then
                                ngx.say("failed to open file ", filePath .. errmsg)
                                return 1
                            end
                            table.insert(fileNames,filename)
                        else
                            return 1
                        end
                        --跳出循环
                        break 
                    end
             end
        end
    elseif typ == "body" then
        if part_name ~= nil and part_name ~="" and part_name ~='file' then
          part_value = res
        end
        if file then
                table.insert(fileRes,res)
                file:write(res)
                sha1:update(res)
        end

    elseif typ == "part_end" then
        if part_name ~= nil and part_name ~="" and part_name ~='file' then
           params[part_name] = part_value

           -- Reset fields for the next part
           part_value = nil
           part_name = nil
        end

        if file then
           local filename = fileNames[#fileNames]
           --ngx.log(ngx.ERR,filename)   
           fileRes = nil
           file:close()
           file = nil
        end
        local sha1_sum = sha1:final()
        sha1:reset()
        --my_save_sha1_sum(sha1_sum)
    elseif typ == "eof" then
        msg['success'] = true
        msg['msg'] = '上传成功'
        msg['data']= fileNames

        ngx.say(cjson.encode(msg))
        fileNames = nil
        break

    else
        -- do nothing
    end
end

  1. 创建图片目录
mkdir -p /tmp/attachment/image
chmod -R 777 /tmp/attachment/image

  1. 配置nginx.conf
location /upload {
    error_log logs/upload_err.log;
    content_by_lua_file lua_lib/nginx_upload.lua;
}

  1. 使用POSTMAN测试

配置裁剪缩略图

  1. 安装依赖
yum install ImageMagick

  1. 上传imagemagick.lua脚本
-- http://domain.com/111/photo/201411/05/5459e306820af926411357_320x320.jpg
-- config
local image_sizes = {"640x640", "320x320", "124x124", "140x140", "64x64", "60x60", "32x32", "0x0"}


-- parse uri
function parseUri(uri)
    local _, _, name, ext, size = string.find(uri, "(.+)(%..+)!(%d+x%d+)")
    --ngx.header.content_type = "text/plain";
    --ngx.say(name,size);
    if name and size and ext then
        return ngx.var.image_root .. name .. ext, size
    else
        return "", ""
    end
end

function fileExists(name)
    local f = io.open(name, "r")
    if f ~= nil then
        io.close(f)
        return true
    else
        return false
    end
end
--ngx.header.content_type = "text/plain";
--ngx.say(name);
function sizeExists(size)
    for _, value in pairs(image_sizes) do
        if value == size then
            return true
        end
    end
    
    return false
end
--ngx.header.content_type = "text/plain";
--ngx.say(size);
function resize()
    local ori_filename, size = parseUri(ngx.var.uri)
    --ngx.header.content_type = "text/plain";
    ngx.log(ngx.ERR,ori_filename..'!'..size);
    if fileExists(ori_filename) == false then  --or sizeExists(size) == false then
        ngx.exit(404)
    end
    --local i = string.find(ori_filename,'.',1,true)
    --local name = string.sub(ori_filename,0,i-1)
    --local ext = string.sub(ori_filename,i,string.len(ori_filename))
    --local dist_file_name = name..size..ext
    --ngx.log(ngx.ERR,'-----'..dist_file_name..'------------') 
    local command = '';
    if size == '0x0' then
        command = table.concat({
            ngx.var.convert_bin,
            ori_filename,
            "/usr/local/nginx/conf/logo.png",
            "-gravity southeast -geometry +5+10 -composite",
            ngx.var.file,
        }, " ")
    else
        command = table.concat({
            ngx.var.convert_bin,
            ori_filename,
            "/usr/local/nginx/conf/logo.png",
            "-gravity southeast -geometry +5+10 -composite -resize",
            size,
            ngx.var.file,
        }, " ")
    end
    --ngx.header.content_type = "text/plain";
    --ngx.say(command);
    os.execute(command)
end
--ngx.header.content_type = "text/plain";
--ngx.say(command);
resize()

  1. 配置nginx.conf
rewrite ^/attachment/image/(.*)\.(png|jpg|jpeg|gif)$ /attachment/image/$1.$2!0x0 last;
location /attachment/image/ {
    root /tmp;
    set $image_root "/tmp";
    set $file "$image_root$uri";
    set $convert_bin "/usr/bin/convert";
    if (!-f $file){
       rewrite_by_lua_file lua_lib/imagemagick.lua;
    }
    expires max;
}
  1. 上传水印图片 /usr/local/nginx/conf/logo.png

  2. 重新加载配置 nginx -s reload

  3. 测试

    http://127.0.0.1/attachment/image/aaaa.png!128x128

标签: none

添加新评论