PHP
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Functions
-
Section 4: Object-Oriented PHP
-
Section 5: Working with Data
-
Section 6: Modern PHP (PHP 8)
-
Section 7: Working with Files and Networking
-
Section 8: Common PHP Frameworks Overview
-
Section 9: Tooling and Ecosystem
-
Section 10: Practical Projects
-
Section 11: Interview Practice
-
Section 12: More Standard Library
-
Section 13: Data Structures and Algorithms in PHP
-
Section 14: More Practice Exercises
-
Section 15: More Security and Best Practices
-
Section 16: More Testing and Tooling
-
Section 17: WordPress-Style CMS Concepts
-
Section 18: Advanced OOP Practice
-
Section 19: More Web Fundamentals
-
Section 20: Database Practice
-
Section 21: PHP Manual: Array Functions
-
Section 22: PHP Manual: Date and Calendar Functions
-
Section 23: PHP Manual: Filesystem and Directory Functions
-
Section 24: PHP Manual: Filter and Var Handling
-
Section 25: PHP Manual: Math Functions
-
Section 26: PHP Manual: JSON and XML
-
Section 27: PHP Manual: Network and Stream Functions
-
Section 28: PHP Manual: Error and Exception Handling
-
Section 29: PHP Manual: Output Control and Misc
-
Section 30: PHP Manual: FTP, Zip, and Mail
-
Section 31: Modern PHP Frameworks Deep Dive
-
Section 32: PHP Design Patterns
-
Section 33: More Practice Exercises
-
Section 34: PHP Performance and Deployment
-
Section 35: More Interview Practice
-
Section 36: More PHP Standard Library
-
Section 37: PHP Concurrency and Async
-
Section 38: More Web Development Practice
-
Section 39: PHP Testing Deep Dive
-
Section 40: Composer and Package Development
-
Section 41: PHP Security Deep Dive
-
Section 42: More Practical Projects
-
Section 43: Legacy PHP Maintenance
-
Section 44: More Algorithm Practice
-
Section 45: Final Practice and Review
-
Section 46: PHP for E-Commerce Patterns
-
Section 47: PHP API Design Deep Dive
-
Section 48: PHP Caching Strategies
-
Section 49: PHP Queue and Background Jobs
-
Section 50: PHP Multi-Tenancy Patterns
-
Section 51: PHP Real-Time Features
-
Section 52: PHP CMS and Content Modeling
-
Section 53: PHP Internationalization
-
Section 54: More Framework-Specific Practice
-
Section 55: PHP Legacy Code Refactoring
-
Section 56: More Practice Projects Round 2
-
Section 57: PHP Command-Line Applications
-
Section 58: PHP and Microservices
-
Section 59: More Interview and Review Round 2
56: Working with Multibyte Strings
I want to show you a bug that has bitten almost every PHP developer I've ever mentored. It usually happens when a project grows from a local "English-only" prototype to a real-world application where users might have names like "François" or use emojis in their bios.
<?php
$bio = "I love 🍕 and coding!";
$preview = substr($bio, 0, 10);
echo "Preview: " . $preview;
// Expected: "I love 🍕"
// Actual: "I love "
?>
If you run this, you'll notice that the emoji doesn't render correctly at the end of the string. Instead, you get a weird replacement character (often a diamond with a question mark). You might think your database encoding is wrong or that the browser is acting up, but the problem is actually right here in the PHP code.
The Byte vs. Character Trap
Here is the deal: standard PHP string functions like strlen() and substr() are "byte-oriented." They don't actually know what a "character" is; they only know how many bytes of data are in the string.
In the old days of ASCII, one character always equaled one byte. But we live in a UTF-8 world now. In UTF-8, a standard English letter is 1 byte, but an emoji or a complex character can be anywhere from 2 to 4 bytes. When we told PHP to substr($bio, 0, 10), it counted exactly 10 bytes. Because the pizza emoji starts at byte 8 and ends at byte 11, we sliced the emoji right in the middle. We handed the browser a fragment of a character, and the browser had no choice but to show an error symbol.
Moving to Multibyte Functions
To fix this, you need to stop using the base string functions and start using the mbstring (multibyte string) extension. These functions are designed to understand character encoding, meaning they count characters, not bytes.
<?php
$bio = "I love 🍕 and coding!";
// We use mb_substr instead of substr
$preview = mb_substr($bio, 0, 10, 'UTF-8');
echo "Preview: " . $preview;
// Result: "I love 🍕"
?>
By switching to mb_substr(), PHP looks at the UTF-8 sequence and says, "Okay, this emoji is one single character, even if it takes up 4 bytes." It handles the math for you so you don't accidentally mutilate your users' data.
Consistency Across Your App
Once you realize you need mb_substr(), you'll realize you probably need a few others too. If you're building a site that supports multiple languages, I strongly suggest you swap out these common functions across your entire codebase:
strlen()$\rightarrow$mb_strlen()strpos()$\rightarrow$mb_strpos()strtolower()$\rightarrow$mb_strtolower()substr()$\rightarrow$mb_substr()
One quick tip: most modern PHP installations have mbstring enabled by default, but if you get a "Call to undefined function" error, you'll need to enable it in your php.ini file or install it via your package manager (e.g., sudo apt-get install php-mbstring). It's a dependency you simply cannot live without in modern web development.
📋 Practical Task
Exercise: Building a Safe International Username Validator
You are building a registration system that requires usernames to be between 3 and 15 characters long. However, you want to support international users who might use non-Latin characters (like "ユーザー" or "Müller").
Write a PHP script that does the following:
- Creates an array of test usernames containing a mix of English, accented characters, and emojis.
- Loops through the array and uses
mb_strlen()to check if the length is within the 3-15 character range. - Prints whether each username is "Valid" or "Invalid".
- Challenge: Ensure that if a username is too long, you provide a "Suggested" version that is safely truncated to 15 characters using
mb_substr()without breaking any multibyte characters.
There are no comments for now.