1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 5 |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) 1997-2009 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: pdo.c 284394 2009-07-19 22:46:03Z felipe $ */
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 1 : {
51 1 : 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 1058070 : {
59 1058070 : return pdo_dbh_ce;
60 : }
61 :
62 : PDO_API zend_class_entry *php_pdo_get_exception(void)
63 25 : {
64 25 : return pdo_exception_ce;
65 : }
66 :
67 : PDO_API char *php_pdo_str_tolower_dup(const char *src, int len)
68 0 : {
69 0 : char *dest = emalloc(len + 1);
70 0 : zend_str_tolower_copy(dest, src, len);
71 0 : return dest;
72 : }
73 :
74 : PDO_API zend_class_entry *php_pdo_get_exception_base(int root TSRMLS_DC)
75 13582 : {
76 : #if can_handle_soft_dependency_on_SPL && defined(HAVE_SPL) && ((PHP_MAJOR_VERSION > 5) || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 1))
77 13582 : if (!root) {
78 13565 : if (!spl_ce_RuntimeException) {
79 : zend_class_entry **pce;
80 :
81 13565 : if (zend_hash_find(CG(class_table), "runtimeexception", sizeof("RuntimeException"), (void **) &pce) == SUCCESS) {
82 13565 : spl_ce_RuntimeException = *pce;
83 13565 : return *pce;
84 : }
85 : } else {
86 0 : 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 17 : 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 0 : {
103 : HashPosition pos;
104 : pdo_driver_t **pdriver;
105 :
106 0 : if (ZEND_NUM_ARGS()) {
107 0 : WRONG_PARAM_COUNT;
108 : }
109 :
110 0 : array_init(return_value);
111 :
112 0 : zend_hash_internal_pointer_reset_ex(&pdo_driver_hash, &pos);
113 0 : while (SUCCESS == zend_hash_get_current_data_ex(&pdo_driver_hash, (void**)&pdriver, &pos)) {
114 0 : add_next_index_stringl(return_value, (char*)(*pdriver)->driver_name, (*pdriver)->driver_name_len, 1);
115 0 : zend_hash_move_forward_ex(&pdo_driver_hash, &pos);
116 : }
117 : }
118 : /* }}} */
119 :
120 : /* {{{ pdo_functions[] */
121 : zend_function_entry pdo_functions[] = {
122 : PHP_FE(pdo_drivers, NULL)
123 : {NULL, NULL, NULL}
124 : };
125 : /* }}} */
126 :
127 : /* {{{ pdo_functions[] */
128 : #if ZEND_MODULE_API_NO >= 20050922
129 : static zend_module_dep pdo_deps[] = {
130 : #ifdef HAVE_SPL
131 : ZEND_MOD_REQUIRED("spl")
132 : #endif
133 : {NULL, NULL, NULL}
134 : };
135 : #endif
136 : /* }}} */
137 :
138 : /* {{{ pdo_module_entry */
139 : zend_module_entry pdo_module_entry = {
140 : #if ZEND_MODULE_API_NO >= 20050922
141 : STANDARD_MODULE_HEADER_EX, NULL,
142 : pdo_deps,
143 : #else
144 : STANDARD_MODULE_HEADER,
145 : #endif
146 : "PDO",
147 : pdo_functions,
148 : PHP_MINIT(pdo),
149 : PHP_MSHUTDOWN(pdo),
150 : NULL,
151 : NULL,
152 : PHP_MINFO(pdo),
153 : "1.0.4dev",
154 : PHP_MODULE_GLOBALS(pdo),
155 : PHP_GINIT(pdo),
156 : NULL,
157 : NULL,
158 : STANDARD_MODULE_PROPERTIES_EX
159 : };
160 : /* }}} */
161 :
162 : /* TODO: visit persistent handles: for each persistent statement handle,
163 : * remove bound parameter associations */
164 :
165 : #ifdef COMPILE_DL_PDO
166 : ZEND_GET_MODULE(pdo)
167 : #endif
168 :
169 : /* {{{ PHP_GINIT_FUNCTION */
170 : static PHP_GINIT_FUNCTION(pdo)
171 13565 : {
172 13565 : pdo_globals->global_value = 0;
173 13565 : }
174 : /* }}} */
175 :
176 : PDO_API int php_pdo_register_driver(pdo_driver_t *driver)
177 67825 : {
178 67825 : if (driver->api_version != PDO_DRIVER_API) {
179 0 : zend_error(E_ERROR, "PDO: driver %s requires PDO API version %ld; this is PDO version %d",
180 : driver->driver_name, driver->api_version, PDO_DRIVER_API);
181 0 : return FAILURE;
182 : }
183 67825 : if (!zend_hash_exists(&module_registry, "pdo", sizeof("pdo"))) {
184 0 : zend_error(E_ERROR, "You MUST load PDO before loading any PDO drivers");
185 0 : return FAILURE; /* NOTREACHED */
186 : }
187 :
188 67825 : return zend_hash_add(&pdo_driver_hash, (char*)driver->driver_name, driver->driver_name_len,
189 : (void**)&driver, sizeof(driver), NULL);
190 : }
191 :
192 : PDO_API void php_pdo_unregister_driver(pdo_driver_t *driver)
193 67990 : {
194 67990 : if (!zend_hash_exists(&module_registry, "pdo", sizeof("pdo"))) {
195 0 : return;
196 : }
197 :
198 67990 : zend_hash_del(&pdo_driver_hash, (char*)driver->driver_name, driver->driver_name_len);
199 : }
200 :
201 : pdo_driver_t *pdo_find_driver(const char *name, int namelen)
202 609 : {
203 609 : pdo_driver_t **driver = NULL;
204 :
205 609 : zend_hash_find(&pdo_driver_hash, (char*)name, namelen, (void**)&driver);
206 :
207 609 : return driver ? *driver : NULL;
208 : }
209 :
210 : PDO_API int php_pdo_parse_data_source(const char *data_source,
211 : unsigned long data_source_len, struct pdo_data_src_parser *parsed,
212 : int nparams)
213 260 : {
214 : int i, j;
215 260 : int valstart = -1;
216 260 : int semi = -1;
217 260 : int optstart = 0;
218 : int nlen;
219 260 : int n_matches = 0;
220 :
221 260 : i = 0;
222 2968 : while (i < data_source_len) {
223 : /* looking for NAME= */
224 :
225 2448 : if (data_source[i] == '\0') {
226 0 : break;
227 : }
228 :
229 2448 : if (data_source[i] != '=') {
230 2063 : ++i;
231 2063 : continue;
232 : }
233 :
234 385 : valstart = ++i;
235 :
236 : /* now we're looking for VALUE; or just VALUE<NUL> */
237 385 : semi = -1;
238 4278 : while (i < data_source_len) {
239 3633 : if (data_source[i] == '\0') {
240 0 : semi = i++;
241 0 : break;
242 : }
243 3633 : if (data_source[i] == ';') {
244 125 : semi = i++;
245 125 : break;
246 : }
247 3508 : ++i;
248 : }
249 :
250 385 : if (semi == -1) {
251 260 : semi = i;
252 : }
253 :
254 : /* find the entry in the array */
255 385 : nlen = valstart - optstart - 1;
256 893 : for (j = 0; j < nparams; j++) {
257 893 : if (0 == strncmp(data_source + optstart, parsed[j].optname, nlen) && parsed[j].optname[nlen] == '\0') {
258 : /* got a match */
259 385 : if (parsed[j].freeme) {
260 0 : efree(parsed[j].optval);
261 : }
262 385 : parsed[j].optval = estrndup(data_source + valstart, semi - valstart);
263 385 : parsed[j].freeme = 1;
264 385 : ++n_matches;
265 385 : break;
266 : }
267 : }
268 :
269 770 : while (i < data_source_len && isspace(data_source[i])) {
270 0 : i++;
271 : }
272 :
273 385 : optstart = i;
274 : }
275 :
276 260 : return n_matches;
277 : }
278 :
279 : static const char digit_vec[] = "0123456789";
280 : PDO_API char *php_pdo_int64_to_str(pdo_int64_t i64 TSRMLS_DC)
281 2 : {
282 : char buffer[65];
283 2 : char outbuf[65] = "";
284 : register char *p;
285 : long long_val;
286 2 : char *dst = outbuf;
287 :
288 2 : if (i64 < 0) {
289 0 : i64 = -i64;
290 0 : *dst++ = '-';
291 : }
292 :
293 2 : if (i64 == 0) {
294 0 : *dst++ = '0';
295 0 : *dst++ = '\0';
296 0 : return estrdup(outbuf);
297 : }
298 :
299 2 : p = &buffer[sizeof(buffer)-1];
300 2 : *p = '\0';
301 :
302 4 : while ((pdo_uint64_t)i64 > (pdo_uint64_t)LONG_MAX) {
303 0 : pdo_uint64_t quo = (pdo_uint64_t)i64 / (unsigned int)10;
304 0 : unsigned int rem = (unsigned int)(i64 - quo*10U);
305 0 : *--p = digit_vec[rem];
306 0 : i64 = (pdo_int64_t)quo;
307 : }
308 2 : long_val = (long)i64;
309 7 : while (long_val != 0) {
310 3 : long quo = long_val / 10;
311 3 : *--p = digit_vec[(unsigned int)(long_val - quo * 10)];
312 3 : long_val = quo;
313 : }
314 5 : while ((*dst++ = *p++) != 0)
315 : ;
316 2 : *dst = '\0';
317 2 : return estrdup(outbuf);
318 : }
319 :
320 : /* {{{ PHP_MINIT_FUNCTION */
321 : PHP_MINIT_FUNCTION(pdo)
322 13565 : {
323 : zend_class_entry ce;
324 :
325 13565 : spl_ce_RuntimeException = NULL;
326 :
327 13565 : if (FAILURE == pdo_sqlstate_init_error_table()) {
328 0 : return FAILURE;
329 : }
330 :
331 13565 : zend_hash_init(&pdo_driver_hash, 0, NULL, NULL, 1);
332 :
333 13565 : le_ppdo = zend_register_list_destructors_ex(NULL, php_pdo_pdbh_dtor,
334 : "PDO persistent database", module_number);
335 :
336 13565 : INIT_CLASS_ENTRY(ce, "PDOException", NULL);
337 :
338 13565 : pdo_exception_ce = zend_register_internal_class_ex(&ce, php_pdo_get_exception_base(0 TSRMLS_CC), NULL TSRMLS_CC);
339 :
340 13565 : zend_declare_property_null(pdo_exception_ce, "errorInfo", sizeof("errorInfo")-1, ZEND_ACC_PUBLIC TSRMLS_CC);
341 :
342 13565 : pdo_dbh_init(TSRMLS_C);
343 13565 : pdo_stmt_init(TSRMLS_C);
344 :
345 13565 : return SUCCESS;
346 : }
347 : /* }}} */
348 :
349 : /* {{{ PHP_MSHUTDOWN_FUNCTION */
350 : PHP_MSHUTDOWN_FUNCTION(pdo)
351 13598 : {
352 13598 : zend_hash_destroy(&pdo_driver_hash);
353 13598 : pdo_sqlstate_fini_error_table();
354 13598 : return SUCCESS;
355 : }
356 : /* }}} */
357 :
358 : /* {{{ PHP_MINFO_FUNCTION */
359 : PHP_MINFO_FUNCTION(pdo)
360 6 : {
361 : HashPosition pos;
362 6 : char *drivers = NULL, *ldrivers = estrdup("");
363 : pdo_driver_t **pdriver;
364 :
365 6 : php_info_print_table_start();
366 6 : php_info_print_table_header(2, "PDO support", "enabled");
367 :
368 6 : zend_hash_internal_pointer_reset_ex(&pdo_driver_hash, &pos);
369 42 : while (SUCCESS == zend_hash_get_current_data_ex(&pdo_driver_hash, (void**)&pdriver, &pos)) {
370 30 : spprintf(&drivers, 0, "%s, %s", ldrivers, (*pdriver)->driver_name);
371 30 : zend_hash_move_forward_ex(&pdo_driver_hash, &pos);
372 30 : efree(ldrivers);
373 30 : ldrivers = drivers;
374 : }
375 :
376 6 : php_info_print_table_row(2, "PDO drivers", drivers ? drivers+2 : "");
377 :
378 6 : if (drivers) {
379 6 : efree(drivers);
380 : } else {
381 0 : efree(ldrivers);
382 : }
383 :
384 6 : php_info_print_table_end();
385 :
386 6 : }
387 : /* }}} */
388 :
389 : /*
390 : * Local variables:
391 : * tab-width: 4
392 : * c-basic-offset: 4
393 : * End:
394 : * vim600: noet sw=4 ts=4 fdm=marker
395 : * vim<600: noet sw=4 ts=4
396 : */
|