PHPとfontforgeで実装するWebフォント変換サーバー
はじめに
Webサイトで好きなフォントを使いたい時、「Webフォント」は非常に強力な選択肢です。しかし、フォント形式にはOTF
, TTF
, WOFF
, WOFF2
, EOT
, SVG
など様々な種類があり、クロスブラウザ対応を考えると複数の形式を用意する必要があって面倒ですよね。
また、フォントファイルをサーバーにアップロードして変換ツールにかける、という作業も手間がかかります。
この記事では、そんな手間を解消するために、PHPのプログラムからサーバーサイドでフォント形式を自動変換する仕組みを実装した際の知見を共有します。
やりたいこと
- ユーザーがフォームから
OTF
またはTTF
形式のフォントファイルをアップロードする。 - サーバー側で、アップロードされたフォントを主要なWebフォント形式(
WOFF2
,WOFF
,EOT
,SVG
)に一括変換する。 - 変換したフォントファイルをZIPファイルにまとめて、ユーザーにダウンロードさせる。
中核を担う技術:FontForgeと各種コンバーター
今回の仕組みの心臓部となるのが、CUI(コマンドライン)で動作するフォント編集・変換ツールです。これらをPHPのexec()
関数から呼び出して利用します。
-
FontForge:
オープンソースの高機能フォントエディタ。コマンドラインからスクリプトを実行でき、OTF
からTTF
、TTF
からSVG
など、主要な変換を担います。 -
ttf2eot, ttf2woff, woff2_compress:
それぞれTTF
を各Webフォント形式に変換するための専用コンバーターツールです。事前にサーバーにインストールしておく必要があります。
# 事前に必要なツールをインストールしておく
sudo apt-get install fontforge woff-tools woff2 ...
実装のポイント (CakePHPでの例)
今回はCakePHPのコントローラー内に実装した例を元に、処理の流れを解説します。
1. ファイルのアップロードと前処理
まず、フォームから送信されたフォントファイルを受け取ります。ファイル名に日本語などが含まれているとサーバーで扱いにくいため、Inflector::slug()
などを使って英数字の安全なファイル名に変換しておきます。
$data = $this->request->getData();
$tmp_path = TMP . 'web_font_files/';
$original_pathinfo = pathinfo($data['WebFontFile']['ttf']['name']);
// ファイル名をASCII文字のみに変換
$file_name = \Cake\Utility\Inflector::slug($original_pathinfo['filename']);
$ttf_file_name = $file_name . '.ttf';
$ttf_file_path = $tmp_path . $ttf_file_name;
// アップロードされたファイルを一時ディレクトリにコピー
exec("cp {$data['WebFontFile']['ttf']['tmp_name']} " . $ttf_file_path);
2. OTFからTTFへの変換
アップロードされたのがOTF
ファイルだった場合、まずFontForge
を使ってTTF
に変換します。TTF
の方が他のWebフォント形式への変換元として扱いやすいためです。
if (!empty($data['WebFontFile']['otf']['name'])) {
// ...前処理...
// FontForgeのスクリプト機能を使ってOTFをTTFに変換
exec('fontforge -lang=ff -c \'Open($1); Generate($1:r + ".ttf")\' ' . $otf_file_path);
// ...後処理...
}
fontforge -lang=ff -c '...'
というコマンドで、FontForgeのスクリプトを直接実行しています。
3. TTFから各種Webフォントへの変換
ベースとなるTTF
ファイルが用意できたら、そこから各種コンバーターを使ってWOFF2
, WOFF
, EOT
, SVG
を生成していきます。
// ttf => svg に変換
exec('fontforge -lang=ff -c \'Open($1); Generate($1:r + ".svg")\' ' . $ttf_file_path);
// ttf => eot に変換
$eot_file_path = $tmp_path . $file_name . '.eot';
exec('ttf2eot ' . $ttf_file_path . ' ' . $eot_file_path);
// ttf => woff に変換
exec('ttf2woff ' . $ttf_file_path);
// ttf => woff2 に変換
exec('woff2_compress ' . $ttf_file_path);
exec()
で外部コマンドを順番に実行しているだけですが、これで一時ディレクトリに各形式のフォントファイルが生成されます。
4. ZIP圧縮とダウンロード
最後に、生成された全てのフォントファイルをzip
コマンドで一つのファイルにまとめ、一時ファイルを削除してから、ユーザーをダウンロード用のURLにリダイレクトさせます。
$zip_files = '';
// ... 生成されたファイルのパスを$zip_filesにまとめる ...
$dl_file_path = WWW_ROOT . 'files/';
$zip_file = $file_name . '.zip';
// -j オプションでディレクトリ構造を無視して圧縮
exec('zip -j ' . $dl_file_path . $zip_file . $zip_files);
// ... 一時ファイルを削除 ...
// ダウンロードアクションにリダイレクト
return $this->redirect(['action's => 'downloadWebFont', '?' => ['file' => $zip_file]]);
注意点
-
セキュリティ:
exec()
関数は、ユーザーからの入力をそのまま渡すと非常に危険です(OSコマンドインジェクション)。ファイル名などをescapeshellarg()
でエスケープ処理するか、今回の例のようにInflector::slug()
で安全な文字列に変換する処理が必須です。 - サーバー負荷: フォントの変換処理はCPUに負荷がかかります。利用頻度が高いサービスにする場合は、処理をキューイングするなどの非同期化を検討する必要があります。
-
エラーハンドリング:
exec()
の実行結果をしっかりハンドリングし、変換に失敗した場合の処理を実装することが重要です(コード例では省略しています)。
まとめ
PHPからFontForge
などのコマンドラインツールを呼び出すことで、Webフォントの変換処理を自動化する仕組みを実装しました。
Webサービスとして公開すれば、デザイナーやフロントエンドエンジニアの面倒なフォント変換作業を効率化できる、価値あるツールになるかもしれません。PHPの可能性とLinuxコマンドの強力さを再認識できた、楽しい開発でした。
この記事で紹介した内容以外にも、技術情報をブログで発信しています。
MyNote
Discussion