SOAP
*/
global $class_path, $base_path, $include_path;
require_once ("$base_path/includes/init.inc.php");
require_once ("$base_path/admin/connecteurs/out/apisoap/apisoap.class.php");
require_once ($class_path."/external_services.class.php");
require_once ($include_path."/connecteurs_out_common.inc.php");
require_once($class_path."/external_services_caches.class.php");
//Cette fonction prend l'url courante et supprime le wsdl de l'url
function serverURL() {
$isHTTPS = (isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == "on");
$port = (isset($_SERVER["SERVER_PORT"]) && ((!$isHTTPS && $_SERVER["SERVER_PORT"] != "80") || ($isHTTPS && $_SERVER["SERVER_PORT"] != "443")));
$port = ($port) ? ':'.$_SERVER["SERVER_PORT"] : '';
$url = ($isHTTPS ? 'https://' : 'http://').$_SERVER["SERVER_NAME"].$port.$_SERVER["SCRIPT_NAME"];
$urls = array();
foreach ($_GET as $agetname => $agetvalue) {
if (strtoupper($agetname) == "WSDL")
continue;
if ($agetvalue)
$urls[] = urlencode($agetname)."=".urlencode($agetvalue);
else
$urls[] = urlencode($agetname);
}
if (count($urls)) {
$url .= "?";
$url .= implode('&', $urls);
}
return $url;
}
class apisoap_soapserver {
public $connector_object;
public $server;
public function __construct($connector_object) {
$this->connector_object = $connector_object;
}
public function return_error($error_string) {
highlight_string(print_r($error_string, true));
die();
}
/*
* Cette fonction convertit un champ input type manifest en type wsdl
*
*/
public function input_to_wsdl($input, $method_name, $base_group_name, &$additional_definitions, $nodetype="element", $base_type=false) {
//Correspondance entre les types des manifests et les types wsdl
$corresponding_scalar_types = array(
"string" => "string",
"integer" => "int",
"boolean" => "boolean"
);
global $declared_types; //Le tableau qui référence les types que l'on a définis
global $type_aliases; //Le tableau qui référence les alias des types, pour les types importés
$default_data_type = 'string'; //En cas de type inconnu
$result = "";
if(is_object($input) && property_exists($input, 'type')) {
$cardinality_information = '';
if (property_exists($input, 'optional') && $input->optional=='yes') {
$cardinality_information = 'minOccurs="0" maxOccurs="1"';
}
switch ($input->type) {
case 'scalar':
if (isset($type_aliases[$base_group_name.'_'.$input->datatype])) {
$corresponding_type = $type_aliases[$base_group_name.'_'.$input->datatype];
$corresponding_type = 'tns:'.$corresponding_type;
} else if (isset($declared_types[$base_group_name.'_'.$input->datatype])) {
$corresponding_type = $base_group_name.'_'.$input->datatype;
$corresponding_type = 'tns:'.$corresponding_type;
} else {
$corresponding_type = isset($corresponding_scalar_types[$input->datatype]) ? $corresponding_scalar_types[$input->datatype] : $default_data_type;
$corresponding_type = 'xsd:'.$corresponding_type;
}
//Type simple, facile
if ($nodetype == "element") {
$result .= '';
} else if ($nodetype == "part") {
$result .= '';
}
break;
case 'array':
//Tableau: il faut déclarer le type et le référencer. Si on génère une part, on peut balancer une structure à occurrences multiples; sinon il faut déclarer un type tableau et le remplir.
//Référence
if ($nodetype == "element") {
$result .= 'name).'" '.$cardinality_information.' />';
if (!isset($additional_definitions["ArrayOf".$method_name."_".XMLEntities($input->name)])) {
//Si le tableau contient un seul élément, on le définit comme un tableau de ce type, sinon il faut définir un type tableau
if (count($input->struct) == 1) {
if (isset($type_aliases[$base_group_name.'_'.$input->struct[0]->datatype])) {
$corresponding_type = $type_aliases[$base_group_name.'_'.$input->struct[0]->datatype];
$corresponding_type = 'tns:'.$corresponding_type;
} else if (isset($declared_types[$base_group_name.'_'.$input->struct[0]->datatype])) {
$corresponding_type = $base_group_name.'_'.$input->struct[0]->datatype;
$corresponding_type = 'tns:'.$corresponding_type;
} else {
$corresponding_type = isset($corresponding_scalar_types[$input->struct[0]->datatype]) ? $corresponding_scalar_types[$input->struct[0]->datatype] : $default_data_type;
$corresponding_type = 'xsd:'.$corresponding_type;
}
$array_content_type = $corresponding_type;
} else {
$array_content_type = "tns:".$method_name."_".XMLEntities($input->name).'_struct';
}
$additional_definition = 'name).'">';
$additional_definition .= ' ';
$additional_definition .= ' ';
$additional_definition .= ' ';
$additional_definition .= ' ';
$additional_definition .= ' ';
$additional_definition .= '';
$additional_definitions["ArrayOf".$method_name."_".XMLEntities($input->name)] = $additional_definition;
}
} else if ($nodetype == "part") {
$result .= 'name).'"/>';
if (!isset($additional_definitions["ArrayOf".$method_name."_".XMLEntities($input->name)])) {
//Si le tableau contient un seul élément, on le définit comme un tableau de ce type, sinon il faut définir un type tableau
if (count($input->struct) == 1) {
if (isset($type_aliases[$base_group_name.'_'.$input->struct[0]->datatype])) {
$corresponding_type = $type_aliases[$base_group_name.'_'.$input->struct[0]->datatype];
$corresponding_type = 'tns:'.$corresponding_type;
}
else if (isset($declared_types[$base_group_name.'_'.$input->struct[0]->datatype])) {
$corresponding_type = $base_group_name.'_'.$input->struct[0]->datatype;
$corresponding_type = 'tns:'.$corresponding_type;
}
else {
$corresponding_type = isset($corresponding_scalar_types[$input->struct[0]->datatype]) ? $corresponding_scalar_types[$input->struct[0]->datatype] : $default_data_type;
$corresponding_type = 'xsd:'.$corresponding_type;
}
$array_content_type = $corresponding_type;
} else {
$array_content_type = "tns:".$method_name."_".XMLEntities($input->name).'_struct';
}
$additional_definition = 'name).'">';
$additional_definition .= ' ';
$additional_definition .= ' ';
$additional_definition .= ' ';
$additional_definition .= ' ';
$additional_definition .= ' ';
$additional_definition .= '';
$additional_definitions["ArrayOf".$method_name."_".XMLEntities($input->name)] = $additional_definition;
}
}
if (count($input->struct) > 1) {
if (!isset($additional_definitions[$method_name."_".XMLEntities($input->name).'_struct'])) {
$additional_definition = 'name).'_struct">';
$additional_definition .= '';
foreach($input->struct as $anotherparam) {
$additional_definition .= $this->input_to_wsdl($anotherparam, $method_name, $base_group_name, $additional_definitions, "element");
}
$additional_definition .= '';
$additional_definition .= '';
$additional_definitions[$method_name."_".XMLEntities($input->name).'_struct'] = $additional_definition;
}
}
break;
case 'structure':
//Structure: il faut déclarer le type en question et lui faire référence
if ($base_type) {
$declared_name = $method_name;
} else {
$declared_name = $method_name."_".XMLEntities($input->name).'_struct';
}
//Référence
if ($nodetype == "element") {
$result .= '';
}
else if ($nodetype == "part") {
$result .= '';
}
//Déclaration du type (ça peut être récursif)
if (!isset($additional_definitions[$declared_name])) {
$additional_definition = '';
$additional_definition .= '';
foreach($input->struct as $anotherparam) {
$additional_definition .= $this->input_to_wsdl($anotherparam, $method_name, $base_group_name, $additional_definitions, "element");
}
$additional_definition .= '';
$additional_definition .= '';
$additional_definitions[$declared_name] = $additional_definition;
}
break;
}
}
return $result;
}
public function output_to_wsdl($output, $method_name, $base_group_name, &$additional_definitions, $nodetype="element") {
//C'est la même que pour les inputs
return $this->input_to_wsdl($output, $method_name, $base_group_name, $additional_definitions, $nodetype);
}
public function type_to_wsdl($output, $method_name, $base_group_name, &$additional_definitions, $nodetype="element") {
//C'est la même que pour les inputs
return $this->input_to_wsdl($output, $method_name, $base_group_name, $additional_definitions, $nodetype, true);
}
/*
* Cette fonction convertit la liste des fonctions de la source en un fichier wsdl, puis l'envoie
*
*/
public function return_wsdl($source_object, $user_id=0) {
global $charset;
global $declared_types;
global $type_aliases;
$cache_ref = "api_soap_wsdl_".$source_object->id;
if ($source_object->connector->config["cache_wsdl"]) {
//Voyons si on peut trouver quelque chose de pas trop vieux dans le cache
$es_cache = new external_services_cache('es_cache_blob', 3600);
$cached_result = $es_cache->decache_single_object($cache_ref, CACHE_TYPE_MISC);
if ($cached_result !== false) {
//Il est bon? On l'envoie
if (!isset($_GET["nx"]))
header('Content-Type: text/xml');
print $cached_result;
exit();
}
}
//Récupérons la liste des fonctions que l'on doit exporter
$api_catalog = es_catalog::get_instance();
$api_es = new external_services();
//$api_rights = new external_services_rights($api_es);
$final_method_list = array();
foreach ($source_object->config["exported_functions"] as $amethod) {
// if ($api_rights->has_rights($user_id, $amethod["group"], $amethod["name"])) {
$final_method_list[] = $amethod;
// }
}
//Les entêtes du fichier
$wsdl_headers = '
';
//Les entêtes des déclarations de type
$wsdl_types = '
';
//On va construire la liste des types à déclarer en fonction de ce que l'on va rencontrer, puis on y reviendra
$additional_definitions = array();
$declared_types = array();
$type_aliases = array();
//Ajoutons les types du manifest s'il y en a
$handled_groups=array();
foreach ($final_method_list as $amethod) {
//Vérifions si on a pas déjà traité les types de ce groupe
if (isset($handled_groups[$amethod["group"]]))
continue;
//Ajoutons les types du groupe de la methode courante
foreach ($api_catalog->groups[$amethod["group"]]->types as &$atype) {
if ($atype->imported) {
$base_name = $api_catalog->groups[$atype->imported_from]->name.'_'.$atype->name;
$local_base_name = $api_catalog->groups[$amethod["group"]]->methods[$amethod["name"]]->group.'_'.$atype->name;
if (isset($declared_types[$base_name])) {
if (!isset($type_aliases[$local_base_name]))
$type_aliases[$local_base_name] = $base_name;
continue;
}
$this->type_to_wsdl($api_catalog->groups[$atype->imported_from]->types[$atype->name], $base_name, $atype->imported_from, $additional_definitions, "element");
$type_aliases[$local_base_name] = $base_name;
}
else {
$base_name = $api_catalog->groups[$amethod["group"]]->methods[$amethod["name"]]->group.'_'.$atype->name;
if (isset($declared_types[$base_name]))
continue;
$this->type_to_wsdl($atype, $base_name, $amethod["group"], $additional_definitions, "element");
}
$declared_types[$base_name] = true;
}
$handled_groups[$amethod["group"]] = true;
}
//Construction des messages
$wsdl_messages = "";
foreach ($final_method_list as $amethod) {
$method_name = $api_catalog->groups[$amethod["group"]]->methods[$amethod["name"]]->group.'_'.$api_catalog->groups[$amethod["group"]]->methods[$amethod["name"]]->name;
$wsdl_messages .= '';
foreach ($api_catalog->groups[$amethod["group"]]->methods[$amethod["name"]]->inputs as $ainput) {
$wsdl_messages .= $this->input_to_wsdl($ainput, $method_name, $amethod["group"], $additional_definitions, "part");
}
$wsdl_messages .= '';
$wsdl_messages .= '';
$output_count = count($api_catalog->groups[$amethod["group"]]->methods[$amethod["name"]]->outputs);
if ($output_count > 1) {
$additional_definition = "";
$additional_definition .= '';
$additional_definition .= '';
foreach ($api_catalog->groups[$amethod["group"]]->methods[$amethod["name"]]->outputs as $ainput) {
$additional_definition .= $this->output_to_wsdl($ainput, $method_name, $amethod["group"], $additional_definitions, "element");
}
$additional_definition .= '';
$additional_definition .= '';
$additional_definitions[XMLEntities($method_name).'ResponseStruct'] = $additional_definition;
$wsdl_messages .= '';
}
else if($output_count) {
$wsdl_messages .= $this->output_to_wsdl($api_catalog->groups[$amethod["group"]]->methods[$amethod["name"]]->outputs[0], $method_name, $amethod["group"], $additional_definitions, "part");
}
$wsdl_messages .= '';
}
//On a maintenant les types, on finit de construire le bloc associé
$wsdl_types .= implode("", $additional_definitions);
$wsdl_types .= '
';
//PortType
$wsdl_porttype = "";
$wsdl_porttype .= '';
foreach ($final_method_list as $amethod) {
$method_name = $api_catalog->groups[$amethod["group"]]->methods[$amethod["name"]]->group.'_'.$api_catalog->groups[$amethod["group"]]->methods[$amethod["name"]]->name;
$method_group = $amethod["group"];
$method_description = $api_catalog->groups[$amethod["group"]]->methods[$amethod["name"]]->description;
$input_description = $api_catalog->groups[$amethod["group"]]->methods[$amethod["name"]]->input_description;
$output_description = $api_catalog->groups[$amethod["group"]]->methods[$amethod["name"]]->output_description;
$wsdl_porttype .= '
'.XMLEntities($api_es->get_text($method_description, $method_group)).'
'.XMLEntities($api_es->get_text($input_description, $method_group)).'
'.XMLEntities($api_es->get_text($output_description, $method_group)).'
';
}
$wsdl_porttype .= '';
//Binding
$wsdl_binding = "";
$wsdl_binding .= '
';
foreach ($final_method_list as $amethod) {
$method_name = $api_catalog->groups[$amethod["group"]]->methods[$amethod["name"]]->group.'_'.$api_catalog->groups[$amethod["group"]]->methods[$amethod["name"]]->name;
$wsdl_binding .= '
';
}
$wsdl_binding .= '';
//Service
$server_location = serverURL();
$wsdl_service = "";
$wsdl_service .= '
';
$wsdl_footer = '';
//On conbine le tout pour donner le wsdl final
$wsdl = $wsdl_headers . $wsdl_types . $wsdl_messages . $wsdl_porttype . $wsdl_binding . $wsdl_service . $wsdl_footer;
if ($charset != 'utf-8')
$wsdl = utf8_encode($wsdl);
//On le met en cache si on le souhaite
if ($source_object->connector->config["cache_wsdl"]) {
$es_cache = new external_services_cache('es_cache_blob', 600);
$es_cache->encache_single_object($cache_ref, CACHE_TYPE_MISC, $wsdl);
}
//Et on l'envoi
if (!isset($_GET["nx"]))
header('Content-Type: text/xml');
print $wsdl;
exit();
}
public function return_soapfault_from_api_exception($e) {
$this->server->fault("Internal API Error", $e->getMessage());
}
public function process($source_id, $pmb_user_id) {
global $wsdl;
$get_wsdl = isset($wsdl);
$the_source = $this->connector_object->instantiate_source_class($source_id);
if (!isset($the_source->config["exported_functions"]))
$this->return_error("Source wasn't configured");
//Si on nous demande le wsdl, on le génère et on l'envoi
if (isset($get_wsdl) && $get_wsdl) {
$this->return_wsdl($the_source, 0);
}
//Si on ne veut pas le wsdl ou qu'on ne demande rien de soap, alors on ne fait rien
if (!isset($_SERVER["HTTP_SOAPACTION"]) || !$_SERVER["HTTP_SOAPACTION"])
die();
//L'url du wsdl dépend de l'url courante, et on rajoute le ?wsdl
$wsdl_location = curPageURL();
$wsdl_location .= (strpos($wsdl_location, "?") === false ? "?wsdl" : "&wsdl");
//Pas de cache, ça nuit au developpement
ini_set("soap.wsdl_cache_enabled", ( (isset($the_source->config["cache_wsdl"]) && $the_source->config["cache_wsdl"]) ? 1 : 0));
//Récupérons à partir des entêtes le nom de l'opération que l'on souhaite exécuter.
//Exemple d'entête:
// SOAPAction: "http://sigb.net/pmb/es/apisoap/pmbesZWMTest1_credential_testfunction"\r\n
$soap_operation = substr(strrchr($_SERVER["HTTP_SOAPACTION"], "/"), 1, -1);
if (!$soap_operation)
die();
//Instantions le serveur SOAP
$this->server = new SoapServer($wsdl_location, array('encoding'=>'utf-8', 'features' => SOAP_SINGLE_ELEMENT_ARRAYS));
//Instantions la classe qui contient les fonctions
$ess = new external_services(true);
if ($ess->operation_need_messages($soap_operation)) {
//Allons chercher les messages
global $class_path;
global $include_path;
global $lang;
require_once("$class_path/XMLlist.class.php");
$messages = new XMLlist("$include_path/messages/$lang.xml", 0);
$messages->analyser();
global $msg;
$msg = $messages->table;
}
$proxy = $ess->get_proxy($pmb_user_id, array($soap_operation));
$proxy->set_error_callback(array(&$this, "return_soapfault_from_api_exception"));
$proxy->input_charset = 'utf-8';
if (!method_exists($proxy, $soap_operation))
$this->server->fault("unknown_method_or_bad_credentials", "Could not find the method according to your group internal's credentials");
//Donnons au serveur SOAP le proxy
$this->server->setObject($proxy);
//Et c'est parti!
$this->server->handle();
}
}