Project

General

Profile

wb-archiv283 / branches / 2.8.x / wb / framework / WbDatabase.php @ 2128

1
<?php
2
/**
3
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
4
 *
5
 * This program is free software: you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation, either version 3 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
 */
18
/**
19
 * WbDatabase.php
20
 *
21
 * @category     Core
22
 * @package      Core_database
23
 * @author       Manuela v.d.Decken <manuela@isteam.de>
24
 * @copyright    Manuela v.d.Decken <manuela@isteam.de>
25
 * @license      http://www.gnu.org/licenses/gpl.html   GPL License
26
 * @version      0.1.1
27
 * @revision     $Revision: 2128 $
28
 * @lastmodified $Date: 2015-06-18 09:54:46 +0200 (Thu, 18 Jun 2015) $
29
 * @description  Mysqli database wrapper for use with websitebaker version 2.8.4
30
 */
31

    
32
/* -------------------------------------------------------- */
33
@define('DATABASE_CLASS_LOADED', true);
34

    
35
    define('MYSQLI_SEEK_LAST',            -1);
36
    define('MYSQLI_SEEK_FIRST',            0);
37
/* define the old mysql consts for Backward compatibility */
38
    if (!defined('MYSQL_ASSOC'))
39
    {
40
        define('MYSQL_SEEK_LAST',            -1);
41
        define('MYSQL_SEEK_FIRST',            0);
42
        define('MYSQL_ASSOC',                 1);
43
        define('MYSQL_NUM',                   2);
44
        define('MYSQL_BOTH',                  3);
45
        define('MYSQL_CLIENT_COMPRESS',      32);
46
        define('MYSQL_CLIENT_IGNORE_SPACE', 256);
47
        define('MYSQL_CLIENT_INTERACTIVE', 1024);
48
        define('MYSQL_CLIENT_SSL',         2048);
49
    }
50

    
51
class WbDatabase extends WbDatabaseHelper {
52

    
53
    private static $_oInstances = array();
54

    
55
    protected $oDbHandle    = null; // readonly from outside
56
    protected $sDbName      = '';
57
    protected $sInstanceIdentifier = '';
58
    protected $sTablePrefix = '';
59
    protected $sCharset     = '';
60
    protected $connected    = false;
61
    protected $error        = '';
62
    protected $error_type   = '';
63
    protected $iQueryCount  = 0;
64

    
65
/**
66
 * __constructor
67
 *  prevent from public instancing
68
 */
69
    final private function  __construct() {}
70
/**
71
 * prevent from cloning
72
 */
73
    final private function __clone() {}
74
/**
75
 * get a valid instance of this class
76
 * @param string $sIdentifier selector for several different instances
77
 * @return WbDatabase object
78
 */
79
    final public static function getInstance($sIdentifier = 'core')
80
    {
81
        if( !isset(self::$_oInstances[$sIdentifier])) {
82
            $c = __CLASS__;
83
            $oInstance = new $c;
84
            $oInstance->sInstanceIdentifier = $sIdentifier;
85
            self::$_oInstances[$sIdentifier] = $oInstance;
86
        }
87
        return self::$_oInstances[$sIdentifier];
88
    }
89
/**
90
 * disconnect and kills an existing instance
91
 * @param string $sIdentifier selector for instance to kill
92
 */
93
    final public static function killInstance($sIdentifier)
94
    {
95
        if($sIdentifier != 'core') {
96
            if( isset(self::$_oInstances[$sIdentifier])) {
97
                self::$_oInstances[$sIdentifier]->disconnect();
98
                unset(self::$_oInstances[$sIdentifier]);
99
            }
100
        }
101
    }
102
/**
103
 * Establish connection
104
 * @param string $url
105
 * @return bool
106
 * @throws WbDatabaseException
107
 * @description opens a connection using connect URL<br />
108
 *              Example for SQL-Url:  'mysql://user:password@example.com[:3306]/database?charset=utf8&tableprefix=xx_'
109
 */
110
    public function doConnect($url = '')
111
    {
112
        if ($this->connected) { return $this->connected; } // prevent from reconnecting
113
        $this->connected = false;
114
        if ($url != '') {
115
        // parse URL and extract connection data
116
            $aIni = parse_url($url);
117
            $scheme   = isset($aIni['scheme']) ? $aIni['scheme'] : 'mysqli';
118
            $hostname = isset($aIni['host']) ? $aIni['host'] : '';
119
            $username = isset($aIni['user']) ? $aIni['user'] : '';
120
            $password = isset($aIni['pass']) ? $aIni['pass'] : '';
121
            $hostport = isset($aIni['port']) ? $aIni['port'] : '3306';
122
            $hostport = $hostport == '3306' ? null : $hostport;
123
            $db_name  = ltrim(isset($aIni['path']) ? $aIni['path'] : '', '/\\');
124
            $sTmp = isset($aIni['query']) ? $aIni['query'] : '';
125
            $aQuery = explode('&', $sTmp);
126
            foreach ($aQuery as $sArgument) {
127
                $aArg = explode('=', $sArgument);
128
                switch (strtolower($aArg[0])) {
129
                    case 'charset':
130
                        $this->sCharset = strtolower(preg_replace('/[^a-z0-9]/i', '', $aArg[1]));
131
                        break;
132
                    case 'tableprefix':
133
                        $this->sTablePrefix = $aArg[1];
134
                        break;
135
                    default:
136
                        break;
137
                }
138
            }
139
            $this->sDbName = $db_name;
140
        } else {
141
            throw new WbDatabaseException('Missing parameter: unable to connect database');
142
        }
143
        $this->oDbHandle = @mysqli_connect($hostname, $username, $password, $db_name, $hostport);
144
        if (!$this->oDbHandle) {
145
            throw new WbDatabaseException('unable to connect \''.$scheme.'://'.$hostname.':'.$hostport.'\'');
146
        } else {
147
            if ($this->sCharset) {
148
                @mysqli_query($this->oDbHandle, 'SET NAMES '.$this->sCharset);
149
                mysqli_set_charset($this->oDbHandle, $this->sCharset);
150
            }
151
            $this->connected = true;
152
        }
153
        return $this->connected;
154
    }
155
/**
156
 * disconnect database
157
 * @return bool
158
 * @description Disconnect current object from the database<br />
159
 *              the 'core' connection can NOT be disconnected!
160
 */
161
    public function disconnect()
162
    {
163
        if ($this->connected == true && $oInstance->sInstanceIdentifier != 'core') {
164
            mysqli_close($this->oDbHandle);
165
            $this->connected = false;
166
            return true;
167
        }
168
        return false;
169
    }
170
/**
171
 * Alias for doQuery()
172
 * @deprecated from WB-2.8.4 and higher
173
 */
174
    public function query($statement)
175
    {
176
        trigger_error('Deprecated function call: '.__CLASS__.'::'.__METHOD__, E_USER_DEPRECATED);
177
        return $this->doQuery($statement);
178
    }
179
/**
180
 * execute query
181
 * @param string $statement the SQL-statement to execute
182
 * @return null|\mysql
183
 */
184
    public function doQuery($statement) {
185
        $oRetval = null;
186
        $this->iQueryCount++;
187
        $mysql = new mysql($this->oDbHandle, $statement);
188
        $this->set_error($mysql->error($this->oDbHandle));
189
        if (!$mysql->error()) {
190
            $oRetval = $mysql;
191
        }
192
        $this->set_error($mysql->error($this->oDbHandle));
193
        return $oRetval;
194
    }
195
/**
196
 * Alias for getOne()
197
 * @deprecated from WB-2.8.4 and higher
198
 */
199
    public function get_one( $statement )
200
    {
201
        trigger_error('Deprecated function call: '.__CLASS__.'::'.__METHOD__, E_USER_DEPRECATED);
202
        return $this->getOne($statement);
203
    }
204
    // Gets the first column of the first row
205
/**
206
 * Gets the first column of the first row
207
 * @param string $statement  SQL-statement
208
 * @return null|mixed
209
 */
210
    public function getOne( $sStatement )
211
    {
212
        $sRetval = null;
213
        if (($oRecSet = $this->doQuery($sStatement))) {
214
            if (($aRecord = $oRecSet->fetchArray(MYSQL_NUM))) {
215
                $sRetval = $aRecord[0];
216
            }
217
        }
218
        return ($this->isError() ? null : $sRetval);
219
    }
220
/**
221
 * Alias for setError()
222
 * @deprecated from WB-2.8.4 and higher
223
 */
224
    public function set_error($message = null)
225
    {
226
        trigger_error('Deprecated function call: '.__CLASS__.'::'.__METHOD__, E_USER_DEPRECATED);
227
        $this->setError($message = null);
228
    }
229
    // Set the DB error
230
/**
231
 * setError
232
 * @param string $message
233
 */
234
    public function setError($message = null)
235
    {
236
        $this->error = $message;
237
    }
238
/**
239
 * Alias for isError
240
 * @deprecated from WB-2.8.4 and higher
241
 */
242
    public function is_error()
243
    {
244
        trigger_error('Deprecated function call: '.__CLASS__.'::'.__METHOD__, E_USER_DEPRECATED);
245
        return $this->isError();
246
    }
247
/**
248
 * isError
249
 * @return bool
250
 */
251
    public function isError()
252
    {
253
        return (!empty($this->error)) ? true : false;
254
    }
255
/**
256
 * Alias for getError
257
 * @deprecated from WB-2.8.4 and higher
258
 */
259
    public function get_error()
260
    {
261
        trigger_error('Deprecated function call: '.__CLASS__.'::'.__METHOD__, E_USER_DEPRECATED);
262
        return $this->getError();
263
    }
264
/**
265
 * get last Error
266
 * @return string
267
 */
268
    public function getError()
269
    {
270
        return $this->error;
271
    }
272
/**
273
 * Protect class from property injections
274
 * @param string name of property
275
 * @param mixed value
276
 * @throws WbDatabaseException
277
 */
278
    public function __set($name, $value)
279
    {
280
        throw new WbDatabaseException('tried to set a readonly or nonexisting property ['.$name.']!! ');
281
    }
282
/**
283
 * default Getter for some properties
284
 * @param string name of the Property
285
 * @return NULL on error | valid property
286
 */
287
    public function __get($sPropertyName)
288
    {
289
        switch ($sPropertyName) {
290
            case 'getDbHandle': // << set deprecated
291
            case 'db_handle': // << set deprecated
292
                trigger_error('Deprecated property call: '.__CLASS__.'::'.__METHOD__.'(getDbHandle|db_handle)', E_USER_DEPRECATED);
293
            case 'DbHandle':
294
                $retval = $this->oDbHandle;
295
                break;
296
            case 'getLastInsertId': // << set deprecated
297
                trigger_error('Deprecated property call: '.__CLASS__.'::'.__METHOD__.'(getLastInsertId)', E_USER_DEPRECATED);
298
            case 'LastInsertId':
299
                $retval = $this->getLastInsertId();
300
                break;
301
            case 'getDbName': // << set deprecated
302
            case 'db_name': // << set deprecated
303
                trigger_error('Deprecated property call: '.__CLASS__.'::'.__METHOD__.'(getDbName|db_name)', E_USER_DEPRECATED);
304
            case 'DbName':
305
                $retval = $this->sDbName;
306
                break;
307
            case 'getTablePrefix': // << set deprecated
308
                trigger_error('Deprecated property call: '.__CLASS__.'::'.__METHOD__.'(getTablePrefix)', E_USER_DEPRECATED);
309
            case 'TablePrefix':
310
                $retval = $this->sTablePrefix;
311
                break;
312
            case 'getQueryCount': // << set deprecated
313
                trigger_error('Deprecated property call: '.__CLASS__.'::'.__METHOD__.'(getQueryCount)', E_USER_DEPRECATED);
314
            case 'QueryCount':
315
                $retval = $this->iQueryCount;
316
                break;
317
            default:
318
                $retval = null;
319
                break;
320
        }
321
        return $retval;
322
    } // __get()
323
/**
324
 * Escapes special characters in a string for use in an SQL statement
325
 * @param string $unescaped_string
326
 * @return string
327
 */
328
    public function escapeString($sUnescapedString)
329
    {
330
        return mysqli_real_escape_string($this->oDbHandle, $sUnescapedString);
331
    }
332
/**
333
 * Escapes wildchar characters in a string for use in an SQL-LIKE statement
334
 * @param string $unescaped_string
335
 * @return string
336
 */
337
    public function escapeLike($sUnescapedString)
338
    {
339
        return addcslashes($sUnescapedString, '_%');
340
    }
341
/**
342
 * Last inserted Id
343
 * @return bool|int false on error, 0 if no record inserted
344
 */
345
    public function getLastInsertId()
346
    {
347
        return mysqli_insert_id($this->oDbHandle);
348
    }
349

    
350
} /// end of class database
351
// //////////////////////////////////////////////////////////////////////////////////// //
352
/**
353
 * WbDatabaseException
354
 *
355
 * @category     Core
356
 * @package      Core_database
357
 * @author       Manuela v.d.Decken <manuela@isteam.de>
358
 * @copyright    Manuela v.d.Decken <manuela@isteam.de>
359
 * @license      http://www.gnu.org/licenses/gpl.html   GPL License
360
 * @version      2.9.0
361
 * @revision     $Revision: 2128 $
362
 * @lastmodified $Date: 2015-06-18 09:54:46 +0200 (Thu, 18 Jun 2015) $
363
 * @description  Exceptionhandler for the WbDatabase and depending classes
364
 */
365
class WbDatabaseException extends AppException {}
366

    
367
/**
368
 * mysql
369
 *
370
 * @category     Core
371
 * @package      Core_database
372
 * @author       Manuela v.d.Decken <manuela@isteam.de>
373
 * @copyright    Manuela v.d.Decken <manuela@isteam.de>
374
 * @license      http://www.gnu.org/licenses/gpl.html   GPL License
375
 * @version      2.9.0
376
 * @revision     $Revision: 2128 $
377
 * @lastmodified $Date: 2015-06-18 09:54:46 +0200 (Thu, 18 Jun 2015) $
378
 * @description  MYSQL result object for requests
379
 *
380
 */
381
class mysql {
382

    
383
    private $result    = null;
384
    private $oDbHandle = null;
385
    private $error     = '';
386

    
387
    public function __construct($oHandle, $sStatement)
388
    {
389
        $this->oDbHandle = $oHandle;
390
        $this->query($sStatement);
391
    }
392
/**
393
 * query sql statement
394
 * @param  string $statement
395
 * @return object
396
 * @throws WbDatabaseException
397
 */
398
    public function query($sStatement)
399
    {
400
        $this->result = @mysqli_query($this->oDbHandle, $sStatement);
401
        if ($this->result === false) {
402
            if (DEBUG) {
403
                throw new WbDatabaseException(mysqli_error($this->oDbHandle));
404
            } else {
405
                throw new WbDatabaseException('Error in SQL-Statement');
406
            }
407
        }
408
        $this->error = mysqli_error($this->oDbHandle);
409
        return $this->result;
410
    }
411
/**
412
 * numRows
413
 * @return integer
414
 * @description number of returned records
415
 */
416
    public function numRows()
417
    {
418
        return mysqli_num_rows($this->result);
419
    }
420
/**
421
 * fetchRow
422
 * @param  int $typ MYSQL_BOTH(default) | MYSQL_ASSOC | MYSQL_NUM // DEPRECATED
423
 * @return array with numeric indexes
424
 * @description get current record and increment pointer
425
 */
426
    public function fetchRow($typ = MYSQLI_BOTH)
427
    {
428
        if ($typ != MYSQLI_NUM) {
429
            trigger_error('Deprecated call: '.__CLASS__.'::'.__METHOD__.' for MYSQLI_ASSOC|MYSQL_BOTH', E_USER_DEPRECATED);
430
            return mysqli_fetch_array($this->result, $typ);
431
        } else {
432
            return mysqli_fetch_row($this->result);
433
        }
434
    }
435
/**
436
 * fetchAssoc
437
 * @return array with assotiative indexes
438
 * @description get current record and increment pointer
439
 */
440
    public function fetchAssoc()
441
    {
442
        return mysqli_fetch_row($this->result);
443
    }
444
/**
445
 * fetchArray
446
 * @param  int $iType MYSQL_ASSOC(default) | MYSQL_BOTH | MYSQL_NUM
447
 * @return array of current record
448
 * @description get current record and increment pointer
449
 */
450
    public function fetchArray($iType = MYSQLI_ASSOC)
451
    {
452
        if ($iType < MYSQLI_ASSOC || $iType > MYSQLI_BOTH) {
453
            $iType = MYSQLI_ASSOC;
454
        }
455
        return mysqli_fetch_array($this->result, $iType);
456
    }
457
/**
458
 * fetchObject
459
 * @param  string $sClassname Name of the class to use. Is no given use stdClass
460
 * @param  string $aParams    optional array of arguments for the constructor
461
 * @return object
462
 * @description get current record as an object and increment pointer
463
 */
464
    public function fetchObject($sClassName = null, array $aParams = null)
465
    {
466
        if ($sClassName === null || class_exists($sClassName)) {
467
            return mysqli_fetch_object($this->result, $sClassName, $aParams);
468
        } else {
469
            throw new WbDatabaseException('Class <'.$sClassName.'> not available on request of mysqli_fetch_object()');
470
        }
471
    }
472
/**
473
 * fetchAll
474
 * @param  int $iType MYSQL_ASSOC(default) | MYSQL_NUM
475
 * @return array of rows
476
 * @description get all records of the result set
477
 */
478
    public function fetchAll($iType = MYSQLI_ASSOC)
479
    {
480
        $iType = $iType != MYSQLI_NUM ? MYSQL_ASSOC : MYSQLI_NUM;
481
        return mysqli_fetch_all($this->result, $iType);
482
    }
483
/**
484
 * rewind
485
 * @return bool
486
 * @description set the recordpointer to the first record || false on error
487
 */
488
    public function rewind()
489
    {
490
        return $this->seekRow(MYSQLI_SEEK_FIRST);
491
    }
492
/**
493
 * seekRow
494
 * @param int $position also can be MYSQLI_SEEK_FIRST||MYSQLI_SEEK_LAST
495
 * @return bool
496
 * @description set the pointer to the given record || false on error
497
 */
498
    public function seekRow( $position = MYSQLI_SEEK_FIRST )
499
    {
500
        $pmax = $this->numRows() - 1;
501
        $p = (($position < 0 || $position > $pmax) ? $pmax : $position);
502
        return mysqli_data_seek($this->result, $p);
503
    }
504
/**
505
 * freeResult
506
 * @return bool
507
 * @description remove retult object from memeory
508
 */
509
    public function freeResult()
510
    {
511
        return mysqli_free_result($this->result);
512
    }
513
/**
514
 * Get error
515
 * @return string || null if no error
516
 */
517
    public function error()
518
    {
519
        if (isset($this->error)) {
520
            return $this->error;
521
        } else {
522
            return null;
523
        }
524
    }
525

    
526
}