Files
resty_functions/scripts/form_upload_to_compress.lua
T

190 lines
6.3 KiB
Lua

-- 指定模块引用目录,否则无法加载同目录下的其他文件
--package.path = package.path .. ';/usr/local/opt/openresty/nginx/scripts/?.lua';
package.path = package.path .. ';<SCRIPT_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()