我正在努力用PDO升级登录脚本

时间:2016-02-11 17:56:06

标签: php mysql pdo

我的函数中有自定义查询()函数。文件。我创建了一个login.php文件,但是当我进行SQL查询时,query()函数返回一个PDO对象,而不是我想要的关联数组。我需要帮助来传递要绑定到存储过程/预准备语句的参数。

以下是login.php文件:

<?php

    // configuration
    require("../../includes/config.php");

    // if form was submitted
    if ($_SERVER["REQUEST_METHOD"] == "POST")
    {
        // validate submission
        if (empty($_POST["username"]))
        {
            adminapologize("You must provide your username.");
        }
        else if (empty($_POST["password"]))
        {
           adminapologize("You must provide your password.");
        }

        $username = $_POST["username"];

        // query database for user
        $sql = "SELECT * FROM admin WHERE username = '$username'";

        $result = query($sql,array($username));        
        //var_dump($result);
        //exit;

        if($sql != false)
        {
            if($result->rowCount() == 0)
            {
                printf("No admin yet.");
            }

            // if we found user, check password
            if($result->rowCount() == 1)
            {
                // first (and only) row
                $row = $result->fetch();

                // compare hash of user's input against hash that's in database
                if ($_POST["username"] == $row["username"] && crypt($_POST["password"], $row["hash"]) == $row["hash"])                 
                {
                    // remember that user is now logged in by storing user's ID in session
                    $_SESSION["admin_id"] = $row["admin_id"];

                    // redirect to admin home
                    redirect("index.php");
                }
            }
        }
        else
        {
            // else apologize
            adminapologize("Invalid username and/or password.");
        }
    }
    else
    {
        // else render form
        adminrender("login_form.php", ["title" => "Admin Log In"]);
    }

?>

请注意config.php包含functions.php文件。以下是functions.php文件的一部分:

/**
* Executes SQL statement, possibly with parameters, returning
* a pdo statement object on success, handling and halting execution on error.
*/

function query($sql, $parameters = null)
{
    static $pdo; // define the var as static so that it will persist between function calls
    try
    {
        // if no db connection, make one
        if (!isset($pdo))
        {
            // connect to database
            // you should set the character encoding for the connection
            $pdo = new PDO("mysql:dbname=" . DB_NAME . ";host=" . DB_SERVER, DB_USERNAME, DB_PASSWORD);
            $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // set the error mode to exceptions
            $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES,false); // turn emulated prepares off
            $pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE,PDO::FETCH_ASSOC); // set default fetch mode to assoc so that you don't have to explicitly list the fetch mode every place
        }

        if(empty($parameters))
        {
            // no bound inputs
            $stmt = $pdo->query($sql);
        } else {
            // has bound inputs
            $stmt = $pdo->prepare($sql);
            // you should use explicit bindValue() statements to bind any inputs, instead of supplying them as a parameter to the ->execute() method. the comments posted in your thread lists the reasons why.
            $stmt->execute($parameters);
        }
    }
    catch (Exception $e)
    {
        // all errors with the connection, query, prepare, and execute will be handled here
        // you should also use the line, file, and backtrace information to produce a detailed error message
        // if the error is due to a query, you should also include the $sql statement as part of the error message
        // if $pdo ($handle in your code) is set, it means that the connection was successful and the error is due to a query. you can use this to include the $sql in the error message.
        trigger_error($e->getMessage(), E_USER_ERROR);

        //exit; // note: E_USER_ERROR causes an exit, so you don't need an exit; here.
    }

    return $stmt; // if the query ran without any errors, return the pdo statement object to the calling code

}

非常感谢您的帮助。

2 个答案:

答案 0 :(得分:1)

你有一个很好的功能,不需要破坏它。

  

query()函数返回一个PDO对象,而不是我想要的关联数组。

它实际上是您想要返回的对象。至于数组,你可以通过链接获取调用来获得它:

$result = query($sql,array($username))->fetch();   // voila!

看,使用返回对象的函数,您不仅可以获得单行,还可以获得数十种不同类型的结果。与fetchColumn()的单列值或fetchAll()支持的多种格式一样。更不用说你可以从数组中获取numRows()而不是数组。

使用此函数的当前形式,您也可以运行DML查询,而返回fetch则最终会出错。返回一个对象真的很酷!

关于你的功能唯一不好的一点是你正在捕捉异常并手动将其转换为错误,而PHP已经为你做了这个。
只需摆脱这个try catch块,你就会有完全相同(实际上甚至更好)的错误报告。

    // all errors with the connection, query, prepare, and execute will be handled here
    // you should also use the line, file, and backtrace information to produce a detailed error message
    // if the error is due to a query, you should also include the $sql statement as part of the error message
    // if $pdo ($handle in your code) is set, it means that the connection was successful and the error is due to a query. you can use this to include the $sql in the error message.

如果您只是没有捕获异常,PHP已经为您做了所有这些事情。

(除了存储实际上不需要的$ sql变量,因为你可以在后面跟踪后找到一个查询)

截至代码时,它应该缩短五倍:

    $sql = "SELECT * FROM admin WHERE username = ?";
    $row = query($sql,array($username))->fetch();
    if($row && crypt($_POST["password"], $row["hash"]) == $row["hash"])
    {
         // remember that user is now logged in by storing user's ID in session
         $_SESSION["admin_id"] = $row["admin_id"];

         // redirect to admin home
         redirect("index.php");

         //this is essential as otherwise anyone will be able to proceed with this page
         exit;
    }

顺便说一句,我刚刚注意到您使用的函数错误,将$ username直接发送到查询中。我也修好了。

答案 1 :(得分:0)

根据@Your Common Sense的回答编辑谁的绝对正确: 致电您的功能&#39;查询&#39;并直接对该结果进行提取。 例如,如以下评论中所述:

$rows = query($sql, $params)->fetch();

如果要将行作为关联数组执行

$rows = query($sql, $params)->fetch(PDO::FETCH_ASSOC);

这显式返回一个关联数组。

执行后必须获取结果。

$stmt->execute($parameters);
return $stmt->fetch(PDO::FETCH_ASSOC);

这应该返回一个关联数组。

另请参阅:http://php.net/manual/de/pdostatement.fetch.php

/**
 * Executes SQL statement, possibly with parameters, returning
 * a pdo statement object on success, handling and halting execution on  error.
 */

function query($sql, $parameters = null)
{
    static $pdo; // define the var as static so that it will persist between function calls
    $return = false;
try {
// if no db connection, make one
    if (!isset($pdo)) {
    // connect to database
    // you should set the character encoding for the connection
    $pdo = new PDO("mysql:dbname=" . DB_NAME . ";host=" . DB_SERVER, DB_USERNAME, DB_PASSWORD);

    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // set the error mode to exceptions

    $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES,false); // turn emulated prepares off

    $pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE,PDO::FETCH_ASSOC); // set default fetch mode to assoc so that you don't have to explicitly list the fetch mode every place

}

if(empty($parameters)){
    // no bound inputs
    $stmt = $pdo->query($sql);
} else {
    // has bound inputs
    $stmt = $pdo->prepare($sql);
     // you should use explicit bindValue() statements to bind any inputs, instead of supplying them as a parameter to the ->execute() method. the comments posted in your thread lists the reasons why.
        $stmt->execute($parameters);
        $return = $stmt->fetch(PDO::FETCH_ASSOC);
    }    
} catch (Exception $e)

{
// all errors with the connection, query, prepare, and execute will be handled here
// you should also use the line, file, and backtrace information to produce a detailed error message
// if the error is due to a query, you should also include the $sql statement as part of the error message
// if $pdo ($handle in your code) is set, it means that the connection was successful and the error is due to a query. you can use this to include the $sql  in the error message.
    trigger_error($e->getMessage(), E_USER_ERROR);
    //exit; // note: E_USER_ERROR causes an exit, so you don't need an exit;     here.
}

return $return; // if the query ran without any errors, return the pdo statement     object to the calling code