BOM有りBOMなしのテキスト出力する PHP7.4 のサンプルコード

shift-jis と utf-8 の混在問題に関する記事(リンクリスト)に戻る

先日の「BOMの有無を判別し、UTFを読み分ける PHP7.4 のサンプルコード」に引き続き、

こんどは「書き込み」版を掲載する。

 

shift-jis と、BOM有りの UTF-8, UTF-16LE, UTF-16BE, UTF-32LE, UTF-32BE をテキストファイルに書き出すサンプルソースコードだ。

BOMなし UTF には対応していない。

改行コードは Windows の「CR+LF」と、Linux の「LF」の両方に対応しており、

自動で現在の実行環境に合わせるように出来ている。

 

前回の「読み込み」版と同様に、コンソールから動作させる CLI プログラムだ。

 

読み込み処理と違って、こちらは PHP ライブラリのバグ対応などないので、比較的簡単である。

 

全ソースを掲載した後、コードの解説を行う。

 

PHP7.4用の全サンプルソースコード

<?php
//--- require_once begin ---
mb_language("Japanese");

//Ecoding Name
define('SJIS', 'Windows-31J');
define('UTF8', 'UTF-8');
define('UTF16LE', 'UTF-16LE');
define('UTF16BE', 'UTF-16BE');
define('UTF32LE', 'UTF-32LE');
define('UTF32BE', 'UTF-32BE');

mb_internal_encoding(UTF8);
//mb_http_output(UTF8);

//Encoding BOM length.
define('BOM_UTF8', "xefxbbxbf");
define('BOM_UTF16LE', "xffxfe");
define('BOM_UTF16BE', "xfexff");
define('BOM_UTF32LE', "xffxfex00x00");
define('BOM_UTF32BE', "x00x00xfexff");

//Encoding CR+LF
define('CRLF_SJIS', "x0Dx0A");
define('CRLF_UTF8', "x0Dx0A");
define('CRLF_UTF16LE', "x0Dx00x0Ax00");
define('CRLF_UTF16BE', "x00x0Dx00x0A");
define('CRLF_UTF32LE', "x0Dx00x00x00x0Ax00x00x00");
define('CRLF_UTF32BE', "x00x00x00x0Dx00x00x00x0A");

//Encoding LF
define('LF_SJIS', "x0A");
define('LF_UTF8', "x0A");
define('LF_UTF16LE', "x0Ax00");
define('LF_UTF16BE', "x00x0A");
define('LF_UTF32LE', "x0Ax00x00x00");
define('LF_UTF32BE', "x00x00x00x0A");

//--- require_once end ---


function WriteBOMTextFile($fileName, $textArray, $encoding){

$allLen = 0;
$internalEncoding = mb_internal_encoding();
$bom = '';
$crlf = '';
$isCrlf = TRUE;

//Check CR+LF.
if(PHP_EOL == CRLF_UTF8){
$isCrlf = TRUE;
}
else{
$isCrlf = FALSE;
}

//Open File.
$fp = fopen($fileName, 'w');
if($fp == FALSE){
echo "Error fopen($fileName) !" . PHP_EOL;
return ;
}

//Init BOM.
switch ($encoding){

case UTF8:
$bom = BOM_UTF8;
if($isCrlf)
$crlf = CRLF_UTF8;
else
$crlf = LF_UTF8;
break;

case UTF16LE:
$bom = BOM_UTF16LE;
if($isCrlf)
$crlf = CRLF_UTF16LE;
else
$crlf = LF_UTF16LE;
break;

case UTF16BE:
$bom = BOM_UTF16BE;
if($isCrlf)
$crlf = CRLF_UTF16BE;
else
$crlf = LF_UTF16BE;
break;

case UTF32LE:
$bom = BOM_UTF32LE;
if($isCrlf)
$crlf = CRLF_UTF32LE;
else
$crlf = LF_UTF32LE;
break;

case UTF32BE:
$bom = BOM_UTF32BE;
if($isCrlf)
$crlf = CRLF_UTF32BE;
else
$crlf = LF_UTF32BE;
break;

default:
$bom = '';
if($isCrlf)
$crlf = CRLF_SJIS;
else
$crlf = LF_SJIS;
break;
}

//Write BOM.
if(strlen($bom) > 0){

$len = fwrite($fp, $bom);

if($len == FALSE){
echo "Error fwrite(bom) !" . PHP_EOL;
fclose($fp);
return FALSE;
}
}

//Loop Of Row.
foreach ($textArray as $text){

//Convert Encoding.
$text = mb_convert_encoding($text, $encoding, $internalEncoding);

//Write Text.
$len = fwrite($fp, $text . $crlf);

if($len == FALSE){
echo "Error fwrite(text) !" . PHP_EOL;
fclose($fp);
return FALSE;
}

$allLen += $len;
}

//Close File.
fclose($fp);

return $allLen;
}

//Init parameters.
$textArray = array(
"ABCDE.12345."
,"!#$%.あいうえお."
,"アイウエオ.アイウエオ."
,"日本漢字,欄廊俠俱."
,"China产乡."
,"Taiwan說姊."
,"Korea희편."
);

//$encoding = SJIS; //SJISでは英語以外の外国語は文字化けします。
$encoding = UTF8;
//$encoding = UTF16LE;
//$encoding = UTF16BE;
//$encoding = UTF32LE;
//$encoding = UTF32BE;

$fileName = 'output.txt';

//Call Function.
$wlen = WriteBOMTextFile($fileName, $textArray, $encoding);

if($wlen == FALSE){
echo "WriteBOMTextFile Error !" . PHP_EOL;
}
else{
echo "Write size = $wlen" . PHP_EOL;
}

//All End.

 

サンプルコードの解説

 

前回同様、ソースの始めの部分の「//— require_once begin —」から「//— require_once end —」で囲まれた部分は、別のソースファイルに移動して「require_once()」関数などでインクルードして使用できるように、コードを書いている。

前回の「読み込み」版との内容と重複する部分もあるので、インクルードを統合する場合は、重複分は共有してください。

同じ定数の値は同じです。

 

ヘッダー定数

読み込み版と同様に「//Ecoding Name」の部分は、文字エンコーディングの名前を定義している。

 

//Encoding CR+LF
define('CRLF_SJIS', "x0Dx0A");
define('CRLF_UTF8', "x0Dx0A");
define('CRLF_UTF16LE', "x0Dx00x0Ax00");
define('CRLF_UTF16BE', "x00x0Dx00x0A");
define('CRLF_UTF32LE', "x0Dx00x00x00x0Ax00x00x00");
define('CRLF_UTF32BE', "x00x00x00x0Dx00x00x00x0A");

これは Windows版の改行コードを定義している。

 

//Encoding LF
define('LF_SJIS', "x0A");
define('LF_UTF8', "x0A");
define('LF_UTF16LE', "x0Ax00");
define('LF_UTF16BE', "x00x0A");
define('LF_UTF32LE', "x0Ax00x00x00");
define('LF_UTF32BE', "x00x00x00x0A");

こちらは Linux版の改行コードだ。

Mac も同様。

 

メイン処理 WriteBOMTextFile 関数

メイン処理の WriteBOMTextFile 関数を定義している。

引数で指定したファイル名のファイルに、第二引数の文字列配列の内容を、文字列ごとに改行して、書き込む。

第三引数で文字エンコーディング名を指定する。

返値に書き込みバイト数を返す。

 

例外処理は書いていない。

一部、エラーの時はメッセージを表示して終了するようにしてはいる。

function WriteBOMTextFile($fileName, $textArray, $encoding){

$fileName は、書き込みファイル名

$textArray は、文字列配列であり、この配列の文字列ごとに改行して書き込む。

$encoding は、書き込みテキストの文字エンコーディングである。

 

基本的な処理の枠組みは以下のような処理になる。

ファイルを開いて、BOMを書き込み、第二引数の文字列配列の数だけループする。

ループでは文字列ごとに文字エンコーディングを変換し、文字列の末尾に改行コードを追加して、行を書き込む。

ループが終わればファイルをクローズする。


$fp = fopen($fileName, 'w');

$len = fwrite($fp, $bom);

foreach ($textArray as $text){

$text = mb_convert_encoding($text, $encoding, $internalEncoding);

$len = fwrite($fp, $text . $crlf);

$allLen += $len;
}

fclose($fp);

return $allLen;

 

詳細の解説をする。

	$internalEncoding = mb_internal_encoding();

内部文字エンコーディングを取得する。

ソースの先頭で「mb_internal_encoding(UTF8);」と宣言しているので、この値は「UTF8」である。

その他は、必要な変数の初期値である。

 

    //Check CR+LF.
if(PHP_EOL == CRLF_UTF8){
$isCrlf = TRUE;
}
else{
$isCrlf = FALSE;
}

現在実行している環境が、Windowsの改行か、Linux や Mac の改行が判定している。

 

    //Open File.
$fp = fopen($fileName, 'w');
if($fp == FALSE){
echo "Error fopen($fileName) !" . PHP_EOL;
return ;
}

ファイルを開いている。開けなければ終了する。

 

    //Init BOM.
switch ($encoding){

case UTF8:
$bom = BOM_UTF8;
if($isCrlf)
$crlf = CRLF_UTF8;
else
$crlf = LF_UTF8;
break;

case UTF16LE:
$bom = BOM_UTF16LE;
if($isCrlf)
$crlf = CRLF_UTF16LE;
else
$crlf = LF_UTF16LE;
break;

case UTF16BE:
$bom = BOM_UTF16BE;
if($isCrlf)
$crlf = CRLF_UTF16BE;
else
$crlf = LF_UTF16BE;
break;

case UTF32LE:
$bom = BOM_UTF32LE;
if($isCrlf)
$crlf = CRLF_UTF32LE;
else
$crlf = LF_UTF32LE;
break;

case UTF32BE:
$bom = BOM_UTF32BE;
if($isCrlf)
$crlf = CRLF_UTF32BE;
else
$crlf = LF_UTF32BE;
break;

default:
$bom = '';
if($isCrlf)
$crlf = CRLF_SJIS;
else
$crlf = LF_SJIS;
break;
}

第三引数で指定された、文字エンコーディングに合わせて、BOMの値と改行コードを設定している。

 

    //Write BOM.
if(strlen($bom) > 0){

$len = fwrite($fp, $bom);

if($len == FALSE){
echo "Error fwrite(bom) !" . PHP_EOL;
fclose($fp);
return FALSE;
}
}

BOMを書き込む。

shift-jis の場合は書き込まない。

 

    //Loop Of Row.
foreach ($textArray as $text){

//Convert Encoding.
$text = mb_convert_encoding($text, $encoding, $internalEncoding);

//Write Text.
$len = fwrite($fp, $text . $crlf);

if($len == FALSE){
echo "Error fwrite(text) !" . PHP_EOL;
fclose($fp);
return FALSE;
}

$allLen += $len;
}

第二引数で指定された、文字列配列の配列数だけループして、文字列を一行づつファイルに書き込む。

文字列ごとに、文字エンコーディングを変換し、末尾に改行コードを追加し、書き込む。

書き込みバイト数は累積加算していく。

 

    //Close File.
fclose($fp);

return $allLen;
}

ファイルを閉じて終了する。

書き込みバイト数を返す。これはBOMのバイト数も含む。

 

これ以降は呼び出し側の処理だ。

//Init parameters.
$textArray = array(
"ABCDE.12345."
,"!#$%.あいうえお."
,"アイウエオ.アイウエオ."
,"日本漢字,欄廊俠俱."
,"China产乡."
,"Taiwan說姊."
,"Korea희편."
);

//$encoding = SJIS; //SJISでは英語以外の外国語は文字化けします。
$encoding = UTF8;
//$encoding = UTF16LE;
//$encoding = UTF16BE;
//$encoding = UTF32LE;
//$encoding = UTF32BE;

$fileName = 'output.txt';

WriteBOMTextFile 関数の呼び出し用の引数を用意する。

$fileName 書き込みファイル名。

$textArray 書き込む内容の文字列配列。一文字列が一行になる。

$encoding 書き込み文字エンコーディングを指定する。

 

//Call Function.
$wlen = WriteBOMTextFile($fileName, $textArray, $encoding);

if($wlen == FALSE){
echo "WriteBOMTextFile Error !" . PHP_EOL;
}
else{
echo "Write size = $wlen" . PHP_EOL;
}

//All End.

WriteBOMTextFile関数を呼び出し、書き込みバイト数を表示して終了する。

エラーの場合は、エラーメッセージを表示する。

 

 

以上、読み込みと違って、簡単だったと思う。

 

要点は文字エンコーディングごとの改行コードの違いに対応している点だ。

 

 

このコードがお役に立てば幸いだ。

 

shift-jis と utf-8 の混在問題に関する記事(リンクリスト)に戻る

タイトルとURLをコピーしました