CSVファイルに保存したデータをPHPで読み込み、セレクトボックスの選択肢を自動生成する方法を紹介します。選択肢をHTMLに直接記述する必要がなく、CSVファイルの内容を変更するだけで、項目の追加や削除、表示内容の更新ができます。
CSVには「りんご」「みかん」「ぶどう」のように項目名だけを1列で登録し、そのまま選択肢として表示することもできます。また、複数の列を用意すれば、表示する文字と選択時に取得する値を分けたり、条件に応じて選択できない項目を設定したりすることも可能です。
今回のデモでは、仕組みを分かりやすくするため、商品ID・商品名・価格・在庫数を登録したCSVデータを使用します。商品名と価格を組み合わせて選択肢に表示し、在庫数が0の商品には「売り切れ」と表示して選択できないようにしています。CSVの各列をどのように利用できるかを確認できるサンプルです。
各選択肢のvalue属性には商品IDを設定しており、商品を選ぶと対応するIDを取得できます。今回は、CSVから選択肢を生成し、選択した項目のIDを取得できるところまでを紹介します。取得したIDを使って商品名・価格・在庫数などの詳細情報を検索する方法や、別のCSVファイルと関連付ける方法については、別の記事で紹介します。
商品データは仕組みを説明するための一例です。CSVの列構成や表示内容を変更すれば、店舗一覧や担当者一覧、カテゴリーなど、さまざまな用途に応用できます。なお、CSVファイルの読み込みにはPHPを使用するため、動作にはPHP対応のサーバー環境が必要です。
デモ
CSVの商品データ
サンプルとして、商品ID・商品名・価格・在庫数を登録したCSVデータを使用しています。
商品ID,商品名,価格,在庫数
101,りんご,150,20
102,みかん,120,0
103,バナナ,180,8
104,ぶどう,450,6
105,いちご,380,12
選択した値(商品ID)
取得した値:なし
変数の内容:value = "";
データ型:string(文字列)
このデモでは、CSVからセレクトボックスの選択肢を生成する仕組みを、商品データを例に紹介しています。商品名と価格を表示し、在庫数が0の「みかん」は選択できないようにしています。商品を選ぶと、その商品のIDが値として取得されます。配布コードではPHPでCSVを読み込むため、CSVの内容を変更すると選択肢にも反映されます。
Q 他のアイコンを使いたい場合はどうするの?
無料のSVGアイコン作成ツールを使って、用途に合ったアイコンを作成できます。
コードをコピーして使おう!
<?php
/* =========================================
CSVファイルの読み込み
========================================= */
// PHPファイルと同じフォルダにあるCSVファイルを指定
$csvFile = __DIR__ . '/data.csv';
// CSVから読み込んだ商品情報を格納する配列
$products = [];
// CSVファイルの読み込み状態
$csvError = false;
// CSVファイルが存在し、読み込めることを確認
if (is_file($csvFile) && is_readable($csvFile)) {
// CSVファイルを読み込み専用で開く
$handle = fopen($csvFile, 'r');
if ($handle !== false) {
// 1行目の見出しを読み飛ばす
fgetcsv($handle);
/* =========================================
CSVの各行から商品情報を取得
========================================= */
while (($columns = fgetcsv($handle)) !== false) {
// 商品ID・商品名・価格・在庫数の4列が必要
if (count($columns) !== 4) {
continue;
}
// CSVの各列を変数へ代入
$id = trim($columns[0]);
$name = trim($columns[1]);
$price = trim($columns[2]);
$stock = trim($columns[3]);
// 商品IDと商品名が空の行は使用しない
if ($id === '' || $name === '') {
continue;
}
// 価格と在庫数が0以上の整数であることを確認
if (!ctype_digit($price) || !ctype_digit($stock)) {
continue;
}
// 商品情報を配列へ追加
$products[] = [
'id' => $id,
'name' => $name,
'price' => (int) $price,
'stock' => (int) $stock
];
}
// 読み込みが終わったCSVファイルを閉じる
fclose($handle);
} else {
// CSVファイルを開けなかった場合
$csvError = true;
}
} else {
// CSVファイルが存在しない、または読み込めない場合
$csvError = true;
}
/* =========================================
HTMLに出力する文字列の安全対策
========================================= */
// CSVの文字列をHTMLへ安全に表示する
function csvProductSelectEscape($value) {
return htmlspecialchars((string) $value, ENT_QUOTES, 'UTF-8');
}
?><!DOCTYPE html>
<html lang="ja">
<head>
<!-- 文字コードの設定 -->
<meta charset="UTF-8">
<!-- スマートフォンなどの画面幅に対応 -->
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- ページタイトル -->
<title>CSVのデータをセレクトボックスに表示</title>
<!-- セレクトボックスのCSSを読み込む -->
<link rel="stylesheet" href="style.css">
</head>
<body>
<!-- セレクトボックス全体の横幅を制御する親要素 -->
<div class="csv-product-select_container">
<!-- セレクトボックスのラベル -->
<label class="csv-product-select_label" for="csv-product-select-item">
商品を選択
</label>
<!-- セレクトボックスとSVG矢印 -->
<div class="csv-product-select_select-wrap">
<!-- 選択した商品のIDをvalue属性から取得できるセレクトボックス -->
<select class="csv-product-select_select" id="csv-product-select-item" name="product">
<!-- 初期表示用の項目。商品を選択するまでは値が空になります -->
<option value="" selected disabled>選択してください</option>
<?php foreach ($products as $product): ?>
<?php
// 商品名と価格を組み合わせて選択肢の文字列を作成
$optionText = $product['name'] . '(' . $product['price'] . '円';
// 在庫数が0の場合は売り切れと表示
if ($product['stock'] === 0) {
$optionText .= '・売り切れ';
}
$optionText .= ')';
?>
<!-- valueには商品IDを設定。在庫0の商品は選択不可 -->
<option
value="<?php echo csvProductSelectEscape($product['id']); ?>"
<?php echo $product['stock'] === 0 ? 'disabled' : ''; ?>
><?php echo csvProductSelectEscape($optionText); ?></option>
<?php endforeach; ?>
</select>
<!-- セレクトボックス右端の下向きSVG矢印 -->
<svg class="csv-product-select_arrow" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<path d="m5 9 7 7 7-7"></path>
</svg>
</div>
<!-- CSVファイルを読み込めなかった場合の案内 -->
<?php if ($csvError): ?>
<p class="csv-product-select_error">
CSVファイルを読み込めませんでした。
</p>
<?php endif; ?>
</div>
</body>
</html>
コードをコピーする場合 使用するコードのタブを選び、「このタブをコピー」をクリックすると、現在表示中のコードをコピーできます。 サンプル一式を取得する場合 HTML・CSSなどすべてのファイルが必要な場合は、「サンプル一式をダウンロード」をクリックしてください。
Q ダウンロードしたけど、これをネット上で動かすにはどうするの?
Googleアカウントがあれば、InfinityFreeで無料サーバーを作成して、ダウンロードしたサンプルをネット上で動かせます。
InfinityFreeを初めて利用する場合は①から、すでにサーバーを作成している場合は②へ進んでください。
ファイル構成と設置方法
今回のサンプルは、PHP・CSS・CSVの3つのファイルで構成されています。PHPでCSVファイルを読み込み、登録されているデータからセレクトボックスの選択肢を生成します。商品名と価格を表示するだけでなく、在庫数を確認して選択できない項目を設定する仕組みも含まれています。
sample/
├── index.php
├── style.css
└── data.csv
各ファイルの役割
index.phpは、CSVファイルの読み込み、データの確認、選択肢の生成を担当します。style.cssでは、セレクトボックスの横幅・余白・枠線・角丸・SVG矢印などを設定しています。data.csvには、選択肢の生成に使用する商品ID・商品名・価格・在庫数が登録されています。
設置方法・使い方
「サンプル一式をダウンロード」をクリックしてZIPファイルを保存し、展開してください。sampleフォルダ内の3つのファイルを同じ階層に配置し、PHPに対応したサーバーへアップロードします。ブラウザからindex.phpにアクセスすると、CSVの内容を読み込んでセレクトボックスが表示されます。
PHPはサーバー側で実行されるため、HTMLファイルのようにパソコン上で直接開くだけでは動作しません。CSVを変更した場合は、ファイルを保存してページを再読み込みすると変更内容が反映されます。
PHP対応のサーバーを用意していない場合は、無料で利用できるInfinityFreeでも動作を確認できます。サーバーの準備方法はInfinityFreeで無料サーバーを作る方法、ファイルのアップロード方法はInfinityFreeのFile Managerの使い方で紹介しています。
CSVファイルの構成と編集方法
data.csvには、次のように1行目へ列の見出しを記述し、2行目以降へ選択肢のデータを登録しています。各項目は半角カンマで区切ります。
商品ID,商品名,価格,在庫数
101,りんご,150,20
102,みかん,120,0
103,バナナ,180,8
104,ぶどう,450,6
105,いちご,380,12
1列目は選択したときに取得する商品ID、2列目は商品名、3列目は価格、4列目は在庫数です。例えば101,りんご,150,20は、商品IDが101、商品名がりんご、価格が150円、在庫数が20であることを表しています。
商品を追加する場合は、同じ順番で新しい行を追加します。商品を削除する場合は該当する行を削除し、価格や在庫数を変更する場合は対象の数値を書き換えます。CSVファイルはUTF-8で保存してください。
PHPでCSVファイルを読み込む仕組み
index.phpでは、__DIR__を使ってPHPファイルと同じフォルダにあるdata.csvを指定しています。ファイルが存在し、読み込み可能であることを確認してからfopen()で開きます。
// PHPファイルと同じフォルダにあるCSVファイルを指定
$csvFile = __DIR__ . '/data.csv';
// CSVから読み込んだ商品情報を格納する配列
$products = [];
// CSVファイルの読み込み状態
$csvError = false;
// CSVファイルが存在し、読み込めることを確認
if (is_file($csvFile) && is_readable($csvFile)) {
// CSVファイルを読み込み専用で開く
$handle = fopen($csvFile, 'r');
if ($handle !== false) {
// 1行目の見出しを読み飛ばす
fgetcsv($handle);
fopen($csvFile, 'r')のrは読み込み専用を意味します。CSVの内容を書き換える処理ではありません。最初のfgetcsv($handle)は見出し行を読み飛ばすために使用しています。
その後、whileとfgetcsv()を組み合わせて、2行目以降のデータを1行ずつ読み込みます。読み込みが終わったファイルはfclose()で閉じます。
CSVの各列を取得する方法
CSVから読み込んだ1行分のデータは、$columnsという配列に格納されます。今回のCSVは4列構成なので、次のコードで各列を取り出しています。
// CSVの各列を変数へ代入
$id = trim($columns[0]);
$name = trim($columns[1]);
$price = trim($columns[2]);
$stock = trim($columns[3]);
// 商品IDと商品名が空の行は使用しない
if ($id === '' || $name === '') {
continue;
}
// 価格と在庫数が0以上の整数であることを確認
if (!ctype_digit($price) || !ctype_digit($stock)) {
continue;
}
// 商品情報を配列へ追加
$products[] = [
'id' => $id,
'name' => $name,
'price' => (int) $price,
'stock' => (int) $stock
];
$columns[0]が商品ID、$columns[1]が商品名、$columns[2]が価格、$columns[3]が在庫数に対応しています。配列の番号は0から始まるため、4列目の在庫数は$columns[3]です。
trim()で前後の空白を取り除き、商品IDや商品名が空の場合はその行を使用しません。また、ctype_digit()で価格と在庫数が0以上の整数として記述されていることを確認しています。条件に合わない行はcontinueで読み飛ばします。
正常なデータは$productsへ追加され、価格と在庫数は(int)によって整数に変換されます。
CSVからセレクトボックスの選択肢を生成する方法
読み込んだ商品データは、foreachを使って1件ずつ取り出します。商品名と価格を組み合わせた文字列を作成し、option要素の表示内容に設定しています。
<?php foreach ($products as $product): ?>
<?php
// 商品名と価格を組み合わせて選択肢の文字列を作成
$optionText = $product['name'] . '(' . $product['price'] . '円';
// 在庫数が0の場合は売り切れと表示
if ($product['stock'] === 0) {
$optionText .= '・売り切れ';
}
$optionText .= ')';
?>
<!-- valueには商品IDを設定。在庫0の商品は選択不可 -->
<option
value="<?php echo csvProductSelectEscape($product['id']); ?>"
<?php echo $product['stock'] === 0 ? 'disabled' : ''; ?>
><?php echo csvProductSelectEscape($optionText); ?></option>
<?php endforeach; ?>
例えば、りんごのデータからは「りんご(150円)」という選択肢が生成されます。商品名や価格を変更した場合は、CSVの内容を変更するだけで表示内容も変わります。
$product['stock'] === 0は、在庫数が0かどうかを判定する条件です。条件に一致した場合は表示文字列へ「・売り切れ」を追加し、option要素にdisabled属性を設定します。今回のCSVでは、在庫数が0の「みかん」が選択できない状態になります。在庫数を1以上に変更すれば、再び選択できるようになります。
また、csvProductSelectEscape()は、CSVの文字列をHTMLへ安全に出力するための関数です。商品名などにHTMLで特別な意味を持つ文字が含まれていても、そのままHTMLのタグとして解釈されないようにしています。
1列だけのCSVを使用する場合
今回は4列のCSVを使用していますが、「りんご」「みかん」「ぶどう」のように、項目名だけを1列で登録して選択肢に表示することもできます。
商品名
りんご
みかん
ぶどう
ただし、現在のindex.phpは4列のデータを前提としており、count($columns) !== 4で列数を確認しています。そのため、CSVを1列に変更するだけでは選択肢は生成されません。
1列のCSVを使用する場合は、PHP側の列数チェック、データの取り出し方、$productsへ格納する内容、選択肢の表示処理も合わせて変更する必要があります。商品IDを持たない1列のCSVでは、項目名そのものをvalueへ設定する方法が考えられます。
今回のコードは商品IDを値として取得する4列構成なので、1列のCSVを使用する場合は、必要な列だけを読み込む構成に変更してください。
選択した商品IDを取得する方法
セレクトボックスでは、表示されている商品名や価格ではなく、各option要素のvalue属性に設定した商品IDを取得します。例えば「りんご(150円)」を選択すると、取得する値は"101"です。
次のJavaScriptは値の取得方法を説明するための追加例であり、ダウンロードするZIPには含まれていません。
// セレクトボックスの要素を取得
const selectBox = document.getElementById("csv-product-select-item");
// 選択した商品IDを変数へ代入
const selectedValue = selectBox.value;
document.getElementById()でセレクトボックスを取得し、selectBox.valueを変数selectedValueへ代入しています。取得される値のデータ型はstring(文字列)です。CSVの商品IDが数値で記述されていても、セレクトボックスから取得する値は文字列になります。
このコードは実行した時点の値を取得します。初期状態では「選択してください」が表示されているため、値は空文字列""です。
商品を切り替えるたびに最新のIDを取得したい場合は、changeイベントを使用します。
// セレクトボックスの要素を取得
const selectBox = document.getElementById("csv-product-select-item");
// 選択項目が変更されたときに値を取得
selectBox.addEventListener("change", () => {
// 選択した商品IDを変数へ代入
const selectedValue = selectBox.value;
// 取得した商品IDを確認
console.log(selectedValue);
});
このコードを使用する場合は、index.phpの</body>の直前に<script>要素を追加し、その中へ記述してください。商品を選択するたびにselectedValueへ商品IDが代入され、ブラウザの開発者ツールのコンソールへ表示されます。
例えば「ぶどう(450円)」を選択すると、コンソールには104と表示されます。取得した商品IDから商品名・価格・在庫数を検索する処理や、別のCSVファイルと関連付ける処理は今回のコードには含まれていません。
セレクトボックスのデザインと矢印の配置
style.cssの.csv-product-select_selectでは、選択欄の内側の余白、枠線、角丸、文字サイズなどを設定しています。特にpadding: 16px 52px 16px 16px;は、上・右・下・左の順番で余白を指定しており、右側の52pxはSVG矢印と文字が重ならないように広く確保しています。
選択欄を縦に大きくしたい場合は上下の16pxを増やし、角の丸みを変更したい場合はborder-radius: 12px;を調整します。枠線の太さはborder: 2px solid #dbe5f1;の2pxで変更できます。
SVG矢印は.csv-product-select_arrowで配置しています。right: 18px;を大きくすると矢印が左へ移動し、小さくすると右端へ近づきます。
レスポンシブ対応
セレクトボックス全体の横幅は、.csv-product-select_containerのwidth: 100%;とmax-width: 480px;で制御しています。広い画面でも最大480pxまでに制限され、margin: 40px auto;によって中央に配置されます。最大横幅を変更したい場合は480pxを調整してください。
また、画面幅が640px以下になると、次のメディアクエリによって選択欄の内側の余白を変更します。
/* =========================================
スマートフォン対応
========================================= */
@media (max-width: 640px) {
/* 画面幅640px以下のセレクトボックス */
.csv-product-select_select {
padding: 14px 50px 14px 14px; /* 上・右・下・左の余白。スマートフォン表示の余白を調整する */
}
}
通常は上下16px、左側16px、右側52pxの余白ですが、画面幅が640px以下では上下と左側を14px、右側を50pxに変更します。小さな画面でもSVG矢印のスペースを確保しながら、セレクトボックスを表示できます。
コメント