quarta-feira, 12 de janeiro de 2011

WebService with NuSOAP

É um conjunto de classes PHP que permite aos desenvolvedores criar e consumir serviços Web baseados em SOAP 1.1, 1.1 e WSDL HTTP 1.0/1.1. Pode ser feito download a partir da página: 
http://sourceforge.net/projects/nusoap/

Instalação:
Depois de ter baixado uma cópia do nusoap.php, basta colocá-lo em sua árvore de código para que você possa incluí-lo em seu código PHP. Alguns usuários colocaram nele um diretório separado lib. Para o meu exemplo, eu coloquei-o no mesmo diretório como o código de exemplo em si.

Exemplos:
Vamos começar com o exemplo simples "Hello world". Isso vai demonstrar a base de clientes de codificação NuSOAP e servidores.
Vamos começar com o código do servidor, já que sem um servidor, não há necessidade de ter qualquer cliente. O servidor SOAP expõe um método único chamado Hello, o que leva um parâmetro de seqüência única de entrada e retorna um string. Felizmente, os comentários dentro do código fornecer uma explicação suficiente! Para os serviços mais simples, tudo o que vai mudar são as funções a ser definido e registrado. 

Nomeie um arquivo como server.php. Seu conteúdo segue abaixo.  
 
require_once('nusoap.php');
// Cria uma instancia do servidor
$server = new soap_server;
// Registrando o metodo criado
$server->register('hello');
// Define o metodo 
function hello($name) {
    return 'Hello, ' . $name;
}
// Usar o request para invocar o servico
$HTTP_RAW_POST_DATA = isset($HTTP_RAW_POST_DATA) ? $HTTP_RAW_POST_DATA : '';
$server->service($HTTP_RAW_POST_DATA);
 O cliente para este serviço segue abaixo. Existem algumas coisas importantes a serem observadas.  
Primeiro, quando a instância do soapclient é criado, o parâmetro especificado é o URL para o serviço. No meu caso, server.php é acessado a partir http://localhost/projeto/webservice. Os serviços que você consome, é claro, estarão localizados em URLs diferentes. 
Em segundo lugar, ao chamar o serviço, o primeiro parâmetro é o nome do serviço. Este deve corresponder ao nome case-sensítive de um método disponível no servidor. Neste exemplo, ele deve corresponder ao método registrados no server.php.  
Finalmente, o segundo parâmetro na chamada é um array de parâmetros que serão passados para o método de serviço SOAP. Como o método de server.php Hello requer um único parâmetro, esse array tem um elemento.

require_once('nusoap.php');
// Criar uma instancia do client
$client = new soapclient('http://localhost/projeto/webservice/server.php');
//Chama o metodo call do SOAP
$result = $client->call('hello', array('name' => 'Scott'));
// exibe o resultado
print_r($result);

// checando faults
if ($client->fault) {
    echo '<p><b>Fault: ';
    print_r($result);
    echo '</b></p>';
} else {
    // Checando erros
    $err = $client->getError();
    if ($err) {
        echo '<p><b>Error: ' . $err . '</b></p>';
    } else {
        print_r($result);
    }
}

//Debugando 
echo '<h2>Request</h2>';
echo '<pre>' . htmlspecialchars($client->request, ENT_QUOTES) . '</pre>';
echo '<h2>Response</h2>';
echo '<pre>' . htmlspecialchars($client->response, ENT_QUOTES) . '</pre>';
echo '<h2>Debug</h2>';
echo '<pre>' . htmlspecialchars($client->getDebug(), ENT_QUOTES) . '</pre>';
Outro exemplo mais completo, que envolve o cadastro de dados de 
clientes no banco de dados. O arquivo server.php segue abaixo:
 
$server = new soap_server();
$server->debug_flag = true;
$server->configureWSDL('MeuNameSpace', 'WSDL');
$server->wsdl->schemaTargetNameSpace='urn:MeuNameSpace';

$server->register('cadastrar', array('entrada'=>'tns:arrCadastro'),  
        array('return'=>'xsd:string'),
 'urn:MeuNameSpace',
 'urn:MeuNameSpace#cadastrar',
 'rpc',
 'encoded',
 ''
); 
$server->wsdl->addComplexType('arrCadastro', 'complexType', 'struct', 'all','',
array(
  'full_name'=>array('name'=>'full_name','type'=>'xsd:string')
  ,'email'=>array('name'=>'email','type'=>'xsd:string')
  ,'dat_nascimento'=>array('name'=>'dat_nascimento','type'=>'xsd:string')
  ,'cpf'=>array('name'=>'cpf','type'=>'xsd:string')
 )
);
function cadastrar($dados=array()){
 $objCliente = new Cliente();
 if($objCliente)
  $id = $objCliente->cadastroWebService($dados);
 return "$id";
}

$HTTP_RAW_POST_DATA = isset($HTTP_RAW_POST_DATA) ? $HTTP_RAW_POST_DATA : '';
$server->service($HTTP_RAW_POST_DATA);
E o client para testes: client.php
 
$client = new nusoap_client('http://localhost/projeto/webservice/server.php?wsdl&debug=1', 'wsdl');
$err = $client->getError();
if ($err) {
 echo '<h2>Constructor error</h2><pre>' . $err . '</pre>';
 echo '<h2>Debug</h2>';
 echo '<pre>' . htmlspecialchars($client->getDebug(), ENT_QUOTES) . '</pre>';
 exit();
}

$dados = array(
  'full_name' => 'Ademir Braga',
  'dat_nascimento' => '30/01/1984',
  'cpf' => '11111111222',
  'email' => 'ademirbraga100@yahoo.com.br',
  ); 
$result = $client->call('cadastrar', array('entrada' => $dados));

if ($client->fault) {
 echo '<h2>Fault</h2><pre>';
 print_r($result);
 echo '</pre>';
} else {
 $err = $client->getError();
 if ($err) {
  echo '<h2>Error</h2><pre>' . $err . '</pre>';
 } else {
  echo '<h2>Result</h2><pre>';
  // Decode the result: it so happens we sent Latin-1 characters
  if (isset($result['return'])) {
   $result1 = utf8_decode($result['return']);
  } elseif (!is_array($result)) {
   $result1 = utf8_decode($result);
  } else {
   $result1 = $result;
  }
  print_r($result1);
  echo '</pre>';
 }
}
echo '<h2>Request</h2>';
echo '<pre>' . htmlspecialchars($client->request, ENT_QUOTES) . '</pre>';
echo '<h2>Response</h2>';
echo '<pre>' . htmlspecialchars($client->response, ENT_QUOTES) . '</pre>';
echo '<h2>Debug</h2>';
echo '<pre>' . htmlspecialchars($client->getDebug(), ENT_QUOTES) . '</pre>';

 Este exemplo mostra o cadastro de um cliente no banco de dados, usando o metodo cadastroWebService 
contido na classe Cliente via webservice.

Conclusão:
Usando webservices podemos integrar sistemas diferentes e independentes definindo apenas os campos necessários para utilização do lado do client.

12 comentários:

  1. Parabêns, o seu artigo esta muito bom, o unico em portugues que funcionou. muito bom mesmo

    ResponderExcluir
  2. Ademar;

    Estou tentando fazer o exemplo básico, e está retornando a seguinte mensagem.

    This service does not provide a Web description

    preciso fazer alguma configuração.

    Obs.: Estou utilizando o PHP/4.4.7

    ResponderExcluir
    Respostas
    1. Cara comigo tbm deu esse problema, vou responder já que outras pessoas podem ter o mesmo problema,
      tenta assim

      $URL = "http://localhost/projeto/webservice/server.php";
      $namespace = $URL . '?wsdl';

      $server = new soap_server;
      $server->configureWSDL('hellotesting', $namespace);

      Excluir
  3. Denilson, acabei de fazer um teste com esse exemplo básico e funcionou normalmente, porem estou utilizando o PHP5 , porém você pode verificar alguns detalhes como, por exemplo, a SOAP do PHP deve estar desativado quando você fizer uso do NUSOAP, outra coisa é que tanto o server quanto o client deve estar no mesmo diretorio para ser utilizado da forma que foi passado neste exemplo.

    ResponderExcluir
  4. Obrigado Wanderley, ja faz um bom tempo que nao posto nada no blog, vou me esforçar pra colocar mais coisas interessanes

    ResponderExcluir
  5. Ademir parabéns pelo post...
    Estou começando a agora neste ramo de webservice...
    Eu fui fazer um teste sobre seu exemplo:
    e está retornando os seguintes erros:
    Warning: gettimeofday() [function.gettimeofday]: It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'America/Sao_Paulo' for '-3.0/no DST' instead in C:\Program Files\VertrigoServ\www\webservices\helloworld\lib\nusoap.php on line 856

    Warning: strftime() [function.strftime]: It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'America/Sao_Paulo' for '-3.0/no DST' instead in C:\Program Files\VertrigoServ\www\webservices\helloworld\lib\nusoap.php on line 863

    Não sei se vou ter que mudar a configuração do timezone, sabe o que eu posso fazer pra encontrar a solução destes erros?

    ResponderExcluir
  6. Bom dia Leandro, verifique se a versão do PHP que você tem instalado tem suporte a estas 2 funcoes gettimeofday() e strftime().
    Caso tenha, tente usar as funcoes indicadas pelo retorno de erros, setando o timezone para a regiao que voce esta.

    ResponderExcluir
  7. Ademir, você é o cara! To a três semanas tentando montar um webservice de forma simples, onde eu pudesse enviar parâmetros e retornar os dados filtrados, já tentei de todas as formas fazer isso, usando Java + webservice Rest, tentei usar Soap com Axis2, mas todas as formas que tentei eram muito confusas pra mim. Daí, numa ultima tentativa de montar um webservice decente, voltei as minhas origens e fui pesquisar algo com a minha tão amada linguagem PHP, e não é que acho um artigo completo e dessa qualidade em PORTUGUÊS ainda por cima! Cara, você é demais... Valew mesmo pela ajuda!

    ResponderExcluir
  8. Tem alguns erros neste arquivo faltou colocar o require_once('nusoap.php'); no segundo exemplo. Também ta faltando a classe cliente e seu retorno. Vou tentar fazer esse classe bem como conexão com banco de dados e colocar o exemplo aqui.

    ResponderExcluir
  9. valeu cara, me ajudou muito esse artigo!

    ResponderExcluir
  10. Parabéns!!! deu super certo usando pdo, show de bola.

    Como seria uma listagem??


    obrigado pela atenação

    ResponderExcluir
  11. Oi boa tarde!

    Parabéns pelo post.
    Eu preciso criar uma função do webserver que retorne um array com todos os clientes. Terias como me ajudar dando um exemplo de como retorna o array que eu receber do banco e como consumir?

    Desde já agradeço.

    ResponderExcluir