/** * Simple wrapper for php-cgi that workarounds * the bug: http://bugs.php.net/bug.php?id=28227 * Tested with thttpd only. * * Compilation: * gcc -Wall -Os -s -o wrapper wrapper.c * * Usage: * 1. Put 'wrapper' binary in the /bin directory. * 2. In the first line of the script instead of line: * #!/bin/php-cgi * use the line: * #!/bin/wrapper /bin/php-cgi */// Translation use-cases://// 1. http://localhost/script/phpinfo.php// PWD=/html/script// PATH_INFO is not set// SCRIPT_NAME=/script/phpinfo.php// -> SCRIPT_FILENAME=/html/script/phpinfo.php//// 2. http://localhost/script/phpinfo.php/asd/qwe// PWD=/html/script// PATH_INFO=/asd/qwe// SCRIPT_NAME=/script/phpinfo.php// -> SCRIPT_FILENAME=/html/script/phpinfo.php//// 3. http://localhost/script/ (here index.htm is a CGI)// PWD=/html/script// PATH_INFO is not set// SCRIPT_NAME=/script/ -> /script/index.htm// -> SCRIPT_FILENAME=/html/script/index.htm - take it from argv[2]//// 4. http://localhost/script/phpinfo.php/asd/qwe/// PWD=/html/script// PATH_INFO=/asd/qwe -> /asd/qwe/// SCRIPT_NAME=/script/phpinfo.php/asd/qwe/ -> /script/phpinfo.php// -> SCRIPT_FILENAME=/html/script/phpinfo.php//// 5. http://localhost/script/phpinfo.php/// PWD=/html/script// PATH_INFO is not set -> /// SCRIPT_NAME=/script/phpinfo.php/ -> /script/phpinfo.php// -> SCRIPT_FILENAME=/html/script/phpinfo.php#include <stdlib.h>#include <unistd.h>#include <string.h>int main(int argc, char *argv[]){ char pwd[1024]; char *name = getenv("SCRIPT_NAME"); if (name && getcwd(pwd, sizeof(pwd)) && !getenv("SCRIPT_FILENAME")) { name = strdup(name); // First check if it has '/' at the end if (name[strlen(name)-1]=='/') { char *info = getenv("PATH_INFO"); if (info) { // case 4, making it similar to case 2: // * stripping tail from SCRIPT_NAME name[strlen(name) - strlen(info) - 1] = 0; // * adding slash to PATH_INFO int infolen = strlen(info); char *newinfo = (char*)malloc(infolen + 2); strcpy(newinfo, info); newinfo[infolen] = '/'; newinfo[infolen+1] = 0; setenv("PATH_INFO", newinfo, 1); free(newinfo); } else { // case 3 or case 5, trying to guess one int pwdlen = strlen(pwd); int namelen = strlen(name); if (pwdlen >= namelen-1 && strncmp(pwd+pwdlen-namelen+1, name, namelen-1) == 0) { // looks like case 3, changing it to case 1 char *newname = (char*)malloc(namelen + strlen(argv[2]) + 2); strcpy(newname, name); strcat(newname, argv[2]); free(name); name = newname; } else { // looks like case 5, changing it to case 2 name[namelen-1] = 0; setenv("PATH_INFO", "/", 0); setenv("PATH_TRANSLATED", "/", 0); } } } // processing cases 1 and 2 // adding SCRIPT_FILENAME variable to environment int pathlen = strrchr(name, '/') - name; int prefixlen = strlen(pwd) - pathlen; char *newenv = (char*)malloc(prefixlen + strlen(name) + 2); strcpy(newenv, pwd); newenv[prefixlen] = 0; strcat(newenv, name); setenv("SCRIPT_FILENAME", newenv, 0); setenv("SCRIPT_NAME", name, 1); // required for cases 3-5 free(newenv); free(name); } else { // Not running from thttpd? What can we do... :( return 1; } // execute real interpreter argv++; return execvp(argv[0], argv);}