php - 修复准备好的声明

标签 php mysql sql

我有两个问题:

  1. 有没有更简洁的方法让我执行这个准备好的语句?似乎这里发生了很多事情。

  2. 您能否解决代码中“我如何清理它”的部分?我想确保它的安全。

顺便说一句,这一切似乎工作得很好。只是想稍微修复一下。

<?php
session_start();
require_once './config/config.php';
require_once 'includes/auth_validate.php';
include_once 'includes/header.php';
error_reporting (E_ALL ^ E_NOTICE); 

//ONLY SUPER AND ADMINS ARE ALLOWED TO ACCESS THIS PAGE 
if ($_SESSION['admin_type'] !=='admin' && $_SESSION['admin_type']  !=='super') {
    $_SESSION['admin_type'] = "undefined";
    echo 'Permission Denied';
    exit();
}

// How can I sanatize this
$customer_id = filter_input(INPUT_GET, 'customer_id', FILTER_VALIDATE_INT);
$operation = filter_input(INPUT_GET, 'operation',FILTER_SANITIZE_STRING); 
($operation == 'edit') ? $edit = true : $edit = false;
 $db = getDbInstance();

$cid = htmlentities ($_GET['customer_id']);
$sql = "SELECT  
        (SELECT treatment_log.bdi FROM treatment_log LEFT JOIN customers ON treatment_log.treatment_fk=customers.id WHERE treatment_log.created_at=(SELECT      MIN(created_at) FROM treatment_log WHERE treatment_fk = ?) AND customers.id = ?) AS first_bdi,   
        
        (SELECT treatment_log.pain FROM treatment_log LEFT JOIN customers ON treatment_log.treatment_fk=customers.id WHERE treatment_log.created_at=(SELECT      MIN(created_at) FROM treatment_log WHERE treatment_fk = ?) AND customers.id = ?) AS first_pain,
        
        (SELECT treatment_log.suicidality FROM treatment_log LEFT JOIN customers ON treatment_log.treatment_fk=customers.id WHERE treatment_log.created_at=(SELECT MIN(created_at) FROM treatment_log WHERE treatment_fk = ?) AND customers.id = ?) AS first_suicidality,  
        
        (SELECT treatment_log.bdi FROM treatment_log LEFT JOIN customers ON treatment_log.treatment_fk=customers.id WHERE treatment_log.created_at=(SELECT MAX(created_at) FROM treatment_log WHERE treatment_fk = ?) AND customers.id = ?) AS last_bdi,         
        
        (SELECT treatment_log.pain FROM treatment_log LEFT JOIN customers ON treatment_log.treatment_fk=customers.id WHERE treatment_log.created_at=(SELECT MAX(created_at) FROM treatment_log WHERE treatment_fk = ?) AND customers.id = ?) AS last_pain,      
        
        (SELECT treatment_log.suicidality FROM treatment_log LEFT JOIN customers ON treatment_log.treatment_fk=customers.id WHERE treatment_log.created_at=(SELECT MAX(created_at) FROM treatment_log WHERE treatment_fk = ?) AND customers.id = ?) AS last_suicidality,    
        
        (SELECT CAST(treatment_log.created_at as DATE) FROM treatment_log LEFT JOIN customers ON treatment_log.treatment_fk = customers.id WHERE treatment_log.created_at = (SELECT MAX(created_at) FROM treatment_log WHERE treatment_fk = ?)AND customers.id = ?) AS last_visit,  
        
        (SELECT COUNT(*) FROM treatment_log WHERE treatment_fk = ?) AS completed_treatments,
        (SELECT COUNT(*) FROM treatment_log WHERE treatment_fk = ? AND missed_treatment='yes') AS number_of_missed_treatments,
        (SELECT COUNT(*) FROM bdi WHERE bdi_fk = ?) AS completed_bdis,
        
        (SELECT customers.f_name FROM customers WHERE customers.id = ?) AS f_name,
        (SELECT customers.l_name FROM customers WHERE customers.id = ?) AS l_name,
        (SELECT customers.status FROM customers WHERE customers.id = ?) AS status,
        (SELECT customers.mrn FROM customers WHERE customers.id = ?) AS mrn,
        (SELECT customers.ohip FROM customers WHERE customers.id = ?) AS ohip,
        (SELECT customers.sex FROM customers WHERE customers.id = ?) AS sex,
        (SELECT customers.address FROM customers WHERE customers.id = ?) AS address,
        (SELECT customers.city FROM customers WHERE customers.id = ?) AS city,
        (SELECT customers.postal_code FROM customers WHERE customers.id = ?) AS country,
        (SELECT customers.phone FROM customers WHERE customers.id = ?) AS phone,
        (SELECT customers.about FROM customers WHERE customers.id = ?) AS about,
        (SELECT customers.date_of_birth FROM customers WHERE customers.id = ?) AS date_of_birth,
        (SELECT customers.protocol FROM customers WHERE customers.id = ?) AS protocol,
        (SELECT customers.treatment_location FROM customers WHERE customers.id = ?) AS treatment_location,
        (SELECT customers.area FROM customers WHERE customers.id = ?) AS area,
        (SELECT customers.dx FROM customers WHERE customers.id = ?) AS dx,
        (SELECT customers.room FROM customers WHERE customers.id = ?) AS room,
        (SELECT customers.coil FROM customers WHERE customers.id = ?) AS coil,
        (SELECT customers.target_threshold FROM customers WHERE customers.id = ?) AS target_thresold,
        (SELECT customers.number_of_treatments FROM customers WHERE customers.id = ?) AS number_of_treatments,
        (SELECT customers.motor_threshold FROM customers WHERE customers.id = ?) AS motor_threshold,
        (SELECT customers.threshold_multiplier FROM customers WHERE customers.id = ?) AS threshold_multiplier,
        (SELECT customers.created_at FROM customers WHERE customers.id = ?) AS created_at,
        (SELECT customers.updated_at FROM customers WHERE customers.id = ?) AS updated_at;";     

$stmt = mysqli_stmt_init($conn);
mysqli_stmt_prepare($stmt, $sql);
mysqli_stmt_bind_param($stmt, "iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii", $cid, $cid, $cid, $cid, $cid, $cid, $cid, $cid, $cid, $cid, $cid, $cid, $cid, $cid, $cid, $cid, $cid, $cid, $cid, $cid, $cid, $cid, $cid, $cid, $cid, $cid, $cid, $cid, $cid, $cid, $cid, $cid, $cid, $cid, $cid, $cid, $cid, $cid, $cid, $cid, $cid);
mysqli_stmt_execute($stmt);
$result = mysqli_stmt_get_result($stmt);        

?>

最佳答案

如评论所述,htmlentities() 与防止 SQL 注入(inject)无关。当你想输出一些内容到 HTML,并且你想避免 XSS 漏洞时使用它。

我不会将所有这些查询都写成单独的子查询。您不太可能需要通过单个 SQL 语句获取所有信息。试图将如此多的工作塞进单个 SQL 调用并不能显着提高效率,但它确实使您编写代码变得更加困难。

记住这个智慧:

Everyone knows that debugging is twice as hard as writing a program in the first place. So if you're as clever as you can be when you write it, how will you ever debug it?

下面是我将如何编写代码:

如果您使用参数化查询,则完全没有必要进行清理。但如果您愿意,这里有一种更简单的方法:

$customer_id = (int) $_GET['customer_id'];

是的!只需转换为 (int)。编写此代码很简单,在代码审查中也很容易解释,而且执行速度比函数调用快。

然后将 SQL 分成几个查询,以合理的方式将它们分组,这样您就不需要子查询或列别名。更简单的查询更容易编写代码、更容易调试、更容易修改(如果您以后需要这样做)(或者如果其他开发人员需要修改它,他们会感谢您编写更易于处理的代码)。

获得首次访问的一个简单方法是按 created_at 排序并使用 LIMIT 1。

$sql = "SELECT bdi, pain, suicidality FROM treatment_log WHERE treatment_fk = ?  
  ORDER BY created_at LIMIT 1";
$stmt = $conn->prepare($sql);
$stmt->bind_param("i", $customer_id);
$stmt->execute();
$rows1 = $stmt->fetch_all(MYSQLI_ASSOC);

获取上次访问 - 按 created_at 降序 排序并使用 LIMIT 1。

$sql = "SELECT bdi, pain, suicidality, DATE(created_at) AS last_visit 
  FROM treatment_log WHERE treatment_fk = ?
  ORDER BY created_at DESC LIMIT 1";
$stmt = $conn->prepare($sql);
$stmt->bind_param("i", $customer_id);
$stmt->execute();
$rows2 = $stmt->fetch_all(MYSQLI_ASSOC);

这是一个技巧:在 MySQL 中,true 为 1,false 为 0,因此您可以SUM() 1 作为计算某些表达式为 true 的行数的方法。

$sql = "SELECT COUNT(*) AS completed_treatments, 
    SUM(missed_treatments='yes') AS number_of_missed_treatments 
  FROM treatment_log WHERE treatment_fk = ?";
$stmt = $conn->prepare($sql);
$stmt->bind_param("i", $customer_id);
$stmt->execute();
$rows3 = $stmt->fetch_all(MYSQLI_ASSOC);

其他查询非常简单。

$sql = "SELECT COUNT(*) AS completed_bdis FROM bdi WHERE bdi_fk = ?";
$stmt = $conn->prepare($sql);
$stmt->bind_param("i", $customer_id);
$stmt->execute();
$rows4 = $stmt->fetch_all(MYSQLI_ASSOC);

$sql = "SELECT f_name, l_name, status, mrn, ohip, sex, address, city, country, 
    phone, about, date_of_birth, protocol, treatment_location, area, dx, room, 
    coil, target_threshold, number_of_treatments, motor_threshold, 
    threshold_multiplier, created_at, updated_at
  FROM customers WHERE id = ?";
$stmt = $conn->prepare($sql);
$stmt->bind_param("i", $customer_id);
$stmt->execute();
$rows5 = $stmt->fetch_all(MYSQLI_ASSOC);

在所有这些查询中,我们只需要为每个查询绑定(bind)一次$customer_id,这使得编写这段代码变得更加容易。无需让自己眼睛疲劳地计算长“iiii...”字符串的长度并将其与参数数量相匹配。

P.S.:我没有测试这段代码,所以如果有错别字,我相信你能解决。

关于php - 修复准备好的声明,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54174501/

相关文章:

MySQL - 查找用户的第一个推荐人

sql - 使用 SSIS 的每周销售总额事实表

php - 为什么计算 1/(n * log(n) - n) 会破坏计算机?

php - 动态 PHP 表过滤和排序

mysql - 比较日期时间不起作用

mysql - 未使用 mysql 注释(<- 未声明)

python - 将从第一个表获取的行值与第二个表的列名匹配,无需循环

SQL - 使用 2 列中的值进行选择,这两个列至少应出现一次

php - 强制一个数组至少有一个项目,每个项目都有一个特定的值

PHP仅在页面完全加载时解析HTML页面