GetLowestPricedOffersForSKU failed processing arguments - amazon-mws

I have a slight issue when trying to call GetLowestPricedOffersForSKU, I get the response :
Failed processing arguments of org.jboss.resteasy.spi.metadata
I can call other functions in the Product Api and they work fine, just get the above error on this function.
I have looked round the net for the answer but can't find anything that is related to this, does anybody have any idea why I'm getting this ?
By the way it all works fine in the MWS Scratchpad !

Posting in case anyone else comes to this and is as confused as I was. There is a fundamental difference with how nearly all Amazon MWS requests work except this particular one. All other requests technically accept the parameters as query parameters instead of POST data. The scratchpad even suggests this is how it is actually working (although the MWS Scratchpad actually sends the data as Post Data Fields also).

MWS needs the POST data passed as form params instead of as a query string for some operations. Otherwise, it pukes a Failed processing arguments of org.jboss.resteasy.spi.metadata style 400 Bad Request error for some operations such as this one (GetMyFeesEstimate is another that suffers from this).
For instance, if you did the following POST request in Guzzle 6 then you'd likely get the error:
$response = $client->request('POST', 'https://mws.amazonservices.com/Products/2011-10-01/?AWSAccessKeyId=YOURAWSACCESSKEY&Action=GetLowestPricedOffersForASIN&SellerId=YOURSELLERID&MWSAuthToken=amzn.mws.fghsffg-4t44e-hfgh-dfgd-zgsdbfe5erg&SignatureVersion=2&Timestamp=2017-07-09T15%3A45%3A18%2B00%3A00&Version=2011-10-01&Signature=bCasdxXmYDCasdaXBhsdgse4pQ6hEbevML%2FJvzdgdsfdy2o%3D&SignatureMethod=HmacSHA256&MarketplaceId=ATVPDKIKX0DER&ASIN=B007EZK19E');
To fix this you'd submit it as form data as in this Guzzle 6 example:
$response = $client->request('POST', 'https://mws.amazonservices.com/Products/2011-10-01', [
'form_params' => [
'AWSAccessKeyId' => 'YOURAWSACCESSKEY',
'Action' => 'GetLowestPricedOffersForASIN',
'SellerId' => 'YOURSELLERID',
'MWSAuthToken' => 'amzn.mws.fghsffg-4t44e-hfgh-dfgd-zgsdbfe5erg',
'SignatureVersion' => 2,
'Timestamp' => '2017-07-09T15%3A45%3A18%2B00%3A00',
'Version' => '2011-10-01',
'Signature' => 'bCasdxXmYDCasdaXBhsdgse4pQ6hEbevML%2FJvzdgdsfdy2o%3D',
'SignatureMethod' => 'HmacSHA256',
'MarketplaceId' => 'ATVPDKIKX0DER',
'ASIN' => 'B007EZK19E',
]
]);

This code worked for me. Hope it will help someone.
<?php
require_once('.config.inc.php');
// More endpoints are listed in the MWS Developer Guide
// North America:
$serviceUrl = "https://mws.amazonservices.com/Products/2011-10-01";
// Europe
//$serviceUrl = "https://mws-eu.amazonservices.com/Products/2011-10-01";
// Japan
//$serviceUrl = "https://mws.amazonservices.jp/Products/2011-10-01";
// China
//$serviceUrl = "https://mws.amazonservices.com.cn/Products/2011-10-01";
$config = array (
'ServiceURL' => $serviceUrl,
'ProxyHost' => null,
'ProxyPort' => -1,
'ProxyUsername' => null,
'ProxyPassword' => null,
'MaxErrorRetry' => 3,
);
$service = new MarketplaceWebServiceProducts_Client(
AWS_ACCESS_KEY_ID,
AWS_SECRET_ACCESS_KEY,
APPLICATION_NAME,
APPLICATION_VERSION,
$config);
// #TODO: set request. Action can be passed as MarketplaceWebServiceProducts_Model_GetLowestPricedOffersForSKU
$request = new MarketplaceWebServiceProducts_Model_GetLowestPricedOffersForSKURequest();
$request->setSellerId(MERCHANT_ID);
$request->setMWSAuthToken(MWSAUTH_TOKEN);
$request->setMarketplaceId(MARKETPLACE_ID);
$request->setSellerSKU($sellerSKU);
$request->setItemCondition($ItemCondition);
// object or array of parameters
invokeGetLowestPricedOffersForSKU($service, $request);
function invokeGetLowestPricedOffersForSKU(MarketplaceWebServiceProducts_Interface $service, $request)
{
try {
$response = $service->GetLowestPricedOffersForSKU($request);
echo ("Service Response\n");
echo ("=============================================================================\n");
$dom = new DOMDocument();
$dom->loadXML($response->toXML());
$dom->preserveWhiteSpace = false;
$dom->formatOutput = true;
echo $dom->saveXML();
echo("ResponseHeaderMetadata: " . $response->getResponseHeaderMetadata() . "\n");
} catch (MarketplaceWebServiceProducts_Exception $ex) {
echo("Caught Exception: " . $ex->getMessage() . "\n");
echo("Response Status Code: " . $ex->getStatusCode() . "\n");
echo("Error Code: " . $ex->getErrorCode() . "\n");
echo("Error Type: " . $ex->getErrorType() . "\n");
echo("Request ID: " . $ex->getRequestId() . "\n");
echo("XML: " . $ex->getXML() . "\n");
echo("ResponseHeaderMetadata: " . $ex->getResponseHeaderMetadata() . "\n");
}
}
?>

As #eComEvoFor stated, for this particularly method, Amazon demands you specify the params in the body of the request. In node.js using axios library you can do this:
const paramsSorted = {}
Object.keys(params)
.sort()
.forEach((key) => {
paramsSorted[key] = params[key]
})
const data = new URLSearchParams(paramsSorted)
url = urljoin(this.marketplace.url, this.api, this.api.Version)
const response = await axios.post(url, data)

Related

save mathod in database cause Array to string conversion error in laravel

when I execute custom command with
php artisan query:all
every thing is good except error shown in console the error is
Array to string conversion
and the data is stored to database I did not understand the cause of this error and it's hidden when hide save to database method
the code of my service which the problem cause inside it is
<?php
namespace App\Services;
use Carbon\Carbon;
use GuzzleHttp\Client;
use App\Models\weatherStatus;
use Illuminate\Support\Collection;
class ApixuService
{
public function query(string $apiKey, Collection $cities): Collection
{
$result = collect();
$guzzleClient = new Client([ //create quzzle Client
'base_uri' => 'http://api.weatherstack.com'
]);
foreach ($cities as $city) {
$response = $guzzleClient->get('current', [
'query' => [
'access_key' => $apiKey,
'query' => $city->name,
]
]);
$response = json_decode($response->getBody()->getContents(), true); //create json from $response
$status = new weatherStatus(); //create weatherStatus object
//adding prameters
$status->city()->associate($city);
$status->temp_celsius = $response['current']['temperature'];
$status->status = $response['current']['weather_descriptions'];
$status->last_update = Carbon::createFromTimestamp($response['location']['localtime_epoch']);
$status->provider = 'weatherstack.com';
//save prameters
$status->save();
$result->push($status);
}
return $result;
}
}
So you can find some clarity in what you are trying to save, do the following:
$response = json_decode($response->getBody()->getContents(), true);
dd($response);
dd() will dump all the data from the $response and exist the script.
One of the values you are trying to save is an array. The field you are trying to save accepts a string and not array.

how to send emails with PHPmailer from WordPress Rest API end point

function my_send_email($name,$email, $current_user, $status, $subject, $Message) {
//most of the code here is from https://github.com/PHPMailer/PHPMailer/tree/master/examples
require_once ABSPATH . WPINC . '/class-phpmailer.php';
require_once ABSPATH . WPINC . '/class-smtp.php';
// build message body`enter code here`
$body = '
<html>
<body>
<h1>My Email</h1>
</body>
</html>
';
try {
//Create a new PHPMailer instance
$mail = new PHPMailer;
//Tell PHPMailer to use SMTP
$mail->isSMTP();
//Enable SMTP debugging
$mail->SMTPDebug = 2;
//Ask for HTML-friendly debug output
$mail->Debugoutput = 'html';
//Set the hostname of the mail server
$mail->Host = "mail.example.com";
//Set the SMTP port number - likely to be 25, 465 or 587
$mail->Port = 25;
//Whether to use SMTP authentication
$mail->SMTPAuth = true;
//Username to use for SMTP authentication
$mail->Username = "contact#example.com";
//Password to use for SMTP authentication
$mail->Password = "1234";
//Set who the message is to be sent from
$mail->setFrom('contact#example.com', 'sender_name');
//Set an alternative reply-to address
$mail->addReplyTo('alternative_contact#example.com', 'alternative_contact_name');
//Set who the message is to be sent to
$mail->addAddress($email, $name);
//Set the subject line
$mail->Subject = 'PHPMailer SMTP test';
//Read an HTML message body from an external file, convert referenced images to embedded,
//convert HTML into a basic plain-text alternative body
//$mail->msgHTML(file_get_contents(dirname(__FILE__) .'/contents.html'));
$mail->MsgHTML($body);
//Replace the plain text body with one created manually
$mail->AltBody = 'This is a plain-text message body';
$success=$mail->send();
//send the message, check for errors
if ($success) {
return array('mailError' => false, 'message' => 'email sent! ' . $mail->ErrorInfo , 'body'=>$body);
} else {
return array('mailError' => true, 'message' => 'email error! ' . $mail->ErrorInfo , 'body'=>$body);
}
} catch (phpmailerException $e) {
return array('mailError' => false, 'message' => 'email error! ' . $e->errorMessage() , 'body'=>$body); //Pretty error messages from PHPMailer
} catch (Exception $e) {
return array('mailError' => false, 'message' => 'email error! ' . $e->getMessage() , 'body'=>$body); //Boring error messages from anything else!
}
}
function my_register_endpoints(){
register_rest_route(
'my_namespace/v1',
'/abc/',
array(
'methods' => 'POST',
'callback' => 'my_end_point',
'args' => array(
.....
),
'permission_callback' => function (WP_REST_Request $request) {
if(!is_user_logged_in()){
.....
}
return true;
}
)
);
}
add_action('rest_api_init','my_register_endpoints');
//endpoint
function my_end_point(WP_REST_Request $request){
global $current_user;
$sender = wp_get_current_user();
$shortMsg=$request['shortMessage'];
$subject="Some text";
$email_resualt=my_send_email("reciver_name","reciver_email",$sender,$status,$subject,$shortMsg);
if($email_resualt['mailError']==false){
process.. $itemes, $item ..
$message='email sent!';
return array('message' => $message,'items' => $items, 'item'=>$item);
} else {
return new WP_Error('email error',__('some message','email-error'),$request['id']);
}
}
I am using angularJS $http.post to call the API end point, The emails are sent and I can see them on my inbox, but for some reason I am getting back undefined response:
Related errors on Chrome console:
1) SyntaxError: Unexpected token S in JSON at position 0
2) TypeError: Cannot read property 'message' of undefined
I use response.message in my client side code but as I stated above but as the response is empty I am getting errors.
I have other end points in my WordPress PHP code that looks the same but doesn't include send emails with PHPmailer and works fine. and even this end point without the send email functionality was also working fine.
I tried to debug it for two days but still I am not sure where the issue in my code?
I found what the issue was, In my send email function I had the lines:
//Enable SMTP debugging
$mail->SMTPDebug = 2;
$mail->Debugoutput = 'html';
And appears that because debugging was turned on the response from my end point was to match for angular to handle after I commented these two lines the response was well structured for for angular to be able to parse it.
The hint to solve it was in the following post Syntax error: Unexpected number at Object.parse, PHP to AngularJS

How to pass data into a Listener when using Guzzle?

I am using Guzzle 3.8.1 with CakePHP 2.5.6 and I am making a call to the Box API. I would like to be able to refresh my access token when it expires. The issue I am encountering is that I may be using any one of N possible access tokens and I want to be able to use the $account_id that is in scope for the function I am defining this in. I don't see how I can pass it into the Listener defined function, since I am not calling that myself. I do see that the expired access_token exists in the $event variable, but I would have to locate it and then parse it from the header that I am passing to Box. I think I could add a custom header containing the account_id, but that seems like a bad way to approach the problem. Can I somehow specify a variable in the request that wouldn't be added as part of the call to Box? Any suggestions are much appreciated, thanks!
`
public function get_folder_list ($account_id = null, $parent_folder_id = null) {
// Get account
$this->Account = ClassRegistry::init('Account');
$account = $this->Account->findById($account_id);
$this->Account->log($account);
// If account doesn't exist, throw error
if(empty($account)) {
throw new NotFoundException(__('Account id not found: ' . $account_id));
}
// Call Box for folder list
$box_url = "https://api.box.com/2.0/folders/";
if (empty($parent_folder_id)) {
$box_url .= "0";
} else {
$box_url .= $parent_folder_id;
}
$this->Account->log($box_url);
$bearer = 'Bearer ' . $account['Account']['access_token'];
$client = new Guzzle\Http\Client();
$client->getEventDispatcher()->addListener('request.error', function(Event $event) {
if ($event['response']->getStatusCode() == 401) {
$Account = new Account;
$Account->log($event);
$Box = new BoxLib;
$account = $Box->refresh_token($account_id);
$bearer = 'Bearer ' . $account['Account']['access_token'];
$request = $client->get($box_url, array('Authorization' => $bearer));
$event['response'] = $newResponse;
$event->stopPropagation();
}
});
$request = $client->get($box_url, array('Authorization' => $bearer));
try {
$response = $request->send();
} catch (Guzzle\Http\Exception\BadResponseException $e) {
// HTTP codes 4xx and 5xx throw BadResponseException
$this->Account->log('Service exception!');
$this->Account->log('Uh oh! ' . $e->getMessage());
$this->Account->log('HTTP request URL: ' . $e->getRequest()->getUrl() . "\n");
$this->Account->log('HTTP request: ' . $e->getRequest() . "\n");
$this->Account->log('HTTP response status: ' . $e->getResponse()->getStatusCode() . "\n");
$this->Account->log('HTTP response: ' . $e->getResponse() . "\n");
}
$this->Account->log($response->json());
$json = $response->json();
$folder_list = array();
foreach ($json['item_collection']['entries'] as $folder) {
$folder_list[$folder['id']] = $folder['name'];
}
//$this->Account->log($folder_list);
return $folder_list;
}
`

How to get MIME type of a file in PHP 5.5?

I am using mime_content_type() in PHP 5.5 to get a MIME type, but it throws fatal: error function not found.
How can I achieve this on PHP 5.5?
Make use of the finfo() functions.
A simple illustration:
<?php
$finfo = finfo_open(FILEINFO_MIME_TYPE);
echo finfo_file($finfo, "path/to/image_dir/image.gif");
finfo_close($finfo);
OUTPUT :
image/gif
Note : Windows users must include the bundled php_fileinfo.dll DLL file in php.ini to enable this extension.
I've spent too much time trying to get the finfo functions to work, properly. I finally just ended up creating my own function to match the file extension to any array of mime types. It's not a full-proof way of assuring that the files are truly what the extension denotes them to be, but that problem can be mitigated by how you process I/O of said files on your server(s).
function mime_type($file) {
// there's a bug that doesn't properly detect
// the mime type of css files
// https://bugs.php.net/bug.php?id=53035
// so the following is used, instead
// src: http://www.freeformatter.com/mime-types-list.html#mime-types-list
$mime_type = array(
"3dml" => "text/vnd.in3d.3dml",
"3g2" => "video/3gpp2",
"3gp" => "video/3gpp",
"7z" => "application/x-7z-compressed",
"aab" => "application/x-authorware-bin",
"aac" => "audio/x-aac",
"aam" => "application/x-authorware-map",
"aas" => "application/x-authorware-seg",
"abw" => "application/x-abiword",
"ac" => "application/pkix-attr-cert",
"acc" => "application/vnd.americandynamics.acc",
"ace" => "application/x-ace-compressed",
"acu" => "application/vnd.acucobol",
"adp" => "audio/adpcm",
"aep" => "application/vnd.audiograph",
"afp" => "application/vnd.ibm.modcap",
"ahead" => "application/vnd.ahead.space",
"ai" => "application/postscript",
"aif" => "audio/x-aiff",
"air" => "application/vnd.adobe.air-application-installer-package+zip",
"ait" => "application/vnd.dvb.ait",
"ami" => "application/vnd.amiga.ami",
"apk" => "application/vnd.android.package-archive",
"application" => "application/x-ms-application",
// etc...
// truncated due to Stack Overflow's character limit in posts
);
$extension = \strtolower(\pathinfo($file, \PATHINFO_EXTENSION));
if (isset($mime_type[$extension])) {
return $mime_type[$extension];
} else {
throw new \Exception("Unknown file type");
}
}
Edit:
I'd like to address Davuz's comment (since it keeps getting up-voted) and remind everyone that I put in the pseudo disclaimer at the top that this isn't "full-proof." So, please keep that in mind when considering the approach I've offered in my answer.
mime_content_type() is not deprecated and works fine.
Why is mime_content_type() deprecated in PHP?
http://php.net/manual/en/function.mime-content-type.php
As of PHP 5.3, it's even built-in.
$finfo = finfo_open(FILEINFO_MIME_TYPE); should do it.
Taken from the php.net docs. Your function is deprecated and probably already removed.
http://www.php.net/manual/en/function.finfo-file.php
You should understand that file_get_contents will upload whole file to the memory, it is not good way to get only mime type. You don't need to use buffer method and file_get_contents function in this case.
To prevent any errors and warnings, better do like this.
$filename = 'path to your file';
if (class_exists('finfo')) {
$finfo = new finfo(FILEINFO_MIME_TYPE);
if (is_object($finfo)) {
echo $finfo->file($filename);
}
} else {
echo 'fileinfo did not installed';
}
Also you should know $finfo->file will throw PHP Warning if it fail.
If fileinfo is not installed properly, and you have a fresh version of PHP, you can get mime type from headers.
You can use cURL to get mime type from headers.
$ch = curl_init();
curl_setopt_array($ch, array(
CURLOPT_HEADER => true,
CURLOPT_NOBODY => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_SSL_VERIFYHOST => false,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_MAXREDIRS => 1,
CURLOPT_URL => $link)
);
$headers = curl_exec($ch);
curl_close($ch);
if (preg_match('/Content-Type:\s(.*)/i', $headers, $matches)) {
echo trim($matches[1], "\t\n\r");
}else {
echo 'There is no content type in the headers!';
}
Also you can use get_headers function, but it more slow than cURL request.
$url = 'http://www.example.com';
$headers = get_headers($url, 1);
echo $headers['Content-Type'];
Get the image size using:
$infFil=getimagesize($the_file_name);
and
echo $infFil["mime"]
The getimagesize returns an associative array which have a MIME key and obviously the image size too
I used it and it works
I use the MimeTypeTool from Bat (https://github.com/lingtalfi/Bat)
It uses fileinfo if available, and defaults back to an "extension => mime type" mapping otherwise.
This is the best solution I found by combining two very good posts
// Thanks to http://php.net/manual/en/function.mime-content-type.php#87856
function getMimeContentType($filename, $ext)
{
if(!function_exists('mime_content_type'))
{
if($mime_types = getMimeTypes())
{
if (array_key_exists($ext, $mime_types))
{
return $mime_types[$ext];
}
elseif (function_exists('finfo_open'))
{
$finfo = finfo_open(FILEINFO_MIME);
$mimetype = finfo_file($finfo, $filename);
finfo_close($finfo);
return $mimetype;
}
}
return 'application/octet-stream';
}
return mime_content_type($filename);
}
// Thanks to http://php.net/manual/en/function.mime-content-type.php#107798
function getMimeTypes()
{
$url = 'http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types';
$mimes = array();
foreach(#explode("\n",#file_get_contents($url)) as $x)
{
if(isset($x[0]) && $x[0]!=='#' && preg_match_all('#([^\s]+)#', $x, $out) && isset($out[1]) && ($c = count($out[1])) > 1)
{
for($i=1; $i < $c; $i++)
{
$mimes[$out[1][$i]] = $out[1][0];
}
}
}
return (#sort($mimes)) ? $mimes : false;
}
Use it link this:
$filename = '/path/to/the/file.pdf';
$ext = strtolower(array_pop(explode('.',$filename)));
$content_type = getMimeContentType($filename, $ext);
Will continue to work even if the mime_content_type function is no longer supported in php.

Joomla Component error - Fatal error

I have installed a ticket module on my Joomla website, I get the following error when a ticket is submitted
Fatal error: Call to undefined method JRegistry::getValue() in /home/xboxfifa/public_html/HD/components/com_jtaghelpdesk/controller.php on line 300
function mailme($formData){
$version = new JVersion();
$body = "A new inquiry has been recieved: <br /> Name : ". $formData['inqName']. "<br /> Email ID : ". $formData['inqEmail']. "<br/> Message : ".$formData['inqMessage'] ;
$mailer =& JFactory::getMailer();
$config =& JFactory::getConfig();
if($version->RELEASE==3.0)
{
$recipient = array(
$config->get('mailfrom'),
$config->get('fromname'));
}else
{
$recipient = array(
$config->getValue( 'config.mailfrom' ),
$config->getValue( 'config.fromname' ));
}
$mailer->addRecipient($recipient);
$subject=$formData['inqSubject'];
$mailer->setSubject($subject);
$mailer->isHTML(true);
$mailer->Encoding = 'base64';
$mailer->setBody($body);
$send =& $mailer->Send();
if ( $send !==true )
{ $msg = 'Reply not Sent!';
} else
{
$msg = 'Reply Sent Successfully!';
}
}
If anyone could help me I would appreciate it.
JRegistry::getvalue() was removed in Joomla 3.x so make sure you use JRegistry::get() instead.
As for your version compare, you should use this:
if (version_compare(JVERSION, '3.0.0', 'ge')){
// code here
}
Editing this answer because I realized the issue is something else. The problem here is the $version check you're doing looks for the release to be EXACTLY == 3.0. When really you want that get() method to be used for 3.0 and up. You should change your if-statement to:
if($version->RELEASE >= 3.0)
{ ... }
Because you're using 3.2.1 this will use the proper method gets for that version.

Resources