基础
我创建了一个简单的评论系统。我的目标是创建一个可以轻松地在每个人的服务器上使用的系统,而不必安装大量的程序。我也试图创造尽可能隐私友好(没有电子邮件地址,没有饼干)。我也需要在没有数据库的情况下解决这个问题。
功能

<#>代码
simpleComments.php
该脚本提供了主要功能:垃圾邮件保护(有来自这里和这里的建议)、发送、回答和标记评论。我认为,尤其是函数save()看起来是一个相当棘手的解决方案。如果你知道更好的选择(没有数据库),我会很高兴听到它。
//The password for the AES-Encryption (has to be length=16)
$encryptionPassword = "****************";
//============================================================================================
//============================================================================================
// ==
// FROM HERE ON NO ADJUSTMENT NECESSARY ==
// ==
//============================================================================================
//============================================================================================
/**
* Creates image
*
* This function creates a black image with the random exercise created by randText() on it.
* Additionally the function adds some random lines to make it more difficult for bots to read
* the text via OCR. The result (for example) looks like this: https://imgur.com/a/6imIE73
*
* @author Philipp Wilhelm
*
* @since 1.0
*
* @param string $rand Random exercise created by randText()
* @param int $width Width of the image (default = 200)
* @param int $height Height of the image (default = 50)
* @param int $textColorRed R-RGB value for the textcolor (0-255) (default = 255)
* @param int $textColorGreen G-RGB value for the textcolor (0-255) (default = 255)
* @param int $textColorBlue B-RGB value for the textcolor (0-255) (default = 255)
* @param int $linesColorRed R-RGB value for the random lines (0-255) (default = 192)
* @param int $linesColorGreen G-RGB value for the random lines (0-255) (default = 192)
* @param int $linesColorBlue B-RGB value for the random lines (0-255) (default = 192)
* @param int $fontSize font size of the text on the image (1-5) (default = 5)
* @param int $upperLeftCornerX x-coordinate of upper-left corner of the first char (default = 18)
* @param int $upperLeftCornerY y-coordinate of the upper-left corner of the first char (default = 18)
* @param int $angle angle the text will be rotated by (default = 10)
*
* @return string created image surrounded by
*/
function randExer($rand, $width = 200, $height = 50, $textColorRed = 255, $textColorGreen = 255,
$textColorBlue = 255, $linesColorRed = 192, $linesColorGreen = 192, $linesColorBlue = 192,
$fontSize = 5, $upperLeftCornerX = 18, $upperLeftCornerY = 18, $angle = 10) {
global $encryptionPassword;
$random = openssl_decrypt($rand,"AES-128-ECB", $encryptionPassword);
$random = substr($random, 0, -40);
//Creates a black picture
$img = imagecreatetruecolor($width, $height);
//uses RGB-values to create a useable color
$textColor = imagecolorallocate($img, $textColorRed, $textColorGreen, $textColorBlue);
$linesColor = imagecolorallocate($img, $linesColorRed, $linesColorGreen, $linesColorBlue);
//Adds text
imagestring($img, $fontSize, $upperLeftCornerX, $upperLeftCornerY, $random . " = ?", $textColor);
//Adds random lines to the images
for($i = 0; $i < 5; $i++) {
imagesetthickness($img, rand(1, 3));
$x1 = rand(0, $width / 2);
$y1 = rand(0, $height / 2);
$x2 = $x1 + rand(0, $width / 2);
$y2 = $y1 + rand(0, $height / 2);
imageline($img, $x1, $x2, $x2, $y2, $linesColor);
}
$rotate = imagerotate($img, $angle, 0);
//Attribution: https://stackoverflow.com/a/22266437/13634030
ob_start();
imagejpeg($rotate);
$contents = ob_get_contents();
ob_end_clean();
$imageData = base64_encode($contents);
$src = "data:" . mime_content_type($contents) . ";base64," . $imageData;
return "";
};
/**
* Returns time stamp
*
* This function returns the current time stamp, encrypted with AES, by using the standard function time().
*
* @author Philipp Wilhelm
*
* @since 1.0
*
* @return int time stamp
*/
function getTime() {
global $encryptionPassword;
return openssl_encrypt(time() . bin2hex(random_bytes(20)),"AES-128-ECB", $encryptionPassword);
}
/**
* Creates random exercise
*
* This function creates a random simple math-problem, by choosing two random numbers between "zero" and "ten".
* The result looks like this: "three + seven"
*
* @author Philipp Wilhelm
*
* @since 1.0
*
* @return string random exercise
*/
function randText() {
global $encryptionPassword;
//Creating random (simple) math problem
$arr = array("zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten");
$item1 = $arr[array_rand($arr)];
$item2 = $arr[array_rand($arr)];
$random = $item1 . " + " . $item2;
$encrypted = openssl_encrypt($random . bin2hex(random_bytes(20)),"AES-128-ECB", $encryptionPassword);
return $encrypted;
}
/**
* flags comment
*
* This function sends an email to the specified adress containing the id of the flagged comment
*
* @author Philipp Wilhelm
*
* @since 1.0
*
* @param string $to Email-adress the mail will be send to
* @param string $url URL of the site the comment was flagged on
*
*/
function flag($to, $url) {
//Which comment was flagged?
$id = $_POST["comment"];
//At what side was the comment flagged?
$referer = $_SERVER["HTTP_REFERER"];
$subject = "FLAG";
$body = $id . " was flagged at " . $referer . ".";
//Send the mail
mail($to, $subject, $body);
//Redirect to what page after flag?
//(In this case to the same page)
header("Location:" . $url);
exit();
}
/**
* redirects to the same page, but with the added parameter to specify to which
* comment will be answered and jumps right to the comment-form
*
*
* @author Philipp Wilhelm
*
* @since 1.0
*
* @param string $url the url of the current page
* @param string $buttonName URL of the site the comment was flagged on
* @param string $urlName the "id-name"
*
*/
function answer($url, $buttonName, $urlName) {
header("Location:" . $url . "?" . $urlName . "=" . $_POST["comment"] . "#" . $buttonName);
exit();
}
/**
* error message
*
* Redirects to the specified url to tell the user that something went wrong
* e.g. entered wrong solution to math-exercise
*
* @author Philipp Wilhelm
*
* @since 1.0
*
* @param string $urlError The specified url
*
*/
function error($urlError) {
header("Location:" . $urlError);
die();
}
/**
* Redirects to specified url when user enters words that are on the "blacklist"
*
* @author Philipp Wilhelm
*
* @since 1.0
*
* @param string $urlBadWords The specified url to which will be redirected
*
*/
function badWords($urlBadWords) {
header("Location:" . $urlBadWords);
die();
}
/**
* Redirects to same url after comment is successfully submitted - comment will be visible
* immediately
*
* @author Philipp Wilhelm
*
* @since 1.0
*
* @param string $url URL of the site
*
*/
function success($url) {
header("Location:" . $url);
die();
}
/**
* checks if user enters any words that are on the "blacklist"
*
* @author Philipp Wilhelm
*
* @since 1.0
*
* @param string $text The user-entered text
* @param string $blackList filename of the "blacklist"
*
* @return boolean true if user entered a word that is on the "blacklist"
*
*/
function isForbidden($text, $blackList) {
//gets content of the blacklist-file
$content = file_get_contents($blackList);
$text = strtolower($text);
//Creates an array with all the words from the blacklist
$explode = explode(",", $content);
foreach($explode as &$value) {
//Pattern checks for whole words only ('hell' in 'hello' will not count)
$pattern = sprintf("/\b(%s)\b/",$value);
if(preg_match($pattern, $text) == 1) {
return true;
}
}
return false;
}
/**
* saves a new comment or an answer to a comment
*
* @author Philipp Wilhelm
*
* @since 1.0
*
* @param string $url Email-adress the mail will be send to
* @param string $urlError URL to the "error"-page
* @param string $urlBadWords URL to redirect to , when user uses words on the "blacklist"
* @param string $blacklist filename of the blacklist
* @param string $fileName filename of the file the comments are stored in
* @param string $nameInputTagName name of the input-field for the "name"
* @param string $messageInputTagName name of the input-field for the "message"
* @param string exerciseInputTagName name of the input-field the math-problem is stored in
* @param string solutionInputTagName name of the input-field the user enters the solution in
* @param string $answerInputTagName in this field the id of the comment the user answers to is saved
* (if answering to a question)
* @param string $timeInputTagName name of the input-field the timestamp is stored in
*
*/
function save($url, $urlError, $urlBadWords, $blacklist, $fileName, $nameInputTagName, $messageInputTagName, $exerciseInputTagName, $solutionInputTagName, $answerInputTagName, $timeInputTagName) {
global $encryptionPassword;
$solution = filter_input(INPUT_POST, $solutionInputTagName, FILTER_VALIDATE_INT);
$exerciseText = filter_input(INPUT_POST, $exerciseInputTagName);
if ($solution === false || $exerciseText === false) {
error($urlError);
}
$time = openssl_decrypt($_POST[$timeInputTagName], "AES-128-ECB", $encryptionPassword);
if(!$time) {
error($urlError);
}
$time = substr($time, 0, -40);
$t = intval($time);
if(time() - $t > 300) {
error($urlError);
}
//Get simple math-problem (e.g. four + six)
$str = openssl_decrypt($_POST[$exerciseInputTagName], "AES-128-ECB", $encryptionPassword);
$str = substr($str, 0, -40);
if (!$str) {
error($urlError);
}
$arr = array("zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten");
//gets array with written numbers
$words = array_map("trim", explode("+", $str));
//gets the numbers as ints
$numbers = array_intersect($arr, $words);
if (count($numbers) != 2) {
error($urlError);
}
$sum = array_sum(array_keys($numbers));
$urlPicture = "identicon.php/?size=24&hash=" . md5($_POST[$nameInputTagName]);
//Did user enter right solution?
if ($solution == $sum) {
$name = $_POST[$nameInputTagName];
$comment = htmlspecialchars($_POST[$messageInputTagName]);
$content = file_get_contents($fileName);
if(strcmp($content, "No comments yet!") == 0 || strcmp($content, "No comments yet!\n") == 0) {
$content = "Identicons created with identicon.php (licensed under GPL-3.0).";
}
$id = bin2hex(random_bytes(20));
$answerID = $_POST[$answerInputTagName];
//Checks if user used any words from the blacklist
if(isForbidden($comment, $blacklist)) {
badWords($urlBadWords);
}
//Case the user writes a new comment (not an answer)
if(strlen($answerID) < 40) {
file_put_contents($fileName,
//Needed styles
"" .
".commentBox {" .
"display: block;" .
"background: LightGray;" .
"width: 90%;" .
"border-radius: 10px;" .
"padding: 10px;" .
"margin-bottom: 5px;" .
"} " .
"input[name='flag'], input[name='answer'] {" .
"border: none;" .
"padding: 0;" .
"margin: 0;" .
"margin-top: 5px;" .
"padding: 2px;" .
"background: transparent;" .
"}" .
"" .
//get random avatar
"" .
//Displaying user name
" " . $name . " says:
" .
//Current UTC-time and -date
"" . gmdate("d-m-Y H:i") . " UTC
" .
//The main comment
"" .
$comment . "
" .
"".
"" .
//Flag-button
"" .
"" .
"" .
"" .
//Answer-button
"" .
"" .
"" .
"" .
"" .
"" .
"
" .
$content);
success($url);
}
//Case that user writes an answer
else {
if(strpos($content, $answerID) !== false) {
$explode = explode("", $content);
file_put_contents($fileName,
$explode[0] . "" . "
" .
//Needed styles
"" .
".answerBox {" .
"display: block;" .
"background: LightGray;" .
"width: 90%;" .
"border-radius: 10px;" .
"padding: 10px;" .
"margin-bottom: 5px;" .
"} " .
"input[name='flag'] {" .
"border: none;" .
"padding: 0;" .
"margin: 0;" .
"margin-top: 5px;" .
"padding: 2px;" .
"background: transparent;" .
"}" .
"" .
"" .
//get random avatar
"" .
//Displaying user name
" " . $name . " says:
" .
//Current UTC-time and -date
"" . gmdate("d-m-Y H:i") . " UTC
" .
//The main comment
"" .
$comment . "
" .
"".
//Flag-button
"" .
"" .
"" .
"" .
"
" .
"" .
"" .
$explode[1]);
success($url);
}
}
}
error($urlError);
}
//============================================================================================
//============================================================================================
// ==
// FROM HERE ON ADJUSTMENT ARE NECESSARY ==
// ==
//============================================================================================
//============================================================================================
/**
* start point of the script
*
* @author Philipp Wilhelm
*
* @since 1.0
*
*
*/
function start() {
//To what email-adress should the flag-notification be send?
$to = "example@example.com";
//What's the url you are using this system for? (exact link to e.g. the blog-post)
$url = "https://example.com/post001.html";
//Which page should be loaded when something goes wrong?
$urlError = "https://example.com/messageError.html";
//What page should be loaded when user submits words from your "blacklist"?
$urlBadWords = "https://example.com/badWords.html";
//In which file are the comments saved?
$fileName = "testComments.php";
//What's the filename of your "blacklist"?
$blackList = "blacklist.txt";
//Replace with the name-attribute of the respective input-field
//No action needed here, if you didn't update form.php
$nameInputTagName = "myName";
$messageInputTagName = "myMessage";
$exerciseInputTagName = "exerciseText";
$solutionInputTagName = "solution";
$answerInputTagName = "answerID";
$timeInputTagName = "time";
$buttonName = "postComment";
$urlName = "id";
if (isset($_POST["flag"])) {
flag($to, $url);
}
if (isset($_POST["answer"])) {
answer($url, $buttonName, $urlName);
}
if (isset($_POST[$buttonName])) {
save($url, $urlError, $urlBadWords, $blackList, $fileName, $nameInputTagName, $messageInputTagName, $exerciseInputTagName, $solutionInputTagName, $answerInputTagName, $timeInputTagName);
}
}
start();
?>代码是用phpcodechecker.com检查的,没有发现任何问题。其他文件不值得审查,所以我会把它留在这里。链接对于那些对其他文件和如何操作感兴趣的人,请参阅该项目的存储库。对于那些想测试它的人,也有一个现场演示。问题所有建议都是受欢迎的。如前所述,我特别感兴趣的是为save()-function提供更优雅的解决方案。发布于 2020-10-06 23:22:10
这只是一个单一的建议,而不是对代码的全面审查。
大多数评论系统都用于对本身不是评论的事物进行评论。就像在你的演示页面里。这意味着您的代码<#>will将包含在其他人的页面中。这可能是一个非常复杂的页面。换句话说,您的代码必须与其他代码共存,这可能是无穷无尽的。如果该代码包括像getTime()、error()或save()这样的函数呢?然后你的代码就会破坏那一页。
这就是为什么我们希望与其他开发人员共享的代码几乎总是以面向对象编程(OOP)的方式编写的。对象和名称空间用于将代码与使用代码的代码隔离开来。
一些链接:
https://phpenthusiast.com/object-oriented-php-tutorials
https://www.thoughtfulcode.com/a-complete-guide-to-php-namespaces
即使你离开了你的代码,就像现在一样,我建议你选择更有创意的名字。例如,函数名randExer()对我来说毫无意义。更好的名字应该是类似于getCaptchaImageHtml()的名字。这个名称实际上描述了函数的功能和返回的内容。其他功能也是如此。我认为在函数名中应该避免不常见的缩写。
发布于 2020-10-07 10:20:10
避免使用全局变量。
变量$encryptionPassword应该作为参数传递给所有需要它的函数(randExer、getTime、randText和save)。
这样做有几个原因:
使用全局变量的函数不能定义为纯函数。出于上述原因,一般倾向于纯函数。
编辑:解决全局变量问题的一种可能方法是将函数提升到类方法,并将加密密码传递给它的构造函数:
class ASuitableClassName
{
private string $encryptionPassword;
public function __construct(string $encryptionPassword)
{
$this->encryptionPassword = $encryptionPassword;
}
public function getTime()
{
return openssl_encrypt(time() . bin2hex(random_bytes(20)),"AES-128-ECB", $this->encryptionPassword);
}
// ....
}
$obj = new ASuitableClassName("****************");
$obj->getTime();https://codereview.stackexchange.com/questions/250286
复制相似问题