Text is everywhere
Websites spend much of their time handling text: names typed into forms, product descriptions, URLs, email addresses, search terms. PHP has a large set of string functions for this. This lesson covers the ones you will use every week. All of them work on bytes, which is fine for English text; for accents and other scripts, see the next lesson on Unicode text and the mb_ functions.
Searching
PHP 8 added three clear functions that answer yes or no:
<?php
$title = "Mechanical Keyboard with RGB lights";
var_dump(str_contains($title, "Keyboard"));
var_dump(str_contains($title, "keyboard"));
var_dump(str_starts_with($title, "Mech"));
var_dump(str_ends_with("invoice.pdf", ".pdf"));bool(true)
bool(false)
bool(true)
bool(true)They are case-sensitive. To find a position, use strpos() (case-sensitive) or stripos() (case-insensitive). They return the position of the first match, counting from 0, or false if there is none:
<?php
$title = "Mechanical Keyboard with RGB lights";
var_dump(strpos($title, "Keyboard"));
var_dump(stripos($title, "keyboard"));
var_dump(strpos($title, "Mouse"));
var_dump(strrpos("a-b-c", "-"));
echo substr_count("banana", "a") . "\n";int(11)
int(11)
bool(false)
int(3)
3As explained in Comparisons, == versus === and type juggling, a match at position 0 is falsy, so always test strpos(...) === false, or use str_contains() when you only need yes or no. strrpos() finds the last match.
Cutting out parts
substr($string, $start, $length) returns part of a string. A negative start counts from the end:
<?php
$sku = "ELEC-KB-2024-0042";
echo substr($sku, 0, 4) . "\n";
echo substr($sku, -4) . "\n";
echo substr($sku, 5, 2) . "\n";
echo strlen($sku) . "\n";ELEC
0042
KB
17For text separated by a character, explode() from Common array functions is usually clearer than counting positions: explode("-", $sku)[1] is KB.
Cleaning input
Text from forms often has stray spaces at the ends. trim() removes whitespace (spaces, tabs, new lines) from both ends; ltrim() and rtrim() do one side. A second argument lists other characters to remove:
<?php
$email = " Asha.Verma@Example.com \n";
$clean = strtolower(trim($email));
echo "[$clean]\n";
echo rtrim("1,2,3,", ",") . "\n";
echo trim("--SALE--", "-") . "\n";[asha.verma@example.com]
1,2,3
SALEChanging case
<?php
$name = "kAVYA nAIR";
echo strtolower($name) . "\n";
echo strtoupper($name) . "\n";
echo ucfirst(strtolower($name)) . "\n";
echo ucwords(strtolower($name)) . "\n";
echo lcfirst("Hello") . "\n";kavya nair
KAVYA NAIR
Kavya nair
Kavya Nair
helloucwords() capitalises the first letter of every word, which is handy for names and titles, but be careful with names such as "O'Brien" or "McDonald": no simple function gets every name right, so do not "correct" what people type unless you have to.
Replacing
str_replace($search, $replace, $subject) replaces every occurrence. It also accepts arrays, applied pair by pair, and an optional fourth argument receives the number of replacements:
<?php
echo str_replace("colour", "color", "Pick a colour, any colour") . "\n";
$template = "Hi {name}, your order {order} has shipped.";
echo str_replace(["{name}", "{order}"], ["Liam", "#1042"], $template) . "\n";
str_replace(" ", "-", "a b c d", $count);
echo "Replaced $count spaces\n";
echo str_ireplace("SALE", "offer", "Big sale today") . "\n";Pick a color, any color
Hi Liam, your order #1042 has shipped.
Replaced 3 spaces
Big offer todaystr_ireplace() ignores case. For patterns rather than fixed text, such as "any run of digits", use preg_replace() from Regular expressions with preg_ functions. strtr() replaces several strings at once from a key-value array.
Padding, repeating and wrapping
<?php
echo str_pad("42", 6, "0", STR_PAD_LEFT) . "\n";
echo str_pad("Total", 10, ".") . "99.00\n";
echo str_repeat("-", 20) . "\n";
echo wordwrap("The quick brown fox jumps over the lazy dog", 15, "\n", true) . "\n";
echo strrev("stressed") . "\n";000042
Total.....99.00
--------------------
The quick brown
fox jumps over
the lazy dog
dessertsBuilding a URL slug
Putting several functions together: turn a product name into a URL-friendly "slug" like the ones this site uses for lesson addresses:
<?php
function slugify(string $text): string
{
$text = strtolower(trim($text));
$text = preg_replace('/[^a-z0-9]+/', '-', $text);
return trim($text, '-');
}
echo slugify(" Noise-Cancelling Headphones (Black) ") . "\n";
echo slugify("PHP & MySQL: The Basics!") . "\n";noise-cancelling-headphones-black
php-mysql-the-basicsThe middle line uses a regular expression to turn every run of characters that are not letters or digits into one hyphen.
Comparing strings
strcmp() compares two strings and returns a negative number, zero or a positive number, like the spaceship operator; strcasecmp() ignores case. To compare secret values such as tokens, use hash_equals(), which takes the same time whatever the input and so does not leak information through timing.
Common mistakes
- Testing strpos() with if (strpos(...)), which fails when the match is at position 0.
- Forgetting that most functions are case-sensitive. Use the
iversions or lowercase both sides. - Using these functions on non-English text and cutting a character in half. Use the
mb_versions. - Not trimming input, so
"asha@example.com "with a trailing space fails to match.
Exercise
Write maskEmail(string $email): string that keeps the first letter of the name and the whole domain, replacing the rest of the name with asterisks: asha.verma@example.com becomes a*********@example.com.
Show one possible answer
<?php
function maskEmail(string $email): string
{
$at = strpos($email, "@");
if ($at === false || $at < 1) {
return $email;
}
$name = substr($email, 0, $at);
$domain = substr($email, $at);
return substr($name, 0, 1) . str_repeat("*", strlen($name) - 1) . $domain;
}
echo maskEmail("asha.verma@example.com") . "\n";
echo maskEmail("li@example.org") . "\n";a*********@example.com
l*@example.orgKey points
- str_contains, str_starts_with and str_ends_with (PHP 8) answer yes-or-no questions about text.
- strpos returns a position or false; always compare its result with === false.
- substr cuts out part of a string; trim removes whitespace from both ends.
- str_replace replaces text, ucfirst / ucwords / strtolower / strtoupper change case, and str_pad pads to a width.