Php 使用函数从数据库中获取内容。这安全吗?

Php 使用函数从数据库中获取内容。这安全吗?,php,mysql,pdo,Php,Mysql,Pdo,我有一个简单的问题。我还不太擅长编程,但这是安全和正确的吗 目前我正在使用各种功能获取用户名、头像等 看起来像这样: try { $conn = new PDO("mysql:host=". $mysql_host .";dbname=" . $mysql_db ."", $mysql_username, $mysql_password); // set the PDO error mode to exception $conn->setAttribute(

我有一个简单的问题。我还不太擅长编程,但这是安全和正确的吗

目前我正在使用各种功能获取用户名、头像等

看起来像这样:

    try {
    $conn = new PDO("mysql:host=". $mysql_host .";dbname=" . $mysql_db ."", $mysql_username, $mysql_password);
    // set the PDO error mode to exception
    $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $conn->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);


    }
catch(PDOException $e)
    {
    echo "Connection failed: " . $e->getMessage();
    }
config.php^^

function getUsername($userid) {
        require "config/config.php";
        $stmt = $conn->prepare("SELECT username FROM accounts WHERE id = ? LIMIT 1"); 
        $stmt->execute([$userid]); 
        $name = $stmt->fetch();
        return $name["username"];
    }
    function getProfilePicture($userid) {
            require "config/config.php";
            $stmt = $conn->prepare("SELECT profilepicture FROM accounts WHERE id = ? LIMIT 1"); 
            $stmt->execute([$userid]); 
            $image = $stmt->fetch();
            return $image["profilepicture"];
        }

这是正确的吗?更重要的是,这是安全的吗?

假设您的配置文件是正确的,它看起来会工作。因为这是一份事先准备好的声明,所以就安全性而言,它看起来不错

他们只传入id。要添加一些安全性,可以做的一件事是确保传入的$userid是正确的类型。(我假设为int)

例如,如果您希望输入一个整数ID,并且您得到一个可能是phishy(可能是SQL注入)的字符串,但是如果您可以确认它是int(如果不是,可能会抛出一个错误),那么您可以确保您得到了想要的

您可以使用:

is_int($userid);
确保它是一个int

有关is_int()的详细信息,请访问

希望这有帮助。

它是安全的(至少这部分代码,我不知道@icecub所指出的数据库连接部分),但您应该注意以下几点:

  • 您只需要在文件开始时
    require
    your
    config.php
    一次
  • 只需准备一次语句,然后在函数上调用它,每次准备语句都可能会减慢脚本的速度: 查询只需要分析(或准备)一次,但可以使用相同或不同的参数执行多次。准备查询时,数据库将分析、编译并优化其执行查询的计划。-

  • (不是一个错误,但我个人建议)用于帮助更好地组织您的代码并使其更易于维护/理解
  • 如@BHinkson所述,您可以使用
    is_int
    验证用户ID(如果您将ID用作数字)
  • 关于HTML转义,我建议您已经注册您的用户名等。HTML转义

  • 是的,SQL注入是安全的

    其他一些答案已经脱离了XSS保护的主题,但您显示的代码没有任何回音,它只是从数据库中获取并从函数中返回值。我建议不要在从函数返回值时预先转义这些值,因为不确定调用该函数是否是为了将结果回显到HTML响应

    没有必要使用
    is_int()
    ,因为在数值上下文中使用参数时,MySQL将自动转换为整数。非数字字符串被解释为零。换句话说,以下谓词给出相同的结果

    WHERE id = 0
    WHERE id = '0'
    WHERE id = 'banana'
    
    我建议不要在每个函数中都连接到数据库。MySQL的连接代码相当快(特别是与其他一些RDBMS相比),但为每个SQL查询建立新连接仍然是浪费。相反,只需连接数据库一次,然后将连接传递给函数

    当您连接到数据库时,会捕获异常并回显错误,但随后允许您的代码继续,就好像连接成功一样。相反,如果出现问题,你应该让你的脚本死掉。另外,不要将系统错误消息输出给用户,因为他们无法处理这些信息,并且可能会泄露太多关于代码的信息。记录错误以便自己进行故障排除,但输出更一般的内容

    <>你也可以考虑为你的连接定义一个函数,并为你的用户定义一个类。下面是一个示例,尽管我还没有对其进行测试:

    function dbConnect() {
        try {
            $conn = new PDO("mysql:host=". $mysql_host .";dbname=" . $mysql_db ."", $mysql_username, $mysql_password);
            // set the PDO error mode to exception
            $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            $conn->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
        }
        catch(PDOException $e)
        {
            error_log("PDO connection failed: " . $e->getMessage());
            die("Application failure, please contact administrator");
        }
    }
    
    class User {
        protected $row;
    
        public function __construct($userid) {
            global $conn;
            if (!isset($conn)) {
                $conn = dbConnect();
            }
            $stmt = $conn->prepare("SELECT username, profilepicture FROM accounts WHERE id = ? LIMIT 1"); 
            $stmt->execute([$userid]); 
            $this->row = $stmt->fetch(PDO::FETCH_ASSOC);
        }
    
        function getUsername() {
            return $this->row["username"]
        }
    
        function getProfilePicture() {
            return $this->row["profilepicture"]
        }
    }
    
    用法:

    $user = new User(123);
    $username = $user->getUsername();
    $profilePicture = $user->getProfilePicture();
    

    这是从数据库中获取数据的好方法。您需要
    escape
    it,将其发送到客户端时使用
    htmlspecialchars'
    it。如果它包含javascript,而您没有逃逸它,那么web浏览器将运行它。我不确定php,但如果它将在客户端可见,那么它将是一场灾难,即使它在客户端不可见,您的应用程序也很容易进行sql注入,因为您直接附加值来构造查询。我认为这对于构造对象后的更改不是很好,因为它仍然会返回旧值。@GGG,类应该返回数据库中存在的值。HTML转义应该通过调用将值输出到HTML的代码来完成。这支持面向对象设计的单一责任原则。看见