CakePHP 3.6: json_encode maximum depth reached - php

I have an ajax request in my application which returns a json object:
public function getCustomerTransactions($customerid = null)
{
$this->viewBuilder()->setLayout(false);
$this->autoRender = false;
$selectedCustomerCompany = $this->request->getData('customer');
$selectedCustomer = TableRegistry::get('Customers')->find('all', [
'conditions' => ['Customers.company LIKE '=> $selectedCustomerCompany]
])->first();
$customerTransactions = TableRegistry::get('Transactions')->find('all', [
'conditions' => ['customer_id '=> $selectedCustomer->id, 'transaction_type_id ' => 1, 'invoice_id IS NULL']//,
]);
echo json_encode($customerTransactions);
}
But instead of 19 transactions it returns 11 and then this message (I can see it from network tab) :
Warning (512): Unable to emit headers. Headers sent in
file=/var/www/vhosts/domain/public_html/demo/app/src/Controller/InvoicesController.php line=508 [CORE/src/Http/ResponseEmitter.php, line
48]Code Context
0000BB">
style="color: #007700">if (
0000BB">Configure::read
007700">('debug')) {
class="code-highlight">
0000BB"> trigger_error
style="color: #007700">(
0000BB">$message, E_USER_WARNING);
style="color:
007700">} else {
none;">$response = object(Cake\Http\Response) {
'status' => (int) 200, 'contentType' =>
'text/html', 'headers' => [
'Content-Type' => [ [maximum depth reached] ] ],
'file' => null, 'fileRange' => [],
'cookies' => object(Cake\Http\Cookie\CookieCollection)
{}, 'cacheDirectives' => [], 'body' =>
''
} $maxBufferLength = (int) 8192 $file =
'/var/www/vhosts/domain/public_html/demo/app/src/Controller/InvoicesController.php'
$line = (int) 508 $message = 'Unable to emit headers. Headers
sent in
file=/var/www/vhosts/domain/public_html/demo/app/src/Controller/InvoicesController.php line=508'Cake\Http\ResponseEmitter::emit() -
CORE/src/Http/ResponseEmitter.php, line 48 Cake\Http\Server::emit() -
CORE/src/Http/Server.php, line 141
So I get this javascript error :
Uncaught SyntaxError: Unexpected token < in JSON at position 6922
Because there is html code in the response.
I tried to set the depth option in json_encode but I get the same results.
UPDATE
I ended up using:
if($this->request->is('ajax')){
Configure::write('debug', 0);
}
In the controller. But is this the correct way?

Related

Error: Failure when receiving data from the peer php GuzzleHttp

I'm trying to make post request and the post request is working but I'm not getting the response
$client = new \GuzzleHttp\Client(['headers' => ['Authorization' => 'Basic ' . 'token==']]);
$data = $client->post(
'url',
[
'form_params' => [
'address' => 'addreww',
'name' => 'Zia Sultan',
'phone_number' => '2136000000',
]
]
);
return $data;
What I'm getting in my insomnia
Error: Failure when receiving data from the peer
You're code is working, post method returns ResponseInterface, we need to fetch the content from it, we need to first fetch the StreamInterface by calling getBody() and chaining it will getContents() gives us the actual response. Keep debug mode On, to get find the exact error for Error: Failure when receiving data from the peer, and when this error occurs, share the entire trace with us
try {
$response = (new \GuzzleHttp\Client())->post(
'url',
[
'headers' => [
'Authorization' => 'Basic ' . 'token=='
],
'form_params' => [
'address' => 'addreww',
'name' => 'Zia Sultan',
'phone_number' => '2136000000',
],
// 'http_errors' => false, // Set to false to disable throwing exceptions on an HTTP protocol errors (i.e., 4xx and 5xx responses)
// 'debug' => true,
// 'connect_timeout' => 30 // number of seconds to wait while trying to connect to a server, Use 0 to wait indefinitely (the default behavior)
// 'read_timeout' => 10 // timeout to use when reading a streamed body, default value is default_socket_timeout in php.ini
// 'timeout' => 30 // the total timeout of the request in seconds. Use 0 to wait indefinitely (the default behavior).
]
);
return $response->getBody()->getContents();
} catch (Throwable $exception) {
print_r($exception);
}
I was returning the data only but I needed to return getBody() like this way
$data->getBody()
Its working now

PHP / Docusign - Verify HMAC signature on completed event

I'm trying to secure my callback url when completed event is triggered.
My Controller:
public function callbackSubscriptionCompleted(
int $subscriptionId,
DocusignService $docusignService,
Request $request
) {
$signature = $request->headers->get("X-DocuSign-Signature-1");
$payload = file_get_contents('php://input');
$isValid = $docusignService->isValidHash($signature, $payload);
if (!$isValid) {
throw new ApiException(
Response::HTTP_BAD_REQUEST,
'invalid_subscription',
'Signature not OK'
);
}
return new Response("Signature OK", Response::HTTP_OK);
}
My DocusignService functions:
private function createEnvelope(Company $company, Subscription $subscription, LegalRepresentative $legalRepresentative, Correspondent $correspondent, $correspondents) : array
{
// ...
$data = [
'disableResponsiveDocument' => 'false',
'emailSubject' => 'Your Subscription',
'emailBlurb' => 'Subscription pending',
'status' => 'sent',
'notification' => [
'useAccountDefaults' => 'false',
'reminders' => [
'reminderEnabled' => 'true',
'reminderDelay' => '1',
'reminderFrequency' => '1'
],
'expirations' => [
'expireEnabled' => 'True',
'expireAfter' => '250',
'expireWarn' => '2'
]
],
'compositeTemplates' => [
[
'serverTemplates' => [
[
'sequence' => '1',
'templateId' => $this->templateId
]
],
'inlineTemplates' => [
[
'sequence' => '2',
'recipients' => [
'signers' => [
[
'email' => $legalRepresentative->getEmail(),
'name' => $legalRepresentative->getLastname(),
'recipientId' => '1',
'recipientSignatureProviders' => [
[
'signatureProviderName' => 'universalsignaturepen_opentrust_hash_tsp',
'signatureProviderOptions' => [
'sms' => substr($legalRepresentative->getCellphone(), 0, 3) == '+33' ? $legalRepresentative->getCellphone() : '+33' . substr($legalRepresentative->getCellphone(), 1),
]
]
],
'roleName' => 'Client',
'clientUserId' => $legalRepresentative->getId(),
'tabs' => [
'textTabs' => $textTabs,
'radioGroupTabs' => $radioTabs,
'checkboxTabs' => $checkboxTabs
]
]
]
]
]
]
]
],
'eventNotification' => [
"url" => $this->router->generate("api_post_subscription_completed_callback", [
"subscriptionId" => $subscription->getId()
], UrlGeneratorInterface::ABSOLUTE_URL),
"includeCertificateOfCompletion" => "false",
"includeDocuments" => "true",
"includeDocumentFields" => "true",
"includeHMAC" => "true",
"requireAcknowledgment" => "true",
"envelopeEvents" => [
[
"envelopeEventStatusCode" => "completed"
]
]
]
];
$response = $this->sendRequest(
'POST',
$this->getBaseUri() . '/envelopes',
[
'Accept' => 'application/json',
'Content-Type' => 'application/json',
'Authorization' => 'Bearer ' . $this->getCacheToken()
],
json_encode($data)
);
}
public function isValidHash(string $signature, string $payload): bool
{
$hexHash = hash_hmac('sha256',utf8_encode($payload),utf8_encode($this->hmacKey));
$base64Hash = base64_encode(hex2bin($hexHash));
return $signature === $base64Hash;
}
I've created my hmac key in my Docusign Connect and i'm receiving the signature in the header and the payload but the verification always failed.
I've followed the Docusign documentation here
What's wrong ?
PS: Sorry for my bad english
Your code looks good to me. Make sure that you are only sending one HMAC signature. That way your hmacKey is the correct one.
As a check, I'd print out the utf8_encode($payload) and check that it looks right (it should be the incoming XML, no headers). Also, I don't think it should have a CR/NL in it at the beginning. That's the separator between the HTTP header and body.
Update
I have verified that the PHP code from the DocuSign web site works correctly.
The payload value must not contain either a leading or trailing newline. It should start with <?xml and end with >
I suspect that your software is adding a leading or trailing newline.
The secret (from DocuSign) ends with an =. It is a Base64 encoded value. Do not decode it. Just use it as a string.
Another update
The payload (the body of the request) contains zero new lines.
If you're printing the payload, you'll need to wrap it in <pre> since it includes < characters. Or look at the page source.
It contains UTF-8 XML such as
<?xml version="1.0" encoding="utf-8"?><DocuSignEnvelopeInformation xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.docusign.net/API/3.0"><EnvelopeStatus><RecipientStatuses><RecipientStatus><Type>Signer</Type><Email>larry#worldwidecorp.us</Email><UserName>Larry Kluger</UserName><RoutingOrder>1</RoutingOrder><Sent>2020-08-05T03:11:13.057</Sent><Delivered>2020-08-05T03:11:27.657</Delivered><DeclineReason xsi:nil="true" /><Status>Delivered</Status><RecipientIPAddress>5.102.239.40</RecipientIPAddress><CustomFields /><TabStatuses><TabStatus><TabType>Custom</TabType><Status>Active</Status><XPosition>223</XPosition><YPosition>744....
We've done some more testing, and the line
$payload = file_get_contents('php://input');
should be very early in your script. The problem is that a framework can munge the php://input stream so it won't work properly thereafter.
Note this page from the Symfony site -- it indicates that the right way to get the request body is:
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\ParameterBag;
$app->before(function (Request $request) {
$payload = $request->getContent();
hmac_verify($payload, $secret);
});
I would try to use the Symfony code instead of file_get_contents('php://input');

Amazon Pay SDK InvalidSignatureError

I'm integrating Amazon Pay php SDK from documentation, but getting this error.
Here's my php implementation code:
$amazonpay_config = array(
'public_key_id' => 'XXXXXXXX',
'private_key' => 'my_private_key_path',
'region' => 'US',
'sandbox' => true
);
$payload = array(
'webCheckoutDetails' => array(
'checkoutReviewReturnUrl' => 'https://www.example.com/review',
'checkoutResultReturnUrl' => 'https://www.example.com/result'
),
'storeId' => 'amzn1.application-oa2-client.XXXXXXXXX'
);
$headers = array('x-amz-pay-Idempotency-Key' => uniqid());
$requestResult = [
'error' => 1,
'msg' => 'Error. Can not create checkout session.',
'checkoutSession' => null,
'payloadSign' => null
];
$client = new Client($amazonpay_config);
$resultCheckOut = $client->createCheckoutSession($payload, $headers);
$resultSignPayload = $client->generateButtonSignature($payload);
if($resultCheckOut['status'] !== 201) {
return json_encode($requestResult, true);
}
else {
$requestResult = [
'error' => 0,
'msg' => null,
'checkoutSession' => json_decode($resultCheckOut['response']),
'payloadSign' => $resultSignPayload
];
return $requestResult;
}
Here's JS implementation code for generating Amazon Pay button.
amazon.Pay.renderButton('#amazon-pay-btn', {
// set checkout environment
merchantId: 'XXXXXXXX',
ledgerCurrency: 'USD',
sandbox: true,
checkoutLanguage: 'en_US',
productType: 'PayOnly',
placement: 'Cart',
buttonColor: 'Gold',
createCheckoutSessionConfig: {
payloadJSON: jsonResult['checkoutSession'],
signature: jsonResult['payloadSign'],
publicKeyId: 'XXXXXXXXXXX'
}
});
Couple of problems with the code, mainly that you aren't passing the payload and signature to the front-end correctly. For the payload, you're using jsonResult['checkoutSession'], while it should be jsonResult['payloadSign']. This doesn't contain the payload though but from the PHP code it's apparently the signature that you have put in there. The full code sample should more like this (not tested).
Back-end:
$headers = array('x-amz-pay-Idempotency-Key' => uniqid());
$requestResult = [
'error' => 1,
'msg' => 'Error. Can not create checkout session.',
'signature' => null,
'payload' => null
];
$client = new Client($amazonpay_config);
$resultCheckOut = $client->createCheckoutSession($payload, $headers);
$resultSignature = $client->generateButtonSignature($payload);
if($resultCheckOut['status'] !== 201) {
return json_encode($requestResult, true);
}
else {
$requestResult = [
'error' => 0,
'msg' => null,
'signature' => $resultSignature,
'payload' => $payload
];
return json_encode($requestResult);
}
Front-end:
amazon.Pay.renderButton('#amazon-pay-btn', {
// set checkout environment
merchantId: 'XXXXXXXX',
ledgerCurrency: 'USD',
sandbox: true,
checkoutLanguage: 'en_US',
productType: 'PayOnly',
placement: 'Cart',
buttonColor: 'Gold',
createCheckoutSessionConfig: {
payloadJSON: JSON.stringify(jsonResult['payload']),
signature: jsonResult['signature'],
publicKeyId: 'XXXXXXXXXXX'
}
});
I'm not sure how you're passing $requestResult back to the front-end, potentially there's some additional JSON encoding/decoding required to get the right string. To prevent a signature mismatch error, please make sure that the payload string used for the signature generation in the backend, and the payload string assigned to the 'payloadJSON' parameter match exactly (especially pay attention to whitespaces, escape characters, line breaks, etc.).
Two comments about this issue:
I have defined the payload as an string (that's the way current AmazonPay doc states - Link).
$payload = '{
"webCheckoutDetails": {
"checkoutReviewReturnUrl": "https://www.example.com/review",
"checkoutResultReturnUrl": "https://www.example.com/result"
},
"storeId": "amzn1.application-oa2-client.XXXXXXXXX"
}';
instead of array
$payload = array(
'webCheckoutDetails' => array(
'checkoutReviewReturnUrl' => 'https://www.example.com/review',
'checkoutResultReturnUrl' => 'https://www.example.com/result'
),
'storeId' => 'amzn1.application-oa2-client.XXXXXXXXX'
);
The signature was created, but when rendering the button and clicking on it I get the following error.
Error Message: Signature Dk4qznkoiTVqjcY8Yn1l0iLbsoIj2pEAHWVtgYrphLtFXR9BKhJJPD53It4qYOswS1T/STYMHRy5jtCHGqvLntDjuy0MrhkpoHTpYEtwdOqGHA2qk+QnSGV5LoYldQ/UkAxSG7m8s2iOr11q2sWxUjrk2M3fgzAIxDeZRjJYeAr97eGANYva3jtGDfM6cJdieInBM4dEWWxKqGIh6HxOrY5K/ga26494vAwZAGvXRhZG48FOVp/XCr0mbu6V5pkEOzRJSc+hN5WKAs/c49UsfKPx75Ce7QbaBCZZT1UiczfyYx/mBuZuysUlGmnXPhLOLTPw4+SIizH/pOQyClOQyw== does not match signedString AMZN-PAY-RSASSA-PSS dfff7a87b93cfa78685a233f2dd59e18ad0451b2e3a90af11e500fcc0ceee924 for merchant XXXXXXXX
I was some time till I realized that this was the reason of the error. Actually, while writing this, the new lines in the string were the reason. If string is only in one line, it works.
The button only needs the payload and the signed payload. The $client->createCheckoutSession is not needed. More over, the checkoutSessionId of the resultCheckOut is different from the one obtained when the checkoutReviewReturnUrl is called.

no such index [index: ] when trying to scroll with elasticsearch

Since I moved from 2.4 to 5.6, I have an error when using a scroll query :
$query = '{
"scroll" : "1m",
"scroll_id" : "'. $scrollId .'"
}';
$path = '/_search/scroll';
$responseArray = $this->sendQuery($index, $path, Request::GET, $query);
error :
CRITICAL - Uncaught PHP Exception Elastica\Exception\ResponseException: "no such index [index: ]" at /code/vendor/ruflin/elastica/lib/Elastica/Transport/Http.php line 179
Here the initial query I'm using :
$path = 'dataIndex/_search?scroll=1m';
$query = sprintf(
'{
"size" : 500,
"stored_fields": "_source"
}'
);
And how I call my scroll function
$hits = $this->getElasticNextScroll($this->dataIndex, $hits['_scroll_id']);
One of the solution I tried was to send the request with POST but I got another error :
CRITICAL - Uncaught PHP Exception Elastica\Exception\ResponseException: "String index out of range: 0" at /code/vendor/ruflin/elastica/lib/Elastica/Transport/Http.php line 179
EDIT SOLUTION :
the path '/_search/scroll' worked in 2.4 but doesn't work anymore in 5.3. You need to remove the first / : '_search/scroll'
specify what value is passed to $index and what is included in the Request :: GET function
Index {#9208
-originalName: null
-typeCache: []
#_name: "index_data"
#_client: Client {#9234
-indexCache: array:1 [
"index_data" => Index {#9208}
]
-stopwatch: Stopwatch {#157
...
And here the stack error I have :
[1] Elastica\Exception\ResponseException: no such index [index: ] at n/a in /code/vendor/ruflin/elastica/lib/Elastica/Transport/Http.php line 179
at Elastica\Transport\Http->exec(object(Request), array('connection' => array('config' => array('headers' => array(), 'curl' => array()), 'host' => '127.0.0.1', 'port' => '9200', 'logger' => false, 'ssl' => false, 'compression' => false, 'retryOnConflict' => '0', 'enabled' => true))) in /code/vendor/ruflin/elastica/lib/Elastica/Request.php line 193
at Elastica\Request->send() in /code/vendor/ruflin/elastica/lib/Elastica/Client.php line 674
at Elastica\Client->request('/_search/scroll', 'GET', '{ "scroll" : "1m", "scroll_id" : "DnF1ZXJ5VGhlbkZldGNoBAAAAAAAAAPfFnF2VnFBRzFWU0RTaTAwVVZLSl9UU2cAAAAAAAAD3RZxdlZxQUcxVlNEU2kwMFVWS0pfVFNnAAAAAAAAA-AWcXZWcUFHMVZTRFNpMDBVVktKX1RTZwAAAAAAAAPeFnF2VnFBRzFWU0RTaTAwVVZLSl9UU2c=" }', array(), 'application/json') in /code/vendor/friendsofsymfony/elastica-bundle/Elastica/Client.php line 50
at FOS\ElasticaBundle\Elastica\Client->request('/_search/scroll', 'GET', '{ "scroll" : "1m", "scroll_id" : "DnF1ZXJ5VGhlbkZldGNoBAAAAAAAAAPfFnF2VnFBRzFWU0RTaTAwVVZLSl9UU2cAAAAAAAAD3RZxdlZxQUcxVlNEU2kwMFVWS0pfVFNnAAAAAAAAA-AWcXZWcUFHMVZTRFNpMDBVVktKX1RTZwAAAAAAAAPeFnF2VnFBRzFWU0RTaTAwVVZLSl9UU2c=" }') in /code/src/AppBundle/Repository/ElasticSearch/BaseElasticSearchRepository.php line 22

Suitescript -- Unexpected error on using getSelectOptions

I'm trying to retrieve available options for shipping method for sales order form but I encountered an unexpected error in using getSelectOptions.
function get_select_options(datain)
{
var rec = nlapiCreateRecord(datain.recordType);
var field = rec.getField(datain.field);
var options = field.getSelectOptions();
return options;
}
And here's my code for calling the script.
$url = "https://rest.sandbox.netsuite.com/app/site/hosting/restlet.nl";
$client = new Client();
$authorization = [
'NLAuth nlauth_account='.getenv('NETSUITE_ACCOUNT'),
'nlauth_email='.getenv('NETSUITE_EMAIL'),
'nlauth_signature='.getenv('NETSUITE_PASSWORD'),
'nlauth_role='.getenv('NETSUITE_ROLE')
];
$response = $client->request('GET', $url,
'headers' => [
'Authorization' => implode(',', $authorization),
'Content-Type' => 'application/json'
],
'query' => [
'script' => '343',
'deploy' => '1',
'recordType' => 'salesorder',
'field' => 'shipmethod'
]
]);
return json_decode($response->getBody());
My record type and field seems to be correct as what I have read in the docs. I also followed some of the example codes that uses getSelectOptions, but I can't move on because of some unexpected/unknown error. I also tried to return only the record (rec) just to make sure that my PHP code is working.
GuzzleHttp\Exception\ServerException with message
'Server error: `GET https://rest.sandbox.netsuite.com/app/site/hosting/restlet.nl?script=343&deploy=1&recordType=salesorder&field=shipmethod`
resulted in a `500 Internal Server Error` response:
{"error" : {"code" : "UNEXPECTED_ERROR", "message" : "An unexpected error has occurred. Error ID: irc3j6d915k2asvrqbfhb" (truncated...) '

Categories