データベース接続

今回は、PHPからデータベースに接続して、データを操作する方法について解説します。データベースは、レンタルサーバで広く使われており、また、多くのレンタルサーバでWebUIの管理ツール「phpmyadmin」を用意していることから、MySQLを使用することを前提とします。なお、ここではMySQLそのものについては解説しませんが、コントロールパネルなどから簡単にデータベースを作成できるレンタルサーバも多数ありますので、レンタルサーバのサポートやSQL解説サイト、書籍などを参考にしてください。

コンフィグファイル

PHPからMySQLに接続するには「ホスト名」「データベース名」「ユーザ名」「パスワード」が必要になります。これらの情報は、データベースへ接続するスクリプトすべてで必要となりますので、その都度記述するのではなく、別ファイルに記述し「include」や「require」で呼び出すのが一般的です。また、これらの情報が漏洩してしないようファイルの配置場所や、スクリプトの記述方法を工夫するようにしましょう。今回はこのファイルを「config.php」として保存します。

スクリプト(PEAR不使用)

<?php
	if(preg_match('/config.php/', $_SERVER['PHP_SELF'] )){
		header("Location: ../index.php");
		exit;
	}
	$db_host = '<MySQLホスト名>';
	$db_user = '<MySQLユーザ名>';
	$db_pass = '<MySQLパスワード>';
	$db_name = '<DB名>';
?>

解説

if(preg_match('/config.php/', $_SERVER['PHP_SELF'])){ … }
このファイルにはデータベース接続のための情報が記述されているので、ブラウザ直接呼び出されて中身を見られると困ります。自身のファイル名に「config.php」が含まれている場合は、トップページにリダイレクトするよう記述しています。preg_match関数は正規表現により一致した文字列を検索し、その回数を結果として返しますが、最初にマッチした時点でpreg_match() は検索を止めるため返り値は0か1になります。preg_match関数の引数は('/<検索したい文字列>/', 検索される側の文字列)になります。以前はpreg_match関数ではなくereg関数が利用されていましたが、PHP5.3.0より非推奨となり、PHP6ではereg関数そのものが無くなってしまうようです。もしこのファイルが直接ではなく、他のファイルから「include」や「require」などで呼び出されているのであれば、グローバル変数「$_SERVER['PHP_SELF']」はその呼び出し元のファイル名に格納されているので、それ以降の処理も実行します。
$db_host = '<MySQLホスト名>'
MySQLに接続するための情報を変数に代入しています。データベースサーバのホスト名はそのレンタルサーバにより異なりますので、レンタルサーバのFAQやコントロールパネルなどで確認してください。

スクリプト(PEAR使用)

<?php
	if(preg_match('/config.php/', $_SERVER['PHP_SELF'] )){
		header("Location: ../index.php");
		exit;
	}
	$dsn = 'mysql://<MySQLユーザ名>:<MySQLパスワード>@<MySQLホスト名>/<DB名>'; 
?>
$dsn = 'mysql://<MySQLユーザ名>:<MySQLパスワード>@<MySQLホスト名>/<DB名>'
変数「$dsn」にMySQL接続情報を代入しています。MySQL接続情報は上記書式で記述しておけば、PEARのDBクラスでMySQLへ接続が可能となります。

実行ファイル

今回のファイルは、まずアクセスすると記事のタイトル一覧を表示、そのタイトルをクリックするとその記事の詳細が閲覧できるというものになります。想定しているテーブルの構造は「id(int)」「date(date)」「title(varchar)」「body(text)」「active(enum'Y','N')」となります。順に「ID」「掲載日」「記事タイトル」「記事本文」「表示フラグ」となります。

スクリプト(PEAR不使用)

<?php
	require_once 'config.php';
	$connect = mysql_connect($db_host, $db_user, $db_pass) or die('DB 接続失敗!');
	mysql_select_db($db_name, $connect) or die('DB 選択失敗!');
	if(isset($_GET['id']) && is_numeric($_GET['id'])){
		$id = $_GET['id'];
		$query = "SELECT * FROM <テーブル名> WHERE id='$id' AND active='Y'";
		$result = mysql_query($query) or die('DB_SELECT 実行失敗!');
		if(mysql_num_rows($result) == 0){
			echo '<p>該当の記事はありません。</p>';
		}else{
			$row = mysql_fetch_assoc($result);
			$date = htmlspecialchars($row['date'], ENT_QUOTES);
			$title = htmlspecialchars($row['title'], ENT_QUOTES);
			$body = htmlspecialchars($row['body'], ENT_QUOTES);
			$body = nl2br($body);
			$body = str_replace('<br /><br />', '</p>\n<p>', $body);
			echo '
				<h3>'.$title.'('.$date.'掲載)</h3>
				<p>'.$body.'</p>
			';
		}
	}else{
		$query = "SELECT * FROM <テーブル名> WHERE active='Y'";
		$result = mysql_query($query) or die('DB_SELECT 実行失敗!');
		echo '<ul>';
		while($row = mysql_fetch_assoc($result)){
			$id = htmlspecialchars($row['id'], ENT_QUOTES);
			$date = htmlspecialchars($row['date'], ENT_QUOTES);
			$title = htmlspecialchars($row['title'], ENT_QUOTES);
			$body = htmlspecialchars($row['body'], ENT_QUOTES);
			echo '<li><a href="'.$_SERVER['PHP_SELF'].'?id='.$id.'">'.$title.'</a> \
			('.$date.'掲載)</li>';
		}
		echo '</ul>';
	}
?>

解説

$connect = mysql_connect($db_host, $db_user, $db_pass) or die('DB 接続失敗!')
mysql_connect関数でMySQLサーバへの接続をオープンし、そのリンクを変数「$connect」に代入しています。接続に失敗した場合には、die関数により引数である「DB 接続失敗!」を出力して一連の処理を終了します。データベースへ接続するファイルには、必ず記述する必要がありますので「config.php」に記述するのもお勧めです。
mysql_select_db($db_name, $connect) or die('DB 選択失敗!')
mysql_select_db関数で使用するデータベースを選択しています。引数は(データベース名、データベース接続リンク)になります。これもデータベースへ接続するファイルには、必ず記述する必要がありますので「config.php」に記述するのが良いかもしれません。
if(isset($_GET['id']) && is_numeric($_GET['id'])){ … }
isset関数でグローバル変数「$_GET['id']」が定義されているか調べます。グローバル変数「$_GET['…']」はURLと一緒に渡されるパラメータを取得したものです。またここではis_numeric関数で「$_GET['id']」に格納されている値が数値かどうか調べます。これは、パラメータの値が必ず数値である場合にはセキュリティ的に大変意味のある処理になります。ここでは「$_GET['id']」が定義されているとともにその値が数値である場合にのみ{ }内の処理を実行します。パラメータの値が必ず数値である場合は、そのパラメータの値を検証してから処理を実行するようにしましょう。
$query = "SELECT * FROM <テーブル名> WHERE id='$id' AND active='Y'"
SQL文を変数「$query」に代入しています。「active='Y'」は表示フラグが立っていると解釈してください。一覧のリンクからこの処理がこの処理が実行されるので、当然「active='Y'」のものしか、この場合「とあるテーブルからidが$_GET['id']と同じ値で、activeの値がYであるレコードのすべてのカラムを抽出しなさい」という意味になります。
$result = mysql_query($query) or die('DB_SELECT 実行失敗!')
mysql_query関数でクエリを実行し、その結果リソースを変数「$result」に代入しています。
if(mysql_num_rows($result) == 0){ … }
mysql_num_rows関数でデータベースからの抽出結果が0行の場合、{ }内の処理、該当する記事がない旨出力します。そうでない場合(idは重複しないことを前提としているので1行だけ抽出される)else{ }内の処理が実行されます。
while($row = mysql_fetch_assoc($result)){ … }
変数「$result」に代入されているのはクエリ実行結果のリソースなのでそのままではデータとして使えません。そこでmysql_fetch_assoc関数を使って配列「$row」に格納します。キーにはカラム名が与えられますので、抽出した行の「title」というカラムの値を取得したい場合は「$row['title']」とします。このループは、抽出したデータの行数分だけ繰り返されます。
$body = nl2br($body)
「\n」などの改行文字を「<br />」タグに変換します。
str_replace('<br /><br />', '</p>\n<p>', $body)
「<br />」タグが連続するのはよろしくないので、str_replace関数を使用し「<br /><br />」を「</p>\n<p>」に置換しています。str_replace関数の引数は(置換前文字列,置換後文字列,置換の対象となる文字列)となります。
while($row = mysql_fetch_assoc($result)){ … }
「<br />」タグが連続するのはよろしくないので、str_replace関数を使用し「<br /><br />」を「</p>\n<p>」に置換しています。str_replace関数の引数は(置換前文字列,置換後文字列,置換の対象となる文字列)となります。

スクリプト(PEAR使用)

<?php
	require_once 'config.php';
	require_once 'DB.php';
	$db = DB::connect($dsn);
	if(PEAR::isError($db)){
  		die($db->getMessage());
	}
	if(isset($_GET['id']) && is_numeric($_GET['id'])){
		$id = $_GET['id'];
		$query = "SELECT * FROM <テーブル名> WHERE id='$id' AND active='Y'";
		$result = $db->query($query);
		if(PEAR::isError($result)){
  			die($db->getMessage());
		}
		if($result->numRows() == 0){
			echo '<p>該当の記事はありません。</p>';
		}else{
			$row = $result->fetchRow(DB_FETCHMODE_ASSOC);
			$date = htmlspecialchars($row['date'], ENT_QUOTES);
			$title = htmlspecialchars($row['title'], ENT_QUOTES);
			$body = htmlspecialchars($row['body'], ENT_QUOTES);
			$body = nl2br($body);
			$body = str_replace('<br /><br />', '</p>\n<p>', $body);
			echo '
				<h3>'.$title.'('.$date.'掲載)</h3>
				<p>'.$body.'</p>
			';
		}
	}else{
		$query = "SELECT * FROM <テーブル名> WHERE active='Y'";
		$result = $db->query($query);
		if(PEAR::isError($result)){
  			die($db->getMessage());
		}
		echo '<ul>';
		while($row = $result->fetchRow(DB_FETCHMODE_ASSOC)){
			$id = htmlspecialchars($row['id'], ENT_QUOTES);
			$date = htmlspecialchars($row['date'], ENT_QUOTES);
			$title = htmlspecialchars($row['title'], ENT_QUOTES);
			$body = htmlspecialchars($row['body'], ENT_QUOTES);
			echo '<li><a href="'.$_SERVER['PHP_SELF'].'?id='.$id.'">'.$title.'</a> \
			('.$date.'掲載)</li>';
		}
		echo '</ul>';
	}
?>

解説

require_once 'DB.php'
PEARのクラスライブラリ「DB.php」を読み込んでいます。PHPの設定でPEARにはパスが通っていることがほとんどですので、このような場合はファイル名ののみで呼び出すことが可能です。
$db = DB::connect($dsn)
スコープ定義演算子「::」を使用することにより、DBクラスのconnectメソッドを実行しています。成功するとオブジェクトが返されますので、変数「$db」はオブジェクトということになります。
if(PEAR::isError($db)){ … }
「PEAR::isError」メソッドで実際にデータベースへの接続が成功しているかどうか確認しています。接続に失敗している場合{ }内の処理を実行します。
die($db->getMessage())
getMessageメソッドでエラーの内容を取得しています。その内容がdie関数の引数となりますので、取得したエラーの内容を出力し、すべての処理を終了します。
$result = $db->query($query)
qyeryメソッドで変数「$query」に代入されているSQL文を実行しています。ここでも成功時に返されるのはオブジェクトになります。
if($result->numRows() == 0){ … }
numRowsメソッドでデータベースから抽出した行数を取得し、その行数が0行の場合{ }内の処理が実行されます。
$row = $result->fetchRow(DB_FETCHMODE_ASSOC)
fetchRowメソッドで取得したデータを取り出し変数「$row」に代入します。fetchRowメソッドの引数はフェッチモードといい、返される値の型式を指定できます。今回は引数を「DB_FETCHMODE_ASSOC」とし、カラム名をキーとした連想配列でデータを取り出しています。「DB_FETCHMODE_ORDERED」とすると添字配列でデータを取り出すことができます。

▲ページトップに戻る