Как сделать SOAP-вызов PHP с использованием класса SoapClient
Я привык писать PHP-код, но не часто использую объектно-ориентированное кодирование. Теперь мне нужно взаимодействовать с SOAP (как клиент), и я не могу правильно получить синтаксис. У меня есть файл WSDL, который позволяет мне правильно настроить новое соединение с использованием класса SoapClient. Тем не менее, я не могу сделать правильный звонок и вернуть данные. Мне нужно отправить следующие (упрощенные) данные:
- Contact ID
- Контактное имя
- Общее описание
- Сумма
В документе WSDL есть две функции, но мне нужен только один ( "FirstFunction" ниже). Вот script, который я запускаю, чтобы получить информацию о доступных функциях и типах:
$client = new SoapClient("http://example.com/webservices?wsdl");
var_dump($client->__getFunctions());
var_dump($client->__getTypes());
И вот результат, который он генерирует:
array(
[0] => "FirstFunction Function1(FirstFunction $parameters)",
[1] => "SecondFunction Function2(SecondFunction $parameters)",
);
array(
[0] => struct Contact {
id id;
name name;
}
[1] => string "string description"
[2] => string "int amount"
}
Предположим, что я хочу позвонить FirstFunction с данными:
- Contact ID: 100
- Контактное лицо: John
- Общее описание: Barrel of Oil
- Сумма: 500
Каким будет правильный синтаксис? Я пробовал всевозможные варианты, но кажется, что мыльная структура довольно гибкая, поэтому есть очень много способов сделать это. Не удалось понять это из руководства...
ОБНОВЛЕНИЕ 1: пробованный образец из MMK:
$client = new SoapClient("http://example.com/webservices?wsdl");
$params = array(
"id" => 100,
"name" => "John",
"description" => "Barrel of Oil",
"amount" => 500,
);
$response = $client->__soapCall("Function1", array($params));
Но я получаю этот ответ: Object has no 'Contact' property
. Как вы можете видеть на выходе getTypes()
, существует struct
, называемый Contact
, поэтому, я думаю, мне почему-то нужно уточнить, что мои параметры включают данные Contact, но вопрос в следующем: как?
ОБНОВЛЕНИЕ 2: Я также пробовал эти структуры, такую же ошибку.
$params = array(
array(
"id" => 100,
"name" => "John",
),
"Barrel of Oil",
500,
);
Также как:
$params = array(
"Contact" => array(
"id" => 100,
"name" => "John",
),
"description" => "Barrel of Oil",
"amount" => 500,
);
Ошибка в обоих случаях: объект не имеет свойства "Контакт"
Ответы
Ответ 1
Это то, что вам нужно сделать.
Я пытался воссоздать ситуацию...
- Для этого примера я создал образец WebService (WS).NET с
WebMethod
именем Function1
ожидая следующих параметров:
Function1 (контактный контакт, описание строки, количество int)
-
Где Contact
- это просто модель, которая имеет методы получения и установки id
и name
как в вашем случае.
-
Вы можете скачать пример .NET WS по адресу:
https://www.dropbox.com/s/6pz1w94a52o5xah/11593623.zip
Код.
Это то, что вам нужно сделать на стороне PHP:
(Проверено и работает)
<?php
// Create Contact class
class Contact {
public function __construct($id, $name)
{
$this->id = $id;
$this->name = $name;
}
}
// Initialize WS with the WSDL
$client = new SoapClient("http://localhost:10139/Service1.asmx?wsdl");
// Create Contact obj
$contact = new Contact(100, "John");
// Set request params
$params = array(
"Contact" => $contact,
"description" => "Barrel of Oil",
"amount" => 500,
);
// Invoke WS method (Function1) with the request params
$response = $client->__soapCall("Function1", array($params));
// Print WS response
var_dump($response);
?>
Тестирование всего этого.
- Если вы выполните
print_r($params)
вы увидите следующий вывод, как и ожидал ваш WS:
Массив ([Контакт] => Контактный объект ([id] => 100 [имя] => Джон) [description] => Баррель нефти [количество] => 500)
- Когда я отладил .NET образец WS, я получил следующее:
![enter image description here]()
(Как вы можете видеть, объект Contact
не имеет null
или другие параметры. Это означает, что ваш запрос был успешно выполнен со стороны PHP)
- Ответ от .NET образца WS был ожидаемым, и вот что я получил на стороне PHP:
object (stdClass) [3] public 'Function1Result' => string 'Подробная информация о вашем запросе! id: 100, имя: John, описание: Barrel of Oil, количество: 500 '(длина = 98)
Удачного кодирования!
Ответ 2
Вы также можете использовать SOAP-сервисы:
<?php
//Create the client object
$soapclient = new SoapClient('http://www.webservicex.net/globalweather.asmx?WSDL');
//Use the functions of the client, the params of the function are in
//the associative array
$params = array('CountryName' => 'Spain', 'CityName' => 'Alicante');
$response = $soapclient->getWeather($params);
var_dump($response);
// Get the Cities By Country
$param = array('CountryName' => 'Spain');
$response = $soapclient->getCitiesByCountry($param);
var_dump($response);
Это пример с реальным сервисом, и он работает.
Надеюсь, что это поможет.
Ответ 3
Сначала выполните инициализацию веб-сервисов:
$client = new SoapClient("http://example.com/webservices?wsdl");
Затем установите и передайте параметры:
$params = array (
"arg0" => $contactid,
"arg1" => $desc,
"arg2" => $contactname
);
$response = $client->__soapCall('methodname', array($params));
Обратите внимание, что имя метода доступно в WSDL в качестве имени операции, например:
<operation name="methodname">
Ответ 4
Я не знаю, почему мой веб-сервис имеет одинаковую структуру с вами, но ему не нужен класс для параметра, просто массив.
Например:
- Мой WSDL:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ns="http://www.kiala.com/schemas/psws/1.0">
<soapenv:Header/>
<soapenv:Body>
<ns:createOrder reference="260778">
<identification>
<sender>5390a7006cee11e0ae3e0800200c9a66</sender>
<hash>831f8c1ad25e1dc89cf2d8f23d2af...fa85155f5c67627</hash>
<originator>VITS-STAELENS</originator>
</identification>
<delivery>
<from country="ES" node=""/>
<to country="ES" node="0299"/>
</delivery>
<parcel>
<description>Zoethout thee</description>
<weight>0.100</weight>
<orderNumber>10K24</orderNumber>
<orderDate>2012-12-31</orderDate>
</parcel>
<receiver>
<firstName>Gladys</firstName>
<surname>Roldan de Moras</surname>
<address>
<line1>Calle General Oraá 26</line1>
<line2>(4º izda)</line2>
<postalCode>28006</postalCode>
<city>Madrid</city>
<country>ES</country>
</address>
<email>[email protected]</email>
<language>es</language>
</receiver>
</ns:createOrder>
</soapenv:Body>
</soapenv:Envelope>
I var_dump:
var_dump($client->getFunctions());
var_dump($client->getTypes());
Вот результат:
array
0 => string 'OrderConfirmation createOrder(OrderRequest $createOrder)' (length=56)
array
0 => string 'struct OrderRequest {
Identification identification;
Delivery delivery;
Parcel parcel;
Receiver receiver;
string reference;
}' (length=130)
1 => string 'struct Identification {
string sender;
string hash;
string originator;
}' (length=75)
2 => string 'struct Delivery {
Node from;
Node to;
}' (length=41)
3 => string 'struct Node {
string country;
string node;
}' (length=46)
4 => string 'struct Parcel {
string description;
decimal weight;
string orderNumber;
date orderDate;
}' (length=93)
5 => string 'struct Receiver {
string firstName;
string surname;
Address address;
string email;
string language;
}' (length=106)
6 => string 'struct Address {
string line1;
string line2;
string postalCode;
string city;
string country;
}' (length=99)
7 => string 'struct OrderConfirmation {
string trackingNumber;
string reference;
}' (length=71)
8 => string 'struct OrderServiceException {
string code;
OrderServiceException faultInfo;
string message;
}' (length=97)
Итак, в моем коде:
$client = new SoapClient('http://packandship-ws.kiala.com/psws/order?wsdl');
$params = array(
'reference' => $orderId,
'identification' => array(
'sender' => param('kiala', 'sender_id'),
'hash' => hash('sha512', $orderId . param('kiala', 'sender_id') . param('kiala', 'password')),
'originator' => null,
),
'delivery' => array(
'from' => array(
'country' => 'es',
'node' => '',
),
'to' => array(
'country' => 'es',
'node' => '0299'
),
),
'parcel' => array(
'description' => 'Description',
'weight' => 0.200,
'orderNumber' => $orderId,
'orderDate' => date('Y-m-d')
),
'receiver' => array(
'firstName' => 'Customer First Name',
'surname' => 'Customer Sur Name',
'address' => array(
'line1' => 'Line 1 Adress',
'line2' => 'Line 2 Adress',
'postalCode' => 28006,
'city' => 'Madrid',
'country' => 'es',
),
'email' => '[email protected]',
'language' => 'es'
)
);
$result = $client->createOrder($params);
var_dump($result);
но он успешно!
Ответ 5
Во-первых, используйте SoapUI, чтобы создать свой мыльный проект из wsdl. Попробуйте отправить запрос, чтобы поиграть с операциями wsdl. Посмотрите, как запрос xml составляет ваши поля данных.
И затем, если у вас возникли проблемы с получением SoapClient, как вы хотите, вот как я отлаживаю его. Установите опцию trace, чтобы функция __getLastRequest() была доступна для использования.
$soapClient = new SoapClient('http://yourwdsdlurl.com?wsdl', ['trace' => true]);
$params = ['user' => 'Hey', 'account' => '12345'];
$response = $soapClient->__soapCall('<operation>', $params);
$xml = $soapClient->__getLastRequest();
Затем переменная $ xml содержит xml, который SoapClient составляет для вашего запроса. Сравните этот xml с тем, который сгенерирован в SoapUI.
Для меня SoapClient, кажется, игнорирует ключи ассоциативного массива $ params и интерпретирует его как индексированный массив, вызывая неправильные данные параметров в xml. То есть, если я переставлю данные в $ params, $ response будет совершенно другим:
$params = ['account' => '12345', 'user' => 'Hey'];
$response = $soapClient->__soapCall('<operation>', $params);
Ответ 6
Если вы создадите объект SoapParam, это решит вашу проблему. Создайте класс и сопоставьте его с типом объекта, данным WebService. Инициализируйте значения и отправьте запрос. Смотрите образец ниже.
struct Contact {
function Contact ($pid, $pname)
{
id = $pid;
name = $pname;
}
}
$struct = new Contact(100,"John");
$soapstruct = new SoapVar($struct, SOAP_ENC_OBJECT, "Contact","http://soapinterop.org/xsd");
$ContactParam = new SoapParam($soapstruct, "Contact")
$response = $client->Function1($ContactParam);
Ответ 7
прочитайте это:
http://php.net/manual/en/soapclient.call.php
или
Это хороший пример для функции SOAP "__call".
Однако он устарел.
<?php
$wsdl = "http://webservices.tekever.eu/ctt/?wsdl";
$int_zona = 5;
$int_peso = 1001;
$cliente = new SoapClient($wsdl);
print "<p>Envio Internacional: ";
$vem = $cliente->__call('CustoEMSInternacional',array($int_zona, $int_peso));
print $vem;
print "</p>";
?>
Ответ 8
Вам нужен многомерный массив, вы можете попробовать следующее:
$params = array(
array(
"id" => 100,
"name" => "John",
),
"Barrel of Oil",
500
);
в PHP массив является структурой и очень гибким. Обычно с вызовами мыла я использую XML-оболочку, поэтому не знаю, будет ли это работать.
EDIT:
То, что вы можете попробовать, - это создать json-запрос для отправки или использования этого для создания xml-покупки, следующего за тем, что находится на этой странице: http://onwebdev.blogspot.com/2011/08/php-converting-rss-to-json.html
Ответ 9
Вам нужно объявить класс Контракт
class Contract {
public $id;
public $name;
}
$contract = new Contract();
$contract->id = 100;
$contract->name = "John";
$params = array(
"Contact" => $contract,
"description" => "Barrel of Oil",
"amount" => 500,
);
или
$params = array(
$contract,
"description" => "Barrel of Oil",
"amount" => 500,
);
Тогда
$response = $client->__soapCall("Function1", array("FirstFunction" => $params));
или
$response = $client->__soapCall("Function1", $params);
Ответ 10
Существует возможность генерировать объекты php5 с помощью класса WsdlInterpreter. Смотрите больше здесь: https://github.com/gkwelding/WSDLInterpreter
например:
require_once 'WSDLInterpreter-v1.0.0/WSDLInterpreter.php';
$wsdlLocation = '<your wsdl url>?wsdl';
$wsdlInterpreter = new WSDLInterpreter($wsdlLocation);
$wsdlInterpreter->savePHP('.');
Ответ 11
У меня была та же проблема, но я просто обернул аргументы, как это, и теперь это работает.
$args = array();
$args['Header'] = array(
'CustomerCode' => 'dsadsad',
'Language' => 'fdsfasdf'
);
$args['RequestObject'] = $whatever;
// this was the catch, double array with "Request"
$response = $this->client->__soapCall($name, array(array( 'Request' => $args )));
Используя эту функцию:
print_r($this->client->__getLastRequest());
Вы можете увидеть запрос XML, меняется ли он или нет в зависимости от ваших аргументов.
Используйте [trace = 1, exceptions = 0] в параметрах SoapClient.
Ответ 12
getLastRequest():
Этот метод работает, только если объект SoapClient был создан с параметром трассировки TRUE.
ИСТИНА в этом случае представлена 1
$wsdl = storage_path('app/mywsdl.wsdl');
try{
$options = array(
// 'soap_version'=>SOAP_1_1,
'trace'=>1,
'exceptions'=>1,
'cache_wsdl'=>WSDL_CACHE_NONE,
// 'stream_context' => stream_context_create($arrContextOptions)
);
// $client = new \SoapClient($wsdl, array('cache_wsdl' => WSDL_CACHE_NONE) );
$client = new \SoapClient($wsdl, array('cache_wsdl' => WSDL_CACHE_NONE));
$client = new \SoapClient($wsdl,$options);
работал на меня.