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

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

ただいまの
回答率

87.37%

SQL文 SELECT文 LIMIT句に変数を入れ、DBからデータを取得したい

解決済

回答 3

投稿

  • 評価
  • クリップ 0
  • VIEW 4,405

score 18

 前提・実現したいこと

初学者です。よろしくお願いいたします。
PHPとmysqlを勉強しており、課題として郵便番号及び住所を検索するプログラムを作成しています。
データベースはMyAdminにて作成しました。

1ページ10件の検索結果を表示し、ページを「次へ」「戻る」で移動できるページング機能を実装するため、
まずはmysqli_query()やSELECT文およびLIMIT句を用いる事が分かり試したのですが、、、

'LIMIT 10'のような文は動いてくれるのですが、変数を用いた'LIMIT 変数'ではエラーが出てしまい、
検索結果も0件になってしまいます。

エラー内容から、データベースに変数の内容が伝わっておらず、'LIMIT なんだこれ' と処理され、
論理型のtrue or falseで返ってしまってるのだと思い、どうすればデータベースに変数の存在を伝えられるか調べてみましたが分かりませんでした。(そもそも上記の解釈で合っているのかも分かりません、、、)

まだページング機能の作成すらまともにわからない状態ではありますが、
まずは'LIMIT 変数'を用いて検索結果が10件表示されるようにしたいです。
エラーの原因、改善をお教え下さる方いらっしゃいましたら、
改めまして、よろしくお願いいたします。

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

Warning: mysqli_fetch_array() expects parameter 1 to be mysqli_result, boolean given in 
Warning: mysqli_free_result() expects parameter 1 to be mysqli_result, boolean given in 

 該当のソースコード

<?php
$zipcode = NULL;
$pref = NULL;
$address = NULL;
//var_dump用
$zipcode_data = NULL;
$address_data = NULL;

//ページング用
$page = 1;
$count = 10;
//////////////////////////////////////////////////////////
//入力された値のチェック
//////////////////////////////////////////////////////////
//ここのissetでボタンの判別してます//hiddenで判別できたなぁ(今更感)
//postボタンを押して入力された値がある場合
if($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST ['post_button']) === true && empty($_POST['zipcode']) !== true) { 
    $trim_zipcode = trim($_POST['zipcode']); //入力された値にトリムをかける
    if(preg_match('/^[0-9]{7}?$/', $trim_zipcode) === 1) { //トリム後1~9の数字7文字なら
        $zipcode = $trim_zipcode; 
    //トリム後1~9の数字7文字でないなら
    } else if($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST ['post_button']) === true && mb_strlen($trim_zipcode) !== 7) {
        $message2 = '郵便番号は半角で7つの数字で入力してください';
    }
//postボタンを押して入力された値がない場合
} else if($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST ['post_button']) === true && empty($_POST['zipcode']) === true) {
        $message2 = '郵便番号を入力してください';
}

//prefボタンを押して、都道府県に入力された値がある場合
if($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST ['pref_button']) === true && empty($_POST['pref']) !== true) {
    $pref = $_POST['pref'];
//prefボタンを押して、都道府県に入力された値がない場合
} else if($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST ['pref_button']) === true && empty($_POST['pref']) === true) {
    $message2 = '都道府県を入力してください';
}

//prefボタンを押して、市区町村に入力された値がある場合
if($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST ['pref_button']) === true && empty($_POST['address']) !== true) {
    $trim_address = trim($_POST['address']);
//正規表現はQiitaの投稿より拝借。凄い闇を感じる、、、
    if(preg_match('/(...??[都道府県])((?:旭川|伊達|石狩|盛岡|奥州|田村|南相馬|那須塩原|東村山|武蔵村山|羽村|十日町|上越|富山|野々市|大町|蒲郡|四日市|姫路|大和郡山|廿日市|下松|岩国|田川|大村)市|.+?郡(?:玉村|大町|.+?)[町村]|.+?市.+?区|.+?[市区町村])(.+)/', $trim_address) === 1) {
        $address = $trim_address;
    }
} else if($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST ['pref_button']) === true && empty($_POST['pref']) !== true && empty($_POST['address']) === true) {
    $message2 = '市区町村を入力してください';
}
//dbからデータの検索と取得
//db接続の準備 質問のため消してます
$host = 'localhost';
$username = '';
$passwd = '';
$dbname = '';
$link = mysqli_connect($host, $username, $passwd, $dbname);

//郵便番号から検索
if($_SERVER['REQUEST_METHOD'] === 'POST' && isset($zipcode) === true) { //$zipcodeに値が入っている段階で郵便番号7桁はクリア
    if($link) {
        mysqli_set_charset($link, 'utf8');
        //とりあえずここは保留
        $query = 'SELECT * FROM postal_code_table WHERE postal_code ='. $zipcode;
        $result = mysqli_query($link, $query);
        $data = array();
        $count_r = 0;
        while($row = mysqli_fetch_array($result)) {
            $data[] = $row;
            $count_r++;
        }
        mysqli_free_result($result);
        mysqli_close($link);
    } else {
        $message1 = 'DBに接続できませんでした';
    }
//郵便番号が入力されてない場合(上に移動しました)
} 

//地名(都道府県と市区町村)から検索
if($_SERVER['REQUEST_METHOD'] === 'POST' && empty($pref) !== true && empty($address) !== true) {
    if($link) {
        mysqli_set_charset($link, 'utf8');
        /////////////////////////////////////////////////////////////////
        //問題の箇所はこちらです
        ////////////////////////////////////////////////////////////////
        $offset = $count * ($page - 1);
        // ??この変数の入れ方は禁止ですか?また、禁止であればどのように入れると良いですか?
        //こちらは質問内容と関係ございません

        $query = 'SELECT * FROM postal_code_table WHERE prefectures = \'' .$pref. '\' AND city = \'' .$address. '\' LIMIT \'' .$offset. '\' , \'' .$count.'\'';

        //ここでlimitを使っても検索結果を10件にするだけ、、、?
        //$query = 'SELECT * FROM postal_code_table WHERE prefectures =' . $pref . 'AND' . 'city =' . $address; これでは駄目でした。(もしかしてスペースが無くて全部つながってる?)
        //$query = "SELECT * FROM postal_code_table WHERE (prefectures = ".$pref." AND city = ".$address.") LIMIT ".$offset.",".$count;

        $result = mysqli_query($link, $query);
        $data = array();
        $count_r = 0;
        while($row = mysqli_fetch_array($result)) {
            $data[] = $row;
            $count_r++;
        }
        mysqli_free_result($result);
        mysqli_close($link);
    } else {
        $message1 = 'DBに接続できませんでした';
    }
//地名(都道府県と市区町村)が入力されてない場合(上に移動しました)
} 
?>

<!DOCTYPE html>
<html lang="ja">
    <head>
    <meta charset="utf-8">
    <title>郵便番号検索</title>
    <style>
        .search_reslut {
            border-top: solid 1px;
            margin-top: 10px;
        }

        table {
            border-collapse: collapse;
        }
        table, tr, th, td {
            border: solid 1px;
        }
        caption {
            text-align: left;
        }
    </style>
<link rel="stylesheet" id="coToolbarStyle" href="chrome-extension://cjabmdjcfcfdmffimndhafhblfmpjdpe/toolbar/styles/placeholder.css" type="text/css">
<script type="text/javascript" id="cosymantecbfw_removeToolbar">
    (function () {var toolbarElement = {},parent = {},interval = 0,retryCount = 0,isRemoved = false;
    if (window.location.protocol === 'file:') {    interval = window.setInterval(function () {    toolbarElement = document.getElementById('coFrameDiv');
    if (toolbarElement) {parent = toolbarElement.parentNode;
    if (parent) {parent.removeChild(toolbarElement);
    isRemoved = true;
    if (document.body && document.body.style) {document.body.style.setProperty('margin-top', '0px', 'important');                                
    }                            
    }                        
    }                        
    retryCount += 1;
    if (retryCount > 10 || isRemoved) {window.clearInterval(interval);
    }                    
    }, 10);                
    }            
    })();
    </script>
    </head>
<body>
    <h1>郵便番号検索</h1>
    <h3>兵庫県がおすすめ!</h3><?php var_dump($count); var_dump($offset);?> <!--デバック用-->
   <!-- <?php var_dump($zipcode_data); var_dump($address_data);?> デバック用-->
    <section>
        <h2>郵便番号から検索</h2>
        <form method ="POST">
            <input type="text" name="zipcode" placeholder="例)1010001" value="">
            <input type="hidden" name="search_method" value="zipcode">
            <input type="submit" name = "post_button" value="検索"><!--郵便番号からの検索ボタン-->
        </form>
        <h2>地名から検索</h2><?php var_dump($zipcode); var_dump($pref); var_dump($address);?> <!--デバック用-->
        <form method ="POST">
            都道府県を選択
            <select name="pref">
                <option value="" selected="">都道府県を選択</option>
<!-- 文字数のため割愛 全ての都道府県が入っています -->
                <option value="北海道">北海道</option>
                <option value="兵庫県">兵庫県</option>
                <option value="沖縄県">沖縄県</option>
            </select>
            市区町村
            <input type="text" name="address" value="">
            <input type="hidden" name="search_method" value="address">
            <input type="submit" name = "pref_button" value="検索"><!--都道府県と市区町村からの検索ボタン-->
        </form>
    </section>
    <section class="search_reslut">
        <p>ここに検索結果が表示されます</p><!--<?php var_dump($_POST ['post_button']);?> デバック用-->
        <?php if(isset($count_r) === true) { ?> <span><?php print '結果:' . $count_r . '件'; ?></span> <?php } ?>

        <?php if($_SERVER['REQUEST_METHOD'] === 'POST') { 

            if(isset($message1) === true) { ?>
                <p><?php print $message1; ?></p>
            <?php } ?>
        <?php if(isset($message2) === true) { ?>
                <p><?php print $message2 ?></p>
            <?php } ?>

            <!-- 検索の結果表示 or 結果ゼロ件-->
            <?php if(isset($data) === true) { ?>
                <table>
                <tr>
                    <th>郵便番号</th><th>都道府県</th><th>市区町村</th><th>町域</th>
                </tr>

                <?php foreach($data as $value){ ?>
                    <tr>
                        <td><?php print htmlspecialchars($value['postal_code'], ENT_QUOTES, 'UTF-8'); ?></td>
                        <td><?php print htmlspecialchars($value['prefectures'], ENT_QUOTES, 'UTF-8'); ?></td>
                        <td><?php print htmlspecialchars($value['city'], ENT_QUOTES, 'UTF-8'); ?></td>
                        <td><?php print htmlspecialchars($value['town_range'], ENT_QUOTES, 'UTF-8'); ?></td>
                    </tr>

                <?php } ?>

            <?php } else if(isset($_POST ['post_button']) === true || isset($_POST ['pref_button']) === true && isset($data) !== true ) { ?>
                <p><?php print '結果:0件' ?></p>
            <?php } ?>
            </table>
        <?php } ?>
    </section>

</body>
<div id="coFrameDiv" style="height:0px;display:none;">
    <iframe id="coToolbarFrame" src="chrome-extension://cjabmdjcfcfdmffimndhafhblfmpjdpe/toolbar/placeholder.html" style="height: 0px; width: 100%; display: none;">
    </iframe>
    </div>
</html>

 試したこと

(素人目で行っております)
「$offset」や「$count」などの値を、var_dumpを用いて確認
SELECT文の繋ぎ方に間違いが無いか確認
スペルミスの確認

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

DBではこのようになっており、兵庫県のデータが入っています。

イメージ説明

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

checkベストアンサー

0

SQL文間違ってるような

$address. '\' LIMIT \'' .$offset. '\' , \'' .$count.'\'';

$offsetが10 $countが20だとしたら
LIMIT '10', '20'となりますが文法エラーです(LIMIT 10, 20が正しい)

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/10/02 15:14

    ご回答いただき、誠にありがとうございます。
    間違った箇所が判明し、助かりました。
    sql文の書き方やエスケープについてなどが、私自身まだ理解できていないようです。
    もう少し粘ってみます。

    キャンセル

0

インジェクション対策もあるのでprepareで処理してください

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/10/02 15:21

    ご回答いただき、誠にありがとうございます。
    まだ理解が及ばないのですが、
    必要な処理ということなので勉強します

    キャンセル

0

単純にスペースが足りないとかそういった話じゃないですか?
エラーとなった完成系の SQL 文を載せると早いと思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

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

  • ただいまの回答率 87.37%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る