如何使用 PHP 更新 mysql 中的一行数据?

How do I update a row of data in mysql using PHP?

我正在尝试创建一个表单,用户可以在其中更新他们的个人资料详细信息,但它似乎不起作用。

我是服务器端编程的初学者,所以我将不同教程中的代码拼凑在一起。来自 http://www.codingcage.com/2015/04/php-login-and-registration-script-with.html

class.user.php文件,原来只有登录和注册的代码。我复制了注册函数并更改了一些内容来更新:

public function update($id,$uname,$umob,$uaddr,$uacc,$upass) {
    try {
        $upass = password_hash($upass, PASSWORD_DEFAULT);

        $stmt = $this->conn->prepare(
            "UPDATE users
                SET
                    id       = :id, 
                    name     = :uname, 
                    mobile   = :umob,
                    address  = :uaddr,
                    accNo    = :uacc, 
                    password = :upass
              WHERE id = :id"
        );

        $stmt->bindParam(":id", $id);
        $stmt->bindParam(":upass", $upass);
        $stmt->bindParam(":uacc", $uacc);                                         
        $stmt->bindParam(":uname", $uname);
        $stmt->bindParam(":uaddr", $uaddr); 
        $stmt->bindParam(":umob", $umob);

        $stmt->execute();   

        return $stmt;   
    }
    catch(PDOException $e) {
        echo $e->getMessage();
    }               
}

并在 view_account.php 中:(编辑 3,整个文件包括@e_i_pi 的代码更正):

<?php
ini_set("error_log", "/path/to/error.log");
    require_once("session.php");

    require_once("class.user.php");

    $auth_user = new USER();

    $stmt = $auth_user->runQuery("SELECT * FROM users WHERE consumer-no=:cno");

    $userRow = $stmt->fetch(PDO::FETCH_ASSOC);

    if(!$session->is_loggedin()){
        // session no set redirects to login page
        $session->redirect('index.php');
    }

    if(isset($_POST['submit']) && $_POST['submit'] === 'save') {
        $uname = strip_tags($_POST['full-name']);
        $umob = strip_tags($_POST['mobile']);
        $uaddr = strip_tags($_POST['addr']);
        $uacc = strip_tags($_POST['bank-acc']);
        $id = strip_tags($_POST['id']);
        $upass = strip_tags($_POST['password']);


        if($uname=="") {
            $signuperror[] = "Please Enter Your Full Name!";    
        }
        else if($umob=="")  {
            $signuperror[] = "Please Enter Your Mobile No.!";   
        }
        else if($uaddr=="") {
            $signuperror[] = 'Please Enter Your Address!';
        }
        else if($upass=="") {
            $signuperror[] = "Please Enter a Password!";
        }
        else if(strlen($upass) < 6) {
            $signuperror[] = "Password must be atleast 6 characters";   
        }
        else {
            try {
// I commented out these for some weird reason I can't even rememebr
//                $stmt = $auth_user->runQuery("SELECT id FROM users WHERE id=:id");
//                $stmt->execute(array(':id'=>$id));
//                $row = $stmt->fetch(PDO::FETCH_ASSOC);
                $auth_user->update($id,$uname,$umob,$uaddr,$uacc,$upass);
            }
            catch(PDOException $e) {
                echo $e->getMessage();
            }
        }   
    }

?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Gas Booking</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <header>
        <h1>gas booking</h1>
        <nav>
            <ul>
                <li><a href="index.php">home</a></li>
                <li><a href="booking.php">booking</a></li>
                <li><a href="payment.php">payment</a></li>
                <li><a href="ticket.php">ticket</a></li>
                <li><a href="view_account.php">view account</a></li>
                <li><a href="user-bank.php">bank</a></li>
                <li><a href="logout.php?logout=true">logout</a></li>
            </ul>
        </nav>
    </header>
    <div class="content">
        <h2>Edit Your Profile Details</h2>

        <form method="post" action="view_account.php">
            <input type="hidden" id="id" name="id" value="<?php echo $_SESSION['id']; ?>">
            <label for="full-name" class="input-info">
                <div class="label">full name</div>
                <input type="text" id="full-name" name="full-name" value="<?php echo $_SESSION['name']; ?>">
            </label>
            <label for="mobile" class="input-info">
                <div class="label">mobile number</div>
                <input type="text" id="mobile" name="mobile" value="<?php echo $_SESSION['mob']; ?>">
            </label>
            <label for="addr" class="input-info">
                <div class="label">address</div>
                <input id="addr" name="addr" value="<?php echo $_SESSION['addr']; ?>">
            </label>
            <label for="bank-acc" class="input-info">
                <div class="label">bank account number</div>
                <input type="text" id="bank-acc" name="bank-acc" value="<?php echo $_SESSION['accNo']; ?>">
            </label>
            <hr>
            <label for="password" class="input-info">
                <div class="label">password</div>
                <input type="password" id="password" name="password">
            </label>
            <button type="submit" name="submit" value="save">
                Save Changes
            </button>
        </form>     
    </div>
</body>
</html>

我的table如下:

--
-- Table structure for table `users`
--

CREATE TABLE IF NOT EXISTS `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `consumerNo` varchar(15) NOT NULL,
  `password` varchar(255) NOT NULL,
  `accNo` varchar(255) NOT NULL,
  `name` varchar(255) NOT NULL,
  `address` varchar(255) NOT NULL,
  `mobile` bigint(10) NOT NULL,
  `balance` bigint(10) NOT NULL,
  `joining_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

我确定我做了一些愚蠢的事情。我真的很感激为我指出正确的方向,我坐在那里直到 5:00am 并且对自己感到沮丧。

与数据库的连接正常,类 已正确包含。如果您需要更多信息,请与我们联系。谢谢!

项目可以在这里下载:https://www.dropbox.com/s/9v69m18l82n1t46/gas.zip?dl=0。警告代码有点乱。

更新

您似乎在 view-account.php 中执行以下操作:

try {
    $auth_user->update($id,$uname,$umob,$uaddr,$uacc,$upass);
} catch(PDOException $e) {
    echo $e->getMessage();
}

然而您已经 try/catch 在您的 update() 方法中。我认为它永远不会发生这种情况,因为在您的 if/elseif/elseif/else/etc 检查中发现了一个错误。出于测试目的,您能否将其修改为如下所示:

$errors = [];
if ($uname == "") {
    $errors[] = "Please Enter Your Full Name!";
}
if ($umob == "") {
    $errors[] = "Please Enter Your Mobile No.!";
}
if ($uaddr == "") {
    $errors[] = 'Please Enter Your Address!';
}
if ($upass == "") {
    $errors[] = "Please Enter a Password!";
}
if (strlen($upass) < 6) {
    $errors[] = "Password must be atleast 6 characters";
}
// check errors
if (!empty($errors)) {
    print_r($errors);
    return false;
}
// otherwise try the query:
$obj = $auth_user->update($id, $uname, $umob, $uaddr, $uacc, $upass);

让我们知道发生了什么!


我假设你会抛出一个错误,类似于;

SQLSTATE[HY093]: Invalid parameter number

这是因为您尝试绑定 :id 两次。您必须记住,用户 ID 是独一无二的,永远不应更改(对吗?)。

将您的查询修改为如下所示:

$stmt = $this->conn->prepare(
    "UPDATE users
     SET
         name = :uname, 
         mobile = :umob,
         address = :uaddr,
         accNo = :uacc, 
         password = :upass
      WHERE id = :id"
);

备注

  • 您最好修改 "password change" 功能,让用户确认他们的密码 (if(PASSWORD == PASSWORD_REPEAT) { .... SET PASSWORD...)
  • 不要在表单内传递用户 ID。这是不安全的。由于它已经在 $_SESSION 中,只需像在 view-account.php 文件中那样访问它!
    • 为什么你问以上?简单的。如果我检查你的 <form... 元素,我可以很容易地将隐藏的输入修改为其他用户 ID,允许我更改他们的 passwords/information/etc.
    • 并且由于看起来您正在处理 "Bank" 相关信息,我建议您尽快这样做!想象一下,如果我可以更改 "Barack Obama's" 银行密码并访问他的帐户。
  • 您的表单也没有任何 action 属性...所以它什么都不做...最好将其更改为您的 view-account.php 页面
  • 我建议您删除对 strip_tags() 的使用。它可能会破坏某些字段(即密码)。你也已经 binding/preparing 你的陈述(支持你,干得好!
  • 在我们处理的同时,您可能想查看您的 view-account.php 文件,可以修改它以停止使用所有这些 if / elseif / elseif / else 语句。您实质上是在检查所有字段,如果失败,则向数组添加错误消息,但如果通过,则您是 运行 查询,这是不好的做法。你应该看看做类似于(伪代码)的事情:

$errors = [];
if (!check_fields()) {
    $errors[] = THE FIELD ERROR MESSAGE;
}

// now check if your errors are empty or not
if(!empty($errors)) {
    // this means we have errors in the form.
    // return the errors array to the front end and handle it appropriately.
    return $errors;
}

// otherwise we can try the query here now!
try {
    // YOUR SQL UPDATE QUERY
} .....`

没错,你有一些问题,比如事情不匹配等,如果你刚开始,这是可以预料到的。

让我们从 HTML 表单开始。这里有两个问题:

  1. 表单没有任何操作属性,因此不会在任何地方提交
  2. 提交按钮有一个特定的名称,没有任何值。 (虽然有些人会认为这没问题,但也许我们可以尝试一种更明智的不同方法)

我建议您将 HTML 表格更改为:

<form method="post" action="view-account.php">
    <input type="hidden" id="id" name="id" value="<?php echo $_SESSION['id']; ?>">
    <label for="full-name" class="input-info">
        <div class="label">full name</div>
        <input type="text" id="full-name" name="full-name" value="<?php echo $_SESSION['name']; ?>">
    </label>
    <label for="mobile" class="input-info">
        <div class="label">mobile number</div>
        <input type="text" id="mobile" name="mobile" value="<?php echo $_SESSION['mob']; ?>">
    </label>
    <label for="addr" class="input-info">
        <div class="label">address</div>
        <input id="addr" name="addr" value="<?php echo $_SESSION['addr']; ?>">
    </label>
    <label for="bank-acc" class="input-info">
        <div class="label">bank account number</div>
        <input type="text" id="bank-acc" name="bank-acc" value="<?php echo $_SESSION['accNo']; ?>">
    </label>
    <hr>
    <label for="password" class="input-info">
        <div class="label">password</div>
        <input type="password" id="password" name="password">
    </label>
    <button type="submit" name="submit" value="save">
        Save Changes
    </button>
</form>  

现在,一旦这个表单被提交到视图-account.php,我们要确保提交按钮是"save"模式,所以我们改变视图的第一行-account.php 对此:

if(isset($_POST['submit']) && $_POST['submit'] === 'save') {

这种方法意味着我们可以在同一个表单上有不同的提交按钮 - 我们将来可能需要保存、删除、归档等操作。

最后,我注意到您的数据库 table 中的 id 字段被声明为 AUTOINCREMENT。太好了,正是您想要的,数据库 id 字段是我们让数据库确定的内部唯一标识符(在 99% 的情况下 - 在某些边缘情况下我们喜欢定义自己的 UID)。这意味着您的 UPDATE 语句有问题。您不能更新自动递增的字段。在您的 class.user.php 文件中,将 $stmt 的声明更改为:

$stmt = $this->conn->prepare(
    "UPDATE users
    SET
        name = :uname, 
        mobile = :umob,
        address = :uaddr,
        accNo = :uacc, 
        password = :upass
    WHERE id = :id"
);

这应该可以解决您的代码问题,我想我已经掌握了一切。 BUT,可能还有其他问题。如果您的代码仍然不起作用,我建议您检查错误日志。如果您不确定它们在哪里,请检查您的 php.ini 文件以查看错误日志位置,或者通过将其放在您尝试调试的页面顶部来覆盖默认位置:

ini_set("error_log", "/path/to/error.log");