From 3ad427dcd671db75a86595eb687e3f3374f09b3f Mon Sep 17 00:00:00 2001 From: Stefano Novelli Date: Thu, 1 Aug 2024 22:56:07 +0200 Subject: [PATCH 01/12] chore: Add vlucas/phpdotenv dependency and update .gitignore --- .gitignore | 2 +- README.md | 13 +++++++++++++ composer.json | 3 ++- tests/ExampleTest.php | 5 ----- 4 files changed, 16 insertions(+), 7 deletions(-) delete mode 100644 tests/ExampleTest.php diff --git a/.gitignore b/.gitignore index ff8bfd7..7fd88fd 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,4 @@ phpunit.xml psalm.xml vendor .php-cs-fixer.cache - +.env \ No newline at end of file diff --git a/README.md b/README.md index c3117dc..59fc9be 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,21 @@ Add in your .env file the following variables: ```dotenv CLOUDFLARE_API_TOKEN='your_cloudflare_api_token' +CLOUDFLARE_ZONE_TAG_ID='zoneTag' ``` +## Refactor + +// init +$cf = new \The3LabsTeam\PhpCloudflareAnalytics\CloudflareAnalytics( + // optional, if you want to use the default values from the .env file + token: 'your_cloudflare_api_token', zoneTag: 'zoneTag' +); + +// 1. +$cf->getPageViews()->whereBetweenDates('2021-10-01', '2021-10-31')->get(); + + ## Usage Default use: diff --git a/composer.json b/composer.json index 54ff0d8..ef4293f 100644 --- a/composer.json +++ b/composer.json @@ -15,7 +15,8 @@ } ], "require": { - "php": "^8.1" + "php": "^8.1", + "vlucas/phpdotenv": "^5.6" }, "require-dev": { "pestphp/pest": "^2.20", diff --git a/tests/ExampleTest.php b/tests/ExampleTest.php deleted file mode 100644 index 5d36321..0000000 --- a/tests/ExampleTest.php +++ /dev/null @@ -1,5 +0,0 @@ -toBeTrue(); -}); From ff08f0be4e353d41efa3ed64c4d5b48c480d2aa4 Mon Sep 17 00:00:00 2001 From: Stefano Novelli Date: Thu, 1 Aug 2024 22:56:15 +0200 Subject: [PATCH 02/12] feat: Add CloudflareAnalyticsTest with test cases for API token and zone tag --- tests/CloudflareAnalyticsTest.php | 49 +++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 tests/CloudflareAnalyticsTest.php diff --git a/tests/CloudflareAnalyticsTest.php b/tests/CloudflareAnalyticsTest.php new file mode 100644 index 0000000..32c810f --- /dev/null +++ b/tests/CloudflareAnalyticsTest.php @@ -0,0 +1,49 @@ +cf = new \The3LabsTeam\PhpCloudflareAnalytics\CloudflareAnalytics; +}); + +it('can set API token and zone tag', function () { + $apiToken = 'your-api-token'; + $zoneTag = 'your-zone-tag'; + + $cf = new \The3LabsTeam\PhpCloudflareAnalytics\CloudflareAnalytics($apiToken, $zoneTag); + + $this->assertEquals($apiToken, $cf->apiToken); + $this->assertEquals($zoneTag, $cf->zoneTag); +}); + + +it('can get total views between two dates', function () { + $startDate = date('Y-m-d', strtotime('-2 months')); + $endDate = date('Y-m-d'); + + $cf = new \The3LabsTeam\PhpCloudflareAnalytics\CloudflareAnalytics(); + $result = $cf->whereBetween($startDate, $endDate)->get(); + + $this->assertIsArray($result); + $this->assertGreaterThan(0, $result); + +}); + +it('can get total views with a specific limit', function () { + $limit = 10; + + $cf = new \The3LabsTeam\PhpCloudflareAnalytics\CloudflareAnalytics(); + $result = $cf->take($limit)->get(); + + $this->assertIsArray($result); + $this->assertGreaterThan(0, $result); +}); + +it('can get total views with custom parameters', function () { + $param = 'cachedRequests'; + $paramType = 'cachedBytes'; + + $cf = new \The3LabsTeam\PhpCloudflareAnalytics\CloudflareAnalytics(); + $result = $cf->get($param, $paramType); + + $this->assertIsArray($result); + $this->assertGreaterThan(0, $result); +}); \ No newline at end of file From ed5c847392de3d75cdb7248849c4762d66a10a2e Mon Sep 17 00:00:00 2001 From: Stefano Novelli Date: Thu, 1 Aug 2024 22:56:23 +0200 Subject: [PATCH 03/12] chore: Refactor CloudflareAnalytics constructor and add dotenv support --- src/CloudflareAnalytics.php | 129 ++++++++++++++++-------------------- 1 file changed, 57 insertions(+), 72 deletions(-) diff --git a/src/CloudflareAnalytics.php b/src/CloudflareAnalytics.php index d4e1d27..5aac319 100755 --- a/src/CloudflareAnalytics.php +++ b/src/CloudflareAnalytics.php @@ -2,24 +2,43 @@ namespace The3LabsTeam\PhpCloudflareAnalytics; +use Dotenv\Dotenv; + + class CloudflareAnalytics { - public string $api_token; - + public string $apiToken; public string $zoneTag; - public string $endpoint; - public function __construct(string $zoneTag) + public string $startDate; + public string $endDate; + public int $limit; + + /** + * CloudflareAnalytics constructor. + * + * @param string|null $apiToken + * @param string|null $zoneTag + */ + public function __construct(?string $apiToken = null, ?string $zoneTag = null) { - $this->api_token = env('CLOUDFLARE_API_TOKEN'); - $this->zoneTag = $zoneTag; + $dotenv = Dotenv::createImmutable(__DIR__.'/../'); + $dotenv->load(); + + $this->apiToken = $apiToken ?? $_ENV['CLOUDFLARE_API_TOKEN']; + $this->zoneTag = $zoneTag ?? $_ENV['CLOUDFLARE_ZONE_TAG_ID']; $this->endpoint = 'https://api.cloudflare.com/client/v4/graphql'; - } - // ================== UTILITY ================== // + $this->startDate = date('Y-m-d', strtotime('-1 month')); + $this->endDate = date('Y-m-d'); + $this->limit = 1000; + } - protected function graphQLQuery($query) + /** + * Query the Cloudflare API + */ + protected function query($query) { $ch = curl_init($this->endpoint); curl_setopt_array($ch, [ @@ -28,7 +47,7 @@ protected function graphQLQuery($query) CURLOPT_POSTFIELDS => json_encode(['query' => $query]), CURLOPT_HTTPHEADER => [ 'Content-Type: application/json', - 'Authorization: Bearer '.$this->api_token, + 'Authorization: Bearer '.$this->apiToken, ], ]); @@ -56,27 +75,40 @@ protected function sumTotal($response, $zonesType, $param, $paramType) return $total; } - // ================== DEFAULT FUNCTIONS ================== // + /** + * Get the total views between two dates - Returns the total views + */ + public function whereBetween(string $startDate, string $endDate) { + $this->startDate = $startDate; + $this->endDate = $endDate; + + return $this; + } - //TODO: Merge all the functions in one function with parameters /** - * Get the total views between two dates - Returns the total views - * - * @param $param - 'sum' | 'uniq' - * @param $paramType - sum : 'request', 'pageViews', 'cachedBytes', 'cachedRequests', 'threats' | uniq: 'uniques' - * @return int|mixed + * Get a specific number of results */ - public function getBetweenDates($startDate, $endDate, $param = 'sum', $paramType = 'pageViews') + public function take(int $limit) { + $this->limit = $limit; + + return $this; + } + + /** + * Get data + */ + public function get($param = 'uniq', $paramType = 'pageViews') { + $query = <<zoneTag"}) { httpRequests1dGroups( - limit: 1000 + limit: $this->limit filter: { - date_geq: "$startDate" - date_lt: "$endDate" + date_geq: "$this->startDate" + date_lt: "$this->endDate" } ) { sum { @@ -95,7 +127,9 @@ public function getBetweenDates($startDate, $endDate, $param = 'sum', $paramType } GRAPHQL; - $response = $this->graphQLQuery($query); + $response = $this->query($query); + + return $response; return $this->sumTotal($response, 'httpRequests1dGroups', $param, $paramType); } @@ -141,58 +175,9 @@ public function getBetweenHours($sub, $param, $paramType) } GRAPHQL; - $response = $this->graphQLQuery($query); + $response = $this->query($query); return $this->sumTotal($response, 'httpRequests1hGroups', $param, $paramType); } - // ================== DEFAULT PRESET ================== // - - /** - * Get the total views last 6 hours - Returns the total views - * - * @return int|mixed - */ - public function getLast6Hours($param, $paramType) - { - return $this->getBetweenHours(sub: '-6 hours', param: $param, paramType: $paramType); - } - - /** - * Get the total views last 24 hours - Returns the total views - * - * @return int|mixed - */ - public function getLast24Hours($param, $paramType) - { - return $this->getBetweenHours(sub: '-24 hours', param: $param, paramType: $paramType); - } - - /** - * Get the total views last 7 days - Returns the total views - * - * @return int|mixed - */ - public function getLast7Days($param, $paramType) - { - // Current date/time in Y-m-d - $startDate = date('Y-m-d', strtotime('-7 days')); - $endDate = date('Y-m-d'); - - return $this->getBetweenDates(startDate: $startDate, endDate: $endDate, param: $param, paramType: $paramType); - } - - /** - * Get the total views last month - Returns the total views - * - * @return int|mixed - */ - public function getLastMonth($param, $paramType) - { - // Current date/time in Y-m-d - $startDate = date('Y-m-d', strtotime('-1 month')); - $endDate = date('Y-m-d'); - - return $this->getBetweenDates(startDate: $startDate, endDate: $endDate, param: $param, paramType: $paramType); - } } From cab2defc6635e7fef607d0e9685318e5aa540078 Mon Sep 17 00:00:00 2001 From: Stefano Novelli Date: Fri, 2 Aug 2024 10:27:22 +0200 Subject: [PATCH 04/12] wip for single call --- README.md | 105 +++++++++++++++++--------- src/CloudflareAnalytics.php | 121 ++++++++++++++++++------------ tests/CloudflareAnalyticsTest.php | 63 ++++++++-------- 3 files changed, 173 insertions(+), 116 deletions(-) diff --git a/README.md b/README.md index 59fc9be..dcd17e9 100644 --- a/README.md +++ b/README.md @@ -8,63 +8,94 @@ CLOUDFLARE_ZONE_TAG_ID='zoneTag' ## Refactor -// init -$cf = new \The3LabsTeam\PhpCloudflareAnalytics\CloudflareAnalytics( - // optional, if you want to use the default values from the .env file +Usabe fields: firewallEventsAdaptive, + +```php + +use The3LabsTeam\PhpCloudflareAnalytics\CloudflareAnalytics; + +$cf = new CloudflareAnalytics( token: 'your_cloudflare_api_token', zoneTag: 'zoneTag' ); -// 1. -$cf->getPageViews()->whereBetweenDates('2021-10-01', '2021-10-31')->get(); +$cf = new CloudflareAnalytics(); +// Get results +// $cf->get(); -## Usage +// // Filter by date +// $cf->whereBetween('2021-01-01', '2021-01-31')->get(); -Default use: +// // Limit the results +// $cf->take(10)->get(); -```php -(new \The3LabsTeam\PhpCloudflareAnalytics\CloudflareAnalytics('zoneTag')) -``` -next you can use the following methods: +// // Order the results +// $cf->orderBy('datetiime', 'DESC')->get(); -```php -->getLast6Hours($param, $paramType) -->getLast24Hours($param, $paramType) +-- multiple filters -- -->getLast7Days($param, $paramType) +$cf->select('firewallEventsAdaptive AS last10Events', 'httpRequestsAdaptiveGroups AS top3DeviceTypes') + ->whereBetween('last10Events.2021-01-01', 'last10Events.2021-01-31') + ->whereBetween('top3DeviceTypes.2021-01-01', 'top3DeviceTypes.2021-01-31') + ->orderBy('last10Events.datetime', 'DESC') + ->orderBy('top3DeviceTypes.count', 'DESC') + ->get(); -->getLastMonth($param, $paramType) ``` -and you can pass the following parameters to get the data: -- PARAM => `sum` or `uniq` -- PARAM TYPE - - SUM: `request`, `pageViews`, `cachedBytes`, `cachedRequests`, `threats` - - UNIQ: `uniques` +DEMO MULTIPLE FILTERS + +```graphql + +{ + viewer { + zones(filter: { zoneTag: $tag }) { + last10Events: firewallEventsAdaptive( + filter: { + datetime_gt: $start + datetime_lt: $end + } + limit: 10 + orderBy: [ + datetime_DESC + ] + ) { + action + datetime + host: clientRequestHTTPHost + } + top3DeviceTypes: httpRequestsAdaptiveGroups( + filter: { + date: $ts + } + limit: 10 + orderBy: [ + count_DESC + ] + ) { + count + dimensions { + device: clientDeviceType + } + } + } + } +} -### Example +``` -Get the total number of requests in the last 6 hours: -```php -$cloudflare = new \The3LabsTeam\PhpCloudflareAnalytics\CloudflareAnalytics('29djm3nr...'); -$cloudflare->getLast6Hours('sum', 'request'); -``` +## Usage -Get the total number of unique visitors in the last 24 hours: -```php -$cloudflare = new \The3LabsTeam\PhpCloudflareAnalytics\CloudflareAnalytics('29djm3nr...'); -$cloudflare->getLast24Hours('uniq', 'uniques'); -``` -Get the total number of page views in the last 7 days: -```php -$cloudflare = new \The3LabsTeam\PhpCloudflareAnalytics\CloudflareAnalytics('29djm3nr...'); -$cloudflare->geLast7Days('sum', 'pageViews'); -``` +and you can pass the following parameters to get the data: +- PARAM => `sum` or `uniq` +- PARAM TYPE + - SUM: `request`, `pageViews`, `cachedBytes`, `cachedRequests`, `threats` + - UNIQ: `uniques` diff --git a/src/CloudflareAnalytics.php b/src/CloudflareAnalytics.php index 5aac319..ea0c683 100755 --- a/src/CloudflareAnalytics.php +++ b/src/CloudflareAnalytics.php @@ -4,35 +4,38 @@ use Dotenv\Dotenv; - class CloudflareAnalytics { - public string $apiToken; - public string $zoneTag; - public string $endpoint; + private string $apiToken; + + private string $zoneTag; + + protected string $endpoint; + + protected string $startDate; + + protected string $endDate; - public string $startDate; - public string $endDate; - public int $limit; + protected ?int $limit; + + protected ?string $orderBy; /** * CloudflareAnalytics constructor. - * - * @param string|null $apiToken - * @param string|null $zoneTag */ public function __construct(?string $apiToken = null, ?string $zoneTag = null) { - $dotenv = Dotenv::createImmutable(__DIR__.'/../'); - $dotenv->load(); + $dotenv = Dotenv::createImmutable(__DIR__.'/../'); + $dotenv->load(); $this->apiToken = $apiToken ?? $_ENV['CLOUDFLARE_API_TOKEN']; $this->zoneTag = $zoneTag ?? $_ENV['CLOUDFLARE_ZONE_TAG_ID']; $this->endpoint = 'https://api.cloudflare.com/client/v4/graphql'; - $this->startDate = date('Y-m-d', strtotime('-1 month')); - $this->endDate = date('Y-m-d'); + $this->startDate = (new \DateTime('-1 day'))->format('c'); + $this->endDate = (new \DateTime)->format('c'); $this->limit = 1000; + $this->orderBy = 'datetime_DESC'; } /** @@ -63,63 +66,74 @@ protected function query($query) return $response; } - protected function sumTotal($response, $zonesType, $param, $paramType) + /** + * Get the total views between two dates - Returns the total views + */ + public function whereBetween(string $startDate, string $endDate) { - $response = $response['data']['viewer']['zones'][0][$zonesType]; - - $total = 0; - foreach ($response as $key => $value) { - $total += $value[$param][$paramType]; - } + $this->startDate = $startDate; + $this->endDate = $endDate; - return $total; + return $this; } - /** - * Get the total views between two dates - Returns the total views + /** + * Set the order by field and direction */ - public function whereBetween(string $startDate, string $endDate) { - $this->startDate = $startDate; - $this->endDate = $endDate; + public function orderBy(string $field, string $direction = 'ASC') + { + $this->orderBy = $field.'_'.$direction; - return $this; + return $this; } /** * Get a specific number of results */ - public function take(int $limit) { - $this->limit = $limit; + public function take(int $limit) + { + $this->limit = $limit; - return $this; + return $this; } /** * Get data */ - public function get($param = 'uniq', $paramType = 'pageViews') + public function get() { $query = <<zoneTag"}) { - httpRequests1dGroups( - limit: $this->limit + last10Events: firewallEventsAdaptive( filter: { - date_geq: "$this->startDate" - date_lt: "$this->endDate" + datetime_gt: "$this->startDate" + datetime_lt: "$this->endDate" } + limit: 10 + orderBy: [ + datetime_DESC + ] ) { - sum { - requests - pageViews - cachedBytes - cachedRequests - threats + action + datetime + host: clientRequestHTTPHost + } + top3DeviceTypes: httpRequestsAdaptiveGroups( + filter: { + datetime_gt: "$this->startDate" + datetime_lt: "$this->endDate" } - uniq { - uniques + limit: 10 + orderBy: [ + count_DESC + ] + ) { + count + dimensions { + device: clientDeviceType } } } @@ -129,11 +143,25 @@ public function get($param = 'uniq', $paramType = 'pageViews') $response = $this->query($query); + dd($response); + return $response; - return $this->sumTotal($response, 'httpRequests1dGroups', $param, $paramType); + // return $this->sumTotal($response, 'httpRequests1dGroups', $param, $paramType); } + // protected function sumTotal($response, $zonesType, $param, $paramType) + // { + // $response = $response['data']['viewer']['zones'][0][$zonesType]; + + // $total = 0; + // foreach ($response as $key => $value) { + // $total += $value[$param][$paramType]; + // } + + // return $total; + // } + /** * Get the total views between two dates - Return the total views * @@ -177,7 +205,6 @@ public function getBetweenHours($sub, $param, $paramType) $response = $this->query($query); - return $this->sumTotal($response, 'httpRequests1hGroups', $param, $paramType); + // return $this->sumTotal($response, 'httpRequests1hGroups', $param, $paramType); } - } diff --git a/tests/CloudflareAnalyticsTest.php b/tests/CloudflareAnalyticsTest.php index 32c810f..f089438 100644 --- a/tests/CloudflareAnalyticsTest.php +++ b/tests/CloudflareAnalyticsTest.php @@ -1,49 +1,48 @@ cf = new \The3LabsTeam\PhpCloudflareAnalytics\CloudflareAnalytics; + $this->cf = new CloudflareAnalytics; }); -it('can set API token and zone tag', function () { - $apiToken = 'your-api-token'; - $zoneTag = 'your-zone-tag'; - - $cf = new \The3LabsTeam\PhpCloudflareAnalytics\CloudflareAnalytics($apiToken, $zoneTag); +it('can get total views', function () { + $cf = new CloudflareAnalytics; + $result = $cf->get(); - $this->assertEquals($apiToken, $cf->apiToken); - $this->assertEquals($zoneTag, $cf->zoneTag); + $this->assertIsArray($result); + $this->assertGreaterThan(0, $result); }); +// it('can get total views between two dates', function () { +// $startDate = date('Y-m-d', strtotime('-2 months')); +// $endDate = date('Y-m-d'); -it('can get total views between two dates', function () { - $startDate = date('Y-m-d', strtotime('-2 months')); - $endDate = date('Y-m-d'); +// $cf = new \The3LabsTeam\PhpCloudflareAnalytics\CloudflareAnalytics(); +// $result = $cf->whereBetween($startDate, $endDate)->get(); - $cf = new \The3LabsTeam\PhpCloudflareAnalytics\CloudflareAnalytics(); - $result = $cf->whereBetween($startDate, $endDate)->get(); +// $this->assertIsArray($result); +// $this->assertGreaterThan(0, $result); - $this->assertIsArray($result); - $this->assertGreaterThan(0, $result); +// }); -}); +// it('can get total views with a specific limit', function () { +// $limit = 10; -it('can get total views with a specific limit', function () { - $limit = 10; +// $cf = new \The3LabsTeam\PhpCloudflareAnalytics\CloudflareAnalytics(); +// $result = $cf->take($limit)->get(); - $cf = new \The3LabsTeam\PhpCloudflareAnalytics\CloudflareAnalytics(); - $result = $cf->take($limit)->get(); +// $this->assertIsArray($result); +// $this->assertGreaterThan(0, $result); +// }); - $this->assertIsArray($result); - $this->assertGreaterThan(0, $result); -}); +// it('can get total views with custom parameters', function () { +// $param = 'cachedRequests'; +// $paramType = 'cachedBytes'; -it('can get total views with custom parameters', function () { - $param = 'cachedRequests'; - $paramType = 'cachedBytes'; +// $cf = new \The3LabsTeam\PhpCloudflareAnalytics\CloudflareAnalytics(); +// $result = $cf->get($param, $paramType); - $cf = new \The3LabsTeam\PhpCloudflareAnalytics\CloudflareAnalytics(); - $result = $cf->get($param, $paramType); - - $this->assertIsArray($result); - $this->assertGreaterThan(0, $result); -}); \ No newline at end of file +// $this->assertIsArray($result); +// $this->assertGreaterThan(0, $result); +// }); From 48d0e8a4b0eab1739069018bcd76894ac46cdc26 Mon Sep 17 00:00:00 2001 From: Stefano Novelli Date: Fri, 2 Aug 2024 12:22:33 +0200 Subject: [PATCH 05/12] dynamic get --- src/CloudflareAnalytics.php | 174 ++++++++++++------------------ tests/CloudflareAnalyticsTest.php | 16 ++- 2 files changed, 80 insertions(+), 110 deletions(-) diff --git a/src/CloudflareAnalytics.php b/src/CloudflareAnalytics.php index ea0c683..174dcbc 100755 --- a/src/CloudflareAnalytics.php +++ b/src/CloudflareAnalytics.php @@ -12,13 +12,13 @@ class CloudflareAnalytics protected string $endpoint; - protected string $startDate; + protected array $selectors = []; - protected string $endDate; + protected array $filters = []; - protected ?int $limit; + protected array $orderBys = []; - protected ?string $orderBy; + protected $takes = []; /** * CloudflareAnalytics constructor. @@ -31,11 +31,16 @@ public function __construct(?string $apiToken = null, ?string $zoneTag = null) $this->apiToken = $apiToken ?? $_ENV['CLOUDFLARE_API_TOKEN']; $this->zoneTag = $zoneTag ?? $_ENV['CLOUDFLARE_ZONE_TAG_ID']; $this->endpoint = 'https://api.cloudflare.com/client/v4/graphql'; + } + + public function select(...$selectors) + { + foreach ($selectors as $selector) { + [$key, $alias] = explode(' AS ', $selector); + $this->selectors[$alias] = $key; + } - $this->startDate = (new \DateTime('-1 day'))->format('c'); - $this->endDate = (new \DateTime)->format('c'); - $this->limit = 1000; - $this->orderBy = 'datetime_DESC'; + return $this; } /** @@ -69,10 +74,12 @@ protected function query($query) /** * Get the total views between two dates - Returns the total views */ - public function whereBetween(string $startDate, string $endDate) + public function whereBetween(string $context, string $startDate, string $endDate) { - $this->startDate = $startDate; - $this->endDate = $endDate; + $this->filters[$context] = [ + 'startDate' => $startDate, + 'endDate' => $endDate, + ]; return $this; } @@ -80,9 +87,9 @@ public function whereBetween(string $startDate, string $endDate) /** * Set the order by field and direction */ - public function orderBy(string $field, string $direction = 'ASC') + public function orderBy(string $context, string $field, string $direction = 'ASC') { - $this->orderBy = $field.'_'.$direction; + $this->orderBys[$context][] = $field.'_'.$direction; return $this; } @@ -90,9 +97,9 @@ public function orderBy(string $field, string $direction = 'ASC') /** * Get a specific number of results */ - public function take(int $limit) + public function take($alias, $limit) { - $this->limit = $limit; + $this->takes[$alias] = $limit; return $this; } @@ -100,111 +107,66 @@ public function take(int $limit) /** * Get data */ - public function get() + public function get(...$fields) { - - $query = <<zoneTag"}) { - last10Events: firewallEventsAdaptive( - filter: { - datetime_gt: "$this->startDate" - datetime_lt: "$this->endDate" - } - limit: 10 - orderBy: [ - datetime_DESC - ] - ) { - action - datetime - host: clientRequestHTTPHost + $queries = []; + foreach ($this->selectors as $alias => $selector) { + $filter = $this->filters[$alias] ?? []; + $orderBy = $this->orderBys[$alias] ?? []; + $limit = isset($this->takes[$alias]) ? $this->takes[$alias] : 10; + + $fieldsList = implode("\n", array_map(fn ($f) => str_replace("$alias.", "", $f), $fields)); + + $queries[] = <<startDate" - datetime_lt: "$this->endDate" - } - limit: 10 - orderBy: [ - count_DESC - ] - ) { - count - dimensions { - device: clientDeviceType - } - } - } + limit: $limit + orderBy: [ + {$this->formatOrderBy($orderBy)} + ] + ) { + $fieldsList + } + GRAPHQL; + } + + $query = <<zoneTag"}) { + {$this->formatQueries($queries)} } } - GRAPHQL; + } + GRAPHQL; $response = $this->query($query); - dd($response); - return $response; - - // return $this->sumTotal($response, 'httpRequests1dGroups', $param, $paramType); } - // protected function sumTotal($response, $zonesType, $param, $paramType) - // { - // $response = $response['data']['viewer']['zones'][0][$zonesType]; - - // $total = 0; - // foreach ($response as $key => $value) { - // $total += $value[$param][$paramType]; - // } + private function formatOrderBy(array $orderBy) + { + return implode("\n", array_map(fn ($o) => $o, $orderBy)); + } - // return $total; - // } + private function formatQueries(array $queries) + { + return implode("\n", array_map(fn ($q) => $q, $queries)); + } - /** - * Get the total views between two dates - Return the total views - * - * @return array - */ - public function getBetweenHours($sub, $param, $paramType) + private function formatTakes() { - // Current date/time in ISO 8601 format - $endDate = date('c'); - $startDate = date('c', strtotime($sub)); - - $query = <<zoneTag"}) { - httpRequests1hGroups( - limit: 1000 - filter: { - datetime_geq: "$startDate" - datetime_lt: "$endDate" - } - ) { - dimensions { - datetime - } - sum { - requests - pageViews - cachedBytes - cachedRequests - threats - } - uniq { - uniques - } - } - } - } + $takes = []; + foreach ($this->takes as $alias => $limit) { + if (is_int($limit)) { + $takes[] = "{$alias}: {$limit}"; } - GRAPHQL; - - $response = $this->query($query); + } - // return $this->sumTotal($response, 'httpRequests1hGroups', $param, $paramType); + return implode(', ', $takes); } } diff --git a/tests/CloudflareAnalyticsTest.php b/tests/CloudflareAnalyticsTest.php index f089438..171a1c0 100644 --- a/tests/CloudflareAnalyticsTest.php +++ b/tests/CloudflareAnalyticsTest.php @@ -6,12 +6,20 @@ $this->cf = new CloudflareAnalytics; }); -it('can get total views', function () { +it('can get firewall data', function () { + $startDate = (new DateTime)->sub(new DateInterval('P1D'))->format('c'); + $endDate = (new DateTime)->format('c'); + $cf = new CloudflareAnalytics; - $result = $cf->get(); - $this->assertIsArray($result); - $this->assertGreaterThan(0, $result); + $results = $cf->select('firewallEventsAdaptive AS firewall') + ->whereBetween('firewall', $startDate, $endDate) + ->orderBy('firewall.datetime', 'DESC') + ->take('firewall', 2) + ->get('firewall.datetime', 'firewall.action'); + + $this->assertIsArray($results); + $this->assertGreaterThan(0, $results); }); // it('can get total views between two dates', function () { From b909ba6a3245b66e7854314fc29d4ec92a5d0af8 Mon Sep 17 00:00:00 2001 From: murdercode Date: Fri, 2 Aug 2024 10:22:58 +0000 Subject: [PATCH 06/12] Fix styling --- src/CloudflareAnalytics.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/CloudflareAnalytics.php b/src/CloudflareAnalytics.php index 174dcbc..e954290 100755 --- a/src/CloudflareAnalytics.php +++ b/src/CloudflareAnalytics.php @@ -109,15 +109,15 @@ public function take($alias, $limit) */ public function get(...$fields) { - $queries = []; - foreach ($this->selectors as $alias => $selector) { - $filter = $this->filters[$alias] ?? []; - $orderBy = $this->orderBys[$alias] ?? []; - $limit = isset($this->takes[$alias]) ? $this->takes[$alias] : 10; + $queries = []; + foreach ($this->selectors as $alias => $selector) { + $filter = $this->filters[$alias] ?? []; + $orderBy = $this->orderBys[$alias] ?? []; + $limit = isset($this->takes[$alias]) ? $this->takes[$alias] : 10; - $fieldsList = implode("\n", array_map(fn ($f) => str_replace("$alias.", "", $f), $fields)); + $fieldsList = implode("\n", array_map(fn ($f) => str_replace("$alias.", '', $f), $fields)); - $queries[] = <<zoneTag"}) { From 1ba6d42d6886ea07d95b4f45045d74b5372b9c5b Mon Sep 17 00:00:00 2001 From: Stefano Novelli Date: Mon, 5 Aug 2024 08:34:28 +0200 Subject: [PATCH 07/12] chore: Refactor CloudflareAnalytics constructor and add dotenv support --- README.md | 113 ++++++++++++------------------ src/CloudflareAnalytics.php | 2 +- tests/CloudflareAnalyticsTest.php | 12 ++++ 3 files changed, 57 insertions(+), 70 deletions(-) diff --git a/README.md b/README.md index dcd17e9..c97d9ac 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,16 @@ +# Cloudflare Analytics GraphQL API PHP Client + +This package is a simple PHP client for the Cloudflare Analytics GraphQL API. + +## Installation + +You can install the package via composer: + +```bash +composer require the3labsteam/php-cloudflare-analytics +``` + +## Configuration Add in your .env file the following variables: @@ -6,96 +19,58 @@ CLOUDFLARE_API_TOKEN='your_cloudflare_api_token' CLOUDFLARE_ZONE_TAG_ID='zoneTag' ``` -## Refactor - -Usabe fields: firewallEventsAdaptive, +or you can pass the token and zoneTag as parameters in the constructor. ```php - use The3LabsTeam\PhpCloudflareAnalytics\CloudflareAnalytics; $cf = new CloudflareAnalytics( token: 'your_cloudflare_api_token', zoneTag: 'zoneTag' ); +``` -$cf = new CloudflareAnalytics(); - -// Get results -// $cf->get(); - -// // Filter by date -// $cf->whereBetween('2021-01-01', '2021-01-31')->get(); - -// // Limit the results -// $cf->take(10)->get(); - -// // Order the results -// $cf->orderBy('datetiime', 'DESC')->get(); +## Usage +You can use the following methods to build your query: --- multiple filters -- +```php +use The3LabsTeam\PhpCloudflareAnalytics\CloudflareAnalytics; +$startDate = (new DateTime)->sub(new DateInterval('P1D'))->format('c'); +$endDate = (new DateTime)->format('c'); -$cf->select('firewallEventsAdaptive AS last10Events', 'httpRequestsAdaptiveGroups AS top3DeviceTypes') - ->whereBetween('last10Events.2021-01-01', 'last10Events.2021-01-31') - ->whereBetween('top3DeviceTypes.2021-01-01', 'top3DeviceTypes.2021-01-31') - ->orderBy('last10Events.datetime', 'DESC') - ->orderBy('top3DeviceTypes.count', 'DESC') - ->get(); +$cf = new CloudflareAnalytics; +$results = $cf->select('firewallEventsAdaptive AS firewall') + ->whereBetween('firewall', $startDate, $endDate) + ->orderBy('firewall.datetime', 'DESC') + ->take('firewall', 2) + ->get('firewall.datetime', 'firewall.action'); ``` +In the example above, we are querying the `firewallEventsAdaptive` field, filtering by the last 24 hours, ordering by datetime in descending order, and limiting the results to 2. -DEMO MULTIPLE FILTERS - -```graphql - -{ - viewer { - zones(filter: { zoneTag: $tag }) { - last10Events: firewallEventsAdaptive( - filter: { - datetime_gt: $start - datetime_lt: $end - } - limit: 10 - orderBy: [ - datetime_DESC - ] - ) { - action - datetime - host: clientRequestHTTPHost - } - top3DeviceTypes: httpRequestsAdaptiveGroups( - filter: { - date: $ts - } - limit: 10 - orderBy: [ - count_DESC - ] - ) { - count - dimensions { - device: clientDeviceType - } - } - } - } -} +The `get` method will return an array with the results. -``` +## Available fields +- `firewallEventsAdaptive` +- `httpRequests1mGroups` +- `httpRequestsAdaptiveGroups` +- `threatsAdaptiveGroups` +- `threatsByCountryAdaptiveGroups` -## Usage +## Testing +```bash +composer test +``` +## License +The MIT License (MIT). Please see [License File](LICENSE.md) for more information. +## Credits -and you can pass the following parameters to get the data: +- [The3LabsTeam](https://3labs.it) -- PARAM => `sum` or `uniq` -- PARAM TYPE - - SUM: `request`, `pageViews`, `cachedBytes`, `cachedRequests`, `threats` - - UNIQ: `uniques` +// TODO: Add the rest of the file \ No newline at end of file diff --git a/src/CloudflareAnalytics.php b/src/CloudflareAnalytics.php index e954290..c200a87 100755 --- a/src/CloudflareAnalytics.php +++ b/src/CloudflareAnalytics.php @@ -115,7 +115,7 @@ public function get(...$fields) $orderBy = $this->orderBys[$alias] ?? []; $limit = isset($this->takes[$alias]) ? $this->takes[$alias] : 10; - $fieldsList = implode("\n", array_map(fn ($f) => str_replace("$alias.", '', $f), $fields)); + $fieldsList = implode("\n", array_map(fn ($f) => str_replace("$alias.", "", $f), $fields)); $queries[] = <<assertGreaterThan(0, $results); }); +it('can get total views', function () { + $cf = new CloudflareAnalytics; + + $results = $cf->select('httpRequests1mGroups AS http') + ->get('http.sum.requests'); + + dd($results); + + $this->assertIsArray($results); + $this->assertGreaterThan(0, $results); +}); + // it('can get total views between two dates', function () { // $startDate = date('Y-m-d', strtotime('-2 months')); // $endDate = date('Y-m-d'); From 2c888f0043208ce071f4cc828cf2ad686ede4db4 Mon Sep 17 00:00:00 2001 From: murdercode Date: Mon, 5 Aug 2024 06:34:58 +0000 Subject: [PATCH 08/12] Fix styling --- src/CloudflareAnalytics.php | 2 +- tests/CloudflareAnalyticsTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/CloudflareAnalytics.php b/src/CloudflareAnalytics.php index c200a87..e954290 100755 --- a/src/CloudflareAnalytics.php +++ b/src/CloudflareAnalytics.php @@ -115,7 +115,7 @@ public function get(...$fields) $orderBy = $this->orderBys[$alias] ?? []; $limit = isset($this->takes[$alias]) ? $this->takes[$alias] : 10; - $fieldsList = implode("\n", array_map(fn ($f) => str_replace("$alias.", "", $f), $fields)); + $fieldsList = implode("\n", array_map(fn ($f) => str_replace("$alias.", '', $f), $fields)); $queries[] = <<select('httpRequests1mGroups AS http') ->get('http.sum.requests'); - dd($results); + dd($results); $this->assertIsArray($results); $this->assertGreaterThan(0, $results); From 226cfc83da4e7f5392d49b48e3039bb285e2d819 Mon Sep 17 00:00:00 2001 From: Stefano Novelli Date: Mon, 5 Aug 2024 12:42:19 +0200 Subject: [PATCH 09/12] Better defaults --- README.md | 49 ++++++++++++++++++++++++++----- src/CloudflareAnalytics.php | 11 +++++-- tests/CloudflareAnalyticsTest.php | 33 +++++++++++++++++---- 3 files changed, 78 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index c97d9ac..a475cc2 100644 --- a/README.md +++ b/README.md @@ -35,20 +35,13 @@ You can use the following methods to build your query: ```php use The3LabsTeam\PhpCloudflareAnalytics\CloudflareAnalytics; -$startDate = (new DateTime)->sub(new DateInterval('P1D'))->format('c'); -$endDate = (new DateTime)->format('c'); $cf = new CloudflareAnalytics; $results = $cf->select('firewallEventsAdaptive AS firewall') - ->whereBetween('firewall', $startDate, $endDate) - ->orderBy('firewall.datetime', 'DESC') - ->take('firewall', 2) ->get('firewall.datetime', 'firewall.action'); ``` -In the example above, we are querying the `firewallEventsAdaptive` field, filtering by the last 24 hours, ordering by datetime in descending order, and limiting the results to 2. - The `get` method will return an array with the results. ## Available fields @@ -59,6 +52,48 @@ The `get` method will return an array with the results. - `threatsAdaptiveGroups` - `threatsByCountryAdaptiveGroups` +## Default fields + +- `datetime`: 1 day +- `take`: 10 +- `orderBy`: `datetime` + +## Demo + +Get last http visits: + +```php +$results = $cf->select('httpRequestsAdaptiveGroups AS http') + ->get('http.datetime', 'http.requests'); +``` + +Get last http visits between two dates: + +```php +$startDate = (new DateTime)->sub(new DateInterval('P1D'))->format('c'); +$endDate = (new DateTime)->format('c'); + +$results = $cf->select('httpRequestsAdaptiveGroups AS http') + ->whereBetween('http', $startDate, $endDate) + ->get('http.datetime', 'http.requests'); +``` + +Get last http visits, limit the results to 2: + +```php +$results = $cf->select('httpRequestsAdaptiveGroups AS http') + ->take('http', 2) + ->get('http.datetime', 'http.requests'); +``` + +Get last http visits, order by datetime: + +```php +$results = $cf->select('httpRequestsAdaptiveGroups AS http') + ->orderBy('http', 'datetime') + ->get('http.datetime', 'http.requests'); +``` + ## Testing ```bash diff --git a/src/CloudflareAnalytics.php b/src/CloudflareAnalytics.php index c200a87..a9aa4dd 100755 --- a/src/CloudflareAnalytics.php +++ b/src/CloudflareAnalytics.php @@ -3,6 +3,8 @@ namespace The3LabsTeam\PhpCloudflareAnalytics; use Dotenv\Dotenv; +use DateTime; +use DateInterval; class CloudflareAnalytics { @@ -112,16 +114,19 @@ public function get(...$fields) $queries = []; foreach ($this->selectors as $alias => $selector) { $filter = $this->filters[$alias] ?? []; - $orderBy = $this->orderBys[$alias] ?? []; + $orderBy = $this->orderBys[$alias] ?? ['datetime_DESC']; $limit = isset($this->takes[$alias]) ? $this->takes[$alias] : 10; + $startDate = $filter['startDate'] ?? (new DateTime)->sub(new DateInterval('P1D'))->format('c'); + $endDate = $filter['endDate'] ?? (new DateTime)->format('c'); + $fieldsList = implode("\n", array_map(fn ($f) => str_replace("$alias.", "", $f), $fields)); $queries[] = <<select('firewallEventsAdaptive AS firewall') + ->get('firewall.datetime', 'firewall.action'); + + $this->assertIsArray($results); + $this->assertGreaterThan(0, $results); +}); + +it('can get firewall between two dates', function () { $startDate = (new DateTime)->sub(new DateInterval('P1D'))->format('c'); $endDate = (new DateTime)->format('c'); @@ -22,18 +32,31 @@ $this->assertGreaterThan(0, $results); }); -it('can get total views', function () { - $cf = new CloudflareAnalytics; +it('can get firewall data with a specific limit', function () { + $limit = 10; - $results = $cf->select('httpRequests1mGroups AS http') - ->get('http.sum.requests'); + $cf = new CloudflareAnalytics; - dd($results); + $results = $cf->select('firewallEventsAdaptive AS firewall') + ->take('firewall', $limit) + ->get('firewall.datetime', 'firewall.action'); $this->assertIsArray($results); $this->assertGreaterThan(0, $results); }); +// it('can get total views', function () { +// $cf = new CloudflareAnalytics; + +// $results = $cf->select('httpRequests1mGroups AS http') +// ->get('http.sum.requests'); + +// dd($results); + +// $this->assertIsArray($results); +// $this->assertGreaterThan(0, $results); +// }); + // it('can get total views between two dates', function () { // $startDate = date('Y-m-d', strtotime('-2 months')); // $endDate = date('Y-m-d'); From 3da701b8d9863162d7be45409a236b1b635c40c1 Mon Sep 17 00:00:00 2001 From: Stefano Novelli Date: Mon, 5 Aug 2024 12:43:34 +0200 Subject: [PATCH 10/12] chore: Refactor CloudflareAnalyticsTest to include specific order, limit, and date range queries --- tests/CloudflareAnalyticsTest.php | 65 +++++++++++++++---------------- 1 file changed, 31 insertions(+), 34 deletions(-) diff --git a/tests/CloudflareAnalyticsTest.php b/tests/CloudflareAnalyticsTest.php index e76e713..ebcba61 100644 --- a/tests/CloudflareAnalyticsTest.php +++ b/tests/CloudflareAnalyticsTest.php @@ -45,47 +45,44 @@ $this->assertGreaterThan(0, $results); }); -// it('can get total views', function () { -// $cf = new CloudflareAnalytics; - -// $results = $cf->select('httpRequests1mGroups AS http') -// ->get('http.sum.requests'); - -// dd($results); - -// $this->assertIsArray($results); -// $this->assertGreaterThan(0, $results); -// }); +it('can get firewall data with a specific order', function () { + $cf = new CloudflareAnalytics; -// it('can get total views between two dates', function () { -// $startDate = date('Y-m-d', strtotime('-2 months')); -// $endDate = date('Y-m-d'); + $results = $cf->select('firewallEventsAdaptive AS firewall') + ->orderBy('firewall.datetime', 'DESC') + ->get('firewall.datetime', 'firewall.action'); -// $cf = new \The3LabsTeam\PhpCloudflareAnalytics\CloudflareAnalytics(); -// $result = $cf->whereBetween($startDate, $endDate)->get(); + $this->assertIsArray($results); + $this->assertGreaterThan(0, $results); +}); -// $this->assertIsArray($result); -// $this->assertGreaterThan(0, $result); +it('can get firewall data with a specific order and limit', function () { + $limit = 10; -// }); + $cf = new CloudflareAnalytics; -// it('can get total views with a specific limit', function () { -// $limit = 10; + $results = $cf->select('firewallEventsAdaptive AS firewall') + ->orderBy('firewall.datetime', 'DESC') + ->take('firewall', $limit) + ->get('firewall.datetime', 'firewall.action'); -// $cf = new \The3LabsTeam\PhpCloudflareAnalytics\CloudflareAnalytics(); -// $result = $cf->take($limit)->get(); + $this->assertIsArray($results); + $this->assertGreaterThan(0, $results); +}); -// $this->assertIsArray($result); -// $this->assertGreaterThan(0, $result); -// }); +it('can get firewall data with a specific order and limit between two dates', function () { + $startDate = (new DateTime)->sub(new DateInterval('P1D'))->format('c'); + $endDate = (new DateTime)->format('c'); + $limit = 10; -// it('can get total views with custom parameters', function () { -// $param = 'cachedRequests'; -// $paramType = 'cachedBytes'; + $cf = new CloudflareAnalytics; -// $cf = new \The3LabsTeam\PhpCloudflareAnalytics\CloudflareAnalytics(); -// $result = $cf->get($param, $paramType); + $results = $cf->select('firewallEventsAdaptive AS firewall') + ->whereBetween('firewall', $startDate, $endDate) + ->orderBy('firewall.datetime', 'DESC') + ->take('firewall', $limit) + ->get('firewall.datetime', 'firewall.action'); -// $this->assertIsArray($result); -// $this->assertGreaterThan(0, $result); -// }); + $this->assertIsArray($results); + $this->assertGreaterThan(0, $results); +}); \ No newline at end of file From fcd9960166b47304584d0c16717a60a62923e8b4 Mon Sep 17 00:00:00 2001 From: Stefano Novelli Date: Mon, 5 Aug 2024 12:44:38 +0200 Subject: [PATCH 11/12] Add notes --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index a475cc2..a58bce6 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,10 @@ This package is a simple PHP client for the Cloudflare Analytics GraphQL API. +> ⚠️ **Note:** This package is not official and is not affiliated with Cloudflare. It is a community-driven package. + +> 🚨 **Note 2:** This package is under development and is not ready for production. + ## Installation You can install the package via composer: From bc0c6d68a04e0de64cbc61d7312863a81112b67c Mon Sep 17 00:00:00 2001 From: murdercode Date: Mon, 5 Aug 2024 10:47:19 +0000 Subject: [PATCH 12/12] Fix styling --- src/CloudflareAnalytics.php | 4 ++-- tests/CloudflareAnalyticsTest.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/CloudflareAnalytics.php b/src/CloudflareAnalytics.php index e5f1f6a..3a58b41 100755 --- a/src/CloudflareAnalytics.php +++ b/src/CloudflareAnalytics.php @@ -2,9 +2,9 @@ namespace The3LabsTeam\PhpCloudflareAnalytics; -use Dotenv\Dotenv; -use DateTime; use DateInterval; +use DateTime; +use Dotenv\Dotenv; class CloudflareAnalytics { diff --git a/tests/CloudflareAnalyticsTest.php b/tests/CloudflareAnalyticsTest.php index ebcba61..4c69692 100644 --- a/tests/CloudflareAnalyticsTest.php +++ b/tests/CloudflareAnalyticsTest.php @@ -85,4 +85,4 @@ $this->assertIsArray($results); $this->assertGreaterThan(0, $results); -}); \ No newline at end of file +});