PageRenderTime 32ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/Braintree/Util.php

https://gitlab.com/vincent.perdereau/picandparts
PHP | 332 lines | 209 code | 22 blank | 101 comment | 22 complexity | 2cf47c3acd49da4a6c2b0a9a55701d7b MD5 | raw file
  1. <?php
  2. /**
  3. * Braintree Utility methods
  4. * PHP version 5
  5. *
  6. * @copyright 2014 Braintree, a division of PayPal, Inc.
  7. */
  8. class Braintree_Util
  9. {
  10. /**
  11. * extracts an attribute and returns an array of objects
  12. *
  13. * extracts the requested element from an array, and converts the contents
  14. * of its child arrays to objects of type Braintree_$attributeName, or returns
  15. * an array with a single element containing the value of that array element
  16. *
  17. * @param array $attribArray attributes from a search response
  18. * @param string $attributeName indicates which element of the passed array to extract
  19. *
  20. * @return array array of Braintree_$attributeName objects, or a single element array
  21. */
  22. public static function extractAttributeAsArray(& $attribArray, $attributeName)
  23. {
  24. if(!isset($attribArray[$attributeName])):
  25. return array();
  26. endif;
  27. // get what should be an array from the passed array
  28. $data = $attribArray[$attributeName];
  29. // set up the class that will be used to convert each array element
  30. $classFactory = self::buildClassName($attributeName) . '::factory';
  31. if(is_array($data)):
  32. // create an object from the data in each element
  33. $objectArray = array_map($classFactory, $data);
  34. else:
  35. return array($data);
  36. endif;
  37. unset($attribArray[$attributeName]);
  38. return $objectArray;
  39. }
  40. /**
  41. * throws an exception based on the type of error
  42. * @param string $statusCode HTTP status code to throw exception from
  43. * @throws Braintree_Exception multiple types depending on the error
  44. *
  45. */
  46. public static function throwStatusCodeException($statusCode, $message=null)
  47. {
  48. switch($statusCode) {
  49. case 401:
  50. throw new Braintree_Exception_Authentication();
  51. break;
  52. case 403:
  53. throw new Braintree_Exception_Authorization($message);
  54. break;
  55. case 404:
  56. throw new Braintree_Exception_NotFound();
  57. break;
  58. case 426:
  59. throw new Braintree_Exception_UpgradeRequired();
  60. break;
  61. case 500:
  62. throw new Braintree_Exception_ServerError();
  63. break;
  64. case 503:
  65. throw new Braintree_Exception_DownForMaintenance();
  66. break;
  67. default:
  68. throw new Braintree_Exception_Unexpected('Unexpected HTTP_RESPONSE #'.$statusCode);
  69. break;
  70. }
  71. }
  72. /**
  73. *
  74. * @param string $className
  75. * @param object $resultObj
  76. * @return object returns the passed object if successful
  77. * @throws Braintree_Exception_ValidationsFailed
  78. */
  79. public static function returnObjectOrThrowException($className, $resultObj)
  80. {
  81. $resultObjName = Braintree_Util::cleanClassName($className);
  82. if ($resultObj->success) {
  83. return $resultObj->$resultObjName;
  84. } else {
  85. throw new Braintree_Exception_ValidationsFailed();
  86. }
  87. }
  88. /**
  89. * removes the Braintree_ header from a classname
  90. *
  91. * @param string $name Braintree_ClassName
  92. * @return camelCased classname minus Braintree_ header
  93. */
  94. public static function cleanClassName($name)
  95. {
  96. $classNamesToResponseKeys = array(
  97. 'CreditCard' => 'creditCard',
  98. 'CreditCardGateway' => 'creditCard',
  99. 'Customer' => 'customer',
  100. 'CustomerGateway' => 'customer',
  101. 'Subscription' => 'subscription',
  102. 'SubscriptionGateway' => 'subscription',
  103. 'Transaction' => 'transaction',
  104. 'TransactionGateway' => 'transaction',
  105. 'CreditCardVerification' => 'verification',
  106. 'CreditCardVerificationGateway' => 'verification',
  107. 'AddOn' => 'addOn',
  108. 'AddOnGateway' => 'addOn',
  109. 'Discount' => 'discount',
  110. 'DiscountGateway' => 'discount',
  111. 'Plan' => 'plan',
  112. 'PlanGateway' => 'plan',
  113. 'Address' => 'address',
  114. 'AddressGateway' => 'address',
  115. 'SettlementBatchSummary' => 'settlementBatchSummary',
  116. 'SettlementBatchSummaryGateway' => 'settlementBatchSummary',
  117. 'MerchantAccount' => 'merchantAccount',
  118. 'MerchantAccountGateway' => 'merchantAccount',
  119. 'PayPalAccount' => 'paypalAccount',
  120. 'PayPalAccountGateway' => 'paypalAccount'
  121. );
  122. $name = str_replace('Braintree_', '', $name);
  123. return $classNamesToResponseKeys[$name];
  124. }
  125. /**
  126. *
  127. * @param string $name className
  128. * @return string Braintree_ClassName
  129. */
  130. public static function buildClassName($name)
  131. {
  132. $responseKeysToClassNames = array(
  133. 'creditCard' => 'CreditCard',
  134. 'customer' => 'Customer',
  135. 'subscription' => 'Subscription',
  136. 'transaction' => 'Transaction',
  137. 'verification' => 'CreditCardVerification',
  138. 'addOn' => 'AddOn',
  139. 'discount' => 'Discount',
  140. 'plan' => 'Plan',
  141. 'address' => 'Address',
  142. 'settlementBatchSummary' => 'SettlementBatchSummary',
  143. 'merchantAccount' => 'MerchantAccount'
  144. );
  145. return 'Braintree_' . $responseKeysToClassNames[$name];
  146. }
  147. /**
  148. * convert alpha-beta-gamma to alphaBetaGamma
  149. *
  150. * @access public
  151. * @param string $string
  152. * @return string modified string
  153. */
  154. public static function delimiterToCamelCase($string, $delimiter = '[\-\_]')
  155. {
  156. // php doesn't garbage collect functions created by create_function()
  157. // so use a static variable to avoid adding a new function to memory
  158. // every time this function is called.
  159. static $callback = null;
  160. if ($callback === null) {
  161. $callback = create_function('$matches', 'return strtoupper($matches[1]);');
  162. }
  163. return preg_replace_callback('/' . $delimiter . '(\w)/', $callback, $string);
  164. }
  165. /**
  166. * convert alpha-beta-gamma to alpha_beta_gamma
  167. *
  168. * @access public
  169. * @param string $string
  170. * @return string modified string
  171. */
  172. public static function delimiterToUnderscore($string)
  173. {
  174. return preg_replace('/-/', '_', $string);
  175. }
  176. /**
  177. * find capitals and convert to delimiter + lowercase
  178. *
  179. * @access public
  180. * @param var $string
  181. * @return var modified string
  182. */
  183. public static function camelCaseToDelimiter($string, $delimiter = '-')
  184. {
  185. // php doesn't garbage collect functions created by create_function()
  186. // so use a static variable to avoid adding a new function to memory
  187. // every time this function is called.
  188. static $callbacks = array();
  189. if (!isset($callbacks[$delimiter])) {
  190. $callbacks[$delimiter] = create_function('$matches', "return '$delimiter' . strtolower(\$matches[1]);");
  191. }
  192. return preg_replace_callback('/([A-Z])/', $callbacks[$delimiter], $string);
  193. }
  194. /**
  195. *
  196. * @param array $array associative array to implode
  197. * @param string $separator (optional, defaults to =)
  198. * @param string $glue (optional, defaults to ', ')
  199. */
  200. public static function implodeAssociativeArray($array, $separator = '=', $glue = ', ')
  201. {
  202. // build a new array with joined keys and values
  203. $tmpArray = null;
  204. foreach ($array AS $key => $value) {
  205. $tmpArray[] = $key . $separator . $value;
  206. }
  207. // implode and return the new array
  208. return (is_array($tmpArray)) ? implode($glue, $tmpArray) : false;
  209. }
  210. public static function attributesToString($attributes) {
  211. $printableAttribs = array();
  212. foreach ($attributes AS $key => $value) {
  213. if (is_array($value)) {
  214. $pAttrib = Braintree_Util::attributesToString($value);
  215. } else if ($value instanceof DateTime) {
  216. $pAttrib = $value->format(DateTime::RFC850);
  217. } else {
  218. $pAttrib = $value;
  219. }
  220. $printableAttribs[$key] = sprintf('%s', $pAttrib);
  221. }
  222. return Braintree_Util::implodeAssociativeArray($printableAttribs);
  223. }
  224. /**
  225. * verify user request structure
  226. *
  227. * compares the expected signature of a gateway request
  228. * against the actual structure sent by the user
  229. *
  230. * @param array $signature
  231. * @param array $attributes
  232. */
  233. public static function verifyKeys($signature, $attributes)
  234. {
  235. $validKeys = self::_flattenArray($signature);
  236. $userKeys = self::_flattenUserKeys($attributes);
  237. $invalidKeys = array_diff($userKeys, $validKeys);
  238. $invalidKeys = self::_removeWildcardKeys($validKeys, $invalidKeys);
  239. if(!empty($invalidKeys)) {
  240. asort($invalidKeys);
  241. $sortedList = join(', ', $invalidKeys);
  242. throw new InvalidArgumentException('invalid keys: '. $sortedList);
  243. }
  244. }
  245. /**
  246. * flattens a numerically indexed nested array to a single level
  247. * @param array $keys
  248. * @param string $namespace
  249. * @return array
  250. */
  251. private static function _flattenArray($keys, $namespace = null)
  252. {
  253. $flattenedArray = array();
  254. foreach($keys AS $key) {
  255. if(is_array($key)) {
  256. $theKeys = array_keys($key);
  257. $theValues = array_values($key);
  258. $scope = $theKeys[0];
  259. $fullKey = empty($namespace) ? $scope : $namespace . '[' . $scope . ']';
  260. $flattenedArray = array_merge($flattenedArray, self::_flattenArray($theValues[0], $fullKey));
  261. } else {
  262. $fullKey = empty($namespace) ? $key : $namespace . '[' . $key . ']';
  263. $flattenedArray[] = $fullKey;
  264. }
  265. }
  266. sort($flattenedArray);
  267. return $flattenedArray;
  268. }
  269. private static function _flattenUserKeys($keys, $namespace = null)
  270. {
  271. $flattenedArray = array();
  272. foreach($keys AS $key => $value) {
  273. $fullKey = empty($namespace) ? $key : $namespace;
  274. if (!is_numeric($key) && $namespace != null) {
  275. $fullKey .= '[' . $key . ']';
  276. }
  277. if (is_numeric($key) && is_string($value)) {
  278. $fullKey .= '[' . $value . ']';
  279. }
  280. if(is_array($value)) {
  281. $more = self::_flattenUserKeys($value, $fullKey);
  282. $flattenedArray = array_merge($flattenedArray, $more);
  283. } else {
  284. $flattenedArray[] = $fullKey;
  285. }
  286. }
  287. sort($flattenedArray);
  288. return $flattenedArray;
  289. }
  290. /**
  291. * removes wildcard entries from the invalid keys array
  292. * @param array $validKeys
  293. * @param <array $invalidKeys
  294. * @return array
  295. */
  296. private static function _removeWildcardKeys($validKeys, $invalidKeys)
  297. {
  298. foreach($validKeys AS $key) {
  299. if (stristr($key, '[_anyKey_]')) {
  300. $wildcardKey = str_replace('[_anyKey_]', '', $key);
  301. foreach ($invalidKeys AS $index => $invalidKey) {
  302. if (stristr($invalidKey, $wildcardKey)) {
  303. unset($invalidKeys[$index]);
  304. }
  305. }
  306. }
  307. }
  308. return $invalidKeys;
  309. }
  310. }