本格的なフレームワークを導入するほどの規模ではないが、それなりに多機能なのである程度の処理は任せたい。今更PHP4に対応させる必要があるが、PHP5でも動作させる必要がある。本番環境のテストが公開直前までできないので、ひととおり内部を見渡せる軽量なフレームワークが好ましい。ついでに、簡易なデータベース管理ツールも欲しい。
…という場合に役に立つかもしれません。というか、そんなことがあったために自作することにした。_(:3 」∠ )_
大まかな処理の流れは以下のとおりです。(何らかのフレームワークを使ったことがある人向けの説明。)
http://www.example.com/index.php/test1/test2
へリクエストが送られたとします。app/controllers/test1/test2.php
が読み込まれます。$view
に値を割り当てます。app/views/test1/test2.php
が読み込まれます。$view
の内容を表示します。すべてのファイルを公開ディレクトリ内に配置する方法です。
public_html / config.php
| index.php
|
+-- app /
|
+-- libs /
ブラウザで index.php
にアクセスし、「About Framework」というページが表示されれば成功です。
一部のファイルを公開ディレクトリ外に配置する方法です。
home / config.php
|
+-- public_html / index.php
|
+-- app /
|
+-- libs /
この場合、index.php
にある
require_once 'config.php';
を以下のように修正します。(index.php
から見た config.php
へのパス。)
require_once '../config.php';
さらに config.php
にある
define('MAIN_LIBRARY_PATH', '');
define('MAIN_APPLICATION_PATH', '');
を以下のように修正します。(index.php
から見た libs/
へのパスと app/
へのパス。)
define('MAIN_LIBRARY_PATH', '../');
define('MAIN_APPLICATION_PATH', '../');
ブラウザで index.php
にアクセスし、「About Framework」というページが表示されれば成功です。
なお、本番環境では config.php
にある
define('DEBUG_LEVEL', 1);
この部分を、必ず 0
に設定しておいてください。(データベース管理ツールなどに不正にアクセスされる可能性があります。)
このフレームワークは処理をMVC(Model-View-Controller)に分割して管理します。
モデルはデータを扱う部品です。データの検索、変換、検証、登録などを行います。
ビューはデータの表示を担当します。主にHTMLのテンプレートを扱います。
コントローラはユーザからのリクエストを扱います。モデルとビューの助けを借りてユーザに結果を返します。
app/
内に作成したいプログラムのファイルを格納します。
libs/cores/
内にフレームワークのコアファイルが可能されています。この内容は編集する必要はありません。
libs/plugins/
内に自分で作成した共通関数のファイルを格納します。
フレームワークを呼び出すURLは通常 http://www.example.com/index.php/test1/test2
のような形式ですが、mod_rewrite
を使用すれば http://www.example.com/test1/test2
のような形式にすることができます。
index.php
と同じディレクトリ内に .htaccess
ファイルを作成し、以下の内容を記載します。
DirectoryIndex index.php
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) index.php/$1
</IfModule>
さらに、config.php
にある以下の部分を修正します。
define('MAIN_FILE', $_SERVER['SCRIPT_NAME']);
この部分を、以下のように修正します。
define('MAIN_FILE', dirname($_SERVER['SCRIPT_NAME']));
コントローラは app/controllers/
内に格納します。
URLで指定された2つの値に従ってコントローラが読み込まれます。(3つ目以降の値を指定しても、コントローラの呼び出しに影響しません。)値が省略されると default
が省略されたものとみなされます。
http://www.example.com/index.php/test1/test2
へリクエストを送ると、app/controllers/test1/test2.php
が読み込まれます。http://www.example.com/index.php/test1
へリクエストを送ると http://www.example.com/index.php/test1/default
へのリクエストとみなされ、app/controllers/test1/default.php
が読み込まれます。http://www.example.com/
へリクエストを送ると http://www.example.com/index.php/default/default
へのリクエストとみなされ、app/controllers/default/default.php
が読み込まれます。コントローラ内で連想配列 $view
に値を格納すると、ビューから参照することができます。
モデルは app/models/
内に格納します。
データベースのテーブル名とモデルのファイル名は一致させます。名前は複数形を推奨します。
例えば members
テーブルのモデルは app/models/members.php
となります。ファイルを作成することにより、select_members()
・insert_members()
・update_members()
・delete_members()
などの命令が使えるようになります。これらはモデル内に以下のような関数を定義することにより、各機能を上書きすることができます。(必要に応じて、さらにコードを追加します。)
function select_members($queries)
{
$queries['from'] = DATABASE_PREFIX . 'members';
$results = db_select($queries);
return $results;
}
function insert_members($queries)
{
$queries['insert_into'] = DATABASE_PREFIX . 'members';
$resource = db_insert($queries);
return $resource;
}
function update_members($queries)
{
$queries['update'] = DATABASE_PREFIX . 'members';
$resource = db_update($queries);
return $resource;
}
function delete_members($queries)
{
$queries['delete_from'] = DATABASE_PREFIX . 'members';
$resource = db_delete($queries);
return $resource;
}
function normalize_members($queries)
{
return $queries;
}
function validate_members($queries)
{
return array();
}
ビューは app/views/
内に格納します。
URLで指定された2つの値に従ってコントローラが読み込まれます。値が省略されると default
が省略されたものとみなされます。
http://www.example.com/index.php/test1/test2
へリクエストを送ると、app/views/test1/test2.php
が読み込まれます。http://www.example.com/index.php/test1
へリクエストを送ると http://www.example.com/index.php/test1/default
へのリクエストとみなされ、app/views/test1/default.php
が読み込まれます。http://www.example.com/
へリクエストを送ると http://www.example.com/index.php/default/default
へのリクエストとみなされ、app/views/default/default.php
が読み込まれます。コントローラ内で連想配列 $view
に値を格納すると、ビューから参照することができます。
フレームワークの動作に必要な命令です。フレームワーク内部で呼び出されていますが、自分で書くプログラムに流用することもできます。
コアライブラリによって提供される命令の一部をフレームワークから提供される関数で紹介しています。
自分で追加することができる命令です。
プラグインは libs/plugins/
内に格納されています。
はじめから用意されているプラグインによって提供される命令の一部をフレームワークから提供されるプラグインで紹介しています。
http://www.example.com/index.php?mode=info_fw
へアクセスすると、フレームワークの情報が表示されます。表示されない場合、config.php
の以下の部分を 1
か 2
に設定してください。(本番環境では 0
にしておくことを推奨します。)
define('DEBUG_LEVEL', 0);
config.php
にある、以下の部分でデータベースの接続設定を行います。データベースを使用しない場合、設定の必要はありません。
define('DATABASE_TYPE', ''); //pdo_mysql or pdo_pgsql or pdo_sqlite or pdo_sqlite2 or mysql or pgsql or sqlite
define('DATABASE_HOST', '');
define('DATABASE_PORT', '');
define('DATABASE_USERNAME', '');
define('DATABASE_PASSWORD', '');
define('DATABASE_NAME', '');
define('DATABASE_PREFIX', '');
上から「接続方法」「ホスト」「ポート番号」「ユーザー名」「パスワード」「データベース名」「テーブル名のプレフィックス」です。
SQLiteを使用する場合、「データベース名」はデータベースファイルへのパスを設定します。例えば DATABASE_NAME
を db/fw.db
と設定した場合、index.php
と階層に db
ディレクトリを作成してパーミッションを 707
に設定し、さらにその中に fw.db
を作成してパーミッションを 606
に設定します。
PDOでMySQLへ接続する場合、一例ですが以下のように設定します。
define('DATABASE_TYPE', 'pdo_mysql'); //pdo_mysql or pdo_pgsql or pdo_sqlite or pdo_sqlite2 or mysql or pgsql or sqlite
define('DATABASE_HOST', 'localhost');
define('DATABASE_PORT', '');
define('DATABASE_USERNAME', 'root');
define('DATABASE_PASSWORD', '1234');
define('DATABASE_NAME', 'fw');
define('DATABASE_PREFIX', '');
PDOでPostgreSQLへ接続する場合、一例ですが以下のように設定します。
define('DATABASE_TYPE', 'pdo_pgsql'); //pdo_mysql or pdo_pgsql or pdo_sqlite or pdo_sqlite2 or mysql or pgsql or sqlite
define('DATABASE_HOST', 'localhost');
define('DATABASE_PORT', '');
define('DATABASE_USERNAME', 'root');
define('DATABASE_PASSWORD', '1234');
define('DATABASE_NAME', 'fw');
define('DATABASE_PREFIX', '');
PDOでSQLite3へ接続する場合、一例ですが以下のように設定します。
define('DATABASE_TYPE', 'pdo_sqlite'); //pdo_mysql or pdo_pgsql or pdo_sqlite or pdo_sqlite2 or mysql or pgsql or sqlite
define('DATABASE_HOST', '');
define('DATABASE_PORT', '');
define('DATABASE_USERNAME', '');
define('DATABASE_PASSWORD', '');
define('DATABASE_NAME', 'db/fw.db');
define('DATABASE_PREFIX', '');
PDOでSQLite2へ接続する場合、一例ですが以下のように設定します。
define('DATABASE_TYPE', 'pdo_sqlite2'); //pdo_mysql or pdo_pgsql or pdo_sqlite or pdo_sqlite2 or mysql or pgsql or sqlite
define('DATABASE_HOST', '');
define('DATABASE_PORT', '');
define('DATABASE_USERNAME', '');
define('DATABASE_PASSWORD', '');
define('DATABASE_NAME', 'db/fw.db');
define('DATABASE_PREFIX', '');
mysql関数で接続する場合、一例ですが以下のように設定します。
define('DATABASE_TYPE', 'mysql'); //pdo_mysql or pdo_pgsql or pdo_sqlite or pdo_sqlite2 or mysql or pgsql or sqlite
define('DATABASE_HOST', 'localhost');
define('DATABASE_PORT', '');
define('DATABASE_USERNAME', 'root');
define('DATABASE_PASSWORD', '1234');
define('DATABASE_NAME', 'fw');
define('DATABASE_PREFIX', '');
pg関数で接続する場合、一例ですが以下のように設定します。
define('DATABASE_TYPE', 'pgsql'); //pdo_mysql or pdo_pgsql or pdo_sqlite or pdo_sqlite2 or mysql or pgsql or sqlite
define('DATABASE_HOST', 'localhost');
define('DATABASE_PORT', '');
define('DATABASE_USERNAME', 'root');
define('DATABASE_PASSWORD', '1234');
define('DATABASE_NAME', 'fw');
define('DATABASE_PREFIX', '');
sqlite関数で接続する場合、一例ですが以下のように設定します。
define('DATABASE_TYPE', 'sqlite'); //pdo_mysql or pdo_pgsql or pdo_sqlite or pdo_sqlite2 or mysql or pgsql or sqlite
define('DATABASE_HOST', '');
define('DATABASE_PORT', '');
define('DATABASE_USERNAME', '');
define('DATABASE_PASSWORD', '');
define('DATABASE_NAME', 'db/fw.db');
define('DATABASE_PREFIX', '');
config.php
にある、以下の部分でデータベースの文字コード設定を行います。
MySQL使用時に DATABASE_CHARSET
を指定すると、「'SET NAMES ' . DATABASE_CHARSET
」でデータベースの文字コードが設定されます。
データベースへ入力する際、DATABASE_CHARSET_INPUT_FROM
から DATABASE_CHARSET_INPUT_TO
に文字コードが変換されます。同じ値が指定されている場合、何も行われません。
データベースから出力する際、DATABASE_CHARSET_OUTPUT_FROM
から DATABASE_CHARSET_OUTPUT_TO
に文字コードが変換されます。同じ値が指定されている場合、何も行われません。
define('DATABASE_CHARSET', 'UTF8'); //for mysql, set names.
define('DATABASE_CHARSET_INPUT_FROM', 'UTF-8'); //for php function.
define('DATABASE_CHARSET_INPUT_TO', 'UTF-8'); //for php function.
define('DATABASE_CHARSET_OUTPUT_FROM', 'UTF-8'); //for php function.
define('DATABASE_CHARSET_OUTPUT_TO', 'UTF-8'); //for php function.
データベースの文字コードが SJIS
で表示の際に EUC-JP
を使う場合、一例ですが以下のように指定します。
define('DATABASE_CHARSET', 'SJIS'); //for mysql, set names.
define('DATABASE_CHARSET_INPUT_FROM', 'auto'); //for php function.
define('DATABASE_CHARSET_INPUT_TO', 'SJIS'); //for php function.
define('DATABASE_CHARSET_OUTPUT_FROM', 'auto'); //for php function.
define('DATABASE_CHARSET_OUTPUT_TO', 'EUC-JP'); //for php function.
http://www.example.com/index.php?mode=db_admin
へアクセスすると、データベースの管理画面が表示されます(データベース使用時のみ)。表示されない場合、config.php
の以下の部分を 1
か 2
に設定してください。
define('DEBUG_LEVEL', 0);
セッションは常に開始されているので、通常のPHPプログラムと同様に $_SESSION
でセッションを読み書きします。ただし $_SESSION['core']
はフレームワーク内部で使用しているので、この値を上書きしたりしないように注意してください。
config.php
の以下の部分を 1
に設定すると、エラー発生時に詳細が表示されます。また、データベース管理ツールなども利用できるようになります。2
に設定すると、さらに実行したSQLがその都度画面に表示されるようになります。
define('DEBUG_LEVEL', 0);
ファイルを読み込みます。
import('app/config.php') //「app/config.php」を読み込む
import('app/views/header.php') //「app/views/header.php」を読み込む
文字コードを変換します。
$converted = convert($data, 'UTF-8', 'EUCJP-WIN'); //「EUCJP-WIN」から「UTF-8」に変換
ワンタイムトークンを扱います。token('create')
でトークンを発行し、フォームなどから送信し、$_REQUEST['token']
で受信して、token('check')
で確認できます。
$token = token('create') //ワンタイムトークンを発行
$flag = token('check') //ワンタイムトークンを確認
リダイレクトします。
redirect('http://www.example.com/sample.html') //外部ページへリダイレクト
redirect('/message/list') //内部ページヘリダイレクト
日時を取得します。
localdate() //タイムスタンプを取得
localdate('Y-m-d H:i:s') //フォーマットして取得
localdate('Y年m月d日 H時i分s秒', 1375335520) //タイムスタンプからフォーマットして取得
localdate('Y年m月d日 H時i分s秒', '2013-08-01 14:38:40') //文字列からフォーマットして取得
この関数の時差は config.php
の MAIN_TIME
で調整出来ます。(date_default_timezone_set()
など、他の方法でも可能。)
入力欄用のテキストを作成&出力します。(htmlspecialchars()
が適用されます。)
t('テキスト') //テキストを出力
$text = t('テキスト', true) //テキストを作成
表示用のテキストを作成&出力します。(htmlspecialchars()
と nl2br()
が適用されます。)
h('テキスト') //テキストを出力
$html = h('テキスト', true) //テキストを作成
ログを記録します。記録先は config.php
の LOGGING_FILE
で指定します。
logging('記録したいメッセージ')
ファイルを扱う命令が提供されます。
ディレクトリを扱う命令が提供されます。
メールを扱う命令が提供されます。
ユーザーインターフェースを扱う命令が提供されます。
簡易な記事管理システムを例に、実際の作成手順を紹介します。ここでは、PHP5+MySQLで作成するものとします。また、作成するファイルの文字コードはすべてUTF-8Nとします。
任意のディレクトリにフレームワークを配置します。
phpMyAdminなどのデータベース管理ツールから、必要に応じてデータベースを作成します。
CREATE DATABASE fw;
USE fw;
テーブルを作成します。
CREATE TABLE posts(
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
created DATETIME NOT NULL,
modified DATETIME NOT NULL,
title VARCHAR(255),
body TEXT,
PRIMARY KEY(id)
);
ダミーデータを登録します。
INSERT INTO posts VALUES(NULL, NOW(), NOW(), 'テスト1', 'これはテスト1です。');
INSERT INTO posts VALUES(NULL, NOW(), NOW(), 'テスト2', 'これはテスト2です。');
INSERT INTO posts VALUES(NULL, NOW(), NOW(), 'テスト3', 'これはテスト3です。');
config.php
を編集します。
define('DATABASE_TYPE', 'pdo_mysql'); //pdo_mysql or pdo_pgsql or pdo_sqlite or pdo_sqlite2 or mysql or pgsql or sqlite
define('DATABASE_HOST', 'localhost');
define('DATABASE_PORT', '');
define('DATABASE_USERNAME', 'root');
define('DATABASE_PASSWORD', '1234');
define('DATABASE_NAME', 'fw');
define('DATABASE_PREFIX', '');
app/models/posts.php
を作成します。ひとまずファイルの内容はカラで大丈夫です。これにより、以下の命令が使えるようになります。
select_posts()
insert_posts()
update_posts()
delete_posts()
normalize_posts()
validate_posts()
app/controllers/posts/list.php
を作成し、以下の内容を入力します。select_posts()
は app/models/posts.php
を作成することにより使えるようになった関数です。
<?php
$view['posts'] = select_posts(array(
'order_by' => 'id DESC',
'limit' => 10
));
?>
app/views/posts/list.php
を作成し、以下の内容を入力します。
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=<?php t(MAIN_CHARSET) ?>" />
<title>ブログ</title>
</head>
<body>
<h1>ブログ</h1>
<table>
<tr>
<th>ID</th>
<th>登録日時</th>
<th>修正日時</th>
<th>タイトル</th>
</tr>
<?php foreach ($view['posts'] as $post) : ?>
<tr>
<td><?php h($post['id']) ?></td>
<td><?php h(localdate('Y/m/d H:i', $post['created'])) ?></td>
<td><?php h(localdate('Y/m/d H:i', $post['modified'])) ?></td>
<td><?php h($post['title']) ?></td>
</tr>
<?php endforeach ?>
</table>
</body>
</html>
index.php/posts/list
にアクセスし、記事一覧が表示されれば成功です。
引き続き機能を実装していきます。
app/controllers/posts/view.php
を作成し、以下の内容を入力します。
<?php
$posts = select_posts(array(
'where' => 'id = ' . db_escape($_GET['id'])
));
if (empty($posts)) {
warning('記事が見つかりません。');
} else {
$view = $posts[0];
}
?>
app/views/posts/view.php
を作成し、以下の内容を入力します。
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=<?php t(MAIN_CHARSET) ?>" />
<title>ブログ</title>
</head>
<body>
<h1>ブログ</h1>
<table>
<tr>
<th>ID</th>
<td><?php h($view['id']) ?></td>
</tr>
<tr>
<th>登録日時</th>
<td><?php h(localdate('Y/m/d H:i', $view['created'])) ?></td>
</tr>
<tr>
<th>修正日時</th>
<td><?php h(localdate('Y/m/d H:i', $view['modified'])) ?></td>
</tr>
<tr>
<th>タイトル</th>
<td><?php h($view['title']) ?></td>
</tr>
<tr>
<th>本文</th>
<td><?php h($view['body']) ?></td>
</tr>
</table>
</body>
</html>
app/views/posts/list.php
にある
<td><?php h($post['title']) ?></td>
この部分を以下のように修正します。
<td><a href="<?php t(MAIN_FILE) ?>/posts/view?id=<?php t($post['id']) ?>"><?php h($post['title']) ?></a></td>
記事一覧の各タイトルから、個別表示ページヘリンクされます。
app/views/posts/add.php
を作成し、以下の内容を入力します。
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=<?php t(MAIN_CHARSET) ?>" />
<title>ブログ</title>
</head>
<body>
<h1>ブログ</h1>
<form action="<?php t(MAIN_FILE) ?>/posts/add" method="post">
<fieldset>
<legend>登録フォーム</legend>
<dl>
<dt>タイトル</dt>
<dd><input type="text" name="title" size="30" value="" /></dd>
<dt>本文</dt>
<dd><textarea name="body" rows="10" cols="50"></textarea></dd>
</dl>
<p><input type="submit" value="登録する" /></p>
</fieldset>
</form>
</body>
</html>
app/controllers/posts/add.php
を作成し、以下の内容を入力します。
<?php
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$resource = insert_posts(array(
'values' => array(
'created' => db_escape(localdate('Y-m-d H:i:s')),
'modified' => db_escape(localdate('Y-m-d H:i:s')),
'title' => db_escape($_POST['title']),
'body' => db_escape($_POST['body'])
)
));
if (!$resource) {
error('データを登録できません。');
}
redirect('/posts/list');
}
?>
app/views/posts/list.php
に以下のコードを追加します。
<p><a href="<?php t(MAIN_FILE) ?>/posts/add">新規登録</a></p>
index.php/posts/list
にアクセスすると「新規登録」リンクが表示されるので、そこから記事を投稿できます。
app/models/posts.php
に以下の内容を入力します。
<?php
function validate_posts($queries)
{
$messages = array();
//タイトル
if (isset($queries['title'])) {
if ($queries['title'] == '') {
$messages[] = 'タイトルが入力されていません。';
} elseif (mb_strlen($queries['title'], MAIN_INTERNAL_ENCODING) > 20) {
$messages[] = 'タイトルは20文字以内で入力してください。';
}
}
//本文
if (isset($queries['body'])) {
if (mb_strlen($queries['body'], MAIN_INTERNAL_ENCODING) > 1000) {
$messages[] = '本文は1000文字以内で入力してください。';
}
}
return $messages;
}
?>
app/controllers/posts/add.php
の
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
この直後に以下の内容を追加します。
$warnings = validate_posts($_POST);
if (!empty($warnings)) {
warning($warnings);
}
例えばタイトルを空欄のままで記事を投稿しようとすると、エラーが表示されるようになります。
app/views/posts/edit.php
を作成し、以下の内容を入力します。
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=<?php t(MAIN_CHARSET) ?>" />
<title>ブログ</title>
</head>
<body>
<h1>ブログ</h1>
<form action="<?php t(MAIN_FILE) ?>/posts/edit" method="post">
<fieldset>
<legend>編集フォーム</legend>
<input type="hidden" name="id" value="<?php t($view['id']) ?>" />
<dl>
<dt>タイトル</dt>
<dd><input type="text" name="title" size="30" value="<?php t($view['title']) ?>" /></dd>
<dt>本文</dt>
<dd><textarea name="body" rows="10" cols="50"><?php t($view['body']) ?></textarea></dd>
</dl>
<p><input type="submit" value="編集する" /></p>
</fieldset>
</form>
</body>
</html>
app/controllers/posts/edit.php
を作成し、以下の内容を入力します。
<?php
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$warnings = validate_posts($_POST);
if (!empty($warnings)) {
warning($warnings);
}
$resource = update_posts(array(
'sets' => array(
'modified' => db_escape(date('Y-m-d H:i:s')),
'title' => db_escape($_POST['title']),
'body' => db_escape($_POST['body'])
),
'where' => 'id = ' . db_escape($_POST['id'])
));
if (!$resource) {
error('データを編集できません。');
}
redirect('/posts/list');
} else {
$posts = select_posts(array(
'where' => 'id = ' . db_escape($_GET['id'])
));
if (empty($posts)) {
warning('記事が見つかりません。');
} else {
$view = $posts[0];
}
}
?>
app/views/posts/list.php
にある
<td><a href="<?php t(MAIN_FILE) ?>/posts/view?id=<?php t($post['id']) ?>"><?php h($post['title']) ?></a></td>
この部分を以下のように修正します。
<td>
<a href="<?php t(MAIN_FILE) ?>/posts/view?id=<?php t($post['id']) ?>"><?php h($post['title']) ?></a>
<a href="<?php t(MAIN_FILE) ?>/posts/edit?id=<?php t($post['id']) ?>">編集</a>
</td>
記事一覧の「編集」リンクから、記事を編集できるようになります。
app/controllers/posts/delete.php
を作成し、以下の内容を入力します。
<?php
$resource = delete_posts(array(
'where' => 'id = ' . db_escape($_GET['id'])
));
if (!$resource) {
error('データを削除できません。');
}
redirect('/posts/list');
?>
app/views/posts/list.php
にある
<td>
<a href="<?php t(MAIN_FILE) ?>/posts/view?id=<?php t($post['id']) ?>"><?php h($post['title']) ?></a>
<a href="<?php t(MAIN_FILE) ?>/posts/edit?id=<?php t($post['id']) ?>">編集</a>
</td>
この部分を以下のように修正します。
<td>
<a href="<?php t(MAIN_FILE) ?>/posts/view?id=<?php t($post['id']) ?>"><?php h($post['title']) ?></a>
<a href="<?php t(MAIN_FILE) ?>/posts/edit?id=<?php t($post['id']) ?>">編集</a>
<a href="<?php t(MAIN_FILE) ?>/posts/delete?id=<?php t($post['id']) ?>">削除</a>
</td>
記事一覧の「削除」リンクから、記事を削除できるようになります。
token()
でトークンの発行と確認ができます。import()
で共通テンプレートを読み込むなどします。db_select()
や db_query()
でSQLを発行するなどします。