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

2020年11月19日木曜日

技術的備忘録 汎用ソースコード&ツール

t f B! P L


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', "\xef\xbb\xbf");
define('BOM_UTF16LE', "\xff\xfe");
define('BOM_UTF16BE', "\xfe\xff");
define('BOM_UTF32LE', "\xff\xfe\x00\x00");
define('BOM_UTF32BE', "\x00\x00\xfe\xff");

//Encoding CR+LF
define('CRLF_SJIS', "\x0D\x0A");
define('CRLF_UTF8', "\x0D\x0A");
define('CRLF_UTF16LE', "\x0D\x00\x0A\x00");
define('CRLF_UTF16BE', "\x00\x0D\x00\x0A");
define('CRLF_UTF32LE', "\x0D\x00\x00\x00\x0A\x00\x00\x00");
define('CRLF_UTF32BE', "\x00\x00\x00\x0D\x00\x00\x00\x0A");

//Encoding LF
define('LF_SJIS', "\x0A");
define('LF_UTF8', "\x0A");
define('LF_UTF16LE', "\x0A\x00");
define('LF_UTF16BE', "\x00\x0A");
define('LF_UTF32LE', "\x0A\x00\x00\x00");
define('LF_UTF32BE', "\x00\x00\x00\x0A");

//--- 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', "\x0D\x0A");
define('CRLF_UTF8', "\x0D\x0A");
define('CRLF_UTF16LE', "\x0D\x00\x0A\x00");
define('CRLF_UTF16BE', "\x00\x0D\x00\x0A");
define('CRLF_UTF32LE', "\x0D\x00\x00\x00\x0A\x00\x00\x00");
define('CRLF_UTF32BE', "\x00\x00\x00\x0D\x00\x00\x00\x0A");

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

 

//Encoding LF
define('LF_SJIS', "\x0A");
define('LF_UTF8', "\x0A");
define('LF_UTF16LE', "\x0A\x00");
define('LF_UTF16BE', "\x00\x0A");
define('LF_UTF32LE', "\x0A\x00\x00\x00");
define('LF_UTF32BE', "\x00\x00\x00\x0A");

こちらは 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 の混在問題に関する記事(リンクリスト)に戻る


このブログを検索

Translate

人気の投稿

自己紹介

自分の写真
オッサンです。実務経験は Windows環境にて C#,VB.NET ,SQL Server T-SQL,Oracle PL/SQL,PostgreSQL,MariaDB。昔はDelphi,C,C++ など。 趣味はUbuntu,PHP,PostgreSQL,MariaDBかな ?基本無料のやつ。

QooQ