From 54be17dad594c5ab88bb39e51a2102335293646f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CNaeel=E2=80=9D?= Date: Tue, 7 Jul 2026 15:34:36 +0400 Subject: [PATCH] =?UTF-8?q?fix:=20drhider=20=5Fbuild=5Fzip=20=E2=80=94=20Z?= =?UTF-8?q?ipInfo=20UTF-8=20flag=20for=20Cyrillic=20filenames=20(v1.7)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- History/drhider-utf8-zip-2026-07-07.md | 28 ++++++++++++++++++++++++++ deploy/drhider/drhider.py | 4 +++- site/services/drhider.py | 4 +++- site/templates/drhider.html | 2 +- site/templates/index.html | 2 +- 5 files changed, 36 insertions(+), 4 deletions(-) create mode 100644 History/drhider-utf8-zip-2026-07-07.md diff --git a/History/drhider-utf8-zip-2026-07-07.md b/History/drhider-utf8-zip-2026-07-07.md new file mode 100644 index 0000000..40c6529 --- /dev/null +++ b/History/drhider-utf8-zip-2026-07-07.md @@ -0,0 +1,28 @@ +# DrHider — Cyrillic filenames in ZIP fix (2026-07-07) + +## Проблема +Кириллические имена файлов в выходном ZIP отображаются кракозябрами +(CP437 вместо UTF-8). Содержимое файлов — OK. + +## Причина +`zipfile.ZipFile` в режиме записи кодирует имена в CP437. +Python 3.12 `metadata_encoding='utf-8'` работает **только на чтение**, +при записи → `ValueError`. + +## Решение +Использовать `ZipInfo` с флагом UTF-8 (бит 11 = 0x800): + +```python +# Было: +zf.writestr(fname, content) + +# Стало: +info = zipfile.ZipInfo(fname) +info.flag_bits |= 0x800 +zf.writestr(info, content) +``` + +## Затронутые файлы +- ВМ: `/home/naeel/contracts/drhider/drhider.py` → `_build_zip` +- `contracts-flask/deploy/drhider/drhider.py` +- `contracts-flask/site/services/drhider.py` diff --git a/deploy/drhider/drhider.py b/deploy/drhider/drhider.py index ec816a1..0582592 100644 --- a/deploy/drhider/drhider.py +++ b/deploy/drhider/drhider.py @@ -466,7 +466,9 @@ class TwoPassObfuscator: buf = io.BytesIO() with zipfile.ZipFile(buf, 'w', zipfile.ZIP_DEFLATED) as zf: for fname, content in files: - zf.writestr(fname, content) + info = zipfile.ZipInfo(fname) + info.flag_bits |= 0x800 # UTF-8 filename + zf.writestr(info, content) if mapping_csv: zf.writestr("mapping.csv", '\ufeff'.encode('utf-8') + mapping_csv.encode('utf-8')) return buf.getvalue() diff --git a/site/services/drhider.py b/site/services/drhider.py index 716d59d..898f7ef 100644 --- a/site/services/drhider.py +++ b/site/services/drhider.py @@ -458,7 +458,9 @@ class TwoPassObfuscator: buf = io.BytesIO() with zipfile.ZipFile(buf, 'w', zipfile.ZIP_DEFLATED) as zf: for fname, content in files: - zf.writestr(fname, content) + info = zipfile.ZipInfo(fname) + info.flag_bits |= 0x800 # UTF-8 filename + zf.writestr(info, content) if mapping_csv: zf.writestr("mapping.csv", '\ufeff'.encode('utf-8') + mapping_csv.encode('utf-8')) return buf.getvalue() diff --git a/site/templates/drhider.html b/site/templates/drhider.html index 30eed88..1fe43fb 100644 --- a/site/templates/drhider.html +++ b/site/templates/drhider.html @@ -84,7 +84,7 @@ Сверка договоров | DrHider - v1.6 + v1.7 diff --git a/site/templates/index.html b/site/templates/index.html index 37e697a..7efbacd 100644 --- a/site/templates/index.html +++ b/site/templates/index.html @@ -73,7 +73,7 @@
Nubes - Сверка договоров — LLM AI-driven Event Sourcing v1.0.193-flask + Сверка договоров — LLM AI-driven Event Sourcing v1.0.194-flask
○ Загрузка ○ Классификация