【问题标题】:PHP MySQL, Can't figure out how to create this program [duplicate]PHP MySQL,无法弄清楚如何创建这个程序[重复]
【发布时间】:2021-01-05 00:45:51
【问题描述】:

我必须为学校创建这个程序,但我不知道该怎么做。我问了老师,接下来去哪里找零方向。 (基本上得到了“google it”的回应) 任务是这样的: 使用以下私有字段创建一个名为“User”的 PHP 类:

名字, yyyy/mm/dd 格式的生日, 年龄,和 部。 在类中,包含 getter 和 setter 方法来获取和设置这些变量的值。

使用 HTML 文本输入框和提交按钮创作数据输入网络表单。当用户单击提交按钮时,会实例化一个“用户”类并填充新用户对象的字段。 HTML 输入框对应于“用户”类中的字段。 添加一个“插入”按钮,允许用户将表单数据插入 MySQL 表。 添加一个“显示”按钮,当最终用户单击该按钮时,该按钮会在 Web 表单上显示 MySQL 表的内容。

这是我迄今为止所拥有的: PHP:

<?PHP 

if ($_POST) {

//create a connection
$conn = mysqli_connect('localhost', 'xxxxxx_hidden', 'xxxxxxxxxx_hidden');
if (! $conn) {
    die("Connection failed" . mysqli_connect_error());
}
else {
    mysqli_select_db($conn, 'junkdb');
}
class USER {
private $userName;
private $userBirthday;
private $userAge;
private $userDepart;

function setter($userName,$userBirth,$userAge,$userDepart) {
    $this->$_POST['Name'] = $userName;
    $this->$_POST['Birth'] = $userBirth;
    $this->$_POST['Age'] = $userAge;
    $this->$_POST['Depart'] = $userDepart;
}
}
$query = "INSERT into junkdb (username, birthday, age, department) VALUES('?','?','?','?')";

$stmt = mysqli_prepare($conn, $query);
$stmt->bind_param('ssss', $_POST['Name'], $_POST['Birth'], $_POST['Age'], $_POST['Depart']);
$stmt->execute();

if(mysqli_query($conn,$query)){
    echo "<p>Record added.</p>";
} else {
    echo "<p>Not added...</p>";
}
}  

mysqli_close($conn);

?>

HTML:

<!DOCTYPE HTML>
<html>
<head>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
</head>
    <body>
        <div class="container">
        <div class="row">
        <div class="col-md-8">
            <h1>Portfolio Project ITS345</h1>
                <form name="contact-form" action="insert.php" method="POST" id="contact-form">
                <div class="form-group">
                    <label for="Name">Name</label>
                    <input type="text" class="form-control" name="Name" placeholder="Name" required>
                </div>
                <div class="form-group">
                    <label for="Birthday">Birthday</label>
                    <input type="text" class="form-control" name="Birth" placeholder="YYYY/MM/DD" 
 required>
                </div>
                <div class="form-group">
                    <label for="Age">Age</label>
                    <input type="text" class="form-control" name="Age" placeholder="Your Age" 
 required>
                </div>
                <div class="form-group">
                    <label for="Depart">Department</label>
                    <input type="text" class="form-control" name="Depart" placeholder="Your 
 Department" required>
                </div>
                <button type="submit" class="btn btn-primary" name="submit" value="Submit" 
 id="submit_form">Submit</button>
                </form>
    </div>
    </div>
    </div>
 </body>
 </html>

我不断收到错误:

警告:mysqli_stmt::bind_param(): 变量数与准备语句中的参数数不匹配

在完成此计划时提供的任何帮助都会非常有帮助。我只是不知道该怎么办。

【问题讨论】:

  • 一般情况下,您希望将您的课程保留在单独的页面上,并在必要时将requireinclude (可能是_once)。您的连接也应该在一个单独的安全文件夹中......您只需在不安全页面中包含或要求。你一般不会自己设置$_POST 属性,只需要像$this-&gt;userName = $_POST['propertyHere']; 这样的实例属性。只是 cmets。
  • 错字'?'。不应引用占位符。

标签: php mysqli


【解决方案1】:

当您编写准备好的语句时,您似乎在混合过程风格和面向对象的风格。

正如 Dharman 所说,您不应该引用 ?占位符(在所有占位符中应该是 ? 而不是 '?')

另一方面,您已经声明了一个类并在您的代码中添加了一个 setter,但它们不是必需的。 (所以可以删除)

对于连接语句(localhost/username/password/db),您可以将其移动到另一个包含文件(例如connection.php),然后在您的php脚本中包含一次。

因此,请尝试将 PHP 更改为以下内容:

connection.php

<?php 
$conn = new mysqli("localhost", "xxxxxusername", "xxxxpassword", "junkdb");

/// other system initstatements

?>

你的 PHP

<?PHP 

include_once 'connection.php';

$query = "INSERT into junkdb (username, birthday, age, department) VALUES(?,?,?,?)";

$stmt = $conn -> prepare($query);
$stmt->bind_param('ssss', $_POST['Name'], $_POST['Birth'], $_POST['Age'], $_POST['Depart']);

if ($stmt->execute()) {
echo "Record added";
} else {
echo "Not added";
}


$stmt->close();
$conn->close();


?>

【讨论】:

  • 哦,谢谢(对不起,我刚刚从 OP 复制,没有通知它),我已经更正了。
  • 如果您的答案确实包含一些解释,那就太好了。 OP 的代码非常混乱,而且有很多问题。您的代码可能有效,但我不确定它是否能很好地解释您所做的更改。
  • 同意。我添加了更多解释。
【解决方案2】:

首先要做的就是整理你写的类。这还不错,但是您错过了正确的行话,然后就有点混乱了。我想我会添加一些建议来让您继续前进。

Setter 和 getter 函数是您可以用来操作对象私有字段而不利用它们的函数。例如,它们对于对要存储在类实例中的值进行完整性检查很有用。

通常它们被称为 get 和 set。您可以使用 automagic 函数来创建它们,但对我来说,您节省了一些输入,但必须与 ide 的自动完成作斗争,而且方法太通用了。

您需要将类的代码与从数据库加载/存储值或从网络检索用户输入的代码分开。每段代码只需要做一件事(并尽你所能)。

class User {
  private $name;
  private $birthdate;
  private $age;
  private $department;
  private $id;  // if you save in a db, you need an id

  function __construct()
  {
    $this->id = 0;
    $this->$name = '';
    $this->birthdate = '';
    $this->age = '';
    $this->department = '';
  }

  function getId(): Int
  {
    return $this->id;
  }

  function setId($id) {
     // check if $id contains a correct value (left as exercise)
     $this->id = $id;
  }

  function setName(String $name)
  { 
    if ($name === '') {
      throw new \UnexpectedValueException("The user name is empty");
    }
    $this->name = $name;
  }

  function getName(): String 
  {
    return $this->name;
  }

  /**
   * The format of the field is YYYY/mm/dd, but you do not have to 
   * struggle with the format you need when you create your setter, 
   * keep you interface easy to use (you'll do it a lot of times), 
   * not to code (you need to wrote it just once).
   *
   * I will do just some obvious check for a valid date, just to 
   * show the point, you will have to complete them.
   *
   * The issue here is that the setter check the value before storing it
   * to assure the developer that the value stored are valid ones (is not
   * that simple usually)
   **/
  function setBirtdate(Int $day, Int $month, Int $year)
  { 
    if ($day > 31) {
      throw new \UnexpectedValueException("Invalid day of the month");
    }
    if ($month < 1 or $month > 12) {
      throw new \UnexpectedValueException("This month does not exists");
    }
    if ($month == 2 ans $day > 29) {
      throw new \UnexpectedValueException("February has just 28 days (29 in the leap years)");
    }
    /* add other checks there, how about the 31 of April, for example?) */
    $this->birthDate = sprintf("%04d-%02d-%02d", $year, $month, $day);
  }

  /**
   * You can have more than a setter, if you need to accomodate different
   * use case for storing a value.
   * If you live in the USA, maybe you want to stick with their common
   * date format.
   *
   * As you see, it is a facade, I do not duplicate the code that manipulate
   * the value, just stick with the canonical one, it will spare a lot of 
   * headache in you (near) future
   **/
  function setBirtdate_USA_format(Int $month, Int $day, Int $year)
  { 
    $this->setBirthday($day, $month, $year);
  }

  /**
   * Same with the getter, but only one does the work
   * CHECK THE VALUE
   * If you need a getter and a setter that get just 
   * your native format, and checks if it make sense,
   * feel free to write it by yourself :-)
   **/
  function getBirthdate()
  {
    list($year, $month, $day) = explode("/", $this->birthdate);
    return [$day, $month, $year];
  }
 
  function getBirthdate_USA_format()
  {
    list($day, $month, $year) = $this->getBirtdate();
    return [$month, $day, $year];
  }

  function setAge($age)
  {
    if ($age < 1) {
      throw new \UnexpectedValueException("No newborn allowed, please");
    }
    $this->age = $age;
  }

  function getAge()
  {
    return $this->age;
  }
  
  /**
   * This is an interesting one, how discover if the department
   * exists, or the string is not mispelled?
   * There are a lot of valid ways to do this check, but it 
   * depends on the environment you are in, maybe there is a 
   * class Department, you can leverage, or a higher level one,
   * which mantains a list of departments in place.
   *
   * We will resort to an hardcoded lists of valid deps, just to 
   * keep the example (not so) short and simple.
   **/
  function setDepartment($departmentName) 
  {
    $knowDeps = ['Human Resource', 'Sales', 'Legal'];
    if (!in_array($departmentName, $knowDeps)) {
        throw new \UnexpectedValueException("The department {$departmentName} does not exists");
    }
    $this->department = $departmenetName;
  }

  function getDepartment() 
  {
    return $this->department;
  }

  function save($dbc) 
  {
     /* put the code for saving data to the db here */
  }
}

这只是此类课程的初稿,在 cmets 中有很多乱七八糟的内容,以帮助您了解其中的内容。

是时候考虑 HTML,您将需要另一个类,通常称为 View,它获取用户对象并创建网页。根据您需要完成的任务,您可以选择多个。

以下是一个快速而肮脏的解决方案,只是为了展示如何使用我们的用户对象,有些是填充的。

假设我们在 /path/to/template/ 目录中有两个 html 片段文件。让我们称它们为 base.html.template 和 contactform.html.template

base.html 文件是:

<!DOCTYPE HTML>
<html>
    <head>
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
    </head>
    <body>
        <div class="container">
        <div class="row">
        <div class="col-md-8">
            <h1>{{ contentTitle }}</h1>
            {{ content }} 
        </div>
        </div>
        </div>
    </body>
</html>

contactform.html 文件是:

<form name="contact-form" action="insert.php" method="POST" id="contact-form">
     <input name="uid" value="{{ uid }}" type="hidden">
    <div class="form-group">
        <label for="Name">Name</label>
        <input name="Name" value="{{ userName }}" type="text" class="form-control" name="Name" placeholder="Name" required>
    </div>
    <div class="form-group">
        <label for="Birthday">Birthday</label>
        <input name="Birth" value="{{ userBday }}" type="text" class="form-control"  placeholder="YYYY/MM/DD" required>
    </div>
    <div class="form-group">
        <label for="Age">Age</label>
        <input name="Age" value="{{ userAge }}˝ type="text" class="form-control" name="Age" placeholder="Your Age" required>
    </div>
    <div class="form-group">
        <label for="Depart">Department</label>
        <input name="Depart" value="{{ userDep }}" type="text"   class="form-control"  placeholder="Your Department" required>
    </div>
    <button type="submit" class="btn btn-primary" name="submit" value="Submit" id="submit_form">Submit</button>
</form>

{{ userName }} jibberish 是我们在创建要在浏览器中显示的页面时需要用实际数据替换的占位符

class UserViewContactForm {
  private $template;

  function __construct() {
  /* We need to load a template somehow. */
   
  $this->template = file_get_contents(`/path/to/template/contactform.html`);
  }

  function render(?User $user=Null) {
    /* When we do not pass any user, just show the form, otherwise 
     * we will fill it with the data of the user we have 
     * to show/edit 
     */
    if (!$user) {
      $user = new User();
    }

    $fields = [
        "{{ uid }} => $user->getId(),
        "{{ userName }}" => $user->getName(),
        "{{ userBday }}" => $user->getBirthday(),
        "{{ userAge }}" => $user->getAge(),
        "{{ userDep }}" => $user->getDepartment()
    ];
  
    // get a copy of the template, maybe we'll need it for another one                
    $htmlform = $this->template;
    // change all the placeholder
    foreach ($fields as $field => $value) {
      $htmlform = str_replace($field, $value, $htmlform);
    }
    return $htmlform;
  }
}

我们需要一个 BaseView 对象来组装完整的 html 页面:

class HtmlPage {
  private $template;

  function __construct() {
  /* We need to load a template somehow. */
   
  $this->template = file_get_contents(`/path/to/template/base.html`);
  }

  function render($content) {
    /* When we do not pass any user, just show the form, otherwise 
     * we will fill it with the data of the user we have 
     * to show/edit 
     */

    // get a copy of the template, maybe we will need to show another
    // user in the next future, who know.                
    $htmlform = $this->template;
    // change all the placeholder
    foreach ($fields as $field => $value) {
      $htmlform = str_replace($field, $value, $htmlform);
    }
    return $htmlform;
  }
}

现在您的用户类与 html 解耦了,您可以在不更改保存您宝贵数据的类的情况下更改视图。

我们只需要一个工厂来根据我们从网络用户那里获得的输入来创建我们的用户。或来自数据库,或来自任何其他来源。

这是一个全新的任务,所以我们需要一个全新的对象。 这个类的任务是创建一个用户

Class UserFactory {
  private $dbc;
  
  function setDbConnector($pdo) {
    /* just injecting an object to manage the interaction with a db */
    $this->dbc = $pdo;
  }
  
  function createFromHash($data) {
    /* Sometime you will need to use different verbs to 
     * send data to the server, hance the need to 
     * decouple the array we take the data from.
     *
     * Important, we should take the time here to 
     * check the input for malicious input. 
     * Since it is an example and I'm too lazy we will
     * skip this important phase of input retrieving.
     */
     $requiredFields = ['uid', 'Name', 'Birth', 'Age', 'Depart'];
     $actual = array_intersect($requiredFields, array_keys($data));
     if (count($requiredFields) != count($actual)) {
       throw new \InvalidArgumentException("Some field is missing");
     }
     $user = new User();
     $user->setId($data['uid']);
     $user->setName($data['Name']);
     $user->setBirthdate($data['Birth']);
     $user->setAge($data['Age']);
     $user->setDepart($data['Depart']);
     return $user;
  }

  function createFromDb($userId) {
    /* If you need to retrieve data from a database, 
     * just retrieve them, put in a suited array hash an
     * reuse the method we already implemented.
     * 
     * It 
     */
     $query = "SELECT id as "uid",
                      username as "Name",
                      birthday as "Birth",
                      age as "Age",
                      department as "Depart"
               FROM users
               WHERE id = :userid";

     $stmt = $this->dbc->prepare($query);
     $stmt->bindParam(':userid', $userId, PDO::FETCH_ASSOC);
     $stmt->execute();
     
     $data = $stmt->fetch(PDO::FETCH_ASSOC);
     return $this->createFromHash($data);
  }
}

如何去数据库? 我认为您使用的功能确实存在并且可能已弃用, 只需坚持使用PDO Object 即可使用数据库。 PDO 使用drivers 连接不同的数据库引擎,确保您可以使用通用接口连接到数据库并执行action on the database

现在是时候把所有东西放在一起了

#Include all the php files you need 

// instance $pdo, a PDO object to connect to the database
try{    
    $factory = new UserFactory();
    $user = $factory->createFromHash($_POST);
} catch (InvalidArgumentException $e) {
    $user = new User();  // an empty one
}

$page = new HtmlPage();
$contactForm = new UserViewContactForm();

echo $page->render($contactForm->render($user));

您应该已经准备好渲染页面以获取数据。 有一些偷工减料,还有很多工作要在那里获得一个真正有效的解决方案,但我认为这是你可以建立的基础。

【讨论】:

  • $this-&gt;$_POST['Name'] = $userName; - 你能解释一下那行应该做什么吗?
  • @NicoHaase 假设您有一个变量$aname = "Hello"。在 PHP 中,如果您有一个包含名为 $Hello 的字段的类,则成语 $this-&gt;$aname 等价于 $this-&gt;Hello。你永远不应该使用这样的成语,因为它令人困惑并且无法通过你使用的 ide 来追踪,引用最明显的反对它的理由。它在原始问题中,以错误的方式使用(因为有正确的使用方式;-))
  • 对不起 - 在原始问题中没有看到。这听起来很令人困惑,因为如果字段名称来自 POST 请求,您将无法再次安全地读取该属性.....
【解决方案3】:

我在这里强调了你应该更正它

$query = "INSERT into junkdb (username, birthday, age, department) VALUES(?,?,?,?)";
$stmt = $conn->prepare($query);

if($stmt->affected_rows){
    echo "<p>Record added.</p>";
} else {
    echo "<p>Not added...</p>";
}
$stmt->close();
$conn->close();

或者你可以复制完整的代码并运行:

<?PHP 

if ($_POST) {

//create a connection
$conn = mysqli_connect('localhost', 'xxxxxx_hidden', 'xxxxxxxxxx_hidden');
if (! $conn) {
    die("Connection failed" . mysqli_connect_error());
}
else {
    mysqli_select_db($conn, 'junkdb');
}
class USER {
private $userName;
private $userBirthday;
private $userAge;
private $userDepart;

function setter($userName,$userBirth,$userAge,$userDepart) {
    $this->$_POST['Name'] = $userName;
    $this->$_POST['Birth'] = $userBirth;
    $this->$_POST['Age'] = $userAge;
    $this->$_POST['Depart'] = $userDepart;
}
}
$query = "INSERT into junkdb (username, birthday, age, department) VALUES(?,?,?,?)";

$stmt = $conn->prepare($query);
$stmt->bind_param('ssss', $_POST['Name'], $_POST['Birth'], $_POST['Age'], $_POST['Depart']);


if($stmt->execute()){
    echo "<p>Record added.</p>";
} else {
    echo "<p>Not added...</p>";
}   

$stmt->close();   

$conn->close();
}  


?>

【讨论】:

  • 如果您还没有执行查询,$stmt-&gt;affected_rows 应该包含什么?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-01-27
  • 1970-01-01
  • 2013-01-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多