2

我开始怀疑Oreily出版社是否严重降低了标准或什么。我什至不打算讨论我从他们那里得到的前两本 PHP 书籍,但是这第三本似乎也很混乱。

无论如何,这就是问题所在。在我正在研究的书中的项目中,书中说要创建一个用户数据库,然后基于该数据库创建一个允许用户登录的程序。下面是应该完成此操作的代码:

创建用户数据库:

    <?php //setupusers.php
    require_once 'login.php';
    $db_server = mysql_connect($db_hostname, $db_username, $db_password);
    if (!$db_server) die("Unable to connect to MySQL: " . mysql_error());
    mysql_select_db($db_database)
        or die("Unable to select database: " . mysql_error());

    $query = "CREATE TABLE users (
                forename VARCHAR(32) NOT NULL,
                surname  VARCHAR(32) NOT NULL,
                username VARCHAR(32) NOT NULL UNIQUE,
                password VARCHAR(32) NOT NULL
            )";

    $result = mysql_query($query);
    if (!$result) die ("Database access failed: " . mysql_error());

    $salt1 = "qm&h*";
    $salt2 = "pg!@";

    $forename = 'Bill';
    $surname  = 'Smith';
    $username = 'bsmith';
    $password = 'mysecret';
    $token    = md5("$salt1$password$salt2");
    add_user($forename, $surname, $username, $token);

    $forename = 'Pauline';
    $surname  = 'Jones';
    $username = 'pjones';
    $password = 'acrobat';
    $token    = md5("$salt1$password$salt2");
    add_user($forename, $surname, $username, $token);

    function add_user($fn, $sn, $un, $pw)
    {
        $query = "INSERT INTO users VALUES('$fn', '$sn', '$un', '$pw')";
        $result = mysql_query($query);
        if (!$result) die ("Database access failed: " . mysql_error());
    }
    ?>

允许用户登录

<?php // authenticate.php
require_once 'login.php';
$db_server = mysql_connect($db_hostname, $db_username, $db_password);
if (!$db_server) die("Unable to connect to MySQL: " . mysql_error());
mysql_select_db($db_database)
    or die("Unable to select database: " . mysql_error());

if (isset($_SERVER['PHP_AUTH_USER']) &&
    isset($_SERVER['PHP_AUTH_PW']))
{
    $un_temp = mysql_entities_fix_string($_SERVER['PHP_AUTH_USER']);
    $pw_temp = mysql_entities_fix_string($_SERVER['PHP_AUTH_PW']);

    $query = "SELECT * FROM users WHERE username='$un_temp'";
    $result = mysql_query($query);
    if (!$result) die("Database access failed: " . mysql_error());
    elseif (mysql_num_rows($result))
    {
        $row = mysql_fetch_row($result);
        $salt1 = "qm&h*";
        $salt2 = "pg!@";
        $token = md5("$salt1$pw_temp$salt2");

        if ($token == $row[3]) echo "$row[0] $row[1] : 
            Hi $row[0], you are now logged in as '$row[2]'";
        else die("Invalid username/password combination");
    }
    else die("Invalid username/password combination");
}
else
{
    header('WWW-Authenticate: Basic realm="Restricted Section"');
    header('HTTP/1.0 401 Unauthorized');
    die ("Please enter your username and password");
}

function mysql_entities_fix_string($string)
{
    return htmlentities(mysql_fix_string($string));
}   

function mysql_fix_string($string)
{
    if (get_magic_quotes_gpc()) $string = stripslashes($string);
    return mysql_real_escape_string($string);
}
?>

问题是,我永远不会收到错误消息,也永远不允许登录。我可以在程序生成的弹出窗口中输入用户名和密码,但输入正确或不正确的任何内容都不会发生任何事情。当我点击“确定”时,用户名和密码字段就被清除了。

我怀疑它与这条线有关:

$query = "SELECT * FROM users WHERE username='$un_temp'";

但我不知道。

仅供参考,这里是一个包含用户代码的 sql 文件。

-- MySQL dump 10.13  Distrib 5.1.50, for Win32 (ia32)
--
-- Host: localhost    Database: publications
-- ------------------------------------------------------
-- Server version   5.1.50-community

/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;

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

DROP TABLE IF EXISTS `users`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `users` (
  `forename` varchar(32) NOT NULL,
  `surname` varchar(32) NOT NULL,
  `username` varchar(32) NOT NULL,
  `password` varchar(32) NOT NULL,
  UNIQUE KEY `username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Dumping data for table `users`
--

LOCK TABLES `users` WRITE;
/*!40000 ALTER TABLE `users` DISABLE KEYS */;
INSERT INTO `users` VALUES ('Bill','Smith','bsmith','be9d31ad4315b2ad9900a8526cd3edb1'),('Pauline','Jones','pjones','b1334d37914cf7561a006f656e27600c');
/*!40000 ALTER TABLE `users` ENABLE KEYS */;
UNLOCK TABLES;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

-- Dump completed on 2012-12-31 11:38:10

是的,我知道这里的一些代码可能是“旧的”。

请听我说完。如果您想推荐一本不使用“旧”代码的 PHP 书籍或教程,请这样做。我正在努力学习这种编程语言。

但是,如果您只是不知道如何解决其中的“旧”代码,请不要浪费我的时间告诉我它是“旧”作为“答案”。任何语言中都没有任何功能会因为某行代码“旧”或“未充分使用”而强制程序无法运行。这只在代码行实际上不再被识别时才重要。我想我最终必须学得更好,但现在我正试图首先学习 php!

4

3 回答 3

1

有问题的书(学习 PHP、MySQL、JavaScript 和 CSS)清楚地表明,并非在所有 Web 服务器上都启用了基本身份验证。这是有充分理由的;除非您的网站使用 https,否则它不可能不安全(一个简单的数据包嗅探器可以从会话中的任何 Web 请求中恢复纯文本用户名和密码)。

如果它在您的 Web 服务器上不可用,那么事情就会默默地失败。这是进行 Web 开发的挑战性(=== 痛苦)方面之一。

Web 安全很难做到正确,因此您可能需要考虑在称职的内容管理系统 (CMS) 之上构建系统,而不是创建自己的身份验证/授权包。这是一篇由 WordPress 开发人员撰写的有用文章,它可以让您了解该主题的一些微妙之处。

http://markjaquith.wordpress.com/2006/06/02/wordpress-203-nonces/

我想这对你未来的用户来说是件好事,这个例子对你不起作用。即使代码有效,它也有一个不安全的盐算法以及基本身份验证问题。

于 2013-01-01T01:10:32.887 回答
0

不要只是盲目地复制/粘贴示例代码并期望它能够工作,请尝试以下操作:

  1. 写几行。
  2. 测试一下
  3. 修复任何出错的地方。
  4. 测试一下
  5. 起泡,冲洗,重复直到完成。

这既是使用其他人的示例代码的最佳方式,也是编写自己的原始代码的最佳方式。

您应该在代码中检查一些事情:

  • 在向 mySQL 发送查询之前,您应该回显该查询以确保它已由您的程序逻辑正确形成。
  • 运行查询后,您应该查看结果集是否返回了预期值,或者在插入的情况下,预期值是否已正确插入。

你从人们那里得到如此多的吹嘘的原因是你似乎没有自己做过这个测试,这是我们大部分时间都在用我们自己的代码做的事情。对我来说,通常是 15% 的写作,75% 的测试,10% 的诅咒/饮酒。

于 2012-12-31T19:41:00.550 回答
0

@David 我感到沮丧。我在没有事先创建数据库的情况下尝试了这个示例(例如,引用本地主机上的现有数据库)并且盐算法失败了。对我来说,有关的错误

    $token = md5($salt1$pw$salt2); 

也就是说,在哪里$pw 被称为“意外发生”。不是真的,但我几乎认为他们这样做是为了迫使我们学习 PDO。

于 2013-03-02T01:51:04.410 回答