feat: add Apache and PHP configuration templates with utility scripts to manage ProxyFCGI path handling and path normalization
This commit is contained in:
@@ -29,9 +29,11 @@ LoadModule deflate_module modules/mod_deflate.so
|
|||||||
AcceptFilter http none
|
AcceptFilter http none
|
||||||
AcceptFilter https none
|
AcceptFilter https none
|
||||||
|
|
||||||
# Required for PHP-FPM on Windows to avoid "No input file specified"
|
# Required for PHP-FPM on Windows
|
||||||
<IfModule proxy_fcgi_module>
|
<IfModule proxy_fcgi_module>
|
||||||
ProxyFCGIBackendType GENERIC
|
ProxyFCGIBackendType GENERIC
|
||||||
|
# Fix for encoded spaces and special characters in Windows paths
|
||||||
|
SetEnv proxy-fcgi-pathinfo unescape
|
||||||
</IfModule>
|
</IfModule>
|
||||||
|
|
||||||
ServerAdmin admin@localhost
|
ServerAdmin admin@localhost
|
||||||
@@ -54,7 +56,7 @@ DocumentRoot "{{ROOT}}"
|
|||||||
</Directory>
|
</Directory>
|
||||||
|
|
||||||
ErrorLog "{{LOG_DIR}}/apache_error.log"
|
ErrorLog "{{LOG_DIR}}/apache_error.log"
|
||||||
LogLevel warn
|
LogLevel warn proxy_fcgi:trace8
|
||||||
|
|
||||||
<IfModule log_config_module>
|
<IfModule log_config_module>
|
||||||
LogFormat "%h %l %u %t \"%r\" %>s %b" common
|
LogFormat "%h %l %u %t \"%r\" %>s %b" common
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ session.save_path = "{{SESSION_DIR}}"
|
|||||||
upload_tmp_dir = "{{TEMP_DIR}}"
|
upload_tmp_dir = "{{TEMP_DIR}}"
|
||||||
sys_temp_dir = "{{TEMP_DIR}}"
|
sys_temp_dir = "{{TEMP_DIR}}"
|
||||||
extension_dir = "{{EXT_DIR}}"
|
extension_dir = "{{EXT_DIR}}"
|
||||||
|
fastcgi.impersonate = 1
|
||||||
cgi.force_redirect = 0
|
cgi.force_redirect = 0
|
||||||
cgi.fix_pathinfo = 1
|
cgi.fix_pathinfo = 1
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
const projectsDir = 'd:/Works/2026/multiphp/generated_configs/projects_apache';
|
||||||
|
|
||||||
|
if (!fs.existsSync(projectsDir)) {
|
||||||
|
console.log('No project configurations found.');
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
const confFiles = fs.readdirSync(projectsDir).filter(f => f.endsWith('.conf'));
|
||||||
|
|
||||||
|
for (const file of confFiles) {
|
||||||
|
const filePath = path.join(projectsDir, file);
|
||||||
|
console.log(`Updating ${filePath}...`);
|
||||||
|
let content = fs.readFileSync(filePath, 'utf8');
|
||||||
|
|
||||||
|
// Extract HOST and PATH from Alias line
|
||||||
|
const aliasRegex = /Alias\s+\/([^\s]+)\s+"([^"]+)"/;
|
||||||
|
const match = content.match(aliasRegex);
|
||||||
|
|
||||||
|
if (match) {
|
||||||
|
const hostname = match[1];
|
||||||
|
let filepath = match[2];
|
||||||
|
|
||||||
|
// Extract PORT from current SetHandler (if present)
|
||||||
|
const portRegex = /proxy:fcgi:\/\/127\.0\.0\.1:(\d+)/;
|
||||||
|
const portMatch = content.match(portRegex);
|
||||||
|
const port = portMatch ? portMatch[1] : '9001';
|
||||||
|
|
||||||
|
// Ensure filepath ends with /
|
||||||
|
if (!filepath.endsWith('/')) filepath += '/';
|
||||||
|
|
||||||
|
// THE TRICK: URL-encode spaces in the path for ProxyPassMatch
|
||||||
|
const encodedPath = filepath.replace(/ /g, '%20');
|
||||||
|
|
||||||
|
// Re-construct the file: Keep Alias and Directory, replace PHP logic
|
||||||
|
const directoryBlockRegex = /<Directory "[^"]+">[\s\S]*?<\/Directory>/;
|
||||||
|
let newContent = content.match(directoryBlockRegex)[0];
|
||||||
|
|
||||||
|
// Remove SetHandler from Directory block
|
||||||
|
newContent = newContent.replace(/<FilesMatch \.php$>[\s\S]*?<\/FilesMatch>/g, '');
|
||||||
|
|
||||||
|
// Start fresh: Alias + Directory + ProxyPassMatch
|
||||||
|
const finalContent = `Alias /${hostname} "${filepath}"
|
||||||
|
${newContent}
|
||||||
|
|
||||||
|
# Explicit PHP mapping for ${hostname} (ProxyPassMatch pattern)
|
||||||
|
ProxyPassMatch "^/${hostname}/(.*\\.php(/.*)?)$" "fcgi://127.0.0.1:${port}/${encodedPath}$1"
|
||||||
|
`;
|
||||||
|
|
||||||
|
fs.writeFileSync(filePath, finalContent, 'utf8');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Done.');
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
const generatedDir = path.join('d:/Works/2026/multiphp', 'generated_configs');
|
||||||
|
const projectsDir = path.join(generatedDir, 'projects_apache');
|
||||||
|
|
||||||
|
function fixApacheConfig(filePath) {
|
||||||
|
if (!fs.existsSync(filePath)) return;
|
||||||
|
console.log(`Updating ${filePath}...`);
|
||||||
|
let content = fs.readFileSync(filePath, 'utf8');
|
||||||
|
|
||||||
|
// ENSURE trailing slash in SetHandler (opposite of my previous mistake)
|
||||||
|
// Match proxy:fcgi://127.0.0.1:PORT and ensure it ends with /
|
||||||
|
const newContent = content.replace(/SetHandler "proxy:fcgi:\/\/127\.0\.0\.1:(\d+)(?!\/)"/g, 'SetHandler "proxy:fcgi://127.0.0.1:$1/"');
|
||||||
|
|
||||||
|
// Ensure ProxyFCGIBackendType GENERIC is there (it should be in global httpd.conf)
|
||||||
|
let finalContent = newContent;
|
||||||
|
if (path.basename(filePath) === 'httpd.conf') {
|
||||||
|
if (!finalContent.includes('ProxyFCGIBackendType GENERIC')) {
|
||||||
|
// Find a good place, maybe after LoadModule
|
||||||
|
finalContent = finalContent.replace(/(LoadModule proxy_fcgi_module .+)/, '$1\n\n<IfModule proxy_fcgi_module>\n ProxyFCGIBackendType GENERIC\n</IfModule>');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.writeFileSync(filePath, finalContent, 'utf8');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. Global config
|
||||||
|
fixApacheConfig(path.join(generatedDir, 'httpd.conf'));
|
||||||
|
|
||||||
|
// 2. Project configs
|
||||||
|
if (fs.existsSync(projectsDir)) {
|
||||||
|
const projectFiles = fs.readdirSync(projectsDir);
|
||||||
|
for (const file of projectFiles) {
|
||||||
|
if (file.endsWith('.conf')) {
|
||||||
|
fixApacheConfig(path.join(projectsDir, file));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Done.');
|
||||||
Reference in New Issue
Block a user