Unable to understand what mistake i doing while invalidating Cloud front resource using AWS PHP SDK Version 3,
My Code
public function cfCreateInvalidation()
{
$item = "http://mycdn.domain.com/resourcepath?queryString" ;
try {
$data = [
'DistributionId' => 'ActualValueHereID',
'InvalidationBatch' => [
'CallerReference' => '16 Char Random String',
'Paths' => [
'Items' => [$item],
'Quantity' => 1,
],
]
];
$result = $this->cloudFrontConnection->createInvalidation($data);
}catch (\Exception $exception) {
echo json_encode($exception->getMessage());
}
}
Every time I am getting:
Error executing "CreateInvalidation" on "https://cloudfront.amazonaws.com/2017-03-25/distribution/AAABBBBCCCCD/invalidation";
AWS HTTP error: Client error: `POST https://cloudfront.amazonaws.com/2017-03-25/distribution/AAABBBBCCCCD/invalidation` resulted in a `400 Bad Request` response:
<?xml version="1.0"?>
<ErrorResponse xmlns="http://cloudfront.amazonaws.com/doc/2017-03-25/"><Error><Type>Sender</Type>< (truncated...)
MalformedInput (client): Could not parse XML - <?xml version="1.0"?>
<ErrorResponse xmlns="http://cloudfront.amazonaws.com/doc/2017-03-25/"><Error><Type>Sender</Type><Code>MalformedInput</Code><Message>Could not parse XML</Message></Error><RequestId>ad9b467c-211e-11e8-ba32-45e52ff9e8b3</RequestId></ErrorResponse>
The error message suggests there may be other issues as well, but your $item expects a path, rather than a URL.
/resourcepath* is expected, here. All cached objects for the specified path will be invalidated, regardless of scheme, method, headers, or cookies that may also be part of the cache key.
The documentation seems ambiguous, but suggests that the * at the end is needed to catch query strings if your distribution is configured to cache on them. (The * matches 0 or more characters). There is no documented example of actually including the query string in the path you submit.
I've encountered the same problem with a Wordpress plugin that handles cleaning cache when updating published posts.
When calling createInvalidation($data) (the $data structure is the same in post question) I got that error
AWS HTTP error: Client error: POST
https://cloudfront.amazonaws.com/2017-10-30/distribution/E3QES3NJL8EBYN/invalidation
resulted in a 400 Bad Request
(that could only be retrieved on log error file while the page output was the generic one
"Access Denied"...)
Reading the CloudFront documentation I found out that the createInvalidation method has its asyncronous version that is:
createInvalidationAsync($data)
You can do this for every CloudFront method indeed as it is written in https://docs.aws.amazon.com/aws-sdk-php/v3/api/api-cloudfront-2016-01-28.html (appending the Async word to the operation name)
With this one all is working properly and no error is retrieved because the system returns an "ok I'll do it soon later" response and all the process of publication post can be carried out with success.
I know this is a workaround because this doesn't eliminate the root cause of the problem but it is working for me and I hope this could help anyone.
Related
An API sends me a stream containing a zip archive of several files that I choose by providing their ids in the parameter SelectedIds of my request.
I receive a PSR7 response that I pass to HttpFoundationFactory to return a Response that corresponds to what the Symfony controller should return.
(the goal is to download the zip in the client side browser.)
Here is the content of my controller method
$client = $this->getApiClient();
$user = $this->getUser();
$idList = [51,52,53];
$psr7ApiResponse = $client->post('/v1/get-zip', [
'headers' => [
'Authorization' => sprintf('Bearer %s', $user->getToken()),
],
'http_errors' => false,
'json' => [
'SelectedIds' => $idList,
],
]);
$httpFoundationFactory = new HttpFoundationFactory();
return $httpFoundationFactory->createResponse($psr7ApiResponse);
It works perfectly locally but on the server I receive nothing, blank page. Would you know which way I should look because I have no error log, it looks like the stream is empty but I don't know how to check.
I tested the API with postman and it's ok ; my controller sends me back a 200 as well
Follow those steps in order to debug the problem:
1. Check if the content of $psr7ApiResponse is valid and correct
You are in a different environment. Maybe for some reason your server side script does not receive a valid answer. Maybe the authentication does not work. Print debug the answer you receive to some log file as detailed as necessary (use loggers:
https://symfony.com/doc/current/logging.html).
If the content or the resulting class of the call are not correct the problem is within the remote call communication and you have to debug that. This is most likely the case.
2. Check if your client really understands the answer and check if the answer is correct
Your client definitely should not receive a blank page (it indicates that the problem is 1).
Try to explicitly return a file by using Symfony\Component\HttpFoundation\File\File.
You also can set certain ZIP headers to a Response object manually - at least for debugging:
// set example variables
$filename = "zip-to-download.zip";
$filepath = "/path"; // maybe save the response to a temp file for debugging purposes
$response = $httpFoundationFactory->createResponse($psr7ApiResponse);
$response->headers->set('Pragma','public');
$response->headers->set('Expires',0);
$response->headers->set('Cache-Control','must-revalidate, post-check=0, pre-check=0');
$response->headers->set('Content-Description','File Transfer');
$response->headers->set('Content-type','application/octet-stream');
$response->headers->set('Content-Disposition','attachment; filename="'.$filename.'"');
$response->headers->set('Content-Transfer-Encoding','binary');
return $response;
I am trying to connect to an API using PHP and its built-in SoapClient. I have checked against the url I was given through the ill-formatted documents the client gave and $client->__getFunctions() returns a list of three functions. HelloWorld($name), which responds with Hello ~name~, shows me that I am communicating with the server through the SoapClient call and the URL is correct.
However, when I try to access one of the other methods that __getFunctions() gives me, even after copy/pasting the XML from the docs and putting in my own credentials, I am still being given an Internal Server Error faultstring and 500 as faultcode from the SoapFault object.
I am sure that it is my own XML string that is causing the issue but I cannot for the life of me figure out how. Reaching out to the API provider directly hasn't proven helpful. This is my first time dealing with Soap/Web Services so I am unsure of where to go from here.
I did wget http//xxx.xxx.xxx?wsdl and it returned me what looks like a valid XML response, the same one I get when I go directly to the url in the browser. What should I be looking into in order to solve this issue? All of the past API's I've dealt with have been JSON/RESTful so I feel out of my element trying to debug PHP errors.
Edit
I have slowly deleted parts of my method call and parts of my XML string, trying to trigger a different error or something in order to find what I need to fix. What I have found is that by not passing in my XML string, I get a valid response from the $client->FunctionCall(...). It's an "this isn't right" message but it's a message! In fact, passing that function ANYTHING for the xml parameter causes the 500 http faultcode/faultstring. Does this mean that my XMl is poorly formatted or does it mean that there is an issue on their end handling requests?
Second Edit
If I make my $client decleration as follows, I get the faultstring Could not connect to host
$opts = array(
'ssl' => array('ciphers'=>'RC4-SHA')
);
$client = new SoapClient($CREDS['orderingWSDL'], array (
"encoding"=>"ISO-8859-1",
'stream_context' => stream_context_create($opts),
'exceptions'=>true,
));
I am getting more confused the longer I try to fix this.
Sometimes a 500 status coming from a SOAP service could be a SoapFault exception being thrown. To help your troubleshooting, you'll want to be able to inspect both your request XML, and the response XML.
Put your code in try/catch blocks, and use $client->__getLastRequest() and $client->__getLastResponse() to inspect the actual XML.
Example:
$client = new SoapClient('http//xxx.xxx.xxx?wsdl', array('soap_version'=>SOAP_1_1,'trace' => 1,'exceptions' => true));
try {
$response = $client->someFunction();
var_dump($response);
} catch (Exception $e) {
var_dump($e->getMessage());
var_dump($client->__getLastRequest());
var_dump($client->__getLastResponse());
}
I am receiving the following error when using the putObject() function of the aws-sdk for php:
PHP Fatal error: Uncaught Aws\S3\Exception\MalformedXMLException: AWS Error Code: MalformedXML,
Status Code: 400, AWS Request ID: 7E36EB414B2A9436, AWS Error Type: client,
AWS Error Message: The XML you provided was not well-formed or did not validate against our published schema,
User-Agent: aws-sdk-php2/2.5.4 Guzzle/3.8.1 curl/7.26.0 PHP/5.5.19-1~dotdeb.1
thrown in /sites/sitename/vendor/aws/aws-sdk-php/src/Aws/Common/Exception/NamespaceExceptionFactory.php on line 91
Even though I am receiving the error, the process continues to run successfully and the files are moved to s3. I know this more than likely has something to do with the parameters that I am including in the function but I'm not sure what else needs to be there as the aws api for php only shows the 'bucket' and 'key' parameters as being required. My configuration is as follows:
$config = array();
$config['Bucket'] = IMAGE_BUCKET;
$config['Key'] = $imageName;
$config['SourceFile'] = $sourceImageDir;
$config['ACL'] = 'public-read';
$config['ContentLength'] = filesize($sourceImageDir);
$response = $s3->putObject($config);
If I knew what format the service was requiring I'm sure I could grab the request that I'm sending after it's turned into an xml string and compare it with that, but I can't seem to find it. If it exists. I would assume there is such a thing?
Thanks to the comment from Michael I was able to track the issue down further. It turns out that the issue was actually coming from a call to deleteObjects(). These commands are being executed within a shell script on the cli and it turns out there was another call preceeding the last call to putObject(). It was trying to send empty arrays to the s3 service...which would obviously return the given MalformedXML Status code.
This question already has an answer here:
Need response body of HTTP 500 with file_get_contents (PHP)
(1 answer)
Closed 8 years ago.
I'm working with an API that I recently noticed is failing in the code some of the time. I retrieve it via file_get_contents, and I'm getting the error "failed to open stream: HTTP request failed!"
I plugged the URL into the browser directly and I get back a response, so I was confused. I thought to check the headers, and I noticed its coming up 403, and I have to assume that's why its failing? When its not 403, it does work. The 403 only comes up when the API authentication fails, and I have code to check if the XML that comes back says its a failure.
So really the question is, how can I get back the code, regardless of if its a 403 or not. I was going to start using simplexml_load_file since I'm loading it into SimpleXML anyway, but if there is another method I can/should use, that advice would be great too.
EDIT: I've attempted a simple curl request, but unless I've done it wrong, its also failed:
$curlObject = curl_init('https://api.eveonline.com/account/Characters.xml.aspx?userID=8166034&characterID=91242713&apiKey=B174C8B7B4364048B8A44B8C494904059D50B942BB4748FD907FF1DBF3F18282');
curl_setopt($curlObject, CURLOPT_RETURNTRANSFER, 1);
$fileContents = curl_exec($curlObject);
curl_close($curlObject);
echo $fileContents;
I would wrap the handling as specified in the duplicate question and then throw a dedicated exception when you trigger that error-response:
$legacyKey = [
'userID' => '8166034',
'apiKey' => 'B174C8B7B4364048B8A44B8C494904059D50B942BB4748FD907FF1DBF3F18282',
];
$api = new EveApi($legacyKey);
$api->define('getAccountCharacters', 'account/Characters.xml.aspx', ['characterID']);
try {
$characters = $api->getAccountCharacters($characterID = '91242713');
} catch(Exception $exception) {
printf("Exception: %s; Code: %s; Message: %s\n", get_class($exception), $exception->getCode(), $exception->getMessage());
throw $exception;
}
In this example, the default handling from the EveApi would be to throw exceptions on such errors:
<?xml version="1.0" encoding="UTF-8"?>
<eveapi version="2">
<currentTime>2013-11-02 13:06:53</currentTime>
<error code="203">Authentication failure.</error>
<cachedUntil>2013-11-03 13:06:53</cachedUntil>
</eveapi>
Can be turned into an EveApiError then as this output shows:
Exception: EveApiError; Code: 203; Message: Authentication failure.
Fatal error: Uncaught exception 'EveApiError' with message
'Authentication failure.' in ...
That would not only wrap the error handling but also the API access allowing you to inject your own API for testing purposes.
Additionally you can wrap the different but common return types.
I'm trying to create a REST service in zend framework. I'm using zend server.
Here's my code:
class ArticleController extends Zend_Rest_Controller
{
public function postAction()
{
//Create the acticle and return it
$data = array("foo" => 0, "boo" => 11);
$this->getResponse()->setHttpResponseCode(201);
$this->_helper->json($data);
}
The HTTP response returns the appropriate headers and JSON data but under the JSON data there's an apache error document.
The only way I can think of to remove the appended error document is to add the following in my httpd.conf file:
ErrorDocument 201 " "
But what's the "corrent" way of doing this?
Your original way is correct. 201 is an appropriate response after POSTing a new resource.
I think that the Error document which you see generated after your own content should not be there. Are you running Zend Server Community Edition v5.0 by any chance? If yes, then see this thread, I think that you encountered the same problem as the other guy there:
How to turn off default HTTP status code errors in Zend Server?
Why are you using code 201? 201 means you have created a resource for the request and are providing a link to it. If you have the article and are returning it you should just use 200.
Otherwise, what you're doing seems like the correct way, you remove the ErrorDocument associated with status-code 201.