PHP for Beginners: Building Your First Simple CMS

Avatar of Jason Lengstorf
Jason Lengstorf on

DigitalOcean 为您旅程的每个阶段提供云产品。从 $200 免费额度 开始!

PHP + MySQL 的魔力

可以肯定地说,如今几乎每个最新网站都使用某种形式的内容管理系统 (CMS)。虽然有很多很棒的免费选项可以为我们提供一个 CMS 来为网站提供动力(WordPress、Drupal 等),但窥视一下引擎盖并了解这些系统的工作原理并不会有什么坏处。

为了开始我们作为后端开发人员的旅程,我们将创建一个简单的 PHP 类,它将

  • 创建一个数据库
  • 连接到数据库
  • 显示包含两个字段的表单
  • 将表单数据保存到数据库
  • 从数据库中显示已保存的数据

下载文件

这个类旨在让您了解 PHP 和 MySQL 如何协同工作,并展示 CMS 的基础知识。我将跳过对一些非常基础的编程内容的解释,所以如果您在任何时候感到迷茫,请查看课程 Diving into PHP 并给自己上一节关于 PHP 的速成课程。不过,我保证不会让任何人迷路。

构建类

第一步是将类简单地放在名为“simpleCMS.php”的文件中,以便我们有一个可以参考的路线图。

<?php

class simpleCMS {
  var $host;
  var $username;
  var $password;
  var $table;

  public function display_public() {
    
  }

  public function display_admin() {
    
  }

  public function write() {
    
  }

  public function connect() {
    
  }

  private function buildDB() {
    
  }
}

?>

如您所见,我们正在创建一个包含四个变量和五个方法的类。我选择使用 PHP 的 面向对象方法,因为它在大型项目中可以生成更清晰的代码,并且在我看来,这是一种良好的实践。

变量

在这种情况下,所有四个变量都用于连接到数据库:$host$username$password$table 为我们提供了一个路径和访问权限来访问服务器上的数据库。目前,我们将它们留空并继续进行数据库构建,该数据库由方法 buildDB() 构建。

构建数据库

private function buildDB() {
    $sql = <<<MySQL_QUERY
        CREATE TABLE IF NOT EXISTS testDB (
            title	VARCHAR(150),
            bodytext	TEXT,
            created	VARCHAR(100)
    )
    MySQL_QUERY;

    return mysql_query($sql);
}

此函数运行一个 MySQL 命令来检查数据库,查看testDB是否存在。如果存在,它只传递一条成功通知;如果不存在,它将创建我们的表并将三个列分配给它以保存数据。

连接到数据库

现在我们有了构建表的函数,让我们创建连接到数据库的函数。

public function connect() {
    mysql_connect($this->host,$this->username,$this->password) or die("Could not connect. " . mysql_error());
    mysql_select_db($this->table) or die("Could not select database. " . mysql_error());

    return $this->buildDB();
}

我们调用 mysql_connect() 来连接到我们的数据库,然后调用 mysql_select_db() 来确保我们将数据保存到正确的位置。这两个函数都伴随有 die() 命令,该命令本质上是说:“如果该函数失败,则停止执行该脚本并显示一条消息。”

我们的 connect() 函数连接到数据库并让我们指向正确的方向,然后运行我们的 buildDB() 函数。还记得我们 MySQL 命令中语法尴尬的“IF NOT EXISTS”部分吗?因为我们将每次加载页面时运行此函数,所以我们必须确保我们不会在每次函数调用时覆盖我们的数据库,这就是该短语的用途。

构建表单

所以,我们有一个数据库。现在我们只需要往里面填东西!

public function display_admin() {
    return <<<ADMIN_FORM

    <form action="{$_SERVER['PHP_SELF']}" method="post">
      <label for="title">Title:</label>
      <input name="title" id="title" type="text" maxlength="150" />
      <label for="bodytext">Body Text:</label>
      <textarea name="bodytext" id="bodytext"></textarea>
      <input type="submit" value="Create This Entry!" />
    </form>

ADMIN_FORM;
}

同样,这是一个非常简单的函数。当被调用时,它只是返回 HTML 标记来创建我们的表单。但是,您会注意到,在 form 元素的 action 属性中,我使用了变量 $_SERVER['PHP_SELF']。这本质上是一个引用您当前使用的文件的快捷方式(在本例中,它是 display.php)。如果您将在整个网站中重复使用您的代码,并且不想为每个页面重新编写此函数,这将非常有用。

我还要花点时间来讨论一下我用于返回 HTML 的方法。它是一种在 PHP 中使用的格式,称为 HEREDOC 语法,而且我非常喜欢它。

HEREDOC 的主要优势是它允许您在输出中包含格式。对于像我这样对杂乱的源代码感到不满的人来说,这非常有用。您可以在 PHP 手册 中了解有关 HEREDOC 语法及其同类的更多信息。

将数据保存到数据库

我们的表单将允许我们输入信息,那么我们如何保存它呢?这就是我们的write()方法发挥作用的地方。

public function write($p) {
    if ( $p['title'] )
      $title = mysql_real_escape_string($p['title']);
    if ( $p['bodytext'])
      $bodytext = mysql_real_escape_string($p['bodytext']);
    if ( $title && $bodytext ) {
      $created = time();
      $sql = "INSERT INTO testDB VALUES('$title','$bodytext','$created')";
      return mysql_query($sql);
    } else {
      return false;
    }
}

让我们从函数调用本身开始——我们向它传递了一个变量,而之前我们还没有这样做。我们的变量 $p 将保存通过 post 方法 从我们的表单发送的信息。

进入函数后,我们首先使用一个 条件语句 来检查在提交表单之前是否设置了 title 值,如果设置了,我们将 $title 变量设置为 $_POST['title'] 值(注意:我们使用的是函数 mysql_real_escape_string() 作为对潜在危险输入的预防措施,这一点在构建任何允许用户输入信息的程序时都要牢记)。如果 $_POST['title'] 未设置,我们将跳过此行,使 $title 变量保持未设置状态。

这个过程会对我们的第二个输入重复,然后检查两个变量以确保在保存到数据库之前没有为空。如果两个变量都已设置,我们将使用当前的 Unix 时间戳 设置 $created 变量,我们将在将来查看条目时使用它按时间顺序排序条目。

现在我们有三个变量,并且由于我们已经运行了检查,我们知道所有三个变量都不为空。现在我们可以编写我们的 MySQL 查询,该查询将把条目保存到数据库中!

从数据库中显示信息

现在我们有了将信息放入数据库的方法,我们需要创建一种方法来将该信息取回。这就是 display_public() 发挥作用的地方。这是我们最复杂的方法,所以让我们花点时间真正弄清楚内部发生了什么。

public function display_public() {
    $q = "SELECT * FROM testDB ORDER BY created DESC LIMIT 3";
    $r = mysql_query($q);

    if ( $r !== false && mysql_num_rows($r) > 0 ) {
      while ( $a = mysql_fetch_assoc($r) ) {
        $title = stripslashes($a['title']);
        $bodytext = stripslashes($a['bodytext']);

        $entry_display .= <<<ENTRY_DISPLAY

    <h2>$title</h2>
    <p>
      $bodytext
    </p>

ENTRY_DISPLAY;
      }
    } else {
      $entry_display = <<<ENTRY_DISPLAY

    <h2>This Page Is Under Construction</h2>
    <p>
      No entries have been made on this page. 
      Please check back soon, or click the
      link below to add an entry!
    </p>

ENTRY_DISPLAY;
    }
    $entry_display .= <<<ADMIN_OPTION

    <p class="admin_link">
      <a href="{$_SERVER['PHP_SELF']}?admin=1">Add a New Entry</a>
    </p>

ADMIN_OPTION;

    return $entry_display;
  }

在从数据库中读取时,需要注意的第一件事是 PHP 和 MySQL 如何相互作用。首先,我们向数据库提出一个问题(查询),数据库会用一个结果(资源)来回答。但是,在使用几种将结果中的信息“获取”或组织成可使用形式(数组)的方法对其进行解码之前,这个结果并不真正有用。

在上面这个函数中,我们首先要做的就是在变量$q中设置我们的查询。MySQL 中的星号 (*) 操作符表示“所有”,所以我们的查询要求数据库从testDB表中的条目中选择所有内容,并按时间倒序排列,限制为返回的前三个条目。

现在查询已经定义好了,我们使用函数mysql_query()将它发送到数据库。结果资源存储在变量$r中。这里就有点棘手了。

现在我们运行一个条件语句,它说:“如果mysql_query()没有失败,并且如果返回的条目数量大于零,就处理结果,否则就显示一个默认消息。”

如果$r包含来自数据库的条目,我们现在必须“提取”这些数据。来自数据库的信息以数组形式返回,其组织方式类似于数据库表本身。函数mysql_fetch_assoc()将获取资源并将每个条目分解为一个关联数组(这意味着当我们将mysql_fetch_assoc()的结果保存到变量$a中时,来自条目的数据可以通过数据库中的列名访问,例如$a['title'])。

然而,mysql_fetch_assoc()一次只能给我们一个条目。为了获取所有返回的条目,我们必须使用一个while循环。本质上,我们是在说:“当$r还有我们尚未使用过的值时,获取下一行条目并对它执行以下操作。”

在这种情况下,我们将检查条目以确保数据已返回,然后使用stripslashes()删除我们在使用stripslashes()将信息保存到数据库时添加的反斜杠。之后,我们只需将变量包装在一些HTML中,瞧!我们得到了可以显示在屏幕上的内容!

作为最后一步,代码在底部添加了一个链接,允许用户添加条目。值得注意的是在while循环中以及在创建“添加新条目”链接时使用的“.=”操作符;一个函数只能返回一个变量,所以我们需要将新信息追加到现有变量中。如果我们只使用等号(“=”),我们将覆盖现有数据,最终只会得到一个指向表单的链接,而没有内容。

所以,你现在已经写了你的第一个CMS类!你可以轻松地将数据写入数据库和从数据库中检索数据。剩下的就是去尝试一下了!

使用这个类

为了使用我们的类,我们需要创建一个单独的文件。我将把它命名为“display.php”,我将在主网页文件夹中保存它,我们的类保存在主文件夹中的“_class”文件夹中,命名为“simpleCMS.php”。首先,我们只需设置一个带有普通HTML的文档。

<!DOCTYPE html>
<html lang="en">

  <head>
    <title>SimpleCMS</title>
  </head>

  <body>

  </body>

</html>

为了使用我们的类,我们只需在body标签之间插入一小段PHP代码即可

<?php

  include_once('_class/simpleCMS.php');
  $obj = new simpleCMS();
  $obj->host = 'database.host.net';
  $obj->username = 'DB1234567';
  $obj->password = 'DBpassword';
  $obj->table = 'DB1234567';
  $obj->connect();

  if ( $_POST )
    $obj->write($_POST);

  echo ( $_GET['admin'] == 1 ) ? $obj->display_admin() : $obj->display_public();

?>

首先,我们必须使用include_once()函数包含这个类。然后,我们必须实例化我们的对象,以便我们的代码知道发生了什么。第三,我们设置了我们在本教程开头谈到的所有那些变量。你必须用从你自己的服务器或托管公司获得的信息替换所有这些值。第四,我们使用connect()方法连接到数据库。

连接到数据库后,我们检查是否有任何$_POST信息存在。这是因为我们使用同一个文件来输入、处理和显示信息。如果通过$_POST传递了任何内容,我们将运行write()函数来验证它并将其保存到数据库中。然后,我们使用一些简写技巧来运行一个条件语句。从本质上讲,我们是在说,“如果$_GET['admin']设置为1,那么使用display_admin()显示表单,否则使用display_public()显示存储的条目。”

就是这样!一旦你对它有了感觉,这种基本的编程将让你开始对构建的网站行使完全控制权,无论你决定深入研究并构建自己的CMS框架,还是仅仅通过例如编写一个WordPress插件来改进现有的CMS。

真的,当涉及到现代网页设计时,你至少应该对幕后发生的事情有一些了解——了解一个网站如何工作,将更有助于你设计出形式和功能更流畅集成的网站。此外,将PHP和MySQL添加到你的简历中肯定不会损害你的信誉……

下载文件

Jason Lengstorf 经营着Ennui Design,一家自由职业设计和开发公司。他热衷于从头开始构建定制应用程序,包括他自己的内容管理系统。当他不粘在键盘上时,他很可能穿着牛仔衬衫,举重,或者假装对葡萄酒很了解。

重要提示

此代码仅用于演示目的。评论中指出了几个安全漏洞,我在本教程系列的第二部分 编辑说明:本系列已经没有第二部分了。Jason 建议他的书PHP for Absolute Beginners 作为最佳实践资源。中进行了处理。不过,我还是强烈建议不要在没有进一步测试的情况下将其用于生产网站。

我已经对安全问题进行了处理,但可能还存在其他问题。有关安全风险和安全PHP代码的更多信息,请参见此处。请在将此代码部署到服务器上之前仔细阅读,以避免潜在的安全漏洞。