v1.0.122: ZIP unzip in Lucee (unzip.cfm) — no CORS, FileReader→base64→same-origin POST

This commit is contained in:
2026-06-23 08:19:09 +04:00
parent 20e1e0dcb8
commit f19e0c970f
2 changed files with 129 additions and 4 deletions
+116
View File
@@ -0,0 +1,116 @@
<cfsetting showdebugoutput="no" enablecfoutputonly="true">
<cfheader name="Content-Type" value="application/json; charset=utf-8">
<cfif cgi.request_method NEQ "POST">
<cfoutput>{"ok":false,"error":"POST required"}</cfoutput><cfabort>
</cfif>
<cfset body = toString(getHttpRequestData().content)>
<cfset data = deserializeJSON(body)>
<cfset result = {ok: false, error: "invalid request"}>
<cftry>
<cfif NOT structKeyExists(data, "filename") OR NOT structKeyExists(data, "data")>
<cfset result.error = "filename and data required">
<cfelse>
<cfset zipName = data.filename>
<cfset zipB64 = data.data>
<cfset zipBytes = binaryDecode(zipB64, "base64")>
<cfset results = []>
<cfset contractId = structKeyExists(data, "contract_id") ? data.contract_id : "">
<cfset zbais = createObject("java", "java.io.ByteArrayInputStream").init(zipBytes)>
<cfset zis = createObject("java", "java.util.zip.ZipInputStream").init(zbais)>
<cfloop condition="true">
<cfset entry = zis.getNextEntry()>
<cfif entry is null><cfbreak></cfif>
<cfset name = entry.getName()>
<!--- Только файлы из корня, не директории --->
<cfif name.endsWith("/") OR name contains "/">
<cfset zis.closeEntry()>
<cfcontinue>
</cfif>
<cfset ext = listLast(name, ".")>
<cfif ext NEQ "docx" AND ext NEQ "doc" AND ext NEQ "pdf">
<cfset zis.closeEntry()>
<cfcontinue>
</cfif>
<!--- Читаем байты файла --->
<cfset buf = createObject("java", "java.io.ByteArrayOutputStream").init()>
<cfset tmp = createObject("java", "java.lang.reflect.Array").newInstance(
createObject("java", "java.lang.Byte").TYPE, 4096)>
<cfloop condition="true">
<cfset n = zis.read(tmp)>
<cfif n LTE 0><cfbreak></cfif>
<cfset buf.write(tmp, 0, n)>
</cfloop>
<cfset fileBytes = buf.toByteArray()>
<cfset zis.closeEntry()>
<cfset mime = "application/octet-stream">
<cfif ext EQ "pdf"><cfset mime = "application/pdf">
<cfelseif ext EQ "docx"><cfset mime = "application/vnd.openxmlformats-officedocument.wordprocessingml.document">
<cfelseif ext EQ "doc"><cfset mime = "application/msword">
</cfif>
<cftransaction>
<cfif len(contractId)>
<cfquery name="oldD" datasource="baza">
SELECT s.id as sid, s.document_id FROM supplements s
JOIN documents d ON d.id = s.document_id
WHERE s.contract_id = <cfqueryparam value="#contractId#" cfsqltype="cf_sql_varchar">
AND d.filename = <cfqueryparam value="#name#" cfsqltype="cf_sql_varchar">
</cfquery>
<cfif oldD.recordCount GT 0>
<cfquery datasource="baza">DELETE FROM supplements WHERE id = <cfqueryparam value="#oldD.sid#" cfsqltype="cf_sql_varchar"></cfquery>
<cfquery datasource="baza">DELETE FROM documents WHERE id = <cfqueryparam value="#oldD.document_id#" cfsqltype="cf_sql_varchar"></cfquery>
</cfif>
</cfif>
<cfquery datasource="baza">
INSERT INTO documents (filename, mime_type, original_bytes, status) VALUES (
<cfqueryparam value="#name#" cfsqltype="cf_sql_varchar">,
<cfqueryparam value="#mime#" cfsqltype="cf_sql_varchar">,
decode(<cfqueryparam value="#binaryEncode(fileBytes, 'hex')#" cfsqltype="cf_sql_varchar">, 'hex'),
'uploaded'
)
</cfquery>
<cfquery name="doc" datasource="baza">
SELECT id FROM documents WHERE filename=<cfqueryparam value="#name#" cfsqltype="cf_sql_varchar"> AND status='uploaded' ORDER BY created_at DESC LIMIT 1
</cfquery>
<cfif NOT len(contractId)>
<cfquery datasource="baza">
INSERT INTO contracts (number, client) VALUES (<cfqueryparam value="б/н #dateFormat(now(),'yyyymmdd')#-#timeFormat(now(),'HHmm')#" cfsqltype="cf_sql_varchar">,'')
</cfquery>
<cfquery name="cid" datasource="baza">
SELECT id FROM contracts ORDER BY created_at DESC LIMIT 1
</cfquery>
<cfset contractId = cid.id>
</cfif>
<cfquery datasource="baza">
INSERT INTO supplements (contract_id, document_id, type) VALUES (
<cfqueryparam value="#contractId#" cfsqltype="cf_sql_varchar">,
<cfqueryparam value="#doc.id#" cfsqltype="cf_sql_varchar">,
<cfqueryparam value="additional" cfsqltype="cf_sql_varchar">
)
</cfquery>
</cftransaction>
<cfset arrayAppend(results, {
filename: name,
doc_id: doc.id,
contract_id: contractId,
size: arrayLen(fileBytes)
})>
</cfloop>
<cfset zis.close()>
<cfset result = {ok: true, files: results, contract_id: contractId}>
</cfif>
<cfcatch>
<cfset result = {ok: false, error: cfcatch.message}>
</cfcatch>
</cftry>
<cfoutput>#serializeJSON(result)#</cfoutput>