using Programming;

A Blog about some of the intrinsics related to programming and how one can get the best out of various languages.

Getting Started with PHP: Part 2

Getting started with PHP: Part 2

In our last discussion we got our PHP environment setup, and we talked about some basic parts of PHP:

  • Statements end in semi-colons (;);
  • We use echo to output things to the caller;
  • There are several comparison operators (==, ===, !=, !==, >, <, >=, <=, <=>);
  • We can use if to change what a program does;
  • Variables ($var);

This got our adventure started, so I want to start moving more into PHP as a language. We're going to start building example products, and talking about the features as we do. We will talk about standard functions, special variables and more.

Let's build a form to show the user's name

For this, we're going to build a web-form that we use to ask for a user's name, and then use the logic we used previously to say hello.

First we'll create a PHP file as we did before. The name is only important in-so-far as you will need to remember it for your browser.

Next, we need a form to show ask the user for their name. For this, we're going to talk about PHP strings for a moment.

PHP: Strings

PHP has 2 different types of strings, and two different ways to create each one. The types are:

Delimited double-quoted strings:

$name = "Elliott";

Delimited single-quoted strings:

$name = 'Elliott';

HEREDOC string (double-quoted):

$name = <<<NAME
Elliott
NAME;

NOWDOC string (single-quoted):

$name = <<<'NAME'
Elliott
NAME;

So, at this point you are likely wondering why PHP has 4 different strings. The logic behind why is actually quite sound, so we'll go over it at a rough-level.

First, single-quoted and double-quoted strings behave differently. Likewise, NOWDOC and HEREDOC behave differently, matching their single-quoted or double-quoted counterpart. A double-quoted string allows you to embed variables within it, such as our previous "Hello $my_name". However, a single-quoted string does not allow this. If we changed our string to 'Hello $my_name', we would get Hello $my_name instead of Hello Elliott as our output.

Next, in delimited strings we have to escape the delimiter if we want to embed it within our string. This means if we want to put the delimiter itself in the string (which we often do with HTML/CSS/JavaScript), we need to escape it, such as:

$html = "<form method=\"POST\"></form>";

Notice how the quotes around "POST" are preceeded by a slash (\). This means that the literal double-quote (") will be put there instead of the escape \".

Enter HEREDOC and NOWDOC: because they don't use delimiters you can include the delimiters in the string freely:

$html = <<<HTML
<form method="POST"></form>
HTML;

The rules around HEREDOC and NOWDOC are as follows:

  1. The string begins with three less-than signs (<<<) and then a name, then the line ends;
  2. The string can contain any characters, and most importantly, the delimiters (" / ') do not need to be escaped;
  3. The string ends when a line that begins with the original name and then a semi-colon is encountered (there may be no whitespace at the beginning of the line);
  4. If the opening name is wrapped with single-quotes, it is a 'NOWDOC' (which acts like a single-quoted string), otherwise it is a HEREDOC (which acts like a double-quoted string);

By "acts like a -quoted string", I mean it either replaces variables like a double-quoted string, or it does not like a single-quoted string.

One key note about HEREDOC and NOWDOC is that you cannot use concatenation in them directly, you must create intermediary strings for that:

$html = <<<HTML
<form method="POST">
HTML;

$html = $html . <<<HTML
</form>
HTML;

That said, both HEREDOC and NOWDOC handle line-continuations / CR;LF; properly, so you could simply do:

$html = <<<HTML
<form method="POST">
</form>
HTML;

Back to our Form

Now that we know about strings, we need to start getting our form ready. In PHP, we can do this either by echo-ing the form, or by ending the PHP tags and including the form as raw data.

For our form, we only need two items within it: a text-box for the name, and a button to submit it. Our HTML might look something like the following:

<form method="POST">
    <input type="text" name="name" />
    <input type="submit" name="submit" value="Say Hello" />
</form>

The name on each of these is important as that is how PHP will access the values.

To see this in action, let's create a PHP page with only that in it. No <?php tags or code at all. If you did it properly, you'll see a webpage with a single text-box and button that says "Say Hello".

This demonstrates that we don't need to echo everything, we can just exit the PHP context and write it out, PHP will output it for us.

Obviously we don't always want to show the form, so it's time we talk about how PHP can access the data that an HTML form sends back.

PHP: Posting

When an HTML form posts data back to a server, it sends a request with the Method: POST header, and a body with each name/value pair encoded as name=encodeValue(value), concatenated with ampersands (&). Thus, if we typed Elliott into our text box and clicked "Say Hello", it would post name=Elliott&submit=Say Hello to our server.

PHP has several "superglobals", which are built-in variables that do special things. The two we'll talk about right now are $_GET and $_POST. You can access both of these from any PHP code.

PHP: Arrays

Before we go deeper into superglobals, let's go over arrays very quickly.

In PHP, an array is a key => value mapping. That is: it has any number of unique keys that have exactly one value. Keys can be anything, most commonly they are integers and strings.

There are two ways in PHP 7.4.6 to construct arrays:

$some_array = array (
    "Key 1" => "Value 1",
    "Key 2" => "Value 2"
);
$some_array = [
    "Key 1" => "Value 1",
    "Key 2" => "Value 2"
];

Both of these methods create the same array, and allow us to use $some_array["Key 1"] and $some_array["Key 2"] to access the values in it. We can also use that to set the values, so we could say $some_array["Key 1"] = "New Value";. Additionally, we can add new keys to the array by doing $some_array["Key 3"] = "Value 3";. Additionally, PHP has a built-in function named print_r that will output the contents of an array for us to troubleshoot.

If we change our PHP page to the following:

<?php
$some_array = array (
    "Key 1" => "Value 1",
    "Key 2" => "Value 2"
);
$some_array = [
    "Key 1" => "Value 1",
    "Key 2" => "Value 2"
];
$some_array["Key 1"] = "New Value";
$some_array["Key 3"] = "Value 3";
print_r($some_array);
?>

We will get the following output:

Array ( [Key 1] => New Value [Key 2] => Value 2 [Key 3] => Value 3 )

This shows us the Key 1 did change, and that Key 3 was added.

Additionally, one other thing we need to discuss on arrays is how to determine if a key exists. Specifically, the isset(...) function.

If we have an array, and we don't know if our key is in it, we use isset( $array[$key] ) to test for it. If we try to use $array[$key] directly, we will get an error:

Notice: Undefined index: $key in $file on line $line

This will put ugly output on our page, and while we can suppress it that doesn't help us: the best way to avoid it is test for it.

To do that, we might do the following:

if (isset($_POST["name"])) {
    // do something with our name
}

Back to Superglobals

The $_GET and $_POST superglobals are arrays where the key comes from a component of the request, and the value comes from that value. As an example, our $_POST will have two keys: $_POST["name"] and $_POST["submit"]. These will have the values set to "Elliott" and "Say Hello" respectively.

Additionally, $_GET derives it's keys and values from the URL parameters. If you've used many websites, you've probably noticed at some point you get wonky URL's that have a question-mark (?) and then names, equal-signs (=) and values, maybe even an ampersand (&) between them. This data is encoded the same way as our POST data, but is accessed via $_GET instead of $_POST. If we did index.php?name=Elliott, we could access our name value with $_GET["name"].

Basically:

  • $_GET will give you an array of the URL parameter keys and values;
  • $_POST will give you an array of the POST body keys and values;

With all this in mind, we can actually build our form now.

For our form, we will need an if statement to determine if the form was "submitted" (test if "name" is in the $_POST array), an else to output the form if it wasn't submitted, and in the if we need to test if it's "Jon", because he owes me a lot of money.

One method of doing this boils down to the following:

<?php
if (isset($_POST["name"])) {
    $name = $_POST["name"];
    if ($name === "Jon") {
        echo "You owe me a lot of money, Jon.";
    } else {
        echo "Hello $name";
    }
} else {
?>
<form method="POST">
    <input type="text" name="name" />
    <input type="submit" name="submit" value="Say Hello" />
</form>
<?php
}
?>

Now, you'll notice we ended the PHP processing before the HTML, then started it again afterwards. This is one technique of printing HTML on a page, but it's not my favourite. I prefer to use an echo with a HEREDOC because it seems to read more clearly, and we do less "context switching" between what is PHP code and what is not.

To use the HEREDOC, we change our code to:

<?php
if (isset($_POST["name"])) {
    $name = $_POST["name"];
    if ($name === "Jon") {
        echo "You owe me a lot of money, Jon.";
    } else {
        echo "Hello $name";
    }
} else {
    echo <<<HTML
<form method="POST">
    <input type="text" name="name" />
    <input type="submit" name="submit" value="Say Hello" />
</form>
HTML;
}

To me, this is a cleaner way to output our HTML. This also allows us to embed variables in it if we need to, whereas the other version would require us to do <?php echo $variable; ?>.

More form Elements

I want to go over some more HTML form elements, such as textarea, checkbox, radio and select.

Of these, three play just as well as text did with our PHP: $_POST[$name] will have the value they are. The one that doesn't play as well is checkbox, and the behaviour it has can vary depending on whether you are using Apache or IIS.

With Apache, if isset($_POST[$checkbox_name]) evaluates to TRUE, then the checkbox was selected, regardless of value. With IIS, the checkbox value will be off if it was not submitted, and either on or the specified value if it was submitted.

We'll go over basic elements, and basic attributes that are important on those elements, but please know that this is not an exhaustive list of the elements nor of the attributes.

HTML: Textarea

An HTML textarea is a large text box that supports multiline input. It is included in a form with the following (basic) markup:

<textarea
    [name="$name"]
    [rows="$row_count"]
    [cols="$col_chars"]>
</textarea>

PHP will see $_POST[$name] as the text-value entered.

HTML: Text

An HTML text is a small text box that supports soft-limits on text input. It is included in a form with the following (basic) markup:

<input type="text"
    [name="$name"]
    [value="$default_value"]
    [maxlength="$max_length_chars"] />

PHP will see $_POST[$name] as the text-value entered.

HTML: Radio

An HTML radio is a group of mutually-exclusive options (that is, only one option may be selected). It is included in a form with the following (basic) markup:

<input type="radio"
    [name="$name"]
    [value="$value"]
    [checked="checked"] />

If multiple radio buttons have the same name, they are part of a single "group" and only one of them may be selected. Additionally, you may default which one is selected with the checked="checked" attribute.

PHP will see $_POST[$name] as the $value of the selected radio button.

HTML: Select

An HTML select is a group of mutually-exclusive options (that is, only one option may be selected) that presents as a drop-down list. It is included in a form with the following (basic) markup:

<select [name="$name"]>
    <option [value="$value"] [selected="selected"]>$display_text</option>
</select>

Any number of <option> elements may be included in it. Additionally, you may default which one is selected with the selected="selected" attribute.

PHP will see $_POST[$name] as the $value of the selected drop-down option.

HTML: Checkbox

An HTML checkbox is a single on/off toggle. It is included in a form with the following (basic) markup:

<input type="checkbox"
    [name="$name"]
    [value="$value"]
    [checked="checked"] />

You may default it to the "checked" state with the checked="checked" attribute.

On Apache:

PHP will see $_POST[$name] as $value (or "on" if there is no value) if it is checked, otherwise $_POST[$name] will not be set.

On IIS:

PHP will see $_POST[$name] as $value (or "on" if there is no value) if it is checked, otherwise it will see $_POST[$name] as "off".

Experimenting with Form Elements

To see all of this in action, you can print_r($_POST) and create a basic form with all of these elements:

<?php
print_r($_POST);
echo <<<HTML
<form method="POST">
    <textarea name="textarea">Textarea Text</textarea><br />
    <input type="text" name="text" value="Text Text" /><br />
    <input type="radio" name="radio" value="Option 1" checked="checked" /><br />
    <input type="radio" name="radio" value="Option 2" /><br />
    <input type="checkbox" name="checkbox_on" checked="checked" /><br />
    <input type="checkbox" name="checkbox_on_value" value="Checkbox On" checked="checked" /><br />
    <input type="checkbox" name="checkbox_off" /><br />
    <input type="checkbox" name="checkbox_off_value" value="Checkbox Off" /><br />
    <select name="select">
        <option value="Option 1" selected="selected">Option 1</option>
        <option value="Option 2">Option 2</option>
        <option value="Option 3">Option 3</option>
        <option value="Option 4">Option 4</option>
    </select>
    <input type="submit" name="submit" value="Submit" /><br />
</form>
HTML;

If you submit the default form on your Apache + PHP environment, you will get the following at the beginning of the page:

Array
(
    [textarea] => Textarea Text
    [text] => Text Text
    [radio] => Option 1
    [checkbox_on] => on
    [checkbox_on_value] => Checkbox On
    [select] => Option 1
    [submit] => Submit
)

Cleaning up Form Elements

One of the many things I have my own standard "PHP library" for is cleaning up these form elements, specifically checkboxes.

I typically do this by creating a PHP class with static functions, but we haven't gotten to that point and there's a lot of ground to cover before we get there, so I'm going to start with regular functions to clean this up.

PHP: Functions

PHP has the concept of "functions", or reusable blocks of code that do a certain, specific task. We have used something that looks like a function (isset), but we haven't used a true function yet.

A function is just code, often with inputs and outputs that do a thing. Functions have different "definitions", such as "pure" vs. "impure", where a "pure" function will produce the exact same output for any given input, and an "impure" function will not.

PHP defines functions quite simply: the keyword function followed by the name, a pair of parenthesis (()), then braces ({}) to denote the code in the function. Additionally, in the parenthesis, you may specify parameters to be passed to your function.

One of the relatively new features of PHP is the ability to specify types for the parameters passed to your function, and the type of data the function will return. We're going to use these, as it's a healthy habit to get into.

If we wanted to define a function to get text from our form, we might do the following:

function text(string $name): ?string {
    if (isset($_POST[$name])) {
        return $_POST[$name];
    }
    return NULL;
}

Some of this is new, so let's start from the beginning and hit all the new pieces:

  • function: as discussed above, this tells PHP we're about to define our own function;
  • text: this is the name, and this can be any string that you would name a variable;
  • string: this is the type for the first input parameter, here we say it has to be a string value;
  • $name: this is the name of the first parameter, in our case we're naming it name;
  • : ?string: this specifies the return type of the function, here it says it is a ?string, where the ? means it is a nullable string;
  • return: this tells PHP to end the function execution and give the caller whatever follows the return keyword;
  • NULL: this is a special value that means "there is no value";

The string for the parameter, and : ?string for the return type are optional, and if you do not specify them PHP will default to allowing any input and will not tell the caller what the output is (because it does not know).

We can call this function by specifying the name and then parameters: text("textarea") will be replaced with the value of $_POST["textarea"] per our function at runtime.

My personal PHP library defines a bunch of these functions, but the one I want to mention is the checkbox function, which will take the IIS oddities into account:

function checkbox(string $name): ?string {
    if (isset($_POST[$name]) && $_POST[$name] !== "off") {
        return $_POST[$name];
    }
    return NULL;
}

Here, we notice we have something new: &&. Let's talk about that for a moment.

PHP: Logical Combination Operators

PHP has the concept of combining logical comparison operators together via several chain operators. This allows you to put multiple conditions in your if statements (and other locations, but that's a discussion for later).

  • &&: if the left and right side of this are both TRUE the result is TRUE, otherwise the result is FALSE, additionally if the left side is FALSE the right side is not evaluated;
  • ||: if the left and right side of this are both FALSE the result is FALSE, otherwise the result is TRUE, additionally if the left side is TRUE the right side is not evaluated;
  • !: flips the right side from TRUE to FALSE, or FALSE to TRUE;
  • xor: if the left and right side are not the same boolean the result is TRUE, otherwise the result is FALSE;

As a result, we can use isset($_POST[$name]) && $_POST[$name] !== "off" to say "if $_POST[$name] has a value, and that value is not "off", then continue into our body." Additionally, PHP will not attempt to test $_POST[$name] !== "off" if isset($_POST[$name]) failed.


In Summation

With logical operators covered, I think now is a good time to wrap up. We'll get further into our adventure next time, but we're building a solid foundation on which we'll continue to develop.