質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Visual Studio Code

Visual Studio Codeとは、Microsoft社が開発したマルチプラットフォーム対応のテキストエディタです。Visual Studioファミリーの一員でもあります。拡張性とカスタマイズ性が高く、テキストエディタでありながら、IDEと遜色ない機能を備えることができます。

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

mysqli

MySQLiはPHP5より導入されているデータベース用のドライバです。MySQL 4.1.3以降の新しい機能の利点をまとめています。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

XAMPP

XAMPP(ザンプ)は、ウェブアプリケーションの実行に必要なフリーソフトウェアをパッケージングしたApacheディストリビューションです。 XAMPPひとつインストールするだけで、Apache、MySQL、PHP、Perlなどのソフトウェアと、 phpMyAdminなどの管理ツール、SQLiteなどのソフトウェアやライブラリモジュールなどを利用することが可能です。

Q&A

解決済

1回答

806閲覧

MySQLで検索機能(PHP)

Tarzan3154

総合スコア7

Visual Studio Code

Visual Studio Codeとは、Microsoft社が開発したマルチプラットフォーム対応のテキストエディタです。Visual Studioファミリーの一員でもあります。拡張性とカスタマイズ性が高く、テキストエディタでありながら、IDEと遜色ない機能を備えることができます。

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

mysqli

MySQLiはPHP5より導入されているデータベース用のドライバです。MySQL 4.1.3以降の新しい機能の利点をまとめています。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

XAMPP

XAMPP(ザンプ)は、ウェブアプリケーションの実行に必要なフリーソフトウェアをパッケージングしたApacheディストリビューションです。 XAMPPひとつインストールするだけで、Apache、MySQL、PHP、Perlなどのソフトウェアと、 phpMyAdminなどの管理ツール、SQLiteなどのソフトウェアやライブラリモジュールなどを利用することが可能です。

0グッド

1クリップ

投稿2023/01/25 06:15

前提

MySQLで作成した検索機能をPHPで表示させるプログラムを作っています。
下記のようにmysqliでプレースホルダを指定しようとして、
devices.phpを出力した際にFatal errorが出てしまい、mysqliが未定義となってしまうのですが、
どのように修正すればよろしいでしょうか?

実現したいこと

mysqliを使用したプレースホルダの正しい指定方法と、検索結果を一覧表示させる為の構文

発生している問題・エラーメッセージ

Warning: Undefined variable $mysqli in C:\xampp\htdocs\test\devices.php on line 9 Fatal error: Uncaught Error: Call to a member function prepare() on null in C:\xampp\htdocs\test\devices.php:9 Stack trace: #0 {main} thrown in C:\xampp\htdocs\test\devices.php on line 9

DBの定義

1CREATE TABLE `devices` ( 2 `device_name` char(9) NOT NULL, 3 `serial_number` varchar(9) NOT NULL, 4 `manufacturer` varchar(9) NOT NULL COMMENT 'メーカー名 1:FUJITSU 2:Microsoft', 5 `model` varchar(32) NOT NULL, 6 `os` char(7) NOT NULL DEFAULT 'Windows', 7 PRIMARY KEY (`device_name`), 8 UNIQUE KEY `serial_number` (`serial_number`),

該当のソースコード

devices.php

1<?php 2//①データ取得ロジックを呼び出す 3include_once('model.php'); 4$deviceData = getDeviceData($_GET); 5 6// ここでSQL文を作成する 7$sql = "SELECT * from devices where device_name = ? and serial_number = ? and manufacturer = ? and model = ? and os = ?"; 8// SQL文を$stmt オブジェクトに紐付ける 9if ($stmt = $mysqli->prepare($sql)) { 10 11// プレースホルダと変数を結びつける 12$stmt->bind_param('sssss', $device_name, $serial_number, $manufacturer, $model, $os); 13 14// 実行する 15$stmt->execute(); 16 17// 取得した値を変数に結びつける 18$stmt->bind_result($folder_name); 19 20// 結びつけた変数に取得した値をセットする。 21$stmt->fetch(); 22 23// クローズする 24$stmt->close(); 25 26/* 接続を閉じます */ 27$mysqli->close(); 28} 29?> 30 31<!DOCTYPE html> 32<html lang="ja"> 33<head> 34<meta charset="utf-8"> 35<meta name="viewport" content="width=device-width, initial-scale=1"> 36<title>端末テーブル表示</title> 37<link rel="stylesheet" href="style.css"> 38<!-- Bootstrap読み込み(スタイリングのため) --> 39<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.0/css/bootstrap.min.css"> 40</head> 41<body> 42<div class="flex_test-box"> 43 <div class="flex_test-item"> 44 <h1 class="col-xs-6 col-xs-offset-3">端末テーブル</h1> 45 </div> 46</div> 47<h3 class="col-xs-6 col-xs-offset-3">検索フォーム</h3> 48<div class="col-xs-6 col-xs-offset-3 well"> 49 50 <?php //②検索フォーム ?> 51 <form method="get"> 52 <div class="form-group"> 53 <label for="InputDevice_name">端末名</label> 54 <input name="device_name" class="form-control" id="InputDevice_name" value="<?php echo isset($_GET['device_name']) ? htmlspecialchars($_GET['device_name']) : '' ?>"> 55 </div> 56 <div class="form-group"> 57 <label for="InputSerial_number">シリアル</label> 58 <input name="serial_number" class="form-control" id="InputSerial_number" value="<?php echo isset($_GET['serial_number']) ? htmlspecialchars($_GET['serial_number']) : '' ?>"> 59 </div> 60 <div class="form-group"> 61 <label for="InputManufacturer">メーカー</label> 62 <select name="manufacturer" class="form-control" id="InputManufacturer"> 63 <option value="0" <?php echo empty($_GET['manufacturer']) ? 'selected' : '' ?>>選択しない</option> 64 <option value="1" <?php echo isset($_GET['manufacturer']) && $_GET['manufacturer'] == '1' ? 'selected' : '' ?>>FUJITSU</option> 65 <option value="2" <?php echo isset($_GET['manufacturer']) && $_GET['manufacturer'] == '2' ? 'selected' : '' ?>>Microsoft</option> 66 </select> 67 </div> 68 <div class="form-group"> 69 <label for="InputModel">品名/型番</label> 70 <select name="model" class="form-control" id="InputModel"> 71 <option value="0" <?php echo empty($_GET['model']) ? 'selected' : '' ?>>選択しない</option> 72 <option value="1" <?php echo isset($_GET['model']) && $_GET['model'] == '1' ? 'selected' : '' ?>>Surface Laptop Go</option> 73 <option value="2" <?php echo isset($_GET['model']) && $_GET['model'] == '2' ? 'selected' : '' ?>>ARROWS Tab Q5010/EEG(FARQ25045Z)</option> 74 <option value="3" <?php echo isset($_GET['model']) && $_GET['model'] == '3' ? 'selected' : '' ?>>ARROWS Tab Q509/VE(FARQ22014)</option> 75 <option value="4" <?php echo isset($_GET['model']) && $_GET['model'] == '4' ? 'selected' : '' ?>>ARROWS Tab Q508/SE(FARQ18011)</option> 76 <option value="5" <?php echo isset($_GET['model']) && $_GET['model'] == '5' ? 'selected' : '' ?>>ARROWS Tab Q507/PE(FARQ14011)</option> 77 </select> 78 </div> 79 <div class="form-group"> 80 <label for="InputOs">OS</label> 81 <input type="os" class="form-control" id="InputOs" value="Windows"> 82 </div> 83 <button type="submit" class="btn btn-default" name="search">検索</button> 84 </form> 85 86</div> 87<div class="col-xs-6 col-xs-offset-3"> 88 <?php //③取得データを表示する ?> 89 90 <?php if(isset($deviceData) && count($deviceData)): ?> 91 <p class="alert alert-success"><?php echo count($deviceData) ?>件見つかりました。</p> 92 <table class="table"> 93 <thead> 94 <tr> 95 <th>端末名</th> 96 <th>シリアル</th> 97 <th>メーカー</th> 98 <th>品名/型番</th> 99 <th>OS</th> 100 </tr> 101 </thead> 102 <tbody> 103 <?php foreach($deviceData as $row): ?> 104 <tr> 105 <td><?php echo htmlspecialchars($row['device_name']) ?></td> 106 <td><?php echo htmlspecialchars($row['serial_number']) ?></td> 107 <td><?php echo htmlspecialchars($row['manufacturer'] == 1 ? 'FUJITSU' : 'Microsoft') ?></td> 108 <td><?php echo htmlspecialchars($row['model'] ) ?></td> 109 <td><?php echo htmlspecialchars($row['os']) ?></td> 110 </tr> 111 <?php endforeach; ?> 112 </tbody> 113 </table> 114 <?php else: ?> 115 <p class="alert alert-danger">検索対象は見つかりませんでした。</p> 116 <?php endif; ?> 117 118</div> 119</body> 120</html>

model.php

1<?php 2 3function getDeviceData($params){ 4 //DBの接続情報 5 include_once('config/database.php'); 6 7 //DBコネクタを生成 8 $Mysqli = new mysqli('localhost', 'root', '', 'deviceswithinventory'); 9 if ($Mysqli->connect_error) { 10 error_log($Mysqli_connect_error); 11 exit; 12 } 13} 14?>

config/database.php

1<?php 2 3//DBの接続情報 4$host = "localhost"; 5$username = "root"; 6$password = ""; 7$dbname = "deviceswithinventory"; 8

試したこと

Mysqli(プリペアドステートメント~execute)の箇所の構文をdevices.phpからmodel.phpに転記させても結果変わりませんでした。

補足情報(FW/ツールのバージョンなど)

PHP7、MySQL8.0を使用

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

追記

最初の回答では大文字小文字の問題と解答しましたが、スコープの問題でした。
関数の中で定義された変数は関数の外では使えません。

現状の実装を拝見するに、自作関数そのもの(特に引数と戻り値の扱い)についての理解が追い付いていない様に見受けられますので、
まずは、
https://www.php.net/manual/ja/functions.user-defined.php
でごく簡単なサンプルから順に確認して理解を深めることをお勧めします。

今回のケースだと、model.phpをインクルードしているのですが、実質的に以下の様に書いているのと同じことになります。

PHP

1//ここから関数 2function getDeviceData($params){ 3 //DBの接続情報 4 include_once('config/database.php'); 5 6 //DBコネクタを生成 7 $Mysqli = new mysqli('localhost', 'root', '', 'deviceswithinventory'); 8 if ($Mysqli->connect_error) { 9 error_log($Mysqli_connect_error); 10 exit; 11 } 12} 13//ここまで関数 14 15$sql = "SELECT * from devices where device_name = ? and serial_number = ? and manufacturer = ? and model = ? and os = ?"; 16// SQL文を$stmt オブジェクトに紐付ける 17//関数の外で関数内で定義した変数は使えないので、$mysqliは存在せず、エラーになる 18if ($stmt = $mysqli->prepare($sql)) { //$mysqliが同じスコープ内で定義されていない 19//以下略

これを修正しようとした場合

PHP

1function getDeviceData(){ 2 //引数とDB接続情報は使っていないので削除。理解が進んだら追加してみてください。 3 //DBコネクタを生成 4 $Mysqli = new mysqli('localhost', 'root', '', 'deviceswithinventory'); 5 if ($Mysqli->connect_error) { 6 error_log($Mysqli_connect_error); 7 exit; 8 } 9 //戻り値として$Mysqiを呼び出し元に返す 10 return $Mysqli; 11}

として(関数名からすると不思議な動きですので、関数名自体をdb_connect()とかに変える方がいいとは思いますが、ここでは無視します)

devices.phpを

PHP

1<?php 2//①データ取得ロジックを呼び出す 3include_once('model.php'); 4$mysqli = getDeviceData(); 5 6// ここでSQL文を作成する 7$sql = "SELECT * from devices where device_name = ? and serial_number = ? and manufacturer = ? and model = ? and os = ?"; 8// SQL文を$stmt オブジェクトに紐付ける 9if ($stmt = $mysqli->prepare($sql)) {

という感じにすればgetDeviceData()内でnewされたmysqiオブジェクトを関数外で使用することが可能になります。

最初の回答

PHPの変数は大文字と小文字が区別されるので、
model.php

PHP

1 $Mysqli = new mysqli('localhost', 'root', '', 'deviceswithinventory');

としたのであれば、

devices.php

PHP

1if ($stmt = $mysqli->prepare($sql)) {

では無く

PHP

1if ($stmt = $Mysqli->prepare($sql)) {

とする必要があります(他の部分も同様に修正が必要です。)

投稿2023/01/25 06:31

編集2023/01/25 07:13
tanat

総合スコア18713

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Tarzan3154

2023/01/25 08:55

ご丁寧に回答ありがとうございます! リンクについても参考にして勉強させていただきます。 1点追加で質問ですが、上記ご指摘のとおりコードを修正して出力したところ 下記のエラーメッセージが表示されてしまいます。 Fatal error: Uncaught ArgumentCountError: Number of bind variables doesn't match number of fields in prepared statement in C:\xampp\htdocs\test\devices.php:18 Stack trace: #0 C:\xampp\htdocs\test\devices.php(18): mysqli_stmt->bind_result(NULL) #1 {main} thrown in C:\xampp\htdocs\test\devices.php on line 18 bind_result内の値を「$device_name」や「$device_name, $serial_number, $manufacturer, $model, $os」 としても同様のエラーが発生します。 こちらのエラーの原因をご教示いただけないでしょうか。
tanat

2023/01/25 11:56 編集

*既に別の問題なので、こちらでのやり取りはこれで終わりにします。(追加質問は他の回答者も入りにくいですし、後から質問と回答を見る人が見にくいのでteratailの主旨に合っていないと思います) 解決しない様であれば整理して別に質問を立ててください。 テーブル定義が変わってない前提であれば、 > bind_result内の値を「$device_name」や「$device_name, $serial_number, $manufacturer, $model, $os」 の後者が正しく設定されていればエラーは出ないはずです。 ただ、 $device_name, $serial_number, $manufacturer, $model, $os は他の用途で使われているので、別の変数を用意する方がいいでしょうね。 $device_name_col, $serial_number_col, $manufacturer_col, $model_col, $os_col の様な形です。 一気に色々やろうとしても分からなくなるので、 PHPマニュアルの https://www.php.net/manual/ja/mysqli-stmt.bind-result.php 例1のコードを読んで理解してみる&データベースとテーブルを作って実際に動かしてみて理解を深める ということをお勧めします。 ***** ローカルでこんなデータと mysql> show create table devices; +---------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Table | Create Table | +---------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | devices | 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', PRIMARY KEY (`device_name`), UNIQUE KEY `serial_number` (`serial_number`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 | +---------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 1 row in set (0.00 sec) mysql> select * from devices; +-------------+---------------+--------------+-------+----+ | device_name | serial_number | manufacturer | model | os | +-------------+---------------+--------------+-------+----+ | aaa | 1 | 2 | 3 | 4 | | aaa2 | 2 | 2 | 3 | 4 | +-------------+---------------+--------------+-------+----+ 2 rows in set (0.00 sec) こんな感じの最小限のコードで動かすととりあえず動いたので、どこか理解しきれていないところでミスがあるんだと思いますよ。 <?php $mysqli = new mysqli('localhost', 'root', 'Spector@lan1', 'tera'); $sql = "SELECT * from devices where device_name = ? and serial_number = ? and manufacturer = ? and model = ? and os = ?"; // SQL文を$stmt オブジェクトに紐付ける $stmt = $mysqli->prepare($sql); // プレースホルダと変数を結びつける //とりあえず検索条件は動作検証用に決め打ち $device_name = "aaa"; $serial_number = "1"; $manufacturer = "2"; $model = "3"; $os = "4"; $stmt->bind_param('sssss', $device_name, $serial_number, $manufacturer, $model, $os); // 実行する $stmt->execute(); // 取得した値を変数に結びつける $stmt->bind_result($device_name_col, $serial_number_col, $manufacturer_col, $model_col, $os_col); $stmt->fetch(); var_dump($device_name_col, $serial_number_col, $manufacturer_col, $model_col, $os_col); // クローズする $stmt->close(); /* 接続を閉じます */ $mysqli->close();
tanat

2023/01/25 13:10

回答ではないですが、 授業での指定がそうである 既存システムの保守運用などでどうしてもmysqliでの実装を習得しなければならない などの理由が無いのであれば、 現在の主流であるPDOでのデータベース操作に学習内容と教材を変更することを強くお勧めします。 初学者にとってはmysqliはPDOに比べると学習環境が整っているとは言い難いです
Tarzan3154

2023/01/26 02:03

詳細までご回答いただき、ありがとうございました。 参考にさせていただきます。 >授業での指定がそうである 既存システムの保守運用などでどうしてもmysqliでの実装を習得しなければならない などの理由が無いのであれば、 現在の主流であるPDOでのデータベース操作に学習内容と教材を変更することを強くお勧めします。 初学者にとってはmysqliはPDOに比べると学習環境が整っているとは言い難いです 上記について、PDOではなくmysqliを選択した理由としては、PDOよりも多くのことができ、高速らしいという話を伺ったからです。(作ろうとしているのが、PCの資産管理データをまとめたDBで総端末台数は5000台を超えます) 上記のプログラムについてPDOを使用した場合でも動作は充分に行えるものなのでしょうか。
tanat

2023/01/26 02:27

> 上記について、PDOではなくmysqliを選択した理由としては、PDOよりも多くのことができ、高速らしいという話を伺ったからです。 これはもう少しソースを確認したり実際に計測する方がいいですね。 15年くらい前のイメージな気がします。 > 上記のプログラムについてPDOを使用した場合でも動作は充分に行えるものなのでしょうか。 まず、パフォーマンスについてはPHP5.6以降だとPDOの方が早いケースが多いはずです、が、基本気にしなくていい範囲でしか変わりません。 パフォーマンスに関しては、DB設計やチューニング、発行するクエリの影響がドライバ(PDO/mysqli)の影響より桁が3-4つ大きいのでパフォーマンスを基準にする場合はドライバは考慮に入れる必要は無いです。 > (作ろうとしているのが、PCの資産管理データをまとめたDBで総端末台数は5000台を超えます) レコード数が5000台という意味であれば、適切にDB設計されていれば5000台でも50万台でも誤差みたいなものなので学習しやすいPDOで学習するのが良いと思いますよ。 (業務で使ったり、インターネットに公開する前提だとフレームワークを使わないと実用的なセキュリティや保守性の実現が難しくなってくる場合もありますが、その辺は一通り基礎が学習で来てからの方が必要性の把握や学習もしやすいと思います。)
Tarzan3154

2023/01/26 02:36

そうなのですね...何から何までありがとうございます。 PDOで作り直してみたいと思います。 詳しく教えていただき本当にありがとうございました! 非常に参考になりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問