| 1 | 1 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,292 @@ |
| 1 |
+<?php |
|
| 2 |
+ |
|
| 3 |
+namespace Telnyx\Util; |
|
| 4 |
+ |
|
| 5 |
+use Telnyx\TelnyxObject; |
|
| 6 |
+ |
|
| 7 |
+abstract class Util |
|
| 8 |
+{
|
|
| 9 |
+ private static $isMbstringAvailable = null; |
|
| 10 |
+ private static $isHashEqualsAvailable = null; |
|
| 11 |
+ |
|
| 12 |
+ /** |
|
| 13 |
+ * Whether the provided array (or other) is a list rather than a dictionary. |
|
| 14 |
+ * A list is defined as an array for which all the keys are consecutive |
|
| 15 |
+ * integers starting at 0. Empty arrays are considered to be lists. |
|
| 16 |
+ * |
|
| 17 |
+ * @param array|mixed $array |
|
| 18 |
+ * @return boolean true if the given object is a list. |
|
| 19 |
+ */ |
|
| 20 |
+ public static function isList($array) |
|
| 21 |
+ {
|
|
| 22 |
+ if (!is_array($array)) {
|
|
| 23 |
+ return false; |
|
| 24 |
+ } |
|
| 25 |
+ if ($array === []) {
|
|
| 26 |
+ return true; |
|
| 27 |
+ } |
|
| 28 |
+ if (array_keys($array) !== range(0, count($array) - 1)) {
|
|
| 29 |
+ return false; |
|
| 30 |
+ } |
|
| 31 |
+ return true; |
|
| 32 |
+ } |
|
| 33 |
+ |
|
| 34 |
+ /** |
|
| 35 |
+ * Recursively converts the PHP Telnyx object to an array. |
|
| 36 |
+ * |
|
| 37 |
+ * @param array $values The PHP Telnyx object to convert. |
|
| 38 |
+ * @return array |
|
| 39 |
+ */ |
|
| 40 |
+ public static function convertTelnyxObjectToArray($values) |
|
| 41 |
+ {
|
|
| 42 |
+ $results = []; |
|
| 43 |
+ foreach ($values as $k => $v) {
|
|
| 44 |
+ // FIXME: this is an encapsulation violation |
|
| 45 |
+ if ($k[0] == '_') {
|
|
| 46 |
+ continue; |
|
| 47 |
+ } |
|
| 48 |
+ if ($v instanceof TelnyxObject) {
|
|
| 49 |
+ $results[$k] = $v->__toArray(true); |
|
| 50 |
+ } elseif (is_array($v)) {
|
|
| 51 |
+ $results[$k] = self::convertTelnyxObjectToArray($v); |
|
| 52 |
+ } else {
|
|
| 53 |
+ $results[$k] = $v; |
|
| 54 |
+ } |
|
| 55 |
+ } |
|
| 56 |
+ return $results; |
|
| 57 |
+ } |
|
| 58 |
+ |
|
| 59 |
+ /** |
|
| 60 |
+ * Converts a response from the Telnyx API to the corresponding PHP object. |
|
| 61 |
+ * |
|
| 62 |
+ * @param array $resp The response from the Telnyx API. |
|
| 63 |
+ * @param array $opts |
|
| 64 |
+ * @return TelnyxObject|array |
|
| 65 |
+ */ |
|
| 66 |
+ public static function convertToTelnyxObject($resp, $opts) |
|
| 67 |
+ {
|
|
| 68 |
+ $types = [ |
|
| 69 |
+ // data structures |
|
| 70 |
+ \Telnyx\Collection::OBJECT_NAME => 'Telnyx\\Collection', |
|
| 71 |
+ |
|
| 72 |
+ // Telnyx API: Numbers |
|
| 73 |
+ \Telnyx\AvailablePhoneNumber::OBJECT_NAME => 'Telnyx\\AvailablePhoneNumber', |
|
| 74 |
+ \Telnyx\NumberOrder::OBJECT_NAME => 'Telnyx\\NumberOrder', |
|
| 75 |
+ \Telnyx\NumberReservation::OBJECT_NAME => 'Telnyx\\NumberReservation', |
|
| 76 |
+ |
|
| 77 |
+ // Telnyx API: Messaging |
|
| 78 |
+ \Telnyx\Message::OBJECT_NAME => 'Telnyx\\Message', |
|
| 79 |
+ \Telnyx\MessagingProfile::OBJECT_NAME => 'Telnyx\\MessagingProfile', |
|
| 80 |
+ \Telnyx\MessagingPhoneNumber::OBJECT_NAME => 'Telnyx\\MessagingPhoneNumber', |
|
| 81 |
+ \Telnyx\AlphanumericSenderID::OBJECT_NAME => 'Telnyx\\AlphanumericSenderID', |
|
| 82 |
+ \Telnyx\ShortCode::OBJECT_NAME => 'Telnyx\\ShortCode', |
|
| 83 |
+ ]; |
|
| 84 |
+ if (self::isList($resp)) {
|
|
| 85 |
+ $mapped = []; |
|
| 86 |
+ foreach ($resp as $i) {
|
|
| 87 |
+ array_push($mapped, self::convertToTelnyxObject($i, $opts)); |
|
| 88 |
+ } |
|
| 89 |
+ return $mapped; |
|
| 90 |
+ } elseif (is_array($resp)) {
|
|
| 91 |
+ if (isset($resp['record_type']) && is_string($resp['record_type']) && isset($types[$resp['record_type']])) {
|
|
| 92 |
+ $class = $types[$resp['record_type']]; |
|
| 93 |
+ } else {
|
|
| 94 |
+ $class = 'Telnyx\\TelnyxObject'; |
|
| 95 |
+ } |
|
| 96 |
+ return $class::constructFrom($resp, $opts); |
|
| 97 |
+ } else {
|
|
| 98 |
+ return $resp; |
|
| 99 |
+ } |
|
| 100 |
+ } |
|
| 101 |
+ |
|
| 102 |
+ /** |
|
| 103 |
+ * @param string|mixed $value A string to UTF8-encode. |
|
| 104 |
+ * |
|
| 105 |
+ * @return string|mixed The UTF8-encoded string, or the object passed in if |
|
| 106 |
+ * it wasn't a string. |
|
| 107 |
+ */ |
|
| 108 |
+ public static function utf8($value) |
|
| 109 |
+ {
|
|
| 110 |
+ if (self::$isMbstringAvailable === null) {
|
|
| 111 |
+ self::$isMbstringAvailable = function_exists('mb_detect_encoding');
|
|
| 112 |
+ |
|
| 113 |
+ if (!self::$isMbstringAvailable) {
|
|
| 114 |
+ trigger_error("It looks like the mbstring extension is not enabled. " .
|
|
| 115 |
+ "UTF-8 strings will not properly be encoded. Ask your system " . |
|
| 116 |
+ "administrator to enable the mbstring extension, or write to " . |
|
| 117 |
+ "support@telnyx.com if you have any questions.", E_USER_WARNING); |
|
| 118 |
+ } |
|
| 119 |
+ } |
|
| 120 |
+ |
|
| 121 |
+ if (is_string($value) && self::$isMbstringAvailable && mb_detect_encoding($value, "UTF-8", true) != "UTF-8") {
|
|
| 122 |
+ return utf8_encode($value); |
|
| 123 |
+ } else {
|
|
| 124 |
+ return $value; |
|
| 125 |
+ } |
|
| 126 |
+ } |
|
| 127 |
+ |
|
| 128 |
+ /** |
|
| 129 |
+ * Compares two strings for equality. The time taken is independent of the |
|
| 130 |
+ * number of characters that match. |
|
| 131 |
+ * |
|
| 132 |
+ * @param string $a one of the strings to compare. |
|
| 133 |
+ * @param string $b the other string to compare. |
|
| 134 |
+ * @return bool true if the strings are equal, false otherwise. |
|
| 135 |
+ */ |
|
| 136 |
+ public static function secureCompare($a, $b) |
|
| 137 |
+ {
|
|
| 138 |
+ if (self::$isHashEqualsAvailable === null) {
|
|
| 139 |
+ self::$isHashEqualsAvailable = function_exists('hash_equals');
|
|
| 140 |
+ } |
|
| 141 |
+ |
|
| 142 |
+ if (self::$isHashEqualsAvailable) {
|
|
| 143 |
+ return hash_equals($a, $b); |
|
| 144 |
+ } else {
|
|
| 145 |
+ if (strlen($a) != strlen($b)) {
|
|
| 146 |
+ return false; |
|
| 147 |
+ } |
|
| 148 |
+ |
|
| 149 |
+ $result = 0; |
|
| 150 |
+ for ($i = 0; $i < strlen($a); $i++) {
|
|
| 151 |
+ $result |= ord($a[$i]) ^ ord($b[$i]); |
|
| 152 |
+ } |
|
| 153 |
+ return ($result == 0); |
|
| 154 |
+ } |
|
| 155 |
+ } |
|
| 156 |
+ |
|
| 157 |
+ /** |
|
| 158 |
+ * Recursively goes through an array of parameters. If a parameter is an instance of |
|
| 159 |
+ * ApiResource, then it is replaced by the resource's ID. |
|
| 160 |
+ * Also clears out null values. |
|
| 161 |
+ * |
|
| 162 |
+ * @param mixed $h |
|
| 163 |
+ * @return mixed |
|
| 164 |
+ */ |
|
| 165 |
+ public static function objectsToIds($h) |
|
| 166 |
+ {
|
|
| 167 |
+ if ($h instanceof \Telnyx\ApiResource) {
|
|
| 168 |
+ return $h->id; |
|
| 169 |
+ } elseif (static::isList($h)) {
|
|
| 170 |
+ $results = []; |
|
| 171 |
+ foreach ($h as $v) {
|
|
| 172 |
+ array_push($results, static::objectsToIds($v)); |
|
| 173 |
+ } |
|
| 174 |
+ return $results; |
|
| 175 |
+ } elseif (is_array($h)) {
|
|
| 176 |
+ $results = []; |
|
| 177 |
+ foreach ($h as $k => $v) {
|
|
| 178 |
+ if (is_null($v)) {
|
|
| 179 |
+ continue; |
|
| 180 |
+ } |
|
| 181 |
+ $results[$k] = static::objectsToIds($v); |
|
| 182 |
+ } |
|
| 183 |
+ return $results; |
|
| 184 |
+ } else {
|
|
| 185 |
+ return $h; |
|
| 186 |
+ } |
|
| 187 |
+ } |
|
| 188 |
+ |
|
| 189 |
+ /** |
|
| 190 |
+ * @param array $params |
|
| 191 |
+ * |
|
| 192 |
+ * @return string |
|
| 193 |
+ */ |
|
| 194 |
+ public static function encodeParameters($params) |
|
| 195 |
+ {
|
|
| 196 |
+ $flattenedParams = self::flattenParams($params); |
|
| 197 |
+ $pieces = []; |
|
| 198 |
+ foreach ($flattenedParams as $param) {
|
|
| 199 |
+ list($k, $v) = $param; |
|
| 200 |
+ array_push($pieces, self::urlEncode($k) . '=' . self::urlEncode($v)); |
|
| 201 |
+ } |
|
| 202 |
+ return implode('&', $pieces);
|
|
| 203 |
+ } |
|
| 204 |
+ |
|
| 205 |
+ /** |
|
| 206 |
+ * @param array $params |
|
| 207 |
+ * @param string|null $parentKey |
|
| 208 |
+ * |
|
| 209 |
+ * @return array |
|
| 210 |
+ */ |
|
| 211 |
+ public static function flattenParams($params, $parentKey = null) |
|
| 212 |
+ {
|
|
| 213 |
+ $result = []; |
|
| 214 |
+ |
|
| 215 |
+ foreach ($params as $key => $value) {
|
|
| 216 |
+ $calculatedKey = $parentKey ? "{$parentKey}[{$key}]" : $key;
|
|
| 217 |
+ |
|
| 218 |
+ if (self::isList($value)) {
|
|
| 219 |
+ $result = array_merge($result, self::flattenParamsList($value, $calculatedKey)); |
|
| 220 |
+ } elseif (is_array($value)) {
|
|
| 221 |
+ $result = array_merge($result, self::flattenParams($value, $calculatedKey)); |
|
| 222 |
+ } else {
|
|
| 223 |
+ array_push($result, [$calculatedKey, $value]); |
|
| 224 |
+ } |
|
| 225 |
+ } |
|
| 226 |
+ |
|
| 227 |
+ return $result; |
|
| 228 |
+ } |
|
| 229 |
+ |
|
| 230 |
+ /** |
|
| 231 |
+ * @param array $value |
|
| 232 |
+ * @param string $calculatedKey |
|
| 233 |
+ * |
|
| 234 |
+ * @return array |
|
| 235 |
+ */ |
|
| 236 |
+ public static function flattenParamsList($value, $calculatedKey) |
|
| 237 |
+ {
|
|
| 238 |
+ $result = []; |
|
| 239 |
+ |
|
| 240 |
+ foreach ($value as $i => $elem) {
|
|
| 241 |
+ if (self::isList($elem)) {
|
|
| 242 |
+ $result = array_merge($result, self::flattenParamsList($elem, $calculatedKey)); |
|
| 243 |
+ } elseif (is_array($elem)) {
|
|
| 244 |
+ $result = array_merge($result, self::flattenParams($elem, "{$calculatedKey}[{$i}]"));
|
|
| 245 |
+ } else {
|
|
| 246 |
+ array_push($result, ["{$calculatedKey}[{$i}]", $elem]);
|
|
| 247 |
+ } |
|
| 248 |
+ } |
|
| 249 |
+ |
|
| 250 |
+ return $result; |
|
| 251 |
+ } |
|
| 252 |
+ |
|
| 253 |
+ /** |
|
| 254 |
+ * @param string $key A string to URL-encode. |
|
| 255 |
+ * |
|
| 256 |
+ * @return string The URL-encoded string. |
|
| 257 |
+ */ |
|
| 258 |
+ public static function urlEncode($key) |
|
| 259 |
+ {
|
|
| 260 |
+ $s = urlencode($key); |
|
| 261 |
+ |
|
| 262 |
+ // Don't use strict form encoding by changing the square bracket control |
|
| 263 |
+ // characters back to their literals. This is fine by the server, and |
|
| 264 |
+ // makes these parameter strings easier to read. |
|
| 265 |
+ $s = str_replace('%5B', '[', $s);
|
|
| 266 |
+ $s = str_replace('%5D', ']', $s);
|
|
| 267 |
+ |
|
| 268 |
+ return $s; |
|
| 269 |
+ } |
|
| 270 |
+ |
|
| 271 |
+ public static function normalizeId($id) |
|
| 272 |
+ {
|
|
| 273 |
+ if (is_array($id)) {
|
|
| 274 |
+ $params = $id; |
|
| 275 |
+ $id = $params['id']; |
|
| 276 |
+ unset($params['id']); |
|
| 277 |
+ } else {
|
|
| 278 |
+ $params = []; |
|
| 279 |
+ } |
|
| 280 |
+ return [$id, $params]; |
|
| 281 |
+ } |
|
| 282 |
+ |
|
| 283 |
+ /** |
|
| 284 |
+ * Returns UNIX timestamp in milliseconds |
|
| 285 |
+ * |
|
| 286 |
+ * @return integer current time in millis |
|
| 287 |
+ */ |
|
| 288 |
+ public static function currentTimeMillis() |
|
| 289 |
+ {
|
|
| 290 |
+ return (int) round(microtime(true) * 1000); |
|
| 291 |
+ } |
|
| 292 |
+} |