Sams Teach Yourself PHP, MySQL and Apache All in One (2012)

Part III. Getting Involved with the Code

Chapter 10. Working with Strings, Dates, and Time


In this chapter, you learn the following:

• How to format strings

• How to determine the length of a string

• How to find a substring within a string

• How to break a string down into component parts

• How to remove whitespace from the beginning or end of a string

• How to replace substrings

• How to change the case of a string

• How to acquire the current date and time

• How to get information about a date and time

• How to format date and time information

• How to test dates for validity

• How to set dates and times


No matter how rich your web content might be, at the heart of it is just HTML that tells the browser how to render string-based content. It is no accident, then, that PHP provides many functions with which you can format and manipulate strings. Similarly, dates and times are so much a part of everyday life that it becomes easy to use them without thinking. However, because the quirks of the Gregorian calendar can be difficult to work with, PHP provides powerful tools that make date manipulation an easy task.

Numerous PHP functions are available to you when it comes to the manipulations of strings, dates, and times, and this chapter does not even begin to cover all of them. However, this chapter does provide a foundation for using some of the basic string, date, and time functions, and an idea of how to begin thinking about using these types of functions in your code. The rule of thumb is this: If you want to transform, manipulate, or display a string, date, or time, don’t build your own custom solution without first visiting the PHP Manual, because chances are good that a function already exists for your desired task.

Formatting Strings with PHP

Until now, you have simply printed any strings you want to display directly to the browser in their original state. PHP provides two functions that enable you first to apply formatting, whether to round doubles to a given number of decimal places, define alignment within a field, or display data according to different number systems. In this section, you learn a few of the formatting options provided by printf() and sprintf().

Working with printf()

If you have any experience with a C-like programming language, you are probably familiar with the concept of the printf() function. The printf() function requires a string argument, known as a format control string. It also accepts additional arguments of different types, which you learn about in a moment. The format control string contains instructions regarding the display of these additional arguments. The following fragment, for example, uses printf() to output an integer as an octal (or base-8) number:

<?php
printf("This is my number: %o", 55);
// prints "This is my number: 67"
?>

Included within the format control string (the first argument) is a special code, known as a conversion specification. A conversion specification begins with a percent (%) symbol and defines how to treat the corresponding argument to printf(). You can include as many conversion specifications as you want within the format control string, as long as you send an equivalent number of arguments to printf().

The following fragment outputs two floating-point numbers using printf():

<?php
printf("First number: %f<br/>Second number: %f<br/>", 55, 66);
// Prints:
// First number: 55.000000
// Second number: 66.000000
?>

The first conversion specification corresponds to the first of the additional arguments to printf(), or 55. The second conversion specification corresponds to 66. The f following the percent symbol requires that the data be treated as a floating-point number. This part of the conversion specification is the type specifier.

printf() and Type Specifiers

You have already come across two type specifiers, o, which displays integers as octals, and f, which displays integers as floating-point numbers. Table 10.1 lists the other type specifiers available.

Table 10.1 Type Specifiers

image

Listing 10.1 uses printf() to display a single number according to some of the type specifiers listed in Table 10.1. Notice that the listing does not only add conversion specifications to the format control string. Any additional text included is also printed.

Listing 10.1 Demonstrating Some Type Specifiers


1:  <?php
2:  $number = 543;
3:  printf("Decimal: %d<br/>", $number);
4:  printf("Binary: %b<br/>", $number);
5:  printf("Double: %f<br/>", $number);
6:  printf("Octal: %o<br/>", $number);
7:  printf("String: %s<br/>", $number);
8:  printf("Hex (lower): %x<br/>", $number);
9:  printf("Hex (upper): %X<br/>", $number);
10: ?>


Put these lines into a text file named printftest.php and place this file in your web server document root. When you access this script through your web browser, it should look something like Figure 10.1. As you can see, printf() is a quick way of converting data from one number system to another and outputting the result.

image

Figure 10.1 Demonstrating conversion specifiers.

When specifying a color in HTML, you combine three hexadecimal numbers between 00 and FF, representing the values for red, green, and blue. You can use printf() to convert three decimal numbers between 0 and 255 to their hexadecimal equivalents:

<?php
$red = 204;
$green = 204;
$blue = 204;
printf("#%X%X%X", $red, $green, $blue);
// prints "#CCCCCC"
?>

Although you can use the type specifier to convert from decimal to hexadecimal numbers, you cannot use it to determine how many characters the output for each argument should occupy. Within an HTML color code, each hexadecimal number should be padded to two characters, which would become a problem if you changed the $red, $green, and $blue variables in the previous fragment to contain 1, for example. You would end up with the output #111. You can force the output of leading zeros by using a padding specifier.

Padding Output with a Padding Specifier

You can require that output be padded by leading characters. The padding specifier should directly follow the percent sign that begins a conversion specification. To pad output with leading zeros, the padding specifier should consist of a zero followed by the number of characters you want the output to take up. If the output occupies fewer characters than this total, zeros fill the difference:

<?php
printf("%04d", 36);
// prints "0036"
?>

To pad output with leading spaces, the padding specifier should consist of a space character followed by the number of characters that the output should occupy:

<?php
printf("% 4d", 36)
// prints "  36"
?>


Tip

A browser will not display multiple spaces in an HTML document. You can force the display of spaces and newlines by placing <pre> tags around your output:

<pre>
<?php
echo "The       spaces       will be visible";
?>
</pre>

If you want to format an entire document as text, you can use the header() function to change the Content-Type header:

header("Content-Type: text/plain");

Remember that your script must not have sent any output to the browser for the header() function to work as desired.


You can specify any character other than a space or a zero in your padding specifier with a single quotation mark followed by the character you want to use:

<?php
printf ("%'x4d", 36);
// prints "xx36"
?>

You now have the tools you need to complete your HTML code example. Until now, you could convert three numbers to hexadecimal, but could not pad the hexadecimal values with leading zeros:

<?php
$red = 1;
$green = 1;
$blue = 1;
printf("#%02X%02X%02X", $red, $green, $blue);
// prints "#010101"
?>

Each variable is output as a hexadecimal number. If the output occupies fewer than two spaces, leading zeros are added.

Specifying a Field Width

You can specify the number of spaces within which your output should sit. A field width specifier is an integer that should be placed after the percent sign that begins a conversion specification (assuming that no padding specifier is defined). The following fragment outputs a list of four items, all of which sit within a field of 20 spaces. To make the spaces visible on the browser, place all the output within a pre element:

<?php
echo "<pre>";
printf("%20s\n", "Books");
printf("%20s\n", "CDs");
printf("%20s\n", "DVDs");
printf("%20s\n", "Games");
printf("%20s\n", "Magazines");
echo "</pre>";
?>

Figure 10.2 shows the output of this fragment.

image

Figure 10.2 Aligning with field width specifiers.

By default, output is right-aligned within the field you specify. You can make it left-aligned by prepending a minus (dash) to the field width specifier:

printf("%-20s\n", "Left aligned");

Note that alignment applies to the decimal portion of any number that you output. In other words, only the portion before the decimal point of a double will sit flush to the end of the field width when right-aligned.

Specifying Precision

If you want to output data in floating-point format, you can specify the precision to which you want to round your data. This proves particularly useful when dealing with currency. The precision identifier should be placed directly before the type specifier. It consists of a dot followed by the number of decimal places to which you want to round. This specifier has an effect only on data that is output with the f type specifier:

<?php
printf("%.2f", 5.333333);
// prints "5.33"
?>


Note

In the C language, it is possible to use a precision specifier with printf() to specify padding for decimal output. The precision specifier has no effect on decimal output in PHP. Use the padding specifier to add leading zeros to integers.


Conversion Specifications: A Recap

Table 10.2 lists the specifiers that can make up a conversion specification in the order that they would be included. Note that it is difficult to use both a padding specifier and a field width specifier. You should choose to use one or the other, but not both.

Table 10.2 Components of Conversion Specification

image

Listing 10.2 uses printf() to output a list of products

Listing 10.2 Using printf() to Format a List of Product Prices


1:  <?php
2:  $products = array("Green armchair" => "222.4",
3:                    "Candlestick"=> "4",
4:                    "Coffee table"=> "80.6");
5:  echo "<pre>";
6:  printf("%-20s%20s\n", "Name", "Price");
7:  printf("%'-40s\n", "");
8:  foreach ($products as $key=>$val) {
9:     printf( "%-20s%20.2f\n", $key, $val );
10: }
11: echo "</pre>";
12: ?>


The listing first defines an associative array containing product names and prices in lines 2 through 4. It prints the opening tag of the pre element, in line 5, so that the browser will recognize the spaces and newlines. The first printf() call on line 6 uses the following format control string:

"%-20s%20s\n"

The first conversion specification in the format control string ("%-20s") defines a width specifier of 20 characters, with the output to be left-justified. The string type specifier is also used. The second conversion specification ("%20s") sets up a right-aligned field width. This printf() call outputs our field headers.

The second printf() function call on line 7 draws a line containing - characters, 40 characters wide. You achieve this with a padding specifier, which adds padding to an empty string.

The final printf() call on line 9 is part of a foreach statement that loops through the product array. The code uses two conversion specifications here—the first ("%–20s") prints the product name as a string left-justified within a 20-character field, and the second ("%20.2f") uses a field width specifier to ensure that output will be right-aligned within a 20-character field. It also uses a precision specifier to ensure that the output is rounded to two decimal places.

Put these lines into a text file named printftest2.php and place this file in your web server document root. When you access this script through your web browser, it should look like Figure 10.3.

image

Figure 10.3 Products and prices formatted with printf().

Argument Swapping

Suppose that you are printing dates to the browser. As shown in the following snippet, assume the dates are in a multidimensional array and you are using printf() to format the output:

<?php
$dates = array(
         array('mon'=> 12, 'mday'=>25, 'year'=>2011),
         array('mon'=>  1, 'mday'=>23, 'year'=>2012),
         array('mon'=> 10, 'mday'=>29, 'year'=>2011)
         );
$format = include("local_format.php");
foreach($dates as $date) {
    printf("$format", $date['mon'], $date['mday'], $date['year']);
}
?>

In the preceding snippet, the format control string comes from an include file named local_format.php. Assuming that this file contains only

<?php
return "%02d/%02d/%d<br/>";
?>

the output will be in the format mm/dd/yyyy:

12/25/2011
01/23/2012
10/29/2011

Imagine now that you are installing your script for a European site, where dates are commonly presented with days before months (dd/mm/yyyy). Assume that the core code is written in stone and cannot be changed. What should you do? Luckily, you can now alter the order in which the arguments are presented from within the format control code by changing the return statement to the following:

return "%2\$02d/%1\$02d/%3\$d<br/>";

You can insert the argument number you are interested in after the initial percentage character that marks each conversion specification, followed by an escaped dollar ($) character. So, in the fragment, you are demanding that the second argument be presented

%2\$02d

followed by the first argument:

%1\$02d

and concluded with the third argument:

%3\$d

The result of the new code is a list of dates in British format:

25/12/2011
23/01/2012
29/10/2011

Storing a Formatted String

The printf() function outputs data to the browser, which means that the results are not available to your scripts. You can, however, use the function sprintf(), which is used just like printf() except that it returns a string that can be stored in a variable for later use. The following fragment uses sprintf() to round a double to two decimal places, storing the result in $cash:

<?php
$cash = sprintf("%.2f", 21.334454);
echo "You have \$$cash to spend.";
// Prints "You have $21.33 to spend."
?>

One particular use of sprintf() is to write formatted data to a file—you can call sprintf() and assign its return value to a variable that can then be printed to a file with fputs().

Investigating Strings in PHP

You do not always know everything about the data you are working with. Strings can arrive from many sources, including user input, databases, files, and web pages. Before you begin to work with data from an external source, you often need to find out more about the data. PHP provides many functions that enable you to acquire information about strings.

A Note About Indexing Strings

This book frequently uses the word index in relation to strings. You have come across this word in the context of arrays, such as in Chapter 8, “Working with Arrays.” In fact, strings and arrays are not as different as you might imagine. You can think of a string as an array of characters, and thus you can access the individual characters of a string as if they were elements of an array:

<?php
$test = "phpcoder";
echo $test[0]; // prints "p"
echo $test[4]; // prints "o"
?>

It is important to remember that when this book discusses the position or index of a character within a string, the characters, just like array elements, have a starting index value of 0, not 1.

Finding the Length of a String with strlen()

You can use the built-in strlen() function to determine the length of a string. This function requires a string as its argument and returns an integer representing the number of characters in the string you passed to it. strlen() might be used to check the length of user input, as in the following fragment, which tests a membership code to ensure that it is exactly four characters long:

<?php
$membership = "pAB7";
if (strlen($membership) == 4) {
    echo "<p>Thank you!</p>";
} else {
    echo "<p>Your membership number must be four characters long.</p>";
}
?>

The user is thanked for his input only if the $membership variable holds a string that is exactly four characters long. Otherwise, an error message is presented.

Finding a Substring Within a String with strstr()

You can use the strstr() function to test whether a string exists within another string. This function requires two arguments: the source string and the substring you want to find within it. The function returns false if it cannot find the substring; otherwise, it returns the portion of the source string, beginning with the substring. For the following example, imagine that you want to treat membership codes that contain the string AB differently from those that do not:

<?php
$membership = "pAB7";
if (strstr($membership, "AB")) {
   echo "<p>Your membership expires soon!</p>";
} else {
   echo "<p>Thank you!</p>";
}
?>

Because the value of the $membership variable contains the substring AB, the strstr() function returns the string AB7. The function resolves to true when tested, so the code prints the appropriate message, "Your membership expires soon!". But what happens if you search for "pab7"? Becausestrstr() is case sensitive, AB will not be found. The if statement’s original test will fail, and the default message (“Thank you!”) will be printed to the browser. If you want to search for either AB or ab within the string, you must use strstr() in place of substr(); the function is used in exactly the same way, but its search is not case sensitive.

Finding the Position of a Substring with strpos()

The strpos() function tells you whether a string exists within a larger string as well as where it is found. The strpos() function requires two arguments: the source string and the substring you are seeking. The function also accepts an optional third argument, an integer representing the index from which you want to start searching. If the substring does not exist, strpos() returns false; otherwise, it returns the index at which the substring begins. The following fragment uses strpos() to ensure that a string begins with the string mz:

<?php
$membership = "mz00xyz";
if (strpos($membership, "mz") === 0) {
   echo "Hello mz!";
}
?>

Notice the trick that had to be played to get the expected results. Although the strpos() function finds mz in the string, it finds it at the first element—the 0 position. Returning zero will resolve to false in the if condition test. To work around this, the code uses the equivalence operator ===, which returns true if the left and right operands are equivalent and of the same type, as they are in this case.

This is just one of several variations on string-related functions meant to find needles in haystacks. Visit the PHP Manual page for this function for links to many other related functions.

Extracting Part of a String with substr()

The substr() function returns a string based on the start index and length of the characters you are looking for. This function requires two arguments: a source string and the starting index. Using these arguments, the function returns all the characters from the starting index to the end of the string you are searching. You can also (optionally) provide a third argument—an integer representing the length of the string you want returned. If this third argument is present, substr() returns only that number of characters, from the start index onward:

<?php
$test = "phpcoder";
echo substr($test,3)."<br/>";  // prints "coder"
echo substr($test,3,2)."<br/>"; // prints "co"
?>

If you pass substr() a negative number as its second (starting index) argument, it will count from the end rather than the beginning of the string. The following fragment writes a specific message to people who have submitted an email address ending in .fr:

<?php
$test = "pierre@wanadoo.fr";
if ($test = substr($test, -3) == ".fr") {
   echo "<p>Bonjour! Nous avons des prix spéciaux de vous.</p>";
} else {
   echo "<p>Welcome to our store.</p>";
}
?>

Tokenizing a String with strtok()

You can parse a string word by word using the strtok() function. This function requires two arguments: the string to tokenize and the delimiters by which to split the string. The delimiter string can include as many characters as you want, and the function will return the first token found. After strtok() has been called for the first time, the source string is cached—for subsequent calls, you should pass only the delimiter string to the strtok() function. The function returns the next found token every time it is called, returning false when the end of the string is reached. Thestrtok() function is usually called repeatedly within a loop. Listing 10.3 uses strtok() to tokenize a URL, splitting the host and path from the query string and further dividing the name/value pairs of the query string.

Listing 10.3 Dividing a String into Tokens with strtok()


1: <?php
2: $test  = "http://www.google.com/search?";
3: $test .= "hl=en&ie=UTF-8&q=php+development+books&btnG=Google+Search";
4: $delims = "?&";
5: $word = strtok($test, $delims);
6: while (is_string($word)) {
7:    if ($word) {
8:        echo $word."<br/>";
9:    }
10:    $word = strtok($delims);
11: }
12: ?>


Put these lines into a text file named teststrtotok.php and place this file in your web server document root. When you access this script through your web browser, it should look like Figure 10.4.

image

Figure 10.4 Output of teststrtotok.php, a tokenized string.

The strtok() function is something of a blunt instrument, and a few tricks are required to work with it. The code first stores the delimiters to work with in a variable, $delims, on line 4. It calls strtok() on line 5, passing it the URL to tokenize and the $delims string, and stores the first result in $word. Within the conditional expression of the while loop on line 6, the code tests that $word is a string. If it isn’t, the end of the string has been reached and no further action is required.

Listing 10.3 tests the return type because a string containing two delimiters in a row would cause strtok() to return an empty string when it reaches the first of these delimiters. So, a more conventional test such as

while ($word) {
      $word = strtok($delims);
}

would fail if $word is an empty string, even if the end of the source string has not yet been reached.

Having established that $word contains a string, the code can go on to work with it. If $word does not contain an empty string, print it to the browser on line 8. The code must then call strtok() again on line 10 to repopulate the $word variable for the next test. Notice that the source string tostrtok() is not passed a second time. (If were to do this, the first word of the source string would be returned once again, and you would find yourself in an infinite loop.)

Manipulating Strings with PHP

PHP provides many functions that transform a string argument, subtly or radically, as you’ll soon see.

Cleaning Up a String with trim()ltrim(), and strip_tags()

When you acquire text from user input or an external file, you cannot always be sure that you haven’t also picked up whitespace at the beginning and end of your data. The trim() function shaves any whitespace characters, including newlines, tabs, and spaces, from both the start and end of a string. It accepts the string to modify, returning the cleaned-up version. For example:

<?php
$text = "\t\tlots of room to breathe      ";
echo "<pre>$text</pre>";
// prints "        lots of room to breathe      ";
$text = trim($text);
echo "<pre>$text</pre>";
// prints "lots of room to breathe";
?>

Of course, this might be more work than you require. You might want to keep whitespace at the beginning of a string but remove it from the end. You can use PHP’s rtrim() function exactly as you would use trim(). However, rtrim() removes whitespace at only the end of the string argument:

<?php
$text = "\t\tlots of room to breathe      ";
echo "<pre>$text</pre>";
// prints "        lots of room to breathe      ";
$text = rtrim($text);
echo "<pre>$text</pre>";
// prints "        lots of room to breathe";
?>

PHP provides the ltrim() function to strip whitespace from only the beginning of a string. Once again, you call this function with the string you want to transform and it returns a new string, shorn of tabs, newlines, and spaces:

<?php
$text = "\t\tlots of room to breathe      ";
echo "<pre>$text</pre>";
// prints "        lots of room to breathe      ";
$text = ltrim($text);
echo "<pre>$text</pre>";
// prints "lots of room to breathe      ";
?>

It is not unusual to have to remove tags from a block of text to display it without any HTML formatting. PHP provides the strip_tags() function for this purpose. The strip_tags() function accepts two arguments: the text to transform and an optional set of HTML tags that strip_tags() can leave in place. The tags in this list should not be separated by any characters:

<?php
$string = "<p>\"I <em>simply</em> will not have it,\" <br/>said Mr Dean.</p>
<p><strong>The end.</strong></p>";
echo strip_tags($string, "<br/><p>");
?>

The previous code fragment creates an HTML-formatted string. When you call strip_tags(), you pass it the $string variable and a list of exceptions. The result is that the <br/> and <p> tags are left in place and all other tags are stripped out. In addition, the matching tag for <p>—</p>—is also removed.

The output of this snippet is as follows:

"I simply will not have it,"
said Mr Dean.

The end.

Note that the emphasis and strong formatting are gone, but the paragraphs and line breaks remain.

Replacing a Portion of a String Using substr_replace()

The substr_replace() function works similarly to the substr() function, except it enables you to replace the portion of the string that you extract. The function requires three arguments: the string to transform, the text to add to it, and the starting index; it also accepts an optional length argument. The substr_replace() function finds the portion of a string specified by the starting index and length arguments, replaces this portion with the string provided, and returns the entire transformed string.

The following code fragment for renewing a user’s membership number changes its second two characters:

<?php
$membership = "mz11xyz";
$membership = substr_replace($membership, "12", 2, 2);
echo "New membership number: $membership";
// prints "New membership number: mz12xyz"
?>

The result of this code is that the old membership number, "mz11xyz", is transformed into the new membership number, "mz12xyz".

Replacing Substrings Using str_replace

The str_replace() function is used to replace all instances of a given string within another string. It requires three arguments: the search string, the replacement string, and the master string. The function returns the transformed string.

The following example uses str_replace() to change all references to 2010 to 2012 within a master string:

<?php
$string = "<h1>The 2010 Guide to All Things Good in the World</h1>";
$string .= "<p>Site contents copyright 2010.</p>";
echo str_replace("2010","2012",$string);
?>

The str_replace() function accepts arrays as well as strings for all its arguments. This enables you to perform multiple search and replace operations on a subject string, and even on more than one subject string. Take the following snippet, for instance:

<?php
$source = array(
  "The package which is at version 4.2 was released in 2005.",
  "The year 2005 was an excellent time for PointyThing 4.2!");
$search  = array("4.2", "2005");
$replace = array("6.3", "2012");
$source = str_replace($search, $replace, $source);
foreach($source as $str) {
  echo "$str<br>";
}
?>

The output is of this snippet is as follows:

The package which is at version 6.3 was released in 2012.
The year 2012 was an excellent time for PointyThing 6.3!

When an array of strings is passed to str_replace() for its first and second arguments, it attempts to switch each search string with its corresponding replace string in the text to be transformed. When the third argument is an array, the str_replace() function returns an array of strings. The search and replace operation will have been executed on each string in the array.

Converting Case

PHP provides several functions that allow you to convert the case of a string. Changing case is often useful for string comparisons. To get an uppercase version of a string, use the strtoupper() function. This function requires only the string that you want to convert and returns the converted string:

<?php
$membership = "mz11xyz";
$membership = strtoupper($membership);
echo "$membership"; // prints "MZ11XYZ"
?>

To convert a string to lowercase characters, use the strtolower() function. Once again, this function requires the string you want to convert and returns the converted version:

<?php
$membership = "MZ11XYZ";
$membership = strtolower($membership);
echo "$membership"; // prints "mz11xyz"
?>

PHP also provides a case function that has a useful cosmetic purpose. The ucwords() function makes the first letter of every word in a string uppercase. The following fragment makes the first letter of every word in a user-submitted string uppercase:

<?php
$full_name = "violet elizabeth bott";
$full_name = ucwords($full_name);
echo $full_name; // prints "Violet Elizabeth Bott"
?>

Although this function makes the first letter of each word uppercase, it does not touch any other letters. So, if the user had had problems with her Shift key in the previous example and submitted VIolEt eLIZaBeTH bOTt, the preceding approach would not have done much to fix the string. The output would have been VIolEt ELIZaBeTH BOTt, which isn’t much of an improvement. You can deal with this by making the submitted string lowercase with the strtolower() function before invoking ucwords():

<?php
$full_name = "VIolEt eLIZaBeTH bOTt";
$full_name = ucwords(strtolower($full_name));
echo $full_name; // prints "Violet Elizabeth Bott"
?>

Finally, the ucfirst() function capitalizes only the first letter in a string. The following fragment capitalizes the first letter in a user-submitted string:

<?php
$myString = "this is my string.";
$myString = ucfirst($myString);
echo $myString; // prints "This is my string."
?>

Working with case-related string functions can prove useful when attempting to authenticate passwords that are not case sensitive, for example. If the user inputs MyPass and the stored password is mypass but you do not want the match to be case sensitive, you can attempt to match a lowercase (or uppercase) version of the user input with the lowercase (or uppercase) version of the stored password. If they match in their similarly cased format, the user can be authenticated even if he typed something different from what was actually stored.

Wrapping Text with wordwrap() and nl2br()

When you present plaintext within a web page, you are often faced with a problem in which new lines are not displayed and your text runs together into one big mess. The nl2br() function conveniently converts every new line into an HTML break. So

<?php
$string  = "one line\n";
$string .= "another line\n";
$string .= "a third for luck\n";
echo nl2br($string);
?>

outputs

one line<br />
another line<br />
a third for luck<br />

The nl2br() function is great for maintaining newlines that are already in the text you are converting. Occasionally, you might want to add arbitrary line breaks to format a column of text. The wordwrap() function is perfect for this. wordwrap() requires one argument: the string to transform. By default, wordwrap() wraps lines every 75 characters and uses \n as its line break character. So, the code fragment

<?php
$string  = "Given a long line, wordwrap() is useful as a means of ";
$string .= "breaking it into a column and thereby making it easier to read";
echo wordwrap($string);
?>

outputs the following:

Given a long line, wordwrap() is useful as a means of breaking it into a
column and thereby making it easier to read

Because the lines are broken with the character \n, the formatting does not show up in HTML code, of course—the output here is what you see if you view the source in your browser. The wordwrap() function has two more optional arguments: a number representing the maximum number of characters per line and a string representing the end of line string you want to use. So, applying the function call

echo wordwrap($string, 24, "<br/>\n");

to the $string variable used earlier, the output is this:

Given a long line,<br/>
wordwrap() is useful as<br/>
a means of breaking it<br/>
into a column and<br/>
thereby making it easier<br/>
to read

The wordwrap() function does not automatically break at your line limit if a word has more characters than the limit. You can, however, use an optional fourth argument to enforce this. The argument should be a positive integer. So, using wordwrap() in conjunction with the fourth argument, you can wrap a string even when it contains words that extend beyond the limit you are setting. This fragment

<?php
$string  = "As usual you will find me at http://www.witteringonaboutit.com/";
$string .= "chat/eating_green_cheese/forum.php. Hope to see you there!";
echo wordwrap($string, 24, "<br/>\n", 1);
?>

outputs

As usual you will find<br/>
me at<br/>
http://www.witteringonab<br/>
outit.com/chat/eating_gr<br/>
een_cheese/forum.php.<br/>
Hope to see you there!

instead of

As usual you will find<br/>
me at<br/>
http://www.witteringonaboutit.com/chat/eating_green_cheese/forum.php. <br/>
Hope to see you there!

Breaking Strings into Arrays with explode()

The delightfully named explode() function is similar in some ways to strtok(). But explode() breaks up a string into an array, which you can then store, sort, or examine as you want. The explode() function requires two arguments: the delimiter string that you want to use to break up the source string and the source string itself. The function optionally accepts a third argument that determines the maximum number of pieces the string can be broken into. The delimiter string can include more than one character, all of which form a single delimiter (unlike multiple delimiter characters passed to strtok(), each of which will be a delimiter in its own right). The following fragment breaks up a date and stores the result in an array:

<?php
$start_date = "2012-02-19";
$date_array = explode("-", $start_date);
// $date_array[0] == "2012"
// $date_array[1] == "02"
// $date_array[2] == "19"
echo $date_array[0]."-".$date_array[1]."-".$date_array[2];
//prints 2012-02-19
?>

Now that your head is full with some common PHP string functions, let’s move on to date and time functions.

Using Date and Time Functions in PHP

The following sections introduce you to the date- and time-related functions specifically in PHP. Try out each listing for yourself to see how simple and powerful these functions can be.

Getting the Date with time()

PHP’s time() function gives you all the information you need about the current date and time. It requires no arguments and returns an integer. For us humans, the returned number is a little hard on the eyes, but it’s extremely useful nonetheless:

echo time();
// sample output: 1326853185
// this represents January 17, 2012 at 09:19PM

The integer returned by time() represents the number of seconds elapsed since midnight GMT on January 1, 1970. This moment is known as the UNIX epoch, and the number of seconds that have elapsed since then is referred to as a timestamp. PHP offers excellent tools to convert a timestamp into a form that humans are comfortable with. Even so, you might think, “Isn’t a timestamp a needlessly convoluted way of storing a date?” In fact, the opposite is true. From just one number, you can extract enormous amounts of information. Even better, a timestamp can make date arithmetic much easier than you might imagine.

Think of a homegrown date system in which you record days of the month as well as months and years. Now imagine a script that must add one day to a given date. If this date happened to be 31 December 1999, rather than adding 1 to the date, you’d have to write code to set the day of the month to 1, the month to January, and the year to 2000. Using a timestamp, you need add only a day’s worth of seconds (60 * 60 * 24, or 86,400) to your current figure and you’re done. You can convert this new figure into something friendlier, at your leisure.

Converting a Timestamp with getdate()

Now that you have a timestamp to work with, you must convert it before you present it to the user. getdate() optionally accepts a timestamp and returns an associative array containing information about the date. If you omit the timestamp, getdate() works with the current timestamp as returned by time(). Table 10.3 lists the elements contained in the array returned by getdate().

Table 10.3 The Associative Array Returned by getdate()

image

Listing 10.4 uses getdate() in line 2 to extract information from a timestamp, employing a foreach statement to print each element (line 3). You can see typical output of this script, called getdate.php, in Figure 10.5.

image

Figure 10.5 Using getdate().

Listing 10.4 Acquiring Date Information with getdate()


1: <?php
2: $date_array = getdate(); // no argument passed so today's date will be used
3: foreach ($date_array as $key => $val) {
4:     echo "$key = $val<br>";
5: }
6: ?>
7: <hr/>
8: <?php
9: echo "<p>Today's date: ".$date_array['mon']."/".$date_array['mday']."/".
10:     $date_array['year']."</p>";
11: ?>



Caution

If running this code results in a warning such as

Warning: getdate(): It is not safe to rely on the system's timezone settings.
  You are *required* to use the date.timezone setting or the
  date_default_timezone_set() function.

you need to make a modification to your php.ini file. Specifically, look for lines like this:

; Defines the default timezone used by the date functions
; http://php.net/date.timezone
;date.timezone =

Change the value of date.timezone to your time zone. (See http://php.net/date.timezone for a valid list.) For example:

; Defines the default timezone used by the date functions
; http://php.net/date.timezone
date.timezone = America/New_York

Be sure to restart Apache after making changes to php.ini.


Converting a Timestamp with date()

You can use getdate() when you want to work with the elements that it outputs. Sometimes, though, you want to display the date as a string. The date() function returns a formatted string that represents a date. You can exercise an enormous amount of control over the format that date()returns with a string argument that you must pass to it. In addition to the format string, date() optionally accepts a timestamp. Table 10.4 lists some of the codes that a format string can contain. You can find the complete list at http://www.php.net/date. Any other data you include in the format string passed to date() is included in the return value.

Table 10.4 Some Format Codes for Use with date()

image

Listing 10.5 puts a few of these formats to the test.

Listing 10.5 Formatting a Date with date()


1: <?php
2: $time = time(); //stores the exact timestamp to use in this script
3: echo date("m/d/y G:i:s e", $time);
4: echo "<br/>";
5: echo "Today is ";
6: echo date("jS \of F Y, \a\\t g:ia \i\\n e", $time);
7: ?>


Listing 10.5 calls date() twice: the first time on line 3 to output an abbreviated date format, and the second time on line 6 for a longer format. Save the text of this listing in a file named datetest.php and open it in your web browser. Your date will differ from the following, obviously, but here’s some sample output:

01/17/12 21:29:31 America/New_York
Today is 17th of January 2012, at 9:29pm in America/New_York

Although the format string looks arcane, it’s easy to build. If you want to add a string that contains letters that are also format codes to the format, you can escape them by placing a backslash (\) in front of them. For characters that become control characters when escaped, you must escape the backslash that precedes them. For example, \t is a format code for a tab. So to ensure that the tab prints, use \\t as in the example in Listing 10.5.

Another example is in the context of a word you are adding to a string (for example, the). The word the is made up of three format codes, so all must be escaped:

<?php
echo date('l \t\h\e jS');
//prints Tuesday the 3rd
?>

Also note that the date() function returns information according to your local time zone. If you want to format a date in GMT, you use the gmdate() function, which works in exactly the same way.

Creating Timestamps with mktime()

You can already get information about the current time, but you cannot yet work with arbitrary dates. mktime() returns a timestamp that you can then use with date() or getdate(). mktime() accepts up to six integer arguments in the following order:

Hour

Minute

Second

Month

Day of month

Year

Listing 10.6 uses mktime() to get a timestamp it then uses with the date() function.

Listing 10.6 Creating a Timestamp with mktime()


1: <?php
2: // make a timestamp for Jan 17 2012 at 9:34 pm
3: $ts = mktime(21, 34, 0, 1, 17, 2012);
4: echo date("m/d/y G:i:s e", $ts);
5: echo "<br/>";
6: echo "The date is ";
7: echo date("jS \of F Y, \a\\t g:ia \i\\n e", $ts );
8: ?>


This code calls mktime() on line 3 and assigns the returned timestamp to the $ts variable. It then uses the date() function on lines 4 and 7 to output formatted versions of the date using $ts. You can choose to omit some of or all the arguments to mktime(), and the value appropriate to the current time is used instead. mktime() also adjusts for values that go beyond the relevant range, so an hour argument of 25 translates to 1:00 a.m. on the day after that specified in the month, day, and year arguments.

Save the text of this listing in a file named mktimetest.php and open it in your web browser. You should see the following

01/17/12 21:34:00 America/New_York
The date is 17th of January 2012, at 9:34pm in America/New_York

Testing a Date with checkdate()

You might need to accept date information from user input. Before you work with a user-entered date or store it in a database, make sure that the date is valid. checkdate() accepts three integers: month, day, and year. checkdate() returns true if the month is between 1 and 12, the day is acceptable for the given month and year (accounting for leap years), and the year is between 0 and 32767. Be careful, though: A date might be valid but not acceptable to other date functions. For example, the following line returns true:

checkdate(4, 4, 1066)

If you were to attempt to build a date with mktime() using these values, you’d end up with a timestamp of -1. As a rule of thumb, don’t use mktime() with years before 1902, and be cautious of using date functions with any date before 1970, because negative numbers are not valid dates. Because the UNIX epoch began January 1, 1970, anything before that is an invalid (negative) timestamp.

Other String, Date, and Time Functions

PHP does not lack for functions, especially for common items such as strings and dates. It is worth your while to bookmark the following chapters in the PHP Manual:

• “Strings” at http://www.php.net/manual/en/ref.strings.php

• “Date/Time” at http://www.php.net/manual/en/ref.datetime.php

In addition to keeping up with functions as they are added to PHP, the user-contributed notes for each function often offer solutions to various programming tasks that you might find useful as you build your own applications.

Summary

In this chapter, you learned about some of the functions that enable you to take control of the strings in your PHP scripts. You learned how to format strings with printf() and sprint(). You should be able to use these functions to create strings that both transform and format data. You learned about functions that investigate strings. You should be able to discover the length of a string with strlen(), determine the presence of a substring with strpos(), and extract a substring with substr(). You should be able to tokenize a string with strtok().

You also learned about functions that transform strings. You can now remove whitespace from the beginning or end of a string with trim(), ltrim(), or rtrim(). You can change the case of characters in a string with strtoupper(), strtolower(), or ucwords(). You can replace all instances of a string with str_replace().

You also learned how to use various PHP functions to perform date- and time-related actions. The time() function gets a date stamp for the current date and time, and you can use getdate() to extract date information from a timestamp and date() to convert a timestamp into a formatted string. You learned how to create a timestamp using mktime(), and how to test a date for validity with checkdate(). You learn many more powerful date-related functions in Chapter 16, “Learning Basic SQL Commands,” so much so that you might find yourself using MySQL and not PHP for many of your date-related needs.

Workshop

The workshop is designed to help you review what you’ve learned and begin putting your knowledge into practice.

Q&A

Q. Can I combine multiple string functions?

A. Yes. You can nest any function, not just string functions. Just remember to count your opening and closing parentheses to ensure that you’ve nested your functions appropriately.

Q. What do I do with dates and times stored in my database, not just in my scripts?

A. You will learn about MySQL date and time functions in Chapter 16, “Learning Basic SQL Commands,” but in general a good rule of thumb is that if you are extracting dates and times from a database and you want to perform date and time-related operations (such as calculating time or converting time from one type to another), you make your database do the work for you. But there’s nothing stopping you from using PHP date and time functions on data extracted out of the database.

Quiz

1. What conversion specifier would you use with printf() to format an integer as a double? Indicate the full syntax required to convert the integer 33.

2. How would you pad the conversion you effected in question 1 with zeros so that the part before the decimal point is four characters long?

3. How would you specify a precision of two decimal places for the floating-point number you have been formatting in the previous questions?

4. What function would you use to extract a substring from a string?

5. How might you remove whitespace from the beginning of a string?

6. How would you break up a delimited string into an array of substrings?

7. Using PHP, how do you acquire a UNIX timestamp that represents the current date and time?

8. Which PHP function accepts a timestamp and returns an associative array that represents the given date?

9. Which PHP function do you use to format date information?

10. Which PHP function could you use to check the validity of a date?

Answers

1. The conversion specifier f is used to format an integer as a double:

printf("%f", 33);

2. You can pad the output from printf() with the padding specifier—that is, a space or a zero followed by a number representing the number of characters you want to pad by:

printf("%04f", 33);

3. The precision specifier consists of a dot (.) followed by a number representing the precision you want to apply. You should place the precision specifier before the conversion specifier:

printf("%04.2f", 33);

4. The substr() function extracts and returns a substring.

5. The ltrim() function removes whitespace from the start of a string.

6. The explode() function splits up a string into an array.

7. Use time().

8. The getdate() function returns an associative array whose elements contain aspects of the given date.

9. Use date().

10. You can check a date with the checkdate() function.

Activities

1. Create a feedback form that accepts a user’s full name and an email address. Use case-conversion functions to capitalize the first letter of each name the user submits and print the result back to the browser. Check that the user’s email address contains the @ symbol and print a warning otherwise.

2. Create an array of doubles and integers. Loop through the array, converting each element to a floating-point number with a precision of 2. Right-align the output within a field of 20 characters.

3. Create a birthday countdown script. Given form input of month, day, and year, output a message that tells the user how many days, hours, minutes, and seconds until the big day.