pdo.c 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 7 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1997-2018 The PHP Group |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 3.01 of the PHP license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available through the world-wide-web at the following url: |
  10. | http://www.php.net/license/3_01.txt |
  11. | If you did not receive a copy of the PHP license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@php.net so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. | Author: Wez Furlong <wez@php.net> |
  16. | Marcus Boerger <helly@php.net> |
  17. | Sterling Hughes <sterling@php.net> |
  18. +----------------------------------------------------------------------+
  19. */
  20. #ifdef HAVE_CONFIG_H
  21. #include "config.h"
  22. #endif
  23. #include <ctype.h>
  24. #include "php.h"
  25. #include "php_ini.h"
  26. #include "ext/standard/info.h"
  27. #include "php_pdo.h"
  28. #include "php_pdo_driver.h"
  29. #include "php_pdo_int.h"
  30. #include "zend_exceptions.h"
  31. #include "ext/spl/spl_exceptions.h"
  32. zend_class_entry *pdo_dbh_ce, *pdo_dbstmt_ce, *pdo_row_ce;
  33. /* for exceptional circumstances */
  34. zend_class_entry *pdo_exception_ce;
  35. ZEND_DECLARE_MODULE_GLOBALS(pdo)
  36. static PHP_GINIT_FUNCTION(pdo);
  37. /* True global resources - no need for thread safety here */
  38. /* the registry of PDO drivers */
  39. HashTable pdo_driver_hash;
  40. /* we use persistent resources for the driver connection stuff */
  41. static int le_ppdo;
  42. int php_pdo_list_entry(void) /* {{{ */
  43. {
  44. return le_ppdo;
  45. }
  46. /* }}} */
  47. PDO_API zend_class_entry *php_pdo_get_dbh_ce(void) /* {{{ */
  48. {
  49. return pdo_dbh_ce;
  50. }
  51. /* }}} */
  52. PDO_API zend_class_entry *php_pdo_get_exception(void) /* {{{ */
  53. {
  54. return pdo_exception_ce;
  55. }
  56. /* }}} */
  57. PDO_API char *php_pdo_str_tolower_dup(const char *src, int len) /* {{{ */
  58. {
  59. char *dest = emalloc(len + 1);
  60. zend_str_tolower_copy(dest, src, len);
  61. return dest;
  62. }
  63. /* }}} */
  64. PDO_API zend_class_entry *php_pdo_get_exception_base(int root) /* {{{ */
  65. {
  66. if (!root) {
  67. return spl_ce_RuntimeException;
  68. }
  69. return zend_ce_exception;
  70. }
  71. /* }}} */
  72. /* {{{ proto array pdo_drivers()
  73. Return array of available PDO drivers */
  74. PHP_FUNCTION(pdo_drivers)
  75. {
  76. pdo_driver_t *pdriver;
  77. if (zend_parse_parameters_none() == FAILURE) {
  78. return;
  79. }
  80. array_init(return_value);
  81. ZEND_HASH_FOREACH_PTR(&pdo_driver_hash, pdriver) {
  82. add_next_index_stringl(return_value, (char*)pdriver->driver_name, pdriver->driver_name_len);
  83. } ZEND_HASH_FOREACH_END();
  84. }
  85. /* }}} */
  86. /* {{{ arginfo */
  87. ZEND_BEGIN_ARG_INFO(arginfo_pdo_drivers, 0)
  88. ZEND_END_ARG_INFO()
  89. /* }}} */
  90. /* {{{ pdo_functions[] */
  91. const zend_function_entry pdo_functions[] = {
  92. PHP_FE(pdo_drivers, arginfo_pdo_drivers)
  93. PHP_FE_END
  94. };
  95. /* }}} */
  96. /* {{{ pdo_functions[] */
  97. static const zend_module_dep pdo_deps[] = {
  98. ZEND_MOD_REQUIRED("spl")
  99. ZEND_MOD_END
  100. };
  101. /* }}} */
  102. /* {{{ pdo_module_entry */
  103. zend_module_entry pdo_module_entry = {
  104. STANDARD_MODULE_HEADER_EX, NULL,
  105. pdo_deps,
  106. "PDO",
  107. pdo_functions,
  108. PHP_MINIT(pdo),
  109. PHP_MSHUTDOWN(pdo),
  110. NULL,
  111. NULL,
  112. PHP_MINFO(pdo),
  113. PHP_PDO_VERSION,
  114. PHP_MODULE_GLOBALS(pdo),
  115. PHP_GINIT(pdo),
  116. NULL,
  117. NULL,
  118. STANDARD_MODULE_PROPERTIES_EX
  119. };
  120. /* }}} */
  121. /* TODO: visit persistent handles: for each persistent statement handle,
  122. * remove bound parameter associations */
  123. #ifdef COMPILE_DL_PDO
  124. ZEND_GET_MODULE(pdo)
  125. #endif
  126. /* {{{ PHP_GINIT_FUNCTION */
  127. static PHP_GINIT_FUNCTION(pdo)
  128. {
  129. pdo_globals->global_value = 0;
  130. }
  131. /* }}} */
  132. PDO_API int php_pdo_register_driver(const pdo_driver_t *driver) /* {{{ */
  133. {
  134. if (driver->api_version != PDO_DRIVER_API) {
  135. zend_error(E_ERROR, "PDO: driver %s requires PDO API version " ZEND_ULONG_FMT "; this is PDO version %d",
  136. driver->driver_name, driver->api_version, PDO_DRIVER_API);
  137. return FAILURE;
  138. }
  139. if (!zend_hash_str_exists(&module_registry, "pdo", sizeof("pdo") - 1)) {
  140. zend_error(E_ERROR, "You MUST load PDO before loading any PDO drivers");
  141. return FAILURE; /* NOTREACHED */
  142. }
  143. return zend_hash_str_add_ptr(&pdo_driver_hash, (char*)driver->driver_name, driver->driver_name_len, (void*)driver) != NULL ? SUCCESS : FAILURE;
  144. }
  145. /* }}} */
  146. PDO_API void php_pdo_unregister_driver(const pdo_driver_t *driver) /* {{{ */
  147. {
  148. if (!zend_hash_str_exists(&module_registry, "pdo", sizeof("pdo") - 1)) {
  149. return;
  150. }
  151. zend_hash_str_del(&pdo_driver_hash, (char*)driver->driver_name, driver->driver_name_len);
  152. }
  153. /* }}} */
  154. pdo_driver_t *pdo_find_driver(const char *name, int namelen) /* {{{ */
  155. {
  156. return zend_hash_str_find_ptr(&pdo_driver_hash, (char*)name, namelen);
  157. }
  158. /* }}} */
  159. PDO_API int php_pdo_parse_data_source(const char *data_source, zend_ulong data_source_len, struct pdo_data_src_parser *parsed, int nparams) /* {{{ */
  160. {
  161. zend_ulong i;
  162. int j;
  163. int valstart = -1;
  164. int semi = -1;
  165. int optstart = 0;
  166. int nlen;
  167. int n_matches = 0;
  168. int n_semicolumns = 0;
  169. i = 0;
  170. while (i < data_source_len) {
  171. /* looking for NAME= */
  172. if (data_source[i] == '\0') {
  173. break;
  174. }
  175. if (data_source[i] != '=') {
  176. ++i;
  177. continue;
  178. }
  179. valstart = ++i;
  180. /* now we're looking for VALUE; or just VALUE<NUL> */
  181. semi = -1;
  182. n_semicolumns = 0;
  183. while (i < data_source_len) {
  184. if (data_source[i] == '\0') {
  185. semi = i++;
  186. break;
  187. }
  188. if (data_source[i] == ';') {
  189. if ((i + 1 >= data_source_len) || data_source[i+1] != ';') {
  190. semi = i++;
  191. break;
  192. } else {
  193. n_semicolumns++;
  194. i += 2;
  195. continue;
  196. }
  197. }
  198. ++i;
  199. }
  200. if (semi == -1) {
  201. semi = i;
  202. }
  203. /* find the entry in the array */
  204. nlen = valstart - optstart - 1;
  205. for (j = 0; j < nparams; j++) {
  206. if (0 == strncmp(data_source + optstart, parsed[j].optname, nlen) && parsed[j].optname[nlen] == '\0') {
  207. /* got a match */
  208. if (parsed[j].freeme) {
  209. efree(parsed[j].optval);
  210. }
  211. if (n_semicolumns == 0) {
  212. parsed[j].optval = estrndup(data_source + valstart, semi - valstart - n_semicolumns);
  213. } else {
  214. int vlen = semi - valstart;
  215. const char *orig_val = data_source + valstart;
  216. char *new_val = (char *) emalloc(vlen - n_semicolumns + 1);
  217. parsed[j].optval = new_val;
  218. while (vlen && *orig_val) {
  219. *new_val = *orig_val;
  220. new_val++;
  221. if (*orig_val == ';') {
  222. orig_val+=2;
  223. vlen-=2;
  224. } else {
  225. orig_val++;
  226. vlen--;
  227. }
  228. }
  229. *new_val = '\0';
  230. }
  231. parsed[j].freeme = 1;
  232. ++n_matches;
  233. break;
  234. }
  235. }
  236. while (i < data_source_len && isspace(data_source[i])) {
  237. i++;
  238. }
  239. optstart = i;
  240. }
  241. return n_matches;
  242. }
  243. /* }}} */
  244. static const char digit_vec[] = "0123456789";
  245. PDO_API char *php_pdo_int64_to_str(pdo_int64_t i64) /* {{{ */
  246. {
  247. char buffer[65];
  248. char outbuf[65] = "";
  249. register char *p;
  250. zend_long long_val;
  251. char *dst = outbuf;
  252. if (i64 < 0) {
  253. i64 = -i64;
  254. *dst++ = '-';
  255. }
  256. if (i64 == 0) {
  257. *dst++ = '0';
  258. *dst++ = '\0';
  259. return estrdup(outbuf);
  260. }
  261. p = &buffer[sizeof(buffer)-1];
  262. *p = '\0';
  263. while ((pdo_uint64_t)i64 > (pdo_uint64_t)ZEND_LONG_MAX) {
  264. pdo_uint64_t quo = (pdo_uint64_t)i64 / (unsigned int)10;
  265. unsigned int rem = (unsigned int)(i64 - quo*10U);
  266. *--p = digit_vec[rem];
  267. i64 = (pdo_int64_t)quo;
  268. }
  269. long_val = (zend_long)i64;
  270. while (long_val != 0) {
  271. zend_long quo = long_val / 10;
  272. *--p = digit_vec[(unsigned int)(long_val - quo * 10)];
  273. long_val = quo;
  274. }
  275. while ((*dst++ = *p++) != 0)
  276. ;
  277. *dst = '\0';
  278. return estrdup(outbuf);
  279. }
  280. /* }}} */
  281. /* {{{ PHP_MINIT_FUNCTION */
  282. PHP_MINIT_FUNCTION(pdo)
  283. {
  284. zend_class_entry ce;
  285. if (FAILURE == pdo_sqlstate_init_error_table()) {
  286. return FAILURE;
  287. }
  288. zend_hash_init(&pdo_driver_hash, 0, NULL, NULL, 1);
  289. le_ppdo = zend_register_list_destructors_ex(NULL, php_pdo_pdbh_dtor,
  290. "PDO persistent database", module_number);
  291. INIT_CLASS_ENTRY(ce, "PDOException", NULL);
  292. pdo_exception_ce = zend_register_internal_class_ex(&ce, php_pdo_get_exception_base(0));
  293. zend_declare_property_null(pdo_exception_ce, "errorInfo", sizeof("errorInfo")-1, ZEND_ACC_PUBLIC);
  294. pdo_dbh_init();
  295. pdo_stmt_init();
  296. return SUCCESS;
  297. }
  298. /* }}} */
  299. /* {{{ PHP_MSHUTDOWN_FUNCTION */
  300. PHP_MSHUTDOWN_FUNCTION(pdo)
  301. {
  302. zend_hash_destroy(&pdo_driver_hash);
  303. pdo_sqlstate_fini_error_table();
  304. return SUCCESS;
  305. }
  306. /* }}} */
  307. /* {{{ PHP_MINFO_FUNCTION */
  308. PHP_MINFO_FUNCTION(pdo)
  309. {
  310. char *drivers = NULL, *ldrivers = estrdup("");
  311. pdo_driver_t *pdriver;
  312. php_info_print_table_start();
  313. php_info_print_table_header(2, "PDO support", "enabled");
  314. ZEND_HASH_FOREACH_PTR(&pdo_driver_hash, pdriver) {
  315. spprintf(&drivers, 0, "%s, %s", ldrivers, pdriver->driver_name);
  316. efree(ldrivers);
  317. ldrivers = drivers;
  318. } ZEND_HASH_FOREACH_END();
  319. php_info_print_table_row(2, "PDO drivers", drivers ? drivers + 2 : "");
  320. if (drivers) {
  321. efree(drivers);
  322. } else {
  323. efree(ldrivers);
  324. }
  325. php_info_print_table_end();
  326. }
  327. /* }}} */
  328. /*
  329. * Local variables:
  330. * tab-width: 4
  331. * c-basic-offset: 4
  332. * End:
  333. * vim600: noet sw=4 ts=4 fdm=marker
  334. * vim<600: noet sw=4 ts=4
  335. */