首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >PHP注释系统

PHP注释系统
EN

Code Review用户
提问于 2020-10-06 17:26:27
回答 2查看 255关注 0票数 4

基础

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

功能

  • 提交新评论的基本表格
  • 标志-功能(通过简单的电子邮件发送给网站所有者)
  • 带有缩进答案的应答功能

<#>代码

simpleComments.php

该脚本提供了主要功能:垃圾邮件保护(有来自这里这里的建议)、发送、回答和标记评论。我认为,尤其是函数save()看起来是一个相当棘手的解决方案。如果你知道更好的选择(没有数据库),我会很高兴听到它。

代码语言:javascript
复制
//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提供更优雅的解决方案。
EN

回答 2

Code Review用户

发布于 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

https://phptherightway.com

即使你离开了你的代码,就像现在一样,我建议你选择更有创意的名字。例如,函数名randExer()对我来说毫无意义。更好的名字应该是类似于getCaptchaImageHtml()的名字。这个名称实际上描述了函数的功能和返回的内容。其他功能也是如此。我认为在函数名中应该避免不常见的缩写。

票数 4
EN

Code Review用户

发布于 2020-10-07 10:20:10

避免使用全局变量。

变量$encryptionPassword应该作为参数传递给所有需要它的函数(randExergetTimerandTextsave)。

这样做有几个原因:

  • 避免与其他全局变量的冲突(而不是应该存在任何)。
  • 您避免那些不应该访问该变量的人意外访问该变量。
  • 函数的签名隐藏了对加密密码的依赖,这使得读者更难理解代码,因为他们必须读取函数体才能理解存在这种依赖关系。仅仅读取函数的签名就足够了。
  • 这些功能更容易测试。
  • 而且可能更..。

使用全局变量的函数不能定义为纯函数。出于上述原因,一般倾向于纯函数。

编辑:解决全局变量问题的一种可能方法是将函数提升到类方法,并将加密密码传递给它的构造函数:

代码语言:javascript
复制
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();
票数 2
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/250286

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档