uniqid.c 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. /*
  2. +----------------------------------------------------------------------+
  3. | Copyright (c) The PHP Group |
  4. +----------------------------------------------------------------------+
  5. | This source file is subject to version 3.01 of the PHP license, |
  6. | that is bundled with this package in the file LICENSE, and is |
  7. | available through the world-wide-web at the following url: |
  8. | https://www.php.net/license/3_01.txt |
  9. | If you did not receive a copy of the PHP license and are unable to |
  10. | obtain it through the world-wide-web, please send a note to |
  11. | license@php.net so we can mail you a copy immediately. |
  12. +----------------------------------------------------------------------+
  13. | Author: Stig Sæther Bakken <ssb@php.net> |
  14. +----------------------------------------------------------------------+
  15. */
  16. #include "php.h"
  17. #include <stdlib.h>
  18. #if HAVE_UNISTD_H
  19. #include <unistd.h>
  20. #endif
  21. #include <string.h>
  22. #include <errno.h>
  23. #include <stdio.h>
  24. #ifdef PHP_WIN32
  25. #include "win32/time.h"
  26. #else
  27. #include <sys/time.h>
  28. #endif
  29. #include "php_lcg.h"
  30. #include "php_random.h"
  31. #ifdef HAVE_GETTIMEOFDAY
  32. ZEND_TLS struct timeval prev_tv = { 0, 0 };
  33. /* {{{ Generates a unique ID */
  34. PHP_FUNCTION(uniqid)
  35. {
  36. char *prefix = "";
  37. bool more_entropy = 0;
  38. zend_string *uniqid;
  39. int sec, usec;
  40. size_t prefix_len = 0;
  41. struct timeval tv;
  42. ZEND_PARSE_PARAMETERS_START(0, 2)
  43. Z_PARAM_OPTIONAL
  44. Z_PARAM_STRING(prefix, prefix_len)
  45. Z_PARAM_BOOL(more_entropy)
  46. ZEND_PARSE_PARAMETERS_END();
  47. /* This implementation needs current microsecond to change,
  48. * hence we poll time until it does. This is much faster than
  49. * calling usleep(1) which may cause the kernel to schedule
  50. * another process, causing a pause of around 10ms.
  51. */
  52. do {
  53. (void)gettimeofday((struct timeval *) &tv, (struct timezone *) NULL);
  54. } while (tv.tv_sec == prev_tv.tv_sec && tv.tv_usec == prev_tv.tv_usec);
  55. prev_tv.tv_sec = tv.tv_sec;
  56. prev_tv.tv_usec = tv.tv_usec;
  57. sec = (int) tv.tv_sec;
  58. usec = (int) (tv.tv_usec % 0x100000);
  59. /* The max value usec can have is 0xF423F, so we use only five hex
  60. * digits for usecs.
  61. */
  62. if (more_entropy) {
  63. uint32_t bytes;
  64. double seed;
  65. if (php_random_bytes_silent(&bytes, sizeof(uint32_t)) == FAILURE) {
  66. seed = php_combined_lcg() * 10;
  67. } else {
  68. seed = ((double) bytes / UINT32_MAX) * 10.0;
  69. }
  70. uniqid = strpprintf(0, "%s%08x%05x%.8F", prefix, sec, usec, seed);
  71. } else {
  72. uniqid = strpprintf(0, "%s%08x%05x", prefix, sec, usec);
  73. }
  74. RETURN_STR(uniqid);
  75. }
  76. #endif
  77. /* }}} */