Skip to content

Commit

Permalink
init commit
Browse files Browse the repository at this point in the history
  • Loading branch information
VKoptev committed Feb 15, 2024
1 parent 6c19f5a commit b74c007
Show file tree
Hide file tree
Showing 11 changed files with 378 additions and 1 deletion.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.idea
composer.phar
composer.lock
vendor

54 changes: 53 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,53 @@
# php-tracking
# php-tracking

## Installation

```bash
composer require affise/php-tracking:^1.0
```

## Documentation

The links bellow should provide all the documentation needed to make the best
use of the library:

- [Documentation](https://help-center.affise.com/en/articles/6466563-postback-integration-s2s-admins)

## Usage

### Clicks

```php
<?php

use Affise\Tracking\Cookie;
use Affise\Tracking\CookieInvalidParamException;
use Affise\Tracking\CookieUnsetException;

try {
Cookie::set();
}
catch (CookieInvalidParamException $e) {
echo "Invalid click id param\n";
}
catch (CookieUnsetException $e) {
echo "Failed to set cookie\n";
}
```

### Conversions

```php
<?php

use Affise\Tracking\PostbackSender;

$sender = new PostbackSender("example.com");

try {
$sender->send(['clickID' => '111111111111111111111111']);
}
catch (PostbackInvalidClickIDException $e) {
echo "Invalid click id\n";
}
```
21 changes: 21 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"name": "affise/php-tracking",
"description": "Affise tracking SDK",
"minimum-stability": "stable",
"license": "MIT",
"authors": [
{
"name": "vladimirkoptev",
"email": "[email protected]"
}
],
"require": {
"php": ">=7.4",
"guzzlehttp/guzzle": "^7.0"
},
"autoload": {
"psr-4": {
"Affise\\Tracking\\": "src"
}
}
}
36 changes: 36 additions & 0 deletions src/Cookie.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

namespace Affise\Tracking;

class Cookie
{
private const QUERY_PARAM = ["click_id", "clickid", "afclick"];
private const COOKIE_NAME = "afclick";

/**
* @return void
* @throws CookieInvalidParamException
* @throws CookieUnsetException
*/
public static function set()
{
$val = "";
foreach ([$_GET, $_POST] as $src) {
foreach (self::QUERY_PARAM as $key) {
if (isset($src[$key])) {
$val = $src[$key];
break 2;
}
}
}

if ($val === "") {
throw new CookieInvalidParamException();
}

$r = setcookie(self::COOKIE_NAME, $val, time()+3600*24*365, "/", $_SERVER['HTTP_HOST'], true, false);
if (!$r) {
throw new CookieUnsetException();
}
}
}
8 changes: 8 additions & 0 deletions src/CookieInvalidParamException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

namespace Affise\Tracking;

class CookieInvalidParamException extends \Exception
{

}
8 changes: 8 additions & 0 deletions src/CookieUnsetException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

namespace Affise\Tracking;

class CookieUnsetException extends \Exception
{

}
118 changes: 118 additions & 0 deletions src/Postback.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
<?php

namespace Affise\Tracking;

class Postback
{
public const CUSTOM_FIELDS_COUNT = 15;
protected string $domain = "";
protected bool $ssl = true;
protected ?string $clickID = null;
protected ?string $actionID = null;
protected ?string $goal = null;
protected ?float $sum = null;
protected ?string $IP = null;
protected ?PostbackStatus $status = null;
protected ?string $referrer = null;
protected ?string $comment = null;
protected ?string $secure = null;
protected ?string $fbClID = null;
protected ?string $deviceType = null;
protected ?string $userID = null;
/**
* @var array<string>
*/
protected ?array $customFields = [];

protected array $propertyMap = [
"clickID" => "click_id",
"actionID" => "action_id",
"goal" => "goal",
"sum" => "sum",
"IP" => "ip",
"status" => "status",
"referrer" => "referrer",
"comment" => "comment",
"secure" => "secure",
"fbClID" => "fbclid",
"deviceType" => "device_type",
"userID" => "user_id",
"customFields" => "custom_field",
];

/**
* @param string $domain
* @param bool $ssl
* @param array $options
* @throws PostbackInvalidDomainException
*/
public function __construct(string $domain, bool $ssl = true, array $options = [])
{
if ($domain === "") {
throw new PostbackInvalidDomainException();
}

$this->domain = $domain;
$this->ssl = $ssl;

foreach ($options as $key => $value) {
if (in_array($key, ["domain", "ssl"])) {
continue;
}

if ($key === "customFields") {
for ($i = 1; $i <= self::CUSTOM_FIELDS_COUNT; $i++) {
if (isset($value[$i])) {
$this->customFields[$i] = $value[$i];
}
}
}

if (property_exists($this, $key)) {
$this->$key = $value;
}
}
}

/**
* @return string
* @throws PostbackInvalidClickIDException
*/
public function url(): string
{
if ($this->clickID === "" || !preg_match('/[0-9a-f]{24}/i', $this->clickID)) {
throw new PostbackInvalidClickIDException();
}

$url = "http" . ($this->ssl ? "s" : "") . "://" . $this->domain . "/postback?";
$query = [];

foreach ($this->propertyMap as $key => $param) {
$query = array_merge($query, $this->mapProperty($key));
}

return $url . http_build_query($query);
}

protected function mapProperty(string $key): array
{
$param = $this->propertyMap[$key] ?? $key;
$query = [];

switch ($key) {
case "status":
$query[$param] = $this->status->value();
break;
case "customFields":
foreach ($this->customFields as $i => $value) {
$query[$param . $i] = $value;
}
break;
default:
$query[$param] = $this->$key;
break;
}

return $query;
}
}
8 changes: 8 additions & 0 deletions src/PostbackInvalidClickIDException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

namespace Affise\Tracking;

class PostbackInvalidClickIDException extends \Exception
{

}
8 changes: 8 additions & 0 deletions src/PostbackInvalidDomainException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

namespace Affise\Tracking;

class PostbackInvalidDomainException extends \Exception
{

}
45 changes: 45 additions & 0 deletions src/PostbackSender.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

namespace Affise\Tracking;

use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;

class PostbackSender
{
private Client $client;
protected string $domain;
protected bool $ssl = true;

public function __construct(string $domain, bool $ssl = true)
{
$this->client = new Client();
$this->domain = $domain;
$this->ssl = $ssl;
}

/**
* @param array $options
* @return bool
* @throws GuzzleException
* @throws PostbackInvalidClickIDException
* @throws PostbackInvalidDomainException
*/
public function send(array $options = []): bool
{
return $this->sendPostback(new Postback($this->domain, $this->ssl, $options));
}

/**
* @param Postback $p
* @return bool
* @throws GuzzleException
* @throws PostbackInvalidClickIDException
*/
public function sendPostback(Postback $p): bool
{
$url = $p->url();
$resp = $this->client->get($url);
return $resp->getStatusCode() === 200;
}
}
68 changes: 68 additions & 0 deletions src/PostbackStatus.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<?php

namespace Affise\Tracking;

/**
* Enum PostbackStatus
*/
final class PostbackStatus
{
public const CONFIRMED = 1;
public const PENDING = 2;
public const DECLINED = 3;
public const HOLD = 5;

private int $value;

private static array $values = [
self::CONFIRMED => null,
self::PENDING => null,
self::DECLINED => null,
self::HOLD => null,
];

public static function Confirmed(): PostbackStatus
{
if (self::$values[self::CONFIRMED] == null) {
self::$values[self::CONFIRMED] = new PostbackStatus(self::CONFIRMED);
}
return self::$values[self::CONFIRMED];
}

public static function Pending(): PostbackStatus
{
if (self::$values[self::PENDING] == null) {
self::$values[self::PENDING] = new PostbackStatus(self::PENDING);
}
return self::$values[self::PENDING];
}

public static function Declined(): PostbackStatus
{
if (self::$values[self::DECLINED] == null) {
self::$values[self::DECLINED] = new PostbackStatus(self::DECLINED);
}
return self::$values[self::DECLINED];
}

public static function Hold(): PostbackStatus
{
if (self::$values[self::HOLD] == null) {
self::$values[self::HOLD] = new PostbackStatus(self::HOLD);
}
return self::$values[self::HOLD];
}

/**
* @param int $status
*/
private function __construct(int $status)
{
$this->value = $status;
}

public function value(): int
{
return $this->value;
}
}

0 comments on commit b74c007

Please sign in to comment.