Guild Wars stat tracking The idea behind this is to track multiple characters individual stats as well as account stats.
Non puoi selezionare più di 25 argomenti Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.
 
 
 
 
 

317 righe
12 KiB

  1. <?php
  2. /**
  3. * A Compatibility library with PHP 5.5's simplified password hashing API.
  4. *
  5. * @author Anthony Ferrara <[email protected]>
  6. * @license http://www.opensource.org/licenses/mit-license.html MIT License
  7. * @copyright 2012 The Authors
  8. */
  9. namespace {
  10. if (!defined('PASSWORD_BCRYPT')) {
  11. /**
  12. * PHPUnit Process isolation caches constants, but not function declarations.
  13. * So we need to check if the constants are defined separately from
  14. * the functions to enable supporting process isolation in userland
  15. * code.
  16. */
  17. define('PASSWORD_BCRYPT', 1);
  18. define('PASSWORD_DEFAULT', PASSWORD_BCRYPT);
  19. define('PASSWORD_BCRYPT_DEFAULT_COST', 10);
  20. }
  21. if (!function_exists('password_hash')) {
  22. /**
  23. * Hash the password using the specified algorithm
  24. *
  25. * @param string $password The password to hash
  26. * @param int $algo The algorithm to use (Defined by PASSWORD_* constants)
  27. * @param array $options The options for the algorithm to use
  28. *
  29. * @return string|false The hashed password, or false on error.
  30. */
  31. function password_hash($password, $algo, array $options = array()) {
  32. if (!function_exists('crypt')) {
  33. trigger_error("Crypt must be loaded for password_hash to function", E_USER_WARNING);
  34. return null;
  35. }
  36. if (is_null($password) || is_int($password)) {
  37. $password = (string) $password;
  38. }
  39. if (!is_string($password)) {
  40. trigger_error("password_hash(): Password must be a string", E_USER_WARNING);
  41. return null;
  42. }
  43. if (!is_int($algo)) {
  44. trigger_error("password_hash() expects parameter 2 to be long, " . gettype($algo) . " given", E_USER_WARNING);
  45. return null;
  46. }
  47. $resultLength = 0;
  48. switch ($algo) {
  49. case PASSWORD_BCRYPT:
  50. $cost = PASSWORD_BCRYPT_DEFAULT_COST;
  51. if (isset($options['cost'])) {
  52. $cost = (int) $options['cost'];
  53. if ($cost < 4 || $cost > 31) {
  54. trigger_error(sprintf("password_hash(): Invalid bcrypt cost parameter specified: %d", $cost), E_USER_WARNING);
  55. return null;
  56. }
  57. }
  58. // The length of salt to generate
  59. $raw_salt_len = 16;
  60. // The length required in the final serialization
  61. $required_salt_len = 22;
  62. $hash_format = sprintf("$2y$%02d$", $cost);
  63. // The expected length of the final crypt() output
  64. $resultLength = 60;
  65. break;
  66. default:
  67. trigger_error(sprintf("password_hash(): Unknown password hashing algorithm: %s", $algo), E_USER_WARNING);
  68. return null;
  69. }
  70. $salt_req_encoding = false;
  71. if (isset($options['salt'])) {
  72. switch (gettype($options['salt'])) {
  73. case 'NULL':
  74. case 'boolean':
  75. case 'integer':
  76. case 'double':
  77. case 'string':
  78. $salt = (string) $options['salt'];
  79. break;
  80. case 'object':
  81. if (method_exists($options['salt'], '__tostring')) {
  82. $salt = (string) $options['salt'];
  83. break;
  84. }
  85. case 'array':
  86. case 'resource':
  87. default:
  88. trigger_error('password_hash(): Non-string salt parameter supplied', E_USER_WARNING);
  89. return null;
  90. }
  91. if (PasswordCompat\binary\_strlen($salt) < $required_salt_len) {
  92. trigger_error(sprintf("password_hash(): Provided salt is too short: %d expecting %d", PasswordCompat\binary\_strlen($salt), $required_salt_len), E_USER_WARNING);
  93. return null;
  94. } elseif (0 == preg_match('#^[a-zA-Z0-9./]+$#D', $salt)) {
  95. $salt_req_encoding = true;
  96. }
  97. } else {
  98. $buffer = '';
  99. $buffer_valid = false;
  100. if (function_exists('mcrypt_create_iv') && !defined('PHALANGER')) {
  101. $buffer = mcrypt_create_iv($raw_salt_len, MCRYPT_DEV_URANDOM);
  102. if ($buffer) {
  103. $buffer_valid = true;
  104. }
  105. }
  106. if (!$buffer_valid && function_exists('openssl_random_pseudo_bytes')) {
  107. $strong = false;
  108. $buffer = openssl_random_pseudo_bytes($raw_salt_len, $strong);
  109. if ($buffer && $strong) {
  110. $buffer_valid = true;
  111. }
  112. }
  113. if (!$buffer_valid && @is_readable('/dev/urandom')) {
  114. $file = fopen('/dev/urandom', 'r');
  115. $read = 0;
  116. $local_buffer = '';
  117. while ($read < $raw_salt_len) {
  118. $local_buffer .= fread($file, $raw_salt_len - $read);
  119. $read = PasswordCompat\binary\_strlen($local_buffer);
  120. }
  121. fclose($file);
  122. if ($read >= $raw_salt_len) {
  123. $buffer_valid = true;
  124. }
  125. $buffer = str_pad($buffer, $raw_salt_len, "\0") ^ str_pad($local_buffer, $raw_salt_len, "\0");
  126. }
  127. if (!$buffer_valid || PasswordCompat\binary\_strlen($buffer) < $raw_salt_len) {
  128. $buffer_length = PasswordCompat\binary\_strlen($buffer);
  129. for ($i = 0; $i < $raw_salt_len; $i++) {
  130. if ($i < $buffer_length) {
  131. $buffer[$i] = $buffer[$i] ^ chr(mt_rand(0, 255));
  132. } else {
  133. $buffer .= chr(mt_rand(0, 255));
  134. }
  135. }
  136. }
  137. $salt = $buffer;
  138. $salt_req_encoding = true;
  139. }
  140. if ($salt_req_encoding) {
  141. // encode string with the Base64 variant used by crypt
  142. $base64_digits =
  143. 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
  144. $bcrypt64_digits =
  145. './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
  146. $base64_string = base64_encode($salt);
  147. $salt = strtr(rtrim($base64_string, '='), $base64_digits, $bcrypt64_digits);
  148. }
  149. $salt = PasswordCompat\binary\_substr($salt, 0, $required_salt_len);
  150. $hash = $hash_format . $salt;
  151. $ret = crypt($password, $hash);
  152. if (!is_string($ret) || PasswordCompat\binary\_strlen($ret) != $resultLength) {
  153. return false;
  154. }
  155. return $ret;
  156. }
  157. /**
  158. * Get information about the password hash. Returns an array of the information
  159. * that was used to generate the password hash.
  160. *
  161. * array(
  162. * 'algo' => 1,
  163. * 'algoName' => 'bcrypt',
  164. * 'options' => array(
  165. * 'cost' => PASSWORD_BCRYPT_DEFAULT_COST,
  166. * ),
  167. * )
  168. *
  169. * @param string $hash The password hash to extract info from
  170. *
  171. * @return array The array of information about the hash.
  172. */
  173. function password_get_info($hash) {
  174. $return = array(
  175. 'algo' => 0,
  176. 'algoName' => 'unknown',
  177. 'options' => array(),
  178. );
  179. if (PasswordCompat\binary\_substr($hash, 0, 4) == '$2y$' && PasswordCompat\binary\_strlen($hash) == 60) {
  180. $return['algo'] = PASSWORD_BCRYPT;
  181. $return['algoName'] = 'bcrypt';
  182. list($cost) = sscanf($hash, "$2y$%d$");
  183. $return['options']['cost'] = $cost;
  184. }
  185. return $return;
  186. }
  187. /**
  188. * Determine if the password hash needs to be rehashed according to the options provided
  189. *
  190. * If the answer is true, after validating the password using password_verify, rehash it.
  191. *
  192. * @param string $hash The hash to test
  193. * @param int $algo The algorithm used for new password hashes
  194. * @param array $options The options array passed to password_hash
  195. *
  196. * @return boolean True if the password needs to be rehashed.
  197. */
  198. function password_needs_rehash($hash, $algo, array $options = array()) {
  199. $info = password_get_info($hash);
  200. if ($info['algo'] !== (int) $algo) {
  201. return true;
  202. }
  203. switch ($algo) {
  204. case PASSWORD_BCRYPT:
  205. $cost = isset($options['cost']) ? (int) $options['cost'] : PASSWORD_BCRYPT_DEFAULT_COST;
  206. if ($cost !== $info['options']['cost']) {
  207. return true;
  208. }
  209. break;
  210. }
  211. return false;
  212. }
  213. /**
  214. * Verify a password against a hash using a timing attack resistant approach
  215. *
  216. * @param string $password The password to verify
  217. * @param string $hash The hash to verify against
  218. *
  219. * @return boolean If the password matches the hash
  220. */
  221. function password_verify($password, $hash) {
  222. if (!function_exists('crypt')) {
  223. trigger_error("Crypt must be loaded for password_verify to function", E_USER_WARNING);
  224. return false;
  225. }
  226. $ret = crypt($password, $hash);
  227. if (!is_string($ret) || PasswordCompat\binary\_strlen($ret) != PasswordCompat\binary\_strlen($hash) || PasswordCompat\binary\_strlen($ret) <= 13) {
  228. return false;
  229. }
  230. $status = 0;
  231. for ($i = 0; $i < PasswordCompat\binary\_strlen($ret); $i++) {
  232. $status |= (ord($ret[$i]) ^ ord($hash[$i]));
  233. }
  234. return $status === 0;
  235. }
  236. }
  237. }
  238. namespace PasswordCompat\binary {
  239. if (!function_exists('PasswordCompat\\binary\\_strlen')) {
  240. /**
  241. * Count the number of bytes in a string
  242. *
  243. * We cannot simply use strlen() for this, because it might be overwritten by the mbstring extension.
  244. * In this case, strlen() will count the number of *characters* based on the internal encoding. A
  245. * sequence of bytes might be regarded as a single multibyte character.
  246. *
  247. * @param string $binary_string The input string
  248. *
  249. * @internal
  250. * @return int The number of bytes
  251. */
  252. function _strlen($binary_string) {
  253. if (function_exists('mb_strlen')) {
  254. return mb_strlen($binary_string, '8bit');
  255. }
  256. return strlen($binary_string);
  257. }
  258. /**
  259. * Get a substring based on byte limits
  260. *
  261. * @see _strlen()
  262. *
  263. * @param string $binary_string The input string
  264. * @param int $start
  265. * @param int $length
  266. *
  267. * @internal
  268. * @return string The substring
  269. */
  270. function _substr($binary_string, $start, $length) {
  271. if (function_exists('mb_substr')) {
  272. return mb_substr($binary_string, $start, $length, '8bit');
  273. }
  274. return substr($binary_string, $start, $length);
  275. }
  276. /**
  277. * Check if current PHP version is compatible with the library
  278. *
  279. * @return boolean the check result
  280. */
  281. function check() {
  282. static $pass = NULL;
  283. if (is_null($pass)) {
  284. if (function_exists('crypt')) {
  285. $hash = '$2y$04$usesomesillystringfore7hnbRJHxXVLeakoG8K30oukPsA.ztMG';
  286. $test = crypt("password", $hash);
  287. $pass = $test == $hash;
  288. } else {
  289. $pass = false;
  290. }
  291. }
  292. return $pass;
  293. }
  294. }
  295. }