-- 指定模块引用目录,否则无法加载同目录下的其他文件 --package.path = package.path .. ';/usr/local/opt/openresty/nginx/scripts/?.lua'; package.path = package.path .. ';/?.lua'; local upload = require "resty.upload" local uuid = require("lib.my_uuid") local http = require "resty.http" local pl = require "pl.pretty" local verify = require('lib.jwt_verify') local authHeader = ngx.req.get_headers().Authorization local sudoerToken = ngx.req.get_headers().HtySudoerToken local httpc = http:new() ngx.log(ngx.INFO, "authHeader ", authHeader) ngx.log(ngx.INFO, "sudoerToken ", sudoerToken) verify(httpc, authHeader, sudoerToken) --- @param disposition_val string raw Content-Disposition header value local function filename_from_disposition(disposition_val) if not disposition_val then return nil end local m = ngx.re.match(disposition_val, [[filename\*=UTF-8''([^;\s]+)]], "ijo") if m and m[1] then return ngx.unescape_uri(m[1]) end m = ngx.re.match(disposition_val, [[filename="([^"]+)"]], "ijo") if m and m[1] then return m[1] end m = ngx.re.match(disposition_val, [[filename=([^;\s]+)]], "ijo") if m and m[1] then return m[1] end return nil end local function extension_from_filename(fn) if not fn then return nil end local em = ngx.re.match(fn, [[\.([A-Za-z0-9]+)$]], "ijo") return em and em[1] or nil end local function read_form_file() local chunk_size = 4096 local form, err = upload:new(chunk_size) if not form then ngx.log(ngx.ERR, "failed to new upload: ", err) ngx.exit(500) end local file_dir = ngx.var.tmp_file_dir local convert = ngx.var.convert if not file_dir or file_dir == "" then ngx.status = 500 ngx.log(ngx.ERR, "tmp_file_dir is not set in nginx (set $tmp_file_dir).") ngx.say("server misconfiguration: tmp_file_dir") return end if not convert or convert == "" then ngx.status = 500 ngx.log(ngx.ERR, "ImageMagick NOT FOUND (set $convert).") ngx.say("server misconfiguration: convert") return end -- 确保临时目录存在(避免 worker 无权限写根路径等导致 io.open 失败) os.execute("mkdir -p " .. file_dir) local file local file_name local files = {} local output_file = {} --- 当前 multipart 部件里 Content-Disposition 里的文件名(用于扩展名回退) local pending_disp_filename while true do local typ, res, read_err = form:read() if not typ then ngx.status = 500 ngx.log(ngx.ERR, "FAILED TO READ upload: ", read_err) ngx.say("FAILED TO READ *UPLOAD IMAGE* -> ", read_err) return end if typ == "header" then local key = res[1] local val = res[2] if key == "Content-Disposition" then pending_disp_filename = filename_from_disposition(val) elseif key == "Content-Type" then local mt = ngx.re.match(val, [[(\w+)/([\w\-\+\.]+)]], "jo") local ext = mt and mt[2] or nil if ext then ext = string.lower(ext) if ext == "jpeg" then ext = "jpg" end end if not ext and pending_disp_filename then ext = extension_from_filename(pending_disp_filename) if ext then ext = string.lower(ext) end end if not ext then ngx.status = 400 ngx.log(ngx.ERR, "cannot derive extension; Content-Type=", val) ngx.say("cannot derive image file extension") return end file_name = uuid.uuid() .. "." .. ext file = io.open(file_dir .. "/" .. file_name, "w+") ngx.log(ngx.INFO, "FILENAME -> ", file_name) if not file then ngx.status = 500 ngx.log(ngx.ERR, "failed to open temp file under ", file_dir, " name=", file_name) ngx.say("failed to open file ", file_name) return end pending_disp_filename = nil end elseif typ == "body" then if file then file:write(res) end elseif typ == "part_end" then if file then file:close() table.insert(files, file_name) end file_name = nil file = nil pending_disp_filename = nil elseif typ == "eof" then local len = #files if len == 0 then ngx.status = 500 ngx.log(ngx.ERR, "No images to compress!") ngx.say("no image data received") return end for i = 1, len do ngx.log(ngx.INFO, 'COMPRESS FILE -> ', files[i]) local incoming = file_dir .. "/" .. files[i] output_file[i] = file_dir .. "/" .. uuid.uuid() .. ".jpg" ngx.log(ngx.INFO, 'INPUT FILE -> ', incoming) ngx.log(ngx.INFO, 'OUTPUT FILE -> ', output_file[i]) local cmd = convert .. " -resize 800x600 " .. incoming .. " " .. output_file[i] ngx.log(ngx.INFO, 'CMD COMPRESS RESIZE -> ', cmd) local handle = io.popen(cmd) local result = handle:read("*a") ngx.log(ngx.INFO, 'CMD RESIZE -> RESULT ', pl.dump(result)) handle:close() local upyun_upload = require("lib.upyun_upload") local ts_compress_audit = require("lib.ts_compress_audit") ngx.log(ngx.INFO, 'UPLOAD COMPRESSED IMAGE -> fullpath -> ', output_file[i]) local public_url = upyun_upload.upload_return_url(output_file[i], nil) if not public_url then return end ts_compress_audit.create(httpc, authHeader, sudoerToken, public_url) ngx.status = 200 ngx.say(public_url) end break end end end read_form_file()