📁 作成ファイル・保存場所
XAMPPがインストールされているhtdocs フォルダに以下のファイルを作成してください。
| ファイル名 | 内容 |
|---|---|
| htdocs/php-basic/read.php htdocs/php-basic/write.php htdocs/php-basic/bbs.php | PHPとHTML |
- XAMPP(Apacheが起動していること)
- XAMPPがインストールされているhtdocs フォルダに内に作成されていること
PHP基礎トレーニング
テキストファイルの読み込み
「sample.txt」ファイルを作成し、下記の日付と名前をカンマ区切りで作成
2025-08-30,山田太郎 2025-08-31,佐藤花子 2025-09-01,鈴木一郎
fopen関数を使って、sample.txtを読み込むプログラムを作成します。
<?php
$filename = 'sample.txt';
$errors = [];
$rows = [];
// エスケープ関数(h)を定義
function h($str) {
return htmlspecialchars($str, ENT_QUOTES, 'UTF-8');
}
// ファイルがあるか、読み込み可能かをチェック
if (!file_exists($filename)) {
$errors[] = 'ファイルが見つかりません。';
} elseif (!is_readable($filename)) {
$errors[] = 'ファイルが読み込めません。';
} else {
$fp = fopen($filename, 'r'); // ファイルを読み込みモードで開く
if ($fp) {
while (($line = fgets($fp)) !== false) { // 1行ずつ読み込み 2025-08-30,山田太郎
$line = trim($line); // 改行文字や空白を除去
if ($line === ''){
continue;
}// 空行はスキップ
$cols = explode(',', $line); // カンマで分割(→ 配列)
if (count($cols) === 2) {
$rows[] = $cols; // データ行として追加
}
}
fclose($fp); // ファイルを閉じる
} else {
$errors[] = 'ファイルのオープンに失敗しました。';
}
}
?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>fopenでメモリに優しい読み込み</title>
<style>
.red { color: red; }
</style>
</head>
<body>
<h1>fopenでメモリに優しい読み込み</h1>
<?php if (!empty($errors)): ?>
<ul class="red">
<?php foreach ($errors as $e): ?>
<li><?= h($e) ?></li>
<?php endforeach; ?>
</ul>
<?php else: ?>
<p>sample.txt の中身を表示します:</p>
<ul>
<?php foreach ($rows as $cols): ?>
<li>
日付:<?= h($cols[0]) ?>
名前:<?= h($cols[1]) ?>
</li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
</body>
</html>
| 処理内容 | 使っている関数 | 説明 |
|---|---|---|
| ファイルがあるか? 読めるか? | file_exists()is_readable() | ファイルが存在し、読み込み可能かどうかを確認 |
| ファイルを開く | fopen($filename, 'r') | 読み込みモード(r)でファイルを開く |
| 1行ずつ読み込む | fgets() | ファイルを1行ずつ読み込む(メモリにやさしい) |
| 改行を削除 | trim() | 読み込んだ1行の両端の空白・改行を除去 |
| データを分割 | explode(',', $line) | カンマで区切って「日付」「名前」に分ける |
| 読み込み終了後に閉じる | fclose() | ファイルを閉じる(開きっぱなしにしない) |
次に読み込んで・書き込んでみよう
上記の「sample.txt」ファイルがある前提で行います。
<?php
$filename = 'sample.txt';
$errors = [];
$rows = [];
// エスケープ関数 h() を定義
function h($str) {
return htmlspecialchars($str, ENT_QUOTES, 'UTF-8');
}
// ---------------------------
// 投稿があればファイルに書き込む
// ---------------------------
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$name = trim($_POST['name'] ?? '');
if ($name === '') {
// 名前が未入力の場合はエラーメッセージを配列に追加
$errors[] = '名前を入力してください。';
} else {
// 日付を取得(例:2025-09-04)
$date = date('Y-m-d');
// ファイルを「追記モード(a)」で開く
$fp = fopen($filename, 'a');
if ($fp) {
// 書き込む内容を「日付,名前」の形式で用意し、改行を追加
$line = $date . ',' . $name . "\n";
// ファイルに1行書き込む(末尾に追記)
fwrite($fp, $line);
// ファイルを閉じる
fclose($fp);
// フォームの再送信(リロード時の重複投稿)を防ぐため、同じページへリダイレクト
header('Location: ' . $_SERVER['PHP_SELF']);
exit; // リダイレクト後に処理を終了
} else {
// ファイルを開けなかった場合のエラーメッセージ
$errors[] = 'ファイルの書き込みに失敗しました。';
}
}
}
// ---------------------------
// ファイル読み込み処理(fopen + fgets)
// ---------------------------
if (!file_exists($filename)) {
$errors[] = 'ファイルが見つかりません。';
} elseif (!is_readable($filename)) {
$errors[] = 'ファイルが読み込めません。';
} else {
$fp = fopen($filename, 'r');
if ($fp) {
while (($line = fgets($fp)) !== false) {
$line = trim($line);
if ($line === '') continue;
$cols = explode(',', $line);
if (count($cols) === 2) {
$rows[] = $cols;
}
}
fclose($fp);
$rows = array_reverse($rows);
} else {
$errors[] = 'ファイルのオープンに失敗しました。';
}
}
?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>PHP:名前を投稿してファイルに保存</title>
<style>
.red { color: red; }
form { margin-bottom: 2em; }
</style>
</head>
<body>
<h1>名前の投稿フォーム</h1>
<form method="post">
<label for="name">名前を入力してください:</label>
<input type="text" id="name" name="name" value="<?= h($_POST['name'] ?? '') ?>">
<button type="submit">投稿</button>
</form>
<?php if (!empty($errors)): ?>
<ul class="red">
<?php foreach ($errors as $e): ?>
<li><?= h($e) ?></li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
<h2>投稿一覧</h2>
<?php if (empty($rows)): ?>
<p>まだ投稿はありません。</p>
<?php else: ?>
<ul>
<?php foreach ($rows as $cols): ?>
<li>
日付:<?= h($cols[0]) ?>
名前:<?= h($cols[1]) ?>
</li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
</body>
</html>
このコードの処理まとめ(簡単な解説)
| 処理内容 | 使っている関数 | 説明 |
|---|---|---|
| 名前をフォームで受け取る | $_POST['name'] | 入力された名前を受け取って変数に代入(空チェックもする) |
| ファイルに追記する | fopen($filename, 'a')fwrite() | 追記モードでファイルを開き、名前と日付を1行書き込む |
| 書き込み後に再読み込みする | header('Location: ...') | フォームの再送信を防ぐため、自分自身にリダイレクト(PRGパターン) |
| ファイルを開いて読み込む | fopen($filename, 'r')fgets() | 読み込みモードで開いて、1行ずつ読み込む(メモリにやさしい) |
| 読み込んだ行を分割する | explode(',', $line) | カンマで分割して「日付」と「名前」に分ける |
| 表示の順番を新しい順にする | array_reverse($rows) | 古い順で読み込まれた投稿を逆にして、新しい順に並べ替える |
| ファイルを閉じる | fclose($fp) | ファイルを開いた後は必ず閉じる(リソース解放) |
??(null合体演算子)の使い方
$name = trim($_POST[‘name’] ?? ”);
このコードでは、フォームから送られてきた「名前」の値を取得しています。
ただし、POSTで送られていない場合(未定義)は空文字にしたい、という目的です。
従来のif文を使って書くと・・・
if (isset($_POST['name'])) {
$name = trim($_POST['name']);
} else {
$name = '';
}
$_POST['name']がセットされていれば(isset)→ その値を使う- そうでなければ(未送信や空)→ 空文字
''を使う trim()で前後の空白も取り除いている
少し進化して、isset() + 三項演算子を使った省略形
同じことを1行で書く省略形
$name = isset($_POST['name']) ? trim($_POST['name']) : '';
isset($_POST['name'])が true のとき →trim($_POST['name'])を使う- false のとき →
''(空文字)を使う ?:は「三項演算子」と呼ばれ、if文を短く書くための記法
さらに進化した null合体演算子(??)を使った書き方(PHP7以降)
PHP7からは、さらにスッキリ書けるようになりました。
$name = trim($_POST['name'] ?? '');
??は「null合体演算子」と呼ばれます$_POST['name']が 存在し、かつ null でなければ それを使う- 存在しなければ
''を使う - 三項演算子+isset の省略形として非常に使いやすい
PHP応用トレーニング
ファイル構成:bbs.phpとbbs.txtを同じフォルダに作成
<?php
$filename = 'bbs.txt';
$errors = [];
$rows = [];
$maxCommentLength = 100;
// エスケープ関数
function h($str)
{
return htmlspecialchars($str, ENT_QUOTES, 'UTF-8');
}
// ---------------------------
// 投稿があればファイルに書き込む
// ---------------------------
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$name = trim($_POST['name'] ?? '');
$comment = trim($_POST['comment'] ?? '');
// 入力チェック
if ($name === '') {
$errors[] = '名前を入力してください。';
}
if ($comment === '') {
$errors[] = 'コメントを入力してください。';
} elseif (mb_strlen($comment) > $maxCommentLength) {
$errors[] = 'コメントは' . $maxCommentLength . '文字以内で入力してください。';
}
if (count($errors)===0) {
$date = date('Y-m-d');
$fp = fopen($filename, 'a');
if ($fp) {
$line = $date . ',' . $name . ',' . $comment . "\n";
fwrite($fp, $line);
fclose($fp);
header('Location: ' . $_SERVER['PHP_SELF']);
exit;
} else {
$errors[] = 'ファイルの書き込みに失敗しました。';
}
}
}
// ---------------------------
// ファイル読み込み
// ---------------------------
if (!file_exists($filename)) {
$errors[] = 'ファイルが見つかりません。';
} elseif (!is_readable($filename)) {
$errors[] = 'ファイルが読み込めません。';
} else {
$fp = fopen($filename, 'r');
if ($fp) {
while (($line = fgets($fp)) !== false) {
$line = trim($line);
if ($line === '') {
continue;
}
$cols = explode(',', $line, 3); // 日付, 名前, コメント
if (count($cols) === 3) {
$rows[] = $cols;
}
}
fclose($fp);
$rows = array_reverse($rows); // 新しい順に
} else {
$errors[] = 'ファイルのオープンに失敗しました。';
}
}
?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>PHP:名前とコメントを投稿する掲示板</title>
<style>
.red {
color: red;
}
h1 {
text-align: center;
}
main {
max-width: 600px;
margin: 0 auto;
}
form {
margin-bottom: 2em;
}
textarea {
width: 100%;
height: 4em;
}
ul li {
margin-bottom: 1em;
}
</style>
</head>
<body>
<h1>ミニ掲示板</h1>
<main>
<form method="post">
<label for="name">名前:</label><br>
<input type="text" id="name" name="name"><br><br>
<label for="comment">コメント(最大<?= h($maxCommentLength) ?>文字):</label><br>
<textarea id="comment" name="comment"></textarea><br><br>
<button type="submit">投稿する</button>
</form>
<?php if (!empty($errors)): ?>
<ul class="red">
<?php foreach ($errors as $e): ?>
<li><?= h($e) ?></li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
<hr>
<h2>投稿一覧(新しい順)</h2>
<?php if (empty($rows)): ?>
<p>まだ投稿はありません。</p>
<?php else: ?>
<ul>
<?php foreach ($rows as $cols): ?>
<li>
<strong><?= h($cols[1]) ?></strong>(<?= h($cols[0]) ?>)<br>
<?= nl2br(h($cols[2])) ?>
</li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
</main>
</body>
</html>
| 処理内容 | 使用している関数・構文 | 解説 |
|---|---|---|
| エスケープ関数を定義 | function h($str) { ... } | 出力時に htmlspecialchars を短く書けるようにした関数 |
| フォームが送信されたか判定 | $_SERVER['REQUEST_METHOD'] === 'POST' | POSTリクエストかどうかを判定して投稿処理に入る |
| 入力値の取得とトリム処理 | trim($_POST['name'])trim($_POST['comment']) | 空白を取り除いた状態で変数に格納 |
| 入力チェック | if ($name === '')mb_strlen() | 空欄か、文字数制限を超えていないかチェック |
| ファイルを追記モードで開く | fopen($filename, 'a') | 投稿を末尾に追加する(a = append) |
| 書き込む内容を組み立てて保存 | $line = 日付,名前,コメントfwrite() | カンマ区切りの文字列を1行書き込む |
| 再送信防止リダイレクト(PRG) | header('Location: ...')exit | フォームの再送信による重複投稿を防ぐ |
| ファイルの存在と読み込みチェック | file_exists()is_readable() | ファイルがなければエラーメッセージを表示 |
| ファイルを読み込む | fopen($filename, 'r')fgets() | ファイルを1行ずつ読み込み、配列に追加 |
| カンマで分割 | explode(',', $line, 3) | 書式:日付,名前,コメント に分解(3つに限定) |
| 新しい順に並べ替える | array_reverse($rows) | 投稿一覧を新しい順に表示したいので並び替え |
| HTML出力時のエスケープ | h()nl2br() | 出力を安全にしつつ、コメントの改行も見やすく表示 |
