<?php
include "config.php";
class Users extends Config {
public function login($username, $password) {
try {
$this->db->beginTransaction();
$stmt = $this->db->prepare("SELECT `username`, `password` FROM `users` WHERE `username` = ? AND `password` = ? LIMIT 1");
$stmt->execute(array($username, $password));
if($stmt->rowCount == 1) {
while($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
header("Location: index.php?p=loggedin");
exit();
}
} else {
header("Location: index.php?p=false");
exit();
}
$this->db->commit();
} catch(PDOException $ex) {
$this->db->rollBack();
echo $ex->getMessage();
}
}
}
$users = new Users();
?>
如上所示,我的代码有两个header()
方法,其中一个重定向到登录页面,而另一个重定向到错误页面。
我相信据我所知,我的脚本应该按照我的输入重新指向登录页面,这是正确的,但它的行为方式是出乎意料的。
它重定向到错误页面而不是登录页面。请看一看,告诉我它不起作用的原因?谢谢!此外,如果您发现我的代码中存在任何缺陷,请随意提出一些批评,因为我希望改善自己。非常感谢。
答案 0 :(得分:47)
我要发布一些有希望比上面那些帖子更有用的东西。这里有几种最佳实践可以让您在编码时更轻松;当然,当你把头包裹起来之后。
首先,这看起来像是您尝试应用程序的身份验证部分。如果用户传递了正确的用户名和密码,则需要显示正确的页面。我不知道你的申请范围,所以我不打算提出大的改变。
您好像手动包含文件。 PHP有spl_autoload_register,如果你关注PSR-0(你真的应该看一下),这意味着你可以将你的目录结构映射到你的类1:1并且有类<当您要求时,em>自动为您解决。因此,当您说new Object
,甚至(在您的情况下)extends Config
时,如果您的Config
班级位于您的最高级别,则会自动找到并使用它。这将让您了解namespaces。
一旦您了解了命名空间的工作原理以及自动加载如何为您节省development time(我的意思是长期的重要时间),您就可以转到依赖管理工具,如{{3} }。 Composer基本上是您运行的脚本,可以为您生成自动加载器,然后您在应用程序开始时需要做的就是require_once __DIR__ . "/vendor/autoload.php"
。但是说真的,看一些composer - 一旦你使用它们,你将永远不会回去,并且基本上会在你将来写的每一个应用程序中使用它们。
您也永远不需要多次输入include
- 如果您尝试包含的文件,只会抛出警告还没有找到。看起来这个文件需要配置文件,所以在这种情况下你应该使用require_once
- 这意味着你的代码将致命如果这个文件不是&#39;找到了(这似乎是你想要的)。
class Users extends Config
出了什么问题。至少做得好,至少有一个好的命名约定(类名称的上限)。基本上,extends
表示是-a 关系。您不仅扩展以获得额外的功能 - 这是代码味道。您在此处说User
是Config
。情况并非如此,如果您将来将此代码交给任何其他开发人员 - 他们就像&#34; WAIT,WTF&#34;。希望以更好的方式。
您的目标是:在类中拥有配置变量。所以,将它们传递给班级。我无法告诉您Config
课程中的内容,但您应该查看autoloading tutorials;这是Dependency Injection pattern。基本上,您可以通过DI(通过构造函数)传递Config
对象,然后解耦您的代码,以便您可以单独测试每个对象的优点,反而嘲笑其他对象。可测试的代码。依赖注入。谷歌吧。
因此,不延长Config
。改为通过您的配置:
class Users
{
/**
* @var Config
*/
protected $config;
/**
* @constructor
*
* @param Config $config The class configuration, duh
*/
public function __construct(Config $config)
{
$this->config = $config;
}
/** Snip **/
}
另请查看tutorial以帮助您编写其他开发人员可以轻松理解和解析的注释代码。
您还使用了您真正不需要用于SELECT
的交易。为什么不?由于交易允许您commit
或rollback
- 但是当您进行选择时,您不会更改任何数据。因此,执行交易毫无意义。请删除它们,然后尝试通过SELECT
检索数据。
每个类,每个对象,应该有一个改变的理由。它所做的一项任务就是它。如果您有一些从数据库中读取的代码,比较一些字符串并保存到文件,那么您至少应该有3个类:一个从持久性中读取,一个执行比较,另一个保存到文件。这被称为phpdoc syntax,你可以阅读和谷歌。
考虑到这一点,这个单独的班级不应该负责发送标题。返回true
或false
并让使用此类的类来代替。 不这个类的责任 - 这应该只处理身份验证。
如果您选择了框架,则可以在Controller
或View
中执行此操作,具体取决于您与Single Responsibility Principle模式的接近程度 - 这实际上是不可能的它对Web应用程序的最严格意义(我把它放在那里为肛门人员提供)但实际上 - 你应该将你的顾虑分开,至少在你的代码库中遵守SRP。
我绝不是安全专家,但您 所做的就是将您的用户名和密码传递给数据库。如果您正在哈希密码,那么您只需通过用户名从数据库中检索User
,然后计算密码是否与PHP代码中的哈希值匹配。这样您就不会将密码发送到数据库,这有助于(尽管只是一点点)对抗MVC。 PHP 5.5包含一些非常有用的SQL Injection函数来帮助您,但由于您可能不使用PHP 5.5,请查看password_*库。
什么是SQL注入?来自password_compat的更多信息,以及下面真正有用的图片。
这些只是一些指示,让您朝着更好的代码方向前进,您可以将其传递给其他能够理解它的开发人员,您可以为此感到自豪。看看像Bobby Tables这样的框架,这样您就不必担心身份验证,自动加载以及类似的事情 - 它们都是为您完成的。作曲家绝对是必须的。您需要逐个var_dump()
开始逐行调试代码,直到您看到不符合预期的内容为止。调试101,它将帮助您,并帮助我们为您提供更多帮助。