phpとmysqlでページング機能を用いたデータの検索ページを作成しています。
limit offset句を使いフォームから入力したデータ(緯度経度の値)に合致するデータを1件ずつ表示させていくようなプログラムを目指して作成しているのですがページを更新しても表示データが変わりません。おそらくlimit offset句の扱い方が違うと予想しているのですが改善案が見つかりません。ご教授の方よろしくお願いいたします。
<html>
<title>表示結果</title>
<body>
<fieldset>
<legend>コメント</legend>
<?php
//データベースに接続する変数名を宣言しておく
define( 'DB_HOST', '' );
define( 'DB_USER', '' );
define( 'DB_PASS', '' );
define( 'DB_NAME', '' );
//-----ページング機能
$form_lon = $_REQUEST['longitude'];
$form_lat = $_REQUEST['latitude'];
//$GLOBALS["offset"] = 0;
$p=0;
if(isset($_GET['page'])){
if(is_numeric($_GET['page'])){
$p=$_GET['page'];
//$GLOBALS["offset"]= $p;
}
}
$com_longitude = $form_lon;
$com_latitude = $form_lat;
//-----下の2つの関数を使い、緯度軽度に合致したテキストを表示する。
CallImg($com_longitude,$com_latitude);
//-----指定した緯度経度を持つテキストを表示する関数
function CallImg($longitude_num,$latitude_num){
print TextSearchDB($longitude_num,$latitude_num);
echo nl2br("\n");
}
//-----データベースから、指定した緯度経度を持つテキストファイルを検索する関数。
function TextSearchDB($longitude_num,$latitude_num){
$com_longitude_minus = $longitude_num - 0.0005;
$com_longitude_plus = $longitude_num + 0.0005;
$com_latitude_minus = $latitude_num - 0.0005;
$com_latitude_plus = $latitude_num + 0.0005;
//-----データベースへ接続する
$db_link1 = mysqli_connect(DB_HOST, DB_USER, DB_PASS, DB_NAME);
$offset = $GLOBALS["offset"];
echo $offset;
//-----指定した緯度経度のテキストを検索
$serch_query1 = mysqli_query($db_link1,"SELECT * FROM `img_table` WHERE (`longitude` BETWEEN '".$com_longitude_minus."' AND '".$com_longitude_plus."') AND (`latitude` BETWEEN '".$com_latitude_minus."' AND '".$com_latitude_plus."') ORDER BY `id_col` ASC LIMIT 1 OFFSET 0");
$row_lon = mysqli_fetch_array($serch_query1);
echo $row_lon['comment'];
$close_flag1 = mysqli_close($db_link1);
}
?>
</fieldset>
<br>
<fieldset>
<legend>画像</legend>
<!--<img src="image.php">-->
</fieldset>
<a href="?page= <?php echo $p+1;?> &longitude= <?php print($form_lon);?> &latitude= <?php print($form_lat);?>">次へ</a>
</body>
</html>
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
+1
PDOで書いていますが、SQL部分はこちら参考になるかもしれません。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
+1
phpを実行環境が無いので、正しいか分かりませんが、
SQLの所を以下のように修正したらどうでしょうか
LIMIT 1 OFFSET 0 -> LIMIT $offset, 1
LIMIT 1 OFFSET 0
だと、常に最初の1件を取得 となっているように思います
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
+1
まず、ページングの区切り方を考えます。例えば、データが5件で2件ずつ(LIMIT 2)表示する時のロジックを考えてみます。
//---- 1ページ目 ----
OFFSET == 0 //←ここが欲しい
OFFSET == 1
//---- 2ページ目 ----
OFFSET == 2 //←ここが欲しい
OFFSET == 3
//---- 3ページ目 ----
OFFSET == 4 //←ここが欲しい
ページが$page = n
の時のオフセット$offset
を求めるには下記のように書けます。
※注意
$offset <= $total - 1 (オフセットはデータ件数-1以下)
例えば、4ページしかないのに5ページ目にアクセスした場合を考慮しなければなりません。
//オフセット初期値
$offset = 0;
//2件ずつ表示
$limit = 2;
if ($page > 0) {
$offset = ($page - 1) * $limit;
}
下記はページングを組み込んだサンプルです。質問にあるようにページングリンクは前後1つのみを考慮しています。複数ページングリンクを表示する場合は、もう少し複雑です。
XSSとSQLインジェクションを考慮して、filter_input()
とmysqli_stmt_init()
を使うコードにしてあります。
また、$form_lon,$form_lat は TextSearchDB() の引数になっていますが、同じくDBパラメーターの $offset,$limit が引数でなかったので関数の引数に変更してあります。
PDO
と違ってMysqli
でmysqlnd
ドライバが使えない場合バインドしてからのデータ取得が非常に面倒ですが、mysqlnd ドライバが使える場合は非常に簡単です。
//-----ページング機能
$form_lon = filter_input(INPUT_GET, 'longitude', FILTER_SANITIZE_NUMBER_FLOAT);
$form_lat = filter_input(INPUT_GET, 'latitude', FILTER_SANITIZE_NUMBER_FLOAT);
$offset = 0;
$limit = 1;
//ページ番号取得
$p = (int)filter_input(INPUT_GET, 'page', FILTER_SANITIZE_NUMBER_INT);
$p = $p < 1 ? 1 : $p;
//オフセット決定
$offset = ($p - 1) * $limit;
//グローバルに保存(TextSearchDB()の引数に変更)
//$GLOBALS['limit'] = $limit;
//$GLOBALS['offset'] = $offset;
//...
//-----データベースから、指定した緯度経度を持つテキストファイルを検索する関数。
function TextSearchDB($longitude_num, $latitude_num, $limit, $offset)
{
//...
//プリペアードステートメント
$stmt = mysqli_stmt_init($db_link1);
//データ件数を取得
mysqli_stmt_prepare($stmt, "SELECT count(*) FROM `img_table` WHERE (`longitude` BETWEEN ? AND ?) AND (`latitude` BETWEEN ? AND ?)");
mysqli_stmt_bind_param($stmt, 'ssss', $com_longitude_minus, $com_longitude_plus, $com_latitude_minus, $com_latitude_plus);
mysqli_stmt_execute($stmt);
mysqli_stmt_bind_result($stmt, $total);
mysqli_stmt_fetch($stmt);
mysqli_stmt_free_result($stmt);
$result = array();
//データ件数以上の時(データがゼロ件の時、4ページのみで5ページ目にアクセスした場合)
if ($offset > $total - 1) {
echo '';
return $result;
}
//-----指定した緯度経度のテキストを検索
mysqli_stmt_prepare($stmt, "SELECT * FROM `img_table` WHERE (`longitude` BETWEEN ? AND ?) AND (`latitude` BETWEEN ? AND ?) ORDER BY `id_col` ASC LIMIT ? OFFSET ?");
mysqli_stmt_bind_param($stmt, 'ssssii', $com_longitude_minus, $com_longitude_plus, $com_latitude_minus, $com_latitude_plus, $limit, $offset);
mysqli_stmt_execute($stmt);
//**** mysqlndが使える場合 ****
$rs = mysqli_stmt_get_result($stmt);
while ($row_lon = mysqli_fetch_array($rs)) {
echo $row_lon['comment'];
$result[] = $row_lon;
}
/*
//**** mysqlndが使えない場合 ****
//bind_result() のためのカラム名をすべて取得
$meta = mysqli_stmt_result_metadata($stmt);
$args = [$stmt];
while ($field = mysqli_fetch_field($meta)) {
$args[] = &$column[$field->name];
}
//一気にバインド
call_user_func_array('mysqli_stmt_bind_result', $args);
//DBデータ取得
while (mysqli_stmt_fetch($stmt)) {
$row_lon = array();
foreach($column as $k => $v) {
$row_lon[$k] = $v;
}
echo $row_lon['comment'];
$result[] = $row_lon;
}
*/
mysqli_stmt_free_result($stmt);
mysqli_stmt_close($stmt);
mysqli_close($db_link1);
return $result;
}
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 91.05%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
2018/01/10 01:35
こちらのページを見つけて参考にさせていただいているのですがこちらでも実装は可能でしょうか。
https://qiita.com/tabo_purify/items/fb902956c1e1a3c75041
2018/01/10 01:42 編集
ただし、PHPのバージョンによってはエラーになる記述が散見されます。
2018/01/10 01:49
開発環境はxamppを使用しておりphpのバージョンは7.1.11となっております。