Developer

魁!小野の塾 PHPで簡単なプログラムを作ってみようの巻 第1話
2020.11.30
Lv2

魁!小野の塾 PHPで簡単なプログラムを作ってみようの巻 第1話

PHPで簡単なプログラムを作ってみよう 第1話

初心者向け、PHPプログラム構築講座です。
初心者といっても、PHPの勉強を少し行い、LAMP環境が自分で構築できるレベルを対象とします。
まったくの初心者の場合は、わからない部分が出てくると思います。
できるだけ細かく説明は入れていきますが、説明がわからない場合は、PHPやMySQLの初心者講座をご覧ください。

対象のスキルレベル

  • LAMP環境の構築
  • PHP言語が読める
  • HTML, CSS, Javascriptが少しわかる
  • Bootstrapのドキュメントをみて、HTMLが書ける
  • CDNを理解している

構築環境

  • Windows10
  • XAMPP(PHP7.3.2, MariaDB 10.1.38)

今回は、CRUD(クラッド:create, read, update, delete)のupdateを除いた、登録、読込、削除を対象に、掲示板を作成する流れを説明致します。
最初に、PHP、CSS、Javascript、DDLなど結果を表示し、それに至る過程を説明していきます。

完成イメージ

完成ソース

index.php
[php] <?php
// db resource
$db = new mysqli(‘localhost’, ‘root’, ”, ‘pjin’);
$db->set_charset("utf8");

// $_POST -> $request
$request = [
‘author’ => $_POST[‘author’] ?? ”,
‘content’ => $_POST[‘content’] ?? ”,
‘action’ => $_POST[‘action’] ?? ”
];

// create or delete
$errors = [];
switch($request[‘action’]){
case ‘create’:
// error check
if(empty($request[‘author’])){
$errors[‘author’][] = ‘名前を入力して下さい。’;
}
if(mb_strlen($request[‘author’]) > 128){
$errors[‘author’][] = ‘名前は128文字以内で入力して下さい。’;
}
if(empty($request[‘content’])){
$errors[‘content’][] = ‘内容を入力して下さい。’;
}
if(mb_strlen($request[‘content’]) > 65535){
$errors[‘content’][] = ‘名前は65,535文字以内で入力して下さい。’;
}

if(count($errors) > 0){
// エラーがあれば終了
break;
}

// 登録処理
$sql = "insert into board(author, content) values (?, ?)";
if($stmt = $db->prepare($sql)){
$stmt->bind_param("ss", $request[‘author’], $request[‘content’]);
$stmt->execute();
$stmt->close();
// 登録後に空にします。
$request = [
‘author’ => ”,
‘content’ => ”
];
}
break;

case ‘delete’;
// 削除処理
$sql = "delete from board where id = ?";
if($stmt = $db->prepare($sql)){
$stmt->bind_param("i", $_POST[‘id’]);
$stmt->execute();
$stmt->close();
}
break;
}

// 検索処理
$rs = [];
$sql = "select * from board order by id desc";
if($stmt = $db->prepare($sql)){
$stmt->execute();
$stmt->bind_result($id, $createdAt, $author, $content);
while($stmt->fetch()){
$rs[] = [
‘id’ => $id,
‘createdAt’ => $createdAt,
‘author’ => $author,
‘content’ => $content
];
}
$stmt->close();
}

// db resource close
$db->close();
?>
<!DOCTYPE html>
<html lang="ja">
<head>
<!– Required meta tags –>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

<!– Bootstrap CSS –>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css"
integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
<!– Font Awesome CSS –>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.1.0/css/all.css"
integrity="sha384-lKuwvrZot6UHsBSfcMvOkWwlCMgc0TaWr+30HWe3a4ltaBwTZhyTEggF5tJv8tbt" crossorigin="anonymous">
<!– Animate.css CSS –>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css" />
<!– Sawarabi Gothic –>
<link href="https://fonts.googleapis.com/css?family=Sawarabi+Gothic" rel="stylesheet">

<link rel="stylesheet" href="assets/css/style.css" />

<title>掲示板 | tech.pjin.jp</title>
</head>
<body>
<header>
<nav class="navbar navbar-expand-lg navbar-dark bg-info fixed-top">
<section class="container">
<a class="navbar-brand" href="<?php echo $_SERVER[‘SCRIPT_NAME’] ?>">
<h1 class="animate__animated animate__backInRight"><i class="far fa-clipboard"></i> 掲示板</h1>
</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarText" aria-controls="navbarText" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarText">
<span class="navbar-text animate__animated animate__bounce animate__delay-3s">
<i class="fas fa-heart"></i> 好きなこと書いて生きよう!
</span>
</div>
</section>
</nav>
</header>

<main class="container">

<?php if(count($errors) > 0){ ?>
<div class="alert alert-danger" role="alert">
<h4 class="alert-heading"><i class="fas fa-exclamation-triangle"></i> エラー</h4>
<ul>
<?php foreach($errors as $err){ ?>
<?php foreach($err as $e){ ?>
<li><?php echo htmlentities($e) ?></li>
<?php } ?>
<?php } ?>
</ul>
</div>
<?php } ?>

<form action="<?php echo $_SERVER[‘SCRIPT_NAME’] ?>" method="POST">
<input type="hidden" name="action" value="create">
<div class="form-group row">
<label for="author" class="col-sm-2 col-form-label">名前</label>
<div class="col-sm-10">
<input type="text" name="author" id="author"
value="<?php echo $request[‘author’] ?>"
class="form-control<?php if(isset($errors[‘author’])){ echo ‘ is-invalid’;} ?>"
placeholder="名前" autofocus>
</div>
</div>
<div class="form-group row">
<label for="content" class="col-sm-2 col-form-label">内容</label>
<div class="col-sm-10">
<textarea name="content" id="content"
class="form-control<?php if(isset($errors[‘content’])){ echo ‘ is-invalid’;} ?>"
rows="10" placeholder="内容を入力してください"><?php echo $request[‘content’] ?></textarea>
</div>
</div>
<div class="form-group row">
<div class="offset-sm-2 col-sm-10">
<button type="submit" class="btn btn-primary"><i class="fas fa-paper-plane"></i> 送信</button>
</div>
</div>
</form>

<hr>

<?php foreach($rs as $row){ ?>
<div class="card">
<div class="card-header">
<div class="row">
<div class="col-sm-6">
<strong><?php echo htmlentities($row[‘author’]) ?></strong>
</div>
<div class="col-sm-6 text-right">
<small><?php echo date(‘Y-m-d H:i:s ‘, strtotime($row[‘createdAt’])) ?></small>
</div>
</div>
</div>
<div class="card-body">
<form action="<?php echo $_SERVER[‘SCRIPT_NAME’] ?>" method="POST">
<p class="float-right">
<input type="hidden" name="action" value="delete">
<input type="hidden" name="id" value="<?php echo htmlentities($row[‘id’]) ?>">
<button type="submit" class="btn btn-outline-danger btn-sm">
<i class="far fa-trash-alt"></i> 削除
</button>
</p>
</form>
<p class="card-text">
<?php echo nl2br(htmlentities($row[‘content’])) ?>
</p>
</div>
</div>

<div class="mt-3"></div>
<?php } ?>

<div class="mt-5"></div>
</main>

<!– Optional JavaScript –>
<!– jQuery first, then Popper.js, then Bootstrap JS –>
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"
integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js"
integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js"
integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" crossorigin="anonymous"></script>
</body>
</html>
[/php]

PHPのコードを新人に見せたら、「ながっ!!」って言われました。ゴメンナサイ。
PHPとHTMLを分ければ良かったと、ちょっと後悔しております。
80行のPHPコードと120行くらいのHTMLです。合わせるとちょっと長い感があるかもしれませんが、慣れですかね。
見慣れると短いくらいです。多分。

assets/css/style.css
[css] @charset "utf-8";
*{
font-family: "Sawarabi Gothic";
}
body{
margin-top: 120px;
}
[/css]

CSSはassetsフォルダーに入れています。元々、Bootstrapでは、リソース(Javascript, CSS, imagesなど)はassetsフォルダーに入れていて、わりと名残でそれを使っているサイトをよく見ます。
まあ、サンプルは、おじさんが作っているということでご容赦頂けると幸いです。
このシリーズでは、リソースはassetsフォルダーを積極的に使っていきますので、あまり冷ややかな目で見ないように、お願い申し上げます。
今回は、Javascriptは利用していないですし、画像もありません。

DDL
[sql] CREATE TABLE `board` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT current_timestamp(),
`author` varchar(128) DEFAULT NULL,
`content` text DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

ALTER TABLE `board`
ADD PRIMARY KEY (`id`);
[/sql]

データベースは「pjin」で、テーブル名は「board」です。
XAMPPで特に設定を入れない場合は、ユーザは「root」で、パスワードはなしでログインできます。

XAMPPのコントローラでMySQL部分の「Admin」ボタンを押下すると、phpMyAdminが開きます。

phpMyAdminにログインしたら、「データベース」タブを押下し、データベース名を入力(今回はpjin)、照合順序(utf8mb4_general_ci)を選択し、「作成」ボタンを押下します。
照合順序はデフォルトが最新では変わっていますが、以前は「latin1_swedish_ci」になっています。(スウェーデン語/フィンランド語)

※参考 MySQL での文字セットと照合順序

後から変更も可能なのですがここは間違えないように、「utf8mb4_general_ci」を選択しましょう。(半角英字の大文字・小文字を区別しませんよー)
※参考 MySQLの文字コードとCollation

あと、DDLという用語ですが、SQLは「DDL」「DCL」「DML」「トランザクション制御」に分かれております。

  • DDL:Data Definition Language データベースやテーブルの作成や破棄 ※DLLではないですので注意。ちなみにDLLはDynamic Link Libraryの略
  • DCL:Data Control Language 権限の付与と剥奪
  • DML:Data Manipulation Language 検索、登録、更新、削除

魁!小野の塾