• TOP
  • 記事一覧
  • ExcelファイルインポートでBOM付き / 無しの違いとは? ハンズオンでWordPressにCSVインポートで投稿してみよう

ExcelファイルインポートでBOM付き / 無しの違いとは? ハンズオンでWordPressにCSVインポートで投稿してみよう

更新日:2025/03/29

BOM付き / 無しとは?

「Byte Order Mark」の略です

BOMは先頭3バイトにに配置されるレベルの様なものです。

この先に続くテキストのエンコーディングの判別ができるようになります。

エンコーディングとテキストファイルについて補足

ファイルのタイプは基本的に「テキストファイル」と「バイナリファイル」があります。

※ バイナリとは基本的に 1 と 2 で構成されるデータです

テキストファイルの中身の文字はコンピュータで処理するにはにバイナリデータに変換する必要があります

上記の文字をバイナリに変換するルールが「エンコーディング」です

テキストファイルのエンコーディング 文字をバイナリデータに変換するルール UTF-8 E3 81 82 Shift-JIS 82 A0 UTF-16 30 42 同じ文字でも異なるエンコーディングでは バイナリデータの表現が異なります

BOMのメリットとデメリット

メリット

  • エンコーディングの自動判別

デメリット

  • 互換性のないソフトウェアで正しく処理されない
  • プログラム処理でBOMの有無の確認が必要
    ➡️プログラムで処理する場合はBOMなしUTF-8が安全

Excelで保存するとBOMつきになります

Excelだと編集はしやすいですがBOMつきになります

メモ帳で開きなおしてBOMなしで再度保存するか下記のようにプログラミング側での設定をする必要があります

$command = 'nkf --overwrite -w --no-bom ' . $filepath;

WordPress自作テーマでインポート処理を記述

固定ページcsv_importからcsc_import_actionにPOSTリクエスト

ファイルアップロード処理は基本的に下記がポイントになると思います!

  • アップロードディレクトリ作成
  • ファイルを管理できるように設定
  • エンコーディング

さらに実装すべきは点は下記で重要です

  • エラーハンドリング
  • ログ

<?php get_header();
$home_url = home_url();
?>
<h2>csv_import用ページ</h2>
<form action="<?php echo $home_url; ?>/csv_import_action/" method="POST" enctype="multipart/form-data">
    <input type="file" name="csv_file">
    <input type="submit" value="csvインポート実行!!">
</form>
<?php get_footer(); ?>
<?php
ini_set('display_errors', 1);
error_reporting(E_ALL);

// アップロードディレクトリ
$upload_dir = dirname(__FILE__) . "/csv/";
if (!file_exists($upload_dir)) {
    // ディレクトリが存在しない場合は作成
    if (!mkdir($upload_dir, 0777, true)) {
        die('ディレクトリの作成に失敗しました');
    }
    // パーミッションの設定
    chmod($upload_dir, 0777);
}

if (is_uploaded_file($_FILES["csv_file"]["tmp_name"])) {
    if (move_uploaded_file($_FILES["csv_file"]["tmp_name"], $upload_dir . $_FILES["csv_file"]["name"])) {
        chmod(dirname(__FILE__) . "/csv/" . $_FILES["csv_file"]["name"], 0644);
        $upload_message = $_FILES["csv_file"]["name"] . "をアップロードしました。";
        // ファイルの読み込み
    } else {
        $upload_message = "ファイルをアップロードできません。";
    }
}

$filepath = $upload_dir . $_FILES["csv_file"]["name"];
/**
 * system() - PHPからサーバー上のシェルコマンドを実行する関数
 * nkf - "Network Kanji Filter"の略で、日本語文字コード変換ツール
 * --overwrite - 元のファイルを上書きするオプション
 * -w - 出力エンコーディングをUTF-8に指定するオプション
 * PHPの内部関数であるmb_convert_encoding()などでも変換できるが、
 * シェルコマンドを直接実行する方が速い?
 */
$command = 'nkf --overwrite -w --no-bom ' . $filepath;
$result = system($command, $return_var);

// デバッグ出力
echo '<pre>';
echo "実行コマンド: " . $command . "\n";
echo "実行結果: " . ($return_var === 0 ? '成功' : '失敗') . "\n";
echo "戻り値: " . $return_var . "\n";
echo '</pre>';

$args = array(
    'post_type' => 'post',      // 通常の投稿タイプ
    'post_status' => 'any',     // 全ての状態(下書き、公開済み等)
    'posts_per_page' => -1,     // 全件取得
);
$posts = get_posts($args);

$update_post_count = 0;
$new_add_post_count = 0;

// ファイルの読み込み
if ($filepath) {
    // https://www.php.net/manual/ja/class.splfileobject.php
    $file = new SplFileObject($filepath);
    // READ_CSVフラグを使用することで、CSVファイルの内容を簡単に配列として扱うことができる
    $file->setFlags(SplFileObject::READ_CSV);

    // デバッグ出力
    echo '<pre>';
    echo "=== CSVファイルの内容 ===\n";
    foreach ($file as $i => $line) {
        echo "行 {$i}: ";
        print_r($line);
        echo "\n";
    }
    echo "=====================\n";
    echo '</pre>';

    // ファイルのインスタンスを配列に格納
    $records = [];
    $records = [];
    foreach ($file as $key => $line) {
        $records[$key] = $line;
    }

    foreach ($records as $i => $line) {

        if ($i === 0) {
            $csv_heads = $line;
            $column_indexes = array_flip($csv_heads); // 配列のキーと値を反転
            continue;
        }

        if (!$line[$column_indexes['post_title']]) {
            // csvファイルに記事の投稿名がない場合
            $non_title_line[] = $i;
            continue;
        }

        // 該当の投稿名の記事があるかどうかを確認
        $found_post = foundPost($line[$column_indexes['post_title']], $posts);
        if ($found_post) {
            // 該当の投稿名の記事がある場合
            $update_post_id = $found_post->ID;
            wp_update_post(array(
                'ID' => $update_post_id,
                'post_content' => $line[$column_indexes['post_content']],
            ));
            $update_post_count++;
        } else {
            // 該当の投稿名の記事がない場合
            wp_insert_post([
                'post_title' => $line[$column_indexes['post_title']],
                'post_content' => $line[$column_indexes['post_content']],
                'post_status' => 'publish',
                'post_type' => 'post'
            ]);
            $new_add_post_count++;
        }
    }
}

function foundPost($post_title, $posts)
{
    foreach ($posts as $post) {
        if ($post->post_title === $post_title) {
            $found_post = $post;
            break;
        }
    }
    return $found_post;
}

get_header();
?>

<div>
    <?php echo "更新記事数:" . $update_post_count; ?>
    <?php echo "<br>"; ?>
    <?php echo "新規追加記事数:" . $new_add_post_count; ?>
</div>

<?php get_footer(); ?>
人気記事ランキング
話題のキーワードから探す