├── test ├── test.sqlite ├── test.sql ├── index.php └── SunDB.php ├── README.md ├── LICENSE └── SunDB.php /test/test.sqlite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msbatal/PHP-PDO-Database-Class/HEAD/test/test.sqlite -------------------------------------------------------------------------------- /test/test.sql: -------------------------------------------------------------------------------- 1 | SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; 2 | SET time_zone = "+00:00"; 3 | 4 | CREATE TABLE `users` ( 5 | `id` int(11) NOT NULL AUTO_INCREMENT, 6 | `name` varchar(100) COLLATE utf8_turkish_ci NOT NULL, 7 | `surname` varchar(100) COLLATE utf8_turkish_ci NOT NULL, 8 | PRIMARY KEY (`id`) 9 | ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_turkish_ci; 10 | 11 | INSERT INTO `users` (`id`, `name`, `surname`) VALUES 12 | (1, '1726', '6158'), 13 | (2, '9342', '9870'), 14 | (3, '7648', '7834'), 15 | (4, '7308', '6102'), 16 | (5, '7966', '9099'), 17 | (6, '4855', '2280'), 18 | (7, '4871', '8713'), 19 | (8, '5566', '9941'), 20 | (9, '5746', '2979'), 21 | (10, '9505', '8015'); -------------------------------------------------------------------------------- /test/index.php: -------------------------------------------------------------------------------- 1 | 'mysql', 'host' => 'localhost', 'port' => 3306, 'dbname'=> 'test', 'username' => 'test', 'password' => '1234', 'charset' => 'utf8']); // Don't forget to change dbname, username, and password 6 | 7 | //$db = new SunDB(['driver' => 'sqlite', 'url' => 'test.sqlite']); 8 | 9 | // Example for Select Query (Single Row) 10 | $select = $db->select('users', ['id', 'name', 'surname'])->orderBy('id', 'desc')->first()->run(); // add "->first()", "->last()", "->random()" before "->run" 11 | echo 'ID: '. $select['id'].'
'.'Name: '.$select['name'].'
'.'Surname: '.$select['surname']; 12 | 13 | 14 | /* 15 | // Example for Select Query (Single Row) 16 | $select = $db->select('users', ['id', 'name', 'surname'])->orderBy('id', 'desc')->run(); 17 | $result = $select[0]; 18 | echo 'ID: '. $result['id'].'
'.'Name: '.$result['name'].'
'.'Surname: '.$result['surname']; 19 | */ 20 | 21 | 22 | /* 23 | // Example for Select Query (Single Row) 24 | $select = $db->select('users', ['id', 'name', 'surname'])->orderBy('id', 'desc')->run(); 25 | foreach ($select as $rows) { 26 | echo 'ID: '. $rows['id'].'
'.'Name: '.$rows['name'].'
'.'Surname: '.$rows['surname']; 27 | echo '

'; 28 | } 29 | */ 30 | 31 | 32 | /* 33 | // Example for Select Query (Multiple Row) 34 | $cols = ['id', 'name', 'surname']; 35 | $select = $db->select('users', $cols)->orderBy('id', 'desc')->run(); // or add "->all()" before "->run" 36 | // $select = $db->select('users', $cols)->orderBy('id', 'desc')->all()->run(); 37 | if ($select) { 38 | echo ''.$db->rowCount().' rows found.

'; 39 | foreach ($select as $rows) { 40 | echo 'ID: '. $rows['id'].'
'.'Name: '.$rows['name'].'
'.'Surname: '.$rows['surname']; 41 | echo '

'; 42 | } 43 | } 44 | */ 45 | 46 | 47 | /* 48 | // Example for Insert Query with Keys and Values 49 | $data = ['id' => Null, 'name' => rand(1111,9999), 'surname' => rand(1111,9999)]; 50 | $insert = $db->insert('users', $data)->run(); 51 | if ($insert) { 52 | echo 'Record inserted successfully! ID: '.$db->lastInsertId(); 53 | } 54 | */ 55 | 56 | 57 | /* 58 | // Example for Insert Query Only with Values 59 | $data = [Null, rand(1111,9999), rand(1111,9999)]; // don't forget to send parameters in same order created in the table 60 | $insert = $db->insert('users', $data)->run(); 61 | if ($insert) { 62 | echo 'Record inserted successfully! ID: '.$db->lastInsertId(); 63 | } 64 | */ 65 | 66 | 67 | /* 68 | // Example for Update Query 69 | $data = ['name' => rand(1111,9999), 'surname' => rand(1111,9999)]; 70 | $update = $db->update('users', $data)->where('id', '1', '=')->run(); 71 | if ($db->rowCount() > 0) { 72 | echo $db->rowCount().' records updated successfully!'; 73 | } else { 74 | echo 'Update failed!'; 75 | } 76 | */ 77 | 78 | 79 | /* 80 | // Example for Delete Query 81 | $delete = $db->delete('users')->where('id', '1', '=')->run(); 82 | if ($db->rowCount() > 0) { 83 | echo $db->rowCount().' records deleted successfully!'; 84 | } else { 85 | echo 'Delete failed!'; 86 | } 87 | */ 88 | 89 | ?> 90 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PHP PDO Database Class 2 | 3 | SunDB is a PHP PDO database class that utilizes PDO and prepared statements (MySQL, MariaDB, MSSQL, SQLite, etc). 4 | 5 | `Technical Document:` https://deepwiki.com/msbatal/PHP-PDO-Database-Class 6 | 7 |
8 | 9 | ### Table of Contents 10 | 11 | - **[Initialization](#initialization)** 12 | - **[Insert Query](#insert-query)** 13 | - **[Update Query](#update-query)** 14 | - **[Delete Query](#delete-query)** 15 | - **[Select Query](#select-query)** 16 | - **[Where Method](#where-method)** 17 | - **[Ordering Method](#ordering-method)** 18 | - **[Limiting Method](#limiting-method)** 19 | - **[Grouping Method](#grouping-method)** 20 | - **[Having Method](#having-method)** 21 | - **[Raw SQL Queries](#raw-sql-queries)** 22 | - **[Backup Database](#backup-database)** 23 | - **[Maintaining Database](#maintaining-database)** 24 | - **[Helper Methods](#helper-methods)** 25 | 26 | ### Installation 27 | 28 | To utilize this class, first import SunDB.php into your project, and require it. 29 | SunDB requires PHP 5.5+ to work. 30 | 31 | ```php 32 | require_once ('SunDB.php'); 33 | ``` 34 | 35 | ### Initialization 36 | 37 | Simple initialization with utf8 charset set by default: 38 | ```php 39 | $db = new SunDB(null, 'host', 'username', 'password', 'dbName'); 40 | ``` 41 | 42 | Advanced initialization: 43 | ```php 44 | $db = new SunDB(['driver' => 'mysql', 45 | 'host' => 'host', 46 | 'port' => 3306, 47 | 'dbname'=> 'dbName', 48 | 'username' => 'username', 49 | 'password' => 'password', 50 | 'charset' => 'utf8' 51 | ]); 52 | ``` 53 | Url, Port and Charset parameters are optional. 54 | 55 | You can use mysql, mssql, and sqlite driver types for Driver parameter. 56 | 57 | If you want use MSSQL: 58 | ```php 59 | $db = new SunDB(['driver' => 'mssql', 60 | 'host' => 'serverName', 61 | 'dbname' => 'dbName', 62 | 'username' => 'username', 63 | 'password' => 'password' 64 | ]); 65 | ``` 66 | 67 | If you want use SQLite: 68 | ```php 69 | $db = new SunDB(['driver' => 'sqlite', 70 | 'url' => 'fileName.sqlite' 71 | ]); 72 | ``` 73 | 74 | Also it's possible to use already connected PDO object: 75 | ```php 76 | $pdo = new PDO('mysql:dbname=sample;host=localhost', 'username', 'password'); 77 | $db = new SunDB($pdo); 78 | ``` 79 | 80 | ### Insert Query 81 | 82 | Simple example with keys and values 83 | ```php 84 | $data = [ 85 | 'column1' => 'Value 1', 86 | 'column2' => 'Value 2', 87 | 'column3' => 'Value 3' 88 | ]; 89 | $insert = $db->insert('tableName', $data)->run(); 90 | //Gives: INSERT INTO tableName (column1, column2, column3) VALUES ('Value 1', 'Value 2', 'Value3'); 91 | 92 | if ($insert) { 93 | echo 'Record inserted successfully! ID: '.$db->lastInsertId(); 94 | } 95 | ``` 96 | 97 | Simple example only with values 98 | ```php 99 | $insert = $db->insert('tableName', [NULL, 'Value 2', 'Value 3'])->run(); 100 | //Don't forget to send parameters in same order created in the table 101 | //Gives: INSERT INTO tableName VALUES (NULL, 'Value 2', 'Value3'); 102 | 103 | if ($insert) { 104 | echo 'Record inserted successfully! ID: '.$db->lastInsertId(); 105 | } 106 | ``` 107 | 108 | Insert with functions use 109 | ```php 110 | $data = [ 111 | 'column1' => 'Value 1', 112 | 'column2' => true, //or false 113 | 'column3' => 'Value 3', 114 | 'column4' => $db->func('sha1', 'stringText'), 115 | //Supported functions date, sha1, md5, base64, ceil, floor, round, etc. 116 | //'columnX' => $db->func('date', 'now'), 117 | //'columnX' => $db->func('date', 'Y-m-d'), 118 | //'columnX' => $db->func('date', 'H:i:s'), 119 | //Supported intervals [s]econd, [m]inute, [h]hour, [d]day, [M]onth, [Y]ear 120 | ]; 121 | 122 | $insert = $db->insert('tableName', $data)->run(); 123 | //Gives: INSERT INTO tableName (...) VALUES (...); 124 | 125 | //if ($insert) { 126 | if ($db->rowCount() > 0) { 127 | echo 'Record inserted successfully! ID: '.$db->lastInsertId(); 128 | } else { 129 | echo 'Insert failed!'; 130 | } 131 | ``` 132 | 133 | Insert query returns `true` or `false` result. Also, you can get the affected (inserted) rows by using `rowCount()` method. If you need last inserted record's id, you may use `lastInsertId()` method. 134 | 135 | ### Update Query 136 | 137 | ```php 138 | $data = [ 139 | 'column1' => 'Value 1', 140 | 'column2' => 'Value 2', 141 | 'column3' => 'Value 3' 142 | ]; 143 | 144 | $update = $db->update('tableName', $data) 145 | ->where('column', 'value', '=') 146 | ->run(); 147 | //Gives: UPDATE tableName SET column1='Value 1', column2='Value 2', column3='Value 3' WHERE column=value; 148 | 149 | //if ($update) { 150 | if ($db->rowCount() > 0) { 151 | echo $db->rowCount().' records updated successfully!'; 152 | } else { 153 | echo 'Update failed!'; 154 | } 155 | ``` 156 | 157 | `update()` also support order by and limit parameters: 158 | ```php 159 | $update = $db->update('tableName', $data) 160 | ->where('column', 'value', '>') 161 | ->orderBy('column', 'desc') 162 | ->limit(2) 163 | ->run(); 164 | //Gives: UPDATE tableName SET ... WHERE column > value ORDER BY column DESC LIMIT 2; 165 | ``` 166 | 167 | Update query returns `true` or `false` result. Also, you can get the affected (updated) rows by using `rowCount()` method. If you don't make changes in column contents (sending same values to db), rowCount() will return a `Zero (0)` value. So, please think twice about controlling the results; true/false or affected row count? 168 | 169 | ### Delete Query 170 | 171 | ```php 172 | $delete = $db->delete('tableName') 173 | ->where('column', 'value', '>') 174 | ->run(); 175 | //Gives: DELETE FROM tableName WHERE column > value; 176 | 177 | //if ($delete) { 178 | if ($db->rowCount() > 0) { 179 | echo $db->rowCount().' records deleted successfully!'; 180 | } else { 181 | echo 'Delete failed!'; 182 | } 183 | ``` 184 | 185 | Delete query returns `true` or `false` result. Also, you can get the affected (deleted) rows by using `rowCount()` method. 186 | 187 | ### Select Query 188 | 189 | After any select function calls returned rows is stored in an array/object 190 | ```php 191 | $select = $db->select('tableName')->run(); //contains an array/object of all records 192 | //Gives: SELECT * FROM tableName; 193 | 194 | $select = $db->select('tableName')->limit(4)->run(); //contains an array/object of X records 195 | //Gives: SELECT * FROM tableName LIMIT 4; 196 | ``` 197 | 198 | or select with custom columns set 199 | 200 | ```php 201 | $cols = ['column1', 'column2', 'column3']; 202 | $select = $db->select('tableName', $cols)->run(); 203 | //Gives: SELECT column1,column2,column3 FROM tableName; 204 | 205 | if ($select) { 206 | foreach ($select as $rows) { 207 | print_r($rows); 208 | } 209 | } 210 | ``` 211 | 212 | or select just one row 213 | 214 | ```php 215 | $select = $db->select('tableName')->where('column', 'value', '=')->first()->run(); 216 | //Gives: SELECT * FROM tableName WHERE column='value'; 217 | 218 | echo $select['column']; 219 | ``` 220 | 221 | or select one column value or function result 222 | 223 | ```php 224 | $select = $db->select('tableName', ['column'])->limit(1)->first()->run(); 225 | //Gives: SELECT column FROM tableName LIMIT 1; 226 | 227 | echo $select['column']; 228 | 229 | $select = $db->select('tableName', ['count(*) as total'])->first()->run(); 230 | //Gives: SELECT count(*) as total FROM tableName; 231 | 232 | echo $select['total']; 233 | ``` 234 | 235 | or you may use these two alternatives to select a single row 236 | 237 | ```php 238 | $select = $db->select('tableName')->run(); 239 | echo $select[0]['column']; //alternative 1 (use '0' key between query variable and column key) 240 | 241 | $select = $db->select('tableName')->run(); 242 | foreach ($select as $row) { 243 | echo $row['column']; //alternative 2 (use 'foreach' like a multiple selection) 244 | } 245 | ``` 246 | 247 | If you need a single row and don't want to use a loop function, don't forget to use `first()`, `last()` or `random()` methods before `run()` method. 248 | 249 | ### Where Method 250 | 251 | `where()` or `orWhere()` methods allow you to specify `where` condition of the query. This method is supported by `select`, `update` and `delete` queries, and uses prepared statements (also bind parameters). 252 | 253 | ```php 254 | $select = $db->select('tableName') 255 | ->where('column', 'value', '=') 256 | ->run(); 257 | //Gives: SELECT * FROM tableName WHERE column='value'; 258 | ``` 259 | 260 | ```php 261 | $select = $db->select('tableName') 262 | ->where('column1', 'value1', '>') 263 | ->where('column2', 'value2', '<') 264 | ->run(); 265 | //Gives: SELECT * FROM tableName WHERE column1 > value1 AND column2 < value2; 266 | ``` 267 | 268 | LIKE / NOT LIKE: 269 | ```php 270 | $select = $db->select('tableName') 271 | ->where('column', 'value', 'like'); //or with wildcard (%value, value%, %value%) 272 | ->run(); 273 | //Gives: SELECT * FROM tableName WHERE column LIKE 'value'; 274 | 275 | $select = $db->select('tableName') 276 | ->where('column', 'value', 'not like'); //or with wildcard (%value, value%, %value%) 277 | ->run(); 278 | //Gives: SELECT * FROM tableName WHERE column NOT LIKE 'value'; 279 | ``` 280 | 281 | BETWEEN / NOT BETWEEN: 282 | ```php 283 | $select = $db->select('tableName') 284 | ->where('column', [date("Y-m-d"), date("Y-m-d")], 'between'); 285 | ->run(); 286 | //Gives: SELECT * FROM tableName WHERE column BETWEEN 'YYYY-mm-dd' AND 'YYYY-mm-dd'; 287 | 288 | $select = $db->select('tableName') 289 | ->where('column', [date("Y-m-d"), date("Y-m-d")], 'not between'); 290 | ->run(); 291 | //Gives: SELECT * FROM tableName WHERE column NOT BETWEEN 'YYYY-mm-dd' AND 'YYYY-mm-dd'; 292 | ``` 293 | 294 | IN / NOT IN: 295 | ```php 296 | $select = $db->select('tableName') 297 | ->where('column', [1, 2, 3, 'a', 'b'], 'in'); 298 | ->run(); 299 | //Gives: SELECT * FROM tableName WHERE column IN (1, 2, 3, 'a', 'b'); 300 | 301 | $select = $db->select('tableName') 302 | ->where('column', [1, 2, 3, 'a', 'b'], 'not in'); 303 | ->run(); 304 | //Gives: SELECT * FROM tableName WHERE column NOT IN (1, 2, 3, 'a', 'b'); 305 | ``` 306 | 307 | OR CASE 308 | ```php 309 | $select = $db->select('tableName') 310 | ->where('column1', 'value1', '=') 311 | ->orWhere('column2', 'value2', '=') 312 | ->run(); 313 | //Gives: SELECT * FROM tableName WHERE column1='value1' OR column2='value2'; 314 | ``` 315 | 316 | AND and OR CASE 317 | ```php 318 | $select = $db->select('tableName') 319 | ->where('column1', 'value1', '=') 320 | ->where('column2', 'value2', '=') 321 | ->orWhere('column3', 'value3', '=') 322 | ->run(); 323 | //Gives: SELECT * FROM tableName WHERE column1='value1' AND column2='value2' OR column3='value3'; 324 | ``` 325 | 326 | ```php 327 | $select = $db->select('tableName') 328 | ->orWhere('column1', 'value1', '=') 329 | ->where('column2', 'value2', '=') 330 | ->where('column3', 'value3', '=') 331 | ->run(); 332 | //Gives: SELECT * FROM tableName WHERE column1='value1' AND column2='value2' AND column3='value3'; 333 | ``` 334 | 335 | Also you can use raw where conditions: 336 | ```php 337 | $select = $db->select('tableName') 338 | ->where('column1 >= value1 AND column2 < value2'); 339 | ->run(); 340 | //Gives: SELECT * FROM tableName WHERE column1 >= value1 AND column2 < value2; 341 | ``` 342 | 343 | Find the total number of rows affected: 344 | ```php 345 | $total = $db->rowCount(); 346 | echo "{$total} rows affected."; 347 | ``` 348 | 349 | Find the total number of rows in table: 350 | ```php 351 | $total = $db->tableCount('tableName'); 352 | echo "{$total} rows found."; 353 | ``` 354 | 355 | ### Ordering Method 356 | 357 | `orderBy()` method allows you to specify `order by` condition of the query. This method is supported by `select`, `update` and `delete` queries. 358 | 359 | ```php 360 | $select = $db->select('tableName', ['column1', 'column2']) 361 | ->orderBy('column1', 'asc') 362 | ->orderBy('column2', 'desc') 363 | ->orderBy("RAND ()") 364 | ->run(); 365 | //Gives: SELECT column1,column2 FROM tableName ORDER BY column1 ASC, column2 DESC, RAND (); 366 | ``` 367 | 368 | ### Limiting Method 369 | 370 | `limit()` method allows you to specify `limit` condition of the query. This method is supported by `select`, `update` and `delete` queries. 371 | 372 | ```php 373 | $select = $db->select('tableName', ['column'])->limit(1)->run(); 374 | //Gives: SELECT column FROM tableName LIMIT 1; 375 | 376 | echo $select['column']; 377 | ``` 378 | 379 | ```php 380 | $select = $db->select('tableName', ['column'])->limit(5, 4)->run(); 381 | //Gives: SELECT column FROM tableName LIMIT 5,4; 382 | 383 | echo $select['column']; 384 | ``` 385 | 386 | ```php 387 | $delete = $db->delete('tableName') 388 | ->where('column', 'value', '>') 389 | ->orderBy('column', 'desc') 390 | ->limit(5) 391 | ->run(); 392 | //Gives: DELETE FROM tableName WHERE column > value ORDER BY column DESC limit 5; 393 | 394 | //if ($delete) { 395 | if ($db->rowCount() > 0) { 396 | echo $db->rowCount().' records deleted successfully!'; 397 | } else { 398 | echo 'Delete failed!'; 399 | } 400 | ``` 401 | 402 | ### Grouping Method 403 | 404 | `groupBy()` method allows you to specify `group by` condition of the query. This method is supported by only `select` query. 405 | 406 | ```php 407 | $select = $db->select('tableName') 408 | ->groupBy('column') 409 | ->run(); 410 | //Gives: SELECT * FROM tableName GROUP BY column; 411 | ``` 412 | 413 | Also you can use functions with `groupBy()` method: 414 | 415 | ```php 416 | $select = $db->select('tableName', 'count(column) as count') 417 | ->groupBy('column', 'DAYNAME') 418 | ->orderby('count(column)', 'desc') 419 | ->run(); 420 | //Gives: SELECT count(column) as count FROM tableName GROUP BY DAYNAME(column) ORDER BY count(column) DESC; 421 | ``` 422 | 423 | ### Having Method 424 | 425 | `having()` method allows you to specify `having` condition of the query. This method is supported by only `select` query. 426 | 427 | ```php 428 | $select = $db->select('tableName') 429 | ->groupBy('column') 430 | ->having('column >= value') 431 | ->run(); 432 | //Gives: SELECT * FROM tableName GROUP BY column HAVING column >= value; 433 | ``` 434 | 435 | ### Raw SQL Queries 436 | 437 | You can use raw queries for more complex SQL statements, or not specified functions and methods in this class. 438 | 439 | Execute raw SQL queries: 440 | ```php 441 | $select = $db->rawQuery("select column1,column2 from tableName where (column1='value1' && column2='value2')") 442 | ->limit(2) 443 | ->run(); 444 | //Gives: SELECT column1,column2 FROM tableName WHERE (column1='value1' && column2='value2') LIMIT 2; 445 | 446 | foreach ($select as $rows) { 447 | print_r($rows); 448 | } 449 | ``` 450 | 451 | or use prepared statements (bind parameters): 452 | ```php 453 | $select = $db->rawQuery("select column1,column2 from tableName where (column1=? && column2=?)", ['value1', 'value2']) 454 | ->limit(2) 455 | ->run(); 456 | //Gives: SELECT column1,column2 FROM tableName WHERE (column1='value1' && column2='value2') LIMIT 2; 457 | 458 | foreach ($select as $rows) { 459 | print_r($rows); 460 | } 461 | ``` 462 | 463 | If you use Insert, Update or Delete commands, Raw SQL query returns `true` or `false` result. If you use Select command, it will return an array/object containing the selected row(s). 464 | 465 | ### Backup Database 466 | 467 | Download the whole database (tables and records) as an SQL file: 468 | ```php 469 | $db->backup('fileName', 'save'); 470 | //File: fileName.sql 471 | ``` 472 | Don't forget to use this code on an empty page. Otherwise, you can see an HTML page into an SQL file. 473 | 474 | Show the whole database (tables and records) as an SQL query: 475 | ```php 476 | $db->backup(null, 'show'); 477 | ``` 478 | 479 | Download/Show the whole database (with exclude some tables) as an SQL query: 480 | ```php 481 | $db->backup(null, 'save', ['table1', 'table2']); //or 'show' action 482 | ``` 483 | 484 | ### Maintaining Database 485 | 486 | Analyze, check, optimize and repair the whole database (tables and records): 487 | ```php 488 | $db->maintenance(); 489 | ``` 490 | 491 | or 492 | 493 | ```php 494 | $maintenance = $db->maintenance(); 495 | if ($maintenance) { 496 | echo 'Maintenance successfully!'; 497 | } else { 498 | echo 'Maintenance failed!'; 499 | } 500 | ``` 501 | 502 | ### Helper Methods 503 | 504 | Get last executed SQL query: 505 | ```php 506 | $db->showQuery(); 507 | ``` 508 | This code will print the last executed query to the screen. 509 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 2.1, February 1999 3 | 4 | Copyright (C) 1991, 1999 Free Software Foundation, Inc. 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | [This is the first released version of the Lesser GPL. It also counts 10 | as the successor of the GNU Library Public License, version 2, hence 11 | the version number 2.1.] 12 | 13 | Preamble 14 | 15 | The licenses for most software are designed to take away your 16 | freedom to share and change it. By contrast, the GNU General Public 17 | Licenses are intended to guarantee your freedom to share and change 18 | free software--to make sure the software is free for all its users. 19 | 20 | This license, the Lesser General Public License, applies to some 21 | specially designated software packages--typically libraries--of the 22 | Free Software Foundation and other authors who decide to use it. You 23 | can use it too, but we suggest you first think carefully about whether 24 | this license or the ordinary General Public License is the better 25 | strategy to use in any particular case, based on the explanations below. 26 | 27 | When we speak of free software, we are referring to freedom of use, 28 | not price. Our General Public Licenses are designed to make sure that 29 | you have the freedom to distribute copies of free software (and charge 30 | for this service if you wish); that you receive source code or can get 31 | it if you want it; that you can change the software and use pieces of 32 | it in new free programs; and that you are informed that you can do 33 | these things. 34 | 35 | To protect your rights, we need to make restrictions that forbid 36 | distributors to deny you these rights or to ask you to surrender these 37 | rights. These restrictions translate to certain responsibilities for 38 | you if you distribute copies of the library or if you modify it. 39 | 40 | For example, if you distribute copies of the library, whether gratis 41 | or for a fee, you must give the recipients all the rights that we gave 42 | you. You must make sure that they, too, receive or can get the source 43 | code. If you link other code with the library, you must provide 44 | complete object files to the recipients, so that they can relink them 45 | with the library after making changes to the library and recompiling 46 | it. And you must show them these terms so they know their rights. 47 | 48 | We protect your rights with a two-step method: (1) we copyright the 49 | library, and (2) we offer you this license, which gives you legal 50 | permission to copy, distribute and/or modify the library. 51 | 52 | To protect each distributor, we want to make it very clear that 53 | there is no warranty for the free library. Also, if the library is 54 | modified by someone else and passed on, the recipients should know 55 | that what they have is not the original version, so that the original 56 | author's reputation will not be affected by problems that might be 57 | introduced by others. 58 | 59 | Finally, software patents pose a constant threat to the existence of 60 | any free program. We wish to make sure that a company cannot 61 | effectively restrict the users of a free program by obtaining a 62 | restrictive license from a patent holder. Therefore, we insist that 63 | any patent license obtained for a version of the library must be 64 | consistent with the full freedom of use specified in this license. 65 | 66 | Most GNU software, including some libraries, is covered by the 67 | ordinary GNU General Public License. This license, the GNU Lesser 68 | General Public License, applies to certain designated libraries, and 69 | is quite different from the ordinary General Public License. We use 70 | this license for certain libraries in order to permit linking those 71 | libraries into non-free programs. 72 | 73 | When a program is linked with a library, whether statically or using 74 | a shared library, the combination of the two is legally speaking a 75 | combined work, a derivative of the original library. The ordinary 76 | General Public License therefore permits such linking only if the 77 | entire combination fits its criteria of freedom. The Lesser General 78 | Public License permits more lax criteria for linking other code with 79 | the library. 80 | 81 | We call this license the "Lesser" General Public License because it 82 | does Less to protect the user's freedom than the ordinary General 83 | Public License. It also provides other free software developers Less 84 | of an advantage over competing non-free programs. These disadvantages 85 | are the reason we use the ordinary General Public License for many 86 | libraries. However, the Lesser license provides advantages in certain 87 | special circumstances. 88 | 89 | For example, on rare occasions, there may be a special need to 90 | encourage the widest possible use of a certain library, so that it becomes 91 | a de-facto standard. To achieve this, non-free programs must be 92 | allowed to use the library. A more frequent case is that a free 93 | library does the same job as widely used non-free libraries. In this 94 | case, there is little to gain by limiting the free library to free 95 | software only, so we use the Lesser General Public License. 96 | 97 | In other cases, permission to use a particular library in non-free 98 | programs enables a greater number of people to use a large body of 99 | free software. For example, permission to use the GNU C Library in 100 | non-free programs enables many more people to use the whole GNU 101 | operating system, as well as its variant, the GNU/Linux operating 102 | system. 103 | 104 | Although the Lesser General Public License is Less protective of the 105 | users' freedom, it does ensure that the user of a program that is 106 | linked with the Library has the freedom and the wherewithal to run 107 | that program using a modified version of the Library. 108 | 109 | The precise terms and conditions for copying, distribution and 110 | modification follow. Pay close attention to the difference between a 111 | "work based on the library" and a "work that uses the library". The 112 | former contains code derived from the library, whereas the latter must 113 | be combined with the library in order to run. 114 | 115 | GNU LESSER GENERAL PUBLIC LICENSE 116 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 117 | 118 | 0. This License Agreement applies to any software library or other 119 | program which contains a notice placed by the copyright holder or 120 | other authorized party saying it may be distributed under the terms of 121 | this Lesser General Public License (also called "this License"). 122 | Each licensee is addressed as "you". 123 | 124 | A "library" means a collection of software functions and/or data 125 | prepared so as to be conveniently linked with application programs 126 | (which use some of those functions and data) to form executables. 127 | 128 | The "Library", below, refers to any such software library or work 129 | which has been distributed under these terms. A "work based on the 130 | Library" means either the Library or any derivative work under 131 | copyright law: that is to say, a work containing the Library or a 132 | portion of it, either verbatim or with modifications and/or translated 133 | straightforwardly into another language. (Hereinafter, translation is 134 | included without limitation in the term "modification".) 135 | 136 | "Source code" for a work means the preferred form of the work for 137 | making modifications to it. For a library, complete source code means 138 | all the source code for all modules it contains, plus any associated 139 | interface definition files, plus the scripts used to control compilation 140 | and installation of the library. 141 | 142 | Activities other than copying, distribution and modification are not 143 | covered by this License; they are outside its scope. The act of 144 | running a program using the Library is not restricted, and output from 145 | such a program is covered only if its contents constitute a work based 146 | on the Library (independent of the use of the Library in a tool for 147 | writing it). Whether that is true depends on what the Library does 148 | and what the program that uses the Library does. 149 | 150 | 1. You may copy and distribute verbatim copies of the Library's 151 | complete source code as you receive it, in any medium, provided that 152 | you conspicuously and appropriately publish on each copy an 153 | appropriate copyright notice and disclaimer of warranty; keep intact 154 | all the notices that refer to this License and to the absence of any 155 | warranty; and distribute a copy of this License along with the 156 | Library. 157 | 158 | You may charge a fee for the physical act of transferring a copy, 159 | and you may at your option offer warranty protection in exchange for a 160 | fee. 161 | 162 | 2. You may modify your copy or copies of the Library or any portion 163 | of it, thus forming a work based on the Library, and copy and 164 | distribute such modifications or work under the terms of Section 1 165 | above, provided that you also meet all of these conditions: 166 | 167 | a) The modified work must itself be a software library. 168 | 169 | b) You must cause the files modified to carry prominent notices 170 | stating that you changed the files and the date of any change. 171 | 172 | c) You must cause the whole of the work to be licensed at no 173 | charge to all third parties under the terms of this License. 174 | 175 | d) If a facility in the modified Library refers to a function or a 176 | table of data to be supplied by an application program that uses 177 | the facility, other than as an argument passed when the facility 178 | is invoked, then you must make a good faith effort to ensure that, 179 | in the event an application does not supply such function or 180 | table, the facility still operates, and performs whatever part of 181 | its purpose remains meaningful. 182 | 183 | (For example, a function in a library to compute square roots has 184 | a purpose that is entirely well-defined independent of the 185 | application. Therefore, Subsection 2d requires that any 186 | application-supplied function or table used by this function must 187 | be optional: if the application does not supply it, the square 188 | root function must still compute square roots.) 189 | 190 | These requirements apply to the modified work as a whole. If 191 | identifiable sections of that work are not derived from the Library, 192 | and can be reasonably considered independent and separate works in 193 | themselves, then this License, and its terms, do not apply to those 194 | sections when you distribute them as separate works. But when you 195 | distribute the same sections as part of a whole which is a work based 196 | on the Library, the distribution of the whole must be on the terms of 197 | this License, whose permissions for other licensees extend to the 198 | entire whole, and thus to each and every part regardless of who wrote 199 | it. 200 | 201 | Thus, it is not the intent of this section to claim rights or contest 202 | your rights to work written entirely by you; rather, the intent is to 203 | exercise the right to control the distribution of derivative or 204 | collective works based on the Library. 205 | 206 | In addition, mere aggregation of another work not based on the Library 207 | with the Library (or with a work based on the Library) on a volume of 208 | a storage or distribution medium does not bring the other work under 209 | the scope of this License. 210 | 211 | 3. You may opt to apply the terms of the ordinary GNU General Public 212 | License instead of this License to a given copy of the Library. To do 213 | this, you must alter all the notices that refer to this License, so 214 | that they refer to the ordinary GNU General Public License, version 2, 215 | instead of to this License. (If a newer version than version 2 of the 216 | ordinary GNU General Public License has appeared, then you can specify 217 | that version instead if you wish.) Do not make any other change in 218 | these notices. 219 | 220 | Once this change is made in a given copy, it is irreversible for 221 | that copy, so the ordinary GNU General Public License applies to all 222 | subsequent copies and derivative works made from that copy. 223 | 224 | This option is useful when you wish to copy part of the code of 225 | the Library into a program that is not a library. 226 | 227 | 4. You may copy and distribute the Library (or a portion or 228 | derivative of it, under Section 2) in object code or executable form 229 | under the terms of Sections 1 and 2 above provided that you accompany 230 | it with the complete corresponding machine-readable source code, which 231 | must be distributed under the terms of Sections 1 and 2 above on a 232 | medium customarily used for software interchange. 233 | 234 | If distribution of object code is made by offering access to copy 235 | from a designated place, then offering equivalent access to copy the 236 | source code from the same place satisfies the requirement to 237 | distribute the source code, even though third parties are not 238 | compelled to copy the source along with the object code. 239 | 240 | 5. A program that contains no derivative of any portion of the 241 | Library, but is designed to work with the Library by being compiled or 242 | linked with it, is called a "work that uses the Library". Such a 243 | work, in isolation, is not a derivative work of the Library, and 244 | therefore falls outside the scope of this License. 245 | 246 | However, linking a "work that uses the Library" with the Library 247 | creates an executable that is a derivative of the Library (because it 248 | contains portions of the Library), rather than a "work that uses the 249 | library". The executable is therefore covered by this License. 250 | Section 6 states terms for distribution of such executables. 251 | 252 | When a "work that uses the Library" uses material from a header file 253 | that is part of the Library, the object code for the work may be a 254 | derivative work of the Library even though the source code is not. 255 | Whether this is true is especially significant if the work can be 256 | linked without the Library, or if the work is itself a library. The 257 | threshold for this to be true is not precisely defined by law. 258 | 259 | If such an object file uses only numerical parameters, data 260 | structure layouts and accessors, and small macros and small inline 261 | functions (ten lines or less in length), then the use of the object 262 | file is unrestricted, regardless of whether it is legally a derivative 263 | work. (Executables containing this object code plus portions of the 264 | Library will still fall under Section 6.) 265 | 266 | Otherwise, if the work is a derivative of the Library, you may 267 | distribute the object code for the work under the terms of Section 6. 268 | Any executables containing that work also fall under Section 6, 269 | whether or not they are linked directly with the Library itself. 270 | 271 | 6. As an exception to the Sections above, you may also combine or 272 | link a "work that uses the Library" with the Library to produce a 273 | work containing portions of the Library, and distribute that work 274 | under terms of your choice, provided that the terms permit 275 | modification of the work for the customer's own use and reverse 276 | engineering for debugging such modifications. 277 | 278 | You must give prominent notice with each copy of the work that the 279 | Library is used in it and that the Library and its use are covered by 280 | this License. You must supply a copy of this License. If the work 281 | during execution displays copyright notices, you must include the 282 | copyright notice for the Library among them, as well as a reference 283 | directing the user to the copy of this License. Also, you must do one 284 | of these things: 285 | 286 | a) Accompany the work with the complete corresponding 287 | machine-readable source code for the Library including whatever 288 | changes were used in the work (which must be distributed under 289 | Sections 1 and 2 above); and, if the work is an executable linked 290 | with the Library, with the complete machine-readable "work that 291 | uses the Library", as object code and/or source code, so that the 292 | user can modify the Library and then relink to produce a modified 293 | executable containing the modified Library. (It is understood 294 | that the user who changes the contents of definitions files in the 295 | Library will not necessarily be able to recompile the application 296 | to use the modified definitions.) 297 | 298 | b) Use a suitable shared library mechanism for linking with the 299 | Library. A suitable mechanism is one that (1) uses at run time a 300 | copy of the library already present on the user's computer system, 301 | rather than copying library functions into the executable, and (2) 302 | will operate properly with a modified version of the library, if 303 | the user installs one, as long as the modified version is 304 | interface-compatible with the version that the work was made with. 305 | 306 | c) Accompany the work with a written offer, valid for at 307 | least three years, to give the same user the materials 308 | specified in Subsection 6a, above, for a charge no more 309 | than the cost of performing this distribution. 310 | 311 | d) If distribution of the work is made by offering access to copy 312 | from a designated place, offer equivalent access to copy the above 313 | specified materials from the same place. 314 | 315 | e) Verify that the user has already received a copy of these 316 | materials or that you have already sent this user a copy. 317 | 318 | For an executable, the required form of the "work that uses the 319 | Library" must include any data and utility programs needed for 320 | reproducing the executable from it. However, as a special exception, 321 | the materials to be distributed need not include anything that is 322 | normally distributed (in either source or binary form) with the major 323 | components (compiler, kernel, and so on) of the operating system on 324 | which the executable runs, unless that component itself accompanies 325 | the executable. 326 | 327 | It may happen that this requirement contradicts the license 328 | restrictions of other proprietary libraries that do not normally 329 | accompany the operating system. Such a contradiction means you cannot 330 | use both them and the Library together in an executable that you 331 | distribute. 332 | 333 | 7. You may place library facilities that are a work based on the 334 | Library side-by-side in a single library together with other library 335 | facilities not covered by this License, and distribute such a combined 336 | library, provided that the separate distribution of the work based on 337 | the Library and of the other library facilities is otherwise 338 | permitted, and provided that you do these two things: 339 | 340 | a) Accompany the combined library with a copy of the same work 341 | based on the Library, uncombined with any other library 342 | facilities. This must be distributed under the terms of the 343 | Sections above. 344 | 345 | b) Give prominent notice with the combined library of the fact 346 | that part of it is a work based on the Library, and explaining 347 | where to find the accompanying uncombined form of the same work. 348 | 349 | 8. You may not copy, modify, sublicense, link with, or distribute 350 | the Library except as expressly provided under this License. Any 351 | attempt otherwise to copy, modify, sublicense, link with, or 352 | distribute the Library is void, and will automatically terminate your 353 | rights under this License. However, parties who have received copies, 354 | or rights, from you under this License will not have their licenses 355 | terminated so long as such parties remain in full compliance. 356 | 357 | 9. You are not required to accept this License, since you have not 358 | signed it. However, nothing else grants you permission to modify or 359 | distribute the Library or its derivative works. These actions are 360 | prohibited by law if you do not accept this License. Therefore, by 361 | modifying or distributing the Library (or any work based on the 362 | Library), you indicate your acceptance of this License to do so, and 363 | all its terms and conditions for copying, distributing or modifying 364 | the Library or works based on it. 365 | 366 | 10. Each time you redistribute the Library (or any work based on the 367 | Library), the recipient automatically receives a license from the 368 | original licensor to copy, distribute, link with or modify the Library 369 | subject to these terms and conditions. You may not impose any further 370 | restrictions on the recipients' exercise of the rights granted herein. 371 | You are not responsible for enforcing compliance by third parties with 372 | this License. 373 | 374 | 11. If, as a consequence of a court judgment or allegation of patent 375 | infringement or for any other reason (not limited to patent issues), 376 | conditions are imposed on you (whether by court order, agreement or 377 | otherwise) that contradict the conditions of this License, they do not 378 | excuse you from the conditions of this License. If you cannot 379 | distribute so as to satisfy simultaneously your obligations under this 380 | License and any other pertinent obligations, then as a consequence you 381 | may not distribute the Library at all. For example, if a patent 382 | license would not permit royalty-free redistribution of the Library by 383 | all those who receive copies directly or indirectly through you, then 384 | the only way you could satisfy both it and this License would be to 385 | refrain entirely from distribution of the Library. 386 | 387 | If any portion of this section is held invalid or unenforceable under any 388 | particular circumstance, the balance of the section is intended to apply, 389 | and the section as a whole is intended to apply in other circumstances. 390 | 391 | It is not the purpose of this section to induce you to infringe any 392 | patents or other property right claims or to contest validity of any 393 | such claims; this section has the sole purpose of protecting the 394 | integrity of the free software distribution system which is 395 | implemented by public license practices. Many people have made 396 | generous contributions to the wide range of software distributed 397 | through that system in reliance on consistent application of that 398 | system; it is up to the author/donor to decide if he or she is willing 399 | to distribute software through any other system and a licensee cannot 400 | impose that choice. 401 | 402 | This section is intended to make thoroughly clear what is believed to 403 | be a consequence of the rest of this License. 404 | 405 | 12. If the distribution and/or use of the Library is restricted in 406 | certain countries either by patents or by copyrighted interfaces, the 407 | original copyright holder who places the Library under this License may add 408 | an explicit geographical distribution limitation excluding those countries, 409 | so that distribution is permitted only in or among countries not thus 410 | excluded. In such case, this License incorporates the limitation as if 411 | written in the body of this License. 412 | 413 | 13. The Free Software Foundation may publish revised and/or new 414 | versions of the Lesser General Public License from time to time. 415 | Such new versions will be similar in spirit to the present version, 416 | but may differ in detail to address new problems or concerns. 417 | 418 | Each version is given a distinguishing version number. If the Library 419 | specifies a version number of this License which applies to it and 420 | "any later version", you have the option of following the terms and 421 | conditions either of that version or of any later version published by 422 | the Free Software Foundation. If the Library does not specify a 423 | license version number, you may choose any version ever published by 424 | the Free Software Foundation. 425 | 426 | 14. If you wish to incorporate parts of the Library into other free 427 | programs whose distribution conditions are incompatible with these, 428 | write to the author to ask for permission. For software which is 429 | copyrighted by the Free Software Foundation, write to the Free 430 | Software Foundation; we sometimes make exceptions for this. Our 431 | decision will be guided by the two goals of preserving the free status 432 | of all derivatives of our free software and of promoting the sharing 433 | and reuse of software generally. 434 | 435 | NO WARRANTY 436 | 437 | 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO 438 | WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. 439 | EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR 440 | OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY 441 | KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE 442 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 443 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE 444 | LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME 445 | THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 446 | 447 | 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN 448 | WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY 449 | AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU 450 | FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR 451 | CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE 452 | LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING 453 | RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A 454 | FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF 455 | SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 456 | DAMAGES. 457 | 458 | END OF TERMS AND CONDITIONS 459 | 460 | How to Apply These Terms to Your New Libraries 461 | 462 | If you develop a new library, and you want it to be of the greatest 463 | possible use to the public, we recommend making it free software that 464 | everyone can redistribute and change. You can do so by permitting 465 | redistribution under these terms (or, alternatively, under the terms of the 466 | ordinary General Public License). 467 | 468 | To apply these terms, attach the following notices to the library. It is 469 | safest to attach them to the start of each source file to most effectively 470 | convey the exclusion of warranty; and each file should have at least the 471 | "copyright" line and a pointer to where the full notice is found. 472 | 473 | 474 | Copyright (C) 475 | 476 | This library is free software; you can redistribute it and/or 477 | modify it under the terms of the GNU Lesser General Public 478 | License as published by the Free Software Foundation; either 479 | version 2.1 of the License, or (at your option) any later version. 480 | 481 | This library is distributed in the hope that it will be useful, 482 | but WITHOUT ANY WARRANTY; without even the implied warranty of 483 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 484 | Lesser General Public License for more details. 485 | 486 | You should have received a copy of the GNU Lesser General Public 487 | License along with this library; if not, write to the Free Software 488 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 489 | USA 490 | 491 | Also add information on how to contact you by electronic and paper mail. 492 | 493 | You should also get your employer (if you work as a programmer) or your 494 | school, if any, to sign a "copyright disclaimer" for the library, if 495 | necessary. Here is a sample; alter the names: 496 | 497 | Yoyodyne, Inc., hereby disclaims all copyright interest in the 498 | library `Frob' (a library for tweaking knobs) written by James Random 499 | Hacker. 500 | 501 | , 1 April 1990 502 | Ty Coon, President of Vice 503 | 504 | That's all there is to it! 505 | -------------------------------------------------------------------------------- /SunDB.php: -------------------------------------------------------------------------------- 1 | 9 | * @copyright Copyright (c) 2020, Sunhill Technology 10 | * @license https://opensource.org/licenses/lgpl-3.0.html The GNU Lesser General Public License, version 3.0 11 | * @link https://github.com/msbatal/PHP-PDO-Database-Class 12 | * @version 2.6.8 13 | */ 14 | 15 | class SunDB 16 | { 17 | /** 18 | * Database credentials 19 | * @var array 20 | */ 21 | private $connectionParams = [ 22 | 'driver' => 'mysql', 23 | 'url' => null, 24 | 'host' => 'localhost', 25 | 'port' => '3306', 26 | 'dbname' => null, 27 | 'username' => null, 28 | 'password' => null, 29 | 'charset' => 'utf8' 30 | ]; 31 | 32 | /** 33 | * PDO instance 34 | * @var object 35 | */ 36 | private $pdo; 37 | 38 | /** 39 | * Static instance of self 40 | * @var object 41 | */ 42 | private static $instance; 43 | 44 | /** 45 | * Dynamic table control (on/off) 46 | * @var boolean 47 | */ 48 | private $checkTable = true; 49 | 50 | /** 51 | * Dynamic column control (on/off) 52 | * @var boolean 53 | */ 54 | private $checkColumn = true; 55 | 56 | /** 57 | * SQL query 58 | * @var string 59 | */ 60 | private $query; 61 | 62 | /** 63 | * Array that holds query result 64 | * @var array 65 | */ 66 | private $queryResult; 67 | 68 | /** 69 | * Action for query string 70 | * @var string 71 | */ 72 | private $action; 73 | 74 | /** 75 | * Record order to be selected 76 | * @var string 77 | */ 78 | private $which; 79 | 80 | /** 81 | * Table name 82 | * @var string 83 | */ 84 | private $table; 85 | 86 | /** 87 | * Array that holds Insert/Update values 88 | * @var array 89 | */ 90 | private $values = []; 91 | 92 | /** 93 | * Array that holds Where conditions (And) 94 | * @var array 95 | */ 96 | private $where = []; 97 | 98 | /** 99 | * Array that holds Where conditions (Or) 100 | * @var array 101 | */ 102 | private $orWhere = []; 103 | 104 | /** 105 | * Array that holds Where values 106 | * @var array 107 | */ 108 | private $whereValues = []; 109 | 110 | /** 111 | * Dynamic type list for Group By condition value 112 | * @var string 113 | */ 114 | private $groupBy; 115 | 116 | /** 117 | * Dynamic type list for Having condition value 118 | * @var string 119 | */ 120 | private $having; 121 | 122 | /** 123 | * Dynamic type list for Order By condition value 124 | * @var array 125 | */ 126 | private $orderBy = []; 127 | 128 | /** 129 | * Limit condition value for SQL query 130 | * @var string 131 | */ 132 | private $limit; 133 | 134 | /** 135 | * Value of the auto increment column 136 | * @var integer 137 | */ 138 | private $lastInsertId = 0; 139 | 140 | /** 141 | * Number of affected rows 142 | * @var integer 143 | */ 144 | private $rowCount = 0; 145 | 146 | /** 147 | * @param string|array|object $type 148 | * @param string $host 149 | * @param string $username 150 | * @param string $password 151 | * @param string $dbname 152 | * @param integer $port 153 | * @param string $charset 154 | */ 155 | public function __construct($type = null, $host = null, $username = null, $password = null, $dbname = null, $port = null, $charset = null) { 156 | set_exception_handler(function($exception) { 157 | echo '[SunClass] Exception: ' . $exception->getMessage(); 158 | }); 159 | if (is_array($type)) { // connect to db using parameters in the array 160 | $this->connectionParams = $type; 161 | } else if (is_object($type)) { // connect to db using pdo object 162 | $this->pdo = $type; 163 | } else { // connect to db using parameters 164 | foreach ($this->connectionParams as $key => $value) { 165 | if (isset($$key) && !is_null($$key)) { 166 | $this->connectionParams[$key] = $$key; 167 | } 168 | } 169 | } 170 | self::$instance = $this; 171 | } 172 | 173 | /** 174 | * Create PDO connection 175 | * 176 | * @throws exception 177 | * @return pdo 178 | */ 179 | private function connect() { 180 | if (empty($this->connectionParams['driver'])) { 181 | throw new \Exception('Database Driver is not set.'); 182 | } 183 | if ($this->connectionParams['driver'] == 'sqlite') { 184 | $connectionString = 'sqlite:' . $this->connectionParams['url']; 185 | $this->pdo = new \PDO($connectionString); 186 | } else if ($this->connectionParams['driver'] == 'mssql') { 187 | $connectionString = 'sqlsrv:Server=' . $this->connectionParams['host'] . ';Database=' . $this->connectionParams['dbname']; 188 | $this->pdo = new \PDO($connectionString, $this->connectionParams['username'], $this->connectionParams['password']); 189 | } else { 190 | $connectionString = $this->connectionParams['driver'] . ':'; 191 | $connectionParams = ['host', 'dbname', 'port', 'charset']; 192 | foreach ($connectionParams as $connectionParam) { 193 | if (!empty($this->connectionParams[$connectionParam])) { 194 | $connectionString .= $connectionParam . '=' . $this->connectionParams[$connectionParam] . ';'; 195 | } 196 | } 197 | $connectionString = rtrim($connectionString, ';'); 198 | $this->pdo = new \PDO($connectionString, $this->connectionParams['username'], $this->connectionParams['password']); 199 | } 200 | $this->pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); 201 | $this->pdo->setAttribute(\PDO::ATTR_DEFAULT_FETCH_MODE, \PDO::FETCH_ASSOC); 202 | $this->pdo->setAttribute(\PDO::ATTR_CURSOR, \PDO::CURSOR_SCROLL); 203 | $this->pdo->setAttribute(\PDO::ATTR_ORACLE_NULLS, \PDO::NULL_EMPTY_STRING); 204 | $this->pdo->setAttribute(\PDO::ATTR_PERSISTENT, true); 205 | if ($this->connectionParams['driver'] == 'mysql') { 206 | $this->pdo->setAttribute(\PDO::ATTR_EMULATE_PREPARES, true); 207 | $this->pdo->setAttribute(\PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true); 208 | $this->pdo->setAttribute(\PDO::MYSQL_ATTR_FOUND_ROWS, true); 209 | $this->pdo->setAttribute(\PDO::MYSQL_ATTR_INIT_COMMAND, 'SET CHARACTER SET utf8, NAMES utf8'); 210 | } 211 | if (!($this->pdo instanceof \PDO)) { 212 | throw new \Exception('This object is not an instance of PDO.'); 213 | } 214 | } 215 | 216 | /** 217 | * Check/Call PDO connection 218 | * 219 | * @throws exception 220 | * @return object 221 | */ 222 | private function pdo() { 223 | if (!$this->pdo) { 224 | $this->connect(); // call connection method 225 | } 226 | if (!($this->pdo instanceof \PDO)) { 227 | throw new \Exception('This object is not an instance of PDO.'); 228 | } 229 | return $this->pdo; 230 | } 231 | 232 | /** 233 | * Reset SunDB internal variables 234 | */ 235 | private function reset() { 236 | $this->query = ''; 237 | $this->action = ''; 238 | $this->which = ''; 239 | $this->table = ''; 240 | $this->values = []; 241 | $this->where = []; 242 | $this->orWhere = []; 243 | $this->whereValues = []; 244 | $this->groupBy = ''; 245 | $this->having = ''; 246 | $this->orderBy = []; 247 | $this->limit = ''; 248 | $this->lastInsertId = 0; 249 | $this->rowCount = 0; 250 | } 251 | 252 | /** 253 | * Check if table exists 254 | * 255 | * @param string $table 256 | * @throws exception 257 | * @return boolean 258 | */ 259 | private function checkTable($table = null) { 260 | $result = $this->pdo()->query("SHOW TABLES LIKE '" . $table . "'"); 261 | if ($result->rowCount() != 1) { 262 | throw new \Exception('Table "' . $table . '" does not exist.'); 263 | } 264 | } 265 | 266 | /** 267 | * Check if column exists 268 | * 269 | * @param string $column 270 | * @throws exception 271 | * @return boolean 272 | */ 273 | private function checkColumn($column = null) { 274 | $result = $this->pdo()->query("SELECT * FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = '" . $this->connectionParams['dbname'] . "' AND TABLE_NAME = '" . $this->table . "' AND COLUMN_NAME = '" . $column . "'"); 275 | if ($result->rowCount() != 1) { 276 | throw new \Exception('Column "' . $column . '" does not exist.'); 277 | } 278 | } 279 | 280 | /** 281 | * Build a SELECT part of the query 282 | * 283 | * @param string $table 284 | * @param string|array $columns 285 | * @return object 286 | */ 287 | public function select($table = null, $columns = '*') { 288 | $this->reset(); 289 | if ($this->connectionParams['driver'] != 'sqlite' && $this->checkTable) { 290 | $this->checkTable($table); 291 | } 292 | if (is_array($columns) && count($columns) > 0) { 293 | $columns = implode(',', $columns); 294 | } else { 295 | $columns = '*'; 296 | } 297 | $this->table = $table; 298 | $this->action = 'select'; 299 | $this->query = 'select ' . $columns . ' from `' . $table . '`'; 300 | return $this; 301 | } 302 | 303 | /** 304 | * Build an INSERT part of the query 305 | * 306 | * @param string $table 307 | * @param array $data 308 | * @throws exception 309 | * @return object 310 | */ 311 | public function insert($table = null, $data = []) { 312 | $this->reset(); 313 | if ($this->connectionParams['driver'] != 'sqlite' && $this->checkTable) { 314 | $this->checkTable($table); 315 | } 316 | if (!is_array($data) || count($data) <= 0) { 317 | throw new \Exception('Insert clause must contain an array data.'); 318 | } 319 | foreach ($data as $key => $value) { 320 | $keys[] = '`' . $key . '`'; 321 | $alias[] = '?'; 322 | if ($value == '' && $value <> '0') {$value = NULL;} 323 | $this->values[] = $value; 324 | } 325 | $strKeys = implode(',', $keys); 326 | $strAlias = implode(',', $alias); 327 | $this->table = $table; 328 | $this->action = 'insert'; 329 | if (is_int($keys[0])) { 330 | $this->query = 'insert into `' . $table . '` (' . $strKeys . ') values (' . $strAlias . ')'; 331 | } else { 332 | $this->query = 'insert into `' . $table . '` values (' . $strAlias . ')'; 333 | } 334 | return $this; 335 | } 336 | 337 | /** 338 | * Build an UPDATE part of the query 339 | * 340 | * @param string $table 341 | * @param string|array $data 342 | * @throws exception 343 | * @return object 344 | */ 345 | public function update($table = null, $data = []) { 346 | $this->reset(); 347 | if ($this->connectionParams['driver'] != 'sqlite' && $this->checkTable) { 348 | $this->checkTable($table); 349 | } 350 | if (!is_array($data) || count($data) <= 0) { 351 | throw new \Exception('Update clause must contain an array data.'); 352 | } 353 | foreach ($data as $key => $value) { 354 | $keys[] = '`' . $key . '`=?'; 355 | if ($value === NULL) {$value = '';} 356 | $this->values[] = $value; 357 | } 358 | $keys = implode(',', $keys); 359 | $this->table = $table; 360 | $this->action = 'update'; 361 | $this->query = 'update `' . $table . '` set ' . $keys; 362 | return $this; 363 | } 364 | 365 | /** 366 | * Build a DELETE part of the query 367 | * 368 | * @param string $table 369 | * @return object 370 | */ 371 | public function delete($table = null) { 372 | $this->reset(); 373 | if ($this->connectionParams['driver'] != 'sqlite' && $this->checkTable) { 374 | $this->checkTable($table); 375 | } 376 | $this->table = $table; 377 | $this->action = 'delete'; 378 | $this->query = 'delete from `' . $table . '`'; 379 | return $this; 380 | } 381 | 382 | /** 383 | * Build the AND WHERE part of the query string 384 | * 385 | * @param string $column 386 | * @param string $value 387 | * @param string $operator 388 | * @param string $condition 389 | * @throws exception 390 | * @return object 391 | */ 392 | public function where($column = null, $value = null, $operator = null, $condition = 'and') { 393 | if (empty($value) && empty($operator)) { 394 | $this->where[] = $condition . ' (' . $column . ') '; 395 | } else { 396 | if (empty($column) || empty($operator)) { 397 | throw new \Exception('Where clause must contain a value and operator.'); 398 | } 399 | if ($this->connectionParams['driver'] != 'sqlite' && $this->checkColumn) { 400 | $this->checkColumn($column); 401 | } 402 | if ($operator == 'like' || $operator == 'not like') { 403 | $this->where[] = $condition . ' (`' . $column . '` ' . $operator . ' ?) '; 404 | if ($value === NULL) {$value = '';} 405 | $this->whereValues[] = $value; 406 | } else if ($operator == 'between' || $operator == 'not between') { 407 | if (!empty($value[0]) && !empty($value[1])) { 408 | $this->whereValues[] = $value[0]; 409 | $this->whereValues[] = $value[1]; 410 | $this->where[] = $condition . ' (`' . $column . '` ' . $operator . ' ? and ?) '; 411 | } 412 | } else if ($operator == 'in' || $operator == 'not in') { 413 | if (is_array($value) && count($value)>0) { 414 | foreach ($value as $val) { 415 | $values[] = '?'; 416 | $this->whereValues[] = $val; 417 | } 418 | $this->where[] = $condition . ' (`' . $column . '` ' . $operator . ' (' . implode(',', $values) . ')) '; 419 | } 420 | } else { 421 | $this->where[] = $condition . ' (`' . $column . '` ' . $operator . '?) '; 422 | if ($value === NULL) {$value = '';} 423 | $this->whereValues[] = $value; 424 | } 425 | } 426 | return $this; 427 | } 428 | 429 | /** 430 | * Build the OR WHERE part of the query string 431 | * 432 | * @param string $column 433 | * @param string $value 434 | * @param string $operator 435 | * @throws exception 436 | * @return object 437 | */ 438 | public function orWhere($column = null, $value = null, $operator = null) { 439 | return $this->where($column, $value, $operator, 'or'); 440 | } 441 | 442 | /** 443 | * Build the GROUP BY part of the WHERE statement 444 | * 445 | * @param string $column 446 | * @throws exception 447 | * @return object 448 | */ 449 | public function groupBy($column = null, $function = null) { 450 | if (empty($column)) { 451 | throw new \Exception('Group By clause must contain a column name.'); 452 | } 453 | if ($this->connectionParams['driver'] != 'sqlite' && $this->checkColumn) { 454 | $this->checkColumn($column); 455 | } 456 | if (!empty($function)) { 457 | $this->groupBy = $function . '(`' . $column . '`)'; 458 | } else { 459 | $this->groupBy = '`' . $column . '`'; 460 | } 461 | return $this; 462 | } 463 | 464 | /** 465 | * Build the HAVING part of the GROUP BY clause 466 | * 467 | * @param string $value 468 | * @throws exception 469 | * @return object 470 | */ 471 | public function having($value = null) { 472 | if (empty($value)) { 473 | throw new \Exception('Having clause must contain a value.'); 474 | } 475 | if ($this->connectionParams['driver'] != 'sqlite') { 476 | $this->having = $value; 477 | } 478 | return $this; 479 | } 480 | 481 | /** 482 | * Build the ORDER BY part of the WHERE statement 483 | * 484 | * @param string $column 485 | * @param string $order 486 | * @throws exception 487 | * @return object 488 | */ 489 | public function orderBy($column = null, $order = null) { 490 | if (strpos(strtoupper($column), 'RAND') !== false && empty($order)) { 491 | $this->orderBy[] = $column; 492 | } else { 493 | if (empty($column) || !in_array(strtoupper($order), ['ASC', 'DESC'], true)) { 494 | throw new \Exception('Order By clause must contain a column name and order value.'); 495 | } 496 | if ($this->connectionParams['driver'] != 'sqlite' && $this->checkColumn) { 497 | $this->checkColumn($column); 498 | } 499 | $this->orderBy[] = '`' . $column . '` ' . $order; 500 | } 501 | return $this; 502 | } 503 | 504 | /** 505 | * Build the LIMIT part of the WHERE statement 506 | * 507 | * @param integer $start 508 | * @param integer $page 509 | * @throws exception 510 | * @return object 511 | */ 512 | public function limit($start = 0, $page = null) { 513 | if (!is_int($start)) { 514 | throw new \Exception('Limit clause must be 0 or above.'); 515 | } 516 | if (empty($page) || !is_int($page)) { 517 | $page = $start; 518 | $start = 0; 519 | } 520 | $this->limit = $start . ',' . $page; 521 | return $this; 522 | } 523 | 524 | /** 525 | * Perform SQL query 526 | * 527 | * @param string $query 528 | * @param array $values 529 | * @return object 530 | */ 531 | public function rawQuery($query = null, $values = []) { 532 | $this->reset(); 533 | if (is_array($values) && count($values) > 0) { 534 | foreach ($values as $value) { 535 | if ($value === NULL) {$value = '';} 536 | $this->values[] = $value; 537 | } 538 | } 539 | $this->action = 'query'; 540 | $this->query = $query; 541 | return $this; 542 | } 543 | 544 | /** 545 | * Return the first record 546 | * 547 | * @return object 548 | */ 549 | public function first() { 550 | $this->which = 'first'; 551 | return $this; 552 | } 553 | 554 | /** 555 | * Return the last record 556 | * 557 | * @return object 558 | */ 559 | public function last() { 560 | $this->which = 'last'; 561 | return $this; 562 | } 563 | 564 | /** 565 | * Return a random record 566 | * 567 | * @return object 568 | */ 569 | public function random() { 570 | $this->which = 'random'; 571 | return $this; 572 | } 573 | 574 | /** 575 | * Return all records 576 | * 577 | * @return object 578 | */ 579 | public function all() { 580 | $this->which = 'all'; 581 | return $this; 582 | } 583 | 584 | /** 585 | * Compile/Execute the SQL query and return the result 586 | * 587 | * @throws exception 588 | * @return array|object|boolean 589 | */ 590 | public function run() { 591 | if (is_array($this->where) && count($this->where) > 0) { // add Where condition 592 | $count = 0; 593 | $clnWhere = array(); 594 | foreach ($this->where as $key => $value) { // remove first And/OR part 595 | $count++; 596 | if ($count == 1) { 597 | $clnWhere[] = ltrim(ltrim($value, 'or'), 'and'); 598 | } else { 599 | $clnWhere[] = $value; 600 | } 601 | } 602 | $this->query .= ' where ' . implode('', $clnWhere) . ''; 603 | } 604 | if (!empty($this->groupBy)) { // add Group By condition 605 | $this->query .= ' group by ' . $this->groupBy; 606 | } 607 | if (!empty($this->groupBy) && !empty($this->having)) { // add Having condition 608 | $this->query .= ' having ' . $this->having; 609 | } 610 | if (is_array($this->orderBy) && count($this->orderBy) > 0) { // add Order By condition 611 | $this->query .= ' order by ' . implode(',', $this->orderBy); 612 | } 613 | if (!empty($this->limit)) { // add Limit condition 614 | $this->query .= ' limit ' . $this->limit; 615 | } 616 | switch ($this->action) { 617 | case 'select': // run Select query and return the result (array|object) 618 | $query = $this->pdo()->prepare($this->query); 619 | $result = $query->execute($this->whereValues); 620 | $this->queryResult = $query->fetchAll(); 621 | $this->rowCount = $query->rowCount(); // selected row count 622 | $query->closeCursor(); unset($query); 623 | if ($this->which == 'first') { 624 | return $this->queryResult[0]; // return only first record 625 | } else if ($this->which == 'last') { 626 | return end($this->queryResult); // return only last record 627 | } else if ($this->which == 'random') { 628 | $index = rand(0, $this->rowCount - 1); 629 | return $this->queryResult[$index]; // return a random record 630 | } else { 631 | return $this->queryResult; // return all records 632 | } 633 | break; 634 | case 'insert': // run Insert query and return the result (bool) 635 | $query = $this->pdo()->prepare($this->query); 636 | $result = $query->execute($this->values); 637 | $this->rowCount = $query->rowCount(); // inserted row count 638 | $this->lastInsertId = $this->pdo()->lastInsertId(); // auto increment value 639 | $query->closeCursor(); unset($query); 640 | return $result; 641 | break; 642 | case 'update': // run Update query and return the result (bool) 643 | $query = $this->pdo()->prepare($this->query); 644 | $result = $query->execute(array_merge($this->values,$this->whereValues)); 645 | $this->rowCount = $query->rowCount(); // updated row count 646 | $query->closeCursor(); unset($query); 647 | return $result; 648 | break; 649 | case 'delete': // run Delete query and return the result (bool) 650 | $query = $this->pdo()->prepare($this->query); 651 | $result = $query->execute($this->whereValues); 652 | $this->rowCount = $query->rowCount(); // deleted row count 653 | $query->closeCursor(); unset($query); 654 | return $result; 655 | break; 656 | case 'query': // run Raw query and return the result (bool) 657 | $query = $this->pdo()->prepare($this->query); 658 | $result = $query->execute($this->values); 659 | $this->rowCount = $query->rowCount(); // affected row count 660 | $exp = explode(' ', $this->query); // for determine the action 661 | if ($exp[0] == 'select') { 662 | $this->queryResult = $query->fetchAll(); 663 | $query->closeCursor(); unset($query); 664 | return $this->queryResult; 665 | } else { 666 | $query->closeCursor(); unset($query); 667 | return $result; 668 | } 669 | break; 670 | default: 671 | throw new \Exception('Command "' . $this->action . '" is not allowed.'); 672 | break; 673 | } 674 | } 675 | 676 | /** 677 | * Perform backup the database and print/download backup file 678 | * 679 | * @param string $fileName 680 | * @param string $action 681 | * @param array $excludeTables 682 | * @throws exception 683 | * @return string|file 684 | */ 685 | public function backup($fileName = null, $action = null, $excludeTables = []) { 686 | if ($this->connectionParams['driver'] == 'sqlite') { 687 | throw new \Exception('SQLite database backup is not allowed. Download "'.$this->connectionParams['url'].'" file directly.'); 688 | } 689 | if (empty($fileName)) {$fileName = 'SunDB-Backup-'.date("dmYHis").'.sql';} else {$fileName .= '.sql';} // define file name 690 | if (empty($action)) {$action = 'save';} // default action 691 | if ($action == 'save') { // if selected the Save method 692 | header('Content-disposition: attachment; filename='.$fileName); 693 | header('Content-type: application/force-download'); // header for download 694 | } 695 | $show = $this->pdo()->query('show tables')->fetchAll(); // list all tables 696 | $tables = []; 697 | foreach ($show as $rows) { 698 | $content = []; 699 | $table = reset($rows); 700 | if (!in_array($table, $excludeTables)) { 701 | $create = $this->pdo()->query("show create table `$table`")->fetchAll(); // list table structures 702 | $content[] = $create[0]['Create Table'].";\n"; // select Create Table structure 703 | $query = $this->pdo()->prepare("select * from `$table`"); // list all values in selected table 704 | $query->execute(array()); 705 | $select = $query->fetchAll(); 706 | if ($query->rowCount() > 0) { 707 | foreach ($select as $row) { 708 | if (count($row) < 1) {continue;} 709 | $header = "INSERT INTO `$table` VALUES ('"; // add Insert query 710 | $body = implode("', '", array_values($row)); // add listed values 711 | $footer = "');"; 712 | $content[] = $header.$body.$footer; 713 | } 714 | if (count($content) < 1) {continue;} 715 | $tables[$table] = implode("\n", $content); 716 | } 717 | } 718 | } 719 | if ($action == 'save') { 720 | echo "# SunDB Database Backup File\n# Backup Date: ".date("Y-m-d H:i:s")."\n# Backup File: ".$fileName."\n\n\n"; 721 | echo implode("\n\n", array_values($tables)); 722 | } else { // if selected the Show method 723 | echo nl2br(implode('

', array_values($tables))); 724 | } 725 | } 726 | 727 | /** 728 | * Analyze, check, optimize and repair tables 729 | * 730 | * @throws exception 731 | * @return boolean 732 | */ 733 | public function maintenance() { 734 | $tables = []; 735 | $show = $this->pdo()->query('show tables')->fetchAll(); // list tables 736 | foreach ($show as $rows) { 737 | if (!is_array($rows)) continue; 738 | if (count($rows) < 1) continue; 739 | $tables[] = '`' . $this->connectionParams['dbname'] . '`.' . '`' . reset($rows) . '`'; 740 | } 741 | if (count($tables) > 0) { 742 | $tables = implode(', ', $tables); 743 | try { 744 | $analyze = $this->pdo()->query("analyze table $tables"); // analyze tables 745 | $check = $this->pdo()->query("check table $tables"); // check tables 746 | $optimize = $this->pdo()->query("optimize table $tables"); // optimize tables 747 | $repair = $this->pdo()->query("repair table $tables"); // repair tables 748 | } catch (Exception $e) { 749 | throw new \Exception($e->getMessage()); 750 | } 751 | if ($analyze && $check && $optimize && $repair) { 752 | return true; 753 | } else { 754 | return false; 755 | } 756 | } else { 757 | return false; 758 | } 759 | } 760 | 761 | /** 762 | * Return a static instance of connection 763 | * 764 | * @return object 765 | */ 766 | public static function getInstance() { 767 | return self::$instance; 768 | } 769 | 770 | /** 771 | * Show/Print executed query as a string 772 | */ 773 | public function showQuery() { 774 | if (empty($this->query)) { 775 | echo '[SunDB] Error: SQL query not found.'; 776 | } else { 777 | if ($this->action == 'query') { 778 | echo '

[SunDB] Query: ' . $this->query . '

'; 779 | } else { 780 | $queryArray = explode('?', $this->query); 781 | for ($i = 0; $i < count($queryArray)-1; $i++) { 782 | $result .= $queryArray[$i] . "'" . $this->whereValues[$i] . "'"; 783 | } 784 | $result .= $queryArray[count($queryArray)-1]; 785 | echo '

[SunDB] Query: ' . $result . '

'; 786 | } 787 | } 788 | } 789 | 790 | /** 791 | * Return the total record count in a table 792 | * 793 | * @param string $table 794 | * @return integer 795 | */ 796 | public function tableCount($table = null) { 797 | if ($this->connectionParams['driver'] != 'sqlite' && $this->checkTable) { 798 | $this->checkTable($table); 799 | } 800 | $query = $this->pdo()->query('select count(*) as total from ' . $table)->fetchAll(); 801 | return (int) $query[0]['total']; 802 | } 803 | 804 | /** 805 | * Return the number of affected rows 806 | * 807 | * @return integer 808 | */ 809 | public function rowCount(){ 810 | return (int) $this->rowCount; 811 | } 812 | 813 | /** 814 | * Return the value of the auto increment column 815 | * 816 | * @return integer 817 | */ 818 | public function lastInsertId() { 819 | return (int) $this->lastInsertId; 820 | } 821 | 822 | /** 823 | * Generate user defined function call 824 | * 825 | * @param string $func 826 | * @param string $param 827 | * @throws exception 828 | * @return string 829 | */ 830 | public function func($func = null, $param = null) { 831 | if (empty($func) || empty($param)) { 832 | throw new \Exception('Missing parameters for "' . $func . '" function.'); 833 | } 834 | return $func($param); 835 | } 836 | 837 | } 838 | 839 | ?> 840 | -------------------------------------------------------------------------------- /test/SunDB.php: -------------------------------------------------------------------------------- 1 | 9 | * @copyright Copyright (c) 2020, Sunhill Technology 10 | * @license https://opensource.org/licenses/lgpl-3.0.html The GNU Lesser General Public License, version 3.0 11 | * @link https://github.com/msbatal/PHP-PDO-Database-Class 12 | * @version 2.6.8 13 | */ 14 | 15 | class SunDB 16 | { 17 | /** 18 | * Database credentials 19 | * @var array 20 | */ 21 | private $connectionParams = [ 22 | 'driver' => 'mysql', 23 | 'url' => null, 24 | 'host' => 'localhost', 25 | 'port' => '3306', 26 | 'dbname' => null, 27 | 'username' => null, 28 | 'password' => null, 29 | 'charset' => 'utf8' 30 | ]; 31 | 32 | /** 33 | * PDO instance 34 | * @var object 35 | */ 36 | private $pdo; 37 | 38 | /** 39 | * Static instance of self 40 | * @var object 41 | */ 42 | private static $instance; 43 | 44 | /** 45 | * Dynamic table control (on/off) 46 | * @var boolean 47 | */ 48 | private $checkTable = true; 49 | 50 | /** 51 | * Dynamic column control (on/off) 52 | * @var boolean 53 | */ 54 | private $checkColumn = true; 55 | 56 | /** 57 | * SQL query 58 | * @var string 59 | */ 60 | private $query; 61 | 62 | /** 63 | * Array that holds query result 64 | * @var array 65 | */ 66 | private $queryResult; 67 | 68 | /** 69 | * Action for query string 70 | * @var string 71 | */ 72 | private $action; 73 | 74 | /** 75 | * Record order to be selected 76 | * @var string 77 | */ 78 | private $which; 79 | 80 | /** 81 | * Table name 82 | * @var string 83 | */ 84 | private $table; 85 | 86 | /** 87 | * Array that holds Insert/Update values 88 | * @var array 89 | */ 90 | private $values = []; 91 | 92 | /** 93 | * Array that holds Where conditions (And) 94 | * @var array 95 | */ 96 | private $where = []; 97 | 98 | /** 99 | * Array that holds Where conditions (Or) 100 | * @var array 101 | */ 102 | private $orWhere = []; 103 | 104 | /** 105 | * Array that holds Where values 106 | * @var array 107 | */ 108 | private $whereValues = []; 109 | 110 | /** 111 | * Dynamic type list for Group By condition value 112 | * @var string 113 | */ 114 | private $groupBy; 115 | 116 | /** 117 | * Dynamic type list for Having condition value 118 | * @var string 119 | */ 120 | private $having; 121 | 122 | /** 123 | * Dynamic type list for Order By condition value 124 | * @var array 125 | */ 126 | private $orderBy = []; 127 | 128 | /** 129 | * Limit condition value for SQL query 130 | * @var string 131 | */ 132 | private $limit; 133 | 134 | /** 135 | * Value of the auto increment column 136 | * @var integer 137 | */ 138 | private $lastInsertId = 0; 139 | 140 | /** 141 | * Number of affected rows 142 | * @var integer 143 | */ 144 | private $rowCount = 0; 145 | 146 | /** 147 | * @param string|array|object $type 148 | * @param string $host 149 | * @param string $username 150 | * @param string $password 151 | * @param string $dbname 152 | * @param integer $port 153 | * @param string $charset 154 | */ 155 | public function __construct($type = null, $host = null, $username = null, $password = null, $dbname = null, $port = null, $charset = null) { 156 | set_exception_handler(function($exception) { 157 | echo '[SunClass] Exception: ' . $exception->getMessage(); 158 | }); 159 | if (is_array($type)) { // connect to db using parameters in the array 160 | $this->connectionParams = $type; 161 | } else if (is_object($type)) { // connect to db using pdo object 162 | $this->pdo = $type; 163 | } else { // connect to db using parameters 164 | foreach ($this->connectionParams as $key => $value) { 165 | if (isset($$key) && !is_null($$key)) { 166 | $this->connectionParams[$key] = $$key; 167 | } 168 | } 169 | } 170 | self::$instance = $this; 171 | } 172 | 173 | /** 174 | * Create PDO connection 175 | * 176 | * @throws exception 177 | * @return pdo 178 | */ 179 | private function connect() { 180 | if (empty($this->connectionParams['driver'])) { 181 | throw new \Exception('Database Driver is not set.'); 182 | } 183 | if ($this->connectionParams['driver'] == 'sqlite') { 184 | $connectionString = 'sqlite:' . $this->connectionParams['url']; 185 | $this->pdo = new \PDO($connectionString); 186 | } else if ($this->connectionParams['driver'] == 'mssql') { 187 | $connectionString = 'sqlsrv:Server=' . $this->connectionParams['host'] . ';Database=' . $this->connectionParams['dbname']; 188 | $this->pdo = new \PDO($connectionString, $this->connectionParams['username'], $this->connectionParams['password']); 189 | } else { 190 | $connectionString = $this->connectionParams['driver'] . ':'; 191 | $connectionParams = ['host', 'dbname', 'port', 'charset']; 192 | foreach ($connectionParams as $connectionParam) { 193 | if (!empty($this->connectionParams[$connectionParam])) { 194 | $connectionString .= $connectionParam . '=' . $this->connectionParams[$connectionParam] . ';'; 195 | } 196 | } 197 | $connectionString = rtrim($connectionString, ';'); 198 | $this->pdo = new \PDO($connectionString, $this->connectionParams['username'], $this->connectionParams['password']); 199 | } 200 | $this->pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); 201 | $this->pdo->setAttribute(\PDO::ATTR_DEFAULT_FETCH_MODE, \PDO::FETCH_ASSOC); 202 | $this->pdo->setAttribute(\PDO::ATTR_CURSOR, \PDO::CURSOR_SCROLL); 203 | $this->pdo->setAttribute(\PDO::ATTR_ORACLE_NULLS, \PDO::NULL_EMPTY_STRING); 204 | $this->pdo->setAttribute(\PDO::ATTR_PERSISTENT, true); 205 | if ($this->connectionParams['driver'] == 'mysql') { 206 | $this->pdo->setAttribute(\PDO::ATTR_EMULATE_PREPARES, true); 207 | $this->pdo->setAttribute(\PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true); 208 | $this->pdo->setAttribute(\PDO::MYSQL_ATTR_FOUND_ROWS, true); 209 | $this->pdo->setAttribute(\PDO::MYSQL_ATTR_INIT_COMMAND, 'SET CHARACTER SET utf8, NAMES utf8'); 210 | } 211 | if (!($this->pdo instanceof \PDO)) { 212 | throw new \Exception('This object is not an instance of PDO.'); 213 | } 214 | } 215 | 216 | /** 217 | * Check/Call PDO connection 218 | * 219 | * @throws exception 220 | * @return object 221 | */ 222 | private function pdo() { 223 | if (!$this->pdo) { 224 | $this->connect(); // call connection method 225 | } 226 | if (!($this->pdo instanceof \PDO)) { 227 | throw new \Exception('This object is not an instance of PDO.'); 228 | } 229 | return $this->pdo; 230 | } 231 | 232 | /** 233 | * Reset SunDB internal variables 234 | */ 235 | private function reset() { 236 | $this->query = ''; 237 | $this->action = ''; 238 | $this->which = ''; 239 | $this->table = ''; 240 | $this->values = []; 241 | $this->where = []; 242 | $this->orWhere = []; 243 | $this->whereValues = []; 244 | $this->groupBy = ''; 245 | $this->having = ''; 246 | $this->orderBy = []; 247 | $this->limit = ''; 248 | $this->lastInsertId = 0; 249 | $this->rowCount = 0; 250 | } 251 | 252 | /** 253 | * Check if table exists 254 | * 255 | * @param string $table 256 | * @throws exception 257 | * @return boolean 258 | */ 259 | private function checkTable($table = null) { 260 | $result = $this->pdo()->query("SHOW TABLES LIKE '" . $table . "'"); 261 | if ($result->rowCount() != 1) { 262 | throw new \Exception('Table "' . $table . '" does not exist.'); 263 | } 264 | } 265 | 266 | /** 267 | * Check if column exists 268 | * 269 | * @param string $column 270 | * @throws exception 271 | * @return boolean 272 | */ 273 | private function checkColumn($column = null) { 274 | $result = $this->pdo()->query("SELECT * FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = '" . $this->connectionParams['dbname'] . "' AND TABLE_NAME = '" . $this->table . "' AND COLUMN_NAME = '" . $column . "'"); 275 | if ($result->rowCount() != 1) { 276 | throw new \Exception('Column "' . $column . '" does not exist.'); 277 | } 278 | } 279 | 280 | /** 281 | * Build a SELECT part of the query 282 | * 283 | * @param string $table 284 | * @param string|array $columns 285 | * @return object 286 | */ 287 | public function select($table = null, $columns = '*') { 288 | $this->reset(); 289 | if ($this->connectionParams['driver'] != 'sqlite' && $this->checkTable) { 290 | $this->checkTable($table); 291 | } 292 | if (is_array($columns) && count($columns) > 0) { 293 | $columns = implode(',', $columns); 294 | } else { 295 | $columns = '*'; 296 | } 297 | $this->table = $table; 298 | $this->action = 'select'; 299 | $this->query = 'select ' . $columns . ' from `' . $table . '`'; 300 | return $this; 301 | } 302 | 303 | /** 304 | * Build an INSERT part of the query 305 | * 306 | * @param string $table 307 | * @param array $data 308 | * @throws exception 309 | * @return object 310 | */ 311 | public function insert($table = null, $data = []) { 312 | $this->reset(); 313 | if ($this->connectionParams['driver'] != 'sqlite' && $this->checkTable) { 314 | $this->checkTable($table); 315 | } 316 | if (!is_array($data) || count($data) <= 0) { 317 | throw new \Exception('Insert clause must contain an array data.'); 318 | } 319 | foreach ($data as $key => $value) { 320 | $keys[] = '`' . $key . '`'; 321 | $alias[] = '?'; 322 | if ($value == '' && $value <> '0') {$value = NULL;} 323 | $this->values[] = $value; 324 | } 325 | $strKeys = implode(',', $keys); 326 | $strAlias = implode(',', $alias); 327 | $this->table = $table; 328 | $this->action = 'insert'; 329 | if (is_int($keys[0])) { 330 | $this->query = 'insert into `' . $table . '` (' . $strKeys . ') values (' . $strAlias . ')'; 331 | } else { 332 | $this->query = 'insert into `' . $table . '` values (' . $strAlias . ')'; 333 | } 334 | return $this; 335 | } 336 | 337 | /** 338 | * Build an UPDATE part of the query 339 | * 340 | * @param string $table 341 | * @param string|array $data 342 | * @throws exception 343 | * @return object 344 | */ 345 | public function update($table = null, $data = []) { 346 | $this->reset(); 347 | if ($this->connectionParams['driver'] != 'sqlite' && $this->checkTable) { 348 | $this->checkTable($table); 349 | } 350 | if (!is_array($data) || count($data) <= 0) { 351 | throw new \Exception('Update clause must contain an array data.'); 352 | } 353 | foreach ($data as $key => $value) { 354 | $keys[] = '`' . $key . '`=?'; 355 | if ($value === NULL) {$value = '';} 356 | $this->values[] = $value; 357 | } 358 | $keys = implode(',', $keys); 359 | $this->table = $table; 360 | $this->action = 'update'; 361 | $this->query = 'update `' . $table . '` set ' . $keys; 362 | return $this; 363 | } 364 | 365 | /** 366 | * Build a DELETE part of the query 367 | * 368 | * @param string $table 369 | * @return object 370 | */ 371 | public function delete($table = null) { 372 | $this->reset(); 373 | if ($this->connectionParams['driver'] != 'sqlite' && $this->checkTable) { 374 | $this->checkTable($table); 375 | } 376 | $this->table = $table; 377 | $this->action = 'delete'; 378 | $this->query = 'delete from `' . $table . '`'; 379 | return $this; 380 | } 381 | 382 | /** 383 | * Build the AND WHERE part of the query string 384 | * 385 | * @param string $column 386 | * @param string $value 387 | * @param string $operator 388 | * @param string $condition 389 | * @throws exception 390 | * @return object 391 | */ 392 | public function where($column = null, $value = null, $operator = null, $condition = 'and') { 393 | if (empty($value) && empty($operator)) { 394 | $this->where[] = $condition . ' (' . $column . ') '; 395 | } else { 396 | if (empty($column) || empty($operator)) { 397 | throw new \Exception('Where clause must contain a value and operator.'); 398 | } 399 | if ($this->connectionParams['driver'] != 'sqlite' && $this->checkColumn) { 400 | $this->checkColumn($column); 401 | } 402 | if ($operator == 'like' || $operator == 'not like') { 403 | $this->where[] = $condition . ' (`' . $column . '` ' . $operator . ' ?) '; 404 | if ($value === NULL) {$value = '';} 405 | $this->whereValues[] = $value; 406 | } else if ($operator == 'between' || $operator == 'not between') { 407 | if (!empty($value[0]) && !empty($value[1])) { 408 | $this->whereValues[] = $value[0]; 409 | $this->whereValues[] = $value[1]; 410 | $this->where[] = $condition . ' (`' . $column . '` ' . $operator . ' ? and ?) '; 411 | } 412 | } else if ($operator == 'in' || $operator == 'not in') { 413 | if (is_array($value) && count($value)>0) { 414 | foreach ($value as $val) { 415 | $values[] = '?'; 416 | $this->whereValues[] = $val; 417 | } 418 | $this->where[] = $condition . ' (`' . $column . '` ' . $operator . ' (' . implode(',', $values) . ')) '; 419 | } 420 | } else { 421 | $this->where[] = $condition . ' (`' . $column . '` ' . $operator . '?) '; 422 | if ($value === NULL) {$value = '';} 423 | $this->whereValues[] = $value; 424 | } 425 | } 426 | return $this; 427 | } 428 | 429 | /** 430 | * Build the OR WHERE part of the query string 431 | * 432 | * @param string $column 433 | * @param string $value 434 | * @param string $operator 435 | * @throws exception 436 | * @return object 437 | */ 438 | public function orWhere($column = null, $value = null, $operator = null) { 439 | return $this->where($column, $value, $operator, 'or'); 440 | } 441 | 442 | /** 443 | * Build the GROUP BY part of the WHERE statement 444 | * 445 | * @param string $column 446 | * @throws exception 447 | * @return object 448 | */ 449 | public function groupBy($column = null, $function = null) { 450 | if (empty($column)) { 451 | throw new \Exception('Group By clause must contain a column name.'); 452 | } 453 | if ($this->connectionParams['driver'] != 'sqlite' && $this->checkColumn) { 454 | $this->checkColumn($column); 455 | } 456 | if (!empty($function)) { 457 | $this->groupBy = $function . '(`' . $column . '`)'; 458 | } else { 459 | $this->groupBy = '`' . $column . '`'; 460 | } 461 | return $this; 462 | } 463 | 464 | /** 465 | * Build the HAVING part of the GROUP BY clause 466 | * 467 | * @param string $value 468 | * @throws exception 469 | * @return object 470 | */ 471 | public function having($value = null) { 472 | if (empty($value)) { 473 | throw new \Exception('Having clause must contain a value.'); 474 | } 475 | if ($this->connectionParams['driver'] != 'sqlite') { 476 | $this->having = $value; 477 | } 478 | return $this; 479 | } 480 | 481 | /** 482 | * Build the ORDER BY part of the WHERE statement 483 | * 484 | * @param string $column 485 | * @param string $order 486 | * @throws exception 487 | * @return object 488 | */ 489 | public function orderBy($column = null, $order = null) { 490 | if (strpos(strtoupper($column), 'RAND') !== false && empty($order)) { 491 | $this->orderBy[] = $column; 492 | } else { 493 | if (empty($column) || !in_array(strtoupper($order), ['ASC', 'DESC'], true)) { 494 | throw new \Exception('Order By clause must contain a column name and order value.'); 495 | } 496 | if ($this->connectionParams['driver'] != 'sqlite' && $this->checkColumn) { 497 | $this->checkColumn($column); 498 | } 499 | $this->orderBy[] = '`' . $column . '` ' . $order; 500 | } 501 | return $this; 502 | } 503 | 504 | /** 505 | * Build the LIMIT part of the WHERE statement 506 | * 507 | * @param integer $start 508 | * @param integer $page 509 | * @throws exception 510 | * @return object 511 | */ 512 | public function limit($start = 0, $page = null) { 513 | if (!is_int($start)) { 514 | throw new \Exception('Limit clause must be 0 or above.'); 515 | } 516 | if (empty($page) || !is_int($page)) { 517 | $page = $start; 518 | $start = 0; 519 | } 520 | $this->limit = $start . ',' . $page; 521 | return $this; 522 | } 523 | 524 | /** 525 | * Perform SQL query 526 | * 527 | * @param string $query 528 | * @param array $values 529 | * @return object 530 | */ 531 | public function rawQuery($query = null, $values = []) { 532 | $this->reset(); 533 | if (is_array($values) && count($values) > 0) { 534 | foreach ($values as $value) { 535 | if ($value === NULL) {$value = '';} 536 | $this->values[] = $value; 537 | } 538 | } 539 | $this->action = 'query'; 540 | $this->query = $query; 541 | return $this; 542 | } 543 | 544 | /** 545 | * Return the first record 546 | * 547 | * @return object 548 | */ 549 | public function first() { 550 | $this->which = 'first'; 551 | return $this; 552 | } 553 | 554 | /** 555 | * Return the last record 556 | * 557 | * @return object 558 | */ 559 | public function last() { 560 | $this->which = 'last'; 561 | return $this; 562 | } 563 | 564 | /** 565 | * Return a random record 566 | * 567 | * @return object 568 | */ 569 | public function random() { 570 | $this->which = 'random'; 571 | return $this; 572 | } 573 | 574 | /** 575 | * Return all records 576 | * 577 | * @return object 578 | */ 579 | public function all() { 580 | $this->which = 'all'; 581 | return $this; 582 | } 583 | 584 | /** 585 | * Compile/Execute the SQL query and return the result 586 | * 587 | * @throws exception 588 | * @return array|object|boolean 589 | */ 590 | public function run() { 591 | if (is_array($this->where) && count($this->where) > 0) { // add Where condition 592 | $count = 0; 593 | $clnWhere = array(); 594 | foreach ($this->where as $key => $value) { // remove first And/OR part 595 | $count++; 596 | if ($count == 1) { 597 | $clnWhere[] = ltrim(ltrim($value, 'or'), 'and'); 598 | } else { 599 | $clnWhere[] = $value; 600 | } 601 | } 602 | $this->query .= ' where ' . implode('', $clnWhere) . ''; 603 | } 604 | if (!empty($this->groupBy)) { // add Group By condition 605 | $this->query .= ' group by ' . $this->groupBy; 606 | } 607 | if (!empty($this->groupBy) && !empty($this->having)) { // add Having condition 608 | $this->query .= ' having ' . $this->having; 609 | } 610 | if (is_array($this->orderBy) && count($this->orderBy) > 0) { // add Order By condition 611 | $this->query .= ' order by ' . implode(',', $this->orderBy); 612 | } 613 | if (!empty($this->limit)) { // add Limit condition 614 | $this->query .= ' limit ' . $this->limit; 615 | } 616 | switch ($this->action) { 617 | case 'select': // run Select query and return the result (array|object) 618 | $query = $this->pdo()->prepare($this->query); 619 | $result = $query->execute($this->whereValues); 620 | $this->queryResult = $query->fetchAll(); 621 | $this->rowCount = $query->rowCount(); // selected row count 622 | $query->closeCursor(); unset($query); 623 | if ($this->which == 'first') { 624 | return $this->queryResult[0]; // return only first record 625 | } else if ($this->which == 'last') { 626 | return end($this->queryResult); // return only last record 627 | } else if ($this->which == 'random') { 628 | $index = rand(0, $this->rowCount - 1); 629 | return $this->queryResult[$index]; // return a random record 630 | } else { 631 | return $this->queryResult; // return all records 632 | } 633 | break; 634 | case 'insert': // run Insert query and return the result (bool) 635 | $query = $this->pdo()->prepare($this->query); 636 | $result = $query->execute($this->values); 637 | $this->rowCount = $query->rowCount(); // inserted row count 638 | $this->lastInsertId = $this->pdo()->lastInsertId(); // auto increment value 639 | $query->closeCursor(); unset($query); 640 | return $result; 641 | break; 642 | case 'update': // run Update query and return the result (bool) 643 | $query = $this->pdo()->prepare($this->query); 644 | $result = $query->execute(array_merge($this->values,$this->whereValues)); 645 | $this->rowCount = $query->rowCount(); // updated row count 646 | $query->closeCursor(); unset($query); 647 | return $result; 648 | break; 649 | case 'delete': // run Delete query and return the result (bool) 650 | $query = $this->pdo()->prepare($this->query); 651 | $result = $query->execute($this->whereValues); 652 | $this->rowCount = $query->rowCount(); // deleted row count 653 | $query->closeCursor(); unset($query); 654 | return $result; 655 | break; 656 | case 'query': // run Raw query and return the result (bool) 657 | $query = $this->pdo()->prepare($this->query); 658 | $result = $query->execute($this->values); 659 | $this->rowCount = $query->rowCount(); // affected row count 660 | $exp = explode(' ', $this->query); // for determine the action 661 | if ($exp[0] == 'select') { 662 | $this->queryResult = $query->fetchAll(); 663 | $query->closeCursor(); unset($query); 664 | return $this->queryResult; 665 | } else { 666 | $query->closeCursor(); unset($query); 667 | return $result; 668 | } 669 | break; 670 | default: 671 | throw new \Exception('Command "' . $this->action . '" is not allowed.'); 672 | break; 673 | } 674 | } 675 | 676 | /** 677 | * Perform backup the database and print/download backup file 678 | * 679 | * @param string $fileName 680 | * @param string $action 681 | * @param array $excludeTables 682 | * @throws exception 683 | * @return string|file 684 | */ 685 | public function backup($fileName = null, $action = null, $excludeTables = []) { 686 | if ($this->connectionParams['driver'] == 'sqlite') { 687 | throw new \Exception('SQLite database backup is not allowed. Download "'.$this->connectionParams['url'].'" file directly.'); 688 | } 689 | if (empty($fileName)) {$fileName = 'SunDB-Backup-'.date("dmYHis").'.sql';} else {$fileName .= '.sql';} // define file name 690 | if (empty($action)) {$action = 'save';} // default action 691 | if ($action == 'save') { // if selected the Save method 692 | header('Content-disposition: attachment; filename='.$fileName); 693 | header('Content-type: application/force-download'); // header for download 694 | } 695 | $show = $this->pdo()->query('show tables')->fetchAll(); // list all tables 696 | $tables = []; 697 | foreach ($show as $rows) { 698 | $content = []; 699 | $table = reset($rows); 700 | if (!in_array($table, $excludeTables)) { 701 | $create = $this->pdo()->query("show create table `$table`")->fetchAll(); // list table structures 702 | $content[] = $create[0]['Create Table'].";\n"; // select Create Table structure 703 | $query = $this->pdo()->prepare("select * from `$table`"); // list all values in selected table 704 | $query->execute(array()); 705 | $select = $query->fetchAll(); 706 | if ($query->rowCount() > 0) { 707 | foreach ($select as $row) { 708 | if (count($row) < 1) {continue;} 709 | $header = "INSERT INTO `$table` VALUES ('"; // add Insert query 710 | $body = implode("', '", array_values($row)); // add listed values 711 | $footer = "');"; 712 | $content[] = $header.$body.$footer; 713 | } 714 | if (count($content) < 1) {continue;} 715 | $tables[$table] = implode("\n", $content); 716 | } 717 | } 718 | } 719 | if ($action == 'save') { 720 | echo "# SunDB Database Backup File\n# Backup Date: ".date("Y-m-d H:i:s")."\n# Backup File: ".$fileName."\n\n\n"; 721 | echo implode("\n\n", array_values($tables)); 722 | } else { // if selected the Show method 723 | echo nl2br(implode('

', array_values($tables))); 724 | } 725 | } 726 | 727 | /** 728 | * Analyze, check, optimize and repair tables 729 | * 730 | * @throws exception 731 | * @return boolean 732 | */ 733 | public function maintenance() { 734 | $tables = []; 735 | $show = $this->pdo()->query('show tables')->fetchAll(); // list tables 736 | foreach ($show as $rows) { 737 | if (!is_array($rows)) continue; 738 | if (count($rows) < 1) continue; 739 | $tables[] = '`' . $this->connectionParams['dbname'] . '`.' . '`' . reset($rows) . '`'; 740 | } 741 | if (count($tables) > 0) { 742 | $tables = implode(', ', $tables); 743 | try { 744 | $analyze = $this->pdo()->query("analyze table $tables"); // analyze tables 745 | $check = $this->pdo()->query("check table $tables"); // check tables 746 | $optimize = $this->pdo()->query("optimize table $tables"); // optimize tables 747 | $repair = $this->pdo()->query("repair table $tables"); // repair tables 748 | } catch (Exception $e) { 749 | throw new \Exception($e->getMessage()); 750 | } 751 | if ($analyze && $check && $optimize && $repair) { 752 | return true; 753 | } else { 754 | return false; 755 | } 756 | } else { 757 | return false; 758 | } 759 | } 760 | 761 | /** 762 | * Return a static instance of connection 763 | * 764 | * @return object 765 | */ 766 | public static function getInstance() { 767 | return self::$instance; 768 | } 769 | 770 | /** 771 | * Show/Print executed query as a string 772 | */ 773 | public function showQuery() { 774 | if (empty($this->query)) { 775 | echo '[SunDB] Error: SQL query not found.'; 776 | } else { 777 | if ($this->action == 'query') { 778 | echo '

[SunDB] Query: ' . $this->query . '

'; 779 | } else { 780 | $queryArray = explode('?', $this->query); 781 | for ($i = 0; $i < count($queryArray)-1; $i++) { 782 | $result .= $queryArray[$i] . "'" . $this->whereValues[$i] . "'"; 783 | } 784 | $result .= $queryArray[count($queryArray)-1]; 785 | echo '

[SunDB] Query: ' . $result . '

'; 786 | } 787 | } 788 | } 789 | 790 | /** 791 | * Return the total record count in a table 792 | * 793 | * @param string $table 794 | * @return integer 795 | */ 796 | public function tableCount($table = null) { 797 | if ($this->connectionParams['driver'] != 'sqlite' && $this->checkTable) { 798 | $this->checkTable($table); 799 | } 800 | $query = $this->pdo()->query('select count(*) as total from ' . $table)->fetchAll(); 801 | return (int) $query[0]['total']; 802 | } 803 | 804 | /** 805 | * Return the number of affected rows 806 | * 807 | * @return integer 808 | */ 809 | public function rowCount(){ 810 | return (int) $this->rowCount; 811 | } 812 | 813 | /** 814 | * Return the value of the auto increment column 815 | * 816 | * @return integer 817 | */ 818 | public function lastInsertId() { 819 | return (int) $this->lastInsertId; 820 | } 821 | 822 | /** 823 | * Generate user defined function call 824 | * 825 | * @param string $func 826 | * @param string $param 827 | * @throws exception 828 | * @return string 829 | */ 830 | public function func($func = null, $param = null) { 831 | if (empty($func) || empty($param)) { 832 | throw new \Exception('Missing parameters for "' . $func . '" function.'); 833 | } 834 | return $func($param); 835 | } 836 | 837 | } 838 | 839 | ?> 840 | --------------------------------------------------------------------------------