Cloudant and Php-on-Couch not working well due to continue - php

I believe Cloudant has recently changed some of their code. Recently, if you do a storedoc operation, in a try/catch statement. Cloudant will return an 'error' to the framework:
Uncaught exception 'couchException' with message 'Continue
Of course you can handle it in the catch statement, but it should really be coming back as 'successful' in the Try statement of the PHP-on-Couch library.
Anyone come across this or know how to handle it? The biggest issues is that you cannot grab the ID and Rev in the catch statement because it's coming up as an error:
try { // does not return here, goes to catch
$response = $client->storeDoc($doc);
$response_json['status'] = 'success';
$response_json['id'] = $response->id;
$response_json['rev'] = $response->rev;
} catch (Exception $e) { // even though the doc is successfully storing
// check for accepted BEG
$error = '';
$error = $e->getMessage();
$err_pos = strpos($error,"Accepted");
$err_pos_2 = strpos($error,"Continue");
if($err_pos !== false OR $err_pos_2 !== false){ // success
$response_json['status'] = 'success';
$response_json['id'] = $response->id; // returns null
$response_json['rev'] = $response->rev; // returns null
} else { // truely an error
$response_json['status'] = 'fail';
$response_json['message'] = $e->getMessage();
$response_json['code'] = $e->getCode();
}
// check for accepted END
}

I tested in both CouchDB and Cloudant and the behavior is the same. This is what I believe is happening. When you create a new couchDocument:
$doc = new couchDocument($client);
By default the document is set to autocommit. You can see this in couchDocument.php:
function __construct(couchClient $client) {
$this->__couch_data = new stdClass();
$this->__couch_data->client = $client;
$this->__couch_data->fields = new stdClass();
$this->__couch_data->autocommit = true;
}
As soon as you set a property on the document:
$doc->set( array('name'=>'Smith','firstname'=>'John') );
storeDoc is immediately called. You are then trying to call storeDoc a second time and couchDB returns an error.
There are 2 ways to fix this:
Turn off autocommit:
$doc = new couchDocument($client);
$doc->setAutocommit(false);
$doc->set( array('name'=>'Smith','firstname'=>'John') );
try {
$response = $client->storeDoc($doc);
$response_json['status'] = 'success';
$response_json['id'] = $response->id;
$response_json['rev'] = $response->rev;
Keep autocommit on and get the id and rev from the $doc after you set a property:
$doc = new couchDocument($client);
try {
$doc->set( array('name'=>'Smith','firstname'=>'John') );
$response_json['status'] = 'success';
$response_json['id'] = $doc->_id;
$response_json['rev'] = $doc->_rev;

Related

php rest API POST request returning null

I've created a REST API base on this tutorial - note that I am a newbie in php and REST...
Now, I am stuck when calling a POST request. The main return function is as follows:
// Requests from the same server don't have a HTTP_ORIGIN header
if (!array_key_exists('HTTP_ORIGIN', $_SERVER)) {
$_SERVER['HTTP_ORIGIN'] = $_SERVER['SERVER_NAME'];
}
try {
$API = new MyAPI($_REQUEST['request'], $_SERVER['HTTP_ORIGIN']);
$res = $API->processAPI();
echo $res; // contains my json as expected
return $res; // always empty string
} catch (Exception $e) {
echo "Exception: " . json_encode(Array('error' => $e->getMessage()));
}
EDIT
I've just tried something even simpler in the API caller method, namely following:
try {
$res = json_encode(Array('test' => "my message"));
// comment out one or the other to check output...
//echo $res;
return $res;
} catch (Exception $e) {
echo "Exception: " . json_encode(Array('error' => $e->getMessage()));
}
Result with echo is (the way I get responese is below... exact response is between # characters):
#{"test":"my message"}#
Result with return is
##
EDIT 2
Here is how I call the API from C#:
using (HttpClient client = new HttpClient()) {
JObject jo = new JObject();
jo.Add("usr", "username");
jo.Add("pwd", "password");
Uri url = new Uri(string.Format("{0}/{1}", RestUrl, "login"));
StringContent content = new StringContent(jo.ToString(), Encoding.UTF8, "application/json");
HttpResponseMessage response = await client.PostAsync(url, content);
bool isOk = response.StatusCode == System.Net.HttpStatusCode.OK;
// this is where I get the result from...
var res = response.Content.ReadAsStringAsync().Result;
}
I really don't understand this - could someone please explain in non-php expert terms??

Slim ignoring try catch block

I am using Slim to code a REST API, I have come upon a situation where I need to check if the date time entered by user is valid and thus came up with this code
$app->post('/test', function() use($app)
{
verifyRequiredParams(array('d_string'));
$response = array();
$d_string = $app->request->post('d_string');
try {
$datetime = datetime::createfromformat('d M Y H:i:s', $d_string);
$output = $datetime->format('d-M-Y H:i:s');
}
catch (Exception $e) {
$response["error"] = true;
$response["message"] = $e->getMessage();
echoRespnse(400,$response);
}
$response["error"] = false;
$response["message"] = "Converted Date";
$response['output'] = $output;
echoRespnse(200,$response);
});
It works fine when I enter a valid date time string like 11-Dec-2015 12:18 but if just for testing purpose I enter some random string, it gives 500 internal error instead of giving me any exception.
Why is it ignoring the try catch block???
Error Info
PHP Fatal error: Call to a member function format() on a non-object
DateTime::createFromFormat will not throw an exception if the provided time string is invalid, but will return a boolean false.
So you don't really need a try/catch block to accomplish this:
$datetime = \DateTime::createFromFormat('d M Y H:i:s', $d_string);
if (false === $datetime) {
// send your 400 response and exit
}
$output = $datetime->format('d-M-Y H:i:s');
// the rest of the code
If you really want to keep your try/catch block for various reasons, you can throw an exception yourself and catch it locally:
try {
$datetime = \DateTime::createFromFormat('d M Y H:i:s', $d_string);
if (false === $datetime) {
throw new \Exception('Invalid date.');
}
$output = $datetime->format('d-M-Y H:i:s');
} catch (\Exception $e) {
$response["error"] = true;
$response["message"] = $e->getMessage();
echoRespnse(400,$response);
}
But I don't see a really good reason to throw an exception just to catch it locally in this situation, so I would go with first solution.
If you want to show more detailed error messages, you can use DateTime::getLastErrors method.

Salesforce error: Element {}item invalid at this location

i am using the below code to connect to salesforce using php
require_once ('SforcePartnerClient.php');
require_once ('SforceHeaderOptions.php');
require_once ('SforceMetadataClient.php');
$mySforceConnection = new SforcePartnerClient();
$mySforceConnection->createConnection("cniRegistration.wsdl");
$loginResult = $mySforceConnection->login("username", "password.token");
$queryOptions = new QueryOptions(200);
try {
$sObject = new stdclass();
$sObject->Name = 'Smith';
$sObject->Phone = '510-555-5555';
$sObject->fieldsToNull = NULL;
echo "**** Creating the following:\r\n";
$createResponse = $mySforceConnection->create($sObject, 'Account');
$ids = array();
foreach ($createResponse as $createResult) {
print_r($createResult);
array_push($ids, $createResult->id);
}
} catch (Exception $e) {
echo $e->faultstring;
}
But the above code is connect to salesforce database.
But is not executing the create commands. it's giving me the below error message
Creating the following: Element {}item invalid at this location
can any one suggest me to overcome the above problem
MAK, in your sample code SessionHeader and Endpoint setup calls are missing
$mySforceConnection->setEndpoint($location);
$mySforceConnection->setSessionHeader($sessionId);
after setting up those, if you still see an issue, check the namespace urn
$mySforceConnection->getNamespace
It should match targetNamespace value in your wsdl
the value of $mySforceConnection should point to the xml file of the partner.wsdl.xml.
E.g $SoapClient = $sfdc->createConnection("soapclient/partner.wsdl.xml");
Try adding the snippet code below to reference the WSDL.
$sfdc = new SforcePartnerClient();
// create a connection using the partner wsdl
$SoapClient = $sfdc->createConnection("soapclient/partner.wsdl.xml");
$loginResult = false;
try {
// log in with username, password and security token if required
$loginResult = $sfdc->login($sfdcUsername, $sfdcPassword.$sfdcToken);
}
catch (Exception $e) {
global $errors;
$errors = $e->faultstring;
echo "Fatal Login Error <b>" . $errors . "</b>";
die;
}
// setup the SOAP client modify the headers
$parsedURL = parse_url($sfdc->getLocation());
define ("_SFDC_SERVER_", substr($parsedURL['host'],0,strpos($parsedURL['host'], '.')));
define ("_SALESFORCE_URL_", "https://test.salesforce.com");
define ("_WS_NAME_", "WebService_WDSL_Name_Here");
define ("_WS_WSDL_", "soapclient/" . _WS_NAME_ . ".wsdl");
define ("_WS_ENDPOINT_", 'https://' . _SFDC_SERVER_ . '.salesforce.com/services/wsdl/class/' . _WS_NAME_);
define ("_WS_NAMESPACE_", 'http://soap.sforce.com/schemas/class/' . _WS_NAME_);
$urlLink = '';
try {
$client = new SoapClient(_WS_WSDL_);
$sforce_header = new SoapHeader(_WS_NAMESPACE_, "SessionHeader", array("sessionId" => $sfdc->getSessionId()));
$client->__setSoapHeaders(array($sforce_header));
} catch ( Exception $e ) {
die( 'Error<br/>' . $e->__toString() );
}
Please check the link on Tech Thought for more details on the error.

Apache thrift: client timeout issues

I have some Apache Thrift (v.0.6.1) test application with perl-server and php-client.
The behaviour I cannot explain: If we call server-method with invalid argument we see the error in server-output, but php-client stays waiting the response infinitely.
Here are the sources of server:
sub new {
my $classname = shift;
my $self = {};
return bless($self,$classname);
}
sub DateToTimestamp
{
my ($self, $date) = #_;
my $result = CommonAPI::DateToTimestamp($date);
return $result;
}
eval {
my $handler = new RPCHandler;
my $processor = new RPCPerformanceTest::RPCPerformanceTestProcessor($handler);
my $serversocket = new Thrift::ServerSocket(9091);
my $forkingserver = new Thrift::ForkingServer($processor, $serversocket);
print "Starting the server...\n";
$forkingserver->serve();
print "done.\n";
}; if ($#) {
if ($# =~ m/TException/ and exists $#->{message}) {
my $message = $#->{message};
my $code = $#->{code};
my $out = $code . ':' . $message;
die $out;
} else {
die $#;
}
}
and client:
try {
$socket = new TSocket($server_host, $server_port);
$transport = new TBufferedTransport($socket, 1024, 1024);
$protocol = new TBinaryProtocol($transport);
$client = new RPCPerformanceTestClient($protocol);
$transport->open();
$start = microtime(true);
$result = $client->DateToTimestamp('071/26/2011 01:23:45');
var_dump($result);
} catch (Exception $e) {
echo 'Exception: <b>' . $e->getMessage() . '</b>';
}
Why is this happening? Is it my fault? Is it expected behavour?
The Thrift PHP library is a bit broken. You need to manually set the timeouts
E.g.
$socket = new TSocket('host', 9095);
$socket->setSendTimeout(60000);
$socket->setRecvTimeout(60000)
This happens often with protocols that do not supply message length: a client sends more data then the server expects and waits for the server to receive the data. The server receives some of the data, tries to parse it and fails. Now the server-side of the protocol is in errorneous state. If it continues to read the data, it may block. Most probably, the server-side has sent you some error response and is waiting at the same time for the client to receive the response, but that will never happen too.
This is my guess. The best strategy IMHO is to set a time-out for both client and server sockets.

Force error message to Zend Form Element

// Process the forms
if (($this->getRequest()->isPost())
&& ($this->getRequest()->isXmlHttpRequest())) {
// Initiate response
$status = false;
$msg = '';
$zf = null;
// Error test
$form->getElement('no')->addError('This is the error message');
if ($form->isValid($this->getRequest()->getPost())) {
// Everything is good
$status = true;
} else {
// Get the error messages
$zf = $form->getMessages();
}
// Setup the response
$result = json_encode(array('status' => $status,
'msg' => $msg,
'zf' => $zf));
$this->_helper->viewRenderer->setNoRender();
$this->_helper->layout()->disableLayout();
$this->getResponse()->setHeader('Content-Type', 'application/json');
$this->getResponse()->setBody($result);
return;
} else {
// Populate the form
}
As you can see, I've used $form->getElement('no')->addError('This is the error message'); to force error on the form element, but $form->getMessages(); would still return NULL. So, what should I do to force error on the selected form element?
I think you've got the get the ErrorMessages()
$form->getErrorMessages()
I've opened a bug report for this issue: http://framework.zend.com/issues/browse/ZF-11088. I'll update this question if there's any new progress.

Categories