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

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