【问题标题】:Problem with selected subcategory when editing Category items编辑类别项目时所选子类别出现问题
【发布时间】:2010-04-03 23:18:19
【问题描述】:

我想在编辑类别时选择项目的子类别:

<?php
  function categoryFormEdit()
 {
  $ID = $_GET['id'];
  $query = "SELECT * FROM category WHERE id= $ID";
  $result = mysql_query($query);
  $row = mysql_fetch_array($result);
  $subcat = $row['subcat'];
  $text = '<div class="form">
        <h2>Add new category</h2>
          <form method="post" action="?page=editCategory">
              <ul>
                  <li><label>Kategori</label></li>
                  <li><input type="text" class="inp" name="cname" value="' . $row['name'] . '"></li>
                  <li><label> Aç&#305;klama</label></li>
                  <li><textarea class="inx" rows="10" cols="40" name="kabst">' . $row['description'] . '</textarea></li>
                  <li>
                    <select class="ins" name="kselect">
                      <option value="1">Aktif</option>
                      <option value="0">Pasif</option>
                    </select>
                  </li>
                  <li>Üst kategorisi</li>
                  <li>
                    <select class="ins" name="subsl">';
                        $s = "SELECT * FROM category";
                        $q = mysql_query($s);
                        while ($r = mysql_fetch_assoc($q)) {
                            $text .= '<option value="' . $r['id'] . '" ' . sQuery() . '>' . $r['name'] . '</option>';
                        }
                    $text .= '</select>
                 </li>

                     <li>Home page:</li> 
                     <li>
                       <input type="radio" value="1" name="kradio"> Active
                       <input type="radio" value="0" name="kradio"> YPassive
                     </li>
                     <li><input type="submit" class="int" value="ekle" name="ksubmit"></li>
                </ul>
            </form>
        </div>';
  return $text;
 }

 function sQuery()
 {
    if ($r['id'] == $subcat) {
      $t = "selected";
    } 
    else {

      $t = "";
    }
   return $t;
  }
?>

上面的代码没有选中的项目。我的脚本有什么问题? 提前致谢

【问题讨论】:

    标签: php


    【解决方案1】:

    好的,上次我试图帮助你时,你对我大肆投票(顺便说一句,SO 团队很好地扭转了这一点),所以我不知道我为什么要帮助你时间,但这里对您的代码进行了一些改进,包括所需的功能。

    基本上,您的代码是 HTML 和 PHP 的混合体且难以阅读,在一个函数中执行的操作太多。如果出了什么问题,你不知道在哪里。我们将把它分解成更小的可重复使用的块。这将提高可维护性、可读性和安全性。

    下面是代码最终的样子:

    <?php error_reporting(-1); // turn on all errors
    
    function getCategoryFormEdit($id)
    {
      $categories = getCategories();
      $category   = getCategoryFromRowsById($categories, $id);   
      $selectBox  = createCategorySelectBoxOptions($categories, $category['subcat']);
    
      $html = getRenderedTemplate('categoryFormEdit.tpl.html', array(
          '{{category:name}}',
          '{{category:description}}',
          '{{category:selectBoxOptions}}',  
      ), array(
          $category['name'],
          $category['description'],
          $selectBox
      ));
    
      return $html;
    }
    

    如您所见,我已经分解了代码,现在很容易从函数名称中理解它的作用。基本上,getCategoryFormEdit 现在所做的一切都是为您获取组装 HTML 所需的一切。其余的东西在其他功能中完成。这使得代码更容易处理,因为现在它只做一件事,而不是四件事。将函数保持小并让它们一次只做一件事被认为是一种很好的做法,因为如果出现问题,您不必搜索数百行代码,而只需在您的小函数中搜索即可。

    其他功能如下:

    function queryDatabase($sql)
    {
        $result = mysql_query($sql);
        $rows   = mysql_fetch_array($result);
        return $rows;    
    }
    

    因为您将多次进行查询和提取,所以我们重构代码以将数据库调用为单独的函数。我们很懒惰,不想一次又一次地在我们的代码中重现这些调用。相反,我们只是向这个函数传递一些 SQL 并让它从查询中返回行,查询是:

    function getCategories()
    {
        return queryDatabase('SELECT id, name, description, subcat FROM category');
    }
    

    您的版本中有* 的查询。仅从数据库中获取您真正需要的内容被认为是一种很好的做法,这就是为什么我将其替换为 HTML 中的列名的原因。数据库查询很昂贵,查询数据库越少越好。第二个:

    function getCategoryById($id)
    {
        $sql = sprintf(
            'SELECT name, description, subcat 
            FROM category WHERE id = %d', $id);
    
        return queryDatabase($sql);
    }
    

    请注意,我没有将 ID 直接包含在查询中,而是使用 sprintf%d。在您的代码中,您使用了$ID = $_GET['id'],然后将$ID 直接插入到SQL 字符串中,打开了SQL Injection 的代码。永远不要那样做。您不能信任用户输入和should always sanitize it。使用%d,我们确保 ID 是一个数字并且只是一个数字。

    如果你再看getCategoryFormEdit,你会注意到我们调用的不是getCategoryById($id),而是下面的函数:

    function getCategoryFromRowsById($rows, $id)
    {
        foreach($rows as $row) {
            if($row['id'] === $id) {
                return $row;
            }
        }
        return FALSE;
    }
    

    原因很简单:在执行getCategories() 时,您已经从数据库中获取了所有类别,因此没有理由再次重新查询数据库以仅获取一个特定类别,因为它包含在返回的行中在所有类别中。记住 db 查询很昂贵,所以让我们遍历所有类别并从那里选择具有给定 $id 的行。

    获得所有类别后,您可以使用它们来创建选择选项:

    function createCategorySelectBoxOptions($rows, $selectedId)
    {
        $options = '';
        foreach($rows as $row) {
            $options .= sprintf(
                '<option value="%s"%s>%s</option>',
                $rows['id'],
                ($rows['id'] === $selectedId) ? ' selected="selected"' : '',
                $rows['name']
            );
        }
        return $options;
    }
    

    同样,这个函数所做的只是一个:它创建选择选项。而已。它还将selected 属性添加到具有与指定$selectedId 相同的$row['id'] 的选项。再次使用sprintf 而不是字符串连接,因为它更容易阅读并且减少了代码的混乱。另请注意,我对选定属性使用了 XHTML 表示法。使用 HTML 风格时,您可以只使用 selected

    最后,我们刚刚准备的所有东西都必须进入模板。为此,您只需创建模板文件并向其中添加一些带有占位符的代码:

    <div class="form">
        <h2>Add new category</h2>
        <form method="post" action="?page=editCategory">
            <ul>
                <li><label>Kategori</label></li>
                <li><input type="text" class="inp" name="cname" 
                           value="{{category:name}}"></li>
                <li><label> Aç&#305;klama</label></li>
                <li><textarea class="inx" rows="10" cols="40" name="kabst">{{category:description}}</textarea></li>
                <li>
                    <input type="checkbox" class="ins" name="kselect" id="kselect">
                    <label for="kselect">Aktif/Pasif</label>
                </li>
                <li>Üst kategorisi</li>
                <li>
                    <select class="ins" name="subsl">
                        {{category:selectBoxOptions}}
                    </select>
                </li>
                <li>Home page:</li> 
                <li>
                    <input type="checkbox" class="ins" name="kradio" id="kradio">
                    <label for="kradio">Aktif/Pasif</label>
                </li>
                <li><input type="submit" class="int" value="ekle" name="ksubmit"></li>
            </ul>
        </form>
    </div>
    

    我们之所以使用模板而不是将所有的 HTML 写入函数,是因为我们希望将表示和逻辑分开。您可能正在与一个不懂 PHP 但会做 HTML 的设计师一起工作,这样您就可以轻松地划分工作。只需更改模板也很容易,而无需在 PHP 代码中搜索放置它的位置。

    接下来我们需要一种方法来替换占位符,也就是下面这个方法的用途:

    function getRenderedTemplate($template, $placeholder, $replacements)
    {
       return str_replace($placeholder, $replacements, file_get_contents($template));
    }
    

    这是一种极其简单的模板方法。您也可以使用 DOM 进行模板或 dedicated template engineTwig 或其他东西。对于这个例子,我只是想让它简单一点,所以我使用str_replace 将所有占位符替换为其对应的值,并将填充的模板返回给调用它的任何函数,例如

    if(is_numeric($_GET['id'])) {
        echo getCategoryFormEdit($_GET['id']);
    } else {
        die('Category ID must be numeric. Exiting');
    }
    

    就是这样。重构完成。我没有测试上面的代码,因此其中可能存在一些错误,但无论如何:重点是说明如何改进问题中显示的代码。基本上,每当您的函数看起来很长时,请尝试用文字描述代码。对于每个“和”,将代码重构为只做一件事的较小部分。通过这样做,我们得到了:

    • 从 SQL 返回行的可重用查询函数
    • 从数据库中获取所有类别的可重用函数
    • 按 ID 获取类别的可重用函数
    • 一个可重用的函数,从类别中创建一个选择框
    • 一个可重复使用的迷你模板引擎
    • 表示和业务逻辑分离
    • 修复了明显的 SQL 注入漏洞
    • 更好的可读性和可维护性。

    如果您在几周或几个月后回到代码中,您将很难弄清楚它的作用。

    【讨论】:

    • 多么彻底的答案!我希望有人每天都这样教我:)
    • 戈登,谢谢 :) 和反对票,对于大多数不阅读就投票问题的人来说是一种反射!并讽刺新手。敲门或者跟别人敲门都不是很好!
    【解决方案2】:

    我已经解决了这个问题:

    $selected = $d == $subcat ? " selected " : "";
    $text .= '<option value="'.$d.'" '.$selected.' >'.$r['name'].'</option>';
    
    function sQuery($x, $y) {
    
     $selected = $x == $y ? " selected " : "";
     return $selected;                                   
    }
    

    【讨论】:

      【解决方案3】:

      你需要在函数内部使用global关键字:

       function sQuery()
       {
          global $r['id'];
          global $subcat;
      
          if ($r['id'] == $subcat) {
            $t = "selected";
          } 
          else {
      
            $t = "";
          }
         return $t;
        }
      

      【讨论】:

      • 我在添加全局时遇到了同样的问题。
      • (旁注) 为什么不直接将$r['id']$subcat 传递给sQuery($id, $subcat)。比使用 global 关键字更简洁可靠。
      • @jasmine:确保您在比较正确的事物,同时检查/回显它们的($r['id']$subcat)值以查看您得到的结果。
      • @Gordon:同意,那肯定会是更好、更少的代码。
      • @Sarfraz 实际上,global 无法工作,因为整个代码不在全局范围内,而是一个函数。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多