WSCOMUN  2.1.0
Web Services Comunes para PHP/GVHidra
WSComunFClient.php
1 <?php
13 namespace WSCOMUN;
23 use DOMDocument;
24 use Exception;
27 use WSClientFirma;
28 use stdClass;
29 
30 
35 define('DEBUG', false);
36 
40 require_once 'WSSSoapClient.php';
44 require_once ('WSCMIME/WSCMime.php');
45 
46 
74 {
78  const KEYCLIENTE_AUTENTICA = 'autentica';
79  const KEYCLIENTE_AUTORIZA = 'autoriza';
80  const KEYCLIENTE_FIRMA = 'firma';
81  const KEYCLIENTE_GDE = 'gde';
82  const KEYCLIENTE_SALT = 'salt';
83  const KEYCLIENTE_CSV = 'csv';
84  const KEYCLIENTE_CATASTRO = 'catastro';
85  const KEYCLIENTE_CATASTRO_BIENES = 'catbienes';
86  const KEYCLIENTE_GDE2 = 'gde2';
87  const KEYCLIENTE_PF = 'pfcons';
88  const KEYCLIENTE_PF_MOD = 'pfmod';
89  const KEYCLIENTE_PF_ADM = 'pfadm';
90  const KEYCLIENTE_GVLOGIN = 'gvlogin';
91  const KEYCLIENTE_REGDEPARTAMENTAL = 'regdepartamental';
92 
93 
97  const TIPOBUSQUEDA_USUARIO = 'USUARIO';
98  const TIPOBUSQUEDA_GRUPO = 'GRUPO';
99 
100 
101 
107  protected static $MYSOAPOP_TRACE = true; //Necesario para tratar las cabeceras MTOM
108  protected static $MYSOAPOP_WSDL_CACHE = WSDL_CACHE_BOTH;//Desarrollo WSDL_CACHE_NONE, produccion WSDL_CACHE_BOTH
109  protected static $MYSOAPOP_SOAP_VERSION = SOAP_1_1;//Los end points son soap 1, no soap 2
110 
111 
112 
116  protected static $NAMESPACE_GVA = 'http://dgm.gva.es/ayf/war/schemas/v2_00';
117  protected static $NAMESPACE_GDE = 'urn:es:gva:dgm:tra:gde:vista:model';
118  protected static $NAMESPACE_SALT = 'http://salt.ws.edu.gva.es/';
119  protected static $NAMESPACE_CSVGVA = 'urn:es:gva:dgm:tra:csvgva';
120  protected static $NAMESPACE_GDE2 = 'urn:es:gva:dgm:tra:gde:vista:v2:model';
121  protected static $NAMESPACE_CAT_ESP = 'http://intermediacion.redsara.es/scsp/esquemas/datosespecificos';
122  protected static $NAMESPACE_CAT_PET = 'http://intermediacion.redsara.es/scsp/esquemas/V3/peticion';
123  protected static $NAMESPACE_CAT_SR = 'http://intermediacion.redsara.es/scsp/esquemas/V3/solicitudRespuesta';
124  protected static $NAMESPACE_PF = null; // 'urn:juntadeandalucia:cice:pfirma:type:v2.0';
125  protected static $NAMESPACE_PF_MOD = null; // 'urn:juntadeandalucia:cice:pfirma:type:v2.0';
126  protected static $NAMESPACE_PF_ADM = null; // 'urn:juntadeandalucia:cice:pfirma:type:v2.0';
127  protected static $NAMESPACE_LOGIN = 'urn:es:gva:gvlogin:sso:model';
128  protected static $NAMESPACE_REGDEPARTAMENTAL = 'urn:es:gva:mastin:departamental:model';
129 
134  private $v_wsdl;
135 
136 
142  private $WSDLTimeOut;
143 
149  protected $v_clienteWS;
150 
151 
157  private $keyFile='';
158 
164  protected $passPhrase=null;
165 
171  private $certFile='';
172 
173 
174 
180  private $_debugMode;
181 
187  private $_debugInfo;
188 
194  protected $vTrazabilidad;
195 
196 
202  private $idApp;
203 
204 
210  private $nsCert;
211 
212 
218  protected $userToken = '';
219 
220 
226  protected $passUserToken = '';
227 
228 
234  protected $enableTrazabilidadPAI = true;
235 
236 
242  protected $enableWSSecurity = true;
243 
244  /* ----------------------------------------------------------------------- */
245  /* --------------------------- Métodos públicos -------------------------- */
246  /* ----------------------------------------------------------------------- */
247 
248 
260  public function __construct($v_wsdl, $v_opciones=null)
261  {
262  if (!is_array($v_wsdl))
263  {
264  throw new Exception (
265  __CLASS__.':'.__METHOD__.'['.__FILE__.'-'.__LINE__.']'.
266  'v_wsdl debe ser un array asociativo (autenticacion,autorizacion,firma) con las URI de los WSDL'
267  );
268  }
269  //Inicializamos el array asociativo de URIs WSDL
270  $this->v_wsdl = $v_wsdl;
271 
272  //Inicializamos el array asociativo de clientes
273  $this->v_clienteWS = array
274  (
275  self::KEYCLIENTE_AUTENTICA => null,
276  self::KEYCLIENTE_AUTORIZA => null,
277  self::KEYCLIENTE_CATASTRO => null,
278  self::KEYCLIENTE_CATASTRO_BIENES => null,
279  self::KEYCLIENTE_CSV => null,
280  self::KEYCLIENTE_FIRMA => null,
281  self::KEYCLIENTE_GDE => null,
282  self::KEYCLIENTE_GDE2 => null,
283  self::KEYCLIENTE_PF => null,
284  self::KEYCLIENTE_PF_ADM => null,
285  self::KEYCLIENTE_PF_MOD => null,
286  self::KEYCLIENTE_SALT => null,
287  self::KEYCLIENTE_GVLOGIN => null,
288  self::KEYCLIENTE_REGDEPARTAMENTAL => null
289  );
290 
291 
292  $this->nsCert = null;
293  $this->enableWSSecurity = true;
294  $this->enableTrazabilidadPAI = true;
295  $this->idApp=null;
296 
297  if (is_array($v_opciones))
298  {
299  //Fijamos datos del certificado
300  if (array_key_exists('certFile', $v_opciones))
301  {
302  $this->setCertFile($v_opciones['certFile']);
303  $this->nsCert = $this->getCertificateSerial();
304  }
305 
306  if (array_key_exists('keyFile', $v_opciones))
307  {
308  $this->setKeyFile($v_opciones['keyFile']);
309  }
310 
311  if (array_key_exists('passPhrase', $v_opciones))
312  {
313  $this->setPassPhrase($v_opciones['passPhrase']);
314  }
315 
316  if (array_key_exists('enableWSSecurity', $v_opciones))
317  {
318  $this->enableWSSecurity = $v_opciones['enableWSSecurity'] && true;
319  }
320 
321  if (array_key_exists('userToken', $v_opciones))
322  {
323  $this->userToken = $v_opciones['userToken'];
324  }
325 
326  if (array_key_exists('passUserToken', $v_opciones))
327  {
328  $this->passUserToken = $v_opciones['passUserToken'];
329  }
330 
331  if (array_key_exists('enableTrazabilidadPAI', $v_opciones))
332  {
333  $this->enableTrazabilidadPAI = $v_opciones['enableTrazabilidadPAI'] && true;
334  }
335 
336 
337  if (array_key_exists('idApp', $v_opciones))
338  {
339  $this->idApp = $v_opciones['idApp'];
340  }
341  }//Fin opciones
342 
343  $this->vTrazabilidad = array
344  (
345  'idApp' => $this->idApp,
346  'nsCert'=> $this->nsCert
347  );
348 
349  /* Opciones de DEBUG y tiempos de espera */
350  $this->setDebugMode(DEBUG);
351  $this->_debugInfo = array();
352  $this->WSDLTimeOut = 15;
353  }//Fin __construct
354 
355 
369  public static function makeWSClient($wsID, $v_wsdl, $v_opciones=null)
370  {
371  $wsClient = NULL;
372  switch ($wsID)
373  {
374  //CATASTRO
375  case self::KEYCLIENTE_CATASTRO:
376  case self::KEYCLIENTE_CATASTRO_BIENES:
377  require_once 'WS/catastro/WSClientCatastro.php';
378  require_once 'WS/catastro/ComposerCatastro.php';
379  require_once 'WS/catastro/objCatastro.php';
381  $wsClient = new WSClientCatastro($v_wsdl, $v_opciones);
382  break;
383 
384  //CSV
385  case self::KEYCLIENTE_CSV:
386  require_once 'WS/CSV/WSClientCSV.php';
388  $wsClient = new WSClientCSV($v_wsdl, $v_opciones);
389  break;
390 
391  //SAFE
392  case self::KEYCLIENTE_AUTENTICA:
393  require_once 'WS/SAFE/WSClientAutentica.php';
394  $wsClient = new WSClientAutentica($v_wsdl, $v_opciones);
395  break;
396 
397  case self::KEYCLIENTE_AUTORIZA:
398  require_once 'WS/SAFE/WSClientAutoriza.php';
399  $wsClient = new WSClientAutoriza($v_wsdl, $v_opciones);
400  break;
401 
402  case self::KEYCLIENTE_FIRMA:
403  require_once 'WS/SAFE/WSClientFirma.php';
404  $wsClient = new WSClientFirma($v_wsdl, $v_opciones);
405  break;
406 
407  //GDE
408  case self::KEYCLIENTE_GDE:
409  require_once 'WS/GDE/WSClientGDE.php';
411  $wsClient = new WSClientGDE($v_wsdl, $v_opciones);
412  break;
413 
414  case self::KEYCLIENTE_GDE2:
415  require_once 'WS/GDE/WSClientGDE2.php';
416  require_once 'WS/GDE/ComposerGDE2.php';
418  $wsClient = new WSClientGDE2($v_wsdl, $v_opciones);
419  break;
420 
421  case self::KEYCLIENTE_SALT:
422  require_once 'WS/SALT/WSClientSALT.php';
424  $wsClient = new WSClientSALT($v_wsdl, $v_opciones);
425  break;
426 
427  //GVLOGIN
428  case self::KEYCLIENTE_GVLOGIN:
429  require_once 'WS/GVLOGIN/WSClientGVLogin.php';
431  $wsClient = new WSClientGVLogin($v_wsdl, $v_opciones);
432  break;
433 
434  //PORTAFIRMAS
435  case self::KEYCLIENTE_PF:
436  case self::KEYCLIENTE_PF_MOD:
437  case self::KEYCLIENTE_PF_ADM:
438  require_once 'WS/PORTAFIRMAS/WSClientPortafirmas.php';
439  require_once 'WS/PORTAFIRMAS/ComposerPortafirmas.php';
441  $wsClient = new WSClientPortafirmas($v_wsdl, $v_opciones);
442  break;
443 
444  // REGISTRO DEPARTAMENTAL
445  case self::KEYCLIENTE_REGDEPARTAMENTAL:
446  require_once 'WS/REGDEPARTAMENTAL/WSClientRegDepartamental.php';
447  require_once 'WS/REGDEPARTAMENTAL/ComposerRegDepartamental.php';
448  $wsClient = new WSClientRegDepartamental($v_wsdl, $v_opciones);
449  break;
450 
451  default:
452  $wsClient = NULL;
453  if (DEBUG)
454  {
455  error_log('Clave cliente no reconocida. ('.$wsClient.')');
456  }
457  break;
458  }
459 
460  if (is_array($v_opciones))
461  {
462  //Fijamos datos del certificado
463  if (array_key_exists('certFile', $v_opciones))
464  {
465  $wsClient->setCertFile($v_opciones['certFile']);
466  $wsClient->nsCert = $wsClient->getCertificateSerial();
467  }
468 
469  if (array_key_exists('keyFile', $v_opciones))
470  {
471  $wsClient->setKeyFile($v_opciones['keyFile']);
472  }
473 
474  if (array_key_exists('passPhrase', $v_opciones))
475  {
476  $wsClient->setPassPhrase($v_opciones['passPhrase']);
477  }
478 
479  if (array_key_exists('enableWSSecurity', $v_opciones))
480  {
481  $wsClient->enableWSSecurity = $v_opciones['enableWSSecurity'] && true;
482  }
483 
484  if (array_key_exists('userToken', $v_opciones))
485  {
486  $wsClient->userToken = $v_opciones['userToken'];
487  }
488 
489  if (array_key_exists('passUserToken', $v_opciones))
490  {
491  $wsClient->passUserToken = $v_opciones['passUserToken'];
492  }
493 
494  if (array_key_exists('enableTrazabilidadPAI', $v_opciones))
495  {
496  $wsClient->enableTrazabilidadPAI = $v_opciones['enableTrazabilidadPAI'] && true;
497  }
498 
499 
500  if (array_key_exists('idApp', $v_opciones))
501  {
502  $wsClient->idApp = $v_opciones['idApp'];
503  }
504 
505  $wsClient->loadTracertPAI($v_opciones);
506  }//Fin opciones
507 
508  return $wsClient;
509 
510  }//Fin makeWSClient
511 
512 
519  public function getDebugMode()
520  {
521  return($this->_debugMode);
522  }//getDebugMode
523 
524 
531  public function getDebugInfo()
532  {
533  return $this->_debugInfo;
534  }//Fin getDebugInfo
535 
536 
537 
544  public function setDebugMode($activo)
545  {
546  self::$MYSOAPOP_TRACE = true;//Necesario para tratar MTOM
547  $this->_debugMode = $activo;
548  if ($activo)
549  {
550  self::$MYSOAPOP_WSDL_CACHE = WSDL_CACHE_NONE;
551  }
552  else
553  {
554  self::$MYSOAPOP_WSDL_CACHE = WSDL_CACHE_MEMORY;//Sólo en memoria
555  $this->_debugInfo = array();//Vaciamos las trazas de debug
556  }
557  }//setDebugMode
558 
559 
566  public function addDebugInfo($info)
567  {
568  if (!empty($info))
569  {
570  $this->_debugInfo[] = $info;
571  }
572 
573  }//addDebugInfo
574 
575 
576 
583  public function setKeyFile($pathKey)
584  {
585  $this->keyFile = $pathKey;
586  }//setKeyFile
587 
588 
595  public function setPassPhrase($passphrase)
596  {
597  $this->passPhrase = $passphrase;
598  }//setPassPhrase
599 
600 
607  public function setCertFile($pathCert)
608  {
609  $this->certFile = $pathCert;
610  }//setCertFile
611 
612 
619  public function setWSDLTimeOut($segs)
620  {
621  $this->WSDLTimeOut = $segs;
622  }//setCertFile
623 
624 
625 
632  public function getCertificateSerial($set=true)
633  {
634  if (empty($this->certFile))
635  {
636  throw new Exception('No se ha fijado valor para el certificado o el mismo no existe.');
637  }
638 
639  $certFile = realpath($this->certFile);
640  if ($certFile === false)
641  {
642  throw new Exception('No existe el fichero de cetificado: '.$this->certFile);
643  }
644 
645  $cert = file_get_contents($certFile);
646  if ($cert === false)
647  {
648  throw new Exception('No puede leerse el certificado : '.$certFile);
649  }
650 
651  $v_certData = openssl_x509_parse($cert, true);
652  $nsCert = strtoupper(self::numberBaseConvert($v_certData['serialNumber']));
653  if ($set==true)
654  {
655  $this->nsCert = $nsCert;
656  }
657  return $nsCert;
658  }//getCertificateSerial
659 
660 
667  public static function getCertificateInfo($ruta, $formato = null)
668  {
669  $certPath = null;
670  $cert = null;
671  $certContent = null;
672 
673  $certPath = realpath($ruta);
674 
675  $certContent = file_get_contents($certPath);
676  if ($certContent === false)
677  {
678  throw new Exception (
679  __CLASS__.':'.__METHOD__.'['.__FILE__.']-L'.__LINE__.
680  '. El certificado no se encuentra en la ruta: '.$certPath
681  );
682  }
683 
684  if (empty($formato))
685  {
686  $formato = pathinfo($certPath, PATHINFO_EXTENSION);
687  }
688 
689  $formato = trim(strtoupper($formato));
690  switch ($formato)
691  {
692  case 'PK12':
693  case 'P12':
694  $v_certPEM = array();
695  openssl_pkcs12_read($certContent, $v_certPEM, '');
696  $cert = $v_certPEM['cert'];
697  break;
698 
699  case 'PEM':
700  case 'CRT':
701  $cert = $certContent;
702  break;
703  }
704 
705  $v_certData = openssl_x509_parse($cert, true);
706  if ($v_certData === false)
707  {
708  throw new Exception (
709  __CLASS__.':'.__METHOD__.'['.__FILE__.']-L'.__LINE__.'.'.
710  'El formato del certificado no se corresponde con '.$formato
711  );
712  }
713  return $v_certData;
714  }//getCertificateInfo
715 
716 
717 
718 
719 
726  public function loadTracertPAI($vTrazabilidadPAI)
727  {
728  if (!is_array($vTrazabilidadPAI))
729  {
730  throw new Exception('Las opciones de trazabilidad deben ser un array asociativo [idApp, nsCert]');
731  }
732 
733  if (array_key_exists('idApp', $vTrazabilidadPAI))
734  {
735  $this->idApp = $vTrazabilidadPAI['idApp'];
736  }
737 
738  if (array_key_exists('nsCert', $vTrazabilidadPAI))
739  {
740  $this->nsCert = $vTrazabilidadPAI['nsCert'];
741  }
742  }//loadTracertPAI
743 
744 
749  public function enableWSSecurity()
750  {
751  $this->enableWSSecurity = true;
752  }//enableWSSecurity
753 
754 
759  public function disableWSSecurity()
760  {
761  $this->enableWSSecurity = false;
762  }//disableWSSecurity
763 
764 
769  public function enableTrazabilidadPAI()
770  {
771  $this->enableTrazabilidadPAI = true;
772  }//enableTrazabilidadPAI
773 
774 
779  public function disableTrazabilidadPAI()
780  {
781  $this->enableTrazabilidadPAI = false;
782  }//disableTrazabilidadPAI
783 
784 
785 
793  public function __getClient($tipo)
794  {
795  // Si esta vacío el tipo, nada
796  if (empty($tipo)) return null;
797 
798  $tipo = trim(strtolower($tipo));
799  try
800  {
801  $this->__clienteOn($tipo);
802 
803  if (!is_object($this->v_clienteWS[$tipo]))
804  return null;
805  else
806  return ($this->v_clienteWS[$tipo]);
807  }
808  catch (Exception $e)
809  {
810  throw $e;
811  }
812  }// Fin __getClient
813 
814 
815 
816 
817  /* ----------------------------------------------------------------------- */
818  /* --------------------- Métodos privados / protegidos ------------------- */
819  /* ----------------------------------------------------------------------- */
820 
821  // --------------- Métodos propios de la clase ---------------- */
822 
831  protected function __clienteOn($tipo, $trazabilidadPai=true, $opcionesClienteWS = null)
832  {
833  $vTiposCliente = array();
834  if (!empty($tipo))
835  {
836  $tipo = trim(strtolower($tipo));
837 
838  if (array_key_exists($tipo, $this->v_clienteWS))
839  {
840  $vTiposCliente = array($tipo);
841  }
842  else
843  {
844  if ($this->getDebugMode())
845  {
846  $this->addDebugInfo(__CLASS__.':'.__METHOD__.'['.__FILE__.'-'.__LINE__.']'.' Tipo de cliente WS ('.$tipo.') no reconocido.');
847  }
848  throw new Exception (
849  __CLASS__.':'.__METHOD__.'['.__FILE__.']-L'.__LINE__.'.'.
850  'Tipo de cliente WS ('.$tipo.') no reconocido'
851  );
852  }
853  }
854 
855  //REVIEW: Estudiar opciones de contructor para mejorar
856  /*
857  //Creamos un contexto para perfilar la conexión HTTP/HTTPS del cliente
858  $streamContext = stream_context_create (
859  array (
860  'ssl' => array (
861  'verify_peer' => false,
862  'verify_peer_name' => false,
863  'allow_self_signed' => true
864  ),
865  'http'=>array (
866  'user_agent' => 'WSSSoapClient',
867  'timeout' => $this->WSDLTimeOut
868  )
869  )
870  );*/
871  if (!is_array($opcionesClienteWS))
872  {
873 
874  //REVIEW: Si utilizamos la versión 1.2 de SOAP no funciona GDE (insertarDoc)
875  /*
876  $opcionesClienteWS = array (
877  'soap_version' => SOAP_1_2,
878  'user_agent' => 'WSSSoapClient',
879  'exceptions' => true,
880  'cache_wsdl' => self::$MYSOAPOP_WSDL_CACHE,
881  'compression' => SOAP_COMPRESSION_ACCEPT | SOAP_COMPRESSION_GZIP| 9,
882  'connection_timeout'=> $this->WSDLTimeOut,
883  'trace' => self::$MYSOAPOP_TRACE //NECESARIO PARA TRATAR MTOM
884  );
885  */
886 
887  $opcionesClienteWS = array (
888  'soap_version' => SOAP_1_1,
889  'user_agent' => 'WSSSoapClient',
890  'exceptions' => true,
891  'cache_wsdl' => self::$MYSOAPOP_WSDL_CACHE,
892  'trace' => self::$MYSOAPOP_TRACE //NECESARIO PARA TRATAR MTOM
893  );
894  }
895  else
896  {
897  $opcionesClienteWS['soap_version'] = SOAP_1_1;//v1.1
898  $opcionesClienteWS['user_agent'] = 'WSSSoapClient';
899  $opcionesClienteWS['exceptions'] = true;
900  $opcionesClienteWS['cache_wsdl'] = self::$MYSOAPOP_WSDL_CACHE;
901  $opcionesClienteWS['trace'] = self::$MYSOAPOP_TRACE; //NECESARIO PARA TRATAR MTOM
902  }
903 
904  if ($this->getDebugMode())
905  {
906  $this->addDebugInfo("Opciones:\n ".print_r($opcionesClienteWS, true));
907  }
908 
909  foreach ($vTiposCliente as $claveTipo)
910  {
911  if (is_object($this->v_clienteWS[$claveTipo])) continue;
912  try
913  {
914  //Comprobamos accesibilidad de la URL
915  if (ini_get('allow_url_fopen') == true)//Si tenemos acceso a allow_url_open
916  {
917  $opciones = array (
918  'http' => array (
919  'timeout' => $this->WSDLTimeOut
920  ),
921  'https' => array (
922  'timeout' => $this->WSDLTimeOut
923  ),
924  'ssl' => array (
925  'verify_peer' => false,
926  'allow_self_signed' => true
927  )
928  );
929 
930  $sc = stream_context_create($opciones);
931  $fd = fopen($this->v_wsdl[$claveTipo], 'r', false, $sc);
932  if ($fd==false)
933  {
934  throw new Exception('allow_url_fopen activo. La URL '.$this->v_wsdl[$claveTipo].' no puede alcanzarse.');
935  }
936  fclose($fd);
937  }
938  /*
939  elseif (function_exists('curl_version'))//Si tenemos acceso CURL utilizamos la extensión
940  {
941  if ($this->getDebugMode())
942  {
943  $this->addDebugInfo(__CLASS__.':'.__METHOD__.'['.__FILE__.'-'.__LINE__.']'.' allow_url_fopen NO ACTIVO');
944  }
945  $url = strtolower(str_replace(' ', '%20', trim($this->v_wsdl[$claveTipo])));
946 
947  $cd = curl_init($url);
948  if ($cd===false)
949  {
950  $mensaje = "CURL. La URL $url no puede alcanzarse";
951  curl_close($cd);
952  $this->addDebugInfo(__CLASS__.':'.__METHOD__.'['.__FILE__.'-'.__LINE__.']'.$mensaje);
953  throw new Exception($mensaje);
954  }
955 
956  @curl_setopt($cd, CURLOPT_HEADER,true); // we want headers
957  @curl_setopt($cd, CURLOPT_NOBODY, true); // dont need body
958  @curl_setopt($cd, CURLOPT_RETURNTRANSFER, true);
959  @curl_setopt($cd, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);
960  @curl_setopt($cd, CURLOPT_CONNECTTIMEOUT, 20);
961  @curl_setopt($cd, CURLOPT_SSL_VERIFYPEER, false);
962  @curl_setopt($cd, CURLOPT_FOLLOWLOCATION, true);
963  @curl_setopt($cd, CURLOPT_MAXREDIRS, 10); // fairly random number, but
964  curl_exec($cd);
965  $codError = @curl_errno($cd);
966  if ($codError!=0)
967  {
968  $mensaje = "CURL. La URL $url no puede alcanzarse. Error: [$codError]";
969  curl_close($cd);
970  $this->addDebugInfo(__CLASS__.':'.__METHOD__.'['.__FILE__.'-'.__LINE__.']'.$mensaje);
971  throw new Exception($mensaje);
972  }
973  $httpcode = curl_getinfo($cd, CURLINFO_HTTP_CODE);
974 
975  curl_close($cd);
976  if (($httpcode!=200))
977  {
978  $mensaje = "CURL. La URL $url no puede alcanzarse: $httpcode";
979  curl_close($cd);
980  $this->addDebugInfo(__CLASS__.':'.__METHOD__.'['.__FILE__.'-'.__LINE__.']'.$mensaje);
981  throw new Exception($mensaje);
982  }
983  echo "CURL: La URL es accesible.";
984  exit;
985  }
986  */
987  else//No lanzamos excepción, sólo registramos la posibilidad
988  {
989  if ($this->getDebugMode())
990  {
991  $this->addDebugInfo(__CLASS__.':'.__METHOD__.'['.__FILE__.'-'.__LINE__.']'.' allow_url_fopen NO ACTIVO y Extensión CURL NO ACTIVA');
992  }
993  }
994 
995  //Si llegamos aquí no hemos podido comprobar la accesibilidad del WSDL previamente, así que saltará la excepción si no es alcanzable
996  $clienteWS = new WSSSoapClient($this->v_wsdl[$claveTipo], $opcionesClienteWS);
997 
998  if ($this->enableWSSecurity == true)
999  {
1000  $clienteWS->setCertFile($this->certFile); //Certificado (sin key) PEM
1001  $clienteWS->setKeyFile($this->keyFile); //Acceso al fichero .key extraido del pk12 formato PEM
1002  $clienteWS->setPassPhrase($this->passPhrase);
1003  $clienteWS->setUserToken($this->userToken, $this->passUserToken);
1004  $clienteWS->enableWSSecurity();
1005  }
1006  else
1007  {
1008  $clienteWS->disableWSSecurity();
1009  }
1010 
1011  if ($this->enableTrazabilidadPAI)
1012  {
1013  $clienteWS->loadTracertPAI($this->vTrazabilidad);
1014  }
1015  $this->v_clienteWS[$claveTipo] = $clienteWS;
1016  }
1017  catch (Exception $e)
1018  {
1019  if ($this->getDebugMode())
1020  {
1021  $this->addDebugInfo(__CLASS__.':'.__METHOD__.'['.__FILE__.'-'.__LINE__.']'."\n");
1022  if (is_object($clienteWS))
1023  {
1024  $this->addDebugInfo("RqH:\n ".$clienteWS->__getLastRequestHeaders());
1025  $this->addDebugInfo("Rq:\n ".$clienteWS->__getLastRequest());
1026  $this->addDebugInfo("RsH:\n ".$clienteWS->__getLastResponse());
1027  $this->addDebugInfo("Rs:\n ".$clienteWS->__getLastResponseHeaders());
1028  }
1029  else
1030  $this->addDebugInfo("\n");
1031  }
1032  throw $e;
1033  }
1034  }//Fin foreach
1035  }// Fin __clienteOn
1036 
1037 
1038 
1046  protected function array2ObjectTree($array)
1047  {
1048  if (!is_array($array)) return;
1049 
1050  if (is_numeric(key($array)))
1051  {
1052  foreach ($array as $key => $value)
1053  {
1054  $array[$key] = $this->array2ObjectTree($value);
1055  }
1056  return $array;
1057  }
1058  $Object = new stdClass;
1059  foreach ($array as $key => $value)
1060  {
1061  if (is_array($value))
1062  {
1063  $Object->$key = $this->array2ObjectTree($value);
1064  }
1065  else
1066  {
1067  $Object->$key = $value;
1068  }
1069  }
1070  return $Object;
1071  }//Fin array2ObjectTree
1072 
1080  protected function objectTree2array($obj)
1081  {
1082  if (is_array($obj) || is_object($obj))
1083  {
1084  $result = array();
1085  foreach ($obj as $key => $value)
1086  {
1087  $result[$key] = $this->objectTree2array($value);
1088  }
1089  return $result;
1090  }
1091  return $obj;
1092  }//Fin objectTree2array
1093 
1094 
1095  protected function tratarExcepcionEstandar($e, $clienteWS)
1096  {
1097  // Comprueba si es una excepcion de PAI, y la lanza en dicho caso como excepcion especifica de PAI
1098  WSComunPAIException::tryToThrow($e);
1099 
1100  // Tratamiento estandar
1101  if ($this->getDebugMode())
1102  {
1103  $this->addDebugInfo(__CLASS__.':'.__METHOD__.'['.__FILE__.'-'.__LINE__.']'."\n");
1104  if (is_object($clienteWS))
1105  {
1106  $this->addDebugInfo("RqH:\n ".$clienteWS->__getLastRequestHeaders());
1107  $this->addDebugInfo("Rq:\n ".$clienteWS->__getLastRequest());
1108  $this->addDebugInfo("RsH:\n ".$clienteWS->__getLastResponse());
1109  $this->addDebugInfo("Rs:\n ".$clienteWS->__getLastResponseHeaders());
1110  }
1111  throw $e;
1112  }
1113  else
1114  {
1115  throw $e;
1116  }
1117  }//tratarExcepcionEstandar
1118 
1119 
1120 
1130  protected function tratarMTOMEstandar($response, $itemToReturn = null)
1131  {
1132  //Comprobamos si existen anexos
1133  $mimeBoundary = '--MIME_Boundary';//Probamos con --MIME Boundary hasta mejora de detección
1134  $vBodyResponse = explode($mimeBoundary, $response); //Fraccionamos la respuesta.
1135  $numElementos = count($vBodyResponse);
1136 
1137  $srcData='';
1138  if ($numElementos<=1)
1139  {
1140  $mimeBoundary = '--uuid:';//Probamos de nuevo con --uuid hasta mejora de detección
1141  $vBodyResponse = explode($mimeBoundary, $response); //Fraccionamos la respuesta.
1142  $numElementos = count($vBodyResponse);
1143  $srcData = $response;
1144  }
1145  elseif ($numElementos>1)
1146  {
1147  $srcData = $vBodyResponse[1];
1148  }
1149 
1150  $vRespuesta = array();
1151  ini_set('pcre.backtrack_limit','100000000'); //Valor por defecto = 1000000 (aprox. 100KBytes)
1152  preg_match("/<[a-z]*:Envelope.*?>(.*)<\/[a-z]*:Envelope>/is", $srcData, $vRespuesta);
1153  if (preg_last_error()!=PREG_NO_ERROR)
1154  {
1155  //Si falta intentamos obtener el anexo con otro sistema
1156  $start = stripos($srcData, ':Envelope');
1157  $start = strripos($srcData, '<', $start - strlen($srcData));
1158  $end = strripos($srcData, ':Envelope>');
1159  $cadenaRespuesta = substr($srcData, $start, $end);
1160  }
1161  elseif (count($vRespuesta)<1)
1162  {
1163  throw new Exception('No puede ubicarse RESPONSE dentro de MTOM');
1164  }
1165  else
1166  {
1167  $cadenaRespuesta = $vRespuesta[0];
1168  unset($vRespuesta);
1169  }
1170 
1171  $dom = new DOMDocument('1.0');
1172  $dom->loadXML($cadenaRespuesta);//Cargamo el XML
1173  $xpath = new \DOMXpath($dom);
1174  $vNodoRespuesta = $xpath->query("/*[local-name()='Envelope']/*[local-name()='Body']/*/*[local-name()='respuesta']");
1175  $subStrXpath='';
1176  if (!empty($itemToReturn))
1177  {
1178  $subStrXpath = "/*[local-name()='{$itemToReturn}']";
1179  }
1180  $vNodoRespuesta = $xpath->query("/*[local-name()='Envelope']/*[local-name()='Body']/*".$subStrXpath);
1181  $nodoRespuesta = $vNodoRespuesta->item(0);
1182 
1183  if ($numElementos>0)
1184  {
1185  $oMimeParser = new WSCMimeParser();
1186  $oMime = $oMimeParser->decodeMTOM($vBodyResponse);
1187  unset($oMime->body);$oMime->body=null;gc_collect_cycles();
1188 
1189  $vNodoInclude = $xpath->query("//*[local-name()='Include']");
1190  foreach ($vNodoInclude as $nodoItem)//Recorremos los nodosXML include y sustituidmos por el contenido
1191  {
1192  $subIdBuscado = (string) $nodoItem->getAttribute('href');
1193  $subIdBuscado = urldecode($subIdBuscado);
1194  $idBuscado = '<'.substr($subIdBuscado, 4).'>';
1195  foreach ($oMime->parts as &$parte)
1196  {
1197  if ($idBuscado == ($parte->headers['content-id']))
1198  {
1199  if ( strtolower(substr($parte->mimetype, 0, 4)) !== 'text')//Si el tipo mime no es texto, convertimos a B64 por ser contenido binario
1200  {
1201  $parte->body = base64_encode($parte->body);
1202  }
1203  $textNode = $dom->createTextNode(($parte->body));
1204  $nodoItem->parentNode->replaceChild($textNode, $nodoItem);
1205  }
1206  }//Fin for partes
1207  }//Fin for nodos
1208  }
1209  return($this->xml_to_array($nodoRespuesta));
1210  }//tratarMTOMEstandar
1211 
1212 
1213 
1214 
1215  protected function xml_to_array(&$root)
1216  {
1217  $result = array();
1218  if ($root->hasAttributes())
1219  {
1220  $attrs = $root->attributes;
1221  foreach ($attrs as $attr)
1222  {
1223  $result['@attributes'][$attr->name] = $attr->value;
1224  }
1225  }
1226  if ($root->hasChildNodes())
1227  {
1228  $children = $root->childNodes;
1229  if ($children->length == 1)
1230  {
1231  $child = $children->item(0);
1232  if ($child->nodeType == XML_TEXT_NODE)
1233  {
1234  $result['_value'] = $child->nodeValue;
1235  return count($result) == 1 ? $result['_value'] : $result;
1236  }
1237  }
1238  $groups = array();
1239  foreach ($children as $child)
1240  {
1241  if (!isset($result[$child->nodeName]))
1242  {
1243  $result[$child->nodeName] = $this->xml_to_array($child);
1244  }
1245  else
1246  {
1247  if (!isset($groups[$child->nodeName]))
1248  {
1249  $result[$child->nodeName] = array($result[$child->nodeName]);
1250  $groups[$child->nodeName] = 1;
1251  }
1252  $result[$child->nodeName][] = $this->xml_to_array($child);
1253  }
1254  }
1255  }
1256  return $result;
1257  }//xml_to_array
1258 
1259 
1271  public static function numberBaseConvert($numstring, $frombase=10, $tobase=16)
1272  {
1273  $chars = "0123456789abcdefghijklmnopqrstuvwxyz";
1274  $tostring = substr($chars, 0, $tobase);
1275  $length = strlen($numstring);
1276  $result = '';
1277  $number = array();
1278  for ($i = 0; $i < $length; $i++)
1279  {
1280  $number[$i] = strpos($chars, $numstring{$i});
1281  }
1282  do
1283  {
1284  $divide = 0;
1285  $newlen = 0;
1286  for ($i = 0; $i < $length; $i++)
1287  {
1288  $divide = $divide * $frombase + $number[$i];
1289  if ($divide >= $tobase)
1290  {
1291  $number[$newlen++] = (int)($divide / $tobase);
1292  $divide = $divide % $tobase;
1293  } elseif ($newlen > 0)
1294  {
1295  $number[$newlen++] = 0;
1296  }
1297  }
1298  $length = $newlen;
1299  $result = $tostring{$divide} . $result;
1300  } while ($newlen != 0);
1301 
1302  return $result;
1303  }//numberBaseConvert
1304 
1310  public static function getClientIP()
1311  {
1312  if (getenv('HTTP_CLIENT_IP'))
1313  {
1314  $ip = getenv('HTTP_CLIENT_IP');
1315  }
1316  else if(getenv('HTTP_X_FORWARDED_FOR'))
1317  {
1318  $ip = getenv('HTTP_X_FORWARDED_FOR');
1319  }
1320  else if (getenv('HTTP_X_FORWARDED'))
1321  {
1322  $ip = getenv('HTTP_X_FORWARDED');
1323  }
1324  else if(getenv('HTTP_FORWARDED_FOR'))
1325  {
1326  $ip = getenv('HTTP_FORWARDED_FOR');
1327  }
1328  else if(getenv('HTTP_FORWARDED'))
1329  {
1330  $ip = getenv('HTTP_FORWARDED');
1331  }
1332  else if(getenv('REMOTE_ADDR'))
1333  {
1334  $ip = getenv('REMOTE_ADDR');
1335  }
1336  else
1337  {
1338  $ip = 'UNKNOWN';
1339  }
1340  return $ip;
1341  }//Fin getClientIP
1342 
1343 
1344 
1345 
1346 }//Fin WSComunFClient
1347 
1348 
1349 
1350 
1358 {
1359 
1360  const ERROR_SERVICIO = '0101';
1361  const TIMESTAMP_INVALIDO = '0230';
1362  const ORGANISMO_NO_AUTORIZADO = '0301';
1363  const CERTIFICADO_CADUCADO = '0302';
1364  const CERTIFICADO_REVOCADO = '0303';
1365  const FIRMA_PETICION_NO_VALIDA = '0305';
1366  const PETICION_SIN_NODO_FIRMA = '0307';
1367  const ESTRUCURA_XML_NO_CORRESPONDE_A_ESQUEMA = '0401';
1368  const MENSAJE_XML_INVALIDO = '0403';
1369  const OPERACION_SOLICITADA_INCORRECTA = '0800';
1370  const FALTA_CABECERA_TRAZABILIDAD = '0807';
1371  const INFO_TRAZABILIDAD_INCOHERENTE = '0808';
1372  const ERROR_GENERAL_INDEFINIDO = '0904';
1373 
1374 
1375  private $CodigoEstado = '';
1376  private $CodigoEstadoSecundario = '';
1377  private $LiteralError = '';
1378  private $LiteralErrorSec = '';
1379 
1380  public function getCodigoEstado() {
1381  return $this->CodigoEstado;
1382  }
1383  public function getCodigoEstadoSecundario() {
1384  return $this->CodigoEstadoSecundario;
1385  }
1386  public function getLiteralError() {
1387  return $this->LiteralError;
1388  }
1389  public function getLiteralErrorSec() {
1390  return $this->LiteralErrorSec;
1391  }
1392 
1393 
1394 
1395  public function __construct($soapFault) {
1396  // Extrae la informacion básica del error
1397  $faultCode = intval($soapFault->detail->Atributos->Estado->CodigoEstado);
1398  $faultString = $soapFault->detail->Atributos->Estado->LiteralError;
1399 
1400  // asegúrese de que todo está asignado apropiadamente
1401  parent::__construct($faultString, $faultCode, $soapFault);
1402 
1403  // Extrae información detallada del error
1404  $this->CodigoEstado = $soapFault->detail->Atributos->Estado->CodigoEstado;
1405  $this->CodigoEstadoSecundario = $soapFault->detail->Atributos->Estado->CodigoEstadoSecundario;
1406  $this->LiteralError = $soapFault->detail->Atributos->Estado->LiteralError;
1407  $this->LiteralErrorSec = $soapFault->detail->Atributos->Estado->LiteralErrorSec;
1408  }
1409 
1410  public function __toString() {
1411  return __CLASS__ . ": [{$this->code}] {$this->message}\n";
1412  }
1413 
1414 
1415 
1423  public static function tryToThrow($e) {
1424  // Si es un SoapFault y su codigo es soap-env:PAI, asumimos que se trata de una excepcion especifica
1425  if (($e instanceof \SoapFault) && ($e->faultcode == 'soap-env:PAI')) {
1426  // Excepcion especifica detallada
1427  throw new WSComunPAIException($e);
1428  }
1429 
1430  return false;
1431  }
1432 
1433 }
1434 
1435 ?>
tratarMTOMEstandar($response, $itemToReturn=null)
static numberBaseConvert($numstring, $frombase=10, $tobase=16)
static makeWSClient($wsID, $v_wsdl, $v_opciones=null)
__construct($v_wsdl, $v_opciones=null)
static getCertificateInfo($ruta, $formato=null)
const DEBUG
loadTracertPAI($vTrazabilidadPAI)
__clienteOn($tipo, $trazabilidadPai=true, $opcionesClienteWS=null)