如何在PHP内置Web服务器中用无.php后缀URL访问PHP文件
Hey there! I see you're working on setting up clean URLs for your local PHP project—like accessing http://localhost:8000/test instead of http://localhost:8000/test.php—using the built-in web server and a router script. Your core idea of checking for corresponding PHP files is on the right track, but let's tweak your implementation to make it more robust, cross-platform, and secure.
First, let's break down the issues with your current code:
- Replacing all
/with\\works on Windows but breaks on Linux/macOS. We should use PHP's nativeDIRECTORY_SEPARATORfor cross-platform compatibility. - Using the full
REQUEST_URIincludes query strings (e.g.,http://localhost:8000/test?foo=barwould turn intotest?foo=bar.phpwhen you append.php—that's invalid). - There's no handling for the root path (accessing
http://localhost:8000/should loadindex.phpby default). - No protection against directory traversal attacks (malicious requests like
http://localhost:8000/../secret-filecould access files outside your project folder).
Here's a Polished, Secure Implementation
This version keeps your include requirement intact and fixes all the above issues:
<?php // router.php // Extract just the path part of the request (ignores query strings like ?foo=bar) $requestPath = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH); // Handle root URL: load index.php when accessing http://localhost:8000/ if ($requestPath === '/') { $indexFile = __DIR__ . DIRECTORY_SEPARATOR . 'index.php'; if (file_exists($indexFile)) { include $indexFile; exit; } } // Clean up the path to prevent directory traversal attacks $cleanPath = trim($requestPath, '/'); // Build the full path to the target PHP file $targetFile = __DIR__ . DIRECTORY_SEPARATOR . $cleanPath . '.php'; // Verify the file exists and is a regular file (not a directory) if (file_exists($targetFile) && is_file($targetFile)) { include $targetFile; } else { // Let the built-in server handle 404, or customize your error page here http_response_code(404); echo "<h1>404 - Page Not Found</h1>"; // Alternatively, return false to let the server try default file handling // return false; } ?>
Key Improvements Explained
- Query string handling:
parse_url(..., PHP_URL_PATH)isolates just the path part of the request, so parameters don't break your file path. - Cross-platform compatibility:
DIRECTORY_SEPARATORautomatically uses the correct path separator (/for Unix/macOS,\for Windows) so your script works everywhere. - Directory traversal protection: Trimming the path and building it with
__DIR__ensures malicious requests can't escape your project directory. - Root path support: Accessing the base URL loads
index.phpas expected. - File validation:
is_file($targetFile)makes sure we're including a regular file, not a directory.
This script also supports nested paths out of the box—for example, http://localhost:8000/blog/post will load blog/post.php if it exists in your project folder.
And just to confirm: your choice to use include instead of readfile is totally correct! include lets the PHP interpreter execute the file's code, whereas readfile would just output the raw source text.
内容的提问来源于stack exchange,提问作者Hafax

