diff options
author | Christian Cleberg <hello@cleberg.net> | 2024-01-08 20:11:17 -0600 |
---|---|---|
committer | Christian Cleberg <hello@cleberg.net> | 2024-01-08 20:11:17 -0600 |
commit | 25945b8fead989cca09a23983623b63ce36dcc0c (patch) | |
tree | 0dfc869ce8b028e04ce9da196af08779780915ce /blog/2021-04-23-php-comment-system.org | |
parent | 22b526be60bf4257c2a1d58a5fad59cf6b044375 (diff) | |
download | cleberg.net-25945b8fead989cca09a23983623b63ce36dcc0c.tar.gz cleberg.net-25945b8fead989cca09a23983623b63ce36dcc0c.tar.bz2 cleberg.net-25945b8fead989cca09a23983623b63ce36dcc0c.zip |
feat: total re-write from Emacs org-mode to Zola markdown
Diffstat (limited to 'blog/2021-04-23-php-comment-system.org')
-rw-r--r-- | blog/2021-04-23-php-comment-system.org | 284 |
1 files changed, 0 insertions, 284 deletions
diff --git a/blog/2021-04-23-php-comment-system.org b/blog/2021-04-23-php-comment-system.org deleted file mode 100644 index d539a4e..0000000 --- a/blog/2021-04-23-php-comment-system.org +++ /dev/null @@ -1,284 +0,0 @@ -#+title: Roll Your Own Static Commenting System in PHP -#+date: 2021-04-23 - -** The Terrible-ness of Commenting Systems -:PROPERTIES: -:CUSTOM_ID: the-terrible-ness-of-commenting-systems -:END: -The current state of affairs regarding interactive comment systems is, -well, terrible. It is especially awful if you're a privacy conscious -person who does not generally load third-party scripts or frames on the -websites you visit. - -Even further, many comment systems are charging exorbitant fees for -something that should be standard. - -Of course, there are some really terrible options: - -- Facebook Comments -- Discourse - -There are some options that are better but still use too many scripts, -frames, or social integrations on your web page that could impact some -users: - -- Disqus -- Isso -- Remark42 - -Lastly, I looked into a few unique ways of generating blog comments, -such as using Twitter threads or GitHub issues to automatically post -issues. However, these both rely on external third-party sites that I -don't currently use. - -** Stay Static with Server-Side Comments -:PROPERTIES: -:CUSTOM_ID: stay-static-with-server-side-comments -:END: -The main issue for my personal use-case is that my blog is completely, -100% static. I use PHP on the back-end but website visitors only see -HTML and a single CSS file. No external javascript and no embedded -frames. - -So, how do we keep a site static and still allow users to interact with -blog posts? The key actually pretty simple - I'm already using PHP, so -why not rely on the classic HTML =<form>= and a PHP script to save the -comments somewhere? As it turns out, this was a perfect solution for me. - -The second issue for my personal use-case is that I am trying to keep -the contents of my website accessible over time, as described by -[cite/t:@brandur], in his post entitled -[[https://brandur.org/fragments/graceful-degradation-time][Blog with -Markdown + Git, and degrade gracefully through time]] . - -This means I cannot rely on a database for comments, since I do not rely -on a database for any other part of my websites. - -I blog in plain Markdown files, commit all articles to Git, and ensure -that future readers will be able to see the source data long after I'm -gone, or the website has gone offline. However, I still haven't -committed any images served on my blog to Git, as I'm not entirely sold -on Git LFS yet - for now, images can be found at -[[https://img.cleberg.net][img.cleberg.net]]. - -Saving my comments back to the Git repository ensures that another -aspect of my site will degrade gracefully. - -** Create a Comment Form -:PROPERTIES: -:CUSTOM_ID: create-a-comment-form -:END: -Okay, let's get started. The first step is to create an HTML form that -users can see and utilize to submit comments. This is fairly easy and -can be changed depending on your personal preferences. - -Take a look at the code block below for the form I currently use. Note -that =<current-url>= is replaced automatically in PHP with the current -post's URL, so that my PHP script used later will know which blog post -the comment is related to. - -The form contains the following structure: - -1. =<form>= - This is the form and will determine which PHP script to - send the comment to. -2. =<section hidden>= - This section is hidden from the user and is used - to ensure that we know which blog post sent the comment. -3. =<section>= Display Name (Optional) - Used to accept a display name, - if entered. -4. =<section>= Comment (Required) - Used to accept the user's full - comment. Markdown is allowed. -5. =<button>= - A button to submit the form. - -#+begin_src html -<form action="/comment.php" method="POST"> - <h3>Leave a Comment</h3> - <section hidden> - <label class="form-label" for="postURL">Post URL</label> - <input - class="form-control" - id="postURL" - name="postURL" - type="text" - value="<current-url>" - /> - </section> - <section> - <label class="form-label" for="userName">Display Name</label> - <input - class="form-control" - id="userName" - name="userName" - placeholder="John Doe" - type="text" - /> - </section> - <section> - <label class="form-label" for="userContent">Your Comment</label> - <textarea - class="form-control" - id="userContent" - name="userContent" - rows="3" - placeholder="# Feel free to use Markdown" - aria-describedby="commentHelp" - required - ></textarea> - <div id="commentHelp" class="form-text"> - Comments are saved as Markdown and cannot be edited or deleted. - </div> - </section> - <button type="submit">Submit</button> -</form> -#+end_src - -** Handle Comments via POST -:PROPERTIES: -:CUSTOM_ID: handle-comments-via-post -:END: -Now that we have a form and can submit comments, we need to create a PHP -script so that the server can fetch the comment data and save it. Make -sure your PHP script name matches the name you entered in the =action= -field in your form. - -See the code block below for the contents of my =comment.php= script. We -perform the following tasks in this script: - -1. Grab the POST data from the HTML form. -2. Sanitize the comment data with =htmlentities=. -3. Set the display name to =Anonymous= if it was left blank. -4. Create a PHP object that combines all of this data. -5. Check if our destination file =comments.json= exists. -6. If so, convert the PHP object to JSON and save it to the file. -7. If the =comments.json= file does not exist, the script will exit with - an error. You can alter this to ensure it creates the script, but my - source code includes the file by default, so it will always exist. -8. Finally, send the user back to the =#comments= section of the blog - post they just read. - -#+begin_src php -// Get the content sent from the comment form -$comment = htmlentities($_POST['userContent']); -$post_url = $_POST['postURL']; - -// Set default values if blank -if (isset($_POST['userName']) && trim($_POST['userName']) !== "") { - $username = $_POST['userName']; -} else { - $username = 'Anonymous'; -} - -// Create an empty PHP object -$user_object = new stdClass(); - -// Add object content -$user_object->timestamp = date('Y-m-d H:i:s'); -$user_object->username = $username; -$user_object->comment = $comment; -$user_object->post_url = $post_url; - -// Append JSON to file -$file_name = 'comments.json'; -if (file_exists($file_name)) { - $source_data = file_get_contents($file_name); - $temp_array = json_decode($source_data); - array_push($temp_array, $user_object); - $json_data = json_encode($temp_array, JSON_PRETTY_PRINT); - file_put_contents($file_name, $json_data); -} else { - die('Error: The "comments.json" file does not exist.'); -} - -// Send the user back -header('Location: ' . $post_url . '#comments'); -#+end_src - -If you're using Apache, make sure the =www-data= user on your server has -the correct permissions to your website directory or else it will not be -able to write to =comments.json=. - -#+begin_src sh -chgrp -R www-data /path/to/website/ -chmod -R g+w comments.json -#+end_src - -** Display User Comments -:PROPERTIES: -:CUSTOM_ID: display-user-comments -:END: -Now that we can submit comments, and they are saved to the -=comments.json= file, let's make sure we can show those comments in each -blog post. - -The code block below shows the function I use to decode my -=comments.json= file, check if the comments apply to the current post, -and then display them. - -This piece of code should *really* be inside a function (or at least in -an organized PHP workflow). Don't just copy-and-paste and expect it to -work. You need to at least supply a =$query= variable depending on the -page visited. - -#+begin_src php -$query = 'your-blog-post.html'; - -// Load saved comments -$comments_file = 'comments.json'; -$comments_raw = file_get_contents($comments_file); -$comments = json_decode($comments_raw); -$comment_section = '<section id="comments" class="comments"><h3>Comments</h3>'; -foreach ($comments as $comment) { - if ($comment->post_url == "https://example.com/post/" . $query) { - // Assign metadata to variables - $comment_timestamp = $comment->timestamp; - $comment_username = $comment->username; - $comment_content = $comment->comment; - - // Parse the comment, in case it contains Markdown - $comment_md = Parsedown::instance()->text($comment_content); - $comment_html = new DOMDocument(); - $comment_html->loadHTML($comment_md); - $comment_html_links = $comment_html->getElementsByTagName('a'); - foreach ($comment_html_links as $comment_html_link) { - $comment_html_link->setAttribute('rel', 'noreferrer'); - $comment_html_link->setAttribute('target', '_blank'); - } - $comment_secured_html = $comment_html->saveHTML(); - - // Apply metadata to comments section - $comment_section .= '<div class="user-comment"><div class="row"><label>Timestamp:</label><p>' . $comment_timestamp . '</p></div><div class="row"><label>Name:</label><p>' . $comment_username . '</p></div><div class="row markdown"><label>Comment:</label><div class="comment-markdown">' . $comment_secured_html . '</div></div></div>'; - } -} - -echo $comment_section; -#+end_src - -** Bonus: Create a 'Recent Comments' Page -:PROPERTIES: -:CUSTOM_ID: bonus-create-a-recent-comments-page -:END: -Finally, the last part of my current system is to create a Recent -Comments page so that I can easily check-in on my blog and moderate any -spam. As an alternative, you could use PHP's =mail()= function to email -you for each blog comment. - -The code to do this is literally the same code as the previous section, -I just make sure it is printed when someone visits -=https://example.com/comments/=. - -** Possible Enhancements -:PROPERTIES: -:CUSTOM_ID: possible-enhancements -:END: -This comment system is by no means a fully-developed system. I have -noted a few possible enhancements here that I may implement in the -future: - -- Create a secure moderator page with user authentication at - =https://blog.example.com/mod/=. This page could have the option to - edit or delete any comment found in =comments.json=. -- Create a temporary file, such as =pending_comments.json=, that will - store newly-submitted comments and won't display on blog posts until - approved by a moderator. -- Create a =/modlog/= page with a chronological log, showing which - moderator approved which comments and why certain comments were - rejected. |