「改行コードを CRLF に統一」とは何か
PHP で複数行の文字列やテキストファイルを扱うとき、「改行」が入りますが、その改行の実体は環境によって違います。
代表的な改行コードは次の3種類です。
LF : \n (Unix / Linux / macOS)
CRLF : \r\n (Windows)
CR : \r (古い Mac)
見た目はどれも「行が変わっている」ように見えますが、プログラム的には別の文字列です。
ここでやりたい「CRLF に統一する」というのは、どんな改行コードが混ざっていても、最終的にすべて \r\n の形にそろえる、という意味です。
なぜ CRLF に統一したくなるのか
Windows 向けのファイルやメールを正しく扱いたい
Windows の世界では、改行コードとして CRLF(\r\n)が標準的に使われます。
例えば、次のようなケースでは CRLF が求められることが多いです。
テキストファイルを Windows のエディタで開いたときに、きれいに行ごとに表示させたい。
Windows 系のツールに渡す CSV やログファイルを、期待通りの改行で扱わせたい。
メールのプロトコル(SMTP)では、行の区切りに CRLF を使うことが仕様として決まっている。
PHP が動いているサーバーは Linux であることが多く、その場合、内部で扱う改行は LF(\n)になりがちです。
そのまま出力すると、「Windows 側で開いたときに改行が崩れる」「仕様上 CRLF が必要なのに LF になっている」といった問題が起こります。
だからこそ、
「内部では LF でもいいけれど、外に出すときは CRLF にそろえる」
という発想が大事になります。
改行コードの違いによる「見えない差」をなくしたい
例えば、次の2つの文字列を見てください。
$text1 = "A\nB"; // LF
$text2 = "A\r\nB"; // CRLF
var_dump($text1 === $text2); // bool(false)
PHP見た目はどちらも「A と B が改行で区切られている」だけですが、プログラム的には別物です。
この違いを意識せずに比較や置換をしていると、「同じはずなのに一致しない」という、やっかいなバグの原因になります。
改行コードを CRLF に統一しておけば、「この文字列は CRLF でそろっている」という前提で処理を書けるようになります。
PHP で改行コードを CRLF に統一する基本パターン
王道パターン:いったん LF に統一してから CRLF に変換する
改行コードを CRLF にそろえるとき、いきなり全部を \r\n に置き換えるのではなく、
- まず「どんな改行コードでも LF(
\n)に統一」 - そのあとで「LF を CRLF(
\r\n)に変換」
という二段階で考えると、シンプルで安全です。
まずは「LF に統一する」関数を用意します。
function normalizeNewlineToLF(string $text): string
{
// 1. CRLF(\r\n)を LF(\n)に
$text = str_replace("\r\n", "\n", $text);
// 2. 残っている CR(\r)を LF(\n)に
$text = str_replace("\r", "\n", $text);
return $text;
}
PHP次に、「LF を CRLF に変換する」関数を用意します。
function convertLFToCRLF(string $text): string
{
// LF を CRLF に変換
return str_replace("\n", "\r\n", $text);
}
PHPそして、「改行コードを CRLF に統一する」処理は、この2つを組み合わせて書きます。
function normalizeNewlineToCRLF(string $text): string
{
// まず LF に統一
$text = normalizeNewlineToLF($text);
// その LF を CRLF に変換
$text = convertLFToCRLF($text);
return $text;
}
PHPこの流れにしておくと、
LF だけの文字列。
CRLF が混ざった文字列。
古い CR だけの文字列。
どれが来ても、最終的にはきれいに CRLF にそろえることができます。
実務での具体的なシチュエーション例
例題1:Windows 向けのテキストファイルを生成する
Linux サーバー上の PHP で、Windows ユーザー向けのテキストファイルを作るケースを考えます。
$lines = [
'1行目のテキスト',
'2行目のテキスト',
'3行目のテキスト',
];
// 内部では LF で結合
$text = implode("\n", $lines);
// 出力前に CRLF に統一
$text = normalizeNewlineToCRLF($text);
file_put_contents('output.txt', $text);
PHPこうしておけば、Windows のメモ帳や他のエディタで開いたときに、期待通りの改行で表示されます。
もし LF のまま出力すると、古いツールや一部の環境では「全部1行に見える」「変な記号が混ざる」といった問題が起きることがあります。
例題2:メール本文の改行を CRLF にそろえる
メールの世界(SMTP の仕様)では、行の区切りに CRLF を使うことが決まっています。
PHP の mail() 関数やライブラリは内部で面倒を見てくれることもありますが、自分でヘッダや本文を組み立てる場合は、改行コードを意識する必要があります。
$body = "お問い合わせありがとうございます。\n";
$body .= "以下の内容で受け付けました。\n";
$body .= "よろしくお願いいたします。\n";
// メール送信前に CRLF に統一
$body = normalizeNewlineToCRLF($body);
// あとは $body をメールライブラリに渡す、など
PHP内部では LF で組み立てておき、最後に CRLF に変換する、というスタイルにしておくと、
「メールの仕様に沿った形で改行されている」という安心感があります。
例題3:Windows ツールに渡す CSV の改行をそろえる
業務システムで CSV を出力し、それを Windows の Excel や他のツールで開いてもらうケースは非常に多いです。
$rows = [
['id', 'name'],
[1, '山田太郎'],
[2, '佐藤花子'],
];
$lines = [];
foreach ($rows as $row) {
$lines[] = implode(',', $row);
}
// 内部では LF で結合
$csv = implode("\n", $lines);
// 出力前に CRLF に統一
$csv = normalizeNewlineToCRLF($csv);
file_put_contents('users.csv', $csv);
PHPこうしておけば、Windows 環境で CSV を開いたときに、行ごとにきれいに認識されます。
改行コードがバラバラだと、「1行に全部くっついて見える」「行数がおかしい」といったトラブルにつながります。
重要ポイントの深掘り
なぜ「いきなり CRLF に置き換えない方がいい」のか
「全部 \r\n にしたいなら、最初から str_replace("\n", "\r\n", $text) でいいのでは?」と思うかもしれません。
ここが少し罠です。
例えば、もともと CRLF(\r\n)が入っている文字列に対して、いきなり \n を \r\n に置き換えるとどうなるでしょうか。
$text = "A\r\nB";
$text = str_replace("\n", "\r\n", $text);
var_dump($text);
PHP"\r\n" の中の \n が \r\n に置き換わるので、結果は "\r\r\n" という、変な改行コードになってしまいます。
これを避けるために、
- まず CRLF を LF にまとめる
- そのあとで LF を CRLF に変換する
という順番が重要になります。
この「順番を意識する」という感覚は、文字列処理全般でとても大事な考え方です。
「内部表現」と「外部表現」を分けて考える
改行コードに限らず、実務ではよく次のような設計をします。
内部では扱いやすい形式(ここでは LF)に統一する。
外部に出すときだけ、相手の都合に合わせた形式(ここでは CRLF)に変換する。
例えば、次のような流れです。
// 1. 外から入ってきたテキスト
$input = file_get_contents('somewhere.txt');
// 2. まず LF に統一(内部表現)
$normalized = normalizeNewlineToLF($input);
// 3. アプリ内部では LF 前提で処理
$lines = explode("\n", $normalized);
// いろいろ処理…
// 4. Windows 向けに出力するときだけ CRLF に変換(外部表現)
$output = normalizeNewlineToCRLF($normalized);
file_put_contents('output_for_windows.txt', $output);
PHPこうして「中では LF、外に出すときだけ CRLF」というルールを決めておくと、
コード全体の見通しがよくなり、バグも減ります。
まとめ:今日から使える「改行コードを CRLF に統一」テンプレ
実務でそのまま使える形で、改行コード関連の関数をまとめておきます。
// どんな改行コードでも、まず LF に統一
function normalizeNewlineToLF(string $text): string
{
$text = str_replace("\r\n", "\n", $text); // CRLF -> LF
$text = str_replace("\r", "\n", $text); // CR -> LF
return $text;
}
// LF を CRLF に変換
function convertLFToCRLF(string $text): string
{
return str_replace("\n", "\r\n", $text);
}
// 改行コードを CRLF に統一するユーティリティ
function normalizeNewlineToCRLF(string $text): string
{
$text = normalizeNewlineToLF($text);
return convertLFToCRLF($text);
}
PHP「Windows で開くファイルを出力するとき」「メール本文を組み立てるとき」「Windows ツールに渡す CSV を作るとき」など、
外部の仕様として CRLF が求められる場面に、この関数を一段かませるだけで、かなり安心感のあるコードになります。
