Recursively find all duplicate files in a directory (Java)

Intro

Sure this could be implemented using a few lines of basic Linux commands. However, understanding how to write such code in Java, requires understanding in several topics - Hash tables, recursion, lists, file system, and more.

That is why I love this problem. Not only does it concern understanding much of Java's fundamentals, but also there is great deal of required efficiency regarding time complexity and space complexity.

Duplicate detection using hash

The first problem to take into consideration is, how do I detect duplicated files? Should I only consider file names? What about file size? Maybe both? Considering both is still not enough. It's pretty easy to come up with a counter example for this approach. Take for example File A thats called fileA.txt and file B called fileB.txt. fileA.txt contains the word "hello" however fileB.txt contains the word "world". Both files contain the same name and size, however are not identical. That is why my approach will contain reading the files bytes, and saving a unique hash id for each file.

    private static MessageDigest messageDigest;
    static {
        try {
            messageDigest = MessageDigest.getInstance("SHA-512");
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("cannot initialize SHA-512 hash function", e);
        }
    }

In the above code, we apply a notable secure hash function called SHA-512. We will use this function to create a unique id for each of the files in the file system.

Duplicated files retrieval using Hash Table

Our second problem, is how to store the files id hash efficiently for future retrieval in an efficient way. One of the best methods for retrieval efficiently is of course Hash Tables which if implemented properly, enable retrieval in O(1) complexity time. What we'll do is store the hash unique id's as keys, and for every key, the value will be a Linked List containing all of the duplicated String paths associated to the same key. Such hash id's are very very big which is why we'll also use the Java library BigInteger.

And finally, we'll traverse all sub directories and files recursively, such that for each directory, traverse all of it's files. The final implementation is as follows:

public static void findDuplicatedFiles(Map<String, List<String>> lists, File directory) {
        for (File child : directory.listFiles()) {
            if (child.isDirectory()) {
                findDuplicatedFiles(lists, child);
            } else {
                try {
                    FileInputStream fileInput = new FileInputStream(child);
                    byte fileData[] = new byte[(int) child.length()];
                    fileInput.read(data);
                    fileInput.close();
                    String uniqueFileHash = new BigInteger(1, md.digest(fileData)).toString(16);
                    List<String> list = lists.get(uniqueFileHash);
                    if (list == null) {
                        list = new LinkedList<String>();
                        lists.put(uniqueFileHash, list);
                    }
                    list.add(child.getAbsolutePath());
                } catch (IOException e) {
                    throw new RuntimeException("cannot read file " + child.getAbsolutePath(), e);
                }
            }
        }
    }

All thats left is to run the above method and print out the Hash tables key values if such exists (that is that the associated linked lists hold duplicates.

Map<String, List<String>> lists = new HashMap<String, List<String>>();
        FindDuplicates.findDuplicateFiles(lists, dir);
        for (List<String> list : lists.values()) {
            if (list.size() > 1) {
                System.out.println("\n");
                for (String file : list) {
                    System.out.println(file);
                }
            }
        }
        System.out.println("\n");

The source code can be found in the download link below:

Feel free to ask any related questions in the comments below.

How to create a dynamic HTML Email Template

HTML automated emails  have come a long way in the past couple of years. What used to be a text-only email, today contains various forms, dynamic links, images, depending each company on there personal style displays.

Today, receiving HTML emails is a standard to most leading companies, which is why adapting this principle over regular text only emails has become a must. 

Developing HTML templates doesn't require a lot of coding skills, however knowing how to code the template to appear correctly on all devices and old email clients is the real challenge.

In this blog post I will go through a step by step guide of how to build a dynamic email template via HTML and PHP.

Basic guidelines

As I've described above, the biggest challenge with developing an HTML email template, is making sure it's cross-platform-compatible. There are so many email clients such as Google Mail, Apple Mail, Outlook, AOL, Thunderbird, Yahoo!, Hotmail, Lotus Notes and etc. Some of these clients and others are light years behind the eight-ball in terms of CSS support, which means we must resort to using HTML tables to control the design layout if we really want our email template to display consistently for every user. In fact, using HTML tables is the only way to achieve a layout that will render consistently across different mail clients. Think of the template as being constructed of tables within tables within tables...

Secondly, we must use inline CSS to control elements within your email, such as background colors and fonts. CSS style declarations should be very basic, without use of any CSS files.

To emphasize the HTML tables rule above, see the example below, where I've modified the border attribute of each table to be visible. Please note that the %s is a placeholder where dynamic text and images will be filled as I'll see soon describe (Scroll to the end to see the final email template):

 
Screen Shot 2016-04-29 at 14.12.47.png
 

As you can see above, the whole layout is built by HTML tables. We'll be using PHP libraries to parse the %s place holder and fill it with dynamic text before an email is sent to the user.

Developing the static template

So let's start programming! Before we begin the template itself, you'll need to begin your HTML file with an XHTML document:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
 <head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  <title>Demystifying Email Design</title>
  <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
</head>
</html>

I recommend defining all tables with border="1" as seen above since it's easier to spot errors and see the skeleton of the layout as you go along. At first, let's create the basic layout:

<body style="margin: 0; padding: 0;">
 <table border="1" cellpadding="0" cellspacing="0" width="100%">
  <tr>
   <td>
    My first email template!
   </td>
  </tr>
 </table>
</body>

Set your cellpadding and cellspacing to zero to avoid any unexpected space in the table. Also set the width to 100% since this table acts as a true body tag for our email, because styling of the body tag isn't fully supported.

Now we'll add instead of the text 'My first email template!' another table which will present the actual email template display.

<table align="center" border="1" cellpadding="0" cellspacing="0" width="600" style="border-collapse: collapse;">
 <tr>
  <td>
   This is the email template body
  </td>
 </tr>
</table>

As you can see, the width is set to 600 pixels. 600 pixels is a safe maximum width for your emails to display correctly on most email clients. In addition, set the border-collapse property to collapse in order to make sure there are no unwanted spaces between the tables and borders.

In the example above, you can see that our email template consists of five sections (rows) which is why we'll create these rows and then add tables accordingly to each in order to complete the template.

<table align="center" border="1" cellpadding="0" cellspacing="0" width="600">
 <tr>
  <td>
   Row 1
  </td>
 </tr>
 <tr>
  <td>
   Row 2
  </td>
 </tr>
 <tr>
  <td>
   Row 3
  </td>
 </tr>
   <tr>
  <td>
   Row 4
  </td>
 </tr>
   <tr>
  <td>
   Row 5
  </td>
 </tr>
</table>

At each row, we'll create a new table in which the mythology is similar to the above. We'll also add columns accordingly and the right paddings to align all objects to reach the desired template.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
    <title>Automatic Email</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
</head>
<body style="margin:0; padding:10px 0 0 0;" bgcolor="#F8F8F8">
<table align="center" border="1" cellpadding="0" cellspacing="0" width="95%%">
    <tr>
        <td align="center">
            <table align="center" border="1" cellpadding="0" cellspacing="0" width="600"
                   style="border-collapse: separate; border-spacing: 2px 5px; box-shadow: 1px 0 1px 1px #B8B8B8;"
                   bgcolor="#FFFFFF">
                <tr>
                    <td align="center" style="padding: 5px 5px 5px 5px;">
                        <a href="http://url-goes-here" target="_blank">
                            <img src="http://logo.png" alt="Logo" style="width:186px;border:0;"/>
                        </a>
                    </td>
                </tr>
                <tr>
                    <td align="center">
                        <!-- Initial relevant banner image goes here under src-->
                        <img src="%s" alt="Image Banner" style="display: block;border:0;" height="100%%" width="600"/>
                    </td>
                </tr>
                <tr>
                    <td bgcolor="#ffffff" style="padding: 40px 30px 40px 30px;">
                        <table border="1" cellpadding="0" cellspacing="0" width="100%%">
                            <tr>
                                <td style="padding: 10px 0 10px 0; font-family: Avenir, sans-serif; font-size: 16px;">
                                    <!-- Initial text goes here-->
                                    %s
                                </td>
                            </tr>
                        </table>
                    </td>
                </tr>
                <tr>
                    <td bgcolor="#E8E8E8">
                        <table border="1" cellpadding="0" cellspacing="0" width="100%%" style="padding: 20px 10px 10px 10px;">
                            <tr>
                                <td width="260" valign="top" style="padding: 0 0 15px 0;">
                                    <table border="1" cellpadding="0" cellspacing="0" width="100%%">
                                        <tr>
                                            <td align="center">
                                                <a href="tel:phone number goes here" target="_blank">
                                                    <img src="url for call image goes here.png" alt="Call us"
                                                         style="display: block;"/>
                                                </a>
                                            </td>
                                        </tr>
                                        <tr>
                                            <td align="center"
                                                style="font-family: Avenir, sans-serif; color:#707070;font-size: 13px;padding: 10px 0 0 0;">
                                                GIVE US A CALL
                                            </td>
                                        </tr>
                                    </table>
                                </td>
                                <td style="font-size: 0; line-height: 0;" width="20">
                                    &nbsp;
                                </td>
                                <td width="260" valign="top">
                                    <table border="1" cellpadding="0" cellspacing="0" width="100%%" >
                                        <tr>
                                            <td align="center">
                                                <a href="mailto:emailgoeshere@gmail.com">
                                                    <img src="url for email image goes here" alt="Email us"
                                                         style="display: block;"/>
                                                </a>
                                            </td>
                                        </tr>
                                        <tr>
                                            <td align="center"
                                                style="font-family: Avenir, sans-serif; color:#707070;font-size: 13px;padding: 10px 0 0 0;">
                                                EMAIL US
                                            </td>
                                        </tr>
                                    </table>
                                </td>
                                <td style="font-size: 0; line-height: 0;" width="20">
                                    &nbsp;
                                </td>
                                <td width="260" valign="top">
                                    <table border="1" cellpadding="0" cellspacing="0" width="100%%">
                                        <tr>
                                            <td align="center">
                                                <a href="url to faq page goes here" target="_blank">
                                                    <img src="url for faq image goes here" alt="FAQ Page"
                                                         style="display: block;"/>
                                                </a>
                                            </td>
                                        </tr>
                                        <tr>
                                            <td align="center"
                                                style="font-family: Avenir, sans-serif; color:#707070;font-size: 13px;padding: 10px 0 0 0;">
                                                BROWSE FAQ PAGE
                                            </td>
                                        </tr>
                                    </table>
                                </td>
                            </tr>
                        </table>
                    </td>
                </tr>
                <tr>
                    <td bgcolor="#66989c" style="padding: 15px 15px 15px 15px;">
                        <table border="1" cellpadding="0" cellspacing="0" width="100%%">
                            <tr>
                                <td align="center">
                                    <table border="1" cellpadding="0" cellspacing="0">
                                        <tr>
                                            <td>
                                                <a href="facebook url goes here" target="_blank">
                                                    <img src="facebook image goes here" alt="Facebook" width="50" height="50"
                                                         style="display: block;" border="1"/>
                                                </a>
                                            </td>
                                            <td style="font-size: 0; line-height: 0;" width="20">&nbsp;</td>
                                            <td>
                                                <a href="youtube page link goes here" target="_blank">
                                                    <img src="youtube image link goes here" alt="Youtube" width="50" height="50"
                                                         style="display: block;" border="1"/>
                                                </a>
                                            </td>
                                            <td style="font-size: 0; line-height: 0;" width="20">&nbsp;</td>
                                            <td>
                                                <a href="twitter page goes here" target="_blank">
                                                    <img src="twitter image goes here" alt="Twitter" width="50" height="50"
                                                         style="display: block;" border="1"/>
                                                </a>
                                            </td>
                                            <td style="font-size: 0; line-height: 0;" width="20">&nbsp;</td>
                                            <td>
                                                <a href="linkedin page goes here" target="_blank">
                                                    <img src="linkedin image goes here" alt="Linkedin" width="50" height="50"
                                                         style="display: block;" border="1"/>
                                                </a>
                                            </td>
                                            <td style="font-size: 0; line-height: 0;" width="20">&nbsp;</td>
                                            <td>
                                                <a href="home page goes here" target="_blank">
                                                    <img src="homepage image goes here" alt="GreenIQ" width="50" height="50"
                                                         style="display: block;" border="1"/>
                                                </a>
                                            </td>
                                        </tr>
                                    </table>
                                </td>
                            </tr>
                        </table>
                    </td>
                </tr>
            </table>
        </td>
    </tr>
</table>
</body>
</html>

A few observations: 

  1. Add alt attributes where needed in order to present text instead of images incase the email client was unable to load them properly. 
  2. Add %s place holders where you'd like the data to appear dynamically depending on the email use case.
  3. If you look carefully, the percentage values appear with an extra '%'. This is so the PHP library used to making this dynamic, knows how to parse the text properly.

Note! I've removed the URLs for security and privacy issues. You can replace them with your own images and personal links.

And that is it! You've successfully developed your own email static template. Now let's get our hands dirty and make it dynamic!

Developing the dynamic template

Save the above code as a template.html file. Now let's create a new PHP file.

On the server side, create the email send method below:

function send_mail_template($to, $from, $subject, $message)
{
  $headers = "MIME-Version: 1.0" . "\r\n";
  $headers .= "Content-type:text/html;charset=UTF-8" . "\r\n";
  $headers .= "From: ContactNameGoesHere <" . $from . ">\r\n";
  $response = mail($to, $subject, $message, $headers);
}

Now if you look carefully back to the HTML email template, you'll see that I've added %s place holders in certain places. More particularly, in the image banner element, and body text. Now all we need to do is import the above HTML template, parse it like regular text, add the relevant text in place of the '%s' and use the above send_mail_template method.

function build_email_template($email_subject_image, $message)
{
    // Get email template as string
    $email_template_string = file_get_contents('template.html', true);
    // Fill email template with message and relevant banner image
    $email_template = sprintf($email_template_string,'URL_to_Banner_Images/banner_' . $email_subject_image. '.png', $message, $mobile_plugin_string);
    return $email_template;
}

After we've got that taken care of, we can use both methods and send are very first dynamic email! Let's use an example. Say a new user has just verified his email. We'd like to automate that use case on the server side and send the user a 'Your email has been successfully verified' email. 

Assume we have the users verified email 'user@user.com' and the company's email is 'company@company.com'. We can now send an automated email:

$from = "company@company.com";
$to = "user@user.com";
$body_text = "Your email has been successfully verified...";
$banner_image_subject = "account_verified";
$final_message = build_email_template($banner_image_subject, $body_text);
send_email($to, $from, "You email has been verified", $final_message);

Finally! You can now use this methodology any way needed. After sending this example, while applying the GreenIQ's company images and text, this is the final email template sent to the user:

Feel free to ask any question below!

How to send push notifications with PHP

Sending push notifications to an iOS/Android Application can enhance the user experience exponentially, while allowing you to deliver key information easily. However, sending the push notification to users can be a bit tedious at times, and at times confusing. You need to ensure that you pack your integers, and times correctly - failing to do this and you'll probably get an unhelpful status from Apple or Google.

I've came across some online PHP Scripts for either iOS or Android implementation however not for both. This PHP script includes implementation for both mobile operating systems.

PHP Script (For a description, scroll below the script):

function send_mobile_notification_request($user_mobile_info, $payload_info)
{
    //Default result
    $result = -1;
    //Change depending on where to send notifications
    $pem_preference = "production";
    $user_device_type = $user_mobile_info['user_device_type'];
    $user_device_key = $user_mobile_info['user_mobile_token'];
    if ($user_device_type == "iOS") {
        $apns_url = NULL;
        $apns_cert = NULL;
        //Apple server listening port
        $apns_port = 2195;
        if ($pem_preference == "production") {
            $apns_url = 'gateway.push.apple.com';
            $apns_cert = __DIR__.'/cert-prod.pem';
        }
        //develop .pem
        else {
            $apns_url = 'gateway.sandbox.push.apple.com';
            $apns_cert = __DIR__.'/cert-dev.pem';
        }
        $stream_context = stream_context_create();
        stream_context_set_option($stream_context, 'ssl', 'local_cert', $apns_cert);
        $apns = stream_socket_client('ssl://' . $apns_url . ':' . $apns_port, $error, $error_string, 2, STREAM_CLIENT_CONNECT,                                   $stream_context);
        $apns_message = chr(0) . chr(0) . chr(32) . pack('H*', str_replace(' ', '', $user_device_key)) . chr(0) . chr(strlen($payload_info)) .                               $payload_info;
        if ($apns) {
            $result = fwrite($apns, $apns_message);
        }
        @socket_close($apns);
        @fclose($apns);
    }
    else if ($user_device_type == "Android") {
        // API access key from Google API's Console
        define('API_ACCESS_KEY', ADD_YOUR_API_KEY_HERE);
        // prep the bundle
        $msg = array
        (
            'message' => json_decode($payload_info)->aps->alert,
            'title' => 'This is a title. title',
            'subtitle' => 'This is a subtitle. subtitle',
            'tickerText' => 'Ticker text here...Ticker text here...',
            'vibrate' => 1,
            'sound' => 1,
            'largeIcon' => 'large_icon',
            'smallIcon' => 'small_icon'
        );
        $fields = array
        (
            'registration_ids' => array($user_device_key),
            'data' => $msg
        );
        $headers = array
        (
            'Authorization: key=' . API_ACCESS_KEY,
            'Content-Type: application/json'
        );
        $ch = curl_init();
        curl_setopt( $ch,CURLOPT_URL,                     'https://android.googleapis.com/gcm/send' );
        curl_setopt( $ch,CURLOPT_POST, true );
        curl_setopt( $ch,CURLOPT_HTTPHEADER, $headers );
        curl_setopt( $ch,CURLOPT_RETURNTRANSFER, false );
        curl_setopt( $ch,CURLOPT_SSL_VERIFYPEER, false );
        curl_setopt( $ch,CURLOPT_POSTFIELDS, json_encode( $fields ) );
        $result = curl_exec($ch);
        curl_close($ch);
    }
    return $result > 0;
}

function create_payload_json($message) {
    //Badge icon to show at users ios app icon after receiving notification
    $badge = "0";
    $sound = 'default';
    $payload = array();
    $payload['aps'] = array('alert' => $message, 'badge' => intval($badge),'sound' => $sound);
    return json_encode($payload);
}

Description

Let's start. The first method builds the body of the notification request depending on the users operating system and sends accordingly. The flow process for sending push notifications is first to Apple/Google servers, and only then to the end user. Therefore, each end user holds on his mobile device, a unique token. Learn more about how to retrieve the user device key in Android or iOS.

Personally, I wrote the main method such that the input contains $user_mobile_info - An array containing the user's device and unique device key, and $payload_info - A JSON which contains the body message for sending the push notification request (Found in the second method). The $pem_preference variable inside the method is also hard coded, however can be changed to your preference. Apple offers two servers for development - sandbox for QA (gateway.sandbox.push.apple.com) and regular for production (gateway.push.apple.com). If you're in the testing phase of your development, just change the url or the variable itself.

The second method builds the message body. I've hard coded some variables such as the sound and badge. Sound can be changed to various options, and badge describes the badge to be shown when the user receives the notification. I've modified it to "0", meaning there will be no badge icon when receiving notifications.

Usage Example

The main part of the push notification is the message itself. Let's say the notification we want to send is "I know how to send push notifications!". We'll first create the payload JSON using the second method:

$payload = create_payload_json("I know how to send push notifications!");

Let's say the user has an iOS (This info can be kept on a server, database etc... for each user) and the array is as follows:

$user_mobile_info = ['user_device_type'=>"iOS", 'user_mobile_token'=>'1234ABCD'];

Now we can send the notification itself using the first method: 

send_mobile_notification_request($user_mobile_info, $payload);

They're many minor sections which have not been covered by this blog post. Feel free to leave me comments if you have any further questions.

To learn about more coding fundamentals visit devclass.io.