I'm writing a soap consumer in PHP for a ws written in Java (Jax ws). The webservice exports a function listRooms() that returns an array of the complex data type Room which contains an id (64 bit long) and a description (string). Now whenever I consume the webservice using SoapClient, the id is converted to float (as there are no 64 bit integers in PHP) and I want to avoid it. As I will need the room id to consume other web services I would rather avoid this implicit conversion to float, keeping it in a string.
Does anyone know how to solve this problem?
This might help:
The long overflows because ext/soap maps it to an int, and you're on a 32bit arch. You can easily fix that problem by using a custom type mapper to override the internal handling of {http://www.w3.org/2001/XMLSchema }long:
function to_long_xml($longVal) {
return '<long>' . $longVal . '</long>';
}
function from_long_xml($xmlFragmentString) {
return (string)strip_tags($xmlFragmentString);
}
$client = new SoapClient('http://acme.com/products.wsdl', array(
'typemap' => array(
array(
'type_ns' => 'http://www.w3.org/2001/XMLSchema',
'type_name' => 'long',
'to_xml' => 'to_long_xml',
'from_xml' => 'from_long_xml',
),
),
));
Also check to see exactly what you get back from the SOAP call, as per the manual add 'trace' and use getLastRequest:
<?php
$client = SoapClient("some.wsdl", array('trace' => 1));
$result = $client->SomeFunction();
echo "REQUEST:\n" . $client->__getLastRequest() . "\n";
?>
Other way to do it, is just using the float() function before the data to sent as a long type.
In the example below I'm use a stdclass object to sent as a parameter:
<?php
if ($index == "Your_longtype_Field"){
$a->$index = (float) $value;
} else {
$a->$index = $value;
}
?>
Related
Preconditions:
Programming language: PHP.
Serialization system: Apache avro
PHP library: https://github.com/wikimedia/avro-php
I send various messages via Apache kafka, each message has its own structure (an array with a specific set of keys) and is sent to a strictly defined topic, the data itself is encoded and decoded using Apache avro.
The problem is that the schema itself is transmitted along with the data, which is redundant in my case (Highload), there is no point in this since the client (the consumer of messages from Kafka) owns the schemas for each message structure (one structure - one Kafka topic).
Apparently, the current package https://github.com/wikimedia/avro-php is not suitable.
I'm looking for a ready-made solution - Avro encoder / decoder on PHP, which will allow not sending the schema itself along with the data every time, but substituting it on the client side (it will be stored as a file and substituted depending on the topic). It will save disk space and network traffic.
example of usage current solution:
<?php
require_once('../lib/avro.php');
$schemaJson = <<<_JSON
{"name":"member",
"type":"record",
"fields":[{"name":"foo", "type":"int"},
{"name":"bar", "type":"string"}]}
_JSON;
$item1 = ['foo' => 123, 'bar' => 'ktwop'];
$itemsForSerializing = [$item1];
$avroSchemaForWriter = \AvroSchema::parse($schemaJson);
$writeAvroStringIO = new \AvroStringIO();
$avroIODatumWriter = new \AvroIODatumWriter($avroSchemaForWriter);
$avroDataIOWriter = new \AvroDataIOWriter($writeAvroStringIO, $avroIODatumWriter, $avroSchemaForWriter);
foreach ($itemsForSerializing as $itemForSerializing) {
$avroDataIOWriter->append($itemForSerializing);
}
$avroDataIOWriter->close();
$encodedString = $writeAvroStringIO->string();
echo $encodedString . PHP_EOL . PHP_EOL;
// ACTUAL OUTPUT:
/*
Objavro.codenullavro.schema�{"type":"record","name":"member","fields":[{"name":"foo","type":"int"},{"name":"bar","type":"string"}]} �k����N�*��1�V��ktwop�k����N�*��1�V�
*/
// EXPECTED OUTPUT: ktwop�k����N�*��1�V�
$readAvroStringIO = new \AvroStringIO($encodedString);
$avroDataIOReader = new \AvroDataIOReader(
$readAvroStringIO, new \AvroIODatumReader($avroSchemaForWriter, $avroSchemaForWriter) // HERE I WANT TO USE SCHEMA FROM FILE ON CLIENT SIDE
);
echo "from binary string:" . PHP_EOL;
foreach ($avroDataIOReader->data() as $dataItem) {
echo var_export($dataItem, true) . PHP_EOL;
}
//OUTPUT:
/*
from binary string:
array (
'foo' => 123,
'bar' => 'ktwop',
)
*/
This should do it.
$io = new AvroStringIO();
$writer = new AvroIODatumWriter($schema);
$encoder = new AvroIOBinaryEncoder($io);
$writer->write($data, $encoder);
$io->string();
I have been working with an API that uses tokens for authentication. I am using PHP's SoapClient class to login to said API and retrieve the tokens I need to make additional requests..
The problem is that the API should return base64 string tokens, but in PHP, they are not being dealt with as bas64 strings.. I get a string that looks like this:
ç$P%’™‹2E‡ºË>Šo_ÑÒúé±N5Tá#=œã
Instead of a base64 string that looks like this:
ERy/R5ycTG0sbRyH9KeMGpi9kPr6kROyaarFYgsPEOU=
Note: These 2 strings are not actually related, as I could not get php to display the base64 representation of that 1st string. The base64 string I listed as the 2nd string came from a valid soapUI response.
So I have confirmed with soapUI, that I the tokens do in fact come over as base64 strings, but I cannot get PHP to use them as strings for additional requests. I have tried doing base64_decode and base64_encode on the strings, along with a bunch of other encodings/decodings, but none of them have worked so far.
Any ideas as to what is going on here, and how I might be able to use the data the way I need?
Edit: Here is the code I use to get the token data. It's the DAT api if that helps.
$wsdlDat = "http://someurl.com:8000/wsdl/someWSDL.wsdl";
$soapOptions = array( 'loginId' => $userName, 'password' => $userPassword, 'thirdPartyId' => 'KEFKA_TMS', 'trace' => 1 );
$this->datClient = new SoapClient( $wsdlDat , $soapOptions );
$creds = array( 'loginId' => $userName, 'password' => $userPassword, 'thirdPartyId' => 'KEFKA_TMS' );
$loginOptions['loginOperation'] = $creds;
$this->token = $this->datClient->Login($loginOptions);
$this->token = datObjectToArray($this->token); // TURN STD CLASS OBJ TO ARRAY
$token = $this->token['loginResult']['loginSuccessData']['token']['primary'];
$token2 = $this->token['loginResult']['loginSuccessData']['token']['secondary'];
$exp = $this->token['loginResult']['loginSuccessData']['expiration'];
I'm currently running into a massive wall due to a problem i cannot seem to solve.
The problem is that, when you issue a payment through the Facebook payment platform (facebook javascript sdk), it sends data to your callback page, which should handle the payment on the background.
This all works decent, but there is 1 problem: The order ID that facebook uses is a 64bit ID, and my server is a 32bits server, thus it loses precision on the ID when it gets saved to a variable in the callback page. This ultimately results in not being able to get a proper order_ID in the end, because it cannot save the ID.
The issue has been described on several pages on this forum, for example:
facebook credit callback, order_id changes format changes after moving to a new server
and
PHP: Converting a 64bit integer to string
Yet, on both pages there is no solution to the problem, and i cannot seem to fix this myself.
I have tried to convert the json data that facebook sends to my callback page into string data instead of an array with integers (this happens in the basic code provided by facebook), but i just cannot get this to work.
Seeing that others have overcome this problem (without having to migrate everything to a 64bits server), i am wondering how.
Is anyone able to shine a light on this subject?
Edit:
I have tried converting to string, the standard facebook code that gets called to decode the json data (code provided by facebook):
$request = parse_signed_request($_POST['signed_request'], $app_secret);
This calls the function parse_signed_request, which does:
function parse_signed_request($signed_request, $secret) {
list($encoded_sig, $payload) = explode('.', $signed_request, 2);
$sig = base64_url_decode($encoded_sig);
$data = json_decode(base64_url_decode($payload), true);
if (strtoupper($data['algorithm']) !== 'HMAC-SHA256') {
error_log('Unknown algorithm. Expected HMAC-SHA256');
return null;
}
// check sig
$expected_sig = hash_hmac('sha256', $payload, $secret, $raw = true);
if ($sig !== $expected_sig) {
error_log('Bad Signed JSON signature!');
return null;
}
return $data;
}
This function decodes the encrypted json data from facebook (using the app secret) and should decode the json data to a PHP array.
That function uses the following function (the exact:
function base64_url_decode($input) {
return base64_decode(strtr($input, '-_', '+/'));
}
Now, the above code results in the order ID not being saved properly, and it loses its precision, resulting in an id like: 4.8567130814993E+14
I have tried to use the following function to somehow decode the json data into a string (so the 64bit integer ID does not lose its precision), but to no avail:
function largeint($rawjson) {
$rawjson = substr($rawjson, 1, -1);
$rawjson = explode(',' , $rawjson);
array_walk($rawjson, 'strfun');
$rawjson = implode(',', $rawjson);
$rawjson = '{' . $rawjson . '}';
$json = json_decode($rawjson);
return $json;
}
function strfun(&$entry, $key) {
$data = explode(':', $entry);
if (FALSE === strpos($data[1], '"')) {
$data[1] = '"' . $data[1] . '"';
$entry = implode(':', $data);
}
}
Edit (Eugenes answer):
If i were to try modifying the JSON data before i use json_decode to make it a php variable, i should be using the preg_replace function?
Below is an example of the initial JSON data that gets sent to the callback page to initiate the payment process.
Here you can already see what the problem is (this is after using json_decode, the id and other data lose their precision). The ID's are modified to not reflect any real data.
If you compare the buyer ID on the top and user id on the bottom, you can see precision is lost.
Array
(
[algorithm] => HMAC-SHA256
[credits] => Array
(
[buyer] => 1.0055555551318E+14
[receiver] => 1.0055555551318E+14
[order_id] => 5.2555555501665E+14
[order_info] => {"item_id":"77"}
[test_mode] => 1
)
[expires] => 1358456400
[issued_at] => 1358452270
[oauth_token] => AAAH4s2ZCCEMkBAPiGSNsmj98HNdTandalotmoredata
[user] => Array
(
[country] => nl
[locale] => nl_NL
[age] => Array
(
[min] => 21
)
)
[user_id] => 100555555513181
)
Edit #3:
I have tried the following to make all the integers in the JSON data seen as strings, but that results in an error from the facebook platform. It does however change the integers to a string, so i do not lose precision (too bad nothing else works now xD)
preg_replace('/([^\\\])":([0-9]{10,})(,|})/', '$1":"$2"$3', $a)
Which version of PHP are you running?
If you are running a version of PHP that supports the JSON "JSON_BIGINT_AS_STRING" option, that may be your answer. You may have to modify their library wherever json_decode is being used to add that option. See http://php.net/manual/en/function.json-decode.php
If your PHP version does not support JSON_BIGINT_AS_STRING, then your options are limited to:
The hacky option: Do some kind of regex operation on the JSON string as it comes back from the FB API and wrap that big ints in double-quotes, so that they decode as a string and not a big int.
The ideal option: Bite the bullet and migrate to a 64 bit environment. It will save you from a lot of headaches in the long run.
I can send function arguments to a SOAP client in PHP like this (searchLinks is a method name):
$client = new SoapClient("https://linksearch.api.cj.com/wsdl/version2/linkSearchServiceV2.wsdl", array('trace'=> true));
$results = $client->searchLinks(array("developerKey" => $developerKey,
"token" => '',
"websiteId" => $websiteId,
"advertiserIds" => 'joined'));
If I want to do the same thing in Python, how can I do this? This is the present code:
server=WSDL.Proxy(url)
results=server.searchLinks({'developerkey':dev_key,'token':'','websiteId':website_id,'advertiserIds':'joined'})
When I try to run this Python script, it throws errors. Why is it not taking function parameters like in PHP?
Which library are you using,
Assuming that you are using SOAPpy, You can do .
#!/usr/bin/python
import SOAPpy
url= 'https://linksearch.api.cj.com/wsdl/version2/linkSearchServiceV2.wsdl'
proxy = SOAPpy.WSDL.Proxy(url)
results=proxy.searchLinks({'developerkey': 'dev_key','token':'','websiteId': 'website_id','advertiserIds':'joined'})
I am creating a 3D Secure PHP Project. I am having a rather bizzare issue in that the "MD" code is going missing when re-submitting the Array of data
My code is as follows :
$paRes = $_REQUEST['PaRes'];
$md = $_REQUEST['MD'];
require "payment_method_3d.php";
x_load('cart','crypt','order','payment','tests');
/*
* For Debugging Purposes
* Only.
echo "The Value Of PaRes is : ";
echo $paRes;
*/
$soapClient = new SoapClient("https://www.secpay.com/java-bin/services/SECCardService?wsdl");
$params = array (
'mid' => '',
'vpn_pswd' => '',
'trans_id' => 'TRAN0095', // Transaction ID MUST match what was sent in payment_cc_new file
'md' => $md,
'paRes' => $paRes,
'options' => ''
);
It seems that the $_REQUEST['MD'] string seems to go missing AFTER the soap call. Although I am having difficulty print this out to the screen. The strange thing is the $paRes variable works without issue.
Any ideas why this would be the case?
Check your case. PHP array keys are case sensitive. From this little bit of code it looks as if the request variable may be 'md' instead of 'MD'.
Try $md = $_REQUEST['md'];
PHP array statements are case sensitive, so this should work:....
$md = $_REQUEST['md'];
Thanks for your responses guys.
What was happening was the include page was sitting in front of the request methods and causing issues loading the REQUEST methods to the page.