1# The embed SAPI 2 3A server application programming interface (SAPI) is the entry point into the Zend Engine. The embed SAPI is a lightweight SAPI for calling into the Zend Engine from C or other languages that have C bindings. 4 5## Basic Example 6 7Below is a basic example in C that uses the embed SAPI to boot up the Zend Engine, start a request, and print the number of functions loaded in the function table. 8 9```c 10/* embed_sapi_basic_example.c */ 11 12#include <sapi/embed/php_embed.h> 13 14int main(int argc, char **argv) 15{ 16 /* Invokes the Zend Engine initialization phase: SAPI (SINIT), modules 17 * (MINIT), and request (RINIT). It also opens a 'zend_try' block to catch 18 * a zend_bailout(). 19 */ 20 PHP_EMBED_START_BLOCK(argc, argv) 21 22 php_printf( 23 "Number of functions loaded: %d\n", 24 zend_hash_num_elements(EG(function_table)) 25 ); 26 27 /* Close the 'zend_try' block and invoke the shutdown phase: request 28 * (RSHUTDOWN), modules (MSHUTDOWN), and SAPI (SSHUTDOWN). 29 */ 30 PHP_EMBED_END_BLOCK() 31} 32``` 33 34To compile this, we must point the compiler to the PHP header files. The paths to the header files are listed from `php-config --includes`. 35 36We must also point the linker and the runtime loader to the `libphp.so` shared lib for linking PHP (`-lphp`) which is located at `$(php-config --prefix)/lib`. So the complete command to compile ends up being: 37 38```bash 39$ gcc \ 40 $(php-config --includes) \ 41 -L$(php-config --prefix)/lib \ 42 embed_sapi_basic_example.c \ 43 -lphp \ 44 -Wl,-rpath=$(php-config --prefix)/lib 45``` 46 47> :memo: The embed SAPI is disabled by default. In order for the above example to compile, PHP must be built with the embed SAPI enabled. To see what SAPIs are installed, run `php-config --php-sapis`. If you don't see `embed` in the list, you'll need to rebuild PHP with `./configure --enable-embed`. The PHP shared library `libphp.so` is built when the embed SAPI is enabled. 48 49If all goes to plan you should be able to run the program. 50 51```bash 52$ ./a.out 53Number of functions loaded: 1046 54``` 55 56## Function call example 57 58The following example calls `mt_rand()` and `var_dump()`s the return value. 59 60```c 61#include <main/php.h> 62#include <ext/standard/php_var.h> 63#include <sapi/embed/php_embed.h> 64 65int main(int argc, char **argv) 66{ 67 PHP_EMBED_START_BLOCK(argc, argv) 68 69 zval retval = {0}; 70 zend_fcall_info fci = {0}; 71 zend_fcall_info_cache fci_cache = {0}; 72 73 zend_string *func_name = zend_string_init(ZEND_STRL("mt_rand"), 0); 74 ZVAL_STR(&fci.function_name, func_name); 75 76 fci.size = sizeof fci; 77 fci.retval = &retval; 78 79 if (zend_call_function(&fci, &fci_cache) == SUCCESS) { 80 php_var_dump(&retval, 1); 81 } 82 83 zend_string_release(func_name); 84 85 PHP_EMBED_END_BLOCK() 86} 87``` 88 89## Execute a PHP script example 90 91```php 92<?php 93 94# example.php 95 96echo 'Hello from userland!' . PHP_EOL; 97``` 98 99```c 100#include <sapi/embed/php_embed.h> 101 102int main(int argc, char **argv) 103{ 104 PHP_EMBED_START_BLOCK(argc, argv) 105 106 zend_file_handle file_handle; 107 zend_stream_init_filename(&file_handle, "example.php"); 108 109 if (php_execute_script(&file_handle) == FAILURE) { 110 php_printf("Failed to execute PHP script.\n"); 111 } 112 113 PHP_EMBED_END_BLOCK() 114} 115``` 116 117## INI defaults 118 119The default value for 'error_prepend_string' is 'NULL'. The following example sets the INI default for 'error_prepend_string' to 'Embed SAPI error:'. 120 121```c 122#include <sapi/embed/php_embed.h> 123 124/* This callback is invoked as soon as the configuration hash table is 125 * allocated so any INI settings added via this callback will have the lowest 126 * precedence and will allow INI files to overwrite them. 127 */ 128static void example_ini_defaults(HashTable *configuration_hash) 129{ 130 zval ini_value; 131 ZVAL_NEW_STR(&ini_value, zend_string_init(ZEND_STRL("Embed SAPI error:"), /* persistent */ 1)); 132 zend_hash_str_update(configuration_hash, ZEND_STRL("error_prepend_string"), &ini_value); 133} 134 135int main(int argc, char **argv) 136{ 137 php_embed_module.ini_defaults = example_ini_defaults; 138 139 PHP_EMBED_START_BLOCK(argc, argv) 140 141 zval retval; 142 143 /* Generates an error by accessing an undefined variable '$a'. */ 144 if (zend_eval_stringl(ZEND_STRL("var_dump($a);"), &retval, "example") == FAILURE) { 145 php_printf("Failed to eval PHP.\n"); 146 } 147 148 PHP_EMBED_END_BLOCK() 149} 150``` 151 152After compiling and running, you should see: 153 154``` 155Embed SAPI error: 156Warning: Undefined variable $a in example on line 1 157NULL 158``` 159 160This default value is overwritable from INI files. We'll update one of the INI files (which can be found by running `$ php --ini`), and set `error_prepend_string="Oops!"`. We don't have to recompile the program, we can just run it again and we should see: 161 162``` 163Oops! 164Warning: Undefined variable $a in example on line 1 165NULL 166``` 167