пятница, 3 января 2014 г.

Веб сервисы на PHP+nuSOAP и подключение из 1С

Это небольшая история о том как я используя библиотеку nuSOAP на PHP запустил веб сервис и подключился к нему из 1С.

Во первых почему nuSOAP - наверное потому что это простота использования, Вам достаточно скачать исходники, положить в Ваш проект и на этом подключение модулей заканчивается.
И начинаются другие трудности о которых я хочу поведать читателю.
Первое с чем я столкнулся, это то что в примерах выложенных на просторах интернета, есть ошибки, по крайней мере у меня по методике копипаста сразу не заработали, а точнее(как я выяснил позже) не заработал клиент на PHP а вот сервер оказался вполне рабочим, и так, вот самый простой работающий пример, который выглядит так:

<?php
// Подключаем код NuSOAP
require_once('lib\nusoap.php');
// Создаем экземпляр сервера
$server = new soap_server();
// Инициализируем поддержку WSDL
$server->configureWSDL('hellowsdl', 'urn:hellowsdl');
// Устанавливаем пространство имен с префиксом tns для WSDL-схемы
$server->wsdl->schemaTargetNamespace = 'urn:hellowsdl';
$server->soap_defencoding = 'utf-8';
// Регистрируем предоставляемый метод
$server->register('hello',                // название метода
    array('name' => 'xsd:string'),        // входные параметры
    array('return' => 'xsd:string'),      // выходные параметры
    'urn:hellowsdl',                      // пространство имен
    'urn:hellowsdl#hello',                // soapaction
    'rpc',                                // стиль
    'encoded',                            // использование
    'Says hello to the caller'            // описание
);

// Определяем метод как функцию PHP
function hello($name) {

      return $name;
}

// Используем HTTP-запрос чтобы вызвать сервис
$HTTP_RAW_POST_DATA = isset($HTTP_RAW_POST_DATA) ? $HTTP_RAW_POST_DATA : '';
$server->service($HTTP_RAW_POST_DATA);
?>

к сожалению выкладывать ссылку на первоисточник не буду, так как на просторах интернета нашел кучу примеров именно этого кода, поэтому кто автор, мне доподлинно не известно.

Более того там был не рабочий код клиента, который должен был обратиться к данному веб сервису и получить с него данные. Но поскольку моя задача состояла подключиться к нему из 1С, то проще оказалось проверить работоспособность веб сервера именно из 1С код подключения к веб сервису получился такой:

Определение = Новый WSОпределения("http://localhost/helloworld.php?wsdl");
Прокси = Новый WSПрокси(Определение, "urn:hellowsdl", "hellowsdl", "hellowsdlPort");
Результат = Прокси.hello(Реквизит1);
Сообщить(Результат);

Все работало, но как показали тесты данный пример на отрез отказывался работать с русской кодировкой. Не буду мучать читателя о всех способах, которые мне пришлось попробовать, чтобы заставить корректно работать с кирилицей данный веб сервис, но решение так-же было найдено на просторах интернета, правда не с первого раза, поэтому и решил написать, что-бы было больше информации на данную тему. Итак суть решения в том что nuSOUP пытается автоматически привести переданные значения  в кодировку utf-8, а поскольку 1с отправляет данные уже в кодировке utf-8  то в итоге нам конвертируют значения несколько раз, и что-бы решить данную проблему, модуль nuSOUP необходимо отучить от автоматической конвертации. Для этого открываем файл nusoup.php и ищем строки:

var $decode_utf8 = true;
Меняем на 
var $decode_utf8 = false;
далее ищем:
function nusoap_parser($xml,$encoding='UTF-8',$method='',$decode_utf8=true){
и меняем на 
function nusoap_parser($xml,$encoding='UTF-8',$method='',$decode_utf8=false){
после этого мой сервис заработал корректно. Однако на сайте где было найдено данное решение были и другие советы, я их тоже оставлю на данной странице, дабы они не потерялись:

И снова отправьте тестовую строку и посмотрите изменился ли результат

Также можно заменить все упоминания ISO-8859-1 на UTF-8 или cp1251

Если дело уж совсем плохо, то можно конвертировать в формат &#1053;&#1072; &#1075; 
Ну и в конце концов можно попробовать использовать другой NuSoap

Если случится чуди и всё заработает как надо 
Замените 
$GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel = 9;
на 
$GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel = 0;