├── .gitignore ├── composer.json ├── src ├── Api.php └── AbstractApi.php ├── README.md └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea 2 | /.idea_modules 3 | /composer.phar 4 | /composer.lock 5 | /vendor 6 | *.lnk 7 | *.ini 8 | /*.php 9 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "zhukmax/smsc", 3 | "description": "Lib for modern integration smsc.ru service", 4 | "license": "Apache-2.0", 5 | "authors": [ 6 | { 7 | "name": "Zhuk Max", 8 | "email": "mail@zhukmax.com" 9 | } 10 | ], 11 | "require": { 12 | "php": ">=5.6.0", 13 | "ext-curl": "*" 14 | }, 15 | "require-dev": {}, 16 | "autoload": { 17 | "classmap": ["src"] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Api.php: -------------------------------------------------------------------------------- 1 | $property; 18 | } 19 | 20 | /** 21 | * Функция отправки SMS. 22 | * 23 | * @param string $phones Список телефонов через запятую или точку с запятой 24 | * @param $message 25 | * @param int $translit 26 | * @param int $time 27 | * @param int $id 28 | * @param int $format 29 | * @param string $sender 30 | * @param string $query 31 | * @param array $files 32 | * @return mixed 33 | * @throws \Exception 34 | */ 35 | public function sendSms($phones, $message, $translit = 0, $time = 0, $id = 0, $format = 0, $sender = null, $query = "", $files = array()) 36 | { 37 | static $formats = array(1 => "flash=1", "push=1", "hlr=1", "bin=1", "bin=2", "ping=1", "mms=1", "mail=1", "call=1"); 38 | $sender = isset($sender) ? $sender : $this->sender; 39 | 40 | $result = $this->sendCmd("send", "cost=3&phones=".urlencode($phones)."&mes=".urlencode($message). 41 | "&translit=$translit&id=$id".($format > 0 ? "&".$formats[$format] : ""). 42 | (!isset($sender) ? "" : "&sender=".urlencode($sender)). 43 | ($time ? "&time=".urlencode($time) : "").($query ? "&$query" : ""), $files); 44 | 45 | if ($result[1] > 0) { 46 | $debugText = "Сообщение отправлено успешно. ID: $result[0], всего SMS: $result[1], стоимость: $result[2], баланс: $result[3].\n"; 47 | } else { 48 | $debugText = "Ошибка №". -$result[1]. $result[0] ? ", ID: ".$result[0] : "". "\n"; 49 | } 50 | $this->log($debugText); 51 | 52 | return $result; 53 | } 54 | 55 | /** 56 | * SMTP версия функции отправки SMS. 57 | * 58 | * @param $phones 59 | * @param $message 60 | * @param int $translit 61 | * @param int $time 62 | * @param int $id 63 | * @param int $format 64 | * @param string $sender 65 | * @return mixed 66 | */ 67 | public function sendSmsMail($phones, $message, $translit = 0, $time = 0, $id = 0, $format = 0, $sender = "") 68 | { 69 | $to = "send@send.smsc.ru"; 70 | $message = $this->login.":".$this->password.":$id:$time:$translit,$format,$sender:$phones:$message"; 71 | $headers = "From: " . $this->from . 72 | "\nContent-Type: text/plain; charset=" . 73 | $this->charset . "\n"; 74 | 75 | return mail($to, "", $message, $headers); 76 | } 77 | 78 | /** 79 | * Функция получения стоимости SMS. 80 | * 81 | * @param $phones 82 | * @param $message 83 | * @param int $translit 84 | * @param int $format 85 | * @param bool $sender 86 | * @param string $query 87 | * @return mixed 88 | * @throws \Exception 89 | */ 90 | public function getSmsCost($phones, $message, $translit = 0, $format = 0, $sender = false, $query = "") 91 | { 92 | static $formats = array(1 => "flash=1", "push=1", "hlr=1", "bin=1", "bin=2", "ping=1", "mms=1", "mail=1", "call=1"); 93 | 94 | $m = $this->sendCmd("send", "cost=1&phones=".urlencode($phones)."&mes=".urlencode($message). 95 | ($sender === false ? "" : "&sender=".urlencode($sender)). 96 | "&translit=$translit".($format > 0 ? "&".$formats[$format] : "").($query ? "&$query" : "")); 97 | 98 | if ($this->debug) { 99 | if ($m[1] > 0) 100 | echo "Стоимость рассылки: $m[0]. Всего SMS: $m[1]\n"; 101 | else 102 | echo "Ошибка №", -$m[1], "\n"; 103 | } 104 | 105 | return $m; 106 | } 107 | 108 | /** 109 | * Функция проверки статуса отправленного SMS или HLR-запроса. 110 | * 111 | * @param $id 112 | * @param $phone 113 | * @param int $all 114 | * @return mixed 115 | * @throws \Exception 116 | */ 117 | public function getStatus($id, $phone, $all = 0) 118 | { 119 | $result = $this->sendCmd("status", "phone=".urlencode($phone)."&id=".urlencode($id)."&all=".(int)$all); 120 | 121 | if (!strpos($id, ",")) { 122 | if ($this->debug) { 123 | if ($result[1] != "" && $result[1] >= 0) { 124 | echo "Статус SMS = $result[0]", $result[1] ? ", время изменения статуса - " . date("d.m.Y H:i:s", $result[1]) : "", "\n"; 125 | } else { 126 | echo "Ошибка №", -$result[1], "\n"; 127 | } 128 | } 129 | 130 | if ($all && count($result) > 9 && (!isset($result[$idx = $all == 1 ? 14 : 17]) || $result[$idx] != "HLR")) { 131 | $result = explode(",", implode(",", $result), $all == 1 ? 9 : 12); 132 | } 133 | } else { 134 | if (count($result) == 1 && strpos($result[0], "-") == 2) { 135 | return explode(",", $result[0]); 136 | } 137 | 138 | foreach ($result as $k => $v) { 139 | $result[$k] = explode(",", $v); 140 | } 141 | } 142 | 143 | return $result; 144 | } 145 | 146 | /** 147 | * Функция получения баланса. 148 | * 149 | * @return array|bool 150 | * @throws \Exception 151 | */ 152 | public function getBalance() 153 | { 154 | $result = $this->sendCmd("balance"); 155 | 156 | if ($this->debug) { 157 | if (!isset($result[1])){ 158 | echo "Сумма на счете: ", $result[0], "\n"; 159 | } else{ 160 | echo "Ошибка №", -$result[1], "\n"; 161 | } 162 | } 163 | 164 | return isset($result[1]) ? false : $result[0]; 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Smsc API 2 | [![Latest Version on Packagist][ico-version]][link-packagist] 3 | [![Software License][ico-license]](license.md) 4 | [![Total Downloads][ico-downloads]][link-downloads] 5 | 6 | Компонент для интеграции сервиса SMSC.RU API (smsc.ru) на сайт. Основано на версии 3.6 официального кода. 7 | 8 | ## Установка 9 | С помощью композера: 10 | ``` 11 | $ composer require zhukmax/smsc 12 | ``` 13 | 14 | ## Использование 15 | Для того, что бы правильно отлавливать Исключения желательно использовать в конструкции try\catch. Не обязательно использовать выход `exit()`, можно эхом вывести текст ошибки и продолжить выполнение скрипта. 16 | ```php 17 | true, 24 | 'charset' => 'windows-1251', 25 | 'from' => 'api@smsc.ru', 26 | 'post' => true, 27 | 'debug' => '/home/user/smsc.log' 28 | ] 29 | ); 30 | } catch (Exception $exception) { 31 | exit($exception->getMessage()); 32 | } 33 | ``` 34 | Так же можно унаследовать класс `\Zhukmax\Smsc\Api` и добавить собственное поведение до/после выполнения методов компонента или, даже, переназначить некоторые из них. 35 | ```php 36 | sendCmd('balance')); 42 | } 43 | } 44 | ``` 45 | 46 | ## Свойства конструктора 47 | * логин клиента 48 | * пароль или MD5-хеш пароля в нижнем регистре 49 | * Массив с опциями: 50 | * protocol - использовать HTTPS протокол, любое значение кроме 'https' приравнивается использованию не защищенного протокола HTTP 51 | * charset - кодировка сообщения: utf-8 (по умолчанию), koi8-r или windows-1251 52 | * from - e-mail адрес отправителя 53 | * post - использовать метод POST, булев 54 | * debug - флаг отладки, булев 55 | 56 | ## Методы 57 | #### Публичные методы: 58 | **sendSms()** - Функция отправки SMS 59 | 60 | * _обязательные параметры:_ 61 | - $phones - список телефонов через запятую или точку с запятой 62 | - $message - отправляемое сообщение 63 | 64 | * _необязательные параметры:_ 65 | - $translit - переводить или нет в транслит (1,2 или 0) 66 | - $time - необходимое время доставки в виде строки (DDMMYYhhmm, h1-h2, 0ts, +m) 67 | - $id - идентификатор сообщения. Представляет собой 32-битное число в диапазоне от 1 до 2147483647. 68 | - $format - формат сообщения (0 - обычное sms, 1 - flash-sms, 2 - wap-push, 3 - hlr, 4 - bin, 5 - bin-hex, 6 - ping-sms, 7 - mms, 8 - mail, 9 - call) 69 | - $sender - имя отправителя (Sender ID). Для отключения Sender ID по умолчанию необходимо в качестве имени 70 | передать пустую строку или точку. 71 | - $query - строка дополнительных параметров, добавляемая в URL-запрос ("valid=01:00&maxsms=3&tz=2") 72 | - $files - массив путей к файлам для отправки mms или e-mail сообщений 73 | 74 | возвращает массив (, <количество sms>, <стоимость>, <баланс>) в случае успешной отправки 75 | либо массив (, -<код ошибки>) в случае ошибки 76 | 77 | **sendSmsMail()** - SMTP версия функции отправки SMS 78 | 79 | **getSmsCost()** - Функция получения стоимости SMS 80 | 81 | * _обязательные параметры:_ 82 | - $phones - список телефонов через запятую или точку с запятой 83 | - $message - отправляемое сообщение 84 | 85 | * _необязательные параметры:_ 86 | - $translit - переводить или нет в транслит (1,2 или 0) 87 | - $format - формат сообщения (0 - обычное sms, 1 - flash-sms, 2 - wap-push, 3 - hlr, 4 - bin, 5 - bin-hex, 6 - ping-sms, 7 - mms, 8 - mail, 9 - call) 88 | - $sender - имя отправителя (Sender ID) 89 | - $query - строка дополнительных параметров, добавляемая в URL-запрос ("list=79999999999:Ваш пароль: 123\n78888888888:Ваш пароль: 456") 90 | 91 | возвращает массив (<стоимость>, <количество sms>) либо массив (0, -<код ошибки>) в случае ошибки 92 | 93 | **getStatus()** - Функция проверки статуса отправленного SMS или HLR-запроса 94 | 95 | - $id - ID cообщения или список ID через запятую 96 | 97 | - $phone - номер телефона или список номеров через запятую 98 | 99 | - $all - вернуть все данные отправленного SMS, включая текст сообщения (0,1 или 2) 100 | 101 | _возвращает массив (для множественного запроса двумерный массив):_ 102 | 103 | _для одиночного SMS-сообщения:_ 104 | (<статус>, <время изменения>, <код ошибки доставки>) 105 | 106 | _для HLR-запроса:_ 107 | (<статус>, <время изменения>, <код ошибки sms>, <код IMSI SIM-карты>, <номер сервис-центра>, <код страны регистрации>, <код оператора>, 108 | <название страны регистрации>, <название оператора>, <название роуминговой страны>, <название роумингового оператора>) 109 | 110 | при $all = 1 дополнительно возвращаются элементы в конце массива: 111 | (<время отправки>, <номер телефона>, <стоимость>, , <название статуса>, <текст сообщения>) 112 | 113 | при $all = 2 дополнительно возвращаются элементы <страна>, <оператор> и <регион> 114 | 115 | при множественном запросе: 116 | если $all = 0, то для каждого сообщения или HLR-запроса дополнительно возвращается и <номер телефона> 117 | 118 | если $all = 1 или $all = 2, то в ответ добавляется 119 | 120 | либо массив (0, -<код ошибки>) в случае ошибки 121 | 122 | **getBalance()** - Функция получения баланса 123 | 124 | возвращает баланс в виде строки или false в случае ошибки 125 | 126 | #### Внутренние методы: 127 | **sendCmd()** - Функция вызова запроса. Формирует URL и делает 5 попыток чтения через разные подключения к сервису 128 | 129 | **readUrl()** - Функция чтения URL. 130 | 131 | Для работы должно быть доступно: 132 | curl или fsockopen (только http) или включена опция allow_url_fopen для file_get_contents 133 | 134 | 135 | [![Stargazers repo roster for @ZhukMax/smsc](https://reporoster.com/stars/ZhukMax/smsc)](https://github.com/ZhukMax/smsc/stargazers) 136 | 137 | ## Лицензия 138 | 139 | The Apache License Version 2.0. Текст лицензии находится в файле [License File](license.md). 140 | 141 | [ico-version]: https://img.shields.io/packagist/v/zhukmax/smsc.svg 142 | [ico-license]: https://img.shields.io/badge/license-Apache%202-brightgreen.svg 143 | [ico-downloads]: https://img.shields.io/packagist/dt/zhukmax/smsc.svg 144 | 145 | [link-packagist]: https://packagist.org/packages/zhukmax/smsc 146 | [link-downloads]: https://packagist.org/packages/zhukmax/smsc 147 | -------------------------------------------------------------------------------- /src/AbstractApi.php: -------------------------------------------------------------------------------- 1 | login = $login ?: null; 43 | $this->password = $password ?: null; 44 | if (!$this->login || !$this->password) { 45 | throw new \Exception("Логин и пароль обязательные поля!"); 46 | } 47 | 48 | $this->protocol = isset($options['https']) ? 'https': 'http'; 49 | $this->charset = isset($options['charset']) ? $options['charset'] : 'utf-8'; 50 | $this->from = isset($options['from']) ? $options['from'] : 'api@smsc.ru'; 51 | $this->httpPost = isset($options['post']) ?: false; 52 | $this->sender = isset($options['sender']) ?: null; 53 | 54 | $this->setDebug($options); 55 | 56 | $this->url = $this->protocol . "://smsc.ru/sys/%s.php?login=" . 57 | urlencode($this->login) . "&psw=" . urlencode($this->password) . 58 | "&fmt=1&charset=" . $this->charset; 59 | } 60 | 61 | /** 62 | * @param string $property 63 | * @return mixed 64 | */ 65 | abstract public function getProperty($property); 66 | 67 | /** 68 | * Функция отправки SMS. 69 | * 70 | * @param $phones 71 | * @param $message 72 | * @param int $translit 73 | * @param int $time 74 | * @param int $id 75 | * @param int $format 76 | * @param string $sender 77 | * @param string $query 78 | * @param array $files 79 | * @return mixed 80 | */ 81 | abstract public function sendSms($phones, $message, $translit = 0, $time = 0, $id = 0, $format = 0, $sender, $query = "", $files = array()); 82 | 83 | /** 84 | * SMTP версия функции отправки SMS. 85 | * 86 | * @param $phones 87 | * @param $message 88 | * @param int $translit 89 | * @param int $time 90 | * @param int $id 91 | * @param int $format 92 | * @param string $sender 93 | * @return mixed 94 | */ 95 | abstract public function sendSmsMail($phones, $message, $translit = 0, $time = 0, $id = 0, $format = 0, $sender = ""); 96 | 97 | /** 98 | * Функция получения стоимости SMS. 99 | * 100 | * @param $phones 101 | * @param $message 102 | * @param int $translit 103 | * @param int $format 104 | * @param bool $sender 105 | * @param string $query 106 | * @return mixed 107 | */ 108 | abstract public function getSmsCost($phones, $message, $translit = 0, $format = 0, $sender = false, $query = ""); 109 | 110 | /** 111 | * Функция проверки статуса отправленного SMS или HLR-запроса. 112 | * 113 | * @param $id 114 | * @param $phone 115 | * @param int $all 116 | * @return mixed 117 | */ 118 | abstract public function getStatus($id, $phone, $all = 0); 119 | 120 | /** 121 | * Функция получения баланса. 122 | * 123 | * @return array|bool 124 | */ 125 | abstract public function getBalance(); 126 | 127 | /** 128 | * Функция вызова запроса. 129 | * Формирует URL и делает 5 попыток чтения через разные подключения к сервису. 130 | * 131 | * @param string $cmd 132 | * @param string $arg 133 | * @param array $files 134 | * @return array 135 | * @throws \Exception 136 | */ 137 | protected function sendCmd($cmd, $arg = "", $files = array()) 138 | { 139 | $url = $_url = str_replace("%s", $cmd, $this->url) . "&" . $arg; 140 | $i = 0; 141 | 142 | do { 143 | if ($i++) { 144 | $url = str_replace('://', '://www' . $i, $_url); 145 | } 146 | 147 | $result = $this->readUrl($url, $files, 3 + $i); 148 | } while ($result == "" && $i < 5); 149 | 150 | if ($result == "") { 151 | if ($this->debug) { 152 | echo "Ошибка чтения адреса: $url\n"; 153 | } 154 | 155 | $result = ","; 156 | } 157 | 158 | $delimiter = ","; 159 | 160 | if ($cmd == "status") { 161 | parse_str($arg, $m); 162 | 163 | if (strpos($m["id"], ",")) { 164 | $delimiter = "\n"; 165 | } 166 | } 167 | 168 | return explode($delimiter, $result); 169 | } 170 | 171 | /** 172 | * Функция чтения URL. 173 | * 174 | * @param $url 175 | * @param $files 176 | * @param int $tm 177 | * @return bool|mixed|string 178 | * @throws \Exception 179 | */ 180 | protected function readUrl($url, $files, $tm = 5) 181 | { 182 | $post = $this->httpPost || strlen($url) > 2000 || $files; 183 | $result = ""; 184 | 185 | if (function_exists("curl_init")) { 186 | $this->initCurl($tm); 187 | curl_setopt($this->curl, CURLOPT_POST, $post); 188 | 189 | if ($post) { 190 | list($url, $post) = explode("?", $url, 2); 191 | 192 | if ($files) { 193 | parse_str($post, $m); 194 | 195 | foreach ($m as $k => $v) { 196 | $m[$k] = isset($v[0]) && $v[0] == "@" ? sprintf("\0%s", $v) : $v; 197 | } 198 | 199 | $post = $m; 200 | foreach ($files as $i => $path) { 201 | if (file_exists($path)) { 202 | $post["file" . $i] = function_exists("curl_file_create") ? curl_file_create($path) : "@" . $path; 203 | } 204 | } 205 | } 206 | 207 | curl_setopt($this->curl, CURLOPT_POSTFIELDS, $post); 208 | } 209 | 210 | curl_setopt($this->curl, CURLOPT_URL, $url); 211 | 212 | $result = curl_exec($this->curl); 213 | } else if ($files) { 214 | if ($this->debug){ 215 | throw new \Exception("Не установлен модуль curl для передачи файлов!"); 216 | } 217 | } else if ($this->protocol === 'https' && function_exists("fsockopen")) { 218 | $m = parse_url($url); 219 | 220 | if (!$fp = fsockopen($m["host"], 80, $errno, $errstr, $tm)) { 221 | $fp = fsockopen("212.24.33.196", 80, $errno, $errstr, $tm); 222 | } 223 | 224 | if ($fp) { 225 | stream_set_timeout($fp, 60); 226 | 227 | fwrite($fp, ($post ? "POST $m[path]" : "GET $m[path]?$m[query]")." HTTP/1.1\r\nHost: smsc.ru\r\nUser-Agent: PHP".($post ? "\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: ".strlen($m['query']) : "")."\r\nConnection: Close\r\n\r\n".($post ? $m['query'] : "")); 228 | 229 | while (!feof($fp)) { 230 | $result .= fgets($fp, 1024); 231 | } 232 | list(, $result) = explode("\r\n\r\n", $result, 2); 233 | 234 | fclose($fp); 235 | } 236 | } else { 237 | $result = file_get_contents($url); 238 | } 239 | 240 | return $result; 241 | } 242 | 243 | /** 244 | * @param string $message 245 | */ 246 | protected function log($message = '') 247 | { 248 | if ($this->debug) { 249 | $data = date("Y-m-d H:i:s") . " | " . $message . "\n"; 250 | file_put_contents($this->debug, $data, FILE_APPEND); 251 | } 252 | } 253 | 254 | /** 255 | * @param int $timeout 256 | */ 257 | private function initCurl($timeout) 258 | { 259 | if (function_exists("curl_init") && !$this->curl) { 260 | $this->curl = curl_init(); 261 | curl_setopt_array($this->curl, [ 262 | CURLOPT_RETURNTRANSFER => true, 263 | CURLOPT_CONNECTTIMEOUT => $timeout, 264 | CURLOPT_TIMEOUT => 60, 265 | CURLOPT_SSL_VERIFYPEER => 0, 266 | CURLOPT_HTTPHEADER => ['Expect:'] 267 | ]); 268 | } 269 | } 270 | 271 | /** 272 | * @param array $options 273 | */ 274 | private function setDebug($options) 275 | { 276 | if (isset($options['debug']) && is_file($options['debug'])) { 277 | $this->debug = $options['debug']; 278 | } else { 279 | $this->debug = null; 280 | } 281 | } 282 | } 283 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | --------------------------------------------------------------------------------