Subversion-Projekte lars-tiefland.php_share

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 1
<?php
2
// +----------------------------------------------------------------------+
3
// | PHP Version 4                                                        |
4
// +----------------------------------------------------------------------+
5
// | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox,                 |
6
// | Stig. S. Bakken, Lukas Smith                                         |
7
// | All rights reserved.                                                 |
8
// +----------------------------------------------------------------------+
9
// | MDB is a merge of PEAR DB and Metabases that provides a unified DB   |
10
// | API as well as database abstraction for PHP applications.            |
11
// | This LICENSE is in the BSD license style.                            |
12
// |                                                                      |
13
// | Redistribution and use in source and binary forms, with or without   |
14
// | modification, are permitted provided that the following conditions   |
15
// | are met:                                                             |
16
// |                                                                      |
17
// | Redistributions of source code must retain the above copyright       |
18
// | notice, this list of conditions and the following disclaimer.        |
19
// |                                                                      |
20
// | Redistributions in binary form must reproduce the above copyright    |
21
// | notice, this list of conditions and the following disclaimer in the  |
22
// | documentation and/or other materials provided with the distribution. |
23
// |                                                                      |
24
// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken,    |
25
// | Lukas Smith nor the names of his contributors may be used to endorse |
26
// | or promote products derived from this software without specific prior|
27
// | written permission.                                                  |
28
// |                                                                      |
29
// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS  |
30
// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT    |
31
// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS    |
32
// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE      |
33
// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,          |
34
// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
35
// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
36
// |  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED  |
37
// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT          |
38
// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
39
// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE          |
40
// | POSSIBILITY OF SUCH DAMAGE.                                          |
41
// +----------------------------------------------------------------------+
42
// | Author: Lukas Smith <smith@backendmedia.com>                         |
43
// +----------------------------------------------------------------------+
44
//
45
// $Id: MDB.php,v 1.59.4.12 2004/02/28 10:37:54 quipo Exp $
46
//
47
require_once('PEAR.php');
48
 
49
/**
50
 * The method mapErrorCode in each MDB_dbtype implementation maps
51
 * native error codes to one of these.
52
 *
53
 * If you add an error code here, make sure you also add a textual
54
 * version of it in MDB::errorMessage().
55
 */
56
 
57
define('MDB_OK',                         1);
58
define('MDB_ERROR',                     -1);
59
define('MDB_ERROR_SYNTAX',              -2);
60
define('MDB_ERROR_CONSTRAINT',          -3);
61
define('MDB_ERROR_NOT_FOUND',           -4);
62
define('MDB_ERROR_ALREADY_EXISTS',      -5);
63
define('MDB_ERROR_UNSUPPORTED',         -6);
64
define('MDB_ERROR_MISMATCH',            -7);
65
define('MDB_ERROR_INVALID',             -8);
66
define('MDB_ERROR_NOT_CAPABLE',         -9);
67
define('MDB_ERROR_TRUNCATED',          -10);
68
define('MDB_ERROR_INVALID_NUMBER',     -11);
69
define('MDB_ERROR_INVALID_DATE',       -12);
70
define('MDB_ERROR_DIVZERO',            -13);
71
define('MDB_ERROR_NODBSELECTED',       -14);
72
define('MDB_ERROR_CANNOT_CREATE',      -15);
73
define('MDB_ERROR_CANNOT_DELETE',      -16);
74
define('MDB_ERROR_CANNOT_DROP',        -17);
75
define('MDB_ERROR_NOSUCHTABLE',        -18);
76
define('MDB_ERROR_NOSUCHFIELD',        -19);
77
define('MDB_ERROR_NEED_MORE_DATA',     -20);
78
define('MDB_ERROR_NOT_LOCKED',         -21);
79
define('MDB_ERROR_VALUE_COUNT_ON_ROW', -22);
80
define('MDB_ERROR_INVALID_DSN',        -23);
81
define('MDB_ERROR_CONNECT_FAILED',     -24);
82
define('MDB_ERROR_EXTENSION_NOT_FOUND',-25);
83
define('MDB_ERROR_NOSUCHDB',           -26);
84
define('MDB_ERROR_ACCESS_VIOLATION',   -27);
85
define('MDB_ERROR_CANNOT_REPLACE',     -28);
86
define('MDB_ERROR_CONSTRAINT_NOT_NULL',-29);
87
define('MDB_ERROR_DEADLOCK',           -30);
88
define('MDB_ERROR_CANNOT_ALTER',       -31);
89
define('MDB_ERROR_MANAGER',            -32);
90
define('MDB_ERROR_MANAGER_PARSE',      -33);
91
define('MDB_ERROR_LOADMODULE',         -34);
92
define('MDB_ERROR_INSUFFICIENT_DATA',  -35);
93
/**
94
 * This is a special constant that tells DB the user hasn't specified
95
 * any particular get mode, so the default should be used.
96
 */
97
 
98
define('MDB_FETCHMODE_DEFAULT', 0);
99
 
100
/**
101
 * Column data indexed by numbers, ordered from 0 and up
102
 */
103
 
104
define('MDB_FETCHMODE_ORDERED',  1);
105
 
106
/**
107
 * Column data indexed by column names
108
 */
109
 
110
define('MDB_FETCHMODE_ASSOC',    2);
111
 
112
/**
113
 * For multi-dimensional results: normally the first level of arrays
114
 * is the row number, and the second level indexed by column number or name.
115
 * MDB_FETCHMODE_FLIPPED switches this order, so the first level of arrays
116
 * is the column name, and the second level the row number.
117
 */
118
 
119
define('MDB_FETCHMODE_FLIPPED',  4);
120
 
121
/**
122
 * These are constants for the tableInfo-function
123
 * they are bitwised or'ed. so if there are more constants to be defined
124
 * in the future, adjust MDB_TABLEINFO_FULL accordingly
125
 */
126
 
127
define('MDB_TABLEINFO_ORDER',      1);
128
define('MDB_TABLEINFO_ORDERTABLE', 2);
129
define('MDB_TABLEINFO_FULL',       3);
130
 
131
/**
132
 * These are constants for each of the supported datatypes
133
 */
134
 
135
define('MDB_TYPE_TEXT'      , 0);
136
define('MDB_TYPE_BOOLEAN'   , 1);
137
define('MDB_TYPE_INTEGER'   , 2);
138
define('MDB_TYPE_DECIMAL'   , 3);
139
define('MDB_TYPE_FLOAT'     , 4);
140
define('MDB_TYPE_DATE'      , 5);
141
define('MDB_TYPE_TIME'      , 6);
142
define('MDB_TYPE_TIMESTAMP' , 7);
143
define('MDB_TYPE_CLOB'      , 8);
144
define('MDB_TYPE_BLOB'      , 9);
145
 
146
/**
147
 * These are global variables that are used to track the various class instances
148
 */
149
 
150
$GLOBALS['_MDB_lobs'] = array();
151
$GLOBALS['_MDB_databases'] = array();
152
 
153
/**
154
 * The main 'MDB' class is simply a container class with some static
155
 * methods for creating DB objects as well as some utility functions
156
 * common to all parts of DB.
157
 *
158
 * The object model of DB is as follows (indentation means inheritance):
159
 *
160
 * MDB          The main DB class.  This is simply a utility class
161
 *              with some 'static' methods for creating MDB objects as
162
 *              well as common utility functions for other MDB classes.
163
 *
164
 * MDB_common   The base for each DB implementation.  Provides default
165
 * |            implementations (in OO lingo virtual methods) for
166
 * |            the actual DB implementations as well as a bunch of
167
 * |            query utility functions.
168
 * |
169
 * +-MDB_mysql  The DB implementation for MySQL. Inherits MDB_Common.
170
 *              When calling MDB::factory or MDB::connect for MySQL
171
 *              connections, the object returned is an instance of this
172
 *              class.
173
 * +-MDB_pgsql  The DB implementation for PostGreSQL. Inherits MDB_Common.
174
 *              When calling MDB::factory or MDB::connect for PostGreSQL
175
 *              connections, the object returned is an instance of this
176
 *              class.
177
 *
178
 * MDB_Date     This class provides several method to convert from and to
179
 *              MDB timestamps.
180
 *
181
 * MDB_Manager  This class handles the xml schema management.
182
 *
183
 * @package  MDB
184
 * @version  $Id: MDB.php,v 1.59.4.12 2004/02/28 10:37:54 quipo Exp $
185
 * @category Database
186
 * @author   Lukas Smith <smith@backendmedia.com>
187
 */
188
class MDB
189
{
190
    // }}}
191
    // {{{ setOptions()
192
 
193
    /**
194
     * set option array in an exiting database object
195
     *
196
     * @param   object  $db       MDB object
197
     * @param   mixed   $options  An associative array of option names and
198
     *                            their values.
199
     * @access  public
200
     */
201
    function setOptions(&$db, $options)
202
    {
203
        if(is_array($options)) {
204
            foreach($options as $option => $value) {
205
                $test = $db->setOption($option, $value);
206
                if(MDB::isError($test)) {
207
                    return $test;
208
                }
209
            }
210
        } else {
211
            $db->setOption('persistent', $options);
212
        }
213
        $include_lob = $db->getOption('includelob');
214
        if(!MDB::isError($include_lob) && $include_lob) {
215
            $db->loadLob('load at start');
216
        }
217
        $includemanager = $db->getOption('includemanager');
218
        if(!MDB::isError($includemanager) && $includemanager) {
219
            $db->loadManager('load at start');
220
        }
221
        $debug = $db->getOption('debug');
222
        if(!MDB::isError($debug) && $debug) {
223
            $db->captureDebugOutput(TRUE);
224
        }
225
    }
226
 
227
    // }}}
228
    // {{{ factory()
229
 
230
    /**
231
     * Create a new DB connection object for the specified database
232
     * type
233
     * IMPORTANT: In order for MDB to work properly it is necessary that
234
     * you make sure that you work with a reference of the original
235
     * object instead of a copy (this is a PHP4 quirk).
236
     *
237
     * For example:
238
     *     $mdb =& MDB::factory($dsn);
239
     *          ^^
240
     * And not:
241
     *     $mdb = MDB::factory($dsn);
242
     *          ^^
243
     *
244
     * @param   string  $type   database type, for example 'mysql'
245
     * @return  mixed   a newly created MDB connection object, or a MDB
246
     *                  error object on error
247
     * @access  public
248
     */
249
    function &factory($type)
250
    {
251
        $class_name = "MDB_$type";
252
 
253
        @include_once("MDB/${type}.php");
254
 
255
        @$db =& new $class_name;
256
 
257
        return($db);
258
    }
259
 
260
    // }}}
261
    // {{{ connect()
262
 
263
    /**
264
     * Create a new MDB connection object and connect to the specified
265
     * database
266
     *
267
     * IMPORTANT: In order for MDB to work properly it is necessary that
268
     * you make sure that you work with a reference of the original
269
     * object instead of a copy (this is a PHP4 quirk).
270
     *
271
     * For example:
272
     *     $mdb =& MDB::connect($dsn);
273
     *          ^^
274
     * And not:
275
     *     $mdb = MDB::connect($dsn);
276
     *          ^^
277
     *
278
     * @param   mixed   $dsn      'data source name', see the MDB::parseDSN
279
     *                            method for a description of the dsn format.
280
     *                            Can also be specified as an array of the
281
     *                            format returned by MDB::parseDSN.
282
     * @param   mixed   $options  An associative array of option names and
283
     *                            their values.
284
     * @return  mixed   a newly created MDB connection object, or a MDB
285
     *                  error object on error
286
     * @access  public
287
     * @see     MDB::parseDSN
288
     */
289
    function &connect($dsn, $options = FALSE)
290
    {
291
        $dsninfo = MDB::parseDSN($dsn);
292
        if(isset($dsninfo['phptype'])) {
293
            $type          = $dsninfo['phptype'];
294
            $class_name    = 'MDB_'.$type;
295
            $include       = 'MDB/'.$type.'.php';
296
        } else {
297
            return(PEAR::raiseError(NULL, MDB_ERROR_NOT_FOUND,
298
                NULL, NULL, 'no RDBMS driver specified',
299
                'MDB_Error', TRUE));
300
        }
301
 
302
        if(is_array($options)
303
            && isset($options['debug'])
304
            && $options['debug'] >= 2
305
        ) {
306
            // expose php errors with sufficient debug level
307
            @include_once($include);
308
        } else {
309
            include_once($include);
310
        }
311
 
312
        if(!class_exists($class_name)) {
313
            $error = PEAR::raiseError(NULL, MDB_ERROR_NOT_FOUND, NULL, NULL,
314
                'Unable to include the '.$include.' file', 'MDB_Error', TRUE);
315
            return($error);
316
        }
317
 
318
        @$db =& new $class_name();
319
 
320
        $db->setDSN($dsninfo);
321
 
322
        MDB::setOptions($db, $options);
323
 
324
        if(isset($dsninfo['database'])) {
325
            $err = $db->connect();
326
            if (MDB::isError($err)) {
327
                $dsn = $db->getDSN();
328
                $err->addUserInfo($dsn);
329
                return($err);
330
            }
331
        }
332
        return($db);
333
    }
334
 
335
    // }}}
336
    // {{{ connect()
337
 
338
    /**
339
     * Returns a MDB connection with the requested DSN.
340
     * A newnew MDB connection object is only created if no object with the
341
     * reuested DSN exists yet.
342
     *
343
     * IMPORTANT: In order for MDB to work properly it is necessary that
344
     * you make sure that you work with a reference of the original
345
     * object instead of a copy (this is a PHP4 quirk).
346
     *
347
     * For example:
348
     *     $mdb =& MDB::sngleton($dsn);
349
     *          ^^
350
     * And not:
351
     *     $mdb = MDB::singleton($dsn);
352
     *          ^^
353
     *
354
     * @param   mixed   $dsn      'data source name', see the MDB::parseDSN
355
     *                            method for a description of the dsn format.
356
     *                            Can also be specified as an array of the
357
     *                            format returned by MDB::parseDSN.
358
     * @param   mixed   $options  An associative array of option names and
359
     *                            their values.
360
     * @return  mixed   a newly created MDB connection object, or a MDB
361
     *                  error object on error
362
     * @access  public
363
     * @see     MDB::parseDSN
364
     */
365
    function &singleton($dsn = NULL, $options = FALSE)
366
    {
367
        if ($dsn) {
368
            $dsninfo = MDB::parseDSN($dsn);
369
            $dsninfo_default = array(
370
                'phptype' => NULL,
371
                'username' => NULL,
372
                'password' => NULL,
373
                'hostspec' => NULL,
374
                'database' => NULL,
375
            );
376
            $dsninfo = array_merge($dsninfo_default, $dsninfo);
377
            $keys = array_keys($GLOBALS['_MDB_databases']);
378
            for ($i=0, $j=count($keys); $i<$j; ++$i) {
379
                $tmp_dsn = $GLOBALS['_MDB_databases'][$keys[$i]]->getDSN('array');
380
                if ($dsninfo['phptype'] == $tmp_dsn['phptype']
381
                    && $dsninfo['username'] == $tmp_dsn['username']
382
                    && $dsninfo['password'] == $tmp_dsn['password']
383
                    && $dsninfo['hostspec'] == $tmp_dsn['hostspec']
384
                    && $dsninfo['database'] == $tmp_dsn['database'])
385
                {
386
                    MDB::setOptions($GLOBALS['_MDB_databases'][$keys[$i]], $options);
387
                    return $GLOBALS['_MDB_databases'][$keys[$i]];
388
                }
389
            }
390
        } else {
391
            if (is_array($GLOBALS['_MDB_databases'])
392
                && reset($GLOBALS['_MDB_databases'])
393
            ) {
394
                $db =& $GLOBALS['_MDB_databases'][key($GLOBALS['_MDB_databases'])];
395
                return $db;
396
            }
397
        }
398
        $db =& MDB::connect($dsn, $options);
399
        return $db;
400
    }
401
 
402
    // }}}
403
    // {{{ loadFile()
404
 
405
    /**
406
     * load a file (like 'Date.php' or 'Manager.php')
407
     *
408
     * @return $file    name of the file to be included from the MDB dir without
409
     *                  the '.php' extension (like 'Date' or 'Manager')
410
     * @access public
411
     */
412
    function loadFile($file)
413
    {
414
        @include_once('MDB/'.$file.'.php');
415
    }
416
 
417
    // }}}
418
    // {{{ apiVersion()
419
 
420
    /**
421
     * Return the MDB API version
422
     *
423
     * @return int     the MDB API version number
424
     * @access public
425
     */
426
    function apiVersion()
427
    {
428
        return(1);
429
    }
430
 
431
    // }}}
432
    // {{{ isError()
433
 
434
    /**
435
     * Tell whether a result code from a MDB method is an error
436
     *
437
     * @param   int       $value  result code
438
     * @return  boolean   whether $value is an MDB_Error
439
     * @access public
440
     */
441
    function isError($value)
442
    {
443
        return is_a($value, 'MDB_Error');
444
    }
445
 
446
    // }}}
447
    // {{{ isConnection()
448
    /**
449
     * Tell whether a value is a MDB connection
450
     *
451
     * @param mixed $value value to test
452
     *
453
     * @return bool whether $value is a MDB connection
454
     *
455
     * @access public
456
     */
457
    function isConnection($value)
458
    {
459
        return is_a($value, 'MDB_Common');
460
    }
461
 
462
    // }}}
463
    // {{{ isManip()
464
 
465
    /**
466
     * Tell whether a query is a data manipulation query (insert,
467
     * update or delete) or a data definition query (create, drop,
468
     * alter, grant, revoke).
469
     *
470
     * @param   string   $query the query
471
     * @return  boolean  whether $query is a data manipulation query
472
     * @access public
473
     */
474
    function isManip($query)
475
    {
476
        $manips = 'INSERT|UPDATE|DELETE|REPLACE|CREATE|DROP|
477
                  ALTER|GRANT|REVOKE|LOCK|UNLOCK|ROLLBACK|COMMIT';
478
        if (preg_match('/^\s*"?('.$manips.')\s+/i', $query)) {
479
            return(TRUE);
480
        }
481
        return(FALSE);
482
    }
483
 
484
    // }}}
485
    // {{{ errorMessage()
486
 
487
    /**
488
     * Return a textual error message for a MDB error code
489
     *
490
     * @param   int     $value error code
491
     * @return  string  error message, or false if the error code was
492
     *                  not recognized
493
     * @access public
494
     */
495
    function errorMessage($value)
496
    {
497
        static $errorMessages;
498
        if (!isset($errorMessages)) {
499
            $errorMessages = array(
500
                MDB_ERROR                    => 'unknown error',
501
                MDB_ERROR_ALREADY_EXISTS     => 'already exists',
502
                MDB_ERROR_CANNOT_CREATE      => 'can not create',
503
                MDB_ERROR_CANNOT_ALTER       => 'can not alter',
504
                MDB_ERROR_CANNOT_REPLACE     => 'can not replace',
505
                MDB_ERROR_CANNOT_DELETE      => 'can not delete',
506
                MDB_ERROR_CANNOT_DROP        => 'can not drop',
507
                MDB_ERROR_CONSTRAINT         => 'constraint violation',
508
                MDB_ERROR_CONSTRAINT_NOT_NULL=> 'null value violates not-null constraint',
509
                MDB_ERROR_DIVZERO            => 'division by zero',
510
                MDB_ERROR_INVALID            => 'invalid',
511
                MDB_ERROR_INVALID_DATE       => 'invalid date or time',
512
                MDB_ERROR_INVALID_NUMBER     => 'invalid number',
513
                MDB_ERROR_MISMATCH           => 'mismatch',
514
                MDB_ERROR_NODBSELECTED       => 'no database selected',
515
                MDB_ERROR_NOSUCHFIELD        => 'no such field',
516
                MDB_ERROR_NOSUCHTABLE        => 'no such table',
517
                MDB_ERROR_NOT_CAPABLE        => 'MDB backend not capable',
518
                MDB_ERROR_NOT_FOUND          => 'not found',
519
                MDB_ERROR_NOT_LOCKED         => 'not locked',
520
                MDB_ERROR_SYNTAX             => 'syntax error',
521
                MDB_ERROR_UNSUPPORTED        => 'not supported',
522
                MDB_ERROR_VALUE_COUNT_ON_ROW => 'value count on row',
523
                MDB_ERROR_INVALID_DSN        => 'invalid DSN',
524
                MDB_ERROR_CONNECT_FAILED     => 'connect failed',
525
                MDB_OK                       => 'no error',
526
                MDB_ERROR_NEED_MORE_DATA     => 'insufficient data supplied',
527
                MDB_ERROR_EXTENSION_NOT_FOUND=> 'extension not found',
528
                MDB_ERROR_NOSUCHDB           => 'no such database',
529
                MDB_ERROR_ACCESS_VIOLATION   => 'insufficient permissions',
530
                MDB_ERROR_MANAGER            => 'MDB_manager error',
531
                MDB_ERROR_MANAGER_PARSE      => 'MDB_manager schema parse error',
532
                MDB_ERROR_LOADMODULE         => 'Error while including on demand module',
533
                MDB_ERROR_TRUNCATED          => 'truncated',
534
                MDB_ERROR_DEADLOCK           => 'deadlock detected',
535
            );
536
        }
537
 
538
        if (MDB::isError($value)) {
539
            $value = $value->getCode();
540
        }
541
 
542
        return(isset($errorMessages[$value]) ?
543
           $errorMessages[$value] : $errorMessages[MDB_ERROR]);
544
    }
545
 
546
    // }}}
547
    // {{{ parseDSN()
548
 
549
    /**
550
     * Parse a data source name
551
     *
552
     * A array with the following keys will be returned:
553
     *  phptype: Database backend used in PHP (mysql, odbc etc.)
554
     *  dbsyntax: Database used with regards to SQL syntax etc.
555
     *  protocol: Communication protocol to use (tcp, unix etc.)
556
     *  hostspec: Host specification (hostname[:port])
557
     *  database: Database to use on the DBMS server
558
     *  username: User name for login
559
     *  password: Password for login
560
     *
561
     * The format of the supplied DSN is in its fullest form:
562
     *
563
     *  phptype(dbsyntax)://username:password@protocol+hostspec/database
564
     *
565
     * Most variations are allowed:
566
     *
567
     *  phptype://username:password@protocol+hostspec:110//usr/db_file.db
568
     *  phptype://username:password@hostspec/database_name
569
     *  phptype://username:password@hostspec
570
     *  phptype://username@hostspec
571
     *  phptype://hostspec/database
572
     *  phptype://hostspec
573
     *  phptype(dbsyntax)
574
     *  phptype
575
     *
576
     * @param   string  $dsn Data Source Name to be parsed
577
     * @return  array   an associative array
578
     * @access public
579
     * @author Tomas V.V.Cox <cox@idecnet.com>
580
     */
581
    function parseDSN($dsn)
582
    {
583
        if (is_array($dsn)) {
584
            return($dsn);
585
        }
586
 
587
        $parsed = array(
588
            'phptype'  => FALSE,
589
            'dbsyntax' => FALSE,
590
            'username' => FALSE,
591
            'password' => FALSE,
592
            'protocol' => FALSE,
593
            'hostspec' => FALSE,
594
            'port'     => FALSE,
595
            'socket'   => FALSE,
596
            'database' => FALSE
597
        );
598
 
599
        // Find phptype and dbsyntax
600
        if (($pos = strpos($dsn, '://')) !== FALSE) {
601
            $str = substr($dsn, 0, $pos);
602
            $dsn = substr($dsn, $pos + 3);
603
        } else {
604
            $str = $dsn;
605
            $dsn = NULL;
606
        }
607
 
608
        // Get phptype and dbsyntax
609
        // $str => phptype(dbsyntax)
610
        if (preg_match('|^(.+?)\((.*?)\)$|', $str, $arr)) {
611
            $parsed['phptype']  = $arr[1];
612
            $parsed['dbsyntax'] = (empty($arr[2])) ? $arr[1] : $arr[2];
613
        } else {
614
            $parsed['phptype']  = $str;
615
            $parsed['dbsyntax'] = $str;
616
        }
617
 
618
        if (empty($dsn)) {
619
            return($parsed);
620
        }
621
 
622
        // Get (if found): username and password
623
        // $dsn => username:password@protocol+hostspec/database
624
        if (($at = strrpos($dsn,'@')) !== FALSE) {
625
            $str = substr($dsn, 0, $at);
626
            $dsn = substr($dsn, $at + 1);
627
            if (($pos = strpos($str, ':')) !== FALSE) {
628
                $parsed['username'] = rawurldecode(substr($str, 0, $pos));
629
                $parsed['password'] = rawurldecode(substr($str, $pos + 1));
630
            } else {
631
                $parsed['username'] = rawurldecode($str);
632
            }
633
        }
634
 
635
        // Find protocol and hostspec
636
 
637
        // $dsn => proto(proto_opts)/database
638
        if (preg_match('|^([^(]+)\((.*?)\)/?(.*?)$|', $dsn, $match)) {
639
            $proto       = $match[1];
640
            $proto_opts  = (!empty($match[2])) ? $match[2] : FALSE;
641
            $dsn         = $match[3];
642
 
643
        // $dsn => protocol+hostspec/database (old format)
644
        } else {
645
            if (strpos($dsn, '+') !== FALSE) {
646
                list($proto, $dsn) = explode('+', $dsn, 2);
647
            }
648
            if (strpos($dsn, '/') !== FALSE) {
649
                list($proto_opts, $dsn) = explode('/', $dsn, 2);
650
            } else {
651
                $proto_opts = $dsn;
652
                $dsn = NULL;
653
            }
654
        }
655
 
656
        // process the different protocol options
657
        $parsed['protocol'] = (!empty($proto)) ? $proto : 'tcp';
658
        $proto_opts = rawurldecode($proto_opts);
659
        if ($parsed['protocol'] == 'tcp') {
660
            if (strpos($proto_opts, ':') !== FALSE) {
661
                list($parsed['hostspec'], $parsed['port']) =
662
                                                     explode(':', $proto_opts);
663
            } else {
664
                $parsed['hostspec'] = $proto_opts;
665
            }
666
        } elseif ($parsed['protocol'] == 'unix') {
667
            $parsed['socket'] = $proto_opts;
668
        }
669
 
670
        // Get dabase if any
671
        // $dsn => database
672
        if (!empty($dsn)) {
673
            // /database
674
            if (($pos = strpos($dsn, '?')) === FALSE) {
675
                $parsed['database'] = $dsn;
676
            // /database?param1=value1&param2=value2
677
            } else {
678
                $parsed['database'] = substr($dsn, 0, $pos);
679
                $dsn = substr($dsn, $pos + 1);
680
                if (strpos($dsn, '&') !== FALSE) {
681
                    $opts = explode('&', $dsn);
682
                } else { // database?param1=value1
683
                    $opts = array($dsn);
684
                }
685
                foreach ($opts as $opt) {
686
                    list($key, $value) = explode('=', $opt);
687
                    if (!isset($parsed[$key])) { // don't allow params overwrite
688
                        $parsed[$key] = rawurldecode($value);
689
                    }
690
                }
691
            }
692
        }
693
 
694
        return($parsed);
695
    }
696
}
697
 
698
/**
699
 * MDB_Error implements a class for reporting portable database error
700
 * messages.
701
 *
702
 * @package MDB
703
 * @category Database
704
 * @author  Stig Bakken <ssb@fast.no>
705
 */
706
class MDB_Error extends PEAR_Error
707
{
708
 
709
    // }}}
710
    // {{{ constructor
711
 
712
    /**
713
     * MDB_Error constructor.
714
     *
715
     * @param mixed   $code      MDB error code, or string with error message.
716
     * @param integer $mode      what 'error mode' to operate in
717
     * @param integer $level     what error level to use for
718
     *                           $mode & PEAR_ERROR_TRIGGER
719
     * @param smixed  $debuginfo additional debug info, such as the last query
720
     */
721
    function MDB_Error($code = MDB_ERROR, $mode = PEAR_ERROR_RETURN,
722
              $level = E_USER_NOTICE, $debuginfo = NULL)
723
    {
724
        if (is_int($code)) {
725
            $this->PEAR_Error('MDB Error: '.MDB::errorMessage($code), $code,
726
                $mode, $level, $debuginfo);
727
        } else {
728
            $this->PEAR_Error("MDB Error: $code", MDB_ERROR, $mode, $level,
729
                $debuginfo);
730
        }
731
    }
732
}
733
?>