diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ae6b738 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.idea +composer.phar +composer.lock +vendor + diff --git a/README.md b/README.md index c5cc090..9457c9c 100644 --- a/README.md +++ b/README.md @@ -1 +1,53 @@ -# php-tracking \ No newline at end of file +# 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 +send(['clickID' => '111111111111111111111111']); +} +catch (PostbackInvalidClickIDException $e) { + echo "Invalid click id\n"; +} +``` diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..619352f --- /dev/null +++ b/composer.json @@ -0,0 +1,21 @@ +{ + "name": "affise/php-tracking", + "description": "Affise tracking SDK", + "minimum-stability": "stable", + "license": "MIT", + "authors": [ + { + "name": "vladimirkoptev", + "email": "vk@affise.com" + } + ], + "require": { + "php": ">=7.4", + "guzzlehttp/guzzle": "^7.0" + }, + "autoload": { + "psr-4": { + "Affise\\Tracking\\": "src" + } + } +} \ No newline at end of file diff --git a/src/Cookie.php b/src/Cookie.php new file mode 100644 index 0000000..17d3372 --- /dev/null +++ b/src/Cookie.php @@ -0,0 +1,36 @@ + + */ + 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; + } +} \ No newline at end of file diff --git a/src/PostbackInvalidClickIDException.php b/src/PostbackInvalidClickIDException.php new file mode 100644 index 0000000..5f06df3 --- /dev/null +++ b/src/PostbackInvalidClickIDException.php @@ -0,0 +1,8 @@ +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; + } +} \ No newline at end of file diff --git a/src/PostbackStatus.php b/src/PostbackStatus.php new file mode 100644 index 0000000..273667e --- /dev/null +++ b/src/PostbackStatus.php @@ -0,0 +1,68 @@ + 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; + } +} \ No newline at end of file