I have been helplessly trying to create a web service in PHP using NuSoap for the past 2 days. However, after endlessly sifting through various tutorials and guides, i am still stuck with 10 lines of code that refuse to work.
Server :
// Pull in the NuSOAP code
require_once('./lib/nusoap.php');
// Create the server instance
$server = new soap_server;
// Initialize WSDL support
$server->configureWSDL('hellowsdl','http://mysite.com');
// Register the method to expose
$server->register('hello',
array("params"=>"xsd:string"),
array("result"=>"xsd:string"),
'http://mysite.com'
);
// Define the method as a PHP function
function hello($name) {
return 'Hello, ' . $name;
}
// Use the request to (try to) invoke the service
$HTTP_RAW_POST_DATA = isset($HTTP_RAW_POST_DATA) ? $HTTP_RAW_POST_DATA : '';
$server->service($HTTP_RAW_POST_DATA);
And the Client :
// Pull in the NuSOAP code
require_once('./lib/nusoap.php');
// Create the client instance
$client = new nusoap_client('http://localhost/nusoap/server.php?wsdl',true);
// Call the SOAP method
$result = $client->call('hello',array("name"=>"Scott"));
var_dump($result);
Gives me a bool(false)
Where am i going wrong ???
When you register the method, you are calling the parameter 'params' not 'name', the code should be:
$server->register('hello',
array("name"=>"xsd:string"),
array("result"=>"xsd:string"),
'http://mysite.com'
);
You shouldn't be getting false though, when I ran the code with the bug in it i still got
string(12) "Hello, "
(empty $name variable). Go to http://localhost/nusoap/server.php?wsdl and make sure you can see the WSDL from the same machine you are executing the client on.
Related
I don't know how to explain it but, I'm gonna give it a try.
This problem concerns 2 servers, a local and a hosting server. Both servers are running the same PHP version which is 7.0 [with almost same configurations]. And 2 controller actions. And the problem comes from $app->run($input, $out); from the codes below.
I have in my controller that action:
/**
* #Route("/testJson")
*/
public function testJsonAction() {
$app = new \Symfony\Bundle\FrameworkBundle\Console\Application($this->get("kernel"));
$app->setAutoExit(false);
$opt = array("command" =>
"doctrine:generate:entity",
"--entity" => "GuervylEditorBundle:TestOnline",
"--fields" => "kl:string");
$input = new \Symfony\Component\Console\Input\ArrayInput($opt);
$out = new \Symfony\Component\Console\Output\BufferedOutput();
$app->run($input, $out);
$out->fetch();
return new JsonResponse(\json_encode(["a" => "b", "c" => "d"]));
}
Calling this action from the local and hosting server returns "{\u0022a\u0022:\u0022b\u0022,\u0022c\u0022:\u0022d\u0022}" and with Content-Type
application/json which is great, it's the expected result.
Now, here comes the problem:
That almost same code above, I set it inside another class, I call it from another controller action, which passes through 4 methods from different classes to call the method that has the code above [callCommand]
This is the method that implement the code:
public function callCommand($cmd, $opt, &$mykernel = null) {
if ($mykernel == NULL) {
$mykernel = new myKernel("dev", false, __DIR__ . "/../Resources/template_2.8/app");
}
$app = new \Symfony\Bundle\FrameworkBundle\Console\Application($mykernel);
$app->setAutoExit(false);
$opt = array("command" => $cmd) + $opt;
$input = new \Symfony\Component\Console\Input\ArrayInput($opt);
$out = new \Symfony\Component\Console\Output\BufferedOutput();
$app->run($input, $out);
}
From that other controller action, I also return a json content at the end. I can't show the code because it's too big.
When I call that controller action from my localhost, I get the JSON content and Content-Type: application/json which is fine.
But calling it from the hosting server I get extra texts like:
Entity generation
created ./src/Guervyl/EditorBundle/Entity/TestCase.php
> Generating entity class src/Guervyl/EditorBundle/Entity/TestCase.php: OK!
> Generating repository class src/Guervyl/EditorBundle/Repository/TestCaseRepository.php: OK!
Everything is OK! Now get to work :).
Which is the output texts from the console when calling $app->run($input, $out);. After that I get the HTTP header that I set then the json content. And also the content-type is application/x-httpd-php5.
That error only happens on a specific hosting server. I tested other hosting server the code works like on my local server.
My question is why am I getting the error on that specific hosting? Is there something I can change from the PHP.ini to fix it? Because I really need to host my website on that hosting because it offers me great features that I need but the others don't or they are too expensive.
Well, After I debugged the code I noticed that error happened because I did not set the --no-interaction option. So without that option, Symfony was waiting for input when no fields are specified for an Entity.
I'm currently working on a PHP application that will be using some websocket connections to talk to another service.
To talk to this websocket service, we are using Ratchet - which is a PHP library based on react PHP.
This piece of code needs to send and respond to a couple of requests, and after that, should return the information to the "main thread".
Example flow:
HTTP request -> controller -> Starts a service which opens a websocket client -> websocket client is talking to server -> once its done it should return the outcome to the controller code -> controller outputs to user
The issue I'm having is that I'm not familiar with Reactive PHP and am not sure how to handle this.
I've tried;
$service = new WebsocketService();
$startTimer = time();
$service->getList(44);
while($service->getResponse() == null) {
usleep(500);
if (time() > $startTimer + 10) {
continue; //Timeout on 10 seconds
}
}
var_dump($service->getResponse());
The service code would set its "response" variable to something other than null once its done. This obviously fails, because the sleep method is blocking the thread. Also without, it seems like the while loop is blocking I/O and the reactive code fails.
A solution would be to open up a new thread and run the websocket code there, but I wouldn't be happy with that.
I feel like I need to implement some sort of "watcher" around the websocket process, but I'm not sure how to do that.
Our Websocket service client code looks like this;
private $response = null;
/**
* #return null|object
*/
public function getResponse() {
return $this->response;
}
public function getList($accountId) {
$this->response = null;
\Ratchet\Client\connect('ws://192.168.56.1:8080')->then(function(\Ratchet\Client\WebSocket $conn) use ($accountId) {
$login = new \stdClass();
$login->action = 'login';
$conn->on('message', function($msg) use ($conn, $login, $accountId) {
try {
$response = json_decode($msg);
if ($response->result_id == 100) {
//Succesfully logged in to websocket server
//Do our request now.
$message = new \stdClass();
$message->target = 'test';
$conn->send(json_encode($message));
}
if (isset($response->reply) && $response->reply == 'list') {
$this->response = $response; //This is the content I need returned in the controller
$conn->close(); //Dont need it anymore
}
} catch (\Exception $e) {
echo 'response exception!';
//Do nothing for now
}
});
$conn->send(json_encode($login));
}, function ($e) {
echo "Could not connect: {$e->getMessage()}\n";
});
}
Running the code like this also does not work;
$service = new WebsocketService();
$service->getList(44);
echo 'Test';
var_dump($service->getResponse());
because the "test" echo comes before I even get a response from the websocket server.
Please, enlighten me! I'm not sure what to search for.
PHP and websockets still seem to be a bit experimental. Nevertheless I have found a great tutorial on medium.com, written by Adam Winnipass which should be really helpful for solving your problem: https://medium.com/#winni4eva/php-websockets-with-ratchet-5e76bacd7548
The only difference is that they are implementing their websocket client with JavaScript instead of PHP. But in the end there should not be much of a difference, because as soon as we have opened the Websocket connection of each end both applications have to send and also wait to receive notifications - this is how they illustrate it:
Seems like one possibility to create a successful Websocket connection is to extend the MessageComponentInterface
use Ratchet\MessageComponentInterface;
which also requires
use Ratchet\ConnectionInterface;
The message component interface defines the following methods:
onOpen
onMessage
onClose
onError
And I think this is how the Ratchet library is implementing it. This is how they are finally starting their server:
use Ratchet\Server\IoServer;
use MyApp\MyCustomMessageComponentInterface;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
require dirname(__DIR__) . '/vendor/autoload.php';
$server = IoServer::factory(
new HttpServer(
new WsServer(
new MyCustomMessageComponentInterface()
)
),
8080
);
$server->run();
With this architecture you already can receive (onMessage) and sending is also possible with the send() method.
I can not solve the exact problem with your existing code. But I guess if you are using the pre-built classes and interfaces of the library as intended (and demonstrated here) you should be able to achieve what you want by adding your code to the corresponding methods.
More information and examples can be found in the docs:
http://socketo.me/docs/server
http://socketo.me/api/namespace-Ratchet.html
Are you extending class with WsServer, This might be issue, if you are getting fatal errors. I am not sure whether you are getting fatal errors or warnings. Also i notice the public function onOpen() opens a connection. Please try referring this document http://socketo.me/api/class-Ratchet.WebSocket.WsServer.html might be useful.
I have a wsdl file that is automatically generated by the nusoap. The server side code is
require_once('lib/nusoap.php'); //include required class for build nusoap web service server
require_once('conf.php');
// Create server object
$server = new soap_server();
// configure WSDL
$server->configureWSDL('Upload Files');//, $namespace);
// Register the method to expose
$server->register('upload_files', // method
array('files' => 'xsd:string'), // input parameters
array('return' => 'xsd:string'), // output parameters
'', // namespace
'', // soapaction
'', // style
'', // use
'Uploads files to the server' // documentation
);
// Define the method as a PHP function
function upload_files($files) {
//code here
}
// Use the request to (try to) invoke the service
$HTTP_RAW_POST_DATA = isset($HTTP_RAW_POST_DATA) ? $HTTP_RAW_POST_DATA : '';
$server->service($HTTP_RAW_POST_DATA);
WSDL seems to be generated properly and is located here: http://dannyphantom.zg5.ru/server.php?wsdl
The client side code fails almost immediatly, right when I try to create a SoapClient:
require_once('lib/nusoap.php');
$wsdl="http://dannyphantom.zg5.ru/server.php?wsdl"; // SOAP Server
try {
$client=new SoapClient($wsdl, array('trace'=>true, "cache_wsdl" => WSDL_CACHE_NONE)); // Connect the SOAP server
//code
} catch(SoapFault $e) {
//...
} catch (Exception $e) {
//...
}
Now, no matter what I try to do - every time I get an error:
"SOAP-ERROR: Parsing WSDL: Couldn't load from
'http://dannyphantom.zg5.ru/server.php?wsdl' : failed to load external
entity "http://dannyphantom.zg5.ru/server.php?wsdl"
I feel like I've searched to whole Google and tried numerous fixes - nothing works. The url_allow_fopen is set to 1. I can open the link as a file manually. I have tried setting
libxml_disable_entity_loader(false);
before creating the new instance. cURL and openSSL extensions are loaded (even though they are not required for HTTP connection). None of this helped. I am totally out of any ideas. Would appreciate any help.
PHP version is 5.2.
Client code is run from Drupal 5 (Don't think that makes any difference)
I have a PHP soap server (Using nuSoap), and a Java client (using Axis2). Which works pretty good, until it doesn't.
The gist of what I'm trying to do is send a code to the service, and return a XML list of file names.
<filename>20120413.zip</filename>
Here's the SSCE
<?
require_once('nusoap/lib/nusoap.php');
$server = new soap_server();
$server->configureWSDL('Download Database Backup', 'urn:downloadDatabase');
$server->register('getBackupFileNames', // method
array('herdCode' => 'xsd:string'), // input parameters
array('fileList' => 'xsd:string'), // output parameters
'urn:uploadDatabase', // namespace
'urn:uploadDatabase#uploadDatabase', // soapaction
'rpc', // style
'encoded', // use
'uploadDatabase' // documentation
);
function getBackupFileNames($herdCode)
{
$location = "/home/rhythms/backups/" . $herdCode;
$fileList = scandir($location);
return $fileList;
}//end function
$HTTP_RAW_POST_DATA = isset($HTTP_RAW_POST_DATA) ? $HTTP_RAW_POST_DATA : '';
$server->service($HTTP_RAW_POST_DATA);
?>
In a pinch, I know I could do a foreach and manually create the XML as a string. However it gets XMLEncoded then. Is there a better way? I would like to publish it by default in the WSDL. I've also tried the complexType but I had trouble handling that on the Axis2 side.
Thank you!
This isn't a direct answer. What I've come to is you can send a SOAP array using the SOAP-ARRAY complex data type. But it's not a very good method. Instead I'm going to investigate the native SOAP implementation that PHP provides.
Axis2 doesn't handle the SOAP-ARRAY complex datatype well, so I think it will be easier to adjust my implementation to PHP's native types.
This is left as a footnote so hopefully someone else won't fall down the same well I did as I was trying to find a good SOAP implementation.
so I have a WSDL I've been giving as documentation for a soap service. I need to implement this service exactly as defined and I don't want to rewrite the wsdl using nusoap. Is there a way to tell the object nusoap_server = new soap_server(); to use an existing wsdl and then implement the functions from the existing wsdl?
thanks
$WSDL = '/path/to/wsdl/file';
$nusoap_server = new soap_server($WSDL);
The only problem with this is that nusoap may not create the response correctly, but it will host the wsdl file.
I had to customize my xml responses.
Which you can tell nusoap to do but you will need to modify the library.
<?PHP
function serialize_return() {
//$this->fuze_debug(array('test',$this->fuze_print_s($this->methodreturn)),'soap_server_debug.log');
$this->debug('Entering serialize_return methodname: ' . $this->methodname . ' methodURI: ' . $this->methodURI);
// if fault
if (isset($this->methodreturn) && is_object($this->methodreturn) && ((get_class($this->methodreturn) == 'soap_fault') || (get_class($this->methodreturn) == 'nusoap_fault'))) {
$this->debug('got a fault object from method');
$this->fault = $this->methodreturn;
return;
// for some reason with code ignitor this doesnot get set correctly
} elseif ($this->methodreturnisliteralxml) {
//$this->fuze_debug(array('literal xml is : ',$this->fuze_print_s($this->methodreturnisliteralxml)),'soap_server_debug.log');
$return_val = $this->methodreturn;
// returned value(s)
} else {
This above code is in the nusoap library as you can see $this->methodreturnisliteralxml
If you set that to true then you can customize the xml you return from the function you define for nusoap to handle the soap request.
To me nusoap seams to be out of date.
I do not think I would use nusoap again for new projects.