├── .gitignore ├── composer.json ├── README.md └── src └── Chatway.php /.gitignore: -------------------------------------------------------------------------------- 1 | vendor 2 | composer.lock -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "chatway-live-chat/chatway-live-chat-php", 3 | "description": "Embed Chatway chat widget in any PHP app", 4 | "license": "MIT", 5 | "autoload": { 6 | "psr-4": { 7 | "Chatway\\": "src/" 8 | } 9 | }, 10 | "authors": [ 11 | { 12 | "name": "Chatway Live Chat", 13 | "email": "contact@poptin.com" 14 | } 15 | ], 16 | "minimum-stability": "stable", 17 | "require": {} 18 | } 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # Chatway PHP SDK 3 | 4 | The **Chatway live chat PHP SDK** is a lightweight, framework-agnostic PHP library that allows you to easily embed the [Chatway](https://chatway.app/?utm_source=packagist) live chat customer support widget on your website and securely identify your visitors using a simple, chainable API. 5 | 6 | Chatway is a powerful live chat solution for websites, offering features such as live chat customer support, real-time visitor tracking, customizable widgets, canned responses, FAQs, multilingual support, private notes, visitor segmentation, analytics, and more. Chatway is available as a web app, as well as native iOS and Android apps. 7 | 8 | This SDK works with any PHP application, including Laravel, WordPress, custom frameworks, or plain PHP projects. 9 | 10 | ![chatway-pack](https://github.com/user-attachments/assets/23333c76-e427-487d-8341-d8579fe537de) 11 | 12 | --- 13 | 14 | ## Key Features 15 | 16 | - Easily embed the Chatway live chat widget using your project’s widget ID 17 | - Securely verify visitors by ID or email (optional) 18 | - Assign tags with custom colors 19 | - Attach custom fields to visitor sessions 20 | - Clean, chainable syntax 21 | - Fully HTML-escaped output for security 22 | 23 | --- 24 | 25 | ## Installation 26 | 27 | To install the SDK via Composer: 28 | 29 | ```bash 30 | composer require chatway-live-chat/chatway-live-chat-php 31 | ``` 32 | 33 | --- 34 | 35 | ## Basic Usage 36 | 37 | Embed the Chatway live chat widget without visitor verification: 38 | 39 | ```php 40 | echo Chatway\Chatway::make('your-widget-id')->getScript(); 41 | ``` 42 | 43 | You can find your widget ID on the [Chatway Installation Page](https://go.chatway.app/installation) (`id=WIDGET_ID`). 44 | 45 | --- 46 | 47 | ## Visitor Verification (Optional) 48 | 49 | To securely verify logged-in visitors, provide: 50 | 51 | - The **user ID** 52 | - The **email address** 53 | - A **secret key** from the [Visitor Verification page](https://go.chatway.app/visitors-verification) 54 | - Whether to generate the signature based on `'id'` or `'email'` 55 | 56 | All four parameters are required for visitor verification. 57 | 58 | Example: 59 | 60 | ```php 61 | echo Chatway\Chatway::make('your-widget-id', 'your-secret-key', 'id') 62 | ->withVisitor('123', 'user@example.com') 63 | ->getScript(); 64 | ``` 65 | 66 | This will generate a secure `window.chatwaySettings` block containing a signature and load the chat widget. 67 | 68 | --- 69 | 70 | ## Adding Tags 71 | 72 | You can assign tags to visitors, each with a name and color. 73 | 74 | **Single Tag:** 75 | 76 | ```php 77 | ->setTags('VIP', '#FFD700') 78 | ``` 79 | 80 | **Multiple Tags:** 81 | 82 | ```php 83 | ->setTags([ 84 | 'VIP' => '#FFD700', 85 | 'Supporter' => '#00FF00' 86 | ]); 87 | ``` 88 | 89 | --- 90 | 91 | ## Custom Fields 92 | 93 | You can attach custom fields to enrich visitor session data. 94 | 95 | **Single Field:** 96 | 97 | ```php 98 | ->setCustomFields('Plan', 'Premium') 99 | ``` 100 | 101 | **Multiple Fields:** 102 | 103 | ```php 104 | ->setCustomFields([ 105 | 'Subscription' => 'Gold', 106 | 'Status' => 'Active' 107 | ]); 108 | ``` 109 | 110 | --- 111 | 112 | ## Full Example 113 | 114 | ```php 115 | echo Chatway\Chatway::make('your-widget-id', 'your-secret-key', 'email') 116 | ->withVisitor('123', 'user@example.com') 117 | ->setTags('VIP', '#FFD700') 118 | ->setTags(['Supporter' => '#00FF00']) 119 | ->setCustomFields('Plan', 'Pro') 120 | ->setCustomFields([ 121 | 'Country' => 'USA', 122 | 'Language' => 'English' 123 | ]) 124 | ->getScript(); 125 | ``` 126 | 127 | --- 128 | 129 | ## Important Notes 130 | 131 | - For visitor verification, you **must** provide: 132 | - `make(widgetId, secretKey, basedOn)` 133 | - `withVisitor(userId, email)` 134 | - The `basedOn` parameter must be either `'id'` or `'email'` 135 | - All tag names, tag colors, field names, and field values must be strings 136 | - Tags must be an associative array in the format `name => color` 137 | - Custom fields must be an associative array in the format `name => value` 138 | 139 | Invalid input will result in an `InvalidArgumentException`. 140 | 141 | --- 142 | 143 | ## License For This Package 144 | 145 | MIT License © [Chatway](https://chatway.app) 146 | -------------------------------------------------------------------------------- /src/Chatway.php: -------------------------------------------------------------------------------- 1 | 'id', 32 | 'email' => 'email', 33 | ]; 34 | 35 | /** 36 | * @param string $userIdentifier 37 | * @param string|null $hmacSecret 38 | * @param string $hmacBasedOn 39 | * @return self 40 | */ 41 | public static function make($userIdentifier, $hmacSecret = null, $hmacBasedOn = self::HMAC_BASE_ON_OPTIONS['id']) 42 | { 43 | $instance = new self(); 44 | $instance->userIdentifier = is_string($userIdentifier) ? $userIdentifier : null; 45 | $instance->hmacSecret = is_string($hmacSecret) ? $hmacSecret : null; 46 | $instance->hmacBasedOn = is_string($hmacBasedOn) && in_array($hmacBasedOn, array_values(self::HMAC_BASE_ON_OPTIONS), true) ? $hmacBasedOn : self::HMAC_BASE_ON_OPTIONS['id']; 47 | 48 | return $instance; 49 | } 50 | 51 | /** 52 | * @param string|array $key 53 | * @param string|null $color 54 | * @return self 55 | */ 56 | public function setTags($key, $color = null) 57 | { 58 | if (is_array($key)) { 59 | if (!$this->isAssoc($key)) { 60 | throw new InvalidArgumentException('Tags must be an associative array: name => color.'); 61 | } 62 | 63 | foreach ($key as $name => $value) { 64 | if (!is_string($name) || !is_string($value)) { 65 | throw new InvalidArgumentException('Both tag name and color must be strings.'); 66 | } 67 | 68 | $this->tags[] = ['name' => $name, 'color' => $value]; 69 | } 70 | } else { 71 | if (!is_string($key) || !is_string($color)) { 72 | throw new InvalidArgumentException('Tag name and color must be strings.'); 73 | } 74 | 75 | $this->tags[] = ['name' => $key, 'color' => $color]; 76 | } 77 | 78 | return $this; 79 | } 80 | 81 | /** 82 | * @param string|array $key 83 | * @param string|null $value 84 | * @return self 85 | */ 86 | public function setCustomFields($key, $value = null) 87 | { 88 | if (is_array($key)) { 89 | if (!$this->isAssoc($key)) { 90 | throw new InvalidArgumentException('Custom fields must be an associative array: name => value.'); 91 | } 92 | 93 | foreach ($key as $name => $val) { 94 | if (!is_string($name) || !is_string($val)) { 95 | throw new InvalidArgumentException('Both custom field name and value must be strings.'); 96 | } 97 | 98 | $this->customFields[] = ['name' => $name, 'value' => $val]; 99 | } 100 | } else { 101 | if (!is_string($key) || !is_string($value)) { 102 | throw new InvalidArgumentException('Custom field name and value must be strings.'); 103 | } 104 | 105 | $this->customFields[] = ['name' => $key, 'value' => $value]; 106 | } 107 | 108 | return $this; 109 | } 110 | 111 | /** 112 | * @param string $userId 113 | * @param string $email 114 | * @return self 115 | */ 116 | public function withVisitor($userId, $email) 117 | { 118 | $this->userId = is_string($userId) || is_int($userId) || is_float($userId) ? $userId : null; 119 | $this->email = is_string($email) ? $email : null; 120 | 121 | return $this; 122 | } 123 | 124 | /** 125 | * @param array $array 126 | * @return bool 127 | */ 128 | protected function isAssoc(array $array) 129 | { 130 | return array_keys($array) !== range(0, count($array) - 1); 131 | } 132 | 133 | /** 134 | * @return string 135 | */ 136 | public function getScript() 137 | { 138 | $script = ''; 139 | 140 | $shouldVerify = $this->hmacSecret && 141 | $this->userId !== null && 142 | $this->email !== null && 143 | in_array($this->hmacBasedOn, array_values(self::HMAC_BASE_ON_OPTIONS), true); 144 | 145 | if ($shouldVerify) { 146 | $safeId = htmlspecialchars($this->userId, ENT_QUOTES, 'UTF-8'); 147 | $safeEmail = htmlspecialchars($this->email, ENT_QUOTES, 'UTF-8'); 148 | $hmacBase = $this->hmacBasedOn === 'email' ? $this->email : $this->userId; 149 | $hmac = hash_hmac('sha256', $hmacBase, $this->hmacSecret); 150 | 151 | $tagsJson = json_encode($this->tags); 152 | $customFieldsJson = json_encode($this->customFields); 153 | 154 | $script .= << 168 | SCRIPT; 169 | } 170 | 171 | $userIdentifier = htmlspecialchars($this->userIdentifier, ENT_QUOTES, 'UTF-8'); 172 | $script .= << 174 | SCRIPT; 175 | 176 | return $script; 177 | } 178 | } 179 | --------------------------------------------------------------------------------