0

I gotta consume a SOAP service from PHP but I keep failing to get the response. Maybe it's a problem with the format or the call or idk. I can for example get all the functions names from the server with the __getFunctions() method. But when I try to invoke any function I keep getting:

SOAP-ERROR: Encoding: Cannot find encoding

Below is the code.

$wsdl = "https://testing.memoryefactura.com/Memory.FEManager/WebService/CFEService.svc?wsdl";


$parameters = array('Rut' => 'XXXXX',
    'CommerceCode' => 'XXXXX',
    'TerminalCode' => 'XXXXX',
    'Timeout' => 5000);


$options = array(
    'style' => SOAP_RPC,
    'use' => SOAP_ENCODED,
    'soap_version' => SOAP_1_1,
    'cache_wsdl' => WSDL_CACHE_NONE,
    'connection_timeout' => 15,
    'trace' => true,
    'exceptions' => true,
);
try {
    $soap = new SoapClient($wsdl, $options);
    $HeaderSecurity = array(
        'stream_context' => stream_context_create(array(
            'http' => array(
                'header' => array('username' => 'XXXXX',
                    'password' => 'XXXXX'
                )
            ),
        )),
    );
    $header[] = new SoapHeader("http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", "Security", $HeaderSecurity);

    $soap->__setSoapHeaders($header);
    $data = $soap->Ping($parameters);
} catch (Exception $e) {
    die($e->getMessage());
}

var_dump($data);
6
  • First thing, get rid of style and use from your options, they should not be used in WSDL mode. Instead of catching Exception try catching SoapFault which can give you more error details: php.net/manual/en/soapfault.soapfault.php Commented Nov 14, 2018 at 21:31
  • And are you really supposed to pass HTTP headers named username and password??? Commented Nov 14, 2018 at 21:32
  • Thanks for the tips. Erased style and use and still the same. Tried catching soupFault and it gives nothing usefull (just this: SoapClient->__call('Ping', Array) #1 {main}). Yes, if i dont send those headers gives authentication error. Commented Nov 14, 2018 at 22:02
  • You need to use the specific functions for SoapFault to get additional details, not just getMessage(). Commented Nov 14, 2018 at 22:04
  • Can you share a link to the WSDL? Commented Nov 14, 2018 at 22:08

1 Answer 1

1

Based on the wsdl, the ping method takes only 3 parameters.

class Ping {
    /** @var BaseMessage */ public $message;
}
class BaseMessage {
    /** @var string */  public $CommerceCode;
    /** @var string */  public $TerminalCode;
    /** @var int */ public $Timeout;
}

Also, you incorrectly set the authorization header. The correct way to do this:

$wsdl = "https://testing.memoryefactura.com/Memory.FEManager/WebService/CFEService.svc?wsdl";

$opts = [
    'ssl' => [
        'verify_peer' => false,
        'verify_peer_name' => false
    ],
    'http' => [
        'user_agent' => 'PHPSoapClient'
    ]
];

$params = [
    'encoding' => 'UTF-8',
    'verifypeer' => false,
    'verifyhost' => false,
    'soap_version' => SOAP_1_1,
    'trace' => 1,
    'exceptions' => 1,
    'connection_timeout' => 180,
    'stream_context' => stream_context_create($opts)
];

try {
    $client = new \SoapClient($wsdl, $params);

    $nameSpace = 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd';

    $soapUsername = new \SoapVar(
        'XXXXX',
        XSD_STRING,
        null,
        $nameSpace,
        null,
        $nameSpace
    );

    $soapPassword = new \SoapVar(
        'XXXXX',
        XSD_STRING,
        null,
        $nameSpace,
        null,
        $nameSpace
    );

    $auth = new \stdClass();
    $auth->Username = $soapUsername;
    $auth->Password = $soapPassword;

    $soapAuth = new \SoapVar(
        $auth,
        SOAP_ENC_OBJECT,
        null,
        $nameSpace,
        'UsernameToken',
        $nameSpace
    );

    $token = new \stdClass();
    $token->UsernameToken = $soapAuth;

    $soapToken = new \SoapVar(
        $token,
        SOAP_ENC_OBJECT,
        null,
        $nameSpace,
        'UsernameToken',
        $nameSpace
    );

    $security = new \SoapVar(
        $soapToken,
        SOAP_ENC_OBJECT,
        null,
        $nameSpace,
        'Security',
        $nameSpace
    );

    $header = new \SoapHeader($nameSpace, 'Security', $security, true);

    $client->__setSoapHeaders([$header]);

    $parameters = array(
        'CommerceCode' => 'XXXXX',
        'TerminalCode' => 'XXXXX',
        'Timeout' => 5000
    );

    $data = $client->Ping($parameters);
} catch (SoapFault $fault) {
    echo "REQUEST:\n" . $client->__getLastRequest();
    die("\nFaultcode: " . $fault->faultcode . "\nFaultstring: " . $fault->faultstring);
} catch (Exception $e) {
    die($e->getMessage());
}
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks man! It throws Faultcode: a:InternalServiceFault Faultstring: Object reference not set to an instance of an object., any clue?
Don't worry, $data = $client->Ping(array('message' => $parameters)); solved it. Thanks a lot man, saved my neck!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.