🗂️

Unicodeフラグ、ZIPファイルの文字化け問題

に公開

はじめに

Windowsローカル環境でZIPファイルを作成し、業務WebシステムにZIPファイルをアップロードすると、PHPで作られているWebシステム上で展開して処理が進むという作業がありました。
しかし、OSがWindows10になり、同様の操作をしたところ、展開されたファイル名がすべて文字化けして表示され処理が進まない問題が発生し、相談を受けました。
「ZIPファイル内部のUnicodeフラグ(Language encoding flag、bit11)」が原因であると想像できました。

この記事では、ZIP仕様の簡単な構造、各種バージョンによる違い、そして実際の対処方法についても紹介します。


第1章:ZIPファイル構造の基本とUnicodeフラグ

ZIPファイルは、以下のような構造で構成されています:

  • Local File Header(各ファイルの先頭情報)
  • Central Directory Header(アーカイブ全体の目次)
  • End of Central Directory(ZIPファイルの終端マーカー)
┌────────────┬──────────────┬──────────────┬──────────────────────┬──────────────┬──────────────┐
│ Signature  │ Version       │ Flags         │ Compression method    │ Mod Time      │ Mod Date      │
│ (4 bytes)  │ (2 bytes)     │ (2 bytes)     │ (2 bytes)             │ (2 bytes)     │ (2 bytes)     │
├────────────┼──────────────┼──────────────┼──────────────────────┼──────────────┼──────────────┤
│ CRC-32     │ Compressed Size │ Uncompressed Size │ File Name Length │ Extra Field Length     │
│ (4 bytes)  │ (4 bytes)        │ (4 bytes)          │ (2 bytes)         │ (2 bytes)              │
├──────────────────────────────────────────────────────────────────────────────────────────────┤
│ File Name (variable size)                                                                     │
├──────────────────────────────────────────────────────────────────────────────────────────────┤
│ Extra Field (variable size)                                                                   │
└──────────────────────────────────────────────────────────────────────────────────────────────┘

このうち Local File HeaderCentral Directory Header には共通して、
"General Purpose Bit Flag"(2バイト) と呼ばれるフラグフィールドが含まれています。

このフラグの bit11(0x0800) がセットされている場合、
そのファイルの ファイル名およびコメントは UTF-8 でエンコードされている として扱われます。

Bit 11 (0x0800): Language encoding flag (EFS)
If set, the file name and comment fields must be UTF-8.
ZIP File Format Specification Version 6.3.2

一方、このフラグがセットされていない場合は、ファイル名やコメントは「ローカルコードページ」でエンコードされていると解釈されます。
日本語環境のWindowsでは、これにあたるのが CP932(いわゆる Shift_JIS 互換、Windows-31J) です。

この Unicodeフラグ(bit11) によってファイル名のエンコーディングを明示的に指定できるようになったのは、
2007年9月に公開された ZIP 仕様バージョン 6.3.2[1] からです。
それ以前のZIPソフトウェアでは、このフラグは未定義か、あるいは独自拡張として使われていたため、
bit11が立っていなくてもUTF-8でファイル名が書かれているといった非公式なケースも存在します。


第2章:Windowsの圧縮フォルダー

Windows環境によるZIPファイルの違い

「圧縮フォルダー」で作成されたZIPファイルについて、Windows XPとWindows 11で比較を行いました。

📌 Local File Header 比較

比較項目 Windows XP Windows 11
version_needed 20 (2.0) 20 (2.0)
general_flag 0000000000000000 0000100000001000
Unicodeフラグ(bit11) ❌ 無効 ✅ 有効(UTF-8で保存)
compression_method 8(Deflate) 8(Deflate)

📌 Central Directory Header 比較

比較項目 Windows XP Windows 11
version_made_by 0x14 (20, ZIP spec 2.0) 0x314 (788, Windows NTFS + Unicode)

このように、Windows 11の圧縮フォルダーでは、UTF-8対応がより意識された構造に変化していることが読み取れます。


Windows 7以前と以降の対応の違い

🖥 Windows 7以前:ローカルコードページ(CP932)

  • Unicodeフラグ(bit11)は未使用
  • version_needed は 0x0A などの古い仕様
  • ファイル名がローカルコードページ(CP932)で記録

Windows 7にホットフィックス(KB2704299)を適用すると、UTF-8で保存されたZIPの展開も一部可能になります。

🖥 Windows 10以降:UTF-8ロケール設定の登場

  • バージョン1903(2019年5月)以降、システムロケールで「Unicode UTF-8を使用する」設定が可能
  • UTF-8を使用することで、ZIPファイルもUTF-8で作成されやすくなります
設定 → 日付と時刻 → 言語と地域 → 管理 → システムロケールの変更

第3章:サードパーティー製ツールの対応状況

代表的なツールの比較

ツール名 Unicodeフラグ出力 ファイル名UTF-8 備考
7-Zip ✅ 対応 ✅ 標準対応 -mcu=on 指定で明示的に設定可能
WinRAR ✅ 対応 ✅ 標準対応 -scutf-8 で明示的設定可能
Explzh ✅ 対応 ✅ 対応 GUIで「UTF-8保存」を選択可能
Bandizip ✅ 対応 ✅ 対応 GUIで細かな指定可能
Lhaplus ❌ 非対応 ⚠ UTF-8でもフラグ未設定

✅ 特におすすめなのは Explzh

[Explzh]https://www.ponsoftware.com/

  • 日本製アーカイバ
  • 商用利用は有償ライセンスが必要
  • zip32j.dll を使用しており、Unicode対応が強化されている

⚠ Bandizip の注意点

[Bandizip]https://www.bandisoft.com/bandizip/

  • 韓国企業 Bandisoft が開発
  • 過去にアップデート時に広告ソフトが同梱された事例がある
  • セキュリティポリシーにより業務利用を避ける企業もある

第4章:Webシステム側の原因と対応バージョンについて

4.1 PHPのZIP展開処理と文字化けの関係

PHPの ZipArchive クラスは、内部で libzip ライブラリを使用します。
この libzip のバージョンによって、Unicodeフラグの解釈対応が変わります。

4.2 バージョンごとの対応状況

PHP バージョン libzip バージョン OSディストリビューション例 Unicode対応
5.6 0.10以下 CentOS 6 ❌ 未対応
7.0〜7.2 0.11〜0.11.2 CentOS 7前期 △ 不完全対応
7.3〜7.4 1.2〜1.5 CentOS 7後期, Ubuntu 18.04+ ✅ 対応済
8.0以降 1.6〜2.x CentOS 8, AlmaLinuxなど ✅ 安定対応

4.3 対処法

  • phpinfo() で libzip バージョンを確認
  • 展開されたファイル名の文字化けを mb_convert_encoding() などで対処
  • PclZipunzip コマンドを代替で使う方法もあり

まとめ

ZIPファイルの文字化け問題は、ローカル環境での作成方法Webシステムでの展開方法の双方に原因が潜んでいます。
特に以下の3点に着目することで、原因の特定と対処がしやすくなります:

  1. ZIP作成環境(OS・ツール):Unicodeフラグや文字コードの扱いが異なる
  2. ZIP仕様のバージョンと互換性:古い仕様ではUTF-8が考慮されていない
  3. Webシステム側(PHP, libzipの対応):libzipのバージョンが文字化けを左右

特定のケースで問題を再現・検証し、作成方法や展開処理を選定することで、トラブルを未然に防ぐことが可能です。

脚注
  1. 公式仕様:https://pkwaredownloads.blob.core.windows.net/pkware-general/Documentation/APPNOTE-6.3.9.TXT ↩︎

Discussion