1 | <?php |
||||||
2 | /** |
||||||
3 | * PDO SQL Related Functionality |
||||||
4 | * @author Joe Huss <[email protected]> |
||||||
5 | * @copyright 2025 |
||||||
6 | * @package MyAdmin |
||||||
7 | * @category SQL |
||||||
8 | */ |
||||||
9 | |||||||
10 | namespace MyDb\Pdo; |
||||||
11 | |||||||
12 | use MyDb\Generic; |
||||||
13 | use MyDb\Db_Interface; |
||||||
14 | use PDO; |
||||||
15 | |||||||
16 | /** |
||||||
17 | * Db |
||||||
18 | * |
||||||
19 | * @access public |
||||||
20 | */ |
||||||
21 | class Db extends Generic implements Db_Interface |
||||||
22 | { |
||||||
23 | /* public: connection parameters */ |
||||||
24 | public $driver = 'mysql'; |
||||||
25 | public $Rows = []; |
||||||
26 | /* public: this is an api revision, not a CVS revision. */ |
||||||
27 | public $type = 'pdo'; |
||||||
28 | |||||||
29 | /** |
||||||
30 | * changes the database we are working with. |
||||||
31 | * |
||||||
32 | * @param string $database the name of the database to use |
||||||
33 | * @return void |
||||||
34 | */ |
||||||
35 | 2 | public function selectDb($database) |
|||||
36 | { |
||||||
37 | 2 | $dSN = "{$this->driver}:dbname={$database};host={$this->host}"; |
|||||
38 | 2 | if ($this->characterSet != '') { |
|||||
39 | 2 | $dSN .= ';charset='.$this->characterSet; |
|||||
40 | } |
||||||
41 | 2 | $this->linkId = new PDO($dSN, $this->user, $this->password); |
|||||
42 | 2 | $this->database = $database; |
|||||
43 | } |
||||||
44 | |||||||
45 | |||||||
46 | /** |
||||||
47 | * alias function of select_db, changes the database we are working with. |
||||||
48 | * |
||||||
49 | * @param string $database the name of the database to use |
||||||
50 | * @return void |
||||||
51 | */ |
||||||
52 | 2 | public function useDb($database) |
|||||
53 | { |
||||||
54 | 2 | $this->selectDb($database); |
|||||
55 | } |
||||||
56 | |||||||
57 | /* public: connection management */ |
||||||
58 | |||||||
59 | /** |
||||||
60 | * Db::connect() |
||||||
61 | * @param string $database |
||||||
62 | * @param string $host |
||||||
63 | * @param string $user |
||||||
64 | * @param string $password |
||||||
65 | * @param string $driver |
||||||
66 | * @return bool|int|PDO |
||||||
67 | */ |
||||||
68 | 3 | public function connect($database = '', $host = '', $user = '', $password = '', $driver = 'mysql') |
|||||
69 | { |
||||||
70 | /* Handle defaults */ |
||||||
71 | 3 | if ('' == $database) { |
|||||
72 | 3 | $database = $this->database; |
|||||
73 | } |
||||||
74 | 3 | if ('' == $host) { |
|||||
75 | 3 | $host = $this->host; |
|||||
76 | } |
||||||
77 | 3 | if ('' == $user) { |
|||||
78 | 3 | $user = $this->user; |
|||||
79 | } |
||||||
80 | 3 | if ('' == $password) { |
|||||
81 | 3 | $password = $this->password; |
|||||
82 | } |
||||||
83 | 3 | if ('' == $driver) { |
|||||
84 | $driver = $this->driver; |
||||||
85 | } |
||||||
86 | /* establish connection, select database */ |
||||||
87 | 3 | $dSN = "{$driver}:dbname={$database};host={$host}"; |
|||||
88 | 3 | if ($this->characterSet != '') { |
|||||
89 | 3 | $dSN .= ';charset='.$this->characterSet; |
|||||
90 | } |
||||||
91 | 3 | if ($this->linkId === false) { |
|||||
0 ignored issues
–
show
introduced
by
![]() |
|||||||
92 | try { |
||||||
93 | $this->linkId = new PDO($dSN, $user, $password); |
||||||
94 | } catch (\PDOException $e) { |
||||||
95 | $this->halt('Connection Failed '.$e->getMessage()); |
||||||
96 | return 0; |
||||||
97 | } |
||||||
98 | } |
||||||
99 | 3 | return $this->linkId; |
|||||
100 | } |
||||||
101 | |||||||
102 | /* This only affects systems not using persistent connections */ |
||||||
103 | |||||||
104 | /** |
||||||
105 | * Db::disconnect() |
||||||
106 | * @return void |
||||||
107 | */ |
||||||
108 | public function disconnect() |
||||||
109 | { |
||||||
110 | } |
||||||
111 | |||||||
112 | /* public: discard the query result */ |
||||||
113 | |||||||
114 | /** |
||||||
115 | * Db::free() |
||||||
116 | * @return void |
||||||
117 | */ |
||||||
118 | public function free() |
||||||
119 | { |
||||||
120 | // @mysql_free_result($this->queryId); |
||||||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
67% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||||||
121 | // $this->queryId = 0; |
||||||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
38% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||||||
122 | } |
||||||
123 | |||||||
124 | /** |
||||||
125 | * Db::query() |
||||||
126 | * |
||||||
127 | * Sends an SQL query to the database |
||||||
128 | * |
||||||
129 | * @param mixed $queryString |
||||||
130 | * @param string $line |
||||||
131 | * @param string $file |
||||||
132 | * @return mixed 0 if no query or query id handler, safe to ignore this return |
||||||
133 | */ |
||||||
134 | 2 | public function query($queryString, $line = '', $file = '') |
|||||
135 | { |
||||||
136 | /* No empty queries, please, since PHP4 chokes on them. */ |
||||||
137 | /* The empty query string is passed on from the constructor, |
||||||
138 | * when calling the class without a query, e.g. in situations |
||||||
139 | * like these: '$db = new db_Subclass;' |
||||||
140 | */ |
||||||
141 | 2 | if ($queryString == '') { |
|||||
142 | return 0; |
||||||
143 | } |
||||||
144 | 2 | if (!$this->connect()) { |
|||||
145 | return 0; |
||||||
146 | /* we already complained in connect() about that. */ |
||||||
147 | } |
||||||
148 | // New query, discard previous result. |
||||||
149 | 2 | if ($this->queryId !== false) { |
|||||
0 ignored issues
–
show
|
|||||||
150 | 2 | $this->free(); |
|||||
151 | } |
||||||
152 | |||||||
153 | 2 | if ($this->Debug) { |
|||||
154 | printf("Debug: query = %s<br>\n", $queryString); |
||||||
155 | } |
||||||
156 | 2 | if (isset($GLOBALS['log_queries']) && $GLOBALS['log_queries'] !== false) { |
|||||
157 | $this->log($queryString, $line, $file); |
||||||
158 | } |
||||||
159 | |||||||
160 | 2 | $this->queryId = $this->linkId->prepare($queryString); |
|||||
161 | 2 | $success = $this->queryId->execute(); |
|||||
162 | 2 | $this->Rows = $this->queryId->fetchAll(); |
|||||
163 | //$this->log("PDO Query $queryString (S:$success) - ".count($this->Rows).' Rows', __LINE__, __FILE__); |
||||||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
69% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||||||
164 | 2 | $this->Row = -1; |
|||||
165 | 2 | if ($success === false) { |
|||||
166 | $this->emailError($queryString, json_encode($this->queryId->errorInfo(), JSON_PRETTY_PRINT), $line, $file); |
||||||
167 | } |
||||||
168 | |||||||
169 | // Will return nada if it fails. That's fine. |
||||||
170 | 2 | return $this->queryId; |
|||||
171 | } |
||||||
172 | |||||||
173 | /* public: walk result set */ |
||||||
174 | |||||||
175 | /** |
||||||
176 | * Db::next_record() |
||||||
177 | * @param mixed $resultType |
||||||
178 | * @return bool |
||||||
179 | */ |
||||||
180 | 2 | public function next_record($resultType = MYSQLI_ASSOC) |
|||||
181 | { |
||||||
182 | // PDO result types so far seem to be +1 |
||||||
183 | 2 | ++$resultType; |
|||||
184 | 2 | if (!$this->queryId) { |
|||||
185 | $this->halt('next_record called with no query pending.'); |
||||||
186 | return 0; |
||||||
187 | } |
||||||
188 | |||||||
189 | 2 | ++$this->Row; |
|||||
190 | 2 | $this->Record = $this->Rows[$this->Row]; |
|||||
191 | |||||||
192 | 2 | $stat = is_array($this->Record); |
|||||
193 | 2 | if (!$stat && $this->autoFree) { |
|||||
194 | $this->free(); |
||||||
195 | } |
||||||
196 | 2 | return $stat; |
|||||
197 | } |
||||||
198 | |||||||
199 | /* public: position in result set */ |
||||||
200 | |||||||
201 | /** |
||||||
202 | * Db::seek() |
||||||
203 | * @param integer $pos |
||||||
204 | * @return int |
||||||
205 | */ |
||||||
206 | public function seek($pos = 0) |
||||||
207 | { |
||||||
208 | if (isset($this->Rows[$pos])) { |
||||||
209 | $this->Row = $pos; |
||||||
210 | } else { |
||||||
211 | $this->halt("seek($pos) failed: result has ".count($this->Rows).' rows'); |
||||||
212 | /* half assed attempt to save the day, |
||||||
213 | * but do not consider this documented or even |
||||||
214 | * desirable behaviour. |
||||||
215 | */ |
||||||
216 | return 0; |
||||||
217 | } |
||||||
218 | return 1; |
||||||
219 | } |
||||||
220 | |||||||
221 | /** |
||||||
222 | * Initiates a transaction |
||||||
223 | * @return bool |
||||||
224 | */ |
||||||
225 | public function transactionBegin() |
||||||
226 | { |
||||||
227 | return $this->linkId->beginTransaction(); |
||||||
228 | } |
||||||
229 | |||||||
230 | /** |
||||||
231 | * Commits a transaction |
||||||
232 | * @return bool |
||||||
233 | */ |
||||||
234 | public function transactionCommit() |
||||||
235 | { |
||||||
236 | return $this->linkId->commit(); |
||||||
237 | } |
||||||
238 | |||||||
239 | /** |
||||||
240 | * Rolls back a transaction |
||||||
241 | * @return bool |
||||||
242 | */ |
||||||
243 | public function transactionAbort() |
||||||
244 | { |
||||||
245 | return $this->linkId->rollBack(); |
||||||
246 | } |
||||||
247 | |||||||
248 | /** |
||||||
249 | * Db::getLastInsertId() |
||||||
250 | * @param mixed $table |
||||||
251 | * @param mixed $field |
||||||
252 | * @return int |
||||||
253 | */ |
||||||
254 | public function getLastInsertId($table, $field) |
||||||
255 | { |
||||||
256 | if (!isset($table) || $table == '' || !isset($field) || $field == '') { |
||||||
257 | return -1; |
||||||
258 | } |
||||||
259 | return $this->linkId->lastInsertId(); |
||||||
260 | } |
||||||
261 | |||||||
262 | /* public: table locking */ |
||||||
263 | |||||||
264 | /** |
||||||
265 | * Db::lock() |
||||||
266 | * @param mixed $table |
||||||
267 | * @param string $mode |
||||||
268 | * @return void |
||||||
269 | */ |
||||||
270 | public function lock($table, $mode = 'write') |
||||||
0 ignored issues
–
show
The parameter
$table is not used and could be removed.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for parameters that have been defined for a function or method, but which are not used in the method body. ![]() The parameter
$mode is not used and could be removed.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for parameters that have been defined for a function or method, but which are not used in the method body. ![]() |
|||||||
271 | { |
||||||
272 | /* $this->connect(); |
||||||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
46% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||||||
273 | |||||||
274 | * $query = "lock tables "; |
||||||
275 | * if (is_array($table)) |
||||||
276 | * { |
||||||
277 | * foreach ($table as $key => $value) |
||||||
278 | * { |
||||||
279 | * if ($key == "read" && $key!=0) |
||||||
280 | * { |
||||||
281 | * $query .= "$value read, "; |
||||||
282 | * } |
||||||
283 | * else |
||||||
284 | * { |
||||||
285 | * $query .= "$value $mode, "; |
||||||
286 | * } |
||||||
287 | * } |
||||||
288 | * $query = mb_substr($query,0,-2); |
||||||
289 | * } |
||||||
290 | * else |
||||||
291 | * { |
||||||
292 | * $query .= "$table $mode"; |
||||||
293 | * } |
||||||
294 | * $res = @mysql_query($query, $this->linkId); |
||||||
295 | * if (!$res) |
||||||
296 | * { |
||||||
297 | * $this->halt("lock($table, $mode) failed."); |
||||||
298 | * return 0; |
||||||
299 | * } |
||||||
300 | * return $res; |
||||||
301 | */ |
||||||
302 | } |
||||||
303 | |||||||
304 | /** |
||||||
305 | * Db::unlock() |
||||||
306 | * @return void |
||||||
307 | */ |
||||||
308 | public function unlock() |
||||||
309 | { |
||||||
310 | /* $this->connect(); |
||||||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
54% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||||||
311 | |||||||
312 | * $res = @mysql_query("unlock tables"); |
||||||
313 | * if (!$res) |
||||||
314 | * { |
||||||
315 | * $this->halt("unlock() failed."); |
||||||
316 | * return 0; |
||||||
317 | * } |
||||||
318 | * return $res; |
||||||
319 | */ |
||||||
320 | } |
||||||
321 | |||||||
322 | /* public: evaluate the result (size, width) */ |
||||||
323 | |||||||
324 | /** |
||||||
325 | * Db::affectedRows() |
||||||
326 | * |
||||||
327 | * @return mixed |
||||||
328 | */ |
||||||
329 | public function affectedRows() |
||||||
330 | { |
||||||
331 | return @$this->queryId->rowCount(); |
||||||
0 ignored issues
–
show
The method
rowCount() does not exist on integer .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed. ![]() |
|||||||
332 | } |
||||||
333 | |||||||
334 | /** |
||||||
335 | * Db::num_rows() |
||||||
336 | * @return int |
||||||
337 | */ |
||||||
338 | public function num_rows() |
||||||
339 | { |
||||||
340 | return count($this->Rows); |
||||||
341 | } |
||||||
342 | |||||||
343 | /** |
||||||
344 | * Db::num_fields() |
||||||
345 | * @return int |
||||||
346 | */ |
||||||
347 | public function num_fields() |
||||||
348 | { |
||||||
349 | $keys = array_keys($this->Rows); |
||||||
350 | return count($this->Rows[$keys[0]]); |
||||||
351 | } |
||||||
352 | |||||||
353 | /** |
||||||
354 | * @param mixed $msg |
||||||
355 | * @param string $line |
||||||
356 | * @param string $file |
||||||
357 | * @return mixed|void |
||||||
358 | */ |
||||||
359 | public function haltmsg($msg, $line = '', $file = '') |
||||||
360 | { |
||||||
361 | $this->log("Database error: $msg", $line, $file, 'error'); |
||||||
362 | if ($this->Errno != '0' || $this->Error != '()') { |
||||||
363 | $this->log('PDO MySQL Error: '.json_encode($this->linkId->errorInfo()), $line, $file, 'error'); |
||||||
364 | } |
||||||
365 | $this->logBackTrace($msg, $line, $file); |
||||||
366 | } |
||||||
367 | |||||||
368 | /** |
||||||
369 | * Db::tableNames() |
||||||
370 | * |
||||||
371 | * @return array |
||||||
372 | */ |
||||||
373 | public function tableNames() |
||||||
374 | { |
||||||
375 | $return = []; |
||||||
376 | $this->query('SHOW TABLES'); |
||||||
377 | foreach ($this->Rows as $i => $info) { |
||||||
378 | $return[$i]['table_name'] = $info[0]; |
||||||
379 | $return[$i]['tablespace_name'] = $this->database; |
||||||
380 | $return[$i]['database'] = $this->database; |
||||||
381 | } |
||||||
382 | return $return; |
||||||
383 | } |
||||||
384 | } |
||||||
385 |