I am trying to invoke AWS Lambda function using AWS SDK for PHP V3.
My source code:
require '../vendor/autoload.php';
use Aws\Lambda\LambdaClient;
use Aws\Exception\AwsException;
$lambdaClient = new Aws\Lambda\LambdaClient([
'version' => 'latest',
'region' => 'us-east-1',
'credentials' => [
'key' => 'MY_ACCESS_KEY',
'secret' => 'MY_SECRET_KEY'
]
]);
$strArrTemp = array('key1' => 'Hello', 'key2' => 'World');
$result = $lambdaClient->invoke([
'FunctionName' => 'testFunc',
'Payload' => json_encode($strArrTemp)
]);
echo $result->get('Payload')->getBody();
This results below:
Fatal error: Call to undefined method GuzzleHttp\Psr7\Stream::getBody() in C:\Apache24\htdocs\FirewallChecker\php\main.php on line xx
The result of var_dump($result->get('Payload')) is below:
object(GuzzleHttp\Psr7\Stream)[116]
private 'stream' => resource(158, stream)
private 'size' => null
private 'seekable' => boolean true
private 'readable' => boolean true
private 'writable' => boolean true
private 'uri' => string 'php://temp' (length=10)
private 'customMetadata' =>
array (size=0)
empty
And the result of 'echo $result->get('Payload')' is below:
{"statusCode": 777, "body": {"key1": "Hello", "key2": "World"}}
I find the link below but it didn't help because getBody() and getContents doesn't work to me at all.
https://stackoverflow.com/a/30549372/6192555
The python code on AWS LAMBDA is below:
import json
import socket
from contextlib import closing
def lambda_handler(event, context):
return {
'statusCode': 777,
'body': event
}
What should I do?
Related
I can't figure out how to delete hosted zone resource record set with Amazon PHP sdk.
So my code is following
public function __construct(\ConsoleOutput $stdout = null, \ConsoleOutput $stderr = null, \ConsoleInput $stdin = null) {
parent::__construct($stdout, $stderr, $stdin);
/** #var \Aws\Route53\Route53Client route53Client */
$this->route53Client = Route53Client::factory([
'version' => '2013-04-01',
'region' => 'eu-west-1',
'credentials' => [
'key' => <my-key>,
'secret' => <my-secret-key>
]
]);
}
And this is my function for deleting resource record set
private function deleteResourceRecordSet() {
$response = $this->route53Client->changeResourceRecordSets([
'ChangeBatch' => [
'Changes' => [
[
'Action' => 'DELETE',
'ResourceRecordSet' => [
'Name' => 'pm-bounces.subdomain.myDomain.com.',
'Region' => 'eu-west-1',
'Type' => 'CNAME',
],
]
]
],
'HostedZoneId' => '/hostedzone/<myHostedZoneId>'
]);
var_dump($response);
die();
}
And the error I'm keep getting is
Error executing "ChangeResourceRecordSets" on "https://route53.amazonaws.com/2013-04-01/hostedzone/<myHostedZoneId>/rrset/"; AWS HTTP error: Client error: `POST https://route53.amazonaws.com/2013-04-01/hostedzone/<myHostedZoneId>/rrset/` resulted in a `400 Bad Request` response:
<?xml version="1.0"?>
<ErrorResponse xmlns="https://route53.amazonaws.com/doc/2013-04-01/"><Error><Type>Sender</Type><Co (truncated...)
InvalidInput (client): Invalid request: Expected exactly one of [AliasTarget, all of [TTL, and ResourceRecords], or TrafficPolicyInstanceId], but found none in Change with [Action=DELETE, Name=pm-bounces.subdomain.myDomain.com., Type=CNAME, SetIdentifier=null] - <?xml version="1.0"?>
<ErrorResponse xmlns="https://route53.amazonaws.com/doc/2013-04-01/"><Error><Type>Sender</Type><Code>InvalidInput</Code><Message>Invalid request: Expected exactly one of [AliasTarget, all of [TTL, and ResourceRecords], or TrafficPolicyInstanceId], but found none in Change with [Action=DELETE, Name=pm-bounces.subdomain.myDomain.com., Type=CNAME, SetIdentifier=null]</Message>
So what exactly is minimum required set of params so I will be available to delete resource record from hosted zone? If you need any additional informations, please let me know and I will provide. Thank you
Ok I have figure it out. If you wan't to delete resource record set from hosted zones, then the code/function for deleting record set should look like following
private function deleteResourceRecordSet($zoneId, $name, $ResourceRecordsValue, $recordType, $ttl) {
$response = $this->route53Client->changeResourceRecordSets([
'ChangeBatch' => [
'Changes' => [
[
'Action' => 'DELETE',
"ResourceRecordSet" => [
'Name' => $name,
'Type' => $recordType,
'TTL' => $ttl,
'ResourceRecords' => [
$ResourceRecordsValue // should be reference array of all resource records set
]
]
]
]
],
'HostedZoneId' => $zoneId
]);
}
I started with AWS Lambda today and I can't succeed in passing a payload to the function. On the server side I try to read all the event data but it is empty. What am I doing wrong here?
$client = LambdaClient::factory(array(
'profile' => 'default',
'key' => AWS_ACCESS_KEY_ID,
'secret' => AWS_SECRET_ACCESS_KEY,
'region' => 'eu-west-1'
));
$payload = array('key1' => '1');
$result = $client->invoke(array(
'FunctionName' => 'hello',
'InvocationType' => 'RequestResponse',
'LogType' => 'Tail',
'Payload' => json_encode($payload)
));
Returns:
Received event: {}
Function code on AWS:
console.log('Loading function');
exports.handler = function(event, context) {
console.log('Received event:', JSON.stringify(event, null, 2));
};
In python I send the payload like this:
from boto3 import client as botoClient
import json
lambdas = botoClient("lambda")
def lambda_handler(event, context):
response = lambdas.invoke(FunctionName="myLambdaFunct", InvocationType="RequestResponse", Payload=json.dumps(event));
where event is a dictionary and, json.dumps serialize event to a JSON formatted string
I get the following errors when I try to use the AWS PHP SDK:
PHP Warning: Illegal string offset 'client.backoff' in C:\xampp\htdocs\aws_test_local\vendor\aws\aws-sdk-php\src\Aws\S3\S3Client.php on line 172
PHP Catchable fatal error: Object of class Guzzle\Plugin\Backoff\BackoffPlugin could not be converted to string in C:\xampp\htdocs\aws_test_local\vendor\aws\aws-sdk-php\src\Aws\S3\S3Client.php on line 172
PHP Warning: Illegal string offset 'signature' in C:\xampp\htdocs\aws_test_local\vendor\aws\aws-sdk-php\src\Aws\S3\S3Client.php on line 175
PHP Catchable fatal error: Object of class Aws\S3\S3Signature could not be converted to string in C:\xampp\htdocs\aws_test_local\vendor\aws\aws-sdk-php\src\Aws\S3\S3Client.php on line 175
They originate from the following code inside the S3Client.php file part of the AWS SDK.
public static function factory($config = array())
{
$exceptionParser = new S3ExceptionParser();
// Configure the custom exponential backoff plugin for retrying S3 specific errors
if (!isset($config[Options::BACKOFF])) {
$config[Options::BACKOFF] = static::createBackoffPlugin($exceptionParser);
}
$config[Options::SIGNATURE] = $signature = static::createSignature($config);
...
The Options-class is the Aws\Common\Enum\ClientOptions. If you look at it it defines a lot of constants like this:
const SIGNATURE = 'signature';
const BACKOFF = 'client.backoff';
I call the factory function in the following way:
$s3 = S3Client::factory(_PS_ROOT_DIR_.'/override/aws/aws-config.php');
My aws-config.php file looks like this:
<?php
return array(
'includes' => array('_aws'),
'services' => array(
'default_settings' => array(
'params' => array(
'key' => 'XXXXXXXXXXX',
'secret' => 'XXXXXXXXXXX',
'region' => 'eu-west-1'
)
)
)
);
?>
Any ideas? I installed the PHP SDK with Composer, so I'd expect any dependancies to be installed.
The argument to S3Client::factory() is supposed to be an array. You're giving it a filename that contains PHP code to return the array, but S3Client doesn't run the file. Try changing the file to:
<?php
$s3options = array(
'includes' => array('_aws'),
'services' => array(
'default_settings' => array(
'params' => array(
'key' => 'XXXXXXXXXXX',
'secret' => 'XXXXXXXXXXX',
'region' => 'eu-west-1'
)
)
)
);
?>
Then your main program can do:
require(_PS_ROOT_DIR_.'/override/aws/aws-config.php');
$s3 = S3Client::factory($s3options);
I am trying to email by using Mandrill with CodeIgniter. I can use Mandrill API as described in their documentation:
require_once(mandrill/Mandrill.php);
$Mandrill = new Mandrill($apikey);
$params = array(
"html" => "<p>\r\n\tHi Adam,</p>\r\n<p>\r\n\tThanks for registering.</p>\r\n<p>etc etc</p>",
"text" => null,
"from_email" => "xxx#xxx.example.com",
"from_name" => "chris french",
"subject" => "Your recent registration",
"to" => array(array("email" => xxx#yyy.example.com")),
"track_opens" => true,
"track_clicks" => true,
"auto_text" => true
);
$Mandrill->messages->send($params, true));
This is pretty straight forward, but when I try to send Mandrill mail via CodeIgniter, I get error as result; here is my code:
$this->load->library('mandrill/Mandrill');
$this->Mandrill->apikey($apikey);
//...
//All other options
$this->Mandrill->messages->send($params, true));
Library is loading successfully, sending email is where I get error.
Error thrown:
Fatal error: Call to a member function send() on null
I guess you load mandrill class wrongly in order to make it "CodeIgniter way" do as follows:
put class (the file mandrill.php and folder mandrill in application/libraries folder) see picture
load class using $this->load->library('mandrill', array($apikey));
fix all typos in $params (you are missing ", last line has two brackets ))in the end)
modify mandrill.php so it accepts array as parameter in constructor; see SOLUTION part of answer
use API as in tutorials from Mandrill (send, ping... whatever)
valid code
$this->load->library('mandrill', array($apikey)); //load mandrill and provide apikey
$params = array(
"html" => "<p>\r\n\tHi Adam,</p>\r\n<p>\r\n\tThanks for registering.</p>\r\n<p>etc etc</p>",
"text" => null,
"from_email" => "xxx#xxx.example.com",
"from_name" => "chris french",
"subject" => "Your recent registration",
"to" => array(array("email" => "xxx#yyy.example.com")),
"track_opens" => true,
"track_clicks" => true,
"auto_text" => true
);
$this->mandrill->messages->send($params, true);
Edit (comments)
please note: I removed real api-key = MY_KEY, email from = EMAIL_FROM, email to = EMAIL_TO
$msg = array(
"html" => "The Message",
"text" => null,
"from_email" => "EMAIL_FROM",
"from_name" => "John Doe",
"subject" => "Acme",
"to" => array(array("email" => "EMAIL_TO")),
"track_opens" => true,
"track_clicks" => true,
"auto_text" => true
);
require_once APPPATH.'libraries/Mandrill.php';
$mandrill = new Mandrill('MY_KEY');
var_dump($mandrill->messages->send($msg, true));
//var_dump($mandrill->users->ping());
$this->load->library('Mandrill', array("MY_KEY")); //load mandrill and provide apikey
var_dump($this->mandrill->messages->send($msg, true));
//var_dump($this->mandrill->users->ping());
Above code sends identical email twice (using different load methods); response && few var_dump() are:
method using require_once...
object(Mandrill)[14] //setup
public 'apikey' => string 'MY_KEY' (length=22)
public 'ch' => resource(40, curl)
public 'root' => string 'https://mandrillapp.com/api/1.0/' (length=32)
public 'debug' => boolean false
array (size=1) //this is response
0 =>
array (size=4)
'email' => string 'EMAIL_TO' (length=24)
'status' => string 'sent' (length=4)
'_id' => string 'f7af72b1e1364a58a2eb302e94a1dc1e' (length=32)
'reject_reason' => null
method using $this->load->library();
object(Mandrill)[30] //setup
public 'apikey' => string 'MY_KEY' (length=22)
public 'ch' => resource(41, curl)
public 'root' => string 'https://mandrillapp.com/api/1.0/' (length=32)
public 'debug' => boolean false
array (size=1) //this is response
0 =>
array (size=4)
'email' => string 'EMAIL_TO' (length=24)
'status' => string 'sent' (length=4)
'_id' => string '5965091637fa42dd98b40a934523022e' (length=32)
'reject_reason' => null
SOLUTION
In order to make it work I changed the way how API_KEY is retrieved in Mandrill constructor, since CodeIgniter's loader is sending parameter to constructor as array()
Mandrill.php
public function __construct($apikey=null) {
if(is_array($apikey)) $apikey = $apikey[0]; //added this line
if(!$apikey) $apikey = getenv('MANDRILL_APIKEY');
if(!$apikey) $apikey = $this->readConfigs();
//... rest of the file
Another option is CI-Mandrill, note that it uses version 1.0; installation time ~5 minutes or less
I have been trying to figure out how to grab contents from an S3 bucket to include in a ZipArchive for a client who is storing files on S3, they now need to create reports that hold the files that were pushed up to S3 by their customers. I have tried the following with the PHP SDK 2 API (Installed with PEAR):
require 'AWSSDKforPHP/aws.phar';
use Aws\S3\S3Client;
use Aws\Common\Enum\Region;
$config = array(
'key' => 'the-aws-key',
'secret' => 'the-aws-secret',
'region' => Region::US_EAST_1
);
$aws_s3 = S3Client::factory($config);
$app_config['s3']['bucket'] = 'the-aws-bucket';
$app_config['s3']['prefix'] = '';
$attach_name = 'hosted-test-file.jpg';
try {
$result = $aws_s3->getObject(
array(
'Bucket' => $app_config['s3']['bucket'],
'Key' => $app_config['s3']['prefix'].$attach_name
)
);
var_dump($result);
$body = $result->get('Body');
var_dump($body);
$handle = fopen('php://temp', 'r');
$content = stream_get_contents($handle);
echo "String length: ".strlen($content);
} catch(Aws\S3\Exception\S3Exception $e) {
echo "Request failed.<br />";
}
However, all it returns is an Guzzle\Http\EntityBody object, not sure how to grab the actual content so I can push it into the zip file.
Grabbing Object
object(Guzzle\Service\Resource\Model)[126]
protected 'structure' => object(Guzzle\Service\Description\Parameter)[109]
protected 'name' => null
protected 'description' => null
protected 'type' => string 'object' (length = 6)
protected 'required' => boolean false
protected 'enum' => null
protected 'additionalProperties' => boolean true
protected 'items' => null
protected 'parent' => null
protected 'ref' => null
protected 'format' => null
protected 'data' => array (size = 11)
'Body' => object(Guzzle\Http\EntityBody)[97]
protected 'contentEncoding' => boolean false
protected 'rewindFunction' => null
protected 'stream' => resource(292, stream)
protected 'size' => int 3078337
protected 'cache' => array (size = 9)
...
'DeleteMarker' => string '' (length = 0)
'Expiration' => string '' (length = 0)
'WebsiteRedirectLocation' => string '' (length = 0)
'LastModified' => string 'Fri, 30 Nov 2012 21:07:30 GMT' (length = 29)
'ContentType' => string 'binary/octet-stream' (length = 19)
'ContentLength' => string '3078337' (length = 7)
'ETag' => string '"the-etag-of-the-file"' (length = 34)
'ServerSideEncryption' => string '' (length = 0)
'VersionId' => string '' (length = 0)
'RequestId' => string 'request-id' (length = 16)
Returned from Body
object(Guzzle\Http\EntityBody)[96]
protected 'contentEncoding' => boolean false
protected 'rewindFunction' => null
protected 'stream' => resource(292, stream)
protected 'size' => int 3078337
protected 'cache' => array (size = 9)
'wrapper_type' => string 'php' (length = 3)
'stream_type' => string 'temp' (length = 4)
'mode' => string 'w+b' (length = 3)
'unread_bytes' => int 0
'seekable' => boolean true
'uri' => string 'php://temp' (length = 10)
'is_local' => boolean true
'is_readable' => boolean true
'is_writable' => boolean true
// Echo of strlen()
String length: 0
Any information would be high appreciated, thanks!
Solution
It me a while to figure it out but I was able to find a gist that pointed me in the right direction, in order to get the contents of the file you need to do the following:
require 'AWSSDKforPHP/aws.phar';
use Aws\S3\S3Client;
use Aws\Common\Enum\Region;
$config = array(
'key' => 'the-aws-key',
'secret' => 'the-aws-secret',
'region' => Region::US_EAST_1
);
$aws_s3 = S3Client::factory($config);
$app_config['s3']['bucket'] = 'the-aws-bucket';
$app_config['s3']['prefix'] = '';
$attach_name = 'hosted-test-file.jpg';
try {
$result = $aws_s3->getObject(
array(
'Bucket' => $app_config['s3']['bucket'],
'Key' => $app_config['s3']['prefix'].$attach_name
)
);
$body = $result->get('Body');
$body->rewind();
$content = $body->read($result['ContentLength']);
} catch(Aws\S3\Exception\S3Exception $e) {
echo "Request failed.<br />";
}
The body of the response is stored in a Guzzle\Http\EntityBody object. This is used to protect your application from downloading extremely large files and running out of memory.
If you need to use the contents of the the EntityBody object as a string, you can cast the object to a string:
$result = $s3Client->getObject(array(
'Bucket' => $bucket,
'Key' => $key
));
// Cast as a string
$bodyAsString = (string) $result['Body'];
// or call __toString directly
$bodyAsString = $result['Body']->__toString();
You can also download directly to the target file if needed:
use Guzzle\Http\EntityBody;
$s3Client->getObject(array(
'Bucket' => $bucket,
'Key' => $key,
'command.response_body' => EntityBody::factory(fopen("/tmp/{$key}", 'w+'))
));
This worked for me:
$tempSave = 'path/to/save/filename.txt';
return $this->S3->getObject([
'Bucket' => 'test',
'Key' => $keyName,
'SaveAs' => $tempSave,
]);
When calling getObject, you can pass in an array of options. In these options, you can specify if you want to download the object to your file system.
$bucket = "bucketName";
$file = "fileName";
$downloadTo = "path/to/save";
$opts = array( // array of options
'fileDownload' => $downloadTo . $file // tells the SDK to download the
// file to this location
);
$result = $aws_s3->getObject($bucket, $file, $opts);
getObject Reference
I am not that familiar with the version 2.00 SDK, but it looks like you have been passed a stream context on php://temp. From looking at your updated question and from a brief glance at the documentation, it seems the stream may be available as:
$result = $aws_s3->getObject(
array(
'Bucket' => $app_config['s3']['bucket'],
'Key' => $app_config['s3']['prefix'].$attach_name
)
);
$stream = $result->get('stream');
$content = file_get_contents($stream);
<?php
$o_iter = $client->getIterator('ListObjects', array(
'Bucket' => $bucketname
));
foreach ($o_iter as $o) {
echo "{$o['Key']}\t{$o['Size']}\t{$o['LastModified']}\n";
}