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 32 : {
51 32 : 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 1410640 : {
59 1410640 : return pdo_dbh_ce;
60 : }
61 :
62 : PDO_API zend_class_entry *php_pdo_get_exception(void)
63 58 : {
64 58 : 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 17662 : {
76 : #if can_handle_soft_dependency_on_SPL && defined(HAVE_SPL) && ((PHP_MAJOR_VERSION > 5) || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 1))
77 17662 : if (!root) {
78 17633 : if (!spl_ce_RuntimeException) {
79 : zend_class_entry **pce;
80 :
81 17633 : if (zend_hash_find(CG(class_table), "runtimeexception", sizeof("RuntimeException"), (void **) &pce) == SUCCESS) {
82 17633 : spl_ce_RuntimeException = *pce;
83 17633 : 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 29 : 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_parse_parameters_none() == FAILURE) {
107 0 : return;
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 : /* {{{ 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 : {NULL, NULL, NULL}
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 : {NULL, NULL, NULL}
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 17633 : {
177 17633 : pdo_globals->global_value = 0;
178 17633 : }
179 : /* }}} */
180 :
181 : PDO_API int php_pdo_register_driver(pdo_driver_t *driver)
182 105798 : {
183 105798 : if (driver->api_version != PDO_DRIVER_API) {
184 0 : 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 0 : return FAILURE;
187 : }
188 105798 : if (!zend_hash_exists(&module_registry, "pdo", sizeof("pdo"))) {
189 0 : zend_error(E_ERROR, "You MUST load PDO before loading any PDO drivers");
190 0 : return FAILURE; /* NOTREACHED */
191 : }
192 :
193 105798 : return zend_hash_add(&pdo_driver_hash, (char*)driver->driver_name, driver->driver_name_len,
194 : (void**)&driver, sizeof(driver), NULL);
195 : }
196 :
197 : PDO_API void php_pdo_unregister_driver(pdo_driver_t *driver)
198 105990 : {
199 105990 : if (!zend_hash_exists(&module_registry, "pdo", sizeof("pdo"))) {
200 0 : return;
201 : }
202 :
203 105990 : 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 1109 : {
208 1109 : pdo_driver_t **driver = NULL;
209 :
210 1109 : zend_hash_find(&pdo_driver_hash, (char*)name, namelen, (void**)&driver);
211 :
212 1109 : 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 697 : {
219 : int i, j;
220 697 : int valstart = -1;
221 697 : int semi = -1;
222 697 : int optstart = 0;
223 : int nlen;
224 697 : int n_matches = 0;
225 :
226 697 : i = 0;
227 118878 : while (i < data_source_len) {
228 : /* looking for NAME= */
229 :
230 117484 : if (data_source[i] == '\0') {
231 0 : break;
232 : }
233 :
234 117484 : if (data_source[i] != '=') {
235 115346 : ++i;
236 115346 : continue;
237 : }
238 :
239 2138 : valstart = ++i;
240 :
241 : /* now we're looking for VALUE; or just VALUE<NUL> */
242 2138 : semi = -1;
243 1045751 : while (i < data_source_len) {
244 1042918 : if (data_source[i] == '\0') {
245 0 : semi = i++;
246 0 : break;
247 : }
248 1042918 : if (data_source[i] == ';') {
249 1443 : semi = i++;
250 1443 : break;
251 : }
252 1041475 : ++i;
253 : }
254 :
255 2138 : if (semi == -1) {
256 695 : semi = i;
257 : }
258 :
259 : /* find the entry in the array */
260 2138 : nlen = valstart - optstart - 1;
261 8615 : for (j = 0; j < nparams; j++) {
262 7613 : if (0 == strncmp(data_source + optstart, parsed[j].optname, nlen) && parsed[j].optname[nlen] == '\0') {
263 : /* got a match */
264 1136 : if (parsed[j].freeme) {
265 4 : efree(parsed[j].optval);
266 : }
267 1136 : parsed[j].optval = estrndup(data_source + valstart, semi - valstart);
268 1136 : parsed[j].freeme = 1;
269 1136 : ++n_matches;
270 1136 : break;
271 : }
272 : }
273 :
274 4276 : while (i < data_source_len && isspace(data_source[i])) {
275 0 : i++;
276 : }
277 :
278 2138 : optstart = i;
279 : }
280 :
281 697 : return n_matches;
282 : }
283 :
284 : static const char digit_vec[] = "0123456789";
285 : PDO_API char *php_pdo_int64_to_str(pdo_int64_t i64 TSRMLS_DC)
286 13 : {
287 : char buffer[65];
288 13 : char outbuf[65] = "";
289 : register char *p;
290 : long long_val;
291 13 : char *dst = outbuf;
292 :
293 13 : if (i64 < 0) {
294 0 : i64 = -i64;
295 0 : *dst++ = '-';
296 : }
297 :
298 13 : if (i64 == 0) {
299 8 : *dst++ = '0';
300 8 : *dst++ = '\0';
301 8 : return estrdup(outbuf);
302 : }
303 :
304 5 : p = &buffer[sizeof(buffer)-1];
305 5 : *p = '\0';
306 :
307 10 : while ((pdo_uint64_t)i64 > (pdo_uint64_t)LONG_MAX) {
308 0 : pdo_uint64_t quo = (pdo_uint64_t)i64 / (unsigned int)10;
309 0 : unsigned int rem = (unsigned int)(i64 - quo*10U);
310 0 : *--p = digit_vec[rem];
311 0 : i64 = (pdo_int64_t)quo;
312 : }
313 5 : long_val = (long)i64;
314 22 : while (long_val != 0) {
315 12 : long quo = long_val / 10;
316 12 : *--p = digit_vec[(unsigned int)(long_val - quo * 10)];
317 12 : long_val = quo;
318 : }
319 17 : while ((*dst++ = *p++) != 0)
320 : ;
321 5 : *dst = '\0';
322 5 : return estrdup(outbuf);
323 : }
324 :
325 : /* {{{ PHP_MINIT_FUNCTION */
326 : PHP_MINIT_FUNCTION(pdo)
327 17633 : {
328 : zend_class_entry ce;
329 :
330 17633 : spl_ce_RuntimeException = NULL;
331 :
332 17633 : if (FAILURE == pdo_sqlstate_init_error_table()) {
333 0 : return FAILURE;
334 : }
335 :
336 17633 : zend_hash_init(&pdo_driver_hash, 0, NULL, NULL, 1);
337 :
338 17633 : le_ppdo = zend_register_list_destructors_ex(NULL, php_pdo_pdbh_dtor,
339 : "PDO persistent database", module_number);
340 :
341 17633 : INIT_CLASS_ENTRY(ce, "PDOException", NULL);
342 :
343 17633 : pdo_exception_ce = zend_register_internal_class_ex(&ce, php_pdo_get_exception_base(0 TSRMLS_CC), NULL TSRMLS_CC);
344 :
345 17633 : zend_declare_property_null(pdo_exception_ce, "errorInfo", sizeof("errorInfo")-1, ZEND_ACC_PUBLIC TSRMLS_CC);
346 :
347 17633 : pdo_dbh_init(TSRMLS_C);
348 17633 : pdo_stmt_init(TSRMLS_C);
349 :
350 17633 : return SUCCESS;
351 : }
352 : /* }}} */
353 :
354 : /* {{{ PHP_MSHUTDOWN_FUNCTION */
355 : PHP_MSHUTDOWN_FUNCTION(pdo)
356 17665 : {
357 17665 : zend_hash_destroy(&pdo_driver_hash);
358 17665 : pdo_sqlstate_fini_error_table();
359 17665 : return SUCCESS;
360 : }
361 : /* }}} */
362 :
363 : /* {{{ PHP_MINFO_FUNCTION */
364 : PHP_MINFO_FUNCTION(pdo)
365 42 : {
366 : HashPosition pos;
367 42 : char *drivers = NULL, *ldrivers = estrdup("");
368 : pdo_driver_t **pdriver;
369 :
370 42 : php_info_print_table_start();
371 42 : php_info_print_table_header(2, "PDO support", "enabled");
372 :
373 42 : zend_hash_internal_pointer_reset_ex(&pdo_driver_hash, &pos);
374 336 : while (SUCCESS == zend_hash_get_current_data_ex(&pdo_driver_hash, (void**)&pdriver, &pos)) {
375 252 : spprintf(&drivers, 0, "%s, %s", ldrivers, (*pdriver)->driver_name);
376 252 : zend_hash_move_forward_ex(&pdo_driver_hash, &pos);
377 252 : efree(ldrivers);
378 252 : ldrivers = drivers;
379 : }
380 :
381 42 : php_info_print_table_row(2, "PDO drivers", drivers ? drivers+2 : "");
382 :
383 42 : if (drivers) {
384 42 : efree(drivers);
385 : } else {
386 0 : efree(ldrivers);
387 : }
388 :
389 42 : php_info_print_table_end();
390 :
391 42 : }
392 : /* }}} */
393 :
394 : /*
395 : * Local variables:
396 : * tab-width: 4
397 : * c-basic-offset: 4
398 : * End:
399 : * vim600: noet sw=4 ts=4 fdm=marker
400 : * vim<600: noet sw=4 ts=4
401 : */
|