PHPプログラミング

最終更新日:
公開日:

ワークショップ

ひと言掲示板を作る(17)

投稿データをCSV形式でダウンロードする

「ひと言掲示板」の管理ページについて、投稿データをCSV形式でダウンロードする機能を実装します。

この記事のポイント

  • ファイル出力はheader関数で指定する
  • ページとして表示しないときはreturnでPHPを終了させる

目次

投稿データをCSV形式でダウンロードする

前回はひと言掲示板の管理ページに管理者がログインするための機能を実装しました。
今回は管理ページに今まで投稿されたひと言メッセージのデータをダウンロードする機能を実装していきます。

今までの投稿されたデータをCSV形式でダウンロードできるようになりますが、大まかな流れは次のようなイメージになります。

admin.php」が「download.php」を呼び出して、「download.php」でCSVファイルを作成、そして最後に作成したファイルをダウンロードの形で出力して終了します。

「ひと言掲示板を作る」の概要については「ひと言掲示板を作る」をご覧ください。
デモはこちら

前回までに作成したコードはこちら:Github

管理ページにダウンロードボタンを設置する

まずは管理ページの「admin.php」に「download.php」を呼び出すためのボタンを設置しましょう。
先ほどのイメージの「(1)呼び出す」にあたる部分です。
次のように赤字になっているform要素input要素を追記してください。

admin.php

---- 省略 ----

<body>
<h1>ひと言掲示板 管理ページ</h1>
<?php if( !empty($error_message) ): ?>
    <ul class="error_message">
		<?php foreach( $error_message as $value ): ?>
            <li>・<?php echo $value; ?></li>
		<?php endforeach; ?>
    </ul>
<?php endif; ?>
<section>
<?php if( !empty($_SESSION['admin_login']) && $_SESSION['admin_login'] === true ): ?>

<form method="get" action="./download.php">
    <input type="submit" name="btn_download" value="ダウンロード">
</form>

<?php if( !empty($message_array) ){ ?>
<?php foreach( $message_array as $value ){ ?>
<article>
    <div class="info">
        <h2><?php echo htmlspecialchars($value['view_name'], ENT_QUOTES, 'UTF-8'); ?></h2>
        <time><?php echo date('Y年m月d日 H:i', strtotime($value['post_date'])); ?></time>
    </div>
    <p><?php echo nl2br( htmlspecialchars( $value['message'], ENT_QUOTES, 'UTF-8') ); ?></p>
</article>
<?php } ?>
<?php } ?>

---- 省略 ----

「ダウンロード」ボタンが押されると、form要素action属性で指定しているdownload.phpが呼び出されます。
また、今回はログイン情報のような大事なパラメータの受け渡しはありませんのでGET形式にしています。

download.phpを作成する

続いて、呼び出される「download.php」を作成します。
admin.php」を複製するなどして「download.php」という名前のファイルを作成し、以下のコードを全て入力してください。

download.php

<?php

// データベースの接続情報
define( 'DB_HOST', 'localhost');
define( 'DB_USER', 'root');
define( 'DB_PASS', 'password');
define( 'DB_NAME', 'board');

// 変数の初期化
$csv_data = null;
$sql = null;
$pdo = null;
$option = null;
$message_array = array();

session_start();

if( !empty($_SESSION['admin_login']) && $_SESSION['admin_login'] === true ) {

	// ここにファイル作成&出力する処理が入る

} else {

	// ログインページへリダイレクト
	header("Location: ./admin.php");
	exit;
}

return;

admin.php」と同様に、データベースへの接続情報は定数として宣言します。
その後に、あとで使う変数の初期化が並びます。

その後には管理ページと同じようにsession_start関数if文によるログインセッションの確認が入ります。
このif文でダウンロードを実行するユーザーが管理者なのかを判断し、もしそうであればファイルを作成する処理を実行する内容になっていきます。

もし管理者以外のユーザーによるアクセスだった場合は、header関数を使って「admin.php」に移動して終了します。
ログインセッションがない状態で管理ページに移動するので、結果としてはログインページが表示されます。

最後に「download.php」はページを表示しないため、明示的にreturn;を記述しています。

CSV形式のファイルを作成する

引き続き「download.php」にCSV形式のファイルを作成するコードを記述していきましょう。
赤字のコードを追記してください。

download.php

<?php

---- 省略 ----

if( !empty($_SESSION['admin_login']) && $_SESSION['admin_login'] === true ) {

	// 出力の設定
	header("Content-Type: text/csv");
	header("Content-Disposition: attachment; filename=メッセージデータ.csv");
	header("Content-Transfer-Encoding: binary");

} else {

---- 省略 ----

return;

3つのheader関数を追記しました。
ここではPHPの出力形式を上から順に「Content-Type」「ファイル名」「エンコーディング」を指定しています。
2つ目の「ファイル名」はダウンロードされるファイル名になります。

続いて、データベースから投稿データを取得するコードを追記します。
先ほど入力した3つのheader関数の上に赤字のコードを追記してください。

download.php

<?php

---- 省略 ----

if( !empty($_SESSION['admin_login']) && $_SESSION['admin_login'] === true ) {

	// データベースに接続
	try {

		$option = array(
			PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
			PDO::MYSQL_ATTR_MULTI_STATEMENTS => false
		);
		$pdo = new PDO('mysql:charset=UTF8;dbname='.DB_NAME.';host='.DB_HOST , DB_USER, DB_PASS, $option);

		// メッセージのデータを取得する
		$sql = "SELECT * FROM message ORDER BY post_date ASC";
		$message_array = $pdo->query($sql);

		// データベースの接続を閉じる
		$pdo = null;

	} catch(PDOException $e) {

		// 管理者ページへリダイレクト
		header("Location: ./admin.php");
		exit;
	}

	// 出力の設定
	header("Content-Type: text/csv");
	header("Content-Disposition: attachment; filename=メッセージデータ.csv");
	header("Content-Transfer-Encoding: binary");

} else {

---- 省略 ----

return;

データベースへの接続、切断は今まで作成したページと同じコードを使います。

header関数より前の位置にデータを取得するコードを書いたのは、PDOの処理を実行しているときにエラーが出て例外がスルー(発生)したときに、管理画面へ戻るためです。
そのためのコードをcatch文に設置しています。
ここではエラーのメッセージは取得せず、管理ページのadmin.phpへ移動しています。

データを取得するSQLは、データが登録された順番(古い順)にするためORDER BY句に「ASC」を指定します。
取得した投稿のデータは変数$message_arrayに入れます。

続いて、取得した投稿データを使ってCSVファイルを作成していきましょう。

download.php

<?php

---- 省略 ----

if( !empty($_SESSION['admin_login']) && $_SESSION['admin_login'] === true ) {

	// データベースに接続
	try {

		$option = array(
			PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
			PDO::MYSQL_ATTR_MULTI_STATEMENTS => false
		);
		$pdo = new PDO('mysql:charset=UTF8;dbname='.DB_NAME.';host='.DB_HOST , DB_USER, DB_PASS, $option);

		// メッセージのデータを取得する
		$sql = "SELECT * FROM message ORDER BY post_date ASC";
		$message_array = $pdo->query($sql);

		// データベースの接続を閉じる
		$pdo = null;

	} catch(PDOException $e) {

		// 管理者ページへリダイレクト
		header("Location: ./admin.php");
		exit;
	}

	// 出力の設定
	header("Content-Type: text/csv");
	header("Content-Disposition: attachment; filename=メッセージデータ.csv");
	header("Content-Transfer-Encoding: binary");

	// CSVデータを作成
	if( !empty($message_array) ) {
		
		// 1行目のラベル作成
		$csv_data .= '"ID","表示名","メッセージ","投稿日時"'."\n";
		
		foreach( $message_array as $value ) {
		
			// データを1行ずつCSVファイルに書き込む
			$csv_data .= '"' . $value['id'] . '","' . $value['view_name'] . '","' . $value['message'] . '","' . $value['post_date'] . "\"\n";
		}
	}

} else {

---- 省略 ----

コードを順に解説します。

まず、外側にあるif文でファイルに出力する投稿データがあるかをempty関数を使って確認しています。
もし投稿データがあれば、if文の中に進んでCSVファイルの1行目を生成します。

// 1行目のラベル作成
$csv_data .= '"ID","表示名","メッセージ","投稿日時"'."\n";

CSVファイルの内容は$csv_dataに入れていきます。

CSV形式のデータは値を「" (ダブルクォーテーション)」で囲み、それぞれを「, (コンマ)」で区切ります。
そして行末には改行コード「\n」を記述することで行の終わりを指定します。
この処理を繰り返して、必要な数の行だけデータを並べてファイルを作成します。

' (シングルクォーテーション)」で囲むと改行コードが通常のテキストとなってしまうため、行末の部分だけは「"」に切り替えている点に注意してください。

続いて、1行目と同じ形で投稿データの数だけループを繰り返して、ファイルの内容を$csv_dataに追記していきます。

foreach( $message_array as $value ) {

	// データを1行ずつCSVファイルに書き込む
	$csv_data .= '"' . $value['id'] . '","' . $value['view_name'] . '","' . $value['message'] . '","' . $value['post_date'] . "\"\n";
}

投稿データを1つずつ$valueに代入して、ファイルを作っていきます。
全ての投稿データをファイル内容として追記したらループが終了し、ファイルの作成も完了します。

ファイルを出力する

最後に、ファイルを出力してダウンロードするためのコードを追記します。

download.php

<?php

---- 省略 ----

if( !empty($_SESSION['admin_login']) && $_SESSION['admin_login'] === true ) {

	// データベースに接続
	try {

		$option = array(
			PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
			PDO::MYSQL_ATTR_MULTI_STATEMENTS => false
		);
		$pdo = new PDO('mysql:charset=UTF8;dbname='.DB_NAME.';host='.DB_HOST , DB_USER, DB_PASS, $option);

		// メッセージのデータを取得する
		$sql = "SELECT * FROM message ORDER BY post_date ASC";
		$message_array = $pdo->query($sql);

		// データベースの接続を閉じる
		$pdo = null;

	} catch(PDOException $e) {

		// 管理者ページへリダイレクト
		header("Location: ./admin.php");
		exit;
	}

	// 出力の設定
	header("Content-Type: text/csv");
	header("Content-Disposition: attachment; filename=メッセージデータ.csv");
	header("Content-Transfer-Encoding: binary");

	// CSVデータを作成
	if( !empty($message_array) ) {
		
		// 1行目のラベル作成
		$csv_data .= '"ID","表示名","メッセージ","投稿日時"'."\n";
		
		foreach( $message_array as $value ) {
		
			// データを1行ずつCSVファイルに書き込む
			$csv_data .= '"' . $value['id'] . '","' . $value['view_name'] . '","' . $value['message'] . '","' . $value['post_date'] . "\"\n";
		}
	}

	// ファイルを出力	
	echo $csv_data;

} else {

---- 省略 ----

すでにheader関数で出力形式をCSVファイル(text/csv)に指定しているため、ここまで投稿データを入れてきた$csv_dataecho関数で出力するだけでファイルを出力することができます。
早速、「admin.php」に設置したダウンロードボタンを押してみましょう。

ファイルのダウンロードが実行されれば成功です。
ダウンロードしたCSVファイルは、テキストエディタで開くと次のような内容が書き込まれています。

ファイルの内容例

"ID","表示名","メッセージ","投稿日時"
"1","涼子","データベースにデータを登録してみる","2019-03-28 16:38:28"
"2","テスト太郎","投稿のテストです","2019-03-28 20:02:58"
"3","康平","こんばんは!","2019-03-28 20:26:38"
"6","花子","セッションのテスト","2019-04-01 16:13:49"

CSVファイルはExcelやNumbersなどの表計算ソフトで開くこともできます。

今回はひと言メッセージの投稿データをダウンロードする機能を実装しました。
次回はさらに機能を拡張して、ダウンロードする投稿データの件数を選べるようにしていきます。

今回作成したコード:Github