PHP Classes

File: application/modules/extensions/aws/Aws/CloudTrail/LogFileIterator.php

Recommend this page to a friend!
  Classes of Tran Tuan   Pretty PHP S3 Files Manager   application/modules/extensions/aws/Aws/CloudTrail/LogFileIterator.php   Download  
File: application/modules/extensions/aws/Aws/CloudTrail/LogFileIterator.php
Role: Application script
Content type: text/plain
Description: Application script
Class: Pretty PHP S3 Files Manager
Web based interface to manage files in Amazon S3
Author: By
Last change:
Date: 8 years ago
Size: 11,689 bytes
 

Contents

Class file image Download
<?php namespace Aws\CloudTrail; use Aws\S3\S3Client; use Aws\CloudTrail\Exception\CloudTrailException; /** * The `Aws\CloudTrail\LogFileIterator` provides an easy way to iterate over * log file generated by AWS CloudTrail. * * CloudTrail log files contain data about your AWS API calls and are stored in * Amazon S3 at a predictable path based on a bucket name, a key prefix, an * account ID, a region, and date information. This class allows you to specify * options, including a date range, and emits each log file that match the * provided options. * * Yields an array containing the Amazon S3 bucket and key of the log file. */ class LogFileIterator extends \IteratorIterator { // For internal use const DEFAULT_TRAIL_NAME = 'Default'; const PREFIX_TEMPLATE = 'prefix/AWSLogs/account/CloudTrail/region/date/'; const PREFIX_WILDCARD = '*'; // Option names used internally or externally const TRAIL_NAME = 'trail_name'; const KEY_PREFIX = 'key_prefix'; const START_DATE = 'start_date'; const END_DATE = 'end_date'; const ACCOUNT_ID = 'account_id'; const LOG_REGION = 'log_region'; /** @var S3Client S3 client used to perform ListObjects operations */ private $s3Client; /** @var string S3 bucket that contains the log files */ private $s3BucketName; /** * Constructs a LogRecordIterator. This factory method is used if the name * of the S3 bucket containing your logs is not known. This factory method * uses a CloudTrail client and the trail name (or "Default") to find the * information about the trail necessary for constructing the * LogRecordIterator. * * @param S3Client $s3Client * @param CloudTrailClient $cloudTrailClient * @param array $options * * @return LogRecordIterator * @throws \InvalidArgumentException * @see LogRecordIterator::__contruct */ public static function forTrail( S3Client $s3Client, CloudTrailClient $cloudTrailClient, array $options = [] ) { $trailName = isset($options[self::TRAIL_NAME]) ? $options[self::TRAIL_NAME] : self::DEFAULT_TRAIL_NAME; $s3BucketName = null; // Use the CloudTrail client to get information about the trail, // including the bucket name. try { $result = $cloudTrailClient->describeTrails([ 'trailNameList' => [$trailName] ]); $s3BucketName = $result->search('trailList[0].S3BucketName'); $options[self::KEY_PREFIX] = $result->search( 'trailList[0].S3KeyPrefix' ); } catch (CloudTrailException $e) { // There was an error describing the trail } // If the bucket name is still unknown, then throw an exception if (!$s3BucketName) { $prev = isset($e) ? $e : null; throw new \InvalidArgumentException('The bucket name could not ' . 'be determined from the trail.', 0, $prev); } return new self($s3Client, $s3BucketName, $options); } /** * Constructs a LogFileIterator using the specified options: * * - trail_name: The name of the trail that is generating our logs. If * none is provided, then "Default" will be used, since that is the name * of the trail created in the AWS Management Console. * - key_prefix: The S3 key prefix of your log files. This value will be * overwritten when using the `fromTrail()` method. However, if you are * using the constructor, then this value will be used. * - start_date: The timestamp of the beginning of date range of the log * records you want to read. You can pass this in as a `DateTime` object, * integer (unix timestamp), or a string compatible with `strtotime()`. * - end_date: The timestamp of the end of date range of the log records * you want to read. You can pass this in as a `DateTime` object, integer * (unix timestamp), or a string compatible with `strtotime()`. * - account_id: This is your AWS account ID, which is the 12-digit number * found on the *Account Identifiers* section of the *AWS Security * Credentials* page. See https://console.aws.amazon.com/iam/home?#security_credential * - log_region: Region of the services of the log records you want to read. * * @param S3Client $s3Client * @param string $s3BucketName * @param array $options */ public function __construct( S3Client $s3Client, $s3BucketName, array $options = [] ) { $this->s3Client = $s3Client; $this->s3BucketName = $s3BucketName; parent::__construct($this->buildListObjectsIterator($options)); } /** * An override of the typical current behavior of \IteratorIterator to * format the output such that the bucket and key are returned in an array * * @return array|bool */ public function current() { if ($object = parent::current()) { return [ 'Bucket' => $this->s3BucketName, 'Key' => $object['Key'] ]; } return false; } /** * Constructs an S3 ListObjects iterator, optionally decorated with * FilterIterators, based on the provided options. * * @param array $options * * @return \Iterator */ private function buildListObjectsIterator(array $options) { // Extract and normalize the date values from the options $startDate = isset($options[self::START_DATE]) ? $this->normalizeDateValue($options[self::START_DATE]) : null; $endDate = isset($options[self::END_DATE]) ? $this->normalizeDateValue($options[self::END_DATE]) : null; // Determine the parts of the key prefix of the log files being read $parts = [ 'prefix' => isset($options[self::KEY_PREFIX]) ? $options[self::KEY_PREFIX] : null, 'account' => isset($options[self::ACCOUNT_ID]) ? $options[self::ACCOUNT_ID] : self::PREFIX_WILDCARD, 'region' => isset($options[self::LOG_REGION]) ? $options[self::LOG_REGION] : self::PREFIX_WILDCARD, 'date' => $this->determineDateForPrefix($startDate, $endDate), ]; // Determine the longest key prefix that can be used to retrieve all // of the relevant log files. $candidatePrefix = ltrim(strtr(self::PREFIX_TEMPLATE, $parts), '/'); $logKeyPrefix = $candidatePrefix; $index = strpos($candidatePrefix, self::PREFIX_WILDCARD); if ($index !== false) { $logKeyPrefix = substr($candidatePrefix, 0, $index); } // Create an iterator that will emit all of the objects matching the // key prefix. $objectsIterator = $this->s3Client->getIterator('ListObjects', [ 'Bucket' => $this->s3BucketName, 'Prefix' => $logKeyPrefix, ]); // Apply regex and/or date filters to the objects iterator to emit only // log files matching the options. $objectsIterator = $this->applyRegexFilter( $objectsIterator, $logKeyPrefix, $candidatePrefix ); $objectsIterator = $this->applyDateFilter( $objectsIterator, $startDate, $endDate ); return $objectsIterator; } /** * Normalizes a date value to a unix timestamp * * @param string|\DateTime|int $date * * @return int * @throws \InvalidArgumentException if the value cannot be converted to * a timestamp */ private function normalizeDateValue($date) { if (is_string($date)) { $date = strtotime($date); } elseif ($date instanceof \DateTime) { $date = $date->format('U'); } elseif (!is_int($date)) { throw new \InvalidArgumentException('Date values must be a ' . 'string, an int, or a DateTime object.'); } return $date; } /** * Uses the provided date values to determine the date portion of the prefix */ private function determineDateForPrefix($startDate, $endDate) { // The default date value should look like "*/*/*" after joining $dateParts = array_fill_keys(['Y', 'm', 'd'], self::PREFIX_WILDCARD); // Narrow down the date by replacing the WILDCARDs with values if they // are the same for the start and end date. if ($startDate && $endDate) { foreach ($dateParts as $key => &$value) { $candidateValue = date($key, $startDate); if ($candidateValue === date($key, $endDate)) { $value = $candidateValue; } else { break; } } } return join('/', $dateParts); } /** * Applies a regex iterator filter that limits the ListObjects result set * based on the provided options. * * @param \Iterator $objectsIterator * @param string $logKeyPrefix * @param string $candidatePrefix * * @return \Iterator */ private function applyRegexFilter( $objectsIterator, $logKeyPrefix, $candidatePrefix ) { // If the prefix and candidate prefix are not the same, then there were // WILDCARDs. if ($logKeyPrefix !== $candidatePrefix) { // Turn the candidate prefix into a regex by trimming and // converting WILDCARDs to regex notation. $regex = rtrim($candidatePrefix, '/' . self::PREFIX_WILDCARD) . '/'; $regex = strtr($regex, [self::PREFIX_WILDCARD => '[^/]+']); // After trimming WILDCARDs or the end, if the regex is the same as // the prefix, then no regex is needed. if ($logKeyPrefix !== $regex) { // Apply a regex filter iterator to remove files that don't // match the provided options. $objectsIterator = new \CallbackFilterIterator( $objectsIterator, function ($object) use ($regex) { return preg_match("#{$regex}#", $object['Key']); } ); } } return $objectsIterator; } /** * Applies an iterator filter to restrict the ListObjects result set to the * specified date range. * * @param \Iterator $objectsIterator * @param int $startDate * @param int $endDate * * @return \Iterator */ private function applyDateFilter($objectsIterator, $startDate, $endDate) { // If either a start or end date was provided, filter out dates that // don't match the date range. if ($startDate || $endDate) { $fn = function ($object) use ($startDate, $endDate) { if (!preg_match('/[0-9]{8}T[0-9]{4}Z/', $object['Key'], $m)) { return false; } $date = strtotime($m[0]); return (!$startDate || $date >= $startDate) && (!$endDate || $date <= $endDate); }; $objectsIterator = new \CallbackFilterIterator($objectsIterator, $fn); } return $objectsIterator; } }