mirror of
https://github.com/php/php-src.git
synced 2024-11-27 03:44:07 +08:00
[ci skip] Fix CS in Markdown files
Checked and quickfixed with Markdown linter - 80 columns line width (~) - code highlighting - ... Some most obvious outdated content updated a bit more.
This commit is contained in:
parent
80f3c69ae9
commit
1c94aac89e
21
README.md
21
README.md
@ -48,23 +48,29 @@ PHP uses autotools on Unix systems to configure the build:
|
||||
|
||||
*See `make -h` for make options.*
|
||||
|
||||
The `-j` option shall set the maximum number of jobs `make` can use for the build:
|
||||
The `-j` option shall set the maximum number of jobs `make` can use for the
|
||||
build:
|
||||
|
||||
make -j4
|
||||
|
||||
Shall run `make` with a maximum of 4 concurrent jobs: Generally the maximum number of jobs should not exceed the number of cores available.
|
||||
Shall run `make` with a maximum of 4 concurrent jobs: Generally the maximum
|
||||
number of jobs should not exceed the number of cores available.
|
||||
|
||||
## Testing PHP source code
|
||||
|
||||
PHP ships with an extensive test suite, the command `make test` is used after successful compilation of the sources to run this test suite.
|
||||
PHP ships with an extensive test suite, the command `make test` is used after
|
||||
successful compilation of the sources to run this test suite.
|
||||
|
||||
It is possible to run tests using multiple cores by setting `-jN` in `TEST_PHP_ARGS`:
|
||||
It is possible to run tests using multiple cores by setting `-jN` in
|
||||
`TEST_PHP_ARGS`:
|
||||
|
||||
make TEST_PHP_ARGS=-j4 test
|
||||
|
||||
Shall run `make test` with a maximum of 4 concurrent jobs: Generally the maximum number of jobs should not exceed the number of cores available.
|
||||
Shall run `make test` with a maximum of 4 concurrent jobs: Generally the maximum
|
||||
number of jobs should not exceed the number of cores available.
|
||||
|
||||
The [qa.php.net](https://qa.php.net) site provides more detailed info about testing and quality assurance.
|
||||
The [qa.php.net](https://qa.php.net) site provides more detailed info about
|
||||
testing and quality assurance.
|
||||
|
||||
## Installing PHP built from source
|
||||
|
||||
@ -72,7 +78,8 @@ After a successful build (and test), PHP may be installed with:
|
||||
|
||||
make install
|
||||
|
||||
Depending on your permissions and prefix, `make install` may need super user permissions.
|
||||
Depending on your permissions and prefix, `make install` may need super user
|
||||
permissions.
|
||||
|
||||
## PHP extensions
|
||||
|
||||
|
@ -1,26 +1,23 @@
|
||||
# Input Filter Support in PHP 5
|
||||
# Input filter support in PHP
|
||||
|
||||
XSS (Cross Site Scripting) hacks are becoming more and more prevalent,
|
||||
and can be quite difficult to prevent. Whenever you accept user data
|
||||
and somehow display this data back to users, you are likely vulnerable
|
||||
to XSS hacks.
|
||||
XSS (Cross Site Scripting) hacks are becoming more and more prevalent, and can
|
||||
be quite difficult to prevent. Whenever you accept user data and somehow display
|
||||
this data back to users, you are likely vulnerable to XSS hacks.
|
||||
|
||||
The Input Filter support in PHP 5 is aimed at providing the framework
|
||||
through which a company-wide or site-wide security policy can be
|
||||
enforced. It is implemented as a SAPI hook and is called from the
|
||||
treat_data and post handler functions. To implement your own security
|
||||
policy you will need to write a standard PHP extension. There is also
|
||||
a powerful standard implementation in ext/filter that should suit most
|
||||
peoples' needs. However, if you want to implement your own security
|
||||
policy, read on.
|
||||
The Input Filter support in PHP is aimed at providing the framework through
|
||||
which a company-wide or site-wide security policy can be enforced. It is
|
||||
implemented as a SAPI hook and is called from the `treat_data` and post handler
|
||||
functions. To implement your own security policy you will need to write a
|
||||
standard PHP extension. There is also a powerful standard implementation in
|
||||
`ext/filter` that should suit most peoples' needs. However, if you want to
|
||||
implement your own security policy, read on.
|
||||
|
||||
A simple implementation might look like the following. This stores the
|
||||
original raw user data and adds a my_get_raw() function while the normal
|
||||
$_POST, $_GET and $_COOKIE arrays are only populated with stripped
|
||||
data. In this simple example all I am doing is calling strip_tags() on
|
||||
the data.
|
||||
A simple implementation might look like the following. This stores the original
|
||||
raw user data and adds a `my_get_raw()` function while the normal `$_POST`,
|
||||
`$_GET` and `$_COOKIE` arrays are only populated with stripped data. In this
|
||||
simple example all I am doing is calling `strip_tags()` on the data.
|
||||
|
||||
```
|
||||
```c
|
||||
ZEND_BEGIN_MODULE_GLOBALS(my_input_filter)
|
||||
zval *post_array;
|
||||
zval *get_array;
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Mailinglist Rules
|
||||
# Mailinglist rules
|
||||
|
||||
This is the first file you should be reading before doing any posts on PHP
|
||||
mailinglists. Following these rules is considered imperative to the success of
|
||||
@ -19,7 +19,6 @@ following some basic rules with regards to mailinglist usage will:
|
||||
|
||||
d. Increase the general level of good will on planet Earth.
|
||||
|
||||
|
||||
Having said that, here are the organizational rules:
|
||||
|
||||
1. Respect other people working on the project.
|
||||
@ -28,9 +27,9 @@ Having said that, here are the organizational rules:
|
||||
your post after a good breather or a good nights sleep.
|
||||
|
||||
3. Make sure you pick the right mailinglist for your posting. Please review
|
||||
the descriptions on the mailinglist overview page
|
||||
(http://www.php.net/mailing-lists.php). When in doubt ask a friend or
|
||||
someone you trust on IRC.
|
||||
the descriptions on the
|
||||
[mailinglist overview page](https://www.php.net/mailing-lists.php). When
|
||||
in doubt ask a friend or someone you trust on IRC.
|
||||
|
||||
4. Make sure you know what you are talking about. PHP is a very large project
|
||||
that strives to be very open. The flip side is that the core developers
|
||||
@ -70,7 +69,7 @@ The next few rules are more some general hints:
|
||||
new thread.
|
||||
|
||||
Finally, additional hints on how to behave inside the virtual community can be
|
||||
found in RFC 1855 (http://www.faqs.org/rfcs/rfc1855.html).
|
||||
found in [RFC 1855](http://www.faqs.org/rfcs/rfc1855.html).
|
||||
|
||||
Happy hacking,
|
||||
|
||||
|
@ -1,139 +1,136 @@
|
||||
API adjustment to the old output control code:
|
||||
# API adjustment to the old output control code
|
||||
|
||||
Everything now resides beneath the php_output namespace,
|
||||
and there's an API call for every output handler op.
|
||||
Everything now resides beneath the php_output namespace, and there's an API call
|
||||
for every output handler op.
|
||||
|
||||
Checking output control layers status:
|
||||
// Using OG()
|
||||
php_output_get_status();
|
||||
Checking output control layers status:
|
||||
// Using OG()
|
||||
php_output_get_status();
|
||||
|
||||
Starting the default output handler:
|
||||
// php_start_ob_buffer(NULL, 0, 1);
|
||||
php_output_start_default();
|
||||
Starting the default output handler:
|
||||
// php_start_ob_buffer(NULL, 0, 1);
|
||||
php_output_start_default();
|
||||
|
||||
Starting an user handler by zval:
|
||||
// php_start_ob_buffer(zhandler, chunk_size, erase);
|
||||
php_output_start_user(zhandler, chunk_size, flags);
|
||||
Starting an user handler by zval:
|
||||
// php_start_ob_buffer(zhandler, chunk_size, erase);
|
||||
php_output_start_user(zhandler, chunk_size, flags);
|
||||
|
||||
Starting an internal handler without context:
|
||||
// php_ob_set_internal_handler(my_php_output_handler_func_t, buffer_size, "output handler name", erase);
|
||||
php_output_start_internal(handler_name, handler_name_len, my_php_output_handler_func_t, chunk_size, flags);
|
||||
Starting an internal handler without context:
|
||||
// php_ob_set_internal_handler(my_php_output_handler_func_t, buffer_size, "output handler name", erase);
|
||||
php_output_start_internal(handler_name, handler_name_len, my_php_output_handler_func_t, chunk_size, flags);
|
||||
|
||||
Starting an internal handler with context:
|
||||
// not possible with old API
|
||||
php_output_handler *h;
|
||||
h = php_output_handler_create_internal(handler_name, handler_name_len, my_php_output_handler_context_func_t, chunk_size, flags);
|
||||
php_output_handler_set_context(h, my_context, my_context_dtor);
|
||||
php_output_handler_start(h);
|
||||
Starting an internal handler with context:
|
||||
// not possible with old API
|
||||
php_output_handler *h;
|
||||
h = php_output_handler_create_internal(handler_name, handler_name_len, my_php_output_handler_context_func_t, chunk_size, flags);
|
||||
php_output_handler_set_context(h, my_context, my_context_dtor);
|
||||
php_output_handler_start(h);
|
||||
|
||||
Testing whether a certain output handler has already been started:
|
||||
// php_ob_handler_used("output handler name");
|
||||
php_output_handler_started(handler_name, handler_name_len);
|
||||
Testing whether a certain output handler has already been started:
|
||||
// php_ob_handler_used("output handler name");
|
||||
php_output_handler_started(handler_name, handler_name_len);
|
||||
|
||||
Flushing one output buffer:
|
||||
// php_end_ob_buffer(1, 1);
|
||||
php_output_flush();
|
||||
Flushing one output buffer:
|
||||
// php_end_ob_buffer(1, 1);
|
||||
php_output_flush();
|
||||
|
||||
Flushing all output buffers:
|
||||
// not possible with old API
|
||||
php_output_flush_all();
|
||||
Flushing all output buffers:
|
||||
// not possible with old API
|
||||
php_output_flush_all();
|
||||
|
||||
Cleaning one output buffer:
|
||||
// php_ob_end_buffer(0, 1);
|
||||
php_output_clean();
|
||||
Cleaning one output buffer:
|
||||
// php_ob_end_buffer(0, 1);
|
||||
php_output_clean();
|
||||
|
||||
Cleaning all output buffers:
|
||||
// not possible with old API
|
||||
php_output_clean_all();
|
||||
Cleaning all output buffers:
|
||||
// not possible with old API
|
||||
php_output_clean_all();
|
||||
|
||||
Discarding one output buffer:
|
||||
// php_ob_end_buffer(0, 0);
|
||||
php_output_discard();
|
||||
Discarding one output buffer:
|
||||
// php_ob_end_buffer(0, 0);
|
||||
php_output_discard();
|
||||
|
||||
Discarding all output buffers:
|
||||
// php_ob_end_buffers(0);
|
||||
php_output_discard_all();
|
||||
Discarding all output buffers:
|
||||
// php_ob_end_buffers(0);
|
||||
php_output_discard_all();
|
||||
|
||||
Stopping (and dropping) one output buffer:
|
||||
// php_ob_end_buffer(1, 0)
|
||||
php_output_end();
|
||||
Stopping (and dropping) one output buffer:
|
||||
// php_ob_end_buffer(1, 0)
|
||||
php_output_end();
|
||||
|
||||
Stopping (and dropping) all output buffers:
|
||||
// php_ob_end_buffers(1, 0);
|
||||
php_output_end_all();
|
||||
Stopping (and dropping) all output buffers:
|
||||
// php_ob_end_buffers(1, 0);
|
||||
php_output_end_all();
|
||||
|
||||
Retrieving output buffers contents:
|
||||
// php_ob_get_buffer(zstring);
|
||||
php_output_get_contents(zstring);
|
||||
Retrieving output buffers contents:
|
||||
// php_ob_get_buffer(zstring);
|
||||
php_output_get_contents(zstring);
|
||||
|
||||
Retrieving output buffers length:
|
||||
// php_ob_get_length(zlength);
|
||||
php_output_get_length(zlength);
|
||||
Retrieving output buffers length:
|
||||
// php_ob_get_length(zlength);
|
||||
php_output_get_length(zlength);
|
||||
|
||||
Retrieving output buffering level:
|
||||
// OG(nesting_level);
|
||||
php_output_get_level();
|
||||
Retrieving output buffering level:
|
||||
// OG(nesting_level);
|
||||
php_output_get_level();
|
||||
|
||||
Issue a warning because of an output handler conflict:
|
||||
// php_ob_init_conflict("to be started handler name", "to be tested if already started handler name");
|
||||
php_output_handler_conflict(new_handler_name, new_handler_name_len, set_handler_name, set_handler_name_len);
|
||||
Issue a warning because of an output handler conflict:
|
||||
// php_ob_init_conflict("to be started handler name", "to be tested if already started handler name");
|
||||
php_output_handler_conflict(new_handler_name, new_handler_name_len, set_handler_name, set_handler_name_len);
|
||||
|
||||
Registering a conflict checking function, which will be checked prior starting the handler:
|
||||
// not possible with old API, unless hardcoding into output.c
|
||||
php_output_handler_conflict_register(handler_name, handler_name_len, my_php_output_handler_conflict_check_t);
|
||||
Registering a conflict checking function, which will be checked prior starting the handler:
|
||||
// not possible with old API, unless hardcoding into output.c
|
||||
php_output_handler_conflict_register(handler_name, handler_name_len, my_php_output_handler_conflict_check_t);
|
||||
|
||||
Registering a reverse conflict checking function, which will be checked prior starting the specified foreign handler:
|
||||
// not possible with old API
|
||||
php_output_handler_reverse_conflict_register(foreign_handler_name, foreign_handler_name_len, my_php_output_handler_conflict_check_t);
|
||||
Registering a reverse conflict checking function, which will be checked prior starting the specified foreign handler:
|
||||
// not possible with old API
|
||||
php_output_handler_reverse_conflict_register(foreign_handler_name, foreign_handler_name_len, my_php_output_handler_conflict_check_t);
|
||||
|
||||
Facilitating a context from within an output handler callable with ob_start():
|
||||
// not possible with old API
|
||||
php_output_handler_hook(PHP_OUTPUT_HANDLER_HOOK_GET_OPAQ, (void *) &custom_ctx_ptr_ptr);
|
||||
Facilitating a context from within an output handler callable with ob_start():
|
||||
// not possible with old API
|
||||
php_output_handler_hook(PHP_OUTPUT_HANDLER_HOOK_GET_OPAQ, (void *) &custom_ctx_ptr_ptr);
|
||||
|
||||
Disabling of the output handler by itself:
|
||||
//not possible with old API
|
||||
php_output_handler_hook(PHP_OUTPUT_HANDLER_HOOK_DISABLE, NULL);
|
||||
Disabling of the output handler by itself:
|
||||
//not possible with old API
|
||||
php_output_handler_hook(PHP_OUTPUT_HANDLER_HOOK_DISABLE, NULL);
|
||||
|
||||
Marking an output handler immutable by itself because of irreversibility of its operation:
|
||||
// not possible with old API
|
||||
php_output_handler_hook(PHP_OUTPUT_HANDLER_HOOK_IMMUTABLE, NULL);
|
||||
Marking an output handler immutable by itself because of irreversibility of its operation:
|
||||
// not possible with old API
|
||||
php_output_handler_hook(PHP_OUTPUT_HANDLER_HOOK_IMMUTABLE, NULL);
|
||||
|
||||
Restarting the output handler because of a CLEAN operation:
|
||||
// not possible with old API
|
||||
if (flags & PHP_OUTPUT_HANDLER_CLEAN) { ... }
|
||||
Restarting the output handler because of a CLEAN operation:
|
||||
// not possible with old API
|
||||
if (flags & PHP_OUTPUT_HANDLER_CLEAN) { ... }
|
||||
|
||||
Recognizing by the output handler itself if it gets discarded:
|
||||
// not possible with old API
|
||||
if ((flags & PHP_OUTPUT_HANDLER_CLEAN) && (flags & PHP_OUTPUT_HANDLER_FINAL)) { ... }
|
||||
Recognizing by the output handler itself if it gets discarded:
|
||||
// not possible with old API
|
||||
if ((flags & PHP_OUTPUT_HANDLER_CLEAN) && (flags & PHP_OUTPUT_HANDLER_FINAL)) { ... }
|
||||
|
||||
## Output handler hooks
|
||||
|
||||
Output handler hooks
|
||||
The output handler can change its abilities at runtime. Eg. the gz handler can
|
||||
remove the CLEANABLE and REMOVABLE bits when the first output has passed through it;
|
||||
or handlers implemented in C to be used with ob_start() can contain a non-global
|
||||
context:
|
||||
|
||||
The output handler can change its abilities at runtime. Eg. the gz handler can
|
||||
remove the CLEANABLE and REMOVABLE bits when the first output has passed through it;
|
||||
or handlers implemented in C to be used with ob_start() can contain a non-global
|
||||
context:
|
||||
PHP_OUTPUT_HANDLER_HOOK_GET_OPAQ
|
||||
pass a void*** pointer as second arg to receive the address of a pointer
|
||||
pointer to the opaque field of the output handler context
|
||||
PHP_OUTPUT_HANDLER_HOOK_GET_FLAGS
|
||||
pass a int* pointer as second arg to receive the flags set for the output handler
|
||||
PHP_OUTPUT_HANDLER_HOOK_GET_LEVEL
|
||||
pass a int* pointer as second arg to receive the level of this output handler
|
||||
(starts with 0)
|
||||
PHP_OUTPUT_HANDLER_HOOK_IMMUTABLE
|
||||
the second arg is ignored; marks the output handler to be neither cleanable
|
||||
nor removable
|
||||
PHP_OUTPUT_HANDLER_HOOK_DISABLE
|
||||
the second arg is ignored; marks the output handler as disabled
|
||||
PHP_OUTPUT_HANDLER_HOOK_GET_OPAQ
|
||||
pass a void*** pointer as second arg to receive the address of a pointer
|
||||
pointer to the opaque field of the output handler context
|
||||
PHP_OUTPUT_HANDLER_HOOK_GET_FLAGS
|
||||
pass a int* pointer as second arg to receive the flags set for the output handler
|
||||
PHP_OUTPUT_HANDLER_HOOK_GET_LEVEL
|
||||
pass a int* pointer as second arg to receive the level of this output handler
|
||||
(starts with 0)
|
||||
PHP_OUTPUT_HANDLER_HOOK_IMMUTABLE
|
||||
the second arg is ignored; marks the output handler to be neither cleanable
|
||||
nor removable
|
||||
PHP_OUTPUT_HANDLER_HOOK_DISABLE
|
||||
the second arg is ignored; marks the output handler as disabled
|
||||
|
||||
## Open questions
|
||||
|
||||
Open questions
|
||||
* Should the userland API be adjusted and unified?
|
||||
|
||||
Should the userland API be adjusted and unified?
|
||||
|
||||
Many bits of the manual (and very first implementation) do not comply
|
||||
with the behaviour of the current (to be obsoleted) code, thus should
|
||||
the manual or the behaviour be adjusted?
|
||||
|
||||
END
|
||||
Many bits of the manual (and very first implementation) do not comply with the
|
||||
behaviour of the current (to be obsoleted) code, thus should the manual or the
|
||||
behaviour be adjusted?
|
||||
|
@ -1,133 +1,140 @@
|
||||
Fast Parameter Parsing API
|
||||
==========================
|
||||
# Fast Parameter Parsing API
|
||||
|
||||
In PHP 7, a "Fast Parameter Parsing API" was introduced. See
|
||||
In PHP 7, a "Fast Parameter Parsing API" was introduced. See
|
||||
[RFC](https://wiki.php.net/rfc/fast_zpp).
|
||||
|
||||
https://wiki.php.net/rfc/fast_zpp
|
||||
This API uses inlining to improve applications performance compared with the
|
||||
`zend_parse_parameters()` function described below.
|
||||
|
||||
This API uses inlining to improve applications performance compared
|
||||
with the zend_parse_parameters() function described below.
|
||||
## Parameter parsing functions
|
||||
|
||||
Borrowing from Python's example, there is a set of functions that given the
|
||||
string of type specifiers, can parse the input parameters and store the results
|
||||
in the user specified variables. This avoids using `IS_*` checks and
|
||||
`convert_to_*` conversions. The functions also check for the appropriate number
|
||||
of parameters, and try to output meaningful error messages.
|
||||
|
||||
Parameter parsing functions
|
||||
===========================
|
||||
## Prototypes
|
||||
|
||||
Borrowing from Python's example, there is a set of functions that
|
||||
given the string of type specifiers, can parse the input parameters
|
||||
and store the results in the user specified variables. This avoids
|
||||
using IS_* checks and convert_to_* conversions. The functions also
|
||||
check for the appropriate number of parameters, and try to output
|
||||
meaningful error messages.
|
||||
|
||||
|
||||
Prototypes
|
||||
----------
|
||||
```c
|
||||
/* Implemented. */
|
||||
int zend_parse_parameters(int num_args, char *type_spec, ...);
|
||||
int zend_parse_parameters_ex(int flags, int num_args, char *type_spec, ...);
|
||||
```
|
||||
|
||||
The zend_parse_parameters() function takes the number of parameters
|
||||
passed to the extension function, the type specifier string, and the
|
||||
list of pointers to variables to store the results in. The _ex() version
|
||||
also takes 'flags' argument -- current only ZEND_PARSE_PARAMS_QUIET can
|
||||
be used as 'flags' to specify that the function should operate quietly
|
||||
and not output any error messages.
|
||||
The `zend_parse_parameters()` function takes the number of parameters passed to
|
||||
the extension function, the type specifier string, and the list of pointers to
|
||||
variables to store the results in. The _ex() version also takes 'flags' argument
|
||||
-- current only `ZEND_PARSE_PARAMS_QUIET` can be used as 'flags' to specify that
|
||||
the function should operate quietly and not output any error messages.
|
||||
|
||||
Both functions return SUCCESS or FAILURE depending on the result.
|
||||
Both functions return `SUCCESS` or `FAILURE` depending on the result.
|
||||
|
||||
The auto-conversions are performed as necessary. Arrays, objects, and
|
||||
resources cannot be auto-converted.
|
||||
The auto-conversions are performed as necessary. Arrays, objects, and resources
|
||||
cannot be auto-converted.
|
||||
|
||||
PHP 5.3 includes a new function (actually implemented as macro):
|
||||
|
||||
```c
|
||||
int zend_parse_parameters_none();
|
||||
```
|
||||
|
||||
This returns SUCCESS if no argument has been passed to the function,
|
||||
FAILURE otherwise.
|
||||
This returns `SUCCESS` if no argument has been passed to the function, `FAILURE`
|
||||
otherwise.
|
||||
|
||||
PHP 5.5 includes a new function:
|
||||
|
||||
```c
|
||||
int zend_parse_parameter(int flags, int arg_num, zval **arg, const char *spec, ...);
|
||||
```
|
||||
|
||||
This function behaves like zend_parse_parameters_ex() except that instead of
|
||||
This function behaves like `zend_parse_parameters_ex()` except that instead of
|
||||
reading the arguments from the stack, it receives a single zval to convert
|
||||
(passed with double indirection). The passed zval may be changed in place as
|
||||
part of the conversion process.
|
||||
|
||||
See also https://wiki.php.net/rfc/zpp_improv#expose_zend_parse_arg_as_zend_parse_parameter
|
||||
See also
|
||||
[Expose zend_parse_arg() as zend_parse_parameter()](https://wiki.php.net/rfc/zpp_improv#expose_zend_parse_arg_as_zend_parse_parameter).
|
||||
|
||||
## Type specifiers
|
||||
|
||||
Type specifiers
|
||||
---------------
|
||||
The following list shows the type specifier, its meaning and the parameter
|
||||
types that need to be passed by address. All passed parameters are set
|
||||
if the PHP parameter is non optional and untouched if optional and the
|
||||
parameter is not present. The only exception is O where the zend_class_entry*
|
||||
has to be provided on input and is used to verify the PHP parameter is an
|
||||
instance of that class.
|
||||
The following list shows the type specifier, its meaning and the parameter types
|
||||
that need to be passed by address. All passed parameters are set if the PHP
|
||||
parameter is non optional and untouched if optional and the parameter is not
|
||||
present. The only exception is O where the zend_class_entry* has to be provided
|
||||
on input and is used to verify the PHP parameter is an instance of that class.
|
||||
|
||||
a - array (zval*)
|
||||
A - array or object (zval*)
|
||||
b - boolean (zend_bool)
|
||||
C - class (zend_class_entry*)
|
||||
d - double (double)
|
||||
f - function or array containing php method call info (returned as
|
||||
zend_fcall_info and zend_fcall_info_cache)
|
||||
h - array (returned as HashTable*)
|
||||
H - array or HASH_OF(object) (returned as HashTable*)
|
||||
l - long (zend_long)
|
||||
L - long, limits out-of-range numbers to LONG_MAX/LONG_MIN (zend_long, ZEND_LONG_MAX/ZEND_LONG_MIN)
|
||||
o - object of any type (zval*)
|
||||
O - object of specific type given by class entry (zval*, zend_class_entry)
|
||||
p - valid path (string without null bytes in the middle) and its length (char*, size_t)
|
||||
P - valid path (string without null bytes in the middle) as zend_string (zend_string*)
|
||||
r - resource (zval*)
|
||||
s - string (with possible null bytes) and its length (char*, size_t)
|
||||
S - string (with possible null bytes) as zend_string (zend_string*)
|
||||
z - the actual zval (zval*)
|
||||
* - variable arguments list (0 or more)
|
||||
+ - variable arguments list (1 or more)
|
||||
```txt
|
||||
a - array (zval*)
|
||||
A - array or object (zval*)
|
||||
b - boolean (zend_bool)
|
||||
C - class (zend_class_entry*)
|
||||
d - double (double)
|
||||
f - function or array containing php method call info (returned as
|
||||
zend_fcall_info and zend_fcall_info_cache)
|
||||
h - array (returned as HashTable*)
|
||||
H - array or HASH_OF(object) (returned as HashTable*)
|
||||
l - long (zend_long)
|
||||
L - long, limits out-of-range numbers to LONG_MAX/LONG_MIN (zend_long, ZEND_LONG_MAX/ZEND_LONG_MIN)
|
||||
o - object of any type (zval*)
|
||||
O - object of specific type given by class entry (zval*, zend_class_entry)
|
||||
p - valid path (string without null bytes in the middle) and its length (char*, size_t)
|
||||
P - valid path (string without null bytes in the middle) as zend_string (zend_string*)
|
||||
r - resource (zval*)
|
||||
s - string (with possible null bytes) and its length (char*, size_t)
|
||||
S - string (with possible null bytes) as zend_string (zend_string*)
|
||||
z - the actual zval (zval*)
|
||||
* - variable arguments list (0 or more)
|
||||
+ - variable arguments list (1 or more)
|
||||
```
|
||||
|
||||
The following characters also have a meaning in the specifier string:
|
||||
| - indicates that the remaining parameters are optional, they
|
||||
should be initialized to default values by the extension since they
|
||||
will not be touched by the parsing function if they are not
|
||||
passed to it.
|
||||
/ - use SEPARATE_ZVAL_IF_NOT_REF() on the parameter it follows
|
||||
! - the parameter it follows can be of specified type or NULL. If NULL is
|
||||
passed and the output for such type is a pointer, then the output
|
||||
pointer is set to a native NULL pointer.
|
||||
For 'b', 'l' and 'd', an extra argument of type zend_bool* must be
|
||||
passed after the corresponding bool*, zend_long* or double* arguments,
|
||||
respectively. A non-zero value will be written to the zend_bool if a
|
||||
PHP NULL is passed.
|
||||
The following characters also have a meaning in the specifier string:
|
||||
|
||||
* `|` - indicates that the remaining parameters are optional, they should be
|
||||
initialized to default values by the extension since they will not be touched
|
||||
by the parsing function if they are not passed to it.
|
||||
* `/` - use SEPARATE_ZVAL_IF_NOT_REF() on the parameter it follows
|
||||
* `!` - the parameter it follows can be of specified type or NULL. If NULL is
|
||||
passed and the output for such type is a pointer, then the output pointer is
|
||||
set to a native NULL pointer. For 'b', 'l' and 'd', an extra argument of type
|
||||
zend_bool* must be passed after the corresponding bool*, zend_long* or
|
||||
double* arguments, respectively. A non-zero value will be written to the
|
||||
zend_bool if a PHP NULL is passed.
|
||||
|
||||
Note on 64bit compatibility
|
||||
---------------------------
|
||||
Please note that since version 7 PHP uses zend_long as integer type and
|
||||
zend_string with size_t as length, so make sure you pass zend_longs to "l"
|
||||
and size_t to strings length (i.e. for "s" you need to pass char * and size_t),
|
||||
not the other way round!
|
||||
## Note on 64bit compatibility
|
||||
|
||||
Please note that since version 7 PHP uses `zend_long` as integer type and
|
||||
`zend_string` with `size_t` as length, so make sure you pass `zend_long`s to "l"
|
||||
and `size_t` to strings length (i.e. for "s" you need to pass char `*` and
|
||||
`size_t`), not the other way round!
|
||||
|
||||
Both mistakes might cause memory corruptions and segfaults:
|
||||
1)
|
||||
char *str;
|
||||
long str_len; /* XXX THIS IS WRONG!! Use size_t instead. */
|
||||
zend_parse_parameters(ZEND_NUM_ARGS(), "s", &str, &str_len)
|
||||
|
||||
2)
|
||||
int num; /* XXX THIS IS WRONG!! Use zend_long instead. */
|
||||
zend_parse_parameters(ZEND_NUM_ARGS(), "l", &num)
|
||||
* 1
|
||||
|
||||
If you're in doubt, use check_parameters.php script to the parameters
|
||||
and their types (it can be found in ./scripts/dev/ directory of PHP sources):
|
||||
```c
|
||||
char *str;
|
||||
long str_len; /* XXX THIS IS WRONG!! Use size_t instead. */
|
||||
zend_parse_parameters(ZEND_NUM_ARGS(), "s", &str, &str_len)
|
||||
```
|
||||
|
||||
# php ./scripts/dev/check_parameters.php /path/to/your/sources/
|
||||
* 2
|
||||
|
||||
```c
|
||||
int num; /* XXX THIS IS WRONG!! Use zend_long instead. */
|
||||
zend_parse_parameters(ZEND_NUM_ARGS(), "l", &num)
|
||||
```
|
||||
|
||||
Examples
|
||||
--------
|
||||
If you're in doubt, use check_parameters.php script to the parameters and their
|
||||
types (it can be found in `./scripts/dev/` directory of PHP sources):
|
||||
|
||||
```bash
|
||||
php ./scripts/dev/check_parameters.php /path/to/your/sources/
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
```c
|
||||
/* Gets a long, a string and its length, and a zval */
|
||||
zend_long l;
|
||||
char *s;
|
||||
@ -138,7 +145,6 @@ if (zend_parse_parameters(ZEND_NUM_ARGS(), "lsz",
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Gets an object of class specified by my_ce, and an optional double. */
|
||||
zval *obj;
|
||||
double d = 0.5;
|
||||
@ -148,7 +154,6 @@ if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|d",
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Gets an object or null, and an array.
|
||||
If null is passed for object, obj will be set to NULL. */
|
||||
zval *obj;
|
||||
@ -158,7 +163,6 @@ if (zend_parse_parameters(ZEND_NUM_ARGS(), "o!a",
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Gets a separated array which can also be null. */
|
||||
zval *arr;
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/!",
|
||||
@ -171,7 +175,7 @@ zend_long l1, l2, l3;
|
||||
char *s;
|
||||
/*
|
||||
* The function expects a pointer to a size_t in this case, not a long
|
||||
* or any other type. If you specify a type which is larger
|
||||
* or any other type. If you specify a type which is larger
|
||||
* than a 'size_t', the upper bits might not be initialized
|
||||
* properly, leading to random crashes on platforms like
|
||||
* Tru64 or Linux/Alpha.
|
||||
@ -190,13 +194,11 @@ if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(),
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Function that accepts only varargs (0 or more) */
|
||||
|
||||
int i, num_varargs;
|
||||
zval *varargs = NULL;
|
||||
|
||||
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS(), "*", &varargs, &num_varargs) == FAILURE) {
|
||||
return;
|
||||
}
|
||||
@ -209,7 +211,6 @@ if (varargs) {
|
||||
efree(varargs);
|
||||
}
|
||||
|
||||
|
||||
/* Function that accepts a string, followed by varargs (1 or more) */
|
||||
|
||||
char *str;
|
||||
@ -243,3 +244,4 @@ for (i = 0; i < num_varargs; i++) {
|
||||
if (zend_parse_parameters_none() == FAILURE) {
|
||||
return;
|
||||
}
|
||||
```
|
||||
|
@ -1,84 +1,83 @@
|
||||
# HOW TO CREATE A SELF-CONTAINED PHP EXTENSION
|
||||
# How to create a self-contained PHP extension
|
||||
|
||||
A self-contained extension can be distributed independently of
|
||||
the PHP source. To create such an extension, two things are
|
||||
required:
|
||||
A self-contained extension can be distributed independently of the PHP source.
|
||||
To create such an extension, two things are required:
|
||||
|
||||
- Configuration file (config.m4)
|
||||
- Source code for your module
|
||||
* Configuration file (config.m4)
|
||||
* Source code for your module
|
||||
|
||||
We will describe now how to create these and how to put things
|
||||
together.
|
||||
We will describe now how to create these and how to put things together.
|
||||
|
||||
## PREPARING YOUR SYSTEM
|
||||
## Prepairing your system
|
||||
|
||||
While the result will run on any system, a developer's setup needs these
|
||||
tools:
|
||||
While the result will run on any system, a developer's setup needs these tools:
|
||||
|
||||
GNU autoconf
|
||||
GNU libtool
|
||||
GNU m4
|
||||
* GNU autoconf
|
||||
* GNU libtool
|
||||
* GNU m4
|
||||
|
||||
All of these are available from
|
||||
All of these are available from
|
||||
|
||||
ftp://ftp.gnu.org/pub/gnu/
|
||||
|
||||
## CONVERTING AN EXISTING EXTENSION
|
||||
## Converting an existing extension
|
||||
|
||||
Just to show you how easy it is to create a self-contained
|
||||
extension, we will convert an embedded extension into a
|
||||
self-contained one. Install PHP and execute the following
|
||||
commands.
|
||||
|
||||
$ mkdir /tmp/newext
|
||||
$ cd /tmp/newext
|
||||
|
||||
You now have an empty directory. We will copy the files from
|
||||
the mysql extension:
|
||||
|
||||
$ cp -rp php-4.0.X/ext/mysql/* .
|
||||
|
||||
It is time to finish the module. Run:
|
||||
|
||||
$ phpize
|
||||
|
||||
You can now ship the contents of the directory - the extension
|
||||
can live completely on its own.
|
||||
|
||||
The user instructions boil down to
|
||||
|
||||
$ ./configure \
|
||||
[--with-php-config=/path/to/php-config] \
|
||||
[--with-mysql=MYSQL-DIR]
|
||||
$ make install
|
||||
|
||||
The MySQL module will either use the embedded MySQL client
|
||||
library or the MySQL installation in MYSQL-DIR.
|
||||
|
||||
|
||||
## DEFINING THE NEW EXTENSION
|
||||
|
||||
Our demo extension is called "foobar".
|
||||
|
||||
It consists of two source files "foo.c" and "bar.c"
|
||||
(and any arbitrary amount of header files, but that is not
|
||||
important here).
|
||||
|
||||
The demo extension does not reference any external
|
||||
libraries (that is important, because the user does not
|
||||
need to specify anything).
|
||||
|
||||
|
||||
LTLIBRARY_SOURCES specifies the names of the sources files. You can
|
||||
name an arbitrary number of source files here.
|
||||
|
||||
## CREATING THE M4 CONFIGURATION FILE
|
||||
|
||||
The m4 configuration can perform additional checks. For a
|
||||
self-contained extension, you do not need more than a few
|
||||
macro calls.
|
||||
Just to show you how easy it is to create a self-contained extension, we will
|
||||
convert an embedded extension into a self-contained one. Install PHP and execute
|
||||
the following commands.
|
||||
|
||||
```bash
|
||||
mkdir /tmp/newext
|
||||
cd /tmp/newext
|
||||
```
|
||||
|
||||
You now have an empty directory. We will copy the files from the mysqli
|
||||
extension:
|
||||
|
||||
```bash
|
||||
cp -rp php-src/ext/mysqli/* .
|
||||
```
|
||||
|
||||
It is time to finish the module. Run:
|
||||
|
||||
```bash
|
||||
phpize
|
||||
```
|
||||
|
||||
You can now ship the contents of the directory - the extension can live
|
||||
completely on its own.
|
||||
|
||||
The user instructions boil down to
|
||||
|
||||
```bash
|
||||
./configure \
|
||||
[--with-php-config=/path/to/php-config] \
|
||||
[--with-mysqli=MYSQL-DIR]
|
||||
make install
|
||||
```
|
||||
|
||||
The MySQL module will either use the embedded MySQL client library or the MySQL
|
||||
installation in MYSQL-DIR.
|
||||
|
||||
## Defining the new extension
|
||||
|
||||
Our demo extension is called "foobar".
|
||||
|
||||
It consists of two source files `foo.c` and `bar.c` (and any arbitrary amount of
|
||||
header files, but that is not important here).
|
||||
|
||||
The demo extension does not reference any external libraries (that is important,
|
||||
because the user does not need to specify anything).
|
||||
|
||||
`LTLIBRARY_SOURCES` specifies the names of the sources files. You can name an
|
||||
arbitrary number of source files here.
|
||||
|
||||
## Creating the M4 configuration file
|
||||
|
||||
The m4 configuration can perform additional checks. For a self-contained
|
||||
extension, you do not need more than a few macro calls.
|
||||
|
||||
```m4
|
||||
PHP_ARG_ENABLE([foobar],
|
||||
[whether to enable foobar],
|
||||
[AS_HELP_STRING([--enable-foobar],
|
||||
@ -89,81 +88,86 @@ if test "$PHP_FOOBAR" != "no"; then
|
||||
fi
|
||||
```
|
||||
|
||||
PHP_ARG_ENABLE will automatically set the correct variables, so
|
||||
that the extension will be enabled by PHP_NEW_EXTENSION in shared mode.
|
||||
`PHP_ARG_ENABLE` will automatically set the correct variables, so that the
|
||||
extension will be enabled by `PHP_NEW_EXTENSION` in shared mode.
|
||||
|
||||
The first argument of PHP_NEW_EXTENSION describes the name of the
|
||||
extension. The second names the source-code files. The third passes
|
||||
$ext_shared which is set by PHP_ARG_ENABLE/WITH to PHP_NEW_EXTENSION.
|
||||
The first argument of `PHP_NEW_EXTENSION` describes the name of the extension.
|
||||
The second names the source-code files. The third passes `$ext_shared` which is
|
||||
set by `PHP_ARG_ENABLE/WITH` to `PHP_NEW_EXTENSION`.
|
||||
|
||||
Please use always PHP_ARG_ENABLE or PHP_ARG_WITH. Even if you do not
|
||||
plan to distribute your module with PHP, these facilities allow you
|
||||
to integrate your module easily into the main PHP module framework.
|
||||
Please use always `PHP_ARG_ENABLE` or `PHP_ARG_WITH`. Even if you do not plan to
|
||||
distribute your module with PHP, these facilities allow you to integrate your
|
||||
module easily into the main PHP module framework.
|
||||
|
||||
## CREATING SOURCE FILES
|
||||
## Create source files
|
||||
|
||||
ext_skel can be of great help when creating the common code for all modules
|
||||
in PHP for you and also writing basic function definitions and C code for
|
||||
handling arguments passed to your functions. See `./ext/ext_skel.php --help`
|
||||
for further information.
|
||||
`ext_skel.php` can be of great help when creating the common code for all
|
||||
modules in PHP for you and also writing basic function definitions and C code
|
||||
for handling arguments passed to your functions. See `./ext/ext_skel.php --help`
|
||||
for further information.
|
||||
|
||||
As for the rest, you are currently alone here. There are a lot of existing
|
||||
modules, use a simple module as a starting point and add your own code.
|
||||
As for the rest, you are currently alone here. There are a lot of existing
|
||||
modules, use a simple module as a starting point and add your own code.
|
||||
|
||||
## Creating the self-contained extension
|
||||
|
||||
## CREATING THE SELF-CONTAINED EXTENSION
|
||||
Put `config.m4` and the source files into one directory. Then, run `phpize`
|
||||
(this is installed during `make install` by PHP).
|
||||
|
||||
Put config.m4 and the source files into one directory. Then, run phpize
|
||||
(this is installed during make install by PHP 4.0).
|
||||
For example, if you configured PHP with `--prefix=/php`, you would run
|
||||
|
||||
For example, if you configured PHP with --prefix=/php, you would run
|
||||
|
||||
$ /php/bin/phpize
|
||||
|
||||
This will automatically copy the necessary build files and create
|
||||
configure from your config.m4.
|
||||
|
||||
And that's it. You now have a self-contained extension.
|
||||
|
||||
## INSTALLING A SELF-CONTAINED EXTENSION
|
||||
|
||||
An extension can be installed by running:
|
||||
|
||||
$ ./configure \
|
||||
[--with-php-config=/path/to/php-config]
|
||||
$ make install
|
||||
|
||||
## ADDING SHARED MODULE SUPPORT TO A MODULE
|
||||
|
||||
In order to be useful, a self-contained extension must be loadable
|
||||
as a shared module. I will explain now how you can add shared module
|
||||
support to an existing module called foo.
|
||||
|
||||
1. In config.m4, use PHP_ARG_WITH/PHP_ARG_ENABLE. Then you will
|
||||
automatically be able to use --with-foo=shared[,..] or
|
||||
--enable-foo=shared[,..].
|
||||
|
||||
2. In config.m4, use PHP_NEW_EXTENSION(foo,.., $ext_shared) to enable
|
||||
building the extension.
|
||||
|
||||
3. Add the following lines to your C source file:
|
||||
|
||||
```
|
||||
#ifdef COMPILE_DL_FOO
|
||||
ZEND_GET_MODULE(foo)
|
||||
#endif
|
||||
```bash
|
||||
/php/bin/phpize
|
||||
```
|
||||
|
||||
## PECL SITE CONFORMITY
|
||||
This will automatically copy the necessary build files and create configure from
|
||||
your `config.m4`.
|
||||
|
||||
If you plan to release an extension to the PECL website, there are several
|
||||
points to be regarded.
|
||||
And that's it. You now have a self-contained extension.
|
||||
|
||||
1. Add LICENSE or COPYING to the package.xml
|
||||
## Installing a self-contained extension
|
||||
|
||||
2. The following should be defined in one of the extension header files
|
||||
An extension can be installed by running:
|
||||
|
||||
#define PHP_FOO_VERSION "1.2.3"
|
||||
```bash
|
||||
./configure \
|
||||
[--with-php-config=/path/to/php-config]
|
||||
make install
|
||||
```
|
||||
|
||||
This macros has to be used within your foo_module_entry to indicate the
|
||||
extension version.
|
||||
## Adding shared module support to a module
|
||||
|
||||
In order to be useful, a self-contained extension must be loadable as a shared
|
||||
module. The following will explain now how you can add shared module support to
|
||||
an existing module called `foo`.
|
||||
|
||||
1. In `config.m4`, use `PHP_ARG_WITH/PHP_ARG_ENABLE`. Then you will
|
||||
automatically be able to use `--with-foo=shared[,..]` or
|
||||
`--enable-foo=shared[,..]`.
|
||||
|
||||
2. In `config.m4`, use `PHP_NEW_EXTENSION(foo,.., $ext_shared)` to enable
|
||||
building the extension.
|
||||
|
||||
3. Add the following lines to your C source file:
|
||||
|
||||
```c
|
||||
#ifdef COMPILE_DL_FOO
|
||||
ZEND_GET_MODULE(foo)
|
||||
#endif
|
||||
```
|
||||
|
||||
## PECL site conformity
|
||||
|
||||
If you plan to release an extension to the PECL website, there are several
|
||||
points to be regarded.
|
||||
|
||||
1. Add `LICENSE` or `COPYING` to the `package.xml`
|
||||
|
||||
2. The following should be defined in one of the extension header files
|
||||
|
||||
```c
|
||||
#define PHP_FOO_VERSION "1.2.3"
|
||||
```
|
||||
|
||||
This macros has to be used within your foo_module_entry to indicate the
|
||||
extension version.
|
||||
|
361
docs/streams.md
361
docs/streams.md
@ -1,29 +1,26 @@
|
||||
An Overview of the PHP Streams abstraction
|
||||
==========================================
|
||||
# An overview of the PHP streams abstraction
|
||||
|
||||
WARNING: some prototypes in this file are out of date.
|
||||
The information contained here is being integrated into
|
||||
the PHP manual - stay tuned...
|
||||
|
||||
Please send comments to: Wez Furlong <wez@thebrainroom.com>
|
||||
## Why streams?
|
||||
|
||||
Why Streams?
|
||||
============
|
||||
You may have noticed a shed-load of issock parameters flying around the PHP
|
||||
code; we don't want them - they are ugly and cumbersome and force you to
|
||||
special case sockets and files every time you need to work with a "user-level"
|
||||
PHP file pointer.
|
||||
code; we don't want them - they are ugly and cumbersome and force you to special
|
||||
case sockets and files every time you need to work with a "user-level" PHP file
|
||||
pointer.
|
||||
|
||||
Streams take care of that and present the PHP extension coder with an ANSI
|
||||
stdio-alike API that looks much nicer and can be extended to support non file
|
||||
based data sources.
|
||||
|
||||
Using Streams
|
||||
=============
|
||||
Streams use a php_stream* parameter just as ANSI stdio (fread etc.) use a
|
||||
FILE* parameter.
|
||||
## Using streams
|
||||
|
||||
Streams use a `php_stream*` parameter just as ANSI stdio (fread etc.) use a
|
||||
`FILE*` parameter.
|
||||
|
||||
The main functions are:
|
||||
|
||||
```c
|
||||
PHPAPI size_t php_stream_read(php_stream * stream, char * buf, size_t count);
|
||||
PHPAPI size_t php_stream_write(php_stream * stream, const char * buf, size_t
|
||||
count);
|
||||
@ -37,210 +34,234 @@ PHPAPI int php_stream_flush(php_stream * stream);
|
||||
PHPAPI int php_stream_seek(php_stream * stream, off_t offset, int whence);
|
||||
PHPAPI off_t php_stream_tell(php_stream * stream);
|
||||
PHPAPI int php_stream_lock(php_stream * stream, int mode);
|
||||
```
|
||||
|
||||
These (should) behave in the same way as the ANSI stdio functions with similar
|
||||
names: fread, fwrite, fprintf, feof, fgetc, fgets, fclose, fflush, fseek, ftell, flock.
|
||||
names: fread, fwrite, fprintf, feof, fgetc, fgets, fclose, fflush, fseek, ftell,
|
||||
flock.
|
||||
|
||||
## Opening streams
|
||||
|
||||
Opening Streams
|
||||
===============
|
||||
In most cases, you should use this API:
|
||||
|
||||
```c
|
||||
PHPAPI php_stream *php_stream_open_wrapper(const char *path, const char *mode,
|
||||
int options, char **opened_path);
|
||||
```
|
||||
|
||||
Where:
|
||||
path is the file or resource to open.
|
||||
mode is the stdio compatible mode eg: "wb", "rb" etc.
|
||||
options is a combination of the following values:
|
||||
IGNORE_PATH (default) - don't use include path to search for the file
|
||||
USE_PATH - use include path to search for the file
|
||||
IGNORE_URL - do not use plugin wrappers
|
||||
REPORT_ERRORS - show errors in a standard format if something
|
||||
goes wrong.
|
||||
STREAM_MUST_SEEK - If you really need to be able to seek the stream
|
||||
and don't need to be able to write to the original
|
||||
file/URL, use this option to arrange for the stream
|
||||
to be copied (if needed) into a stream that can
|
||||
be seek()ed.
|
||||
|
||||
opened_path is used to return the path of the actual file opened,
|
||||
but if you used STREAM_MUST_SEEK, may not be valid. You are
|
||||
responsible for efree()ing opened_path. opened_path may be (and usually
|
||||
is) NULL.
|
||||
* `path` is the file or resource to open.
|
||||
* `mode` is the stdio compatible mode eg: "wb", "rb" etc.
|
||||
* `options` is a combination of the following values:
|
||||
* `IGNORE_PATH` (default) - don't use include path to search for the file
|
||||
* `USE_PATH` - use include path to search for the file
|
||||
* `IGNORE_URL` - do not use plugin wrappers
|
||||
* `REPORT_ERRORS` - show errors in a standard format if something goes wrong.
|
||||
* `STREAM_MUST_SEEK` - If you really need to be able to seek the stream and
|
||||
don't need to be able to write to the original file/URL, use this option to
|
||||
arrange for the stream to be copied (if needed) into a stream that can be
|
||||
seek()ed.
|
||||
* `opened_path` is used to return the path of the actual file opened, but if you
|
||||
used `STREAM_MUST_SEEK`, may not be valid. You are responsible for
|
||||
`efree()ing` `opened_path`.
|
||||
* `opened_path` may be (and usually is) `NULL`.
|
||||
|
||||
If you need to open a specific stream, or convert standard resources into
|
||||
streams there are a range of functions to do this defined in php_streams.h.
|
||||
A brief list of the most commonly used functions:
|
||||
streams there are a range of functions to do this defined in `php_streams.h`. A
|
||||
brief list of the most commonly used functions:
|
||||
|
||||
```c
|
||||
PHPAPI php_stream *php_stream_fopen_from_file(FILE *file, const char *mode);
|
||||
Convert a FILE * into a stream.
|
||||
/* Convert a FILE * into a stream. */
|
||||
|
||||
PHPAPI php_stream *php_stream_fopen_tmpfile(void);
|
||||
Open a FILE * with tmpfile() and convert into a stream.
|
||||
/* Open a FILE * with tmpfile() and convert into a stream. */
|
||||
|
||||
PHPAPI php_stream *php_stream_fopen_temporary_file(const char *dir,
|
||||
const char *pfx, char **opened_path);
|
||||
Generate a temporary file name and open it.
|
||||
/* Generate a temporary file name and open it. */
|
||||
```
|
||||
|
||||
There are some network enabled relatives in php_network.h:
|
||||
There are some network enabled relatives in `php_network.h`:
|
||||
|
||||
```c
|
||||
PHPAPI php_stream *php_stream_sock_open_from_socket(int socket, int persistent);
|
||||
Convert a socket into a stream.
|
||||
/* Convert a socket into a stream. */
|
||||
|
||||
PHPAPI php_stream *php_stream_sock_open_host(const char *host, unsigned short port,
|
||||
int socktype, int timeout, int persistent);
|
||||
Open a connection to a host and return a stream.
|
||||
int socktype, int timeout, int persistent);
|
||||
/* Open a connection to a host and return a stream. */
|
||||
|
||||
PHPAPI php_stream *php_stream_sock_open_unix(const char *path, int persistent,
|
||||
struct timeval *timeout);
|
||||
Open a UNIX domain socket.
|
||||
/* Open a UNIX domain socket. */
|
||||
```
|
||||
|
||||
## Stream utilities
|
||||
|
||||
Stream Utilities
|
||||
================
|
||||
|
||||
If you need to copy some data from one stream to another, you will be please
|
||||
to know that the streams API provides a standard way to do this:
|
||||
If you need to copy some data from one stream to another, you will be please to
|
||||
know that the streams API provides a standard way to do this:
|
||||
|
||||
```c
|
||||
PHPAPI size_t php_stream_copy_to_stream(php_stream *src,
|
||||
php_stream *dest, size_t maxlen);
|
||||
```
|
||||
|
||||
If you want to copy all remaining data from the src stream, pass
|
||||
PHP_STREAM_COPY_ALL as the maxlen parameter, otherwise maxlen indicates the
|
||||
number of bytes to copy.
|
||||
This function will try to use mmap where available to make the copying more
|
||||
efficient.
|
||||
`PHP_STREAM_COPY_ALL` as the maxlen parameter, otherwise maxlen indicates the
|
||||
number of bytes to copy. This function will try to use mmap where available to
|
||||
make the copying more efficient.
|
||||
|
||||
If you want to read the contents of a stream into an allocated memory buffer,
|
||||
you should use:
|
||||
|
||||
```c
|
||||
PHPAPI size_t php_stream_copy_to_mem(php_stream *src, char **buf,
|
||||
size_t maxlen, int persistent);
|
||||
```
|
||||
|
||||
This function will set buf to the address of the buffer that it allocated,
|
||||
which will be maxlen bytes in length, or will be the entire length of the
|
||||
data remaining on the stream if you set maxlen to PHP_STREAM_COPY_ALL.
|
||||
The buffer is allocated using pemalloc(); you need to call pefree() to
|
||||
release the memory when you are done.
|
||||
As with copy_to_stream, this function will try use mmap where it can.
|
||||
This function will set buf to the address of the buffer that it allocated, which
|
||||
will be maxlen bytes in length, or will be the entire length of the data
|
||||
remaining on the stream if you set maxlen to `PHP_STREAM_COPY_ALL`. The buffer
|
||||
is allocated using `pemalloc()`. You need to call `pefree()` to release the
|
||||
memory when you are done. As with `copy_to_stream`, this function will try use
|
||||
mmap where it can.
|
||||
|
||||
If you have an existing stream and need to be able to seek() it, you
|
||||
can use this function to copy the contents into a new stream that can
|
||||
be seek()ed:
|
||||
If you have an existing stream and need to be able to `seek()` it, you can use
|
||||
this function to copy the contents into a new stream that can be `seek()ed`:
|
||||
|
||||
```c
|
||||
PHPAPI int php_stream_make_seekable(php_stream *origstream, php_stream **newstream);
|
||||
```
|
||||
|
||||
It returns one of the following values:
|
||||
#define PHP_STREAM_UNCHANGED 0 /* orig stream was seekable anyway */
|
||||
#define PHP_STREAM_RELEASED 1 /* newstream should be used; origstream is no longer valid */
|
||||
#define PHP_STREAM_FAILED 2 /* an error occurred while attempting conversion */
|
||||
#define PHP_STREAM_CRITICAL 3 /* an error occurred; origstream is in an unknown state; you should close origstream */
|
||||
|
||||
make_seekable will always set newstream to be the stream that is valid
|
||||
if the function succeeds.
|
||||
When you have finished, remember to close the stream.
|
||||
```c
|
||||
#define PHP_STREAM_UNCHANGED 0 /* orig stream was seekable anyway */
|
||||
#define PHP_STREAM_RELEASED 1 /* newstream should be used; origstream is no longer valid */
|
||||
#define PHP_STREAM_FAILED 2 /* an error occurred while attempting conversion */
|
||||
#define PHP_STREAM_CRITICAL 3 /* an error occurred; origstream is in an unknown state; you should close origstream */
|
||||
```
|
||||
|
||||
NOTE: If you only need to seek forward, there is no need to call this
|
||||
function, as the php_stream_seek can emulate forward seeking when the
|
||||
whence parameter is SEEK_CUR.
|
||||
`make_seekable` will always set newstream to be the stream that is valid if the
|
||||
function succeeds. When you have finished, remember to close the stream.
|
||||
|
||||
NOTE: Writing to the stream may not affect the original source, so it
|
||||
only makes sense to use this for read-only use.
|
||||
NOTE: If you only need to seek forward, there is no need to call this function,
|
||||
as the `php_stream_seek` can emulate forward seeking when the whence parameter
|
||||
is `SEEK_CUR`.
|
||||
|
||||
NOTE: If the origstream is network based, this function will block
|
||||
until the whole contents have been downloaded.
|
||||
NOTE: Writing to the stream may not affect the original source, so it only makes
|
||||
sense to use this for read-only use.
|
||||
|
||||
NOTE: Never call this function with an origstream that is referenced
|
||||
as a resource! It will close the origstream on success, and this
|
||||
can lead to a crash when the resource is later used/released.
|
||||
NOTE: If the origstream is network based, this function will block until the
|
||||
whole contents have been downloaded.
|
||||
|
||||
NOTE: Never call this function with an origstream that is referenced as a
|
||||
resource! It will close the origstream on success, and this can lead to a crash
|
||||
when the resource is later used/released.
|
||||
|
||||
NOTE: If you are opening a stream and need it to be seekable, use the
|
||||
STREAM_MUST_SEEK option to php_stream_open_wrapper();
|
||||
`STREAM_MUST_SEEK` option to php_stream_open_wrapper();
|
||||
|
||||
```c
|
||||
PHPAPI int php_stream_supports_lock(php_stream * stream);
|
||||
```
|
||||
|
||||
This function will return either 1 (success) or 0 (failure) indicating whether or
|
||||
not a lock can be set on this stream. Typically you can only set locks on stdio streams.
|
||||
This function will return either 1 (success) or 0 (failure) indicating whether
|
||||
or not a lock can be set on this stream. Typically you can only set locks on
|
||||
stdio streams.
|
||||
|
||||
Casting Streams
|
||||
===============
|
||||
What if your extension needs to access the FILE* of a user level file pointer?
|
||||
You need to "cast" the stream into a FILE*, and this is how you do it:
|
||||
## Casting streams
|
||||
|
||||
What if your extension needs to access the `FILE*` of a user level file pointer?
|
||||
You need to "cast" the stream into a `FILE*`, and this is how you do it:
|
||||
|
||||
```c
|
||||
FILE * fp;
|
||||
php_stream * stream; /* already opened */
|
||||
|
||||
if (php_stream_cast(stream, PHP_STREAM_AS_STDIO, (void*)&fp, REPORT_ERRORS) == FAILURE) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
```
|
||||
|
||||
The prototype is:
|
||||
|
||||
PHPAPI int php_stream_cast(php_stream * stream, int castas, void ** ret, int
|
||||
show_err);
|
||||
```c
|
||||
PHPAPI int php_stream_cast(php_stream * stream, int castas, void ** ret, int show_err);
|
||||
```
|
||||
|
||||
The show_err parameter, if non-zero, will cause the function to display an
|
||||
appropriate error message of type E_WARNING if the cast fails.
|
||||
The `show_err` parameter, if non-zero, will cause the function to display an
|
||||
appropriate error message of type `E_WARNING` if the cast fails.
|
||||
|
||||
castas can be one of the following values:
|
||||
`castas` can be one of the following values:
|
||||
|
||||
```txt
|
||||
PHP_STREAM_AS_STDIO - a stdio FILE*
|
||||
PHP_STREAM_AS_FD - a generic file descriptor
|
||||
PHP_STREAM_AS_SOCKETD - a socket descriptor
|
||||
```
|
||||
|
||||
If you ask a socket stream for a FILE*, the abstraction will use fdopen to
|
||||
create it for you. Be warned that doing so may cause buffered data to be lost
|
||||
If you ask a socket stream for a `FILE*`, the abstraction will use fdopen to
|
||||
create it for you. Be warned that doing so may cause buffered data to be lost
|
||||
if you mix ANSI stdio calls on the FILE* with php stream calls on the stream.
|
||||
|
||||
If your system has the fopencookie function, php streams can synthesize a
|
||||
FILE* on top of any stream, which is useful for SSL sockets, memory based
|
||||
`FILE*` on top of any stream, which is useful for SSL sockets, memory based
|
||||
streams, data base streams etc. etc.
|
||||
|
||||
In situations where this is not desirable, you should query the stream
|
||||
to see if it naturally supports FILE *. You can use this code snippet
|
||||
for this purpose:
|
||||
In situations where this is not desirable, you should query the stream to see if
|
||||
it naturally supports `FILE *`. You can use this code snippet for this purpose:
|
||||
|
||||
if (php_stream_is(stream, PHP_STREAM_IS_STDIO)) {
|
||||
/* can safely cast to FILE* with no adverse side effects */
|
||||
}
|
||||
```c
|
||||
if (php_stream_is(stream, PHP_STREAM_IS_STDIO)) {
|
||||
/* can safely cast to FILE* with no adverse side effects */
|
||||
}
|
||||
```
|
||||
|
||||
You can use:
|
||||
|
||||
```c
|
||||
PHPAPI int php_stream_can_cast(php_stream * stream, int castas)
|
||||
```
|
||||
|
||||
to find out if a stream can be cast, without actually performing the cast, so
|
||||
to check if a stream is a socket you might use:
|
||||
to find out if a stream can be cast, without actually performing the cast, so to
|
||||
check if a stream is a socket you might use:
|
||||
|
||||
```c
|
||||
if (php_stream_can_cast(stream, PHP_STREAM_AS_SOCKETD) == SUCCESS) {
|
||||
/* it can be a socket */
|
||||
}
|
||||
```
|
||||
|
||||
Please note the difference between php_stream_is and php_stream_can_cast;
|
||||
stream_is tells you if the stream is a particular type of stream, whereas
|
||||
can_cast tells you if the stream can be forced into the form you request.
|
||||
The former doesn't change anything, while the later *might* change some
|
||||
state in the stream.
|
||||
Please note the difference between `php_stream_is` and `php_stream_can_cast`;
|
||||
`stream_is` tells you if the stream is a particular type of stream, whereas
|
||||
`can_cast` tells you if the stream can be forced into the form you request. The
|
||||
former doesn't change anything, while the later *might* change some state in the
|
||||
stream.
|
||||
|
||||
Stream Internals
|
||||
================
|
||||
## Stream internals
|
||||
|
||||
There are two main structures associated with a stream - the php_stream
|
||||
There are two main structures associated with a stream - the `php_stream`
|
||||
itself, which holds some state information (and possibly a buffer) and a
|
||||
php_stream_ops structure, which holds the "virtual method table" for the
|
||||
`php_stream_ops` structure, which holds the "virtual method table" for the
|
||||
underlying implementation.
|
||||
|
||||
The php_streams ops struct consists of pointers to methods that implement
|
||||
read, write, close, flush, seek, gets and cast operations. Of these, an
|
||||
implementation need only implement write, read, close and flush. The gets
|
||||
method is intended to be used for streams if there is an underlying method
|
||||
that can efficiently behave as fgets. The ops struct also contains a label
|
||||
for the implementation that will be used when printing error messages - the
|
||||
stdio implementation has a label of "STDIO" for example.
|
||||
The `php_streams` ops struct consists of pointers to methods that implement
|
||||
read, write, close, flush, seek, gets and cast operations. Of these, an
|
||||
implementation need only implement write, read, close and flush. The gets method
|
||||
is intended to be used for streams if there is an underlying method that can
|
||||
efficiently behave as fgets. The ops struct also contains a label for the
|
||||
implementation that will be used when printing error messages - the stdio
|
||||
implementation has a label of `STDIO` for example.
|
||||
|
||||
The idea is that a stream implementation defines a php_stream_ops struct, and
|
||||
associates it with a php_stream using php_stream_alloc.
|
||||
The idea is that a stream implementation defines a `php_stream_ops` struct, and
|
||||
associates it with a `php_stream` using `php_stream_alloc`.
|
||||
|
||||
As an example, the php_stream_fopen() function looks like this:
|
||||
As an example, the `php_stream_fopen()` function looks like this:
|
||||
|
||||
```c
|
||||
PHPAPI php_stream * php_stream_fopen(const char * filename, const char * mode)
|
||||
{
|
||||
FILE * fp = fopen(filename, mode);
|
||||
@ -255,62 +276,64 @@ PHPAPI php_stream * php_stream_fopen(const char * filename, const char * mode)
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
```
|
||||
|
||||
php_stream_stdio_ops is a php_stream_ops structure that can be used to handle
|
||||
FILE* based streams.
|
||||
`php_stream_stdio_ops` is a `php_stream_ops` structure that can be used to
|
||||
handle `FILE*` based streams.
|
||||
|
||||
A socket based stream would use code similar to that above to create a stream
|
||||
to be passed back to fopen_wrapper (or it's yet to be implemented successor).
|
||||
A socket based stream would use code similar to that above to create a stream to
|
||||
be passed back to fopen_wrapper (or it's yet to be implemented successor).
|
||||
|
||||
The prototype for php_stream_alloc is this:
|
||||
|
||||
```c
|
||||
PHPAPI php_stream * php_stream_alloc(php_stream_ops * ops, void * abstract,
|
||||
size_t bufsize, int persistent, const char * mode)
|
||||
```
|
||||
|
||||
ops is a pointer to the implementation,
|
||||
abstract holds implementation specific data that is relevant to this instance
|
||||
of the stream,
|
||||
bufsize is the size of the buffer to use - if 0, then buffering at the stream
|
||||
level will be disabled (recommended for underlying sources that implement
|
||||
their own buffering - such a FILE*),
|
||||
persistent controls how the memory is to be allocated - persistently so that
|
||||
it lasts across requests, or non-persistently so that it is freed at the end
|
||||
of a request (it uses pemalloc),
|
||||
mode is the stdio-like mode of operation - php streams places no real meaning
|
||||
in the mode parameter, except that it checks for a 'w' in the string when
|
||||
attempting to write (this may change).
|
||||
* `ops` is a pointer to the implementation,
|
||||
* `abstract` holds implementation specific data that is relevant to this
|
||||
instance of the stream,
|
||||
* `bufsize` is the size of the buffer to use - if 0, then buffering at the
|
||||
stream
|
||||
* `level` will be disabled (recommended for underlying sources that implement
|
||||
their own buffering - such a `FILE*`)
|
||||
* `persistent` controls how the memory is to be allocated - persistently so that
|
||||
it lasts across requests, or non-persistently so that it is freed at the end
|
||||
of a request (it uses pemalloc),
|
||||
* `mode` is the stdio-like mode of operation - php streams places no real
|
||||
meaning in the mode parameter, except that it checks for a `w` in the string
|
||||
when attempting to write (this may change).
|
||||
|
||||
The mode parameter is passed on to fdopen/fopencookie when the stream is cast
|
||||
into a FILE*, so it should be compatible with the mode parameter of fopen().
|
||||
The mode parameter is passed on to `fdopen/fopencookie` when the stream is cast
|
||||
into a `FILE*`, so it should be compatible with the mode parameter of `fopen()`.
|
||||
|
||||
Writing your own stream implementation
|
||||
======================================
|
||||
## Writing your own stream implementation
|
||||
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
RULE #1: when writing your own streams: make sure you have configured PHP with
|
||||
--enable-debug.
|
||||
I've taken some great pains to hook into the Zend memory manager to help track
|
||||
down allocation problems. It will also help you spot incorrect use of the
|
||||
STREAMS_DC, STREAMS_CC and the semi-private STREAMS_REL_CC macros for function
|
||||
definitions.
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
* **RULE #1**: when writing your own streams: make sure you have configured PHP
|
||||
with `--enable-debug`.
|
||||
Some great great pains have been taken to hook into the Zend memory manager to
|
||||
help track down allocation problems. It will also help you spot incorrect use
|
||||
of the STREAMS_DC, STREAMS_CC and the semi-private STREAMS_REL_CC macros for
|
||||
function definitions.
|
||||
|
||||
RULE #2: Please use the stdio stream as a reference; it will help you
|
||||
understand the semantics of the stream operations, and it will always
|
||||
be more up to date than these docs :-)
|
||||
* RULE #2: Please use the stdio stream as a reference; it will help you
|
||||
understand the semantics of the stream operations, and it will always be more
|
||||
up to date than these docs :-)
|
||||
|
||||
First, you need to figure out what data you need to associate with the
|
||||
php_stream. For example, you might need a pointer to some memory for memory
|
||||
`php_stream`. For example, you might need a pointer to some memory for memory
|
||||
based streams, or if you were making a stream to read data from an RDBMS like
|
||||
MySQL, you might want to store the connection and rowset handles.
|
||||
|
||||
The stream has a field called abstract that you can use to hold this data.
|
||||
If you need to store more than a single field of data, define a structure to
|
||||
hold it, allocate it (use pemalloc with the persistent flag set
|
||||
appropriately), and use the abstract pointer to refer to it.
|
||||
The stream has a field called abstract that you can use to hold this data. If
|
||||
you need to store more than a single field of data, define a structure to hold
|
||||
it, allocate it (use pemalloc with the persistent flag set appropriately), and
|
||||
use the abstract pointer to refer to it.
|
||||
|
||||
For structured state you might have this:
|
||||
|
||||
```c
|
||||
struct my_state {
|
||||
MYSQL conn;
|
||||
MYSQL_RES * result;
|
||||
@ -327,6 +350,7 @@ state->result = mysql_use_result(&state->conn);
|
||||
stream = php_stream_alloc(&my_ops, state, 0, persistent, "r");
|
||||
|
||||
/* now stream->abstract == state */
|
||||
```
|
||||
|
||||
Once you have that part figured out, you can write your implementation and
|
||||
define the your own php_stream_ops struct (we called it my_ops in the above
|
||||
@ -334,6 +358,7 @@ example).
|
||||
|
||||
For example, for reading from this weird MySQL stream:
|
||||
|
||||
```c
|
||||
static size_t php_mysqlop_read(php_stream * stream, char * buf, size_t count)
|
||||
{
|
||||
struct my_state * state = (struct my_state*)stream->abstract;
|
||||
@ -354,23 +379,27 @@ static size_t php_mysqlop_read(php_stream * stream, char * buf, size_t count)
|
||||
such as coping with a buffer size too small to hold the data,
|
||||
so I won't even go in to how to do that here */
|
||||
}
|
||||
```
|
||||
|
||||
Implement the other operations - remember that write, read, close and flush
|
||||
are all mandatory. The rest are optional. Declare your stream ops struct:
|
||||
Implement the other operations - remember that write, read, close and flush are
|
||||
all mandatory. The rest are optional. Declare your stream ops struct:
|
||||
|
||||
```c
|
||||
php_stream_ops my_ops = {
|
||||
php_mysqlop_write, php_mysqlop_read, php_mysqlop_close,
|
||||
php_mysqlop_flush, NULL, NULL, NULL,
|
||||
"Strange MySQL example"
|
||||
}
|
||||
```
|
||||
|
||||
That's it!
|
||||
|
||||
Take a look at the STDIO implementation in streams.c for more information
|
||||
about how these operations work.
|
||||
Take a look at the STDIO implementation in streams.c for more information about
|
||||
how these operations work.
|
||||
|
||||
The main thing to remember is that in your close operation you need to release
|
||||
and free the resources you allocated for the abstract field. In the case of
|
||||
the example above, you need to use mysql_free_result on the rowset, close the
|
||||
connection and then use pefree to dispose of the struct you allocated.
|
||||
You may read the stream->persistent field to determine if your struct was
|
||||
allocated in persistent mode or not.
|
||||
and free the resources you allocated for the abstract field. In the case of the
|
||||
example above, you need to use mysql_free_result on the rowset, close the
|
||||
connection and then use pefree to dispose of the struct you allocated. You may
|
||||
read the stream->persistent field to determine if your struct was allocated in
|
||||
persistent mode or not.
|
||||
|
@ -1,113 +1,121 @@
|
||||
# PHP Build System V5 Overview
|
||||
# PHP build system V5 overview
|
||||
|
||||
- supports Makefile.ins during transition phase
|
||||
- not-really-portable Makefile includes have been eliminated
|
||||
- supports separate build directories without VPATH by using
|
||||
explicit rules only
|
||||
- does not waste disk-space/CPU-time for building temporary libraries
|
||||
=> especially noticeable on slower systems
|
||||
- slow recursive make replaced with one global Makefile
|
||||
- eases integration of proper dependencies
|
||||
- adds PHP_DEFINE(what[, value]) which creates a single include-file
|
||||
per what. This will allow more fine-grained dependencies.
|
||||
- abandoning the "one library per directory" concept
|
||||
- improved integration of the CLI
|
||||
- several new targets
|
||||
build-modules: builds and copies dynamic modules into modules/
|
||||
install-cli: installs the CLI only, so that the install-sapi
|
||||
target does only what its name says
|
||||
- finally abandoned automake
|
||||
- changed some configure-time constructs to run at buildconf-time
|
||||
- upgraded shtool to 1.5.4
|
||||
- removed $(moduledir) (use EXTENSION_DIR)
|
||||
* supports Makefile.ins during transition phase
|
||||
* not-really-portable Makefile includes have been eliminated
|
||||
* supports separate build directories without VPATH by using explicit rules only
|
||||
* does not waste disk-space/CPU-time for building temporary libraries =>
|
||||
especially noticeable on slower systems
|
||||
* slow recursive make replaced with one global Makefile
|
||||
* eases integration of proper dependencies
|
||||
* adds PHP_DEFINE(what[, value]) which creates a single include-file per what.
|
||||
This will allow more fine-grained dependencies.
|
||||
* abandoning the "one library per directory" concept
|
||||
* improved integration of the CLI
|
||||
* several new targets:
|
||||
* `build-modules`: builds and copies dynamic modules into `modules/`
|
||||
* `install-cli`: installs the CLI only, so that the install-sapi target does
|
||||
only what its name says
|
||||
* finally abandoned automake
|
||||
* changed some configure-time constructs to run at buildconf-time
|
||||
* upgraded shtool to 1.5.4
|
||||
* removed `$(moduledir)` (use `EXTENSION_DIR`)
|
||||
|
||||
## The Reason For a New System
|
||||
## The reason for a new system
|
||||
|
||||
It became more and more apparent that there is a severe need
|
||||
for addressing the portability concerns and improving the chance
|
||||
that your build is correct (how often have you been told to
|
||||
"make clean"? When this is done, you won't need to anymore).
|
||||
It became more and more apparent that there is a severe need for addressing the
|
||||
portability concerns and improving the chance that your build is correct (how
|
||||
often have you been told to `make clean`? When this is done, you won't need to
|
||||
anymore).
|
||||
|
||||
## If You Build PHP on a Unix System
|
||||
## If you build PHP on a Unix system
|
||||
|
||||
You, as a user of PHP, will notice no changes. Of course, the build
|
||||
system will be faster, look better and work smarter.
|
||||
You, as a user of PHP, will notice no changes. Of course, the build system will
|
||||
be faster, look better and work smarter.
|
||||
|
||||
## If You Are Developing PHP
|
||||
## If you are developing PHP
|
||||
|
||||
### Extension developers:
|
||||
### Extension developers
|
||||
|
||||
Makefile.ins are abandoned. The files which are to be compiled
|
||||
are specified in the config.m4 now using the following macro:
|
||||
Makefile.ins are abandoned. The files which are to be compiled are specified in
|
||||
the `config.m4` now using the following macro:
|
||||
|
||||
```m4
|
||||
PHP_NEW_EXTENSION(foo, foo.c bar.c baz.cpp, $ext_shared)
|
||||
```
|
||||
|
||||
E.g. this enables the extension foo which consists of three source-code
|
||||
modules, two in C and one in C++. And, depending on the user's wishes,
|
||||
the extension will even be built as a dynamic module.
|
||||
E.g. this enables the extension foo which consists of three source-code modules,
|
||||
two in C and one in C++. And, depending on the user's wishes, the extension will
|
||||
even be built as a dynamic module.
|
||||
|
||||
The full syntax:
|
||||
|
||||
```m4
|
||||
PHP_NEW_EXTENSION(extname, sources [, shared [,sapi_class[, extra-cflags]]])
|
||||
```
|
||||
|
||||
Please have a look at acinclude.m4 for the gory details and meanings
|
||||
of the other parameters.
|
||||
Please have a look at `acinclude.m4` for the gory details and meanings of the
|
||||
other parameters.
|
||||
|
||||
And that's basically it for the extension side.
|
||||
|
||||
If you previously built sub-libraries for this module, add
|
||||
the source-code files here as well. If you need to specify
|
||||
separate include directories, do it this way:
|
||||
If you previously built sub-libraries for this module, add the source-code files
|
||||
here as well. If you need to specify separate include directories, do it this
|
||||
way:
|
||||
|
||||
```m4
|
||||
PHP_NEW_EXTENSION(foo, foo.c mylib/bar.c mylib/gregor.c,,,-I@ext_srcdir@/lib)
|
||||
```
|
||||
|
||||
E.g. this builds the three files which are located relative to the
|
||||
extension source directory and compiles all three files with the
|
||||
special include directive (@ext_srcdir@ is automatically replaced).
|
||||
E.g. this builds the three files which are located relative to the extension
|
||||
source directory and compiles all three files with the special include directive
|
||||
(`@ext_srcdir@` is automatically replaced).
|
||||
|
||||
Now, you need to tell the build system that you want to build files
|
||||
in a directory called $ext_builddir/lib:
|
||||
Now, you need to tell the build system that you want to build files in a
|
||||
directory called `$ext_builddir/lib`:
|
||||
|
||||
```m4
|
||||
PHP_ADD_BUILD_DIR($ext_builddir/lib)
|
||||
```
|
||||
|
||||
Make sure to call this after PHP_NEW_EXTENSION, because $ext_builddir
|
||||
is only set by the latter.
|
||||
Make sure to call this after `PHP_NEW_EXTENSION`, because `$ext_builddir` is
|
||||
only set by the latter.
|
||||
|
||||
If you have a complex extension, you might to need add special
|
||||
Make rules. You can do this by calling PHP_ADD_MAKEFILE_FRAGMENT
|
||||
in your config.m4 after PHP_NEW_EXTENSION.
|
||||
If you have a complex extension, you might to need add special Make rules. You
|
||||
can do this by calling `PHP_ADD_MAKEFILE_FRAGMENT` in your `config.m4` after
|
||||
`PHP_NEW_EXTENSION`.
|
||||
|
||||
This will read a file in the source-dir of your extension called
|
||||
Makefile.frag. In this file, $(builddir) and $(srcdir) will be
|
||||
replaced by the values which are correct for your extension
|
||||
and which are again determined by the PHP_NEW_EXTENSION macro.
|
||||
`Makefile.frag`. In this file, `$(builddir)` and `$(srcdir)` will be replaced by
|
||||
the values which are correct for your extension and which are again determined
|
||||
by the `PHP_NEW_EXTENSION` macro.
|
||||
|
||||
Make sure to prefix *all* relative paths correctly with either
|
||||
$(builddir) or $(srcdir). Because the build system does not
|
||||
change the working directory anymore, we must use either
|
||||
absolute paths or relative ones to the top build-directory.
|
||||
Correct prefixing ensures that.
|
||||
Make sure to prefix *all* relative paths correctly with either `$(builddir)` or
|
||||
`$(srcdir)`. Because the build system does not change the working directory
|
||||
anymore, we must use either absolute paths or relative ones to the top
|
||||
build-directory. Correct prefixing ensures that.
|
||||
|
||||
### SAPI developers:
|
||||
### SAPI developers
|
||||
|
||||
Instead of using PHP_SAPI=foo/PHP_BUILD_XYZ, you will need to type
|
||||
Instead of using `PHP_SAPI=foo/PHP_BUILD_XYZ`, you will need to type
|
||||
|
||||
```m4
|
||||
PHP_SELECT_SAPI(name, type, sources.c)
|
||||
```
|
||||
|
||||
I.e. specify the source-code files as above and also pass the
|
||||
information regarding how PHP is supposed to be built (shared
|
||||
module, program, etc).
|
||||
I.e. specify the source-code files as above and also pass the information
|
||||
regarding how PHP is supposed to be built (shared module, program, etc).
|
||||
|
||||
For example for APXS:
|
||||
|
||||
```m4
|
||||
PHP_SELECT_SAPI(apache, shared, sapi_apache.c mod_php7.c php_apache.c)
|
||||
```
|
||||
|
||||
## General info
|
||||
|
||||
The foundation for the new system is the flexible handling of
|
||||
sources and their contexts. With the help of macros you
|
||||
can define special flags for each source-file, where it is
|
||||
located, in which target context it can work, etc.
|
||||
The foundation for the new system is the flexible handling of sources and their
|
||||
contexts. With the help of macros you can define special flags for each
|
||||
source-file, where it is located, in which target context it can work, etc.
|
||||
|
||||
Have a look at the well documented macros
|
||||
PHP_ADD_SOURCES(_X) in acinclude.m4.
|
||||
Have a look at the well documented macros `PHP_ADD_SOURCES(_X)` in
|
||||
`acinclude.m4`.
|
||||
|
@ -1,6 +1,9 @@
|
||||
# FFI PHP extension (Foreign Function Interface)
|
||||
|
||||
FFI PHP extension provides a simple way to call native functions, access native variables and create/access data structures defined in C language. The API of the extension is very simple and demonstrated by the following example and its output.
|
||||
FFI PHP extension provides a simple way to call native functions, access native
|
||||
variables and create/access data structures defined in C language. The API of
|
||||
the extension is very simple and demonstrated by the following example and its
|
||||
output.
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -22,7 +25,7 @@ $libc = FFI::cdef("
|
||||
int tz_dsttime;
|
||||
};
|
||||
|
||||
int gettimeofday(struct timeval *tv, struct timezone *tz);
|
||||
int gettimeofday(struct timeval *tv, struct timezone *tz);
|
||||
", "libc.so.6");
|
||||
|
||||
$libc->printf("Hello World from %s!\n", "PHP");
|
||||
@ -36,7 +39,7 @@ var_dump($tv->tv_sec, $tv->tv_usec, $tz);
|
||||
?>
|
||||
```
|
||||
|
||||
```
|
||||
```txt
|
||||
Hello World from PHP!
|
||||
string(135) "/usr/lib64/qt-3.3/bin:/usr/lib64/ccache:/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/home/dmitry/.local/bin:/home/dmitry/bin"
|
||||
int(1523617815)
|
||||
@ -50,13 +53,22 @@ object(FFI\CData:<struct>)#3 (2) {
|
||||
}
|
||||
```
|
||||
|
||||
FFI::cdef() takes two arguments (both are optional). The first one is a collection of C declarations and the second is DSO library. All variables and functions defined by first arguments are bound to corresponding native symbols in DSO library and then may be accessed as FFI object methods and properties. C types of argument, return value and variables are automatically converted to/from PHP types (if possible). Otherwise, they are wrapped in a special CData proxy object and may be accessed by elements.
|
||||
`FFI::cdef()` takes two arguments (both are optional). The first one is a
|
||||
collection of C declarations and the second is DSO library. All variables and
|
||||
functions defined by first arguments are bound to corresponding native symbols
|
||||
in DSO library and then may be accessed as FFI object methods and properties. C
|
||||
types of argument, return value and variables are automatically converted
|
||||
to/from PHP types (if possible). Otherwise, they are wrapped in a special CData
|
||||
proxy object and may be accessed by elements.
|
||||
|
||||
In some cases (e.g. passing C structure by pointer) we may need to create a real C data structures. This is possible using FFF::new() method. It takes a C type definition and may reuse C types and tags defined by FFI::cdef().
|
||||
In some cases (e.g. passing C structure by pointer) we may need to create a real
|
||||
C data structures. This is possible using `FFF::new()` method. It takes a C type
|
||||
definition and may reuse C types and tags defined by `FFI::cdef()`.
|
||||
|
||||
It's also possible to use FFI::new() as a static method to create arbitrary C data structures.
|
||||
It's also possible to use `FFI::new()` as a static method to create arbitrary C
|
||||
data structures.
|
||||
|
||||
``` php
|
||||
```php
|
||||
<?php
|
||||
$p = FFI::new("struct {int x,y;} [2]");
|
||||
$p[0]->x = 5;
|
||||
@ -64,7 +76,7 @@ $p[1]->y = 10;
|
||||
var_dump($p);
|
||||
```
|
||||
|
||||
```
|
||||
```txt
|
||||
object(FFI\CData:<struct>[2])#1 (2) {
|
||||
[0]=>
|
||||
object(FFI\CData:<struct>)#2 (2) {
|
||||
@ -83,132 +95,169 @@ object(FFI\CData:<struct>[2])#1 (2) {
|
||||
}
|
||||
```
|
||||
|
||||
### API Reference
|
||||
## API reference
|
||||
|
||||
##### function FFI::cdef([string $cdef = "" [, string $lib = null]]): FFI
|
||||
### function FFI::cdef([string $cdef = "" [, string $lib = null]]): FFI
|
||||
|
||||
##### Call Native Functions
|
||||
#### Call native functions
|
||||
|
||||
All functions defined in FFI::cdef() may be called as methods of the created FFI object.
|
||||
All functions defined in `FFI::cdef()` may be called as methods of the created
|
||||
FFI object.
|
||||
|
||||
```php
|
||||
$libc = FFI::cdef("const char * getenv(const char *);", "libc.so.6");
|
||||
var_dump($libc->getenv("PATH"));
|
||||
```
|
||||
|
||||
##### Read/Write Values of Native Variables
|
||||
#### Read/write values of native variables
|
||||
|
||||
All functions defined in FFI::cdef() may be accessed as properties of the created FFI object.
|
||||
All functions defined in `FFI::cdef()` may be accessed as properties of the
|
||||
created FFI object.
|
||||
|
||||
```php
|
||||
$libc = FFI::cdef("extern int errno;", "libc.so.6");
|
||||
var_dump($libc->errno);
|
||||
```
|
||||
|
||||
##### function FFI::type(string $type): FFI\CType
|
||||
### function FFI::type(string $type): FFI\CType
|
||||
|
||||
This function creates and returns a **FFI\CType** object, representng type of the given C type declaration string.
|
||||
This function creates and returns a `FFI\CType` object, representng type of
|
||||
the given C type declaration string.
|
||||
|
||||
FFI::type() may be called statically and use only predefined types, or as a method of previously created FFI object. In last case the first argument may reuse all type and tag names defined in FFI::cdef().
|
||||
`FFI::type()` may be called statically and use only predefined types, or as a
|
||||
method of previously created FFI object. In last case the first argument may
|
||||
reuse all type and tag names defined in `FFI::cdef()`.
|
||||
|
||||
### function FFI::typeof(FFI\CData $type): FFI\CType
|
||||
|
||||
##### function FFI::typeof(FFI\CData $type): FFI\CType
|
||||
This function returns a `FFI\CType` object, representing the type of the given
|
||||
`FFI\CData` object.
|
||||
|
||||
This function returns a **FFI\CType** object, representing the type of the given **FFI\CData** object.
|
||||
### static function FFI::arrayType(FFI\CType $type, array $dims): FFI\CType
|
||||
|
||||
##### static function FFI::arrayType(FFI\CType $type, array $dims): FFI\CType
|
||||
Constructs a new C array type with elements of $type and dimensions specified by
|
||||
$dims.
|
||||
|
||||
Constructs a new C array type with elements of $type and dimensions specified by $dims.
|
||||
### function FFI::new(mixed $type [, bool $own = true [, bool $persistent = false]]): FFI\CData
|
||||
|
||||
##### function FFI::new(mixed $type [, bool $own = true [, bool $persistent = false]]): FFI\CData
|
||||
|
||||
This function may be used to create a native data structure. The first argument is a C type definition. It may be a **string** or **FFI\CType** object. The following example creates two dimensional array of integers.
|
||||
This function may be used to create a native data structure. The first argument
|
||||
is a C type definition. It may be a `string` or `FFI\CType` object. The
|
||||
following example creates two dimensional array of integers.
|
||||
|
||||
```php
|
||||
$p = FFI::new("int[2][2]");
|
||||
var_dump($p, FFI::sizeof($p));
|
||||
```
|
||||
|
||||
FFI::new() may be called statically and use only predefined types, or as a method of previously created FFI object. In last case the first argument may reuse all type and tag names defined in FFI::cdef().
|
||||
`FFI::new()` may be called statically and use only predefined types, or as a
|
||||
method of previously created FFI object. In last case the first argument may
|
||||
reuse all type and tag names defined in `FFI::cdef()`.
|
||||
|
||||
By default **FFI::new()** creates "owned" native data structures, that live together with corresponding PHP object, reusing PHP reference-counting and GC. However, in some cases it may be necessary to manually control the life time of the data structure. In this case, the PHP ownership on the corresponding data, may be manually changed, using **false** as the second optianal argument. Later, not-owned CData should be manually deallocated using **FFI::free()**.
|
||||
By default `FFI::new()` creates "owned" native data structures, that live
|
||||
together with corresponding PHP object, reusing PHP reference-counting and GC.
|
||||
However, in some cases it may be necessary to manually control the life time of
|
||||
the data structure. In this case, the PHP ownership on the corresponding data,
|
||||
may be manually changed, using `false` as the second optianal argument. Later,
|
||||
not-owned CData should be manually deallocated using `FFI::free()`.
|
||||
|
||||
Using the optional $persistent argument it's possible to allocate C objects in persistent memory, through malloc(), otherwise memory is allocated in PHP request heap, through emalloc().
|
||||
Using the optional $persistent argument it's possible to allocate C objects in
|
||||
persistent memory, through `malloc()`, otherwise memory is allocated in PHP
|
||||
request heap, through `emalloc()`.
|
||||
|
||||
##### static function FFI::free(FFI\CData $cdata): void
|
||||
### static function FFI::free(FFI\CData $cdata): void
|
||||
|
||||
manually removes previously created "not-owned" data structure.
|
||||
Manually removes previously created "not-owned" data structure.
|
||||
|
||||
##### Read/Write Elements of Native Arrays
|
||||
#### Read/write elements of native arrays
|
||||
|
||||
Elements of native array may be accessed in the same way as elements of PHP arrays. Of course, native arrays support only integer indexes. It's not possible to check element existence using isset() or empty() and remove element using unset(). Native arrays work fine with "foreach" statement.
|
||||
Elements of native array may be accessed in the same way as elements of PHP
|
||||
arrays. Of course, native arrays support only integer indexes. It's not possible
|
||||
to check element existence using `isset()` or `empty()` and remove element using
|
||||
`unset()`. Native arrays work fine with "foreach" statement.
|
||||
|
||||
```php
|
||||
$p = FFI::new("int[2]");
|
||||
$p[0] = 1;
|
||||
$p[1] = 2;
|
||||
foreach ($p as $key => $val) {
|
||||
echo "$key => $val\n";
|
||||
echo "$key => $val\n";
|
||||
}
|
||||
```
|
||||
|
||||
##### Read/Write Fields of Native "struct" or "union"
|
||||
#### Read/write fields of native "struct" or "union"
|
||||
|
||||
Fields of native struct/union may be accessed in the same way as properties of PHP objects. It's not possible to check filed existence using isset() or empty(), remove them using unset(), and iterate using "foreach" statement.
|
||||
Fields of native struct/union may be accessed in the same way as properties of
|
||||
PHP objects. It's not possible to check filed existence using `isset()` or
|
||||
`empty()`, remove them using `unset()`, and iterate using "foreach" statement.
|
||||
|
||||
```php
|
||||
$pp = FFI::new("struct {int x,y;}[2]");
|
||||
foreach($pp as $n => &$p) {
|
||||
$p->x = $p->y = $n;
|
||||
$p->x = $p->y = $n;
|
||||
}
|
||||
var_dump($pp);
|
||||
```
|
||||
|
||||
##### Pointer arithmetic
|
||||
#### Pointer arithmetic
|
||||
|
||||
CData pointer values may be incremented/decremented by a number. The result is a pointer of the same type moved on given offset.
|
||||
CData pointer values may be incremented/decremented by a number. The result is a
|
||||
pointer of the same type moved on given offset.
|
||||
|
||||
Two pointers to the same type may be subtracted and return difference (similar to C).
|
||||
Two pointers to the same type may be subtracted and return difference (similar
|
||||
to C).
|
||||
|
||||
##### static function FFI::sizeof(mixed $cdata_or_ctype): int
|
||||
### static function FFI::sizeof(mixed $cdata_or_ctype): int
|
||||
|
||||
returns size of C data type of the given **FFI\CData** or **FFI\CType**.
|
||||
Returns size of C data type of the given `FFI\CData` or `FFI\CType`.
|
||||
|
||||
##### static function FFI::alignof(mixed $cdata_or_ctype): int
|
||||
### static function FFI::alignof(mixed $cdata_or_ctype): int
|
||||
|
||||
returns size of C data type of the given **FFI\CData** or **FFI\CType**.
|
||||
Returns size of C data type of the given `FFI\CData` or `FFI\CType`.
|
||||
|
||||
##### static function FFI::memcpy(FFI\CData $dst, mixed $src, int $size): void
|
||||
### static function FFI::memcpy(FFI\CData $dst, mixed $src, int $size): void
|
||||
|
||||
copies $size bytes from memory area $src to memory area $dst. $src may be any native data structure (**FFI\CData**) or PHP **string**.
|
||||
Copies $size bytes from memory area $src to memory area $dst. $src may be any
|
||||
native data structure (`FFI\CData`) or PHP `string`.
|
||||
|
||||
##### static function FFI::memcmp(mixed $src1, mixed $src2, int $size): int
|
||||
### static function FFI::memcmp(mixed $src1, mixed $src2, int $size): int
|
||||
|
||||
compares $size bytes from memory area $src1 and $dst2. $src1 and $src2 may be any native data structures (**FFI\CData**) or PHP **string**s.
|
||||
Compares $size bytes from memory area `$src1` and `$dst2`. `$src1` and `$src2`
|
||||
may be any native data structures (`FFI\CData`) or PHP `string`s.
|
||||
|
||||
##### static function FFI::memset(FFI\CData $dst, int $c, int $size): void
|
||||
### static function FFI::memset(FFI\CData $dst, int $c, int $size): void
|
||||
|
||||
fills the $size bytes of the memory area pointed to by $dst with the constant byte $c
|
||||
Fills the $size bytes of the memory area pointed to by `$dst` with the constant
|
||||
byte `$c`.
|
||||
|
||||
##### static function FFI::string(FFI\CData $src [, int $size]): string
|
||||
### static function FFI::string(FFI\CData $src [, int $size]): string
|
||||
|
||||
creates a PHP string from $size bytes of memory area pointed by $src. If size is omitted, $src must be zero terminated array of C chars.
|
||||
Creates a PHP string from `$size` bytes of memory area pointed by `$src`. If
|
||||
size is omitted, $src must be zero terminated array of C chars.
|
||||
|
||||
##### function FFI::cast(mixed $type, FFI\CData $cdata): FFI\CData
|
||||
### function FFI::cast(mixed $type, FFI\CData $cdata): FFI\CData
|
||||
|
||||
Casts given $cdata to another C type, specified by C declaration **string** or **FFI\CType** object.
|
||||
Casts given $cdata to another C type, specified by C declaration `string` or
|
||||
`FFI\CType` object.
|
||||
|
||||
This function may be called statically and use only predefined types, or as a method of previously created FFI object. In last case the first argument may reuse all type and tag names defined in FFI::cdef().
|
||||
This function may be called statically and use only predefined types, or as a
|
||||
method of previously created FFI object. In last case the first argument may
|
||||
reuse all type and tag names defined in `FFI::cdef()`.
|
||||
|
||||
##### static function addr(FFI\CData $cdata): FFI\CData;
|
||||
### static function addr(FFI\CData $cdata): FFI\CData
|
||||
|
||||
Returns C pointer to the given C data structure. The pointer is not "owned" and won't be free. Anyway, this is a potentially unsafe operation, because the life-time of the returned pointer may be longer than life-time of the source object, and this may cause dangling pointer dereference (like in regular C).
|
||||
Returns C pointer to the given C data structure. The pointer is not "owned" and
|
||||
won't be free. Anyway, this is a potentially unsafe operation, because the
|
||||
life-time of the returned pointer may be longer than life-time of the source
|
||||
object, and this may cause dangling pointer dereference (like in regular C).
|
||||
|
||||
##### static function load(string $filename): FFI;
|
||||
### static function load(string $filename): FFI
|
||||
|
||||
Instead of embedding of a long C definition into PHP string, and creating FFI through FFI::cdef(), it's possible to separate it into a C header file. Note, that C preprocessor directives (e.g. #define or #ifdef) are not supported. And only a couple of special macros may be used especially for FFI.
|
||||
Instead of embedding of a long C definition into PHP string, and creating FFI
|
||||
through `FFI::cdef()`, it's possible to separate it into a C header file. Note,
|
||||
that C preprocessor directives (e.g. `#define` or `#ifdef`) are not supported.
|
||||
And only a couple of special macros may be used especially for FFI.
|
||||
|
||||
``` C
|
||||
```c
|
||||
#define FFI_LIB "libc.so.6"
|
||||
|
||||
int printf(const char *format, ...);
|
||||
@ -216,41 +265,54 @@ int printf(const char *format, ...);
|
||||
|
||||
Here, FFI_LIB specifies, that the given library should be loaded.
|
||||
|
||||
``` php
|
||||
```php
|
||||
$ffi = FFI::load(__DIR__ . "/printf.h");
|
||||
$ffi->printf("Hello world!\n");
|
||||
|
||||
```
|
||||
|
||||
##### static function scope(string $name): FFI;
|
||||
### static function scope(string $name): FFI
|
||||
|
||||
FFI definition parsing and shared library loading may take significant time. It's not useful to do it on each HTTP request in WEB environment. However, it's possible to pre-load FFI definitions and libraries at php startup, and instantiate FFI objects when necessary. Header files may be extended with **FFI_SCOPE** define (default pre-loading scope is "C"). This name is going to be used as **FFI::scope()** argument. It's possible to pre-load few files into a single scope.
|
||||
FFI definition parsing and shared library loading may take significant time.
|
||||
It's not useful to do it on each HTTP request in WEB environment. However, it's
|
||||
possible to pre-load FFI definitions and libraries at php startup, and
|
||||
instantiate FFI objects when necessary. Header files may be extended with
|
||||
`FFI_SCOPE` define (default pre-loading scope is "C"). This name is going to
|
||||
be used as `FFI::scope()` argument. It's possible to pre-load few files into a
|
||||
single scope.
|
||||
|
||||
``` C
|
||||
```c
|
||||
#define FFI_LIB "libc.so.6"
|
||||
#define FFI_SCOPE "libc"
|
||||
|
||||
int printf(const char *format, ...);
|
||||
```
|
||||
|
||||
These files are loaded through the same **FFI::load()** load function, executed from file loaded by **opcache.preload** php.ini directive.
|
||||
These files are loaded through the same `FFI::load()` load function, executed
|
||||
from file loaded by `opcache.preload` php.ini directive.
|
||||
|
||||
``` ini
|
||||
```ini
|
||||
ffi.preload=/etc/php/ffi/printf.h
|
||||
```
|
||||
|
||||
Finally, **FFI::scope()** instantiate an **FFI** object, that implements all C definition from the given scope.
|
||||
Finally, `FFI::scope()` instantiates an `FFI` object, that implements all C
|
||||
definitions from the given scope.
|
||||
|
||||
``` php
|
||||
```php
|
||||
$ffi = FFI::scope("libc");
|
||||
$ffi->printf("Hello world!\n");
|
||||
```
|
||||
|
||||
##### Owned and Not-Owned CData
|
||||
## Owned and not-owned CData
|
||||
|
||||
FFI extension uses two kind of native C data structures. "Owned" pointers are created using **FFI::new([, true])**, **clone**ed. Owned data is deallocated together with last PHP variable, that reference it. This mechanism reuses PHP reference-counting and garbage-collector.
|
||||
FFI extension uses two kind of native C data structures. "Owned" pointers are
|
||||
created using `FFI::new([, true])`, `clone`d. Owned data is deallocated
|
||||
together with last PHP variable, that reference it. This mechanism reuses PHP
|
||||
reference-counting and garbage-collector.
|
||||
|
||||
Elements of C arrays and structures, as well as most data structures returned by C functions are "not-owned". They work just as regular C pointers. They may leak memory, if not freed manually using **FFI::free()**, or may become dangling pointers and lead to PHP crashes.
|
||||
Elements of C arrays and structures, as well as most data structures returned by
|
||||
C functions are "not-owned". They work just as regular C pointers. They may leak
|
||||
memory, if not freed manually using `FFI::free()`, or may become dangling
|
||||
pointers and lead to PHP crashes.
|
||||
|
||||
The following example demonstrates the problem.
|
||||
|
||||
@ -261,7 +323,8 @@ unset($p1); // $p1 is deallocated ($p2 became dangling pointer)
|
||||
var_dump($p2); // crash because dereferencing of dangling pointer
|
||||
```
|
||||
|
||||
It's possible to change ownership, to avoid this crash, but this would require manual memory management and may lead to memory leaks
|
||||
It's possible to change ownership, to avoid this crash, but this would require
|
||||
manual memory management and may lead to memory leaks.
|
||||
|
||||
```php
|
||||
$p1 = FFI::new("int[2][2]", false); // $p1 is not-owned pointer
|
||||
@ -270,36 +333,50 @@ unset($p1); // $p1 CData is keep alive (memory leak)
|
||||
var_dump($p2); // works fine, except of memory leak
|
||||
```
|
||||
|
||||
##### PHP Callbacks
|
||||
## PHP callbacks
|
||||
|
||||
It's possible to assign PHP function to native function variable (or pass it as a function argument). This seems to work, but this functionality is not supported on all libffi platforms, it is not efficient and leaks resources by the end of request.
|
||||
It's possible to assign PHP function to native function variable (or pass it as
|
||||
a function argument). This seems to work, but this functionality is not
|
||||
supported on all libffi platforms, it is not efficient and leaks resources by
|
||||
the end of request.
|
||||
|
||||
##### FFI API restriction
|
||||
## FFI API restriction
|
||||
|
||||
With FFI users may do almost anything, like in C, and therefor may crash PHP in thousand ways. It's possible to completely disable or enable all FFI functions using ffi.enable=0/1 configuration directives, or limit FFI usage to preloaded scripts using ffi.enable=preload (this is the default setting). In case FFI is not completely disabled, it's also enabled for CLI scripts. Finally, the restriction affects only FFI functions their selves, but not the overloaded method of created FFI or CData objects.
|
||||
With FFI users may do almost anything, like in C, and therefor may crash PHP in
|
||||
thousand ways. It's possible to completely disable or enable all FFI functions
|
||||
using `ffi.enable=0/1` configuration directives, or limit FFI usage to preloaded
|
||||
scripts using `ffi.enable=preload` (this is the default setting). In case FFI is
|
||||
not completely disabled, it's also enabled for CLI scripts. Finally, the
|
||||
restriction affects only FFI functions their selves, but not the overloaded
|
||||
method of created FFI or CData objects.
|
||||
|
||||
### Status
|
||||
## Status
|
||||
|
||||
In current state, access to FFI data structures is significantly (about 2 times) slower, than access to PHP arrays and objects. It make no sense to use them for speed, but may make sense to reduce memory consumption.
|
||||
In current state, access to FFI data structures is significantly (about 2 times)
|
||||
slower, than access to PHP arrays and objects. It makes no sense to use them for
|
||||
speed, but may make sense to reduce memory consumption.
|
||||
|
||||
FFI functionality may be included into PHP-8 core, to provide better interpretation performance and integrate with JIT, providing almost C performance (similar to LuaJIT)
|
||||
FFI functionality may be included into PHP-8 core, to provide better
|
||||
interpretation performance and integrate with JIT, providing almost C
|
||||
performance (similar to LuaJIT).
|
||||
|
||||
### Requirement
|
||||
## Requirement
|
||||
|
||||
- [libffi-3.*](http://sourceware.org/libffi/)
|
||||
* [libffi-3.*](https://sourceware.org/libffi/)
|
||||
|
||||
### Install
|
||||
## Installation
|
||||
|
||||
``` bash
|
||||
```bash
|
||||
./configure ... --with-ffi
|
||||
make
|
||||
sudo make install
|
||||
```
|
||||
|
||||
### Real Usage
|
||||
## Real usage
|
||||
|
||||
FFI extension was used to implement [PHP TensorFlow binding](https://github.com/dstogov/php-tensorflow)
|
||||
FFI extension was used to implement
|
||||
[PHP TensorFlow binding](https://github.com/dstogov/php-tensorflow).
|
||||
|
||||
### FFI Parser
|
||||
## FFI parser
|
||||
|
||||
FFI C parser is generated using [LLK](https://github.com/dstogov/llk).
|
||||
|
@ -1,221 +1,204 @@
|
||||
Introduction
|
||||
============
|
||||
# Introduction
|
||||
|
||||
LiteSpeed SAPI module is a dedicated interface for PHP integration with
|
||||
LiteSpeed Web Server. LiteSpeed SAPI has similar architecture to the
|
||||
FastCGI SAPI with there major enhancements: better performance, dynamic
|
||||
spawning and PHP configuration modification through web server
|
||||
configuration and .htaccess files.
|
||||
LiteSpeed Web Server. LiteSpeed SAPI has similar architecture to the FastCGI
|
||||
SAPI with there major enhancements: better performance, dynamic spawning and PHP
|
||||
configuration modification through web server configuration and `.htaccess`
|
||||
files.
|
||||
|
||||
Our simple benchmark test ("hello world") shows that PHP with
|
||||
LiteSpeed SAPI has 30% better performance over PHP with FastCGI SAPI,
|
||||
which is nearly twice the performance that Apache mod_php can deliver.
|
||||
A simple benchmark test ("hello world") shows that PHP with LiteSpeed SAPI has
|
||||
30% better performance over PHP with FastCGI SAPI, which is nearly twice the
|
||||
performance that Apache mod_php can deliver.
|
||||
|
||||
A major drawback of FastCGI PHP comparing to Apache mod_php is lacking
|
||||
the flexibilities in PHP configurations. PHP configurations cannot be
|
||||
changed at runtime via configuration files like .htaccess files or web
|
||||
server's virtual host configuration. In shared hosting environment,
|
||||
each hosting account will has its own "open_basedir" overridden in
|
||||
server configuration to enhance server security when mod_php is used.
|
||||
usually, FastCGI PHP is not an option in shared hosting environment
|
||||
due to lacking of this flexibility. LiteSpeed SAPI is carefully designed
|
||||
to address this issue. PHP configurations can be modified the same way
|
||||
as that in mod_php with the same configuration directives.
|
||||
A major drawback of FastCGI PHP comparing to Apache mod_php is lacking the
|
||||
flexibilities in PHP configurations. PHP configurations cannot be changed at
|
||||
runtime via configuration files like `.htaccess` files or web server's virtual
|
||||
host configuration. In shared hosting environment, each hosting account will has
|
||||
its own `open_basedir` overridden in server configuration to enhance server
|
||||
security when mod_php is used. Usually, FastCGI PHP is not an option in shared
|
||||
hosting environment due to lacking of this flexibility. LiteSpeed SAPI is
|
||||
carefully designed to address this issue. PHP configurations can be modified the
|
||||
same way as that in mod_php with the same configuration directives.
|
||||
|
||||
PHP with LiteSpeed SAPI is highly recommended over FastCGI PHP for
|
||||
PHP scripting with LiteSpeed web server.
|
||||
PHP with LiteSpeed SAPI is highly recommended over FastCGI PHP for PHP scripting
|
||||
with LiteSpeed web server.
|
||||
|
||||
## Building PHP with LiteSpeed SAPI
|
||||
|
||||
Building PHP with LiteSpeed SAPI
|
||||
================================
|
||||
|
||||
You need to add "--with-litespeed" to the configure command to build
|
||||
PHP with LiteSpeed SAPI, all other SAPI related configure options
|
||||
should be removed.
|
||||
You need to add `--with-litespeed` to the configure command to build PHP with
|
||||
LiteSpeed SAPI, all other SAPI related configure options should be removed.
|
||||
|
||||
For example:
|
||||
./configure --with-litespeed
|
||||
make
|
||||
|
||||
You should find an executable called 'php' under sapi/litespeed/
|
||||
directory after the compilation succeeds. Copy it to
|
||||
'lsws/fcgi-bin/lsphp' or wherever you prefer, if LiteSpeed web server
|
||||
has been configured to run PHP with LiteSpeed SAPI already, you just
|
||||
need to overwrite the old executable with this one and you are all
|
||||
set.
|
||||
```bash
|
||||
./configure --with-litespeed
|
||||
make
|
||||
```
|
||||
|
||||
Start PHP from command line
|
||||
===========================
|
||||
You should find an executable called `lsphp` under `sapi/litespeed/` directory
|
||||
after the compilation succeeds. Copy it to `lsws/fcgi-bin/lsphp` or wherever you
|
||||
prefer, if LiteSpeed web server has been configured to run PHP with LiteSpeed
|
||||
SAPI already, you just need to overwrite the old executable with this one and
|
||||
you are all set.
|
||||
|
||||
Usually, lsphp is managed by LiteSpeed web server in a single server
|
||||
installation. lsphp can be used in clustered environment with one
|
||||
LiteSpeed web server at the front, load balancing lsphp processes
|
||||
running on multiple backend servers. In such environment, lsphp can be
|
||||
start manually from command with option "-b <socket_address>", socket
|
||||
address can be IPv4, IPv6 or Unix Domain Socket address.
|
||||
for example:
|
||||
## Start PHP from command line
|
||||
|
||||
./lsphp -b [::]:3000
|
||||
Usually, `lsphp` is managed by LiteSpeed web server in a single server
|
||||
installation. lsphp can be used in clustered environment with one LiteSpeed web
|
||||
server at the front, load balancing lsphp processes running on multiple backend
|
||||
servers. In such environment, lsphp can be start manually from command with
|
||||
option `-b <socket_address>`, socket address can be IPv4, IPv6 or Unix Domain
|
||||
Socket address.
|
||||
|
||||
For example:
|
||||
|
||||
```bash
|
||||
./lsphp -b [::]:3000
|
||||
```
|
||||
|
||||
have lsphp bind to port 3000 on all IPv4 and IPv6 address,
|
||||
|
||||
./lsphp -b *:3000
|
||||
```bash
|
||||
./lsphp -b *:3000
|
||||
```
|
||||
|
||||
have lsphp bind to port 300 on all IPv4 address.
|
||||
have lsphp bind to port 300 on all IPv4 address,
|
||||
|
||||
./lsphp -b 192.168.0.2:3000
|
||||
```bash
|
||||
./lsphp -b 192.168.0.2:3000
|
||||
```
|
||||
|
||||
have lsphp bind to address 192.168.0.2:3000.
|
||||
have lsphp bind to address 192.168.0.2:3000,
|
||||
|
||||
./lsphp -b /tmp/lsphp_manual.sock
|
||||
```bash
|
||||
./lsphp -b /tmp/lsphp_manual.sock
|
||||
```
|
||||
|
||||
have lsphp accept request on Unix domain socket "/tmp/lsphp_manual.sock"
|
||||
have lsphp accept request on Unix domain socket `/tmp/lsphp_manual.sock`.
|
||||
|
||||
## Using LiteSpeed PHP with LiteSpeed Web Server
|
||||
|
||||
Using LiteSpeed PHP with LiteSpeed Web Server
|
||||
=============================================
|
||||
Detailed information about how to configure LiteSpeed web server with PHP
|
||||
support is available from
|
||||
[LiteSpeed website](https://www.litespeedtech.com/docs/webserver).
|
||||
|
||||
Detailed information about how to configure LiteSpeed web server with
|
||||
PHP support is available from our website, at:
|
||||
|
||||
https://www.litespeedtech.com/docs/webserver
|
||||
|
||||
Usually, PHP support has been configured out of box, you don't need to
|
||||
change it unless you want to change PHP interface from FastCGI to
|
||||
LiteSpeed SAPI or vice versa.
|
||||
Usually, PHP support has been configured out of box, you don't need to change it
|
||||
unless you want to change PHP interface from FastCGI to LiteSpeed SAPI or vice
|
||||
versa.
|
||||
|
||||
Brief instructions are as follow:
|
||||
|
||||
1) Login to web administration interface, go to 'Server'->'Ext App' tab,
|
||||
add an external application of type "LSAPI app", "Command" should be
|
||||
set to a shell command that executes the PHP binary you just built.
|
||||
"Instances" should be set to "1". Add "LSAPI_CHILDREN" environment
|
||||
variable to match the value of "Max Connections". More tunable
|
||||
environment variable described below can be added.
|
||||
1. Login to web administration interface, go to 'Server'->'Ext App' tab, add an
|
||||
external application of type "LSAPI app", "Command" should be set to a shell
|
||||
command that executes the PHP binary you just built. "Instances" should be
|
||||
set to "1". Add "LSAPI_CHILDREN" environment variable to match the value of
|
||||
"Max Connections". More tunable environment variable described below can be
|
||||
added.
|
||||
|
||||
2) Go to 'Server'->'Script Handler' tab, add a script handler
|
||||
configuration: set 'suffix' to 'php', 'Handler Type' to 'LiteSpeed
|
||||
API', 'Handler Name' should be the name of external application
|
||||
just defined.
|
||||
2. Go to 'Server'->'Script Handler' tab, add a script handler configuration: set
|
||||
'suffix' to 'php', 'Handler Type' to 'LiteSpeed API', 'Handler Name' should
|
||||
be the name of external application just defined.
|
||||
|
||||
|
||||
3) Click 'Apply Changes' link on the top left of the page, then click
|
||||
3. Click 'Apply Changes' link on the top left of the page, then click
|
||||
'graceful restart'. Now PHP is running with LiteSpeed SAPI.
|
||||
|
||||
Tunings
|
||||
-------
|
||||
## Tunings
|
||||
|
||||
There are a few environment variables that can be tweaked to control the
|
||||
behavior of LSAPI application.
|
||||
|
||||
* LSAPI_CHILDREN or PHP_LSAPI_CHILDREN (default: 0)
|
||||
* `LSAPI_CHILDREN` or `PHP_LSAPI_CHILDREN` (default: 0)
|
||||
|
||||
There are two ways to let PHP handle multiple requests concurrently,
|
||||
Server Managed Mode and Self Managed Mode. In Server Managed Mode,
|
||||
LiteSpeed web server dynamically spawn/stop PHP processes, in this mode
|
||||
"Instances" should match "Max Connections" configuration for PHP
|
||||
external application. To start PHP in Self Managed Mode, "Instances"
|
||||
should be set to "1", while "LSAPI_CHILDREN" environment variable should
|
||||
be set to match the value of "Max Connections" and >1. Web Server will
|
||||
start one PHP process, this process will start/stop children PHP processes
|
||||
dynamically based on on demand. If "LSAPI_CHILDREN" <=1, PHP will be
|
||||
started in server managed mode.
|
||||
There are two ways to let PHP handle multiple requests concurrently, Server
|
||||
Managed Mode and Self Managed Mode. In Server Managed Mode, LiteSpeed web
|
||||
server dynamically spawn/stop PHP processes, in this mode "Instances" should
|
||||
match "Max Connections" configuration for PHP external application. To start
|
||||
PHP in Self Managed Mode, "Instances" should be set to "1", while
|
||||
`LSAPI_CHILDREN` environment variable should be set to match the value of "Max
|
||||
Connections" and greater than 1. Web Server will start one PHP process, this
|
||||
process will start/stop children PHP processes dynamically based on on demand.
|
||||
If `LSAPI_CHILDREN` less or equal to 1, PHP will be started in server managed
|
||||
mode.
|
||||
|
||||
Self Managed Mode is preferred because all PHP processes can share one
|
||||
shared memory block for the opcode cache.
|
||||
Self Managed Mode is preferred because all PHP processes can share one shared
|
||||
memory block for the opcode cache.
|
||||
|
||||
Usually, there is no need to set value of LSAPI_CHILDREN over 100 in
|
||||
most server environment.
|
||||
Usually, there is no need to set value of `LSAPI_CHILDREN` over 100 in most
|
||||
server environments.
|
||||
|
||||
* `LSAPI_AVOID_FORK` (default: 0)
|
||||
|
||||
* LSAPI_AVOID_FORK (default: 0)
|
||||
`LSAPI_AVOID_FORK` specifies the policy of the internal process manager in
|
||||
"Self Managed Mode". When set to 0, the internal process manager will stop and
|
||||
start children process on demand to save system resource. This is preferred in
|
||||
a shared hosting environment. When set to 1, the internal process manager will
|
||||
try to avoid freqently stopping and starting children process. This might be
|
||||
preferred in a dedicate hosting environment.
|
||||
|
||||
LSAPI_AVOID_FORK specifies the policy of the internal process manager in
|
||||
"Self Managed Mode". When set to 0, the internal process manager will stop
|
||||
and start children process on demand to save system resource. This is
|
||||
preferred in a shared hosting environment. When set to 1, the internal
|
||||
process manager will try to avoid freqently stopping and starting children
|
||||
process. This might be preferred in a dedicate hosting environment.
|
||||
* `LSAPI_EXTRA_CHILDREN` (default: 1/3 of `LSAPI_CHILDREN` or 0)
|
||||
|
||||
`LSAPI_EXTRA_CHILDREN` controls the maximum number of extra children processes
|
||||
can be started when some or all existing children processes are in
|
||||
malfunctioning state. Total number of children processes will be reduced to
|
||||
`LSAPI_CHILDREN` level as soon as service is back to normal. When
|
||||
`LSAPI_AVOID_FORK` is set to 0, the default value is 1/3 of `LSAPI_CHILDREN`,
|
||||
When `LSAPI_AVOID_FORK` is set to 1, the default value is 0.
|
||||
|
||||
* LSAPI_EXTRA_CHILDREN (default: 1/3 of LSAPI_CHILDREN or 0)
|
||||
* `LSAPI_MAX_REQS` or `PHP_LSAPI_MAX_REQUESTS` (default value: 10000)
|
||||
|
||||
LSAPI_EXTRA_CHILDREN controls the maximum number of extra children processes
|
||||
can be started when some or all existing children processes are in
|
||||
malfunctioning state. Total number of children processes will be reduced to
|
||||
LSAPI_CHILDREN level as soon as service is back to normal.
|
||||
When LSAPI_AVOID_FORK is set to 0, the default value is 1/3 of
|
||||
LSAPI_CHIDLREN, When LSAPI_AVOID_FORK is set to 1, the default value is 0.
|
||||
This controls how many requests each child process will handle before it exits
|
||||
automatically. Several PHP functions have been identified having memory leaks.
|
||||
This parameter can help reducing memory usage of leaky PHP functions.
|
||||
|
||||
* `LSAPI_MAX_IDLE` (default value: 300 seconds)
|
||||
|
||||
* LSAPI_MAX_REQS or PHP_LSAPI_MAX_REQUESTS (default value: 10000)
|
||||
In Self Managed Mode, LSAPI_MAX_IDLE controls how long a idle child process
|
||||
will wait for a new request before it exits. This option help releasing system
|
||||
resources taken by idle processes.
|
||||
|
||||
This controls how many requests each child process will handle before
|
||||
it exits automatically. Several PHP functions have been identified
|
||||
having memory leaks. This parameter can help reducing memory usage
|
||||
of leaky PHP functions.
|
||||
* `LSAPI_MAX_IDLE_CHILDREN` (default value: 1/3 of `LSAPI_CHILDREN` or
|
||||
`LSAPI_CHILDREN`)
|
||||
|
||||
In Self Managed Mode, `LSAI_MAX_IDLE_CHILDREN` controls how many idle children
|
||||
processes are allowed. Excessive idle children processes will be killed by the
|
||||
parent process immediately. When `LSAPI_AVOID_FORK` is set to 0, the default
|
||||
value is 1/3 of `LSAPI_CHIDLREN`, When `LSAPI_AVOID_FORK` is set to 1, the
|
||||
default value is `LSAPI_CHILDREN`.
|
||||
|
||||
* LSAPI_MAX_IDLE (default value: 300 seconds)
|
||||
* `LSAPI_MAX_PROCESS_TIME` (default value: 300 seconds)
|
||||
|
||||
In Self Managed Mode, LSAPI_MAX_IDLE controls how long a idle child
|
||||
process will wait for a new request before it exits. This option help
|
||||
releasing system resources taken by idle processes.
|
||||
In Self Managed Mode, `LSAPI_MAX_PROCESS_TIME` controls the maximum processing
|
||||
time allowed when processing a request. If a child process can not finish
|
||||
processing of a request in the given time period, it will be killed by the
|
||||
parent process. This option can help getting rid of dead or runaway child
|
||||
process.
|
||||
|
||||
* `LSAPI_PGRP_MAX_IDLE` (default value: FOREVER)
|
||||
|
||||
* LSAPI_MAX_IDLE_CHILDREN
|
||||
(default value: 1/3 of LSAPI_CHILDREN or LSAPI_CHILDREN)
|
||||
In Self Managed Mode, `LSAPI_PGRP_MAX_IDLE` controls how long the parent
|
||||
process will wait before exiting when there is no child process. This option
|
||||
helps releasing system resources taken by an idle parent process.
|
||||
|
||||
In Self Managed Mode, LSAI_MAX_IDLE_CHILDREN controls how many idle
|
||||
children processes are allowed. Excessive idle children processes
|
||||
will be killed by the parent process immediately.
|
||||
When LSAPI_AVOID_FORK is set to 0, the default value is 1/3 of
|
||||
LSAPI_CHIDLREN, When LSAPI_AVOID_FORK is set to 1, the default value
|
||||
is LSAPI_CHILDREN.
|
||||
* `LSAPI_PPID_NO_CHECK`
|
||||
|
||||
By default a LSAPI application check the existence of its parent process and
|
||||
exits automatically if the parent process died. This is to reduce orphan
|
||||
process when web server is restarted. However, it is desirable to disable this
|
||||
feature, such as when a LSAPI process was started manually from command line.
|
||||
`LSAPI_PPID_NO_CHECK` should be set when you want to disable the checking of
|
||||
existence of parent process. When PHP is started by `-b` option, it is
|
||||
disabled automatically.
|
||||
|
||||
* LSAPI_MAX_PROCESS_TIME (default value: 300 seconds)
|
||||
|
||||
In Self Managed Mode, LSAPI_MAX_PROCESS_TIME controls the maximum
|
||||
processing time allowed when processing a request. If a child process
|
||||
can not finish processing of a request in the given time period, it
|
||||
will be killed by the parent process. This option can help getting rid
|
||||
of dead or runaway child process.
|
||||
|
||||
|
||||
* LSAPI_PGRP_MAX_IDLE (default value: FOREVER )
|
||||
|
||||
In Self Managed Mode, LSAPI_PGRP_MAX_IDLE controls how long the parent
|
||||
process will wait before exiting when there is no child process.
|
||||
This option help releasing system resources taken by an idle parent
|
||||
process.
|
||||
|
||||
|
||||
* LSAPI_PPID_NO_CHECK
|
||||
|
||||
By default a LSAPI application check the existence of its parent process
|
||||
and exits automatically if the parent process died. This is to reduce
|
||||
orphan process when web server is restarted. However, it is desirable
|
||||
to disable this feature, such as when a LSAPI process was started
|
||||
manually from command line. LSAPI_PPID_NO_CHECK should be set when
|
||||
you want to disable the checking of existence of parent process.
|
||||
When PHP started by "-b" option, it is disabled automatically.
|
||||
|
||||
|
||||
Compatibility with Apache mod_php
|
||||
=================================
|
||||
## Compatibility with Apache mod_php
|
||||
|
||||
LSAPI PHP supports PHP configuration overridden via web server configuration
|
||||
as well as .htaccess.
|
||||
Since 4.0 release "apache_response_headers" function is supported.
|
||||
as well as `.htaccess`.
|
||||
|
||||
Since 4.0 release `apache_response_headers` function is supported.
|
||||
|
||||
## Contact
|
||||
|
||||
Contact
|
||||
=======
|
||||
|
||||
For support questions, please post to our free support forum, at:
|
||||
|
||||
https://www.litespeedtech.com/support/forum/
|
||||
For support questions, please post to the free support
|
||||
[forum](https://www.litespeedtech.com/support/forum/):
|
||||
|
||||
For bug report, please send bug report to bug [at] litespeedtech.com.
|
||||
|
@ -1,81 +1,78 @@
|
||||
The interactive PHP debugger
|
||||
============================
|
||||
# The interactive PHP debugger
|
||||
|
||||
Implemented as a SAPI module, phpdbg can exert complete control over the environment without impacting the functionality or performance of your code.
|
||||
Implemented as a SAPI module, phpdbg can exert complete control over the
|
||||
environment without impacting the functionality or performance of your code.
|
||||
|
||||
phpdbg aims to be a lightweight, powerful, easy to use debugging platform for PHP 5.4+
|
||||
phpdbg aims to be a lightweight, powerful, easy to use debugging platform for
|
||||
PHP 5.4+.
|
||||
|
||||
Features
|
||||
========
|
||||
## Features
|
||||
|
||||
- Stepthrough Debugging
|
||||
- Flexible Breakpoints (Class Method, Function, File:Line, Address, Opcode)
|
||||
- Easy Access to PHP with built-in eval()
|
||||
- Easy Access to Currently Executing Code
|
||||
- Userland API
|
||||
- SAPI Agnostic - Easily Integrated
|
||||
- PHP Configuration File Support
|
||||
- JIT Super Globals - Set Your Own!!
|
||||
- Optional readline Support - Comfortable Terminal Operation
|
||||
- Remote Debugging Support - Bundled Java GUI
|
||||
- Easy Operation - See Help :)
|
||||
* Stepthrough Debugging
|
||||
* Flexible Breakpoints (Class Method, Function, File:Line, Address, Opcode)
|
||||
* Easy Access to PHP with built-in eval()
|
||||
* Easy Access to Currently Executing Code
|
||||
* Userland API
|
||||
* SAPI Agnostic - Easily Integrated
|
||||
* PHP Configuration File Support
|
||||
* JIT Super Globals - Set Your Own!!
|
||||
* Optional readline Support - Comfortable Terminal Operation
|
||||
* Remote Debugging Support - Bundled Java GUI
|
||||
* Easy Operation - See Help
|
||||
|
||||
Planned
|
||||
=======
|
||||
## Planned
|
||||
|
||||
- Improve Everything :)
|
||||
* Improve Everything :)
|
||||
|
||||
Installation
|
||||
============
|
||||
## Installation
|
||||
|
||||
To install **phpdbg**, you must compile the source against your PHP installation sources, and enable the SAPI with the configure command.
|
||||
To install **phpdbg**, you must compile the source against your PHP installation
|
||||
sources, and enable the SAPI with the configure command. It is enabled by
|
||||
default:
|
||||
|
||||
```
|
||||
cd /usr/src/php-src/sapi
|
||||
git clone https://github.com/krakjoe/phpdbg
|
||||
cd ../
|
||||
```bash
|
||||
cd /path/to/php-src
|
||||
./buildconf --force
|
||||
./configure --enable-phpdbg
|
||||
./configure
|
||||
make -j8
|
||||
make install-phpdbg
|
||||
./sapi/phpdbg/phpdbg --version
|
||||
```
|
||||
|
||||
Where the source directory has been used previously to build PHP, there exists a file named *config.nice* which can be used to invoke configure with the same
|
||||
parameters as were used by the last execution of *configure*.
|
||||
Where the source directory has been used previously to build PHP, there exists a
|
||||
file named `config.nice` which can be used to invoke configure with the same
|
||||
parameters as were used by the last execution of `configure`.
|
||||
|
||||
**Note:** PHP must be configured with the switch --with-readline for phpdbg to support history, autocompletion, tab-listing etc.
|
||||
**Note:** PHP must be configured with the switch `--with-readline` for phpdbg to
|
||||
support history, autocompletion, tab-listing etc.
|
||||
|
||||
Command Line Options
|
||||
====================
|
||||
## Command line options
|
||||
|
||||
The following switches are implemented (just like cli SAPI):
|
||||
|
||||
- -n ignore php ini
|
||||
- -c search for php ini in path
|
||||
- -z load zend extension
|
||||
- -d define php ini entry
|
||||
* `-n` ignore php ini
|
||||
* `-c` search for php ini in path
|
||||
* `-z` load zend extension
|
||||
* `-d` define php ini entry
|
||||
|
||||
The following switches change the default behaviour of phpdbg:
|
||||
|
||||
- -v disables quietness
|
||||
- -s enabled stepping
|
||||
- -e sets execution context
|
||||
- -b boring - disables use of colour on the console
|
||||
- -I ignore .phpdbginit (default init file)
|
||||
- -i override .phpgdbinit location (implies -I)
|
||||
- -O set oplog output file
|
||||
- -q do not print banner on startup
|
||||
- -r jump straight to run
|
||||
- -E enable step through eval()
|
||||
- -l listen ports for remote mode
|
||||
- -a listen address for remote mode
|
||||
- -S override SAPI name
|
||||
* `-v` disables quietness
|
||||
* `-s` enabled stepping
|
||||
* `-e` sets execution context
|
||||
* `-b` boring - disables use of colour on the console
|
||||
* `-I` ignore .phpdbginit (default init file)
|
||||
* `-i` override .phpgdbinit location (implies -I)
|
||||
* `-O` set oplog output file
|
||||
* `-q` do not print banner on startup
|
||||
* `-r` jump straight to run
|
||||
* `-E` enable step through eval()
|
||||
* `-l` listen ports for remote mode
|
||||
* `-a` listen address for remote mode
|
||||
* `-S` override SAPI name
|
||||
|
||||
**Note:** Passing -rr will cause phpdbg to quit after execution, rather than returning to the console.
|
||||
**Note:** Passing `-rr` will cause phpdbg to quit after execution, rather than
|
||||
returning to the console.
|
||||
|
||||
Getting Started
|
||||
===============
|
||||
## Getting started
|
||||
|
||||
See the website for tutorials/documentation
|
||||
|
||||
https://phpdbg.room11.org
|
||||
See the [website](https://phpdbg.room11.org) for tutorials/documentation.
|
||||
|
Loading…
Reference in New Issue
Block a user