Home Backend Development PHP Tutorial That Strange PHP Code in Frameworks and CMSs

That Strange PHP Code in Frameworks and CMSs

Nov 14, 2024 pm 08:45 PM

That Strange PHP Code in Frameworks and CMSs

Note: To follow along with this post, it's assumed you have some basic knowledge of programming in PHP.

This article discusses a PHP code snippet that you’ve likely seen at the top of your favorite CMS or framework. You've probably read that you should always include it at the beginning of every PHP file you develop, for security reasons, although without a very clear explanation of why. I’m referring to this code:

<?php

if ( ! defined( 'ABSPATH' ) ) {
    exit; // Exit if accessed directly
}
Copy after login
Copy after login
Copy after login

This type of code is very common in WordPress files, although it appears in nearly all frameworks and CMSs. In the case of the Joomla CMS, for example, the only change is that instead of ABSPATH, it uses JEXEC. Other than that, the logic remains the same. This CMS evolved from a previous system called Mambo, which also used similar code, but with _VALID_MOS as the constant. If we go even further back, we find that the first CMS to use this kind of code was PHP-Nuke (considered by some to be the first PHP-based CMS).

The execution flow of PHP-Nuke (and most CMSs and frameworks today) consisted of sequentially loading multiple files to respond to the action the user or visitor had taken on the website. For example, imagine a website from that era hosted at example.net with this CMS installed. Every time the homepage loaded, the system executed a sequence of files in order (this is just an example, not an actual sequence): index.php => load_modules.php => modules.php. In this chain, index.php was loaded first, which then loaded load_modules.php, which in turn loaded modules.php.

This execution chain didn’t always start with the first file (index.php). In fact, anyone could bypass part of the flow by directly accessing one of the other PHP files through its URL (for example, http://example.net/load_modules.php or http://example.net/modules.php), which, as we will see, could be risky in many cases.

How was this problem solved? A security measure was introduced, adding code similar to this at the beginning of each file:

<?php

if (!eregi("modules.php", $HTTP_SERVER_VARS['PHP_SELF'])) {
    die ("You can't access this file directly...");
}
Copy after login
Copy after login

Essentially, this code, placed at the top of a file named modules.php, checked if modules.php was being accessed directly via the URL. If so, execution was stopped, displaying the message: “You can’t access this file directly…” If $HTTP_SERVER_VARS['PHP_SELF'] didn’t contain modules.php, it meant that the normal execution flow was active, allowing the script to continue.

This code, however, had some limitations. First, the code was different for each file in which it was inserted, which added complexity. Additionally, in certain situations, PHP did not assign a value to $HTTP_SERVER_VARS['PHP_SELF'], which limited its effectiveness.

So, what did the developers do? They replaced all those code snippets with a simpler and more efficient version:

<?php

if ( ! defined( 'ABSPATH' ) ) {
    exit; // Exit if accessed directly
}
Copy after login
Copy after login
Copy after login

In this new code, which had become quite popular in the PHP community, the existence of a constant was checked. This constant was defined and assigned a value in the first file of the execution flow (index.php, home.php, or a similar file). Therefore, if this constant didn’t exist in any other file in the sequence, it meant that someone had bypassed index.php and was attempting to access another file directly.

Dangers of Directly Running a PHP File

At this point, you may be thinking that breaking the execution chain must be extremely serious. However, the truth is that, usually, it doesn’t pose a major threat.

The risk might arise when a PHP error exposes the path to our files. This shouldn’t concern us if the server is configured to suppress errors; even if errors weren’t hidden, the exposed information would be minimal, providing only a few clues to a potential attacker.

It could also happen that someone accesses files containing HTML fragments (views), revealing part of their content. In most cases, this should not be a cause for concern either.

Finally, a developer, either by mistake or lack of experience, might place risky code without external dependencies in the middle of an execution flow. This is very uncommon since framework or CMS code generally depends on other classes, functions, or external variables for its execution. So, if an attempt is made to execute a script directly through the URL, errors will arise as these dependencies won’t be found, and the execution won’t proceed.

So, why add the constant code if there is little reason for concern? The answer is this: "This method also prevents accidental variable injection through a register globals attack, preventing the PHP file from assuming it's within the application when it’s actually not."

Register Globals

Since the early days of PHP, all variables sent via URLs (GET) or forms (POST) were automatically converted into global variables. For example, if the file download.php?filepath=/etc/passwd was accessed, in the download.php file (and in those depending on it in the execution flow), you could use echo $filepath; and it would output /etc/passwd.

Inside download.php, there was no way to know if the variable $filepath was created by a prior file in the execution chain or if it was tampered with via the URL or POST. This created significant security vulnerabilities. Let’s look at an example, assuming the download.php file contains the following code:

<?php

if ( ! defined( 'ABSPATH' ) ) {
    exit; // Exit if accessed directly
}
Copy after login
Copy after login
Copy after login

The developer likely intended to use a Front Controller pattern for their code, meaning all web requests would go through a single entry file (index.php, home.php, etc.). This file would handle session initialization, load common variables, and finally redirect the request to a specific script (in this case, download.php) to perform the file download.

However, an attacker could bypass the intended execution sequence simply by calling download.php?filepath=/etc/passwd, as mentioned before. PHP would automatically create the global variable $filepath with the value /etc/passwd, allowing the attacker to download that file from the system. Serious problem.

This is only the tip of the iceberg since even more dangerous attacks could be executed with minimal effort. For example, in code like the following, which the programmer might have left as an unfinished script:

<?php

if (!eregi("modules.php", $HTTP_SERVER_VARS['PHP_SELF'])) {
    die ("You can't access this file directly...");
}
Copy after login
Copy after login

An attacker could execute any code by using a Remote File Inclusion (RFI) attack. If the attacker created a file My.class.php on their own site https://mysite.net containing any code they wanted to execute, they could call the vulnerable script by passing in their domain: useless_code.php?base_path=https://mysite.net, and the attack would be complete.

Another example: in a script named remove_file.inc.php with the following code:

<?php

if (!defined('MODULE_FILE')) {
    die ("You can't access this file directly...");
}
Copy after login

an attacker could call this file directly with a URL like remove_file.inc.php?filename=/etc/hosts, attempting to delete the /etc/hosts file from the system (if the system allows it, or other files they have permission to delete).

In a CMS like WordPress, which also uses global variables internally, these types of attacks were devastating. However, thanks to the constant technique, these and other PHP scripts were protected. Let’s look at the last example:

<?php

if(file_exists($filepath)) {
    header('Content-Description: File Transfer');
    header('Content-Type: application/octet-stream');
    header('Content-Disposition: attachment; filename="'.basename($filepath).'"');
    header('Expires: 0');
    header('Cache-Control: must-revalidate');
    header('Pragma: public');
    header('Content-Length: ' . filesize($filepath));
    flush(); // Flush system output buffer
    readfile($filepath);
    exit;
}
Copy after login

Now, if someone attempted to access remove_file.inc.php?filename=/etc/hosts, the constant would block the access. It is essential that this is a constant because, logically, if it were a variable, an attacker could inject it.

By now, you may wonder why PHP kept this functionality if it was so dangerous. Also, if you know other scripting languages (JSP, Ruby, etc.), you’ll see they have nothing similar (which is why they also don’t use the constant technique). Recall that PHP was initially created as a C-based templating system, and this behavior made development easier. The good news is that, seeing the issues it caused, PHP maintainers introduced a php.ini directive called register_globals (enabled by default) to allow this functionality to be disabled.

But as problems persisted, they disabled it by default. Even so, many hosts kept enabling it out of fear that their clients’ projects would stop working, as much of the code at the time did not use the recommended HTTP_*_VARS variables to access GET/POST/... values but rather used global variables.

Finally, seeing that the situation didn’t improve, they made a drastic decision: to remove this functionality in PHP 5.4 to avoid all these problems. Thus, today, scripts like those we’ve seen (without using constants) are usually no longer a risk, except for some harmless warnings/notices in certain cases.

Current Use

Today, the constant technique is still common. However, the unfortunate reality — and the reason for this article — is that few developers understand the true reason behind its use.

As with other best practices from the past (like copying parameters into local variables inside functions to avoid issues with references or using underscores in private variables to distinguish them), many continue to apply it simply because someone once told them it was a good practice, without questioning whether it still adds value today. The truth is that, in the majority of cases, this technique is no longer necessary.

Here are some reasons why this practice has lost relevance:

  • Removal of *register globals: Since PHP 5.4, the automatic registration of GET and POST variables as globals in PHP was removed. Without *register globals, executing individual scripts directly is harmless, removing the main reason for this technique.

  • Better Code Design: Even in pre-PHP 5.4 versions, modern code is better structured, generally in classes and functions, making access or manipulation via external variables more challenging. Even WordPress, which traditionally used global variables, minimizes these risks.

  • Use of *front-controllers: Nowadays, most web applications employ well-designed *front-controllers to ensure that class and function code only executes if the execution chain starts at the main entry point. Thus, if someone attempts to load files in isolation, the logic won’t trigger unless the flow starts from the correct entry point.

  • Class Autoloading: With the widespread use of class autoloading in modern development, the use of include or require has significantly decreased. This reduces risks associated with these methods (like Remote File Inclusion or Local File Inclusion) among more experienced developers.

  • Separation of Public and Private Code: In many modern CMSs and frameworks, public code (like assets) is separated from private code (logic). This measure is especially valuable, as it ensures that, if PHP fails on the server, PHP code (whether or not it uses the constant technique) is not exposed. Although this separation wasn’t implemented specifically to mitigate register globals, it helps prevent other security issues.

  • Widespread Use of Friendly URLs: Nowadays, configuring servers to use friendly URLs is common practice, ensuring a single entry point for application logic. This makes it nearly impossible for anyone to load PHP files in isolation.

  • Error Suppression in Production: Most modern CMSs and frameworks disable error output by default, so attackers don’t find clues about the application’s inner workings, which could facilitate other types of attacks.

Even though this technique is no longer necessary in the majority of cases, that doesn’t mean it’s never useful. As a professional developer, it’s essential to analyze each situation and decide whether the constant technique is relevant to the specific context in which you’re working. This kind of critical thinking should always be applied, even to so-called best practices.

Not Sure? Here are Some Tips

If you’re still unsure when to apply the constant technique, these recommendations may guide you:

  • Always use it if you think your code might run on a PHP version earlier than 5.4.
  • Don’t use it if the file only contains a class definition.
  • Don’t use it if the file contains only functions.
  • Don’t use it if the file only includes HTML/CSS, unless the HTML reveals sensitive information.
  • Don’t use it if the file only contains constants.

For everything else, if you’re in doubt, apply it. In most cases, it won’t be harmful and could protect you in unexpected circumstances, especially if you’re starting out. With time and experience, you’ll be able to assess when to apply this and other techniques more effectively.

That Strange PHP Code in Frameworks and CMSs

Keep Learning...

  • register_globals - MediaWiki
  • PHP: Using Register Globals - Manual
  • Remote file inclusion vulnerabilities [LWN.net]
  • Bugtraq: Serious security hole in Mambo Site Server version 3.0.X

The above is the detailed content of That Strange PHP Code in Frameworks and CMSs. For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

AI Hentai Generator

AI Hentai Generator

Generate AI Hentai for free.

Hot Article

R.E.P.O. Energy Crystals Explained and What They Do (Yellow Crystal)
1 months ago By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Best Graphic Settings
1 months ago By 尊渡假赌尊渡假赌尊渡假赌
Will R.E.P.O. Have Crossplay?
1 months ago By 尊渡假赌尊渡假赌尊渡假赌

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

Explain JSON Web Tokens (JWT) and their use case in PHP APIs. Explain JSON Web Tokens (JWT) and their use case in PHP APIs. Apr 05, 2025 am 12:04 AM

JWT is an open standard based on JSON, used to securely transmit information between parties, mainly for identity authentication and information exchange. 1. JWT consists of three parts: Header, Payload and Signature. 2. The working principle of JWT includes three steps: generating JWT, verifying JWT and parsing Payload. 3. When using JWT for authentication in PHP, JWT can be generated and verified, and user role and permission information can be included in advanced usage. 4. Common errors include signature verification failure, token expiration, and payload oversized. Debugging skills include using debugging tools and logging. 5. Performance optimization and best practices include using appropriate signature algorithms, setting validity periods reasonably,

Describe the SOLID principles and how they apply to PHP development. Describe the SOLID principles and how they apply to PHP development. Apr 03, 2025 am 12:04 AM

The application of SOLID principle in PHP development includes: 1. Single responsibility principle (SRP): Each class is responsible for only one function. 2. Open and close principle (OCP): Changes are achieved through extension rather than modification. 3. Lisch's Substitution Principle (LSP): Subclasses can replace base classes without affecting program accuracy. 4. Interface isolation principle (ISP): Use fine-grained interfaces to avoid dependencies and unused methods. 5. Dependency inversion principle (DIP): High and low-level modules rely on abstraction and are implemented through dependency injection.

Explain the concept of late static binding in PHP. Explain the concept of late static binding in PHP. Mar 21, 2025 pm 01:33 PM

Article discusses late static binding (LSB) in PHP, introduced in PHP 5.3, allowing runtime resolution of static method calls for more flexible inheritance.Main issue: LSB vs. traditional polymorphism; LSB's practical applications and potential perfo

How to automatically set permissions of unixsocket after system restart? How to automatically set permissions of unixsocket after system restart? Mar 31, 2025 pm 11:54 PM

How to automatically set the permissions of unixsocket after the system restarts. Every time the system restarts, we need to execute the following command to modify the permissions of unixsocket: sudo...

How to send a POST request containing JSON data using PHP's cURL library? How to send a POST request containing JSON data using PHP's cURL library? Apr 01, 2025 pm 03:12 PM

Sending JSON data using PHP's cURL library In PHP development, it is often necessary to interact with external APIs. One of the common ways is to use cURL library to send POST�...

Framework Security Features: Protecting against vulnerabilities. Framework Security Features: Protecting against vulnerabilities. Mar 28, 2025 pm 05:11 PM

Article discusses essential security features in frameworks to protect against vulnerabilities, including input validation, authentication, and regular updates.

Customizing/Extending Frameworks: How to add custom functionality. Customizing/Extending Frameworks: How to add custom functionality. Mar 28, 2025 pm 05:12 PM

The article discusses adding custom functionality to frameworks, focusing on understanding architecture, identifying extension points, and best practices for integration and debugging.

See all articles