HostPapa Targeted Thomua.com

HostPapa hit me a few years ago with the resource limit bullshit. I cancelled all of my services with HostPapa. I knew it was just a matter of time before HostPapa went after my clients.

According to their automated performance scans, Thơ mưa had exceeded the allocated resources. Of course it was a scam because Thơ mưa was not even powered by WordPress. It was just a static site built on HTML, CSS, and a bit of PHP. No way it was hogging up the resources.

When my client forwarded to me the HostPapa scheme trying to upsell their service, I advised my client to get out. My client agreed. I transferred the domain and migrated the entire site over to Namecheap. I haven’t used Namecheap in the past. Since my client already has a few domains with Namecheap, I signed up for their hosting as well. Namecheap seams to be a good, reliable company.

HostPapa took 9 days to release the domain. Even though the migration process was time-consuming, I didn’t charge my client a penny. I created Thơ mưa 8 years ago and I had no obligation to take on the migration, but it was the right thing to do. This is one of the reasons I am not doing good at business, but I am OK with that.

If your site is hosted with HostPapa, you need to get out. They are a horrible company.

A Year of Nada

A year ago, we licensed a commercial CMS ($21,500 annually) and a cloud server ($11,000 annually). We also paid almost $200,000 for the design, development, implementation, and migration. A year went by, the new website has gotten nowhere. Yet, we need to pay $32,500. This is super wasteful, but it is what happen when someone has no experience in web technologies take charge of the website. I have nothing to say. I just do my part and go with the flow.

Users’ Privacy

I have been in the game for over 20 years making websites and my philosophy hasn’t changed. My first priority has always been our users. From accessibility to usability to security to privacy, I fight for our users every step of the way.

When I was in charge of the site, I made sure the pages are fast, secured, easy to navigate, and optimized across devices and screen readers. The pages had to work with JavaScript turned off. I am not against using JavaScript. In fact, I encourage using JavaScript through progressive enhancement. My concern has always been the abuse of JavaScript, particularly in the privacy territory.

When I had to work directly with third-party vendors on digital marketing, I needed to know exactly what information they collect from our users and what they do with the data. Furthermore, I would limit their tracking to relevant pages, and not the entire website. I also made sure that they would be responsible for any privacy issues they created. If I didn’t hold them accountable, they would have the ability to use cross-site scripting to hijack our site to do whatever they wanted with our users’ data. I wouldn’t allow that to happen under my watch.

Dark-Pattern Scripting

As I was driving on the road, I received text messages, emails, and phone calls about our site was being hacked. When someone clicked on an email link on any page, they would get a pop-up form instead of their email client. The recipients would get an email from [email protected] instead of the senders’.

My first thought was our site was being hacked with XSS (Cross-Site Scripting). I called my assistant on my phone and walked her through the diagnose. I asked her to look for strange scripts in our templates. Then I asked her to comment out the script tags, which included Google Tag Manager and Pixel Tracking. When she commented out the Pixel Tracking script from a third-party vendor, the pop-up form went away.

The Pixel Tracking script allowed them to hijack our site and inject XSS into our pages with any email links. The JavaScript codes created the pop-up form. The submission from the pop-up form allows them to obtain all of the email messages. This is a serious privacy concern. Email communications should be between the sender and receiver, not the third-party.

I didn’t work with them on this Pixel Tracking script. When I worked with third-party vendors in the past, I made sure that they told me exactly what they were capturing. They would need to check with me first before they implement these types of dark patterns. I would also limit their tracking to a specific set of pages under a directory instead of the entire site.

List Files In a Directory Using PHP

This handy PHP script will print out all the specified files (.jpg and .png):


<?php
// open this directory
$myDirectory = opendir(".");

// get each entry
while($entryName = readdir($myDirectory)) {
$dirArray[] = $entryName;
}

// close directory
closedir($myDirectory);

// count elements in array
$indexCount = count($dirArray);

// sort 'em
sort($dirArray);

// print 'em

// loop through the array of files and print them all
for($index=0; $index < $indexCount; $index++) {
if ((substr("$dirArray[$index]", -4, 4) == ".jpg") || (substr("$dirArray[$index]", -4, 4) == ".png")){ // only list jpg and png files
print('<img src="'.$dirArray[$index].'">');
}
}

?>

Simple Slideshow

I needed a simple slideshow to display images on a large-screen TV and I came across Simple Fullscreen Image Slideshow. It was exactly what I needed and the codes are just so simple. I loved it so much, I replaced all my Flickity slideshows with this one. Here’s an example. Although it works as webpage, my goal is to create a digital display slider. Here’s the entire page:


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>Slideshow</title>
<style>
@keyframes fadey {
0% { opacity: 0; }
15% { opacity: 1; }
85% { opacity: 1; }
100% { opacity: 0; }
}
body {
  font-family: Avenir, Arial, sans-serif;
  font-size: 0;
  background: #000;
}

body, figure {  margin: 0; padding: 0;}

figure#slideshow {
  width: 100%;
  margin: 0 auto;
  position: relative;
  /*border: 1px solid #000;*/
  cursor: pointer;
}
figure#slideshow img {
  position: absolute;
  left: 0; top: 0;
  width: 100%; height: auto;
  opacity: 0;
}
figure#slideshow img:first-child { position: relative; }

#container:fullscreen {
  display: flex;
  justify-content: center;
  align-items: center;
  background: #000;
}
#container:-moz-full-screen figure, #container:-ms-full-screen figure, #container:-webkit-fullscreen figure, #container:fullscreen figure {
  width: 100%;
  margin: 0 auto;
  background: #000;
}
:-webkit-full-screen {
  width: 100%; height: 100%;
}
*:-moz-full-screen {
  background: #000;
}
*:-webkit-full-screen {
  background: #000;
}
</style>

<script>
function cancelFullScreen() {
if (document.cancelFullScreen) {
document.cancelFullScreen();
} else if (document.mozCancelFullScreen) {
document.mozCancelFullScreen();
} else if (document.webkitCancelFullScreen) {
document.webkitCancelFullScreen();
} else if (document.msCancelFullScreen) {
document.msCancelFullScreen();
}
link = document.getElementById("container");
link.removeAttribute("onclick");
link.setAttribute("onclick", "fullScreen(this)");
}

function fullScreen(element) {
if (element.requestFullScreen) {
element.requestFullScreen();
} else if (element.webkitRequestFullScreen) {
element.webkitRequestFullScreen();
} else if (element.mozRequestFullScreen) {
element.mozRequestFullScreen();
}
link = document.getElementById("container");
link.removeAttribute("onclick");
link.setAttribute("onclick", "cancelFullScreen()");
}

window.onload = function() {
  imgs = document.getElementById('slideshow').children;
  interval = 8000;
  currentPic = 0;
  imgs[currentPic].style.webkitAnimation = 'fadey '+interval+'ms';
  imgs[currentPic].style.animation = 'fadey '+interval+'ms';
  var infiniteLoop = setInterval(function(){
imgs[currentPic].removeAttribute('style');
if ( currentPic == imgs.length - 1) { currentPic = 0; } else { currentPic++; }
imgs[currentPic].style.webkitAnimation = 'fadey '+interval+'ms';
imgs[currentPic].style.animation = 'fadey '+interval+'ms';
  }, interval);
}
</script>
</head>
<body>
<figure id="container" onclick="fullScreen(this)">
<figure id="slideshow">
<img loading="lazy" src="img/01.jpg" alt>
<img loading="lazy" src="img/02.jpg" alt>
<img loading="lazy" src="img/03.jpg" alt>
</figure>
</figure>
</body>
</html>

Hanging Punctuation in CSS

To hang your quotes in CSS, this is all you need:


html {
  hanging-punctuation: first allow-end last;
}

At the time of this writing, only Safari implemented this property. To make it work in other browsers, negative text-indent is needed. Nevertheless, I went ahead and added hanging-punctuation and removed text-indent for the title of JAY-Z’s song from the Beacon of HOV project. That way, the hanging punctuation would just work in all browsers in the future.

MODX Support Team Rocks!

The MODX Support Team had proved once again to be indisputable in customer service. Their team members assisted us every step of the way to migrate the Scalia Law School’s CDN and WAF from StackPath over to CloudFlare Enterprise. We ran into a few obstacles during the process, but they were patience, responsive, and diligence in making sure that we succeeded in the migration.

If you need a CMS that offers flexibility, durability, and security, MODX is the solution. If you need a rock-solid hosting with top-notch support, MODX Cloud is the way to go. The Scalia Law School Website has been powered by MODX for more than 15 years and hosted by MODX Cloud for more than 3 years.

In the CMS space, MODX beats WordPress, Drupal, Joomla, and Cascade to the pulp. Hats off to Jay, Liz, Garry, Ryan, and Jimmy. You all rock!

Pretty Text Wrap

I just learned about a CSS feature that would prevent orphans on text blocks. Of course, I applied it to this blog:

.content {text-wrap: pretty;}

This will make my body text less lonely (no orphans left behind). Thanks to Robin Rendle and Stephanie Stimac for the tip.

Install PHP 8.2 on DigitalOcean Droplet’s Ubuntu

Perform update and upgrade to the current Droplet.

List all the installed PHP version:

ls /etc/php/

The latest version should appear on the list.

7.4 8.0 8.1 8.2

If PHP 8.2 doesn’t exist, install it, but update the package lists first:

sudo apt-get update

Run the installation:

sudo apt-get install php8.2 php8.2-cli php8.2-common

Install additional PHP modules

sudo apt-get install php8.2-mysql php8.2-soap php8.2-bcmath php8.2-xml php8.2-mbstring php8.2-gd php8.2-curl

Disable PHP 8.0:

sudo a2dismod php8.0

Enable PHP 8.2:

sudo a2enmod php8.2

Restart Apache:

sudo systemctl restart apache2

Source: Based on instructions by Bobby Iliev