Saturday 15 September 2018

Web Tutorial: Nike Meme Generator

In 2016, quarterback Colin Kaepernick made waves when he opted to take a knee while the United States national anthem was being played before the start of NFL games. There were some who felt this was disrespectful, though, coming from a country where you can literally wear the flag next to your crotch, I'm really not seeing the problem.

Others saw it as a brave protest against racial injustice. I may be overly cynical here, but all I saw was an aging athlete trying his darnedest to stay relevant. Still... good-looking guy. Great shoulders. Build to die for. And the dramatic shots of him bravely enduring the jeers and abuse to "stand up for his beliefs" sure didn't hurt the narrative.

Fast forward to 2018, and Kaepernick has been made the new face of Nike, ostensibly because they were interested in his message. Methinks they were a wee bit more interested in milking the controversy surrounding Kaepernick and turning it into cash, but anyways. The first ad to be displayed was this.


Conservatives started losing their shit, but I'm not gonna go into that black hole of inanity. Suffice to say, a whole new wave of spoofed memes have been made off this. Brilliant, I say. Brilliant!



Therefore, today, I'll walk you through how to make your very own Nike Meme Generator!

What you'll need

This will be done in PHP (cue the groans from purist snobs. Bite me, dipshits.) and you'll need an Apache server to run your code. First, create a folder called uploads and put this picture of Kaepernick in there. It'll be called, quite appropriately, colinkaepernick.jpg.



Then create index.php in the main folder. And place this tiny white Nike swoosh in the main folder as well, and call it... nikelogo.png? It has a transparent background, and we're going to need that transparency.


You may want to refer to a previous web tutorial, The Asynchronous File Upload, also done in PHP. We'll be copying a fair bit of code from the repository.

Let's Begin!

This is the HTML we start with.
<!DOCTYPE html>
<html>
    <head>
        <title>Nike Meme Generator</title>

        <style>

        </style>
    </head>

    <body>

    </body>
</html>


In the body, we have three divs, ids pnlMessage, formContainer and memeContainer. pnlMessage is meant to provide user feedback (sucess or failure) while formContainer will contain the controls. memeContainer will contain the resulting meme!
<!DOCTYPE html>
<html>
    <head>
        <title>Nike Meme Generator</title>

        <style>

        </style>
    </head>

    <body>
                <div id="pnlMessage"></div>

                <div id="formContainer">

                </div>

                <div id="memeContainer">

                </div>
    </body>
</html>


Got all that? Good. Now here's some styling.

pnlMessage will take up the top. Its text will be red, it will take up the entire screen's width, and have a height of 50 pixels.

formContainer will have its width, but not height, specified. I've given it and memeContainer widths, paddings and margins, and the float property of left.

Not to mention a grey outline for all three divs so you can visualize what we're doing here.

memeContainer's width and height will be equal to each other, because it's square.
<!DOCTYPE html>
<html>
    <head>
        <title>Nike Meme Generator</title>

        <style>
            #pnlMessage
            {
                width: 100%;
                height: 50px;
                color: #FF0000;
                outline: 1px solid #DDDDDD;
            }

            #formContainer
            {
                width: 400px;
                padding: 5px;
                margin: 5px;
                float: left;
                outline: 1px solid #DDDDDD;
            }

            #memeContainer
            {
                width: 500px;
                height: 500px;
                padding: 5px;
                margin: 5px;
                float: left;   
                outline: 1px solid #DDDDDD;
            }
        </style>
    </head>

    <body>
                <div id="pnlMessage"></div>

                <div id="formContainer">

                </div>

                <div id="memeContainer">

                </div>
    </body>
</html>


Looking right? Now you have a good idea where everything is going to be.


Now do this so that only the outline remains for memeContainer. The other divs don't need it.
            #pnlMessage
            {
                width: 100%;
                height: 50px;
                color: #FF0000;
                outline: 0px solid #DDDDDD;
            }

            #formContainer
            {
                width: 400px;
                padding: 5px;
                margin: 5px;
                float: left;
                outline: 0px solid #DDDDDD;
            }

            #memeContainer
            {
                width: 500px;
                height: 500px;
                padding: 5px;
                margin: 5px;
                float: left;   
                outline: 1px solid #DDDDDD;
            }


Now, within formContainer, we'll have a form tag. It points to this page itself, and the enctype attribute needs to be set to "multipart/form-data" because we're using the form to upload an image file. We have three text boxes (for the first and second line of the meme, and the Nike slogan), a file input object, and a submit button. And of course, their respective labels.

As per The Asynchronous File Upload web tutorial, there's also a hidden field, id hidUploadSize, that will be used to restrict the size of the file being uploaded. Not absolutely necessary, but I'm paranoid like that.
        <div id="formContainer">          
            <form id="frmUpload" name="frmUpload" action="" method="POST" enctype="multipart/form-data">
                <label for="flUpload">File</label>
                <input type="file" name="flUpload" id="flUpload">
                <input type="hidden" name="hidUploadSize" id="hidUploadSize" value="50000000">
                <br /><br />
                   <label for="txtLine1">Line 1</label>
                <input name="txtLine1" id="txtLine1" maxlength="50" value="" />
                <br /><br />
                   <label for="txtLine2">Line 2</label>
                <input name="txtLine2" id="txtLine2" maxlength="50" value="" />
                <br /><br />
                <label for="txtSlogan">Slogan</label>
               <input name="txtSlogan" id="txtSlogan" maxlength="20" value="" />
               <br /><br />
               <input type="submit" name="btSubmit" id="btSubmit" value="Create your Meme!">
           </form>
        </div>


This is not a very pretty form, but it's functional and that's all we really need.


Now for some PHP!

At the top of the file, before the doctype declaration, declare a PHP block, then the following variables as defaults. So the  default meme will use colinkaepernick.jpg and the default text will be "Believe in something. Even if it means sacrificing everything.", followed by the slogan "Just Do It.". By default, strmessage will be an empty string.
<?php
$filecode = "colinkaepernick";
$filetype = "jpg";
$line1 = "Believe in something.";
$line2 = "Even if it means sacrificing everything.";
$slogan = "Just Do It.";

$strmessage="";
?>

<!DOCTYPE html>


Next, we use an If block to check if a form has been submitted. If so, replace the current values of line1, line2 and slogan with the values POSTed from the form.
$filecode = "colinkaepernick";
$filetype = "jpg";
$line1 = "Believe in something.";
$line2 = "Even if it means sacrificing everything.";
$slogan = "Just Do It.";

$strmessage="";

if (isset($_POST["btSubmit"]))
{
    $line1 = $_POST["txtLine1"];
    $line2 = $_POST["txtLine2"];
    $slogan = $_POST["txtSlogan"];   
}


Then check if there's been a file upload. If not, set an error message to strmessage. line1, line2 and slogan are optional.
if (isset($_POST["btSubmit"]))
{
    $line1 = $_POST["txtLine1"];
    $line2 = $_POST["txtLine2"];
    $slogan = $_POST["txtSlogan"];

    if (basename($_FILES["flUpload"]["name"]) != "")
    {

    }
    else
    {
        $strmessage="No file selected.";
    }   
}


If there has been an upload, verify that the size of the upload doesn't exceed the size you specified in hidUploadSize. I don't want to repeat myself; all these steps can be found in the earlier web tutorial.
if (isset($_POST["btSubmit"]))
{
    $line1 = $_POST["txtLine1"];
    $line2 = $_POST["txtLine2"];
    $slogan = $_POST["txtSlogan"];

    if (basename($_FILES["flUpload"]["name"]) != "")
    {
        $uploadsize = intval($_POST["hidUploadSize"]);
        $filetype = pathinfo($_FILES["flUpload"]["name"],PATHINFO_EXTENSION);
        $filetype = strtolower($filetype);

        if ($_FILES["flUpload"]["size"] > $uploadsize)
        {
                $strmessage = "Error was encountered while uploading file. File cannot exceed " . ($uploadsize/1000) . "kb";
        }
        else
        {

        }
    }
    else
    {
        $strmessage="No file selected.";
    }   
}


The next step, however, is not in the previous web tutorial. Here, we check if the file uploaded is a valid image file. If not, we set the value of strmessage to an error message.

How, exactly, do we check if it's a valid image file? We certainly can't simply go by the extension. That's one of the easiest things to fake. So what we do, is use the getimagesize() function in PHP. Pass in the temporary filepath from the $_FILES["flUpload"] array. If the file is an image, the function should return you an array. Thus, if we use the is_array() function on the result and it comes back false, the uploaded file is not an image file.
if (isset($_POST["btSubmit"]))
{
    $line1 = $_POST["txtLine1"];
    $line2 = $_POST["txtLine2"];
    $slogan = $_POST["txtSlogan"];

    if (basename($_FILES["flUpload"]["name"]) != "")
    {
        $uploadsize = intval($_POST["hidUploadSize"]);
        $filetype = pathinfo($_FILES["flUpload"]["name"],PATHINFO_EXTENSION);
        $filetype = strtolower($filetype);

        if ($_FILES["flUpload"]["size"] > $uploadsize)
        {
                $strmessage = "Error was encountered while uploading file. File cannot exceed " . ($uploadsize/1000) . "kb";
        }
        else
        {
            if (!is_array(getimagesize($_FILES["flUpload"]["tmp_name"])))
            {
                $strmessage = "File type invalid";
            }
            else
            {
   
            }
        }
    }
    else
    {
        $strmessage="No file selected.";
    }   
}


And at this point, you upload the file.
if (isset($_POST["btSubmit"]))
{
    $line1 = $_POST["txtLine1"];
    $line2 = $_POST["txtLine2"];
    $slogan = $_POST["txtSlogan"];

    if (basename($_FILES["flUpload"]["name"]) != "")
    {
        $uploadsize = intval($_POST["hidUploadSize"]);
        $filetype = pathinfo($_FILES["flUpload"]["name"],PATHINFO_EXTENSION);
        $filetype = strtolower($filetype);

        if ($_FILES["flUpload"]["size"] > $uploadsize)
        {
                $strmessage = "Error was encountered while uploading file. File cannot exceed " . ($uploadsize/1000) . "kb";
        }
        else
        {
            if (!is_array(getimagesize($_FILES["flUpload"]["tmp_name"])))
            {
                $strmessage = "File type invalid";
            }
            else
            {
                $filecode=strtotime("now").rand();
               
                if (move_uploaded_file($_FILES["flUpload"]["tmp_name"], "uploads/" . $filecode . "." . $filetype))
                {
                       $strmessage = "File uploaded.";
                }
                else
                {
                       $strmessage = "Error was encountered while uploading file.";
                }
            }
        }
    }
    else
    {
        $strmessage="No file selected.";
    }   
}


Alter the HTML to show the variable strmessage.
<div id="pnlMessage"><?php echo $strmessage; ?></div>


Try uploading invalid files, or files that are too big. In this example, I tried to upload a PDF.


And after that, let's add the default variables into the form. Just for the users' convenience.
            <form id="frmUpload" name="frmUpload" action="" method="POST" enctype="multipart/form-data">
                <label for="flUpload">File</label>
                <input type="file" name="flUpload" id="flUpload">
                <input type="hidden" name="hidUploadSize" id="hidUploadSize" value="50000000">
                <br /><br />
                   <label for="txtLine1">Line 1</label>
                <input name="txtLine1" id="txtLine1" maxlength="50" value="<?php echo $line1; ?>" />
                <br /><br />
                   <label for="txtLine2">Line 2</label>
                <input name="txtLine2" id="txtLine2" maxlength="50" value="<?php echo $line2; ?>" />
                <br /><br />
                <label for="txtSlogan">Slogan</label>
               <input name="txtSlogan" id="txtSlogan" maxlength="20" value="<?php echo $slogan; ?>" />
               <br /><br />
               <input type="submit" name="btSubmit" id="btSubmit" value="Create your Meme!">
           </form>




Let's modify the CSS a bit. The memeContainer div needs to have a background image specified, and in this case, we use colinkaepernick.jpg as a default (that's what filecode and filetype are set to). Make sure it covers the entire square by setting background-size to cover. Do whatever you want with the font, but I'd recommend white. The filter property is important here. It shows images in greyscale.
            #memeContainer
            {
                width: 500px;
                height: 500px;
                padding: 5px;
                margin: 5px;
                float: left;
                outline: 1px solid #DDDDDD;
                background: url(<?php echo "uploads/" . $filecode . "." . $filetype; ?>) center center no-repeat;
                background-size: cover;
                font-family: georgia;
                color: #FFFFFF;
                font-size: 25px;
                -webkit-filter: grayscale(100%);
                filter: grayscale(100%);
                text-align: center;
            }


Oooh.


Now, for the text within the meme, I can't be arsed to create a new CSS class for this, so I'll just go with two paragraph tags, one of which is set in the middle of the box, and the other at the bottom. The first paragraph will display line1 and line2. The second paragraph will display the Nike swoosh and the string slogan.
        <div id="memeContainer">
            <p style="margin-top:50%"><?php echo $line1;?><br /><?php echo $line2;?></p>
            <p style="margin-top:30%"><img src="nikelogo.png"> <?php echo $slogan;?></p>
        </div>


There's your meme! Well, the default anyway.


Let's try something here... well now we have a Serena Williams meme! If you're wondering if I'm mocking her for her recent display at the US Open... yes, I really fucking am.


One last thing...

Let's add a bit of CSS so we can print. formContainer and pnlMessage will be totally invisible, while memeContainer will have the float property set to none, and then aligned center of the screen.
            #memeContainer
            {
                width: 500px;
                height: 500px;
                padding: 5px;
                margin: 5px;
                float: left;
                outline: 1px solid #DDDDDD;
                background: url(<?php echo "uploads/" . $filecode . "." . $filetype; ?>) center center no-repeat;
                background-size: cover;
                font-family: georgia;
                color: #FFFFFF;
                font-size: 25px;
                -webkit-filter: grayscale(100%);
                filter: grayscale(100%);
                text-align: center;
            }

            @media print
            {
                #formContainer, #pnlMessage
                {
                    display: none;
                }

                #memeContainer
                {
                    margin: 10% auto 0 auto;
                    float: none;
                }
            }


Do a Ctrl-P. Beautiful, isn't it.


Last words...

Well, I certainly enjoyed myself. Remember to sanitize your inputs (I didn't do it here because it's out of scope) to prevent a nasty XSS attack. And... have fun. Go crazy.

#justdoit
T___T

No comments:

Post a Comment