You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

907 lines
26 KiB

25 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
23 years ago
23 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
25 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 4 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1997-2003 The PHP Group |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 3.0 of the PHP license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available through the world-wide-web at the following url: |
  10. | http://www.php.net/license/3_0.txt. |
  11. | If you did not receive a copy of the PHP license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@php.net so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. | Author: Jayakumar Muthukumarasamy <jk@kasenna.com> |
  16. | Uwe Schindler <uwe@thetaphi.de> |
  17. +----------------------------------------------------------------------+
  18. */
  19. /* $Id$ */
  20. /*
  21. * PHP includes
  22. */
  23. #define NSAPI 1
  24. #ifdef HAVE_CONFIG_H
  25. #include "config.h"
  26. #endif
  27. #include "php.h"
  28. #include "php_variables.h"
  29. #include "ext/standard/info.h"
  30. #include "php_ini.h"
  31. #include "php_globals.h"
  32. #include "SAPI.h"
  33. #include "php_main.h"
  34. #include "php_version.h"
  35. #include "TSRM.h"
  36. #include "ext/standard/php_standard.h"
  37. #include <sys/types.h>
  38. #include <sys/stat.h>
  39. #ifndef RTLD_DEFAULT
  40. #define RTLD_DEFAULT NULL
  41. #endif
  42. /*
  43. * If neither XP_UNIX not XP_WIN32 is defined use PHP_WIN32
  44. */
  45. #if !defined(XP_UNIX) && !defined(XP_WIN32)
  46. #ifdef PHP_WIN32
  47. #define XP_WIN32
  48. #else
  49. #define XP_UNIX
  50. #endif
  51. #endif
  52. /*
  53. * NSAPI includes
  54. */
  55. #include "nsapi.h"
  56. #include "base/pblock.h"
  57. #include "base/session.h"
  58. #include "frame/req.h"
  59. #include "frame/protocol.h" /* protocol_start_response */
  60. #include "base/util.h" /* is_mozilla, getline */
  61. #include "frame/log.h" /* log_error */
  62. #define NSLS_D struct nsapi_request_context *request_context
  63. #define NSLS_DC , NSLS_D
  64. #define NSLS_C request_context
  65. #define NSLS_CC , NSLS_C
  66. #define NSG(v) (request_context->v)
  67. #define NS_BUF_SIZE 2048
  68. /*
  69. * ZTS needs to be defined for NSAPI to work
  70. */
  71. #if !defined(ZTS)
  72. #error "NSAPI module needs ZTS to be defined"
  73. #endif
  74. /*
  75. * Structure to encapsulate the NSAPI request in SAPI
  76. */
  77. typedef struct nsapi_request_context {
  78. pblock *pb;
  79. Session *sn;
  80. Request *rq;
  81. int read_post_bytes;
  82. } nsapi_request_context;
  83. /*
  84. * Mappings between NSAPI names and environment variables. This
  85. * mapping was obtained from the sample programs at the iplanet
  86. * website.
  87. */
  88. typedef struct nsapi_equiv {
  89. const char *env_var;
  90. const char *nsapi_eq;
  91. } nsapi_equiv;
  92. static nsapi_equiv nsapi_headers[] = {
  93. { "CONTENT_LENGTH", "content-length" },
  94. { "CONTENT_TYPE", "content-type" }
  95. };
  96. static size_t nsapi_headers_size = sizeof(nsapi_headers)/sizeof(nsapi_headers[0]);
  97. static nsapi_equiv nsapi_reqpb[] = {
  98. { "QUERY_STRING", "query" },
  99. { "REQUEST_LINE", "clf-request" },
  100. { "REQUEST_METHOD", "method" },
  101. { "PHP_SELF", "uri" },
  102. { "SERVER_PROTOCOL", "protocol" }
  103. };
  104. static size_t nsapi_reqpb_size = sizeof(nsapi_reqpb)/sizeof(nsapi_reqpb[0]);
  105. static nsapi_equiv nsapi_vars[] = {
  106. { "PATH_INFO", "path-info" },
  107. { "SCRIPT_FILENAME", "path" },
  108. { "AUTH_TYPE", "auth-type" },
  109. { "CLIENT_CERT", "auth-cert" },
  110. { "REMOTE_USER", "auth-user" }
  111. };
  112. static size_t nsapi_vars_size = sizeof(nsapi_vars)/sizeof(nsapi_vars[0]);
  113. static nsapi_equiv nsapi_client[] = {
  114. { "HTTPS_KEYSIZE", "keysize" },
  115. { "HTTPS_SECRETSIZE", "secret-keysize" },
  116. { "REMOTE_ADDR", "ip" },
  117. { "REMOTE_HOST", "ip" }
  118. };
  119. static size_t nsapi_client_size = sizeof(nsapi_client)/sizeof(nsapi_client[0]);
  120. static char *nsapi_strdup(char *str)
  121. {
  122. if (str != NULL) {
  123. return STRDUP(str);
  124. }
  125. return NULL;
  126. }
  127. static void nsapi_free(void *addr)
  128. {
  129. if (addr != NULL) {
  130. FREE(addr);
  131. }
  132. }
  133. /*******************/
  134. /* PHP module part */
  135. /*******************/
  136. PHP_MINIT_FUNCTION(nsapi);
  137. PHP_MSHUTDOWN_FUNCTION(nsapi);
  138. PHP_RINIT_FUNCTION(nsapi);
  139. PHP_RSHUTDOWN_FUNCTION(nsapi);
  140. PHP_MINFO_FUNCTION(nsapi);
  141. PHP_FUNCTION(virtual);
  142. PHP_FUNCTION(nsapi_request_headers);
  143. PHP_FUNCTION(nsapi_response_headers);
  144. ZEND_BEGIN_MODULE_GLOBALS(nsapi)
  145. long read_timeout;
  146. ZEND_END_MODULE_GLOBALS(nsapi)
  147. ZEND_DECLARE_MODULE_GLOBALS(nsapi)
  148. #define NSAPI_G(v) TSRMG(nsapi_globals_id, zend_nsapi_globals *, v)
  149. /* {{{ nsapi_functions[]
  150. *
  151. * Every user visible function must have an entry in nsapi_functions[].
  152. */
  153. function_entry nsapi_functions[] = {
  154. PHP_FE(virtual, NULL) /* Make subrequest */
  155. PHP_FE(nsapi_request_headers, NULL) /* get request headers */
  156. PHP_FALIAS(getallheaders, nsapi_request_headers, NULL) /* compatibility */
  157. PHP_FALIAS(apache_request_headers, nsapi_request_headers, NULL) /* compatibility */
  158. PHP_FE(nsapi_response_headers, NULL) /* get response headers */
  159. PHP_FALIAS(apache_response_headers, nsapi_response_headers, NULL) /* compatibility */
  160. {NULL, NULL, NULL}
  161. };
  162. /* }}} */
  163. /* {{{ nsapi_module_entry
  164. */
  165. zend_module_entry nsapi_module_entry = {
  166. STANDARD_MODULE_HEADER,
  167. "nsapi",
  168. nsapi_functions,
  169. PHP_MINIT(nsapi),
  170. PHP_MSHUTDOWN(nsapi),
  171. NULL,
  172. NULL,
  173. PHP_MINFO(nsapi),
  174. "$Id$",
  175. STANDARD_MODULE_PROPERTIES
  176. };
  177. /* }}} */
  178. /* {{{ PHP_INI
  179. */
  180. PHP_INI_BEGIN()
  181. STD_PHP_INI_ENTRY("nsapi.read_timeout", "60", PHP_INI_ALL, OnUpdateLong, read_timeout, zend_nsapi_globals, nsapi_globals)
  182. PHP_INI_END()
  183. /* }}} */
  184. /* newer servers hide this functions from the programmer so redefine the functions dynamically
  185. thanks to Chris Elving from Sun for the function declarations */
  186. typedef int (*nsapi_servact_prototype)(Session *sn, Request *rq);
  187. nsapi_servact_prototype nsapi_servact_uri2path = NULL;
  188. nsapi_servact_prototype nsapi_servact_pathchecks = NULL;
  189. nsapi_servact_prototype nsapi_servact_fileinfo = NULL;
  190. nsapi_servact_prototype nsapi_servact_service = NULL;
  191. #ifdef PHP_WIN32
  192. /* The following dll-names for nsapi are in use at this time. The undocumented
  193. * servact_* functions are always in the newest one, older ones are supported by
  194. * the server only by wrapping the function table nothing else. So choose
  195. * the newest one found in process space for dynamic linking */
  196. char *nsapi_dlls[] = { "ns-httpd40.dll", "ns-httpd36.dll", "ns-httpd35.dll", "ns-httpd30.dll", NULL };
  197. #endif
  198. /* {{{ php_nsapi_init_dynamic_symbols
  199. */
  200. static void php_nsapi_init_dynamic_symbols(void)
  201. {
  202. #if defined(servact_uri2path) && defined(servact_pathchecks) && defined(servact_fileinfo) && defined(servact_service)
  203. /* use functions from nsapi.h if available */
  204. nsapi_servact_uri2path = &servact_uri2path;
  205. nsapi_servact_pathchecks = &servact_pathchecks;
  206. nsapi_servact_fileinfo = &servact_fileinfo;
  207. nsapi_servact_service = &servact_service;
  208. #else
  209. /* find address of internal NSAPI functions */
  210. #ifdef PHP_WIN32
  211. register int i;
  212. DL_HANDLE module = NULL;
  213. /* find a LOADED dll module from nsapi_dlls */
  214. for (i=0; nsapi_dlls[i]; i++) {
  215. if (module = GetModuleHandle(nsapi_dlls[i])) {
  216. break;
  217. }
  218. }
  219. if (!module) return;
  220. #else
  221. DL_HANDLE module = RTLD_DEFAULT;
  222. #endif
  223. nsapi_servact_uri2path = (nsapi_servact_prototype)DL_FETCH_SYMBOL(module, "INTservact_uri2path");
  224. nsapi_servact_pathchecks = (nsapi_servact_prototype)DL_FETCH_SYMBOL(module, "INTservact_pathchecks");
  225. nsapi_servact_fileinfo = (nsapi_servact_prototype)DL_FETCH_SYMBOL(module, "INTservact_fileinfo");
  226. nsapi_servact_service = (nsapi_servact_prototype)DL_FETCH_SYMBOL(module, "INTservact_service");
  227. if (!(nsapi_servact_uri2path && nsapi_servact_pathchecks && nsapi_servact_fileinfo && nsapi_servact_service)) {
  228. /* not found - could be cause they are undocumented */
  229. nsapi_servact_uri2path = NULL;
  230. nsapi_servact_pathchecks = NULL;
  231. nsapi_servact_fileinfo = NULL;
  232. nsapi_servact_service = NULL;
  233. }
  234. #endif
  235. }
  236. /* }}} */
  237. /* {{{ php_nsapi_init_globals
  238. */
  239. static void php_nsapi_init_globals(zend_nsapi_globals *nsapi_globals)
  240. {
  241. nsapi_globals->read_timeout = 60;
  242. }
  243. /* }}} */
  244. /* {{{ PHP_MINIT_FUNCTION
  245. */
  246. PHP_MINIT_FUNCTION(nsapi)
  247. {
  248. php_nsapi_init_dynamic_symbols();
  249. ZEND_INIT_MODULE_GLOBALS(nsapi, php_nsapi_init_globals, NULL);
  250. REGISTER_INI_ENTRIES();
  251. return SUCCESS;
  252. }
  253. /* }}} */
  254. /* {{{ PHP_MSHUTDOWN_FUNCTION
  255. */
  256. PHP_MSHUTDOWN_FUNCTION(nsapi)
  257. {
  258. UNREGISTER_INI_ENTRIES();
  259. return SUCCESS;
  260. }
  261. /* }}} */
  262. /* {{{ PHP_MINFO_FUNCTION
  263. */
  264. PHP_MINFO_FUNCTION(nsapi)
  265. {
  266. php_info_print_table_start();
  267. php_info_print_table_row(2, "NSAPI Module Version", nsapi_module_entry.version);
  268. php_info_print_table_row(2, "Server Software", system_version());
  269. php_info_print_table_row(2, "Sub-requests with virtual()",
  270. (nsapi_servact_service)?((zend_ini_long("zlib.output_compression", sizeof("zlib.output_compression"), 0))?"not supported with zlib.output_compression":"enabled"):"not supported on this platform" );
  271. php_info_print_table_end();
  272. DISPLAY_INI_ENTRIES();
  273. }
  274. /* }}} */
  275. /* {{{ proto bool virtual(string filename)
  276. Perform an NSAPI sub-request */
  277. /* This function is equivalent to <!--#include virtual...-->
  278. * in SSI. It does an NSAPI sub-request. It is useful
  279. * for including CGI scripts or .shtml files, or anything else
  280. * that you'd parse through webserver.
  281. */
  282. PHP_FUNCTION(virtual)
  283. {
  284. pval **uri;
  285. int rv;
  286. char *value;
  287. Request *rq;
  288. nsapi_request_context *rc = (nsapi_request_context *)SG(server_context);
  289. if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &uri) == FAILURE) {
  290. WRONG_PARAM_COUNT;
  291. }
  292. convert_to_string_ex(uri);
  293. if (!nsapi_servact_service) {
  294. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to include uri '%s' - Sub-requests not supported on this platform", (*uri)->value.str.val);
  295. RETURN_FALSE;
  296. } else if (zend_ini_long("zlib.output_compression", sizeof("zlib.output_compression"), 0)) {
  297. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to include uri '%s' - Sub-requests do not work with zlib.output_compression", (*uri)->value.str.val);
  298. RETURN_FALSE;
  299. } else {
  300. php_end_ob_buffers(1 TSRMLS_CC);
  301. php_header(TSRMLS_C);
  302. /* do the sub-request */
  303. /* thanks to Chris Elving from Sun for this code sniplet */
  304. if ((rq = request_restart_internal((*uri)->value.str.val, NULL)) == NULL) {
  305. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to include uri '%s' - Internal request creation failed", (*uri)->value.str.val);
  306. RETURN_FALSE;
  307. }
  308. /* insert host of current request to get page from same vhost */
  309. param_free(pblock_remove("host", rq->headers));
  310. if (value = pblock_findval("host", rc->rq->headers)) {
  311. pblock_nvinsert("host", value, rq->headers);
  312. }
  313. /* go through the normal request stages as given in obj.conf,
  314. but leave out the logging/error section */
  315. do {
  316. rv = (*nsapi_servact_uri2path)(rc->sn, rq);
  317. if (rv != REQ_PROCEED) {
  318. continue;
  319. }
  320. rv = (*nsapi_servact_pathchecks)(rc->sn, rq);
  321. if (rv != REQ_PROCEED) {
  322. continue;
  323. }
  324. rv = (*nsapi_servact_fileinfo)(rc->sn, rq);
  325. if (rv != REQ_PROCEED) {
  326. continue;
  327. }
  328. rv = (*nsapi_servact_service)(rc->sn, rq);
  329. } while (rv == REQ_RESTART);
  330. if (rq->status_num != 200) {
  331. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to include uri '%s' - HTTP status code %d during subrequest", (*uri)->value.str.val, rq->status_num);
  332. request_free(rq);
  333. RETURN_FALSE;
  334. }
  335. request_free(rq);
  336. RETURN_TRUE;
  337. }
  338. }
  339. /* }}} */
  340. /* {{{ proto array nsapi_request_headers(void)
  341. Get all headers from the request */
  342. PHP_FUNCTION(nsapi_request_headers)
  343. {
  344. register int i;
  345. struct pb_entry *entry;
  346. nsapi_request_context *rc = (nsapi_request_context *)SG(server_context);
  347. if (array_init(return_value) == FAILURE) {
  348. RETURN_FALSE;
  349. }
  350. for (i=0; i < rc->rq->headers->hsize; i++) {
  351. entry=rc->rq->headers->ht[i];
  352. while (entry) {
  353. if (!PG(safe_mode) || strcasecmp(entry->param->name, "authorization")) {
  354. add_assoc_string(return_value, entry->param->name, entry->param->value, 1);
  355. }
  356. entry=entry->next;
  357. }
  358. }
  359. }
  360. /* }}} */
  361. /* {{{ proto array nsapi_response_headers(void)
  362. Get all headers from the response */
  363. PHP_FUNCTION(nsapi_response_headers)
  364. {
  365. register int i;
  366. struct pb_entry *entry;
  367. nsapi_request_context *rc = (nsapi_request_context *)SG(server_context);
  368. if (array_init(return_value) == FAILURE) {
  369. RETURN_FALSE;
  370. }
  371. php_header(TSRMLS_C);
  372. for (i=0; i < rc->rq->srvhdrs->hsize; i++) {
  373. entry=rc->rq->srvhdrs->ht[i];
  374. while (entry) {
  375. add_assoc_string(return_value, entry->param->name, entry->param->value, 1);
  376. entry=entry->next;
  377. }
  378. }
  379. }
  380. /* }}} */
  381. /*************/
  382. /* SAPI part */
  383. /*************/
  384. static int sapi_nsapi_ub_write(const char *str, unsigned int str_length TSRMLS_DC)
  385. {
  386. int retval;
  387. nsapi_request_context *rc;
  388. rc = (nsapi_request_context *)SG(server_context);
  389. retval = net_write(rc->sn->csd, (char *)str, str_length);
  390. if (retval == IO_ERROR /* -1 */ || retval == IO_EOF /* 0 */) {
  391. php_handle_aborted_connection();
  392. }
  393. return retval;
  394. }
  395. static int sapi_nsapi_header_handler(sapi_header_struct *sapi_header, sapi_headers_struct *sapi_headers TSRMLS_DC)
  396. {
  397. char *header_name, *header_content, *p;
  398. nsapi_request_context *rc = (nsapi_request_context *)SG(server_context);
  399. header_name = sapi_header->header;
  400. header_content = p = strchr(header_name, ':');
  401. if (p == NULL) {
  402. efree(sapi_header->header);
  403. return 0;
  404. }
  405. *p = 0;
  406. do {
  407. header_content++;
  408. } while (*header_content == ' ');
  409. if (!strcasecmp(header_name, "Content-Type")) {
  410. param_free(pblock_remove("content-type", rc->rq->srvhdrs));
  411. pblock_nvinsert("content-type", header_content, rc->rq->srvhdrs);
  412. } else if (!strcasecmp(header_name, "Set-Cookie")) {
  413. pblock_nvinsert("set-cookie", header_content, rc->rq->srvhdrs);
  414. } else {
  415. pblock_nvinsert(header_name, header_content, rc->rq->srvhdrs);
  416. }
  417. *p = ':'; /* restore '*p' */
  418. efree(sapi_header->header);
  419. return 0; /* don't use the default SAPI mechanism, NSAPI duplicates this functionality */
  420. }
  421. static int sapi_nsapi_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC)
  422. {
  423. int retval;
  424. nsapi_request_context *rc = (nsapi_request_context *)SG(server_context);
  425. /*
  426. * We could probably just do this in the header_handler. But, I
  427. * don't know what the implication of doing it there is.
  428. */
  429. if (SG(sapi_headers).send_default_content_type) {
  430. param_free(pblock_remove("content-type", rc->rq->srvhdrs));
  431. pblock_nvinsert("content-type", "text/html", rc->rq->srvhdrs);
  432. }
  433. protocol_status(rc->sn, rc->rq, SG(sapi_headers).http_response_code, NULL);
  434. retval = protocol_start_response(rc->sn, rc->rq);
  435. if (retval == REQ_PROCEED || retval == REQ_NOACTION) {
  436. return SAPI_HEADER_SENT_SUCCESSFULLY;
  437. } else {
  438. return SAPI_HEADER_SEND_FAILED;
  439. }
  440. }
  441. static int sapi_nsapi_read_post(char *buffer, uint count_bytes TSRMLS_DC)
  442. {
  443. nsapi_request_context *rc = (nsapi_request_context *)SG(server_context);
  444. char *read_ptr = buffer, *content_length_str = NULL;
  445. uint bytes_read = 0;
  446. int length, content_length = 0;
  447. netbuf *nbuf = rc->sn->inbuf;
  448. /*
  449. * Yesss!
  450. */
  451. count_bytes = MIN(count_bytes, SG(request_info).content_length-rc->read_post_bytes);
  452. content_length = SG(request_info).content_length;
  453. if (content_length <= 0) {
  454. return 0;
  455. }
  456. /*
  457. * Gobble any pending data in the netbuf.
  458. */
  459. length = nbuf->cursize - nbuf->pos;
  460. length = MIN(count_bytes, length);
  461. if (length > 0) {
  462. memcpy(read_ptr, nbuf->inbuf + nbuf->pos, length);
  463. bytes_read += length;
  464. read_ptr += length;
  465. content_length -= length;
  466. nbuf->pos += length;
  467. }
  468. /*
  469. * Read the remaining from the socket.
  470. */
  471. while (content_length > 0 && bytes_read < count_bytes) {
  472. int bytes_to_read = count_bytes - bytes_read;
  473. if (content_length < bytes_to_read) {
  474. bytes_to_read = content_length;
  475. }
  476. length = net_read(rc->sn->csd, read_ptr, bytes_to_read, NSAPI_G(read_timeout));
  477. if (length == IO_ERROR || length == IO_EOF) {
  478. break;
  479. }
  480. bytes_read += length;
  481. read_ptr += length;
  482. content_length -= length;
  483. }
  484. if ( bytes_read > 0 ) {
  485. rc->read_post_bytes += bytes_read;
  486. }
  487. return bytes_read;
  488. }
  489. static char *sapi_nsapi_read_cookies(TSRMLS_D)
  490. {
  491. char *cookie_string;
  492. nsapi_request_context *rc = (nsapi_request_context *)SG(server_context);
  493. cookie_string = pblock_findval("cookie", rc->rq->headers);
  494. return cookie_string;
  495. }
  496. static void sapi_nsapi_register_server_variables(zval *track_vars_array TSRMLS_DC)
  497. {
  498. nsapi_request_context *rc = (nsapi_request_context *)SG(server_context);
  499. register size_t i;
  500. char *value,*p;
  501. char buf[NS_BUF_SIZE + 1];
  502. struct pb_entry *entry;
  503. for (i = 0; i < nsapi_reqpb_size; i++) {
  504. value = pblock_findval(nsapi_reqpb[i].nsapi_eq, rc->rq->reqpb);
  505. if (value) {
  506. php_register_variable((char *)nsapi_reqpb[i].env_var, value, track_vars_array TSRMLS_CC);
  507. }
  508. }
  509. for (i = 0; i < nsapi_headers_size; i++) {
  510. value = pblock_findval(nsapi_headers[i].nsapi_eq, rc->rq->headers);
  511. if (value) {
  512. php_register_variable((char *)nsapi_headers[i].env_var, value, track_vars_array TSRMLS_CC);
  513. }
  514. }
  515. for (i=0; i < rc->rq->headers->hsize; i++) {
  516. entry=rc->rq->headers->ht[i];
  517. while (entry) {
  518. if (!PG(safe_mode) || strcasecmp(entry->param->name, "authorization")) {
  519. snprintf(buf, NS_BUF_SIZE, "HTTP_%s", entry->param->name);
  520. for(p = buf + 5; *p; p++) {
  521. *p = toupper(*p);
  522. if (*p < 'A' || *p > 'Z') {
  523. *p = '_';
  524. }
  525. }
  526. buf[NS_BUF_SIZE]='\0';
  527. php_register_variable(buf, entry->param->value, track_vars_array TSRMLS_CC);
  528. }
  529. entry=entry->next;
  530. }
  531. }
  532. for (i = 0; i < nsapi_vars_size; i++) {
  533. value = pblock_findval(nsapi_vars[i].nsapi_eq, rc->rq->vars);
  534. if (value) {
  535. php_register_variable((char *)nsapi_vars[i].env_var, value, track_vars_array TSRMLS_CC);
  536. }
  537. }
  538. for (i = 0; i < nsapi_client_size; i++) {
  539. value = pblock_findval(nsapi_client[i].nsapi_eq, rc->sn->client);
  540. if (value) {
  541. php_register_variable((char *)nsapi_client[i].env_var, value, track_vars_array TSRMLS_CC);
  542. }
  543. }
  544. if (value = session_dns(rc->sn)) {
  545. php_register_variable("REMOTE_HOST", value, track_vars_array TSRMLS_CC);
  546. nsapi_free(value);
  547. }
  548. sprintf(buf, "%d", conf_getglobals()->Vport);
  549. php_register_variable("SERVER_PORT", buf, track_vars_array TSRMLS_CC);
  550. php_register_variable("SERVER_NAME", conf_getglobals()->Vserver_hostname, track_vars_array TSRMLS_CC);
  551. value = http_uri2url_dynamic("", "", rc->sn, rc->rq);
  552. php_register_variable("SERVER_URL", value, track_vars_array TSRMLS_CC);
  553. nsapi_free(value);
  554. php_register_variable("SERVER_SOFTWARE", system_version(), track_vars_array TSRMLS_CC);
  555. php_register_variable("HTTPS", (security_active ? "ON" : "OFF"), track_vars_array TSRMLS_CC);
  556. php_register_variable("GATEWAY_INTERFACE", "CGI/1.1", track_vars_array TSRMLS_CC);
  557. /* DOCUMENT_ROOT */
  558. if (value = request_translate_uri("/", rc->sn)) {
  559. value[strlen(value) - 1] = 0;
  560. php_register_variable("DOCUMENT_ROOT", value, track_vars_array TSRMLS_CC);
  561. nsapi_free(value);
  562. }
  563. /* PATH_TRANSLATED */
  564. if (value = pblock_findval("path-info", rc->rq->vars)) {
  565. if (value = request_translate_uri(value, rc->sn)) {
  566. php_register_variable("PATH_TRANSLATED", value, track_vars_array TSRMLS_CC);
  567. nsapi_free(value);
  568. }
  569. }
  570. /* Create full Request-URI */
  571. if (value = pblock_findval("uri", rc->rq->reqpb)) {
  572. strncpy(buf, value, NS_BUF_SIZE);
  573. buf[NS_BUF_SIZE]='\0';
  574. if (value = pblock_findval("query", rc->rq->reqpb)) {
  575. p = strchr(buf, 0);
  576. snprintf(p, NS_BUF_SIZE-(p-buf), "?%s", value);
  577. buf[NS_BUF_SIZE]='\0';
  578. }
  579. php_register_variable("REQUEST_URI", buf, track_vars_array TSRMLS_CC);
  580. }
  581. /* Create Script-Name */
  582. if (value = pblock_findval("uri", rc->rq->reqpb)) {
  583. strncpy(buf, value, NS_BUF_SIZE);
  584. buf[NS_BUF_SIZE]='\0';
  585. if (value = pblock_findval("path-info", rc->rq->vars)) {
  586. buf[strlen(buf) - strlen(value)] = '\0';
  587. }
  588. php_register_variable("SCRIPT_NAME", buf, track_vars_array TSRMLS_CC);
  589. }
  590. }
  591. static void nsapi_log_message(char *message)
  592. {
  593. TSRMLS_FETCH();
  594. nsapi_request_context *rc = (nsapi_request_context *)SG(server_context);
  595. log_error(LOG_INFORM, "PHP module", rc->sn, rc->rq, "%s", message);
  596. }
  597. static int php_nsapi_startup(sapi_module_struct *sapi_module)
  598. {
  599. if (php_module_startup(sapi_module, &nsapi_module_entry, 1)==FAILURE) {
  600. return FAILURE;
  601. }
  602. return SUCCESS;
  603. }
  604. static sapi_module_struct nsapi_sapi_module = {
  605. "nsapi", /* name */
  606. "NSAPI", /* pretty name */
  607. php_nsapi_startup, /* startup */
  608. php_module_shutdown_wrapper, /* shutdown */
  609. NULL, /* activate */
  610. NULL, /* deactivate */
  611. sapi_nsapi_ub_write, /* unbuffered write */
  612. NULL, /* flush */
  613. NULL, /* get uid */
  614. NULL, /* getenv */
  615. php_error, /* error handler */
  616. sapi_nsapi_header_handler, /* header handler */
  617. sapi_nsapi_send_headers, /* send headers handler */
  618. NULL, /* send header handler */
  619. sapi_nsapi_read_post, /* read POST data */
  620. sapi_nsapi_read_cookies, /* read Cookies */
  621. sapi_nsapi_register_server_variables, /* register server variables */
  622. nsapi_log_message, /* Log message */
  623. NULL, /* Block interruptions */
  624. NULL, /* Unblock interruptions */
  625. STANDARD_SAPI_MODULE_PROPERTIES
  626. };
  627. static void nsapi_php_ini_entries(NSLS_D TSRMLS_DC)
  628. {
  629. struct pb_entry *entry;
  630. register int i;
  631. for (i=0; i < NSG(pb)->hsize; i++) {
  632. entry=NSG(pb)->ht[i];
  633. while (entry) {
  634. /* exclude standard entries given to "Service" which should not go into ini entries */
  635. if (strcasecmp(entry->param->name,"fn") && strcasecmp(entry->param->name,"type")
  636. && strcasecmp(entry->param->name,"method") && strcasecmp(entry->param->name,"directive")) {
  637. /* change the ini entry */
  638. if (zend_alter_ini_entry(entry->param->name, strlen(entry->param->name)+1,
  639. entry->param->value, strlen(entry->param->value),
  640. PHP_INI_USER, PHP_INI_STAGE_RUNTIME)==FAILURE) {
  641. log_error(LOG_WARN, "php4_execute", NSG(sn), NSG(rq), "Cannot change php.ini key \"%s\" to \"%s\"", entry->param->name, entry->param->value);
  642. }
  643. }
  644. entry=entry->next;
  645. }
  646. }
  647. }
  648. void NSAPI_PUBLIC php4_close(void *vparam)
  649. {
  650. if (nsapi_sapi_module.shutdown) {
  651. nsapi_sapi_module.shutdown(&nsapi_sapi_module);
  652. }
  653. if (nsapi_sapi_module.php_ini_path_override) {
  654. free(nsapi_sapi_module.php_ini_path_override);
  655. }
  656. tsrm_shutdown();
  657. log_error(LOG_INFORM, "php4_close", NULL, NULL, "Shutdown PHP Module");
  658. }
  659. int NSAPI_PUBLIC php4_init(pblock *pb, Session *sn, Request *rq)
  660. {
  661. php_core_globals *core_globals;
  662. char *ini_path;
  663. int threads=128; /* default for server */
  664. /* fetch max threads from NSAPI and initialize TSRM with it */
  665. #if defined(pool_maxthreads)
  666. threads=pool_maxthreads;
  667. if (threads<1) {
  668. threads=128; /* default for server */
  669. }
  670. #endif
  671. tsrm_startup(threads, 1, 0, NULL);
  672. core_globals = ts_resource(core_globals_id);
  673. /* look if php_ini parameter is given to php4_init */
  674. if (ini_path = pblock_findval("php_ini", pb)) {
  675. nsapi_sapi_module.php_ini_path_override = strdup(ini_path);
  676. }
  677. /* start SAPI */
  678. sapi_startup(&nsapi_sapi_module);
  679. nsapi_sapi_module.startup(&nsapi_sapi_module);
  680. daemon_atrestart(&php4_close, NULL);
  681. log_error(LOG_INFORM, "php4_init", sn, rq, "Initialized PHP Module (%d threads exspected)", threads);
  682. return REQ_PROCEED;
  683. }
  684. int NSAPI_PUBLIC php4_execute(pblock *pb, Session *sn, Request *rq)
  685. {
  686. int retval;
  687. nsapi_request_context *request_context;
  688. zend_file_handle file_handle = {0};
  689. struct stat fst;
  690. char *query_string = pblock_findval("query", rq->reqpb);
  691. char *uri = pblock_findval("uri", rq->reqpb);
  692. char *path_info = pblock_findval("path-info", rq->vars);
  693. char *request_method = pblock_findval("method", rq->reqpb);
  694. char *content_type = pblock_findval("content-type", rq->headers);
  695. char *content_length = pblock_findval("content-length", rq->headers);
  696. char *path_translated = pblock_findval("path", rq->vars);
  697. TSRMLS_FETCH();
  698. request_context = (nsapi_request_context *)MALLOC(sizeof(nsapi_request_context));
  699. request_context->pb = pb;
  700. request_context->sn = sn;
  701. request_context->rq = rq;
  702. request_context->read_post_bytes = 0;
  703. SG(server_context) = request_context;
  704. SG(request_info).query_string = nsapi_strdup(query_string);
  705. SG(request_info).request_uri = nsapi_strdup(uri);
  706. SG(request_info).request_method = nsapi_strdup(request_method);
  707. SG(request_info).path_translated = nsapi_strdup(path_translated);
  708. SG(request_info).content_type = nsapi_strdup(content_type);
  709. SG(request_info).content_length = (content_length == NULL) ? 0 : strtoul(content_length, 0, 0);
  710. SG(sapi_headers).http_response_code = 200;
  711. nsapi_php_ini_entries(NSLS_C TSRMLS_CC);
  712. file_handle.type = ZEND_HANDLE_FILENAME;
  713. file_handle.filename = SG(request_info).path_translated;
  714. file_handle.free_filename = 0;
  715. file_handle.opened_path = NULL;
  716. if (stat(SG(request_info).path_translated, &fst)==0 && S_ISREG(fst.st_mode)) {
  717. if (php_request_startup(TSRMLS_C) == SUCCESS) {
  718. php_execute_script(&file_handle TSRMLS_CC);
  719. php_request_shutdown(NULL);
  720. retval=REQ_PROCEED;
  721. } else {
  722. /* send 500 internal server error */
  723. log_error(LOG_WARN, "php4_execute", sn, rq, "Cannot prepare PHP engine!");
  724. protocol_status(sn, rq, 500, NULL);
  725. retval=REQ_ABORTED;
  726. }
  727. } else {
  728. /* send 404 because file not found */
  729. log_error(LOG_WARN, "php4_execute", sn, rq, "Cannot execute PHP script: %s", SG(request_info).path_translated);
  730. protocol_status(sn, rq, 404, NULL);
  731. retval=REQ_ABORTED;
  732. }
  733. nsapi_free(SG(request_info).query_string);
  734. nsapi_free(SG(request_info).request_uri);
  735. nsapi_free((void*)(SG(request_info).request_method));
  736. nsapi_free(SG(request_info).path_translated);
  737. nsapi_free((void*)(SG(request_info).content_type));
  738. FREE(request_context);
  739. return retval;
  740. }
  741. /*********************************************************
  742. / authentication
  743. /
  744. / we have to make a 'fake' authenticator for netscape so it
  745. / will pass authentication through to php, and allow us to
  746. / check authentication with our scripts.
  747. /
  748. / php4_auth_trans
  749. / main function called from netscape server to authenticate
  750. / a line in obj.conf:
  751. / funcs=php4_auth_trans shlib="path/to/this/phpnsapi.dll"
  752. / and:
  753. / <Object ppath="path/to/be/authenticated/by/php/*">
  754. / AuthTrans fn="php4_auth_trans"
  755. /*********************************************************/
  756. int NSAPI_PUBLIC php4_auth_trans(pblock * pb, Session * sn, Request * rq)
  757. {
  758. /* This is a DO NOTHING function that allows authentication
  759. * information
  760. * to be passed through to PHP scripts.
  761. */
  762. return REQ_PROCEED;
  763. }
  764. /*
  765. * Local variables:
  766. * tab-width: 4
  767. * c-basic-offset: 4
  768. * End:
  769. * vim600: sw=4 ts=4 fdm=marker
  770. * vim<600: sw=4 ts=4
  771. */