【问题标题】:Error Inserting data in Database using Prepared Statement使用 Prepared Statement 在数据库中插入数据时出错
【发布时间】:2018-05-28 04:10:53
【问题描述】:

我正在使用 PHP 和 Prepared Statement 为我的公司开发票务系统。 添加工单时,您应该填写以下字段:

  1. 票种
  2. 票名
  3. 门票说明
  4. 要求的日期
  5. 要求的小时数
  6. 公司
  7. 访问类型
  8. 优先级
  9. 状态
  10. 指派技术员

这行得通: 1.您可以选择从数据库中提取的票证类型。 2.您可以选择从数据库中提取的公司。 3.您可以选择从数据库中提取的访问类型。 4.您可以选择从数据库中提取的技术人员。

问题是当你按下添加票时,它不会向数据库中添加任何东西。

这是我的代码:

newticket.php

<?php
   $projects = ProjectData::getAll();
   $priorities = PriorityData::getAll();
   $ticket= TicketData::getAll();
   $statuses = StatusData::getAll();
   $kinds = KindData::getAll();
   $users = UserData::getAll();

   ?>
<div class="row">
   <div class="col-md-12">
      <div class="card">
         <div class="card-header" data-background-color="blue">
            <h4 class="title">Nuevo Ticket</h4>
         </div>
         <div class="card-content table-responsive">
            <form class="form-horizontal" role="form" method="post" action="./?action=addticket">
               <div class="form-group">
                  <label for="inputEmail1" class="col-lg-2 control-label">Tipo</label>
                  <div class="col-lg-10">
                     <select name="kind_id" class="form-control" required>
                        <?php foreach($kinds as $p):?>
                        <option value="<?php echo $p->id; ?>"><?php echo $p->name; ?></option>
                        <?php endforeach; ?>
                     </select>
                  </div>
               </div>
               <div class="form-group">
                  <label for="inputEmail1" class="col-lg-2 control-label">Titulo</label>
                  <div class="col-lg-10">
                     <input type="text" name="title" required class="form-control" id="inputEmail1" placeholder="Titulo">
                  </div>
               </div>
               <div class="form-group">
                  <label for="inputEmail1" class="col-lg-2 control-label">Descripcion</label>
                  <div class="col-lg-10">
                     <textarea class="form-control" name="description" required placeholder="Descripcion"></textarea>
                  </div>
               </div>
               <div class="form-group">
                  <label for="inputEmail1" class="col-lg-2 control-label">Fecha de la Visita</label>
                  <div class="col-lg-4">
                     <input name="date_at" id="date_at" class="form-control" type="date">
                  </div>
                  <label for="inputEmail1" class="col-lg-2 control-label">Hora de la Visita</label>
                  <div class="col-lg-4">
                     <input name="time_at" id="time_at" class="form-control" type="time" />
                  </div>
               </div>
               <div class="form-group">
                  <label for="inputEmail1" class="col-lg-2 control-label">Proyecto</label>
                  <div class="col-lg-4">
                     <select name="project_id" class="form-control" required>
                        <option value="">-- SELECCIONE --</option>
                        <?php foreach($projects as $p):?>
                        <option value="<?php echo $p->id; ?>"><?php echo $p->name; ?></option>
                        <?php endforeach; ?>
                     </select>
                  </div>
                  <label for="inputEmail1" class="col-lg-2 control-label">Categoria</label>
                  <div class="col-lg-4">
                     <select name="category_id" class="form-control" required>
                        <option value="">-- SELECCIONE --</option>
                        <?php foreach(CategoryData::getAll() as $p):?>
                        <option value="<?php echo $p->id; ?>"><?php echo $p->name; ?></option>
                        <?php endforeach; ?>
                     </select>
                  </div>
               </div>
               <div class="form-group">
                  <label for="inputEmail1" class="col-lg-2 control-label">Prioridad</label>
                  <div class="col-lg-4">
                     <select name="priority_id" class="form-control" required>
                        <option value="">-- SELECCIONE --</option>
                        <?php foreach($priorities as $p):?>
                        <option value="<?php echo $p->id; ?>"><?php echo $p->name; ?></option>
                        <?php endforeach; ?>
                     </select>
                  </div>
                  <label for="inputEmail1" class="col-lg-2 control-label">Estado</label>
                  <div class="col-lg-4">
                     <select name="status_id" class="form-control" required>
                        <?php foreach($statuses as $p):?>
                        <option value="<?php echo $p->id; ?>"><?php echo $p->name; ?></option>
                        <?php endforeach; ?>
                     </select>
                  </div>
               </div>
               <div class="form-group">
                  <label for="inputEmail1" class="col-lg-2 control-label">Asignar a</label>
                  <div class="col-lg-4">
                     <select name="tecnico_id" class="form-control" required>
                        <option value="">-- SELECCIONE --</option>
                        <?php foreach($users as $p):?>
                        <option value="<?php echo $p->id; ?>"><?php echo $p->name." ".$p->lastname; ?></option>
                        <?php endforeach; ?>
                     </select>
                  </div>
               </div>
               <div class="form-group">
                  <div class="col-lg-offset-2 col-lg-10">
                     <button type="submit" class="btn btn-default">Agregar Ticket</button>
                  </div>
               </div>
            </form>
         </div>
      </div>
   </div>
</div>

ticketdata.php

<?php
class TicketData {
    public static $tablename = "ticket";


    public function TicketData(){
        $this->name = "";
        $this->lastname = "";
        $this->email = "";
        $this->password = "";
        $this->date_at="";
        $this->time_at="";
        $this->tecnico_id="";
        $this->created_at = "NOW()";
    }
    public function getTicket(){ return TicketData::getById($this->ticket_id); }
    public function getProject(){ return ProjectData::getById($this->project_id); }
    public function getPriority(){ return PriorityData::getById($this->priority_id); }
    public function getStatus(){ return StatusData::getById($this->status_id); }
    public function getKind(){ return KindData::getById($this->kind_id); }
    public function getCategory(){ return CategoryData::getById($this->category_id); }

    public function add(){
        $sql = "insert into ticket (title,description,date_at,time_at,category_id,project_id,priority_id,user_id,status_id,kind_id,created_at,tecnico_id) ";
        $sql .= "value (\"$this->title\",\"$this->description\",\"$this->date_at\",\"$this->time_at\",\"$this->category_id\",\"$this->project_id\",$this->priority_id,$this->user_id,$this->status_id,$this->kind_id,$this->created_at,$this->tecnico_id)";
        return Executor::doit($sql);
    }

    public static function delById($id){
        $sql = "delete from ".self::$tablename." where id=$id";
        Executor::doit($sql);
    }
    public function del(){
        $sql = "delete from ".self::$tablename." where id=$this->id";
        Executor::doit($sql);
    }

// partiendo de que ya tenemos creado un objecto TicketData previamente utilizamos el contexto
    public function update(){
        $sql = "update ".self::$tablename." set title=\"$this->title\",category_id=\"$this->category_id\",date_at=\"$this->date_at\",time_at=\"$this->time_at\",tecnico_id=\"$this->tecnico_id\",project_id=\"$this->project_id\",priority_id=\"$this->priority_id\",description=\"$this->description\",status_id=\"$this->status_id\",kind_id=\"$this->kind_id\",updated_at=NOW() where id=$this->id";
        Executor::doit($sql);
    }

    public static function getById($id){
        $sql = "select * from ".self::$tablename." where id=$id";
        $query = Executor::doit($sql);
        return Model::one($query[0],new TicketData());
    }

    public static function getRepeated($pacient_id,$medic_id,$date_at,$time_at){
        $sql = "select * from ".self::$tablename." where pacient_id=$pacient_id and medic_id=$medic_id and date_at=\"$date_at\" and time_at=\"$time_at\"";
        $query = Executor::doit($sql);
        return Model::one($query[0],new TicketData());
    }



    public static function getByMail($mail){
        $sql = "select * from ".self::$tablename." where mail=\"$mail\"";
        $query = Executor::doit($sql);
        return Model::one($query[0],new TicketData());
    }

    public static function getEvery(){
        $sql = "select * from ".self::$tablename;
        $query = Executor::doit($sql);
        return Model::many($query[0],new TicketData()); 
    }

    public static function getEvents(){
        $sql = "select * from ".self::$tablename;
        $query = Executor::doit($sql);
        return Model::many($query[0],new TicketData());
    }

    public static function getAll(){
        $sql = "select * from ".self::$tablename." order by created_at desc";
        $query = Executor::doit($sql);
        return Model::many($query[0],new TicketData());
    }

    public static function getAllPendings(){
        $sql = "select * from ".self::$tablename." where status_id=1";
        $query = Executor::doit($sql);
        return Model::many($query[0],new TicketData());
    }


    public static function getAllByPacientId($id){
        $sql = "select * from ".self::$tablename." where pacient_id=$id order by created_at";
        $query = Executor::doit($sql);
        return Model::many($query[0],new TicketData());
    }

    public static function getAllByMedicId($id){
        $sql = "select * from ".self::$tablename." where medic_id=$id order by created_at";
        $query = Executor::doit($sql);
        return Model::many($query[0],new TicketData());
    }

    public static function getBySQL($sql){
        $query = Executor::doit($sql);
        return Model::many($query[0],new TicketData());
    }

    public static function getOld(){
        $sql = "select * from ".self::$tablename." where date(date_at)<date(NOW()) order by date_at";
        $query = Executor::doit($sql);
        return Model::many($query[0],new TicketData());
    }

    public static function getLike($q){
        $sql = "select * from ".self::$tablename." where title like '%$q%'";
        $query = Executor::doit($sql);
        return Model::many($query[0],new TicketData());
    }


}

?>

更新

对 TicketData.php 进行了细微更改,以纠正@smith 和@Nick 的观察结果。 它们看起来像这样:

class TicketData {
    public static $tablename = "ticket";
    public function TicketData(){
        $this->name = "";
        $this->title = "";
        $this->description= "";
        $this->lastname = "";
        $this->email = "";
        $this->password = "";
        $this->date_at="";
        $this->time_at="";
        $this->tecnico_id="";
        $this->created_at = "NOW()";
    }
    public function getProject(){ return ProjectData::getById($this->project_id); }
    public function getPriority(){ return PriorityData::getById($this->priority_id); }
    public function getStatus(){ return StatusData::getById($this->status_id); }
    public function getKind(){ return KindData::getById($this->kind_id); }
    public function getCategory(){ return CategoryData::getById($this->category_id); }
    public function add(){
        $sql = "insert into ticket (title,description,date_at,time_at,category_id,project_id,priority_id,user_id,status_id,kind_id,created_at,tecnico_id) ";
        $sql .= "values (\"$this->title\",\"$this->description\",\"$this->date_at\",\"$this->time_at\",\"$this->category_id\",\"$this->project_id\",\"$this->priority_id\",\"$this->user_id\",\"$this->status_id\",\"$this->kind_id\",\"$this->created_at\",\"$this->tecnico_id\")";
        return Executor::doit($sql);
    }

现在,它将保存这些字段:

  1. 票证类型 (kind_id)
  2. 票证标题 (title)
  3. 门票说明 (description)
  4. 请求日期 (date_at)
  5. 请求小时数 (hour_at)
  6. 公司 (project_id)
  7. 访问类型 (category_id)
  8. 优先级 (priority_id)
  9. 状态 (status_id)

它不会保存这个字段:

  1. 指派技术员 (tecnico_id)

addticket-action.php

    <?php
        $r = new TicketData();
        $r->title = $_POST["title"];
        $r->description = $_POST["description"];
        $r->category_id = $_POST["category_id"];
        $r->project_id = $_POST["project_id"];
        $r->priority_id = $_POST["priority_id"];
        $r->user_id = $_SESSION["user_id"];
        $r->status_id = $_POST["status_id"];
        $r->kind_id = $_POST["kind_id"];
        $r->date_at = $_POST["date_at"];
        $r->time_at = $_POST["time_at"];
        $r->tecnico_id = $_POST["tecnico_id"];
        $r->created_at = $_POST["created_at"];
        $r->add();
        Core::alert("Successfully added!");
        Core::redir("./index.php?view=tickets");
 ?>

我想在清理并转换为适当的准备好的语句之前让一切正常工作。 我需要更正/添加什么以使脚本保存 (date_at) (hour_at) 和 (tecnico_id) 字段?

【问题讨论】:

  • 提示:了解查询参数。
  • 我看不到 $this-&gt;title 等被设置
  • 它应该是values,而不是insert查询中的value
  • 类构造函数不应使用旧样式 (public function ClassName()),因为它在 PHP 7 中已被弃用,并将在未来版本中完全删除。请改用public function __construct()。如果您将所有属性(及其默认值)定义为属性,而不是在构造函数中隐式添加它们,您的代码也会更清晰。
  • 您还在代码中使用了多个根本不存在的类属性。您也永远不会在任何时候设置/填充属性。这段代码有几个问题。你是如何使用这个类的?您是否以其他方式设置属性?

标签: php mysql prepared-statement ticket-system


【解决方案1】:

提供一些日志或后端错误消息可能有助于解决此问题。

但乍一看,主要的问题是您实际上并没有使用准备好的语句。您基本上是将一个字符串连接在一起以创建一条 SQL 语句,这非常糟糕有几个原因:

  1. 您容易受到 SQL 注入的攻击。例如,如果你把 ","",""); DROP TABLE ticket; -- 到您的标题字段中,有人可能会破坏您的票表,因为您的代码没有检查这一点。
  2. 您需要清理输入。如果 title 包含双引号,它将过早结束您的字符串输入,导致您的 SQL 失败。

这是一个相当大的安全漏洞,因此请堵住它,同时为自己省去一些输入清理问题!如果您转换为准备好的语句并且它可以工作,那么它可能是一个清理问题。如果它仍然不起作用,请在其中获取一些日志记录语句,让我们看看你有什么。

http://php.net/manual/en/mysqli.quickstart.prepared-statements.php https://www.w3schools.com/php/php_mysql_prepared_statements.asp

【讨论】:

  • 奇怪的是,它没有显示任何错误消息。这就是为什么我在这里问大声笑的原因。我会尝试清理代码,看看是否能解决它?谢谢
  • 哦,顺便说一句:我很好奇,我在标题字段中输入了","",""); DROP TABLE ticket; --。没啥事儿。它甚至没有保存票。
  • 这往往表明除了上述问题外,某处可能存在与数据库的连接错误。你能做一个简单的“从票限制5中选择*”并让它返回吗?同样对于 Drop 语法,我提供了一个示例,但是您必须使用足够的引号来填写插入内容。
  • 是的,出现连接错误,因为我忘记将新字段添加到 addticket-action.php。尽管如此,代码仍会“检测到”这一点并且不会保存票证。如果我输入其他内容,它肯定会保存它。
  • 这可能意味着注入攻击语法中仍然存在错误 - 基于上面的代码,我向您保证没有任何事情可以“检测”它并阻止攻击。不过,这是您要发送给 prod 的代码,因此请按照您的意愿对其进行清理。票务系统的风险可能较低,但鉴于您在那里有电子邮件和密码,您真的应该在 15 分钟内做出准备好的声明。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-23
  • 1970-01-01
相关资源
最近更新 更多