1<?php 2// (c) Copyright by authors of the Tiki Wiki CMS Groupware Project 3// 4// All Rights Reserved. See copyright.txt for details and a complete list of authors. 5// Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details. 6// $Id$ 7 8require_once 'lib/ointegratelib.php'; 9require_once 'soap/soaplib.php'; 10require_once 'soap/wsdllib.php'; 11 12/** 13 * Tiki_Webservice 14 * 15 */ 16class Tiki_Webservice 17{ 18 private $name; 19 public $url; 20 public $body; 21 public $operation; 22 public $wstype; 23 public $schemaVersion; 24 public $schemaDocumentation; 25 public $allowCookies; 26 27 private $templates = []; 28 private $all = false; 29 30 /** 31 * @param $name 32 * @return Tiki_Webservice 33 */ 34 public static function create($name) 35 { 36 if (! ctype_alpha($name) || self::getService($name)) { 37 return null; 38 } 39 40 $ws = new self; 41 $ws->name = strtolower($name); 42 43 return $ws; 44 } 45 46 /** 47 * @param $name 48 * @return Tiki_Webservice 49 */ 50 public static function getService($name) 51 { 52 $name = strtolower($name); 53 54 global $tikilib; 55 $result = $tikilib->query( 56 "SELECT url, operation, wstype, body, schema_version, schema_documentation FROM tiki_webservice WHERE service = ?", 57 [ $name ] 58 ); 59 60 while ($row = $result->fetchRow()) { 61 $service = new self; 62 63 $service->name = $name; 64 $service->url = $row['url']; 65 $service->body = $row['body']; 66 $service->operation = $row['operation']; 67 $service->wstype = $row['wstype']; 68 $service->schemaVersion = $row['schema_version']; 69 $service->schemaDocumentation = $row['schema_documentation']; 70 71 return $service; 72 } 73 } 74 75 /** 76 * @return array 77 */ 78 public static function getTypes() 79 { 80 return ['REST', 'SOAP']; 81 } 82 83 /** 84 * @return array 85 */ 86 public static function getList() 87 { 88 global $tikilib; 89 90 $result = $tikilib->query("SELECT service FROM tiki_webservice ORDER BY service"); 91 $list = []; 92 93 while ($row = $result->fetchRow()) { 94 $list[] = $row['service']; 95 } 96 97 return $list; 98 } 99 100 function save() 101 { 102 global $tikilib; 103 $tikilib->query("DELETE FROM tiki_webservice WHERE service = ?", [ $this->name ]); 104 105 $tikilib->query( 106 "INSERT INTO tiki_webservice (service, url, operation, wstype, body, schema_version, schema_documentation) VALUES(?,?,?,?,?,?,?)", 107 [ 108 $this->name, 109 $this->url, 110 $this->operation, 111 $this->wstype, 112 $this->body, 113 $this->schemaVersion, 114 $this->schemaDocumentation, 115 ] 116 ); 117 } 118 119 function delete() 120 { 121 global $tikilib; 122 $tikilib->query("DELETE FROM tiki_webservice WHERE service = ?", [ $this->name ]); 123 $tikilib->query("DELETE FROM tiki_webservice_template WHERE service = ?", [ $this->name ]); 124 } 125 126 /** 127 * @param $newName 128 * @return $this|null 129 */ 130 function rename($newName) 131 { 132 $tiki_webservice = TikiDb::get()->table('tiki_webservice'); 133 if (ctype_alpha($newName) && $tiki_webservice->fetchCount(['service' => $newName]) == 0) { 134 TikiDb::get()->table('tiki_webservice_template')->updateMultiple( 135 ['service' => $newName,], 136 ['service' => $this->name] 137 ); 138 $tiki_webservice->update(['service' => $newName,], ['service' => $this->name]); 139 $this->name = $newName; 140 return $this; 141 } else { 142 return null; 143 } 144 } 145 146 /** 147 * @return array 148 */ 149 function getParameters() 150 { 151 global $wsdllib; 152 153 switch ($this->wstype) { 154 case 'SOAP': 155 return $wsdllib->getParametersNames($this->url, $this->operation); 156 157 case 'REST': 158 default: 159 if (preg_match_all("/%(\w+)%/", $this->url . ' ' . $this->body, $matches, PREG_PATTERN_ORDER)) { 160 return array_diff($matches[1], [ 'service', 'template' ]); 161 } else { 162 return []; 163 } 164 } 165 } 166 167 /** 168 * @param $params 169 * @return array 170 */ 171 function getParameterMap($params) 172 { 173 $parameters = []; 174 175 foreach ($this->getParameters() as $key => $name) { 176 if (isset($params[$name])) { 177 $parameters[$name] = $params[$name]; 178 } else { 179 $parameters[$name] = ''; 180 } 181 } 182 183 return $parameters; 184 } 185 186 /* 187 * If fullResponse = true, "out" parameters from .NET calls are included in the response. 188 * If false, only the <request>Response part of the reply is included. 189 * fullResponse has no effect for REST calls 190 */ 191 /** 192 * @param $params 193 * @param bool $fullReponse 194 * @return bool|OIntegrate_Response 195 */ 196 function performRequest($params, $fullReponse = false, $clearCache = false) 197 { 198 global $soaplib, $prefs; 199 200 $built = $this->url; 201 $builtBody = $this->body; 202 203 $map = $this->getParameterMap($params); 204 205 if ($built) { 206 switch ($this->wstype) { 207 case 'SOAP': 208 if (! empty($this->operation)) { 209 $options = [ 'encoding' => 'UTF-8' ]; 210 211 if ($prefs['use_proxy'] == 'y' && ! strpos($built, 'localhost')) { 212 $options['proxy_host'] = $prefs['proxy_host']; 213 $options['proxy_port'] = $prefs['proxy_port']; 214 } 215 216 $response = new OIntegrate_Response(); 217 $soaplib->allowCookies = $this->allowCookies; 218 try { 219 $response->data = $soaplib->performRequest($built, $this->operation, $map, $options, $fullReponse); 220 } catch (Exception $e) { 221 Feedback::error(tr('Webservice error on %0 request "%1"', $this->wstype, $this->url) 222 . '<br>' . $e->getMessage()); 223 } 224 225 return $response; 226 } 227 228 return false; 229 230 case 'REST': 231 default: 232 foreach ($map as $name => $value) { 233 $built = str_replace("%$name%", urlencode($value), $built); 234 $builtBody = str_replace("%$name%", urlencode($value), $builtBody); 235 } 236 237 $ointegrate = new OIntegrate; 238 $ointegrate->addAcceptTemplate('smarty', 'tikiwiki'); 239 $ointegrate->addAcceptTemplate('smarty', 'html'); 240 $ointegrate->addAcceptTemplate('javascript', 'html'); 241 242 if ($this->schemaVersion) { 243 $ointegrate->addSchemaVersion($this->schemaVersion); 244 } 245 246 try { 247 $response = $ointegrate->performRequest($built, $builtBody, $clearCache); 248 } catch (Exception $e) { 249 Feedback::error(tr('Webservice error on %0 request "%1"', $this->wstype, $this->url) 250 . '<br>' . $e->getMessage()); 251 } 252 253 return $response; 254 } 255 } 256 } 257 258 /** 259 * @param $name 260 * @return Tiki_Webservice_Template 261 */ 262 function addTemplate($name) 263 { 264 if (! ctype_alpha($name) || empty($name)) { 265 return; 266 } 267 268 $template = new Tiki_Webservice_Template; 269 $template->webservice = $this; 270 $template->name = strtolower($name); 271 272 $this->templates[$name] = $template; 273 274 return $template; 275 } 276 277 /** 278 * @param $name 279 */ 280 function removeTemplate($name) 281 { 282 global $tikilib; 283 284 $tikilib->query("DELETE FROM tiki_webservice_template WHERE service = ? AND template = ?", [ $this->name, $name ]); 285 } 286 287 /** 288 * @return array 289 */ 290 function getTemplates() 291 { 292 if ($this->all) { 293 return $this->templates; 294 } 295 296 global $tikilib; 297 $result = $tikilib->query( 298 "SELECT template, last_modif, engine, output, content FROM tiki_webservice_template WHERE service = ?", 299 [ $this->name ] 300 ); 301 302 while ($row = $result->fetchRow()) { 303 $template = new Tiki_Webservice_Template; 304 $template->webservice = $this; 305 $template->name = $row['template']; 306 $template->lastModif = $row['last_modif']; 307 $template->engine = $row['engine']; 308 $template->output = $row['output']; 309 $template->content = $row['content']; 310 311 $this->templates[$template->name] = $template; 312 } 313 314 $this->all = true; 315 return $this->templates; 316 } 317 318 /** 319 * @param $name 320 * @return Tiki_Webservice_Template 321 */ 322 function getTemplate($name) 323 { 324 if (isset($this->templates[$name])) { 325 return $this->templates[$name]; 326 } 327 328 global $tikilib; 329 330 $result = $tikilib->query( 331 "SELECT last_modif, engine, output, content FROM tiki_webservice_template WHERE service = ? AND template = ?", 332 [ $this->name, $name ] 333 ); 334 335 while ($row = $result->fetchRow()) { 336 $template = new Tiki_Webservice_Template; 337 $template->webservice = $this; 338 $template->name = $name; 339 $template->lastModif = $row['last_modif']; 340 $template->engine = $row['engine']; 341 $template->output = $row['output']; 342 $template->content = $row['content']; 343 344 $this->templates[$name] = $template; 345 return $template; 346 } 347 } 348 349 function getName() 350 { 351 return $this->name; 352 } 353} 354 355 356/** 357 * Tiki_Webservice_Template 358 * 359 */ 360class Tiki_Webservice_Template 361{ 362 public $webservice; 363 public $name; 364 public $engine; 365 public $output; 366 public $content; 367 public $lastModif; 368 369 function save() 370 { 371 global $tikilib; 372 373 $tikilib->query( 374 "DELETE FROM tiki_webservice_template WHERE service = ? AND template = ?", 375 [ $this->webservice->getName(), $this->name ] 376 ); 377 378 $tikilib->query( 379 "INSERT INTO tiki_webservice_template (service, template, engine, output, content, last_modif) VALUES(?,?,?,?,?,?)", 380 [ 381 $this->webservice->getName(), 382 $this->name, 383 $this->engine, 384 $this->output, 385 $this->content, 386 time(), 387 ] 388 ); 389 390 if ($this->engine === 'index') { 391 if ($this->output === 'mindex') { 392 Feedback::warning(tra('You will need to rebuild the search index to see these changes')); 393 } 394 395 require_once 'lib/search/refresh-functions.php'; 396 refresh_index('webservice', $this->name); 397 } 398 } 399 400 /** 401 * @return string 402 */ 403 function getTemplateFile() 404 { 405 $token = sprintf("%s_%s", $this->webservice->getName(), $this->name); 406 $file = "temp/cache/" . md5($token) . '.tpl'; 407 408 if (! file_exists($file) || $this->lastModif > filemtime($file)) { 409 file_put_contents($file, $this->content); 410 } 411 412 return realpath($file); 413 } 414 415 /** 416 * @param OIntegrate_Response $response 417 * @param $outputContext 418 * @return mixed|string 419 */ 420 function render(OIntegrate_Response $response, $outputContext) 421 { 422 return $response->render($this->engine, $this->output, $outputContext, $this->getTemplateFile()); 423 } 424} 425