<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>実践プロジェクト | Code-ch</title>
	<atom:link href="https://code-ch.com/category/%E5%AE%9F%E8%B7%B5%E3%83%97%E3%83%AD%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88/feed/" rel="self" type="application/rss+xml" />
	<link>https://code-ch.com</link>
	<description></description>
	<lastBuildDate>Thu, 27 Feb 2025 23:38:04 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	

<image>
	<url>https://code-ch.com/wp-content/uploads/2024/04/logo_code-ch-150x150.png</url>
	<title>実践プロジェクト | Code-ch</title>
	<link>https://code-ch.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>PHPで作る！シンプルなTodoリスト &#8211; データベース連携編</title>
		<link>https://code-ch.com/php-project-todolist-with-db/</link>
					<comments>https://code-ch.com/php-project-todolist-with-db/#respond</comments>
		
		<dc:creator><![CDATA[TJR]]></dc:creator>
		<pubDate>Mon, 24 Feb 2025 09:55:11 +0000</pubDate>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[実践プロジェクト]]></category>
		<category><![CDATA[初学者向け]]></category>
		<guid isPermaLink="false">https://code-ch.com/?p=713</guid>

					<description><![CDATA[前回の記事では、セッションでの一時的なデータ保存を実装しました。今回は、実践的なデータベース管理へとステップアップしましょう。この記事では、PHPとMySQLを使ってTodoリストを改良し、永続的にデータを保存できるよう [&#8230;]]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-large"><img fetchpriority="high" decoding="async" width="1024" height="576" src="https://code-ch.com/wp-content/uploads/2025/02/thumbnail_todo_db-1024x576.jpg" alt="" class="wp-image-714" srcset="https://code-ch.com/wp-content/uploads/2025/02/thumbnail_todo_db-1024x576.jpg 1024w, https://code-ch.com/wp-content/uploads/2025/02/thumbnail_todo_db-300x169.jpg 300w, https://code-ch.com/wp-content/uploads/2025/02/thumbnail_todo_db-768x432.jpg 768w, https://code-ch.com/wp-content/uploads/2025/02/thumbnail_todo_db-1536x864.jpg 1536w, https://code-ch.com/wp-content/uploads/2025/02/thumbnail_todo_db-120x68.jpg 120w, https://code-ch.com/wp-content/uploads/2025/02/thumbnail_todo_db-160x90.jpg 160w, https://code-ch.com/wp-content/uploads/2025/02/thumbnail_todo_db-320x180.jpg 320w, https://code-ch.com/wp-content/uploads/2025/02/thumbnail_todo_db.jpg 1920w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">前回の記事では、セッションでの一時的なデータ保存を実装しました。今回は、実践的なデータベース管理へとステップアップしましょう。この記事では、PHPとMySQLを使ってTodoリストを改良し、永続的にデータを保存できるようにします。</p>



<div class="wp-block-cocoon-blocks-tab-caption-box-1 tab-caption-box block-box has-background has-border-color has-cocoon-white-background-color has-blue-border-color not-nested-style cocoon-block-tab-caption-box" style="--cocoon-custom-background-color:#ffffff;--cocoon-custom-border-color:#0095d9"><div class="tab-caption-box-label block-box-label box-label"><span class="tab-caption-box-label-text block-box-label-text box-label-text">前回の記事はこちら</span></div><div class="tab-caption-box-content block-box-content box-content">
<div class="wp-block-cocoon-blocks-blogcard blogcard-type bct-none">

<a href="https://code-ch.com/php-project-todolist/" title="PHPで作る！シンプルなTodoリスト入門" class="blogcard-wrap internal-blogcard-wrap a-wrap cf"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img decoding="async" width="160" height="90" src="https://code-ch.com/wp-content/uploads/2025/01/thumbnail_try-todo-2-160x90.jpg" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://code-ch.com/wp-content/uploads/2025/01/thumbnail_try-todo-2-160x90.jpg 160w, https://code-ch.com/wp-content/uploads/2025/01/thumbnail_try-todo-2-300x169.jpg 300w, https://code-ch.com/wp-content/uploads/2025/01/thumbnail_try-todo-2-768x432.jpg 768w, https://code-ch.com/wp-content/uploads/2025/01/thumbnail_try-todo-2-120x68.jpg 120w, https://code-ch.com/wp-content/uploads/2025/01/thumbnail_try-todo-2-320x180.jpg 320w, https://code-ch.com/wp-content/uploads/2025/01/thumbnail_try-todo-2.jpg 1024w" sizes="(max-width: 160px) 100vw, 160px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">PHPで作る！シンプルなTodoリスト入門</div><div class="blogcard-snippet internal-blogcard-snippet">PHPの基本機能を使ってTodoリストを作成します。セッション管理、フォーム処理、配列操作など、Web開発の基礎が学べる実践的なプロジェクトです。</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img decoding="async" src="https://www.google.com/s2/favicons?domain=https://code-ch.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">code-ch.com</div></div><div class="blogcard-date internal-blogcard-date"><div class="blogcard-post-date internal-blogcard-post-date">2025.02.02</div></div></div></div></a>
</div>
</div></div>



<div class="wp-block-cocoon-blocks-tab-caption-box-1 tab-caption-box block-box has-background has-border-color has-cocoon-white-background-color has-blue-border-color not-nested-style cocoon-block-tab-caption-box" style="--cocoon-custom-background-color:#ffffff;--cocoon-custom-border-color:#0095d9"><div class="tab-caption-box-label block-box-label box-label"><span class="tab-caption-box-label-text block-box-label-text box-label-text">XAMPPの導入がまだの方はこちら</span></div><div class="tab-caption-box-content block-box-content box-content">
<div class="wp-block-cocoon-blocks-blogcard blogcard-type bct-none">

<a href="https://code-ch.com/php-xampp-install/" title="【PHP】環境構築（Windows11）" class="blogcard-wrap internal-blogcard-wrap a-wrap cf"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img loading="lazy" decoding="async" width="160" height="90" src="https://code-ch.com/wp-content/uploads/2024/09/thumbnail-php-xampp-160x90.jpg" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://code-ch.com/wp-content/uploads/2024/09/thumbnail-php-xampp-160x90.jpg 160w, https://code-ch.com/wp-content/uploads/2024/09/thumbnail-php-xampp-300x169.jpg 300w, https://code-ch.com/wp-content/uploads/2024/09/thumbnail-php-xampp-1024x576.jpg 1024w, https://code-ch.com/wp-content/uploads/2024/09/thumbnail-php-xampp-768x432.jpg 768w, https://code-ch.com/wp-content/uploads/2024/09/thumbnail-php-xampp-1536x864.jpg 1536w, https://code-ch.com/wp-content/uploads/2024/09/thumbnail-php-xampp-120x68.jpg 120w, https://code-ch.com/wp-content/uploads/2024/09/thumbnail-php-xampp-320x180.jpg 320w, https://code-ch.com/wp-content/uploads/2024/09/thumbnail-php-xampp.jpg 1920w" sizes="(max-width: 160px) 100vw, 160px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">【PHP】環境構築（Windows11）</div><div class="blogcard-snippet internal-blogcard-snippet">PHPの実行環境を構築する手順を分かりやすく解説。XAMPPを使ったローカル環境で、PHPスクリプトを実行します。</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img decoding="async" src="https://www.google.com/s2/favicons?domain=https://code-ch.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">code-ch.com</div></div><div class="blogcard-date internal-blogcard-date"><div class="blogcard-post-date internal-blogcard-post-date">2024.09.16</div></div></div></div></a>
</div>
</div></div>




  <div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-2" checked><label class="toc-title" for="toc-checkbox-2">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">データベースの作成</a></li><li><a href="#toc2" tabindex="0">テーブルの作成</a></li><li><a href="#toc3" tabindex="0">php側の処理</a><ol><li><a href="#toc4" tabindex="0">定数の定義</a></li><li><a href="#toc5" tabindex="0">データベースとの接続</a></li><li><a href="#toc6" tabindex="0">フロントエンドとデータベースの連携</a><ol><li><a href="#toc7" tabindex="0">Todo追加機能</a></li></ol></li><li><a href="#toc8" tabindex="0">Todo一覧取得機能</a></li><li><a href="#toc9" tabindex="0">フォーム処理部分</a></li><li><a href="#toc10" tabindex="0">フロントエンド側の処理</a></li></ol></li></ol>
    </div>
  </div>

<h2 class="wp-block-heading"><span id="toc1">データベースの作成</span></h2>



<p class="wp-block-paragraph">まずXAMPP Control Panelを開き、ApacheとMySQLをStartします。</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="665" src="https://code-ch.com/wp-content/uploads/2025/02/php-todo-1-1024x665.png" alt="" class="wp-image-734" srcset="https://code-ch.com/wp-content/uploads/2025/02/php-todo-1-1024x665.png 1024w, https://code-ch.com/wp-content/uploads/2025/02/php-todo-1-300x195.png 300w, https://code-ch.com/wp-content/uploads/2025/02/php-todo-1-768x499.png 768w, https://code-ch.com/wp-content/uploads/2025/02/php-todo-1.png 1336w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">次にMySQLの行にあるAdminをクリックします。</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="665" src="https://code-ch.com/wp-content/uploads/2025/02/php-todo-2-1024x665.png" alt="" class="wp-image-735" srcset="https://code-ch.com/wp-content/uploads/2025/02/php-todo-2-1024x665.png 1024w, https://code-ch.com/wp-content/uploads/2025/02/php-todo-2-300x195.png 300w, https://code-ch.com/wp-content/uploads/2025/02/php-todo-2-768x499.png 768w, https://code-ch.com/wp-content/uploads/2025/02/php-todo-2.png 1336w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">するとブラウザでphpmyadminが開きます。</p>



<div class="wp-block-cocoon-blocks-tab-caption-box-1 tab-caption-box block-box has-border-color has-orange-border-color not-nested-style cocoon-block-tab-caption-box" style="--cocoon-custom-border-color:#f39800"><div class="tab-caption-box-label block-box-label box-label fab-question-circle"><span class="tab-caption-box-label-text block-box-label-text box-label-text">phpmyadminとは</span></div><div class="tab-caption-box-content block-box-content box-content">
<p class="wp-block-paragraph">phpMyAdminはMySQLをブラウザ上で簡単に扱えるツールです。データベースやテーブルの編集をGUI（マウスでの操作）で行うことができます。</p>
</div></div>



<p class="wp-block-paragraph">サイドバーの「新規作成」からデータベースを作成します。今回はtodo_dbという名前にします。</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="210" src="https://code-ch.com/wp-content/uploads/2025/02/image-1024x210.png" alt="" class="wp-image-736" srcset="https://code-ch.com/wp-content/uploads/2025/02/image-1024x210.png 1024w, https://code-ch.com/wp-content/uploads/2025/02/image-300x61.png 300w, https://code-ch.com/wp-content/uploads/2025/02/image-768x157.png 768w, https://code-ch.com/wp-content/uploads/2025/02/image.png 1245w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<h2 class="wp-block-heading"><span id="toc2">テーブルの作成</span></h2>



<p class="wp-block-paragraph">データベースを作成したら次にテーブルを作成するのですが、その前にTodoを構成するデータを洗い出していきます。</p>



<div class="wp-block-cocoon-blocks-iconlist-box iconlist-box blank-box list-caret-right block-box"><div class="iconlist-title">Todoを構成する要素、およびデータの形式</div>
<ul class="wp-block-list">
<li>id &#8211; 文字列</li>



<li>text &#8211; 文字列</li>



<li>作成日時 &#8211; 日時</li>
</ul>
</div>



<p class="wp-block-paragraph">テーブル名は「todos」、カラム数は3（id・Todo・作成日時）です。</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="263" src="https://code-ch.com/wp-content/uploads/2025/02/image-1-1024x263.png" alt="" class="wp-image-737" srcset="https://code-ch.com/wp-content/uploads/2025/02/image-1-1024x263.png 1024w, https://code-ch.com/wp-content/uploads/2025/02/image-1-300x77.png 300w, https://code-ch.com/wp-content/uploads/2025/02/image-1-768x197.png 768w, https://code-ch.com/wp-content/uploads/2025/02/image-1.png 1086w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">テーブルを作成すると、カラムの詳細を設定する画面に移ります。下記画像のように変更していきます。<span class="marker-blue">（<span class="cocoon-custom-text-1">色のついている</span>箇所です）</span></p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="233" src="https://code-ch.com/wp-content/uploads/2025/02/image-7-1024x233.png" alt="" class="wp-image-749" srcset="https://code-ch.com/wp-content/uploads/2025/02/image-7-1024x233.png 1024w, https://code-ch.com/wp-content/uploads/2025/02/image-7-300x68.png 300w, https://code-ch.com/wp-content/uploads/2025/02/image-7-768x174.png 768w, https://code-ch.com/wp-content/uploads/2025/02/image-7-1536x349.png 1536w, https://code-ch.com/wp-content/uploads/2025/02/image-7-2048x465.png 2048w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<div class="wp-block-cocoon-blocks-iconlist-box iconlist-box blank-box list-caret-right block-box"><div class="iconlist-title">Todoを構成する要素、およびMySQLでのデータ型</div>
<ul class="wp-block-list">
<li>id &#8211; VARCHAR(13)
<ul class="wp-block-list">
<li>文字列を格納できます</li>



<li>カッコ内の数字は最大文字数を表します</li>



<li>IDなどの文字列型の識別子によく使用されます</li>
</ul>
</li>



<li>text &#8211; TEXT
<ul class="wp-block-list">
<li>長い文字列データを格納できます</li>



<li>メモや説明文など、長さが決まっていない文字列データに向いています</li>
</ul>
</li>



<li>created_at &#8211; DATETIME
<ul class="wp-block-list">
<li>日付と時刻を格納できます</li>



<li>&#8216;YYYY-MM-DD HH:MM:SS&#8217; の形式で保存されます</li>



<li>current_timestampをデフォルト値とすることで、レコード作成時の時刻が自動的に設定されます</li>



<li>タイムスタンプとして使用され、データの作成・更新時刻の管理に適しています</li>
</ul>
</li>
</ul>
</div>



<p class="wp-block-paragraph">上記入力後、「保存する」を押すとテーブルが完成します。これでデータを保存できるようになりました！</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="246" src="https://code-ch.com/wp-content/uploads/2025/02/image-8-1024x246.png" alt="" class="wp-image-750" srcset="https://code-ch.com/wp-content/uploads/2025/02/image-8-1024x246.png 1024w, https://code-ch.com/wp-content/uploads/2025/02/image-8-300x72.png 300w, https://code-ch.com/wp-content/uploads/2025/02/image-8-768x185.png 768w, https://code-ch.com/wp-content/uploads/2025/02/image-8-1536x369.png 1536w, https://code-ch.com/wp-content/uploads/2025/02/image-8.png 1748w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<h2 class="wp-block-heading"><span id="toc3">php側の処理</span></h2>



<p class="wp-block-paragraph">phpのコーディングに移ります。config.phpを新たに作成して、データベースに関する処理を記述していきます。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-php" data-file="config.php" data-lang="PHP"><code>&lt;?php
define(&#39;DB_HOST&#39;, &#39;localhost&#39;);
define(&#39;DB_NAME&#39;, &#39;todo_db&#39;);
define(&#39;DB_USER&#39;, &#39;root&#39;);
define(&#39;DB_PASS&#39;, &#39;&#39;);

try {
    $pdo = new PDO(
        &quot;mysql:host=&quot; . DB_HOST . &quot;;dbname=&quot; . DB_NAME,
        DB_USER,
        DB_PASS
    );
} catch (PDOException $e) {
    exit(&#39;データベース接続に失敗しました。&#39; . $e-&gt;getMessage());
}</code></pre></div>



<h3 class="wp-block-heading"><span id="toc4">定数の定義</span></h3>



<div class="hcb_wrap"><pre class="prism line-numbers lang-php" data-lang="PHP"><code>define(&#39;DB_HOST&#39;, &#39;localhost&#39;);
define(&#39;DB_NAME&#39;, &#39;todo_db&#39;);
define(&#39;DB_USER&#39;, &#39;root&#39;);
define(&#39;DB_PASS&#39;, &#39;&#39;);</code></pre></div>



<p class="wp-block-paragraph">まずdefine構文で定数を宣言しています。</p>



<div class="wp-block-cocoon-blocks-tab-caption-box-1 tab-caption-box block-box not-nested-style cocoon-block-tab-caption-box"><div class="tab-caption-box-label block-box-label box-label fab-graduation-cap"><span class="tab-caption-box-label-text block-box-label-text box-label-text">Manual &#8211; define関数</span></div><div class="tab-caption-box-content block-box-content box-content">
<div class="hcb_wrap"><pre class="prism line-numbers lang-php" data-lang="PHP"><code>define(定数名, 値);</code></pre></div>



<p class="wp-block-paragraph">指定した名前で定数を作成します。定数は変更できず、内容が変化しないことが保証される名前が必要なときに使用されます。</p>
</div></div>



<p class="wp-block-paragraph">上から順に、ホスト名、データベース名、ユーザー名、パスワードと定義しています。</p>



<h3 class="wp-block-heading"><span id="toc5">データベースとの接続</span></h3>



<p class="wp-block-paragraph">次のtry節ではデータベースと接続しています。PDOというオブジェクトを使うことで、DBとの接続をシンプルに行えます。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-php" data-lang="PHP"><code>try {
    $pdo = new PDO(
        &quot;mysql:host=&quot; . DB_HOST . &quot;;dbname=&quot; . DB_NAME . &quot;;charset=utf8mb4&quot;,
        DB_USER,
        DB_PASS
    );
} catch (PDOException $e) {
    exit(&#39;データベース接続に失敗しました。&#39; . $e-&gt;getMessage());
}</code></pre></div>



<div class="wp-block-cocoon-blocks-tab-caption-box-1 tab-caption-box block-box not-nested-style cocoon-block-tab-caption-box"><div class="tab-caption-box-label block-box-label box-label fab-graduation-cap"><span class="tab-caption-box-label-text block-box-label-text box-label-text">Manual &#8211; PDO</span></div><div class="tab-caption-box-content block-box-content box-content">
<p class="wp-block-paragraph">pdoはmysqlのほか、postgreSQLやSQLiteなどのデータベースと接続できます。データベースが何であるかにかかわらず、同じ関数を使用してクエリの発行やデータの取得が行えます。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-php" data-lang="PHP"><code>new PDO(dsn, ユーザー名, パスワード);</code></pre></div>



<p class="wp-block-paragraph">dsn(Data Source Name)にはデータベースに接続するために必要な情報（データベースの種類、ホスト名、データベース名、文字セットなど）が記載されています。</p>



<p class="wp-block-paragraph">今回使っているdsnは以下のようになります。<br>&#8220;mysql:host=localhost; dbname=todo_db; charset=utf8mb4&#8221;</p>



<ul class="wp-block-list">
<li>mysql: [データベース管理システム]</li>



<li>host=localhost [ホスト名]</li>



<li>dbname=todo_db [データベース名]</li>



<li>charset=utf8mb4 [文字セット]</li>
</ul>
</div></div>



<h3 class="wp-block-heading"><span id="toc6">フロントエンドとデータベースの連携</span></h3>



<p class="wp-block-paragraph">先ほど見たconfig.phpファイルを読み込んで、データベースに接続します。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-php" data-file="index.php" data-lang="PHP"><code>&lt;?php
require_once &#39;config.php&#39;;

// Todo追加
function addTodo($text)
{
    global $pdo;
    $id = uniqid();
    $stmt = $pdo-&gt;prepare(&quot;INSERT INTO todos (id, text) VALUES (?, ?)&quot;);
    return $stmt-&gt;execute([$id, $text]);
}

// Todo一覧取得
function getTodos()
{
    global $pdo;
    $stmt = $pdo-&gt;query(&quot;SELECT * FROM todos ORDER BY created_at DESC&quot;);
    return $stmt-&gt;fetchAll(PDO::FETCH_ASSOC);
}

// Todo削除
function deleteTodo($id)
{
    global $pdo;
    $stmt = $pdo-&gt;prepare(&quot;DELETE FROM todos WHERE id = ?&quot;);
    return $stmt-&gt;execute([$id]);
}

// フォーム処理
if (isset($_POST[&#39;add&#39;]) && !empty($_POST[&#39;todo&#39;])) {
    addTodo($_POST[&#39;todo&#39;]);
}

if (isset($_POST[&#39;delete&#39;]) && !empty($_POST[&#39;id&#39;])) {
    deleteTodo($_POST[&#39;id&#39;]);
}

// Todo一覧取得
$todos = getTodos();
?&gt;

&lt;!DOCTYPE html&gt;
&lt;html&gt;

&lt;head&gt;
    &lt;title&gt;My Todo List&lt;/title&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;
    &lt;link rel=&quot;stylesheet&quot; href=&quot;style.css&quot;&gt;
&lt;/head&gt;

&lt;body&gt;
    &lt;div class=&quot;container&quot;&gt;
        &lt;h1&gt;My Todo List&lt;/h1&gt;

        &lt;form method=&quot;POST&quot; class=&quot;add-form&quot;&gt;
            &lt;input type=&quot;text&quot; name=&quot;todo&quot; placeholder=&quot;新しいタスクを入力&quot; required&gt;
            &lt;button type=&quot;submit&quot; name=&quot;add&quot;&gt;追加&lt;/button&gt;
        &lt;/form&gt;

        &lt;div class=&quot;todo-list&quot;&gt;
            &lt;?php foreach ($todos as $todo): ?&gt;
                &lt;div class=&quot;todo-item&quot;&gt;
                    &lt;div class=&quot;todo-content&quot;&gt;
                        &lt;div class=&quot;todo-text&quot;&gt;&lt;?php echo htmlspecialchars($todo[&#39;text&#39;]); ?&gt;&lt;/div&gt;
                    &lt;/div&gt;
                    &lt;form method=&quot;POST&quot; class=&quot;form-inline&quot;&gt;
                        &lt;input type=&quot;hidden&quot; name=&quot;id&quot; value=&quot;&lt;?php echo $todo[&#39;id&#39;]; ?&gt;&quot;&gt;
                        &lt;button type=&quot;submit&quot; name=&quot;delete&quot; class=&quot;delete-btn&quot;&gt;delete&lt;/button&gt;
                    &lt;/form&gt;
                &lt;/div&gt;
            &lt;?php endforeach; ?&gt;
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/body&gt;

&lt;/html&gt;</code></pre></div>



<h4 class="wp-block-heading"><span id="toc7">Todo追加機能</span></h4>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>function addTodo($text)
{
    global $pdo;
    $id = uniqid();
    $stmt = $pdo-&gt;prepare(&quot;INSERT INTO todos (id, text) VALUES (?, ?)&quot;);
    return $stmt-&gt;execute([$id, $text]);
}</code></pre></div>



<p class="wp-block-paragraph">この関数で新しいTodoをデータベースに追加します。<br>まず関数の中で外部の$pdo変数を使うために、global宣言をしています。</p>



<p class="has-small-font-size wp-block-paragraph">（※今回はシンプルな解説にするためにglobalを使用しています。基本的には、管理が難しくなるためglobal宣言は避けた方が良いです。）</p>



<p class="wp-block-paragraph">次に、PDOの<span class="marker-under">prepare関数</span>によってSQL文をセットしています。IDとTodoをINSERT文に安全に挿入するために、INSERT文の中には疑問符 (?) パラメータマークを使っています。最後のexecute関数に、疑問符パラメータの数と同じ要素数の配列を引数として渡します。配列の中身の順番と、疑問符パラメータの順番が一致するようにしましょう。</p>



<div class="wp-block-cocoon-blocks-tab-caption-box-1 tab-caption-box block-box not-nested-style cocoon-block-tab-caption-box"><div class="tab-caption-box-label block-box-label box-label fab-graduation-cap"><span class="tab-caption-box-label-text block-box-label-text box-label-text">Manual &#8211; prepare関数</span></div><div class="tab-caption-box-content block-box-content box-content">
<p class="wp-block-paragraph">SQL文に変数を挿入するなら、そのまま結合なり展開なりしてしまえば楽なのでは？と思いますが、そうすると攻撃者が悪意のあるSQL文を挿入、実行できてしまいます。この攻撃をSQLインジェクションと言います。</p>



<p class="wp-block-paragraph">SQL文をセットする際に変数を挿入したいときは、PDOのprepare関数を使います。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-php" data-lang="PHP"><code>$pdo-&gt;prepare(&quot;SQL文&quot;)</code></pre></div>



<p class="wp-block-paragraph">prepare関数でSQL文をセットした後、execute関数により後から変数を代入しています。この一連の流れはプリペアドステートメントと呼ばれ、SQL文の中に安全に変数を挿入できます。このひと手間を怠るとセキュリティホールが生まれることがありますので、ユーザの入力値をSQL文に使用する場合は必ず行ってください。</p>
</div></div>



<h3 class="wp-block-heading"><span id="toc8">Todo一覧取得機能</span></h3>



<div class="hcb_wrap"><pre class="prism line-numbers lang-php" data-lang="PHP"><code>function getTodos() {
    global $pdo;
    $stmt = $pdo-&gt;query(&quot;SELECT * FROM todos ORDER BY created_at DESC&quot;);
    return $stmt-&gt;fetchAll(PDO::FETCH_ASSOC);
}</code></pre></div>



<p class="wp-block-paragraph">この関数でデータベースから全てのTodoを取得しています。<br>Todoの取得には変数を使用しないため、PDOのprepare関数ではなく<span class="marker-under">query関数</span>でSQL文をセットします。created_atの降順（新しい順）で並び替えしています。</p>



<p class="wp-block-paragraph">最後に、$stmtのfetchAll関数によりTodoを全て取得して、returnしています。引数には、データの取得形式を指定します。<br>PDO::FETCH_ASSOCは、[カラム名1 => 値1, カラム名2 => 値2, &#8230;]のような連想配列でデータを取得します。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-php" data-lang="PHP"><code>$todos = getTodos();</code></pre></div>



<p class="wp-block-paragraph">今回は$todos変数にTodoのリストを代入しています。</p>



<h3 class="wp-block-heading"><span id="toc9">フォーム処理部分</span></h3>



<div class="hcb_wrap"><pre class="prism line-numbers lang-php" data-lang="PHP"><code>if (isset($_POST[&#39;add&#39;]) && !empty($_POST[&#39;todo&#39;])) {
    addTodo($_POST[&#39;todo&#39;]);
}

if (isset($_POST[&#39;delete&#39;]) && !empty($_POST[&#39;id&#39;])) {
    deleteTodo($_POST[&#39;id&#39;]);
}</code></pre></div>



<p class="wp-block-paragraph">2つ条件分岐を記述しています。</p>



<p class="wp-block-paragraph">1つ目のif文はボタンの押下判定とテキストの存在判定を行い、Todoの追加処理をしています。2つ目のif文はボタンの押下判定とテキストの存在判定を行い、削除処理をしています。</p>



<h3 class="wp-block-heading"><span id="toc10">フロントエンド側の処理</span></h3>



<p class="wp-block-paragraph">フロントエンド側は前回とほぼ変わっていません。一点、前回はセッションからTodoリストを取得、foreach文で回していたので、そこを$todos変数からの取得に変更しています。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>&lt;?php foreach ($todos as $todo): ?&gt;
    // 略
&lt;?php endforeach; ?&gt;</code></pre></div>



<p class="wp-block-paragraph">これでデータベースとの連携が完了し、Todoリストを永続的に保存できるようになりました。お疲れさまでした！</p>
]]></content:encoded>
					
					<wfw:commentRss>https://code-ch.com/php-project-todolist-with-db/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>PHPで作る！シンプルなTodoリスト入門</title>
		<link>https://code-ch.com/php-project-todolist/</link>
		
		<dc:creator><![CDATA[TJR]]></dc:creator>
		<pubDate>Sun, 02 Feb 2025 09:04:57 +0000</pubDate>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[実践プロジェクト]]></category>
		<category><![CDATA[初学者向け]]></category>
		<guid isPermaLink="false">https://code-ch.com/?post_type=learning-projects&#038;p=676</guid>

					<description><![CDATA[この記事ではPHPでTodoリストを制作していきます。セッション管理、フォーム処理、配列操作など、Web開発の基礎が学べる実践的なプロジェクトになっています。 目次 Todoリストの概要必要な前提知識ソースコードテンプレ [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">この記事ではPHPでTodoリストを制作していきます。セッション管理、フォーム処理、配列操作など、Web開発の基礎が学べる実践的なプロジェクトになっています。</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="1024" height="576" src="https://code-ch.com/wp-content/uploads/2025/01/変数のコピー-4-1.jpg" alt="" class="wp-image-689" srcset="https://code-ch.com/wp-content/uploads/2025/01/変数のコピー-4-1.jpg 1024w, https://code-ch.com/wp-content/uploads/2025/01/変数のコピー-4-1-300x169.jpg 300w, https://code-ch.com/wp-content/uploads/2025/01/変数のコピー-4-1-768x432.jpg 768w, https://code-ch.com/wp-content/uploads/2025/01/変数のコピー-4-1-120x68.jpg 120w, https://code-ch.com/wp-content/uploads/2025/01/変数のコピー-4-1-160x90.jpg 160w, https://code-ch.com/wp-content/uploads/2025/01/変数のコピー-4-1-320x180.jpg 320w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>




  <div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-4" checked><label class="toc-title" for="toc-checkbox-4">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">Todoリストの概要</a><ol><li><a href="#toc2" tabindex="0">必要な前提知識</a></li><li><a href="#toc3" tabindex="0">ソースコードテンプレート</a></li></ol></li><li><a href="#toc4" tabindex="0">メモ入力機能 ※フロントエンド側</a></li><li><a href="#toc5" tabindex="0">メモ保存機能　※バックエンド側</a><ol><li><a href="#toc6" tabindex="0">セッションの初期化</a></li><li><a href="#toc7" tabindex="0">データの保存構造</a></li><li><a href="#toc8" tabindex="0">実装のポイント</a></li></ol></li><li><a href="#toc9" tabindex="0">メモの一覧表示機能　※フロントエンド側</a><ol><li><a href="#toc10" tabindex="0">データの取り出し</a></li><li><a href="#toc11" tabindex="0">表示の安全性</a></li><li><a href="#toc12" tabindex="0">実装のポイント</a></li></ol></li><li><a href="#toc13" tabindex="0">メモの削除機能</a><ol><li><a href="#toc14" tabindex="0">削除ボタンの実装　※フロントエンド側</a></li><li><a href="#toc15" tabindex="0">削除処理の実装　※バックエンド側</a></li><li><a href="#toc16" tabindex="0">重要なポイント</a></li><li><a href="#toc17" tabindex="0">データの永続性</a></li></ol></li></ol>
    </div>
  </div>

<h2 class="wp-block-heading"><span id="toc1">Todoリストの概要</span></h2>



<p class="wp-block-paragraph">今回実装していくTodoリストはシンプルな機能を盛り込んでいます。機能の一覧は以下です。</p>



<ul class="wp-block-list is-style-icon-list-check has-list-style">
<li>メモの追加</li>



<li>メモの一覧</li>



<li>メモの削除</li>
</ul>



<figure class="wp-block-video"><video height="888" style="aspect-ratio: 1784 / 888;" width="1784" autoplay controls loop src="https://code-ch.com/wp-content/uploads/2025/01/画面録画-2025-01-26-185607.mp4" playsinline></video><figcaption class="wp-element-caption">完成イメージ</figcaption></figure>



<h3 class="wp-block-heading"><span id="toc2">必要な前提知識</span></h3>



<ul class="wp-block-list">
<li>HTML/CSSの基本</li>



<li>PHPの基本文法</li>



<li>フォームの仕組み</li>



<li>配列の扱い方</li>
</ul>



<p class="wp-block-paragraph">phpの環境構築がまだの方は、次の記事から導入してください。</p>



<div class="wp-block-cocoon-blocks-blogcard blogcard-type bct-none">

<a href="https://code-ch.com/php-xampp-install/" title="【PHP】環境構築（Windows11）" class="blogcard-wrap internal-blogcard-wrap a-wrap cf"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img loading="lazy" decoding="async" width="160" height="90" src="https://code-ch.com/wp-content/uploads/2024/09/thumbnail-php-xampp-160x90.jpg" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://code-ch.com/wp-content/uploads/2024/09/thumbnail-php-xampp-160x90.jpg 160w, https://code-ch.com/wp-content/uploads/2024/09/thumbnail-php-xampp-300x169.jpg 300w, https://code-ch.com/wp-content/uploads/2024/09/thumbnail-php-xampp-1024x576.jpg 1024w, https://code-ch.com/wp-content/uploads/2024/09/thumbnail-php-xampp-768x432.jpg 768w, https://code-ch.com/wp-content/uploads/2024/09/thumbnail-php-xampp-1536x864.jpg 1536w, https://code-ch.com/wp-content/uploads/2024/09/thumbnail-php-xampp-120x68.jpg 120w, https://code-ch.com/wp-content/uploads/2024/09/thumbnail-php-xampp-320x180.jpg 320w, https://code-ch.com/wp-content/uploads/2024/09/thumbnail-php-xampp.jpg 1920w" sizes="(max-width: 160px) 100vw, 160px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">【PHP】環境構築（Windows11）</div><div class="blogcard-snippet internal-blogcard-snippet">PHPの実行環境を構築する手順を分かりやすく解説。XAMPPを使ったローカル環境で、PHPスクリプトを実行します。</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://code-ch.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">code-ch.com</div></div><div class="blogcard-date internal-blogcard-date"><div class="blogcard-post-date internal-blogcard-post-date">2024.09.16</div></div></div></div></a>
</div>



<h3 class="wp-block-heading"><span id="toc3">ソースコードテンプレート</span></h3>



<p class="wp-block-paragraph">下記ソースコードに処理を追加していきます。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-php" data-file="index.php" data-lang="PHP"><code>&lt;?php
// ※バックエンドの処理を記述していきます
?&gt;

&lt;!DOCTYPE html&gt;
&lt;html&gt;

&lt;head&gt;
    &lt;title&gt;My Todo List&lt;/title&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;
    &lt;link rel=&quot;stylesheet&quot; href=&quot;style.css&quot;&gt;
&lt;/head&gt;

&lt;body&gt;
    &lt;div class=&quot;container&quot;&gt;
        &lt;h1&gt;My Todo List&lt;/h1&gt;
        &lt;!-- ※フロントエンドの処理を記述していきます --&gt;
    &lt;/div&gt;
&lt;/body&gt;

&lt;/html&gt;</code></pre></div>



<p class="wp-block-paragraph">スタイリングが必要であれば以下のcssを利用してください。（任意）</p>



<details class="wp-block-details my-details is-layout-flow wp-block-details-is-layout-flow"><summary>css（クリックで開く）</summary>
<div class="hcb_wrap"><pre class="prism line-numbers lang-css" data-file="style.css" data-lang="CSS"><code>* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
    font-family: &quot;Helvetica Neue&quot;,
        Arial,
        &quot;Hiragino Kaku Gothic ProN&quot;,
        &quot;Hiragino Sans&quot;,
        Meiryo,
        sans-serif;
}

body {
    background-color: #f5f5f5;
    color: rgba(0, 0, 0, 0.87);
}

.container {
    max-width: 800px;
    margin: 0 auto;
    padding: 20px;
}

h1 {
    color: #1976d2;
    font-weight: 60 0;
    margin: 2rem 0;
    text-align: center;
}

.add-form {
    background: white;
    padding: 20px;
    border-radius: 8px;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
    margin-bottom: 20px;
    display: flex;
    gap: 10px;
}

.add-form input[type=&quot;text&quot;] {
    flex: 1;
    padding: 12px 16px;
    border: 1px solid #e0e0e0;
    border-radius: 4px;
    font-size: 16px;
    transition: border-color 0.2s;
}

.add-form input[type=&quot;text&quot;]:focus {
    outline: none;
    border-color: #1976d2;
}

button {
    background: #1976d2;
    color: white;
    border: none;
    padding: 12px 24px;
    border-radius: 4px;
    font-size: 14px;
    font-weight: 500;
    text-transform: uppercase;
    cursor: pointer;
    transition: background 0.2s;
}

button:hover {
    background: #1565c0;
}

.todo-list {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.todo-item {
    background: white;
    padding: 16px;
    border-radius: 8px;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
    display: flex;
    align-items: center;
    justify-content: space-between;
    transition: transform 0.2s;
}

.todo-item:hover {
    transform: translateY(-2px);
}

.todo-content {
    flex: 1;
}

.todo-text {
    font-size: 16px;
}

.delete-btn {
    background: transparent;
    color: #f44336;
    padding: 8px;
    min-width: auto;
}

.delete-btn:hover {
    background: rgba(244, 67, 54, 0.1);
}

@media (max-width: 600px) {
    .container {
        padding: 10px;
    }

    .add-form {
        flex-direction: column;
    }
}</code></pre></div>
</details>



<p class="wp-block-paragraph"></p>



<h2 class="wp-block-heading"><span id="toc4">メモ入力機能 ※フロントエンド側</span></h2>



<p class="wp-block-paragraph">メモを追加するには、ユーザーが入力したテキストをサーバ側で受け取り、保持しておく必要があります。まずはメモ入力フォームを作成していきます。</p>



<div class="hcb_wrap"><pre class="prism off-numbers lang-php" data-lang="PHP"><code>        &lt;form method=&quot;POST&quot; class=&quot;add-form&quot;&gt;
            &lt;input type=&quot;text&quot; name=&quot;todo&quot; placeholder=&quot;新しいタスクを入力&quot; required&gt;
            &lt;button type=&quot;submit&quot; name=&quot;add&quot;&gt;追加&lt;/button&gt;
        &lt;/form&gt;</code></pre></div>



<p class="wp-block-paragraph">これはユーザーが入力したテキストを、同ページに<span class="marker-under-red"><strong>POST</strong></span>する処理です。追加ボタンが押されると、フォーム内のデータがまとめてWebサーバに送られます。</p>



<h2 class="wp-block-heading"><span id="toc5">メモ保存機能　※バックエンド側</span></h2>



<p class="wp-block-paragraph">送られたデータは、<span class="marker-under-red"><strong>セッション</strong></span>によって保持しています。セッションはサーバ内にデータを保存し、ブラウザを閉じるまでデータを保持することができます。</p>



<p class="wp-block-paragraph">注意点として、セッションを使うにはsession_start()を行う必要があります。session_start()することで、セッション本体にあたるグローバル変数$_SESSIONにアクセスできるようになります。</p>



<h3 class="wp-block-heading"><span id="toc6">セッションの初期化</span></h3>



<div class="hcb_wrap"><pre class="prism line-numbers lang-php" data-lang="PHP"><code>session_start();

if (!isset($_SESSION[&#39;todos&#39;])) {
    $_SESSION[&#39;todos&#39;] = [];
}</code></pre></div>



<p class="wp-block-paragraph">まずセッションをスタートして、セッションにメモが格納されていない場合、空の配列で初期化します。これにより、エラーを防ぎ、安全にデータを追加できます。</p>



<p class="wp-block-paragraph">isset関数は、連想配列に指定のキーが<strong>存在する場合</strong>にtrueを返します。今回は関数の前に!がついているため、条件が反転されます。グローバル変数$_SESSIONに&#8217;todos&#8217;がなければ、空の配列で初期化する処理を行います。</p>



<h3 class="wp-block-heading"><span id="toc7">データの保存構造</span></h3>



<p class="wp-block-paragraph">送信されたデータは以下のような構造で保存されます。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-php" data-lang="PHP"><code>$todo = [
    &#39;id&#39; =&gt; uniqid(),      // ユニークなID
    &#39;text&#39; =&gt; $_POST[&#39;todo&#39;] // メモの内容
];</code></pre></div>



<p class="wp-block-paragraph">各項目の役割を見ていきましょう。</p>



<ul class="wp-block-list">
<li>uniqid(): 各メモを識別するための被らないIDを生成</li>



<li>$_POST[&#8216;todo&#8217;]: フォームから送信されたメモの内容</li>
</ul>



<div class="hcb_wrap"><pre class="prism line-numbers lang-php" data-lang="PHP" data-line="1,6,7"><code>if (isset($_POST[&#39;add&#39;]) && !empty($_POST[&#39;todo&#39;])) {
    $todo = [
        &#39;id&#39; =&gt; uniqid(),      // ユニークなID
        &#39;text&#39; =&gt; $_POST[&#39;todo&#39;] // メモの内容
    ];
    array_push($_SESSION[&#39;todos&#39;], $todo);
}</code></pre></div>



<p class="wp-block-paragraph">この部分では、2つの条件を両方とも満たしているか確認しています。</p>



<ol class="wp-block-list">
<li>isset($_POST[&#8216;add&#8217;]): 追加ボタンが押されたかの確認</li>



<li>!empty($_POST[&#8216;todo&#8217;]): メモの内容が空でないことの確認</li>



<li>条件A <strong>&amp;&amp;</strong> 条件B: 左と右の条件が両方とも満たされる場合にtrueを返す</li>
</ol>



<p class="wp-block-paragraph">empty関数は、連想配列に指定のキーが<strong>存在しない場合</strong>にtrueを返します。くわえて、<strong>空文字やnullの場合</strong>もtrueを返します。先述したコードでは、empty関数に!をつけることで条件を反転しています。<br>条件を満たした場合、array_push()を使って新しいメモを配列に追加します。</p>



<h3 class="wp-block-heading"><span id="toc8">実装のポイント</span></h3>



<ol class="wp-block-list">
<li>フォームのバリデーション
<ul class="wp-block-list">
<li>必須入力項目の設定（required属性）</li>



<li>サーバーサイドでの入力チェック</li>
</ul>
</li>



<li>データの永続化
<ul class="wp-block-list">
<li>セッションを使用したデータの一時保存</li>



<li>配列構造での管理</li>
</ul>
</li>



<li>一意性の確保
<ul class="wp-block-list">
<li>uniqid()によるユニークなID付与</li>



<li>後の削除処理で使用</li>
</ul>
</li>
</ol>



<p class="wp-block-paragraph">このように、メモの追加機能は単純な処理に見えて、様々な要素が組み合わさっています。次は、保存したメモの一覧表示について解説していきましょう。</p>



<h2 class="wp-block-heading"><span id="toc9">メモの一覧表示機能　※フロントエンド側</span></h2>



<p class="wp-block-paragraph">保存したメモを表示する部分を追加していきましょう。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-php" data-lang="PHP"><code>&lt;div class=&quot;todo-list&quot;&gt;
    &lt;?php foreach ($_SESSION[&#39;todos&#39;] as $todo): ?&gt;
        &lt;div class=&quot;todo-item&quot;&gt;
            &lt;div class=&quot;todo-content&quot;&gt;
                &lt;div class=&quot;todo-text&quot;&gt;&lt;?php echo htmlspecialchars($todo[&#39;text&#39;]); ?&gt;&lt;/div&gt;
            &lt;/div&gt;
        &lt;/div&gt;
    &lt;?php endforeach; ?&gt;
&lt;/div&gt;</code></pre></div>



<h3 class="wp-block-heading"><span id="toc10">データの取り出し</span></h3>



<p class="wp-block-paragraph">セッションに保存されたメモは、foreachループを使って1件ずつ取り出します。&nbsp;$_SESSION[&#8216;todos&#8217;]には先ほど保存した配列が入っており、これを$todo変数に順番に代入しながら処理していきます。</p>



<h3 class="wp-block-heading"><span id="toc11">表示の安全性</span></h3>



<div class="hcb_wrap"><pre class="prism line-numbers lang-php" data-lang="PHP"><code>&lt;?php echo htmlspecialchars($todo[&#39;text&#39;]); ?&gt;</code></pre></div>



<p class="wp-block-paragraph">メモの内容を表示する際は、必ずhtmlspecialchars()関数でエスケープ処理をします。 これはXSS（クロスサイトスクリプティング）と呼ばれる攻撃を防ぐための対策です。ユーザーの入力を表示する場合は必須です。</p>



<h3 class="wp-block-heading"><span id="toc12">実装のポイント</span></h3>



<ol class="wp-block-list">
<li>データの取り出し
<ul class="wp-block-list">
<li>foreachループによる配列処理</li>



<li>配列のキーを意識した実装</li>
</ul>
</li>



<li>セキュリティ対策
<ul class="wp-block-list">
<li>htmlspecialchars()によるエスケープ処理</li>



<li>安全な出力</li>
</ul>
</li>



<li>レイアウト設計
<ul class="wp-block-list">
<li>階層構造を持つHTML</li>



<li>CSSによるスタイリング</li>
</ul>
</li>
</ol>



<h2 class="wp-block-heading"><span id="toc13">メモの削除機能</span></h2>



<p class="wp-block-paragraph">保存したメモを削除する機能を見ていきましょう。フロントエンド側の処理から解説していきます。</p>



<h3 class="wp-block-heading"><span id="toc14">削除ボタンの実装　※フロントエンド側</span></h3>



<div class="hcb_wrap"><pre class="prism line-numbers lang-php" data-lang="PHP"><code>&lt;form method=&quot;POST&quot; class=&quot;form-inline&quot;&gt;
    &lt;input type=&quot;hidden&quot; name=&quot;id&quot; value=&quot;&lt;?php echo $todo[&#39;id&#39;]; ?&gt;&quot;&gt;
    &lt;button type=&quot;submit&quot; name=&quot;delete&quot; class=&quot;delete-btn&quot;&gt;delete&lt;/button&gt;
&lt;/form&gt;</code></pre></div>



<p class="wp-block-paragraph">各メモに削除用のフォームを用意します。</p>



<ul class="wp-block-list">
<li>hidden項目で対象メモのIDを保持</li>



<li>POSTメソッドで送信</li>
</ul>



<h3 class="wp-block-heading"><span id="toc15">削除処理の実装　※バックエンド側</span></h3>



<div class="hcb_wrap"><pre class="prism line-numbers lang-php" data-lang="PHP"><code>if (isset($_POST[&#39;delete&#39;]) && !empty($_POST[&#39;id&#39;])) {
    $_SESSION[&#39;todos&#39;] = array_filter($_SESSION[&#39;todos&#39;], function ($todo) {
        return $todo[&#39;id&#39;] != $_POST[&#39;id&#39;];
    });
}</code></pre></div>



<h3 class="wp-block-heading"><span id="toc16">重要なポイント</span></h3>



<ol class="wp-block-list">
<li>削除の判定
<ul class="wp-block-list">
<li>削除ボタンが押されたか確認: isset($_POST[&#8216;delete&#8217;])</li>



<li>削除対象のIDが存在するか確認: !empty($_POST[&#8216;id&#8217;])</li>



<li>両方の条件を満たしているか確認: isset($_POST[&#8216;delete&#8217;]) &amp;&amp; !empty($_POST[&#8216;id&#8217;])</li>
</ul>
</li>



<li>array_filter関数の使用
<ul class="wp-block-list">
<li>配列から特定の要素を除外</li>



<li>コールバック関数で条件指定</li>



<li>新しい配列を生成</li>
</ul>
</li>



<li>セキュリティ
<ul class="wp-block-list">
<li>POSTメソッドによるセキュリティリスクの低減</li>



<li>IDの存在確認</li>
</ul>
</li>
</ol>



<h3 class="wp-block-heading"><span id="toc17">データの永続性</span></h3>



<p class="wp-block-paragraph">削除されたデータはセッションから完全に削除されます。ブラウザを閉じるまでこの状態が維持されます。</p>



<p class="wp-block-paragraph">これで基本的なTodoリストの機能が完成しました！ソースはこちらです。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-php" data-lang="PHP"><code>&lt;?php
session_start();

// 初期化
if (!isset($_SESSION[&#39;todos&#39;])) {
    $_SESSION[&#39;todos&#39;] = [];
}

// Todoの追加
if (isset($_POST[&#39;add&#39;]) && !empty($_POST[&#39;todo&#39;])) {
    $todo = [
        &#39;id&#39; =&gt; uniqid(),
        &#39;text&#39; =&gt; $_POST[&#39;todo&#39;],
    ];
    array_push($_SESSION[&#39;todos&#39;], $todo);
}

// Todoの削除
if (isset($_POST[&#39;delete&#39;]) && !empty($_POST[&#39;id&#39;])) {
    $_SESSION[&#39;todos&#39;] = array_filter($_SESSION[&#39;todos&#39;], function ($todo) {
        return $todo[&#39;id&#39;] != $_POST[&#39;id&#39;];
    });
}
?&gt;
&lt;!DOCTYPE html&gt;
&lt;html&gt;

&lt;head&gt;
    &lt;title&gt;My Todo List&lt;/title&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;
    &lt;link rel=&quot;stylesheet&quot; href=&quot;style.css&quot;&gt;
&lt;/head&gt;

&lt;body&gt;
    &lt;div class=&quot;container&quot;&gt;
        &lt;h1&gt;My Todo List&lt;/h1&gt;

        &lt;form method=&quot;POST&quot; class=&quot;add-form&quot;&gt;
            &lt;input type=&quot;text&quot; name=&quot;todo&quot; placeholder=&quot;新しいタスクを入力&quot; required&gt;
            &lt;button type=&quot;submit&quot; name=&quot;add&quot;&gt;追加&lt;/button&gt;
        &lt;/form&gt;

        &lt;div class=&quot;todo-list&quot;&gt;
            &lt;?php foreach ($_SESSION[&#39;todos&#39;] as $todo): ?&gt;
                &lt;div class=&quot;todo-item&quot;&gt;
                    &lt;div class=&quot;todo-content&quot;&gt;
                        &lt;div class=&quot;todo-text&quot;&gt;&lt;?php echo htmlspecialchars($todo[&#39;text&#39;]); ?&gt;&lt;/div&gt;
                    &lt;/div&gt;
                    &lt;form method=&quot;POST&quot; class=&quot;form-inline&quot;&gt;
                        &lt;input type=&quot;hidden&quot; name=&quot;id&quot; value=&quot;&lt;?php echo $todo[&#39;id&#39;]; ?&gt;&quot;&gt;
                        &lt;button type=&quot;submit&quot; name=&quot;delete&quot; class=&quot;delete-btn&quot;&gt;delete&lt;/button&gt;
                    &lt;/form&gt;
                &lt;/div&gt;
            &lt;?php endforeach; ?&gt;
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/body&gt;

&lt;/html&gt;</code></pre></div>



<p class="wp-block-paragraph">次回は、ブラウザが終了してもデータを保持できるように、データベースと連携していきます。</p>



<div class="wp-block-cocoon-blocks-blogcard blogcard-type bct-next">

<a href="https://code-ch.com/php-project-todolist-with-db/" title="PHPで作る！シンプルなTodoリスト - データベース連携編" class="blogcard-wrap internal-blogcard-wrap a-wrap cf"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img loading="lazy" decoding="async" width="160" height="90" src="https://code-ch.com/wp-content/uploads/2025/02/thumbnail_todo_db-160x90.jpg" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://code-ch.com/wp-content/uploads/2025/02/thumbnail_todo_db-160x90.jpg 160w, https://code-ch.com/wp-content/uploads/2025/02/thumbnail_todo_db-300x169.jpg 300w, https://code-ch.com/wp-content/uploads/2025/02/thumbnail_todo_db-1024x576.jpg 1024w, https://code-ch.com/wp-content/uploads/2025/02/thumbnail_todo_db-768x432.jpg 768w, https://code-ch.com/wp-content/uploads/2025/02/thumbnail_todo_db-1536x864.jpg 1536w, https://code-ch.com/wp-content/uploads/2025/02/thumbnail_todo_db-120x68.jpg 120w, https://code-ch.com/wp-content/uploads/2025/02/thumbnail_todo_db-320x180.jpg 320w, https://code-ch.com/wp-content/uploads/2025/02/thumbnail_todo_db.jpg 1920w" sizes="(max-width: 160px) 100vw, 160px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">PHPで作る！シンプルなTodoリスト - データベース連携編</div><div class="blogcard-snippet internal-blogcard-snippet">PHPとMySQLを使って永続的なTodoリストを作成する方法を解説。データベースの作成からテーブル設計、PHPでのMySQL操作まで、実践的なステップで学べます。XAMPPを使用した環境構築から、セキュアなデータベース連携までをカバー。</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://code-ch.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">code-ch.com</div></div><div class="blogcard-date internal-blogcard-date"><div class="blogcard-post-date internal-blogcard-post-date">2025.02.24</div></div></div></div></a>
</div>
]]></content:encoded>
					
		
		<enclosure url="https://code-ch.com/wp-content/uploads/2025/01/画面録画-2025-01-26-185607.mp4" length="152745" type="video/mp4" />

			</item>
	</channel>
</rss>
