我在使用SQL查询(嵌套在PHP中)时遇到问题,在Firefox和IE中无法正常工作,但在Chrome中工作正常。
当我切换WP主题时,功能似乎也有所不同。不好的结果是当查询不起作用并且结果显示数据库中的所有记录时。当我更改主题(更改为Nisarg)时,查询效果更好,但随后在后退按钮上显示了“文档过期”页面。这一切在Chrome中均不会发生,而Firefox中的问题是间歇性的-有时可以正常工作,有时会挂起并返回数据库中的所有项目。
注意:查询上一个查询的结果时会发生这种情况。任何想法从哪里开始?
更新:我将其范围缩小到只能在WP Nisarg主题中正常工作。如果更改主题并清除缓存,则查询将不起作用。我认为与$ _SESSION名称不是来自原始搜索页面的原因有关。
以下是初始查询的结果页以及附加查询的以下代码。谢谢大家!
<?php
//header('Cache-Control: no cache'); //no cache
//session_cache_limiter('private_no_expire'); // works
header('Cache-Control: no cache'); //no cache
session_cache_limiter('private_no_expire'); // works
session_start();
// These are external files.
// In order to protect the database/application from SQL injections, you should be using prepared statements.
// MySQLi is capable of this, but PDO has a lot more flexibility, in my opinion, so I went with PDO instead.
//
// Here are two links explaining how to use PDO:
// https://phpdelusions.net/pdo
// http://www.phptherightway.com/#pdo_extension
// external_db.php contains credentials for the rock database, and builds the MyPDO class for the rest of the operations.
require ('rock_config.php');
// cast each of the posted variables as an integer, just to make it easier to recognize unselected entries for when we
// build the SQL statement in the next steps.
$p['rockNameId'] = (int)$_POST['rock-name'];
$p['districtId'] = (int)$_POST['district'];
$p['mineId'] = (int)$_POST['mine'];
$p['depositTypeId'] = (int)$_POST['deposit-type'];
$p['mineralId'] = (int)$_POST['mineral'];
if (!isset($_SESSION["pageVisited"])){
echo "problem";
}
if(strcmp($_SESSION["pageVisited"], "rock_results") == 0){
$p['rockNameId'] = 0;
$p['districtId'] = 0;
$p['mineId'] = 0;
$p['depositTypeId'] = 0;
$p['mineralId'] = 0;
$p[$_GET['dt']] = (int)$_GET['dv'];
}
$_SESSION["pageVisited"] = "rock_results";
// This is the building block of the select query.
// The where clause(s) gets added dynamically based on user selections
// Further, this can turn into a subquery in the event someone chooses to search by mineral.
$sql = "SELECT s.*, rn.rockName, d.district, m.mine, dt.depositType, gl.geolocation
FROM specimens s
LEFT JOIN rockNames rn ON s.rockNameId = rn.rockNameId
LEFT JOIN districts d ON s.districtId = d.districtId
LEFT JOIN mines m ON s.mineId = m.mineId
LEFT JOIN depositTypes dt ON s.depositTypeId = dt.depositTypeId
LEFT JOIN geoLocations gl ON s.geolocationId = gl.geolocationId";
// This is to track whether a WHERE clause has already been inserted into the query. If it's 0, then use WHERE,
// if it's 1, then use AND instead.
$vars = 0;
// Add seach clauses dynamically, with parameters that will be bound in later.
// Bound parameters can help prevent SQL injections, whether intentional or accidental.
if($p['rockNameId'] > 0) {
if($vars == 0) {
$operator = 'WHERE ';
// set vars to 1 so that the rest of the search criteria is added with AND rather than WHERE
$vars = 1;
} else {
$operator = ' AND ';
}
$sql .= "\n" . $operator . "s.rockNameId = :rockNameId";
}
if($p['districtId'] > 0) {
if($vars == 0) {
$operator = 'WHERE ';
// set vars to 1 so that the rest of the search criteria is added with AND rather than WHERE
$vars = 1;
} else {
$operator = ' AND ';
}
$sql .= "\n" . $operator . 's.districtId = :districtId';
}
if($p['mineId'] > 0) {
if($vars == 0) {
$operator = 'WHERE ';
// set vars to 1 so that the rest of the search criteria is added with AND rather than WHERE
$vars = 1;
} else {
$operator = ' AND ';
}
$sql .= "\n" . $operator . 's.mineId = :mineId';
}
if($p['depositTypeId'] > 0) {
if($vars == 0) {
$operator = 'WHERE ';
// set vars to 1 so that the rest of the search criteria is added with AND rather than WHERE
$vars = 1;
} else {
$operator = ' AND ';
}
$sql .= "\n" . $operator . 's.depositTypeId = :depositTypeId';
}
// BUILD COMPLEX QUERY
// If a user is searching for deposits containing a specific mineral, it wraps the previously generated query
// inside of a new query. This will be fine for a database of this size. If it ever grew to hundreds of thousands
// of records, you MIGHT need to rewrite it, but that's probably not going to be an outcome anytime soon.
if($p['mineralId'] > 0) {
$sql = "SELECT DISTINCT m.*, sm.*, s.*
FROM minerals m
LEFT JOIN specimensMinerals sm ON m.mineralId = sm.mineralId
INNER JOIN (
" . $sql . "
) s ON sm.specimenId = s.specimenId
WHERE m.mineralId = :mineralId";
}
// PREPARE THE SQL STATEMENT FOR EXECUTION
$stmt = $pdo->prepare($sql);
// BIND EACH PARAMTER TO THE QUERY.
// Using the same logic as when we built the query above, we're just binding the same
// parameters as will be used in our query.
if($p['rockNameId'] > 0) {
$stmt->bindParam(':rockNameId', $p['rockNameId'], PDO::PARAM_INT);
}
if($p['districtId'] > 0) {
$stmt->bindParam(':districtId', $p['districtId'], PDO::PARAM_INT);
}
if($p['mineId'] > 0) {
$stmt->bindParam(':mineId', $p['mineId'], PDO::PARAM_INT);
}
if($p['depositTypeId'] > 0) {
$stmt->bindParam(':depositTypeId', $p['depositTypeId'], PDO::PARAM_INT);
}
if($p['mineralId'] > 0) {
$stmt->bindParam(':mineralId', $p['mineralId'], PDO::PARAM_INT);
}
// EXECUTE THE QUERY
$stmt->execute();
// ROW COUNT
$count = $stmt->rowCount();
// QUERY RESULT
// This is an array, which you can traverse using foreach($results as $r), for example
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>