SOAP en PHP: SoapClient para consumir y SoapServer para publicar servicios web

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 curl para verificarlo.
  • Could not connect to host: revisa firewalls, proxies corporativos y que PHP tenga la extensión soap activada (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.

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP