php_embed.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. /*
  2. +----------------------------------------------------------------------+
  3. | Copyright (c) The PHP Group |
  4. +----------------------------------------------------------------------+
  5. | This source file is subject to version 3.01 of the PHP license, |
  6. | that is bundled with this package in the file LICENSE, and is |
  7. | available through the world-wide-web at the following url: |
  8. | https://www.php.net/license/3_01.txt |
  9. | If you did not receive a copy of the PHP license and are unable to |
  10. | obtain it through the world-wide-web, please send a note to |
  11. | license@php.net so we can mail you a copy immediately. |
  12. +----------------------------------------------------------------------+
  13. | Author: Edin Kadribasic <edink@php.net> |
  14. +----------------------------------------------------------------------+
  15. */
  16. #include "php_embed.h"
  17. #include "ext/standard/php_standard.h"
  18. #include "ext/standard/dl_arginfo.h"
  19. #ifdef PHP_WIN32
  20. #include <io.h>
  21. #include <fcntl.h>
  22. #endif
  23. const char HARDCODED_INI[] =
  24. "html_errors=0\n"
  25. "register_argc_argv=1\n"
  26. "implicit_flush=1\n"
  27. "output_buffering=0\n"
  28. "max_execution_time=0\n"
  29. "max_input_time=-1\n\0";
  30. #if defined(PHP_WIN32) && defined(ZTS)
  31. ZEND_TSRMLS_CACHE_DEFINE()
  32. #endif
  33. static char* php_embed_read_cookies(void)
  34. {
  35. return NULL;
  36. }
  37. static int php_embed_deactivate(void)
  38. {
  39. fflush(stdout);
  40. return SUCCESS;
  41. }
  42. /* Here we prefer to use write(), which is unbuffered, over fwrite(), which is
  43. * buffered. Using an unbuffered write operation to stdout will ensure PHP's
  44. * output buffering feature does not compete with a SAPI output buffer and
  45. * therefore we avoid situations wherein flushing the output buffer results in
  46. * nondeterministic behavior.
  47. */
  48. static inline size_t php_embed_single_write(const char *str, size_t str_length)
  49. {
  50. #ifdef PHP_WRITE_STDOUT
  51. zend_long ret;
  52. ret = write(STDOUT_FILENO, str, str_length);
  53. if (ret <= 0) return 0;
  54. return ret;
  55. #else
  56. size_t ret;
  57. ret = fwrite(str, 1, MIN(str_length, 16384), stdout);
  58. return ret;
  59. #endif
  60. }
  61. /* SAPIs only have unbuffered write operations. This is because PHP's output
  62. * buffering feature will handle any buffering of the output and invoke the
  63. * SAPI unbuffered write operation when it flushes the buffer.
  64. */
  65. static size_t php_embed_ub_write(const char *str, size_t str_length)
  66. {
  67. const char *ptr = str;
  68. size_t remaining = str_length;
  69. size_t ret;
  70. while (remaining > 0) {
  71. ret = php_embed_single_write(ptr, remaining);
  72. if (!ret) {
  73. php_handle_aborted_connection();
  74. }
  75. ptr += ret;
  76. remaining -= ret;
  77. }
  78. return str_length;
  79. }
  80. static void php_embed_flush(void *server_context)
  81. {
  82. if (fflush(stdout)==EOF) {
  83. php_handle_aborted_connection();
  84. }
  85. }
  86. static void php_embed_send_header(sapi_header_struct *sapi_header, void *server_context)
  87. {
  88. }
  89. /* The SAPI error logger that is called when the 'error_log' INI setting is not
  90. * set.
  91. *
  92. * https://www.php.net/manual/en/errorfunc.configuration.php#ini.error-log
  93. */
  94. static void php_embed_log_message(const char *message, int syslog_type_int)
  95. {
  96. fprintf(stderr, "%s\n", message);
  97. }
  98. static void php_embed_register_variables(zval *track_vars_array)
  99. {
  100. php_import_environment_variables(track_vars_array);
  101. }
  102. /* Module initialization (MINIT) */
  103. static int php_embed_startup(sapi_module_struct *sapi_module)
  104. {
  105. if (php_module_startup(sapi_module, NULL, 0) == FAILURE) {
  106. return FAILURE;
  107. }
  108. return SUCCESS;
  109. }
  110. EMBED_SAPI_API sapi_module_struct php_embed_module = {
  111. "embed", /* name */
  112. "PHP Embedded Library", /* pretty name */
  113. php_embed_startup, /* startup */
  114. php_module_shutdown_wrapper, /* shutdown */
  115. NULL, /* activate */
  116. php_embed_deactivate, /* deactivate */
  117. php_embed_ub_write, /* unbuffered write */
  118. php_embed_flush, /* flush */
  119. NULL, /* get uid */
  120. NULL, /* getenv */
  121. php_error, /* error handler */
  122. NULL, /* header handler */
  123. NULL, /* send headers handler */
  124. php_embed_send_header, /* send header handler */
  125. NULL, /* read POST data */
  126. php_embed_read_cookies, /* read Cookies */
  127. php_embed_register_variables, /* register server variables */
  128. php_embed_log_message, /* Log message */
  129. NULL, /* Get request time */
  130. NULL, /* Child terminate */
  131. STANDARD_SAPI_MODULE_PROPERTIES
  132. };
  133. /* }}} */
  134. static const zend_function_entry additional_functions[] = {
  135. ZEND_FE(dl, arginfo_dl)
  136. ZEND_FE_END
  137. };
  138. EMBED_SAPI_API int php_embed_init(int argc, char **argv)
  139. {
  140. #if defined(SIGPIPE) && defined(SIG_IGN)
  141. signal(SIGPIPE, SIG_IGN); /* ignore SIGPIPE in standalone mode so
  142. that sockets created via fsockopen()
  143. don't kill PHP if the remote site
  144. closes it. in apache|apxs mode apache
  145. does that for us! thies@thieso.net
  146. 20000419 */
  147. #endif
  148. #ifdef ZTS
  149. php_tsrm_startup();
  150. # ifdef PHP_WIN32
  151. ZEND_TSRMLS_CACHE_UPDATE();
  152. # endif
  153. #endif
  154. zend_signal_startup();
  155. /* SAPI initialization (SINIT)
  156. *
  157. * Initialize the SAPI globals (memset to 0). After this point we can set
  158. * SAPI globals via the SG() macro.
  159. *
  160. * Reentrancy startup.
  161. *
  162. * This also sets 'php_embed_module.ini_entries = NULL' so we cannot
  163. * allocate the INI entries until after this call.
  164. */
  165. sapi_startup(&php_embed_module);
  166. #ifdef PHP_WIN32
  167. _fmode = _O_BINARY; /*sets default for file streams to binary */
  168. setmode(_fileno(stdin), O_BINARY); /* make the stdio mode be binary */
  169. setmode(_fileno(stdout), O_BINARY); /* make the stdio mode be binary */
  170. setmode(_fileno(stderr), O_BINARY); /* make the stdio mode be binary */
  171. #endif
  172. /* This hard-coded string of INI settings is parsed and read into PHP's
  173. * configuration hash table at the very end of php_init_config(). This
  174. * means these settings will overwrite any INI settings that were set from
  175. * an INI file.
  176. *
  177. * To provide overwritable INI defaults, hook the ini_defaults function
  178. * pointer that is part of the sapi_module_struct
  179. * (php_embed_module.ini_defaults).
  180. *
  181. * void (*ini_defaults)(HashTable *configuration_hash);
  182. *
  183. * This callback is invoked as soon as the configuration hash table is
  184. * allocated so any INI settings added via this callback will have the
  185. * lowest precedence and will allow INI files to overwrite them.
  186. */
  187. php_embed_module.ini_entries = malloc(sizeof(HARDCODED_INI));
  188. memcpy(php_embed_module.ini_entries, HARDCODED_INI, sizeof(HARDCODED_INI));
  189. /* SAPI-provided functions. */
  190. php_embed_module.additional_functions = additional_functions;
  191. if (argv) {
  192. php_embed_module.executable_location = argv[0];
  193. }
  194. /* Module initialization (MINIT) */
  195. if (php_embed_module.startup(&php_embed_module) == FAILURE) {
  196. return FAILURE;
  197. }
  198. /* Do not chdir to the script's directory. This is akin to calling the CGI
  199. * SAPI with '-C'.
  200. */
  201. SG(options) |= SAPI_OPTION_NO_CHDIR;
  202. SG(request_info).argc=argc;
  203. SG(request_info).argv=argv;
  204. /* Request initialization (RINIT) */
  205. if (php_request_startup() == FAILURE) {
  206. php_module_shutdown();
  207. return FAILURE;
  208. }
  209. SG(headers_sent) = 1;
  210. SG(request_info).no_headers = 1;
  211. php_register_variable("PHP_SELF", "-", NULL);
  212. return SUCCESS;
  213. }
  214. EMBED_SAPI_API void php_embed_shutdown(void)
  215. {
  216. /* Request shutdown (RSHUTDOWN) */
  217. php_request_shutdown((void *) 0);
  218. /* Module shutdown (MSHUTDOWN) */
  219. php_module_shutdown();
  220. /* SAPI shutdown (SSHUTDOWN) */
  221. sapi_shutdown();
  222. #ifdef ZTS
  223. tsrm_shutdown();
  224. #endif
  225. if (php_embed_module.ini_entries) {
  226. free(php_embed_module.ini_entries);
  227. php_embed_module.ini_entries = NULL;
  228. }
  229. }