WSCOMUN  2.1.2
Web Services Comunes para PHP/GVHidra
WSSSoapClient.php
1 <?php
2 
6 namespace WSCOMUN;
7 
8 use SoapClient;
9 use WSSESoap;
10 use XMLSecurityKey;
11 
12 require_once('XMLSecLibs/WSSESoap.php');
13 
33 {
38  protected $keyFile='';
39 
44  protected $passPhrase='';
45 
50  protected $certFile='';
51 
55  private $conTrazabilidadPAI = true;
56 
60  private $enableWSSecurity = true;
61 
65  private $userToken = '';
66 
70  private $passUserToken = '';
71 
75  protected $nsCert = null;
76 
80  protected $idApp = null;
81 
86  protected $mtom = false;
87 
88 
96  public function __construct($wsdl, $vOptions=null)
97  {
98 
99  $this->soapSent='';
100  $this->keyFile='';
101  $this->passPhrase='';
102  $this->certFile='';
103 
104  $this->conTrazabilidadPAI = true;
105  $this->enableWSSecurity = true;
106 
107  if (is_array($vOptions))
108  {
109  $vOptions['trace'] = true;
110  }
111  else
112  {
113  $vOptions = array('trace' => true);
114  }
115 
116  return parent::__construct($wsdl, $vOptions);
117  }//Fin __contruct
118 
119 
126  public function setKeyFile($pathKey)
127  {
128  $this->keyFile = $pathKey;
129  }//setKeyFile
130 
131 
138  public function getKeyFile()
139  {
140  return($this->keyFile);
141  }//getKeyFile
142 
143 
150  public function setPassPhrase($passphrase)
151  {
152  $this->passPhrase = $passphrase;
153  }//setPassPhrase
154 
155 
162  public function getPassPhrase()
163  {
164  return($this->passPhrase);
165  }//getPassPhrase
166 
167 
174  public function setCertFile($pathCert)
175  {
176  $this->certFile = $pathCert;
177  }//setCertFile
178 
185  public function getCertFile()
186  {
187  return($this->certFile);
188  }//getCertFile
189 
190 
197  public function loadCert($vCertData)
198  {
199  if (!is_array($vCertData))
200  throw new \Exception('La información debe venir como array asociativo');
201 
202  if (array_key_exists('certFile', $vCertData))
203  {
204  $this->certFile = $vCertData['certFile'];
205  }
206  else
207  {
208  throw new \Exception('El array asociativo debe contener la ruta al certificado');
209  }
210 
211  if (array_key_exists('keyFile', $vCertData))
212  {
213  $this->keyFile = $vCertData['keyFile'];
214  }
215  else
216  {
217  throw new \Exception('El array asociativo debe contener la ruta al fichero de clave');
218  }
219 
220  if (array_key_exists('passPhrase', $vCertData))
221  {
222  $this->passPhrase = $vCertData['passPhrase'];
223  }
224  }//loadCert
225 
226 
227 
234  public function isMTOM()
235  {
236  return($this->mtom);
237  }//isMTOM
238 
239 
240 
241  // ---------------------------------------------
242  // Métodos para el uso de trazabilidad de la PAI
243  // ---------------------------------------------
250  public function loadTracertPAI($vTrazabilidadPAI)
251  {
252  if (!is_array($vTrazabilidadPAI))
253  {
254  throw new \Exception('Las opciones de trazabilidad deben ser un array asociativo');
255  }
256 
257  if (array_key_exists('idApp', $vTrazabilidadPAI))
258  {
259  $this->idApp = $vTrazabilidadPAI['idApp'];
260  }
261  else
262  {
263  throw new \Exception('El array asociativo debe contener el ID de la aplicación que consume el WS');
264  }
265 
266  if ($this->enableWSSecurity)
267  {
268  if (!empty($this->certFile))
269  {
270  $this->getCertificateSerial();
271  }
272  }
273  }//loadTracertPAI
274 
275 
282  public function enablePAITrace___($vTrazabilidadPAI = null)
283  {
284  if (empty ($vTrazabilidadPAI))
285  {
286  if (empty($this->idApp))
287  {
288  throw new \Exception(__CLASS__.":: Debe fijarse el idApp");
289  }
290 
291  if ($this->enableWSSecurity())
292  {
293  if(empty($this->nsCert) && !empty($this->certFile))
294  {
295  $this->nsCert = $this->getCertificateSerial();
296  }
297  }
298  }
299  else
300  {
301  try
302  {
303  $this->loadTrazabilidad($vTrazabilidadPAI);
304  }
305  catch (\Exception $e)
306  {
307  throw $e;
308  }
309  }
310  $this->conTrazabilidadPAI = true;
311  }//enablePAITrace
312 
313 
318  public function disablePAITrace()
319  {
320  $this->conTrazabilidadPAI = false;
321  }//disablePAITrace
322 
323 
324 
329  public function enableWSSecurity()
330  {
331  $this->enableWSSecurity = true;
332  }//enableWSSecurity
333 
334 
339  public function disableWSSecurity()
340  {
341  $this->enableWSSecurity = false;
342  }//disableWSSecurity
343 
344 
351  public function setUserToken($username, $password)
352  {
353  $this->userToken = $username;
354  $this->passUserToken = $password;
355  }//setUserToken
356 
357 
364  public function getCertificateSerial()
365  {
366  $certFile = realpath($this->certFile);
367  $cert = file_get_contents($certFile);
368  if ($cert === false)
369  {
370  throw new \Exception(__FILE__.'::'.__CLASS__." - No puedo leere el contenido de $certFile ");
371  }
372  $v_certData = openssl_x509_parse($cert, true);
373  $this->nsCert = strtoupper(self::numberBaseConvert($v_certData['serialNumber']));
374  return $this->nsCert;
375  }//getCertificateSerial
376 
377 
389  private static function numberBaseConvert($numstring, $frombase=10, $tobase=16)
390  {
391  $chars = "0123456789abcdefghijklmnopqrstuvwxyz";
392  $tostring = substr($chars, 0, $tobase);
393  $length = strlen($numstring);
394  $result = '';
395  $number = array();
396  for ($i = 0; $i < $length; $i++)
397  {
398  $number[$i] = strpos($chars, $numstring{$i});
399  }
400  do
401  {
402  $divide = 0;
403  $newlen = 0;
404  for ($i = 0; $i < $length; $i++)
405  {
406  $divide = $divide * $frombase + $number[$i];
407  if ($divide >= $tobase)
408  {
409  $number[$newlen++] = (int)($divide / $tobase);
410  $divide = $divide % $tobase;
411  } elseif ($newlen > 0)
412  {
413  $number[$newlen++] = 0;
414  }
415  }
416  $length = $newlen;
417  $result = $tostring{$divide} . $result;
418  } while ($newlen != 0);
419 
420  return $result;
421  }
422 
423 
431  private function getPAITraceToken()
432  {
433  $t = microtime(true);
434  $micro = sprintf("%06d",($t - floor($t)) * 1000000);
435  $date = new \DateTime( date('Y-m-d H:i:s.'.$micro, $t));
436  $token = $this->nsCert.'-'.$this->idApp.'-'.substr($date->format('YmdHisu'), 0, 17);
437 
438  return $token;
439  }//getPAITraceToken
440 
441 
442 
443 
452  public function __doRequest($newRequest, $location, $action, $version, $one_way = null)
453  {
454  if ($this->enableWSSecurity==true)//Si trabajamos con WSSecurity
455  {
456  //Creamos un DOMDocument
457  $doc = new \DOMDocument('1.0');
458 
459  //Cargamos el XML pasado por parámetro (WSDL)
460  $doc->loadXML($newRequest);
461 
462  //Creamos una instancia de WSSESoap con el documento, sin "mustUnderstand" ni "actor"
463  $objWSSE = new WSSESoap($doc, false, false);
464 
465  if (!empty($this->certFile))
466  {
467  //Creamos una instacian de XMLSecurityKey con el RSA SHA1 y de tipo privado
468  $objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type'=>'private'));
469  //Pasamos el valor de passphrase
470  $objKey->passphrase = $this->getPassPhrase();
471  //Cargamos la clave privada con la ruta del fichero, que es fichero y que no es certificado
472  $objKey->loadKey($this->getKeyFile(), true);
473 
474  //Firmamos el mensaje
475  $objWSSE->signSoapDoc($objKey);
476 
477  //Añadimos el BinarySecurityToken, pasamos el contenido del certificado, le decimos que es formato PEM
478  $token = $objWSSE->addBinaryToken(file_get_contents($this->getCertFile()), true);
479  //Añadimos el KeyInfo
480  $objWSSE->attachTokentoSig($token);
481  }
482  elseif (!empty($this->userToken))
483  {
484  //Añadimos el UserToken
485  $objWSSE->addUserToken($this->userToken, $this->passUserToken, $this->true);
486  }
487  else
488  {
489  // Si no se suministra certificado o UserToken se lanza una excepcion
490  throw new \Exception('Al activar WSSecurity es obligatorio suministrar un certificado o los datos que componene el UserToken');
491  }
492 
493  //Añadimos el Timestamp
494  $objWSSE->addTimestamp(3600);
495 
496  //Obtenemos el REQUEST modificado
497  $newRequest = $objWSSE->saveXML();
498  }
499 
500  if ($this->conTrazabilidadPAI)//Si trabajamos con la trazabilidad PAI
501  {
502  $dom = new \DOMDocument('1.0');
503  $dom->loadXML($newRequest);
504  $xpath = new \DOMXpath($dom);
505  $headers = $xpath->query("/*[local-name()='Envelope']/*[local-name()='Header']");
506 
507  if (($headers->length) > 0)
508  {
509  $header = $headers->item(0);//Localizamos la cabecera
510  }
511  else
512  {
513  $envelop = $dom->firstChild;
514  $prefijo = $dom->lookupPrefix ('http://schemas.xmlsoap.org/soap/envelope/');
515  $header = $dom->createElementNS ('http://schemas.xmlsoap.org/soap/envelope/',$prefijo.':Header','');
516  $body = $envelop->firstChild;
517  $header = $envelop->insertBefore($header, $body);
518  }
519  //Creamos el nodo traza
520  $nodoTraza = $dom->createElementNS('http://dgti.gva.es/interoperabilidad', 'Id_trazabilidad');
521  $nodoTraza->appendChild(new \DOMText( (string) $this->getPAITraceToken()));
522  $header->appendChild($nodoTraza);
523  unset($newRequest);$newRequest=null;gc_collect_cycles();
524  $newRequest = $dom->saveXML();
525  }
526 
527  //Tratamos la respuesta
528  $response = parent::__doRequest($newRequest, $location, $action, $version, $one_way);
529 
530  //Si la respuesta NO contiene MTOM la devolvemos
531  if (strpos($response, "Content-Type: application/xop+xml") === false)
532  {
533  $this->mtom = true;
534  }
535  return $response;
536  }
537 
538 
539 
540 }//Fin WSSSoapClient
541 ?>
__construct($wsdl, $vOptions=null)
setUserToken($username, $password)
enablePAITrace___($vTrazabilidadPAI=null)
setPassPhrase($passphrase)
loadTracertPAI($vTrazabilidadPAI)
__doRequest($newRequest, $location, $action, $version, $one_way=null)