first commit, version 8.0.30
This commit is contained in:
commit
69b1ab3c3c
|
|
@ -0,0 +1,55 @@
|
||||||
|
version: "{branch}.build.{build}"
|
||||||
|
|
||||||
|
image: Visual Studio 2019
|
||||||
|
|
||||||
|
clone_depth: 1
|
||||||
|
|
||||||
|
skip_commits:
|
||||||
|
files:
|
||||||
|
- docs/*
|
||||||
|
- NEWS
|
||||||
|
- UPGRADING
|
||||||
|
- UPGRADING.INTERNALS
|
||||||
|
|
||||||
|
cache:
|
||||||
|
- c:\build-cache
|
||||||
|
|
||||||
|
environment:
|
||||||
|
PHP_BUILD_CACHE_BASE_DIR: c:\build-cache
|
||||||
|
PHP_BUILD_OBJ_DIR: c:\obj
|
||||||
|
PHP_BUILD_CACHE_SDK_DIR: c:\build-cache\sdk
|
||||||
|
PHP_BUILD_SDK_BRANCH: php-sdk-2.2.0
|
||||||
|
PHP_BUILD_CRT: vs16
|
||||||
|
# ext and env setup for tests
|
||||||
|
#MYSQL_TEST_PASSWD: Password12!
|
||||||
|
#MYSQL_TEST_USER: root
|
||||||
|
#PDO_MYSQL_TEST_DSN: "pgsql:host=127.0.0.1 port=5432 dbname=test user=root password=Password12!"
|
||||||
|
#PDO_MYSQL_TEST_USER: root
|
||||||
|
#PDO_MYSQL_TEST_PASS: Password12!
|
||||||
|
#PGSQL_TEST_CONNSTR: "host=127.0.0.1 dbname=test port=5432 user=postgres password=Password12!"
|
||||||
|
#PDO_PGSQL_TEST_DSN: "pgsql:host=127.0.0.1 port=5432 dbname=test user=postgres password=Password12!"
|
||||||
|
#build permutations
|
||||||
|
matrix:
|
||||||
|
- THREAD_SAFE: 0
|
||||||
|
OPCACHE: 0
|
||||||
|
PARALLEL: -j2
|
||||||
|
- THREAD_SAFE: 1
|
||||||
|
OPCACHE: 1
|
||||||
|
PARALLEL: -j2
|
||||||
|
INTRINSICS: AVX2
|
||||||
|
|
||||||
|
services:
|
||||||
|
# the setup scripts have to be touched, once some other db version is used
|
||||||
|
- mysql
|
||||||
|
- postgresql101
|
||||||
|
- mssql2017
|
||||||
|
|
||||||
|
platform:
|
||||||
|
- x64
|
||||||
|
#- x86
|
||||||
|
|
||||||
|
build_script:
|
||||||
|
- .github\scripts\windows\build.bat
|
||||||
|
|
||||||
|
test_script:
|
||||||
|
- .github\scripts\windows\test.bat
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
# https://editorconfig.org/
|
||||||
|
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
|
end_of_line = lf
|
||||||
|
charset = utf-8
|
||||||
|
tab_width = 4
|
||||||
|
|
||||||
|
[{*.{awk,bat,c,cpp,d,h,l,re,skl,w32,y},Makefile*}]
|
||||||
|
indent_size = 4
|
||||||
|
indent_style = tab
|
||||||
|
|
||||||
|
[*.{dtd,html,inc,php,phpt,rng,wsdl,xml,xsd,xsl}]
|
||||||
|
indent_size = 4
|
||||||
|
indent_style = space
|
||||||
|
|
||||||
|
[*.{ac,m4,sh,yml}]
|
||||||
|
indent_size = 2
|
||||||
|
indent_style = space
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
indent_style = space
|
||||||
|
max_line_length = 80
|
||||||
|
|
||||||
|
[COMMIT_EDITMSG]
|
||||||
|
indent_size = 4
|
||||||
|
indent_style = space
|
||||||
|
max_line_length = 80
|
||||||
|
|
||||||
|
[*.patch]
|
||||||
|
trim_trailing_whitespace = false
|
||||||
|
|
@ -0,0 +1,645 @@
|
||||||
|
define set_ts
|
||||||
|
set $tsrm_ls = $arg0
|
||||||
|
end
|
||||||
|
|
||||||
|
document set_ts
|
||||||
|
set the ts resource, it is impossible for gdb to
|
||||||
|
call ts_resource_ex while no process is running,
|
||||||
|
but we could get the resource from the argument
|
||||||
|
of frame info.
|
||||||
|
end
|
||||||
|
|
||||||
|
define ____executor_globals
|
||||||
|
if basic_functions_module.zts
|
||||||
|
set $tsrm_ls = _tsrm_ls_cache
|
||||||
|
set $eg = ((zend_executor_globals*) (*((void ***) $tsrm_ls))[executor_globals_id-1])
|
||||||
|
set $cg = ((zend_compiler_globals*) (*((void ***) $tsrm_ls))[compiler_globals_id-1])
|
||||||
|
set $eg_ptr = $eg
|
||||||
|
else
|
||||||
|
set $eg = executor_globals
|
||||||
|
set $cg = compiler_globals
|
||||||
|
set $eg_ptr = (zend_executor_globals*) &executor_globals
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
document ____executor_globals
|
||||||
|
portable way of accessing executor_globals, set $eg
|
||||||
|
this also sets compiler_globals to $cg
|
||||||
|
ZTS detection is automatically based on ext/standard module struct
|
||||||
|
end
|
||||||
|
|
||||||
|
define print_cvs
|
||||||
|
if $argc == 0
|
||||||
|
____executor_globals
|
||||||
|
set $cv_ex_ptr = $eg.current_execute_data
|
||||||
|
else
|
||||||
|
set $cv_ex_ptr = (zend_execute_data *)$arg0
|
||||||
|
end
|
||||||
|
set $cv_count = $cv_ex_ptr.func.op_array.last_var
|
||||||
|
set $cv = $cv_ex_ptr.func.op_array.vars
|
||||||
|
set $cv_idx = 0
|
||||||
|
set $callFrameSize = (sizeof(zend_execute_data) + sizeof(zval) - 1) / sizeof(zval)
|
||||||
|
|
||||||
|
printf "Compiled variables count: %d\n\n", $cv_count
|
||||||
|
while $cv_idx < $cv_count
|
||||||
|
printf "[%d] '%s'\n", $cv_idx, $cv[$cv_idx].val
|
||||||
|
set $zvalue = ((zval *) $cv_ex_ptr) + $callFrameSize + $cv_idx
|
||||||
|
printzv $zvalue
|
||||||
|
set $cv_idx = $cv_idx + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
document print_cvs
|
||||||
|
Prints the compiled variables and their values.
|
||||||
|
If a zend_execute_data pointer is set this will print the compiled
|
||||||
|
variables of that scope. If no parameter is used it will use
|
||||||
|
current_execute_data for scope.
|
||||||
|
|
||||||
|
usage: print_cvs [zend_execute_data *]
|
||||||
|
end
|
||||||
|
|
||||||
|
define dump_bt
|
||||||
|
set $ex = $arg0
|
||||||
|
while $ex
|
||||||
|
printf "[%p] ", $ex
|
||||||
|
set $func = $ex->func
|
||||||
|
if $func
|
||||||
|
if $ex->This->value.obj
|
||||||
|
if $func->common.scope
|
||||||
|
printf "%s->", $func->common.scope->name->val
|
||||||
|
else
|
||||||
|
printf "%s->", $ex->This->value.obj->ce.name->val
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if $func->common.scope
|
||||||
|
printf "%s::", $func->common.scope->name->val
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if $func->common.function_name
|
||||||
|
printf "%s(", $func->common.function_name->val
|
||||||
|
else
|
||||||
|
printf "(main"
|
||||||
|
end
|
||||||
|
|
||||||
|
set $callFrameSize = (sizeof(zend_execute_data) + sizeof(zval) - 1) / sizeof(zval)
|
||||||
|
|
||||||
|
set $count = $ex->This.u2.num_args
|
||||||
|
set $arg = 0
|
||||||
|
while $arg < $count
|
||||||
|
if $arg > 0
|
||||||
|
printf ", "
|
||||||
|
end
|
||||||
|
|
||||||
|
set $zvalue = (zval *) $ex + $callFrameSize + $arg
|
||||||
|
set $type = $zvalue->u1.v.type
|
||||||
|
if $type == 1
|
||||||
|
printf "NULL"
|
||||||
|
end
|
||||||
|
if $type == 2
|
||||||
|
printf "false"
|
||||||
|
end
|
||||||
|
if $type == 3
|
||||||
|
printf "true"
|
||||||
|
end
|
||||||
|
if $type == 4
|
||||||
|
printf "%ld", $zvalue->value.lval
|
||||||
|
end
|
||||||
|
if $type == 5
|
||||||
|
printf "%f", $zvalue->value.dval
|
||||||
|
end
|
||||||
|
if $type == 6
|
||||||
|
____print_str $zvalue->value.str->val $zvalue->value.str->len
|
||||||
|
end
|
||||||
|
if $type == 7
|
||||||
|
printf "array(%d)[%p]", $zvalue->value.arr->nNumOfElements, $zvalue
|
||||||
|
end
|
||||||
|
if $type == 8
|
||||||
|
printf "object[%p]", $zvalue
|
||||||
|
end
|
||||||
|
if $type == 9
|
||||||
|
printf "resource(#%d)", $zvalue->value.lval
|
||||||
|
end
|
||||||
|
if $type == 10
|
||||||
|
printf "reference"
|
||||||
|
end
|
||||||
|
if $type > 10
|
||||||
|
printf "unknown type %d", $type
|
||||||
|
end
|
||||||
|
set $arg = $arg + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
printf ") "
|
||||||
|
else
|
||||||
|
printf "??? "
|
||||||
|
end
|
||||||
|
if $func != 0
|
||||||
|
if $func->type == 2
|
||||||
|
printf "%s:%d ", $func->op_array.filename->val, $ex->opline->lineno
|
||||||
|
else
|
||||||
|
printf "[internal function]"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
set $ex = $ex->prev_execute_data
|
||||||
|
printf "\n"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
document dump_bt
|
||||||
|
dumps the current execution stack. usage: dump_bt executor_globals.current_execute_data
|
||||||
|
end
|
||||||
|
|
||||||
|
define printzv
|
||||||
|
set $ind = 1
|
||||||
|
____printzv $arg0 0
|
||||||
|
end
|
||||||
|
|
||||||
|
document printzv
|
||||||
|
prints zval contents
|
||||||
|
end
|
||||||
|
|
||||||
|
define ____printzv_contents
|
||||||
|
set $zvalue = $arg0
|
||||||
|
set $type = $zvalue->u1.v.type
|
||||||
|
|
||||||
|
# 15 == IS_INDIRECT
|
||||||
|
if $type > 5 && $type < 12
|
||||||
|
printf "(refcount=%d) ", $zvalue->value.counted->gc.refcount
|
||||||
|
end
|
||||||
|
|
||||||
|
if $type == 0
|
||||||
|
printf "UNDEF"
|
||||||
|
end
|
||||||
|
if $type == 1
|
||||||
|
printf "NULL"
|
||||||
|
end
|
||||||
|
if $type == 2
|
||||||
|
printf "bool: false"
|
||||||
|
end
|
||||||
|
if $type == 3
|
||||||
|
printf "bool: true"
|
||||||
|
end
|
||||||
|
if $type == 4
|
||||||
|
printf "long: %ld", $zvalue->value.lval
|
||||||
|
end
|
||||||
|
if $type == 5
|
||||||
|
printf "double: %f", $zvalue->value.dval
|
||||||
|
end
|
||||||
|
if $type == 6
|
||||||
|
printf "string: %s", $zvalue->value.str->val
|
||||||
|
end
|
||||||
|
if $type == 7
|
||||||
|
printf "array: "
|
||||||
|
if ! $arg1
|
||||||
|
set $ind = $ind + 1
|
||||||
|
____print_ht $zvalue->value.arr 1
|
||||||
|
set $ind = $ind - 1
|
||||||
|
set $i = $ind
|
||||||
|
while $i > 0
|
||||||
|
printf " "
|
||||||
|
set $i = $i - 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
set $type = 0
|
||||||
|
end
|
||||||
|
if $type == 8
|
||||||
|
printf "object"
|
||||||
|
____executor_globals
|
||||||
|
set $handle = $zvalue->value.obj.handle
|
||||||
|
set $handlers = $zvalue->value.obj.handlers
|
||||||
|
set $zobj = $zvalue->value.obj
|
||||||
|
set $cname = $zobj->ce->name->val
|
||||||
|
printf "(%s) #%d", $cname, $handle
|
||||||
|
if ! $arg1
|
||||||
|
if $handlers->get_properties == &zend_std_get_properties
|
||||||
|
if $zobj->properties
|
||||||
|
printf "\nProperties "
|
||||||
|
set $ht = $zobj->properties
|
||||||
|
set $ind = $ind + 1
|
||||||
|
____print_ht $ht 1
|
||||||
|
set $ind = $ind - 1
|
||||||
|
set $i = $ind
|
||||||
|
while $i > 0
|
||||||
|
printf " "
|
||||||
|
set $i = $i - 1
|
||||||
|
end
|
||||||
|
else
|
||||||
|
printf " {\n"
|
||||||
|
set $ht = &$zobj->ce->properties_info
|
||||||
|
set $k = 0
|
||||||
|
set $num = $ht->nNumUsed
|
||||||
|
while $k < $num
|
||||||
|
set $p = (Bucket*)($ht->arData + $k)
|
||||||
|
set $name = $p->key
|
||||||
|
set $prop = (zend_property_info*)$p->val.value.ptr
|
||||||
|
set $val = (zval*)((char*)$zobj + $prop->offset)
|
||||||
|
printf "%s => ", $name->val
|
||||||
|
printzv $val
|
||||||
|
set $k = $k + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
set $type = 0
|
||||||
|
end
|
||||||
|
if $type == 9
|
||||||
|
printf "resource: #%d", $zvalue->value.res->handle
|
||||||
|
end
|
||||||
|
if $type == 10
|
||||||
|
printf "reference: "
|
||||||
|
____printzv &$zvalue->value.ref->val $arg1
|
||||||
|
end
|
||||||
|
if $type == 11
|
||||||
|
printf "CONSTANT_AST"
|
||||||
|
end
|
||||||
|
if $type == 12
|
||||||
|
printf "indirect: "
|
||||||
|
____printzv $zvalue->value.zv $arg1
|
||||||
|
end
|
||||||
|
if $type == 13
|
||||||
|
printf "pointer: %p", $zvalue->value.ptr
|
||||||
|
end
|
||||||
|
if $type == 15
|
||||||
|
printf "_ERROR"
|
||||||
|
end
|
||||||
|
if $type == 16
|
||||||
|
printf "_BOOL"
|
||||||
|
end
|
||||||
|
if $type == 17
|
||||||
|
printf "_NUMBER"
|
||||||
|
end
|
||||||
|
if $type > 17
|
||||||
|
printf "unknown type %d", $type
|
||||||
|
end
|
||||||
|
printf "\n"
|
||||||
|
end
|
||||||
|
|
||||||
|
define ____printzv
|
||||||
|
____executor_globals
|
||||||
|
set $zvalue = $arg0
|
||||||
|
|
||||||
|
printf "[%p] ", $zvalue
|
||||||
|
|
||||||
|
set $zcontents = (zval*) $zvalue
|
||||||
|
if $arg1
|
||||||
|
____printzv_contents $zcontents $arg1
|
||||||
|
else
|
||||||
|
____printzv_contents $zcontents 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
define print_global_vars
|
||||||
|
____executor_globals
|
||||||
|
set $symtable = ((HashTable *)&($eg_ptr->symbol_table))
|
||||||
|
print_ht $symtable
|
||||||
|
end
|
||||||
|
|
||||||
|
document print_global_vars
|
||||||
|
Prints the global variables
|
||||||
|
end
|
||||||
|
|
||||||
|
define print_const_table
|
||||||
|
set $ind = 1
|
||||||
|
printf "[%p] {\n", $arg0
|
||||||
|
____print_ht $arg0 4
|
||||||
|
printf "}\n"
|
||||||
|
end
|
||||||
|
|
||||||
|
document print_const_table
|
||||||
|
Dumps elements of Constants HashTable
|
||||||
|
Example: print_const_table executor_globals.zend_constants
|
||||||
|
end
|
||||||
|
|
||||||
|
define ____print_ht
|
||||||
|
set $ht = (HashTable*)$arg0
|
||||||
|
set $n = $ind
|
||||||
|
while $n > 0
|
||||||
|
printf " "
|
||||||
|
set $n = $n - 1
|
||||||
|
end
|
||||||
|
|
||||||
|
if $ht->u.v.flags & 4
|
||||||
|
printf "Packed"
|
||||||
|
else
|
||||||
|
printf "Hash"
|
||||||
|
end
|
||||||
|
printf "(%d)[%p]: {\n", $ht->nNumOfElements, $ht
|
||||||
|
|
||||||
|
set $num = $ht->nNumUsed
|
||||||
|
set $i = 0
|
||||||
|
set $ind = $ind + 1
|
||||||
|
while $i < $num
|
||||||
|
set $p = (Bucket*)($ht->arData + $i)
|
||||||
|
set $n = $ind
|
||||||
|
if $p->val.u1.v.type > 0
|
||||||
|
while $n > 0
|
||||||
|
printf " "
|
||||||
|
set $n = $n - 1
|
||||||
|
end
|
||||||
|
printf "[%d] ", $i
|
||||||
|
if $p->key
|
||||||
|
____print_str $p->key->val $p->key->len
|
||||||
|
printf " => "
|
||||||
|
else
|
||||||
|
printf "%d => ", $p->h
|
||||||
|
end
|
||||||
|
if $arg1 == 0
|
||||||
|
printf "%p\n", (zval *)&$p->val
|
||||||
|
end
|
||||||
|
if $arg1 == 1
|
||||||
|
set $zval = (zval *)&$p->val
|
||||||
|
____printzv $zval 1
|
||||||
|
end
|
||||||
|
if $arg1 == 2
|
||||||
|
printf "%s\n", (char*)$p->val.value.ptr
|
||||||
|
end
|
||||||
|
if $arg1 == 3
|
||||||
|
set $func = (zend_function*)$p->val.value.ptr
|
||||||
|
printf "\"%s\"\n", $func->common.function_name->val
|
||||||
|
end
|
||||||
|
if $arg1 == 4
|
||||||
|
set $const = (zend_constant *)$p->val.value.ptr
|
||||||
|
____printzv $const 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
set $i = $i + 1
|
||||||
|
end
|
||||||
|
set $ind = $ind - 1
|
||||||
|
printf "}\n"
|
||||||
|
end
|
||||||
|
|
||||||
|
define print_ht
|
||||||
|
set $ind = 0
|
||||||
|
____print_ht $arg0 1
|
||||||
|
end
|
||||||
|
|
||||||
|
document print_ht
|
||||||
|
dumps elements of HashTable made of zval
|
||||||
|
end
|
||||||
|
|
||||||
|
define print_htptr
|
||||||
|
set $ind = 0
|
||||||
|
____print_ht $arg0 0
|
||||||
|
end
|
||||||
|
|
||||||
|
document print_htptr
|
||||||
|
dumps elements of HashTable made of pointers
|
||||||
|
end
|
||||||
|
|
||||||
|
define print_htstr
|
||||||
|
set $ind = 0
|
||||||
|
____print_ht $arg0 2
|
||||||
|
end
|
||||||
|
|
||||||
|
document print_htstr
|
||||||
|
dumps elements of HashTable made of strings
|
||||||
|
end
|
||||||
|
|
||||||
|
define print_ft
|
||||||
|
set $ind = 0
|
||||||
|
____print_ht $arg0 3
|
||||||
|
end
|
||||||
|
|
||||||
|
document print_ft
|
||||||
|
dumps a function table (HashTable)
|
||||||
|
end
|
||||||
|
|
||||||
|
define ____print_inh_class
|
||||||
|
set $ce = $arg0
|
||||||
|
if $ce->ce_flags & 0x10 || $ce->ce_flags & 0x20
|
||||||
|
printf "abstract "
|
||||||
|
else
|
||||||
|
if $ce->ce_flags & 0x40
|
||||||
|
printf "final "
|
||||||
|
end
|
||||||
|
end
|
||||||
|
printf "class %s", $ce->name->val
|
||||||
|
if $ce->parent != 0
|
||||||
|
printf " extends %s", $ce->parent->name->val
|
||||||
|
end
|
||||||
|
if $ce->num_interfaces != 0
|
||||||
|
printf " implements"
|
||||||
|
set $tmp = 0
|
||||||
|
while $tmp < $ce->num_interfaces
|
||||||
|
printf " %s", $ce->interfaces[$tmp]->name->val
|
||||||
|
set $tmp = $tmp + 1
|
||||||
|
if $tmp < $ce->num_interfaces
|
||||||
|
printf ","
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
set $ce = $ce->parent
|
||||||
|
end
|
||||||
|
|
||||||
|
define ____print_inh_iface
|
||||||
|
set $ce = $arg0
|
||||||
|
printf "interface %s", $ce->name->val
|
||||||
|
if $ce->num_interfaces != 0
|
||||||
|
set $ce = $ce->interfaces[0]
|
||||||
|
printf " extends %s", $ce->name->val
|
||||||
|
else
|
||||||
|
set $ce = 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
define print_inh
|
||||||
|
set $ce = $arg0
|
||||||
|
set $depth = 0
|
||||||
|
while $ce != 0
|
||||||
|
set $tmp = $depth
|
||||||
|
while $tmp != 0
|
||||||
|
printf " "
|
||||||
|
set $tmp = $tmp - 1
|
||||||
|
end
|
||||||
|
set $depth = $depth + 1
|
||||||
|
if $ce->ce_flags & 0x80
|
||||||
|
____print_inh_iface $ce
|
||||||
|
else
|
||||||
|
____print_inh_class $ce
|
||||||
|
end
|
||||||
|
printf " {\n"
|
||||||
|
end
|
||||||
|
while $depth != 0
|
||||||
|
set $tmp = $depth
|
||||||
|
while $tmp != 1
|
||||||
|
printf " "
|
||||||
|
set $tmp = $tmp - 1
|
||||||
|
end
|
||||||
|
printf "}\n"
|
||||||
|
set $depth = $depth - 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
define print_pi
|
||||||
|
set $pi = (zend_property_info *)$arg0
|
||||||
|
set $initial_offset = ((uint32_t)(zend_uintptr_t)(&((zend_object*)0)->properties_table[(0)]))
|
||||||
|
set $ptr_to_val = (zval*)((char*)$pi->ce->default_properties_table + $pi->offset - $initial_offset)
|
||||||
|
printf "[%p] {\n", $pi
|
||||||
|
printf " offset = %p\n", $pi->offset
|
||||||
|
printf " ce = [%p] %s\n", $pi->ce, $pi->ce->name->val
|
||||||
|
printf " flags = 0x%x (", $pi->flags
|
||||||
|
if $pi->flags & 0x100
|
||||||
|
printf "ZEND_ACC_PUBLIC"
|
||||||
|
else
|
||||||
|
if $pi->flags & 0x200
|
||||||
|
printf "ZEND_ACC_PROTECTED"
|
||||||
|
else
|
||||||
|
if $pi->flags & 0x400
|
||||||
|
printf "ZEND_ACC_PRIVATE"
|
||||||
|
else
|
||||||
|
if $pi->flags & 0x800
|
||||||
|
printf "ZEND_ACC_EARLY_BINDING"
|
||||||
|
else
|
||||||
|
if $pi->flags & 0x20000
|
||||||
|
printf "ZEND_ACC_SHADOW"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
printf ")\n"
|
||||||
|
printf " name = "
|
||||||
|
print_zstr $pi->name
|
||||||
|
printf " default value: "
|
||||||
|
printzv $ptr_to_val
|
||||||
|
printf "}\n"
|
||||||
|
end
|
||||||
|
|
||||||
|
document print_pi
|
||||||
|
Takes a pointer to an object's property and prints the property information
|
||||||
|
usage: print_pi <ptr>
|
||||||
|
end
|
||||||
|
|
||||||
|
define ____print_str
|
||||||
|
set $tmp = 0
|
||||||
|
set $str = $arg0
|
||||||
|
if $argc > 2
|
||||||
|
set $maxlen = $arg2
|
||||||
|
else
|
||||||
|
set $maxlen = 256
|
||||||
|
end
|
||||||
|
|
||||||
|
printf "\""
|
||||||
|
while $tmp < $arg1 && $tmp < $maxlen
|
||||||
|
if $str[$tmp] > 31 && $str[$tmp] < 127
|
||||||
|
printf "%c", $str[$tmp]
|
||||||
|
else
|
||||||
|
printf "\\%o", $str[$tmp]
|
||||||
|
end
|
||||||
|
set $tmp = $tmp + 1
|
||||||
|
end
|
||||||
|
if $tmp != $arg1
|
||||||
|
printf "..."
|
||||||
|
end
|
||||||
|
printf "\""
|
||||||
|
end
|
||||||
|
|
||||||
|
define printzn
|
||||||
|
____executor_globals
|
||||||
|
set $ind = 0
|
||||||
|
set $znode = $arg0
|
||||||
|
if $znode->op_type == 1
|
||||||
|
set $optype = "IS_CONST"
|
||||||
|
end
|
||||||
|
if $znode->op_type == 2
|
||||||
|
set $optype = "IS_TMP_VAR"
|
||||||
|
end
|
||||||
|
if $znode->op_type == 4
|
||||||
|
set $optype = "IS_VAR"
|
||||||
|
end
|
||||||
|
if $znode->op_type == 8
|
||||||
|
set $optype = "IS_UNUSED"
|
||||||
|
end
|
||||||
|
|
||||||
|
printf "[%p] %s", $znode, $optype
|
||||||
|
|
||||||
|
if $znode->op_type == 1
|
||||||
|
printf ": "
|
||||||
|
____printzv &$znode->u.constant 0
|
||||||
|
end
|
||||||
|
if $znode->op_type == 2
|
||||||
|
printf ": "
|
||||||
|
set $tvar = (union _temp_variable *)((char *)$eg.current_execute_data->Ts + $znode->u.var)
|
||||||
|
____printzv ((union _temp_variable *)$tvar)->tmp_var 0
|
||||||
|
end
|
||||||
|
if $znode->op_type == 4
|
||||||
|
printf ": "
|
||||||
|
set $tvar = (union _temp_variable *)((char *)$eg.current_execute_data->Ts + $znode->u.var)
|
||||||
|
____printzv *$tvar->var.ptr_ptr 0
|
||||||
|
end
|
||||||
|
if $znode->op_type == 8
|
||||||
|
printf "\n"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
document printzn
|
||||||
|
print type and content of znode.
|
||||||
|
usage: printzn &opline->op1
|
||||||
|
end
|
||||||
|
|
||||||
|
define printzops
|
||||||
|
printf "op1 => "
|
||||||
|
printzn &execute_data->opline.op1
|
||||||
|
printf "op2 => "
|
||||||
|
printzn &execute_data->opline.op2
|
||||||
|
printf "result => "
|
||||||
|
printzn &execute_data->opline.result
|
||||||
|
end
|
||||||
|
|
||||||
|
document printzops
|
||||||
|
dump operands of the current opline
|
||||||
|
end
|
||||||
|
|
||||||
|
define print_zstr
|
||||||
|
set $zstr = (zend_string *)$arg0
|
||||||
|
if $argc == 2
|
||||||
|
set $maxlen = $arg1
|
||||||
|
else
|
||||||
|
set $maxlen = $zstr->len
|
||||||
|
end
|
||||||
|
printf "string(%d) ", $zstr->len
|
||||||
|
____print_str $zstr->val $zstr->len $maxlen
|
||||||
|
printf "\n"
|
||||||
|
end
|
||||||
|
|
||||||
|
document print_zstr
|
||||||
|
print the length and contents of a zend string
|
||||||
|
usage: print_zstr <ptr> [max length]
|
||||||
|
end
|
||||||
|
|
||||||
|
define zbacktrace
|
||||||
|
____executor_globals
|
||||||
|
dump_bt $eg.current_execute_data
|
||||||
|
end
|
||||||
|
|
||||||
|
document zbacktrace
|
||||||
|
prints backtrace.
|
||||||
|
This command is almost a short cut for
|
||||||
|
> (gdb) ____executor_globals
|
||||||
|
> (gdb) dump_bt $eg.current_execute_data
|
||||||
|
end
|
||||||
|
|
||||||
|
define lookup_root
|
||||||
|
set $found = 0
|
||||||
|
if gc_globals->roots
|
||||||
|
set $current = gc_globals->roots->next
|
||||||
|
printf "looking ref %p in roots\n", $arg0
|
||||||
|
while $current != &gc_globals->roots
|
||||||
|
if $current->ref == $arg0
|
||||||
|
set $found = $current
|
||||||
|
break
|
||||||
|
end
|
||||||
|
set $current = $current->next
|
||||||
|
end
|
||||||
|
if $found != 0
|
||||||
|
printf "found root %p\n", $found
|
||||||
|
else
|
||||||
|
printf "not found\n"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
document lookup_root
|
||||||
|
lookup a refcounted in root
|
||||||
|
usage: lookup_root [ptr].
|
||||||
|
end
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
# Replace $Id$ strings with 40-character hexadecimal blob object name.
|
||||||
|
/ext/ext_skel.php ident
|
||||||
|
/ext/phar/phar/pharcommand.inc ident
|
||||||
|
/ext/dba/libinifile/inifile.c ident
|
||||||
|
/ext/dba/libflatfile/flatfile.c ident
|
||||||
|
/ext/dba/libcdb/cdb_make.c ident
|
||||||
|
/ext/dba/libcdb/cdb.c ident
|
||||||
|
/run-tests.php ident
|
||||||
|
|
||||||
|
# A custom merge driver to avoid automatic merges. These are manually merged.
|
||||||
|
# See https://wiki.php.net/vcs/gitfaq
|
||||||
|
/NEWS merge=NEWS
|
||||||
|
/UPGRADING merge=NEWS
|
||||||
|
/UPGRADING.INTERNALS merge=NEWS
|
||||||
|
|
||||||
|
# Enable commit diffs for binary PHP test files. Some PHP test files include
|
||||||
|
# special characters, such as ASCII control characters. Git recognizes these as
|
||||||
|
# binary and wouldn't generate diffs.
|
||||||
|
*.phpt diff
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
name: apt
|
||||||
|
runs:
|
||||||
|
using: composite
|
||||||
|
steps:
|
||||||
|
- shell: bash
|
||||||
|
run: |
|
||||||
|
set -x
|
||||||
|
|
||||||
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
|
dpkg --add-architecture i386
|
||||||
|
apt-get update -y | true
|
||||||
|
# TODO: Reenable postgresql + postgresql-contrib packages once they work again.
|
||||||
|
apt-get install -y \
|
||||||
|
autoconf \
|
||||||
|
bison \
|
||||||
|
g++-multilib \
|
||||||
|
gcc-multilib \
|
||||||
|
language-pack-de \
|
||||||
|
libaspell-dev:i386 \
|
||||||
|
libbz2-dev:i386 \
|
||||||
|
libc6:i386 \
|
||||||
|
libcurl4-openssl-dev:i386 \
|
||||||
|
libffi-dev:i386 \
|
||||||
|
libfreetype6-dev:i386 \
|
||||||
|
libgmp-dev:i386 \
|
||||||
|
libgssapi-krb5-2:i386 \
|
||||||
|
libicu-dev:i386 \
|
||||||
|
libjpeg-dev:i386 \
|
||||||
|
libkrb5-dev:i386 \
|
||||||
|
libonig-dev:i386 \
|
||||||
|
libpng-dev:i386 \
|
||||||
|
libpq-dev:i386 \
|
||||||
|
libpspell-dev:i386 \
|
||||||
|
libreadline-dev:i386 \
|
||||||
|
libsasl2-dev:i386 \
|
||||||
|
libsodium-dev:i386 \
|
||||||
|
libsqlite3-dev:i386 \
|
||||||
|
libssl-dev:i386 \
|
||||||
|
libtidy-dev:i386 \
|
||||||
|
libwebp-dev:i386 \
|
||||||
|
libxml2-dev:i386 \
|
||||||
|
libxml2-dev:i386 \
|
||||||
|
libxpm-dev:i386 \
|
||||||
|
libxslt1-dev:i386 \
|
||||||
|
libzip-dev:i386 \
|
||||||
|
locales \
|
||||||
|
make \
|
||||||
|
pkg-config:i386 \
|
||||||
|
re2c \
|
||||||
|
unzip \
|
||||||
|
wget \
|
||||||
|
zlib1g-dev:i386
|
||||||
|
|
@ -0,0 +1,73 @@
|
||||||
|
name: apt
|
||||||
|
runs:
|
||||||
|
using: composite
|
||||||
|
steps:
|
||||||
|
- shell: bash
|
||||||
|
run: |
|
||||||
|
set -x
|
||||||
|
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install \
|
||||||
|
bison \
|
||||||
|
re2c \
|
||||||
|
locales \
|
||||||
|
ldap-utils \
|
||||||
|
openssl \
|
||||||
|
slapd \
|
||||||
|
language-pack-de \
|
||||||
|
libgmp-dev \
|
||||||
|
libicu-dev \
|
||||||
|
libtidy-dev \
|
||||||
|
libenchant-2-dev \
|
||||||
|
libaspell-dev \
|
||||||
|
libpspell-dev \
|
||||||
|
libsasl2-dev \
|
||||||
|
libxpm-dev \
|
||||||
|
libzip-dev \
|
||||||
|
libsqlite3-dev \
|
||||||
|
libwebp-dev \
|
||||||
|
libonig-dev \
|
||||||
|
libkrb5-dev \
|
||||||
|
libgssapi-krb5-2 \
|
||||||
|
libcurl4-openssl-dev \
|
||||||
|
libxml2-dev \
|
||||||
|
libxslt1-dev \
|
||||||
|
libpq-dev \
|
||||||
|
libreadline-dev \
|
||||||
|
libldap2-dev \
|
||||||
|
libsodium-dev \
|
||||||
|
libargon2-0-dev \
|
||||||
|
libmm-dev \
|
||||||
|
libsnmp-dev \
|
||||||
|
postgresql \
|
||||||
|
postgresql-contrib \
|
||||||
|
snmpd \
|
||||||
|
snmp-mibs-downloader \
|
||||||
|
freetds-dev \
|
||||||
|
unixodbc-dev \
|
||||||
|
llvm \
|
||||||
|
libc-client-dev \
|
||||||
|
dovecot-core \
|
||||||
|
dovecot-pop3d \
|
||||||
|
dovecot-imapd \
|
||||||
|
sendmail \
|
||||||
|
firebird-dev \
|
||||||
|
liblmdb-dev \
|
||||||
|
libtokyocabinet-dev \
|
||||||
|
libdb-dev \
|
||||||
|
libqdbm-dev \
|
||||||
|
libjpeg-dev \
|
||||||
|
libpng-dev \
|
||||||
|
libfreetype6-dev
|
||||||
|
|
||||||
|
mkdir /opt/oracle
|
||||||
|
wget -nv https://download.oracle.com/otn_software/linux/instantclient/instantclient-basiclite-linuxx64.zip
|
||||||
|
unzip instantclient-basiclite-linuxx64.zip && rm instantclient-basiclite-linuxx64.zip
|
||||||
|
wget -nv https://download.oracle.com/otn_software/linux/instantclient/instantclient-sdk-linuxx64.zip
|
||||||
|
unzip instantclient-sdk-linuxx64.zip && rm instantclient-sdk-linuxx64.zip
|
||||||
|
mv instantclient_*_* /opt/oracle/instantclient
|
||||||
|
# interferes with libldap2 headers
|
||||||
|
rm /opt/oracle/instantclient/sdk/include/ldap.h
|
||||||
|
# fix debug build warning: zend_signal: handler was replaced for signal (2) after startup
|
||||||
|
echo DISABLE_INTERRUPT=on > /opt/oracle/instantclient/network/admin/sqlnet.ora
|
||||||
|
sudo sh -c 'echo /opt/oracle/instantclient >/etc/ld.so.conf.d/oracle-instantclient.conf && ldconfig'
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
name: brew
|
||||||
|
runs:
|
||||||
|
using: composite
|
||||||
|
steps:
|
||||||
|
- shell: bash
|
||||||
|
run: |
|
||||||
|
set -x
|
||||||
|
brew install \
|
||||||
|
pkg-config \
|
||||||
|
autoconf \
|
||||||
|
bison \
|
||||||
|
re2c
|
||||||
|
brew install \
|
||||||
|
openssl@1.1 \
|
||||||
|
krb5 \
|
||||||
|
bzip2 \
|
||||||
|
enchant \
|
||||||
|
libffi \
|
||||||
|
libpng \
|
||||||
|
webp \
|
||||||
|
freetype \
|
||||||
|
intltool \
|
||||||
|
icu4c \
|
||||||
|
libiconv \
|
||||||
|
zlib \
|
||||||
|
t1lib \
|
||||||
|
gd \
|
||||||
|
libzip \
|
||||||
|
gmp \
|
||||||
|
tidy-html5 \
|
||||||
|
libxml2 \
|
||||||
|
libjpeg \
|
||||||
|
libxslt \
|
||||||
|
postgresql
|
||||||
|
brew link icu4c gettext --force
|
||||||
|
|
@ -0,0 +1,71 @@
|
||||||
|
name: ./configure
|
||||||
|
inputs:
|
||||||
|
configurationParameters:
|
||||||
|
default: ''
|
||||||
|
required: false
|
||||||
|
runs:
|
||||||
|
using: composite
|
||||||
|
steps:
|
||||||
|
- shell: bash
|
||||||
|
run: |
|
||||||
|
set -x
|
||||||
|
export PATH="/usr/local/opt/bison/bin:$PATH"
|
||||||
|
export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:/usr/local/opt/openssl@1.1/lib/pkgconfig"
|
||||||
|
export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:/usr/local/opt/krb5/lib/pkgconfig"
|
||||||
|
export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:/usr/local/opt/libffi/lib/pkgconfig"
|
||||||
|
export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:/usr/local/opt/libxml2/lib/pkgconfig"
|
||||||
|
export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:/usr/local/opt/libxslt/lib/pkgconfig"
|
||||||
|
export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:/usr/local/opt/zlib/lib/pkgconfig"
|
||||||
|
export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:/usr/local/opt/icu4c/lib/pkgconfig"
|
||||||
|
./buildconf --force
|
||||||
|
./configure \
|
||||||
|
--enable-option-checking=fatal \
|
||||||
|
--prefix=/usr/local \
|
||||||
|
--enable-fpm \
|
||||||
|
--with-pdo-mysql=mysqlnd \
|
||||||
|
--with-mysqli=mysqlnd \
|
||||||
|
--with-pgsql=/usr/local/opt/libpq \
|
||||||
|
--with-pdo-pgsql=/usr/local/opt/libpq \
|
||||||
|
--with-pdo-sqlite \
|
||||||
|
--without-pear \
|
||||||
|
--enable-gd \
|
||||||
|
--with-jpeg \
|
||||||
|
--with-webp \
|
||||||
|
--with-freetype \
|
||||||
|
--enable-exif \
|
||||||
|
--with-zip \
|
||||||
|
--with-zlib \
|
||||||
|
--enable-soap \
|
||||||
|
--enable-xmlreader \
|
||||||
|
--with-xsl \
|
||||||
|
--with-tidy=/usr/local/opt/tidy-html5 \
|
||||||
|
--with-libxml \
|
||||||
|
--enable-sysvsem \
|
||||||
|
--enable-sysvshm \
|
||||||
|
--enable-shmop \
|
||||||
|
--enable-pcntl \
|
||||||
|
--with-readline=/usr/local/opt/readline \
|
||||||
|
--enable-mbstring \
|
||||||
|
--with-curl \
|
||||||
|
--with-gettext=/usr/local/opt/gettext \
|
||||||
|
--enable-sockets \
|
||||||
|
--with-bz2=/usr/local/opt/bzip2 \
|
||||||
|
--with-openssl \
|
||||||
|
--with-gmp=/usr/local/opt/gmp \
|
||||||
|
--with-iconv=/usr/local/opt/libiconv \
|
||||||
|
--enable-bcmath \
|
||||||
|
--enable-calendar \
|
||||||
|
--enable-ftp \
|
||||||
|
--with-pspell=/usr/local/opt/aspell \
|
||||||
|
--with-kerberos \
|
||||||
|
--enable-sysvmsg \
|
||||||
|
--with-ffi \
|
||||||
|
--enable-zend-test \
|
||||||
|
--enable-intl \
|
||||||
|
--with-mhash \
|
||||||
|
--with-sodium \
|
||||||
|
--enable-dba \
|
||||||
|
--enable-werror \
|
||||||
|
--with-config-file-path=/etc \
|
||||||
|
--with-config-file-scan-dir=/etc/php.d \
|
||||||
|
${{ inputs.configurationParameters }}
|
||||||
|
|
@ -0,0 +1,67 @@
|
||||||
|
name: ./configure
|
||||||
|
inputs:
|
||||||
|
configurationParameters:
|
||||||
|
default: ''
|
||||||
|
required: false
|
||||||
|
runs:
|
||||||
|
using: composite
|
||||||
|
steps:
|
||||||
|
- shell: bash
|
||||||
|
run: |
|
||||||
|
set -x
|
||||||
|
|
||||||
|
./buildconf --force
|
||||||
|
export CFLAGS="-m32 -msse2"
|
||||||
|
export CXXFLAGS="-m32 -msse2"
|
||||||
|
export LDFLAGS=-L/usr/lib/i386-linux-gnu
|
||||||
|
./configure ${{ inputs.configurationParameters }} \
|
||||||
|
--enable-option-checking=fatal \
|
||||||
|
--prefix=/usr \
|
||||||
|
--enable-phpdbg \
|
||||||
|
--enable-fpm \
|
||||||
|
--enable-intl \
|
||||||
|
--with-pdo-mysql=mysqlnd \
|
||||||
|
--with-mysqli=mysqlnd \
|
||||||
|
--with-pgsql \
|
||||||
|
--with-pdo-pgsql \
|
||||||
|
--with-pdo-sqlite \
|
||||||
|
--without-pear \
|
||||||
|
--enable-gd \
|
||||||
|
--with-jpeg \
|
||||||
|
--with-webp \
|
||||||
|
--with-freetype \
|
||||||
|
--with-xpm \
|
||||||
|
--enable-exif \
|
||||||
|
--with-zip \
|
||||||
|
--with-zlib \
|
||||||
|
--with-zlib-dir=/usr \
|
||||||
|
--enable-soap \
|
||||||
|
--enable-xmlreader \
|
||||||
|
--with-xsl \
|
||||||
|
--with-tidy \
|
||||||
|
--enable-sysvsem \
|
||||||
|
--enable-sysvshm \
|
||||||
|
--enable-shmop \
|
||||||
|
--enable-pcntl \
|
||||||
|
--with-readline \
|
||||||
|
--enable-mbstring \
|
||||||
|
--with-curl \
|
||||||
|
--with-gettext \
|
||||||
|
--enable-sockets \
|
||||||
|
--with-bz2 \
|
||||||
|
--with-openssl \
|
||||||
|
--with-gmp \
|
||||||
|
--enable-bcmath \
|
||||||
|
--enable-calendar \
|
||||||
|
--enable-ftp \
|
||||||
|
--with-pspell=/usr \
|
||||||
|
--with-kerberos \
|
||||||
|
--enable-sysvmsg \
|
||||||
|
--with-ffi \
|
||||||
|
--enable-zend-test \
|
||||||
|
--with-mhash \
|
||||||
|
--with-sodium \
|
||||||
|
--enable-dba \
|
||||||
|
--enable-werror \
|
||||||
|
--with-config-file-path=/etc \
|
||||||
|
--with-config-file-scan-dir=/etc/php.d
|
||||||
|
|
@ -0,0 +1,80 @@
|
||||||
|
name: ./configure
|
||||||
|
inputs:
|
||||||
|
configurationParameters:
|
||||||
|
default: ''
|
||||||
|
required: false
|
||||||
|
runs:
|
||||||
|
using: composite
|
||||||
|
steps:
|
||||||
|
- shell: bash
|
||||||
|
run: |
|
||||||
|
set -x
|
||||||
|
./buildconf --force
|
||||||
|
./configure \
|
||||||
|
--enable-option-checking=fatal \
|
||||||
|
--prefix=/usr \
|
||||||
|
--enable-phpdbg \
|
||||||
|
--enable-fpm \
|
||||||
|
--with-pdo-mysql=mysqlnd \
|
||||||
|
--with-mysqli=mysqlnd \
|
||||||
|
--with-pgsql \
|
||||||
|
--with-pdo-pgsql \
|
||||||
|
--with-pdo-sqlite \
|
||||||
|
--enable-intl \
|
||||||
|
--without-pear \
|
||||||
|
--enable-gd \
|
||||||
|
--with-jpeg \
|
||||||
|
--with-webp \
|
||||||
|
--with-freetype \
|
||||||
|
--with-xpm \
|
||||||
|
--enable-exif \
|
||||||
|
--with-zip \
|
||||||
|
--with-zlib \
|
||||||
|
--with-zlib-dir=/usr \
|
||||||
|
--enable-soap \
|
||||||
|
--enable-xmlreader \
|
||||||
|
--with-xsl \
|
||||||
|
--with-tidy \
|
||||||
|
--enable-sysvsem \
|
||||||
|
--enable-sysvshm \
|
||||||
|
--enable-shmop \
|
||||||
|
--enable-pcntl \
|
||||||
|
--with-readline \
|
||||||
|
--enable-mbstring \
|
||||||
|
--with-curl \
|
||||||
|
--with-gettext \
|
||||||
|
--enable-sockets \
|
||||||
|
--with-bz2 \
|
||||||
|
--with-openssl \
|
||||||
|
--with-gmp \
|
||||||
|
--enable-bcmath \
|
||||||
|
--enable-calendar \
|
||||||
|
--enable-ftp \
|
||||||
|
--with-pspell=/usr \
|
||||||
|
--with-enchant=/usr \
|
||||||
|
--with-kerberos \
|
||||||
|
--enable-sysvmsg \
|
||||||
|
--with-ffi \
|
||||||
|
--enable-zend-test \
|
||||||
|
--with-ldap \
|
||||||
|
--with-ldap-sasl \
|
||||||
|
--with-password-argon2 \
|
||||||
|
--with-mhash \
|
||||||
|
--with-sodium \
|
||||||
|
--enable-dba \
|
||||||
|
--with-cdb \
|
||||||
|
--enable-flatfile \
|
||||||
|
--enable-inifile \
|
||||||
|
--with-tcadb \
|
||||||
|
--with-lmdb \
|
||||||
|
--with-qdbm \
|
||||||
|
--with-snmp \
|
||||||
|
--with-unixODBC \
|
||||||
|
--with-imap \
|
||||||
|
--with-imap-ssl \
|
||||||
|
--with-pdo-odbc=unixODBC,/usr \
|
||||||
|
--with-pdo-oci=shared,instantclient,/opt/oracle/instantclient \
|
||||||
|
--with-oci8=shared,instantclient,/opt/oracle/instantclient \
|
||||||
|
--with-config-file-path=/etc \
|
||||||
|
--with-config-file-scan-dir=/etc/php.d \
|
||||||
|
${{ inputs.configurationParameters }}
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
name: Install
|
||||||
|
runs:
|
||||||
|
using: composite
|
||||||
|
steps:
|
||||||
|
- shell: bash
|
||||||
|
run: |
|
||||||
|
set -x
|
||||||
|
make install
|
||||||
|
mkdir /etc/php.d
|
||||||
|
chmod 777 /etc/php.d
|
||||||
|
echo mysqli.default_socket=/var/run/mysqld/mysqld.sock > /etc/php.d/mysqli.ini
|
||||||
|
echo pdo_mysql.default_socket=/var/run/mysqld/mysqld.sock > /etc/php.d/pdo_mysql.ini
|
||||||
|
echo opcache.enable_cli=1 >> /etc/php.d/opcache.ini
|
||||||
|
echo opcache.protect_memory=1 >> /etc/php.d/opcache.ini
|
||||||
|
echo opcache.preload_user=root >> /etc/php.d/opcache.ini
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
name: Install
|
||||||
|
runs:
|
||||||
|
using: composite
|
||||||
|
steps:
|
||||||
|
- shell: bash
|
||||||
|
run: |
|
||||||
|
set -x
|
||||||
|
sudo make install
|
||||||
|
sudo mkdir /etc/php.d
|
||||||
|
sudo chmod 777 /etc/php.d
|
||||||
|
echo mysqli.default_socket=/var/run/mysqld/mysqld.sock > /etc/php.d/mysqli.ini
|
||||||
|
echo pdo_mysql.default_socket=/var/run/mysqld/mysqld.sock > /etc/php.d/pdo_mysql.ini
|
||||||
|
echo extension=oci8.so > /etc/php.d/oci8.ini
|
||||||
|
echo extension=pdo_oci.so > /etc/php.d/pdo_oci.ini
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
name: Create MSSQL container
|
||||||
|
runs:
|
||||||
|
using: composite
|
||||||
|
steps:
|
||||||
|
- shell: bash
|
||||||
|
run: |
|
||||||
|
set -x
|
||||||
|
docker run \
|
||||||
|
-e "ACCEPT_EULA=Y" \
|
||||||
|
-e "SA_PASSWORD=<YourStrong@Passw0rd>" \
|
||||||
|
-p 1433:1433 \
|
||||||
|
--name sql1 \
|
||||||
|
-h sql1 \
|
||||||
|
-d mcr.microsoft.com/mssql/server:2019-CU8-ubuntu-16.04
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
name: Create Oracle container
|
||||||
|
runs:
|
||||||
|
using: composite
|
||||||
|
steps:
|
||||||
|
- shell: bash
|
||||||
|
run: |
|
||||||
|
set -x
|
||||||
|
docker run \
|
||||||
|
-e "ORACLE_PASSWORD=pass" \
|
||||||
|
-p 1521:1521 \
|
||||||
|
--name oracle \
|
||||||
|
-h oracle \
|
||||||
|
-d gvenzl/oracle-xe:slim
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
name: Setup
|
||||||
|
runs:
|
||||||
|
using: composite
|
||||||
|
steps:
|
||||||
|
- shell: bash
|
||||||
|
run: |
|
||||||
|
set -x
|
||||||
|
|
||||||
|
sudo service mysql start
|
||||||
|
sudo service postgresql start
|
||||||
|
sudo service slapd start
|
||||||
|
mysql -uroot -proot -e "CREATE DATABASE IF NOT EXISTS test"
|
||||||
|
# Ensure local_infile tests can run.
|
||||||
|
mysql -uroot -proot -e "SET GLOBAL local_infile = true"
|
||||||
|
sudo -u postgres psql -c "ALTER USER postgres PASSWORD 'postgres';"
|
||||||
|
sudo -u postgres psql -c "CREATE DATABASE test;"
|
||||||
|
docker exec sql1 /opt/mssql-tools/bin/sqlcmd -S 127.0.0.1 -U SA -P "<YourStrong@Passw0rd>" -Q "create login pdo_test with password='password', check_policy=off; create user pdo_test for login pdo_test; grant alter, control to pdo_test;"
|
||||||
|
sudo locale-gen de_DE
|
||||||
|
|
||||||
|
./.github/scripts/setup-slapd.sh &>/dev/null
|
||||||
|
|
||||||
|
sudo cp ext/snmp/tests/snmpd.conf /etc/snmp
|
||||||
|
sudo cp ext/snmp/tests/bigtest /etc/snmp
|
||||||
|
sudo service snmpd restart
|
||||||
|
|
||||||
|
sudo groupadd -g 5000 vmail
|
||||||
|
sudo useradd -m -d /var/vmail -s /bin/false -u 5000 -g vmail vmail
|
||||||
|
sudo cp ext/imap/tests/setup/dovecot.conf /etc/dovecot/dovecot.conf
|
||||||
|
sudo cp ext/imap/tests/setup/dovecotpass /etc/dovecot/dovecotpass
|
||||||
|
sudo service dovecot restart
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
name: Test
|
||||||
|
inputs:
|
||||||
|
runTestsParameters:
|
||||||
|
default: ''
|
||||||
|
required: false
|
||||||
|
runs:
|
||||||
|
using: composite
|
||||||
|
steps:
|
||||||
|
- shell: bash
|
||||||
|
run: |
|
||||||
|
set -x
|
||||||
|
export MYSQL_TEST_USER=root
|
||||||
|
export MYSQL_TEST_PASSWD=root
|
||||||
|
if [[ -z "$PDO_MYSQL_TEST_DSN" ]]; then
|
||||||
|
export PDO_MYSQL_TEST_DSN="mysql:host=localhost;dbname=test"
|
||||||
|
fi
|
||||||
|
export PDO_MYSQL_TEST_USER=root
|
||||||
|
export PDO_MYSQL_TEST_PASS=root
|
||||||
|
export PDO_DBLIB_TEST_DSN="dblib:host=127.0.0.1;dbname=master;version=7.0"
|
||||||
|
export PDO_DBLIB_TEST_USER="pdo_test"
|
||||||
|
export PDO_DBLIB_TEST_PASS="password"
|
||||||
|
export PHP_OCI8_TEST_USER="system"
|
||||||
|
export PHP_OCI8_TEST_PASS="pass"
|
||||||
|
export PHP_OCI8_TEST_DB="localhost/XEPDB1"
|
||||||
|
export PDO_OCI_TEST_USER="system"
|
||||||
|
export PDO_OCI_TEST_PASS="pass"
|
||||||
|
export PDO_OCI_TEST_DSN="oci:dbname=localhost/XEPDB1;charset=AL32UTF8"
|
||||||
|
export SKIP_IO_CAPTURE_TESTS=1
|
||||||
|
sapi/cli/php run-tests.php -P -q ${{ inputs.runTestsParameters }} \
|
||||||
|
-j$(/usr/bin/nproc) \
|
||||||
|
-g FAIL,XFAIL,BORK,WARN,LEAK,XLEAK,SKIP \
|
||||||
|
--offline \
|
||||||
|
--show-diff \
|
||||||
|
--show-slow 1000 \
|
||||||
|
--set-timeout 120
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
name: Test
|
||||||
|
inputs:
|
||||||
|
runTestsParameters:
|
||||||
|
default: ''
|
||||||
|
required: false
|
||||||
|
runs:
|
||||||
|
using: composite
|
||||||
|
steps:
|
||||||
|
- shell: bash
|
||||||
|
run: |
|
||||||
|
set -x
|
||||||
|
export SKIP_IO_CAPTURE_TESTS=1
|
||||||
|
export CI_NO_IPV6=1
|
||||||
|
sapi/cli/php run-tests.php -P -q ${{ inputs.runTestsParameters }} \
|
||||||
|
-j$(sysctl -n hw.ncpu) \
|
||||||
|
-g FAIL,XFAIL,BORK,WARN,LEAK,XLEAK,SKIP \
|
||||||
|
--offline \
|
||||||
|
--show-diff \
|
||||||
|
--show-slow 1000 \
|
||||||
|
--set-timeout 120
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
name: Verify generated files are up to date
|
||||||
|
runs:
|
||||||
|
using: composite
|
||||||
|
steps:
|
||||||
|
- shell: bash
|
||||||
|
run: |
|
||||||
|
set -x
|
||||||
|
[[ "$OSTYPE" == "darwin"* ]] && export PATH="/usr/local/opt/bison/bin:$PATH"
|
||||||
|
scripts/dev/genfiles
|
||||||
|
Zend/zend_vm_gen.php
|
||||||
|
build/gen_stub.php -f
|
||||||
|
git add . -Nu && git diff --exit-code
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
leak:acommon::DictInfoList::elements
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
const BRANCHES = ['master', 'PHP-8.1', 'PHP-8.0'];
|
||||||
|
|
||||||
|
function get_branch_commit_cache_file_path(): string {
|
||||||
|
return dirname(__DIR__) . '/branch-commit-cache.json';
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_branch_matrix(array $branches) {
|
||||||
|
$result = array_map(function ($branch) {
|
||||||
|
$branch_key = strtoupper(str_replace('.', '', $branch));
|
||||||
|
return [
|
||||||
|
'name' => $branch_key,
|
||||||
|
'ref' => $branch,
|
||||||
|
];
|
||||||
|
}, $branches);
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_branches() {
|
||||||
|
$branch_commit_cache_file = get_branch_commit_cache_file_path();
|
||||||
|
$branch_commit_map = [];
|
||||||
|
if (file_exists($branch_commit_cache_file)) {
|
||||||
|
$branch_commit_map = json_decode(file_get_contents($branch_commit_cache_file), JSON_THROW_ON_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
$changed_branches = [];
|
||||||
|
foreach (BRANCHES as $branch) {
|
||||||
|
$previous_commit_hash = $branch_commit_map[$branch] ?? null;
|
||||||
|
$current_commit_hash = trim(shell_exec('git rev-parse origin/' . $branch));
|
||||||
|
|
||||||
|
if ($previous_commit_hash !== $current_commit_hash) {
|
||||||
|
$changed_branches[] = $branch;
|
||||||
|
}
|
||||||
|
|
||||||
|
$branch_commit_map[$branch] = $current_commit_hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
file_put_contents($branch_commit_cache_file, json_encode($branch_commit_map));
|
||||||
|
|
||||||
|
return get_branch_matrix($changed_branches);
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_matrix_include(array $branches) {
|
||||||
|
$jobs = [];
|
||||||
|
foreach ($branches as $branch) {
|
||||||
|
$jobs[] = [
|
||||||
|
'name' => '_ASAN_UBSAN',
|
||||||
|
'branch' => $branch,
|
||||||
|
'debug' => true,
|
||||||
|
'zts' => true,
|
||||||
|
'configuration_parameters' => "CFLAGS='-fsanitize=undefined,address -DZEND_TRACK_ARENA_ALLOC' LDFLAGS='-fsanitize=undefined,address'",
|
||||||
|
'run_tests_parameters' => '--asan',
|
||||||
|
'test_function_jit' => false,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return $jobs;
|
||||||
|
}
|
||||||
|
|
||||||
|
$trigger = $argv[1] ?? 'schedule';
|
||||||
|
$attempt = (int) ($argv[2] ?? 1);
|
||||||
|
$discard_cache = ($trigger === 'schedule' && $attempt !== 1) || $trigger === 'workflow_dispatch';
|
||||||
|
if ($discard_cache) {
|
||||||
|
@unlink(get_branch_commit_cache_file_path());
|
||||||
|
}
|
||||||
|
|
||||||
|
$branches = get_branches();
|
||||||
|
$matrix_include = get_matrix_include($branches);
|
||||||
|
|
||||||
|
echo '::set-output name=branches::' . json_encode($branches, JSON_UNESCAPED_SLASHES) . "\n";
|
||||||
|
echo '::set-output name=matrix-include::' . json_encode($matrix_include, JSON_UNESCAPED_SLASHES) . "\n";
|
||||||
|
|
@ -0,0 +1,185 @@
|
||||||
|
#!/bin/sh
|
||||||
|
set -ex
|
||||||
|
|
||||||
|
# Create TLS certificate
|
||||||
|
sudo mkdir -p /etc/ldap/ssl
|
||||||
|
|
||||||
|
alt_names() {
|
||||||
|
(
|
||||||
|
(
|
||||||
|
(hostname && hostname -a && hostname -A && hostname -f) |
|
||||||
|
xargs -n 1 |
|
||||||
|
sort -u |
|
||||||
|
sed -e 's/\(\S\+\)/DNS:\1/g'
|
||||||
|
) && (
|
||||||
|
(hostname -i && hostname -I && echo "127.0.0.1 ::1") |
|
||||||
|
xargs -n 1 |
|
||||||
|
sort -u |
|
||||||
|
sed -e 's/\(\S\+\)/IP:\1/g'
|
||||||
|
)
|
||||||
|
) | paste -d, -s
|
||||||
|
}
|
||||||
|
|
||||||
|
sudo openssl req -newkey rsa:4096 -x509 -nodes -days 3650 \
|
||||||
|
-out /etc/ldap/ssl/server.crt -keyout /etc/ldap/ssl/server.key \
|
||||||
|
-subj "/C=US/ST=Arizona/L=Localhost/O=localhost/CN=localhost" \
|
||||||
|
-addext "subjectAltName = `alt_names`"
|
||||||
|
|
||||||
|
sudo chown -R openldap:openldap /etc/ldap/ssl
|
||||||
|
|
||||||
|
# Display the TLS certificate (should be world readable)
|
||||||
|
openssl x509 -noout -text -in /etc/ldap/ssl/server.crt
|
||||||
|
|
||||||
|
# Point to the certificate generated
|
||||||
|
if ! grep -q 'TLS_CACERT \/etc\/ldap\/ssl\/server.crt' /etc/ldap/ldap.conf; then
|
||||||
|
sudo sed -e 's|^\s*TLS_CACERT|# TLS_CACERT|' -i /etc/ldap/ldap.conf
|
||||||
|
echo 'TLS_CACERT /etc/ldap/ssl/server.crt' | sudo tee -a /etc/ldap/ldap.conf
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Configure LDAP protocols to serve.
|
||||||
|
sudo sed -e 's|^\s*SLAPD_SERVICES\s*=.*$|SLAPD_SERVICES="ldap:/// ldaps:/// ldapi:///"|' -i /etc/default/slapd
|
||||||
|
|
||||||
|
# Configure LDAP database.
|
||||||
|
DBDN=`sudo ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b cn=config '(&(olcRootDN=*)(olcSuffix=*))' dn | grep -i '^dn:' | sed -e 's/^dn:\s*//'`;
|
||||||
|
|
||||||
|
sudo ldapadd -Q -Y EXTERNAL -H ldapi:/// -f /etc/ldap/schema/ppolicy.ldif
|
||||||
|
|
||||||
|
sudo service slapd restart
|
||||||
|
|
||||||
|
sudo ldapmodify -Q -Y EXTERNAL -H ldapi:/// << EOF
|
||||||
|
dn: $DBDN
|
||||||
|
changetype: modify
|
||||||
|
replace: olcSuffix
|
||||||
|
olcSuffix: dc=my-domain,dc=com
|
||||||
|
-
|
||||||
|
replace: olcRootDN
|
||||||
|
olcRootDN: cn=Manager,dc=my-domain,dc=com
|
||||||
|
-
|
||||||
|
replace: olcRootPW
|
||||||
|
olcRootPW: secret
|
||||||
|
|
||||||
|
dn: cn=config
|
||||||
|
changetype: modify
|
||||||
|
add: olcTLSCACertificateFile
|
||||||
|
olcTLSCACertificateFile: /etc/ldap/ssl/server.crt
|
||||||
|
-
|
||||||
|
add: olcTLSCertificateFile
|
||||||
|
olcTLSCertificateFile: /etc/ldap/ssl/server.crt
|
||||||
|
-
|
||||||
|
add: olcTLSCertificateKeyFile
|
||||||
|
olcTLSCertificateKeyFile: /etc/ldap/ssl/server.key
|
||||||
|
-
|
||||||
|
add: olcTLSVerifyClient
|
||||||
|
olcTLSVerifyClient: never
|
||||||
|
-
|
||||||
|
add: olcAuthzRegexp
|
||||||
|
olcAuthzRegexp: uid=usera,cn=digest-md5,cn=auth cn=usera,dc=my-domain,dc=com
|
||||||
|
-
|
||||||
|
replace: olcLogLevel
|
||||||
|
olcLogLevel: -1
|
||||||
|
|
||||||
|
dn: cn=module{0},cn=config
|
||||||
|
changetype: modify
|
||||||
|
add: olcModuleLoad
|
||||||
|
olcModuleLoad: sssvlv
|
||||||
|
-
|
||||||
|
add: olcModuleLoad
|
||||||
|
olcModuleLoad: ppolicy
|
||||||
|
-
|
||||||
|
add: olcModuleLoad
|
||||||
|
olcModuleLoad: dds
|
||||||
|
EOF
|
||||||
|
|
||||||
|
sudo service slapd restart
|
||||||
|
|
||||||
|
sudo ldapadd -Q -Y EXTERNAL -H ldapi:/// << EOF
|
||||||
|
dn: olcOverlay=sssvlv,$DBDN
|
||||||
|
objectClass: olcOverlayConfig
|
||||||
|
objectClass: olcSssVlvConfig
|
||||||
|
olcOverlay: sssvlv
|
||||||
|
olcSssVlvMax: 10
|
||||||
|
olcSssVlvMaxKeys: 5
|
||||||
|
|
||||||
|
dn: olcOverlay=ppolicy,$DBDN
|
||||||
|
objectClass: olcOverlayConfig
|
||||||
|
objectClass: olcPPolicyConfig
|
||||||
|
olcOverlay: ppolicy
|
||||||
|
### This would clutter our DIT and make tests to fail, while ppolicy does not
|
||||||
|
### seem to work as we expect (it does not seem to provide expected controls)
|
||||||
|
## olcPPolicyDefault: cn=default,ou=pwpolicies,dc=my-domain,dc=com
|
||||||
|
## olcPPolicyHashCleartext: FALSE
|
||||||
|
## olcPPolicyUseLockout: TRUE
|
||||||
|
|
||||||
|
dn: olcOverlay=dds,$DBDN
|
||||||
|
objectClass: olcOverlayConfig
|
||||||
|
objectClass: olcDdsConfig
|
||||||
|
olcOverlay: dds
|
||||||
|
EOF
|
||||||
|
|
||||||
|
sudo service slapd restart
|
||||||
|
|
||||||
|
sudo ldapmodify -Q -Y EXTERNAL -H ldapi:/// << EOF
|
||||||
|
dn: $DBDN
|
||||||
|
changetype: modify
|
||||||
|
add: olcDbIndex
|
||||||
|
olcDbIndex: entryExpireTimestamp eq
|
||||||
|
EOF
|
||||||
|
|
||||||
|
sudo service slapd restart
|
||||||
|
|
||||||
|
ldapadd -H ldapi:/// -D cn=Manager,dc=my-domain,dc=com -w secret <<EOF
|
||||||
|
dn: dc=my-domain,dc=com
|
||||||
|
objectClass: top
|
||||||
|
objectClass: organization
|
||||||
|
objectClass: dcObject
|
||||||
|
dc: my-domain
|
||||||
|
o: php ldap tests
|
||||||
|
|
||||||
|
### This would clutter our DIT and make tests to fail, while ppolicy does not
|
||||||
|
### seem to work as we expect (it does not seem to provide expected controls)
|
||||||
|
## dn: ou=pwpolicies,dc=my-domain,dc=com
|
||||||
|
## objectClass: top
|
||||||
|
## objectClass: organizationalUnit
|
||||||
|
## ou: pwpolicies
|
||||||
|
##
|
||||||
|
## dn: cn=default,ou=pwpolicies,dc=my-domain,dc=com
|
||||||
|
## objectClass: top
|
||||||
|
## objectClass: person
|
||||||
|
## objectClass: pwdPolicy
|
||||||
|
## cn: default
|
||||||
|
## sn: default
|
||||||
|
## pwdAttribute: userPassword
|
||||||
|
## pwdMaxAge: 2592000
|
||||||
|
## pwdExpireWarning: 3600
|
||||||
|
## #pwdInHistory: 0
|
||||||
|
## pwdCheckQuality: 0
|
||||||
|
## pwdMaxFailure: 5
|
||||||
|
## pwdLockout: TRUE
|
||||||
|
## #pwdLockoutDuration: 0
|
||||||
|
## #pwdGraceAuthNLimit: 0
|
||||||
|
## #pwdFailureCountInterval: 0
|
||||||
|
## pwdMustChange: FALSE
|
||||||
|
## pwdMinLength: 3
|
||||||
|
## pwdAllowUserChange: TRUE
|
||||||
|
## pwdSafeModify: FALSE
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Verify TLS connection
|
||||||
|
tries=0
|
||||||
|
while : ; do
|
||||||
|
ldapsearch -d 255 -H ldaps://localhost -D cn=Manager,dc=my-domain,dc=com -w secret -s base -b dc=my-domain,dc=com 'objectclass=*'
|
||||||
|
rt=$?
|
||||||
|
if [ $rt -eq 0 ]; then
|
||||||
|
echo "OK"
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
tries=$((tries+1))
|
||||||
|
if [ $((tries)) -gt 3 ]; then
|
||||||
|
echo "exit failure $rt"
|
||||||
|
exit $rt
|
||||||
|
else
|
||||||
|
echo "trying again"
|
||||||
|
sleep 3
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
@echo off
|
||||||
|
|
||||||
|
set SDK_REMOTE=https://github.com/php/php-sdk-binary-tools.git
|
||||||
|
set SDK_BRANCH=%PHP_BUILD_SDK_BRANCH%
|
||||||
|
set SDK_RUNNER=%PHP_BUILD_CACHE_SDK_DIR%\phpsdk-%PHP_BUILD_CRT%-%PLATFORM%.bat
|
||||||
|
|
||||||
|
if not exist "%PHP_BUILD_CACHE_BASE_DIR%" (
|
||||||
|
echo Creating %PHP_BUILD_CACHE_BASE_DIR%
|
||||||
|
mkdir "%PHP_BUILD_CACHE_BASE_DIR%"
|
||||||
|
)
|
||||||
|
|
||||||
|
if not exist "%PHP_BUILD_OBJ_DIR%" (
|
||||||
|
echo Creating %PHP_BUILD_OBJ_DIR%
|
||||||
|
mkdir "%PHP_BUILD_OBJ_DIR%"
|
||||||
|
)
|
||||||
|
|
||||||
|
if not exist "%SDK_RUNNER%" (
|
||||||
|
if exist "%PHP_BUILD_CACHE_SDK_DIR%" rmdir /s /q "%PHP_BUILD_CACHE_SDK_DIR%"
|
||||||
|
)
|
||||||
|
|
||||||
|
if not exist "%PHP_BUILD_CACHE_SDK_DIR%" (
|
||||||
|
echo Cloning remote SDK repository
|
||||||
|
git clone --branch %SDK_BRANCH% %SDK_REMOTE% "%PHP_BUILD_CACHE_SDK_DIR%" 2>&1
|
||||||
|
)
|
||||||
|
|
||||||
|
for /f "tokens=*" %%a in ('type %PHP_BUILD_CACHE_SDK_DIR%\VERSION') do set GOT_SDK_VER=%%a
|
||||||
|
echo Got SDK version %GOT_SDK_VER%
|
||||||
|
if NOT "%GOT_SDK_VER%" == "%PHP_BUILD_SDK_BRANCH:~8%" (
|
||||||
|
echo Switching to the configured SDK version %SDK_BRANCH:~8%
|
||||||
|
echo Fetching remote SDK repository
|
||||||
|
git --git-dir="%PHP_BUILD_CACHE_SDK_DIR%\.git" --work-tree="%PHP_BUILD_CACHE_SDK_DIR%" fetch --prune origin 2>&1
|
||||||
|
echo Checkout SDK repository branch
|
||||||
|
git --git-dir="%PHP_BUILD_CACHE_SDK_DIR%\.git" --work-tree="%PHP_BUILD_CACHE_SDK_DIR%" checkout --force %SDK_BRANCH%
|
||||||
|
)
|
||||||
|
|
||||||
|
if not exist "%SDK_RUNNER%" (
|
||||||
|
echo "%SDK_RUNNER%" doesn't exist
|
||||||
|
exit /b 3
|
||||||
|
)
|
||||||
|
|
||||||
|
cmd /c %SDK_RUNNER% -t %APPVEYOR_BUILD_FOLDER%\.github\scripts\windows\build_task.bat
|
||||||
|
if %errorlevel% neq 0 exit /b 3
|
||||||
|
|
||||||
|
exit /b 0
|
||||||
|
|
@ -0,0 +1,73 @@
|
||||||
|
@echo off
|
||||||
|
|
||||||
|
if "%APPVEYOR%" equ "True" rmdir /s /q C:\cygwin >NUL 2>NUL
|
||||||
|
if %errorlevel% neq 0 exit /b 3
|
||||||
|
if "%APPVEYOR%" equ "True" rmdir /s /q C:\cygwin64 >NUL 2>NUL
|
||||||
|
if %errorlevel% neq 0 exit /b 3
|
||||||
|
if "%APPVEYOR%" equ "True" rmdir /s /q C:\mingw >NUL 2>NUL
|
||||||
|
if %errorlevel% neq 0 exit /b 3
|
||||||
|
if "%APPVEYOR%" equ "True" rmdir /s /q C:\mingw-w64 >NUL 2>NUL
|
||||||
|
if %errorlevel% neq 0 exit /b 3
|
||||||
|
if "%APPVEYOR%" equ "True" rmdir /s /q C:\msys64 >NUL 2>NUL
|
||||||
|
if %errorlevel% neq 0 exit /b 3
|
||||||
|
if "%APPVEYOR%" equ "True" rmdir /s /q c:\OpenSSL-Win32 >NUL 2>NUL
|
||||||
|
if %errorlevel% neq 0 exit /b 3
|
||||||
|
if "%APPVEYOR%" equ "True" rmdir /s /q c:\OpenSSL-Win64 >NUL 2>NUL
|
||||||
|
if %errorlevel% neq 0 exit /b 3
|
||||||
|
if "%APPVEYOR%" equ "True" rmdir /s /q c:\OpenSSL-v11-Win32 >NUL 2>NUL
|
||||||
|
if %errorlevel% neq 0 exit /b 3
|
||||||
|
if "%APPVEYOR%" equ "True" rmdir /s /q c:\OpenSSL-v11-Win64 >NUL 2>NUL
|
||||||
|
if %errorlevel% neq 0 exit /b 3
|
||||||
|
if "%APPVEYOR%" equ "True" del /f /q C:\Windows\System32\libcrypto-1_1-x64.dll >NUL 2>NUL
|
||||||
|
if %errorlevel% neq 0 exit /b 3
|
||||||
|
if "%APPVEYOR%" equ "True" del /f /q C:\Windows\System32\libssl-1_1-x64.dll >NUL 2>NUL
|
||||||
|
if %errorlevel% neq 0 exit /b 3
|
||||||
|
|
||||||
|
cd /D %APPVEYOR_BUILD_FOLDER%
|
||||||
|
if %errorlevel% neq 0 exit /b 3
|
||||||
|
|
||||||
|
if /i "%APPVEYOR_REPO_BRANCH:~0,4%" equ "php-" (
|
||||||
|
set BRANCH=%APPVEYOR_REPO_BRANCH:~4,3%
|
||||||
|
) else (
|
||||||
|
set BRANCH=master
|
||||||
|
)
|
||||||
|
set STABILITY=staging
|
||||||
|
set DEPS_DIR=%PHP_BUILD_CACHE_BASE_DIR%\deps-%BRANCH%-%PHP_SDK_VS%-%PHP_SDK_ARCH%
|
||||||
|
rem SDK is cached, deps info is cached as well
|
||||||
|
echo Updating dependencies in %DEPS_DIR%
|
||||||
|
cmd /c phpsdk_deps --update --no-backup --branch %BRANCH% --stability %STABILITY% --deps %DEPS_DIR% --crt %PHP_BUILD_CRT%
|
||||||
|
if %errorlevel% neq 0 exit /b 3
|
||||||
|
|
||||||
|
rem Something went wrong, most likely when concurrent builds were to fetch deps
|
||||||
|
rem updates. It might be, that some locking mechanism is needed.
|
||||||
|
if not exist "%DEPS_DIR%" (
|
||||||
|
cmd /c phpsdk_deps --update --force --no-backup --branch %BRANCH% --stability %STABILITY% --deps %DEPS_DIR%
|
||||||
|
)
|
||||||
|
if %errorlevel% neq 0 exit /b 3
|
||||||
|
|
||||||
|
cmd /c buildconf.bat --force
|
||||||
|
if %errorlevel% neq 0 exit /b 3
|
||||||
|
|
||||||
|
if "%THREAD_SAFE%" equ "0" set ADD_CONF=%ADD_CONF% --disable-zts
|
||||||
|
if "%INTRINSICS%" neq "" set ADD_CONF=%ADD_CONF% --enable-native-intrinsics=%INTRINSICS%
|
||||||
|
|
||||||
|
set EXT_EXCLUDE_FROM_TEST=snmp,oci8_12c,pdo_oci,pdo_firebird,ldap,imap,ftp
|
||||||
|
if "%OPCACHE%" equ "0" set EXT_EXCLUDE_FROM_TEST=%EXT_EXCLUDE_FROM_TEST%,opcache
|
||||||
|
|
||||||
|
set CFLAGS=/W1 /WX
|
||||||
|
|
||||||
|
cmd /c configure.bat ^
|
||||||
|
--enable-snapshot-build ^
|
||||||
|
--disable-debug-pack ^
|
||||||
|
--enable-com-dotnet=shared ^
|
||||||
|
--without-analyzer ^
|
||||||
|
--enable-object-out-dir=%PHP_BUILD_OBJ_DIR% ^
|
||||||
|
--with-php-build=%DEPS_DIR% ^
|
||||||
|
%ADD_CONF% ^
|
||||||
|
--with-test-ini-ext-exclude=%EXT_EXCLUDE_FROM_TEST%
|
||||||
|
if %errorlevel% neq 0 exit /b 3
|
||||||
|
|
||||||
|
nmake /NOLOGO
|
||||||
|
if %errorlevel% neq 0 exit /b 3
|
||||||
|
|
||||||
|
exit /b 0
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
@echo off
|
||||||
|
|
||||||
|
set SDK_RUNNER=%PHP_BUILD_CACHE_SDK_DIR%\phpsdk-%PHP_BUILD_CRT%-%PLATFORM%.bat
|
||||||
|
if not exist "%SDK_RUNNER%" (
|
||||||
|
echo "%SDK_RUNNER%" doesn't exist
|
||||||
|
exit /b 3
|
||||||
|
)
|
||||||
|
|
||||||
|
cmd /c %SDK_RUNNER% -t %APPVEYOR_BUILD_FOLDER%\.github\scripts\windows\test_task.bat
|
||||||
|
if %errorlevel% neq 0 exit /b 3
|
||||||
|
|
||||||
|
exit /b 0
|
||||||
|
|
@ -0,0 +1,107 @@
|
||||||
|
@echo off
|
||||||
|
|
||||||
|
set NO_INTERACTION=1
|
||||||
|
set REPORT_EXIT_STATUS=1
|
||||||
|
set SKIP_IO_CAPTURE_TESTS=1
|
||||||
|
|
||||||
|
if /i "%APPVEYOR_REPO_BRANCH:~0,4%" equ "php-" (
|
||||||
|
set BRANCH=%APPVEYOR_REPO_BRANCH:~4,3%
|
||||||
|
set STABILITY=stable
|
||||||
|
) else (
|
||||||
|
set BRANCH=master
|
||||||
|
set STABILITY=staging
|
||||||
|
)
|
||||||
|
set DEPS_DIR=%PHP_BUILD_CACHE_BASE_DIR%\deps-%BRANCH%-%PHP_SDK_VS%-%PHP_SDK_ARCH%
|
||||||
|
if not exist "%DEPS_DIR%" (
|
||||||
|
echo "%DEPS_DIR%" doesn't exist
|
||||||
|
exit /b 3
|
||||||
|
)
|
||||||
|
|
||||||
|
rem setup MySQL related exts
|
||||||
|
set MYSQL_PWD=Password12!
|
||||||
|
set MYSQL_TEST_PASSWD=%MYSQL_PWD%
|
||||||
|
set MYSQL_TEST_USER=root
|
||||||
|
set MYSQL_TEST_HOST=127.0.0.1
|
||||||
|
set MYSQL_TEST_PORT=3306
|
||||||
|
set PDO_MYSQL_TEST_USER=%MYSQL_TEST_USER%
|
||||||
|
set PDO_MYSQL_TEST_PASS=%MYSQL_PWD%
|
||||||
|
set PDO_MYSQL_TEST_HOST=%MYSQL_TEST_HOST%
|
||||||
|
set PDO_MYSQL_TEST_PORT=%MYSQL_TEST_PORT%
|
||||||
|
set PDO_MYSQL_TEST_DSN=mysql:host=%PDO_MYSQL_TEST_HOST%;port=%PDO_MYSQL_TEST_PORT%;dbname=test
|
||||||
|
"C:\Program Files\MySql\MySQL Server 5.7\bin\mysql.exe" --user=%MYSQL_TEST_USER% -e "CREATE DATABASE IF NOT EXISTS test"
|
||||||
|
if %errorlevel% neq 0 exit /b 3
|
||||||
|
|
||||||
|
rem setup PostgreSQL related exts
|
||||||
|
set PGUSER=postgres
|
||||||
|
set PGPASSWORD=Password12!
|
||||||
|
rem set PGSQL_TEST_CONNSTR=host=127.0.0.1 dbname=test port=5432 user=postgres password=Password12!
|
||||||
|
echo ^<?php $conn_str = "host=127.0.0.1 dbname=test port=5432 user=%PGUSER% password=%PGPASSWORD%"; ?^> >> "./ext/pgsql/tests/config.inc"
|
||||||
|
set PDO_PGSQL_TEST_DSN=pgsql:host=127.0.0.1 port=5432 dbname=test user=%PGUSER% password=%PGPASSWORD%
|
||||||
|
"C:\Program Files\PostgreSQL\10\bin\createdb.exe" test
|
||||||
|
if %errorlevel% neq 0 exit /b 3
|
||||||
|
|
||||||
|
rem setup ODBC related exts
|
||||||
|
set ODBC_TEST_USER=sa
|
||||||
|
set ODBC_TEST_PASS=Password12!
|
||||||
|
set ODBC_TEST_DSN=Driver={ODBC Driver 13 for SQL Server};Server=(local)\SQL2017;Database=master;uid=%ODBC_TEST_USER%;pwd=%ODBC_TEST_PASS%
|
||||||
|
set PDOTEST_DSN=odbc:%ODBC_TEST_DSN%
|
||||||
|
|
||||||
|
rem prepare for ext/openssl
|
||||||
|
if "%APPVEYOR%" equ "True" rmdir /s /q C:\OpenSSL-Win32 >NUL 2>NUL
|
||||||
|
if "%APPVEYOR%" equ "True" rmdir /s /q C:\OpenSSL-Win64 >NUL 2>NUL
|
||||||
|
if "%PLATFORM%" == "x64" (
|
||||||
|
set OPENSSLDIR="C:\Program Files\Common Files\SSL"
|
||||||
|
) else (
|
||||||
|
set OPENSSLDIR="C:\Program Files (x86)\Common Files\SSL"
|
||||||
|
)
|
||||||
|
mkdir %OPENSSLDIR%
|
||||||
|
if %errorlevel% neq 0 exit /b 3
|
||||||
|
copy %DEPS_DIR%\template\ssl\openssl.cnf %OPENSSLDIR%
|
||||||
|
if %errorlevel% neq 0 exit /b 3
|
||||||
|
rem set OPENSSL_CONF=%OPENSSLDIR%\openssl.cnf
|
||||||
|
set OPENSSL_CONF=
|
||||||
|
rem set SSLEAY_CONF=
|
||||||
|
|
||||||
|
rem prepare for Opcache
|
||||||
|
if "%OPCACHE%" equ "1" set OPCACHE_OPTS=-d opcache.enable=1 -d opcache.enable_cli=1 -d opcache.protect_memory=1 -d opcache.jit_buffer_size=16M
|
||||||
|
|
||||||
|
rem prepare for enchant
|
||||||
|
mkdir C:\usr\local\lib\enchant-2
|
||||||
|
if %errorlevel% neq 0 exit /b 3
|
||||||
|
copy %DEPS_DIR%\bin\libenchant2_hunspell.dll C:\usr\local\lib\enchant-2
|
||||||
|
if %errorlevel% neq 0 exit /b 3
|
||||||
|
reg add HKEY_CURRENT_USER\SOFTWARE\Enchant\Config /v Module_Dir /t REG_SZ /d c:\enchant_plugins
|
||||||
|
if %errorlevel% neq 0 exit /b 3
|
||||||
|
set PHP_BUILD_CACHE_ENCHANT_DICT_DIR=%PHP_BUILD_CACHE_BASE_DIR%\enchant_dict
|
||||||
|
if not exist "%PHP_BUILD_CACHE_ENCHANT_DICT_DIR%" (
|
||||||
|
echo Creating %PHP_BUILD_CACHE_ENCHANT_DICT_DIR%
|
||||||
|
mkdir "%PHP_BUILD_CACHE_ENCHANT_DICT_DIR%"
|
||||||
|
)
|
||||||
|
if not exist "%PHP_BUILD_CACHE_ENCHANT_DICT_DIR%\en_US.aff" (
|
||||||
|
echo Fetching enchant dicts
|
||||||
|
pushd %PHP_BUILD_CACHE_ENCHANT_DICT_DIR%
|
||||||
|
del /q *
|
||||||
|
powershell -Command wget http://windows.php.net/downloads/qa/appveyor/ext/enchant/dict.zip -OutFile dict.zip
|
||||||
|
unzip dict.zip
|
||||||
|
del /q dict.zip
|
||||||
|
popd
|
||||||
|
)
|
||||||
|
mkdir %LOCALAPPDATA%\enchant\hunspell
|
||||||
|
copy %PHP_BUILD_CACHE_ENCHANT_DICT_DIR%\* %LOCALAPPDATA%\enchant\hunspell
|
||||||
|
|
||||||
|
set TEST_PHPDBG_EXECUTABLE=%PHP_BUILD_OBJ_DIR%\Release
|
||||||
|
if "%THREAD_SAFE%" equ "1" set TEST_PHPDBG_EXECUTABLE=%TEST_PHPDBG_EXECUTABLE%_TS
|
||||||
|
set TEST_PHPDBG_EXECUTABLE=%TEST_PHPDBG_EXECUTABLE%\phpdbg.exe
|
||||||
|
|
||||||
|
mkdir c:\tests_tmp
|
||||||
|
|
||||||
|
set TEST_PHP_JUNIT=c:\junit.out.xml
|
||||||
|
|
||||||
|
cd "%APPVEYOR_BUILD_FOLDER%"
|
||||||
|
nmake test TESTS="%OPCACHE_OPTS% -q --offline --show-diff --show-slow 1000 --set-timeout 120 --temp-source c:\tests_tmp --temp-target c:\tests_tmp %PARALLEL%"
|
||||||
|
|
||||||
|
set EXIT_CODE=%errorlevel%
|
||||||
|
|
||||||
|
appveyor PushArtifact %TEST_PHP_JUNIT%
|
||||||
|
|
||||||
|
exit /b %EXIT_CODE%
|
||||||
|
|
@ -0,0 +1,547 @@
|
||||||
|
name: Nightly
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: "0 1 * * *"
|
||||||
|
workflow_dispatch: ~
|
||||||
|
jobs:
|
||||||
|
GENERATE_MATRIX:
|
||||||
|
name: Generate Matrix
|
||||||
|
if: github.repository_owner == 'php' || github.event_name == 'workflow_dispatch'
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
branches: ${{ steps.set-matrix.outputs.branches }}
|
||||||
|
matrix-include: ${{ steps.set-matrix.outputs.matrix-include }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
# Set fetch-depth to 0 to clone the full repository
|
||||||
|
# including all branches. This is required to find
|
||||||
|
# the correct commit hashes.
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: Grab the commit mapping
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: branch-commit-cache.json
|
||||||
|
# The cache key needs to change every time for the
|
||||||
|
# cache to be updated after this job finishes.
|
||||||
|
key: nightly-${{ github.run_id }}-${{ github.run_attempt }}
|
||||||
|
restore-keys: |
|
||||||
|
nightly-
|
||||||
|
- name: Generate Matrix
|
||||||
|
id: set-matrix
|
||||||
|
run: php .github/nightly_matrix.php "${{ github.event_name }}" "${{ github.run_attempt }}"
|
||||||
|
LINUX_X64:
|
||||||
|
needs: GENERATE_MATRIX
|
||||||
|
if: ${{ needs.GENERATE_MATRIX.outputs.branches != '[]' }}
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
branch: ${{ fromJson(needs.GENERATE_MATRIX.outputs.branches) }}
|
||||||
|
configuration_parameters: ['']
|
||||||
|
debug: [true, false]
|
||||||
|
name: ['']
|
||||||
|
run_tests_parameters: ['']
|
||||||
|
test_function_jit: [true]
|
||||||
|
zts: [true, false]
|
||||||
|
include: ${{ fromJson(needs.GENERATE_MATRIX.outputs.matrix-include) }}
|
||||||
|
name: "${{ matrix.branch.name }}_LINUX_X64${{ matrix.name }}_${{ matrix.debug && 'DEBUG' || 'RELEASE' }}_${{ matrix.zts && 'ZTS' || 'NTS' }}"
|
||||||
|
runs-on: ubuntu-20.04
|
||||||
|
steps:
|
||||||
|
- name: git checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
ref: ${{ matrix.branch.ref }}
|
||||||
|
- name: Create MSSQL container
|
||||||
|
uses: ./.github/actions/setup-mssql
|
||||||
|
- name: Create Oracle container
|
||||||
|
uses: ./.github/actions/setup-oracle
|
||||||
|
- name: apt
|
||||||
|
uses: ./.github/actions/apt-x64
|
||||||
|
- name: ./configure
|
||||||
|
uses: ./.github/actions/configure-x64
|
||||||
|
with:
|
||||||
|
configurationParameters: >-
|
||||||
|
${{ matrix.configuration_parameters }}
|
||||||
|
--${{ matrix.debug && 'enable' || 'disable' }}-debug
|
||||||
|
--${{ matrix.zts && 'enable' || 'disable' }}-zts
|
||||||
|
- name: make
|
||||||
|
run: make -j$(/usr/bin/nproc) >/dev/null
|
||||||
|
- name: make install
|
||||||
|
uses: ./.github/actions/install-linux
|
||||||
|
- name: Setup
|
||||||
|
uses: ./.github/actions/setup-x64
|
||||||
|
- name: Test
|
||||||
|
uses: ./.github/actions/test-linux
|
||||||
|
with:
|
||||||
|
runTestsParameters: >-
|
||||||
|
${{ matrix.run_tests_parameters }}
|
||||||
|
- name: Test Tracing JIT
|
||||||
|
uses: ./.github/actions/test-linux
|
||||||
|
with:
|
||||||
|
runTestsParameters: >-
|
||||||
|
${{ matrix.run_tests_parameters }}
|
||||||
|
-d zend_extension=opcache.so
|
||||||
|
-d opcache.enable_cli=1
|
||||||
|
-d opcache.jit_buffer_size=16M
|
||||||
|
- name: Test OpCache
|
||||||
|
uses: ./.github/actions/test-linux
|
||||||
|
with:
|
||||||
|
runTestsParameters: >-
|
||||||
|
${{ matrix.run_tests_parameters }}
|
||||||
|
-d zend_extension=opcache.so
|
||||||
|
-d opcache.enable_cli=1
|
||||||
|
- name: Test Function JIT
|
||||||
|
# ASAN frequently timeouts. Each test run takes ~90 minutes, we can
|
||||||
|
# avoid running into the 6 hour timeout by skipping the function JIT.
|
||||||
|
if: matrix.test_function_jit
|
||||||
|
uses: ./.github/actions/test-linux
|
||||||
|
with:
|
||||||
|
runTestsParameters: >-
|
||||||
|
${{ matrix.run_tests_parameters }}
|
||||||
|
-d zend_extension=opcache.so
|
||||||
|
-d opcache.enable_cli=1
|
||||||
|
-d opcache.jit_buffer_size=16M
|
||||||
|
-d opcache.jit=1205
|
||||||
|
- name: Verify generated files are up to date
|
||||||
|
uses: ./.github/actions/verify-generated-files
|
||||||
|
LINUX_X32:
|
||||||
|
needs: GENERATE_MATRIX
|
||||||
|
if: ${{ needs.GENERATE_MATRIX.outputs.branches != '[]' }}
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
branch: ${{ fromJson(needs.GENERATE_MATRIX.outputs.branches) }}
|
||||||
|
debug: [true, false]
|
||||||
|
zts: [true, false]
|
||||||
|
name: "${{ matrix.branch.name }}_LINUX_X32_${{ matrix.debug && 'DEBUG' || 'RELEASE' }}_${{ matrix.zts && 'ZTS' || 'NTS' }}"
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: ubuntu:20.04
|
||||||
|
env:
|
||||||
|
MYSQL_TEST_HOST: mysql
|
||||||
|
PDO_MYSQL_TEST_DSN: mysql:host=mysql;dbname=test
|
||||||
|
PDO_MYSQL_TEST_HOST: mysql
|
||||||
|
services:
|
||||||
|
mysql:
|
||||||
|
image: mysql:8
|
||||||
|
ports:
|
||||||
|
- 3306:3306
|
||||||
|
env:
|
||||||
|
MYSQL_DATABASE: test
|
||||||
|
MYSQL_ROOT_PASSWORD: root
|
||||||
|
steps:
|
||||||
|
- name: git checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
ref: ${{ matrix.branch.ref }}
|
||||||
|
- name: apt
|
||||||
|
uses: ./.github/actions/apt-x32
|
||||||
|
- name: ./configure
|
||||||
|
uses: ./.github/actions/configure-x32
|
||||||
|
with:
|
||||||
|
configurationParameters: >-
|
||||||
|
--${{ matrix.debug && 'enable' || 'disable' }}-debug
|
||||||
|
--${{ matrix.zts && 'enable' || 'disable' }}-zts
|
||||||
|
- name: make
|
||||||
|
run: make -j$(/usr/bin/nproc) >/dev/null
|
||||||
|
- name: make install
|
||||||
|
uses: ./.github/actions/install-linux-x32
|
||||||
|
- name: Test
|
||||||
|
uses: ./.github/actions/test-linux
|
||||||
|
with:
|
||||||
|
runTestsParameters: >-
|
||||||
|
${{ matrix.run_tests_parameters }}
|
||||||
|
- name: Test Tracing JIT
|
||||||
|
uses: ./.github/actions/test-linux
|
||||||
|
with:
|
||||||
|
runTestsParameters: >-
|
||||||
|
${{ matrix.run_tests_parameters }}
|
||||||
|
-d zend_extension=opcache.so
|
||||||
|
-d opcache.enable_cli=1
|
||||||
|
-d opcache.jit_buffer_size=16M
|
||||||
|
- name: Test OpCache
|
||||||
|
uses: ./.github/actions/test-linux
|
||||||
|
with:
|
||||||
|
runTestsParameters: >-
|
||||||
|
${{ matrix.run_tests_parameters }}
|
||||||
|
-d zend_extension=opcache.so
|
||||||
|
-d opcache.enable_cli=1
|
||||||
|
- name: Test Function JIT
|
||||||
|
uses: ./.github/actions/test-linux
|
||||||
|
with:
|
||||||
|
runTestsParameters: >-
|
||||||
|
${{ matrix.run_tests_parameters }}
|
||||||
|
-d zend_extension=opcache.so
|
||||||
|
-d opcache.enable_cli=1
|
||||||
|
-d opcache.jit_buffer_size=16M
|
||||||
|
-d opcache.jit=1205
|
||||||
|
MACOS:
|
||||||
|
needs: GENERATE_MATRIX
|
||||||
|
if: ${{ needs.GENERATE_MATRIX.outputs.branches != '[]' }}
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
branch: ${{ fromJson(needs.GENERATE_MATRIX.outputs.branches) }}
|
||||||
|
debug: [true, false]
|
||||||
|
zts: [true, false]
|
||||||
|
name: "${{ matrix.branch.name }}_MACOS_${{ matrix.debug && 'DEBUG' || 'RELEASE' }}_${{ matrix.zts && 'ZTS' || 'NTS' }}"
|
||||||
|
runs-on: macos-11
|
||||||
|
steps:
|
||||||
|
- name: git checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
ref: ${{ matrix.branch.ref }}
|
||||||
|
- name: brew
|
||||||
|
uses: ./.github/actions/brew
|
||||||
|
- name: ./configure
|
||||||
|
uses: ./.github/actions/configure-macos
|
||||||
|
with:
|
||||||
|
configurationParameters: >-
|
||||||
|
--${{ matrix.debug && 'enable' || 'disable' }}-debug
|
||||||
|
--${{ matrix.zts && 'enable' || 'disable' }}-zts
|
||||||
|
- name: make
|
||||||
|
run: |-
|
||||||
|
export PATH="/usr/local/opt/bison/bin:$PATH"
|
||||||
|
make -j$(sysctl -n hw.logicalcpu) >/dev/null
|
||||||
|
- name: make install
|
||||||
|
run: sudo make install
|
||||||
|
- name: Test
|
||||||
|
uses: ./.github/actions/test-macos
|
||||||
|
- name: Test Tracing JIT
|
||||||
|
uses: ./.github/actions/test-macos
|
||||||
|
with:
|
||||||
|
runTestsParameters: >-
|
||||||
|
-d zend_extension=opcache.so
|
||||||
|
-d opcache.enable_cli=1
|
||||||
|
-d opcache.protect_memory=1
|
||||||
|
-d opcache.jit_buffer_size=16M
|
||||||
|
- name: Test OpCache
|
||||||
|
uses: ./.github/actions/test-macos
|
||||||
|
with:
|
||||||
|
runTestsParameters: >-
|
||||||
|
-d zend_extension=opcache.so
|
||||||
|
-d opcache.enable_cli=1
|
||||||
|
-d opcache.protect_memory=1
|
||||||
|
- name: Test Function JIT
|
||||||
|
uses: ./.github/actions/test-macos
|
||||||
|
with:
|
||||||
|
runTestsParameters: >-
|
||||||
|
-d zend_extension=opcache.so
|
||||||
|
-d opcache.enable_cli=1
|
||||||
|
-d opcache.protect_memory=1
|
||||||
|
-d opcache.jit_buffer_size=16M
|
||||||
|
-d opcache.jit=1205
|
||||||
|
- name: Verify generated files are up to date
|
||||||
|
uses: ./.github/actions/verify-generated-files
|
||||||
|
COVERAGE_DEBUG_NTS:
|
||||||
|
if: github.repository_owner == 'php' || github.event_name == 'workflow_dispatch'
|
||||||
|
runs-on: ubuntu-20.04
|
||||||
|
steps:
|
||||||
|
- name: git checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
- name: Create MSSQL container
|
||||||
|
uses: ./.github/actions/setup-mssql
|
||||||
|
- name: Create Oracle container
|
||||||
|
uses: ./.github/actions/setup-oracle
|
||||||
|
- name: apt
|
||||||
|
uses: ./.github/actions/apt-x64
|
||||||
|
- name: Install gcovr
|
||||||
|
run: sudo -H pip install gcovr
|
||||||
|
- name: ./configure
|
||||||
|
uses: ./.github/actions/configure-x64
|
||||||
|
with:
|
||||||
|
configurationParameters: --enable-debug --disable-zts --enable-gcov
|
||||||
|
- name: make
|
||||||
|
run: make -j$(/usr/bin/nproc) >/dev/null
|
||||||
|
- name: make install
|
||||||
|
uses: ./.github/actions/install-linux
|
||||||
|
- name: Setup
|
||||||
|
uses: ./.github/actions/setup-x64
|
||||||
|
# We only test with OpCache, the difference in coverage is negligible
|
||||||
|
- name: Test OpCache
|
||||||
|
uses: ./.github/actions/test-linux
|
||||||
|
with:
|
||||||
|
runTestsParameters: >-
|
||||||
|
-d zend_extension=opcache.so
|
||||||
|
-d opcache.enable_cli=1
|
||||||
|
- name: Upload Test Coverage to Codecov.io
|
||||||
|
if: always()
|
||||||
|
run: bash <(curl -s https://codecov.io/bash)
|
||||||
|
COMMUNITY:
|
||||||
|
needs: GENERATE_MATRIX
|
||||||
|
if: ${{ needs.GENERATE_MATRIX.outputs.branches != '[]' }}
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
branch: ${{ fromJson(needs.GENERATE_MATRIX.outputs.branches) }}
|
||||||
|
name: "${{ matrix.branch.name }}_COMMUNITY"
|
||||||
|
runs-on: ubuntu-20.04
|
||||||
|
env:
|
||||||
|
UBSAN_OPTIONS: print_stacktrace=1
|
||||||
|
USE_ZEND_ALLOC: 0
|
||||||
|
USE_TRACKED_ALLOC: 1
|
||||||
|
steps:
|
||||||
|
- name: git checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
ref: ${{ matrix.branch.ref }}
|
||||||
|
- name: apt
|
||||||
|
uses: ./.github/actions/apt-x64
|
||||||
|
- name: ./configure
|
||||||
|
uses: ./.github/actions/configure-x64
|
||||||
|
with:
|
||||||
|
configurationParameters: >-
|
||||||
|
--enable-debug
|
||||||
|
--enable-zts
|
||||||
|
CFLAGS='-fsanitize=undefined,address -fno-sanitize-recover -DZEND_TRACK_ARENA_ALLOC'
|
||||||
|
LDFLAGS='-fsanitize=undefined,address'
|
||||||
|
- name: make
|
||||||
|
run: make -j$(/usr/bin/nproc) >/dev/null
|
||||||
|
- name: make install
|
||||||
|
uses: ./.github/actions/install-linux
|
||||||
|
- name: Setup
|
||||||
|
run: |
|
||||||
|
sudo service mysql start
|
||||||
|
mysql -uroot -proot -e "CREATE DATABASE IF NOT EXISTS test"
|
||||||
|
mysql -uroot -proot -e "SET GLOBAL local_infile = true"
|
||||||
|
- name: Enable Opcache and JIT
|
||||||
|
run: |
|
||||||
|
echo zend_extension=opcache.so > /etc/php.d/opcache.ini
|
||||||
|
echo opcache.enable_cli=1 >> /etc/php.d/opcache.ini
|
||||||
|
echo opcache.protect_memory=1 >> /etc/php.d/opcache.ini
|
||||||
|
echo opcache.jit_buffer_size=1G >> /etc/php.d/opcache.ini
|
||||||
|
- name: Test Laravel
|
||||||
|
if: matrix.branch.ref != 'PHP-8.0'
|
||||||
|
run: |
|
||||||
|
git clone https://github.com/laravel/framework.git --branch=master --depth=1
|
||||||
|
cd framework
|
||||||
|
git rev-parse HEAD
|
||||||
|
php /usr/bin/composer install --no-progress --ignore-platform-reqs
|
||||||
|
# Hack to disable a test that hangs
|
||||||
|
php -r '$c = file_get_contents("tests/Filesystem/FilesystemTest.php"); $c = str_replace("*/\n public function testSharedGet()", "* @group skip\n */\n public function testSharedGet()", $c); file_put_contents("tests/Filesystem/FilesystemTest.php", $c);'
|
||||||
|
export ASAN_OPTIONS=exitcode=139
|
||||||
|
php vendor/bin/phpunit --exclude-group skip || EXIT_CODE=$?
|
||||||
|
if [ $EXIT_CODE -gt 128 ]; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
- name: Test Symfony
|
||||||
|
if: matrix.branch.ref != 'PHP-8.0'
|
||||||
|
run: |
|
||||||
|
git clone https://github.com/symfony/symfony.git --depth=1
|
||||||
|
cd symfony
|
||||||
|
git rev-parse HEAD
|
||||||
|
php /usr/bin/composer install --no-progress --ignore-platform-reqs
|
||||||
|
php ./phpunit install
|
||||||
|
# Test causes a heap-buffer-overflow but I cannot reproduce it locally...
|
||||||
|
php -r '$c = file_get_contents("src/Symfony/Component/HtmlSanitizer/Tests/HtmlSanitizerCustomTest.php"); $c = str_replace("public function testSanitizeDeepNestedString()", "/** @group skip */\n public function testSanitizeDeepNestedString()", $c); file_put_contents("src/Symfony/Component/HtmlSanitizer/Tests/HtmlSanitizerCustomTest.php", $c);'
|
||||||
|
# Buggy FFI test in Symfony, see https://github.com/symfony/symfony/issues/47668
|
||||||
|
php -r '$c = file_get_contents("src/Symfony/Component/VarDumper/Tests/Caster/FFICasterTest.php"); $c = str_replace("*/\n public function testCastNonTrailingCharPointer()", "* @group skip\n */\n public function testCastNonTrailingCharPointer()", $c); file_put_contents("src/Symfony/Component/VarDumper/Tests/Caster/FFICasterTest.php", $c);'
|
||||||
|
export ASAN_OPTIONS=exitcode=139
|
||||||
|
export SYMFONY_DEPRECATIONS_HELPER=max[total]=999
|
||||||
|
X=0
|
||||||
|
for component in $(find src/Symfony -mindepth 2 -type f -name phpunit.xml.dist -printf '%h\n'); do
|
||||||
|
php ./phpunit $component --exclude-group tty,benchmark,intl-data,transient --exclude-group skip || EXIT_CODE=$?
|
||||||
|
if [ $EXIT_CODE -gt 128 ]; then
|
||||||
|
X=1;
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
exit $X
|
||||||
|
- name: Test PHPUnit
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
git clone https://github.com/sebastianbergmann/phpunit.git --branch=main --depth=1
|
||||||
|
cd phpunit
|
||||||
|
git rev-parse HEAD
|
||||||
|
export ASAN_OPTIONS=exitcode=139
|
||||||
|
php /usr/bin/composer install --no-progress --ignore-platform-reqs
|
||||||
|
php ./phpunit || EXIT_CODE=$?
|
||||||
|
if [ $EXIT_CODE -gt 128 ]; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
- name: 'Symfony Preloading'
|
||||||
|
if: matrix.branch.ref != 'PHP-8.0'
|
||||||
|
run: |
|
||||||
|
php /usr/bin/composer create-project symfony/symfony-demo symfony_demo --no-progress --ignore-platform-reqs
|
||||||
|
cd symfony_demo
|
||||||
|
git rev-parse HEAD
|
||||||
|
sed -i 's/PHP_SAPI/"cli-server"/g' var/cache/dev/App_KernelDevDebugContainer.preload.php
|
||||||
|
php -d opcache.preload=var/cache/dev/App_KernelDevDebugContainer.preload.php public/index.php
|
||||||
|
- name: Test Wordpress
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
git clone https://github.com/WordPress/wordpress-develop.git wordpress --depth=1
|
||||||
|
cd wordpress
|
||||||
|
git rev-parse HEAD
|
||||||
|
export ASAN_OPTIONS=exitcode=139
|
||||||
|
php /usr/bin/composer install --no-progress --ignore-platform-reqs
|
||||||
|
cp wp-tests-config-sample.php wp-tests-config.php
|
||||||
|
sed -i 's/youremptytestdbnamehere/test/g' wp-tests-config.php
|
||||||
|
sed -i 's/yourusernamehere/root/g' wp-tests-config.php
|
||||||
|
sed -i 's/yourpasswordhere/root/g' wp-tests-config.php
|
||||||
|
php vendor/bin/phpunit || EXIT_CODE=$?
|
||||||
|
if [ $EXIT_CODE -gt 128 ]; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
OPCACHE_VARIATION:
|
||||||
|
needs: GENERATE_MATRIX
|
||||||
|
if: ${{ needs.GENERATE_MATRIX.outputs.branches != '[]' }}
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
branch: ${{ fromJson(needs.GENERATE_MATRIX.outputs.branches) }}
|
||||||
|
name: "${{ matrix.branch.name }}_OPCACHE_VARIATION"
|
||||||
|
runs-on: ubuntu-20.04
|
||||||
|
steps:
|
||||||
|
- name: git checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
ref: ${{ matrix.branch.ref }}
|
||||||
|
- name: Create MSSQL container
|
||||||
|
uses: ./.github/actions/setup-mssql
|
||||||
|
- name: Create Oracle container
|
||||||
|
uses: ./.github/actions/setup-oracle
|
||||||
|
- name: apt
|
||||||
|
uses: ./.github/actions/apt-x64
|
||||||
|
- name: ./configure
|
||||||
|
uses: ./.github/actions/configure-x64
|
||||||
|
with:
|
||||||
|
configurationParameters: >-
|
||||||
|
--enable-debug --disable-zts
|
||||||
|
- name: make
|
||||||
|
run: make -j$(/usr/bin/nproc) >/dev/null
|
||||||
|
- name: make install
|
||||||
|
uses: ./.github/actions/install-linux
|
||||||
|
- name: Setup
|
||||||
|
uses: ./.github/actions/setup-x64
|
||||||
|
- name: Test File Cache (prime shm)
|
||||||
|
uses: ./.github/actions/test-linux
|
||||||
|
with:
|
||||||
|
runTestsParameters: >-
|
||||||
|
-d zend_extension=opcache.so
|
||||||
|
-d opcache.enable_cli=1
|
||||||
|
--file-cache-prime
|
||||||
|
- name: Test File Cache (prime shm, use shm)
|
||||||
|
uses: ./.github/actions/test-linux
|
||||||
|
with:
|
||||||
|
runTestsParameters: >-
|
||||||
|
-d zend_extension=opcache.so
|
||||||
|
-d opcache.enable_cli=1
|
||||||
|
--file-cache-use
|
||||||
|
- name: Test File Cache (prime shm, use file)
|
||||||
|
uses: ./.github/actions/test-linux
|
||||||
|
with:
|
||||||
|
runTestsParameters: >-
|
||||||
|
-d zend_extension=opcache.so
|
||||||
|
-d opcache.enable_cli=1
|
||||||
|
--file-cache-use
|
||||||
|
-d opcache.file_cache_only=1
|
||||||
|
- name: Test File Cache Only (prime)
|
||||||
|
uses: ./.github/actions/test-linux
|
||||||
|
with:
|
||||||
|
runTestsParameters: >-
|
||||||
|
-d zend_extension=opcache.so
|
||||||
|
-d opcache.enable_cli=1
|
||||||
|
--file-cache-prime
|
||||||
|
-d opcache.file_cache_only=1
|
||||||
|
- name: Test File Cache Only (use)
|
||||||
|
uses: ./.github/actions/test-linux
|
||||||
|
with:
|
||||||
|
runTestsParameters: >-
|
||||||
|
-d zend_extension=opcache.so
|
||||||
|
-d opcache.enable_cli=1
|
||||||
|
--file-cache-use
|
||||||
|
-d opcache.file_cache_only=1
|
||||||
|
- name: Verify generated files are up to date
|
||||||
|
uses: ./.github/actions/verify-generated-files
|
||||||
|
MSAN:
|
||||||
|
needs: GENERATE_MATRIX
|
||||||
|
if: ${{ needs.GENERATE_MATRIX.outputs.branches != '[]' }}
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
branch: ${{ fromJson(needs.GENERATE_MATRIX.outputs.branches) }}
|
||||||
|
name: "${{ matrix.branch.name }}_MSAN"
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
steps:
|
||||||
|
- name: git checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
ref: ${{ matrix.branch.ref }}
|
||||||
|
- name: apt
|
||||||
|
uses: ./.github/actions/apt-x64
|
||||||
|
- name: ./configure
|
||||||
|
run: |
|
||||||
|
export CC=clang
|
||||||
|
export CXX=clang++
|
||||||
|
export CFLAGS="-DZEND_TRACK_ARENA_ALLOC"
|
||||||
|
./buildconf --force
|
||||||
|
# msan requires all used libraries to be instrumented,
|
||||||
|
# so we should avoiding linking against anything but libc here
|
||||||
|
./configure \
|
||||||
|
--enable-debug \
|
||||||
|
--enable-zts \
|
||||||
|
--enable-option-checking=fatal \
|
||||||
|
--prefix=/usr \
|
||||||
|
--without-sqlite3 \
|
||||||
|
--without-pdo-sqlite \
|
||||||
|
--without-libxml \
|
||||||
|
--disable-dom \
|
||||||
|
--disable-simplexml \
|
||||||
|
--disable-xml \
|
||||||
|
--disable-xmlreader \
|
||||||
|
--disable-xmlwriter \
|
||||||
|
--without-pcre-jit \
|
||||||
|
--disable-opcache-jit \
|
||||||
|
--enable-phpdbg \
|
||||||
|
--enable-fpm \
|
||||||
|
--with-pdo-mysql=mysqlnd \
|
||||||
|
--with-mysqli=mysqlnd \
|
||||||
|
--disable-mysqlnd-compression-support \
|
||||||
|
--without-pear \
|
||||||
|
--enable-exif \
|
||||||
|
--enable-sysvsem \
|
||||||
|
--enable-sysvshm \
|
||||||
|
--enable-shmop \
|
||||||
|
--enable-pcntl \
|
||||||
|
--enable-mbstring \
|
||||||
|
--disable-mbregex \
|
||||||
|
--enable-sockets \
|
||||||
|
--enable-bcmath \
|
||||||
|
--enable-calendar \
|
||||||
|
--enable-ftp \
|
||||||
|
--enable-zend-test \
|
||||||
|
--enable-werror \
|
||||||
|
--enable-memory-sanitizer \
|
||||||
|
--with-config-file-path=/etc \
|
||||||
|
--with-config-file-scan-dir=/etc/php.d
|
||||||
|
- name: make
|
||||||
|
run: make -j$(/usr/bin/nproc) >/dev/null
|
||||||
|
- name: make install
|
||||||
|
run: |
|
||||||
|
sudo make install
|
||||||
|
sudo mkdir /etc/php.d
|
||||||
|
sudo chmod 777 /etc/php.d
|
||||||
|
echo mysqli.default_socket=/var/run/mysqld/mysqld.sock > /etc/php.d/mysqli.ini
|
||||||
|
echo pdo_mysql.default_socket=/var/run/mysqld/mysqld.sock > /etc/php.d/pdo_mysql.ini
|
||||||
|
- name: Setup
|
||||||
|
run: |
|
||||||
|
set -x
|
||||||
|
sudo service mysql start
|
||||||
|
mysql -uroot -proot -e "CREATE DATABASE IF NOT EXISTS test"
|
||||||
|
# Ensure local_infile tests can run.
|
||||||
|
mysql -uroot -proot -e "SET GLOBAL local_infile = true"
|
||||||
|
sudo locale-gen de_DE
|
||||||
|
- name: Test
|
||||||
|
uses: ./.github/actions/test-linux
|
||||||
|
with:
|
||||||
|
runTestsParameters: >-
|
||||||
|
--msan
|
||||||
|
- name: Test Opcache
|
||||||
|
uses: ./.github/actions/test-linux
|
||||||
|
with:
|
||||||
|
runTestsParameters: >-
|
||||||
|
--msan
|
||||||
|
-d zend_extension=opcache.so
|
||||||
|
-d opcache.enable_cli=1
|
||||||
|
- name: Verify generated files are up to date
|
||||||
|
uses: ./.github/actions/verify-generated-files
|
||||||
|
|
@ -0,0 +1,133 @@
|
||||||
|
name: Push
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
paths-ignore:
|
||||||
|
- docs/*
|
||||||
|
- NEWS
|
||||||
|
- UPGRADING
|
||||||
|
- UPGRADING.INTERNALS
|
||||||
|
- README.md
|
||||||
|
- CONTRIBUTING.md
|
||||||
|
- CODING_STANDARDS.md
|
||||||
|
branches:
|
||||||
|
- PHP-7.4
|
||||||
|
- PHP-8.0
|
||||||
|
- PHP-8.1
|
||||||
|
- master
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- '**'
|
||||||
|
jobs:
|
||||||
|
LINUX_X64:
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- debug: true
|
||||||
|
zts: false
|
||||||
|
- debug: false
|
||||||
|
zts: true
|
||||||
|
name: "LINUX_X64_${{ matrix.debug && 'DEBUG' || 'RELEASE' }}_${{ matrix.zts && 'ZTS' || 'NTS' }}"
|
||||||
|
runs-on: ubuntu-20.04
|
||||||
|
steps:
|
||||||
|
- name: git checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
- name: Create MSSQL container
|
||||||
|
uses: ./.github/actions/setup-mssql
|
||||||
|
- name: Create Oracle container
|
||||||
|
uses: ./.github/actions/setup-oracle
|
||||||
|
- name: apt
|
||||||
|
uses: ./.github/actions/apt-x64
|
||||||
|
- name: ./configure
|
||||||
|
uses: ./.github/actions/configure-x64
|
||||||
|
with:
|
||||||
|
configurationParameters: >-
|
||||||
|
--${{ matrix.debug && 'enable' || 'disable' }}-debug
|
||||||
|
--${{ matrix.zts && 'enable' || 'disable' }}-zts
|
||||||
|
- name: make
|
||||||
|
run: make -j$(/usr/bin/nproc) >/dev/null
|
||||||
|
- name: make install
|
||||||
|
uses: ./.github/actions/install-linux
|
||||||
|
- name: Setup
|
||||||
|
uses: ./.github/actions/setup-x64
|
||||||
|
- name: Test
|
||||||
|
uses: ./.github/actions/test-linux
|
||||||
|
- name: Test Tracing JIT
|
||||||
|
uses: ./.github/actions/test-linux
|
||||||
|
with:
|
||||||
|
runTestsParameters: >-
|
||||||
|
-d zend_extension=opcache.so
|
||||||
|
-d opcache.enable_cli=1
|
||||||
|
-d opcache.jit_buffer_size=16M
|
||||||
|
- name: Verify generated files are up to date
|
||||||
|
uses: ./.github/actions/verify-generated-files
|
||||||
|
LINUX_X32:
|
||||||
|
name: LINUX_X32_DEBUG_ZTS
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: ubuntu:20.04
|
||||||
|
env:
|
||||||
|
MYSQL_TEST_HOST: mysql
|
||||||
|
PDO_MYSQL_TEST_DSN: mysql:host=mysql;dbname=test
|
||||||
|
PDO_MYSQL_TEST_HOST: mysql
|
||||||
|
services:
|
||||||
|
mysql:
|
||||||
|
image: mysql:8
|
||||||
|
ports:
|
||||||
|
- 3306:3306
|
||||||
|
env:
|
||||||
|
MYSQL_DATABASE: test
|
||||||
|
MYSQL_ROOT_PASSWORD: root
|
||||||
|
steps:
|
||||||
|
- name: git checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
- name: apt
|
||||||
|
uses: ./.github/actions/apt-x32
|
||||||
|
- name: ./configure
|
||||||
|
uses: ./.github/actions/configure-x32
|
||||||
|
with:
|
||||||
|
configurationParameters: >-
|
||||||
|
--enable-debug
|
||||||
|
--enable-zts
|
||||||
|
- name: make
|
||||||
|
run: make -j$(/usr/bin/nproc) >/dev/null
|
||||||
|
- name: make install
|
||||||
|
uses: ./.github/actions/install-linux-x32
|
||||||
|
- name: Test
|
||||||
|
uses: ./.github/actions/test-linux
|
||||||
|
- name: Test Tracing JIT
|
||||||
|
uses: ./.github/actions/test-linux
|
||||||
|
with:
|
||||||
|
runTestsParameters: >-
|
||||||
|
-d zend_extension=opcache.so
|
||||||
|
-d opcache.enable_cli=1
|
||||||
|
-d opcache.jit_buffer_size=16M
|
||||||
|
MACOS_DEBUG_NTS:
|
||||||
|
runs-on: macos-11
|
||||||
|
steps:
|
||||||
|
- name: git checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
- name: brew
|
||||||
|
uses: ./.github/actions/brew
|
||||||
|
- name: ./configure
|
||||||
|
uses: ./.github/actions/configure-macos
|
||||||
|
with:
|
||||||
|
configurationParameters: --enable-debug --disable-zts
|
||||||
|
- name: make
|
||||||
|
run: |-
|
||||||
|
export PATH="/usr/local/opt/bison/bin:$PATH"
|
||||||
|
make -j$(sysctl -n hw.logicalcpu) >/dev/null
|
||||||
|
- name: make install
|
||||||
|
run: sudo make install
|
||||||
|
- name: Test
|
||||||
|
uses: ./.github/actions/test-macos
|
||||||
|
- name: Test Tracing JIT
|
||||||
|
uses: ./.github/actions/test-macos
|
||||||
|
with:
|
||||||
|
runTestsParameters: >-
|
||||||
|
-d zend_extension=opcache.so
|
||||||
|
-d opcache.enable_cli=1
|
||||||
|
-d opcache.protect_memory=1
|
||||||
|
-d opcache.jit_buffer_size=16M
|
||||||
|
- name: Verify generated files are up to date
|
||||||
|
uses: ./.github/actions/verify-generated-files
|
||||||
|
|
@ -0,0 +1,290 @@
|
||||||
|
# These files are generated during building or development and are intentionally
|
||||||
|
# untracked to ignore by Git. For other development environment specific files,
|
||||||
|
# such as editor configuration, a good practice is to exclude them using the
|
||||||
|
# .git/info/exclude in the cloned repository or a global .gitignore file.
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Common files ignored across the repository
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# Backup copies created by various editors or development tools
|
||||||
|
*~
|
||||||
|
|
||||||
|
# Patches downloaded to patch files or to apply open source contributions
|
||||||
|
*.patch
|
||||||
|
|
||||||
|
# Swap files created by editors and tools to indicate a locked file
|
||||||
|
*.swp
|
||||||
|
|
||||||
|
# Various temporary generated files
|
||||||
|
*.tmp
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Generated by the PHP build system
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# Archive library containing .o files, generated during build process
|
||||||
|
*.a
|
||||||
|
|
||||||
|
# Libtool library files generated during build process
|
||||||
|
*.la
|
||||||
|
|
||||||
|
# Directories created by Libtool for storing generated library files
|
||||||
|
.libs/
|
||||||
|
|
||||||
|
# Library object files generated during build process
|
||||||
|
*.lo
|
||||||
|
|
||||||
|
# Temporary library object files generated by compiler and libtool due to failure
|
||||||
|
*.loT
|
||||||
|
|
||||||
|
# Standard object files generated during build process
|
||||||
|
*.o
|
||||||
|
|
||||||
|
# Cache directories created by Autoconf tools
|
||||||
|
autom4te.cache/
|
||||||
|
|
||||||
|
# Cache file(s) generated by Autoconf's configure when run as `configure -C`
|
||||||
|
config.cache
|
||||||
|
|
||||||
|
# A log file(s) generated by Autoconf during *nix build system
|
||||||
|
config.log
|
||||||
|
|
||||||
|
# Helper(s) generated by *nix build system to save the last configure command
|
||||||
|
config.nice
|
||||||
|
|
||||||
|
# Generated by Autoconf's configure script for instantiating templates
|
||||||
|
config.status
|
||||||
|
|
||||||
|
# Main *nix build system configuration script(s) generated by Autoconf
|
||||||
|
configure
|
||||||
|
|
||||||
|
# Generated by `./configure` when test programs create temporary files
|
||||||
|
confdefs.h
|
||||||
|
conftest*
|
||||||
|
|
||||||
|
# Generated by configure scripts on all systems
|
||||||
|
/main/internal_functions.c
|
||||||
|
/main/internal_functions_cli.c
|
||||||
|
|
||||||
|
# The Libtool script(s) generated by the *nix build system
|
||||||
|
libtool
|
||||||
|
|
||||||
|
# Makefile(s) generated from Makefile fragment templates by `./configure`
|
||||||
|
Makefile
|
||||||
|
Makefile.fragments
|
||||||
|
Makefile.objects
|
||||||
|
|
||||||
|
# Directories for shared object files and headers generated by `./configure`
|
||||||
|
include/
|
||||||
|
libs/
|
||||||
|
modules/
|
||||||
|
|
||||||
|
# Used by build/gen_stub.php
|
||||||
|
build/PHP-Parser-*
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Configuration headers generated by the PHP build system
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
config.h
|
||||||
|
config.h.in
|
||||||
|
/ext/date/lib/timelib_config.h
|
||||||
|
/main/build-defs.h
|
||||||
|
/main/php_config.h.in
|
||||||
|
/main/php_config.h
|
||||||
|
/Zend/zend_config.h
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Manual (man 1 and 8) pages generated from templates for *nix alike systems
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
/ext/phar/phar.1
|
||||||
|
/ext/phar/phar.phar.1
|
||||||
|
/sapi/cgi/php-cgi.1
|
||||||
|
/sapi/cli/php.1
|
||||||
|
/sapi/fpm/php-fpm.1
|
||||||
|
/sapi/fpm/php-fpm.8
|
||||||
|
/sapi/phpdbg/phpdbg.1
|
||||||
|
/scripts/man1/*.1
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# SAPIs specific ignores
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
/sapi/apache2handler/libphp.module
|
||||||
|
/sapi/fpm/fpm/php-cgi
|
||||||
|
/sapi/fpm/init.d.php-fpm
|
||||||
|
/sapi/fpm/php-fpm.conf
|
||||||
|
/sapi/fpm/php-fpm.service
|
||||||
|
/sapi/fpm/status.html
|
||||||
|
/sapi/fpm/www.conf
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Executable binaries and scripts generated during the build process
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
/ext/phar/phar.phar
|
||||||
|
/ext/phar/phar.php
|
||||||
|
/pear/install-pear-nozlib.phar
|
||||||
|
/sapi/cgi/php-cgi
|
||||||
|
/sapi/fpm/php-fpm
|
||||||
|
/sapi/phpdbg/phpdbg
|
||||||
|
/scripts/php-config
|
||||||
|
/scripts/phpize
|
||||||
|
php
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Lexer files generated by re2c
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
/ext/json/json_scanner.c
|
||||||
|
/ext/json/php_json_scanner_defs.h
|
||||||
|
/ext/pdo/pdo_sql_parser.c
|
||||||
|
/ext/phar/phar_path_check.c
|
||||||
|
/ext/standard/url_scanner_ex.c
|
||||||
|
/ext/standard/var_unserializer.c
|
||||||
|
/sapi/phpdbg/phpdbg_lexer.c
|
||||||
|
/Zend/zend_ini_scanner.c
|
||||||
|
/Zend/zend_ini_scanner_defs.h
|
||||||
|
/Zend/zend_language_scanner.c
|
||||||
|
/Zend/zend_language_scanner_defs.h
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# PHP parser files generated by bison during the build process
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
/ext/json/json_parser.tab.h
|
||||||
|
/ext/json/json_parser.tab.c
|
||||||
|
/sapi/phpdbg/phpdbg_parser.c
|
||||||
|
/sapi/phpdbg/phpdbg_parser.h
|
||||||
|
/sapi/phpdbg/phpdbg_parser.output
|
||||||
|
/Zend/zend_ini_parser.c
|
||||||
|
/Zend/zend_ini_parser.h
|
||||||
|
/Zend/zend_ini_parser.output
|
||||||
|
/Zend/zend_language_parser.c
|
||||||
|
/Zend/zend_language_parser.h
|
||||||
|
/Zend/zend_language_parser.output
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Extensions files
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# Miscellaneous extensions files
|
||||||
|
/ext/opcache/jit/zend_jit_x86.c
|
||||||
|
/ext/opcache/minilua
|
||||||
|
|
||||||
|
# Generated by `cd ext/name && phpize && ./configure`
|
||||||
|
/ext/*/build/
|
||||||
|
/ext/*/configure.ac
|
||||||
|
/ext/*/run-tests.php
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Generated by Windows build system
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# Generated by `/buildconf.bat`
|
||||||
|
/configure.bat
|
||||||
|
/configure.js
|
||||||
|
|
||||||
|
# Generated by `/configure.(bat|js)` (architecture dependent)
|
||||||
|
/config.nice.bat
|
||||||
|
|
||||||
|
# NTS debug build x86
|
||||||
|
/Debug/
|
||||||
|
|
||||||
|
# ZTS debug build x86
|
||||||
|
/Debug_TS/
|
||||||
|
|
||||||
|
# NTS build x86
|
||||||
|
/Release/
|
||||||
|
|
||||||
|
# ZTS build x86
|
||||||
|
/Release_TS/
|
||||||
|
|
||||||
|
# Generated by x64 compiler, includes Debug, Debug_TS, Release, Release_TS
|
||||||
|
/x64/
|
||||||
|
|
||||||
|
# Miscellaneous files generated by Windows build system
|
||||||
|
/main/config.w32.h
|
||||||
|
/win32/build/deplister.exe
|
||||||
|
/win32/build/deplister.obj
|
||||||
|
/win32/*.aps
|
||||||
|
/win32/*.positions
|
||||||
|
/win32/*.suo
|
||||||
|
/win32/ext
|
||||||
|
/win32/syslog.reg
|
||||||
|
/win32/wsyslog.h
|
||||||
|
|
||||||
|
# Standard object files generated by Visual Studio
|
||||||
|
*.obj
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Tests
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# Generated by `./run-tests.php` upon failure
|
||||||
|
**/tests/**/*.diff
|
||||||
|
**/tests/**/*.out*
|
||||||
|
**/tests/**/*.php
|
||||||
|
**/tests/**/*.exp
|
||||||
|
**/tests/**/*.log
|
||||||
|
**/tests/**/*.sh
|
||||||
|
|
||||||
|
# Generated by some test cases
|
||||||
|
**/tests/**/*.db
|
||||||
|
|
||||||
|
# Microsoft Access database created for passing to tests
|
||||||
|
/ext/pdo_odbc/tests/*.mdb
|
||||||
|
|
||||||
|
# Files generated by `./run-tests.php -m` when checking for memory leaks
|
||||||
|
**/tests/**/*.mem
|
||||||
|
|
||||||
|
# Test results generated by `./run-tests.php`
|
||||||
|
php_test_results_*.txt
|
||||||
|
|
||||||
|
# Temporary test information generated by `./run-tests.php`
|
||||||
|
/run-test-info.php
|
||||||
|
|
||||||
|
# Temporary POST data placeholder files generated by `./run-tests.php`
|
||||||
|
phpt.*
|
||||||
|
|
||||||
|
# Temporary PHP INI configuration file(s) for tests, generated by `make test`
|
||||||
|
tmp-php.ini
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Generated by GCC's gcov and LCOV via build/Makefile.gcov and gcov.php.net
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
*.gcda
|
||||||
|
*.gcno
|
||||||
|
/gcovr.xml
|
||||||
|
/gcovr_html/
|
||||||
|
/lcov_html/
|
||||||
|
/php_lcov.info
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Archives generated during the PHP release process
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
/*.tar.gz
|
||||||
|
/*.tar.bz2
|
||||||
|
/*.tar.xz
|
||||||
|
/*.tar.gz.asc
|
||||||
|
/*.tar.bz2.asc
|
||||||
|
/*.tar.xz.asc
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Generated by `./configure --enable-dtrace` for using DTrace framework
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
/ext/oci8/oci8_dtrace_gen.h
|
||||||
|
/ext/oci8/oci8_dtrace_gen.h.bak
|
||||||
|
/Zend/zend_dtrace_gen.h
|
||||||
|
/Zend/zend_dtrace_gen.h.bak
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# GitHub actions cache
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
/branch-commit-cache.json
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Special cases to invert previous ignore patterns
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
!/ext/bcmath/libbcmath/src/config.h
|
||||||
|
!/ext/fileinfo/libmagic/config.h
|
||||||
|
!/ext/fileinfo/libmagic.patch
|
||||||
|
!/ext/fileinfo/magicdata.patch
|
||||||
|
!/ext/pcre/pcre2lib/config.h
|
||||||
|
!/win32/build/Makefile
|
||||||
|
|
@ -0,0 +1,98 @@
|
||||||
|
git:
|
||||||
|
quiet: true
|
||||||
|
|
||||||
|
dist: bionic
|
||||||
|
language: c
|
||||||
|
os: linux
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
packages:
|
||||||
|
- locales
|
||||||
|
- language-pack-de
|
||||||
|
- re2c
|
||||||
|
- ccache
|
||||||
|
- mysql-server
|
||||||
|
- libaspell-dev
|
||||||
|
- libbz2-dev
|
||||||
|
- libcurl4-gnutls-dev
|
||||||
|
- libenchant-dev
|
||||||
|
- libfreetype6-dev
|
||||||
|
- libgmp-dev
|
||||||
|
- libicu-dev
|
||||||
|
- libjpeg-dev
|
||||||
|
- libkrb5-dev
|
||||||
|
- libonig-dev
|
||||||
|
- libpng-dev
|
||||||
|
- libpq-dev
|
||||||
|
- libpspell-dev
|
||||||
|
- libsasl2-dev
|
||||||
|
- libsqlite3-dev
|
||||||
|
- libsodium-dev
|
||||||
|
- libtidy-dev
|
||||||
|
- libwebp-dev
|
||||||
|
- libxml2-dev
|
||||||
|
- libxpm-dev
|
||||||
|
- libxslt1-dev
|
||||||
|
- libzip-dev
|
||||||
|
|
||||||
|
|
||||||
|
services:
|
||||||
|
- mysql
|
||||||
|
- postgresql
|
||||||
|
|
||||||
|
notifications:
|
||||||
|
email:
|
||||||
|
on_failure: change
|
||||||
|
irc:
|
||||||
|
template:
|
||||||
|
- "%{repository}#%{build_number} (%{branch} - %{commit} : %{author}): %{message} - Change view : %{compare_url} - Build details : %{build_url}"
|
||||||
|
channels:
|
||||||
|
- "irc.efnet.org#php.pecl"
|
||||||
|
on_success: change
|
||||||
|
on_failure: always
|
||||||
|
|
||||||
|
cache:
|
||||||
|
apt: true
|
||||||
|
ccache: true
|
||||||
|
|
||||||
|
env:
|
||||||
|
global:
|
||||||
|
- MYSQL_TEST_HOST=127.0.0.1
|
||||||
|
- MYSQL_TEST_USER=travis
|
||||||
|
- PDO_MYSQL_TEST_DSN="mysql:host=127.0.0.1;dbname=test"
|
||||||
|
- PDO_MYSQL_TEST_USER=travis
|
||||||
|
- PDO_MYSQL_TEST_PASS=
|
||||||
|
- PDO_MYSQL_TEST_HOST=127.0.0.1
|
||||||
|
- PDO_PGSQL_TEST_DSN="pgsql:host=localhost port=5432 dbname=test user=postgres password="
|
||||||
|
- REPORT_EXIT_STATUS=1
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
include:
|
||||||
|
- env: ENABLE_ZTS=1 ENABLE_DEBUG=1 SKIP_IO_CAPTURE_TESTS=1 ARM64=1
|
||||||
|
arch: arm64
|
||||||
|
if: type = cron
|
||||||
|
- env: ENABLE_ZTS=1 ENABLE_DEBUG=1 SKIP_IO_CAPTURE_TESTS=1 S390X=1
|
||||||
|
arch: s390x
|
||||||
|
if: type = cron
|
||||||
|
|
||||||
|
before_script:
|
||||||
|
- ccache --version
|
||||||
|
- ccache --zero-stats
|
||||||
|
- export USE_CCACHE=1
|
||||||
|
# Enable IPv6
|
||||||
|
- sudo sh -c 'echo 0 > /proc/sys/net/ipv6/conf/all/disable_ipv6'
|
||||||
|
# Compile PHP
|
||||||
|
- travis_wait ./travis/compile.sh
|
||||||
|
# Setup Extensions
|
||||||
|
- ./travis/setup-mysql.sh
|
||||||
|
- ./travis/setup-pgsql.sh
|
||||||
|
|
||||||
|
# Run PHPs run-tests.php
|
||||||
|
script:
|
||||||
|
# ARM64 CI reports nproc=32, which is excessive.
|
||||||
|
- if [ -z "$ARM64" ]; then export JOBS=$(nproc); else export JOBS=16; fi
|
||||||
|
- ./sapi/cli/php run-tests.php -P -d extension=`pwd`/modules/zend_test.so $(if [ $ENABLE_DEBUG == 0 ]; then echo "-d opcache.enable_cli=1 -d opcache.protect_memory=1 -d opcache.jit_buffer_size=16M -d zend_extension=`pwd`/modules/opcache.so"; fi) -g "FAIL,XFAIL,BORK,WARN,LEAK,SKIP" --offline --show-diff --show-slow 1000 --set-timeout 120 -j$JOBS
|
||||||
|
- sapi/cli/php -d extension_dir=`pwd`/modules -r 'dl("zend_test");'
|
||||||
|
|
||||||
|
after_success:
|
||||||
|
- ccache --show-stats
|
||||||
|
|
@ -0,0 +1,320 @@
|
||||||
|
# PHP coding standards
|
||||||
|
|
||||||
|
This file lists several standards that any programmer adding or changing code in
|
||||||
|
PHP should follow. Since this file was added at a very late stage of the
|
||||||
|
development of PHP v3.0, the code base does not fully follow it, but new
|
||||||
|
features are going in that general direction. Many sections have been recoded to
|
||||||
|
use these rules.
|
||||||
|
|
||||||
|
## Code implementation
|
||||||
|
|
||||||
|
1. Document your code in source files and the manual. (tm)
|
||||||
|
|
||||||
|
2. Functions that are given pointers to resources should not free them.
|
||||||
|
|
||||||
|
For instance, `function int mail(char *to, char *from)` should NOT free to
|
||||||
|
and/or from.
|
||||||
|
|
||||||
|
Exceptions:
|
||||||
|
|
||||||
|
* The function's designated behavior is freeing that resource. E.g.
|
||||||
|
`efree()`
|
||||||
|
|
||||||
|
* The function is given a boolean argument, that controls whether or not the
|
||||||
|
function may free its arguments (if true - the function must free its
|
||||||
|
arguments, if false - it must not)
|
||||||
|
|
||||||
|
* Low-level parser routines, that are tightly integrated with the token
|
||||||
|
cache and the bison code for minimum memory copying overhead.
|
||||||
|
|
||||||
|
3. Functions that are tightly integrated with other functions within the same
|
||||||
|
module, and rely on each other non-trivial behavior, should be documented as
|
||||||
|
such and declared `static`. They should be avoided if possible.
|
||||||
|
|
||||||
|
4. Use definitions and macros whenever possible, so that constants have
|
||||||
|
meaningful names and can be easily manipulated. The only exceptions to this
|
||||||
|
rule are 0 and 1, when used as `false` and `true` (respectively). Any other
|
||||||
|
use of a numeric constant to specify different behavior or actions should be
|
||||||
|
done through a `#define`.
|
||||||
|
|
||||||
|
5. When writing functions that deal with strings, be sure to remember that PHP
|
||||||
|
holds the length property of each string, and that it shouldn't be
|
||||||
|
calculated with `strlen()`. Write your functions in such a way so that
|
||||||
|
they'll take advantage of the length property, both for efficiency and in
|
||||||
|
order for them to be binary-safe. Functions that change strings and obtain
|
||||||
|
their new lengths while doing so, should return that new length, so it
|
||||||
|
doesn't have to be recalculated with `strlen()` (e.g. `php_addslashes()`).
|
||||||
|
|
||||||
|
6. NEVER USE `strncat()`. If you're absolutely sure you know what you're doing,
|
||||||
|
check its man page again, and only then, consider using it, and even then,
|
||||||
|
try avoiding it.
|
||||||
|
|
||||||
|
7. Use `PHP_*` macros in the PHP source, and `ZEND_*` macros in the Zend part of
|
||||||
|
the source. Although the `PHP_*` macros are mostly aliased to the `ZEND_*`
|
||||||
|
macros it gives a better understanding on what kind of macro you're calling.
|
||||||
|
|
||||||
|
8. When commenting out code using a `#if` statement, do NOT use `0` only.
|
||||||
|
Instead use `"<git username here>_0"`. For example, `#if FOO_0`, where `FOO`
|
||||||
|
is your git user `foo`. This allows easier tracking of why code was
|
||||||
|
commented out, especially in bundled libraries.
|
||||||
|
|
||||||
|
9. Do not define functions that are not available. For instance, if a library is
|
||||||
|
missing a function, do not define the PHP version of the function, and do
|
||||||
|
not raise a run-time error about the function not existing. End users should
|
||||||
|
use `function_exists()` to test for the existence of a function.
|
||||||
|
|
||||||
|
10. Prefer `emalloc()`, `efree()`, `estrdup()`, etc. to their standard C library
|
||||||
|
counterparts. These functions implement an internal "safety-net" mechanism
|
||||||
|
that ensures the deallocation of any unfreed memory at the end of a request.
|
||||||
|
They also provide useful allocation and overflow information while running
|
||||||
|
in debug mode.
|
||||||
|
|
||||||
|
In almost all cases, memory returned to the engine must be allocated using
|
||||||
|
`emalloc()`.
|
||||||
|
|
||||||
|
The use of `malloc()` should be limited to cases where a third-party library
|
||||||
|
may need to control or free the memory, or when the memory in question needs
|
||||||
|
to survive between multiple requests.
|
||||||
|
|
||||||
|
## User functions/methods naming conventions
|
||||||
|
|
||||||
|
1. Function names for user-level functions should be enclosed with in the
|
||||||
|
`PHP_FUNCTION()` macro. They should be in lowercase, with words underscore
|
||||||
|
delimited, with care taken to minimize the letter count. Abbreviations
|
||||||
|
should not be used when they greatly decrease the readability of the
|
||||||
|
function name itself:
|
||||||
|
|
||||||
|
Good:
|
||||||
|
|
||||||
|
```php
|
||||||
|
str_word_count
|
||||||
|
array_key_exists
|
||||||
|
```
|
||||||
|
|
||||||
|
Ok:
|
||||||
|
|
||||||
|
```php
|
||||||
|
date_interval_create_from_date_string
|
||||||
|
// Could be 'date_intvl_create_from_date_str'?
|
||||||
|
get_html_translation_table()
|
||||||
|
// Could be 'html_get_trans_table'?
|
||||||
|
```
|
||||||
|
|
||||||
|
Bad:
|
||||||
|
|
||||||
|
```php
|
||||||
|
hw_GetObjectByQueryCollObj
|
||||||
|
pg_setclientencoding
|
||||||
|
jf_n_s_i
|
||||||
|
```
|
||||||
|
|
||||||
|
2. If they are part of a "parent set" of functions, that parent should be
|
||||||
|
included in the user function name, and should be clearly related to the
|
||||||
|
parent program or function family. This should be in the form of `parent_*`:
|
||||||
|
|
||||||
|
A family of `foo` functions, for example:
|
||||||
|
|
||||||
|
Good:
|
||||||
|
|
||||||
|
```php
|
||||||
|
foo_select_bar
|
||||||
|
foo_insert_baz
|
||||||
|
foo_delete_baz
|
||||||
|
```
|
||||||
|
|
||||||
|
Bad:
|
||||||
|
|
||||||
|
```php
|
||||||
|
fooselect_bar
|
||||||
|
fooinsertbaz
|
||||||
|
delete_foo_baz
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Function names used by user functions should be prefixed with `_php_`, and
|
||||||
|
followed by a word or an underscore-delimited list of words, in lowercase
|
||||||
|
letters, that describes the function. If applicable, they should be declared
|
||||||
|
`static`.
|
||||||
|
|
||||||
|
4. Variable names must be meaningful. One letter variable names must be avoided,
|
||||||
|
except for places where the variable has no real meaning or a trivial
|
||||||
|
meaning (e.g. `for (i=0; i<100; i++) ...`).
|
||||||
|
|
||||||
|
5. Variable names should be in lowercase. Use underscores to separate between
|
||||||
|
words.
|
||||||
|
|
||||||
|
6. Method names follow the *studlyCaps* (also referred to as *bumpy case* or
|
||||||
|
*camel caps*) naming convention, with care taken to minimize the letter
|
||||||
|
count. The initial letter of the name is lowercase, and each letter that
|
||||||
|
starts a new `word` is capitalized:
|
||||||
|
|
||||||
|
Good:
|
||||||
|
|
||||||
|
```php
|
||||||
|
connect()
|
||||||
|
getData()
|
||||||
|
buildSomeWidget()
|
||||||
|
```
|
||||||
|
|
||||||
|
Bad:
|
||||||
|
|
||||||
|
```php
|
||||||
|
get_Data()
|
||||||
|
buildsomewidget()
|
||||||
|
getI()
|
||||||
|
```
|
||||||
|
|
||||||
|
7. Class names should be descriptive nouns in *PascalCase* and as short as
|
||||||
|
possible. Each word in the class name should start with a capital letter,
|
||||||
|
without underscore delimiters. The class name should be prefixed with the
|
||||||
|
name of the "parent set" (e.g. the name of the extension) if no namespaces
|
||||||
|
are used. Abbreviations and acronyms as well as initialisms should be
|
||||||
|
avoided wherever possible, unless they are much more widely used than the
|
||||||
|
long form (e.g. HTTP or URL). Abbreviations start with a capital letter
|
||||||
|
followed by lowercase letters, whereas acronyms and initialisms are written
|
||||||
|
according to their standard notation. Usage of acronyms and initialisms is
|
||||||
|
not allowed if they are not widely adopted and recognized as such.
|
||||||
|
|
||||||
|
Good:
|
||||||
|
|
||||||
|
```php
|
||||||
|
Curl
|
||||||
|
CurlResponse
|
||||||
|
HTTPStatusCode
|
||||||
|
URL
|
||||||
|
BTreeMap // B-tree Map
|
||||||
|
Id // Identifier
|
||||||
|
ID // Identity Document
|
||||||
|
Char // Character
|
||||||
|
Intl // Internationalization
|
||||||
|
Radar // Radio Detecting and Ranging
|
||||||
|
```
|
||||||
|
|
||||||
|
Bad:
|
||||||
|
|
||||||
|
```php
|
||||||
|
curl
|
||||||
|
curl_response
|
||||||
|
HttpStatusCode
|
||||||
|
Url
|
||||||
|
BtreeMap
|
||||||
|
ID // Identifier
|
||||||
|
CHAR
|
||||||
|
INTL
|
||||||
|
RADAR // Radio Detecting and Ranging
|
||||||
|
```
|
||||||
|
|
||||||
|
## Internal function naming conventions
|
||||||
|
|
||||||
|
1. Functions that are part of the external API should be named
|
||||||
|
`php_modulename_function()` to avoid symbol collision. They should be in
|
||||||
|
lowercase, with words underscore delimited. Exposed API must be defined in
|
||||||
|
`php_modulename.h`.
|
||||||
|
|
||||||
|
```c
|
||||||
|
PHPAPI char *php_session_create_id(PS_CREATE_SID_ARGS);
|
||||||
|
```
|
||||||
|
|
||||||
|
Unexposed module function should be static and should not be defined in
|
||||||
|
`php_modulename.h`.
|
||||||
|
|
||||||
|
```c
|
||||||
|
static int php_session_destroy()
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Main module source file must be named `modulename.c`.
|
||||||
|
|
||||||
|
3. Header file that is used by other sources must be named `php_modulename.h`.
|
||||||
|
|
||||||
|
## Syntax and indentation
|
||||||
|
|
||||||
|
1. Never use C++ style comments (i.e. `//` comment). Always use C-style comments
|
||||||
|
instead. PHP is written in C, and is aimed at compiling under any ANSI-C
|
||||||
|
compliant compiler. Even though many compilers accept C++-style comments in
|
||||||
|
C code, you have to ensure that your code would compile with other compilers
|
||||||
|
as well. The only exception to this rule is code that is Win32-specific,
|
||||||
|
because the Win32 port is MS-Visual C++ specific, and this compiler is known
|
||||||
|
to accept C++-style comments in C code.
|
||||||
|
|
||||||
|
2. Use K&R-style. Of course, we can't and don't want to force anybody to use a
|
||||||
|
style he or she is not used to, but, at the very least, when you write code
|
||||||
|
that goes into the core of PHP or one of its standard modules, please
|
||||||
|
maintain the K&R style. This applies to just about everything, starting with
|
||||||
|
indentation and comment styles and up to function declaration syntax. Also
|
||||||
|
see [Indentstyle](http://www.catb.org/~esr/jargon/html/I/indent-style.html).
|
||||||
|
|
||||||
|
3. Be generous with whitespace and braces. Keep one empty line between the
|
||||||
|
variable declaration section and the statements in a block, as well as
|
||||||
|
between logical statement groups in a block. Maintain at least one empty
|
||||||
|
line between two functions, preferably two. Always prefer:
|
||||||
|
|
||||||
|
```c
|
||||||
|
if (foo) {
|
||||||
|
bar;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
to:
|
||||||
|
|
||||||
|
```c
|
||||||
|
if(foo)bar;
|
||||||
|
```
|
||||||
|
|
||||||
|
4. When indenting, use the tab character. A tab is expected to represent four
|
||||||
|
spaces. It is important to maintain consistency in indenture so that
|
||||||
|
definitions, comments, and control structures line up correctly.
|
||||||
|
|
||||||
|
5. Preprocessor statements (`#if` and such) MUST start at column one. To indent
|
||||||
|
preprocessor directives you should put the `#` at the beginning of a line,
|
||||||
|
followed by any number of whitespace.
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
1. Extensions should be well tested using `*.phpt` tests. Read about that at
|
||||||
|
[qa.php.net](https://qa.php.net/write-test.php) documentation.
|
||||||
|
|
||||||
|
## Folding hooks
|
||||||
|
|
||||||
|
Use `{{{` symbols for the folding mode in Emacs and vim (`set fdm=marker`).
|
||||||
|
Folding is very useful when dealing with large files because you can scroll
|
||||||
|
through the file quickly and just unfold the function you wish to work on.
|
||||||
|
The `}}}` at the end of each function marks the end of the fold, and should
|
||||||
|
be on a separate line.
|
||||||
|
|
||||||
|
```c
|
||||||
|
/* {{{ Returns the absolute value of the number */
|
||||||
|
PHP_FUNCTION(abs)
|
||||||
|
{
|
||||||
|
...
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
```
|
||||||
|
|
||||||
|
## New and experimental functions
|
||||||
|
|
||||||
|
To reduce the problems normally associated with the first public implementation
|
||||||
|
of a new set of functions, it has been suggested that the first implementation
|
||||||
|
include a file labeled `EXPERIMENTAL` in the function directory, and that the
|
||||||
|
functions follow the standard prefixing conventions during their initial
|
||||||
|
implementation.
|
||||||
|
|
||||||
|
The file labelled `EXPERIMENTAL` should include the following information:
|
||||||
|
|
||||||
|
* Any authoring information (known bugs, future directions of the module).
|
||||||
|
* Ongoing status notes which may not be appropriate for Git comments.
|
||||||
|
|
||||||
|
In general new features should go to PECL or experimental branches until there
|
||||||
|
are specific reasons for directly adding it to the core distribution.
|
||||||
|
|
||||||
|
## Aliases & legacy documentation
|
||||||
|
|
||||||
|
You may also have some deprecated aliases with close to duplicate names, for
|
||||||
|
example, `somedb_select_result` and `somedb_selectresult`. For documentation
|
||||||
|
purposes, these will only be documented by the most current name, with the
|
||||||
|
aliases listed in the documentation for the parent function. For ease of
|
||||||
|
reference, user-functions with completely different names, that alias to the
|
||||||
|
same function (such as `highlight_file` and `show_source`), will be separately
|
||||||
|
documented.
|
||||||
|
|
||||||
|
Backwards compatible functions and names should be maintained as long as the
|
||||||
|
code can be reasonably be kept as part of the codebase. See the `README` in the
|
||||||
|
PHP documentation repository for more information on documentation.
|
||||||
|
|
@ -0,0 +1,425 @@
|
||||||
|
# Contributing to PHP
|
||||||
|
|
||||||
|
Anybody who programs in PHP can be a contributing member of the community that
|
||||||
|
develops and deploys it; the task of deploying PHP, documentation and associated
|
||||||
|
websites is a never ending one. With every release, or release candidate comes a
|
||||||
|
wave of work, which takes a lot of organization and co-ordination.
|
||||||
|
|
||||||
|
You don't need any special access to download, build, debug and begin submitting
|
||||||
|
PHP or PECL code, tests or documentation. Once you've followed this guide and
|
||||||
|
had several contributions accepted, commit privileges are often quickly granted.
|
||||||
|
|
||||||
|
## Index
|
||||||
|
|
||||||
|
* [Pull requests](#pull-requests)
|
||||||
|
* [Filing bugs](#filing-bugs)
|
||||||
|
* [Feature requests](#feature-requests)
|
||||||
|
* [Writing tests](#writing-tests)
|
||||||
|
* [Writing documentation](#writing-documentation)
|
||||||
|
* [Getting help](#getting-help)
|
||||||
|
* [PHP source code directory structure](#php-source-code-directory-structure)
|
||||||
|
* [PHP internals](#php-internals)
|
||||||
|
* [PECL extensions](#pecl-extensions)
|
||||||
|
* [Checklist for submitting contribution](#checklist-for-submitting-contribution)
|
||||||
|
* [What happens after submitting contribution?](#what-happens-after-submitting-contribution)
|
||||||
|
* [What happens when your contribution is applied?](#what-happens-when-your-contribution-is-applied)
|
||||||
|
* [Git commit rules](#git-commit-rules)
|
||||||
|
* [Copyright and license headers](#copyright-and-license-headers)
|
||||||
|
|
||||||
|
## Pull requests
|
||||||
|
|
||||||
|
PHP welcomes pull requests to [add tests](#writing-tests), fix bugs and to
|
||||||
|
implement RFCs. Please be sure to include tests as appropriate!
|
||||||
|
|
||||||
|
If you are fixing a bug, then please submit your PR against the lowest actively
|
||||||
|
supported branch of PHP that the bug affects (only green branches on
|
||||||
|
[the supported version page](https://www.php.net/supported-versions.php) are
|
||||||
|
supported). For example, at the time of writing, the lowest supported version is
|
||||||
|
PHP 7.3, which corresponds to the `PHP-7.3` branch in Git. Please also make sure
|
||||||
|
you add a link to the PR in the bug on [the bug tracker](https://bugs.php.net/).
|
||||||
|
|
||||||
|
Pull requests implementing RFCs should be submitted against `master`.
|
||||||
|
|
||||||
|
Pull requests should *never* be submitted against `PHP-x.y.z` branches, as these
|
||||||
|
are only used for release management.
|
||||||
|
|
||||||
|
If your pull request exhibits conflicts with the base branch, please resolve
|
||||||
|
them by using `git rebase` instead of `git merge`.
|
||||||
|
|
||||||
|
Fork the official PHP repository and send a pull request. A notification will be
|
||||||
|
sent to the pull request mailing list. Sending a note to PHP Internals list
|
||||||
|
(internals@lists.php.net) may help getting more feedback and quicker turnaround.
|
||||||
|
You can also add pull requests to [bug reports](https://bugs.php.net/).
|
||||||
|
|
||||||
|
Read [Git access page](https://www.php.net/git.php) for help on using Git to get
|
||||||
|
and build PHP source code. We recommend to look at our
|
||||||
|
[workflow](https://wiki.php.net/vcs/gitworkflow) and our
|
||||||
|
[FAQ](https://wiki.php.net/vcs/gitfaq).
|
||||||
|
|
||||||
|
## Filing bugs
|
||||||
|
|
||||||
|
Bugs can be filed on the [PHP bug tracker](https://bugs.php.net/). If this is
|
||||||
|
the first time you've filed a bug, we suggest reading the
|
||||||
|
[guide to reporting a bug](https://bugs.php.net/how-to-report.php).
|
||||||
|
|
||||||
|
Where possible, please include a self-contained reproduction case!
|
||||||
|
|
||||||
|
## Feature requests
|
||||||
|
|
||||||
|
Feature requests are generally submitted in the form of
|
||||||
|
[Requests for Comments (RFC)](https://wiki.php.net/rfc/howto), ideally
|
||||||
|
accompanied by [pull requests](#pull-requests). You can find the extremely large
|
||||||
|
list of RFCs that have been previously considered on the
|
||||||
|
[PHP Wiki](https://wiki.php.net/rfc).
|
||||||
|
|
||||||
|
To create a RFC, discuss it with the extension maintainer, and discuss it on the
|
||||||
|
development mailing list internals@lists.php.net. RFC Wiki accounts can be
|
||||||
|
requested on https://wiki.php.net/start?do=register. PHP extension maintainers
|
||||||
|
can be found in the [EXTENSIONS](/EXTENSIONS) file in the PHP source code
|
||||||
|
repository. Mailing list subscription is explained on the
|
||||||
|
[mailing lists page](https://www.php.net/mailing-lists.php).
|
||||||
|
|
||||||
|
You may also want to read
|
||||||
|
[The Mysterious PHP RFC Process](https://blogs.oracle.com/opal/post/the-mysterious-php-rfc-process-and-how-you-can-change-the-web)
|
||||||
|
for additional notes on the best way to approach submitting an RFC.
|
||||||
|
|
||||||
|
## Writing tests
|
||||||
|
|
||||||
|
We love getting new tests! PHP is a huge project and improving code coverage is
|
||||||
|
a huge win for every PHP user.
|
||||||
|
|
||||||
|
[Our QA site includes a page detailing how to write test cases.](https://qa.php.net/write-test.php)
|
||||||
|
|
||||||
|
Submitting test scripts helps us to understand what functionality has changed.
|
||||||
|
It is important for the stability and maintainability of PHP that tests are
|
||||||
|
comprehensive.
|
||||||
|
|
||||||
|
Failure conditions of `zend_parse_parameters`, `ZEND_PARSE_PARAMETERS()` and
|
||||||
|
similar functions should not be tested. These parameter parsing APIs are already
|
||||||
|
extensively tested, and additional tests only complicate future modifications.
|
||||||
|
|
||||||
|
For newly created tests, a `--CREDITS--` section should no longer be included,
|
||||||
|
as test authorship is already accurately tracked by Git. If multiple authors
|
||||||
|
should be credited, the `Co-authored-by` tag in the commit message may be used.
|
||||||
|
|
||||||
|
## Writing documentation
|
||||||
|
|
||||||
|
There are two ways to contribute to the PHP manual. You can edit the manual and
|
||||||
|
send patches anonymously via [the online editor](https://edit.php.net/), or you
|
||||||
|
can check the XML source out from Subversion and edit that and build it
|
||||||
|
[per the instructions on the documentation site](http://doc.php.net/tutorial/).
|
||||||
|
Patches created that way should be sent to the
|
||||||
|
[documentation mailing list](mailto:phpdoc@lists.php.net).
|
||||||
|
|
||||||
|
## Getting help
|
||||||
|
|
||||||
|
If you are having trouble contributing to PHP, or just want to talk to a human
|
||||||
|
about what you're working on, you can contact us via the
|
||||||
|
[internals mailing list](mailto:internals@lists.php.net), or the
|
||||||
|
[documentation mailing list](mailto:phpdoc@lists.php.net) for documentation
|
||||||
|
issues.
|
||||||
|
|
||||||
|
Although not a formal channel, you can also find a number of core developers on
|
||||||
|
the #php.pecl channel on [EFnet](http://www.efnet.org/). Similarly, many
|
||||||
|
documentation writers can be found on #php.doc. Windows development IRC channel
|
||||||
|
is available at #winphp-dev on FreeNode.
|
||||||
|
|
||||||
|
## PHP source code directory structure
|
||||||
|
|
||||||
|
PHP source code also includes several files generated during development and
|
||||||
|
several parts where maintenance is happening upstream in their respective
|
||||||
|
locations.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
<php-src>/
|
||||||
|
├─ .git/ # Git configuration and source directory
|
||||||
|
├─ TSRM/ # Thread Safe Resource Manager
|
||||||
|
└─ Zend/ # Zend Engine
|
||||||
|
├─ zend_vm_execute.h # Generated by `Zend/zend_vm_gen.php`
|
||||||
|
├─ zend_vm_opcodes.c # Generated by `Zend/zend_vm_gen.php`
|
||||||
|
├─ zend_vm_opcodes.h # Generated by `Zend/zend_vm_gen.php`
|
||||||
|
└─ ...
|
||||||
|
├─ appveyor/ # Appveyor CI service files
|
||||||
|
└─ build/ # *nix build system files
|
||||||
|
├─ ax_*.m4 # https://github.com/autoconf-archive/autoconf-archive
|
||||||
|
├─ config.guess # https://git.savannah.gnu.org/cgit/config.git
|
||||||
|
├─ config.sub # https://git.savannah.gnu.org/cgit/config.git
|
||||||
|
├─ libtool.m4 # https://git.savannah.gnu.org/cgit/libtool.git
|
||||||
|
├─ ltmain.sh # https://git.savannah.gnu.org/cgit/libtool.git
|
||||||
|
├─ shtool # https://www.gnu.org/software/shtool/
|
||||||
|
└─ ...
|
||||||
|
├─ docs/ # PHP internals and repository documentation
|
||||||
|
└─ ext/ # PHP core extensions
|
||||||
|
└─ bcmath/
|
||||||
|
├─ libbcmath/ # Forked and maintained in php-src
|
||||||
|
└─ ...
|
||||||
|
└─ curl/
|
||||||
|
├─ sync-constants.php # The curl symbols checker
|
||||||
|
└─ ...
|
||||||
|
└─ date/
|
||||||
|
└─ lib/ # Bundled datetime library https://github.com/derickr/timelib
|
||||||
|
├─ parse_date.c # Generated by re2c 0.15.3
|
||||||
|
├─ parse_iso_intervals.c # Generated by re2c 0.15.3
|
||||||
|
└─ ...
|
||||||
|
└─ ...
|
||||||
|
└─ ffi/
|
||||||
|
├─ ffi_parser.c # Generated by https://github.com/dstogov/llk
|
||||||
|
└─ ...
|
||||||
|
└─ fileinfo/
|
||||||
|
├─ libmagic/ # Modified libmagic https://github.com/file/file
|
||||||
|
├─ data_file.c # Generated by `ext/fileinfo/create_data_file.php`
|
||||||
|
├─ libmagic.patch # Modifications patch from upstream libmagic
|
||||||
|
├─ magicdata.patch # Modifications patch from upstream libmagic
|
||||||
|
└─ ...
|
||||||
|
└─ gd/
|
||||||
|
├─ libgd/ # Bundled and modified GD library https://github.com/libgd/libgd
|
||||||
|
└─ ...
|
||||||
|
└─ mbstring/
|
||||||
|
├─ libmbfl/ # Forked and maintained in php-src
|
||||||
|
├─ unicode_data.h # Generated by `ext/mbstring/ucgendat/ucgendat.php`
|
||||||
|
└─ ...
|
||||||
|
└─ pcre/
|
||||||
|
├─ pcre2lib/ # https://www.pcre.org/
|
||||||
|
└─ ...
|
||||||
|
└─ pdo_mysql/
|
||||||
|
├─ php_pdo_mysql_sqlstate.h # Generated by `ext/pdo_mysql/get_error_codes.php`
|
||||||
|
└─ ...
|
||||||
|
└─ skeleton/ # Skeleton for developing new extensions with `ext/ext_skel.php`
|
||||||
|
└─ ...
|
||||||
|
└─ standard/
|
||||||
|
└─ html_tables/
|
||||||
|
├─ mappings/ # https://www.unicode.org/Public/MAPPINGS/
|
||||||
|
└─ ...
|
||||||
|
├─ credits_ext.h # Generated by `scripts/dev/credits`
|
||||||
|
├─ credits_sapi.h # Generated by `scripts/dev/credits`
|
||||||
|
├─ html_tables.h # Generated by `ext/standard/html_tables/html_table_gen.php`
|
||||||
|
└─ ...
|
||||||
|
└─ tokenizer/
|
||||||
|
├─ tokenizer_data.c # Generated by `ext/tokenizer/tokenizer_data_gen.sh`
|
||||||
|
└─ ...
|
||||||
|
└─ zend_test # For testing internal APIs. Not needed for regular builds.
|
||||||
|
└─ ...
|
||||||
|
└─ zip/ # Bundled https://github.com/pierrejoye/php_zip
|
||||||
|
└─ ...
|
||||||
|
└─ ...
|
||||||
|
└─ main/ # Binding that ties extensions, SAPIs, and engine together
|
||||||
|
├─ streams/ # Streams layer subsystem
|
||||||
|
├─ php_version.h # Generated by release managers using `configure`
|
||||||
|
└─ ...
|
||||||
|
├─ pear/ # PEAR installation
|
||||||
|
└─ sapi/ # PHP SAPI modules
|
||||||
|
└─ cli/
|
||||||
|
├─ mime_type_map.h # Generated by `sapi/cli/generate_mime_type_map.php`
|
||||||
|
└─ ...
|
||||||
|
└─ ...
|
||||||
|
├─ scripts/ # php-config, phpize and internal development scripts
|
||||||
|
├─ tests/ # Core features tests
|
||||||
|
├─ travis/ # Travis CI service files
|
||||||
|
└─ win32/ # Windows build system files
|
||||||
|
├─ cp_enc_map.c # Generated by `win32/cp_enc_map_gen.exe`
|
||||||
|
└─ ...
|
||||||
|
└─ ...
|
||||||
|
```
|
||||||
|
|
||||||
|
## PHP internals
|
||||||
|
|
||||||
|
For information on PHP internal C functions see
|
||||||
|
[References about Maintaining and Extending PHP](https://wiki.php.net/internals/references).
|
||||||
|
Various external resources can be found on the web. A standard printed reference
|
||||||
|
is the book "Extending and Embedding PHP" by Sara Golemon.
|
||||||
|
|
||||||
|
## PECL extensions
|
||||||
|
|
||||||
|
If you are fixing broken functionality in a [PECL](https://pecl.php.net)
|
||||||
|
extension then create a bug or identify an existing bug at
|
||||||
|
[bugs.php.net](https://bugs.php.net). A bug can be used to track the change
|
||||||
|
progress and prevent your changes getting lost in the PHP mail archives. Some
|
||||||
|
PECL extensions have their own bug tracker locations and different contributing
|
||||||
|
procedures.
|
||||||
|
|
||||||
|
If your change is large then create a
|
||||||
|
[Request for Comments (RFC)](https://wiki.php.net/rfc), discuss it with the
|
||||||
|
extension maintainer, and discuss it on the development mailing list
|
||||||
|
pecl-dev@lists.php.net depending on the extension. PECL mailing list
|
||||||
|
subscription is explained on the
|
||||||
|
[PECL support page](https://pecl.php.net/support.php).
|
||||||
|
|
||||||
|
Update any open bugs and add a link to the source of your change. Send the patch
|
||||||
|
or pointer to the bug to pecl-dev@lists.php.net. Also CC the extension
|
||||||
|
maintainer. Explain what has been changed by your patch. Test scripts should be
|
||||||
|
included.
|
||||||
|
|
||||||
|
## Checklist for submitting contribution
|
||||||
|
|
||||||
|
- Read [Coding standards](/CODING_STANDARDS.md) before you start working.
|
||||||
|
- Update git source just before running your final `diff` and before testing.
|
||||||
|
- Add in-line comments and/or have external documentation ready. Use only
|
||||||
|
`/* */` style comments, not `//`.
|
||||||
|
- Create test scripts for use with `make test`.
|
||||||
|
- Run `make test` to check your change doesn't break other features.
|
||||||
|
- Rebuild PHP with `--enable-debug` which will show some kinds of memory errors
|
||||||
|
and check the PHP and web server error logs after running your PHP tests.
|
||||||
|
- Rebuild PHP with `--enable-zts` to check your change compiles and operates
|
||||||
|
correctly in a thread safe PHP.
|
||||||
|
- Review the change once more just before submitting it.
|
||||||
|
|
||||||
|
## What happens after submitting contribution?
|
||||||
|
|
||||||
|
If your change is easy to review and obviously has no side-effects, it might be
|
||||||
|
committed relatively quickly.
|
||||||
|
|
||||||
|
Because PHP is a volunteer-driven effort more complex changes will require
|
||||||
|
patience on your side. If you do not receive feedback in a few days, consider
|
||||||
|
bumping. Before doing this think about these questions:
|
||||||
|
|
||||||
|
- Did I send the patch to the right mailing list?
|
||||||
|
- Did I review the mailing list archives to see if these kind of changes had
|
||||||
|
been discussed before?
|
||||||
|
- Did I explain my change clearly?
|
||||||
|
- Is my change too hard to review? Because of what factors?
|
||||||
|
|
||||||
|
## What happens when your contribution is applied?
|
||||||
|
|
||||||
|
Your name will likely be included in the Git commit log. If your change affects
|
||||||
|
end users, a brief description and your name might be added to the [NEWS](/NEWS)
|
||||||
|
file.
|
||||||
|
|
||||||
|
## Git commit rules
|
||||||
|
|
||||||
|
This section refers to contributors that have Git push access and make commit
|
||||||
|
changes themselves. We'll assume you're basically familiar with Git, but feel
|
||||||
|
free to post your questions on the mailing list. Please have a look at the more
|
||||||
|
detailed [information on Git](https://git-scm.com/).
|
||||||
|
|
||||||
|
PHP is developed through the efforts of a large number of people. Collaboration
|
||||||
|
is a Good Thing(tm), and Git lets us do this. Thus, following some basic rules
|
||||||
|
with regards to Git usage will:
|
||||||
|
|
||||||
|
* Make everybody happier, especially those responsible for maintaining PHP
|
||||||
|
itself.
|
||||||
|
* Keep the changes consistently well documented and easily trackable.
|
||||||
|
* Prevent some of those 'Oops' moments.
|
||||||
|
* 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.
|
||||||
|
|
||||||
|
2. Discuss any significant changes on the list before committing and get
|
||||||
|
confirmation from the release manager for the given branch.
|
||||||
|
|
||||||
|
3. Look at [EXTENSIONS](/EXTENSIONS) file to see who is the primary maintainer
|
||||||
|
of the code you want to contribute to.
|
||||||
|
|
||||||
|
4. If you "strongly disagree" about something another person did, don't start
|
||||||
|
fighting publicly - take it up in private email.
|
||||||
|
|
||||||
|
5. If you don't know how to do something, ask first!
|
||||||
|
|
||||||
|
6. Test your changes before committing them. We mean it. Really. To do so use
|
||||||
|
`make test`.
|
||||||
|
|
||||||
|
7. For development use the `--enable-debug` switch to avoid memory leaks and the
|
||||||
|
`--enable-zts` switch to ensure your code handles TSRM correctly and doesn't
|
||||||
|
break for those who need that.
|
||||||
|
|
||||||
|
Currently we have the following branches in use:
|
||||||
|
|
||||||
|
| Branch | |
|
||||||
|
| --------- | --------- |
|
||||||
|
| master | Active development branch for PHP 8.0, which is open for backwards incompatible changes and major internal API changes. |
|
||||||
|
| PHP-7.4 | Is used to release the PHP 7.4.x series. This is a current stable version and is open for bugfixes only. |
|
||||||
|
| PHP-7.3 | Is used to release the PHP 7.3.x series. This is a current stable version and is open for bugfixes only. |
|
||||||
|
| PHP-7.2 | Is used to release the PHP 7.2.x series. This is an old stable version and is open for security fixes only. |
|
||||||
|
| PHP-7.1 | This branch is closed. |
|
||||||
|
| PHP-7.0 | This branch is closed. |
|
||||||
|
| PHP-5.6 | This branch is closed. |
|
||||||
|
| PHP-5.5 | This branch is closed. |
|
||||||
|
| PHP-5.4 | This branch is closed. |
|
||||||
|
| PHP-5.3 | This branch is closed. |
|
||||||
|
| PHP-5.2 | This branch is closed. |
|
||||||
|
| PHP-5.1 | This branch is closed. |
|
||||||
|
| PHP-4.4 | This branch is closed. |
|
||||||
|
| PHP-X.Y.Z | These branches are used for the release managers for tagging the releases, hence they are closed to the general public. |
|
||||||
|
|
||||||
|
The next few rules are more of a technical nature:
|
||||||
|
|
||||||
|
1. All non-security bugfix changes should first go to the lowest bugfix branch
|
||||||
|
(i.e. 7.3) and then get merged up to all other branches. All security fixes
|
||||||
|
should go to the lowest security fixes branch (i.e 7.2). If a change is not
|
||||||
|
needed for later branches (i.e. fixes for features which were dropped from
|
||||||
|
later branches) an empty merge should be done.
|
||||||
|
|
||||||
|
2. All news updates intended for public viewing, such as new features, bug
|
||||||
|
fixes, improvements, etc., should go into the NEWS file of *any stable
|
||||||
|
release* version with the given change. In other words, news about a bug fix
|
||||||
|
which went into PHP-5.4, PHP-5.5 and master should be noted in both
|
||||||
|
PHP-5.4/NEWS and PHP-5.5/NEWS but not master, which is not a public released
|
||||||
|
version yet.
|
||||||
|
|
||||||
|
3. Do not commit multiple files and dump all messages in one commit. If you
|
||||||
|
modified several unrelated files, commit each group separately and provide a
|
||||||
|
nice commit message for each one. See example below.
|
||||||
|
|
||||||
|
4. Do write your commit message in such a way that it makes sense even without
|
||||||
|
the corresponding diff. One should be able to look at it, and immediately
|
||||||
|
know what was modified. Definitely include the function name in the message
|
||||||
|
as shown below.
|
||||||
|
|
||||||
|
5. In your commit messages, keep each line shorter than 80 characters. And try
|
||||||
|
to align your lines vertically, if they wrap. It looks bad otherwise.
|
||||||
|
|
||||||
|
6. If you modified a function that is callable from PHP, prepend PHP to the
|
||||||
|
function name as shown below.
|
||||||
|
|
||||||
|
The format of the commit messages is pretty simple.
|
||||||
|
|
||||||
|
<max 79 characters short description>\n
|
||||||
|
\n
|
||||||
|
<long description, 79 chars per line>
|
||||||
|
\n
|
||||||
|
|
||||||
|
An Example from the git project (commit 2b34e486bc):
|
||||||
|
|
||||||
|
pack-objects: Fix compilation with NO_PTHREDS
|
||||||
|
|
||||||
|
It looks like commit 99fb6e04 (pack-objects: convert to use parse_options(),
|
||||||
|
2012-02-01) moved the #ifdef NO_PTHREDS around but hasn't noticed that the
|
||||||
|
'arg' variable no longer is available.
|
||||||
|
|
||||||
|
If you fix some bugs, you should note the bug ID numbers in your commit message.
|
||||||
|
Bug ID should be prefixed by `#`.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
Fixed bug #14016 (pgsql notice handler double free crash bug.)
|
||||||
|
|
||||||
|
When you change the NEWS file for a bug fix, then please keep the bugs sorted in
|
||||||
|
decreasing order under the fixed version.
|
||||||
|
|
||||||
|
You can use [gitweb](https://git.php.net/) to look at PHP Git repository in
|
||||||
|
various ways.
|
||||||
|
|
||||||
|
## Copyright and license headers
|
||||||
|
|
||||||
|
New source code files should include the following header block:
|
||||||
|
|
||||||
|
```c
|
||||||
|
/*
|
||||||
|
+----------------------------------------------------------------------+
|
||||||
|
| Copyright (c) The PHP Group |
|
||||||
|
+----------------------------------------------------------------------+
|
||||||
|
| This source file is subject to version 3.01 of the PHP license, |
|
||||||
|
| that is bundled with this package in the file LICENSE, and is |
|
||||||
|
| available through the world-wide-web at the following url: |
|
||||||
|
| https://www.php.net/license/3_01.txt |
|
||||||
|
| If you did not receive a copy of the PHP license and are unable to |
|
||||||
|
| obtain it through the world-wide-web, please send a note to |
|
||||||
|
| license@php.net so we can mail you a copy immediately. |
|
||||||
|
+----------------------------------------------------------------------+
|
||||||
|
| Author: |
|
||||||
|
+----------------------------------------------------------------------+
|
||||||
|
*/
|
||||||
|
```
|
||||||
|
|
||||||
|
Thank you for contributing to PHP!
|
||||||
|
|
@ -0,0 +1,516 @@
|
||||||
|
List of PHP maintainers
|
||||||
|
=======================
|
||||||
|
|
||||||
|
Maintenance legend
|
||||||
|
------------------
|
||||||
|
Maintained: Someone actually looks after it.
|
||||||
|
Odd Fixes: It has a maintainer but they don't have time to do
|
||||||
|
much other than throw the odd patch in. See below.
|
||||||
|
Orphan: No current maintainer [but maybe you could take the
|
||||||
|
role as you write your new code].
|
||||||
|
Obsolete: Old code. Something tagged obsolete generally means
|
||||||
|
it has been replaced by a better system and you
|
||||||
|
should be using that.
|
||||||
|
Unknown: Not known at this time.
|
||||||
|
|
||||||
|
Status legend
|
||||||
|
-------------
|
||||||
|
Working: Working under both Windows and Unix.
|
||||||
|
Windows: Working only under Windows.
|
||||||
|
Unix: Working only under Unix.
|
||||||
|
Experimental: Under development or initial release.
|
||||||
|
Not Working: Not working.
|
||||||
|
Unknown: Status unknown.
|
||||||
|
|
||||||
|
|
||||||
|
== Server APIs ==
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: apache2handler
|
||||||
|
PRIMARY MAINTAINER: Aaron Bannert <aaron@php.net>, Ilia Alshanetsky <iliaa@php.net>
|
||||||
|
MAINTENANCE: Maintained
|
||||||
|
STATUS: Working
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: cgi
|
||||||
|
MAINTENANCE: Unknown
|
||||||
|
STATUS: Working
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: cli
|
||||||
|
PRIMARY MAINTAINER: Marcus Börger <helly@php.net>, Edin Kadribasic <edink@php.net>
|
||||||
|
MAINTENANCE: Xinchen Hui <laruence@php.net> (2013 - 2020)
|
||||||
|
STATUS: Working
|
||||||
|
SINCE: 4.3.0
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: embed
|
||||||
|
PRIMARY MAINTAINER: Edin Kadribasic <edink@php.net>
|
||||||
|
MAINTENANCE: Maintained
|
||||||
|
STATUS: Working
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: fpm
|
||||||
|
PRIMARY MAINTAINER: Jakub Zelenka <bukka@php.net>
|
||||||
|
MAINTENANCE: Maintained
|
||||||
|
STATUS: Working
|
||||||
|
SINCE: 5.3.3
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: litespeed
|
||||||
|
PRIMARY MAINTAINER: George Wang <gwang@php.net>
|
||||||
|
MAINTENANCE: Maintained
|
||||||
|
STATUS: Working
|
||||||
|
SINCE: 5.3
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: phpdbg
|
||||||
|
PRIMARY MAINTAINER: Joe Watkins <krakjoe@php.net>, Bob Weinand <bwoebi@php.net>
|
||||||
|
MAINTENANCE: Unknown
|
||||||
|
STATUS: 5.6
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
== Database extensions ==
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: dba
|
||||||
|
PRIMARY MAINTAINER: Marcus Börger <helly@php.net> (2002 - 2007)
|
||||||
|
Christopher Jones <sixd@php.net> (2008 - 2013)
|
||||||
|
Pierre-Alain Joye <pajoye@php.net> (2011 - 2011)
|
||||||
|
MAINTENANCE: Maintained
|
||||||
|
STATUS: Working
|
||||||
|
COMMENT: DBM abstraction for db2, db3, db4, dbm, ndbm, gdbm, ini
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: mysqli
|
||||||
|
PRIMARY MAINTAINER: Georg Richter <georg@php.net> (2003 - 2006)
|
||||||
|
Andrey Hristov <andrey@php.net> (2003 - 2016)
|
||||||
|
Johannes Schlüter <johannes@php.net> (2008 - 2014)
|
||||||
|
Ulf Wendel <uw@php.net> (2007 - 2013)
|
||||||
|
MAINTENANCE: Maintained
|
||||||
|
STATUS: Working
|
||||||
|
SINCE: 5.0
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: mysqlnd
|
||||||
|
PRIMARY MAINTAINER: Andrey Hristov <andrey@php.net> (2007 - 2017)
|
||||||
|
Johannes Schlüter <johannes@php.net> (2008 - 2018)
|
||||||
|
Ulf Wendel <uw@php.net> (2009 - 2011)
|
||||||
|
MAINTENANCE: Maintained
|
||||||
|
STATUS: Working
|
||||||
|
SINCE: 5.3
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: oci8
|
||||||
|
PRIMARY MAINTAINER: Christopher Jones <sixd@php.net> (2007 - 2017)
|
||||||
|
Antony Dovgal <tony2001@php.net> (2003 - 2009)
|
||||||
|
MAINTENANCE: Maintained
|
||||||
|
STATUS: Working
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: odbc
|
||||||
|
PRIMARY MAINTAINER: Daniel R. Kalowsky <kalowsky@php.net> (2000 - 2004)
|
||||||
|
MAINTENANCE: Maintained
|
||||||
|
STATUS: Working
|
||||||
|
COMMENT: Working
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: pdo
|
||||||
|
PRIMARY MAINTAINER: Ilia Alshanetsky <iliaa@php.net> (2004 - 2011)
|
||||||
|
Wez Furlong <wez@php.net> (2004 - 2006)
|
||||||
|
MAINTENANCE: Odd fixes
|
||||||
|
STATUS: Working
|
||||||
|
SINCE: 5.1
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: pdo_dblib
|
||||||
|
PRIMARY MAINTAINER: Adam Baratz <adambaratz@php.net> (2016 - 2017)
|
||||||
|
MAINTENANCE: Maintained
|
||||||
|
STATUS: Working
|
||||||
|
SINCE: 5.1
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: pdo_firebird
|
||||||
|
PRIMARY MAINTAINER: Lars Westermann <lwe@php.net> (2007 - 2007)
|
||||||
|
MAINTENANCE: Maintained
|
||||||
|
STATUS: Working
|
||||||
|
SINCE: 5.1
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: pdo_mysql
|
||||||
|
PRIMARY MAINTAINER: Ilia Alshanetsky <iliaa@php.net> (2004 - 2010)
|
||||||
|
Johannes Schlüter <johannes@php.net> (2008 - 2014)
|
||||||
|
Andrey Hristov <andrey@php.net> (2005 - 2015)
|
||||||
|
Ulf Wendel <uw@php.net> (2008 - 2012)
|
||||||
|
MAINTENANCE: Odd fixes
|
||||||
|
STATUS: Working
|
||||||
|
SINCE: 5.1
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: pdo_odbc
|
||||||
|
PRIMARY MAINTAINER: Unknown
|
||||||
|
MAINTENANCE: Odd fixes
|
||||||
|
STATUS: Working
|
||||||
|
SINCE: 5.1
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: pdo_oci
|
||||||
|
PRIMARY MAINTAINER: Christopher Jones <sixd@php.net> (2007 - 2017)
|
||||||
|
MAINTENANCE: Odd fixes
|
||||||
|
STATUS: Working
|
||||||
|
SINCE: 5.1
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: pdo_pgsql
|
||||||
|
PRIMARY MAINTAINER: Ilia Alshanetsky <iliaa@php.net> (2004 - 2011)
|
||||||
|
MAINTENANCE: Odd fixes
|
||||||
|
STATUS: Working
|
||||||
|
SINCE: 5.1
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: pdo_sqlite
|
||||||
|
PRIMARY MAINTAINER: Ilia Alshanetsky <iliaa@php.net> (2005 - 2011)
|
||||||
|
MAINTENANCE: Odd fixes
|
||||||
|
STATUS: Working
|
||||||
|
SINCE: 5.1
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: pgsql
|
||||||
|
PRIMARY MAINTAINER: Marcus Börger <helly@php.net> (2002 - 2007)
|
||||||
|
Yasuo Ohgaki <yohgaki@php.net> (2001 - 2015)
|
||||||
|
MAINTENANCE: Maintained
|
||||||
|
STATUS: Working
|
||||||
|
COMMENT: Use PostgreSQL 7.0.x or later. PostgreSQL 6.5.3 or less have fatal bug.
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: sqlite3
|
||||||
|
PRIMARY MAINTAINER: Scott MacVicar <scottmac@php.net> (2008 - 2011)
|
||||||
|
Christoph M. Becker <cmb@php.net> (2016 - 2020)
|
||||||
|
MAINTENANCE: Maintained
|
||||||
|
STATUS: Working
|
||||||
|
SINCE: 5.3
|
||||||
|
COMMENT: Integrates SQLite 3 embeddable SQL database engine.
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
== XML extensions ==
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: dom
|
||||||
|
PRIMARY MAINTAINER: Christian Stocker <chregu@php.net> (2003 - 2011)
|
||||||
|
Rob Richards <rrichards@php.net> (2003 - 2012)
|
||||||
|
Marcus Börger <helly@php.net> (2003 - 2006)
|
||||||
|
MAINTENANCE: Maintained
|
||||||
|
STATUS: Working
|
||||||
|
SINCE: 5.0
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: simplexml
|
||||||
|
PRIMARY MAINTAINER: Marcus Börger <helly@php.net> (2003 - 2008)
|
||||||
|
MAINTENANCE: Maintained
|
||||||
|
STATUS: Working
|
||||||
|
SINCE: 5.0
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: soap
|
||||||
|
PRIMARY MAINTAINER: Dmitry Stogov <dmitry@php.net> (2004 - 2018)
|
||||||
|
MAINTENANCE: Maintained
|
||||||
|
STATUS: Working
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: xml
|
||||||
|
PRIMARY MAINTAINER: Thies C. Arntzen <thies@thieso.net> (1999 - 2002)
|
||||||
|
Rob Richards <rrichards@php.net> (2003 - 2013)
|
||||||
|
MAINTENANCE: Maintained
|
||||||
|
STATUS: Working
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: libxml
|
||||||
|
PRIMARY MAINTAINER: Rob Richards <rrichards@php.net> (2003 - 2009)
|
||||||
|
Christian Stocker <chregu@php.net> (2004 - 2011)
|
||||||
|
MAINTENANCE: Maintained
|
||||||
|
STATUS: Working
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: xmlreader
|
||||||
|
PRIMARY MAINTAINER: Rob Richards <rrichards@php.net> (2004 - 2010)
|
||||||
|
Christian Stocker <chregu@php.net> (2004 - 2004)
|
||||||
|
MAINTENANCE: Maintained
|
||||||
|
STATUS: Working
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: xmlwriter
|
||||||
|
PRIMARY MAINTAINER: Rob Richards <rrichards@php.net> (2004 - 2010)
|
||||||
|
Pierre-Alain Joye <pajoye@php.net> (2005-2009)
|
||||||
|
MAINTENANCE: Maintained
|
||||||
|
STATUS: Working
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: xsl
|
||||||
|
PRIMARY MAINTAINER: Christian Stocker <chregu@php.net> (2003 - 2011)
|
||||||
|
Rob Richards <rrichards@php.net> (2003 - 2010)
|
||||||
|
MAINTENANCE: Maintained
|
||||||
|
STATUS: Working
|
||||||
|
SINCE: 5.0
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
== Other extensions ==
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: bcmath
|
||||||
|
PRIMARY MAINTAINER: Andi Gutmans <andi@php.net> (2000 - 2004)
|
||||||
|
MAINTENANCE: Unknown
|
||||||
|
STATUS: Working
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: bz2
|
||||||
|
PRIMARY MAINTAINER: Hartmut Holzgraefe <hholzgra@php.net> (2004 - 2004)
|
||||||
|
MAINTENANCE: Odd Fixes
|
||||||
|
STATUS: Working
|
||||||
|
SINCE: 4.0.3
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: calendar
|
||||||
|
PRIMARY MAINTAINER: Hartmut Holzgraefe <hholzgra@php.net> (2000 - 2004)
|
||||||
|
MAINTENANCE: Odd Fixes
|
||||||
|
STATUS: Working
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: com_dotnet
|
||||||
|
PRIMARY MAINTAINER: Wez Furlong <wez@php.net> (2003 - 2005)
|
||||||
|
Christoph M. Becker <cmb@php.net> (2018 - 2020)
|
||||||
|
MAINTENANCE: Maintained
|
||||||
|
STATUS: Windows
|
||||||
|
SINCE: 5.0
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: ctype
|
||||||
|
PRIMARY MAINTAINER: Hartmut Holzgraefe <hholzgra@php.net> (2000 - 2004)
|
||||||
|
MAINTENANCE: Maintained
|
||||||
|
STATUS: Working
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: curl
|
||||||
|
PRIMARY MAINTAINER: Sterling Hughes <sterling@php.net> (2000 - 2004)
|
||||||
|
Ilia Alshanetsky <iliaa@php.net> (2002 - 2011)
|
||||||
|
Pierrick Charron <pierrick@php.net> (2010 - 2016)
|
||||||
|
MAINTENANCE: Maintained
|
||||||
|
STATUS: Working
|
||||||
|
SINCE: 4.0.2
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: date
|
||||||
|
PRIMARY MAINTAINER: Derick Rethans <derick@php.net> (2005 - 2018)
|
||||||
|
MAINTENANCE: Maintained
|
||||||
|
STATUS: Working
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: enchant
|
||||||
|
PRIMARY MAINTAINER: Unknown
|
||||||
|
MAINTENANCE: Maintained
|
||||||
|
STATUS: Working
|
||||||
|
SINCE: 5.3
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: exif
|
||||||
|
PRIMARY MAINTAINER: Kalle Sommer Nielsen <kalle@php.net> (2010 - 2018)
|
||||||
|
MAINTENANCE: Maintained
|
||||||
|
STATUS: Working
|
||||||
|
SINCE: 4.2
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: ffi
|
||||||
|
PRIMARY MAINTAINER: Dmitry Stogov <dmitry@php.net> (2018 - 2019)
|
||||||
|
MAINTENANCE: Maintained
|
||||||
|
STATUS: Experimental
|
||||||
|
SINCE: 7.4.0
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: fileinfo
|
||||||
|
PRIMARY MAINTAINER: Derick Rethans <derick@php.net> (2004 - 2008)
|
||||||
|
Anatol Belski <ab@php.net> (2012 - 2020)
|
||||||
|
MAINTENANCE: Maintained
|
||||||
|
STATUS: Working
|
||||||
|
SINCE: 5.3
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: filter
|
||||||
|
PRIMARY MAINTAINER: Derick Rethans <derick@php.net> (2006 - 2006)
|
||||||
|
Pierre-Alain Joye <pajoye@php.net> (2006 - 2011)
|
||||||
|
Ilia Alshanetsky <iliaa@php.net> (2006 - 2011)
|
||||||
|
MAINTENANCE: Maintained
|
||||||
|
STATUS: Working
|
||||||
|
SINCE: 5.2
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: ftp
|
||||||
|
PRIMARY MAINTAINER: Unknown
|
||||||
|
MAINTENANCE: Odd fixes
|
||||||
|
STATUS: Working
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: gd
|
||||||
|
PRIMARY MAINTAINER: Pierre-Alain Joye <pajoye@php.net> (2002 - 2016)
|
||||||
|
Christoph M. Becker <cmb@php.net> (2015 - 2020)
|
||||||
|
MAINTENANCE: Maintained
|
||||||
|
STATUS: Working
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: gettext
|
||||||
|
PRIMARY MAINTAINER: Unknown
|
||||||
|
MAINTENANCE: Unknown
|
||||||
|
STATUS: Working
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: gmp
|
||||||
|
PRIMARY MAINTAINER: Stanislav Malyshev <stas@php.net> (2000 - 2019)
|
||||||
|
Antony Dovgal <tony2001@php.net> (2005 - 2010)
|
||||||
|
Nikita Popov <nikic@php.net> (2013 - 2020)
|
||||||
|
MAINTENANCE: Maintained
|
||||||
|
STATUS: Working
|
||||||
|
SINCE: 4.0.4
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: hash
|
||||||
|
PRIMARY MAINTAINER: Sara Golemon <pollita@php.net> (2005 - 2017)
|
||||||
|
Mike Wallner <mike@php.net> (2005 - 2013)
|
||||||
|
Anatol Belski <ab@php.net> (2014 - 2018)
|
||||||
|
MAINTENANCE: Maintained
|
||||||
|
STATUS: Working
|
||||||
|
SINCE: 5.1.2
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: iconv
|
||||||
|
PRIMARY MAINTAINER: Moriyoshi Koizumi <moriyoshi@php.net> (2002 - 2010)
|
||||||
|
MAINTENANCE: Maintained
|
||||||
|
STATUS: Working
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: intl
|
||||||
|
PRIMARY MAINTAINER: Stanislav Malyshev <stas@php.net> (2008 - 2019)
|
||||||
|
Anatol Belski <ab@php.net> (2017 - 2018)
|
||||||
|
MAINTENANCE: Maintained
|
||||||
|
STATUS: Working
|
||||||
|
SINCE: 5.3
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: imap
|
||||||
|
PRIMARY MAINTAINER: Chuck Hagenbuch <chuck@horde.org> (1999 - 2004)
|
||||||
|
Ilia Alshanetsky <iliaa@php.net> (2002 - 2010)
|
||||||
|
Pierre-Alain Joye <pajoye@php.net> (2008 - 2010)
|
||||||
|
Bishop Bettini <bishop@php.net> (2018 - 2019)
|
||||||
|
MAINTENANCE: Maintained
|
||||||
|
STATUS: Working
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: json
|
||||||
|
PRIMARY MAINTAINER: Jakub Zelenka <bukka@php.net> (2014 - 2018)
|
||||||
|
MAINTENANCE: Maintained
|
||||||
|
STATUS: Working
|
||||||
|
SINCE: 5.2
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: ldap
|
||||||
|
PRIMARY MAINTAINER: Stig Venaas <venaas@php.net> (2000 - 2002)
|
||||||
|
Douglas Goldstein <cardoe@php.net> (2007 - 2007)
|
||||||
|
Pierre-Alain Joye <pajoye@php.net> (2008 - 2010)
|
||||||
|
Côme Bernigaud <mcmic@php.net> (2015 - 2017)
|
||||||
|
MAINTENANCE: Maintained
|
||||||
|
STATUS: Working
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: mbstring
|
||||||
|
PRIMARY MAINTAINER: Rui Hirokawa <hirokawa@php.net> (2001 - 2013)
|
||||||
|
Nikita Popov <nikic@php.net> (2017 - 2020)
|
||||||
|
MAINTENANCE: Maintained
|
||||||
|
STATUS: Working
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: opcache
|
||||||
|
PRIMARY MAINTAINER: Dmitry Stogov <dmitry@php.net> (2013 - 2018)
|
||||||
|
Xinchen Hui <laruence@php.net> (2013 - 2020)
|
||||||
|
Nikita Popov <nikic@php.net> (2016 - 2020)
|
||||||
|
MAINTENANCE: Maintained
|
||||||
|
STATUS: Working
|
||||||
|
SINCE: 5.5.0
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: openssl
|
||||||
|
PRIMARY MAINTAINER: Wez Furlong <wez@php.net> (2001 - 2006)
|
||||||
|
Pierre-Alain Joye <pajoye@php.net> (2006 - 2011)
|
||||||
|
Jakub Zelenka <bukka@php.net> (2015 - 2019)
|
||||||
|
MAINTENANCE: Maintained
|
||||||
|
STATUS: Working
|
||||||
|
SINCE: 4.0.4
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: pcntl
|
||||||
|
PRIMARY MAINTAINER: Arnaud Le Blanc <lbarnaud@php.net> (2008 - 2010)
|
||||||
|
MAINTENANCE: Maintained
|
||||||
|
STATUS: Working
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: pcre
|
||||||
|
PRIMARY MAINTAINER: Andrei Zmievski <andrei@php.net> (1999 - 2006)
|
||||||
|
Nuno Lopes <nlopess@php.net> (2006 - 2009)
|
||||||
|
MAINTENANCE: Maintained
|
||||||
|
STATUS: Working
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: phar
|
||||||
|
PRIMARY MAINTAINER: Greg Beaver <cellog@php.net> (2008 - 2009)
|
||||||
|
Marcus Börger <helly@php.net> (2008 - 2008)
|
||||||
|
Steph Fox <sfox@php.net> (2008 - 2008)
|
||||||
|
Bishop Bettini <bishop@php.net> (2018 - 2019)
|
||||||
|
MAINTENANCE: Maintained
|
||||||
|
STATUS: Working
|
||||||
|
SINCE: 5.3
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: posix
|
||||||
|
PRIMARY MAINTAINER: Kristian Köhntopp <kris@koehntopp.de> (2000 - 2000)
|
||||||
|
MAINTENANCE: Maintained
|
||||||
|
STATUS: Working
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: pspell
|
||||||
|
PRIMARY MAINTAINER: Vlad Krupin <phpdevel@echospace.com> (2000 - 2004)
|
||||||
|
MAINTENANCE: Unknown
|
||||||
|
STATUS: Working
|
||||||
|
SINCE: 4.0.2
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: readline
|
||||||
|
PRIMARY MAINTAINER: Unknown
|
||||||
|
MAINTENANCE: Unknown
|
||||||
|
STATUS: Working
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: reflection
|
||||||
|
PRIMARY MAINTAINER: Marcus Börger <helly@php.net> (2003 - 2009)
|
||||||
|
Johannes Schlüter <johannes@php.net> (2006 - 2014)
|
||||||
|
Nikita Popov <nikic@php.net> (2019 - 2020)
|
||||||
|
MAINTENANCE: Maintained
|
||||||
|
STATUS: Working
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: session
|
||||||
|
PRIMARY MAINTAINER: Sascha Schumann <sascha@schumann.cx> (1999 - 2004)
|
||||||
|
Ilia Alshanetsky <iliaa@php.net> (2002 - 2012)
|
||||||
|
MAINTENANCE: Maintained
|
||||||
|
STATUS: Working
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: shmop
|
||||||
|
PRIMARY MAINTAINER: Ilia Alshanetsky <iliaa@php.net> (2002 - 2008)
|
||||||
|
MAINTENANCE: Maintained
|
||||||
|
STATUS: Working
|
||||||
|
SINCE: 4.0.3
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: snmp
|
||||||
|
PRIMARY MAINTAINER: Boris Lytochkin <lytboris@php.net> (2011 - 2013)
|
||||||
|
Rasmus Lerdorf <rasmus@php.net> (1999 - 2002)
|
||||||
|
Pierre-Alain Joye <pajoye@php.net> (2010 - 2011)
|
||||||
|
MAINTENANCE: Maintained
|
||||||
|
STATUS: Working
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: sockets
|
||||||
|
PRIMARY MAINTAINER: Chris Vandomelen <chrisv@b0rked.dhs.org> (2000 - 2000)
|
||||||
|
MAINTENANCE: Maintained
|
||||||
|
STATUS: Working
|
||||||
|
SINCE: 4.0.2
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: sodium
|
||||||
|
PRIMARY MAINTAINER: Frank Denis <jedisct1@php.net> (2017 - 2017)
|
||||||
|
MAINTENANCE: Maintained
|
||||||
|
STATUS: Working
|
||||||
|
SINCE: 7.2.0
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: spl
|
||||||
|
PRIMARY MAINTAINER: Marcus Börger <helly@php.net> (2003 - 2009)
|
||||||
|
Etienne Kneuss <colder@php.net> (2008 - 2014)
|
||||||
|
MAINTENANCE: Maintained
|
||||||
|
STATUS: Working
|
||||||
|
SINCE: 5.0.0
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: sysvmsg
|
||||||
|
PRIMARY MAINTAINER: Unknown
|
||||||
|
MAINTENANCE: Unknown
|
||||||
|
STATUS: Working
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: sysvsem
|
||||||
|
PRIMARY MAINTAINER: Unknown
|
||||||
|
MAINTENANCE: Unknown
|
||||||
|
STATUS: Working
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: sysvshm
|
||||||
|
PRIMARY MAINTAINER: Unknown
|
||||||
|
MAINTENANCE: Unknown
|
||||||
|
STATUS: Working
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: tidy
|
||||||
|
PRIMARY MAINTAINER: John Coggeshall <john@php.net> (2003 - 2006)
|
||||||
|
Ilia Alshanetsky <iliaa@php.net> (2003 - 2009)
|
||||||
|
Nuno Lopes <nlopess@php.net> (2006 - 2012)
|
||||||
|
MAINTENANCE: Maintained
|
||||||
|
STATUS: Working
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: tokenizer
|
||||||
|
PRIMARY MAINTAINER: Andrei Zmievski <andrei@php.net> (2002 - 2002)
|
||||||
|
Nikita Popov <nikic@php.net> (2013 - 2020)
|
||||||
|
MAINTENANCE: Maintained
|
||||||
|
STATUS: Working
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: zip
|
||||||
|
PRIMARY MAINTAINER: Pierre-Alain Joye <pajoye@php.net> (2006 - 2011)
|
||||||
|
Remi Collet <remi@php.net> (2013-2020)
|
||||||
|
MAINTENANCE: Maintained
|
||||||
|
STATUS: Working
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
EXTENSION: zlib
|
||||||
|
PRIMARY MAINTAINER: Stefan Roehrich <sr@linux.de> (1999 - 2003)
|
||||||
|
MAINTENANCE: Maintained
|
||||||
|
STATUS: Working
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
@ -0,0 +1,68 @@
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
The PHP License, version 3.01
|
||||||
|
Copyright (c) 1999 - 2021 The PHP Group. All rights reserved.
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, is permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in
|
||||||
|
the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
|
||||||
|
3. The name "PHP" must not be used to endorse or promote products
|
||||||
|
derived from this software without prior written permission. For
|
||||||
|
written permission, please contact group@php.net.
|
||||||
|
|
||||||
|
4. Products derived from this software may not be called "PHP", nor
|
||||||
|
may "PHP" appear in their name, without prior written permission
|
||||||
|
from group@php.net. You may indicate that your software works in
|
||||||
|
conjunction with PHP by saying "Foo for PHP" instead of calling
|
||||||
|
it "PHP Foo" or "phpfoo"
|
||||||
|
|
||||||
|
5. The PHP Group may publish revised and/or new versions of the
|
||||||
|
license from time to time. Each version will be given a
|
||||||
|
distinguishing version number.
|
||||||
|
Once covered code has been published under a particular version
|
||||||
|
of the license, you may always continue to use it under the terms
|
||||||
|
of that version. You may also choose to use such covered code
|
||||||
|
under the terms of any subsequent version of the license
|
||||||
|
published by the PHP Group. No one other than the PHP Group has
|
||||||
|
the right to modify the terms applicable to covered code created
|
||||||
|
under this License.
|
||||||
|
|
||||||
|
6. Redistributions of any form whatsoever must retain the following
|
||||||
|
acknowledgment:
|
||||||
|
"This product includes PHP software, freely available from
|
||||||
|
<http://www.php.net/software/>".
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE PHP DEVELOPMENT TEAM ``AS IS'' AND
|
||||||
|
ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PHP
|
||||||
|
DEVELOPMENT TEAM OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||||
|
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||||
|
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||||
|
OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
|
||||||
|
This software consists of voluntary contributions made by many
|
||||||
|
individuals on behalf of the PHP Group.
|
||||||
|
|
||||||
|
The PHP Group can be contacted via Email at group@php.net.
|
||||||
|
|
||||||
|
For more information on the PHP Group and the PHP project,
|
||||||
|
please see <http://www.php.net>.
|
||||||
|
|
||||||
|
PHP includes the Zend Engine, freely available at
|
||||||
|
<http://www.zend.com>.
|
||||||
|
|
@ -0,0 +1,642 @@
|
||||||
|
1. libmagic (ext/fileinfo) see ext/fileinfo/libmagic/LICENSE
|
||||||
|
2. libmbfl (ext/mbstring) see ext/mbstring/libmbfl/LICENSE
|
||||||
|
3. pcre2lib (ext/pcre)
|
||||||
|
4. ext/standard crypt
|
||||||
|
5. ext/standard crypt's blowfish implementation
|
||||||
|
6. ext/standard/rand
|
||||||
|
7. ext/standard/scanf
|
||||||
|
8. ext/standard/strnatcmp.c
|
||||||
|
9. ext/standard/uuencode
|
||||||
|
10. main/snprintf.c
|
||||||
|
11. main/strlcat
|
||||||
|
12. main/strlcpy
|
||||||
|
13. libgd (ext/gd)
|
||||||
|
14. ext/phar portions of tar implementations
|
||||||
|
15. ext/phar/zip.c portion extracted from libzip
|
||||||
|
16. libbcmath (ext/bcmath) see ext/bcmath/libbcmath/LICENSE
|
||||||
|
17. ext/mbstring/ucgendat portions based on the ucgendat.c from the OpenLDAP
|
||||||
|
|
||||||
|
|
||||||
|
3. pcre2lib (ext/pcre)
|
||||||
|
|
||||||
|
PCRE2 LICENCE
|
||||||
|
-------------
|
||||||
|
|
||||||
|
PCRE2 is a library of functions to support regular expressions whose syntax
|
||||||
|
and semantics are as close as possible to those of the Perl 5 language.
|
||||||
|
|
||||||
|
Releases 10.00 and above of PCRE2 are distributed under the terms of the "BSD"
|
||||||
|
licence, as specified below, with one exemption for certain binary
|
||||||
|
redistributions. The documentation for PCRE2, supplied in the "doc" directory,
|
||||||
|
is distributed under the same terms as the software itself. The data in the
|
||||||
|
testdata directory is not copyrighted and is in the public domain.
|
||||||
|
|
||||||
|
The basic library functions are written in C and are freestanding. Also
|
||||||
|
included in the distribution is a just-in-time compiler that can be used to
|
||||||
|
optimize pattern matching. This is an optional feature that can be omitted when
|
||||||
|
the library is built.
|
||||||
|
|
||||||
|
|
||||||
|
THE BASIC LIBRARY FUNCTIONS
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
Written by: Philip Hazel
|
||||||
|
Email local part: ph10
|
||||||
|
Email domain: cam.ac.uk
|
||||||
|
|
||||||
|
University of Cambridge Computing Service,
|
||||||
|
Cambridge, England.
|
||||||
|
|
||||||
|
Copyright (c) 1997-2019 University of Cambridge
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
|
||||||
|
PCRE2 JUST-IN-TIME COMPILATION SUPPORT
|
||||||
|
--------------------------------------
|
||||||
|
|
||||||
|
Written by: Zoltan Herczeg
|
||||||
|
Email local part: hzmester
|
||||||
|
Email domain: freemail.hu
|
||||||
|
|
||||||
|
Copyright(c) 2010-2019 Zoltan Herczeg
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
|
||||||
|
STACK-LESS JUST-IN-TIME COMPILER
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
Written by: Zoltan Herczeg
|
||||||
|
Email local part: hzmester
|
||||||
|
Email domain: freemail.hu
|
||||||
|
|
||||||
|
Copyright(c) 2009-2019 Zoltan Herczeg
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
|
||||||
|
THE "BSD" LICENCE
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright notices,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
notices, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
* Neither the name of the University of Cambridge nor the names of any
|
||||||
|
contributors may be used to endorse or promote products derived from this
|
||||||
|
software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
|
||||||
|
EXEMPTION FOR BINARY LIBRARY-LIKE PACKAGES
|
||||||
|
------------------------------------------
|
||||||
|
|
||||||
|
The second condition in the BSD licence (covering binary redistributions) does
|
||||||
|
not apply all the way down a chain of software. If binary package A includes
|
||||||
|
PCRE2, it must respect the condition, but if package B is software that
|
||||||
|
includes package A, the condition is not imposed on package B unless it uses
|
||||||
|
PCRE2 independently.
|
||||||
|
|
||||||
|
End
|
||||||
|
|
||||||
|
|
||||||
|
4. ext/standard crypt
|
||||||
|
|
||||||
|
FreeSec: libcrypt for NetBSD
|
||||||
|
|
||||||
|
Copyright (c) 1994 David Burren
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. Neither the name of the author nor the names of other contributors
|
||||||
|
may be used to endorse or promote products derived from this software
|
||||||
|
without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
SUCH DAMAGE.
|
||||||
|
|
||||||
|
|
||||||
|
5. ext/standard crypt's blowfish implementation
|
||||||
|
|
||||||
|
The crypt_blowfish homepage is:
|
||||||
|
|
||||||
|
http://www.openwall.com/crypt/
|
||||||
|
|
||||||
|
This code comes from John the Ripper password cracker, with reentrant
|
||||||
|
and crypt(3) interfaces added, but optimizations specific to password
|
||||||
|
cracking removed.
|
||||||
|
|
||||||
|
Written by Solar Designer <solar at openwall.com> in 1998-2011.
|
||||||
|
No copyright is claimed, and the software is hereby placed in the public
|
||||||
|
domain. In case this attempt to disclaim copyright and place the software
|
||||||
|
in the public domain is deemed null and void, then the software is
|
||||||
|
Copyright (c) 1998-2011 Solar Designer and it is hereby released to the
|
||||||
|
general public under the following terms:
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted.
|
||||||
|
|
||||||
|
There's ABSOLUTELY NO WARRANTY, express or implied.
|
||||||
|
|
||||||
|
It is my intent that you should be able to use this on your system,
|
||||||
|
as part of a software package, or anywhere else to improve security,
|
||||||
|
ensure compatibility, or for any other purpose. I would appreciate
|
||||||
|
it if you give credit where it is due and keep your modifications in
|
||||||
|
the public domain as well, but I don't require that in order to let
|
||||||
|
you place this code and any modifications you make under a license
|
||||||
|
of your choice.
|
||||||
|
|
||||||
|
This implementation is mostly compatible with OpenBSD's bcrypt.c (prefix
|
||||||
|
"$2a$") by Niels Provos <provos at citi.umich.edu>, and uses some of his
|
||||||
|
ideas. The password hashing algorithm was designed by David Mazieres
|
||||||
|
<dm at lcs.mit.edu>. For more information on the level of compatibility,
|
||||||
|
please refer to the comments in BF_set_key() and to the crypt(3) man page
|
||||||
|
included in the crypt_blowfish tarball.
|
||||||
|
|
||||||
|
There's a paper on the algorithm that explains its design decisions:
|
||||||
|
|
||||||
|
http://www.usenix.org/events/usenix99/provos.html
|
||||||
|
|
||||||
|
Some of the tricks in BF_ROUND might be inspired by Eric Young's
|
||||||
|
Blowfish library (I can't be sure if I would think of something if I
|
||||||
|
hadn't seen his code).
|
||||||
|
|
||||||
|
|
||||||
|
6. ext/standard/rand
|
||||||
|
|
||||||
|
The following php_mt_...() functions are based on a C++ class MTRand by
|
||||||
|
Richard J. Wagner. For more information see the web page at
|
||||||
|
http://www-personal.engin.umich.edu/~wagnerr/MersenneTwister.html
|
||||||
|
|
||||||
|
Mersenne Twister random number generator -- a C++ class MTRand
|
||||||
|
Based on code by Makoto Matsumoto, Takuji Nishimura, and Shawn Cokus
|
||||||
|
Richard J. Wagner v1.0 15 May 2003 rjwagner@writeme.com
|
||||||
|
|
||||||
|
The Mersenne Twister is an algorithm for generating random numbers. It
|
||||||
|
was designed with consideration of the flaws in various other generators.
|
||||||
|
The period, 2^19937-1, and the order of equidistribution, 623 dimensions,
|
||||||
|
are far greater. The generator is also fast; it avoids multiplication and
|
||||||
|
division, and it benefits from caches and pipelines. For more information
|
||||||
|
see the inventors' web page at http://www.math.keio.ac.jp/~matumoto/emt.html
|
||||||
|
|
||||||
|
Reference
|
||||||
|
M. Matsumoto and T. Nishimura, "Mersenne Twister: A 623-Dimensionally
|
||||||
|
Equidistributed Uniform Pseudo-Random Number Generator", ACM Transactions on
|
||||||
|
Modeling and Computer Simulation, Vol. 8, No. 1, January 1998, pp 3-30.
|
||||||
|
|
||||||
|
Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
|
||||||
|
Copyright (C) 2000 - 2003, Richard J. Wagner
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
3. The names of its contributors may not be used to endorse or promote
|
||||||
|
products derived from this software without specific prior written
|
||||||
|
permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
|
||||||
|
7. ext/standard/scanf
|
||||||
|
|
||||||
|
scanf.c --
|
||||||
|
|
||||||
|
This file contains the base code which implements sscanf and by extension
|
||||||
|
fscanf. Original code is from TCL8.3.0 and bears the following copyright:
|
||||||
|
|
||||||
|
This software is copyrighted by the Regents of the University of
|
||||||
|
California, Sun Microsystems, Inc., Scriptics Corporation,
|
||||||
|
and other parties. The following terms apply to all files associated
|
||||||
|
with the software unless explicitly disclaimed in individual files.
|
||||||
|
|
||||||
|
The authors hereby grant permission to use, copy, modify, distribute,
|
||||||
|
and license this software and its documentation for any purpose, provided
|
||||||
|
that existing copyright notices are retained in all copies and that this
|
||||||
|
notice is included verbatim in any distributions. No written agreement,
|
||||||
|
license, or royalty fee is required for any of the authorized uses.
|
||||||
|
Modifications to this software may be copyrighted by their authors
|
||||||
|
and need not follow the licensing terms described here, provided that
|
||||||
|
the new terms are clearly indicated on the first page of each file where
|
||||||
|
they apply.
|
||||||
|
|
||||||
|
IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
|
||||||
|
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||||
|
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
|
||||||
|
DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
|
||||||
|
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
|
||||||
|
IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
|
||||||
|
NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
|
||||||
|
MODIFICATIONS.
|
||||||
|
|
||||||
|
GOVERNMENT USE: If you are acquiring this software on behalf of the
|
||||||
|
U.S. government, the Government shall have only "Restricted Rights"
|
||||||
|
in the software and related documentation as defined in the Federal
|
||||||
|
Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you
|
||||||
|
are acquiring the software on behalf of the Department of Defense, the
|
||||||
|
software shall be classified as "Commercial Computer Software" and the
|
||||||
|
Government shall have only "Restricted Rights" as defined in Clause
|
||||||
|
252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the
|
||||||
|
authors grant the U.S. Government and others acting in its behalf
|
||||||
|
permission to use and distribute the software in accordance with the
|
||||||
|
terms specified in this license.
|
||||||
|
|
||||||
|
|
||||||
|
8. ext/standard/strnatcmp.c
|
||||||
|
|
||||||
|
strnatcmp.c -- Perform 'natural order' comparisons of strings in C.
|
||||||
|
Copyright (C) 2000 by Martin Pool <mbp@humbug.org.au>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
|
||||||
|
|
||||||
|
9. ext/standard/uuencode
|
||||||
|
|
||||||
|
Portions of this code are based on Berkeley's uuencode/uudecode
|
||||||
|
implementation.
|
||||||
|
|
||||||
|
Copyright (c) 1983, 1993
|
||||||
|
The Regents of the University of California. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. All advertising materials mentioning features or use of this software
|
||||||
|
must display the following acknowledgement:
|
||||||
|
This product includes software developed by the University of
|
||||||
|
California, Berkeley and its contributors.
|
||||||
|
4. Neither the name of the University nor the names of its contributors
|
||||||
|
may be used to endorse or promote products derived from this software
|
||||||
|
without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||||
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
SUCH DAMAGE.
|
||||||
|
|
||||||
|
|
||||||
|
10. main/snprintf.c
|
||||||
|
|
||||||
|
Copyright (c) 2002, 2006 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
Sponsored in part by the Defense Advanced Research Projects
|
||||||
|
Agency (DARPA) and Air Force Research Laboratory, Air Force
|
||||||
|
Materiel Command, USAF, under agreement number F39502-99-1-0512.
|
||||||
|
|
||||||
|
main/spprintf
|
||||||
|
Copyright (c) 1995-1998 The Apache Group. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in
|
||||||
|
the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
|
||||||
|
3. All advertising materials mentioning features or use of this
|
||||||
|
software must display the following acknowledgment:
|
||||||
|
"This product includes software developed by the Apache Group
|
||||||
|
for use in the Apache HTTP server project (http://www.apache.org/)."
|
||||||
|
|
||||||
|
4. The names "Apache Server" and "Apache Group" must not be used to
|
||||||
|
endorse or promote products derived from this software without
|
||||||
|
prior written permission.
|
||||||
|
|
||||||
|
5. Redistributions of any form whatsoever must retain the following
|
||||||
|
acknowledgment:
|
||||||
|
"This product includes software developed by the Apache Group
|
||||||
|
for use in the Apache HTTP server project (http://www.apache.org/)."
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
|
||||||
|
EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR
|
||||||
|
ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||||
|
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||||
|
OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
====================================================================
|
||||||
|
|
||||||
|
This software consists of voluntary contributions made by many
|
||||||
|
individuals on behalf of the Apache Group and was originally based
|
||||||
|
on public domain software written at the National Center for
|
||||||
|
Supercomputing Applications, University of Illinois, Urbana-Champaign.
|
||||||
|
For more information on the Apache Group and the Apache HTTP server
|
||||||
|
project, please see <http://www.apache.org/>.
|
||||||
|
|
||||||
|
This code is based on, and used with the permission of, the
|
||||||
|
SIO stdio-replacement strx_* functions by Panos Tsirigotis
|
||||||
|
<panos@alumni.cs.colorado.edu> for xinetd.
|
||||||
|
|
||||||
|
|
||||||
|
11. main/strlcat
|
||||||
|
12. main/strlcpy
|
||||||
|
|
||||||
|
Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
|
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||||
|
THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||||
|
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||||
|
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||||
|
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
|
||||||
|
13. libgd (ext/gd)
|
||||||
|
|
||||||
|
* Portions copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
|
||||||
|
2002, 2003, 2004 by Cold Spring Harbor Laboratory. Funded under
|
||||||
|
Grant P41-RR02188 by the National Institutes of Health.
|
||||||
|
|
||||||
|
* Portions copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
|
||||||
|
2004 by Boutell.Com, Inc.
|
||||||
|
|
||||||
|
* Portions relating to GD2 format copyright 1999, 2000, 2001, 2002,
|
||||||
|
2003, 2004 Philip Warner.
|
||||||
|
|
||||||
|
* Portions relating to PNG copyright 1999, 2000, 2001, 2002, 2003,
|
||||||
|
2004 Greg Roelofs.
|
||||||
|
|
||||||
|
* Portions relating to gdttf.c copyright 1999, 2000, 2001, 2002,
|
||||||
|
2003, 2004 John Ellson (ellson@graphviz.org).
|
||||||
|
|
||||||
|
* Portions relating to gdft.c copyright 2001, 2002, 2003, 2004 John
|
||||||
|
Ellson (ellson@graphviz.org).
|
||||||
|
|
||||||
|
* Portions copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
|
||||||
|
Pierre-Alain Joye (pierre@libgd.org).
|
||||||
|
|
||||||
|
* Portions relating to JPEG and to color quantization copyright
|
||||||
|
2000, 2001, 2002, 2003, 2004, Doug Becker and copyright (C) 1994,
|
||||||
|
1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 Thomas
|
||||||
|
G. Lane. This software is based in part on the work of the
|
||||||
|
Independent JPEG Group. See the file README-JPEG.TXT for more
|
||||||
|
information.
|
||||||
|
|
||||||
|
* Portions relating to GIF compression copyright 1989 by Jef
|
||||||
|
Poskanzer and David Rowley, with modifications for thread safety
|
||||||
|
by Thomas Boutell.
|
||||||
|
|
||||||
|
* Portions relating to GIF decompression copyright 1990, 1991, 1993
|
||||||
|
by David Koblas, with modifications for thread safety by Thomas
|
||||||
|
Boutell.
|
||||||
|
|
||||||
|
* Portions relating to WBMP copyright 2000, 2001, 2002, 2003, 2004
|
||||||
|
Maurice Szmurlo and Johan Van den Brande.
|
||||||
|
|
||||||
|
* Portions relating to GIF animations copyright 2004 Jaakko Hyvätti
|
||||||
|
(jaakko.hyvatti@iki.fi)
|
||||||
|
|
||||||
|
Permission has been granted to copy, distribute and modify gd in
|
||||||
|
any context without fee, including a commercial application,
|
||||||
|
provided that this notice is present in user-accessible supporting
|
||||||
|
documentation.
|
||||||
|
|
||||||
|
This does not affect your ownership of the derived work itself,
|
||||||
|
and the intent is to assure proper credit for the authors of gd,
|
||||||
|
not to interfere with your productive use of gd. If you have
|
||||||
|
questions, ask. "Derived works" includes all programs that utilize
|
||||||
|
the library. Credit must be given in user-accessible
|
||||||
|
documentation.
|
||||||
|
|
||||||
|
This software is provided "AS IS." The copyright holders disclaim
|
||||||
|
all warranties, either express or implied, including but not
|
||||||
|
limited to implied warranties of merchantability and fitness for a
|
||||||
|
particular purpose, with respect to this code and accompanying
|
||||||
|
documentation.
|
||||||
|
|
||||||
|
Although their code does not appear in the current release, the
|
||||||
|
authors wish to thank David Koblas, David Rowley, and Hutchison
|
||||||
|
Avenue Software Corporation for their prior contributions.
|
||||||
|
|
||||||
|
END OF COPYRIGHT STATEMENT
|
||||||
|
|
||||||
|
|
||||||
|
14. ext/phar portions of tar implementations
|
||||||
|
|
||||||
|
portions of tar implementations in ext/phar - phar_tar_octal() are based on an
|
||||||
|
implementation by Tim Kientzle from libarchive, licensed with this license:
|
||||||
|
|
||||||
|
Copyright (c) 2003-2007 Tim Kientzle
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
|
||||||
|
15. ext/phar/zip.c portion extracted from libzip
|
||||||
|
|
||||||
|
zip_dirent.c -- read directory entry (local or central), clean dirent
|
||||||
|
Copyright (C) 1999, 2003, 2004, 2005 Dieter Baron and Thomas Klausner
|
||||||
|
|
||||||
|
This function is part of libzip, a library to manipulate ZIP archives.
|
||||||
|
The authors can be contacted at <nih@giga.or.at>
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in
|
||||||
|
the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
3. The names of the authors may not be used to endorse or promote
|
||||||
|
products derived from this software without specific prior
|
||||||
|
written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
|
||||||
|
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
|
||||||
|
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||||
|
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||||
|
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||||
|
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||||
|
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
|
||||||
|
16. ext/mbstring/ucgendat portions based on the ucgendat.c from the OpenLDAP
|
||||||
|
|
||||||
|
The OpenLDAP Public License
|
||||||
|
Version 2.8, 17 August 2003
|
||||||
|
|
||||||
|
Redistribution and use of this software and associated documentation
|
||||||
|
("Software"), with or without modification, are permitted provided
|
||||||
|
that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions in source form must retain copyright statements
|
||||||
|
and notices,
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce applicable copyright
|
||||||
|
statements and notices, this list of conditions, and the following
|
||||||
|
disclaimer in the documentation and/or other materials provided
|
||||||
|
with the distribution, and
|
||||||
|
|
||||||
|
3. Redistributions must contain a verbatim copy of this document.
|
||||||
|
|
||||||
|
The OpenLDAP Foundation may revise this license from time to time.
|
||||||
|
Each revision is distinguished by a version number. You may use
|
||||||
|
this Software under terms of this license revision or under the
|
||||||
|
terms of any subsequent revision of the license.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE OPENLDAP FOUNDATION AND ITS
|
||||||
|
CONTRIBUTORS ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||||
|
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
|
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||||
|
SHALL THE OPENLDAP FOUNDATION, ITS CONTRIBUTORS, OR THE AUTHOR(S)
|
||||||
|
OR OWNER(S) OF THE SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
The names of the authors and copyright holders must not be used in
|
||||||
|
advertising or otherwise to promote the sale, use or other dealing
|
||||||
|
in this Software without specific, written prior permission. Title
|
||||||
|
to copyright in this Software shall at all times remain with copyright
|
||||||
|
holders.
|
||||||
|
|
||||||
|
OpenLDAP is a registered trademark of the OpenLDAP Foundation.
|
||||||
|
|
||||||
|
Copyright 1999-2003 The OpenLDAP Foundation, Redwood City,
|
||||||
|
California, USA. All Rights Reserved. Permission to copy and
|
||||||
|
distribute verbatim copies of this document is granted.
|
||||||
|
|
@ -0,0 +1,136 @@
|
||||||
|
<div align="center">
|
||||||
|
<a href="https://php.net">
|
||||||
|
<img
|
||||||
|
alt="PHP"
|
||||||
|
src="https://www.php.net/images/logos/new-php-logo.svg"
|
||||||
|
width="150">
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
# The PHP Interpreter
|
||||||
|
|
||||||
|
PHP is a popular general-purpose scripting language that is especially suited to
|
||||||
|
web development. Fast, flexible and pragmatic, PHP powers everything from your
|
||||||
|
blog to the most popular websites in the world. PHP is distributed under the
|
||||||
|
[PHP License v3.01](LICENSE).
|
||||||
|
|
||||||
|
[](https://travis-ci.org/php/php-src)
|
||||||
|
[](https://ci.appveyor.com/project/php/php-src)
|
||||||
|
[](https://dev.azure.com/phpazuredevops/php/_build/latest?definitionId=1&branchName=master)
|
||||||
|
[](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:php)
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
The PHP manual is available at [php.net/docs](https://php.net/docs).
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
### Prebuilt packages and binaries
|
||||||
|
|
||||||
|
Prebuilt packages and binaries can be used to get up and running fast with PHP.
|
||||||
|
|
||||||
|
For Windows, the PHP binaries can be obtained from
|
||||||
|
[windows.php.net](https://windows.php.net). After extracting the archive the
|
||||||
|
`*.exe` files are ready to use.
|
||||||
|
|
||||||
|
For other systems, see the [installation chapter](https://php.net/install).
|
||||||
|
|
||||||
|
### Building PHP source code
|
||||||
|
|
||||||
|
*For Windows, see [Build your own PHP on Windows](https://wiki.php.net/internals/windows/stepbystepbuild_sdk_2).*
|
||||||
|
|
||||||
|
For a minimal PHP build from Git, you will need autoconf, bison, and re2c. For
|
||||||
|
a default build, you will additionally need libxml2 and libsqlite3. On Ubuntu,
|
||||||
|
you can install these using:
|
||||||
|
|
||||||
|
sudo apt install -y pkg-config build-essential autoconf bison re2c \
|
||||||
|
libxml2-dev libsqlite3-dev
|
||||||
|
|
||||||
|
Generate configure:
|
||||||
|
|
||||||
|
./buildconf
|
||||||
|
|
||||||
|
Configure your build. `--enable-debug` is recommended for development, see
|
||||||
|
`./configure --help` for a full list of options.
|
||||||
|
|
||||||
|
# For development
|
||||||
|
./configure --enable-debug
|
||||||
|
# For production
|
||||||
|
./configure
|
||||||
|
|
||||||
|
Build PHP. To speed up the build, specify the maximum number of jobs using `-j`:
|
||||||
|
|
||||||
|
make -j4
|
||||||
|
|
||||||
|
The number of jobs should usually match the number of available cores, which
|
||||||
|
can be determined using `nproc`.
|
||||||
|
|
||||||
|
## 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.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
The [qa.php.net](https://qa.php.net) site provides more detailed info about
|
||||||
|
testing and quality assurance.
|
||||||
|
|
||||||
|
## Installing PHP built from source
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
## PHP extensions
|
||||||
|
|
||||||
|
Extensions provide additional functionality on top of PHP. PHP consists of many
|
||||||
|
essential bundled extensions. Additional extensions can be found in the PHP
|
||||||
|
Extension Community Library - [PECL](https://pecl.php.net).
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
The PHP source code is located in the Git repository at
|
||||||
|
[github.com/php/php-src](https://github.com/php/php-src). Contributions are most
|
||||||
|
welcome by forking the repository and sending a pull request.
|
||||||
|
|
||||||
|
Discussions are done on GitHub, but depending on the topic can also be relayed
|
||||||
|
to the official PHP developer mailing list internals@lists.php.net.
|
||||||
|
|
||||||
|
New features require an RFC and must be accepted by the developers. See
|
||||||
|
[Request for comments - RFC](https://wiki.php.net/rfc) and
|
||||||
|
[Voting on PHP features](https://wiki.php.net/rfc/voting) for more information
|
||||||
|
on the process.
|
||||||
|
|
||||||
|
Bug fixes don't require an RFC. If the bug has a GitHub issue, reference it in
|
||||||
|
the commit message using `GH-NNNNNN`. Use `#NNNNNN` for tickets in the old
|
||||||
|
[bugs.php.net](https://bugs.php.net) bug tracker.
|
||||||
|
|
||||||
|
Fix GH-7815: php_uname doesn't recognise latest Windows versions
|
||||||
|
Fix #55371: get_magic_quotes_gpc() throws deprecation warning
|
||||||
|
|
||||||
|
See [Git workflow](https://wiki.php.net/vcs/gitworkflow) for details on how pull
|
||||||
|
requests are merged.
|
||||||
|
|
||||||
|
### Guidelines for contributors
|
||||||
|
|
||||||
|
See further documents in the repository for more information on how to
|
||||||
|
contribute:
|
||||||
|
|
||||||
|
- [Contributing to PHP](/CONTRIBUTING.md)
|
||||||
|
- [PHP coding standards](/CODING_STANDARDS.md)
|
||||||
|
- [Mailinglist rules](/docs/mailinglist-rules.md)
|
||||||
|
- [PHP release process](/docs/release-process.md)
|
||||||
|
|
||||||
|
## Credits
|
||||||
|
|
||||||
|
For the list of people who've put work into PHP, please see the
|
||||||
|
[PHP credits page](https://php.net/credits.php).
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
Copyright (c) 1999-2006, Andi Gutmans, Sascha Schumann, Zeev Suraski.
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
- Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
- Neither name of the copyright holders nor the names of their contributors
|
||||||
|
may be used to endorse or promote products derived from this software
|
||||||
|
without specific prior written permission.
|
||||||
|
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
|
||||||
|
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
|
||||||
|
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
@ -0,0 +1,777 @@
|
||||||
|
/*
|
||||||
|
+----------------------------------------------------------------------+
|
||||||
|
| Thread Safe Resource Manager |
|
||||||
|
+----------------------------------------------------------------------+
|
||||||
|
| Copyright (c) 1999-2011, Andi Gutmans, Sascha Schumann, Zeev Suraski |
|
||||||
|
| This source file is subject to the TSRM license, that is bundled |
|
||||||
|
| with this package in the file LICENSE |
|
||||||
|
+----------------------------------------------------------------------+
|
||||||
|
| Authors: Zeev Suraski <zeev@php.net> |
|
||||||
|
+----------------------------------------------------------------------+
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "TSRM.h"
|
||||||
|
|
||||||
|
#ifdef ZTS
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
#if ZEND_DEBUG
|
||||||
|
# include <assert.h>
|
||||||
|
# define TSRM_ASSERT(c) assert(c)
|
||||||
|
#else
|
||||||
|
# define TSRM_ASSERT(c)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct _tsrm_tls_entry tsrm_tls_entry;
|
||||||
|
|
||||||
|
/* TSRMLS_CACHE_DEFINE; is already done in Zend, this is being always compiled statically. */
|
||||||
|
TSRMLS_CACHE_EXTERN();
|
||||||
|
|
||||||
|
struct _tsrm_tls_entry {
|
||||||
|
void **storage;
|
||||||
|
int count;
|
||||||
|
THREAD_T thread_id;
|
||||||
|
tsrm_tls_entry *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
size_t size;
|
||||||
|
ts_allocate_ctor ctor;
|
||||||
|
ts_allocate_dtor dtor;
|
||||||
|
size_t fast_offset;
|
||||||
|
int done;
|
||||||
|
} tsrm_resource_type;
|
||||||
|
|
||||||
|
|
||||||
|
/* The memory manager table */
|
||||||
|
static tsrm_tls_entry **tsrm_tls_table=NULL;
|
||||||
|
static int tsrm_tls_table_size;
|
||||||
|
static ts_rsrc_id id_count;
|
||||||
|
|
||||||
|
/* The resource sizes table */
|
||||||
|
static tsrm_resource_type *resource_types_table=NULL;
|
||||||
|
static int resource_types_table_size;
|
||||||
|
|
||||||
|
/* Reserved space for fast globals access */
|
||||||
|
static size_t tsrm_reserved_pos = 0;
|
||||||
|
static size_t tsrm_reserved_size = 0;
|
||||||
|
|
||||||
|
static MUTEX_T tsmm_mutex; /* thread-safe memory manager mutex */
|
||||||
|
static MUTEX_T tsrm_env_mutex; /* tsrm environ mutex */
|
||||||
|
|
||||||
|
/* New thread handlers */
|
||||||
|
static tsrm_thread_begin_func_t tsrm_new_thread_begin_handler = NULL;
|
||||||
|
static tsrm_thread_end_func_t tsrm_new_thread_end_handler = NULL;
|
||||||
|
static tsrm_shutdown_func_t tsrm_shutdown_handler = NULL;
|
||||||
|
|
||||||
|
/* Debug support */
|
||||||
|
int tsrm_error(int level, const char *format, ...);
|
||||||
|
|
||||||
|
/* Read a resource from a thread's resource storage */
|
||||||
|
static int tsrm_error_level;
|
||||||
|
static FILE *tsrm_error_file;
|
||||||
|
|
||||||
|
#ifdef TSRM_DEBUG
|
||||||
|
#define TSRM_ERROR(args) tsrm_error args
|
||||||
|
#define TSRM_SAFE_RETURN_RSRC(array, offset, range) \
|
||||||
|
{ \
|
||||||
|
int unshuffled_offset = TSRM_UNSHUFFLE_RSRC_ID(offset); \
|
||||||
|
\
|
||||||
|
if (offset==0) { \
|
||||||
|
return &array; \
|
||||||
|
} else if ((unshuffled_offset)>=0 && (unshuffled_offset)<(range)) { \
|
||||||
|
TSRM_ERROR((TSRM_ERROR_LEVEL_INFO, "Successfully fetched resource id %d for thread id %ld - 0x%0.8X", \
|
||||||
|
unshuffled_offset, (long) thread_resources->thread_id, array[unshuffled_offset])); \
|
||||||
|
return array[unshuffled_offset]; \
|
||||||
|
} else { \
|
||||||
|
TSRM_ERROR((TSRM_ERROR_LEVEL_ERROR, "Resource id %d is out of range (%d..%d)", \
|
||||||
|
unshuffled_offset, TSRM_SHUFFLE_RSRC_ID(0), TSRM_SHUFFLE_RSRC_ID(thread_resources->count-1))); \
|
||||||
|
return NULL; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define TSRM_ERROR(args)
|
||||||
|
#define TSRM_SAFE_RETURN_RSRC(array, offset, range) \
|
||||||
|
if (offset==0) { \
|
||||||
|
return &array; \
|
||||||
|
} else { \
|
||||||
|
return array[TSRM_UNSHUFFLE_RSRC_ID(offset)]; \
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef TSRM_WIN32
|
||||||
|
static DWORD tls_key;
|
||||||
|
# define tsrm_tls_set(what) TlsSetValue(tls_key, (void*)(what))
|
||||||
|
# define tsrm_tls_get() TlsGetValue(tls_key)
|
||||||
|
#else
|
||||||
|
static pthread_key_t tls_key;
|
||||||
|
# define tsrm_tls_set(what) pthread_setspecific(tls_key, (void*)(what))
|
||||||
|
# define tsrm_tls_get() pthread_getspecific(tls_key)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
TSRM_TLS uint8_t in_main_thread = 0;
|
||||||
|
TSRM_TLS uint8_t is_thread_shutdown = 0;
|
||||||
|
|
||||||
|
/* Startup TSRM (call once for the entire process) */
|
||||||
|
TSRM_API int tsrm_startup(int expected_threads, int expected_resources, int debug_level, const char *debug_filename)
|
||||||
|
{/*{{{*/
|
||||||
|
#ifdef TSRM_WIN32
|
||||||
|
tls_key = TlsAlloc();
|
||||||
|
#else
|
||||||
|
pthread_key_create(&tls_key, 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* ensure singleton */
|
||||||
|
in_main_thread = 1;
|
||||||
|
is_thread_shutdown = 0;
|
||||||
|
|
||||||
|
tsrm_error_file = stderr;
|
||||||
|
tsrm_error_set(debug_level, debug_filename);
|
||||||
|
tsrm_tls_table_size = expected_threads;
|
||||||
|
|
||||||
|
tsrm_tls_table = (tsrm_tls_entry **) calloc(tsrm_tls_table_size, sizeof(tsrm_tls_entry *));
|
||||||
|
if (!tsrm_tls_table) {
|
||||||
|
TSRM_ERROR((TSRM_ERROR_LEVEL_ERROR, "Unable to allocate TLS table"));
|
||||||
|
is_thread_shutdown = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
id_count=0;
|
||||||
|
|
||||||
|
resource_types_table_size = expected_resources;
|
||||||
|
resource_types_table = (tsrm_resource_type *) calloc(resource_types_table_size, sizeof(tsrm_resource_type));
|
||||||
|
if (!resource_types_table) {
|
||||||
|
TSRM_ERROR((TSRM_ERROR_LEVEL_ERROR, "Unable to allocate resource types table"));
|
||||||
|
is_thread_shutdown = 1;
|
||||||
|
free(tsrm_tls_table);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
tsmm_mutex = tsrm_mutex_alloc();
|
||||||
|
|
||||||
|
TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Started up TSRM, %d expected threads, %d expected resources", expected_threads, expected_resources));
|
||||||
|
|
||||||
|
tsrm_reserved_pos = 0;
|
||||||
|
tsrm_reserved_size = 0;
|
||||||
|
|
||||||
|
tsrm_env_mutex = tsrm_mutex_alloc();
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}/*}}}*/
|
||||||
|
|
||||||
|
|
||||||
|
/* Shutdown TSRM (call once for the entire process) */
|
||||||
|
TSRM_API void tsrm_shutdown(void)
|
||||||
|
{/*{{{*/
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (is_thread_shutdown) {
|
||||||
|
/* shutdown must only occur once */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
is_thread_shutdown = 1;
|
||||||
|
|
||||||
|
if (!in_main_thread) {
|
||||||
|
/* only the main thread may shutdown tsrm */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i=0; i<tsrm_tls_table_size; i++) {
|
||||||
|
tsrm_tls_entry *p = tsrm_tls_table[i], *next_p;
|
||||||
|
|
||||||
|
while (p) {
|
||||||
|
int j;
|
||||||
|
|
||||||
|
next_p = p->next;
|
||||||
|
for (j=0; j<p->count; j++) {
|
||||||
|
if (p->storage[j]) {
|
||||||
|
if (resource_types_table) {
|
||||||
|
if (!resource_types_table[j].done) {
|
||||||
|
if (resource_types_table[j].dtor) {
|
||||||
|
resource_types_table[j].dtor(p->storage[j]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!resource_types_table[j].fast_offset) {
|
||||||
|
free(p->storage[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(p->storage);
|
||||||
|
free(p);
|
||||||
|
p = next_p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(tsrm_tls_table);
|
||||||
|
free(resource_types_table);
|
||||||
|
tsrm_mutex_free(tsmm_mutex);
|
||||||
|
tsrm_mutex_free(tsrm_env_mutex);
|
||||||
|
TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Shutdown TSRM"));
|
||||||
|
if (tsrm_error_file!=stderr) {
|
||||||
|
fclose(tsrm_error_file);
|
||||||
|
}
|
||||||
|
#ifdef TSRM_WIN32
|
||||||
|
TlsFree(tls_key);
|
||||||
|
#else
|
||||||
|
pthread_setspecific(tls_key, 0);
|
||||||
|
pthread_key_delete(tls_key);
|
||||||
|
#endif
|
||||||
|
if (tsrm_shutdown_handler) {
|
||||||
|
tsrm_shutdown_handler();
|
||||||
|
}
|
||||||
|
tsrm_new_thread_begin_handler = NULL;
|
||||||
|
tsrm_new_thread_end_handler = NULL;
|
||||||
|
tsrm_shutdown_handler = NULL;
|
||||||
|
|
||||||
|
tsrm_reserved_pos = 0;
|
||||||
|
tsrm_reserved_size = 0;
|
||||||
|
}/*}}}*/
|
||||||
|
|
||||||
|
/* {{{ */
|
||||||
|
/* environ lock api */
|
||||||
|
TSRM_API void tsrm_env_lock(void) {
|
||||||
|
tsrm_mutex_lock(tsrm_env_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
TSRM_API void tsrm_env_unlock(void) {
|
||||||
|
tsrm_mutex_unlock(tsrm_env_mutex);
|
||||||
|
} /* }}} */
|
||||||
|
|
||||||
|
/* enlarge the arrays for the already active threads */
|
||||||
|
static void tsrm_update_active_threads(void)
|
||||||
|
{/*{{{*/
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i=0; i<tsrm_tls_table_size; i++) {
|
||||||
|
tsrm_tls_entry *p = tsrm_tls_table[i];
|
||||||
|
|
||||||
|
while (p) {
|
||||||
|
if (p->count < id_count) {
|
||||||
|
int j;
|
||||||
|
|
||||||
|
p->storage = (void *) realloc(p->storage, sizeof(void *)*id_count);
|
||||||
|
for (j=p->count; j<id_count; j++) {
|
||||||
|
if (resource_types_table[j].fast_offset) {
|
||||||
|
p->storage[j] = (void *) (((char*)p) + resource_types_table[j].fast_offset);
|
||||||
|
} else {
|
||||||
|
p->storage[j] = (void *) malloc(resource_types_table[j].size);
|
||||||
|
}
|
||||||
|
if (resource_types_table[j].ctor) {
|
||||||
|
resource_types_table[j].ctor(p->storage[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p->count = id_count;
|
||||||
|
}
|
||||||
|
p = p->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}/*}}}*/
|
||||||
|
|
||||||
|
|
||||||
|
/* allocates a new thread-safe-resource id */
|
||||||
|
TSRM_API ts_rsrc_id ts_allocate_id(ts_rsrc_id *rsrc_id, size_t size, ts_allocate_ctor ctor, ts_allocate_dtor dtor)
|
||||||
|
{/*{{{*/
|
||||||
|
TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Obtaining a new resource id, %d bytes", size));
|
||||||
|
|
||||||
|
tsrm_mutex_lock(tsmm_mutex);
|
||||||
|
|
||||||
|
/* obtain a resource id */
|
||||||
|
*rsrc_id = TSRM_SHUFFLE_RSRC_ID(id_count++);
|
||||||
|
TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Obtained resource id %d", *rsrc_id));
|
||||||
|
|
||||||
|
/* store the new resource type in the resource sizes table */
|
||||||
|
if (resource_types_table_size < id_count) {
|
||||||
|
tsrm_resource_type *_tmp;
|
||||||
|
_tmp = (tsrm_resource_type *) realloc(resource_types_table, sizeof(tsrm_resource_type)*id_count);
|
||||||
|
if (!_tmp) {
|
||||||
|
TSRM_ERROR((TSRM_ERROR_LEVEL_ERROR, "Unable to allocate storage for resource"));
|
||||||
|
*rsrc_id = 0;
|
||||||
|
tsrm_mutex_unlock(tsmm_mutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
resource_types_table = _tmp;
|
||||||
|
resource_types_table_size = id_count;
|
||||||
|
}
|
||||||
|
resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].size = size;
|
||||||
|
resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].ctor = ctor;
|
||||||
|
resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].dtor = dtor;
|
||||||
|
resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].fast_offset = 0;
|
||||||
|
resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].done = 0;
|
||||||
|
|
||||||
|
tsrm_update_active_threads();
|
||||||
|
tsrm_mutex_unlock(tsmm_mutex);
|
||||||
|
|
||||||
|
TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Successfully allocated new resource id %d", *rsrc_id));
|
||||||
|
return *rsrc_id;
|
||||||
|
}/*}}}*/
|
||||||
|
|
||||||
|
|
||||||
|
/* Reserve space for fast thread-safe-resources */
|
||||||
|
TSRM_API void tsrm_reserve(size_t size)
|
||||||
|
{/*{{{*/
|
||||||
|
tsrm_reserved_pos = 0;
|
||||||
|
tsrm_reserved_size = TSRM_ALIGNED_SIZE(size);
|
||||||
|
}/*}}}*/
|
||||||
|
|
||||||
|
|
||||||
|
/* allocates a new fast thread-safe-resource id */
|
||||||
|
TSRM_API ts_rsrc_id ts_allocate_fast_id(ts_rsrc_id *rsrc_id, size_t *offset, size_t size, ts_allocate_ctor ctor, ts_allocate_dtor dtor)
|
||||||
|
{/*{{{*/
|
||||||
|
TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Obtaining a new fast resource id, %d bytes", size));
|
||||||
|
|
||||||
|
tsrm_mutex_lock(tsmm_mutex);
|
||||||
|
|
||||||
|
/* obtain a resource id */
|
||||||
|
*rsrc_id = TSRM_SHUFFLE_RSRC_ID(id_count++);
|
||||||
|
TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Obtained resource id %d", *rsrc_id));
|
||||||
|
|
||||||
|
size = TSRM_ALIGNED_SIZE(size);
|
||||||
|
if (tsrm_reserved_size - tsrm_reserved_pos < size) {
|
||||||
|
TSRM_ERROR((TSRM_ERROR_LEVEL_ERROR, "Unable to allocate space for fast resource"));
|
||||||
|
*rsrc_id = 0;
|
||||||
|
*offset = 0;
|
||||||
|
tsrm_mutex_unlock(tsmm_mutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
*offset = TSRM_ALIGNED_SIZE(sizeof(tsrm_tls_entry)) + tsrm_reserved_pos;
|
||||||
|
tsrm_reserved_pos += size;
|
||||||
|
|
||||||
|
/* store the new resource type in the resource sizes table */
|
||||||
|
if (resource_types_table_size < id_count) {
|
||||||
|
tsrm_resource_type *_tmp;
|
||||||
|
_tmp = (tsrm_resource_type *) realloc(resource_types_table, sizeof(tsrm_resource_type)*id_count);
|
||||||
|
if (!_tmp) {
|
||||||
|
TSRM_ERROR((TSRM_ERROR_LEVEL_ERROR, "Unable to allocate storage for resource"));
|
||||||
|
*rsrc_id = 0;
|
||||||
|
tsrm_mutex_unlock(tsmm_mutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
resource_types_table = _tmp;
|
||||||
|
resource_types_table_size = id_count;
|
||||||
|
}
|
||||||
|
resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].size = size;
|
||||||
|
resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].ctor = ctor;
|
||||||
|
resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].dtor = dtor;
|
||||||
|
resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].fast_offset = *offset;
|
||||||
|
resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].done = 0;
|
||||||
|
|
||||||
|
tsrm_update_active_threads();
|
||||||
|
tsrm_mutex_unlock(tsmm_mutex);
|
||||||
|
|
||||||
|
TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Successfully allocated new resource id %d", *rsrc_id));
|
||||||
|
return *rsrc_id;
|
||||||
|
}/*}}}*/
|
||||||
|
|
||||||
|
|
||||||
|
static void allocate_new_resource(tsrm_tls_entry **thread_resources_ptr, THREAD_T thread_id)
|
||||||
|
{/*{{{*/
|
||||||
|
int i;
|
||||||
|
|
||||||
|
TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Creating data structures for thread %x", thread_id));
|
||||||
|
(*thread_resources_ptr) = (tsrm_tls_entry *) malloc(TSRM_ALIGNED_SIZE(sizeof(tsrm_tls_entry)) + tsrm_reserved_size);
|
||||||
|
(*thread_resources_ptr)->storage = NULL;
|
||||||
|
if (id_count > 0) {
|
||||||
|
(*thread_resources_ptr)->storage = (void **) malloc(sizeof(void *)*id_count);
|
||||||
|
}
|
||||||
|
(*thread_resources_ptr)->count = id_count;
|
||||||
|
(*thread_resources_ptr)->thread_id = thread_id;
|
||||||
|
(*thread_resources_ptr)->next = NULL;
|
||||||
|
|
||||||
|
/* Set thread local storage to this new thread resources structure */
|
||||||
|
tsrm_tls_set(*thread_resources_ptr);
|
||||||
|
TSRMLS_CACHE = *thread_resources_ptr;
|
||||||
|
|
||||||
|
if (tsrm_new_thread_begin_handler) {
|
||||||
|
tsrm_new_thread_begin_handler(thread_id);
|
||||||
|
}
|
||||||
|
for (i=0; i<id_count; i++) {
|
||||||
|
if (resource_types_table[i].done) {
|
||||||
|
(*thread_resources_ptr)->storage[i] = NULL;
|
||||||
|
} else {
|
||||||
|
if (resource_types_table[i].fast_offset) {
|
||||||
|
(*thread_resources_ptr)->storage[i] = (void *) (((char*)(*thread_resources_ptr)) + resource_types_table[i].fast_offset);
|
||||||
|
} else {
|
||||||
|
(*thread_resources_ptr)->storage[i] = (void *) malloc(resource_types_table[i].size);
|
||||||
|
}
|
||||||
|
if (resource_types_table[i].ctor) {
|
||||||
|
resource_types_table[i].ctor((*thread_resources_ptr)->storage[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tsrm_new_thread_end_handler) {
|
||||||
|
tsrm_new_thread_end_handler(thread_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
tsrm_mutex_unlock(tsmm_mutex);
|
||||||
|
}/*}}}*/
|
||||||
|
|
||||||
|
|
||||||
|
/* fetches the requested resource for the current thread */
|
||||||
|
TSRM_API void *ts_resource_ex(ts_rsrc_id id, THREAD_T *th_id)
|
||||||
|
{/*{{{*/
|
||||||
|
THREAD_T thread_id;
|
||||||
|
int hash_value;
|
||||||
|
tsrm_tls_entry *thread_resources;
|
||||||
|
|
||||||
|
if (!th_id) {
|
||||||
|
/* Fast path for looking up the resources for the current
|
||||||
|
* thread. Its used by just about every call to
|
||||||
|
* ts_resource_ex(). This avoids the need for a mutex lock
|
||||||
|
* and our hashtable lookup.
|
||||||
|
*/
|
||||||
|
thread_resources = tsrm_tls_get();
|
||||||
|
|
||||||
|
if (thread_resources) {
|
||||||
|
TSRM_ERROR((TSRM_ERROR_LEVEL_INFO, "Fetching resource id %d for current thread %d", id, (long) thread_resources->thread_id));
|
||||||
|
/* Read a specific resource from the thread's resources.
|
||||||
|
* This is called outside of a mutex, so have to be aware about external
|
||||||
|
* changes to the structure as we read it.
|
||||||
|
*/
|
||||||
|
TSRM_SAFE_RETURN_RSRC(thread_resources->storage, id, thread_resources->count);
|
||||||
|
}
|
||||||
|
thread_id = tsrm_thread_id();
|
||||||
|
} else {
|
||||||
|
thread_id = *th_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
TSRM_ERROR((TSRM_ERROR_LEVEL_INFO, "Fetching resource id %d for thread %ld", id, (long) thread_id));
|
||||||
|
tsrm_mutex_lock(tsmm_mutex);
|
||||||
|
|
||||||
|
hash_value = THREAD_HASH_OF(thread_id, tsrm_tls_table_size);
|
||||||
|
thread_resources = tsrm_tls_table[hash_value];
|
||||||
|
|
||||||
|
if (!thread_resources) {
|
||||||
|
allocate_new_resource(&tsrm_tls_table[hash_value], thread_id);
|
||||||
|
return ts_resource_ex(id, &thread_id);
|
||||||
|
} else {
|
||||||
|
do {
|
||||||
|
if (thread_resources->thread_id == thread_id) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (thread_resources->next) {
|
||||||
|
thread_resources = thread_resources->next;
|
||||||
|
} else {
|
||||||
|
allocate_new_resource(&thread_resources->next, thread_id);
|
||||||
|
return ts_resource_ex(id, &thread_id);
|
||||||
|
/*
|
||||||
|
* thread_resources = thread_resources->next;
|
||||||
|
* break;
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
} while (thread_resources);
|
||||||
|
}
|
||||||
|
tsrm_mutex_unlock(tsmm_mutex);
|
||||||
|
/* Read a specific resource from the thread's resources.
|
||||||
|
* This is called outside of a mutex, so have to be aware about external
|
||||||
|
* changes to the structure as we read it.
|
||||||
|
*/
|
||||||
|
TSRM_SAFE_RETURN_RSRC(thread_resources->storage, id, thread_resources->count);
|
||||||
|
}/*}}}*/
|
||||||
|
|
||||||
|
|
||||||
|
/* frees all resources allocated for the current thread */
|
||||||
|
void ts_free_thread(void)
|
||||||
|
{/*{{{*/
|
||||||
|
tsrm_tls_entry *thread_resources;
|
||||||
|
int i;
|
||||||
|
THREAD_T thread_id = tsrm_thread_id();
|
||||||
|
int hash_value;
|
||||||
|
tsrm_tls_entry *last=NULL;
|
||||||
|
|
||||||
|
TSRM_ASSERT(!in_main_thread);
|
||||||
|
|
||||||
|
tsrm_mutex_lock(tsmm_mutex);
|
||||||
|
hash_value = THREAD_HASH_OF(thread_id, tsrm_tls_table_size);
|
||||||
|
thread_resources = tsrm_tls_table[hash_value];
|
||||||
|
|
||||||
|
while (thread_resources) {
|
||||||
|
if (thread_resources->thread_id == thread_id) {
|
||||||
|
for (i=0; i<thread_resources->count; i++) {
|
||||||
|
if (resource_types_table[i].dtor) {
|
||||||
|
resource_types_table[i].dtor(thread_resources->storage[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (i=0; i<thread_resources->count; i++) {
|
||||||
|
if (!resource_types_table[i].fast_offset) {
|
||||||
|
free(thread_resources->storage[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(thread_resources->storage);
|
||||||
|
if (last) {
|
||||||
|
last->next = thread_resources->next;
|
||||||
|
} else {
|
||||||
|
tsrm_tls_table[hash_value] = thread_resources->next;
|
||||||
|
}
|
||||||
|
tsrm_tls_set(0);
|
||||||
|
free(thread_resources);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (thread_resources->next) {
|
||||||
|
last = thread_resources;
|
||||||
|
}
|
||||||
|
thread_resources = thread_resources->next;
|
||||||
|
}
|
||||||
|
tsrm_mutex_unlock(tsmm_mutex);
|
||||||
|
}/*}}}*/
|
||||||
|
|
||||||
|
/* deallocates all occurrences of a given id */
|
||||||
|
void ts_free_id(ts_rsrc_id id)
|
||||||
|
{/*{{{*/
|
||||||
|
int i;
|
||||||
|
int j = TSRM_UNSHUFFLE_RSRC_ID(id);
|
||||||
|
|
||||||
|
tsrm_mutex_lock(tsmm_mutex);
|
||||||
|
|
||||||
|
TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Freeing resource id %d", id));
|
||||||
|
|
||||||
|
if (tsrm_tls_table) {
|
||||||
|
for (i=0; i<tsrm_tls_table_size; i++) {
|
||||||
|
tsrm_tls_entry *p = tsrm_tls_table[i];
|
||||||
|
|
||||||
|
while (p) {
|
||||||
|
if (p->count > j && p->storage[j]) {
|
||||||
|
if (resource_types_table) {
|
||||||
|
if (resource_types_table[j].dtor) {
|
||||||
|
resource_types_table[j].dtor(p->storage[j]);
|
||||||
|
}
|
||||||
|
if (!resource_types_table[j].fast_offset) {
|
||||||
|
free(p->storage[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p->storage[j] = NULL;
|
||||||
|
}
|
||||||
|
p = p->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
resource_types_table[j].done = 1;
|
||||||
|
|
||||||
|
tsrm_mutex_unlock(tsmm_mutex);
|
||||||
|
|
||||||
|
TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Successfully freed resource id %d", id));
|
||||||
|
}/*}}}*/
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Utility Functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Obtain the current thread id */
|
||||||
|
TSRM_API THREAD_T tsrm_thread_id(void)
|
||||||
|
{/*{{{*/
|
||||||
|
#ifdef TSRM_WIN32
|
||||||
|
return GetCurrentThreadId();
|
||||||
|
#else
|
||||||
|
return pthread_self();
|
||||||
|
#endif
|
||||||
|
}/*}}}*/
|
||||||
|
|
||||||
|
|
||||||
|
/* Allocate a mutex */
|
||||||
|
TSRM_API MUTEX_T tsrm_mutex_alloc(void)
|
||||||
|
{/*{{{*/
|
||||||
|
MUTEX_T mutexp;
|
||||||
|
#ifdef TSRM_WIN32
|
||||||
|
mutexp = malloc(sizeof(CRITICAL_SECTION));
|
||||||
|
InitializeCriticalSection(mutexp);
|
||||||
|
#else
|
||||||
|
mutexp = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t));
|
||||||
|
pthread_mutex_init(mutexp,NULL);
|
||||||
|
#endif
|
||||||
|
#ifdef THR_DEBUG
|
||||||
|
printf("Mutex created thread: %d\n",mythreadid());
|
||||||
|
#endif
|
||||||
|
return( mutexp );
|
||||||
|
}/*}}}*/
|
||||||
|
|
||||||
|
|
||||||
|
/* Free a mutex */
|
||||||
|
TSRM_API void tsrm_mutex_free(MUTEX_T mutexp)
|
||||||
|
{/*{{{*/
|
||||||
|
if (mutexp) {
|
||||||
|
#ifdef TSRM_WIN32
|
||||||
|
DeleteCriticalSection(mutexp);
|
||||||
|
free(mutexp);
|
||||||
|
#else
|
||||||
|
pthread_mutex_destroy(mutexp);
|
||||||
|
free(mutexp);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#ifdef THR_DEBUG
|
||||||
|
printf("Mutex freed thread: %d\n",mythreadid());
|
||||||
|
#endif
|
||||||
|
}/*}}}*/
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Lock a mutex.
|
||||||
|
A return value of 0 indicates success
|
||||||
|
*/
|
||||||
|
TSRM_API int tsrm_mutex_lock(MUTEX_T mutexp)
|
||||||
|
{/*{{{*/
|
||||||
|
TSRM_ERROR((TSRM_ERROR_LEVEL_INFO, "Mutex locked thread: %ld", tsrm_thread_id()));
|
||||||
|
#ifdef TSRM_WIN32
|
||||||
|
EnterCriticalSection(mutexp);
|
||||||
|
return 0;
|
||||||
|
#else
|
||||||
|
return pthread_mutex_lock(mutexp);
|
||||||
|
#endif
|
||||||
|
}/*}}}*/
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Unlock a mutex.
|
||||||
|
A return value of 0 indicates success
|
||||||
|
*/
|
||||||
|
TSRM_API int tsrm_mutex_unlock(MUTEX_T mutexp)
|
||||||
|
{/*{{{*/
|
||||||
|
TSRM_ERROR((TSRM_ERROR_LEVEL_INFO, "Mutex unlocked thread: %ld", tsrm_thread_id()));
|
||||||
|
#ifdef TSRM_WIN32
|
||||||
|
LeaveCriticalSection(mutexp);
|
||||||
|
return 0;
|
||||||
|
#else
|
||||||
|
return pthread_mutex_unlock(mutexp);
|
||||||
|
#endif
|
||||||
|
}/*}}}*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Changes the signal mask of the calling thread
|
||||||
|
*/
|
||||||
|
#ifdef HAVE_SIGPROCMASK
|
||||||
|
TSRM_API int tsrm_sigmask(int how, const sigset_t *set, sigset_t *oldset)
|
||||||
|
{/*{{{*/
|
||||||
|
TSRM_ERROR((TSRM_ERROR_LEVEL_INFO, "Changed sigmask in thread: %ld", tsrm_thread_id()));
|
||||||
|
|
||||||
|
return pthread_sigmask(how, set, oldset);
|
||||||
|
}/*}}}*/
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
TSRM_API void *tsrm_set_new_thread_begin_handler(tsrm_thread_begin_func_t new_thread_begin_handler)
|
||||||
|
{/*{{{*/
|
||||||
|
void *retval = (void *) tsrm_new_thread_begin_handler;
|
||||||
|
|
||||||
|
tsrm_new_thread_begin_handler = new_thread_begin_handler;
|
||||||
|
return retval;
|
||||||
|
}/*}}}*/
|
||||||
|
|
||||||
|
|
||||||
|
TSRM_API void *tsrm_set_new_thread_end_handler(tsrm_thread_end_func_t new_thread_end_handler)
|
||||||
|
{/*{{{*/
|
||||||
|
void *retval = (void *) tsrm_new_thread_end_handler;
|
||||||
|
|
||||||
|
tsrm_new_thread_end_handler = new_thread_end_handler;
|
||||||
|
return retval;
|
||||||
|
}/*}}}*/
|
||||||
|
|
||||||
|
|
||||||
|
TSRM_API void *tsrm_set_shutdown_handler(tsrm_shutdown_func_t shutdown_handler)
|
||||||
|
{/*{{{*/
|
||||||
|
void *retval = (void *) tsrm_shutdown_handler;
|
||||||
|
|
||||||
|
tsrm_shutdown_handler = shutdown_handler;
|
||||||
|
return retval;
|
||||||
|
}/*}}}*/
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Debug support
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef TSRM_DEBUG
|
||||||
|
int tsrm_error(int level, const char *format, ...)
|
||||||
|
{/*{{{*/
|
||||||
|
if (level<=tsrm_error_level) {
|
||||||
|
va_list args;
|
||||||
|
int size;
|
||||||
|
|
||||||
|
fprintf(tsrm_error_file, "TSRM: ");
|
||||||
|
va_start(args, format);
|
||||||
|
size = vfprintf(tsrm_error_file, format, args);
|
||||||
|
va_end(args);
|
||||||
|
fprintf(tsrm_error_file, "\n");
|
||||||
|
fflush(tsrm_error_file);
|
||||||
|
return size;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}/*}}}*/
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
void tsrm_error_set(int level, const char *debug_filename)
|
||||||
|
{/*{{{*/
|
||||||
|
tsrm_error_level = level;
|
||||||
|
|
||||||
|
#ifdef TSRM_DEBUG
|
||||||
|
if (tsrm_error_file!=stderr) { /* close files opened earlier */
|
||||||
|
fclose(tsrm_error_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (debug_filename) {
|
||||||
|
tsrm_error_file = fopen(debug_filename, "w");
|
||||||
|
if (!tsrm_error_file) {
|
||||||
|
tsrm_error_file = stderr;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tsrm_error_file = stderr;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}/*}}}*/
|
||||||
|
|
||||||
|
TSRM_API void *tsrm_get_ls_cache(void)
|
||||||
|
{/*{{{*/
|
||||||
|
return tsrm_tls_get();
|
||||||
|
}/*}}}*/
|
||||||
|
|
||||||
|
/* Returns offset of tsrm_ls_cache slot from Thread Control Block address */
|
||||||
|
TSRM_API size_t tsrm_get_ls_cache_tcb_offset(void)
|
||||||
|
{/*{{{*/
|
||||||
|
#if defined(__APPLE__) && defined(__x86_64__)
|
||||||
|
// TODO: Implement support for fast JIT ZTS code ???
|
||||||
|
return 0;
|
||||||
|
#elif defined(__x86_64__) && defined(__GNUC__) && !defined(__FreeBSD__) && \
|
||||||
|
!defined(__OpenBSD__) && !defined(__MUSL__) && !defined(__HAIKU__)
|
||||||
|
size_t ret;
|
||||||
|
|
||||||
|
asm ("movq _tsrm_ls_cache@gottpoff(%%rip),%0"
|
||||||
|
: "=r" (ret));
|
||||||
|
return ret;
|
||||||
|
#elif defined(__i386__) && defined(__GNUC__) && !defined(__FreeBSD__) && \
|
||||||
|
!defined(__OpenBSD__) && !defined(__MUSL__) && !defined(__HAIKU__)
|
||||||
|
size_t ret;
|
||||||
|
|
||||||
|
asm ("leal _tsrm_ls_cache@ntpoff,%0"
|
||||||
|
: "=r" (ret));
|
||||||
|
return ret;
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}/*}}}*/
|
||||||
|
|
||||||
|
TSRM_API uint8_t tsrm_is_main_thread(void)
|
||||||
|
{/*{{{*/
|
||||||
|
return in_main_thread;
|
||||||
|
}/*}}}*/
|
||||||
|
|
||||||
|
TSRM_API uint8_t tsrm_is_shutdown(void)
|
||||||
|
{/*{{{*/
|
||||||
|
return is_thread_shutdown;
|
||||||
|
}/*}}}*/
|
||||||
|
|
||||||
|
TSRM_API const char *tsrm_api_name(void)
|
||||||
|
{/*{{{*/
|
||||||
|
#ifdef TSRM_WIN32
|
||||||
|
return "Windows Threads";
|
||||||
|
#else
|
||||||
|
return "POSIX Threads";
|
||||||
|
#endif
|
||||||
|
}/*}}}*/
|
||||||
|
|
||||||
|
#endif /* ZTS */
|
||||||
|
|
@ -0,0 +1,194 @@
|
||||||
|
/*
|
||||||
|
+----------------------------------------------------------------------+
|
||||||
|
| Thread Safe Resource Manager |
|
||||||
|
+----------------------------------------------------------------------+
|
||||||
|
| Copyright (c) 1999-2011, Andi Gutmans, Sascha Schumann, Zeev Suraski |
|
||||||
|
| This source file is subject to the TSRM license, that is bundled |
|
||||||
|
| with this package in the file LICENSE |
|
||||||
|
+----------------------------------------------------------------------+
|
||||||
|
| Authors: Zeev Suraski <zeev@php.net> |
|
||||||
|
+----------------------------------------------------------------------+
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TSRM_H
|
||||||
|
#define TSRM_H
|
||||||
|
|
||||||
|
#if !defined(__CYGWIN__) && defined(WIN32)
|
||||||
|
# define TSRM_WIN32
|
||||||
|
# include "Zend/zend_config.w32.h"
|
||||||
|
#else
|
||||||
|
# include "main/php_config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "main/php_stdint.h"
|
||||||
|
|
||||||
|
#ifdef TSRM_WIN32
|
||||||
|
# ifdef TSRM_EXPORTS
|
||||||
|
# define TSRM_API __declspec(dllexport)
|
||||||
|
# else
|
||||||
|
# define TSRM_API __declspec(dllimport)
|
||||||
|
# endif
|
||||||
|
#elif defined(__GNUC__) && __GNUC__ >= 4
|
||||||
|
# define TSRM_API __attribute__ ((visibility("default")))
|
||||||
|
#else
|
||||||
|
# define TSRM_API
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef intptr_t tsrm_intptr_t;
|
||||||
|
typedef uintptr_t tsrm_uintptr_t;
|
||||||
|
|
||||||
|
/* Only compile multi-threading functions if we're in ZTS mode */
|
||||||
|
#ifdef ZTS
|
||||||
|
|
||||||
|
#ifdef TSRM_WIN32
|
||||||
|
# ifndef TSRM_INCLUDE_FULL_WINDOWS_HEADERS
|
||||||
|
# define WIN32_LEAN_AND_MEAN
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# include <pthread.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if SIZEOF_SIZE_T == 4
|
||||||
|
# define TSRM_ALIGNED_SIZE(size) \
|
||||||
|
(((size) + INT32_C(15)) & ~INT32_C(15))
|
||||||
|
#else
|
||||||
|
# define TSRM_ALIGNED_SIZE(size) \
|
||||||
|
(((size) + INT64_C(15)) & ~INT64_C(15))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef int ts_rsrc_id;
|
||||||
|
|
||||||
|
/* Define THREAD_T and MUTEX_T */
|
||||||
|
#ifdef TSRM_WIN32
|
||||||
|
# define THREAD_T DWORD
|
||||||
|
# define MUTEX_T CRITICAL_SECTION *
|
||||||
|
#else
|
||||||
|
# define THREAD_T pthread_t
|
||||||
|
# define MUTEX_T pthread_mutex_t *
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
|
typedef void (*ts_allocate_ctor)(void *);
|
||||||
|
typedef void (*ts_allocate_dtor)(void *);
|
||||||
|
|
||||||
|
#define THREAD_HASH_OF(thr,ts) (unsigned long)thr%(unsigned long)ts
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* startup/shutdown */
|
||||||
|
TSRM_API int tsrm_startup(int expected_threads, int expected_resources, int debug_level, const char *debug_filename);
|
||||||
|
TSRM_API void tsrm_shutdown(void);
|
||||||
|
|
||||||
|
/* environ lock API */
|
||||||
|
TSRM_API void tsrm_env_lock(void);
|
||||||
|
TSRM_API void tsrm_env_unlock(void);
|
||||||
|
|
||||||
|
/* allocates a new thread-safe-resource id */
|
||||||
|
TSRM_API ts_rsrc_id ts_allocate_id(ts_rsrc_id *rsrc_id, size_t size, ts_allocate_ctor ctor, ts_allocate_dtor dtor);
|
||||||
|
|
||||||
|
/* Fast resource in reserved (pre-allocated) space */
|
||||||
|
TSRM_API void tsrm_reserve(size_t size);
|
||||||
|
TSRM_API ts_rsrc_id ts_allocate_fast_id(ts_rsrc_id *rsrc_id, size_t *offset, size_t size, ts_allocate_ctor ctor, ts_allocate_dtor dtor);
|
||||||
|
|
||||||
|
/* fetches the requested resource for the current thread */
|
||||||
|
TSRM_API void *ts_resource_ex(ts_rsrc_id id, THREAD_T *th_id);
|
||||||
|
#define ts_resource(id) ts_resource_ex(id, NULL)
|
||||||
|
|
||||||
|
/* frees all resources allocated for the current thread */
|
||||||
|
TSRM_API void ts_free_thread(void);
|
||||||
|
|
||||||
|
/* deallocates all occurrences of a given id */
|
||||||
|
TSRM_API void ts_free_id(ts_rsrc_id id);
|
||||||
|
|
||||||
|
|
||||||
|
/* Debug support */
|
||||||
|
#define TSRM_ERROR_LEVEL_ERROR 1
|
||||||
|
#define TSRM_ERROR_LEVEL_CORE 2
|
||||||
|
#define TSRM_ERROR_LEVEL_INFO 3
|
||||||
|
|
||||||
|
typedef void (*tsrm_thread_begin_func_t)(THREAD_T thread_id);
|
||||||
|
typedef void (*tsrm_thread_end_func_t)(THREAD_T thread_id);
|
||||||
|
typedef void (*tsrm_shutdown_func_t)(void);
|
||||||
|
|
||||||
|
|
||||||
|
TSRM_API int tsrm_error(int level, const char *format, ...);
|
||||||
|
TSRM_API void tsrm_error_set(int level, const char *debug_filename);
|
||||||
|
|
||||||
|
/* utility functions */
|
||||||
|
TSRM_API THREAD_T tsrm_thread_id(void);
|
||||||
|
TSRM_API MUTEX_T tsrm_mutex_alloc(void);
|
||||||
|
TSRM_API void tsrm_mutex_free(MUTEX_T mutexp);
|
||||||
|
TSRM_API int tsrm_mutex_lock(MUTEX_T mutexp);
|
||||||
|
TSRM_API int tsrm_mutex_unlock(MUTEX_T mutexp);
|
||||||
|
#ifdef HAVE_SIGPROCMASK
|
||||||
|
TSRM_API int tsrm_sigmask(int how, const sigset_t *set, sigset_t *oldset);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
TSRM_API void *tsrm_set_new_thread_begin_handler(tsrm_thread_begin_func_t new_thread_begin_handler);
|
||||||
|
TSRM_API void *tsrm_set_new_thread_end_handler(tsrm_thread_end_func_t new_thread_end_handler);
|
||||||
|
TSRM_API void *tsrm_set_shutdown_handler(tsrm_shutdown_func_t shutdown_handler);
|
||||||
|
|
||||||
|
TSRM_API void *tsrm_get_ls_cache(void);
|
||||||
|
TSRM_API size_t tsrm_get_ls_cache_tcb_offset(void);
|
||||||
|
TSRM_API uint8_t tsrm_is_main_thread(void);
|
||||||
|
TSRM_API uint8_t tsrm_is_shutdown(void);
|
||||||
|
TSRM_API const char *tsrm_api_name(void);
|
||||||
|
|
||||||
|
#ifdef TSRM_WIN32
|
||||||
|
# define TSRM_TLS __declspec(thread)
|
||||||
|
#else
|
||||||
|
# define TSRM_TLS __thread
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __has_attribute
|
||||||
|
# define __has_attribute(x) 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !__has_attribute(tls_model) || defined(__FreeBSD__) || defined(__MUSL__) || defined(__HAIKU__)
|
||||||
|
# define TSRM_TLS_MODEL_ATTR
|
||||||
|
#elif __PIC__
|
||||||
|
# define TSRM_TLS_MODEL_ATTR __attribute__((tls_model("initial-exec")))
|
||||||
|
#else
|
||||||
|
# define TSRM_TLS_MODEL_ATTR __attribute__((tls_model("local-exec")))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define TSRM_SHUFFLE_RSRC_ID(rsrc_id) ((rsrc_id)+1)
|
||||||
|
#define TSRM_UNSHUFFLE_RSRC_ID(rsrc_id) ((rsrc_id)-1)
|
||||||
|
|
||||||
|
#define TSRMG(id, type, element) (TSRMG_BULK(id, type)->element)
|
||||||
|
#define TSRMG_BULK(id, type) ((type) (*((void ***) tsrm_get_ls_cache()))[TSRM_UNSHUFFLE_RSRC_ID(id)])
|
||||||
|
#define TSRMG_FAST(offset, type, element) (TSRMG_FAST_BULK(offset, type)->element)
|
||||||
|
#define TSRMG_FAST_BULK(offset, type) ((type) (((char*) tsrm_get_ls_cache())+(offset)))
|
||||||
|
|
||||||
|
#define TSRMG_STATIC(id, type, element) (TSRMG_BULK_STATIC(id, type)->element)
|
||||||
|
#define TSRMG_BULK_STATIC(id, type) ((type) (*((void ***) TSRMLS_CACHE))[TSRM_UNSHUFFLE_RSRC_ID(id)])
|
||||||
|
#define TSRMG_FAST_STATIC(offset, type, element) (TSRMG_FAST_BULK_STATIC(offset, type)->element)
|
||||||
|
#define TSRMG_FAST_BULK_STATIC(offset, type) ((type) (((char*) TSRMLS_CACHE)+(offset)))
|
||||||
|
#define TSRMLS_CACHE_EXTERN() extern TSRM_TLS void *TSRMLS_CACHE TSRM_TLS_MODEL_ATTR;
|
||||||
|
#define TSRMLS_CACHE_DEFINE() TSRM_TLS void *TSRMLS_CACHE TSRM_TLS_MODEL_ATTR = NULL;
|
||||||
|
#define TSRMLS_CACHE_UPDATE() TSRMLS_CACHE = tsrm_get_ls_cache()
|
||||||
|
#define TSRMLS_CACHE _tsrm_ls_cache
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else /* non ZTS */
|
||||||
|
|
||||||
|
#define tsrm_env_lock()
|
||||||
|
#define tsrm_env_unlock()
|
||||||
|
|
||||||
|
#define TSRMG_STATIC(id, type, element)
|
||||||
|
#define TSRMLS_CACHE_EXTERN()
|
||||||
|
#define TSRMLS_CACHE_DEFINE()
|
||||||
|
#define TSRMLS_CACHE_UPDATE()
|
||||||
|
#define TSRMLS_CACHE
|
||||||
|
|
||||||
|
#define TSRM_TLS
|
||||||
|
|
||||||
|
#endif /* ZTS */
|
||||||
|
|
||||||
|
#endif /* TSRM_H */
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
// vim:ft=javascript
|
||||||
|
|
||||||
|
ADD_SOURCES("TSRM", "TSRM.c tsrm_win32.c");
|
||||||
|
ADD_FLAG("CFLAGS_BD_TSRM", "/D ZEND_ENABLE_STATIC_TSRMLS_CACHE=1");
|
||||||
|
|
@ -0,0 +1,140 @@
|
||||||
|
dnl Copyright (c) 1999, 2000 Sascha Schumann. All rights reserved.
|
||||||
|
dnl
|
||||||
|
dnl Redistribution and use in source and binary forms, with or without
|
||||||
|
dnl modification, are permitted provided that the following conditions
|
||||||
|
dnl are met:
|
||||||
|
dnl
|
||||||
|
dnl 1. Redistributions of source code must retain the above copyright
|
||||||
|
dnl notice, this list of conditions and the following disclaimer.
|
||||||
|
dnl
|
||||||
|
dnl 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
dnl notice, this list of conditions and the following disclaimer in
|
||||||
|
dnl the documentation and/or other materials provided with the
|
||||||
|
dnl distribution.
|
||||||
|
dnl
|
||||||
|
dnl THIS SOFTWARE IS PROVIDED BY SASCHA SCHUMANN ``AS IS'' AND ANY
|
||||||
|
dnl EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
dnl IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
dnl PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SASCHA SCHUMANN OR
|
||||||
|
dnl HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
dnl SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
dnl NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
dnl LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
dnl HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||||
|
dnl STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
dnl ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||||
|
dnl OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
dnl
|
||||||
|
dnl PTHREADS_FLAGS
|
||||||
|
dnl
|
||||||
|
dnl Set some magic defines to achieve POSIX threads conformance.
|
||||||
|
dnl
|
||||||
|
AC_DEFUN([PTHREADS_FLAGS],[
|
||||||
|
if test -z "$host_alias" && test -n "$host"; then
|
||||||
|
host_alias=$host
|
||||||
|
fi
|
||||||
|
if test -z "$host_alias"; then
|
||||||
|
AC_MSG_ERROR(host_alias is not set. Make sure to run config.guess)
|
||||||
|
fi
|
||||||
|
case $host_alias in
|
||||||
|
*solaris*)
|
||||||
|
PTHREAD_FLAGS="-D_POSIX_PTHREAD_SEMANTICS -D_REENTRANT";;
|
||||||
|
*freebsd*)
|
||||||
|
PTHREAD_FLAGS="-D_REENTRANT -D_THREAD_SAFE";;
|
||||||
|
*linux*)
|
||||||
|
PTHREAD_FLAGS=-D_REENTRANT;;
|
||||||
|
*aix*)
|
||||||
|
PTHREAD_FLAGS=-D_THREAD_SAFE;;
|
||||||
|
*irix*)
|
||||||
|
PTHREAD_FLAGS=-D_POSIX_THREAD_SAFE_FUNCTIONS;;
|
||||||
|
*hpux*)
|
||||||
|
PTHREAD_FLAGS=-D_REENTRANT;;
|
||||||
|
*sco*)
|
||||||
|
PTHREAD_FLAGS=-D_REENTRANT;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if test -n "$PTHREAD_FLAGS"; then
|
||||||
|
CPPFLAGS="$CPPFLAGS $PTHREAD_FLAGS"
|
||||||
|
fi
|
||||||
|
])
|
||||||
|
|
||||||
|
dnl
|
||||||
|
dnl PTHREADS_CHECK_COMPILE
|
||||||
|
dnl
|
||||||
|
dnl Check whether the current setup can use POSIX threads calls.
|
||||||
|
dnl
|
||||||
|
AC_DEFUN([PTHREADS_CHECK_COMPILE], [
|
||||||
|
AC_LINK_IFELSE([ AC_LANG_SOURCE([
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
void *thread_routine(void *data) {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
pthread_t thd;
|
||||||
|
pthread_mutexattr_t mattr;
|
||||||
|
int data = 1;
|
||||||
|
pthread_mutexattr_init(&mattr);
|
||||||
|
return pthread_create(&thd, NULL, thread_routine, &data);
|
||||||
|
} ]) ], [
|
||||||
|
pthreads_checked=yes
|
||||||
|
], [
|
||||||
|
pthreads_checked=no
|
||||||
|
]
|
||||||
|
) ] )
|
||||||
|
|
||||||
|
dnl
|
||||||
|
dnl PTHREADS_CHECK
|
||||||
|
dnl
|
||||||
|
dnl Try to find a way to enable POSIX threads.
|
||||||
|
dnl
|
||||||
|
dnl Magic flags
|
||||||
|
dnl -kthread gcc (FreeBSD)
|
||||||
|
dnl -Kthread UDK cc (UnixWare)
|
||||||
|
dnl -mt WorkShop cc (Solaris)
|
||||||
|
dnl -mthreads gcc (AIX)
|
||||||
|
dnl -pthread gcc (Linux, FreeBSD, NetBSD, OpenBSD)
|
||||||
|
dnl -pthreads gcc (Solaris)
|
||||||
|
dnl -qthreaded AIX cc V5
|
||||||
|
dnl -threads gcc (HP-UX)
|
||||||
|
dnl
|
||||||
|
AC_DEFUN([PTHREADS_CHECK],[
|
||||||
|
AC_CACHE_CHECK(for pthreads_cflags,ac_cv_pthreads_cflags,[
|
||||||
|
ac_cv_pthreads_cflags=
|
||||||
|
if test "$pthreads_working" != "yes"; then
|
||||||
|
for flag in -kthread -pthread -pthreads -mthreads -Kthread -threads -mt -qthreaded; do
|
||||||
|
ac_save=$CFLAGS
|
||||||
|
CFLAGS="$CFLAGS $flag"
|
||||||
|
PTHREADS_CHECK_COMPILE
|
||||||
|
CFLAGS=$ac_save
|
||||||
|
if test "$pthreads_checked" = "yes"; then
|
||||||
|
ac_cv_pthreads_cflags=$flag
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
])
|
||||||
|
|
||||||
|
AC_CACHE_CHECK(for pthreads_lib, ac_cv_pthreads_lib,[
|
||||||
|
ac_cv_pthreads_lib=
|
||||||
|
if test "$pthreads_working" != "yes"; then
|
||||||
|
for lib in pthread pthreads c_r; do
|
||||||
|
ac_save=$LIBS
|
||||||
|
LIBS="$LIBS -l$lib"
|
||||||
|
PTHREADS_CHECK_COMPILE
|
||||||
|
LIBS=$ac_save
|
||||||
|
if test "$pthreads_checked" = "yes"; then
|
||||||
|
ac_cv_pthreads_lib=$lib
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
])
|
||||||
|
|
||||||
|
if test "x$ac_cv_pthreads_cflags" != "x" -o "x$ac_cv_pthreads_lib" != "x"; then
|
||||||
|
pthreads_working="yes"
|
||||||
|
fi
|
||||||
|
])
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
dnl This file contains TSRM specific autoconf macros.
|
||||||
|
|
||||||
|
dnl
|
||||||
|
dnl TSRM_CHECK_PTHREADS
|
||||||
|
dnl
|
||||||
|
AC_DEFUN([TSRM_CHECK_PTHREADS],[
|
||||||
|
PTHREADS_CHECK
|
||||||
|
|
||||||
|
if test "$pthreads_working" != "yes"; then
|
||||||
|
AC_MSG_ERROR(Your system seems to lack POSIX threads.)
|
||||||
|
fi
|
||||||
|
|
||||||
|
AC_DEFINE(PTHREADS, 1, Whether to use Pthreads)
|
||||||
|
|
||||||
|
AC_MSG_CHECKING(for POSIX threads)
|
||||||
|
AC_MSG_RESULT(yes)
|
||||||
|
])
|
||||||
|
|
@ -0,0 +1,829 @@
|
||||||
|
/*
|
||||||
|
+----------------------------------------------------------------------+
|
||||||
|
| Copyright (c) The PHP Group |
|
||||||
|
+----------------------------------------------------------------------+
|
||||||
|
| This source file is subject to version 3.01 of the PHP license, |
|
||||||
|
| that is bundled with this package in the file LICENSE, and is |
|
||||||
|
| available through the world-wide-web at the following url: |
|
||||||
|
| http://www.php.net/license/3_01.txt |
|
||||||
|
| If you did not receive a copy of the PHP license and are unable to |
|
||||||
|
| obtain it through the world-wide-web, please send a note to |
|
||||||
|
| license@php.net so we can mail you a copy immediately. |
|
||||||
|
+----------------------------------------------------------------------+
|
||||||
|
| Authors: Daniel Beulshausen <daniel@php4win.de> |
|
||||||
|
+----------------------------------------------------------------------+
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <io.h>
|
||||||
|
#include <process.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#define TSRM_INCLUDE_FULL_WINDOWS_HEADERS
|
||||||
|
#include "SAPI.h"
|
||||||
|
#include "TSRM.h"
|
||||||
|
|
||||||
|
#ifdef TSRM_WIN32
|
||||||
|
#include <Sddl.h>
|
||||||
|
#include "tsrm_win32.h"
|
||||||
|
#include "zend_virtual_cwd.h"
|
||||||
|
#include "win32/ioutil.h"
|
||||||
|
|
||||||
|
#ifdef ZTS
|
||||||
|
static ts_rsrc_id win32_globals_id;
|
||||||
|
#else
|
||||||
|
static tsrm_win32_globals win32_globals;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void tsrm_win32_ctor(tsrm_win32_globals *globals)
|
||||||
|
{/*{{{*/
|
||||||
|
#ifdef ZTS
|
||||||
|
TSRMLS_CACHE_UPDATE();
|
||||||
|
#endif
|
||||||
|
globals->process = NULL;
|
||||||
|
globals->shm = NULL;
|
||||||
|
globals->process_size = 0;
|
||||||
|
globals->shm_size = 0;
|
||||||
|
globals->comspec = _strdup("cmd.exe");
|
||||||
|
|
||||||
|
/* Set it to INVALID_HANDLE_VALUE
|
||||||
|
* It will be initialized correctly in tsrm_win32_access or set to
|
||||||
|
* NULL if no impersonation has been done.
|
||||||
|
* the impersonated token can't be set here as the impersonation
|
||||||
|
* will happen later, in fcgi_accept_request (or whatever is the
|
||||||
|
* SAPI being used).
|
||||||
|
*/
|
||||||
|
globals->impersonation_token = INVALID_HANDLE_VALUE;
|
||||||
|
globals->impersonation_token_sid = NULL;
|
||||||
|
}/*}}}*/
|
||||||
|
|
||||||
|
static void tsrm_win32_dtor(tsrm_win32_globals *globals)
|
||||||
|
{/*{{{*/
|
||||||
|
shm_pair *ptr;
|
||||||
|
|
||||||
|
if (globals->process) {
|
||||||
|
free(globals->process);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (globals->shm) {
|
||||||
|
for (ptr = globals->shm; ptr < (globals->shm + globals->shm_size); ptr++) {
|
||||||
|
UnmapViewOfFile(ptr->addr);
|
||||||
|
CloseHandle(ptr->segment);
|
||||||
|
UnmapViewOfFile(ptr->descriptor);
|
||||||
|
CloseHandle(ptr->info);
|
||||||
|
}
|
||||||
|
free(globals->shm);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(globals->comspec);
|
||||||
|
|
||||||
|
if (globals->impersonation_token && globals->impersonation_token != INVALID_HANDLE_VALUE ) {
|
||||||
|
CloseHandle(globals->impersonation_token);
|
||||||
|
}
|
||||||
|
if (globals->impersonation_token_sid) {
|
||||||
|
free(globals->impersonation_token_sid);
|
||||||
|
}
|
||||||
|
}/*}}}*/
|
||||||
|
|
||||||
|
TSRM_API void tsrm_win32_startup(void)
|
||||||
|
{/*{{{*/
|
||||||
|
#ifdef ZTS
|
||||||
|
ts_allocate_id(&win32_globals_id, sizeof(tsrm_win32_globals), (ts_allocate_ctor)tsrm_win32_ctor, (ts_allocate_ctor)tsrm_win32_dtor);
|
||||||
|
#else
|
||||||
|
tsrm_win32_ctor(&win32_globals);
|
||||||
|
#endif
|
||||||
|
}/*}}}*/
|
||||||
|
|
||||||
|
TSRM_API void tsrm_win32_shutdown(void)
|
||||||
|
{/*{{{*/
|
||||||
|
#ifndef ZTS
|
||||||
|
tsrm_win32_dtor(&win32_globals);
|
||||||
|
#endif
|
||||||
|
}/*}}}*/
|
||||||
|
|
||||||
|
const char * tsrm_win32_get_path_sid_key(const char *pathname, size_t pathname_len, size_t *key_len)
|
||||||
|
{/*{{{*/
|
||||||
|
PSID pSid = TWG(impersonation_token_sid);
|
||||||
|
char *ptcSid = NULL;
|
||||||
|
char *bucket_key = NULL;
|
||||||
|
size_t ptc_sid_len;
|
||||||
|
|
||||||
|
if (!pSid) {
|
||||||
|
*key_len = pathname_len;
|
||||||
|
return pathname;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ConvertSidToStringSid(pSid, &ptcSid)) {
|
||||||
|
*key_len = 0;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ptc_sid_len = strlen(ptcSid);
|
||||||
|
*key_len = pathname_len + ptc_sid_len;
|
||||||
|
bucket_key = (char *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *key_len + 1);
|
||||||
|
if (!bucket_key) {
|
||||||
|
LocalFree(ptcSid);
|
||||||
|
*key_len = 0;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(bucket_key, ptcSid, ptc_sid_len);
|
||||||
|
memcpy(bucket_key + ptc_sid_len, pathname, pathname_len + 1);
|
||||||
|
|
||||||
|
LocalFree(ptcSid);
|
||||||
|
return bucket_key;
|
||||||
|
}/*}}}*/
|
||||||
|
|
||||||
|
|
||||||
|
PSID tsrm_win32_get_token_sid(HANDLE hToken)
|
||||||
|
{/*{{{*/
|
||||||
|
DWORD dwLength = 0;
|
||||||
|
PTOKEN_USER pTokenUser = NULL;
|
||||||
|
DWORD sid_len;
|
||||||
|
PSID pResultSid = NULL;
|
||||||
|
|
||||||
|
/* Get the actual size of the TokenUser structure */
|
||||||
|
if (!GetTokenInformation(
|
||||||
|
hToken, TokenUser, (LPVOID) pTokenUser, 0, &dwLength)) {
|
||||||
|
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
|
||||||
|
goto Finished;
|
||||||
|
}
|
||||||
|
|
||||||
|
pTokenUser = (PTOKEN_USER)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwLength);
|
||||||
|
if (pTokenUser == NULL) {
|
||||||
|
goto Finished;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* and fetch it now */
|
||||||
|
if (!GetTokenInformation(
|
||||||
|
hToken, TokenUser, (LPVOID) pTokenUser, dwLength, &dwLength)) {
|
||||||
|
goto Finished;
|
||||||
|
}
|
||||||
|
|
||||||
|
sid_len = GetLengthSid(pTokenUser->User.Sid);
|
||||||
|
|
||||||
|
/* ConvertSidToStringSid(pTokenUser->User.Sid, &ptcSidOwner); */
|
||||||
|
pResultSid = malloc(sid_len);
|
||||||
|
if (!pResultSid) {
|
||||||
|
goto Finished;
|
||||||
|
}
|
||||||
|
if (!CopySid(sid_len, pResultSid, pTokenUser->User.Sid)) {
|
||||||
|
goto Finished;
|
||||||
|
}
|
||||||
|
HeapFree(GetProcessHeap(), 0, (LPVOID)pTokenUser);
|
||||||
|
return pResultSid;
|
||||||
|
|
||||||
|
Finished:
|
||||||
|
if (pResultSid) {
|
||||||
|
free(pResultSid);
|
||||||
|
}
|
||||||
|
/* Free the buffer for the token groups. */
|
||||||
|
if (pTokenUser != NULL) {
|
||||||
|
HeapFree(GetProcessHeap(), 0, (LPVOID)pTokenUser);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}/*}}}*/
|
||||||
|
|
||||||
|
TSRM_API int tsrm_win32_access(const char *pathname, int mode)
|
||||||
|
{/*{{{*/
|
||||||
|
time_t t;
|
||||||
|
HANDLE thread_token = NULL;
|
||||||
|
PSID token_sid;
|
||||||
|
SECURITY_INFORMATION sec_info = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION;
|
||||||
|
GENERIC_MAPPING gen_map = { FILE_GENERIC_READ, FILE_GENERIC_WRITE, FILE_GENERIC_EXECUTE, FILE_ALL_ACCESS };
|
||||||
|
DWORD priv_set_length = sizeof(PRIVILEGE_SET);
|
||||||
|
|
||||||
|
PRIVILEGE_SET privilege_set = {0};
|
||||||
|
DWORD sec_desc_length = 0, desired_access = 0, granted_access = 0;
|
||||||
|
BYTE * psec_desc = NULL;
|
||||||
|
BOOL fAccess = FALSE;
|
||||||
|
|
||||||
|
realpath_cache_bucket * bucket = NULL;
|
||||||
|
char real_path[MAXPATHLEN] = {0};
|
||||||
|
|
||||||
|
if(!IS_ABSOLUTE_PATH(pathname, strlen(pathname)+1)) {
|
||||||
|
if(tsrm_realpath(pathname, real_path) == NULL) {
|
||||||
|
SET_ERRNO_FROM_WIN32_CODE(ERROR_FILE_NOT_FOUND);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
pathname = real_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
PHP_WIN32_IOUTIL_INIT_W(pathname)
|
||||||
|
if (!pathw) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Either access call failed, or the mode was asking for a specific check.*/
|
||||||
|
int ret = php_win32_ioutil_access_w(pathw, mode);
|
||||||
|
if (0 > ret || X_OK == mode || F_OK == mode) {
|
||||||
|
PHP_WIN32_IOUTIL_CLEANUP_W()
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Only in NTS when impersonate==1 (aka FastCGI) */
|
||||||
|
|
||||||
|
/*
|
||||||
|
AccessCheck() requires an impersonation token. We first get a primary
|
||||||
|
token and then create a duplicate impersonation token. The
|
||||||
|
impersonation token is not actually assigned to the thread, but is
|
||||||
|
used in the call to AccessCheck. Thus, this function itself never
|
||||||
|
impersonates, but does use the identity of the thread. If the thread
|
||||||
|
was impersonating already, this function uses that impersonation context.
|
||||||
|
*/
|
||||||
|
if(!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, TRUE, &thread_token)) {
|
||||||
|
if (GetLastError() == ERROR_NO_TOKEN) {
|
||||||
|
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &thread_token)) {
|
||||||
|
TWG(impersonation_token) = NULL;
|
||||||
|
goto Finished;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* token_sid will be freed in tsrmwin32_dtor */
|
||||||
|
token_sid = tsrm_win32_get_token_sid(thread_token);
|
||||||
|
if (!token_sid) {
|
||||||
|
if (TWG(impersonation_token_sid)) {
|
||||||
|
free(TWG(impersonation_token_sid));
|
||||||
|
}
|
||||||
|
TWG(impersonation_token_sid) = NULL;
|
||||||
|
goto Finished;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Different identity, we need a new impersontated token as well */
|
||||||
|
if (!TWG(impersonation_token_sid) || !EqualSid(token_sid, TWG(impersonation_token_sid))) {
|
||||||
|
if (TWG(impersonation_token_sid)) {
|
||||||
|
free(TWG(impersonation_token_sid));
|
||||||
|
}
|
||||||
|
TWG(impersonation_token_sid) = token_sid;
|
||||||
|
|
||||||
|
/* Duplicate the token as impersonated token */
|
||||||
|
if (!DuplicateToken(thread_token, SecurityImpersonation, &TWG(impersonation_token))) {
|
||||||
|
goto Finished;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* we already have it, free it then */
|
||||||
|
free(token_sid);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CWDG(realpath_cache_size_limit)) {
|
||||||
|
t = time(0);
|
||||||
|
bucket = realpath_cache_lookup(pathname, strlen(pathname), t);
|
||||||
|
if(bucket == NULL && !real_path[0]) {
|
||||||
|
/* We used the pathname directly. Call tsrm_realpath */
|
||||||
|
/* so that entry is created in realpath cache */
|
||||||
|
if(tsrm_realpath(pathname, real_path) != NULL) {
|
||||||
|
pathname = real_path;
|
||||||
|
bucket = realpath_cache_lookup(pathname, strlen(pathname), t);
|
||||||
|
PHP_WIN32_IOUTIL_REINIT_W(pathname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Do a full access check because access() will only check read-only attribute */
|
||||||
|
if(mode == 0 || mode > 6) {
|
||||||
|
if(bucket != NULL && bucket->is_rvalid) {
|
||||||
|
fAccess = bucket->is_readable;
|
||||||
|
goto Finished;
|
||||||
|
}
|
||||||
|
desired_access = FILE_GENERIC_READ;
|
||||||
|
} else if(mode <= 2) {
|
||||||
|
if(bucket != NULL && bucket->is_wvalid) {
|
||||||
|
fAccess = bucket->is_writable;
|
||||||
|
goto Finished;
|
||||||
|
}
|
||||||
|
desired_access = FILE_GENERIC_WRITE;
|
||||||
|
} else if(mode <= 4) {
|
||||||
|
if(bucket != NULL && bucket->is_rvalid) {
|
||||||
|
fAccess = bucket->is_readable;
|
||||||
|
goto Finished;
|
||||||
|
}
|
||||||
|
desired_access = FILE_GENERIC_READ|FILE_FLAG_BACKUP_SEMANTICS;
|
||||||
|
} else { // if(mode <= 6)
|
||||||
|
if(bucket != NULL && bucket->is_rvalid && bucket->is_wvalid) {
|
||||||
|
fAccess = bucket->is_readable & bucket->is_writable;
|
||||||
|
goto Finished;
|
||||||
|
}
|
||||||
|
desired_access = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(TWG(impersonation_token) == NULL) {
|
||||||
|
goto Finished;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get size of security buffer. Call is expected to fail */
|
||||||
|
if(GetFileSecurityW(pathw, sec_info, NULL, 0, &sec_desc_length)) {
|
||||||
|
goto Finished;
|
||||||
|
}
|
||||||
|
|
||||||
|
psec_desc = (BYTE *)malloc(sec_desc_length);
|
||||||
|
if(psec_desc == NULL ||
|
||||||
|
!GetFileSecurityW(pathw, sec_info, (PSECURITY_DESCRIPTOR)psec_desc, sec_desc_length, &sec_desc_length)) {
|
||||||
|
goto Finished;
|
||||||
|
}
|
||||||
|
|
||||||
|
MapGenericMask(&desired_access, &gen_map);
|
||||||
|
|
||||||
|
if(!AccessCheck((PSECURITY_DESCRIPTOR)psec_desc, TWG(impersonation_token), desired_access, &gen_map, &privilege_set, &priv_set_length, &granted_access, &fAccess)) {
|
||||||
|
goto Finished_Impersonate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Keep the result in realpath_cache */
|
||||||
|
if(bucket != NULL) {
|
||||||
|
if(desired_access == (FILE_GENERIC_READ|FILE_FLAG_BACKUP_SEMANTICS)) {
|
||||||
|
bucket->is_rvalid = 1;
|
||||||
|
bucket->is_readable = fAccess;
|
||||||
|
}
|
||||||
|
else if(desired_access == FILE_GENERIC_WRITE) {
|
||||||
|
bucket->is_wvalid = 1;
|
||||||
|
bucket->is_writable = fAccess;
|
||||||
|
} else if (desired_access == (FILE_GENERIC_READ | FILE_GENERIC_WRITE)) {
|
||||||
|
bucket->is_rvalid = 1;
|
||||||
|
bucket->is_readable = fAccess;
|
||||||
|
bucket->is_wvalid = 1;
|
||||||
|
bucket->is_writable = fAccess;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Finished_Impersonate:
|
||||||
|
if(psec_desc != NULL) {
|
||||||
|
free(psec_desc);
|
||||||
|
psec_desc = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Finished:
|
||||||
|
if(thread_token != NULL) {
|
||||||
|
CloseHandle(thread_token);
|
||||||
|
}
|
||||||
|
|
||||||
|
PHP_WIN32_IOUTIL_CLEANUP_W()
|
||||||
|
if(fAccess == FALSE) {
|
||||||
|
errno = EACCES;
|
||||||
|
return errno;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}/*}}}*/
|
||||||
|
|
||||||
|
|
||||||
|
static process_pair *process_get(FILE *stream)
|
||||||
|
{/*{{{*/
|
||||||
|
process_pair *ptr;
|
||||||
|
process_pair *newptr;
|
||||||
|
|
||||||
|
for (ptr = TWG(process); ptr < (TWG(process) + TWG(process_size)); ptr++) {
|
||||||
|
if (ptr->stream == stream) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ptr < (TWG(process) + TWG(process_size))) {
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
newptr = (process_pair*)realloc((void*)TWG(process), (TWG(process_size)+1)*sizeof(process_pair));
|
||||||
|
if (newptr == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
TWG(process) = newptr;
|
||||||
|
ptr = newptr + TWG(process_size);
|
||||||
|
TWG(process_size)++;
|
||||||
|
return ptr;
|
||||||
|
}/*}}}*/
|
||||||
|
|
||||||
|
static shm_pair *shm_get(key_t key, void *addr)
|
||||||
|
{/*{{{*/
|
||||||
|
shm_pair *ptr;
|
||||||
|
shm_pair *newptr;
|
||||||
|
|
||||||
|
for (ptr = TWG(shm); ptr < (TWG(shm) + TWG(shm_size)); ptr++) {
|
||||||
|
if (!ptr->descriptor) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!addr && ptr->descriptor->shm_perm.key == key) {
|
||||||
|
break;
|
||||||
|
} else if (ptr->addr == addr) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ptr < (TWG(shm) + TWG(shm_size))) {
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
newptr = (shm_pair*)realloc((void*)TWG(shm), (TWG(shm_size)+1)*sizeof(shm_pair));
|
||||||
|
if (newptr == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
TWG(shm) = newptr;
|
||||||
|
ptr = newptr + TWG(shm_size);
|
||||||
|
TWG(shm_size)++;
|
||||||
|
memset(ptr, 0, sizeof(*ptr));
|
||||||
|
return ptr;
|
||||||
|
}/*}}}*/
|
||||||
|
|
||||||
|
static HANDLE dupHandle(HANDLE fh, BOOL inherit)
|
||||||
|
{/*{{{*/
|
||||||
|
HANDLE copy, self = GetCurrentProcess();
|
||||||
|
if (!DuplicateHandle(self, fh, self, ©, 0, inherit, DUPLICATE_SAME_ACCESS|DUPLICATE_CLOSE_SOURCE)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return copy;
|
||||||
|
}/*}}}*/
|
||||||
|
|
||||||
|
TSRM_API FILE *popen(const char *command, const char *type)
|
||||||
|
{/*{{{*/
|
||||||
|
|
||||||
|
return popen_ex(command, type, NULL, NULL);
|
||||||
|
}/*}}}*/
|
||||||
|
|
||||||
|
TSRM_API FILE *popen_ex(const char *command, const char *type, const char *cwd, const char *env)
|
||||||
|
{/*{{{*/
|
||||||
|
FILE *stream = NULL;
|
||||||
|
int fno, type_len, read, mode;
|
||||||
|
STARTUPINFOW startup;
|
||||||
|
PROCESS_INFORMATION process;
|
||||||
|
SECURITY_ATTRIBUTES security;
|
||||||
|
HANDLE in, out;
|
||||||
|
DWORD dwCreateFlags = 0;
|
||||||
|
BOOL res;
|
||||||
|
process_pair *proc;
|
||||||
|
char *cmd = NULL;
|
||||||
|
wchar_t *cmdw = NULL, *cwdw = NULL, *envw = NULL;
|
||||||
|
char *ptype = (char *)type;
|
||||||
|
HANDLE thread_token = NULL;
|
||||||
|
HANDLE token_user = NULL;
|
||||||
|
BOOL asuser = TRUE;
|
||||||
|
|
||||||
|
if (!type) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
type_len = (int)strlen(type);
|
||||||
|
if (type_len < 1 || type_len > 2) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ptype[0] != 'r' && ptype[0] != 'w') {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type_len > 1 && (ptype[1] != 'b' && ptype[1] != 't')) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd = (char*)malloc(strlen(command)+strlen(TWG(comspec))+sizeof(" /s /c ")+2);
|
||||||
|
if (!cmd) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
sprintf(cmd, "%s /s /c \"%s\"", TWG(comspec), command);
|
||||||
|
cmdw = php_win32_cp_any_to_w(cmd);
|
||||||
|
if (!cmdw) {
|
||||||
|
free(cmd);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cwd) {
|
||||||
|
cwdw = php_win32_ioutil_any_to_w(cwd);
|
||||||
|
if (!cwdw) {
|
||||||
|
free(cmd);
|
||||||
|
free(cmdw);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
security.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||||
|
security.bInheritHandle = TRUE;
|
||||||
|
security.lpSecurityDescriptor = NULL;
|
||||||
|
|
||||||
|
if (!type_len || !CreatePipe(&in, &out, &security, 2048L)) {
|
||||||
|
free(cmdw);
|
||||||
|
free(cwdw);
|
||||||
|
free(cmd);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&startup, 0, sizeof(STARTUPINFOW));
|
||||||
|
memset(&process, 0, sizeof(PROCESS_INFORMATION));
|
||||||
|
|
||||||
|
startup.cb = sizeof(STARTUPINFOW);
|
||||||
|
startup.dwFlags = STARTF_USESTDHANDLES;
|
||||||
|
startup.hStdError = GetStdHandle(STD_ERROR_HANDLE);
|
||||||
|
|
||||||
|
read = (type[0] == 'r') ? TRUE : FALSE;
|
||||||
|
mode = ((type_len == 2) && (type[1] == 'b')) ? O_BINARY : O_TEXT;
|
||||||
|
|
||||||
|
if (read) {
|
||||||
|
in = dupHandle(in, FALSE);
|
||||||
|
startup.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
|
||||||
|
startup.hStdOutput = out;
|
||||||
|
} else {
|
||||||
|
out = dupHandle(out, FALSE);
|
||||||
|
startup.hStdInput = in;
|
||||||
|
startup.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
dwCreateFlags = NORMAL_PRIORITY_CLASS;
|
||||||
|
if (strcmp(sapi_module.name, "cli") != 0) {
|
||||||
|
dwCreateFlags |= CREATE_NO_WINDOW;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get a token with the impersonated user. */
|
||||||
|
if(OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, TRUE, &thread_token)) {
|
||||||
|
DuplicateTokenEx(thread_token, MAXIMUM_ALLOWED, &security, SecurityImpersonation, TokenPrimary, &token_user);
|
||||||
|
} else {
|
||||||
|
DWORD err = GetLastError();
|
||||||
|
if (err == ERROR_NO_TOKEN) {
|
||||||
|
asuser = FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
envw = php_win32_cp_env_any_to_w(env);
|
||||||
|
if (envw) {
|
||||||
|
dwCreateFlags |= CREATE_UNICODE_ENVIRONMENT;
|
||||||
|
} else {
|
||||||
|
if (env) {
|
||||||
|
free(cmd);
|
||||||
|
free(cmdw);
|
||||||
|
free(cwdw);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (asuser) {
|
||||||
|
res = CreateProcessAsUserW(token_user, NULL, cmdw, &security, &security, security.bInheritHandle, dwCreateFlags, envw, cwdw, &startup, &process);
|
||||||
|
CloseHandle(token_user);
|
||||||
|
} else {
|
||||||
|
res = CreateProcessW(NULL, cmdw, &security, &security, security.bInheritHandle, dwCreateFlags, envw, cwdw, &startup, &process);
|
||||||
|
}
|
||||||
|
free(cmd);
|
||||||
|
free(cmdw);
|
||||||
|
free(cwdw);
|
||||||
|
free(envw);
|
||||||
|
|
||||||
|
if (!res) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
CloseHandle(process.hThread);
|
||||||
|
proc = process_get(NULL);
|
||||||
|
|
||||||
|
if (read) {
|
||||||
|
fno = _open_osfhandle((tsrm_intptr_t)in, _O_RDONLY | mode);
|
||||||
|
CloseHandle(out);
|
||||||
|
} else {
|
||||||
|
fno = _open_osfhandle((tsrm_intptr_t)out, _O_WRONLY | mode);
|
||||||
|
CloseHandle(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
stream = _fdopen(fno, type);
|
||||||
|
proc->prochnd = process.hProcess;
|
||||||
|
proc->stream = stream;
|
||||||
|
return stream;
|
||||||
|
}/*}}}*/
|
||||||
|
|
||||||
|
TSRM_API int pclose(FILE *stream)
|
||||||
|
{/*{{{*/
|
||||||
|
DWORD termstat = 0;
|
||||||
|
process_pair *process;
|
||||||
|
|
||||||
|
if ((process = process_get(stream)) == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fflush(process->stream);
|
||||||
|
fclose(process->stream);
|
||||||
|
|
||||||
|
WaitForSingleObject(process->prochnd, INFINITE);
|
||||||
|
GetExitCodeProcess(process->prochnd, &termstat);
|
||||||
|
process->stream = NULL;
|
||||||
|
CloseHandle(process->prochnd);
|
||||||
|
|
||||||
|
return termstat;
|
||||||
|
}/*}}}*/
|
||||||
|
|
||||||
|
#define SEGMENT_PREFIX "TSRM_SHM_SEGMENT:"
|
||||||
|
#define DESCRIPTOR_PREFIX "TSRM_SHM_DESCRIPTOR:"
|
||||||
|
#define INT_MIN_AS_STRING "-2147483648"
|
||||||
|
|
||||||
|
TSRM_API int shmget(key_t key, size_t size, int flags)
|
||||||
|
{/*{{{*/
|
||||||
|
shm_pair *shm;
|
||||||
|
char shm_segment[sizeof(SEGMENT_PREFIX INT_MIN_AS_STRING)], shm_info[sizeof(DESCRIPTOR_PREFIX INT_MIN_AS_STRING)];
|
||||||
|
HANDLE shm_handle = NULL, info_handle = NULL;
|
||||||
|
BOOL created = FALSE;
|
||||||
|
|
||||||
|
if (key != IPC_PRIVATE) {
|
||||||
|
snprintf(shm_segment, sizeof(shm_segment), SEGMENT_PREFIX "%d", key);
|
||||||
|
snprintf(shm_info, sizeof(shm_info), DESCRIPTOR_PREFIX "%d", key);
|
||||||
|
|
||||||
|
shm_handle = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, shm_segment);
|
||||||
|
info_handle = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, shm_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!shm_handle && !info_handle) {
|
||||||
|
if (flags & IPC_CREAT) {
|
||||||
|
#if SIZEOF_SIZE_T == 8
|
||||||
|
DWORD high = size >> 32;
|
||||||
|
DWORD low = (DWORD)size;
|
||||||
|
#else
|
||||||
|
DWORD high = 0;
|
||||||
|
DWORD low = size;
|
||||||
|
#endif
|
||||||
|
shm_handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, high, low, key == IPC_PRIVATE ? NULL : shm_segment);
|
||||||
|
info_handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(shm->descriptor), key == IPC_PRIVATE ? NULL : shm_info);
|
||||||
|
created = TRUE;
|
||||||
|
}
|
||||||
|
if (!shm_handle || !info_handle) {
|
||||||
|
if (shm_handle) {
|
||||||
|
CloseHandle(shm_handle);
|
||||||
|
}
|
||||||
|
if (info_handle) {
|
||||||
|
CloseHandle(info_handle);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (flags & IPC_EXCL) {
|
||||||
|
if (shm_handle) {
|
||||||
|
CloseHandle(shm_handle);
|
||||||
|
}
|
||||||
|
if (info_handle) {
|
||||||
|
CloseHandle(info_handle);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
shm = shm_get(key, NULL);
|
||||||
|
if (!shm) {
|
||||||
|
CloseHandle(shm_handle);
|
||||||
|
CloseHandle(info_handle);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
shm->segment = shm_handle;
|
||||||
|
shm->info = info_handle;
|
||||||
|
shm->descriptor = MapViewOfFileEx(shm->info, FILE_MAP_ALL_ACCESS, 0, 0, 0, NULL);
|
||||||
|
|
||||||
|
if (NULL != shm->descriptor && created) {
|
||||||
|
shm->descriptor->shm_perm.key = key;
|
||||||
|
shm->descriptor->shm_segsz = size;
|
||||||
|
shm->descriptor->shm_ctime = time(NULL);
|
||||||
|
shm->descriptor->shm_cpid = getpid();
|
||||||
|
shm->descriptor->shm_perm.mode = flags;
|
||||||
|
|
||||||
|
shm->descriptor->shm_perm.cuid = shm->descriptor->shm_perm.cgid= 0;
|
||||||
|
shm->descriptor->shm_perm.gid = shm->descriptor->shm_perm.uid = 0;
|
||||||
|
shm->descriptor->shm_atime = shm->descriptor->shm_dtime = 0;
|
||||||
|
shm->descriptor->shm_lpid = shm->descriptor->shm_nattch = 0;
|
||||||
|
shm->descriptor->shm_perm.mode = shm->descriptor->shm_perm.seq = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NULL != shm->descriptor && (shm->descriptor->shm_perm.key != key || size > shm->descriptor->shm_segsz)) {
|
||||||
|
if (NULL != shm->segment) {
|
||||||
|
CloseHandle(shm->segment);
|
||||||
|
}
|
||||||
|
UnmapViewOfFile(shm->descriptor);
|
||||||
|
CloseHandle(shm->info);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return key;
|
||||||
|
}/*}}}*/
|
||||||
|
|
||||||
|
TSRM_API void *shmat(int key, const void *shmaddr, int flags)
|
||||||
|
{/*{{{*/
|
||||||
|
shm_pair *shm = shm_get(key, NULL);
|
||||||
|
|
||||||
|
if (!shm || !shm->segment) {
|
||||||
|
return (void*)-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
shm->addr = MapViewOfFileEx(shm->segment, FILE_MAP_ALL_ACCESS, 0, 0, 0, NULL);
|
||||||
|
|
||||||
|
if (NULL == shm->addr) {
|
||||||
|
int err = GetLastError();
|
||||||
|
SET_ERRNO_FROM_WIN32_CODE(err);
|
||||||
|
return (void*)-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
shm->descriptor->shm_atime = time(NULL);
|
||||||
|
shm->descriptor->shm_lpid = getpid();
|
||||||
|
shm->descriptor->shm_nattch++;
|
||||||
|
|
||||||
|
return shm->addr;
|
||||||
|
}/*}}}*/
|
||||||
|
|
||||||
|
TSRM_API int shmdt(const void *shmaddr)
|
||||||
|
{/*{{{*/
|
||||||
|
shm_pair *shm = shm_get(0, (void*)shmaddr);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!shm || !shm->segment) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
shm->descriptor->shm_dtime = time(NULL);
|
||||||
|
shm->descriptor->shm_lpid = getpid();
|
||||||
|
shm->descriptor->shm_nattch--;
|
||||||
|
|
||||||
|
ret = UnmapViewOfFile(shm->addr) ? 0 : -1;
|
||||||
|
if (!ret && shm->descriptor->shm_nattch <= 0) {
|
||||||
|
ret = UnmapViewOfFile(shm->descriptor) ? 0 : -1;
|
||||||
|
shm->descriptor = NULL;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}/*}}}*/
|
||||||
|
|
||||||
|
TSRM_API int shmctl(int key, int cmd, struct shmid_ds *buf)
|
||||||
|
{/*{{{*/
|
||||||
|
shm_pair *shm = shm_get(key, NULL);
|
||||||
|
|
||||||
|
if (!shm || !shm->segment) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (cmd) {
|
||||||
|
case IPC_STAT:
|
||||||
|
memcpy(buf, shm->descriptor, sizeof(struct shmid_ds));
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case IPC_SET:
|
||||||
|
shm->descriptor->shm_ctime = time(NULL);
|
||||||
|
shm->descriptor->shm_perm.uid = buf->shm_perm.uid;
|
||||||
|
shm->descriptor->shm_perm.gid = buf->shm_perm.gid;
|
||||||
|
shm->descriptor->shm_perm.mode = buf->shm_perm.mode;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case IPC_RMID:
|
||||||
|
if (shm->descriptor->shm_nattch < 1) {
|
||||||
|
shm->descriptor->shm_perm.key = -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}/*}}}*/
|
||||||
|
|
||||||
|
static zend_always_inline void UnixTimeToFileTime(time_t t, LPFILETIME pft) /* {{{ */
|
||||||
|
{
|
||||||
|
// Note that LONGLONG is a 64-bit value
|
||||||
|
LONGLONG ll;
|
||||||
|
|
||||||
|
ll = t * 10000000LL + 116444736000000000LL;
|
||||||
|
pft->dwLowDateTime = (DWORD)ll;
|
||||||
|
pft->dwHighDateTime = ll >> 32;
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
TSRM_API int win32_utime(const char *filename, struct utimbuf *buf) /* {{{ */
|
||||||
|
{
|
||||||
|
FILETIME mtime, atime;
|
||||||
|
HANDLE hFile;
|
||||||
|
PHP_WIN32_IOUTIL_INIT_W(filename)
|
||||||
|
|
||||||
|
if (!pathw) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
hFile = CreateFileW(pathw, GENERIC_WRITE, FILE_SHARE_WRITE|FILE_SHARE_READ, NULL,
|
||||||
|
OPEN_ALWAYS, FILE_FLAG_BACKUP_SEMANTICS, NULL);
|
||||||
|
|
||||||
|
PHP_WIN32_IOUTIL_CLEANUP_W()
|
||||||
|
|
||||||
|
/* OPEN_ALWAYS mode sets the last error to ERROR_ALREADY_EXISTS but
|
||||||
|
the CreateFile operation succeeds */
|
||||||
|
if (GetLastError() == ERROR_ALREADY_EXISTS) {
|
||||||
|
SetLastError(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( hFile == INVALID_HANDLE_VALUE ) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!buf) {
|
||||||
|
SYSTEMTIME st;
|
||||||
|
GetSystemTime(&st);
|
||||||
|
SystemTimeToFileTime(&st, &mtime);
|
||||||
|
atime = mtime;
|
||||||
|
} else {
|
||||||
|
UnixTimeToFileTime(buf->modtime, &mtime);
|
||||||
|
UnixTimeToFileTime(buf->actime, &atime);
|
||||||
|
}
|
||||||
|
if (!SetFileTime(hFile, NULL, &atime, &mtime)) {
|
||||||
|
CloseHandle(hFile);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
CloseHandle(hFile);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,107 @@
|
||||||
|
/*
|
||||||
|
+----------------------------------------------------------------------+
|
||||||
|
| Copyright (c) The PHP Group |
|
||||||
|
+----------------------------------------------------------------------+
|
||||||
|
| This source file is subject to version 3.01 of the PHP license, |
|
||||||
|
| that is bundled with this package in the file LICENSE, and is |
|
||||||
|
| available through the world-wide-web at the following url: |
|
||||||
|
| http://www.php.net/license/3_01.txt |
|
||||||
|
| If you did not receive a copy of the PHP license and are unable to |
|
||||||
|
| obtain it through the world-wide-web, please send a note to |
|
||||||
|
| license@php.net so we can mail you a copy immediately. |
|
||||||
|
+----------------------------------------------------------------------+
|
||||||
|
| Authors: Daniel Beulshausen <daniel@php4win.de> |
|
||||||
|
+----------------------------------------------------------------------+
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TSRM_WIN32_H
|
||||||
|
#define TSRM_WIN32_H
|
||||||
|
|
||||||
|
#include "TSRM.h"
|
||||||
|
#include <windows.h>
|
||||||
|
#include <sys/utime.h>
|
||||||
|
#include "win32/ipc.h"
|
||||||
|
|
||||||
|
struct ipc_perm {
|
||||||
|
key_t key;
|
||||||
|
unsigned short uid;
|
||||||
|
unsigned short gid;
|
||||||
|
unsigned short cuid;
|
||||||
|
unsigned short cgid;
|
||||||
|
unsigned short mode;
|
||||||
|
unsigned short seq;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct shmid_ds {
|
||||||
|
struct ipc_perm shm_perm;
|
||||||
|
size_t shm_segsz;
|
||||||
|
time_t shm_atime;
|
||||||
|
time_t shm_dtime;
|
||||||
|
time_t shm_ctime;
|
||||||
|
unsigned short shm_cpid;
|
||||||
|
unsigned short shm_lpid;
|
||||||
|
short shm_nattch;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
FILE *stream;
|
||||||
|
HANDLE prochnd;
|
||||||
|
} process_pair;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
void *addr;
|
||||||
|
HANDLE info;
|
||||||
|
HANDLE segment;
|
||||||
|
struct shmid_ds *descriptor;
|
||||||
|
} shm_pair;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
process_pair *process;
|
||||||
|
shm_pair *shm;
|
||||||
|
int process_size;
|
||||||
|
int shm_size;
|
||||||
|
char *comspec;
|
||||||
|
HANDLE impersonation_token;
|
||||||
|
PSID impersonation_token_sid;
|
||||||
|
} tsrm_win32_globals;
|
||||||
|
|
||||||
|
#ifdef ZTS
|
||||||
|
# define TWG(v) TSRMG_STATIC(win32_globals_id, tsrm_win32_globals *, v)
|
||||||
|
TSRMLS_CACHE_EXTERN()
|
||||||
|
#else
|
||||||
|
# define TWG(v) (win32_globals.v)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define IPC_PRIVATE 0
|
||||||
|
#define IPC_CREAT 00001000
|
||||||
|
#define IPC_EXCL 00002000
|
||||||
|
#define IPC_NOWAIT 00004000
|
||||||
|
|
||||||
|
#define IPC_RMID 0
|
||||||
|
#define IPC_SET 1
|
||||||
|
#define IPC_STAT 2
|
||||||
|
#define IPC_INFO 3
|
||||||
|
|
||||||
|
#define SHM_R PAGE_READONLY
|
||||||
|
#define SHM_W PAGE_READWRITE
|
||||||
|
|
||||||
|
#define SHM_RDONLY FILE_MAP_READ
|
||||||
|
#define SHM_RND FILE_MAP_WRITE
|
||||||
|
#define SHM_REMAP FILE_MAP_COPY
|
||||||
|
|
||||||
|
const char * tsrm_win32_get_path_sid_key(const char *pathname, size_t pathname_len, size_t *key_len);
|
||||||
|
|
||||||
|
TSRM_API void tsrm_win32_startup(void);
|
||||||
|
TSRM_API void tsrm_win32_shutdown(void);
|
||||||
|
|
||||||
|
TSRM_API FILE *popen_ex(const char *command, const char *type, const char *cwd, const char *env);
|
||||||
|
TSRM_API FILE *popen(const char *command, const char *type);
|
||||||
|
TSRM_API int pclose(FILE *stream);
|
||||||
|
TSRM_API int tsrm_win32_access(const char *pathname, int mode);
|
||||||
|
TSRM_API int win32_utime(const char *filename, struct utimbuf *buf);
|
||||||
|
|
||||||
|
TSRM_API int shmget(key_t key, size_t size, int flags);
|
||||||
|
TSRM_API void *shmat(int key, const void *shmaddr, int flags);
|
||||||
|
TSRM_API int shmdt(const void *shmaddr);
|
||||||
|
TSRM_API int shmctl(int key, int cmd, struct shmid_ds *buf);
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,461 @@
|
||||||
|
PHP 8.0 INTERNALS UPGRADE NOTES
|
||||||
|
|
||||||
|
1. Internal API changes
|
||||||
|
a. Object Handlers API
|
||||||
|
b. ZEND_OVERLOADED_FUNCTION and corresponding call_method() object handler
|
||||||
|
c. TSRM changes
|
||||||
|
d. get() and set() object handlers
|
||||||
|
e. zend_parse_parameters 'L' specifier
|
||||||
|
f. Arginfo argument types
|
||||||
|
g. zend_free_op type and should_free argument of zend_get_zval_ptr()
|
||||||
|
h. zend_value_error()
|
||||||
|
i. get_closure() object handler
|
||||||
|
j. compare_objects() and compare() object handlers
|
||||||
|
k. The 'I' length modifier
|
||||||
|
l. Some VM instructions switched to IS_TMP_VAR result instead of IS_VAR
|
||||||
|
m. All internal functions must have arginfo
|
||||||
|
n. zend_hash_sort compare function and zend_hash_sort signature change
|
||||||
|
o. cast_object() object handler is now required
|
||||||
|
p. ARG_COUNT() macro removed
|
||||||
|
q. GC_COLLECTABLE flag
|
||||||
|
r. Cannot implement Traversable only
|
||||||
|
s. zend_fcall_info no_separation flag removed
|
||||||
|
t. Signature changes
|
||||||
|
u. Error Notification callbacks to replace zend_error_cb overwrite use-cases
|
||||||
|
v. Removed Zend APIs
|
||||||
|
w. Renamed Zend APIs
|
||||||
|
x. ZEND_EXT_NOP no longer emitted
|
||||||
|
|
||||||
|
2. Build system changes
|
||||||
|
a. Abstract
|
||||||
|
b. Unix build system changes
|
||||||
|
c. Windows build system changes
|
||||||
|
|
||||||
|
3. Module changes
|
||||||
|
|
||||||
|
========================
|
||||||
|
1. Internal API changes
|
||||||
|
========================
|
||||||
|
|
||||||
|
a. The Object Handlers API was changed to receive zend_object* instead of
|
||||||
|
zval* and zend_string* instead of zval* for property names. See also
|
||||||
|
section t for other similar changes.
|
||||||
|
|
||||||
|
b. ZEND_OVERLOADED_FUNCTION and corresponding call_method() object handler
|
||||||
|
were removed. ZEND_INTERNAL_FUNCTION with ZEND_ACC_CALL_VIA_HANDLER and
|
||||||
|
defined "handler" callback should be used instead. This "handler" callback
|
||||||
|
should also take care about function cleanup. See ext/zend_test/test.c
|
||||||
|
for example.
|
||||||
|
|
||||||
|
c. The following things have been removed from TSRM:
|
||||||
|
- TSRMLS_DC
|
||||||
|
- TSRMLS_D
|
||||||
|
- TSRMLS_CC
|
||||||
|
- TSRMLS_C
|
||||||
|
- TSRMLS_FETCH
|
||||||
|
- TSRMLS_FETCH_FROM_CTX
|
||||||
|
- TSRMLS_SET_CTX
|
||||||
|
- tsrm_new_interpreter_context
|
||||||
|
- tsrm_set_interpreter_context
|
||||||
|
- tsrm_free_interpreter_context
|
||||||
|
- support for GNUPTH, SGI ST, and BETHREADS
|
||||||
|
|
||||||
|
d. The get() and set() object handlers have been removed. The get() handler
|
||||||
|
can generally be replaced with cast_object(). Some uses of set() may be
|
||||||
|
replaced by do_operation(). If set() was used to overload direct
|
||||||
|
assignments using "=", then this is no longer supported and the
|
||||||
|
functionality should be provided in some other way (for example, as
|
||||||
|
modification of an object property).
|
||||||
|
|
||||||
|
e. The zend_parse_parameters 'L' specifier and the Z_PARAM_STRICT_LONG()
|
||||||
|
family of macros have been removed. Use 'l' and Z_PARAM_LONG() instead,
|
||||||
|
which, despite the confusing name, actually have stricter input validation.
|
||||||
|
|
||||||
|
f. Arginfo argument types for internal functions are no longer checked.
|
||||||
|
Instead type checks should be performed using the zend_parse_parameters()
|
||||||
|
or ZEND_PARSE_PARAMETERS_*() APIs.
|
||||||
|
|
||||||
|
g. The zend_free_op type and the "should_free" and "type" arguments of
|
||||||
|
zend_get_zval_ptr() were removed. It's possible to get the old
|
||||||
|
"should_free" value using the following code:
|
||||||
|
|
||||||
|
zval *ret = zend_get_zval_ptr(
|
||||||
|
opline, opline->op1_type, &opline->op1, execute_data);
|
||||||
|
zval *should_free = (op_type & (IS_TMP_VAR|IS_VAR)) ? ret : NULL;
|
||||||
|
|
||||||
|
h. Added the zend_value_error() function, which is intended to be used
|
||||||
|
to raise ValueError when inappropriate argument values are passed
|
||||||
|
to functions.
|
||||||
|
|
||||||
|
i. get_closure() object handlers now accept an additional zend_bool parameter
|
||||||
|
`check_only`. If it is true, the handler is called to check whether the
|
||||||
|
object is callable; in this case the handler should not throw an exception.
|
||||||
|
|
||||||
|
j. compare_objects() handler was removed. Extensions should use compare() object
|
||||||
|
handler instead and check if both arguments are objects and have the same
|
||||||
|
compare handler, using ZEND_COMPARE_OBJECTS_FALLBACK() macro.
|
||||||
|
|
||||||
|
k. The 'I' length modifier, used to denote 32 and 64bit integer from the custom
|
||||||
|
snprintf and spprintf implementations has been removed.
|
||||||
|
Use the ZEND_LONG_FMT, ZEND_ULONG_FMT and ZEND_XLONG_FMT macros defined in
|
||||||
|
php-src/Zend/zend_long.h
|
||||||
|
|
||||||
|
The 'v' format from the custom snprintf and spprintf implementations has
|
||||||
|
been removed. Use the standard 's' format instead.
|
||||||
|
|
||||||
|
l. Some VM instructions switched to IS_TMP_VAR result instead of IS_VAR.
|
||||||
|
Actually, all assignments (ZEND_ASSIGN, ZEND_ASSIGN_DIM, ZEND_ASSIGN_OBJ,
|
||||||
|
ZEND_ASSIGN_STATIC_PROP), all compound assignments (ZEND_ASSIGN_OP,
|
||||||
|
ZEND_ASSIGN_DIM_OP, ZEND_ASSIGN_OBJ_OP, ZEND_ASSIGN_STATIC_PROP_OP) and all
|
||||||
|
pre increments/decrements (ZEND_PRE_INC, ZEND_PRE_DEC, ZEND_PRE_INC_OBJ
|
||||||
|
ZEND_PRE_DEC_OBJ, ZEND_PRE_INC_STATIC_PROP ZEND_PRE_DEC_STATIC_PROP).
|
||||||
|
|
||||||
|
m. All internal functions and methods are now required to specify arginfo
|
||||||
|
information, otherwise warnings will be thrown on startup.
|
||||||
|
|
||||||
|
n. The zend_hash_sort and zend_hash_minmax APIs now accept a comparison
|
||||||
|
function with the following signature:
|
||||||
|
|
||||||
|
typedef int (*bucket_compare_func_t)(Bucket *a, Bucket *b);
|
||||||
|
|
||||||
|
Previously compare_func_t was used, which accepted void pointers.
|
||||||
|
Furthermore, the return type of zend_hash_sort and zend_ts_hash_sort has
|
||||||
|
been changed from int to void; these functions always succeed.
|
||||||
|
|
||||||
|
o. The cast_object() handler is now required, i.e. must be non-null. You can
|
||||||
|
indicate that casting is not supported by always returning FAILURE.
|
||||||
|
|
||||||
|
p. The ARG_COUNT() macro has been removed use ZEND_NUM_ARGS() instead.
|
||||||
|
|
||||||
|
q. GC_COLLECTABLE flag was inverted into GC_NOT_COLLECTABLE.
|
||||||
|
Assignments to GC_TYPE_INFO() might need to be changed to properly
|
||||||
|
set the value of the GC_NOT_COLLECTABLE flag.
|
||||||
|
|
||||||
|
r. Just for for userland classes, it is no longer allowed to implement only
|
||||||
|
the Traversable interface. Instead, it is necessary to implement either
|
||||||
|
Iterator or IteratorAggregate. You can do the latter by implementing
|
||||||
|
zend_ce_aggregate and providing the following method implementation:
|
||||||
|
|
||||||
|
ZEND_METHOD(MyClass, getIterator) {
|
||||||
|
ZEND_PARSE_PARAMETERS_NONE();
|
||||||
|
zend_create_internal_iterator_zval(return_value, ZEND_THIS);
|
||||||
|
}
|
||||||
|
|
||||||
|
s. The zend_fcall_info no_separation flag has been removed, and separation is
|
||||||
|
never allowed. If you wish to pass (or allow passing) arguments by
|
||||||
|
reference, explicitly create those arguments as references using
|
||||||
|
ZEND_MAKE_REF. This removal also affects call_user_function_ex(), which
|
||||||
|
should be replaced by call_user_function().
|
||||||
|
|
||||||
|
t. The following ZEND_API function have changed signature:
|
||||||
|
1. Void in Zend Engine 4.0:
|
||||||
|
- add_assoc_*()
|
||||||
|
- add_index_*()
|
||||||
|
- add_property_*()
|
||||||
|
- object_init()
|
||||||
|
- zend_declare_class_constant*()
|
||||||
|
- zend_declare_property*()
|
||||||
|
- zend_startup_modules()
|
||||||
|
- zend_wrong_parameters_none_error()
|
||||||
|
- zend_fcall_info_argp()
|
||||||
|
- zend_fcall_info_argv()
|
||||||
|
- zend_fcall_info_argn()
|
||||||
|
- zend_startup()
|
||||||
|
- zend_set_memory_limit()
|
||||||
|
- pass_two()
|
||||||
|
- zend_startup_constants()
|
||||||
|
- zend_shutdown_constants()
|
||||||
|
- zend_startup_extensions_mechanism()
|
||||||
|
- zend_startup_extensions()
|
||||||
|
- zend_register_extension()
|
||||||
|
- highlight_string()
|
||||||
|
- zend_ini_startup()
|
||||||
|
- zend_ini_shutdown()
|
||||||
|
- zend_ini_global_shutdown()
|
||||||
|
- zend_ini_deactivate()
|
||||||
|
- zend_copy_ini_directives()
|
||||||
|
- zend_prepare_string_for_scanning()
|
||||||
|
- zend_init_rsrc_list()
|
||||||
|
- zend_list_close()
|
||||||
|
- zend_signal()
|
||||||
|
- zend_sigaction()
|
||||||
|
- zend_stack_init()
|
||||||
|
- zend_stack_del_top()
|
||||||
|
- zend_stack_destroy()
|
||||||
|
2. Argument int to uint32_t in Zend Engine 4.0:
|
||||||
|
- _zend_get_parameters_array_ex()
|
||||||
|
- zend_copy_parameters_array()
|
||||||
|
- zend_fcall_info_args_save()
|
||||||
|
- zend_fcall_info_args_restore()
|
||||||
|
- zend_fcall_info_argp()
|
||||||
|
- zend_fcall_info_argv()
|
||||||
|
- zend_fcall_info_argn()
|
||||||
|
- zend_wrong_parameter*()
|
||||||
|
- zend_wrong_callback_error()
|
||||||
|
- zend_parse_arg_class()
|
||||||
|
3. Argument int to bool in Zend Engine 4.0:
|
||||||
|
- add_next_index_bool()
|
||||||
|
- zend_register_class_alias_ex()
|
||||||
|
- add_assoc_bool_ex()
|
||||||
|
- add_index_bool()
|
||||||
|
- zend_fcall_info_args_clear()
|
||||||
|
- zend_set_local_var()
|
||||||
|
- zend_set_local_var_str()
|
||||||
|
- zend_parse_arg_*()
|
||||||
|
- shutdown_memory_manager()
|
||||||
|
- zend_memory_usage()
|
||||||
|
- zend_memory_peak_usage()
|
||||||
|
- zend_mm_shutdown()
|
||||||
|
- zend_eval_string*()
|
||||||
|
- zend_set_timeout()
|
||||||
|
- _zend_hash_append_ex()
|
||||||
|
- _zend_hash_append_ptr_ex()
|
||||||
|
- zend_alter_ini_entry_ex()
|
||||||
|
- (*zend_encoding_list_parser) typedef
|
||||||
|
- zend_multibyte_parse_encoding_list()
|
||||||
|
- zend_safe_address()
|
||||||
|
- zend_string_tolower_ex()
|
||||||
|
- zend_string_alloc()
|
||||||
|
- zend_string_safe_alloc()
|
||||||
|
- zend_string_init()
|
||||||
|
- zend_string_dup()
|
||||||
|
- zend_string_realloc()
|
||||||
|
- zend_string_extend()
|
||||||
|
- zend_string_truncate()
|
||||||
|
- zend_string_safe_realloc()
|
||||||
|
- zend_string_release_ex()
|
||||||
|
- zend_ts_hash_merge()
|
||||||
|
- zend_ts_hash_sort()
|
||||||
|
4. Argument int to size_t in Zend Engine 4.0:
|
||||||
|
- zend_set_hash_symbol()
|
||||||
|
5. Argument zval* to zend_object* in Zend Engine 4.0:
|
||||||
|
- zend_read_property()
|
||||||
|
- zend_update_property()
|
||||||
|
- zend_unset_property()
|
||||||
|
- zend_call_method()
|
||||||
|
- zend_objects_clone_obj()
|
||||||
|
- zend_get_closure_method_def()
|
||||||
|
- zend_throw_exception_hook()
|
||||||
|
- zend_throw_exception_internal()
|
||||||
|
- zend_get_exception_base()
|
||||||
|
6. Argument zval* to zend_long in Zend Engine 4.0:
|
||||||
|
- _php_math_longtobase()
|
||||||
|
7. Return type from int to zend_result in Zend Engine 4.0:
|
||||||
|
- (*stream_open_function) in _zend_utility_functions
|
||||||
|
- (*zend_post_startup_cb)
|
||||||
|
- (*zend_preload_autoload)
|
||||||
|
- zend_execute_scripts()
|
||||||
|
- zend_post_startup()
|
||||||
|
- _zend_get_parameters_array_ex()
|
||||||
|
- zend_copy_parameters_array()
|
||||||
|
- zend_parse_parameters()
|
||||||
|
- zend_parse_parameters_ex()
|
||||||
|
- zend_parse_method_parameters()
|
||||||
|
- zend_parse_method_parameters_ex()
|
||||||
|
- zend_parse_method_parameters()
|
||||||
|
- zend_register_functions()
|
||||||
|
- zend_startup_module()
|
||||||
|
- zend_startup_module_ex()
|
||||||
|
- zend_register_class_alias_ex()
|
||||||
|
- zend_disable_function()
|
||||||
|
- zend_disable_class()
|
||||||
|
- zend_update_class_constants()
|
||||||
|
- zend_update_static_property*()
|
||||||
|
- object_init_ex()
|
||||||
|
- object_and_properties_init()
|
||||||
|
- add_index_zval()
|
||||||
|
- add_next_index_long_*()
|
||||||
|
- array_set_zval_key()
|
||||||
|
- _call_user_function_impl()
|
||||||
|
- zend_fcall_info_*()
|
||||||
|
- zend_call_function()
|
||||||
|
- zend_set_hash_symbol()
|
||||||
|
- zend_delete_global_variable()
|
||||||
|
- zend_set_local_var()
|
||||||
|
- zend_set_local_var_str()
|
||||||
|
- zend_forbid_dynamic_call()
|
||||||
|
- zend_get_default_from_internal_arg_info()
|
||||||
|
- zend_try_assign_typed_ref*()
|
||||||
|
- zend_ast_evaluate()
|
||||||
|
- zend_startup_builtin_functions()
|
||||||
|
- do_bind_function()
|
||||||
|
- do_bind_class()
|
||||||
|
- zend_unmangle_property_name_ex()
|
||||||
|
- zend_register_auto_global()
|
||||||
|
- zend_register_constant()
|
||||||
|
- zend_exception_error()
|
||||||
|
- zend_eval_string*()
|
||||||
|
- zend_undefined_offset_write()
|
||||||
|
- zend_undefined_index_write()
|
||||||
|
- zval_update_constant(_ex)()
|
||||||
|
- zend_load_extension()
|
||||||
|
- zend_load_extension_handle()
|
||||||
|
- zend_hash_del(_ind)()
|
||||||
|
- zend_hash_str_del(_ind)()
|
||||||
|
- zend_hash_index_del()
|
||||||
|
- zend_hash_move_forward_ex()
|
||||||
|
- zend_hash_move_backward_ex()
|
||||||
|
- zend_hash_get_current_key_ex()
|
||||||
|
- zend_hash_get_current_key_type_ex()
|
||||||
|
- zend_symtable_del(_ind)()
|
||||||
|
- zend_symtable_str_del(_ind)()
|
||||||
|
- highlight_file()
|
||||||
|
- zend_do_link_class()
|
||||||
|
- zend_alter_ini_entry*()
|
||||||
|
- zend_restore_ini_entry()
|
||||||
|
- zend_ini_register_displayer()
|
||||||
|
- zend_ini_open_file_for_scanning()
|
||||||
|
- zend_ini_prepare_string_for_scanning()
|
||||||
|
- zend_user_it_valid()
|
||||||
|
- zend_create_internal_iterator_zval()
|
||||||
|
- zend_multibyte_set_filter()
|
||||||
|
- zend_lex_tstring()
|
||||||
|
- _zend_module_entry module_startup_func, module_shutdown_func,
|
||||||
|
request_startup_func, request_shutdown_func, and post_deactivate_func function pointers
|
||||||
|
- (*zend_encoding_list_parser) typedef
|
||||||
|
- (*zend_encoding_internal_encoding_setter) typedef
|
||||||
|
- zend_multibyte_set_functions()
|
||||||
|
- zend_multibyte_set_script_encoding_by_string()
|
||||||
|
- add_function()
|
||||||
|
- sub_function()
|
||||||
|
- mul_function()
|
||||||
|
- pow_function()
|
||||||
|
- div_function()
|
||||||
|
- mod_function()
|
||||||
|
- boolean_xor_function()
|
||||||
|
- boolean_not_function()
|
||||||
|
- bitwise_not_function()
|
||||||
|
- bitwise_or_function()
|
||||||
|
- bitwise_and_function()
|
||||||
|
- bitwise_xor_function()
|
||||||
|
- shift_left_function()
|
||||||
|
- shift_right_function()
|
||||||
|
- concat_function()
|
||||||
|
- is_equal_function(
|
||||||
|
- is_identical_function()
|
||||||
|
- is_not_identical_function()
|
||||||
|
- is_not_equal_function()
|
||||||
|
- is_smaller_function()
|
||||||
|
- is_smaller_or_equal_function(zv
|
||||||
|
- increment_function()
|
||||||
|
- decrement_function()
|
||||||
|
- zend_stream_open()
|
||||||
|
- zend_stream_fixup()
|
||||||
|
- zend_ts_hash_del()
|
||||||
|
- zend_ts_hash_index_del()
|
||||||
|
8. Return type from int to bool in Zend Engine 4.0:
|
||||||
|
- zend_make_printable_zval()
|
||||||
|
- zend_parse_arg_*()
|
||||||
|
- is_zend_mm()
|
||||||
|
- is_zend_ptr()
|
||||||
|
- zend_mm_is_custom_heap()
|
||||||
|
- (*zend_mm_chunk_truncate_t)
|
||||||
|
- (*zend_mm_chunk_extend_t)
|
||||||
|
- zend_bitset_empty()
|
||||||
|
- zend_is_smart_branch()
|
||||||
|
- zend_check_arg_send_type()
|
||||||
|
- zend_verify_const_access()
|
||||||
|
- zend_gdb_register_code()
|
||||||
|
- zend_gdb_present()
|
||||||
|
- _zend_handle_numeric_str(_ex)()
|
||||||
|
- zend_hash_exists_ind()
|
||||||
|
- zend_hash_str_exists_ind()
|
||||||
|
- zend_symtable_exists(_ind)()
|
||||||
|
- zend_symtable_str_exists()
|
||||||
|
- (*zend_encoding_lexer_compatibility_checker)
|
||||||
|
- zend_object_is_true()
|
||||||
|
- i_zend_is_true()
|
||||||
|
- zendi_smart_streq()
|
||||||
|
- zend_stack_is_empty()
|
||||||
|
- zend_ts_hash_exists()
|
||||||
|
- zend_ts_hash_index_exists()
|
||||||
|
9. Argument void to const char* in Zend Engine 4.0:
|
||||||
|
- zend_get_op_array_extension_handle()
|
||||||
|
10. Argument zend_extension to const char* in Zend Engine 4.0:
|
||||||
|
- zend_get_resource_handle()
|
||||||
|
11. Argument const char * to HMODULE in Zend Engine 4.0:
|
||||||
|
- php_win32_image_compatible()
|
||||||
|
12. const char * argument dropped in Zend Engine 4.0:
|
||||||
|
- php_win32_crt_compatible()
|
||||||
|
|
||||||
|
u. Instead of overwriting zend_error_cb extensions with debugging, monitoring
|
||||||
|
use-cases catching Errors/Exceptions are strongly encouraged to use
|
||||||
|
the new error observer API instead.
|
||||||
|
|
||||||
|
Error observering callbacks are guaranteed to be called regardless of
|
||||||
|
the users error_reporting setting or userland error handler return values.
|
||||||
|
|
||||||
|
Register observer callbacks during MINIT of an extension:
|
||||||
|
|
||||||
|
void my_error_observer_cb(int type,
|
||||||
|
const char *error_filename,
|
||||||
|
uint32_t error_lineno,
|
||||||
|
zend_string *message) {
|
||||||
|
}
|
||||||
|
zend_observer_error_register(my_error_observer_cb);
|
||||||
|
|
||||||
|
v. The following APIs have been removed from the Zend Engine:
|
||||||
|
- zend_ts_hash_init_ex(), drop the last argument and use zend_ts_hash_init() instead
|
||||||
|
- zend_hash_init_ex(), drop the last argument and use zend_hash_init() instead
|
||||||
|
- zval_internal_dtor(), use zval_internal_ptr_dtor() instead
|
||||||
|
- zval_dtor_func(), use rc_dtor_func() instead
|
||||||
|
- zval_ptr_dtor_wrapper(), use zval_ptr_dtor() instead
|
||||||
|
- zval_internal_ptr_dtor_wrapper(), use zval_internal_ptr_dtor() instead
|
||||||
|
|
||||||
|
w. The following APIs have been renamed:
|
||||||
|
- _zend_ts_hash_init() to zend_ts_hash_init()
|
||||||
|
|
||||||
|
x. In COMPILE_EXTENDED_STMT mode, a ZEND_EXT_NOP opcode will no longer be
|
||||||
|
generated at the start of a function. Use the new observer APIs or hook
|
||||||
|
into zend_execute_ex instead.
|
||||||
|
|
||||||
|
========================
|
||||||
|
2. Build system changes
|
||||||
|
========================
|
||||||
|
|
||||||
|
a. Abstract
|
||||||
|
1. Symbol HAVE_HASH_EXT is removed and is no longer defined. It should be
|
||||||
|
considered to have hash extension always available since PHP 7.4.
|
||||||
|
|
||||||
|
2. Symbol HAVE_PCRE is removed and is no longer defined. It should be
|
||||||
|
considered to have pcre extension always available since PHP 7.4.
|
||||||
|
|
||||||
|
3. Symbol HAVE_LOCALE_H has been removed and is no longer defined.
|
||||||
|
|
||||||
|
4. --disable-inline-optimization (which actually disabled all compiler
|
||||||
|
optimizations) has been removed. If you wish to build PHP on a host
|
||||||
|
with extremely constrained memory, and compilation fails with an "out
|
||||||
|
of memory" message, add "-O0" to CFLAGS.
|
||||||
|
|
||||||
|
5. build system and provider are displayed in phpinfo from environment:
|
||||||
|
- PHP_BUILD_SYSTEM (default is same as PHP_UNAME)
|
||||||
|
- PHP_BUILD_PROVIDER (no default)
|
||||||
|
|
||||||
|
b. Unix build system changes
|
||||||
|
|
||||||
|
1. --enable-maintainer-zts is renamed --enable-zts for parity with Windows
|
||||||
|
and as recognition that ZTS is not a "maintainer" or experimental
|
||||||
|
feature.
|
||||||
|
|
||||||
|
2. The PHP_CHECK_GCC_ARG() m4 macro has been removed in favor of
|
||||||
|
AX_CHECK_COMPILE_FLAG().
|
||||||
|
|
||||||
|
3. The 6th argument of PHP_ADD_SOURCES_X has been removed.
|
||||||
|
|
||||||
|
4. The 'special-flags' (3rd) argument of PHP_ADD_SOURCES_X are
|
||||||
|
now appended instead of prepended to previous compiler flags.
|
||||||
|
This means compiler flags passed to PHP_NEW_EXTENSION and PHP_ADD_SOURCES
|
||||||
|
are now appended, this allows to disable compiler flags set by Zend/Zend.m4
|
||||||
|
(e.g. disable certain compiler flags enabled by -Wextra)
|
||||||
|
|
||||||
|
c. Windows build system changes
|
||||||
|
|
||||||
|
- The configuration option --enable-crt-debug has been removed. The VC
|
||||||
|
debug heap can now be enabled for debug builds by setting the environment
|
||||||
|
variable PHP_WIN32_DEBUG_HEAP to a non-negative number before PHP process
|
||||||
|
startup.
|
||||||
|
|
||||||
|
========================
|
||||||
|
3. Module changes
|
||||||
|
========================
|
||||||
|
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
The Zend Engine License, Version 2.00
|
||||||
|
Copyright (c) 1999-2006 Zend Technologies Ltd. All rights reserved.
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, is permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following
|
||||||
|
disclaimer in the documentation and/or other materials provided
|
||||||
|
with the distribution.
|
||||||
|
|
||||||
|
3. The names "Zend" and "Zend Engine" must not be used to endorse
|
||||||
|
or promote products derived from this software without prior
|
||||||
|
permission from Zend Technologies Ltd. For written permission,
|
||||||
|
please contact license@zend.com.
|
||||||
|
|
||||||
|
4. Zend Technologies Ltd. may publish revised and/or new versions
|
||||||
|
of the license from time to time. Each version will be given a
|
||||||
|
distinguishing version number.
|
||||||
|
Once covered code has been published under a particular version
|
||||||
|
of the license, you may always continue to use it under the
|
||||||
|
terms of that version. You may also choose to use such covered
|
||||||
|
code under the terms of any subsequent version of the license
|
||||||
|
published by Zend Technologies Ltd. No one other than Zend
|
||||||
|
Technologies Ltd. has the right to modify the terms applicable
|
||||||
|
to covered code created under this License.
|
||||||
|
|
||||||
|
5. Redistributions of any form whatsoever must retain the following
|
||||||
|
acknowledgment:
|
||||||
|
"This product includes the Zend Engine, freely available at
|
||||||
|
http://www.zend.com"
|
||||||
|
|
||||||
|
6. All advertising materials mentioning features or use of this
|
||||||
|
software must display the following acknowledgment:
|
||||||
|
"The Zend Engine is freely available at http://www.zend.com"
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY ZEND TECHNOLOGIES LTD. ``AS IS'' AND
|
||||||
|
ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ZEND
|
||||||
|
TECHNOLOGIES LTD. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||||
|
USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||||
|
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
SUCH DAMAGE.
|
||||||
|
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
#
|
||||||
|
# Zend
|
||||||
|
#
|
||||||
|
|
||||||
|
$(builddir)/zend_language_scanner.lo: $(srcdir)/zend_language_parser.h
|
||||||
|
$(builddir)/zend_ini_scanner.lo: $(srcdir)/zend_ini_parser.h
|
||||||
|
|
||||||
|
$(srcdir)/zend_language_scanner.c: $(srcdir)/zend_language_scanner.l
|
||||||
|
@(cd $(top_srcdir); $(RE2C) $(RE2C_FLAGS) --no-generation-date --case-inverted -cbdFt Zend/zend_language_scanner_defs.h -oZend/zend_language_scanner.c Zend/zend_language_scanner.l)
|
||||||
|
|
||||||
|
$(srcdir)/zend_language_parser.h: $(srcdir)/zend_language_parser.c
|
||||||
|
$(srcdir)/zend_language_parser.c: $(srcdir)/zend_language_parser.y
|
||||||
|
# Tweak zendparse to be exported through ZEND_API. This has to be revisited once
|
||||||
|
# bison supports foreign skeletons and that bison version is used. Read
|
||||||
|
# https://git.savannah.gnu.org/cgit/bison.git/tree/data/README.md for more.
|
||||||
|
@$(YACC) $(YFLAGS) -v -d $(srcdir)/zend_language_parser.y -o $@
|
||||||
|
@$(SED) -e 's,^int zendparse\(.*\),ZEND_API int zendparse\1,g' < $@ \
|
||||||
|
> $@.tmp && \
|
||||||
|
mv $@.tmp $@
|
||||||
|
@$(SED) -e 's,^int zendparse\(.*\),ZEND_API int zendparse\1,g' < $(srcdir)/zend_language_parser.h \
|
||||||
|
> $(srcdir)/zend_language_parser.h.tmp && \
|
||||||
|
mv $(srcdir)/zend_language_parser.h.tmp $(srcdir)/zend_language_parser.h
|
||||||
|
@nlinit=`echo 'nl="'; echo '"'`; eval "$$nlinit"; \
|
||||||
|
$(SED) -e "s/^#ifndef YYTOKENTYPE/#include \"zend.h\"\\$${nl}#ifndef YYTOKENTYPE/" < $(srcdir)/zend_language_parser.h \
|
||||||
|
> $(srcdir)/zend_language_parser.h.tmp && \
|
||||||
|
mv $(srcdir)/zend_language_parser.h.tmp $(srcdir)/zend_language_parser.h
|
||||||
|
|
||||||
|
$(srcdir)/zend_ini_parser.h: $(srcdir)/zend_ini_parser.c
|
||||||
|
$(srcdir)/zend_ini_parser.c: $(srcdir)/zend_ini_parser.y
|
||||||
|
$(YACC) $(YFLAGS) -v -d $(srcdir)/zend_ini_parser.y -o $@
|
||||||
|
|
||||||
|
$(srcdir)/zend_ini_scanner.c: $(srcdir)/zend_ini_scanner.l
|
||||||
|
@(cd $(top_srcdir); $(RE2C) $(RE2C_FLAGS) --no-generation-date --case-inverted -cbdFt Zend/zend_ini_scanner_defs.h -oZend/zend_ini_scanner.c Zend/zend_ini_scanner.l)
|
||||||
|
|
||||||
|
$(builddir)/zend_highlight.lo $(builddir)/zend_compile.lo: $(srcdir)/zend_language_parser.h
|
||||||
|
|
||||||
|
Zend/zend_execute.lo: $(srcdir)/zend_vm_execute.h $(srcdir)/zend_vm_opcodes.h
|
||||||
|
|
@ -0,0 +1,139 @@
|
||||||
|
# Zend Engine
|
||||||
|
|
||||||
|
## Zend memory manager
|
||||||
|
|
||||||
|
### General
|
||||||
|
|
||||||
|
The goal of the new memory manager (available since PHP 5.2) is to reduce memory
|
||||||
|
allocation overhead and speedup memory management.
|
||||||
|
|
||||||
|
### Debugging
|
||||||
|
|
||||||
|
Normal:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sapi/cli/php -r 'leak();'
|
||||||
|
```
|
||||||
|
|
||||||
|
Zend MM disabled:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
USE_ZEND_ALLOC=0 valgrind --leak-check=full sapi/cli/php -r 'leak();'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Shared extensions
|
||||||
|
|
||||||
|
Since PHP 5.3.11 it is possible to prevent shared extensions from unloading so
|
||||||
|
that valgrind can correctly track the memory leaks in shared extensions. For
|
||||||
|
this there is the `ZEND_DONT_UNLOAD_MODULES` environment variable. If set, then
|
||||||
|
`DL_UNLOAD()` is skipped during the shutdown of shared extensions.
|
||||||
|
|
||||||
|
## ZEND_VM
|
||||||
|
|
||||||
|
`ZEND_VM` architecture allows specializing opcode handlers according to
|
||||||
|
`op_type` fields and using different execution methods (call threading, switch
|
||||||
|
threading and direct threading). As a result ZE2 got more than 20% speedup on
|
||||||
|
raw PHP code execution (with specialized executor and direct threading execution
|
||||||
|
method). As in most PHP applications raw execution speed isn't the limiting
|
||||||
|
factor but system calls and database calls are, your mileage with this patch
|
||||||
|
will vary.
|
||||||
|
|
||||||
|
Most parts of the old zend_execute.c go into `zend_vm_def.h`. Here you can find
|
||||||
|
opcode handlers and helpers. The typical opcode handler template looks like
|
||||||
|
this:
|
||||||
|
|
||||||
|
```c
|
||||||
|
ZEND_VM_HANDLER(<OPCODE-NUMBER>, <OPCODE>, <OP1_TYPES>, <OP2_TYPES>)
|
||||||
|
{
|
||||||
|
<HANDLER'S CODE>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`<OPCODE-NUMBER>` is a opcode number (0, 1, ...)
|
||||||
|
`<OPCODE>` is an opcode name (ZEN_NOP, ZEND_ADD, :)
|
||||||
|
`<OP1_TYPES>` and `<OP2_TYPES>` are masks for allowed operand op_types.
|
||||||
|
Specializer will generate code only for defined combination of types. You can
|
||||||
|
use any combination of the following op_types UNUSED, CONST, VAR, TMP and CV
|
||||||
|
also you can use ANY mask to disable specialization according operand's op_type.
|
||||||
|
`<HANDLER'S CODE>` is a handler's code itself. For most handlers it stills the
|
||||||
|
same as in old `zend_execute.c`, but now it uses macros to access opcode
|
||||||
|
operands and some internal executor data.
|
||||||
|
|
||||||
|
You can see the conformity of new macros to old code in the following list:
|
||||||
|
|
||||||
|
```c
|
||||||
|
EXECUTE_DATA
|
||||||
|
execute_data
|
||||||
|
ZEND_VM_DISPATCH_TO_HANDLER(<OP>)
|
||||||
|
return <OP>_helper(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)
|
||||||
|
ZEND_VM_DISPATCH_TO_HELPER(<NAME>)
|
||||||
|
return <NAME>(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)
|
||||||
|
ZEND_VM_DISPATCH_TO_HELPER_EX(<NAME>,<PARAM>,<VAL>)
|
||||||
|
return <NAME>(<VAL>, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)
|
||||||
|
ZEND_VM_CONTINUE()
|
||||||
|
return 0
|
||||||
|
ZEND_VM_NEXT_OPCODE()
|
||||||
|
NEXT_OPCODE()
|
||||||
|
ZEND_VM_SET_OPCODE(<TARGET>
|
||||||
|
SET_OPCODE(<TARGET>
|
||||||
|
ZEND_VM_INC_OPCODE()
|
||||||
|
INC_OPCOD()
|
||||||
|
ZEND_VM_RETURN_FROM_EXECUTE_LOOP()
|
||||||
|
RETURN_FROM_EXECUTE_LOOP()
|
||||||
|
ZEND_VM_C_LABEL(<LABEL>):
|
||||||
|
<LABEL>:
|
||||||
|
ZEND_VM_C_GOTO(<LABEL>)
|
||||||
|
goto <LABEL>
|
||||||
|
OP<X>_TYPE
|
||||||
|
opline->op<X>.op_type
|
||||||
|
GET_OP<X>_ZVAL_PTR(<TYPE>)
|
||||||
|
get_zval_ptr(&opline->op<X>, EX(Ts), &free_op<X>, <TYPE>)
|
||||||
|
GET_OP<X>_ZVAL_PTR_PTR(<TYPE>)
|
||||||
|
get_zval_ptr_ptr(&opline->op<X>, EX(Ts), &free_op<X>, <TYPE>)
|
||||||
|
GET_OP<X>_OBJ_ZVAL_PTR(<TYPE>)
|
||||||
|
get_obj_zval_ptr(&opline->op<X>, EX(Ts), &free_op<X>, <TYPE>)
|
||||||
|
GET_OP<X>_OBJ_ZVAL_PTR_PTR(<TYPE>)
|
||||||
|
get_obj_zval_ptr_ptr(&opline->op<X>, EX(Ts), &free_op<X>, <TYPE>)
|
||||||
|
IS_OP<X>_TMP_FREE()
|
||||||
|
IS_TMP_FREE(free_op<X>)
|
||||||
|
FREE_OP<X>()
|
||||||
|
FREE_OP(free_op<X>)
|
||||||
|
FREE_OP<X>_IF_VAR()
|
||||||
|
FREE_VAR(free_op<X>)
|
||||||
|
FREE_OP<X>_VAR_PTR()
|
||||||
|
FREE_VAR_PTR(free_op<X>)
|
||||||
|
```
|
||||||
|
|
||||||
|
Executor's helpers can be defined without parameters or with one parameter. This
|
||||||
|
is done with the following constructs:
|
||||||
|
|
||||||
|
```c
|
||||||
|
ZEND_VM_HELPER(<HELPER-NAME>, <OP1_TYPES>, <OP2_TYPES>)
|
||||||
|
{
|
||||||
|
<HELPER'S CODE>
|
||||||
|
}
|
||||||
|
|
||||||
|
ZEND_VM_HELPER_EX(<HELPER-NAME>, <OP1_TYPES>, <OP2_TYPES>, <PARAM_SPEC>)
|
||||||
|
{
|
||||||
|
<HELPER'S CODE>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Executor's code is generated by PHP script zend_vm_gen.php it uses
|
||||||
|
`zend_vm_def.h` and `zend_vm_execute.skl` as input and produces
|
||||||
|
`zend_vm_opcodes.h` and `zend_vm_execute.h`. The first file is a list of opcode
|
||||||
|
definitions. It is included from `zend_compile.h`. The second one is an executor
|
||||||
|
code itself. It is included from `zend_execute.c`.
|
||||||
|
|
||||||
|
`zend_vm_gen.php` can produce different kind of executors. You can select
|
||||||
|
different opcode threading model using `--with-vm-kind=CALL|SWITCH|GOTO`. You
|
||||||
|
can disable opcode specialization using `--without-specializer`. You can include
|
||||||
|
or exclude old executor together with specialized one using
|
||||||
|
`--without-old-executor`. At last you can debug executor using original
|
||||||
|
`zend_vm_def.h` or generated file `zend_vm_execute.h`. Debugging with original
|
||||||
|
file requires `--with-lines` option. By default ZE2 uses the following command
|
||||||
|
to generate executor:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
php zend_vm_gen.php --with-vm-kind=CALL
|
||||||
|
```
|
||||||
|
|
@ -0,0 +1,346 @@
|
||||||
|
dnl This file contains Zend specific autoconf macros.
|
||||||
|
|
||||||
|
dnl
|
||||||
|
dnl ZEND_CHECK_FLOAT_PRECISION
|
||||||
|
dnl
|
||||||
|
dnl x87 floating point internal precision control checks
|
||||||
|
dnl See: http://wiki.php.net/rfc/rounding
|
||||||
|
dnl
|
||||||
|
AC_DEFUN([ZEND_CHECK_FLOAT_PRECISION],[
|
||||||
|
AC_MSG_CHECKING([for usable _FPU_SETCW])
|
||||||
|
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
|
||||||
|
#include <fpu_control.h>
|
||||||
|
]],[[
|
||||||
|
fpu_control_t fpu_oldcw, fpu_cw;
|
||||||
|
volatile double result;
|
||||||
|
double a = 2877.0;
|
||||||
|
volatile double b = 1000000.0;
|
||||||
|
|
||||||
|
_FPU_GETCW(fpu_oldcw);
|
||||||
|
fpu_cw = (fpu_oldcw & ~_FPU_EXTENDED & ~_FPU_SINGLE) | _FPU_DOUBLE;
|
||||||
|
_FPU_SETCW(fpu_cw);
|
||||||
|
result = a / b;
|
||||||
|
_FPU_SETCW(fpu_oldcw);
|
||||||
|
]])],[ac_cfp_have__fpu_setcw=yes],[ac_cfp_have__fpu_setcw=no])
|
||||||
|
if test "$ac_cfp_have__fpu_setcw" = "yes" ; then
|
||||||
|
AC_DEFINE(HAVE__FPU_SETCW, 1, [whether _FPU_SETCW is present and usable])
|
||||||
|
AC_MSG_RESULT(yes)
|
||||||
|
else
|
||||||
|
AC_MSG_RESULT(no)
|
||||||
|
fi
|
||||||
|
|
||||||
|
AC_MSG_CHECKING([for usable fpsetprec])
|
||||||
|
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
|
||||||
|
#include <machine/ieeefp.h>
|
||||||
|
]],[[
|
||||||
|
fp_prec_t fpu_oldprec;
|
||||||
|
volatile double result;
|
||||||
|
double a = 2877.0;
|
||||||
|
volatile double b = 1000000.0;
|
||||||
|
|
||||||
|
fpu_oldprec = fpgetprec();
|
||||||
|
fpsetprec(FP_PD);
|
||||||
|
result = a / b;
|
||||||
|
fpsetprec(fpu_oldprec);
|
||||||
|
]])], [ac_cfp_have_fpsetprec=yes], [ac_cfp_have_fpsetprec=no])
|
||||||
|
if test "$ac_cfp_have_fpsetprec" = "yes" ; then
|
||||||
|
AC_DEFINE(HAVE_FPSETPREC, 1, [whether fpsetprec is present and usable])
|
||||||
|
AC_MSG_RESULT(yes)
|
||||||
|
else
|
||||||
|
AC_MSG_RESULT(no)
|
||||||
|
fi
|
||||||
|
|
||||||
|
AC_MSG_CHECKING([for usable _controlfp])
|
||||||
|
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
|
||||||
|
#include <float.h>
|
||||||
|
]],[[
|
||||||
|
unsigned int fpu_oldcw;
|
||||||
|
volatile double result;
|
||||||
|
double a = 2877.0;
|
||||||
|
volatile double b = 1000000.0;
|
||||||
|
|
||||||
|
fpu_oldcw = _controlfp(0, 0);
|
||||||
|
_controlfp(_PC_53, _MCW_PC);
|
||||||
|
result = a / b;
|
||||||
|
_controlfp(fpu_oldcw, _MCW_PC);
|
||||||
|
]])], [ac_cfp_have__controlfp=yes], [ac_cfp_have__controlfp=no])
|
||||||
|
if test "$ac_cfp_have__controlfp" = "yes" ; then
|
||||||
|
AC_DEFINE(HAVE__CONTROLFP, 1, [whether _controlfp is present usable])
|
||||||
|
AC_MSG_RESULT(yes)
|
||||||
|
else
|
||||||
|
AC_MSG_RESULT(no)
|
||||||
|
fi
|
||||||
|
|
||||||
|
AC_MSG_CHECKING([for usable _controlfp_s])
|
||||||
|
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
|
||||||
|
#include <float.h>
|
||||||
|
]],[[
|
||||||
|
unsigned int fpu_oldcw, fpu_cw;
|
||||||
|
volatile double result;
|
||||||
|
double a = 2877.0;
|
||||||
|
volatile double b = 1000000.0;
|
||||||
|
|
||||||
|
_controlfp_s(&fpu_cw, 0, 0);
|
||||||
|
fpu_oldcw = fpu_cw;
|
||||||
|
_controlfp_s(&fpu_cw, _PC_53, _MCW_PC);
|
||||||
|
result = a / b;
|
||||||
|
_controlfp_s(&fpu_cw, fpu_oldcw, _MCW_PC);
|
||||||
|
]])], [ac_cfp_have__controlfp_s=yes], [ac_cfp_have__controlfp_s=no])
|
||||||
|
if test "$ac_cfp_have__controlfp_s" = "yes" ; then
|
||||||
|
AC_DEFINE(HAVE__CONTROLFP_S, 1, [whether _controlfp_s is present and usable])
|
||||||
|
AC_MSG_RESULT(yes)
|
||||||
|
else
|
||||||
|
AC_MSG_RESULT(no)
|
||||||
|
fi
|
||||||
|
|
||||||
|
AC_MSG_CHECKING([whether FPU control word can be manipulated by inline assembler])
|
||||||
|
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
|
||||||
|
/* nothing */
|
||||||
|
]],[[
|
||||||
|
unsigned int oldcw, cw;
|
||||||
|
volatile double result;
|
||||||
|
double a = 2877.0;
|
||||||
|
volatile double b = 1000000.0;
|
||||||
|
|
||||||
|
__asm__ __volatile__ ("fnstcw %0" : "=m" (*&oldcw));
|
||||||
|
cw = (oldcw & ~0x0 & ~0x300) | 0x200;
|
||||||
|
__asm__ __volatile__ ("fldcw %0" : : "m" (*&cw));
|
||||||
|
|
||||||
|
result = a / b;
|
||||||
|
|
||||||
|
__asm__ __volatile__ ("fldcw %0" : : "m" (*&oldcw));
|
||||||
|
]])], [ac_cfp_have_fpu_inline_asm_x86=yes], [ac_cfp_have_fpu_inline_asm_x86=no])
|
||||||
|
if test "$ac_cfp_have_fpu_inline_asm_x86" = "yes" ; then
|
||||||
|
AC_DEFINE(HAVE_FPU_INLINE_ASM_X86, 1, [whether FPU control word can be manipulated by inline assembler])
|
||||||
|
AC_MSG_RESULT(yes)
|
||||||
|
else
|
||||||
|
AC_MSG_RESULT(no)
|
||||||
|
fi
|
||||||
|
])
|
||||||
|
|
||||||
|
dnl
|
||||||
|
dnl LIBZEND_BASIC_CHECKS
|
||||||
|
dnl
|
||||||
|
dnl Basic checks specific for the Zend engine library.
|
||||||
|
dnl
|
||||||
|
AC_DEFUN([LIBZEND_BASIC_CHECKS],[
|
||||||
|
AC_REQUIRE([AC_PROG_CC])
|
||||||
|
|
||||||
|
AC_CHECK_HEADERS([cpuid.h])
|
||||||
|
|
||||||
|
dnl
|
||||||
|
dnl LIBZEND_DLSYM_CHECK
|
||||||
|
dnl
|
||||||
|
dnl Ugly hack to check if dlsym() requires a leading underscore in symbol name.
|
||||||
|
dnl
|
||||||
|
AC_DEFUN([LIBZEND_DLSYM_CHECK],[
|
||||||
|
AC_MSG_CHECKING([whether dlsym() requires a leading underscore in symbol names])
|
||||||
|
_LT_AC_TRY_DLOPEN_SELF([
|
||||||
|
AC_MSG_RESULT(no)
|
||||||
|
], [
|
||||||
|
AC_MSG_RESULT(yes)
|
||||||
|
AC_DEFINE(DLSYM_NEEDS_UNDERSCORE, 1, [Define if dlsym() requires a leading underscore in symbol names. ])
|
||||||
|
], [
|
||||||
|
AC_MSG_RESULT(no)
|
||||||
|
], [])
|
||||||
|
])
|
||||||
|
|
||||||
|
dnl Checks for library functions.
|
||||||
|
AC_CHECK_FUNCS(getpid kill sigsetjmp)
|
||||||
|
|
||||||
|
ZEND_CHECK_FLOAT_PRECISION
|
||||||
|
])
|
||||||
|
|
||||||
|
dnl
|
||||||
|
dnl LIBZEND_OTHER_CHECKS
|
||||||
|
dnl
|
||||||
|
AC_DEFUN([LIBZEND_OTHER_CHECKS],[
|
||||||
|
|
||||||
|
AC_MSG_CHECKING(whether to enable thread-safety)
|
||||||
|
AC_MSG_RESULT($ZEND_ZTS)
|
||||||
|
|
||||||
|
AC_MSG_CHECKING(whether to enable Zend debugging)
|
||||||
|
AC_MSG_RESULT($ZEND_DEBUG)
|
||||||
|
|
||||||
|
if test "$ZEND_DEBUG" = "yes"; then
|
||||||
|
AC_DEFINE(ZEND_DEBUG,1,[ ])
|
||||||
|
echo " $CFLAGS" | grep ' -g' >/dev/null || DEBUG_CFLAGS="-g"
|
||||||
|
if test "$CFLAGS" = "-g -O2"; then
|
||||||
|
CFLAGS=-g
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
AC_DEFINE(ZEND_DEBUG,0,[ ])
|
||||||
|
fi
|
||||||
|
|
||||||
|
test -n "$GCC" && CFLAGS="-Wall -Wextra -Wno-strict-aliasing -Wno-implicit-fallthrough -Wno-unused-parameter -Wno-sign-compare $CFLAGS"
|
||||||
|
dnl Check if compiler supports -Wno-clobbered (only GCC)
|
||||||
|
AX_CHECK_COMPILE_FLAG([-Wno-clobbered], CFLAGS="-Wno-clobbered $CFLAGS", , [-Werror])
|
||||||
|
|
||||||
|
test -n "$DEBUG_CFLAGS" && CFLAGS="$CFLAGS $DEBUG_CFLAGS"
|
||||||
|
|
||||||
|
if test "$ZEND_ZTS" = "yes"; then
|
||||||
|
AC_DEFINE(ZTS,1,[ ])
|
||||||
|
CFLAGS="$CFLAGS -DZTS"
|
||||||
|
fi
|
||||||
|
|
||||||
|
AC_C_INLINE
|
||||||
|
|
||||||
|
AC_MSG_CHECKING(target system is Darwin)
|
||||||
|
if echo "$target" | grep "darwin" > /dev/null; then
|
||||||
|
AC_DEFINE([DARWIN], 1, [Define if the target system is darwin])
|
||||||
|
AC_MSG_RESULT(yes)
|
||||||
|
else
|
||||||
|
AC_MSG_RESULT(no)
|
||||||
|
fi
|
||||||
|
|
||||||
|
dnl Test and set the alignment define for ZEND_MM. This also does the
|
||||||
|
dnl logarithmic test for ZEND_MM.
|
||||||
|
AC_MSG_CHECKING(for MM alignment and log values)
|
||||||
|
|
||||||
|
AC_RUN_IFELSE([AC_LANG_SOURCE([[
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
typedef union _mm_align_test {
|
||||||
|
void *ptr;
|
||||||
|
double dbl;
|
||||||
|
long lng;
|
||||||
|
} mm_align_test;
|
||||||
|
|
||||||
|
#if (defined (__GNUC__) && __GNUC__ >= 2)
|
||||||
|
#define ZEND_MM_ALIGNMENT (__alignof__ (mm_align_test))
|
||||||
|
#else
|
||||||
|
#define ZEND_MM_ALIGNMENT (sizeof(mm_align_test))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
int i = ZEND_MM_ALIGNMENT;
|
||||||
|
int zeros = 0;
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
while (i & ~0x1) {
|
||||||
|
zeros++;
|
||||||
|
i = i >> 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fp = fopen("conftest.zend", "w");
|
||||||
|
fprintf(fp, "%d %d\n", ZEND_MM_ALIGNMENT, zeros);
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
]])], [
|
||||||
|
LIBZEND_MM_ALIGN=`cat conftest.zend | cut -d ' ' -f 1`
|
||||||
|
LIBZEND_MM_ALIGN_LOG2=`cat conftest.zend | cut -d ' ' -f 2`
|
||||||
|
AC_DEFINE_UNQUOTED(ZEND_MM_ALIGNMENT, $LIBZEND_MM_ALIGN, [ ])
|
||||||
|
AC_DEFINE_UNQUOTED(ZEND_MM_ALIGNMENT_LOG2, $LIBZEND_MM_ALIGN_LOG2, [ ])
|
||||||
|
], [], [
|
||||||
|
dnl Cross compilation needs something here.
|
||||||
|
LIBZEND_MM_ALIGN=8
|
||||||
|
])
|
||||||
|
|
||||||
|
AC_MSG_RESULT(done)
|
||||||
|
|
||||||
|
AC_CHECK_FUNCS(mremap)
|
||||||
|
|
||||||
|
AC_ARG_ENABLE([zend-signals],
|
||||||
|
[AS_HELP_STRING([--disable-zend-signals],
|
||||||
|
[whether to enable zend signal handling])],
|
||||||
|
[ZEND_SIGNALS=$enableval],
|
||||||
|
[ZEND_SIGNALS=yes])
|
||||||
|
|
||||||
|
AC_CHECK_FUNCS([sigaction], [], [
|
||||||
|
ZEND_SIGNALS=no
|
||||||
|
])
|
||||||
|
if test "$ZEND_SIGNALS" = "yes"; then
|
||||||
|
AC_DEFINE(ZEND_SIGNALS, 1, [Use zend signal handling])
|
||||||
|
CFLAGS="$CFLAGS -DZEND_SIGNALS"
|
||||||
|
fi
|
||||||
|
|
||||||
|
AC_MSG_CHECKING(whether to enable zend signal handling)
|
||||||
|
AC_MSG_RESULT($ZEND_SIGNALS)
|
||||||
|
|
||||||
|
])
|
||||||
|
|
||||||
|
AC_MSG_CHECKING(whether /dev/urandom exists)
|
||||||
|
if test -r "/dev/urandom" && test -c "/dev/urandom"; then
|
||||||
|
AC_DEFINE([HAVE_DEV_URANDOM], 1, [Define if the target system has /dev/urandom device])
|
||||||
|
AC_MSG_RESULT(yes)
|
||||||
|
else
|
||||||
|
AC_MSG_RESULT(no)
|
||||||
|
fi
|
||||||
|
|
||||||
|
AC_ARG_ENABLE([gcc-global-regs],
|
||||||
|
[AS_HELP_STRING([--disable-gcc-global-regs],
|
||||||
|
[whether to enable GCC global register variables])],
|
||||||
|
[ZEND_GCC_GLOBAL_REGS=$enableval],
|
||||||
|
[ZEND_GCC_GLOBAL_REGS=yes])
|
||||||
|
|
||||||
|
AC_MSG_CHECKING(for global register variables support)
|
||||||
|
if test "$ZEND_GCC_GLOBAL_REGS" != "no"; then
|
||||||
|
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
# define ZEND_GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__)
|
||||||
|
#else
|
||||||
|
# define ZEND_GCC_VERSION 0
|
||||||
|
#endif
|
||||||
|
#if defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(i386)
|
||||||
|
# define ZEND_VM_FP_GLOBAL_REG "%esi"
|
||||||
|
# define ZEND_VM_IP_GLOBAL_REG "%edi"
|
||||||
|
#elif defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(__x86_64__)
|
||||||
|
# define ZEND_VM_FP_GLOBAL_REG "%r14"
|
||||||
|
# define ZEND_VM_IP_GLOBAL_REG "%r15"
|
||||||
|
#elif defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(__powerpc64__)
|
||||||
|
# define ZEND_VM_FP_GLOBAL_REG "r28"
|
||||||
|
# define ZEND_VM_IP_GLOBAL_REG "r29"
|
||||||
|
#elif defined(__IBMC__) && ZEND_GCC_VERSION >= 4002 && defined(__powerpc64__)
|
||||||
|
# define ZEND_VM_FP_GLOBAL_REG "r28"
|
||||||
|
# define ZEND_VM_IP_GLOBAL_REG "r29"
|
||||||
|
#elif defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(__aarch64__)
|
||||||
|
# define ZEND_VM_FP_GLOBAL_REG "x27"
|
||||||
|
# define ZEND_VM_IP_GLOBAL_REG "x28"
|
||||||
|
#else
|
||||||
|
# error "global register variables are not supported"
|
||||||
|
#endif
|
||||||
|
typedef int (*opcode_handler_t)(void);
|
||||||
|
register void *FP __asm__(ZEND_VM_FP_GLOBAL_REG);
|
||||||
|
register const opcode_handler_t *IP __asm__(ZEND_VM_IP_GLOBAL_REG);
|
||||||
|
int emu(const opcode_handler_t *ip, void *fp) {
|
||||||
|
const opcode_handler_t *orig_ip = IP;
|
||||||
|
void *orig_fp = FP;
|
||||||
|
IP = ip;
|
||||||
|
FP = fp;
|
||||||
|
while ((*ip)());
|
||||||
|
FP = orig_fp;
|
||||||
|
IP = orig_ip;
|
||||||
|
}
|
||||||
|
]], [[
|
||||||
|
]])], [
|
||||||
|
ZEND_GCC_GLOBAL_REGS=yes
|
||||||
|
], [
|
||||||
|
ZEND_GCC_GLOBAL_REGS=no
|
||||||
|
])
|
||||||
|
fi
|
||||||
|
if test "$ZEND_GCC_GLOBAL_REGS" = "yes"; then
|
||||||
|
AC_DEFINE([HAVE_GCC_GLOBAL_REGS], 1, [Define if the target system has support for global register variables])
|
||||||
|
else
|
||||||
|
HAVE_GCC_GLOBAL_REGS=no
|
||||||
|
fi
|
||||||
|
AC_MSG_RESULT($ZEND_GCC_GLOBAL_REGS)
|
||||||
|
|
||||||
|
dnl Check whether __cpuid_count is available.
|
||||||
|
AC_CACHE_CHECK(whether __cpuid_count is available, ac_cv_cpuid_count_available, [
|
||||||
|
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
|
||||||
|
#include <cpuid.h>
|
||||||
|
]], [[
|
||||||
|
unsigned eax, ebx, ecx, edx;
|
||||||
|
__cpuid_count(0, 0, eax, ebx, ecx, edx);
|
||||||
|
]])], [
|
||||||
|
ac_cv_cpuid_count_available=yes
|
||||||
|
], [
|
||||||
|
ac_cv_cpuid_count_available=no
|
||||||
|
])])
|
||||||
|
if test "$ac_cv_cpuid_count_available" = "yes"; then
|
||||||
|
AC_DEFINE([HAVE_CPUID_COUNT], 1, [whether __cpuid_count is available])
|
||||||
|
fi
|
||||||
|
|
@ -0,0 +1,422 @@
|
||||||
|
<?php
|
||||||
|
if (function_exists("date_default_timezone_set")) {
|
||||||
|
date_default_timezone_set("UTC");
|
||||||
|
}
|
||||||
|
|
||||||
|
function simple() {
|
||||||
|
$a = 0;
|
||||||
|
for ($i = 0; $i < 1000000; $i++)
|
||||||
|
$a++;
|
||||||
|
|
||||||
|
$thisisanotherlongname = 0;
|
||||||
|
for ($thisisalongname = 0; $thisisalongname < 1000000; $thisisalongname++)
|
||||||
|
$thisisanotherlongname++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****/
|
||||||
|
|
||||||
|
function simplecall() {
|
||||||
|
for ($i = 0; $i < 1000000; $i++)
|
||||||
|
strlen("hallo");
|
||||||
|
}
|
||||||
|
|
||||||
|
/****/
|
||||||
|
|
||||||
|
function hallo($a) {
|
||||||
|
}
|
||||||
|
|
||||||
|
function simpleucall() {
|
||||||
|
for ($i = 0; $i < 1000000; $i++)
|
||||||
|
hallo("hallo");
|
||||||
|
}
|
||||||
|
|
||||||
|
/****/
|
||||||
|
|
||||||
|
function simpleudcall() {
|
||||||
|
for ($i = 0; $i < 1000000; $i++)
|
||||||
|
hallo2("hallo");
|
||||||
|
}
|
||||||
|
|
||||||
|
function hallo2($a) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/****/
|
||||||
|
|
||||||
|
function mandel() {
|
||||||
|
$w1=50;
|
||||||
|
$h1=150;
|
||||||
|
$recen=-.45;
|
||||||
|
$imcen=0.0;
|
||||||
|
$r=0.7;
|
||||||
|
$s=0; $rec=0; $imc=0; $re=0; $im=0; $re2=0; $im2=0;
|
||||||
|
$x=0; $y=0; $w2=0; $h2=0; $color=0;
|
||||||
|
$s=2*$r/$w1;
|
||||||
|
$w2=40;
|
||||||
|
$h2=12;
|
||||||
|
for ($y=0 ; $y<=$w1; $y=$y+1) {
|
||||||
|
$imc=$s*($y-$h2)+$imcen;
|
||||||
|
for ($x=0 ; $x<=$h1; $x=$x+1) {
|
||||||
|
$rec=$s*($x-$w2)+$recen;
|
||||||
|
$re=$rec;
|
||||||
|
$im=$imc;
|
||||||
|
$color=1000;
|
||||||
|
$re2=$re*$re;
|
||||||
|
$im2=$im*$im;
|
||||||
|
while( ((($re2+$im2)<1000000) && $color>0)) {
|
||||||
|
$im=$re*$im*2+$imc;
|
||||||
|
$re=$re2-$im2+$rec;
|
||||||
|
$re2=$re*$re;
|
||||||
|
$im2=$im*$im;
|
||||||
|
$color=$color-1;
|
||||||
|
}
|
||||||
|
if ( $color==0 ) {
|
||||||
|
print "_";
|
||||||
|
} else {
|
||||||
|
print "#";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
print "<br>";
|
||||||
|
flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/****/
|
||||||
|
|
||||||
|
function mandel2() {
|
||||||
|
$b = " .:,;!/>)|&IH%*#";
|
||||||
|
//float r, i, z, Z, t, c, C;
|
||||||
|
for ($y=30; printf("\n"), $C = $y*0.1 - 1.5, $y--;){
|
||||||
|
for ($x=0; $c = $x*0.04 - 2, $z=0, $Z=0, $x++ < 75;){
|
||||||
|
for ($r=$c, $i=$C, $k=0; $t = $z*$z - $Z*$Z + $r, $Z = 2*$z*$Z + $i, $z=$t, $k<5000; $k++)
|
||||||
|
if ($z*$z + $Z*$Z > 500000) break;
|
||||||
|
echo $b[$k%16];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/****/
|
||||||
|
|
||||||
|
function Ack($m, $n){
|
||||||
|
if($m == 0) return $n+1;
|
||||||
|
if($n == 0) return Ack($m-1, 1);
|
||||||
|
return Ack($m - 1, Ack($m, ($n - 1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
function ackermann($n) {
|
||||||
|
$r = Ack(3,$n);
|
||||||
|
print "Ack(3,$n): $r\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/****/
|
||||||
|
|
||||||
|
function ary($n) {
|
||||||
|
for ($i=0; $i<$n; $i++) {
|
||||||
|
$X[$i] = $i;
|
||||||
|
}
|
||||||
|
for ($i=$n-1; $i>=0; $i--) {
|
||||||
|
$Y[$i] = $X[$i];
|
||||||
|
}
|
||||||
|
$last = $n-1;
|
||||||
|
print "$Y[$last]\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/****/
|
||||||
|
|
||||||
|
function ary2($n) {
|
||||||
|
for ($i=0; $i<$n;) {
|
||||||
|
$X[$i] = $i; ++$i;
|
||||||
|
$X[$i] = $i; ++$i;
|
||||||
|
$X[$i] = $i; ++$i;
|
||||||
|
$X[$i] = $i; ++$i;
|
||||||
|
$X[$i] = $i; ++$i;
|
||||||
|
|
||||||
|
$X[$i] = $i; ++$i;
|
||||||
|
$X[$i] = $i; ++$i;
|
||||||
|
$X[$i] = $i; ++$i;
|
||||||
|
$X[$i] = $i; ++$i;
|
||||||
|
$X[$i] = $i; ++$i;
|
||||||
|
}
|
||||||
|
for ($i=$n-1; $i>=0;) {
|
||||||
|
$Y[$i] = $X[$i]; --$i;
|
||||||
|
$Y[$i] = $X[$i]; --$i;
|
||||||
|
$Y[$i] = $X[$i]; --$i;
|
||||||
|
$Y[$i] = $X[$i]; --$i;
|
||||||
|
$Y[$i] = $X[$i]; --$i;
|
||||||
|
|
||||||
|
$Y[$i] = $X[$i]; --$i;
|
||||||
|
$Y[$i] = $X[$i]; --$i;
|
||||||
|
$Y[$i] = $X[$i]; --$i;
|
||||||
|
$Y[$i] = $X[$i]; --$i;
|
||||||
|
$Y[$i] = $X[$i]; --$i;
|
||||||
|
}
|
||||||
|
$last = $n-1;
|
||||||
|
print "$Y[$last]\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/****/
|
||||||
|
|
||||||
|
function ary3($n) {
|
||||||
|
for ($i=0; $i<$n; $i++) {
|
||||||
|
$X[$i] = $i + 1;
|
||||||
|
$Y[$i] = 0;
|
||||||
|
}
|
||||||
|
for ($k=0; $k<1000; $k++) {
|
||||||
|
for ($i=$n-1; $i>=0; $i--) {
|
||||||
|
$Y[$i] += $X[$i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$last = $n-1;
|
||||||
|
print "$Y[0] $Y[$last]\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/****/
|
||||||
|
|
||||||
|
function fibo_r($n){
|
||||||
|
return(($n < 2) ? 1 : fibo_r($n - 2) + fibo_r($n - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
function fibo($n) {
|
||||||
|
$r = fibo_r($n);
|
||||||
|
print "$r\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/****/
|
||||||
|
|
||||||
|
function hash1($n) {
|
||||||
|
for ($i = 1; $i <= $n; $i++) {
|
||||||
|
$X[dechex($i)] = $i;
|
||||||
|
}
|
||||||
|
$c = 0;
|
||||||
|
for ($i = $n; $i > 0; $i--) {
|
||||||
|
if ($X[dechex($i)]) { $c++; }
|
||||||
|
}
|
||||||
|
print "$c\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/****/
|
||||||
|
|
||||||
|
function hash2($n) {
|
||||||
|
for ($i = 0; $i < $n; $i++) {
|
||||||
|
$hash1["foo_$i"] = $i;
|
||||||
|
$hash2["foo_$i"] = 0;
|
||||||
|
}
|
||||||
|
for ($i = $n; $i > 0; $i--) {
|
||||||
|
foreach($hash1 as $key => $value) $hash2[$key] += $value;
|
||||||
|
}
|
||||||
|
$first = "foo_0";
|
||||||
|
$last = "foo_".($n-1);
|
||||||
|
print "$hash1[$first] $hash1[$last] $hash2[$first] $hash2[$last]\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/****/
|
||||||
|
|
||||||
|
function gen_random ($n) {
|
||||||
|
global $LAST;
|
||||||
|
return( ($n * ($LAST = ($LAST * IA + IC) % IM)) / IM );
|
||||||
|
}
|
||||||
|
|
||||||
|
function heapsort_r($n, &$ra) {
|
||||||
|
$l = ($n >> 1) + 1;
|
||||||
|
$ir = $n;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
if ($l > 1) {
|
||||||
|
$rra = $ra[--$l];
|
||||||
|
} else {
|
||||||
|
$rra = $ra[$ir];
|
||||||
|
$ra[$ir] = $ra[1];
|
||||||
|
if (--$ir == 1) {
|
||||||
|
$ra[1] = $rra;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$i = $l;
|
||||||
|
$j = $l << 1;
|
||||||
|
while ($j <= $ir) {
|
||||||
|
if (($j < $ir) && ($ra[$j] < $ra[$j+1])) {
|
||||||
|
$j++;
|
||||||
|
}
|
||||||
|
if ($rra < $ra[$j]) {
|
||||||
|
$ra[$i] = $ra[$j];
|
||||||
|
$j += ($i = $j);
|
||||||
|
} else {
|
||||||
|
$j = $ir + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$ra[$i] = $rra;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function heapsort($N) {
|
||||||
|
global $LAST;
|
||||||
|
|
||||||
|
define("IM", 139968);
|
||||||
|
define("IA", 3877);
|
||||||
|
define("IC", 29573);
|
||||||
|
|
||||||
|
$LAST = 42;
|
||||||
|
for ($i=1; $i<=$N; $i++) {
|
||||||
|
$ary[$i] = gen_random(1);
|
||||||
|
}
|
||||||
|
heapsort_r($N, $ary);
|
||||||
|
printf("%.10f\n", $ary[$N]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****/
|
||||||
|
|
||||||
|
function mkmatrix ($rows, $cols) {
|
||||||
|
$count = 1;
|
||||||
|
$mx = array();
|
||||||
|
for ($i=0; $i<$rows; $i++) {
|
||||||
|
for ($j=0; $j<$cols; $j++) {
|
||||||
|
$mx[$i][$j] = $count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return($mx);
|
||||||
|
}
|
||||||
|
|
||||||
|
function mmult ($rows, $cols, $m1, $m2) {
|
||||||
|
$m3 = array();
|
||||||
|
for ($i=0; $i<$rows; $i++) {
|
||||||
|
for ($j=0; $j<$cols; $j++) {
|
||||||
|
$x = 0;
|
||||||
|
for ($k=0; $k<$cols; $k++) {
|
||||||
|
$x += $m1[$i][$k] * $m2[$k][$j];
|
||||||
|
}
|
||||||
|
$m3[$i][$j] = $x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return($m3);
|
||||||
|
}
|
||||||
|
|
||||||
|
function matrix($n) {
|
||||||
|
$SIZE = 30;
|
||||||
|
$m1 = mkmatrix($SIZE, $SIZE);
|
||||||
|
$m2 = mkmatrix($SIZE, $SIZE);
|
||||||
|
while ($n--) {
|
||||||
|
$mm = mmult($SIZE, $SIZE, $m1, $m2);
|
||||||
|
}
|
||||||
|
print "{$mm[0][0]} {$mm[2][3]} {$mm[3][2]} {$mm[4][4]}\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/****/
|
||||||
|
|
||||||
|
function nestedloop($n) {
|
||||||
|
$x = 0;
|
||||||
|
for ($a=0; $a<$n; $a++)
|
||||||
|
for ($b=0; $b<$n; $b++)
|
||||||
|
for ($c=0; $c<$n; $c++)
|
||||||
|
for ($d=0; $d<$n; $d++)
|
||||||
|
for ($e=0; $e<$n; $e++)
|
||||||
|
for ($f=0; $f<$n; $f++)
|
||||||
|
$x++;
|
||||||
|
print "$x\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/****/
|
||||||
|
|
||||||
|
function sieve($n) {
|
||||||
|
$count = 0;
|
||||||
|
while ($n-- > 0) {
|
||||||
|
$count = 0;
|
||||||
|
$flags = range (0,8192);
|
||||||
|
for ($i=2; $i<8193; $i++) {
|
||||||
|
if ($flags[$i] > 0) {
|
||||||
|
for ($k=$i+$i; $k <= 8192; $k+=$i) {
|
||||||
|
$flags[$k] = 0;
|
||||||
|
}
|
||||||
|
$count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
print "Count: $count\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/****/
|
||||||
|
|
||||||
|
function strcat($n) {
|
||||||
|
$str = "";
|
||||||
|
while ($n-- > 0) {
|
||||||
|
$str .= "hello\n";
|
||||||
|
}
|
||||||
|
$len = strlen($str);
|
||||||
|
print "$len\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****/
|
||||||
|
|
||||||
|
function gethrtime()
|
||||||
|
{
|
||||||
|
$hrtime = hrtime();
|
||||||
|
return (($hrtime[0]*1000000000 + $hrtime[1]) / 1000000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
function start_test()
|
||||||
|
{
|
||||||
|
ob_start();
|
||||||
|
return gethrtime();
|
||||||
|
}
|
||||||
|
|
||||||
|
function end_test($start, $name)
|
||||||
|
{
|
||||||
|
global $total;
|
||||||
|
$end = gethrtime();
|
||||||
|
ob_end_clean();
|
||||||
|
$total += $end-$start;
|
||||||
|
$num = number_format($end-$start,3);
|
||||||
|
$pad = str_repeat(" ", 24-strlen($name)-strlen($num));
|
||||||
|
|
||||||
|
echo $name.$pad.$num."\n";
|
||||||
|
ob_start();
|
||||||
|
return gethrtime();
|
||||||
|
}
|
||||||
|
|
||||||
|
function total()
|
||||||
|
{
|
||||||
|
global $total;
|
||||||
|
$pad = str_repeat("-", 24);
|
||||||
|
echo $pad."\n";
|
||||||
|
$num = number_format($total,3);
|
||||||
|
$pad = str_repeat(" ", 24-strlen("Total")-strlen($num));
|
||||||
|
echo "Total".$pad.$num."\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
$t0 = $t = start_test();
|
||||||
|
simple();
|
||||||
|
$t = end_test($t, "simple");
|
||||||
|
simplecall();
|
||||||
|
$t = end_test($t, "simplecall");
|
||||||
|
simpleucall();
|
||||||
|
$t = end_test($t, "simpleucall");
|
||||||
|
simpleudcall();
|
||||||
|
$t = end_test($t, "simpleudcall");
|
||||||
|
mandel();
|
||||||
|
$t = end_test($t, "mandel");
|
||||||
|
mandel2();
|
||||||
|
$t = end_test($t, "mandel2");
|
||||||
|
ackermann(7);
|
||||||
|
$t = end_test($t, "ackermann(7)");
|
||||||
|
ary(50000);
|
||||||
|
$t = end_test($t, "ary(50000)");
|
||||||
|
ary2(50000);
|
||||||
|
$t = end_test($t, "ary2(50000)");
|
||||||
|
ary3(2000);
|
||||||
|
$t = end_test($t, "ary3(2000)");
|
||||||
|
fibo(30);
|
||||||
|
$t = end_test($t, "fibo(30)");
|
||||||
|
hash1(50000);
|
||||||
|
$t = end_test($t, "hash1(50000)");
|
||||||
|
hash2(500);
|
||||||
|
$t = end_test($t, "hash2(500)");
|
||||||
|
heapsort(20000);
|
||||||
|
$t = end_test($t, "heapsort(20000)");
|
||||||
|
matrix(20);
|
||||||
|
$t = end_test($t, "matrix(20)");
|
||||||
|
nestedloop(12);
|
||||||
|
$t = end_test($t, "nestedloop(12)");
|
||||||
|
sieve(30);
|
||||||
|
$t = end_test($t, "sieve(30)");
|
||||||
|
strcat(200000);
|
||||||
|
$t = end_test($t, "strcat(200000)");
|
||||||
|
total();
|
||||||
|
?>
|
||||||
|
|
@ -0,0 +1,358 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
function hallo() {
|
||||||
|
}
|
||||||
|
|
||||||
|
function simpleucall($n) {
|
||||||
|
for ($i = 0; $i < $n; $i++)
|
||||||
|
hallo();
|
||||||
|
}
|
||||||
|
|
||||||
|
function simpleudcall($n) {
|
||||||
|
for ($i = 0; $i < $n; $i++)
|
||||||
|
hallo2();
|
||||||
|
}
|
||||||
|
|
||||||
|
function hallo2() {
|
||||||
|
}
|
||||||
|
|
||||||
|
function simpleicall($n) {
|
||||||
|
for ($i = 0; $i < $n; $i++)
|
||||||
|
func_num_args();
|
||||||
|
}
|
||||||
|
|
||||||
|
class Foo {
|
||||||
|
static $a = 0;
|
||||||
|
public $b = 0;
|
||||||
|
const TEST = 0;
|
||||||
|
|
||||||
|
static function read_static($n) {
|
||||||
|
for ($i = 0; $i < $n; ++$i) {
|
||||||
|
$x = self::$a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static function write_static($n) {
|
||||||
|
for ($i = 0; $i < $n; ++$i) {
|
||||||
|
self::$a = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static function isset_static($n) {
|
||||||
|
for ($i = 0; $i < $n; ++$i) {
|
||||||
|
$x = isset(self::$a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static function empty_static($n) {
|
||||||
|
for ($i = 0; $i < $n; ++$i) {
|
||||||
|
$x = empty(self::$a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static function f() {
|
||||||
|
}
|
||||||
|
|
||||||
|
static function call_static($n) {
|
||||||
|
for ($i = 0; $i < $n; ++$i) {
|
||||||
|
self::f();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function read_prop($n) {
|
||||||
|
for ($i = 0; $i < $n; ++$i) {
|
||||||
|
$x = $this->b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function write_prop($n) {
|
||||||
|
for ($i = 0; $i < $n; ++$i) {
|
||||||
|
$this->b = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function assign_add_prop($n) {
|
||||||
|
for ($i = 0; $i < $n; ++$i) {
|
||||||
|
$this->b += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function pre_inc_prop($n) {
|
||||||
|
for ($i = 0; $i < $n; ++$i) {
|
||||||
|
++$this->b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function pre_dec_prop($n) {
|
||||||
|
for ($i = 0; $i < $n; ++$i) {
|
||||||
|
--$this->b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function post_inc_prop($n) {
|
||||||
|
for ($i = 0; $i < $n; ++$i) {
|
||||||
|
$this->b++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function post_dec_prop($n) {
|
||||||
|
for ($i = 0; $i < $n; ++$i) {
|
||||||
|
$this->b--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function isset_prop($n) {
|
||||||
|
for ($i = 0; $i < $n; ++$i) {
|
||||||
|
$x = isset($this->b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function empty_prop($n) {
|
||||||
|
for ($i = 0; $i < $n; ++$i) {
|
||||||
|
$x = empty($this->b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function g() {
|
||||||
|
}
|
||||||
|
|
||||||
|
function call($n) {
|
||||||
|
for ($i = 0; $i < $n; ++$i) {
|
||||||
|
$this->g();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function read_const($n) {
|
||||||
|
for ($i = 0; $i < $n; ++$i) {
|
||||||
|
$x = $this::TEST;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function read_static($n) {
|
||||||
|
for ($i = 0; $i < $n; ++$i) {
|
||||||
|
$x = Foo::$a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function write_static($n) {
|
||||||
|
for ($i = 0; $i < $n; ++$i) {
|
||||||
|
Foo::$a = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function isset_static($n) {
|
||||||
|
for ($i = 0; $i < $n; ++$i) {
|
||||||
|
$x = isset(Foo::$a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function empty_static($n) {
|
||||||
|
for ($i = 0; $i < $n; ++$i) {
|
||||||
|
$x = empty(Foo::$a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function call_static($n) {
|
||||||
|
for ($i = 0; $i < $n; ++$i) {
|
||||||
|
Foo::f();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function create_object($n) {
|
||||||
|
for ($i = 0; $i < $n; ++$i) {
|
||||||
|
$x = new Foo();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
define('TEST', null);
|
||||||
|
|
||||||
|
function read_const($n) {
|
||||||
|
for ($i = 0; $i < $n; ++$i) {
|
||||||
|
$x = TEST;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function read_auto_global($n) {
|
||||||
|
for ($i = 0; $i < $n; ++$i) {
|
||||||
|
$x = $_GET;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$g_var = 0;
|
||||||
|
|
||||||
|
function read_global_var($n) {
|
||||||
|
for ($i = 0; $i < $n; ++$i) {
|
||||||
|
$x = $GLOBALS['g_var'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function read_hash($n) {
|
||||||
|
$hash = array('test' => 0);
|
||||||
|
for ($i = 0; $i < $n; ++$i) {
|
||||||
|
$x = $hash['test'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function read_str_offset($n) {
|
||||||
|
$str = "test";
|
||||||
|
for ($i = 0; $i < $n; ++$i) {
|
||||||
|
$x = $str[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function issetor($n) {
|
||||||
|
$val = array(0,1,2,3,4,5,6,7,8,9);
|
||||||
|
for ($i = 0; $i < $n; ++$i) {
|
||||||
|
$x = $val ?: null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function issetor2($n) {
|
||||||
|
$f = false; $j = 0;
|
||||||
|
for ($i = 0; $i < $n; ++$i) {
|
||||||
|
$x = $f ?: $j + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function ternary($n) {
|
||||||
|
$val = array(0,1,2,3,4,5,6,7,8,9);
|
||||||
|
$f = false;
|
||||||
|
for ($i = 0; $i < $n; ++$i) {
|
||||||
|
$x = $f ? null : $val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function ternary2($n) {
|
||||||
|
$f = false; $j = 0;
|
||||||
|
for ($i = 0; $i < $n; ++$i) {
|
||||||
|
$x = $f ? $f : $j + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****/
|
||||||
|
|
||||||
|
function empty_loop($n) {
|
||||||
|
for ($i = 0; $i < $n; ++$i) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function gethrtime()
|
||||||
|
{
|
||||||
|
$hrtime = hrtime();
|
||||||
|
return (($hrtime[0]*1000000000 + $hrtime[1]) / 1000000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
function start_test()
|
||||||
|
{
|
||||||
|
ob_start();
|
||||||
|
return gethrtime();
|
||||||
|
}
|
||||||
|
|
||||||
|
function end_test($start, $name, $overhead = null)
|
||||||
|
{
|
||||||
|
global $total;
|
||||||
|
global $last_time;
|
||||||
|
$end = gethrtime();
|
||||||
|
ob_end_clean();
|
||||||
|
$last_time = $end-$start;
|
||||||
|
$total += $last_time;
|
||||||
|
$num = number_format($last_time,3);
|
||||||
|
$pad = str_repeat(" ", 24-strlen($name)-strlen($num));
|
||||||
|
if (is_null($overhead)) {
|
||||||
|
echo $name.$pad.$num."\n";
|
||||||
|
} else {
|
||||||
|
$num2 = number_format($last_time - $overhead,3);
|
||||||
|
echo $name.$pad.$num." ".$num2."\n";
|
||||||
|
}
|
||||||
|
ob_start();
|
||||||
|
return gethrtime();
|
||||||
|
}
|
||||||
|
|
||||||
|
function total()
|
||||||
|
{
|
||||||
|
global $total;
|
||||||
|
$pad = str_repeat("-", 24);
|
||||||
|
echo $pad."\n";
|
||||||
|
$num = number_format($total,3);
|
||||||
|
$pad = str_repeat(" ", 24-strlen("Total")-strlen($num));
|
||||||
|
echo "Total".$pad.$num."\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
const N = 5000000;
|
||||||
|
|
||||||
|
$t0 = $t = start_test();
|
||||||
|
empty_loop(N);
|
||||||
|
$t = end_test($t, 'empty_loop');
|
||||||
|
$overhead = $last_time;
|
||||||
|
simpleucall(N);
|
||||||
|
$t = end_test($t, 'func()', $overhead);
|
||||||
|
simpleudcall(N);
|
||||||
|
$t = end_test($t, 'undef_func()', $overhead);
|
||||||
|
simpleicall(N);
|
||||||
|
$t = end_test($t, 'int_func()', $overhead);
|
||||||
|
Foo::read_static(N);
|
||||||
|
$t = end_test($t, '$x = self::$x', $overhead);
|
||||||
|
Foo::write_static(N);
|
||||||
|
$t = end_test($t, 'self::$x = 0', $overhead);
|
||||||
|
Foo::isset_static(N);
|
||||||
|
$t = end_test($t, 'isset(self::$x)', $overhead);
|
||||||
|
Foo::empty_static(N);
|
||||||
|
$t = end_test($t, 'empty(self::$x)', $overhead);
|
||||||
|
read_static(N);
|
||||||
|
$t = end_test($t, '$x = Foo::$x', $overhead);
|
||||||
|
write_static(N);
|
||||||
|
$t = end_test($t, 'Foo::$x = 0', $overhead);
|
||||||
|
isset_static(N);
|
||||||
|
$t = end_test($t, 'isset(Foo::$x)', $overhead);
|
||||||
|
empty_static(N);
|
||||||
|
$t = end_test($t, 'empty(Foo::$x)', $overhead);
|
||||||
|
Foo::call_static(N);
|
||||||
|
$t = end_test($t, 'self::f()', $overhead);
|
||||||
|
call_static(N);
|
||||||
|
$t = end_test($t, 'Foo::f()', $overhead);
|
||||||
|
$x = new Foo();
|
||||||
|
$x->read_prop(N);
|
||||||
|
$t = end_test($t, '$x = $this->x', $overhead);
|
||||||
|
$x->write_prop(N);
|
||||||
|
$t = end_test($t, '$this->x = 0', $overhead);
|
||||||
|
$x->assign_add_prop(N);
|
||||||
|
$t = end_test($t, '$this->x += 2', $overhead);
|
||||||
|
$x->pre_inc_prop(N);
|
||||||
|
$t = end_test($t, '++$this->x', $overhead);
|
||||||
|
$x->pre_dec_prop(N);
|
||||||
|
$t = end_test($t, '--$this->x', $overhead);
|
||||||
|
$x->post_inc_prop(N);
|
||||||
|
$t = end_test($t, '$this->x++', $overhead);
|
||||||
|
$x->post_dec_prop(N);
|
||||||
|
$t = end_test($t, '$this->x--', $overhead);
|
||||||
|
$x->isset_prop(N);
|
||||||
|
$t = end_test($t, 'isset($this->x)', $overhead);
|
||||||
|
$x->empty_prop(N);
|
||||||
|
$t = end_test($t, 'empty($this->x)', $overhead);
|
||||||
|
$x->call(N);
|
||||||
|
$t = end_test($t, '$this->f()', $overhead);
|
||||||
|
$x->read_const(N);
|
||||||
|
$t = end_test($t, '$x = Foo::TEST', $overhead);
|
||||||
|
create_object(N);
|
||||||
|
$t = end_test($t, 'new Foo()', $overhead);
|
||||||
|
read_const(N);
|
||||||
|
$t = end_test($t, '$x = TEST', $overhead);
|
||||||
|
read_auto_global(N);
|
||||||
|
$t = end_test($t, '$x = $_GET', $overhead);
|
||||||
|
read_global_var(N);
|
||||||
|
$t = end_test($t, '$x = $GLOBALS[\'v\']', $overhead);
|
||||||
|
read_hash(N);
|
||||||
|
$t = end_test($t, '$x = $hash[\'v\']', $overhead);
|
||||||
|
read_str_offset(N);
|
||||||
|
$t = end_test($t, '$x = $str[0]', $overhead);
|
||||||
|
issetor(N);
|
||||||
|
$t = end_test($t, '$x = $a ?: null', $overhead);
|
||||||
|
issetor2(N);
|
||||||
|
$t = end_test($t, '$x = $f ?: tmp', $overhead);
|
||||||
|
ternary(N);
|
||||||
|
$t = end_test($t, '$x = $f ? $f : $a', $overhead);
|
||||||
|
ternary2(N);
|
||||||
|
$t = end_test($t, '$x = $f ? $f : tmp', $overhead);
|
||||||
|
total($t0, "Total");
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
--TEST--
|
||||||
|
func_num_args() tests
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
function test1() {
|
||||||
|
var_dump(func_num_args());
|
||||||
|
}
|
||||||
|
|
||||||
|
function test2($a) {
|
||||||
|
var_dump(func_num_args());
|
||||||
|
}
|
||||||
|
|
||||||
|
function test3($a, $b) {
|
||||||
|
var_dump(func_num_args());
|
||||||
|
}
|
||||||
|
|
||||||
|
test1();
|
||||||
|
test2(1);
|
||||||
|
try {
|
||||||
|
test2();
|
||||||
|
} catch (Throwable $e) {
|
||||||
|
echo "Exception: " . $e->getMessage() . "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
test3(1,2);
|
||||||
|
|
||||||
|
call_user_func("test1");
|
||||||
|
try {
|
||||||
|
call_user_func("test3", 1);
|
||||||
|
} catch (Throwable $e) {
|
||||||
|
echo "Exception: " . $e->getMessage() . "\n";
|
||||||
|
}
|
||||||
|
call_user_func("test3", 1, 2);
|
||||||
|
|
||||||
|
class test {
|
||||||
|
static function test1($a) {
|
||||||
|
var_dump(func_num_args());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test::test1(1);
|
||||||
|
|
||||||
|
try {
|
||||||
|
func_num_args();
|
||||||
|
} catch (Error $exception) {
|
||||||
|
echo $exception->getMessage() . "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Done\n";
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
int(0)
|
||||||
|
int(1)
|
||||||
|
Exception: Too few arguments to function test2(), 0 passed in %s on line %d and exactly 1 expected
|
||||||
|
int(2)
|
||||||
|
int(0)
|
||||||
|
Exception: Too few arguments to function test3(), 1 passed in %s on line %d and exactly 2 expected
|
||||||
|
int(2)
|
||||||
|
int(1)
|
||||||
|
func_num_args() must be called from a function context
|
||||||
|
Done
|
||||||
|
|
@ -0,0 +1,121 @@
|
||||||
|
--TEST--
|
||||||
|
func_get_arg() tests
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
function test1() {
|
||||||
|
try {
|
||||||
|
var_dump(func_get_arg(-10));
|
||||||
|
} catch (\ValueError $e) {
|
||||||
|
echo $e->getMessage() . \PHP_EOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
var_dump(func_get_arg(0));
|
||||||
|
} catch (\Error $e) {
|
||||||
|
echo $e->getMessage() . \PHP_EOL;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
var_dump(func_get_arg(1));
|
||||||
|
} catch (\Error $e) {
|
||||||
|
echo $e->getMessage() . \PHP_EOL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function test2($a) {
|
||||||
|
try {
|
||||||
|
var_dump(func_get_arg(0));
|
||||||
|
} catch (\Error $e) {
|
||||||
|
echo $e->getMessage() . \PHP_EOL;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
var_dump(func_get_arg(1));
|
||||||
|
} catch (\Error $e) {
|
||||||
|
echo $e->getMessage() . \PHP_EOL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function test3($a, $b) {
|
||||||
|
try {
|
||||||
|
var_dump(func_get_arg(0));
|
||||||
|
} catch (\Error $e) {
|
||||||
|
echo $e->getMessage() . \PHP_EOL;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
var_dump(func_get_arg(1));
|
||||||
|
} catch (\Error $e) {
|
||||||
|
echo $e->getMessage() . \PHP_EOL;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
var_dump(func_get_arg(2));
|
||||||
|
} catch (\Error $e) {
|
||||||
|
echo $e->getMessage() . \PHP_EOL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test1();
|
||||||
|
test1(10);
|
||||||
|
test2(1);
|
||||||
|
try {
|
||||||
|
test2();
|
||||||
|
} catch (Throwable $e) {
|
||||||
|
echo "Exception: " . $e->getMessage() . "\n";
|
||||||
|
}
|
||||||
|
test3(1,2);
|
||||||
|
|
||||||
|
call_user_func("test1");
|
||||||
|
try {
|
||||||
|
call_user_func("test3", 1);
|
||||||
|
} catch (Throwable $e) {
|
||||||
|
echo "Exception: " . $e->getMessage() . "\n";
|
||||||
|
}
|
||||||
|
call_user_func("test3", 1, 2);
|
||||||
|
|
||||||
|
class test {
|
||||||
|
static function test1($a) {
|
||||||
|
try {
|
||||||
|
var_dump(func_get_arg(0));
|
||||||
|
} catch (\Error $e) {
|
||||||
|
echo $e->getMessage() . \PHP_EOL;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
var_dump(func_get_arg(1));
|
||||||
|
} catch (\Error $e) {
|
||||||
|
echo $e->getMessage() . \PHP_EOL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test::test1(1);
|
||||||
|
try {
|
||||||
|
var_dump(func_get_arg(1));
|
||||||
|
} catch (\Error $e) {
|
||||||
|
echo $e->getMessage() . \PHP_EOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Done\n";
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
func_get_arg(): Argument #1 ($position) must be greater than or equal to 0
|
||||||
|
func_get_arg(): Argument #1 ($position) must be less than the number of the arguments passed to the currently executed function
|
||||||
|
func_get_arg(): Argument #1 ($position) must be less than the number of the arguments passed to the currently executed function
|
||||||
|
func_get_arg(): Argument #1 ($position) must be greater than or equal to 0
|
||||||
|
int(10)
|
||||||
|
func_get_arg(): Argument #1 ($position) must be less than the number of the arguments passed to the currently executed function
|
||||||
|
int(1)
|
||||||
|
func_get_arg(): Argument #1 ($position) must be less than the number of the arguments passed to the currently executed function
|
||||||
|
Exception: Too few arguments to function test2(), 0 passed in %s002.php on line %d and exactly 1 expected
|
||||||
|
int(1)
|
||||||
|
int(2)
|
||||||
|
func_get_arg(): Argument #1 ($position) must be less than the number of the arguments passed to the currently executed function
|
||||||
|
func_get_arg(): Argument #1 ($position) must be greater than or equal to 0
|
||||||
|
func_get_arg(): Argument #1 ($position) must be less than the number of the arguments passed to the currently executed function
|
||||||
|
func_get_arg(): Argument #1 ($position) must be less than the number of the arguments passed to the currently executed function
|
||||||
|
Exception: Too few arguments to function test3(), 1 passed in %s on line %d and exactly 2 expected
|
||||||
|
int(1)
|
||||||
|
int(2)
|
||||||
|
func_get_arg(): Argument #1 ($position) must be less than the number of the arguments passed to the currently executed function
|
||||||
|
int(1)
|
||||||
|
func_get_arg(): Argument #1 ($position) must be less than the number of the arguments passed to the currently executed function
|
||||||
|
func_get_arg() cannot be called from the global scope
|
||||||
|
Done
|
||||||
|
|
@ -0,0 +1,82 @@
|
||||||
|
--TEST--
|
||||||
|
func_get_args() tests
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
function test1() {
|
||||||
|
var_dump(func_get_args());
|
||||||
|
}
|
||||||
|
|
||||||
|
function test2($a) {
|
||||||
|
var_dump(func_get_args());
|
||||||
|
}
|
||||||
|
|
||||||
|
function test3($a, $b) {
|
||||||
|
var_dump(func_get_args());
|
||||||
|
}
|
||||||
|
|
||||||
|
test1();
|
||||||
|
test1(10);
|
||||||
|
test2(1);
|
||||||
|
try {
|
||||||
|
test2();
|
||||||
|
} catch (Throwable $e) {
|
||||||
|
echo "Exception: " . $e->getMessage() . "\n";
|
||||||
|
}
|
||||||
|
test3(1,2);
|
||||||
|
|
||||||
|
call_user_func("test1");
|
||||||
|
try {
|
||||||
|
call_user_func("test3", 1);
|
||||||
|
} catch (Throwable $e) {
|
||||||
|
echo "Exception: " . $e->getMessage() . "\n";
|
||||||
|
}
|
||||||
|
call_user_func("test3", 1, 2);
|
||||||
|
|
||||||
|
class test {
|
||||||
|
static function test1($a) {
|
||||||
|
var_dump(func_get_args());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test::test1(1);
|
||||||
|
|
||||||
|
try {
|
||||||
|
var_dump(func_get_args());
|
||||||
|
} catch (\Error $e) {
|
||||||
|
echo $e->getMessage() . \PHP_EOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
array(0) {
|
||||||
|
}
|
||||||
|
array(1) {
|
||||||
|
[0]=>
|
||||||
|
int(10)
|
||||||
|
}
|
||||||
|
array(1) {
|
||||||
|
[0]=>
|
||||||
|
int(1)
|
||||||
|
}
|
||||||
|
Exception: Too few arguments to function test2(), 0 passed in %s003.php on line %d and exactly 1 expected
|
||||||
|
array(2) {
|
||||||
|
[0]=>
|
||||||
|
int(1)
|
||||||
|
[1]=>
|
||||||
|
int(2)
|
||||||
|
}
|
||||||
|
array(0) {
|
||||||
|
}
|
||||||
|
Exception: Too few arguments to function test3(), 1 passed in %s003.php on line %d and exactly 2 expected
|
||||||
|
array(2) {
|
||||||
|
[0]=>
|
||||||
|
int(1)
|
||||||
|
[1]=>
|
||||||
|
int(2)
|
||||||
|
}
|
||||||
|
array(1) {
|
||||||
|
[0]=>
|
||||||
|
int(1)
|
||||||
|
}
|
||||||
|
func_get_args() cannot be called from the global scope
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
--TEST--
|
||||||
|
strncmp() tests
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
var_dump(strncmp("", "", 100));
|
||||||
|
try {
|
||||||
|
var_dump(strncmp("aef", "dfsgbdf", -1));
|
||||||
|
} catch (\ValueError $e) {
|
||||||
|
echo $e->getMessage() . \PHP_EOL;
|
||||||
|
}
|
||||||
|
var_dump(strncmp("fghjkl", "qwer", 0));
|
||||||
|
var_dump(strncmp("qwerty", "qwerty123", 6));
|
||||||
|
var_dump(strncmp("qwerty", "qwerty123", 7));
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
int(0)
|
||||||
|
strncmp(): Argument #3 ($length) must be greater than or equal to 0
|
||||||
|
int(0)
|
||||||
|
int(0)
|
||||||
|
int(-1)
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
--TEST--
|
||||||
|
strcasecmp() tests
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
var_dump(strcasecmp("", ""));
|
||||||
|
var_dump(strcasecmp("aef", "dfsgbdf"));
|
||||||
|
var_dump(strcasecmp("qwe", "qwer"));
|
||||||
|
var_dump(strcasecmp("qwerty", "QweRty"));
|
||||||
|
var_dump(strcasecmp("qwErtY", "qwerty"));
|
||||||
|
var_dump(strcasecmp("q123", "Q123"));
|
||||||
|
var_dump(strcasecmp("01", "01"));
|
||||||
|
|
||||||
|
echo "Done\n";
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
int(0)
|
||||||
|
int(-3)
|
||||||
|
int(-1)
|
||||||
|
int(0)
|
||||||
|
int(0)
|
||||||
|
int(0)
|
||||||
|
int(0)
|
||||||
|
Done
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
--TEST--
|
||||||
|
strncasecmp() tests
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
try {
|
||||||
|
var_dump(strncasecmp("", "", -1));
|
||||||
|
} catch (\ValueError $e) {
|
||||||
|
echo $e->getMessage() . \PHP_EOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
var_dump(strncasecmp("aef", "dfsgbdf", 0));
|
||||||
|
var_dump(strncasecmp("aef", "dfsgbdf", 10));
|
||||||
|
var_dump(strncasecmp("qwe", "qwer", 3));
|
||||||
|
var_dump(strncasecmp("qwerty", "QweRty", 6));
|
||||||
|
var_dump(strncasecmp("qwErtY", "qwer", 7));
|
||||||
|
var_dump(strncasecmp("q123", "Q123", 3));
|
||||||
|
var_dump(strncasecmp("01", "01", 1000));
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
strncasecmp(): Argument #3 ($length) must be greater than or equal to 0
|
||||||
|
int(0)
|
||||||
|
int(-3)
|
||||||
|
int(0)
|
||||||
|
int(0)
|
||||||
|
int(2)
|
||||||
|
int(0)
|
||||||
|
int(0)
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
--TEST--
|
||||||
|
define() tests
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
try {
|
||||||
|
var_dump(define(array(1,2,3,4,5), 1));
|
||||||
|
} catch (TypeError $e) {
|
||||||
|
echo "TypeError: ", $e->getMessage(), "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
var_dump(define("TRUE", 1));
|
||||||
|
var_dump(define(" ", 1));
|
||||||
|
var_dump(define("[[[", 2));
|
||||||
|
var_dump(define("test const", 3));
|
||||||
|
var_dump(define("test const", 3));
|
||||||
|
var_dump(define("test", array(1)));
|
||||||
|
var_dump(define("test1", fopen(__FILE__, 'r')));
|
||||||
|
|
||||||
|
try {
|
||||||
|
var_dump(define("test2", new stdclass));
|
||||||
|
} catch (TypeError $exception) {
|
||||||
|
echo $exception->getMessage() . "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
var_dump(constant(" "));
|
||||||
|
var_dump(constant("[[["));
|
||||||
|
var_dump(constant("test const"));
|
||||||
|
|
||||||
|
echo "Done\n";
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
TypeError: define(): Argument #1 ($constant_name) must be of type string, array given
|
||||||
|
|
||||||
|
Warning: Constant TRUE already defined in %s on line %d
|
||||||
|
bool(false)
|
||||||
|
bool(true)
|
||||||
|
bool(true)
|
||||||
|
bool(true)
|
||||||
|
|
||||||
|
Warning: Constant test const already defined in %s on line %d
|
||||||
|
bool(false)
|
||||||
|
bool(true)
|
||||||
|
bool(true)
|
||||||
|
define(): Argument #2 ($value) cannot be an object, stdClass given
|
||||||
|
int(1)
|
||||||
|
int(2)
|
||||||
|
int(3)
|
||||||
|
Done
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
--TEST--
|
||||||
|
get_class() tests
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class foo {
|
||||||
|
function bar () {
|
||||||
|
var_dump(get_class());
|
||||||
|
}
|
||||||
|
function testNull ()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
var_dump(get_class(null));
|
||||||
|
} catch (TypeError $e) {
|
||||||
|
echo $e->getMessage(), "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class foo2 extends foo {
|
||||||
|
}
|
||||||
|
|
||||||
|
$f1 = new foo;
|
||||||
|
$f2 = new foo2;
|
||||||
|
|
||||||
|
$f1->bar();
|
||||||
|
$f2->bar();
|
||||||
|
|
||||||
|
try {
|
||||||
|
var_dump(get_class());
|
||||||
|
} catch (Error $e) {
|
||||||
|
echo $e->getMessage(), "\n";
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
var_dump(get_class("qwerty"));
|
||||||
|
} catch (TypeError $e) {
|
||||||
|
echo $e->getMessage(), "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
var_dump(get_class($f1));
|
||||||
|
var_dump(get_class($f2));
|
||||||
|
|
||||||
|
$f1->testNull();
|
||||||
|
|
||||||
|
echo "Done\n";
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
string(3) "foo"
|
||||||
|
string(3) "foo"
|
||||||
|
get_class() without arguments must be called from within a class
|
||||||
|
get_class(): Argument #1 ($object) must be of type object, string given
|
||||||
|
string(3) "foo"
|
||||||
|
string(4) "foo2"
|
||||||
|
get_class(): Argument #1 ($object) must be of type object, null given
|
||||||
|
Done
|
||||||
|
|
@ -0,0 +1,84 @@
|
||||||
|
--TEST--
|
||||||
|
get_parent_class() tests
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
interface i {
|
||||||
|
function test();
|
||||||
|
}
|
||||||
|
|
||||||
|
class foo implements i {
|
||||||
|
function test() {
|
||||||
|
var_dump(get_parent_class());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class bar extends foo {
|
||||||
|
function test_bar() {
|
||||||
|
var_dump(get_parent_class());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$bar = new bar;
|
||||||
|
$foo = new foo;
|
||||||
|
|
||||||
|
$foo->test();
|
||||||
|
$bar->test();
|
||||||
|
$bar->test_bar();
|
||||||
|
|
||||||
|
var_dump(get_parent_class($bar));
|
||||||
|
var_dump(get_parent_class($foo));
|
||||||
|
var_dump(get_parent_class("bar"));
|
||||||
|
var_dump(get_parent_class("foo"));
|
||||||
|
var_dump(get_parent_class("i"));
|
||||||
|
|
||||||
|
try {
|
||||||
|
get_parent_class("");
|
||||||
|
} catch (TypeError $exception) {
|
||||||
|
echo $exception->getMessage() . "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
get_parent_class("[[[[");
|
||||||
|
} catch (TypeError $exception) {
|
||||||
|
echo $exception->getMessage() . "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
get_parent_class(" ");
|
||||||
|
} catch (TypeError $exception) {
|
||||||
|
echo $exception->getMessage() . "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
var_dump(get_parent_class(new stdclass));
|
||||||
|
|
||||||
|
try {
|
||||||
|
get_parent_class(array());
|
||||||
|
} catch (TypeError $exception) {
|
||||||
|
echo $exception->getMessage() . "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
get_parent_class(1);
|
||||||
|
} catch (TypeError $exception) {
|
||||||
|
echo $exception->getMessage() . "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Done\n";
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
bool(false)
|
||||||
|
bool(false)
|
||||||
|
string(3) "foo"
|
||||||
|
string(3) "foo"
|
||||||
|
bool(false)
|
||||||
|
string(3) "foo"
|
||||||
|
bool(false)
|
||||||
|
bool(false)
|
||||||
|
get_parent_class(): Argument #1 ($object_or_class) must be an object or a valid class name, string given
|
||||||
|
get_parent_class(): Argument #1 ($object_or_class) must be an object or a valid class name, string given
|
||||||
|
get_parent_class(): Argument #1 ($object_or_class) must be an object or a valid class name, string given
|
||||||
|
bool(false)
|
||||||
|
get_parent_class(): Argument #1 ($object_or_class) must be an object or a valid class name, array given
|
||||||
|
get_parent_class(): Argument #1 ($object_or_class) must be an object or a valid class name, int given
|
||||||
|
Done
|
||||||
|
|
@ -0,0 +1,99 @@
|
||||||
|
--TEST--
|
||||||
|
property_exists() tests
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class foo {
|
||||||
|
public $pp1 = 1;
|
||||||
|
private $pp2 = 2;
|
||||||
|
protected $pp3 = 3;
|
||||||
|
|
||||||
|
function bar() {
|
||||||
|
var_dump(property_exists("foo","pp1"));
|
||||||
|
var_dump(property_exists("foo","pp2"));
|
||||||
|
var_dump(property_exists("foo","pp3"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class bar extends foo {
|
||||||
|
function test() {
|
||||||
|
var_dump(property_exists("foo","pp1"));
|
||||||
|
var_dump(property_exists("foo","pp2"));
|
||||||
|
var_dump(property_exists("foo","pp3"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var_dump(property_exists("foo","pp1"));
|
||||||
|
var_dump(property_exists("foo","pp2"));
|
||||||
|
var_dump(property_exists("foo","pp3"));
|
||||||
|
var_dump(property_exists("foo","nonexistent"));
|
||||||
|
var_dump(property_exists("fo","nonexistent"));
|
||||||
|
var_dump(property_exists("foo",""));
|
||||||
|
var_dump(property_exists("","test"));
|
||||||
|
var_dump(property_exists("",""));
|
||||||
|
|
||||||
|
$foo = new foo;
|
||||||
|
|
||||||
|
var_dump(property_exists($foo,"pp1"));
|
||||||
|
var_dump(property_exists($foo,"pp2"));
|
||||||
|
var_dump(property_exists($foo,"pp3"));
|
||||||
|
var_dump(property_exists($foo,"nonexistent"));
|
||||||
|
var_dump(property_exists($foo,""));
|
||||||
|
|
||||||
|
try {
|
||||||
|
var_dump(property_exists(array(), "test"));
|
||||||
|
} catch (\TypeError $e) {
|
||||||
|
echo $e->getMessage() . \PHP_EOL;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
var_dump(property_exists(1, "test"));
|
||||||
|
} catch (\TypeError $e) {
|
||||||
|
echo $e->getMessage() . \PHP_EOL;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
var_dump(property_exists(3.14, "test"));
|
||||||
|
} catch (\TypeError $e) {
|
||||||
|
echo $e->getMessage() . \PHP_EOL;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
var_dump(property_exists(true, "test"));
|
||||||
|
} catch (\TypeError $e) {
|
||||||
|
echo $e->getMessage() . \PHP_EOL;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
var_dump(property_exists(null, "test"));
|
||||||
|
} catch (\TypeError $e) {
|
||||||
|
echo $e->getMessage() . \PHP_EOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
$foo->bar();
|
||||||
|
|
||||||
|
$bar = new bar;
|
||||||
|
$bar->test();
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
bool(true)
|
||||||
|
bool(true)
|
||||||
|
bool(true)
|
||||||
|
bool(false)
|
||||||
|
bool(false)
|
||||||
|
bool(false)
|
||||||
|
bool(false)
|
||||||
|
bool(false)
|
||||||
|
bool(true)
|
||||||
|
bool(true)
|
||||||
|
bool(true)
|
||||||
|
bool(false)
|
||||||
|
bool(false)
|
||||||
|
property_exists(): Argument #1 ($object_or_class) must be of type object|string, array given
|
||||||
|
property_exists(): Argument #1 ($object_or_class) must be of type object|string, int given
|
||||||
|
property_exists(): Argument #1 ($object_or_class) must be of type object|string, float given
|
||||||
|
property_exists(): Argument #1 ($object_or_class) must be of type object|string, bool given
|
||||||
|
property_exists(): Argument #1 ($object_or_class) must be of type object|string, null given
|
||||||
|
bool(true)
|
||||||
|
bool(true)
|
||||||
|
bool(true)
|
||||||
|
bool(true)
|
||||||
|
bool(true)
|
||||||
|
bool(true)
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
--TEST--
|
||||||
|
class_exists() tests
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class foo {
|
||||||
|
}
|
||||||
|
|
||||||
|
var_dump(class_exists("qwerty"));
|
||||||
|
var_dump(class_exists(""));
|
||||||
|
var_dump(class_exists("test", false));
|
||||||
|
var_dump(class_exists("foo", false));
|
||||||
|
var_dump(class_exists("foo"));
|
||||||
|
var_dump(class_exists("stdClass", false));
|
||||||
|
var_dump(class_exists("stdClass"));
|
||||||
|
|
||||||
|
echo "Done\n";
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
bool(false)
|
||||||
|
bool(false)
|
||||||
|
bool(false)
|
||||||
|
bool(true)
|
||||||
|
bool(true)
|
||||||
|
bool(true)
|
||||||
|
bool(true)
|
||||||
|
Done
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
--TEST--
|
||||||
|
interface_exists() tests
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
interface foo {
|
||||||
|
}
|
||||||
|
|
||||||
|
var_dump(interface_exists("qwerty"));
|
||||||
|
var_dump(interface_exists(""));
|
||||||
|
var_dump(interface_exists("test", false));
|
||||||
|
var_dump(interface_exists("foo", false));
|
||||||
|
var_dump(interface_exists("foo"));
|
||||||
|
var_dump(interface_exists("stdClass", false));
|
||||||
|
var_dump(interface_exists("stdClass"));
|
||||||
|
|
||||||
|
echo "Done\n";
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
bool(false)
|
||||||
|
bool(false)
|
||||||
|
bool(false)
|
||||||
|
bool(true)
|
||||||
|
bool(true)
|
||||||
|
bool(false)
|
||||||
|
bool(false)
|
||||||
|
Done
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
<?php
|
||||||
|
/* dummy file for 014.phpt */
|
||||||
|
?>
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
--TEST--
|
||||||
|
get_included_files() tests
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
var_dump(get_included_files());
|
||||||
|
|
||||||
|
include(__DIR__."/014.inc");
|
||||||
|
var_dump(get_included_files());
|
||||||
|
|
||||||
|
include_once(__DIR__."/014.inc");
|
||||||
|
var_dump(get_included_files());
|
||||||
|
|
||||||
|
include(__DIR__."/014.inc");
|
||||||
|
var_dump(get_included_files());
|
||||||
|
|
||||||
|
echo "Done\n";
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
array(1) {
|
||||||
|
[0]=>
|
||||||
|
string(%d) "%s"
|
||||||
|
}
|
||||||
|
array(2) {
|
||||||
|
[0]=>
|
||||||
|
string(%d) "%s"
|
||||||
|
[1]=>
|
||||||
|
string(%d) "%s"
|
||||||
|
}
|
||||||
|
array(2) {
|
||||||
|
[0]=>
|
||||||
|
string(%d) "%s"
|
||||||
|
[1]=>
|
||||||
|
string(%d) "%s"
|
||||||
|
}
|
||||||
|
array(2) {
|
||||||
|
[0]=>
|
||||||
|
string(%d) "%s"
|
||||||
|
[1]=>
|
||||||
|
string(%d) "%s"
|
||||||
|
}
|
||||||
|
Done
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
--TEST--
|
||||||
|
trigger_error() tests
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
var_dump(trigger_error("error"));
|
||||||
|
|
||||||
|
try {
|
||||||
|
var_dump(trigger_error("error", -1));
|
||||||
|
} catch (\ValueError $e) {
|
||||||
|
echo $e->getMessage() . \PHP_EOL;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
var_dump(trigger_error("error", 0));
|
||||||
|
} catch (\ValueError $e) {
|
||||||
|
echo $e->getMessage() . \PHP_EOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
var_dump(trigger_error("error", E_USER_WARNING));
|
||||||
|
var_dump(trigger_error("error", E_USER_DEPRECATED));
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
Notice: error in %s on line %d
|
||||||
|
bool(true)
|
||||||
|
trigger_error(): Argument #2 ($error_level) must be one of E_USER_ERROR, E_USER_WARNING, E_USER_NOTICE, or E_USER_DEPRECATED
|
||||||
|
trigger_error(): Argument #2 ($error_level) must be one of E_USER_ERROR, E_USER_WARNING, E_USER_NOTICE, or E_USER_DEPRECATED
|
||||||
|
|
||||||
|
Warning: error in %s on line %d
|
||||||
|
bool(true)
|
||||||
|
|
||||||
|
Deprecated: error in %s on line %d
|
||||||
|
bool(true)
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
--TEST--
|
||||||
|
isset() with object properties when operating on non-object
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
$foo = NULL;
|
||||||
|
isset($foo->bar->bar);
|
||||||
|
|
||||||
|
echo "Done\n";
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
Done
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
--TEST--
|
||||||
|
builtin functions tests
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
$fp = fopen(__FILE__, "r");
|
||||||
|
var_dump(get_resource_type($fp));
|
||||||
|
fclose($fp);
|
||||||
|
var_dump(get_resource_type($fp));
|
||||||
|
|
||||||
|
var_dump(gettype(get_loaded_extensions()));
|
||||||
|
var_dump(count(get_loaded_extensions()));
|
||||||
|
var_dump(gettype(get_loaded_extensions(true)));
|
||||||
|
var_dump(count(get_loaded_extensions(true)));
|
||||||
|
|
||||||
|
define("USER_CONSTANT", "test");
|
||||||
|
|
||||||
|
var_dump(gettype(get_defined_constants(true)));
|
||||||
|
var_dump(gettype(get_defined_constants()));
|
||||||
|
var_dump(count(get_defined_constants()));
|
||||||
|
|
||||||
|
function test () {
|
||||||
|
}
|
||||||
|
|
||||||
|
var_dump(gettype(get_defined_functions()));
|
||||||
|
var_dump(count(get_defined_functions()));
|
||||||
|
|
||||||
|
var_dump(gettype(get_declared_interfaces()));
|
||||||
|
var_dump(count(get_declared_interfaces()));
|
||||||
|
|
||||||
|
var_dump(get_extension_funcs(true));
|
||||||
|
var_dump(gettype(get_extension_funcs("standard")));
|
||||||
|
var_dump(count(get_extension_funcs("standard")));
|
||||||
|
var_dump(gettype(get_extension_funcs("zend")));
|
||||||
|
var_dump(count(get_extension_funcs("zend")));
|
||||||
|
|
||||||
|
|
||||||
|
echo "Done\n";
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
string(6) "stream"
|
||||||
|
string(7) "Unknown"
|
||||||
|
string(5) "array"
|
||||||
|
int(%d)
|
||||||
|
string(5) "array"
|
||||||
|
int(%d)
|
||||||
|
string(5) "array"
|
||||||
|
string(5) "array"
|
||||||
|
int(%d)
|
||||||
|
string(5) "array"
|
||||||
|
int(%d)
|
||||||
|
string(5) "array"
|
||||||
|
int(%d)
|
||||||
|
bool(false)
|
||||||
|
string(5) "array"
|
||||||
|
int(%d)
|
||||||
|
string(5) "array"
|
||||||
|
int(%d)
|
||||||
|
Done
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
--TEST--
|
||||||
|
constant() tests
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
try {
|
||||||
|
var_dump(constant(""));
|
||||||
|
} catch (Error $e) {
|
||||||
|
echo $e->getMessage(), "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
define("TEST_CONST", 1);
|
||||||
|
var_dump(constant("TEST_CONST"));
|
||||||
|
|
||||||
|
define("TEST_CONST2", "test");
|
||||||
|
var_dump(constant("TEST_CONST2"));
|
||||||
|
|
||||||
|
echo "Done\n";
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
Undefined constant ""
|
||||||
|
int(1)
|
||||||
|
string(4) "test"
|
||||||
|
Done
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,29 @@
|
||||||
|
--TEST--
|
||||||
|
func_get_arg() invalid usage
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
try {
|
||||||
|
var_dump(func_get_arg(1));
|
||||||
|
} catch (\Error $e) {
|
||||||
|
echo $e->getMessage() . \PHP_EOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
function bar() {
|
||||||
|
var_dump(func_get_arg(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
function foo() {
|
||||||
|
bar(func_get_arg(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
foo(1,2);
|
||||||
|
} catch (\Error $e) {
|
||||||
|
echo $e->getMessage() . \PHP_EOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
func_get_arg() cannot be called from the global scope
|
||||||
|
func_get_arg(): Argument #1 ($position) must be less than the number of the arguments passed to the currently executed function
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
--TEST--
|
||||||
|
?: operator
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
var_dump(true ?: false);
|
||||||
|
var_dump(false ?: true);
|
||||||
|
var_dump(23 ?: 42);
|
||||||
|
var_dump(0 ?: "bar");
|
||||||
|
|
||||||
|
$a = 23;
|
||||||
|
$b = 0;
|
||||||
|
$c = "";
|
||||||
|
$d = 23.5;
|
||||||
|
|
||||||
|
var_dump($a ?: $b);
|
||||||
|
var_dump($c ?: $d);
|
||||||
|
|
||||||
|
var_dump(1 ?: print(2));
|
||||||
|
|
||||||
|
$e = array();
|
||||||
|
|
||||||
|
$e['e'] = 'e';
|
||||||
|
$e['e'] = $e['e'] ?: 'e';
|
||||||
|
print_r($e);
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
bool(true)
|
||||||
|
bool(true)
|
||||||
|
int(23)
|
||||||
|
string(3) "bar"
|
||||||
|
int(23)
|
||||||
|
float(23.5)
|
||||||
|
int(1)
|
||||||
|
Array
|
||||||
|
(
|
||||||
|
[e] => e
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
--TEST--
|
||||||
|
Implementing abstracting methods and optional parameters
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
abstract class Base
|
||||||
|
{
|
||||||
|
abstract function someMethod($param);
|
||||||
|
}
|
||||||
|
|
||||||
|
class Ext extends Base
|
||||||
|
{
|
||||||
|
function someMethod($param = "default")
|
||||||
|
{
|
||||||
|
echo $param, "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$a = new Ext();
|
||||||
|
$a->someMethod("foo");
|
||||||
|
$a->someMethod();
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
foo
|
||||||
|
default
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
--TEST--
|
||||||
|
Testing variable variables as function name
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
$a = 'ucfirst';
|
||||||
|
$b = 'a';
|
||||||
|
print $$b('test');
|
||||||
|
print "\n";
|
||||||
|
|
||||||
|
|
||||||
|
class bar {
|
||||||
|
public function a() {
|
||||||
|
return "bar!";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class foo {
|
||||||
|
public function test() {
|
||||||
|
print "foo!\n";
|
||||||
|
return new bar;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function test() {
|
||||||
|
return new foo;
|
||||||
|
}
|
||||||
|
|
||||||
|
$a = 'test';
|
||||||
|
$b = 'a';
|
||||||
|
var_dump($$b()->$$b()->$b());
|
||||||
|
|
||||||
|
|
||||||
|
$a = 'strtoupper';
|
||||||
|
$b = 'a';
|
||||||
|
$c = 'b';
|
||||||
|
$d = 'c';
|
||||||
|
var_dump($$$$d('foo'));
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
Test
|
||||||
|
foo!
|
||||||
|
string(4) "bar!"
|
||||||
|
string(3) "FOO"
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
--TEST--
|
||||||
|
Testing operations with undefined variable
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
var_dump($a[1]);
|
||||||
|
var_dump($a[$c]);
|
||||||
|
var_dump($a + 1);
|
||||||
|
var_dump($a + $b);
|
||||||
|
var_dump($a++);
|
||||||
|
var_dump(++$b);
|
||||||
|
var_dump($a->$b);
|
||||||
|
var_dump($a->$b);
|
||||||
|
var_dump($a->$b->{$c[1]});
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
Warning: Undefined variable $a in %s on line %d
|
||||||
|
|
||||||
|
Warning: Trying to access array offset on value of type null in %s on line %d
|
||||||
|
NULL
|
||||||
|
|
||||||
|
Warning: Undefined variable $a in %s on line %d
|
||||||
|
|
||||||
|
Warning: Undefined variable $c in %s on line %d
|
||||||
|
|
||||||
|
Warning: Trying to access array offset on value of type null in %s on line %d
|
||||||
|
NULL
|
||||||
|
|
||||||
|
Warning: Undefined variable $a in %s on line %d
|
||||||
|
int(1)
|
||||||
|
|
||||||
|
Warning: Undefined variable $a in %s on line %d
|
||||||
|
|
||||||
|
Warning: Undefined variable $b in %s on line %d
|
||||||
|
int(0)
|
||||||
|
|
||||||
|
Warning: Undefined variable $a in %s on line %d
|
||||||
|
NULL
|
||||||
|
|
||||||
|
Warning: Undefined variable $b in %s on line %d
|
||||||
|
int(1)
|
||||||
|
|
||||||
|
Warning: Attempt to read property "1" on int in %s on line %d
|
||||||
|
NULL
|
||||||
|
|
||||||
|
Warning: Attempt to read property "1" on int in %s on line %d
|
||||||
|
NULL
|
||||||
|
|
||||||
|
Warning: Undefined variable $c in %s on line %d
|
||||||
|
|
||||||
|
Warning: Trying to access array offset on value of type null in %s on line %d
|
||||||
|
|
||||||
|
Warning: Attempt to read property "1" on int in %s on line %d
|
||||||
|
|
||||||
|
Warning: Attempt to read property "" on null in %s on line %d
|
||||||
|
NULL
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
--TEST--
|
||||||
|
Testing dynamic calls
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class foo {
|
||||||
|
static public function a() {
|
||||||
|
print "ok\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$a = 'a';
|
||||||
|
$b = 'a';
|
||||||
|
|
||||||
|
$class = 'foo';
|
||||||
|
|
||||||
|
foo::a();
|
||||||
|
foo::$a();
|
||||||
|
foo::$$b();
|
||||||
|
|
||||||
|
$class::a();
|
||||||
|
$class::$a();
|
||||||
|
$class::$$b();
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
ok
|
||||||
|
ok
|
||||||
|
ok
|
||||||
|
ok
|
||||||
|
ok
|
||||||
|
ok
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
--TEST--
|
||||||
|
Trying assign value to property when an object is not returned in a function
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class foo {
|
||||||
|
public function a() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$test = new foo;
|
||||||
|
|
||||||
|
$test->a()->a;
|
||||||
|
print "ok\n";
|
||||||
|
|
||||||
|
try {
|
||||||
|
$test->a()->a = 1;
|
||||||
|
} catch (Error $e) {
|
||||||
|
echo $e->getMessage(), "\n";
|
||||||
|
}
|
||||||
|
print "ok\n";
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
Warning: Attempt to read property "a" on null in %s on line %d
|
||||||
|
ok
|
||||||
|
Attempt to assign property "a" on null
|
||||||
|
ok
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
--TEST--
|
||||||
|
Testing dynamic calls using variable variables with curly syntax
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
$a = 'b';
|
||||||
|
$b = 'c';
|
||||||
|
$c = 'strtoupper';
|
||||||
|
|
||||||
|
var_dump(${${$a}}('foo') == 'FOO');
|
||||||
|
|
||||||
|
$a = 'b';
|
||||||
|
$b = 'c';
|
||||||
|
$c = 'strtoupper';
|
||||||
|
$strtoupper = 'strtolower';
|
||||||
|
|
||||||
|
var_dump(${${++$a}}('FOO') == 'foo');
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
bool(true)
|
||||||
|
bool(true)
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
--TEST--
|
||||||
|
Testing function call through of array item
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
$arr = array('strtoupper', 'strtolower');
|
||||||
|
|
||||||
|
$k = 0;
|
||||||
|
|
||||||
|
var_dump($arr[0]('foo') == 'FOO');
|
||||||
|
var_dump($arr[$k]('foo') == 'FOO');
|
||||||
|
var_dump($arr[++$k]('FOO') == 'foo');
|
||||||
|
var_dump($arr[++$k]('FOO') == 'foo');
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
bool(true)
|
||||||
|
bool(true)
|
||||||
|
bool(true)
|
||||||
|
|
||||||
|
Warning: Undefined array key 2 in %s on line %d
|
||||||
|
|
||||||
|
Fatal error: Uncaught Error: Value of type null is not callable in %s:%d
|
||||||
|
Stack trace:
|
||||||
|
#0 {main}
|
||||||
|
thrown in %s on line %d
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
--TEST--
|
||||||
|
Testing assign to property of an object in an array
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
$arr = array(new stdClass);
|
||||||
|
|
||||||
|
$arr[0]->a = clone $arr[0];
|
||||||
|
var_dump($arr);
|
||||||
|
|
||||||
|
$arr[0]->b = new $arr[0];
|
||||||
|
var_dump($arr);
|
||||||
|
|
||||||
|
$arr[0]->c = $arr[0]->a;
|
||||||
|
var_dump($arr);
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
array(1) {
|
||||||
|
[0]=>
|
||||||
|
object(stdClass)#1 (1) {
|
||||||
|
["a"]=>
|
||||||
|
object(stdClass)#2 (0) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
array(1) {
|
||||||
|
[0]=>
|
||||||
|
object(stdClass)#1 (2) {
|
||||||
|
["a"]=>
|
||||||
|
object(stdClass)#2 (0) {
|
||||||
|
}
|
||||||
|
["b"]=>
|
||||||
|
object(stdClass)#3 (0) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
array(1) {
|
||||||
|
[0]=>
|
||||||
|
object(stdClass)#1 (3) {
|
||||||
|
["a"]=>
|
||||||
|
object(stdClass)#2 (0) {
|
||||||
|
}
|
||||||
|
["b"]=>
|
||||||
|
object(stdClass)#3 (0) {
|
||||||
|
}
|
||||||
|
["c"]=>
|
||||||
|
object(stdClass)#2 (0) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
--TEST--
|
||||||
|
Overriding $this in catch and checking the object properties later.
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class foo {
|
||||||
|
public $test = 0;
|
||||||
|
private $test_2 = 1;
|
||||||
|
protected $test_3 = 2;
|
||||||
|
|
||||||
|
public function bar() {
|
||||||
|
try {
|
||||||
|
throw new Exception('foo');
|
||||||
|
} catch (Exception $this) {
|
||||||
|
var_dump($this);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->baz();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function baz() {
|
||||||
|
foreach ($this as $k => $v) {
|
||||||
|
printf("'%s' => '%s'\n", $k, $v);
|
||||||
|
}
|
||||||
|
print "ok\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$test = new foo;
|
||||||
|
$test->bar();
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
Fatal error: Cannot re-assign $this in %s030.php on line 11
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
--TEST--
|
||||||
|
Testing array with '[]' passed as argument by value
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
function test($var) { }
|
||||||
|
test($arr[]);
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
Fatal error: Cannot use [] for reading in %s on line %d
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
--TEST--
|
||||||
|
Testing array with '[]' passed as argument by reference
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
function test(&$var) { }
|
||||||
|
test($arr[]);
|
||||||
|
|
||||||
|
print "ok!\n";
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
ok!
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
--TEST--
|
||||||
|
Using undefined multidimensional array
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
$arr[1][2][3][4][5];
|
||||||
|
|
||||||
|
echo $arr[1][2][3][4][5];
|
||||||
|
|
||||||
|
$arr[1][2][3][4][5]->foo;
|
||||||
|
|
||||||
|
try {
|
||||||
|
$arr[1][2][3][4][5]->foo = 1;
|
||||||
|
} catch (Error $e) {
|
||||||
|
echo $e->getMessage(), "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
$arr[][] = 2;
|
||||||
|
|
||||||
|
try {
|
||||||
|
$arr[][]->bar = 2;
|
||||||
|
} catch (Error $e) {
|
||||||
|
echo $e->getMessage(), "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
Warning: Undefined variable $arr in %s on line %d
|
||||||
|
|
||||||
|
Warning: Trying to access array offset on value of type null in %s on line %d
|
||||||
|
|
||||||
|
Warning: Trying to access array offset on value of type null in %s on line %d
|
||||||
|
|
||||||
|
Warning: Trying to access array offset on value of type null in %s on line %d
|
||||||
|
|
||||||
|
Warning: Trying to access array offset on value of type null in %s on line %d
|
||||||
|
|
||||||
|
Warning: Trying to access array offset on value of type null in %s on line %d
|
||||||
|
|
||||||
|
Warning: Undefined variable $arr in %s on line %d
|
||||||
|
|
||||||
|
Warning: Trying to access array offset on value of type null in %s on line %d
|
||||||
|
|
||||||
|
Warning: Trying to access array offset on value of type null in %s on line %d
|
||||||
|
|
||||||
|
Warning: Trying to access array offset on value of type null in %s on line %d
|
||||||
|
|
||||||
|
Warning: Trying to access array offset on value of type null in %s on line %d
|
||||||
|
|
||||||
|
Warning: Trying to access array offset on value of type null in %s on line %d
|
||||||
|
|
||||||
|
Warning: Undefined variable $arr in %s on line %d
|
||||||
|
|
||||||
|
Warning: Trying to access array offset on value of type null in %s on line %d
|
||||||
|
|
||||||
|
Warning: Trying to access array offset on value of type null in %s on line %d
|
||||||
|
|
||||||
|
Warning: Trying to access array offset on value of type null in %s on line %d
|
||||||
|
|
||||||
|
Warning: Trying to access array offset on value of type null in %s on line %d
|
||||||
|
|
||||||
|
Warning: Trying to access array offset on value of type null in %s on line %d
|
||||||
|
|
||||||
|
Warning: Attempt to read property "foo" on null in %s on line %d
|
||||||
|
Attempt to assign property "foo" on null
|
||||||
|
Attempt to assign property "bar" on null
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
--TEST--
|
||||||
|
Testing multiples 'default:' in switch
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
switch (1) {
|
||||||
|
case 2:
|
||||||
|
print 'foo';
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
print 'bar';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
print 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
print 2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
print 3;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
Fatal error: Switch statements may only contain one default clause in %s on line 13
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
--TEST--
|
||||||
|
Using 'static' and 'global' in global scope
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
static $var, $var, $var = -1;
|
||||||
|
var_dump($var);
|
||||||
|
|
||||||
|
global $var, $var, $var;
|
||||||
|
var_dump($var);
|
||||||
|
|
||||||
|
var_dump($GLOBALS['var']);
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
int(-1)
|
||||||
|
int(-1)
|
||||||
|
int(-1)
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
--TEST--
|
||||||
|
Trying to use lambda in array offset
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
try {
|
||||||
|
$test[function(){}] = 1;
|
||||||
|
} catch (Error $e) {
|
||||||
|
echo $e->getMessage(), "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
Illegal offset type
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
--TEST--
|
||||||
|
Trying to access inexistent static property of Closure
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace closure;
|
||||||
|
|
||||||
|
class closure { static $x = 1;}
|
||||||
|
|
||||||
|
$x = __NAMESPACE__;
|
||||||
|
var_dump(closure::$x);
|
||||||
|
|
||||||
|
var_dump($x::$x);
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
int(1)
|
||||||
|
|
||||||
|
Fatal error: Uncaught Error: Access to undeclared static property Closure::$x in %s:%d
|
||||||
|
Stack trace:
|
||||||
|
#0 {main}
|
||||||
|
thrown in %s on line %d
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
--TEST--
|
||||||
|
Trying to use lambda as array key
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
try {
|
||||||
|
var_dump(array(function() { } => 1));
|
||||||
|
} catch (Error $e) {
|
||||||
|
echo $e->getMessage(), "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
Illegal offset type
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
--TEST--
|
||||||
|
Bug #67468 (Segfault in highlight_file()/highlight_string())
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
highlight_string("<?php __CLASS__;", true);
|
||||||
|
echo "done";
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
done
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
--TEST--
|
||||||
|
Using indirect append on ArrayAccess object
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class AA implements ArrayAccess {
|
||||||
|
private $data = [];
|
||||||
|
public function &offsetGet($name) {
|
||||||
|
if (null === $name) {
|
||||||
|
return $this->data[];
|
||||||
|
} else {
|
||||||
|
return $this->data[$name];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public function offsetSet($name, $value) {
|
||||||
|
$this->data[$name] = $value;
|
||||||
|
}
|
||||||
|
public function offsetUnset($name) {}
|
||||||
|
public function offsetExists($name) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
$aa = new AA;
|
||||||
|
$aa[3] = 1;
|
||||||
|
$aa[][][0] = 2;
|
||||||
|
var_dump($aa);
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
object(AA)#1 (1) {
|
||||||
|
["data":"AA":private]=>
|
||||||
|
array(2) {
|
||||||
|
[3]=>
|
||||||
|
int(1)
|
||||||
|
[4]=>
|
||||||
|
array(1) {
|
||||||
|
[0]=>
|
||||||
|
array(1) {
|
||||||
|
[0]=>
|
||||||
|
int(2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
--TEST--
|
||||||
|
Test default value handling of ErrorException::__construct()
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
$e = new ErrorException();
|
||||||
|
var_dump($e->getMessage());
|
||||||
|
var_dump($e->getFile());
|
||||||
|
var_dump($e->getLine());
|
||||||
|
|
||||||
|
$e = new ErrorException("Second", 0, E_ERROR, null);
|
||||||
|
var_dump($e->getMessage());
|
||||||
|
var_dump($e->getFile());
|
||||||
|
var_dump($e->getLine());
|
||||||
|
|
||||||
|
$e = new ErrorException("Third", 0, E_ERROR, null, null);
|
||||||
|
var_dump($e->getMessage());
|
||||||
|
var_dump($e->getFile());
|
||||||
|
var_dump($e->getLine());
|
||||||
|
|
||||||
|
$e = new ErrorException("Forth", 0, E_ERROR, null, 123);
|
||||||
|
var_dump($e->getMessage());
|
||||||
|
var_dump($e->getFile());
|
||||||
|
var_dump($e->getLine());
|
||||||
|
|
||||||
|
$e = new ErrorException("Fifth", 0, E_ERROR, "abc.php");
|
||||||
|
var_dump($e->getMessage());
|
||||||
|
var_dump($e->getFile());
|
||||||
|
var_dump($e->getLine());
|
||||||
|
|
||||||
|
$e = new ErrorException("Sixth", 0, E_ERROR, "abc.php", null);
|
||||||
|
var_dump($e->getMessage());
|
||||||
|
var_dump($e->getFile());
|
||||||
|
var_dump($e->getLine());
|
||||||
|
|
||||||
|
$e = new ErrorException("Seventh", 0, E_ERROR, "abc.php", 123);
|
||||||
|
var_dump($e->getMessage());
|
||||||
|
var_dump($e->getFile());
|
||||||
|
var_dump($e->getLine());
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
string(0) ""
|
||||||
|
string(%d) "%sErrorException_construct.php"
|
||||||
|
int(3)
|
||||||
|
string(6) "Second"
|
||||||
|
string(%d) "%sErrorException_construct.php"
|
||||||
|
int(8)
|
||||||
|
string(5) "Third"
|
||||||
|
string(%d) "%sErrorException_construct.php"
|
||||||
|
int(13)
|
||||||
|
string(5) "Forth"
|
||||||
|
string(%d) "%sErrorException_construct.php"
|
||||||
|
int(123)
|
||||||
|
string(5) "Fifth"
|
||||||
|
string(7) "abc.php"
|
||||||
|
int(0)
|
||||||
|
string(5) "Sixth"
|
||||||
|
string(7) "abc.php"
|
||||||
|
int(0)
|
||||||
|
string(7) "Seventh"
|
||||||
|
string(7) "abc.php"
|
||||||
|
int(123)
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,12 @@
|
||||||
|
--TEST--
|
||||||
|
Test for abstract static classes
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
abstract class TestClass
|
||||||
|
{
|
||||||
|
abstract static public function getName();
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
===DONE===
|
||||||
|
--EXPECT--
|
||||||
|
===DONE===
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
--TEST--
|
||||||
|
Allow abstract function override
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
abstract class A { abstract function bar($x); }
|
||||||
|
abstract class B extends A { abstract function bar($x); }
|
||||||
|
|
||||||
|
echo "DONE";
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
DONE
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
--TEST--
|
||||||
|
Allow abstract function override
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
abstract class A { abstract function bar($x); }
|
||||||
|
abstract class B extends A { abstract function bar($x, $y = 0); }
|
||||||
|
|
||||||
|
echo "DONE";
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
DONE
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
--TEST--
|
||||||
|
Allow abstract function override
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
abstract class A { abstract function bar($x, $y = 0); }
|
||||||
|
abstract class B extends A { abstract function bar($x); }
|
||||||
|
|
||||||
|
echo "DONE";
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
Fatal error: Declaration of B::bar($x) must be compatible with A::bar($x, $y = 0) in %s
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
--TEST--
|
||||||
|
using multiple access modifiers (methods)
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class test {
|
||||||
|
static public public static final public final function foo() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Done\n";
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
Fatal error: Multiple access type modifiers are not allowed in %s on line %d
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
--TEST--
|
||||||
|
using multiple access modifiers (attributes)
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class test {
|
||||||
|
static public public static final public final $var;
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Done\n";
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
Fatal error: Multiple access type modifiers are not allowed in %s on line %d
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue