如何从数据库中回显具有特定变量的行
Posted
技术标签:
【中文标题】如何从数据库中回显具有特定变量的行【英文标题】:How do I echo rows that have a specific variable in it from Database 【发布时间】:2017-12-18 22:16:02 【问题描述】:所以首先我的数据库表是这样设置的:
标识 |关注 |报价名称 |日期 |时间 |支付
1 |字符串这里 |报价 | 2017-09-12 | 06:47:00 | 1
我想将所有包含 affsub 字符串的行都回显到一个 html 表中。我试过这个:
<?php
$id = $get_info_id;
$mysqli = new \mysqli('localhost', 'user', 'pass', 'db');
$aff = $mysqli->query("SELECT affsub FROM users WHERE id = $id")->fetch_object()->affsub;
$affsub = $aff;
$userinfo= $mysqli->query("SELECT offer_name, time, payout FROM conversions WHERE affsub = ". $affsub . "");
if ($userinfo->num_rows > 0)
while($row = $userinfo->fetch_assoc())
echo '<tr>
<td><b><color=black>' .$row['offer_name'].' </b></td>
<td><color=black>' .$row['time'].'</td>
<td>$<color=black>' .$row['payout'].'</td>
</tr>';
else
echo "<b><center>No Conversions Have Happened.</center></b>";
?>
我知道它正在获取 affsub,因为如果我回显 $affsub,我的 affsub 会被回显,但桌子上没有显示任何内容,我不确定发生了什么。
【问题讨论】:
您正在尝试将查询结果用作另一个查询中的 where 子句? $userinfo= $mysqli->query("SELECT offer_name, time, payout FROM Conversions WHERE affsub = ". $affsub . ""); 是的,因为我想使用用户的 id 并从另一个表中找到用户 affsub 并将其用于此表 @Accountantم 我修复了这个问题,但现在我该如何修复 sql 注入漏洞? 不需要,但谢谢。我将其发布为答案只是因为您需要一个示例并且因为这是您查看代码的最佳方式。所以不要接受。无论如何,请把conversions
表的列也贴出来。
不,那叫转义参数。如果您使用正确的数据库编码,它可以保护您免受 SQL 注入攻击。但我们人类通常会忘记逃避某些事情。这个question 是关于切换到准备好的语句。搜索主题并等待明天@aendeerei 示例
【参考方案1】:
请注意,我使用的 sql 语句的学分属于 @Barmar,因为他昨天首先想到了连接查询。
现在,下面是使用的两种方法。请注意,我没有使用任何 OOP 或函数。原因是我希望您对所有步骤有一个简洁的了解。
如何使用mysqli预处理语句及异常处理
1。使用 get_result() + fetch_object() 或 fetch_array() 或 fetch_all():
此方法(推荐)仅在安装/激活驱动程序 mysqlnd (MySQL Native Driver) 时有效。我认为驱动程序默认在 PHP >= 5.3 中激活。实现代码并让它运行。它应该工作。如果它有效,那么它是完美的。如果没有,请尝试激活 mysqlnd 驱动程序,例如在 php.ini 中取消注释 extension=php_mysqli_mysqlnd.dll
。否则必须使用第二种方法(2)。
<?php
/*
* Define constants for db connection.
*/
define('MYSQL_HOST', '...');
define('MYSQL_PORT', '...');
define('MYSQL_DATABASE', '...');
define('MYSQL_CHARSET', 'utf8');
define('MYSQL_USERNAME', '...');
define('MYSQL_PASSWORD', '...');
/*
* Activate PHP error reporting.
* Use ONLY on development code, NEVER on production code!!!
* ALWAYS resolve WARNINGS and ERRORS.
* I recommend to always resolve NOTICES too.
*/
error_reporting(E_ALL);
ini_set('display_errors', 1);
/*
* Enable internal report functions. This enables the exception handling,
* e.g. mysqli will not throw PHP warnings anymore, but mysqli exceptions
* (mysqli_sql_exception). They are catched in the try-catch block.
*
* MYSQLI_REPORT_ERROR: Report errors from mysqli function calls.
* MYSQLI_REPORT_STRICT: Throw a mysqli_sql_exception for errors instead of warnings.
*
* See:
* http://php.net/manual/en/class.mysqli-driver.php
* http://php.net/manual/en/mysqli-driver.report-mode.php
* http://php.net/manual/en/mysqli.constants.php
*/
$mysqliDriver = new mysqli_driver();
$mysqliDriver->report_mode = (MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
try
// To delete (just for test here).
$get_info_id = 1;
$userId = $get_info_id;
$fetchedData = array();
/*
* Create the db connection.
*
* Throws mysqli_sql_exception.
* See: http://php.net/manual/en/mysqli.construct.php
*/
$connection = new mysqli(
MYSQL_HOST
, MYSQL_USERNAME
, MYSQL_PASSWORD
, MYSQL_DATABASE
, MYSQL_PORT
);
if ($connection->connect_error)
throw new Exception('Connect error: ' . $connection->connect_errno . ' - ' . $connection->connect_error);
/*
* The SQL statement to be prepared. Notice the so-called markers,
* e.g. the "?" signs. They will be replaced later with the
* corresponding values when using mysqli_stmt::bind_param.
*
* See: http://php.net/manual/en/mysqli.prepare.php
*/
$sql = 'SELECT
cnv.offer_name,
cnv.time,
cnv.payout
FROM conversions AS cnv
LEFT JOIN users AS usr ON usr.affsub = cnv.affsub
WHERE usr.id = ?';
/*
* Prepare the SQL statement for execution.
*
* Throws mysqli_sql_exception.
* See: http://php.net/manual/en/mysqli.prepare.php
*/
$statement = $connection->prepare($sql);
if (!$statement)
throw new Exception('Prepare error: ' . $connection->errno . ' - ' . $connection->error);
/*
* Bind variables for the parameter markers (?) in the
* SQL statement that was passed to mysqli::prepare. The first
* argument of mysqli_stmt::bind_param is a string that contains one
* or more characters which specify the types for the corresponding bind variables.
*
* See: http://php.net/manual/en/mysqli-stmt.bind-param.php
*/
$bound = $statement->bind_param('i', $userId);
if (!$bound)
throw new Exception('Bind error: The variables could not be bound to the prepared statement');
/*
* Execute the prepared SQL statement.
* When executed any parameter markers which exist will
* automatically be replaced with the appropriate data.
*
* See: http://php.net/manual/en/mysqli-stmt.execute.php
*/
$executed = $statement->execute();
if (!$executed)
throw new Exception('Execute error: The prepared statement could not be executed!');
/*
* Get the result set from the prepared statement. In case of
* failure use errno, error and/or error_list to see the error.
*
* NOTA BENE:
* Available only with mysqlnd ("MySQL Native Driver")! If this
* is not installed, then uncomment "extension=php_mysqli_mysqlnd.dll" in
* PHP config file (php.ini) and restart web server (I assume Apache) and
* mysql service. Or use the following functions instead:
* mysqli_stmt::store_result + mysqli_stmt::bind_result + mysqli_stmt::fetch.
*
* See:
* http://php.net/manual/en/mysqli-stmt.get-result.php
* https://***.com/questions/8321096/call-to-undefined-method-mysqli-stmtget-result
*/
$result = $statement->get_result();
if (!$result)
throw new Exception('Get result error: ' . $connection->errno . ' - ' . $connection->error);
/*
* Get the number of rows in the result.
*
* See: http://php.net/manual/en/mysqli-result.num-rows.php
*/
$numberOfRows = $result->num_rows;
/*
* Fetch data and save it into $fetchedData array.
*
* See: http://php.net/manual/en/mysqli-result.fetch-array.php
*/
if ($numberOfRows > 0)
/*
* Use mysqli_result::fetch_object to fetch a row - as object -
* at a time. E.g. use it in a loop construct like 'while'.
*/
while ($row = $result->fetch_object())
$fetchedData[] = $row;
/*
* Free the memory associated with the result. You should
* always free your result when it is not needed anymore.
*
* See: http://php.net/manual/en/mysqli-result.free.php
*/
$result->close();
/*
* Close the prepared statement. It also deallocates the statement handle.
* If the statement has pending or unread results, it cancels them
* so that the next query can be executed.
*
* See: http://php.net/manual/en/mysqli-stmt.close.php
*/
$statementClosed = $statement->close();
if (!$statementClosed)
throw new Exception('The prepared statement could not be closed!');
// Close db connection.
$connectionClosed = $connection->close();
if (!$connectionClosed)
throw new Exception('The db connection could not be closed!');
catch (mysqli_sql_exception $e)
echo 'Error: ' . $e->getCode() . ' - ' . $e->getMessage();
exit();
catch (Exception $e)
echo $e->getMessage();
exit();
/*
* Disable internal report functions.
*
* MYSQLI_REPORT_OFF: Turns reporting off.
*
* See:
* http://php.net/manual/en/class.mysqli-driver.php
* http://php.net/manual/en/mysqli-driver.report-mode.php
* http://php.net/manual/en/mysqli.constants.php
*/
$mysqliDriver->report_mode = MYSQLI_REPORT_OFF;
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Example code: Mysqli prepared statements & exception handling</title>
</head>
<style>
table
font-family: "Verdana", Arial, sans-serif;
font-size: 14px;
border-collapse: collapse;
table, th, td
border: 1px solid #ccc;
th, td
padding: 7px;
thead
color: #fff;
font-weight: normal;
background-color: coral;
tfoot
background-color: wheat;
tfoot td
text-align: right;
</style>
<body>
<?php
$countOfFetchedData = count($fetchedData);
if ($countOfFetchedData > 0)
?>
<table>
<thead>
<tr>
<th>Crt. No.</th>
<th>OFFER NAME</th>
<th>TIME</th>
<th>PAYOUT</th>
</tr>
</thead>
<tbody>
<?php
foreach ($fetchedData as $key => $item)
$offerName = $item->offer_name;
$time = $item->time;
$payout = $item->payout;
?>
<tr>
<td><?php echo $key + 1; ?></td>
<td><?php echo $offerName; ?></td>
<td><?php echo $time; ?></td>
<td><?php echo $payout; ?></td>
</tr>
<?php
?>
</tbody>
<tfoot>
<tr>
<td colspan="7">
- <?php echo $countOfFetchedData; ?> records found -
</td>
</tr>
</tfoot>
</table>
<?php
else
?>
<span>
No records found.
</span>
<?php
?>
</body>
</html>
注意:如何使用 fetch_array() 代替 fetch_object():
//...
if ($numberOfRows > 0)
/*
* Use mysqli_result::fetch_array to fetch a row at a time.
* e.g. use it in a loop construct like 'while'.
*/
while ($row = $result->fetch_array(MYSQLI_ASSOC))
$fetchedData[] = $row;
//...
在html代码中也做相应的修改。
注意:如何使用 fetch_all() 而不是 fetch_object():
//...
if ($numberOfRows > 0)
/*
* Use mysqli_result::fetch_all to fetch all rows at once.
*/
$fetchedData = $result->fetch_all(MYSQLI_ASSOC);
//...
在html代码中也做相应的修改。
2。使用 store_result() + bind_result() + fetch():
在没有驱动程序 mysqlnd(MySQL Native Driver)的情况下工作。
<?php
/*
* Define constants for db connection.
*/
define('MYSQL_HOST', '...');
define('MYSQL_PORT', '...');
define('MYSQL_DATABASE', '...');
define('MYSQL_CHARSET', 'utf8');
define('MYSQL_USERNAME', '...');
define('MYSQL_PASSWORD', '...');
/*
* Activate PHP error reporting.
* Use ONLY on development code, NEVER on production code!!!
* ALWAYS resolve WARNINGS and ERRORS.
* I recommend to always resolve NOTICES too.
*/
error_reporting(E_ALL);
ini_set('display_errors', 1);
/*
* Enable internal report functions. This enables the exception handling,
* e.g. mysqli will not throw PHP warnings anymore, but mysqli exceptions
* (mysqli_sql_exception). They are catched in the try-catch block.
*
* MYSQLI_REPORT_ERROR: Report errors from mysqli function calls.
* MYSQLI_REPORT_STRICT: Throw a mysqli_sql_exception for errors instead of warnings.
*
* See:
* http://php.net/manual/en/class.mysqli-driver.php
* http://php.net/manual/en/mysqli-driver.report-mode.php
* http://php.net/manual/en/mysqli.constants.php
*/
$mysqliDriver = new mysqli_driver();
$mysqliDriver->report_mode = (MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
try
// To delete (just for test here).
$get_info_id = 1;
$userId = $get_info_id;
$fetchedData = array();
/*
* Create the db connection.
*
* Throws mysqli_sql_exception.
* See: http://php.net/manual/en/mysqli.construct.php
*/
$connection = new mysqli(
MYSQL_HOST
, MYSQL_USERNAME
, MYSQL_PASSWORD
, MYSQL_DATABASE
, MYSQL_PORT
);
if ($connection->connect_error)
throw new Exception('Connect error: ' . $connection->connect_errno . ' - ' . $connection->connect_error);
/*
* The SQL statement to be prepared. Notice the so-called markers,
* e.g. the "?" signs. They will be replaced later with the
* corresponding values when using mysqli_stmt::bind_param.
*
* See: http://php.net/manual/en/mysqli.prepare.php
*/
$sql = 'SELECT
cnv.offer_name,
cnv.time,
cnv.payout
FROM conversions AS cnv
LEFT JOIN users AS usr ON usr.affsub = cnv.affsub
WHERE usr.id = ?';
/*
* Prepare the SQL statement for execution.
*
* Throws mysqli_sql_exception.
* See: http://php.net/manual/en/mysqli.prepare.php
*/
$statement = $connection->prepare($sql);
if (!$statement)
throw new Exception('Prepare error: ' . $connection->errno . ' - ' . $connection->error);
/*
* Bind variables for the parameter markers (?) in the
* SQL statement that was passed to mysqli::prepare. The first
* argument of mysqli_stmt::bind_param is a string that contains one
* or more characters which specify the types for the corresponding bind variables.
*
* See: http://php.net/manual/en/mysqli-stmt.bind-param.php
*/
$bound = $statement->bind_param('i', $userId);
if (!$bound)
throw new Exception('Bind error: The variables could not be bound to the prepared statement');
/*
* Execute the prepared SQL statement.
* When executed any parameter markers which exist will
* automatically be replaced with the appropriate data.
*
* See: http://php.net/manual/en/mysqli-stmt.execute.php
*/
$executed = $statement->execute();
if (!$executed)
throw new Exception('Execute error: The prepared statement could not be executed!');
/*
* Transfer the result set resulted from executing the prepared statement.
* E.g. store, e.g. buffer the result set into the (same) prepared statement.
*
* See:
* http://php.net/manual/en/mysqli-stmt.store-result.php
* https://***.com/questions/8321096/call-to-undefined-method-mysqli-stmtget-result
*/
$resultStored = $statement->store_result();
if (!$resultStored)
throw new Exception('Store result error: The result set could not be transfered');
/*
* Get the number of rows from the prepared statement.
*
* See: http://php.net/manual/en/mysqli-stmt.num-rows.php
*/
$numberOfRows = $statement->num_rows;
/*
* Fetch data and save it into $fetchedData array.
*
* See: http://php.net/manual/en/mysqli-result.fetch-array.php
*/
if ($numberOfRows > 0)
/*
* Bind the result set columns to corresponding variables.
* E.g. these variables will hold the column values after fetching.
*
* See: http://php.net/manual/en/mysqli-stmt.bind-result.php
*/
$varsBound = $statement->bind_result(
$resOfferName
, $resTime
, $resPayout
);
if (!$varsBound)
throw new Exception('Bind result error: The result set columns could not be bound to variables');
/*
* Fetch results from the result set (of the prepared statement) into the bound variables.
*
* See: http://php.net/manual/en/mysqli-stmt.fetch.php
*/
while ($row = $statement->fetch())
$fetchedObject = new stdClass();
$fetchedObject->offer_name = $resOfferName;
$fetchedObject->time = $resTime;
$fetchedObject->payout = $resPayout;
$fetchedData[] = $fetchedObject;
/*
* Frees the result memory associated with the statement,
* which was allocated by mysqli_stmt::store_result.
*
* See: http://php.net/manual/en/mysqli-stmt.store-result.php
*/
$statement->free_result();
/*
* Close the prepared statement. It also deallocates the statement handle.
* If the statement has pending or unread results, it cancels them
* so that the next query can be executed.
*
* See: http://php.net/manual/en/mysqli-stmt.close.php
*/
$statementClosed = $statement->close();
if (!$statementClosed)
throw new Exception('The prepared statement could not be closed!');
// Close db connection.
$connectionClosed = $connection->close();
if (!$connectionClosed)
throw new Exception('The db connection could not be closed!');
catch (mysqli_sql_exception $e)
echo 'Error: ' . $e->getCode() . ' - ' . $e->getMessage();
exit();
catch (Exception $e)
echo $e->getMessage();
exit();
/*
* Disable internal report functions.
*
* MYSQLI_REPORT_OFF: Turns reporting off.
*
* See:
* http://php.net/manual/en/class.mysqli-driver.php
* http://php.net/manual/en/mysqli-driver.report-mode.php
* http://php.net/manual/en/mysqli.constants.php
*/
$mysqliDriver->report_mode = MYSQLI_REPORT_OFF;
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Example code: Mysqli prepared statements & exception handling</title>
</head>
<style>
table
font-family: "Verdana", Arial, sans-serif;
font-size: 14px;
border-collapse: collapse;
table, th, td
border: 1px solid #ccc;
th, td
padding: 7px;
thead
color: #fff;
font-weight: normal;
background-color: coral;
tfoot
background-color: wheat;
tfoot td
text-align: right;
</style>
<body>
<?php
$countOfFetchedData = count($fetchedData);
if ($countOfFetchedData > 0)
?>
<table>
<thead>
<tr>
<th>Crt. No.</th>
<th>OFFER NAME</th>
<th>TIME</th>
<th>PAYOUT</th>
</tr>
</thead>
<tbody>
<?php
foreach ($fetchedData as $key => $item)
$offerName = $item->offer_name;
$time = $item->time;
$payout = $item->payout;
?>
<tr>
<td><?php echo $key + 1; ?></td>
<td><?php echo $offerName; ?></td>
<td><?php echo $time; ?></td>
<td><?php echo $payout; ?></td>
</tr>
<?php
?>
</tbody>
<tfoot>
<tr>
<td colspan="7">
- <?php echo $countOfFetchedData; ?> records found -
</td>
</tr>
</tfoot>
</table>
<?php
else
?>
<span>
No records found.
</span>
<?php
?>
</body>
</html>
最后,我建议您使用面向对象的方法,例如实现 MySQLiConnection 类(用于处理数据库连接)和 MySQLiAdapter 类(用于处理查询功能)。两个类都应该只实例化一次。 MySQLiConnection 应该作为构造函数参数传递给 MySQLiAdapter 类。 MySQLiAdapter 类需要一个 MySQLiConnection 类来查询数据库和接收结果。你也可以通过实现相应的接口来扩展它们的使用,但我尽量保持我的解释简单。
我还建议您使用 PDO 而不是 MySQLi。我在实现此代码时发现的原因之一是:MySQLi 中的异常处理系统颇具挑战性。
祝你好运!
【讨论】:
@awesomexbox3 欢迎您。尝试始终使用准备好的语句和异常处理。祝你好运。 @awesomexbox3 PS:您的表需要一些重构。两者在 id 列上应该是外键关系。 好的,但由于我使用用户管理框架,我应该摆脱 define('MYSQL_HOST', '...');定义('MYSQL_PORT', '...');定义('MYSQL_DATABASE','...');定义('MYSQL_CHARSET','utf8');定义('MYSQL_USERNAME','...');定义('MYSQL_PASSWORD', '...');并将其放入我的数据库文件中 这是最简单且安全的方法吗?还是有更简单的方法,因为我对什么 cnv 感到困惑。是? @awesomexbox3 是的,这些常量不应该在发生数据库连接的页面中定义。例如定义一个函数(可能在 Connection 类中)以连接到 db。然后,这些连接字符串变量应该被定义为函数的参数。喜欢public function connect($host, $port, $dbName,...)
。并且参数的值(“localhost”、“3306”、“db”、...)应该作为参数注入函数...【参考方案2】:
你应该简单地加入这两个查询:
$userinfo = $mysql->query("SELECT c.offer_name, c.time, c.payout
FROM conversations AS c
JOIN users AS u ON u.affsub = c.affsub
WHERE u.id = $id");
【讨论】:
【参考方案3】:我认为问题在于您在 WHERE 子句中缺少搜索词的引号。它应该看起来像这样 affsub = '$affsub' 。
试试这个。
$userinfo= $mysqli->query("SELECT offer_name, time, payout FROM conversions WHERE affsub = '$affsub' ");
【讨论】:
以上是关于如何从数据库中回显具有特定变量的行的主要内容,如果未能解决你的问题,请参考以下文章
在 WooCommerce 购物车中回显特定的产品属性和元数据
从返回前置响应的变量或对象中回显 PHP 中 JSON 字符串的一部分