root/ext/pdo/pdo.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ZEND_DECLARE_MODULE_GLOBALS
  2. php_pdo_get_dbh_ce
  3. php_pdo_get_exception
  4. php_pdo_str_tolower_dup
  5. php_pdo_get_exception_base
  6. PHP_FUNCTION
  7. ZEND_GET_MODULE
  8. php_pdo_register_driver
  9. php_pdo_unregister_driver
  10. pdo_find_driver
  11. php_pdo_parse_data_source
  12. php_pdo_int64_to_str
  13. PHP_MINIT_FUNCTION
  14. PHP_MSHUTDOWN_FUNCTION
  15. PHP_MINFO_FUNCTION

   1 /*
   2   +----------------------------------------------------------------------+
   3   | PHP Version 7                                                        |
   4   +----------------------------------------------------------------------+
   5   | Copyright (c) 1997-2016 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 
  21 /* $Id$ */
  22 
  23 #ifdef HAVE_CONFIG_H
  24 #include "config.h"
  25 #endif
  26 
  27 #include <ctype.h>
  28 #include "php.h"
  29 #include "php_ini.h"
  30 #include "ext/standard/info.h"
  31 #include "php_pdo.h"
  32 #include "php_pdo_driver.h"
  33 #include "php_pdo_int.h"
  34 #include "zend_exceptions.h"
  35 
  36 static zend_class_entry *spl_ce_RuntimeException;
  37 
  38 zend_class_entry *pdo_dbh_ce, *pdo_dbstmt_ce, *pdo_row_ce;
  39 
  40 /* for exceptional circumstances */
  41 zend_class_entry *pdo_exception_ce;
  42 
  43 ZEND_DECLARE_MODULE_GLOBALS(pdo)
  44 static PHP_GINIT_FUNCTION(pdo);
  45 
  46 /* True global resources - no need for thread safety here */
  47 
  48 /* the registry of PDO drivers */
  49 HashTable pdo_driver_hash;
  50 
  51 /* we use persistent resources for the driver connection stuff */
  52 static int le_ppdo;
  53 
  54 int php_pdo_list_entry(void) /* {{{ */
  55 {
  56         return le_ppdo;
  57 }
  58 /* }}} */
  59 
  60 PDO_API zend_class_entry *php_pdo_get_dbh_ce(void) /* {{{ */
  61 {
  62         return pdo_dbh_ce;
  63 }
  64 /* }}} */
  65 
  66 PDO_API zend_class_entry *php_pdo_get_exception(void) /* {{{ */
  67 {
  68         return pdo_exception_ce;
  69 }
  70 /* }}} */
  71 
  72 PDO_API char *php_pdo_str_tolower_dup(const char *src, int len) /* {{{ */
  73 {
  74         char *dest = emalloc(len + 1);
  75         zend_str_tolower_copy(dest, src, len);
  76         return dest;
  77 }
  78 /* }}} */
  79 
  80 PDO_API zend_class_entry *php_pdo_get_exception_base(int root) /* {{{ */
  81 {
  82 #if defined(HAVE_SPL)
  83         if (!root) {
  84                 if (!spl_ce_RuntimeException) {
  85                         zend_class_entry *pce;
  86 
  87                         if ((pce = zend_hash_str_find_ptr(CG(class_table), "runtimeexception", sizeof("RuntimeException") - 1))) {
  88                                 spl_ce_RuntimeException = pce;
  89                                 return pce;
  90                         }
  91                 } else {
  92                         return spl_ce_RuntimeException;
  93                 }
  94         }
  95 #endif
  96         return zend_ce_exception;
  97 }
  98 /* }}} */
  99 
 100 /* {{{ proto array pdo_drivers()
 101  Return array of available PDO drivers */
 102 PHP_FUNCTION(pdo_drivers)
 103 {
 104         pdo_driver_t *pdriver;
 105 
 106         if (zend_parse_parameters_none() == FAILURE) {
 107                 return;
 108         }
 109 
 110         array_init(return_value);
 111 
 112         ZEND_HASH_FOREACH_PTR(&pdo_driver_hash, pdriver) {
 113                 add_next_index_stringl(return_value, (char*)pdriver->driver_name, pdriver->driver_name_len);
 114         } ZEND_HASH_FOREACH_END();
 115 }
 116 /* }}} */
 117 
 118 /* {{{ arginfo */
 119 ZEND_BEGIN_ARG_INFO(arginfo_pdo_drivers, 0)
 120 ZEND_END_ARG_INFO()
 121 /* }}} */
 122 
 123 /* {{{ pdo_functions[] */
 124 const zend_function_entry pdo_functions[] = {
 125         PHP_FE(pdo_drivers,             arginfo_pdo_drivers)
 126         PHP_FE_END
 127 };
 128 /* }}} */
 129 
 130 /* {{{ pdo_functions[] */
 131 #if ZEND_MODULE_API_NO >= 20050922
 132 static const zend_module_dep pdo_deps[] = {
 133 #ifdef HAVE_SPL
 134         ZEND_MOD_REQUIRED("spl")
 135 #endif
 136         ZEND_MOD_END
 137 };
 138 #endif
 139 /* }}} */
 140 
 141 /* {{{ pdo_module_entry */
 142 zend_module_entry pdo_module_entry = {
 143         STANDARD_MODULE_HEADER_EX, NULL,
 144         pdo_deps,
 145         "PDO",
 146         pdo_functions,
 147         PHP_MINIT(pdo),
 148         PHP_MSHUTDOWN(pdo),
 149         NULL,
 150         NULL,
 151         PHP_MINFO(pdo),
 152         PHP_PDO_VERSION,
 153         PHP_MODULE_GLOBALS(pdo),
 154         PHP_GINIT(pdo),
 155         NULL,
 156         NULL,
 157         STANDARD_MODULE_PROPERTIES_EX
 158 };
 159 /* }}} */
 160 
 161 /* TODO: visit persistent handles: for each persistent statement handle,
 162  * remove bound parameter associations */
 163 
 164 #ifdef COMPILE_DL_PDO
 165 ZEND_GET_MODULE(pdo)
 166 #endif
 167 
 168 /* {{{ PHP_GINIT_FUNCTION */
 169 static PHP_GINIT_FUNCTION(pdo)
 170 {
 171         pdo_globals->global_value = 0;
 172 }
 173 /* }}} */
 174 
 175 PDO_API int php_pdo_register_driver(pdo_driver_t *driver) /* {{{ */
 176 {
 177         if (driver->api_version != PDO_DRIVER_API) {
 178                 zend_error(E_ERROR, "PDO: driver %s requires PDO API version %pd; this is PDO version %d",
 179                         driver->driver_name, driver->api_version, PDO_DRIVER_API);
 180                 return FAILURE;
 181         }
 182         if (!zend_hash_str_exists(&module_registry, "pdo", sizeof("pdo") - 1)) {
 183                 zend_error(E_ERROR, "You MUST load PDO before loading any PDO drivers");
 184                 return FAILURE; /* NOTREACHED */
 185         }
 186 
 187         return zend_hash_str_add_ptr(&pdo_driver_hash, (char*)driver->driver_name, driver->driver_name_len, driver) != NULL;
 188 }
 189 /* }}} */
 190 
 191 PDO_API void php_pdo_unregister_driver(pdo_driver_t *driver) /* {{{ */
 192 {
 193         if (!zend_hash_str_exists(&module_registry, "pdo", sizeof("pdo") - 1)) {
 194                 return;
 195         }
 196 
 197         zend_hash_str_del(&pdo_driver_hash, (char*)driver->driver_name, driver->driver_name_len);
 198 }
 199 /* }}} */
 200 
 201 pdo_driver_t *pdo_find_driver(const char *name, int namelen) /* {{{ */
 202 {
 203         return zend_hash_str_find_ptr(&pdo_driver_hash, (char*)name, namelen);
 204 }
 205 /* }}} */
 206 
 207 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) /* {{{ */
 208 {
 209         int i, j;
 210         int valstart = -1;
 211         int semi = -1;
 212         int optstart = 0;
 213         int nlen;
 214         int n_matches = 0;
 215         int n_semicolumns = 0;
 216 
 217         i = 0;
 218         while (i < data_source_len) {
 219                 /* looking for NAME= */
 220 
 221                 if (data_source[i] == '\0') {
 222                         break;
 223                 }
 224 
 225                 if (data_source[i] != '=') {
 226                         ++i;
 227                         continue;
 228                 }
 229 
 230                 valstart = ++i;
 231 
 232                 /* now we're looking for VALUE; or just VALUE<NUL> */
 233                 semi = -1;
 234                 n_semicolumns = 0;
 235                 while (i < data_source_len) {
 236                         if (data_source[i] == '\0') {
 237                                 semi = i++;
 238                                 break;
 239                         }
 240                         if (data_source[i] == ';') {
 241                                 if ((i + 1 >= data_source_len) || data_source[i+1] != ';') {
 242                                         semi = i++;
 243                                         break;
 244                                 } else {
 245                                         n_semicolumns++;
 246                                         i += 2;
 247                                         continue;
 248                                 }
 249                         }
 250                         ++i;
 251                 }
 252 
 253                 if (semi == -1) {
 254                         semi = i;
 255                 }
 256 
 257                 /* find the entry in the array */
 258                 nlen = valstart - optstart - 1;
 259                 for (j = 0; j < nparams; j++) {
 260                         if (0 == strncmp(data_source + optstart, parsed[j].optname, nlen) && parsed[j].optname[nlen] == '\0') {
 261                                 /* got a match */
 262                                 if (parsed[j].freeme) {
 263                                         efree(parsed[j].optval);
 264                                 }
 265 
 266                                 if (n_semicolumns == 0) {
 267                                         parsed[j].optval = estrndup(data_source + valstart, semi - valstart - n_semicolumns);
 268                                 } else {
 269                                         int vlen = semi - valstart;
 270                                         const char *orig_val = data_source + valstart;
 271                                         char *new_val  = (char *) emalloc(vlen - n_semicolumns + 1);
 272 
 273                                         parsed[j].optval = new_val;
 274 
 275                                         while (vlen && *orig_val) {
 276                                                 *new_val = *orig_val;
 277                                                 new_val++;
 278 
 279                                                 if (*orig_val == ';') {
 280                                                         orig_val+=2;
 281                                                         vlen-=2;
 282                                                 } else {
 283                                                         orig_val++;
 284                                                         vlen--;
 285                                                 }
 286                                         }
 287                                         *new_val = '\0';
 288                                 }
 289 
 290                                 parsed[j].freeme = 1;
 291                                 ++n_matches;
 292                                 break;
 293                         }
 294                 }
 295 
 296                 while (i < data_source_len && isspace(data_source[i])) {
 297                         i++;
 298                 }
 299 
 300                 optstart = i;
 301         }
 302 
 303         return n_matches;
 304 }
 305 /* }}} */
 306 
 307 static const char digit_vec[] = "0123456789";
 308 PDO_API char *php_pdo_int64_to_str(pdo_int64_t i64) /* {{{ */
 309 {
 310         char buffer[65];
 311         char outbuf[65] = "";
 312         register char *p;
 313         zend_long long_val;
 314         char *dst = outbuf;
 315 
 316         if (i64 < 0) {
 317                 i64 = -i64;
 318                 *dst++ = '-';
 319         }
 320 
 321         if (i64 == 0) {
 322                 *dst++ = '0';
 323                 *dst++ = '\0';
 324                 return estrdup(outbuf);
 325         }
 326 
 327         p = &buffer[sizeof(buffer)-1];
 328         *p = '\0';
 329 
 330         while ((pdo_uint64_t)i64 > (pdo_uint64_t)ZEND_LONG_MAX) {
 331                 pdo_uint64_t quo = (pdo_uint64_t)i64 / (unsigned int)10;
 332                 unsigned int rem = (unsigned int)(i64 - quo*10U);
 333                 *--p = digit_vec[rem];
 334                 i64 = (pdo_int64_t)quo;
 335         }
 336         long_val = (zend_long)i64;
 337         while (long_val != 0) {
 338                 zend_long quo = long_val / 10;
 339                 *--p = digit_vec[(unsigned int)(long_val - quo * 10)];
 340                 long_val = quo;
 341         }
 342         while ((*dst++ = *p++) != 0)
 343                 ;
 344         *dst = '\0';
 345         return estrdup(outbuf);
 346 }
 347 /* }}} */
 348 
 349 /* {{{ PHP_MINIT_FUNCTION */
 350 PHP_MINIT_FUNCTION(pdo)
 351 {
 352         zend_class_entry ce;
 353 
 354         spl_ce_RuntimeException = NULL;
 355 
 356         if (FAILURE == pdo_sqlstate_init_error_table()) {
 357                 return FAILURE;
 358         }
 359 
 360         zend_hash_init(&pdo_driver_hash, 0, NULL, NULL, 1);
 361 
 362         le_ppdo = zend_register_list_destructors_ex(NULL, php_pdo_pdbh_dtor,
 363                 "PDO persistent database", module_number);
 364 
 365         INIT_CLASS_ENTRY(ce, "PDOException", NULL);
 366 
 367         pdo_exception_ce = zend_register_internal_class_ex(&ce, php_pdo_get_exception_base(0));
 368 
 369         zend_declare_property_null(pdo_exception_ce, "errorInfo", sizeof("errorInfo")-1, ZEND_ACC_PUBLIC);
 370 
 371         pdo_dbh_init();
 372         pdo_stmt_init();
 373 
 374         return SUCCESS;
 375 }
 376 /* }}} */
 377 
 378 /* {{{ PHP_MSHUTDOWN_FUNCTION */
 379 PHP_MSHUTDOWN_FUNCTION(pdo)
 380 {
 381         zend_hash_destroy(&pdo_driver_hash);
 382         pdo_sqlstate_fini_error_table();
 383         return SUCCESS;
 384 }
 385 /* }}} */
 386 
 387 /* {{{ PHP_MINFO_FUNCTION */
 388 PHP_MINFO_FUNCTION(pdo)
 389 {
 390         char *drivers = NULL, *ldrivers = estrdup("");
 391         pdo_driver_t *pdriver;
 392 
 393         php_info_print_table_start();
 394         php_info_print_table_header(2, "PDO support", "enabled");
 395 
 396         ZEND_HASH_FOREACH_PTR(&pdo_driver_hash, pdriver) {
 397                 spprintf(&drivers, 0, "%s, %s", ldrivers, pdriver->driver_name);
 398                 efree(ldrivers);
 399                 ldrivers = drivers;
 400         } ZEND_HASH_FOREACH_END();
 401 
 402         php_info_print_table_row(2, "PDO drivers", drivers ? drivers + 2 : "");
 403 
 404         if (drivers) {
 405                 efree(drivers);
 406         } else {
 407                 efree(ldrivers);
 408         }
 409 
 410         php_info_print_table_end();
 411 
 412 }
 413 /* }}} */
 414 
 415 /*
 416  * Local variables:
 417  * tab-width: 4
 418  * c-basic-offset: 4
 419  * End:
 420  * vim600: noet sw=4 ts=4 fdm=marker
 421  * vim<600: noet sw=4 ts=4
 422  */

/* [<][>][^][v][top][bottom][index][help] */