Add PHP 7 binding (#28608)

License: MIT
This commit is contained in:
Tomohiro "Tomo-p" KATO 2018-12-05 05:22:07 +09:00 committed by Benjamin Dauvergne
parent 37a0fa6f8b
commit 9c8c4b9937
19 changed files with 2150 additions and 5 deletions

View File

@ -6,6 +6,9 @@ endif
if PHP5_ENABLED
SUBDIRS += php5
endif
if PHP7_ENABLED
SUBDIRS += php7
endif
if JAVA_ENABLED
SUBDIRS += java
endif
@ -15,7 +18,10 @@ endif
CLEANFILES = bindings.pyc lang_java.pyc lang_python.pyc lang_php5.pyc \
utils.pyc lang_php5_helpers/__init__.pyc lang_php5_helpers/php_code.pyc \
lang_php5_helpers/wrapper_header.pyc lang_php5_helpers/wrapper_source.pyc
lang_php5_helpers/wrapper_header.pyc lang_php5_helpers/wrapper_source.pyc \
lang_php7.pyc \
lang_php7_helpers/__init__.pyc lang_php7_helpers/php_code.pyc \
lang_php7_helpers/wrapper_header.pyc lang_php7_helpers/wrapper_source.pyc
EXTRA_DIST = bindings.py \
overrides.xml \

View File

@ -629,6 +629,11 @@ def main():
php5_binding = lang.Binding(binding)
php5_binding.generate()
elif options.language == 'php7':
from php7 import lang
php7_binding = lang.Binding(binding)
php7_binding.generate()
elif options.language == 'java':
from java import lang

View File

@ -198,10 +198,10 @@
<func name="lasso_log_set_handler" skip="true"/>
<func name="lasso_log_remove_handler" skip="true"/>
<func name="lasso_key_new_for_signature_from_memory" skip="true"/>
<func name="lasso_samlp2_extensions_get_any" skip="php5,perl,java"/>
<func name="lasso_samlp2_extensions_set_any" skip="php5,perl,java"/>
<func name="lasso_samlp2_extensions_get_attributes" skip="php5,perl,java"/>
<func name="lasso_samlp2_extensions_set_attributes" skip="php5,perl,java"/>
<func name="lasso_samlp2_extensions_get_any" skip="php5,php7,perl,java"/>
<func name="lasso_samlp2_extensions_set_any" skip="php5,php7,perl,java"/>
<func name="lasso_samlp2_extensions_get_attributes" skip="php5,php7,perl,java"/>
<func name="lasso_samlp2_extensions_set_attributes" skip="php5,php7,perl,java"/>
<!-- Xml -->
<func name="lasso_node_export_to_soap_with_headers">
<param name="node"/>

41
bindings/php7/Makefile.am Normal file
View File

@ -0,0 +1,41 @@
CLEANFILES = lasso.php php_lasso.h _lasso.c
DISTCLEANFILES = __init__.pyc lang.pyc php_code.pyc wrapper_header.pyc wrapper_top.pyc wrapper_source.pyc
SUBDIRS = examples tests
AM_CPPFLAGS = \
-I$(top_builddir) \
-I$(top_srcdir) \
$(SASL_CFLAGS)
php_extensiondir = ${prefix}@PHP7_UNPREFIXED_EXTENSION_DIR@
php_extension_LTLIBRARIES = lasso.la
php_includedir = @PHP7_INCLUDE_DIR@
nodist_php_include_DATA = lasso.php
php_configdir=@PHP7_CONFIG_DIR@
php_config_DATA = lasso.ini
lasso_la_CFLAGS = -fno-strict-aliasing $(LASSO_CORE_CFLAGS) -I$(top_srcdir) -I$(top_builddir) $(PHP7_INCLUDES) $(AM_CFLAGS)
lasso_la_CFLAGS += -Wno-unused-parameter -Wno-sign-compare # problem in zend.h
lasso_la_LDFLAGS = -export-dynamic -prefer-pic -module -avoid-version
lasso_la_LIBADD = $(top_builddir)/lasso/liblasso.la $(LASSO_LIBS) $(PHP7_LDFLAGS)
nodist_lasso_la_SOURCES = _lasso.c
BUILT_SOURCES = _lasso.c
if WSF_ENABLED
EXTRA_ARGS = --enable-id-wsf
endif
lasso.php _lasso.c: lang.py wrapper_source.py wrapper_header.py wrapper_source_top.c php_code.py ../overrides.xml
$(AM_V_GEN) $(PYTHON) $(top_srcdir)/bindings/bindings.py -l php7 --src-dir=$(top_srcdir)/lasso/ $(EXTRA_ARGS)
doc:
phpdoc -o HTML:frames:earthli -f lasso.php -t docs
.PHONY: doc
EXTRA_DIST = lasso.ini lang.py php_code.py wrapper_header.py wrapper_source.py __init__.py wrapper_source_top.c

View File

View File

@ -0,0 +1,2 @@
MAINTAINERCLEANFILES = Makefile.in
EXTRA_DIST = get_attributes_from_assertion.php

View File

@ -0,0 +1,11 @@
/* Example SP PHP5 code to get attributes from an assertion */
foreach ($assertion->attributeStatement[0]->attribute as $attribute) {
if ($attribute->name == LASSO_SAML2_ATTRIBUTE_NAME_EPR) {
continue;
}
echo 'attribute : ' . $attribute->name . "\n";
foreach ($attribute->attributeValue as $value) {
echo ' value : ' . $value->any[0]->content . "\n";
}
}

43
bindings/php7/lang.py Normal file
View File

@ -0,0 +1,43 @@
# Lasso - A free implementation of the Liberty Alliance specifications.
#
# Copyright (C) 2004-2007 Entr'ouvert
# http://lasso.entrouvert.org
#
# Authors: See AUTHORS file in top-level directory.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <http://www.gnu.org/licenses/>.
import os
from php7.wrapper_source import WrapperSource
from php7.wrapper_header import WrapperHeader
from php7.php_code import PhpCode
class Binding:
def __init__(self, binding_data):
self.binding_data = binding_data
def generate(self):
fd = open('_lasso.c', 'w')
wrapper_source = WrapperSource(self.binding_data, fd)
wrapper_source.generate()
fd.close()
fd = open('php_lasso.h', 'w')
WrapperHeader(self.binding_data, fd, wrapper_source.functions_list).generate()
fd.close()
fd = open('lasso.php', 'w')
PhpCode(self.binding_data, fd).generate()
fd.close()

2
bindings/php7/lasso.ini Normal file
View File

@ -0,0 +1,2 @@
; configuration for php PDO module
extension=lasso.so

511
bindings/php7/php_code.py Normal file
View File

@ -0,0 +1,511 @@
# Lasso - A free implementation of the Liberty Alliance specifications.
#
# Copyright (C) 2004-2007 Entr'ouvert
# http://lasso.entrouvert.org
#
# Authors: See AUTHORS file in top-level directory.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <http://www.gnu.org/licenses/>.
import re
import sys
import six
from utils import *
class PhpCode:
def __init__(self, binding_data, fd):
self.binding_data = binding_data
self.fd = fd
def is_object(self, t):
return is_object(t) and not is_int(t, self.binding_data)
def generate(self):
self.generate_header()
for klass in self.binding_data.structs:
self.generate_class(klass)
self.generate_exceptions()
self.generate_footer()
def generate_header(self):
six.print_('''\
<?php
/* this file has been generated automatically; do not edit */
/**
* @package Lasso
*/
// Try to load Lasso extension if it's not already loaded.
if (!extension_loaded('lasso')) {
die("Lasso extension is not loaded");
}
/**
* @package Lasso
*
* Root class of all Lasso objects to define generic getter and setter
*/
class LassoObject {
/**
* @return mixed
*/
public function __get($attr) {
$func = "get_" . $attr;
if (method_exists($this, $func)) {
return call_user_func(array($this, $func));
}
return null;
}
public function __set($attr, $value) {
$func = "set_" . $attr;
if (method_exists($this, $func)) {
call_user_func(array($this, $func), $value);
}
}
}
/*
* Convert a C object to a PHP object
*/
function cptrToPhp ($cptr) {
if (is_null($cptr) || !$cptr) return null;
$typename = lasso_get_object_typename($cptr);
$class_name = $typename . "NoInit";
$obj = new $class_name();
if (! is_null($obj)) {
$obj->_cptr = $cptr;
return $obj;
}
return null;
}
function lassoGetRequestTypeFromSoapMsg($mesg) {
return lasso_get_request_type_from_soap_msg($mesg);
}
function lassoRegisterIdWsf2DstService($prefix, $href) {
lasso_register_idwsf2_dst_service($prefix, $href);
}
''', file=self.fd)
def generate_class(self, klass):
class_name = klass.name
if klass.parent != 'GObject':
inheritence = ' extends %s' % klass.parent
else:
inheritence = ' extends LassoObject'
six.print_('/**', file=self.fd)
six.print_(' * @package Lasso', file=self.fd)
six.print_(' */', file=self.fd)
six.print_('class %(class_name)s%(inheritence)s {' % locals(), file=self.fd)
if klass.members or klass.methods:
self.generate_constructors(klass)
self.generate_getters_and_setters(klass)
self.generate_methods(klass)
six.print_('}', file=self.fd)
six.print_('', file=self.fd)
# Add a special class to get an object instance without initialising
six.print_('/**', file=self.fd)
six.print_(' * @package Lasso', file=self.fd)
six.print_(' */', file=self.fd)
six.print_('class %(class_name)sNoInit extends %(class_name)s {' % locals(), file=self.fd)
six.print_(' public function __construct() {}', file=self.fd)
six.print_('}', file=self.fd)
six.print_('', file=self.fd)
def generate_constructors(self, klass):
method_prefix = format_as_underscored(klass.name) + '_'
for m in self.binding_data.functions:
name = m.rename or m.name
if m.name == method_prefix + 'new':
php_args = []
c_args = []
for arg in m.args:
arg_type, arg_name, arg_options = arg
if arg_options.get('optional'):
php_args.append('$%s = null' % arg_name)
else:
php_args.append('$%s' % arg_name)
if self.is_object(arg_type):
c_args.append('$%s->_cptr' % arg_name)
else:
c_args.append('$%s' % arg_name)
php_args = ', '.join(php_args)
c_args = ', '.join(c_args)
# XXX: could check $this->_cptr->typename to see if it got the
# right class type
six.print_(' public $_cptr = null;', file=self.fd)
six.print_('', file=self.fd)
six.print_(' public function __construct(%s) {' % php_args, file=self.fd)
six.print_(' $this->_cptr = %s(%s);' % (m.name, c_args), file=self.fd)
six.print_(' if (is_null($this->_cptr)) { throw new Exception("Constructor for ', klass.name, ' failed "); }', file=self.fd)
six.print_(' }', file=self.fd)
six.print_('', file=self.fd)
elif name.startswith(method_prefix) and m.args \
and clean_type(unconstify(m.args[0][0])) != klass.name:
if m.rename:
php_name = m.rename
else:
mname = m.name
mname = mname[len(method_prefix):]
if 'new' in mname and not mname.startswith('new'):
continue
php_name = format_underscore_as_camelcase(mname)
php_args = []
c_args = []
for arg in m.args:
arg_type, arg_name, arg_options = arg
if arg_options.get('optional'):
php_args.append('$%s = null' % arg_name)
else:
php_args.append('$%s' % arg_name)
if self.is_object(arg_type):
c_args.append('$%s->_cptr' % arg_name)
else:
c_args.append('$%s' % arg_name)
php_args = ', '.join(php_args)
c_args = ', '.join(c_args)
six.print_(' public static function %s(%s) {' % (php_name, php_args), file=self.fd)
six.print_(' return cptrToPhp(%s(%s));' % (m.name, c_args), file=self.fd)
six.print_(' }', file=self.fd)
six.print_('', file=self.fd)
def generate_getter(self, c, m):
d = {
'type': arg_type(m),
'name': format_as_camelcase(arg_name(m)),
'docstring': self.get_docstring_return_type(arg_type(m)),
'class': c.name
}
six.print_('''\
/**
* @return %(docstring)s
*/
protected function get_%(name)s() {''' % d, file=self.fd)
six.print_(' $t = %(class)s_%(name)s_get($this->_cptr);' % d, file=self.fd)
if self.is_object(m):
six.print_(' $t = cptrToPhp($t);', file=self.fd)
elif (is_glist(m) or is_hashtable(m)) and self.is_object(element_type(m)):
six.print_(' foreach ($t as $key => $item) {', file=self.fd)
six.print_(' $t[$key] = cptrToPhp($item);', file=self.fd)
six.print_(' }', file=self.fd)
elif is_hashtable(m) or (is_glist(m) and (is_cstring(element_type(m)) \
or is_xml_node(element_type(m)))) or is_int(m, self.binding_data) \
or is_boolean(m) or is_cstring(m) or is_xml_node(m):
pass
else:
raise Exception('Cannot generate a Php getter %s.%s' % (c,m))
six.print_(' return $t;', file=self.fd)
six.print_(' }', file=self.fd)
def generate_setter(self, c, m):
d = { 'type': arg_type(m), 'name': format_as_camelcase(arg_name(m)),
'docstring': self.get_docstring_return_type(arg_type(m)), 'class': c.name }
six.print_(' protected function set_%(name)s($value) {' % d, file=self.fd)
if self.is_object(m):
six.print_(' $value = $value->_cptr;', file=self.fd)
elif (is_glist(m) or is_hashtable(m)) and self.is_object(element_type(m)):
six.print_(' $array = array();', file=self.fd)
six.print_(' if (!is_null($value)) {', file=self.fd)
six.print_(' foreach ($value as $key => $item) {', file=self.fd)
six.print_(' $array[$key] = $item->_cptr;', file=self.fd)
six.print_(' }', file=self.fd)
six.print_(' }', file=self.fd)
six.print_(' $value = $array;', file=self.fd)
elif is_hashtable(m) or (is_glist(m) and (is_cstring(element_type(m)) \
or is_xml_node(element_type(m)))) or is_int(m, self.binding_data) \
or is_boolean(m) or is_cstring(m) or is_xml_node(m):
pass
else:
raise Exception('Cannot generate a Php setter %s.%s' % (c,m))
six.print_(' %(class)s_%(name)s_set($this->_cptr, $value);' % d, file=self.fd)
six.print_(' }', file=self.fd)
six.print_('', file=self.fd)
def generate_getters_and_setters(self, klass):
for m in klass.members:
self.generate_getter(klass, m)
self.generate_setter(klass, m)
def generate_methods(self, klass):
methods = klass.methods[:]
# first pass on methods, removing accessors
for m in klass.methods:
if m.rename:
meth_name = m.rename
else:
meth_name = m.name
if not ('_get_' in meth_name and len(m.args) == 1):
continue
methods.remove(m)
try:
setter_name = meth_name.replace('_get_', '_set_')
setter = [x for x in methods if x.name == setter_name][0]
methods.remove(setter)
except IndexError:
setter = None
mname = re.match(r'lasso_.*_get_(\w+)', meth_name).group(1)
mname = format_as_camelcase(mname)
six.print_(' /**', file=self.fd)
six.print_(' * @return %s' % self.get_docstring_return_type(m.return_type), file=self.fd)
six.print_(' */', file=self.fd)
six.print_(' protected function get_%s() {' % mname, file=self.fd)
if self.is_object(m.return_type):
six.print_(' $cptr = %s($this->_cptr);' % meth_name, file=self.fd)
six.print_(' if (! is_null($cptr)) {', file=self.fd)
six.print_(' return cptrToPhp($cptr);', file=self.fd)
six.print_(' }', file=self.fd)
six.print_(' return null;', file=self.fd)
else:
six.print_(' return %s($this->_cptr);' % meth_name, file=self.fd)
six.print_(' }', file=self.fd)
if setter:
six.print_(' protected function set_%s($value) {' % mname, file=self.fd)
if self.is_object(m.return_type):
six.print_(' %s($this->_cptr, $value->_cptr);' % setter.name, file=self.fd)
else:
six.print_(' %s($this->_cptr, $value);' % setter.name, file=self.fd)
six.print_(' }', file=self.fd)
six.print_('', file=self.fd)
# second pass on methods, real methods
method_prefix = format_as_underscored(klass.name) + '_'
for m in methods:
if m.name.endswith('_new') or m.name.endswith('_new_from_dump') or \
m.name.endswith('_new_full'):
continue
if not m.name.startswith(method_prefix):
print >> sys.stderr, 'W:', m.name, 'vs', method_prefix
continue
if m.rename:
mname = m.rename
else:
mname = m.name
cname = mname
mname = mname[len(method_prefix):]
php_args = []
c_args = []
outarg = None
for arg in m.args[1:]:
arg_type, arg_name, arg_options = arg
arg_name = '$' + arg_name
if is_out(arg):
assert not outarg
outarg = arg
if arg_options.get('optional'):
if arg_options.get('default'):
defval = arg_options.get('default')
if defval.startswith('c:'): # constant
php_args.append('%s = %s' % (arg_name, defval[2:]))
elif defval.startswith('b:'): # boolean
php_args.append('%s = %s' % (arg_name, defval[2:]))
else:
print >> sys.stderr, "E: don't know what to do with %s" % defval
sys.exit(1)
else:
php_args.append('%s = null' % arg_name)
else:
php_args.append(arg_name)
if is_xml_node(arg) or is_boolean(arg) or is_cstring(arg) or \
is_int(arg, self.binding_data) or is_glist(arg) or \
is_hashtable(arg) or is_time_t_pointer(arg):
c_args.append(arg_name)
elif self.is_object(arg):
c_args.append('%s->_cptr' % arg_name)
else:
raise Exception('Does not handle argument of type: %s' % ((m, arg),))
if is_out(arg):
php_args.pop()
php_args.append(arg_name)
c_args.pop()
c_args.append(arg_name)
if php_args:
php_args = ', '.join(php_args)
else:
php_args = ''
if c_args:
c_args = ', ' + ', '.join(c_args)
else:
c_args = ''
if m.docstring:
six.print_(self.generate_docstring(m, mname, 4), file=self.fd)
six.print_(' public function %s(%s) {' % (
format_underscore_as_camelcase(mname), php_args), file=self.fd)
if m.return_type == 'void':
six.print_(' %s($this->_cptr%s);' % (cname, c_args), file=self.fd)
elif is_rc(m.return_type):
six.print_(' $rc = %s($this->_cptr%s);' % (cname, c_args), file=self.fd)
six.print_(' if ($rc == 0) {', file=self.fd)
six.print_(' return 0;', file=self.fd)
six.print_(' } else if ($rc > 0) {', file=self.fd) # recoverable error
six.print_(' return $rc;', file=self.fd)
six.print_(' } else if ($rc < 0) {', file=self.fd) # unrecoverable error
six.print_(' LassoError::throw_on_rc($rc);', file=self.fd)
six.print_(' }', file=self.fd)
else:
six.print_(' return %s($this->_cptr%s);' % (cname, c_args), file=self.fd)
six.print_(' }', file=self.fd)
six.print_('', file=self.fd)
six.print_('', file=self.fd)
def generate_docstring(self, func, method_name, indent):
docstring = func.docstring.orig_docstring
if func.args:
first_arg_name = func.args[0][1]
else:
first_arg_name = None
def rep(s):
type = s.group(1)[0]
var = s.group(1)[1:]
if type == '#': # struct
return var
elif type == '%': # %TRUE, %FALSE
if var in ('TRUE', 'FALSE'):
return var
print >> sys.stderr, 'W: unknown docstring thingie \'%s\' in \'%s\'' % (s.group(1), func.docstring.orig_docstring)
elif type == '@':
if var == first_arg_name:
return '$this'
else:
return '$' + var
return s.group(1)
lines = []
for l in docstring.splitlines():
if l.strip() and not lines:
continue
lines.append(l)
s = indent * ' ' + '/**\n'
s += '\n'.join([indent * ' ' + ' * ' + x for x in lines[1:]])
s += '\n' + indent * ' ' + ' */'
regex = re.compile(r'([\#%@]\w+)', re.DOTALL)
s = regex.sub(rep, s)
s = s.replace('Return value: ', '@return %s ' % self.get_docstring_return_type(func.return_type))
return s
def get_docstring_return_type(self, return_type):
if return_type == None:
return ''
elif return_type == 'gboolean':
return 'boolean'
elif return_type in ['int', 'gint'] + self.binding_data.enums:
return 'int'
elif return_type in ('char*', 'gchar*', 'const char*', 'const gchar*', 'xmlNode*'):
return 'string'
elif return_type in ('GList*', 'GHashTable*'):
return 'array'
else:
# Objects
return return_type.replace('*', '')
def generate_exceptions(self):
done_cats = []
for exc_cat in self.binding_data.overrides.findall('exception/category'):
cat = exc_cat.attrib.get('name')
done_cats.append(cat)
parent_cat = exc_cat.attrib.get('parent', '')
six.print_('''\
/**
* @package Lasso
*/
class Lasso%sError extends Lasso%sError {}
''' % (cat, parent_cat), file=self.fd)
exceptions_dict = {}
for c in self.binding_data.constants:
m = re.match(r'LASSO_(\w+)_ERROR_(.*)', c[1])
if not m:
continue
cat, detail = m.groups()
cat = cat.title().replace('_', '')
detail = (cat + '_' + detail).title().replace('_', '')
if not cat in done_cats:
done_cats.append(cat)
for exc_cat in self.binding_data.overrides.findall('exception/category'):
if exc_cat.attrib.get('name') == cat:
parent_cat = exc_cat.attrib.get('parent')
break
else:
parent_cat = ''
six.print_('''\
/**
* @package Lasso
*/
class Lasso%sError extends Lasso%sError {}
''' % (cat, parent_cat), file=self.fd)
if detail not in exceptions_dict:
six.print_('''\
/**
* @package Lasso
*/
class Lasso%sError extends Lasso%sError {
protected $code = %s;
}
''' % (detail, cat, c[1]), file=self.fd)
exceptions_dict[detail] = c[1]
six.print_('''\
/**
* @package Lasso
*/
class LassoError extends Exception {
private static $exceptions_dict = array(''', file=self.fd)
for k, v in exceptions_dict.items():
six.print_(' %s => "Lasso%sError",' % (v, k), file=self.fd)
six.print_('''\
);
public static function throw_on_rc($rc) {
$exception = self::$exceptions_dict[$rc];
if (! class_exists($exception)) {
$exception = "LassoError";
}
throw new $exception(strError($rc), $rc);
}
}
''', file=self.fd)
def generate_footer(self):
six.print_('''\
?>''', file=self.fd)

View File

@ -0,0 +1,8 @@
MAINTAINERCLEANFILES = Makefile.in
if PHP7_ENABLED
TESTS_ENVIRONMENT=env "SRCDIR=$(srcdir)/" "PHP7=$(PHP7)"
TESTS = profile_tests.sh binding_tests.sh
endif
EXTRA_DIST = profile_tests.php binding_tests.php profile_tests.sh binding_tests.sh

View File

@ -0,0 +1,211 @@
#!/usr/bin/php
<?php
# Lasso - A free implementation of the Liberty Alliance specifications.
#
# Copyright (C) 2004-2007 Entr'ouvert
# http://lasso.entrouvert.org
#
# Authors: See AUTHORS file in top-level directory.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <http://www.gnu.org/licenses/>.
require("../lasso.php");
define("DATA_DIR", getenv("SRCDIR") . "../../../tests/data/");
function test01() {
echo "Get an xmlNode* from a Lasso function... ";
$organisation_string = '<Organization xmlns="urn:liberty:metadata:2003-08">
<OrganizationName>Name of the organization</OrganizationName>
</Organization>';
$server = new LassoServer(
DATA_DIR . "sp1-la/metadata.xml",
DATA_DIR . "sp1-la/private-key-raw.pem",
NULL,
DATA_DIR . "sp1-la/certificate.pem");
assert(!is_null($server->organization));
assert($server->organization == $organisation_string);
echo "OK.\n";
}
function test02() {
echo "Get and set a list of strings... ";
$requestAuthnContext = new LassoLibRequestAuthnContext();
$requestAuthnContext->authnContextClassRef = array(LASSO_LIB_AUTHN_CONTEXT_CLASS_REF_PASSWORD);
assert(! is_null($requestAuthnContext->authnContextClassRef));
assert(sizeof($requestAuthnContext->authnContextClassRef) == 1);
assert($requestAuthnContext->authnContextClassRef[0] == LASSO_LIB_AUTHN_CONTEXT_CLASS_REF_PASSWORD);
echo "OK.\n";
}
function test03() {
echo "Get and set a list of xmlNode*... ";
$server = new LassoServer(
DATA_DIR . "sp1-la/metadata.xml",
DATA_DIR . "sp1-la/private-key-raw.pem",
NULL,
DATA_DIR . "sp1-la/certificate.pem");
$server->addProvider(
LASSO_PROVIDER_ROLE_IDP,
DATA_DIR . "idp1-la/metadata.xml",
DATA_DIR . "idp1-la/public-key.pem",
DATA_DIR . "idp1-la/certificate.pem");
$login = new LassoLogin($server);
$login->initAuthnRequest();
$requestAuthnContext = new LassoLibRequestAuthnContext();
$extension1 = '<lib:Extension xmlns:lib="urn:liberty:iff:2003-08">
<action>do</action>
</lib:Extension>';
$extension2 = '<lib:Extension xmlns:lib="urn:liberty:iff:2003-08">
<action2>do action 2</action2><action3>do action 3</action3>
</lib:Extension>';
$extensionList = array($extension1, $extension2);
$login->request->extension = $extensionList;
assert($login->request->extension == $extensionList);
assert($login->request->extension[0] == $extension1);
assert($login->request->extension[1] == $extension2);
echo "OK.\n";
}
function test04() {
echo "Get and set a list of Lasso objects... ";
$response = new LassoSamlpResponse();
assert(!$response->assertion);
$assertions = array();
$assertion1 = new LassoSamlAssertion();
$assertion1->assertionId = "assertion 1";
$assertions[] = $assertion1;
assert($assertions[0]->assertionId == "assertion 1");
$assertion2 = new LassoSamlAssertion();
$assertion2->assertionId = "assertion 2";
$assertions[] = $assertion2;
$response->assertion = $assertions;
assert($response->assertion[0]->assertionId == "assertion 1");
assert($response->assertion[1]->assertionId == "assertion 2");
unset($assertions);
assert($response->assertion[0]->assertionId == "assertion 1");
assert($response->assertion[1]->assertionId == "assertion 2");
$assertions = $response->assertion;
assert($assertions[0]->assertionId == "assertion 1");
assert($assertions[1]->assertionId == "assertion 2");
echo "OK.\n";
}
function test05() {
echo "Get and set a hashtable of objects... ";
$server = new LassoServer(
DATA_DIR . "sp1-la/metadata.xml",
DATA_DIR . "sp1-la/private-key-raw.pem",
NULL,
DATA_DIR . "sp1-la/certificate.pem");
$server->addProvider(
LASSO_PROVIDER_ROLE_IDP,
DATA_DIR . "idp1-la/metadata.xml",
DATA_DIR . "idp1-la/public-key.pem",
DATA_DIR . "idp1-la/certificate.pem");
assert(!is_null($server->providers));
assert($server->providers["https://idp1/metadata"]->providerId == "https://idp1/metadata");
assert($server->providers["https://idp1/metadata"]->providerId == "https://idp1/metadata");
$tmp_providers = $server->providers;
$server->providers = NULL;
assert(!$server->providers);
$server->providers = $tmp_providers;
$provider = $server->providers["https://idp1/metadata"];
assert($server->providers["https://idp1/metadata"]->providerId == "https://idp1/metadata");
echo "OK.\n";
}
function test06() {
echo "Get and set SAML 2.0 assertion attribute values... ";
$attribute1_name = "first attribute";
$attribute1_string = "first string";
$attribute2_name = "second attribute";
$attribute2_string = "second string";
$attribute3_string = "third string";
$expected_assertion_dump = '<saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" SignType="0" SignMethod="0" EncryptionActivated="false" EncryptionSymKeyType="0"><saml:AttributeStatement><saml:Attribute Name="first attribute"><saml:AttributeValue><XXX>first string</XXX></saml:AttributeValue></saml:Attribute><saml:Attribute Name="second attribute"><saml:AttributeValue><XXX>second string</XXX></saml:AttributeValue><saml:AttributeValue><XXX>third string</XXX></saml:AttributeValue></saml:Attribute></saml:AttributeStatement></saml:Assertion>';
$text_node1 = new LassoMiscTextNode();
$text_node1->content = $attribute1_string;
$any1 = array();
$any1[] = $text_node1;
$attribute_value1 = new LassoSaml2AttributeValue();
$attribute_value1->any = $any1;
$attribute_values1 = array();
$attribute_values1[] = $attribute_value1;
$attribute1 = new LassoSaml2Attribute();
$attribute1->name = $attribute1_name;
$attribute1->attributeValue = $attribute_values1;
$text_node2 = new LassoMiscTextNode();
$text_node2->content = $attribute2_string;
$any2 = array();
$any2[] = $text_node2;
$attribute_value2 = new LassoSaml2AttributeValue();
$attribute_value2->any = $any2;
$text_node3 = new LassoMiscTextNode();
$text_node3->content = $attribute3_string;
$any3 = array();
$any3[] = $text_node3;
$attribute_value3 = new LassoSaml2AttributeValue();
$attribute_value3->any = $any3;
$attribute_values2 = array();
$attribute_values2[] = $attribute_value2;
$attribute_values2[] = $attribute_value3;
$attribute2 = new LassoSaml2Attribute();
$attribute2->name = $attribute2_name;
$attribute2->attributeValue = $attribute_values2;
$attributes = array();
$attributes[] = $attribute1;
$attributes[] = $attribute2;
$attributeStatement = new LassoSaml2AttributeStatement();
$attributeStatement->attribute = $attributes;
$attributeStatements = array();
$attributeStatements[] = $attributeStatement;
$assertion = new LassoSaml2Assertion();
$assertion->attributeStatement = $attributeStatements;
assert($assertion->dump() == $expected_assertion_dump);
echo "OK.\n";
}
lasso_init();
test01();
test02();
test03();
test04();
//test05();
test06();
lasso_shutdown();

View File

@ -0,0 +1,3 @@
#!/bin/sh
${PHP7:?PHP7 variable is not defined} -n -d extension_dir=../.libs -d extension=lasso.so ${SRCDIR}binding_tests.php

View File

@ -0,0 +1,224 @@
#!/usr/bin/php
<?php
# Lasso - A free implementation of the Liberty Alliance specifications.
#
# Copyright (C) 2004-2007 Entr'ouvert
# http://lasso.entrouvert.org
#
# Authors: See AUTHORS file in top-level directory.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <http://www.gnu.org/licenses/>.
require("../lasso.php");
define(DATA_DIR, getenv('SRCDIR') . '../../../tests/data/');
function test01() {
echo "Server construction, dump & newFromDump... ";
$server = new LassoServer(
DATA_DIR . "sp1-la/metadata.xml",
DATA_DIR . "sp1-la/private-key-raw.pem",
NULL,
DATA_DIR . "sp1-la/certificate.pem");
$server->addProvider(
LASSO_PROVIDER_ROLE_IDP,
DATA_DIR . "idp1-la/metadata.xml",
DATA_DIR . "idp1-la/public-key.pem",
DATA_DIR . "idp1-la/certificate.pem");
$dump = $server->dump();
assert(! is_null($dump));
assert($dump != "");
$server2 = LassoServer::newFromDump($dump);
$dump2 = $server2->dump();
assert($dump == $dump2);
echo "OK.\n";
}
function test02() {
echo "Server construction with no optional argument, dump & newFromDump... ";
$server = new LassoServer(DATA_DIR . "sp1-la/metadata.xml");
$server->addProvider(
LASSO_PROVIDER_ROLE_IDP,
DATA_DIR . "idp1-la/metadata.xml",
DATA_DIR . "idp1-la/public-key.pem",
DATA_DIR . "idp1-la/certificate.pem");
$dump = $server->dump();
$server2 = LassoServer::newFromDump($dump);
$dump2 = $server2->dump();
assert($dump == $dump2);
echo "OK.\n";
}
function test03() {
echo "SP login; testing access to authentication request... ";
$server = new LassoServer(
DATA_DIR . "sp1-la/metadata.xml",
DATA_DIR . "sp1-la/private-key-raw.pem",
NULL,
DATA_DIR . "sp1-la/certificate.pem");
$server->addProvider(
LASSO_PROVIDER_ROLE_IDP,
DATA_DIR . "idp1-la/metadata.xml",
DATA_DIR . "idp1-la/public-key.pem",
DATA_DIR . "idp1-la/certificate.pem");
$login = new LassoLogin($server);
$result = $login->initAuthnRequest();
assert(! is_null($login->request));
assert(get_class($login->request) == "LassoLibAuthnRequestNoInit");
$dump = $login->request->dump();
$login->request->protocolProfile = LASSO_LIB_PROTOCOL_PROFILE_BRWS_ART;
assert($login->request->protocolProfile == LASSO_LIB_PROTOCOL_PROFILE_BRWS_ART);
$dump2 = $login->request->dump();
assert($dump != $dump2);
echo "OK.\n";
}
function test04() {
echo "SP login; testing processing of an empty Response... ";
$server = new LassoServer(
DATA_DIR . "sp1-la/metadata.xml",
DATA_DIR . "sp1-la/private-key-raw.pem",
NULL,
DATA_DIR . "sp1-la/certificate.pem");
$server->addProvider(
LASSO_PROVIDER_ROLE_IDP,
DATA_DIR . "idp1-la/metadata.xml",
DATA_DIR . "idp1-la/public-key.pem",
DATA_DIR . "idp1-la/certificate.pem");
$login = new LassoLogin($server);
try {
$login->processResponseMsg("");
}
catch (LassoProfileInvalidMsgError $error) {
}
echo "OK.\n";
}
function test05() {
echo "Conversion of a lib:AuthnRequest with an AuthnContext into a query and back... ";
$spServer = new LassoServer(
DATA_DIR . "sp1-la/metadata.xml",
DATA_DIR . "sp1-la/private-key-raw.pem",
NULL,
DATA_DIR . "sp1-la/certificate.pem");
$spServer->addProvider(
LASSO_PROVIDER_ROLE_IDP,
DATA_DIR . "idp1-la/metadata.xml",
DATA_DIR . "idp1-la/public-key.pem",
DATA_DIR . "idp1-la/certificate.pem");
$spLogin = new LassoLogin($spServer);
$spLogin->initAuthnRequest();
$requestAuthnContext = new LassoLibRequestAuthnContext();
$requestAuthnContext->authnContextClassRef = array(LASSO_LIB_AUTHN_CONTEXT_CLASS_REF_PASSWORD);
assert($requestAuthnContext->authnContextClassRef[0] == LASSO_LIB_AUTHN_CONTEXT_CLASS_REF_PASSWORD);
$spLogin->request->requestAuthnContext = $requestAuthnContext;
assert(! is_null($spLogin->request->requestAuthnContext));
$spLogin->request->protocolProfile = LASSO_LIB_PROTOCOL_PROFILE_BRWS_ART;
assert($spLogin->request->protocolProfile == LASSO_LIB_PROTOCOL_PROFILE_BRWS_ART);
$spLogin->buildAuthnRequestMsg();
assert(! is_null($spLogin->msgUrl));
assert($spLogin->msgUrl != "");
$idpServer = new LassoServer(
DATA_DIR . "idp1-la/metadata.xml",
DATA_DIR . "idp1-la/private-key-raw.pem",
NULL,
DATA_DIR . "idp1-la/certificate.pem");
$idpServer->addProvider(
LASSO_PROVIDER_ROLE_IDP,
DATA_DIR . "sp1-la/metadata.xml",
DATA_DIR . "sp1-la/public-key.pem",
DATA_DIR . "sp1-la/certificate.pem");
$idpLogin = new LassoLogin($idpServer);
list($urlBase, $authnRequestQuery) = explode("?", $spLogin->msgUrl, 2);
assert($authnRequestQuery != "");
$idpLogin->processAuthnRequestMsg($authnRequestQuery);
assert(! is_null($idpLogin->request));
assert(! is_null($idpLogin->request->requestAuthnContext));
assert($idpLogin->request->requestAuthnContext != "");
assert(sizeof($idpLogin->request->requestAuthnContext->authnContextClassRef) == 1);
assert($idpLogin->request->requestAuthnContext->authnContextClassRef[0] ==
LASSO_LIB_AUTHN_CONTEXT_CLASS_REF_PASSWORD);
echo "OK.\n";
}
function test06() {
echo "SP logout without session and identity; testing initRequest... ";
$server = new LassoServer(
DATA_DIR . "sp1-la/metadata.xml",
DATA_DIR . "sp1-la/private-key-raw.pem",
NULL,
DATA_DIR . "sp1-la/certificate.pem");
$server->addProvider(
LASSO_PROVIDER_ROLE_IDP,
DATA_DIR . "idp1-la/metadata.xml",
DATA_DIR . "idp1-la/public-key.pem",
DATA_DIR . "idp1-la/certificate.pem");
$logout = new LassoLogout($server);
try {
$logout->initRequest();
echo "logout.initRequest without having set identity before should fail\n";
assert(False);
}
catch (LassoProfileSessionNotFoundError $error) {
}
echo "OK.\n";
}
function test07() {
echo "IDP logout without session and identity; testing logout.getNextProviderId... ";
$server = new LassoServer(
DATA_DIR . "idp1-la/metadata.xml",
DATA_DIR . "idp1-la/private-key-raw.pem",
NULL,
DATA_DIR . "idp1-la/certificate.pem");
$server->addProvider(
LASSO_PROVIDER_ROLE_IDP,
DATA_DIR . "sp1-la/metadata.xml",
DATA_DIR . "sp1-la/public-key.pem",
DATA_DIR . "sp1-la/certificate.pem");
$logout = new LassoLogout($server);
assert(is_null($logout->next_providerID));
echo "OK.\n";
}
test01();
test02();
test03();
test04();
test05();
test06();
test07();

View File

@ -0,0 +1,3 @@
#!/bin/sh
${PHP7:?PHP7 variable is not defined} -n -d extension_dir=../.libs -d extension=lasso.so ${SRCDIR}profile_tests.php

View File

@ -0,0 +1,64 @@
# Lasso - A free implementation of the Liberty Alliance specifications.
#
# Copyright (C) 2004-2007 Entr'ouvert
# http://lasso.entrouvert.org
#
# Authors: See AUTHORS file in top-level directory.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <http://www.gnu.org/licenses/>.
import six
class WrapperHeader:
def __init__(self, binding_data, fd, functions_list):
self.binding_data = binding_data
self.fd = fd
self.functions_list = functions_list
def generate(self):
self.generate_header()
self.generate_functions_list()
self.generate_footer()
def generate_header(self):
# FIXME: Get the current version and name
six.print_('''\
/* this file has been generated automatically; do not edit */
#include "../../config.h"
#ifndef PHP_LASSO_H
#define PHP_LASSO_H 1
#define PHP_LASSO_EXTNAME "lasso"
#define PHP_LASSO_VERSION VERSION
#define PHP_LASSO_SERVER_RES_NAME "Lasso Server"
PHP_MINIT_FUNCTION(lasso);
PHP_MSHUTDOWN_FUNCTION(lasso);
''', file=self.fd)
def generate_functions_list(self):
for m in self.functions_list:
six.print_('PHP_FUNCTION(%s);' % m, file=self.fd)
six.print_('', file=self.fd)
def generate_footer(self):
six.print_('''\
extern zend_module_entry lasso_module_entry;
#define phpext_lasso_ptr &lasso_module_entry
#endif
''', file=self.fd)

View File

@ -0,0 +1,550 @@
# Lasso - A free implementation of the Liberty Alliance specifications.
#
# Copyright (C) 2004-2007 Entr'ouvert
# http://lasso.entrouvert.org
#
# Authors: See AUTHORS file in top-level directory.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <http://www.gnu.org/licenses/>.
import sys
import os
import six
from utils import *
class WrapperSource:
def __init__(self, binding_data, fd):
self.binding_data = binding_data
self.fd = fd
self.functions_list = []
self.src_dir = os.path.dirname(__file__)
def is_object(self, t):
return t not in ['char*', 'const char*', 'gchar*', 'const gchar*', 'GList*', 'GHashTable*', 'GType',
'xmlNode*', 'int', 'gint', 'gboolean', 'const gboolean'] + self.binding_data.enums
def generate(self):
self.generate_header()
self.generate_constants()
self.generate_middle()
for m in self.binding_data.functions:
self.generate_function(m)
for c in self.binding_data.structs:
self.generate_members(c)
for m in c.methods:
self.generate_function(m)
self.generate_functions_list()
self.generate_footer()
def generate_header(self):
self.functions_list.append('lasso_get_object_typename')
self.functions_list.append('lasso_init')
self.functions_list.append('lasso_shutdown')
six.print_('''\
/* this file has been generated automatically; do not edit */
''', file=self.fd)
six.print_(open(os.path.join(self.src_dir,'wrapper_source_top.c')).read(), file=self.fd)
for h in self.binding_data.headers:
six.print_('#include <%s>' % h, file=self.fd)
six.print_('', file=self.fd)
six.print_('''\
PHP_MINIT_FUNCTION(lasso)
{
le_lasso_server = zend_register_list_destructors_ex(php_gobject_generic_destructor, NULL, PHP_LASSO_SERVER_RES_NAME, module_number);
lasso_init();
''', file=self.fd)
def generate_constants(self):
six.print_(' /* Constants (both enums and defines) */', file=self.fd)
for c in self.binding_data.constants:
if c[0] == 'i':
six.print_(' REGISTER_LONG_CONSTANT("%s", %s, CONST_CS|CONST_PERSISTENT);' % (c[1], c[1]), file=self.fd)
elif c[0] == 's':
six.print_(' REGISTER_STRING_CONSTANT("%s", (char*) %s, CONST_CS|CONST_PERSISTENT);' % (c[1], c[1]), file=self.fd)
elif c[0] == 'b':
six.print_('''\
#ifdef %s
REGISTER_LONG_CONSTANT("%s", 1, CONST_CS|CONST_PERSISTENT);
#else
REGISTER_LONG_CONSTANT("%s", 0, CONST_CS|CONST_PERSISTENT);
#endif''' % (c[1], c[1], c[1]), file=self.fd)
else:
six.print_('E: unknown constant type: %r' % c[0], file=sys.stderr)
six.print_('', file=self.fd)
def generate_middle(self):
six.print_('''\
return SUCCESS;
}
PHP_MSHUTDOWN_FUNCTION(lasso)
{
lasso_shutdown();
return SUCCESS;
}
''', file=self.fd)
def set_zval(self, zval_name, c_variable, type, free = False):
'''Emit code to set a zval* of name zval_name, from the value of the C variable called c_variable type, type.
'''
# first we free the previous value
p = (zval_name, c_variable)
q = { 'zval_name' : zval_name, 'c_variable' : c_variable }
six.print_(' zval_dtor(%s);' % zval_name, file=self.fd)
if is_pointer(type):
six.print_(' if (! %s) {' % c_variable, file=self.fd)
six.print_(' ZVAL_NULL(%s);' % zval_name, file=self.fd)
six.print_(' } else {', file=self.fd)
if is_int(type, self.binding_data):
six.print_(' ZVAL_LONG(%s, %s);' % p, file=self.fd)
elif is_boolean(type):
six.print_(' ZVAL_BOOL(%s, %s);' % p, file=self.fd)
elif is_cstring(type):
six.print_(' ZVAL_STRING(%s, (char*)%s);' % p, file=self.fd)
if free and not is_const(type):
six.print_('g_free(%s)' % c_variable, file=self.fd)
elif arg_type(type) == 'xmlNode*':
six.print_('''\
{
char* xmlString = get_string_from_xml_node(%(c_variable)s);
if (xmlString) {
ZVAL_STRING(%(zval_name)s, xmlString);
} else {
ZVAL_NULL(%(zval_name)s);
}
}
''' % q, file=self.fd)
elif is_glist(type):
elem_type = make_arg(element_type(type))
if not arg_type(elem_type):
raise Exception('unknown element-type: ' + repr(type))
if is_cstring(elem_type):
function = 'set_array_from_list_of_strings'
free_function = 'free_glist(&%(c_variable)s, (GFunc)free);'
elif arg_type(elem_type).startswith('xmlNode'):
function = 'set_array_from_list_of_xmlnodes'
free_function = 'free_glist(&%(c_variable)s, (GFunc)xmlFree);'
elif is_object(elem_type):
function = 'set_array_from_list_of_objects'
free_function = 'g_list_free(%(c_variable)s);'
else:
raise Exception('unknown element-type: ' + repr(type))
six.print_(' %s((GList*)%s, &%s);' % (function, c_variable, zval_name), file=self.fd)
if free:
six.print_(' ', free_function % q, file=self.fd)
elif is_object(type):
six.print_('''\
if (G_IS_OBJECT(%(c_variable)s)) {
PhpGObjectPtr *obj = PhpGObjectPtr_New(G_OBJECT(%(c_variable)s));
zend_resource *res = zend_register_resource(obj, le_lasso_server);
ZVAL_RES(%(zval_name)s, res);
} else {
ZVAL_NULL(%(zval_name)s);
}''' % q, file=self.fd)
if free:
six.print_('''\
if (%(c_variable)s) {
g_object_unref(%(c_variable)s); // If constructor ref is off by one'
}''' % q, file=self.fd)
else:
raise Exception('unknown type: ' + repr(type) + unconstify(arg_type(type)))
if is_pointer(type):
six.print_(' }', file=self.fd)
def return_value(self, arg, free = False):
if arg is None:
return
if is_boolean(arg):
six.print_(' RETVAL_BOOL(return_c_value);', file=self.fd)
elif is_int(arg, self.binding_data):
six.print_(' RETVAL_LONG(return_c_value);', file=self.fd)
elif is_cstring(arg):
six.print_('''\
if (return_c_value) {
RETVAL_STRING((char*)return_c_value);
} else {
RETVAL_NULL();
}''', file=self.fd)
if free:
six.print_(' free(return_c_value);', file=self.fd)
elif is_xml_node(arg):
six.print_('''\
{
char* xmlString = get_string_from_xml_node(return_c_value);
if (xmlString) {
RETVAL_STRING(xmlString);
} else {
RETVAL_NULL();
}
}
''', file=self.fd)
if free:
six.print_(' lasso_release_xml_node(return_c_value);', file=self.fd)
elif is_glist(arg):
el_type = element_type(arg)
if is_cstring(el_type):
six.print_('''\
set_array_from_list_of_strings((GList*)return_c_value, &return_value);
''', file=self.fd)
if free:
six.print_(' lasso_release_list_of_strings(return_c_value);', file=self.fd)
elif is_xml_node(el_type):
six.print_('''\
set_array_from_list_of_xmlnodes((GList*)return_c_value, &return_value);
''', file=self.fd)
if free or is_transfer_full(arg):
six.print_(' lasso_release_list_of_xml_node(return_c_value);', file=self.fd)
elif is_object(el_type):
six.print_('''\
set_array_from_list_of_objects((GList*)return_c_value, &return_value);
''', file=self.fd)
if free:
six.print_(' lasso_release_list_of_gobjects(return_c_value);', file=self.fd)
else:
raise Exception('cannot return value for %s' % (arg,))
elif is_hashtable(arg):
el_type = element_type(arg)
if is_object(el_type):
six.print_('''\
set_array_from_hashtable_of_objects(return_c_value, &return_value);
''', file=self.fd)
else:
if not is_cstring(arg):
print >>sys.stderr, 'W: %s has no explicit string annotation' % (arg,)
six.print_('''\
set_array_from_hashtable_of_strings(return_c_value, &return_value);
''', file=self.fd)
elif is_object(arg):
six.print_('''\
if (return_c_value) {
PhpGObjectPtr *self;
self = PhpGObjectPtr_New(G_OBJECT(return_c_value));
zend_resource *res = zend_register_resource(self, le_lasso_server);
ZVAL_RES(return_value, res);
} else {
RETVAL_NULL();
}''', file=self.fd)
if free:
six.print_(' lasso_release_gobject(return_c_value);', file=self.fd)
else:
raise Exception('cannot return value for %s' % (arg,))
def generate_function(self, m):
if m.name in ('lasso_init','lasso_shutdown'):
return
if m.rename:
name = m.rename
else:
name = m.name
self.functions_list.append(name)
six.print_('''PHP_FUNCTION(%s)
{''' % name, file=self.fd)
parse_tuple_format = []
parse_tuple_args = []
for arg in m.args:
if is_out(arg):
six.print_(' zval *php_out_%s = NULL;' % arg_name(arg), file=self.fd)
six.print_(' %s %s;' % (var_type(arg), arg_name(arg)), file=self.fd)
parse_tuple_format.append('z!')
parse_tuple_args.append('&php_out_%s' % arg_name(arg))
elif is_cstring(arg):
parse_tuple_format.append('s!')
parse_tuple_args.append('&%s_str, &%s_len' % (arg_name(arg), arg_name(arg)))
six.print_(' %s %s = NULL;' % ('char*', arg_name(arg)), file=self.fd)
six.print_(' %s %s_str = NULL;' % ('char*', arg_name(arg)), file=self.fd)
six.print_(' %s %s_len = 0;' % ('size_t', arg_name(arg)), file=self.fd)
elif is_int(arg, self.binding_data) or is_boolean(arg):
parse_tuple_format.append('l')
parse_tuple_args.append('&%s' % arg_name(arg))
six.print_(' %s %s;' % ('long', arg_name(arg)), file=self.fd)
elif is_time_t_pointer(arg):
parse_tuple_format.append('l')
parse_tuple_args.append('&%s' % (arg_name(arg),))
print >>self.fd, ' time_t %s = 0;' % (arg_name(arg),)
elif is_xml_node(arg):
parse_tuple_format.append('s!')
parse_tuple_args.append('&%s_str, &%s_len' % (arg_name(arg), arg_name(arg)))
six.print_(' %s %s = NULL;' % ('xmlNode*', arg_name(arg)), file=self.fd)
six.print_(' %s %s_str = NULL;' % ('char*', arg_name(arg)), file=self.fd)
six.print_(' %s %s_len = 0;' % ('size_t', arg_name(arg)), file=self.fd)
elif is_glist(arg):
parse_tuple_format.append('a!')
parse_tuple_args.append('&zval_%s' % arg_name(arg))
six.print_(' %s zval_%s = NULL;' % ('zval*', arg_name(arg)), file=self.fd)
six.print_(' %s %s = NULL;' % ('GList*', arg_name(arg)), file=self.fd)
elif is_object(arg):
parse_tuple_format.append('r')
parse_tuple_args.append('&zval_%s' % arg_name(arg))
six.print_(' %s %s = NULL;' % (arg_type(arg), arg_name(arg)), file=self.fd)
six.print_(' %s zval_%s = NULL;' % ('zval*', arg_name(arg)), file=self.fd)
six.print_(' %s cvt_%s = NULL;' % ('PhpGObjectPtr*', arg_name(arg)), file=self.fd)
else:
raise Exception('Unsupported type %s %s' % (arg, m))
if m.return_type:
six.print_(' %s return_c_value;' % m.return_type, file=self.fd)
if m.return_type is not None and self.is_object(m.return_arg):
six.print_(' G_GNUC_UNUSED PhpGObjectPtr *self;', file=self.fd)
six.print_('', file=self.fd)
parse_tuple_args = ', '.join(parse_tuple_args)
if parse_tuple_args:
parse_tuple_args = ', ' + parse_tuple_args
six.print_('''\
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "%s"%s) == FAILURE) {
RETURN_FALSE;
}
''' % (''.join(parse_tuple_format), parse_tuple_args), file=self.fd)
for f, arg in zip(parse_tuple_format, m.args):
if is_out(arg):
continue
elif is_xml_node(arg):
six.print_('''\
%(name)s = get_xml_node_from_string(%(name)s_str);''' % {'name': arg[1]}, file=self.fd)
elif f.startswith('s'):
six.print_('''\
%(name)s = %(name)s_str;''' % {'name': arg[1]}, file=self.fd)
elif f.startswith('r'):
six.print_(' if ((cvt_%s = (PhpGObjectPtr *)zend_fetch_resource(Z_RES_P(zval_%s), PHP_LASSO_SERVER_RES_NAME, le_lasso_server)) == NULL) {' % (arg[1], arg[1]), file=self.fd)
six.print_(' RETURN_FALSE;', file=self.fd)
six.print_(' }', file=self.fd)
six.print_(' %s = (%s)cvt_%s->obj;' % (arg[1], arg[0], arg[1]), file=self.fd)
elif f.startswith('a'):
el_type = element_type(arg)
if is_cstring(el_type):
six.print_(' %(name)s = get_list_from_array_of_strings(zval_%(name)s);' % {'name': arg[1]}, file=self.fd)
elif is_object(el_type):
six.print_(' %(name)s = get_list_from_array_of_objects(zval_%(name)s);' % {'name': arg[1]}, file=self.fd)
else:
six.print_('E: In %(function)s arg %(name)s is of type GList<%(elem)s>' % { 'function': m.name, 'name': arg[1], 'elem': el_type }, file=sys.stderr)
elif f == 'l':
pass
else:
raise Exception('%s format inconnu' % f)
if m.return_type is not None:
six.print_(' return_c_value = ', file=self.fd)
if 'new' in m.name:
six.print_('(%s)' % m.return_type, file=self.fd)
else:
six.print_(' ', file=self.fd)
def special(x):
if is_time_t_pointer(x):
return '%(name)s ? &%(name)s : NULL' % { 'name': arg_name(x) }
else:
return ref_name(x)
six.print_('%s(%s);' % (m.name, ', '.join([special(x) for x in m.args])), file=self.fd)
# Free the converted arguments
for f, arg in zip(parse_tuple_format, m.args):
argtype, argname, argoptions = arg
if is_out(arg):
# export the returned variable
free = is_transfer_full(unref_type(arg))
self.set_zval('php_out_%s' % argname, argname, unref_type(arg), free = free)
pass
elif argtype == 'xmlNode*':
six.print_(' xmlFree(%s);' % argname, file=self.fd)
elif f.startswith('a'):
el_type = element_type(arg)
if is_cstring(el_type):
six.print_(' if (%(name)s) {' % { 'name': arg[1] }, file=self.fd)
six.print_(' free_glist(&%(name)s,(GFunc)free);' % { 'name': arg[1] }, file=self.fd)
six.print_(' }', file=self.fd)
try:
self.return_value(m.return_arg, is_transfer_full(m.return_arg, default=True))
except:
raise Exception('Cannot return value for function %s' % m)
six.print_('}', file=self.fd)
six.print_('', file=self.fd)
def generate_members(self, c):
for m in c.members:
self.generate_getter(c, m)
self.generate_setter(c, m)
def generate_getter(self, c, m):
klassname = c.name
name = arg_name(m)
type = arg_type(m)
function_name = '%s_%s_get' % (klassname, format_as_camelcase(name))
six.print_('''PHP_FUNCTION(%s)
{''' % function_name, file=self.fd)
self.functions_list.append(function_name)
six.print_(' %s return_c_value;' % type, file=self.fd)
six.print_(' %s* this;' % klassname, file=self.fd)
six.print_(' zval* zval_this;', file=self.fd)
six.print_(' PhpGObjectPtr *cvt_this;', file=self.fd)
six.print_('', file=self.fd)
six.print_('''\
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zval_this) == FAILURE) {
RETURN_FALSE;
}
if ((cvt_this = (PhpGObjectPtr *)zend_fetch_resource(Z_RES_P(zval_this), PHP_LASSO_SERVER_RES_NAME, le_lasso_server)) == NULL) {
RETURN_FALSE;
}
this = (%s*)cvt_this->obj;
''' % (klassname), file=self.fd)
six.print_(' return_c_value = (%s)this->%s;' % (type, name), file=self.fd)
self.return_value(m)
six.print_('}', file=self.fd)
six.print_('', file=self.fd)
def generate_setter(self, c, m):
klassname = c.name
name = arg_name(m)
type = arg_type(m)
function_name = '%s_%s_set' % (klassname, format_as_camelcase(name))
six.print_('''PHP_FUNCTION(%s)
{''' % function_name, file=self.fd)
self.functions_list.append(function_name)
six.print_(' %s* this;' % klassname, file=self.fd)
six.print_(' zval* zval_this;', file=self.fd)
six.print_(' PhpGObjectPtr *cvt_this;', file=self.fd)
# FIXME: This bloc should be factorised
parse_tuple_format = ''
parse_tuple_args = []
if is_cstring(m) or is_xml_node(m):
# arg_type = arg_type.replace('const ', '')
parse_tuple_format += 's'
parse_tuple_args.append('&%s_str, &%s_len' % (name, name))
six.print_(' %s %s_str = NULL;' % ('char*', name), file=self.fd)
six.print_(' %s %s_len = 0;' % ('size_t', name), file=self.fd)
elif is_int(m, self.binding_data) or is_boolean(m):
parse_tuple_format += 'l'
parse_tuple_args.append('&%s' % name)
six.print_(' %s %s;' % ('long', name), file=self.fd)
# Must also handle lists of Objects
elif is_glist(m) or is_hashtable(m):
parse_tuple_format += 'a'
parse_tuple_args.append('&zval_%s' % name)
six.print_(' %s zval_%s;' % ('zval*', name), file=self.fd)
elif is_object(m):
parse_tuple_format += 'r'
parse_tuple_args.append('&zval_%s' % name)
six.print_(' %s zval_%s = NULL;' % ('zval*', name), file=self.fd)
six.print_(' %s cvt_%s = NULL;' % ('PhpGObjectPtr*', name), file=self.fd)
else:
raise Exception('Cannot make a setter for %s.%s' % (c,m))
if parse_tuple_args:
parse_tuple_arg = parse_tuple_args[0]
else:
six.print_('}', file=self.fd)
six.print_('', file=self.fd)
return
six.print_('', file=self.fd)
six.print_('''\
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r%s", &zval_this, %s) == FAILURE) {
return;
}
''' % (parse_tuple_format, parse_tuple_arg), file=self.fd)
# Get 'this' object
six.print_('''\
if ((cvt_this = (PhpGObjectPtr *)zend_fetch_resource(Z_RES_P(zval_this), PHP_LASSO_SERVER_RES_NAME, le_lasso_server)) == NULL) {
RETURN_FALSE;
}
this = (%s*)cvt_this->obj;
''' % klassname, file=self.fd)
# Set new value
d = { 'name': name, 'type': type }
if is_int(m, self.binding_data) or is_boolean(m):
six.print_(' this->%s = %s;' % (name, name), file=self.fd)
elif is_cstring(m):
six.print_(' lasso_assign_string(this->%(name)s, %(name)s_str);' % d, file=self.fd)
elif is_xml_node(m):
six.print_(' lasso_assign_new_xml_node(this->%(name)s, get_xml_node_from_string(%(name)s_str));' % d, file=self.fd)
elif is_glist(m):
el_type = element_type(m)
if is_cstring(el_type):
six.print_(' lasso_assign_new_list_of_strings(this->%(name)s, get_list_from_array_of_strings(zval_%(name)s));' % d, file=self.fd)
elif is_xml_node(el_type):
six.print_(' lasso_assign_new_list_of_xml_node(this->%(name)s, get_list_from_array_of_xmlnodes(zval_%(name)s))' % d, file=self.fd)
elif is_object(el_type):
six.print_(' lasso_assign_new_list_of_gobjects(this->%(name)s, get_list_from_array_of_objects(zval_%(name)s));' % d, file=self.fd)
else:
raise Exception('Cannot create C setter for %s.%s' % (c,m))
elif is_hashtable(m):
el_type = element_type(m)
six.print_('''\
{
GHashTable *oldhash = this->%(name)s;''' % d, file=self.fd)
if is_object(el_type):
six.print_(' this->%(name)s = get_hashtable_from_array_of_objects(zval_%(name)s);' % d, file=self.fd)
else:
six.print_(' this->%(name)s = get_hashtable_from_array_of_strings(zval_%(name)s);' % d, file=self.fd)
six.print_(' g_hash_table_destroy(oldhash);', file=self.fd)
six.print_(' }', file=self.fd)
elif is_object(m):
six.print_(' if ((cvt_%(name)s = (PhpGObjectPtr*)zend_fetch_resource(Z_RES_P(zval_%(name)s), PHP_LASSO_SERVER_RES_NAME, le_lasso_server)) == NULL) {' % d, file=self.fd)
six.print_(' RETURN_FALSE;', file=self.fd)
six.print_(' }', file=self.fd)
six.print_(' lasso_assign_gobject(this->%(name)s, cvt_%(name)s->obj);' % d, file=self.fd)
six.print_('}', file=self.fd)
six.print_('', file=self.fd)
def generate_functions_list(self):
six.print_('''\
static zend_function_entry lasso_functions[] = {''', file=self.fd)
for m in self.functions_list:
six.print_(' PHP_FE(%s, NULL)' % m, file=self.fd)
six.print_('''\
{NULL, NULL, NULL, 0, 0}
};
''', file=self.fd)
def generate_footer(self):
six.print_('''\
zend_module_entry lasso_module_entry = {
#if ZEND_MODULE_API_NO >= 20010901
STANDARD_MODULE_HEADER,
#endif
PHP_LASSO_EXTNAME,
lasso_functions,
PHP_MINIT(lasso),
PHP_MSHUTDOWN(lasso),
NULL,
NULL,
NULL,
#if ZEND_MODULE_API_NO >= 20010901
PHP_LASSO_VERSION,
#endif
STANDARD_MODULE_PROPERTIES
};
''', file=self.fd)

View File

@ -0,0 +1,380 @@
#include <php.h>
#undef PACKAGE_BUGREPORT
#undef PACKAGE_NAME
#undef PACKAGE_STRING
#undef PACKAGE_TARNAME
#undef PACKAGE_VERSION
#include <lasso/lasso.h>
#include "php_lasso.h"
#include "../ghashtable.h"
#define LASSO_LOG_STATIC
#if defined(__GNUC__)
# define lasso_log(level, filename, line, function, format, args...) \
g_log("Lasso", level, "%s:%i:%s" format, filename, line, function, ##args)
#elif defined(HAVE_VARIADIC_MACROS)
# define lasso_log(level, format, line, function, ...) \
g_log("Lasso", leve, "%s:%i:%s" format, filename, line, function, __VA_ARGS__)
#else
static inline void lasso_log(GLogLevelFlags level, const char *filename,
int line, const char *function, const char *format, ...)
{
va_list ap;
char s[1024];
va_start(ap, format);
g_vsnprintf(s, 1024, format, ap);
va_end(ap);
g_log("Lasso", level, "%s:%i:%s %s", filename, line, function, s);
}
#define lasso_log lasso_log
#endif
#include "../../lasso/utils.h"
#include "../utils.c"
/* utility functions */
static void free_glist(GList **list, GFunc free_function);
/* Define the Lasso PHP module */
int le_lasso_server;
ZEND_GET_MODULE(lasso)
/* Wrapper around GObject to get the dynamic typename */
typedef struct {
GObject *obj;
char *typename;
} PhpGObjectPtr;
/** FIXME: implement caching of objects inside GObjects using a GQuark */
static PhpGObjectPtr*
PhpGObjectPtr_New(GObject *obj)
{
PhpGObjectPtr *self;
if (obj == NULL) {
return NULL;
}
self = (PhpGObjectPtr *)malloc(sizeof(PhpGObjectPtr));
self->obj = g_object_ref(obj);
self->typename = strdup(G_OBJECT_TYPE_NAME(obj));
//printf("Allocating container %p for object %p of type %s with refcnt %i\n", self, obj, self->typename, obj->ref_count);
return self;
}
PHP_FUNCTION(lasso_init)
{
RETURN_NULL();
}
PHP_FUNCTION(lasso_shutdown)
{
RETURN_NULL();
}
PHP_FUNCTION(lasso_get_object_typename)
{
PhpGObjectPtr *self;
zval *zval_self;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zval_self) == FAILURE) {
RETURN_FALSE;
}
if ((self = (PhpGObjectPtr *)zend_fetch_resource(Z_RES_P(zval_self), PHP_LASSO_SERVER_RES_NAME, le_lasso_server)) == NULL) {
RETURN_FALSE;
}
RETURN_STRING(self->typename);
}
/* Generic destructor for PHP GObject */
static void php_gobject_generic_destructor(zend_resource *rsrc TSRMLS_DC)
{
PhpGObjectPtr* gobject = (PhpGObjectPtr*)rsrc->ptr;
if (gobject) {
if (gobject->obj) {
//printf("Deallocating container %p\n", gobject);
//printf("Deallocating %p that has %u refcounts\n", gobject->obj, gobject->obj->ref_count);
g_object_unref(G_OBJECT(gobject->obj));
//printf("now %u refcounts\n", gobject->obj->ref_count);
}
if (gobject->typename) {
free(gobject->typename);
}
free(gobject);
}
}
/* List handling */
static void
free_glist(GList **list, GFunc free_function) {
lasso_return_if_fail(list);
if (*list) {
if (free_function) {
g_list_foreach(*list, free_function, NULL);
}
g_list_free(*list);
}
*list = NULL;
}
/* Conversion functions */
static xmlBuffer*
xmlnode_to_xmlbuffer(xmlNode *node)
{
xmlOutputBufferPtr output_buffer;
xmlBuffer *buffer;
if (! node)
return NULL;
buffer = xmlBufferCreate();
output_buffer = xmlOutputBufferCreateBuffer(buffer, NULL);
xmlNodeDumpOutput(output_buffer, NULL, node, 0, 0, NULL);
xmlOutputBufferClose(output_buffer);
xmlBufferAdd(buffer, BAD_CAST "", 1);
return buffer;
}
static char*
get_string_from_xml_node(xmlNode *xmlnode)
{
xmlBuffer *buffer;
char *result;
if (xmlnode == NULL) {
return NULL;
}
buffer = xmlnode_to_xmlbuffer(xmlnode);
if (buffer == NULL) {
result = NULL;
} else {
result = estrdup((char*)xmlBufferContent(buffer));
xmlBufferFree(buffer);
}
return result;
}
static xmlNode*
get_xml_node_from_string(char *string)
{
return lasso_string_fragment_to_xmlnode(string, 0);
}
static GList*
get_list_from_array_of_strings(zval* array)
{
HashTable* hashtable;
HashPosition pointer;
zval* data;
zval temp;
GList* result = NULL;
hashtable = Z_ARRVAL_P(array);
for (zend_hash_internal_pointer_reset_ex(hashtable, &pointer);
(data = zend_hash_get_current_data_ex(hashtable, &pointer)) != NULL;
zend_hash_move_forward_ex(hashtable, &pointer)) {
temp = *data;
zval_copy_ctor(&temp);
convert_to_string(&temp);
result = g_list_append(result, g_strndup(Z_STRVAL(temp), Z_STRLEN(temp)));
zval_dtor(&temp);
}
return result;
}
static void
set_array_from_list_of_strings(GList* list, zval **array) {
GList* item;
array_init(*array);
for (item = g_list_first(list); item != NULL; item = g_list_next(item)) {
if (item->data != NULL) {
add_next_index_string(*array, item->data);
} else {
add_next_index_null(*array);
}
}
}
static GList*
get_list_from_array_of_xmlnodes(zval* array)
{
HashTable* hashtable;
HashPosition pointer;
zval* data;
zval temp;
GList* result = NULL;
hashtable = Z_ARRVAL_P(array);
for (zend_hash_internal_pointer_reset_ex(hashtable, &pointer);
(data = zend_hash_get_current_data_ex(hashtable, &pointer)) != NULL;
zend_hash_move_forward_ex(hashtable, &pointer)) {
xmlNode *value;
temp = *data;
zval_copy_ctor(&temp);
convert_to_string(&temp);
value = get_xml_node_from_string(Z_STRVAL(temp));
if (value) {
lasso_list_add_new_xml_node(result, value);
}
zval_dtor(&temp);
}
return result;
}
static void
set_array_from_list_of_xmlnodes(GList* list, zval **array) {
GList* item;
array_init(*array);
for (item = g_list_first(list); item != NULL; item = g_list_next(item)) {
if (item->data != NULL) {
add_next_index_string(*array, get_string_from_xml_node(item->data));
} else {
add_next_index_null(*array);
}
}
}
static GList*
get_list_from_array_of_objects(zval *array)
{
HashTable *hashtable;
HashPosition pointer;
zval *data;
PhpGObjectPtr *cvt_temp;
GList *result = NULL;
hashtable = Z_ARRVAL_P(array);
for (zend_hash_internal_pointer_reset_ex(hashtable, &pointer);
(data = zend_hash_get_current_data_ex(hashtable, &pointer)) != NULL;
zend_hash_move_forward_ex(hashtable, &pointer)) {
cvt_temp = (PhpGObjectPtr*) zend_fetch_resource(Z_RES_P(data), PHP_LASSO_SERVER_RES_NAME, le_lasso_server);
if (cvt_temp != NULL) {
g_object_ref(cvt_temp->obj);
result = g_list_append(result, cvt_temp->obj);
} else {
result = g_list_append(result, NULL);
}
}
return result;
}
static void
set_array_from_list_of_objects(GList *list, zval **array)
{
GList *item = NULL;
zend_resource *res_item;
zval zval_item;
array_init(*array);
for (item = g_list_first(list); item != NULL; item = g_list_next(item)) {
if (item->data != NULL) {
res_item = zend_register_resource(PhpGObjectPtr_New(item->data), le_lasso_server);
ZVAL_RES(&zval_item, res_item);
add_next_index_zval(*array, &zval_item);
} else {
add_next_index_null(*array);
}
}
}
/* FIXME: This function doesn't work yet */
static GHashTable*
get_hashtable_from_array_of_objects(zval *array)
{
HashTable *hashtable = NULL;
HashPosition pointer;
zend_string *key;
zend_ulong index;
zval *data = NULL;
PhpGObjectPtr *cvt_temp = NULL;
GHashTable *result = NULL;
result = g_hash_table_new(g_str_hash, g_str_equal);
hashtable = Z_ARRVAL_P(array);
for (zend_hash_internal_pointer_reset_ex(hashtable, &pointer);
(data = zend_hash_get_current_data_ex(hashtable, &pointer)) != NULL;
zend_hash_move_forward_ex(hashtable, &pointer)) {
cvt_temp = (PhpGObjectPtr*) zend_fetch_resource(Z_RES_P(data), PHP_LASSO_SERVER_RES_NAME, le_lasso_server);
if (zend_hash_get_current_key_ex(hashtable, &key, &index, &pointer) == HASH_KEY_IS_STRING) {
g_hash_table_insert(result, ZSTR_VAL(key), lasso_ref(cvt_temp->obj));
} else {
/* FIXME: throw an exception */
}
}
return result;
}
G_GNUC_UNUSED static GHashTable*
get_hashtable_from_array_of_strings(zval *array)
{
HashTable *hashtable = NULL;
HashPosition pointer;
zend_string *key = NULL;
zend_ulong index;
zval *data = NULL;
GHashTable *result = NULL;
result = g_hash_table_new(g_str_hash, g_str_equal);
hashtable = Z_ARRVAL_P(array);
for (zend_hash_internal_pointer_reset_ex(hashtable, &pointer);
(data = zend_hash_get_current_data_ex(hashtable, &pointer)) != NULL;
zend_hash_move_forward_ex(hashtable, &pointer)) {
if (Z_TYPE_P(data) == IS_STRING) {
if (zend_hash_get_current_key_ex(hashtable, &key, &index, &pointer) == HASH_KEY_IS_STRING) {
g_hash_table_insert(result, g_strdup(ZSTR_VAL(key)), g_strdup(Z_STRVAL_P(data)));
} else {
/* FIXME: throw an exception */
}
}
}
return result;
}
static void
set_array_from_hashtable_of_objects(GHashTable *hashtable, zval **array)
{
GList *keys = NULL;
GObject *item = NULL;
zend_resource *res_item;
zval zval_item;
array_init(*array);
for (keys = g_hash_table_get_keys(hashtable); keys; keys = g_list_next(keys)) {
item = g_hash_table_lookup(hashtable, keys->data);
if (item) {
res_item = zend_register_resource(PhpGObjectPtr_New(item), le_lasso_server);
ZVAL_RES(&zval_item, res_item);
add_assoc_zval(*array, (char*)keys->data, &zval_item);
} else {
add_assoc_null(*array, (char*)keys->data);
}
}
g_list_free(keys);
}
G_GNUC_UNUSED static void
set_array_from_hashtable_of_strings(GHashTable *hashtable, zval **array)
{
GList *keys = NULL;
zval zval_item;
array_init(*array);
for (keys = g_hash_table_get_keys(hashtable); keys; keys = g_list_next(keys)) {
char *item = g_hash_table_lookup(hashtable, keys->data);
if (item) {
ZVAL_STRING(&zval_item, item);
add_assoc_zval(*array, (char*)keys->data, &zval_item);
} else {
add_assoc_null(*array, (char*)keys->data);
}
}
g_list_free(keys);
}

View File

@ -131,6 +131,8 @@ dnl AC_CHECK_PROGS(JAR, fastjar jar)
AC_CHECK_PROGS(PERL, perl)
AC_CHECK_PROGS(PHP5, php5 php)
AC_CHECK_PROGS(PHP5_CONFIG, php-config5 php-config)
AC_CHECK_PROGS(PHP7, php7.4 php7.3 php7.2 php7.1 php7.0 php7)
AC_CHECK_PROGS(PHP7_CONFIG, php-config7.4 php-config7.3 php-config7.2 php-config7.1 php-config7.0 php-config7)
AC_CHECK_PROGS(PYTHON, python3 python python2)
AC_CHECK_PROGS(SWIG, swig)
@ -433,6 +435,81 @@ AM_CONDITIONAL([PHP5_ENABLED], [test "x$enable_php5" = "xyes"])
AC_SUBST(PHP5_VERSION)
# -----------
# PHP 7 binding
# -----------
dnl Check if php is explicitly enabled.
AC_ARG_ENABLE(php7, [ --enable-php7 enable the PHP 7 binding],,
enable_php7="yes")
AC_ARG_WITH(php7-config,
[ --with-php7-config=(PHP7_CONFIG) Specify full path to php-config7.])
AC_ARG_ENABLE(php7-force, [ --enable-php7-force always enable of the PHP 7 binding (win32)],
[ENABLE_PHP7_FORCE="yes"],
[ENABLE_PHP7_FORCE="no"])
dnl Check if user passed a specific php-config program.
if test "X$with_php7_config" != "X" ; then
PHP7_CONFIG=$with_php7_config
fi
if test "X$PHP7_CONFIG" != "X" ; then
PHP7_INCLUDES=`$PHP7_CONFIG --includes`
PHP7_LDFLAGS=`$PHP7_CONFIG --ldflags`
PHP7_LIBS=`$PHP7_CONFIG --libs`
PHP7_PREFIX=`$PHP7_CONFIG --prefix`
PHP7_QUOTED_PREFIX=$(echo $PHP7_PREFIX | $SED 's/\//\\\//g')
PHP7_UNPREFIXED_EXTENSION_DIR=$($PHP7_CONFIG --extension-dir | $SED "s/$PHP7_QUOTED_PREFIX//g")
else
# We assume PHP are in /usr/local directory.
if test $MINGW -eq 1; then
CFLAGS="$CFLAGS -DZTS -DZEND_WIN32 -DWIN32 -D_MBCS"
fi
PHP7_INCLUDES="-I/usr/local/include/php7 -I/usr/local/include/php7/main -I/usr/local/include/php7/Zend -I/usr/local/include/php7/TSRM -I/usr/local/include/php7/win32"
PHP7_LDFLAGS=
PHP7_LIBS="-lphp7ts -lxmlparse -lxmltok"
PHP7_UNPREFIXED_EXTENSION_DIR=
PHP7_PREFIX=
fi
AC_ARG_WITH(php7,
[ --with-php7=(PHP) Specify full path to php 7 executable.],
[PHP7="$withval"],[PHP7_INCLUDE_DIR=php7])
AC_ARG_WITH(php7-include-dir,
[ --with-php7-include-dir=(PHP7_INCLUDE_DIR) Specify full path to php 7 include dir.],
[PHP7_INCLUDE_DIR="$withval"],[PHP7_INCLUDE_DIR=${datadir}/php])
AC_ARG_WITH(php7-config-dir,
[ --with-php7-config-dir=(PHP7_CONFIG_DIR) Specify full path to php 7 config dir.],
[PHP7_CONFIG_DIR="$withval"],[PHP7_CONFIG_DIR=${sysconfdir}/php7/conf.d/])
AC_SUBST(PHP7_INCLUDES)
AC_SUBST(PHP7_LDFLAGS)
AC_SUBST(PHP7_LIBS)
AC_SUBST(PHP7_UNPREFIXED_EXTENSION_DIR)
AC_SUBST(PHP7_EXTENSION_DIR)
AC_SUBST(PHP7_PREFIX)
AC_SUBST(PHP7_INCLUDE_DIR)
AC_SUBST(PHP7_CONFIG_DIR)
AC_MSG_CHECKING(for PHP 7 development files)
if $PHP7_CONFIG --version | grep -q "^7" || test "x$ENABLE_PHP7_FORCE" = "xyes"
then
PHP7_VERSION=`$PHP7_CONFIG --version 2> /dev/null`
languages_available="$languages_available php7($PHP7_VERSION)"
else
enable_php7=no
fi
AC_MSG_RESULT($enable_php7)
AM_CONDITIONAL([PHP7_ENABLED], [test "x$enable_php7" = "xyes"])
AC_SUBST(PHP7_VERSION)
### # ----------
### # C# binding (disabled for the moment)
### # ----------
@ -827,6 +904,9 @@ bindings/python/tests/Makefile
bindings/php5/Makefile
bindings/php5/examples/Makefile
bindings/php5/tests/Makefile
bindings/php7/Makefile
bindings/php7/examples/Makefile
bindings/php7/tests/Makefile
bindings/perl/Makefile
])
@ -854,6 +934,7 @@ Available languages: ${languages_available}
Java binding: ${enable_java}
Perl binding: ${enable_perl}
PHP 5 binding: ${enable_php5}
PHP 7 binding: ${enable_php7}
Python binding: ${enable_python}
C API references: ${enable_gtk_doc}