SOAP (Simple Object Access Protocol) es un protocolo basado en XML para intercambio de servicios web. Aunque REST lo ha desplazado en proyectos nuevos, muchos sistemas bancarios, de facturación y B2B siguen usándolo. PHP incluye soporte nativo con SoapClient y SoapServer.
SoapClient: consumir un servicio SOAP
Con WSDL disponible, PHP configura automáticamente los métodos y tipos:
<?php
$client = new SoapClient(
'https://www.dneonline.com/calculator.asmx?WSDL',
[
'trace' => true, // Permite depurar peticiones
'exceptions' => true, // Lanza SoapFault en lugar de devolver false
'cache_wsdl' => WSDL_CACHE_NONE, // Importante en desarrollo
]
);
try {
$resultado = $client->Add(['intA' => 10, 'intB' => 25]);
echo $resultado->AddResult; // 35
} catch (SoapFault $e) {
echo "Error SOAP: [{$e->faultcode}] {$e->faultstring}";
}
?>
Listar métodos disponibles
<?php
$metodos = $client->__getFunctions();
foreach ($metodos as $m) {
echo $m . "n";
}
?>
Depurar con __getLastRequest() y __getLastResponse()
<?php
try {
$resultado = $client->ObtenerFactura(['id' => 12345]);
} catch (SoapFault $e) {
echo "Petición XML enviada:n";
echo $client->__getLastRequest() . "nn";
echo "Respuesta XML recibida:n";
echo $client->__getLastResponse() . "n";
}
?>
Solo funciona si trace => true está activo.
Autenticación HTTP básica y cabeceras
<?php
$client = new SoapClient($wsdlUrl, [
'login' => 'usuario',
'password' => 'clave',
'trace' => true,
]);
// Cabecera SOAP personalizada (WS-Security, etc.)
$header = new SoapHeader(
'http://www.ejemplo.com/ns',
'AuthHeader',
['Token' => 'abc123'],
false // mustUnderstand
);
$client->__setSoapHeaders([$header]);
?>
Modo sin WSDL
<?php
$client = new SoapClient(
null, // sin WSDL
[
'location' => 'http://api.ejemplo.com/soap',
'uri' => 'http://api.ejemplo.com/ns',
'style' => SOAP_RPC,
'use' => SOAP_ENCODED,
]
);
$resultado = $client->__soapCall('ObtenerPrecio', [
new SoapParam('12345', 'codigoProducto')
]);
?>
SoapServer: publicar un servicio SOAP
<?php
// calculadora.php (el endpoint)
class Calculadora
{
public function sumar(float $a, float $b): float
{
return $a + $b;
}
public function multiplicar(float $a, float $b): float
{
return $a * $b;
}
}
$server = new SoapServer(
null, // sin WSDL propio (modo no-WSDL)
['uri' => 'http://mi-servidor.com/calculadora']
);
$server->setClass('Calculadora');
$server->handle();
?>
SoapServer con WSDL
Generar el WSDL manualmente es tedioso; lo habitual es usar herramientas como Zend_Soap (parte de Laminas) para auto-generarlo a partir de DocBlocks:
<?php
// Con WSDL generado previamente
$server = new SoapServer('/var/www/wsdl/calculadora.wsdl');
$server->setClass('Calculadora');
$server->handle();
?>
SoapFault: gestión de errores del servidor
<?php
class MiServicio
{
public function buscarCliente(int $id): array
{
if ($id <= 0) {
throw new SoapFault('Client', 'ID de cliente inválido');
}
$cliente = buscarEnBD($id);
if (!$cliente) {
throw new SoapFault('Server', "Cliente $id no encontrado");
}
return $cliente;
}
}
?>
El código 'Client' indica que el error es del llamante; 'Server' indica error interno.
El truco del caché de WSDL
Por defecto, PHP cachea el WSDL en disco durante 24 horas. Si el WSDL cambia y el cliente no lo detecta, añade esto al inicio del script o al php.ini:
<?php
// Desactivar caché para este script
ini_set('soap.wsdl_cache_enabled', '0');
// O usar la opción en el constructor:
$client = new SoapClient($url, ['cache_wsdl' => WSDL_CACHE_NONE]);
?>
Errores comunes
- SOAP-ERROR: Parsing WSDL: el WSDL no es accesible o tiene errores XML. Descárgalo manualmente con
curlpara verificarlo. - Could not connect to host: revisa firewalls, proxies corporativos y que PHP tenga la extensión
soapactivada (php -m | grep soap). - Versión SOAP incorrecta: algunos servidores usan SOAP 1.1, otros SOAP 1.2. Especifícala con
'soap_version' => SOAP_1_2.
