I'm trying to create a soap server in laravel 5.2. This is my code:
Content of SoapController.php:
<?php namespace Giant\Http\Controllers;
class SoapController extends Controller {
public function __construct() {
parent::__construct();
ini_set('soap.wsdl_cache_enabled', 0);
ini_set('soap.wsdl_cache_ttl', 0);
ini_set('default_socket_timeout', 300);
ini_set('max_execution_time', 0);
}
public function server() {
$location = url('server'); // http://payment.dev/server
$namespace = $location;
$class = "\\Giant\\Http\\Controllers\\HelloWorld";
$wsdl = new \WSDL\WSDLCreator($class, $location);
$wsdl->setNamespace($namespace);
if (isset($_GET['wsdl'])) {
$wsdl->renderWSDL();
exit;
}
$wsdl->renderWSDLService();
$wsdlUrl = url('wsdl/server.wsdl');
$server = new \SoapServer(
url('server?wsdl'),
array(
'exceptions' => 1,
'trace' => 1,
)
);
$server->setClass($class);
$server->handle();
exit;
}
public function client() {
$wsdl = url('server?wsdl');
$client = new \SoapClient($wsdl);
try {
$res = $client->hello('world');
dd($res);
} catch (\Exception $ex) {
dd($ex);
}
}
}
class HelloWorld {
/**
* #WebMethod
* #desc Hello Web-Service
* #param string $name
* #return string $helloMessage
*/
public function hello($name) {
return "hello {$name}";
}
}
My wsdl file is: wsdl
And my routes:
Route::any('/server', 'SoapController#server');
Route::any('/client', 'SoapController#client');
And the result I get:
Internal Server Error
:(
I use piotrooo/wsdl-creator to generate wsdl. (There is no problem with that, It is working in laravel 4.2). And I have also tried nusoap and php2wsdl libraries.
My SoapClient is working well. Because it can get service from other soap servers in other urls, But I think my SoapServer can not work well.
I even get no errors in error-log file.
I just figured out wht was the problem:
The problem with log was that i was checking error-log in my www folder while laravel has its own log file. And using that i figured that i have problem with TokenMismatchException. Laravel's CsrfVerifyMiddleware would not letting me to request using soap.
I just added my url to "except" array inside CsrfVerifyMiddleware file.
Do not use two classes in one file
This is my experience from our project in which used Soap
This is SoapServerController . Paste wsdl file in root folder of your project
class SoapServerController extends Controller {
public function service() {
$server = new \SoapServer('http://' . request()->server('HTTP_HOST') . '/yourwsdlfile.wsdl');
$server->setClass('App\Http\Requests\somenamespace\SoapRequest');
$server->handle();
}
}
and in requests create class for requests like this:
class SoapRequest{
public function functionFromWsdl($args if you want) {
$parameters = (array) $args;
return with(new fooClass())->barMethod($parameters);
}
}
and route must be post:
Route::post('webservice','SoapServerController#service');
In laravel 5 all before statements have turned into middlewares (just like what is in django framework). And you need to implement using middlewares.
Related
I have this error with Zend (v1) XmlRpc client :
Uncaught exception 'Zend_XmlRpc_Client_FaultException' with message 'Failed to parse response'.
It's the error status 651.
The call never reaches the class/method requested, it seems that the call is not fired like it was blocked or something. I'm in debug on the method called and it's not triggered.
PHP version is 5.4.
EDIT
Here is the code :
Caller class :
require_once 'library/Zend/XmlRpc/Client.php';
class FrontService
{
private $client;
public function __construct($xmlRpc)
{
$this->client = new Zend_XmlRpc_Client($xmlRpc);
}
public function call($name, $params = array())
{
return $this->client->call($name, $params);
}
}
Call to the class :
$this->_fs = new FrontService(HM_Config::getParam("amf-url"));
$editos = $this->_fs->call('getEdito',$params_home);
Code called :
include_once realpath(dirname(__FILE__) .'/..')
.'/application/bootstrap.php';
require_once '_config.php';
require_once 'DirectDbConnectionV2.php';
class FrontGateway extends DirectDbConnectionV2
{
public static $smStatic;
function __construct()
{
mysql_query("SET NAMES 'utf8'");
$this->sm = self::$smStatic;
$this->log = new Log();
$this->log->set_file('amfDbConnection');
$this->log->write('construct bordel');
}
}
FrontGateway::$smStatic = $sm;
$controllerManager = $sm->get('EditoWebsiteMVC\ControllerManager');
$controllerManager->run('EditoWebsite\Controller\UIGateway', 'xmlRpc');
Code that should be executed :
namespace EditoWebsite\Controller;
use EditoWebsiteMVC\AbstractController;
use EditoWebsiteMVC\ViewRender\CLI as CLIViewRender;
use EditoWebsiteMVC\ViewRender\HTMLTemplate as HTMLTemplateViewRender;
use Zend_XmlRpc_Server as XmlRpcServer;
class UIGatewayController extends AbstractController
{
public function xmlRpcAction()
{
$svr = new XmlRpcServer();
$svr->setClass('FrontGateway');
echo $svr->handle();
exit;
}
}
The code in the getEdito method from the DirectDbConnectionV2 is never reached.
Is there something I need to enable on the server ? or a port that I need to open ?
EDIT EDIT
I should mention that the code is working on another server that I've access to, is there anything I should compare / check to maybe solve that issue ?
Thanks a lot
I don't think there's enough info to even make a guess, but let me try.
I've faced similar issue, where requests sent never reached the server. It turned out to be that Zend_Http_Client_Adapter_Socket adapter is binding to an IPv6 and due to routing issues request never got to the server.
In the end, what solved the issue was:
$client->getAdapter()->setStreamContext(array(
'socket' => array('bindto' => '0:0'),
));
where $client is an instance of Zend_Http_Client.
Again, it's just a shot in the dark, but could be worth trying. :)
Edit:
In your case, you should add following to FrontService constructor:
$this->client->getHttpClient()->getAdapter()->setStreamContext(array(
'socket' => array('bindto' => '0:0'),
));
Edit Edit:
Since back on 1.9.0 there's no getAdapter on Zend_Http_Client, you have to create adapter yourself and pass it to http client:
public function __construct($xmlRpc)
{
$this->client = new Zend_XmlRpc_Client($xmlRpc);
$adapter = Zend_Http_Client_Adapter_Socket();
$adapter->setStreamContext(array(
'socket' => array('bindto' => '0:0'),
));
$this->client->getHttpClient()->setAdapter($adapter);
}
Cheers.
I have a function in my Laravel application that generates TwiML for a holding queue. It seems that when I try to dynamically generate the value for the waitUrl attribute, I end up getting a 500 server error during runtime. Routes are properly established and I'm able to view the correct XML at the waitURL in the browser. However, the error persists.
If I create a static XML file with the same exact content, or use a TwiML Bin, it works like a charm.
Here are the relevant functions:
public function wait() {
return $this->generateWaitTwiml();
}
public function onHold($agentId) {
return $this->generateHoldQueueTwiml($agentId, '/phone/wait');
}
private function generateHoldQueueTwiml($agentId, $waitUrl = null) {
$queue = $agentId . '_hold';
if ($waitUrl === null){
$waitUrl = 'path_to_static.xml';
}
$queue = $agentId . '_hold';
$response = new Twiml();
$response->enqueue(
$queue,
['waitUrl' => $waitUrl]
);
return response($response)->header('Content-Type', 'application/xml');
}
private function generateWaitTwiml() {
$response = new Twiml();
$response
->play('http://path_to_my.mp3');
return response($response)->header('Content-Type', 'application/xml');
}
This was resolved by excluding the URIs from the CSRF verification (in VerifyCsrfToken.php):
class VerifyCsrfToken extends Middleware {
protected $except = [
'uri/',
'uri2/*',
];
}
On Owncloud 8.1 using the owncloud command line, I create a new test app:
ocdev startapp MyApp --email mail#example.com --author "Your Name" --description "My first app" --owncloud 8
The app is working, I can add it in the owncloud control panel.
Now I'd like to write to a file, so I use one example from the owncloud documentation:
https://doc.owncloud.org/server/8.1/developer_manual/app/filesystem.html
[Edit] I started over and now, I don't know if I omitted something, but "myapp" comes with no "application.php" file.
So I create it at /var/www/core/apps/myapp/appinfo/application.php :
<?php
namespace OCA\MyApp\AppInfo;
use \OCP\AppFramework\App;
use \OCA\MyApp\Storage\AuthorStorage;
class Application extends App {
public function __construct(array $urlParams=array()){
parent::__construct('myapp', $urlParams);
$container = $this->getContainer();
/**
* Storage Layer
*/
$container->registerService('AuthorStorage', function($c) {
return new AuthorStorage($c->query('RootStorage'));
});
$container->registerService('RootStorage', function($c) {
return $c->query('ServerContainer')->getRootFolder();
});
}
}
Then I create a file called /var/www/core/apps/myapp/storage/AuthorStorage.php with:
<?php
namespace OCA\MyApp\Storage;
class AuthorStorage {
private $storage;
public function __construct($storage){
$this->storage = $storage;
}
public function writeTxt($content) {
// check if file exists and write to it if possible
try {
try {
$file = $this->storage->get('/myfile.txt');
} catch(\OCP\Files\NotFoundException $e) {
$this->storage->touch('/myfile.txt');
$file = $this->storage->get('/myfile.txt');
}
// the id can be accessed by $file->getId();
$file->putContent($content);
} catch(\OCP\Files\NotPermittedException $e) {
// you have to create this exception by yourself ;)
throw new StorageException('Cant write to file');
}
}
}
The sample app already gives me a route to the index function in the pagecontroller.php
['name' => 'page#index', 'url' => '/', 'verb' => 'GET']
How do I call the function "writeTxt" from there?
Based on http://php.net/manual/en/language.oop5.basic.php
I tried:
use \OCA\MyApp\Storage\AuthorStorage;
and
public function index() {
//added part
$a = new AuthorStorage();
$a->writeTxt('test');
//original part
$params = ['user' => $this->userId];
return new TemplateResponse('myapp', 'main', $params); //templates/main.php
}
After running I get a "Class 'OCA\MyApp\Storage\AuthorStorage' not found at /var/www/core/apps/myapp/controller/pagecontroller.php#44"
Even with the help of use \OCA\MyApp\Storage\AuthorStorage; ( ClassNotFoundException: Attempted to load class... Symfony ) it doesn't seem to help.
Thanks
Time has gone by, so I'm posting an answer to my question for owncloud 9.
Here are the steps to a basic script with read, write, copy file ability.
"application.php" has definitively been removed from the example. It was not a bug.
Following:
https://doc.owncloud.org/server/9.0/developer_manual/app/startapp.html
Generate the demo "MyApp" app:
ocdev startapp MyApp --email mail#example.com --author "Your Name" --description "My first app" --owncloud 9
Edit the file myapp/controller/pagecontroller.php
<?php
/**
* ownCloud - myapp
*
* This file is licensed under the Affero General Public License version 3 or
* later. See the COPYING file.
*
* #author Your Name <mail#example.com>
* #copyright Your Name 2016
*/
namespace OCA\MyApp\Controller;
use OCP\IRequest;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\Controller;
use OCP\Files\IRootFolder;
use OC\Files\Storage\Temporary;
class PageController extends Controller {
private $userId;
private $storage;
private $userstorage;
public function __construct($AppName, IRequest $request, IRootFolder $storage, $UserId){
parent::__construct($AppName, $request);
$this->storage = $storage;
$this->userId = $UserId;
$this->userstorage = $this->storage->get($this->userId.'/files/');
}
/**
* CAUTION: the #Stuff turns off security checks; for this page no admin is
* required and no CSRF check. If you don't know what CSRF is, read
* it up in the docs or you might create a security hole. This is
* basically the only required method to add this exemption, don't
* add it to any other method if you don't exactly know what it does
*
* #NoAdminRequired
* #NoCSRFRequired
*/
public function index() {
$listedudossier = $this->userstorage->getDirectoryListing();
//list all items in the root directory
//and copies the files in an directory called old
//the directory "old" is not script created
foreach ($listedudossier as $value) {
if ( $value->getType() == 'file' ){
$value->copy($this->userId.'/files/old/'.$value->getName());
//also works
//$value->copy($this->userstorage->getPath().'/old/'.$value->getName());
}
}
$params = ['listedudossier' => $listedudossier ];
return new TemplateResponse('myapp', 'main', $params); // templates/main.php
}
/**
* Simply method that posts back the payload of the request
* #NoAdminRequired
*/
public function doEcho($echo) {
//creates a file
$this->userstorage->newFile('myfile2.txt');
//opens a file, adds inputbox content and saves the file
$file = $this->userstorage->get('myfile.txt');
$contenu = $file->getContent();
$file->putContent($contenu.$echo);
return new DataResponse(['echo' => $echo]);
}
}
You also need to edit the myapp/templates/part.content.php
<p>Hello World <?php p($_['user']) ?></p>
<p><button id="hello">click me</button></p>
<p><textarea id="echo-content">
Send this as ajax
</textarea></p>
<p><button id="echo">Send ajax request</button></p>
Ajax response: <div id="echo-result"></div>
<p>listedudossier:<p> <?php
foreach ($_['listedudossier'] as $file) {
echo "type:".$file->getType();
echo "<p>";
echo "nom:".$file->getName();
echo "<p>";
echo "modif:".$file->getMTime();
echo "<p>";
}
From here you can test the code in a development environment:
https://github.com/owncloud/ocdev/blob/master/README.rst#installation
I have a class which is meant to "load" an another class, however I haven't been able to get it to work.
Error Message
Fatal error: Call to undefined method stdClass::echoString() in C:\Program Files (x86)\EasyPHP-DevServer-14.1VC11\data\localweb\classes\example.php on line 5
Code
My code is broken up into three main sections:
api.php - the class to load the other classes.
API/exampleExternalAPI.php - (multiple files) the classes that api.php loads
example.php - the file that uses the main class (api.php)
If it helps these files can be downloaded from my dropbox
api.php
<?php
/* Config */
define('pathToAPIs','API/');
/* Autoload Function */
spl_autoload_register(function($className){
$namespace=str_replace("\\","/",__NAMESPACE__);
$className=str_replace("\\","/",$className);
$class=pathToAPIs.(empty($namespace)?"":$namespace."/")."{$className}.php";
include_once($class);
});
class api {
private $listOfAPIs;
public $APIs;
public function __construct($setAPI = null){
$this->updateListOfAPIs();
if (isset($setAPI)){
return $this->setAPI($setAPI);
}
}
public function setAPIs($setAPIs){
$this->APIs = null; // clears a previous call to this method
if (!is_array($setAPIs)){ // if not an array
$setAPIs = array($setAPIs); // make array
}
foreach ($setAPIs as $setAPIType){
if(in_array($setAPIType,$this->listOfAPIs)){
$array[$setAPIType] = new $setAPIType;
}
}
$this->APIs = json_decode(json_encode($array), FALSE); // convert array of required api objects to an object
return $this->APIs;
}
public function getListOfAPIs($update = false){
if ($update){
$this->updateListOfAPIs();
}
return $this->listOfAPIs;
}
private function updateListOfAPIs(){
$this->listOfAPIs = null; // clears a previous call to this method
$it = new FilesystemIterator(pathToAPIs);
foreach ($it as $fileinfo){
$filename = pathinfo($fileinfo->getFilename(), PATHINFO_FILENAME); // removes extension
$this->listOfAPIs[]= $filename;
}
}
public function __call($method,$args){
}
}
API/exampleExternalAPI.php
<?php
class exampleExternalAPI {
public function echoString($string){
echo $string;
}
}
example.php
<?php
require_once 'api.php';
$api = new api();
$api->setAPIs('exampleExternalAPI');
$api->APIs->exampleExternalAPI->echoString('string');
Background Info
(may give some insight to my madness)
I'm working on a project where I need to connect to lots of external APIs.
So I decided to creating a class to look after all my communications with external APIs ( not sure if best way - new to Object Oriented Programming).
I'm not entirely sure what problem you're trying to solve, but if your APIs is a simple stdClass instance it should work as expected:
public function setAPIs($setAPIs)
{
$this->APIs = new stdClass; // clears a previous call to this method
if (!is_array($setAPIs)) { // if not an array
$setAPIs = array($setAPIs); // make array
}
foreach ($setAPIs as $setAPIType) {
if (in_array($setAPIType, $this->listOfAPIs)) {
$this->APIs->{$setAPIType} = new $setAPIType;
}
}
return $this->APIs;
}
I wish to show custom exception pages in my application. In documentation is written:
"Note: We can also use HMVC to issue a sub-request to another page rather than generating the Response in the HTTP_Exception itself." The problem is i don't know how to do it.
Code which I am using is:
class HTTP_Exception_404 extends Kohana_HTTP_Exception_404 {
/**
* Generate a Response for the 404 Exception.
*
* The user should be shown a nice 404 page.
*
* #return Response
*/
public function get_response()
{
$view = View::factory('errors/404');
// Remembering that `$this` is an instance of HTTP_Exception_404
$view->message = $this->getMessage();
$response = Response::factory()
->status(404)
->body($view->render());
return $response;
}
}
It is working but i need to show the message in currently used template.
Regards
You shouldn't need to bother with sub-requests if all you want is to use the template. Here's the easy way:
class HTTP_Exception_404 extends Kohana_HTTP_Exception_404 {
public function get_response()
{
$view = View::factory('errors/404');
// Remembering that `$this` is an instance of HTTP_Exception_404
$view->message = $this->getMessage();
// Wrap it in our layout
$layout = $layout = View::factory('template');
$layout->body = $view->render();
$response = Response::factory()
->status(404)
->body($layout->render());
return $response;
}
}
If you really must use a sub-request, just do the sub-request normally:
class HTTP_Exception_404 extends Kohana_HTTP_Exception_404 {
public function get_response()
{
$request = Request::factory('route_to_error_page_action')
->method(Request::POST)
->post(array('message' => $this->getMessage()));
$response = $request->execute();
// If you didn't return the 404 code from the sub-request, uncomment this:
$response->status(404);
return $response;
}
}