@Tarzan3154

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

PHPで表示したMySQLでの検索機能について

解決したいこと

MySQLで作成したDBをPHPで表示させるプログラムを作っています。
端末テーブル(devices.php)に検索フォームを追加し、入力 or 検索した項目を含む行を表示するようにしたいのですが、
①入力フォーム(device_name,serial_number,os,school_year,class)に値を入力して検索すると正常に検索結果が表示されますが、
_②選択フォーム(model,os_version,school_id)を選択して検索しても、「検索対象は見つかりませんでした。」と表示されて、検索結果が表示されません。
_
検索条件からSQl文を生成する部分についてご教示お願いします。

エラーコード

※modelのoption valueやissetの引数を数字ではなく「Surface Laptop Go」に書き換えて、選択フォームから検索を実行した場合に発生するエラー

Fatal error: Uncaught mysqli_sql_exception: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'Laptop Go' at line 1 in C:\xampp\htdocs\DevicesWithInventory\devices\model.php:51 Stack trace: #0 C:\xampp\htdocs\DevicesWithInventory\devices\model.php(51): mysqli->query('select * from d...') #1 C:\xampp\htdocs\DevicesWithInventory\devices\devices.php(6): getDeviceData(Array) #2 {main} thrown in C:\xampp\htdocs\DevicesWithInventory\devices\model.php on line 51

DBの定義

CREATE TABLE `devices` (
  `device_name` char(9) NOT NULL,
  `serial_number` varchar(9) NOT NULL,
  `manufacturer` varchar(9) NOT NULL COMMENT 'メーカー名 1:FUJITSU 2:Microsoft',
  `model` varchar(32) NOT NULL,
  `os` char(7) NOT NULL DEFAULT 'Windows',
  `os_version` varchar(15) NOT NULL,
  `school_id` char(4) NOT NULL,
  `school_year` int(1) DEFAULT NULL,
  `class` int(1) DEFAULT NULL,
  PRIMARY KEY (`device_name`),
  UNIQUE KEY `serial_number` (`serial_number`),
  KEY `fk_school_id` (`school_id`),
  CONSTRAINT `fk_school_id` FOREIGN KEY (`school_id`) REFERENCES `school` (`school_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4

該当するソースコード

devices.php

<?php

//①データ取得ロジックを呼び出す
include_once('model.php');

$deviceData = getDeviceData($_GET);

?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>端末テーブル表示</title>
<link rel="stylesheet" href="style.css">
<!-- Bootstrap読み込み(スタイリングのため) -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.0/css/bootstrap.min.css">
</head>
<body>
<h1 class="col-xs-6 col-xs-offset-3">端末テーブル</h1> 
<h3 class="col-xs-6 col-xs-offset-3">検索フォーム</h3>
<div class="col-xs-6 col-xs-offset-3 well">
	
	<?php //②検索フォーム ?>
	<form method="get">
		<div class="form-group">
			<label for="InputDevice_name">端末名</label>
			<input name="device_name" class="form-control" id="InputDevice_name" value="<?php echo isset($_GET['device_name']) ? htmlspecialchars($_GET['device_name']) : '' ?>">
		</div>
		<div class="form-group">
			<label for="InputSerial_number">シリアル</label>
			<input name="serial_number" class="form-control" id="InputSerial_number" value="<?php echo isset($_GET['serial_number']) ? htmlspecialchars($_GET['serial_number']) : '' ?>">
		</div>
		<div class="form-group">
			<label for="InputManufacturer">メーカー</label>
			<select name="manufacturer" class="form-control" id="InputManufacturer">
				<option value="0" <?php echo empty($_GET['manufacturer']) ? 'selected' : '' ?>>選択しない</option>
				<option value="1" <?php echo isset($_GET['manufacturer']) && $_GET['manufacturer'] == '1' ? 'selected' : '' ?>>FUJITSU</option>
				<option value="2" <?php echo isset($_GET['manufacturer']) && $_GET['manufacturer'] == '2' ? 'selected' : '' ?>>Microsoft</option>
			</select>
		</div>
		<div class="form-group">
			<label for="InputModel">品名/型番</label>
			<select name="model" class="form-control" id="InputModel">
				<option value="0" <?php echo empty($_GET['model']) ? 'selected' : '' ?>>選択しない</option>
				<option value="Surface Laptop Go" <?php echo isset($_GET['model']) && $_GET['model'] == '1' ? 'selected' : '' ?>>Surface Laptop Go</option>
				<option value="2" <?php echo isset($_GET['model']) && $_GET['model'] == '2' ? 'selected' : '' ?>>ARROWS Tab Q5010/EEG(FARQ25045Z)</option>
				<option value="3" <?php echo isset($_GET['model']) && $_GET['model'] == '3' ? 'selected' : '' ?>>ARROWS Tab Q509/VE(FARQ22014)</option>
				<option value="4" <?php echo isset($_GET['model']) && $_GET['model'] == '4' ? 'selected' : '' ?>>ARROWS Tab Q508/SE(FARQ18011)</option>
				<option value="5" <?php echo isset($_GET['model']) && $_GET['model'] == '5' ? 'selected' : '' ?>>ARROWS Tab Q507</option>
			</select>
		</div>
		<div class="form-group">
			<label for="InputOs">OS</label>
			<input type="os" class="form-control" id="InputOs" value="Windows">
		</div>
        <div class="form-group">
			<label for="InputOs_version">OS Version</label>
			<select name="os_version" class="form-control" id="InputOs_version">
				<option value="0" <?php echo empty($_GET['os_version']) ? 'selected' : '' ?>>選択しない</option>
				<option value="1" <?php echo isset($_GET['os_version']) && $_GET['os_version'] == '1' ? 'selected' : '' ?>>10.0.19041.1165</option>
				<option value="2" <?php echo isset($_GET['os_version']) && $_GET['os_version'] == '2' ? 'selected' : '' ?>>10.0.19041.329</option>
				
~~~以下略~~~
				<option value="15" <?php echo isset($_GET['os_version']) && $_GET['os_version'] == '15' ? 'selected' : '' ?>>10.0.19044.1889</option>
			</select>
		</div>
        <div class="form-group">
			<label for="InputSchool_id">学校ID</label>
			<select name="school_id" class="form-control" id="InputSchool_id">
				<option value="0" <?php echo empty($_GET['school_id']) ? 'selected' : '' ?>>選択しない</option>
				<option value="1" <?php echo isset($_GET['school_id']) && $_GET['school_id'] == '1' ? 'selected' : '' ?>>X01X</option>
				~~~以下略~~~
				<option value="20" <?php echo isset($_GET['school_id']) && $_GET['school_id'] == '20' ? 'selected' : '' ?>>X07X</option>
			</select>
		</div>
		<div class="form-group">
			<label for="InputSchool_year">学年</label>
			<input name="school_year" class="form-control" id="InputSchool_year" value="<?php echo isset($_GET['school_year']) ? htmlspecialchars($_GET['school_year']) : '' ?>">
		</div>
		<div class="form-group">
			<label for="InputClass">クラス</label>
			<input name="class" class="form-control" id="InputClass" value="<?php echo isset($_GET['class']) ? htmlspecialchars($_GET['class']) : '' ?>">
		</div>
		<button type="submit" class="btn btn-default" name="search">検索</button>
	</form>

</div>
<div class="col-xs-6 col-xs-offset-3">
	<?php //③取得データを表示する ?>
	<?php if(isset($deviceData) && count($deviceData)): ?>
		<p class="alert alert-success"><?php echo count($deviceData) ?>件見つかりました。</p>
		<table class="table">
			<thead>
				<tr>
					<th>端末名</th>
					<th>シリアル</th>
					<th>メーカー</th>
					<th>品名/型番</th>
					<th>OS</th>
					<th>OS Version</th>
					<th>学校ID</th>
					<th>学年</th>
					<th>クラス</th>
				</tr>
			</thead>
			<tbody>
				<?php foreach($deviceData as $row): ?>
					<tr>
						<td><?php echo htmlspecialchars($row['device_name']) ?></td>
						<td><?php echo htmlspecialchars($row['serial_number']) ?></td>
						<td><?php echo htmlspecialchars($row['manufacturer'] == 1 ? 'FUJITSU' : 'Microsoft') ?></td>
						<td><?php echo htmlspecialchars($row['model']) ?></td>
						<td><?php echo htmlspecialchars($row['os']) ?></td>
						<td><?php echo htmlspecialchars($row['os_version']) ?></td>
						<td><?php echo htmlspecialchars($row['school_id']) ?></td>
						<td><?php echo htmlspecialchars($row['school_year']) ?></td>
						<td><?php echo htmlspecialchars($row['class']) ?></td>
					</tr>
				<?php endforeach; ?>
			</tbody>
		</table>
	<?php else: ?>
		<p class="alert alert-danger">検索対象は見つかりませんでした。</p>
	<?php endif; ?>

	<form action="input_devices.php" method="post"> 
		<input type="submit" value="新規端末登録">
	</form>

</div>
</body>
</html>
config/database.php

<?php

//DBの接続情報
$host = "127.0.0.1";
$username = "XXX00";
$password = "";
$dbname = "XXXX";
model.php

<?php

function getDeviceData($params){
	//DBの接続情報
	include_once('config/database.php');

	//DBコネクタを生成
	$Mysqli = new mysqli('127.0.0.1', 'XXX00', '', 'XXXX');
	if ($Mysqli->connect_error) {
			error_log($Mysqli->connect_error);
			exit;
	}

	//入力された検索条件からSQl文を生成
	$where = [];
	if(!empty($params['device_name'])){
		$where[] = "device_name like '%{$params['device_name']}%'";
	}
	if(!empty($params['serial_number'])){
		$where[] = "serial_number like '%{$params['serial_number']}%'";
	}
	if(!empty($params['manufacturer'])){
		$where[] = 'manufacturer = ' . $params['manufacturer'];
	}
	if(!empty($params['model'])){
		$where[] = 'model = ' . $params['model'];
	}
	if(!empty($params['os'])){
		$where[] = 'os = ' . $params['os'];
	}
	if(!empty($params['os_version'])){
		$where[] = 'os_version = ' . $params['os_version'];
	}
	if(!empty($params['school_id'])){
		$where[] = 'school_id = ' . $params['school_id'];
	}
	if(!empty($params['school_year'])){
		$where[] = "school_year like '%{$params['school_year']}%'";
	}
	if(!empty($params['class'])){
		$where[] = "class like '%{$params['class']}%'";
	}
	if($where){
		$whereSql = implode(' AND ', $where);
		$sql = 'select * from devices where ' . $whereSql ;
	}else{
		$sql = 'select * from devices';
	}
	
	//SQL文を実行する
	$DeviceDataSet = $Mysqli->query($sql);

	//扱いやすい形に変える
	$result = [];
	while($row = $DeviceDataSet->fetch_assoc()){
		$result[] = $row;
	}
	return $result;
}

自分で試したこと

manufacturerについては上記のように修正して正常に表示されるようになりましたが、
(例えば)modelについてoption valueやissetの値を文字列に変更するとエラーが発生してしまいますが、
値の記述の仕方が分かりません。

0 likes

1Answer

SQL文にユーザ入力を直接展開しないでください.
必ずSQLのプレースホルダを使用します.

https://qiita.com/mpyw/items/b00b72c5c95aac573b71

ざっと見た感じではvalue"0"の場合にempty($params['*'])trueにならないです?

var が存在しない、 または空や0の値が設定されている場合、 つまり boolean のコンテキストで false と見なされる場合、 true を返します。 詳細は boolean への変換 を参照して下さい。 それ以外の場合は false を返します。

0Like

Comments

  1. @Tarzan3154

    Questioner

    @Verclene様
    ソースコードの修正、エラーコード・DBの定義の追記を行いました。
    良ければご確認をお願いします。
  2. 現状modelに関わるSQL文は以下のように展開されるので当然エラーになります.

    $where[] = 'model = ' . $params['model'];

    model = Surface Laptop Go

    いずれにせよこのSQL生成を根本的に書き直さないままで改善案を出すというわけにもいきませんので,プレースホルダを使用して書き直すのが先決です.
  3. @Tarzan3154

    Questioner

    ご回答ありがとうございます。
    modelに関わるSQL文を以下のように書き直し、
    (値を「:model」としましたが、プレースホルダを使用する認識として合ってますでしょうか)
    エラーは発生しなくなりましたが、検索結果は全項目表示となってしまいます。
    他に確認事項はありますでしょうか。

    if(!empty($params[':model'])){
    $where[] = ':model = ' . $params[':model'];
    }
  4. とりあえずプレースホルダの使用方法については上記リンクを参照していただければと思います.
    端的に言うと,PHP側で直接変数展開する事自体がよろしくありません.
    form側の名前を変えても何の意味もないです.

Your answer might help someone💌