Subversion Repositories oidplus

Rev

Rev 236 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
150 daniel-mar 1
<?php
2
 
3
/*
4
 * OIDplus 2.0
5
 * Copyright 2019 Daniel Marschall, ViaThinkSoft
6
 *
7
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * you may not use this file except in compliance with the License.
9
 * You may obtain a copy of the License at
10
 *
11
 *     http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 * Unless required by applicable law or agreed to in writing, software
14
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * See the License for the specific language governing permissions and
17
 * limitations under the License.
18
 */
19
 
20
if (!defined('IN_OIDPLUS')) die();
21
 
227 daniel-mar 22
class OIDplusDataBasePluginPDO extends OIDplusDataBasePlugin {
150 daniel-mar 23
        private $pdo;
24
        private $last_query;
25
        private $prepare_cache = array();
26
 
236 daniel-mar 27
        public static function getPluginInformation(): array {
222 daniel-mar 28
                $out = array();
29
                $out['name'] = 'PDO';
30
                $out['author'] = 'ViaThinkSoft';
31
                $out['version'] = null;
32
                $out['descriptionHTML'] = null;
33
                return $out;
34
        }
35
 
236 daniel-mar 36
        public static function name(): string {
150 daniel-mar 37
                return "PDO";
38
        }
39
 
236 daniel-mar 40
        public function query($sql, $prepared_args=null): OIDplusQueryResult {
150 daniel-mar 41
                $this->last_query = $sql;
42
                if (is_null($prepared_args)) {
236 daniel-mar 43
                        $res = $this->pdo->query($sql);
44
 
45
                        if ($res === false) {
46
                                throw new OIDplusSQLException($sql, $this->error());
47
                        } else {
48
                                return new OIDplusQueryResultPDO($res);
49
                        }
150 daniel-mar 50
                } else {
51
                        // TEST: Emulate the prepared statement
236 daniel-mar 52
                        /*
150 daniel-mar 53
                        foreach ($prepared_args as $arg) {
54
                                $needle = '?';
55
                                $replace = "'$arg'"; // TODO: types
56
                                $pos = strpos($sql, $needle);
57
                                if ($pos !== false) {
58
                                        $sql = substr_replace($sql, $replace, $pos, strlen($needle));
59
                                }
60
                        }
236 daniel-mar 61
                        return OIDplusQueryResultPDO($this->pdo->query($sql));
62
                        */
150 daniel-mar 63
 
64
                        if (!is_array($prepared_args)) {
65
                                throw new Exception("'prepared_args' must be either NULL or an ARRAY.");
66
                        }
67
                        if (isset($this->prepare_cache[$sql])) {
68
                                $ps = $this->prepare_cache[$sql];
69
                        } else {
70
                                $ps = $this->pdo->prepare($sql);
71
                                if (!$ps) {
236 daniel-mar 72
                                        throw new OIDplusSQLException($sql, 'Cannot prepare statement');
150 daniel-mar 73
                                }
74
                                $this->prepare_cache[$sql] = $ps;
75
                        }
76
                        if (!$ps->execute($prepared_args)) {
236 daniel-mar 77
                                throw new OIDplusSQLException($sql, $this->error());
150 daniel-mar 78
                        }
236 daniel-mar 79
                        return new OIDplusQueryResultPDO($ps);
150 daniel-mar 80
                }
81
        }
236 daniel-mar 82
 
83
        public function insert_id(): int {
150 daniel-mar 84
                return $this->pdo->lastInsertId();
85
        }
236 daniel-mar 86
 
87
        public function error(): string {
150 daniel-mar 88
                return $this->pdo->errorInfo()[2];
89
        }
236 daniel-mar 90
 
91
        public function connect(): void {
150 daniel-mar 92
                try {
93
                        $options = [
94
                        #    PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
95
                            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
96
                            PDO::ATTR_EMULATE_PREPARES   => true,
97
                        ];
98
 
99
                        // Try connecting to the database
100
                        $this->pdo = new PDO(OIDPLUS_PDO_DSN, OIDPLUS_PDO_USERNAME, base64_decode(OIDPLUS_PDO_PASSWORD), $options);
101
                } catch (PDOException $e) {
237 daniel-mar 102
                        parent::showConnectError($e->getMessage());
150 daniel-mar 103
                        die();
104
                }
105
 
106
                $this->query("SET NAMES 'utf8'");
237 daniel-mar 107
                $this->afterConnect();
150 daniel-mar 108
                $this->connected = true;
109
        }
110
 
111
        private $intransaction = false;
112
 
236 daniel-mar 113
        public function transaction_begin(): void {
150 daniel-mar 114
                if ($this->intransaction) throw new Exception("Nested transactions are not supported by this database plugin.");
115
                $this->pdo->beginTransaction();
116
                $this->intransaction = true;
117
        }
118
 
236 daniel-mar 119
        public function transaction_commit(): void {
150 daniel-mar 120
                $this->pdo->commit();
121
                $this->intransaction = false;
122
        }
123
 
236 daniel-mar 124
        public function transaction_rollback(): void {
150 daniel-mar 125
                $this->pdo->rollBack();
126
                $this->intransaction = false;
127
        }
128
}
236 daniel-mar 129
 
130
class OIDplusQueryResultPDO extends OIDplusQueryResult {
131
        protected $no_resultset;
132
        protected $res;
133
 
134
        public function __construct($res) {
135
                $this->no_resultset = $res === false;
136
                $this->res = $res;
137
        }
138
 
139
        public function containsResultSet(): bool {
140
                return !$this->no_resultset;
141
        }
142
 
143
        public function num_rows(): int {
144
                if ($this->no_resultset) throw new Exception("The query has returned no result set (i.e. it was not a SELECT query)");
145
                return $this->res->rowCount();
146
        }
147
 
148
        public function fetch_array()/*: ?array*/ {
149
                if ($this->no_resultset) throw new Exception("The query has returned no result set (i.e. it was not a SELECT query)");
150
                $ret = $this->res->fetch(PDO::FETCH_ASSOC);
151
                if ($ret === false) $ret = null;
152
                return $ret;
153
        }
154
 
155
        public function fetch_object()/*: ?object*/ {
156
                if ($this->no_resultset) throw new Exception("The query has returned no result set (i.e. it was not a SELECT query)");
157
                $ret = $this->res->fetch(PDO::FETCH_OBJ);
158
                if ($ret === false) $ret = null;
159
                return $ret;
160
        }
161
}