By David Sklar, Adam Trachtenberg
Cover | Table of Contents | Colophon
$neighbor = 'Hilda';
print $neighbor[3];
d
print 'I have gone to the store.'; print 'I\'ve gone to the store.'; print 'Would you pay $1.75 for 8 ounces of tap water?'; print 'In double-quoted strings, newline is represented by \n'; I have gone to the store. I've gone to the store. Would you pay $1.75 for 8 ounces of tap water? In double-quoted strings, newline is represented by \n
$neighbor = 'Hilda';
print $neighbor[3];
d
print 'I have gone to the store.'; print 'I\'ve gone to the store.'; print 'Would you pay $1.75 for 8 ounces of tap water?'; print 'In double-quoted strings, newline is represented by \n'; I have gone to the store. I've gone to the store. Would you pay $1.75 for 8 ounces of tap water? In double-quoted strings, newline is represented by \n
|
Escape sequence |
|---|
substr( )
to select your substrings:
$substring = substr($string,$start,$length); $username = substr($_REQUEST['username'],0,8);
$start and $length are
positive, substr( ) returns
$length characters in the string, starting at
$start. The first character in the string is at
position 0:
print substr('watch out for that tree',6,5);
out f
$length, substr(
) returns the string from $start to the
end of the original string:
print substr('watch out for that tree',17);
t tree
$start plus $length goes
past the end of the string, substr( ) returns all
of the string from $start forward:
print substr('watch out for that tree',20,5);
ree
$start is negative, substr(
) counts back from the end of the string to determine where
your substring starts:
print substr('watch out for that tree',-6);
print substr('watch out for that tree',-17,5);
t tree
out f
$length is negative, substr(
) counts back from the end of the string to determine where
your substring ends:
print substr('watch out for that tree',15,-2);
print substr('watch out for that tree',-4,-1);
hat tr
tre
substr( ) at
http://www.php.net/substr.
substr_replace(
)
:
// Everything from position $start to the end of $old_string // becomes $new_substring $new_string = substr_replace($old_string,$new_substring,$start); // $length characters, starting at position $start, become $new_substring $new_string = substr_replace($old_string,$new_substring,$start,$length);
$length argument,
substr_replace( ) replaces everything from
$start to the end of the string. If
$length is specified, only that many characters
are replaced:
print substr_replace('My pet is a blue dog.','fish.',12);
print substr_replace('My pet is a blue dog.','green',12,4);
$credit_card = '4111 1111 1111 1111';
print substr_replace($credit_card,'xxxx ',0,strlen($credit_card)-4);
My pet is a fish.
My pet is a green dog.
xxxx 1111
$start is negative, the new substring is placed
at $start characters counting from the end of
$old_string, not from the beginning:
print substr_replace('My pet is a blue dog.','fish.',-9);
print substr_replace('My pet is a blue dog.','green',-9,4);
My pet is a fish.
My pet is a green dog.
$start and $length are 0,
the new substring is inserted at the start of
$old_string:
print substr_replace('My pet is a blue dog.','Title: ',0,0);
Title: My pet is a blue dog.
substr_replace( ) is useful when
you've got text that's too big to
display all at once, and you want to display some of the text with a
link to the rest. For example, this displays the first 25 characters
of a message with an ellipsis after it as a link to a page that
displays more text:
$r = mysql_query("SELECT id,message FROM messages WHERE id = $id") or die( );
$ob = mysql_fetch_object($r);
printf('<a href="more-text.php?id=%d">%s</a>',
$ob->id, substr_replace($ob->message,' ...',25));for. This example counts the vowels in a string:
$string = "This weekend, I'm going shopping for a pet chicken.";
$vowels = 0;
for ($i = 0, $j = strlen($string); $i < $j; $i++) {
if (strstr('aeiouAEIOU',$string[$i])) {
$vowels++;
}
}
function lookandsay($s) {
// initialize the return value to the empty string
$r = '';
/* $m holds the character we're counting, initialize to the first
// character in the string*/
$m = $s[0];
// $n is the number of $m's we've seen, initialize to 1
$n = 1;
for ($i = 1, $j = strlen($s); $i < $j; $i++) {
// if this character is the same as the last one
if ($s[$i] == $m) {
// increment the count of this character
$n++;
} else {
// otherwise, add the count and character to the return value
$r .= $n.$m;
// set the character we're looking for to the current one
$m = $s[$i];
// and reset the count to 1
$n = 1;
}
}
// return the built up string as well as the last count and character
return $r.$n.$m;
}
for ($i = 0, $s = 1; $i < 10; $i++) {
$s = lookandsay($s);
print "$s\n";
}
1
11
21
1211
111221
312211
13112221
1113213211
31131211131221
13211311123113112211
strrev( )
to reverse by character:
print strrev('This is not a palindrome.');
.emordnilap a ton si sihT
$s = "Once upon a time there was a turtle.";
// break the string up into words
$words = explode(' ',$s);
// reverse the array of words
$words = array_reverse($words);
// rebuild the string
$s = join(' ',$words);
print $s;
turtle. a was there time a upon Once
$reversed_s = join(' ',array_reverse(explode(' ',$s)));
strrev( ) at
http://www.php.net/strrev and
array_reverse( ) at
http://www.php.net/array-reverse.
str_replace( )
to switch spaces to tabs or tabs to
spaces:
$r = mysql_query("SELECT message FROM messages WHERE id = 1") or die();
$ob = mysql_fetch_object($r);
$tabbed = str_replace(' ',"\t",$ob->message);
$spaced = str_replace("\t",' ',$ob->message);
print "With Tabs: <pre>$tabbed</pre>";
print "With Spaces: <pre>$spaced</pre>";
str_replace( ) for conversion, however,
doesn't respect tab stops. If you want tab stops
every eight characters, a line beginning with a five-letter word and
a tab should have that tab replaced with three spaces, not one. Use
the pc_tab_expand( ) function shown in Example 1-1 to turn tabs to spaces in a way that respects
tab stops.
function pc_tab_expand($a) {
$tab_stop = 8;
while (strstr($a,"\t")) {
$a = preg_replace('/^([^\t]*)(\t+)/e',
"'\\1'.str_repeat(' ',strlen('\\2') *
$tab_stop - strlen('\\1') % $tab_stop)",$a);
}
return $a;
}
$spaced = pc_tab_expand($ob->message);
pc_tab_unexpand()
function shown in Example 1-2 to turn spaces back to tabs.
function pc_tab_unexpand($x) {
$tab_stop = 8;
$lines = explode("\n",$x);
for ($i = 0, $j = count($lines); $i < $j; $i++) {
$lines[$i] = pc_tab_expand($lines[$i]);
$e = preg_split("/(.\{$tab_stop})/",$lines[$i],-1,PREG_SPLIT_DELIM_CAPTURE);
$lastbit = array_pop($e);
if (!isset($lastbit)) { $lastbit = ''; }
if ($lastbit == str_repeat(' ',$tab_stop)) { $lastbit = "\t"; }
for ($m = 0, $n = count($e); $m < $n; $m++) {
$e[$m] = preg_replace('/ +$',"\t",$e[$m]);
}
$lines[$i] = join('',$e).$lastbit;
}
$x = join("\n", $lines);
return $x;
}
$tabbed = pc_tab_unexpand($ob->message);ucfirst( )
or ucwords( ) to
capitalize
the first letter of one or more words:
print ucfirst("how do you do today?");
print ucwords("the prince of wales");
How do you do today?
The Prince Of Wales
strtolower( ) or strtoupper( )
to modify the case of entire strings:
print strtoupper("i'm not yelling!");
// Tags must be lowercase to be XHTML compliant
print strtolower('<A HREF="one.php">one</A>');
I'M NOT YELLING!
<a href="one.php">one</a>
ucfirst( ) to capitalize the first character
in a string:
print ucfirst('monkey face');
print ucfirst('1 monkey face');
Monkey face
1 monkey face
ucwords(
) to capitalize the first character of each word in a
string:
print ucwords('1 monkey face');
print ucwords("don't play zone defense against the philadelphia 76-ers");
1 Monkey Face
Don't Play Zone Defense Against The Philadelphia 76-ers
ucwords( ) doesn't
capitalize the "t" in
"don't." But it
also doesn't capitalize the
"e" in
"76-ers." For ucwords(
), a word is any sequence of nonwhitespace characters that
follows one or more whitespace characters. Since both
' and - aren't
whitespace characters, ucwords( )
doesn't consider the
"t" in
"don't" or the
"e" in
"76-ers" to be word-starting
characters.
ucfirst( ) and ucwords( )
don't change the case of nonfirst letters:
print ucfirst('macWorld says I should get a iBook');
print ucwords('eTunaFish.com might buy itunaFish.Com!');
print 'You have '.($_REQUEST['boys'] + $_REQUEST['girls']).' children.'; print "The word '$word' is ".strlen($word).' characters long.'; print 'You owe '.$amounts['payment'].' immediately'; print "My circle's diameter is ".$circle->getDiameter().' inches.';
print "I have $children children."; print "You owe $amounts[payment] immediately."; print "My circle's diameter is $circle->diameter inches.";
print <<< END
Right now, the time is
END
. strftime('%c') . <<< END
but tomorrow it will be
END
. strftime('%c',time() + 86400);
${"amount_$i"}), see Recipe 5.5; documentation on the string concatenation
operator at
http://www.php.net/language.operators.string.
ltrim( )
, rtrim( ), or
trim( ). ltrim( ) removes
whitespace from the beginning of a string, rtrim(
) from the end of a string, and trim( )
from both the beginning and end of a string:
$zipcode = trim($_REQUEST['zipcode']); $no_linefeed = rtrim($_REQUEST['text']); $name = ltrim($_REQUEST['name']);
<pre> tags, for example. If you are doing
comparisons with user input, you should trim the data first, so that
someone who mistakenly enters "98052
" as their Zip Code isn't forced to
fix an error that really isn't. Trimming before
exact text comparisons also ensures that, for example,
"salami\n" equals
"salami." It's
also a good idea to normalize string data by trimming it before
storing it in a database.
trim( ) functions can also remove
user-specified characters from strings. Pass the characters you want
to remove as a second argument. You can indicate a range of
characters with two dots between the first and last characters in the
range.
// Remove numerals and space from the beginning of the line
print ltrim('10 PRINT A$',' 0..9');
// Remove semicolon from the end of the line
print rtrim('SELECT * FROM turtles;',';');
PRINT A$
SELECT * FROM turtles
chop( )
as an alias for rtrim( ).
However, you're best off using rtrim(
) instead, because PHP's chop(
) behaves differently than
Perl's
fopen( )
and read in the data with fgetcsv(
). This prints out the data in an HTML table:
$fp = fopen('sample2.csv','r') or die("can't open file");
print "<table>\n";
while($csv_line = fgetcsv($fp,1024)) {
print '<tr>';
for ($i = 0, $j = count($csv_line); $i < $j; $i++) {
print '<td>'.$csv_line[$i].'</td>';
}
print "</tr>\n";
}
print '</table>\n';
fclose($fp) or die("can't close file");
fgetcsv( ) must be longer
than the maximum length of a line in your CSV file.
(Don't forget to count the end-of-line whitespace.)
If you read in CSV lines longer than 1K, change the 1024 used in this
recipe to something that accommodates your line length.
fgetcsv( ) an optional third
argument, a delimiter to use instead of a comma (,). Using a
different delimiter however, somewhat defeats the purpose of CSV as
an easy way to exchange tabular data.
fgetcsv(
) and just read a line in and explode(
)
on the commas. CSV is more complicated
than that, in order to deal with embedded commas and double quotes.
Using fgetcsv( ) protects you and your code from
subtle errors.
fgetcsv( ) at
http://www.php.net/fgetcsv.
substr( )
:
$fp = fopen('fixed-width-records.txt','r') or die ("can't open file");
while ($s = fgets($fp,1024)) {
$fields[1] = substr($s,0,10); // first field: first 10 characters of the line
$fields[2] = substr($s,10,5); // second field: next 5 characters of the line
$fields[3] = substr($s,15,12); // third field: next 12 characters of the line
// a function to do something with the fields
process_fields($fields);
}
fclose($fp) or die("can't close file");
unpack( )
:
$fp = fopen('fixed-width-records.txt','r') or die ("can't open file");
while ($s = fgets($fp,1024)) {
// an associative array with keys "title", "author", and "publication_year"
$fields = unpack('A25title/A14author/A4publication_year',$s);
// a function to do something with the fields
process_fields($fields);
}
fclose($fp) or die("can't close file");
$booklist=<<<END Elmer Gantry Sinclair Lewis1927 The Scarlatti InheritanceRobert Ludlum 1971 The Parsifal Mosaic Robert Ludlum 1982 Sophie's Choice William Styron1979 END;
substr(
) to parse the fields into an array:
$books = explode("\n",$booklist);
for($i = 0, $j = count($books); $i < $j; $i++) {
$book_array[$i]['title'] = substr($books[$i],0,25);
$book_array[$i]['author'] = substr($books[$i],25,14);
$book_array[$i]['publication_year'] = substr($books[$i],39,4);
}
<textarea> form field.
explode( )
if what separates the pieces is a
constant string:
$words = explode(' ','My sentence is not very complicated');
split( )
or preg_split( ) if you
need a POSIX or Perl regular expression to describe the separator:
$words = split(' +','This sentence has some extra whitespace in it.');
$words = preg_split('/\d\. /','my day: 1. get up 2. get dressed 3. eat toast');
$lines = preg_split('/[\n\r]+/',$_REQUEST['textarea']);
spliti( ) or the /i flag to
preg_split( ) for
case-insensitive separator matching:
$words = spliti(' x ','31 inches x 22 inches X 9 inches');
$words = preg_split('/ x /i','31 inches x 22 inches X 9 inches');
explode( ).
Pass it your separator string, the string to be separated, and an
optional limit on how many elements should be returned:
$dwarves = 'dopey,sleepy,happy,grumpy,sneezy,bashful,doc';
$dwarf_array = explode(',',$dwarves);
$dwarf_array is a seven element array:print_r($dwarf_array); Array ( [0] => dopey [1] => sleepy [2] => happy [3] => grumpy [4] => sneezy [5] => bashful [6] => doc )
$dwarf_array = explode(',',$dwarves,5);
print_r($dwarf_array);
Array
(
[0] => dopey
[1] => sleepy
[2] => happy
[3] => grumpy
[4] => sneezy,bashful,doc<pre>/</pre> tags
but have it stay within a regularly sized browser window.
wordwrap( )
:
$s = "Four score and seven years ago our fathers brought forth on this continen t a new nation, conceived in liberty and dedicated to the proposition that all men are created equal."; print "<pre>\n".wordwrap($s)."\n</pre>"; <pre> Four score and seven years ago our fathers brought forth on this continent a new nation, conceived in liberty and dedicated to the proposition that all men are created equal. </pre>
wordwrap( ) wraps text at 75
characters per line. An optional second argument specifies different
line length:
print wordwrap($s,50); Four score and seven years ago our fathers brought forth on this continent a new nation, conceived in liberty and dedicated to the proposition that all men are created equal.
print wordwrap($s,50,"\n\n"); Four score and seven years ago our fathers brought forth on this continent a new nation, conceived in liberty and dedicated to the proposition that all men are created equal.
wordwrap(
) that controls the treatment of words that are longer than
the specified line length. If this argument is 1, these words are
wrapped. Otherwise, they span past the specified line length:
print wordwrap('jabberwocky',5);
print wordwrap('jabberwocky',5,"\n",1);
jabberwocky
jabbe
rwock
y
pack( )
to store binary data in a string:
$packed = pack('S4',1974,106,28225,32725);
unpack( )
to extract binary data from a string:
$nums = unpack('S4',$packed);
pack(
)
is a format string
that describes how to encode the data that's passed
in the rest of the arguments. The format string S4
tells pack( ) to produce four unsigned short
16-bit numbers in machine byte order from its input data. Given 1974,
106, 28225, and 32725 as input, this returns eight bytes: 182, 7,
106, 0, 65, 110, 213, and 127. Each two-byte pair corresponds to one
of the input numbers: 7 * 256 + 182 is 1974; 0 * 256 + 106 is 106;
110 * 256 + 65 = 28225; 127 * 256 + 213 = 32725.
unpack(
)
is also a format string, and the
second argument is the data to decode. Passing a format string of
S4, the eight-byte sequence that pack(
) produced returns a four-element array of the original
numbers:
print_r($nums); Array ( [1] => 1974 [2] => 106 [3] => 28225 [4] => 32725 )
unpack( ), format characters and their count
can be followed by a string to be used as an array key. For example:
$nums = unpack('S4num',$packed);
print_r($nums);
Array
(
[num1] => 1974
[num2] => 106
[num3] => 28225
[num4] => 32725
)
3/2 is
1.5, not 1, as it would be in
some programming languages. PHP also automatically converts from
strings to numbers and back. For
instance, 1+"1" is 2.
3/2 is
1.5, not 1, as it would be in
some programming languages. PHP also automatically converts from
strings to numbers and back. For
instance, 1+"1" is 2.
is_numeric( )
:
if (is_numeric('five')) { /* false */ }
if (is_numeric(5)) { /* true */ }
if (is_numeric('5')) { /* true */ }
if (is_numeric(-5)) { /* true */ }
if (is_numeric('-5')) { /* true */ }
is_numeric( ) can also be applied to numeric
strings. The distinction here is that the integer
5 and the string 5 technically
aren't the same in PHP.
is_numeric( ) properly parses decimal
numbers, such as 5.1; however, numbers with
thousands separators, such as 5,100, cause
is_numeric( ) to return false.
is_numeric( ) use str_replace(
):
is_numeric(str_replace($number, ',', ''));
is_bool( )
, is_float( ) (or
is_double( ) or is_real( );
they're all the same), and is_int(
) (or is_integer( ) or is_long(
)
).
is_numeric(
)
at
http://www.php.net/is-numeric and
str_replace( )
at
http://www.php.net/str-replace.
$delta = 0.00001;
$a = 1.00000001;
$b = 1.00000000;
if (abs($a - $b) < $delta) { /* $a and $b are equal */ }
$a ==
$b, make sure the first number is within a very small
amount ($delta) of the second one. The size of
your delta should be the smallest amount of difference you care about
between two numbers. Then use abs( ) to get the
absolute value of the difference.
http://www.php.net/language.types.float.
round(
)
:
$number = round(2.4); // $number = 2
ceil( ):$number = ceil(2.4); // $number = 3
floor( ):$number = floor(2.4); // $number = 2
$number = round(2.5); // $number is 2 or 3!
$delta = 0.0000001; $number = round(2.5 + $delta); // $number = 3
round( ) accepts an optional precision argument.
For example, if you are calculating the total price for the items in
a user's shopping cart:
$cart = 54.23; $tax = $cart * .05; $total = $cart + $tax; // $total = 56.9415 $final = round($total, 2); // $final = 56.94
round( )
at http://www.php.net/round.
range( )
function, which returns an array populated
with integers:
foreach(range($start,$end) as $i) {
plot_point($i);
}
range( ), it can be more
efficient to use a for
loop. Also, you can
increment using values other than 1. For example:
for ($i = $start; $i <= $end; $i += $increment) {
plot_point($i);
}
range( ) returns an array
with values from $start to
$end. Then
foreach
pulls out each element and assigns it to
$i inside of the loop. The advantage of using
range( ) is its brevity, but this technique has a
few disadvantages. For one, a large array can take up unnecessary
memory. Also, you're forced to increment the series
one number at a time, so you can't loop through a
series of even integers, for example.
$start to be larger
than $end. In this case, the numbers returned by
range( ) are in descending order. Also, you can
use iterate over character sequences:
print_r(range('l', 'p'));
Array
(
[0] => l
[1] => m
[2] => n
[3] => o
[4] => p
)
for loop method just uses a single integer and
avoids the array entirely. While it's longer, you
have greater control over the loop, because you can increment and
decrement $i more freely. Also, you can modify
$i from inside the loop, something you
can't do with mt_rand( ):// random number between $upper and $lower, inclusive $random_number = mt_rand($lower, $upper);
mt_rand( )
two arguments:
$random_number = mt_rand(1, 100);
mt_rand( ) without any arguments returns a
number between 0 and the maximum random number,
which is returned by mt_getrandmax(
)
.
rand(
)
and a
better function called mt_rand( ). MT stands for
Mersenne Twister, which is named for the French monk and
mathematician Marin Mersenne and the type of prime numbers
he's associated with. The algorithm is based on
these prime numbers. Since mt_rand( ) is more
random and faster than rand( ), we prefer it to
rand( ).
mt_rand( ) (or rand(
)) for the first time in a script, you need to seed the
generator, by calling mt_srand( ) (or
srand( )). The
seed
is a number the random function uses
as the basis for generating the random numbers it returns;
it's how to solve the repeatable versus random
dilemma mentioned earlier. Use the value returned by
pc_rand_weighted( ) function shown in
Example 2-1.
// returns the weighted randomly selected key
function pc_rand_weighted($numbers) {
$total = 0;
foreach ($numbers as $number => $weight) {
$total += $weight;
$distribution[$number] = $total;
}
$rand = mt_rand(0, $total - 1);
foreach ($distribution as $number => $weights) {
if ($rand < $weights) { return $number; }
}
}
$ads = array('ford' => 12234, // advertiser, remaining impressions
'att' => 33424,
'ibm' => 16823);
$ad = pc_rand_weighted($ads);
log( ):
$log = log(10); // 2.30258092994
log10( ):
$log10 = log10(10); // 1
pc_logn( ):function pc_logn($number, $base) {
return log($number) / log($base);
}
$log2 = pc_logn(10, 2); // 3.3219280948874
log( ) and log10( ) are
defined only for numbers that are greater than zero. The
pc_logn( )
function uses the change of base formula,
which says that the log of a number in base n is
equal to the log of that number, divided by the log of
n.
log( ) at
http://www.php.net/log and log10(
) at http://www.php.net/log10.
exp( ):
$exp = exp(2); // 7.3890560989307
pow(
)
:
$exp = pow( 2, M_E); // 6.5808859910179 $pow = pow( 2, 10); // 1024 $pow = pow( 2, -2); // 0.25 $pow = pow( 2, 2.5); // 5.6568542494924 $pow = pow(-2, 10); // 1024 $pow = pow( 2, -2); // 0.25 $pow = pow(-2, -2.5); // NAN (Error: Not a Number)
M_E is an
approximation of the value of e. It equals
2.7182818284590452354. So exp($n) and
pow(M_E,
$n) are identical.
exp( ) and pow( ); if you
outgrow PHP's maximum size (almost 1.8e308), see
Recipe 2.14 for how to use the arbitrary
precision functions. With these functions, PHP returns
INF, infinity, if the result is too large and
NAN, not-a-number, on an error.
pow( ) at
http://www.php.net/pow, exp(
) at http://www.php.net/exp, and
information on predefined mathematical constants at
http://www.php.net/math.
number_format(
)
function to format as an integer:
$number = 1234.56; print number_format($number); // 1,235 because number is rounded up
print number_format($number, 2); // 1,234.56
number_format( ) function formats a number by
inserting the correct decimal and thousands separators for your
locale. If you want to manually specify these values, pass them as
the third and fourth parameters:
$number = 1234.56; print number_format($number, 2, '@', '#'); // 1#234@56
number_format( ) rounds the number to
the nearest integer. If you want to preserve the entire number, but
you don't know ahead of time how many digits follow
the decimal point in your number, use this:
$number = 1234.56; // your number
list($int, $dec) = explode('.', $number);
print number_format($number, strlen($dec));
number_format( ) at
http://www.php.net/number-format.
$number = 4;
print "Your search returned $number " . ($number == 1 ? 'hit' : 'hits') . '.';
Your search returned 4 hits.
print "Your search returned $number hit" . ($number == 1 ? '' : 's') . '.';
pc_may_pluralize(
)
function in Example 2-2.
function pc_may_pluralize($singular_word, $amount_of) {
// array of special plurals
$plurals = array(
'fish' =>