How to fix if operation is not defined in the WSDL using php nusoap - linux

I am currently working on a project that uses web service PHP Nusoap. I implement it at first in the local computer and it is already working perfectly fine, it can insert already in the database.Since, we are also deploying our project in the production server (Linux RHEL 4) so we also need to include the web service. In implementing this in the production server, we got this error :
Operation '' is not defined in the WSDL for this service Here is the
full details :
<?xml version="1.0" encoding="utf-8"?><SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<SOAP-ENV:Fault>
<faultcode xsi:type="xsd:string">SOAP-ENV:Client</faultcode>
<faultactor xsi:type="xsd:string"></faultactor>
<faultstring xsi:type="xsd:string">Operation &apos;&apos; is not defined in the WSDL for this service
</faultstring>
<detail xsi:type="xsd:string"></detail>
</SOAP-ENV:Fault>
HERE IS THE CODE :
client.php
<?php
require_once('lib/nusoap.php');
$data = json_decode(file_get_contents("php://input"), true);
$file_name = $data['file_name'];
$location = $data['location'];
$client = new nusoap_client('http://servername:port/WebService/server.php?wsdl', true);
if ($SERVER['REQUEST_METHOD'] == 'POST') {
$err = $client->getError();
if ($err) {
echo "<h2> Constructor error </h2><pre>" . $err. "</pre>" ;
echo "<h2> Debug </h2><pre>" . htmlspecialchars($client->getdebug(), ENT_QUOTES) . "</pre>" ;
exit();
}
$datas = array (
'file_name' => $file_name,
'location' => $location
);
$result = $client->call('InsertData', $datas);
if ($client->fault) {
echo "<h2> Fault (Expect - The request contains an invalid SOAP Body)</h2> <pre>" ;
print_r ($result);
echo "</pre>";
} else {
$err = $client->getError ();
if ($err) {
echo "<h2> Error </h2><pre>" . $err. "</pre>";
} else {
print_r ($result);
}
}
} else if ($_SERVER['REQUEST_METHOD'] != 'POST') {
echo "Method is not POST " ;
}
?>
server.php
<?php
require_once('lib.nusoap');
$server = new soap_server();
$server->configureWSDL('Database Sample Insertion', 'urn:Insert');
$server->soap_defenconding = 'UTF-8' ;
$server->register('InsertData',
array (
'file_name' => 'xsd:file_name',
'location' => 'xsd:location'
),
array ('return' => 'xsd:string'),
'urn:Insert',
'urn:Insertwsdl#InsertDate',
'rpc',
'literal'
);
function InsertData ($file_name, $location) {
$db_host = 'localhost';
$db_username = 'username';
$db_password = '' ;
$db_name = 'sample' ;
$conn = new mysqli ($db_host, $db_username, $db_password, $db_name);
if ($conn->connect_error) {
trigger_error('Database connection failed : ' .$conn->connect_error , E_USER_ERROR);
}
$sql = "INSERT INTO transaction (`filename`, `location`) VALUES ('$file_name', '$location')";
$query = $conn->query($sql);
}
$HTTP_RAW_POST_DATA = isset($HTTP_RAW_POST_DATA) ? $HTTP_RAW_POST_DATA : '' ;
$server->service($HTTP_RAW_POST_DATA);
?>
what does this problem means and how can we solve this? Or how to setup the web service PHP Nusoap in the production server? Any ideas/suggestions is appreciated. Thanks

I'v had the same problem when PHP/Apache version changed at my server. Im my case the problem was located inside nusoap library function: parse_http_headers()
There is a function used to get all HTTP headers getallheaders() and it seems not getting all headers as it should. There were no Content-Type which is required for nusoap to parse request (ex. text/xml).
Fortunately nusoap checks if function getallheaders() exists and if not it uses $_SERVER array to parse headers.
Finally the one thing I had to do was to change one line of code inside nusoap.php file to disable this function:
if (function_exists('getallheaders')){ ...
to this one:
if (0 && function_exists('getallheaders')){ ...
Hope this help others!

Related

Trigger an URL with a cron job

I'm working on a Symfony 3 website and I need to call a URL of my website with a cron job.
My website is hosted on OVH where I can configure my cron job.
For now, I have setup the command : ./demo/Becowo/batch/emailNewUser.php
emailNewUser.php content :
<?php
header("Location: https://demo.becowo.com/email/newusers");
?>
In the log I have :
[2017-03-07 08:08:04] ## OVH ## END - 2017-03-07 08:08:04.448008 exitcode: 0
[2017-03-07 09:08:03] ## OVH ## START - 2017-03-07 09:08:03.988105 executing: /usr/local/php5.6/bin/php /homez.2332/coworkinwq/./demo/Becowo/batch/emailNewUser.php
But emails are not sent.
How should I configure my cron job to execute this URL ?
Or should I call directly my controller ? How ?
ok, finally it works !!!
Here are the step I followed for others :
1/ You need a controller to send emails :
As the controller will be called via command, you need to injec some services
em : entity manager to flush data
mailer : to access swiftMailer service to send the email
templating : to access TWIG service to use template in the email body
MemberController.php
<?php
namespace Becowo\MemberBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Becowo\CoreBundle\Form\Type\ContactType;
use Becowo\CoreBundle\Entity\Contact;
use Doctrine\ORM\EntityManager;
use Symfony\Bundle\FrameworkBundle\Templating\EngineInterface;
class MemberController extends Controller
{
private $em = null;
private $mailer = null;
private $templating = null;
private $appMember = null;
public function __construct(EntityManager $em, $mailer, EngineInterface $templating, $appMember)
{
$this->em = $em;
$this->mailer = $mailer;
$this->templating = $templating;
$this->appMember = $appMember;
}
public function sendEmailToNewUsersAction()
{
// To call this method, use the command declared in Becowo\CronBundle\Command\EmailNewUserCommand
// php bin/console app:send-email-new-users
$members = $this->appMember->getMembersHasNotReceivedMailNewUser();
$nbMembers = 0;
$nbEmails = 0;
$listEmails = "";
foreach ($members as $member) {
$nbMembers++;
if($member->getEmail() !== null)
{
$message = \Swift_Message::newInstance()
->setSubject("Hello")
->setFrom(array('toto#xxx.com' => 'Contact Becowo'))
->setTo($member->getEmail())
->setContentType("text/html")
->setBody(
$this->templating->render(
'CommonViews/Mail/NewMember.html.twig',
array('member' => $member)
))
;
$this->mailer->send($message);
$nbEmails++;
$listEmails = $listEmails . "\n" . $member->getEmail() ;
$member->setHasReceivedEmailNewUser(true);
$this->em->persist($member);
}
}
$this->em->flush();
$result = " Nombre de nouveaux membres : " . $nbMembers . "\n Nombre d'emails envoyes : " . $nbEmails . "\n Liste des emails : " . $listEmails ;
return $result;
}
}
2/ Call you controller as a service
app/config/services.yml
app.member.sendEmailNewUsers :
class: Becowo\MemberBundle\Controller\MemberController
arguments: ['#doctrine.orm.entity_manager', '#mailer', '#templating', '#app.member']
3/ Create a console command to call your controller
Doc : http://symfony.com/doc/current/console.html
YourBundle/Command/EmailNewUserCommand.php
<?php
namespace Becowo\CronBundle\Command;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
class EmailNewUserCommand extends ContainerAwareCommand
{
protected function configure()
{
// the name of the command (the part after "php bin/console")
$this->setName('app:send-email-new-users')
->setDescription('Send welcome emails to new users')
;
}
protected function execute(InputInterface $input, OutputInterface $output)
{
// outputs a message to the console followed by a "\n"
$output->writeln('Debut de la commande d\'envoi d\'emails');
// access the container using getContainer()
$memberService = $this->getContainer()->get('app.member.sendEmailNewUsers');
$results = $memberService->sendEmailToNewUsersAction();
$output->writeln($results);
}
}
4/ Test your command !
In the console, call you command : php bin/console app:send-email-new-users
5/ Create a script to run the command
Doc (french) : http://www.christophe-meneses.fr/article/deployer-son-projet-symfony-sur-un-hebergement-perso-ovh
..Web/Batch/EmailNewUsers.sh
#!/bin/bash
today=$(date +"%Y-%m-%d-%H")
/usr/local/php5.6/bin/php /homez.1111/coworkinwq/./demo/toto/bin/console app:send-email-new-users --env=demo > /homez.1111/coworkinwq/./demo/toto/var/logs/Cron/emailNewUsers-$today.txt
Here it took me some time to get the correct script.
Take care of php5.6 : it has to match your PHP version on OVH
Don't forget to upload bin/console file on the server
homez.xxxx/name has to match with your config (I found mine on OVH, and then in the logs)
IMPORTANT : when you upload the file on the server, add execute right (CHMOD 704)
6/ Create the cron job in OVH
Call your script with the command : ./demo/Becowo/web/Batch/EmailNewUsers.sh
Language : other
7/ Wait !
You need to wait for the next run. Then have a look on OVH cron logs, or on your own logs created via the command in the .sh file
It took me several days to get it..
Enjoy !!
As commented above, you should do it with a symfony commaad. This is an example for you.
NOTE: Although it is working, you can always improve this example. Especially the way command calls your endpoint.
Controller service definition:
services:
yow_application.controller.default:
class: yow\ApplicationBundle\Controller\DefaultController
Controller itself
namespace yow\ApplicationBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Symfony\Component\HttpFoundation\Response;
/**
* #Route("", service="yow_application.controller.default")
*/
class DefaultController
{
/**
* #Method({"GET"})
* #Route("/plain", name="plain_response")
*
* #return Response
*/
public function plainResponseAction()
{
return new Response('This is a plain response!');
}
}
Command service definition
services:
yow_application.command.email_users:
class: yow\ApplicationBundle\Command\EmailUsersCommand
arguments:
- '#http_kernel'
tags:
- { name: console.command }
Command itself
namespace yow\ApplicationBundle\Command;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\HttpKernelInterface;
class EmailUsersCommand extends Command
{
private $httpKernel;
public function __construct(HttpKernelInterface $httpKernel)
{
parent::__construct();
$this->httpKernel = $httpKernel;
}
protected function configure()
{
$this->setName('email:users')->setDescription('Emails users');
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$request = new Request();
$attributes = [
'_controller' => 'yow_application.controller.default:plainResponseAction',
'request' => $request
];
$subRequest = $request->duplicate([], null, $attributes);
$response = $this->httpKernel->handle($subRequest, HttpKernelInterface::SUB_REQUEST);
$output->writeln($response);
}
}
Test
$ php bin/console email:users
Cache-Control: no-cache, private
X-Debug-Token: 99d025
X-Debug-Token-Link: /_profiler/99d025
This is a plain response!
1.0
200
OK

Error: Undefined index: HTTP_X_FORWARDED_FOR

I have written this code
$ips = preg_split("/,/", $_SERVER["HTTP_X_FORWARDED_FOR"]);
$ip = $ips[0];
if ($key === $ip && $val === env('SERVER_ADDR')) {
$addr = env($ip);
if ($addr !== null) {
$val = $addr;
}
}
But I am getting following error:
<b>Notice</b>: Undefined index: HTTP_X_FORWARDED_FOR
Just dont use array keys without knowing for sure they always exist..
basic PHP one o' one
if (!empty($_SERVER["HTTP_X_FORWARDED_FOR"])) {
// now only try to access this key
}
The alternative in Cake is to use wrapper methods that are designed to automatically check on the existence internally. Then you can just read the value directly. In your case env() checks on those server vars:
$result = env('HTTP_X_FORWARDED_FOR');

login to modx from external/other server revolution 2.2.5

I am pissed off with this problem from 2 days.
I am using MODx Revolution 2.2.5 (traditional) and want to login to modx from external server just to fetch some user details.
1) I know that runprocessor method works only if i am logged in to manager (unfortunately, that's the only way i know to login user in) So i tried IFRAME method to avoid (cross scripting) it worked perfectly but i am not able to read the data from IFRAME using javascript because of same issue, cross domain access policy.
When i try to post data using some other method like CURL, Ajax using
header("Access-Control-Allow-Origin: *");
I am able to login (I see $response->response['success'] == 1) but cant access any data and it says
Fatal error: Call to a member function get() on a non-object
Below is the snippet code i am using
if(isset($_POST) && count($_POST)){
$c = array(
'username' => $_POST['username'],
'password' => $_POST['password']
);
$response = $modx->runProcessor('security/login',$c);
if($response->response['success'] == 1){
$user['id'] = $modx->user->get('id');
$profile = $modx->user->getOne('Profile');
$user['fullname'] = $profile->get('fullname');
$user['email'] = $profile->get('email');
echo json_encode($user);
}else{
echo json_encode($response->response);
}
}
2) I can use login snippet but it doesnt return output what i expect. We have ready site and we are already using login plugin so i cant even modify login plugin to respond with expected data
How can i login to modx using api or any other method ??
You are really attacking this problem completely wrong in my opinion. If you want to access a server/webpage from another, you don't iFrame and do it the way you are. That is hacking, and this hole will most likely be fixed in a future version.
What you SHOULD do is connecting to the database and just gather the information from the user-table.
No hacking, no "tricks", won't stop working and much safer.
Well, I sorted out this today, Below is the complete come that worked perfectly.
Pay attention to
header("Access-Control-Allow-Origin: http://www.xyz.com");
Using above CORS specification you can allow 2 servers to communication.
header("Access-Control-Allow-Origin: http://www.xyz.com");
if(isset($_POST['username']) && isset($_POST['password'])){
// get username and password from POST array
$username = $modx->sanitizeString($_POST['username']);
$password = $modx->sanitizeString($_POST['password']);
if(trim($username) != "" and trim($password) != ""){
// Load lexicons to show proper error messages
if (!isset($modx->lexicon) || !is_object($modx->lexicon)) {
$modx->getService('lexicon','modLexicon');
}
$modx->lexicon->load('login');
$loginContext= isset ($scriptProperties['login_context']) ? $scriptProperties['login_context'] :
$modx->context->get('key');
$addContexts= isset ($scriptProperties['add_contexts']) && !empty($scriptProperties['add_contexts']) ? explode(',', $scriptProperties['add_contexts']) : array();
$mgrEvents = ($loginContext == 'mgr');
$givenPassword = $password;
/** #var $user modUser */
$user= $modx->getObjectGraph('modUser', '{"Profile":{},"UserSettings":{}}', array ('modUser.username' => $username));
if (!$user) {
$ru = $modx->invokeEvent("OnUserNotFound", array(
'user' => &$user,
'username' => $username,
'password' => $password,
'attributes' => array(
'loginContext' => $loginContext,
)
));
if (!empty($ru)) {
foreach ($ru as $obj) {
if (is_object($obj) && $obj instanceof modUser) {
$user = $obj;
break;
}
}
}
if (!is_object($user) || !($user instanceof modUser)) {
//echo "cant locate account";
echo $modx->toJSON($modx->error->failure($modx->lexicon('login_cannot_locate_account')));
exit;
}
}
if (!$user->get('active')) {
//echo "inactivated accout";
echo $modx->toJSON($modx->error->failure($modx->lexicon('login_user_inactive')));
exit;
}
if (!$user->passwordMatches($givenPassword)) {
if (!array_key_exists('login_failed', $_SESSION)) {
$_SESSION['login_failed'] = 0;
}
if ($_SESSION['login_failed'] == 0) {
$flc = ((integer) $user->Profile->get('failedlogincount')) + 1;
$user->Profile->set('failedlogincount', $flc);
$user->Profile->save();
$_SESSION['login_failed']++;
} else {
$_SESSION['login_failed'] = 0;
}
//echo "wrong username pass";
echo $modx->toJSON($modx->error->failure($modx->lexicon('login_username_password_incorrect')));
exit;
}
$fullname = $user->Profile->get('fullname');
echo '{"success":true,"message":"Welcome '.$fullname.'!"}';
}else{
echo '{"success":false,"message":"Please enter username and password"}';
}
}

Search Facebook using PHP SDK

In the last days, I'm working on the application which needs to search for users on Facebook. Since the FQL query for "username" was deprecated/canceled, I have decided to use common search API.
I use PHP so FB PHP SDK is the way I'd prefer. I have used it earlier for FQL queries, just like this:
// $api is already initialized, with access_key, app secret and so on
$users = $api(array(
'method' => 'fql.query',
'query' => "SELECT first_name,last_name FROM user WHERE uid='12345'",
));
I'd like to build the search query in the similar way. Especially, I don't want to urlencode the parameters, specify access key, app secret and all the stuff the SDK is supposed to do for me. However, I haven't been able to build this query using SDK yet. Is there any possibility to do it? If yes, how? I have found long list of sdk-supported "api calls" but I need to build the query for graph.facebook.com/search?arguments.
Thanks in advance.
EDIT: To make it clear, I don't want to build the string by myself. I know this solution works. But imho it's ugly when I have SDK:
$name = urlencode(trim($first_name . " " . $last_name_));
$users = $this->facebook->api("/search?q=$name&type=user&access_token=$key");
Searching User via Graph API using php-sdk 3.1.1
User will need to authorize your app before making a search for
users.
{
"error": {
"message": "A user access token is required to request this resource.",
"type": "OAuthException"
}
}
Php-skd 3.1.1 init.
<?php
require './src/facebook.php';
$facebook = new Facebook(array(
'appId' => 'your-app-id',
'secret' => 'your-app-secret',
));
$user = $facebook->getUser();
if ($user) {
try {
// Proceed knowing you have a logged in user who's authenticated.
$user_profile = $facebook->api('/me');
} catch (FacebookApiException $e) {
error_log($e);
$user = null;
}
}
/* */
if ($user) {
$logoutUrl = $facebook->getLogoutUrl();
} else {
$loginUrl = $facebook->getLoginUrl();
}
?>
Search includes, encoding search term, setting results limit, and
offset for paging.
<?php
/* Get Search parameter from url or post and urlencode it. */
$q = urlencode($_GET['qs']);
if(!$_GET['qs']){
$q = urlencode($_POST['qs']);
if(!$_POST['qs']){
/* Default Search Term */
$q = "Shawn+E+Carter";
}
}
/* Get Results Limit from url or set default. */
$limit = $_GET['limit'];
if (!$_GET['limit']){
$limit = 60;
}
/* Get Offset from url or set default for paging. */
$offset = $_GET['offset'];
if (!$_GET['offset']){
$offset = 0;
}
/* Make Graph API call to user */
$usersearch = 'search%3Fq='.$q.'%26type=user%26limit='.$limit.'%26offset='.$offset.'';
echo '<pre style="text-align: left;">';
print_r($usersearch);
echo '</pre>';
?>

Webforms in excel instead of e-mail

A client of mine asked me if i can find a solution for this problem.
His website (still a WIP) http://welkommagazine.nl/luuk/ has a form. The form obviously uses a sendmail script to send the form to e-mail. From thereon he manually copy/pastes all the submissions to excel.
What he wants is that the forms online automaticcaly are added to an excel document to save him a lot of work.
Now i am not a programmer, but a designer.. I think this can be done, but i have absolutely no clue how. I googled alot for it and the only thing i found was a dreamweaverplugin.
Is there a way to do this, if so, how?
Not a programmer's response, but...
I think an easy solution is to use Google docs. You can set-up a Google Spreadsheet and associate a form to it. Whenever a user fills the form , his data is added to the spreadsheet.
Your client may download that anytime.
There are some other providers on the market, some free, some not. E.g: wufoo.com
Found the answer myself. I wrote a PHP code snippet which actually stores the fields comma seperated in a CSV file and sends an email to a desired adress with the filled in fields.
if(isset($_POST['Submit'])){
$pakket = $_POST['pakket'];
$extragidsen = $_POST['extragidsen'];
$naambedrijf = $_POST['naambedrijf'];
$err = '';
if(trim($pakket)==''){
$err .= '-Please enter a name';
}
if(empty($extragidsen)){
$err .= '-Please enter an email address';
}
if(strlen($naambedrijf)==0){
$err .= '-Please enter a comment';
}
if($err!=''){
echo $err;
}
else{
$filename = 'file.csv';
$somecontent = $pakket . ',' . $extragidsen . ',' . $naambedrijf . "\n";
// Let's make sure the file exists and is writable first.
if (is_writable($filename)) {
// In our example we're opening $filename in append mode.
// The file pointer is at the bottom of the file hence
// that's where $somecontent will go when we fwrite() it.
if (!$handle = fopen($filename, 'a')) {
echo "Cannot open file ($filename)";
exit;
}
// Write $somecontent to our opened file.
if (fwrite($handle, $somecontent) === FALSE) {
echo "Cannot write to file ($filename)";
exit;
}
//--------------------------Set these paramaters--------------------------
// Subject of email sent to you.
$subject = 'Inschrijving welkom';
// Your email address. This is where the form information will be sent.
$emailadd = 'luuk#luukratief.com';
// Where to redirect after form is processed.
$url = 'http://www.google.com';
// Makes all fields required. If set to '1' no field can not be empty. If set to '0' any or all fields can be empty.
$req = '0';
// --------------------------Do not edit below this line--------------------------
$text = "Results from form:\n\n";
$space = ' ';
$line = '
';
foreach ($_POST as $key => $value)
{
if ($req == '1')
{
if ($value == '')
{echo "$key is empty";die;}
}
$j = strlen($key);
if ($j >= 20)
{echo "Name of form element $key cannot be longer than 20 characters";die;}
$j = 20 - $j;
for ($i = 1; $i ';
fclose($handle);
} else {
echo "The file $filename is not writable";
}
}
}
Maybe the code aint that clean as it can be, but eh it works.
Feel free to clean up the code if you want to :)
I guessed I would answer this myself for the community...
BTW u need to set "write" rights to "file.csv"
cheers

Resources