我注意到我是一个非常草率的编码员并做了一些与众不同的事情。
您可以查看我的代码并向我提供一些有关如何更有效地编码的提示吗?我该怎么做才能改善?
session_start();
/*check if the token is correct*/
if ($_SESSION['token'] == $_GET['custom1']){
/*connect to db*/
mysql_connect('localhost','x','x') or die(mysql_error());
mysql_select_db('x');
/*get data*/
$orderid = mysql_real_escape_string($_GET['order_id']);
$amount = mysql_real_escape_string($_GET['amount']);
$product = mysql_real_escape_string($_GET['product1Name']);
$cc = mysql_real_escape_string($_GET['Credit_Card_Number']);
$length = strlen($cc);
$last = 4;
$start = $length - $last;
$last4 = substr($cc, $start, $last);
$ipaddress = mysql_real_escape_string($_GET['ipAddress']);
$accountid = $_SESSION['user_id'];
$credits = mysql_real_escape_string($_GET['custom3']);
/*insert history into db*/
mysql_query("INSERT into billinghistory (orderid, price, description, credits, last4, orderip, accountid) VALUES ('$orderid', '$amount', '$product', '$credits', '$last4', '$ipaddress', '$accountid')");
/*add the credits to the users account*/
mysql_query("UPDATE accounts SET credits = credits + $credits WHERE user_id = '$accountid'");
/*redirect is successful*/
header("location: index.php?x=1");
}else{
/*something messed up*/
header("location: error.php");
}
答案 0 :(得分:4)
您的代码似乎非常标准。您可能应该使用某种缩进,并且对于MySQL查询使用prepared statements而不是仅在查询中间包含变量。从风格的角度来看,它虽然很好,但
答案 1 :(得分:3)
您可能希望研究使用框架,或者至少使用对象关系映射器。
如果您使用面向对象的方法,它确实使SQL操作非常容易。
例如,使用我的框架,只需几行代码就可以在填写注册表后创建新用户。当然,在对象后面封装了大量代码以防止任何有趣的业务或黑客攻击,但它使得使用起来非常简单。
$account = new Account();
$account->insert(array(
'userid' => $id,
'accountpass' => $passhash,
'accountemail' => $emailhash
));
我没有使用任何众所周知的框架或对象关系映射器,但我听说CodeIgniter,Kohana和Doctrine是一些好的。然而,他们有一个学习曲线,所以你应该事先知道你的应用程序是否足以保证学习另一个API。
答案 2 :(得分:3)
通过GET传递信用卡号和IP地址不是很安全,包含GET字符串的URL可能会保留在浏览器历史记录中。你是如何分配$_GET['ipAddress']
的?您应该使用$_SERVER['REMOTE_ADDR']
代替。
要获取信用卡的最后4位数字,您可以执行以下操作来保存几行代码:
$last4 = substr($cc,-4);
答案 3 :(得分:1)
在这里取决于你所说的“干净”。整个过程将从基本缩进中受益匪浅 - 几乎就是将现有的空白移动到更高效的地方。 (你的换行似乎非常不一致,只有一个。)缩进和换行一致性极大地提高了代码的可读性。
在下一个级别的样式中,我知道为什么你需要在那里分配大量的变量,因为你正在使用原始的MySQL函数。如果您打算坚持使用该系统,至少以合理的顺序分配变量,更不用说我在下面做了一些其他更改和注释。
// Let's just strip all non-numerics from the card number so that we can validate it.
$cc = preg_replace('/[^0-9]/', '', $_GET['Credit_Card_Number']);
if(strlen($cc) != 12) {
// The card number is invalid; go back to form and try again.
}
$last4 = substr($cc, -4); // A negative start value is cleaner.
$accountid = $_SESSION['user_id'];
$amount = mysql_real_escape_string($_GET['amount']);
$credits = mysql_real_escape_string($_GET['custom3']);
// note: don't trust that users won't change the ipAddress parameter before submitting
$ipaddress = mysql_real_escape_string($_GET['ipAddress']);
$orderid = (int) $_GET['order_id'];
$product = mysql_real_escape_string($_GET['product1Name']);
我将变量赋值分成三个块。第一个用于数据转换,第二个用于从非GET源获取数据,第三个是从$_GET
变量的基本分配,按字母顺序排序。现在,分配更加结构化,并且很容易找到任何给定的行。 (当然,这绝不是一种破坏事物的标准方式;它只是在这里有意义的。)
关于优秀代码的重要性 - 您可以轻松维护。做任何最适合你的事情,但我怀疑,从长远来看,代码可读性和有组织的变量赋值运作良好。
此外,正如其他人所提到的,考虑使用PDO这样的数据库操作,这允许您使用预准备语句并避免所有这些转义函数。您可能还想查看类似Doctrine的ORM,或者可能是完整的framework。使用功能更强大的工具具有更高的学习曲线,但一旦精通OOP,也可以提高工作效率。
答案 4 :(得分:1)
对我而言,第一件事就是代码中存在一个相当大的安全漏洞。通过将$ _GET变量直接放入SQL查询中,您可以接受各种攻击。此外,由于它似乎使用获取数据进行计费,因此可以通过使用获取变量来操纵自己的帐户余额。
我会建议对传入的GET数据进行一些数据检查,然后再将其转储到数据库中。
答案 5 :(得分:1)
我想补充一点,每当你看到自己重复同样的动作时,你可能想要创建一个函数。
如果明天要更改数据转义方式,则必须编辑所有使用mysql_real_escape_string
的行。
为什么不添加诸如
之类的功能function escape_data($data) {
$escaped_data = mysql_real_escape_string($data);
// room for more actions ...
return ($escaped_data);
}
另外,如果您将相同的函数应用于数组的所有成员(此处为$ _GET),您可能会发现array_map()
有用:
$_GET = array_map('escape_data', $_GET);