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
101: Working with Symbolic Links in PHP
I've noticed a recurring pattern when developers first start managing files on a server: they treat symbolic links (symlinks) as if they are just "special copies" of files. Specifically, there's a common belief that is_file() or is_dir() can be used to detect whether a path is a symlink. It seems intuitive—if the link points to a file, is_file() should tell you it's a link, right?
Wrong. Here is why that breaks your logic:
// Assume 'current_log' is a symlink pointing to 'logs/2023-10-27.log'
if (is_file('current_log')) {
echo "This is a regular file!";
}
// Result: "This is a regular file!"
PHP "follows" the link. When you call is_file() on a symlink, PHP doesn't care about the link itself; it looks at the target. If the target is a file, it returns true. This is a nightmare when you're trying to write a cleanup script to remove old links without accidentally deleting the actual data they point to.
is_file() identifies the target, not the link
To actually detect a symlink, you have to use is_link(). This function specifically checks if the path is a pointer. I always tell my team to check is_link() first before any other file-type check if they're working in a directory where symlinks are expected (like a deployment folder or a shared assets directory).
$path = 'current_release';
if (is_link($path)) {
echo "This is a symlink. It's just a pointer.";
echo "It points to: " . readlink($path);
} elseif (is_dir($path)) {
echo "This is a real directory.";
}
The readlink() function is your best friend here. It resolves the link and tells you exactly where it's pointing. Without it, you're essentially flying blind.
unlink() destroys the pointer, not the source
Another point of anxiety I see is the fear of using unlink() on a symlink. New developers often worry that deleting the link will "reach through" and delete the original file on the disk. I can promise you it doesn't. When you call unlink() on a symlink, you are only destroying the shortcut.
Think of it like a desktop shortcut in Windows or an alias in macOS. Deleting the icon on your desktop doesn't uninstall the application from your Program Files. In PHP, it works exactly the same way. This is actually the secret sauce behind "zero-downtime deployments."
Here is the workflow I've used in production for years:
- Upload your new code to a unique folder (e.g.,
/releases/202310271200/). - Create a symlink called
/currentthat points to that folder. - When you're ready to update, create a new symlink for the new version and
unlink()the old one (or simply overwrite it).
// Creating a symlink: symlink(target, link)
$target = '/var/www/releases/v2';
$link = '/var/www/html/current';
if (symlink($target, $link)) {
echo "Deployment successful!";
} else {
echo "Check your permissions; PHP might not have rights to create links here.";
}
One last tip: be careful with permissions. Your PHP process (like www-data) needs write permissions on the directory where the link is being created, not necessarily on the target file itself. If symlink() returns false, that's usually the first place I look.
📋 Practical Task
Building a Zero-Downtime Release Switcher
You are tasked with creating a script that simulates a production deployment switch. You need to manage two folders and a symlink to ensure the website always points to the "active" version of the code.
Requirements:
- Create two directories:
release_v1andrelease_v2. - Place a dummy file named
version.txtinside each folder with the text "Version 1" and "Version 2" respectively. - Write a PHP script that:
- Checks if a symlink named
active_releasealready exists usingis_link(). - If it exists, deletes it using
unlink(). - Creates a new symlink named
active_releasepointing torelease_v2. - Uses
readlink()to print the current target of theactive_releaselink to the screen. - Uses
file_get_contents('active_release/version.txt')to prove that PHP is successfully following the link to the correct version of the file.
- Checks if a symlink named
There are no comments for now.