1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* |
4
|
|
|
* @filesource PostgreSQLDriver.php |
5
|
|
|
* @created 21.02.2016 |
6
|
|
|
* @package chillerlan\Database\Drivers\PostgreSQL |
7
|
|
|
* @author Smiley <[email protected]> |
8
|
|
|
* @copyright 2016 Smiley |
9
|
|
|
* @license MIT |
10
|
|
|
*/ |
11
|
|
|
|
12
|
|
|
namespace chillerlan\Database\Drivers\PostgreSQL; |
13
|
|
|
|
14
|
|
|
use chillerlan\Database\DBException; |
15
|
|
|
use chillerlan\Database\Drivers\DBDriverAbstract; |
16
|
|
|
|
17
|
|
|
/** |
18
|
|
|
* Class PostgreSQLDriver |
19
|
|
|
*/ |
20
|
|
|
class PostgreSQLDriver extends DBDriverAbstract{ |
21
|
|
|
|
22
|
|
|
/** |
23
|
|
|
* Holds the database resource object |
24
|
|
|
* |
25
|
|
|
* @var resource |
26
|
|
|
*/ |
27
|
|
|
protected $db; |
28
|
|
|
|
29
|
|
|
/** |
30
|
|
|
* Establishes a database connection and returns the connection object |
31
|
|
|
* |
32
|
|
|
* @return resource the database resource object |
33
|
|
|
* @throws \chillerlan\Database\DBException |
34
|
|
|
*/ |
35
|
|
|
public function connect() { |
36
|
|
|
|
37
|
|
|
if(gettype($this->db) === 'resource'){ |
38
|
|
|
return $this->db; |
39
|
|
|
} |
40
|
|
|
|
41
|
|
|
// i am an ugly duckling. fix me please. |
42
|
|
|
|
43
|
|
|
$options = [ |
44
|
|
|
'--client_encoding='.$this->options->pgsql_charset, |
45
|
|
|
]; |
46
|
|
|
|
47
|
|
|
$conn_str = [ |
48
|
|
|
'host=\''.$this->options->host.'\'', |
49
|
|
|
'port=\''.(int)$this->options->port.'\'', |
50
|
|
|
'dbname=\''.$this->options->database.'\'', |
51
|
|
|
'user=\''.$this->options->username.'\'', |
52
|
|
|
'password=\''.$this->options->password.'\'', |
53
|
|
|
'options=\''.implode(' ', $options).'\'', |
54
|
|
|
]; |
55
|
|
|
|
56
|
|
|
if(!$this->db = pg_connect(implode(' ', $conn_str))){ |
57
|
|
|
throw new DBException('Could not connect to the database.'); |
58
|
|
|
} |
59
|
|
|
|
60
|
|
|
return $this->db; |
61
|
|
|
} |
62
|
|
|
|
63
|
|
|
/** |
64
|
|
|
* Closes a database connection |
65
|
|
|
* |
66
|
|
|
* @return bool |
67
|
|
|
*/ |
68
|
|
|
public function disconnect():bool { |
69
|
|
|
return pg_close($this->db); |
70
|
|
|
} |
71
|
|
|
|
72
|
|
|
/** |
73
|
|
|
* Returns info about the used php client |
74
|
|
|
* |
75
|
|
|
* @return string php's database client string |
76
|
|
|
*/ |
77
|
|
|
public function getClientInfo():string { |
78
|
|
|
$ver = pg_version($this->db); |
79
|
|
|
|
80
|
|
|
return 'PostgreSQL '.$ver['client'].' ('.$ver['client_encoding'].')'; |
81
|
|
|
} |
82
|
|
|
|
83
|
|
|
/** |
84
|
|
|
* Returns info about the database server |
85
|
|
|
* |
86
|
|
|
* @return string database's serverinfo string |
87
|
|
|
*/ |
88
|
|
|
public function getServerInfo():string { |
89
|
|
|
$ver = pg_version($this->db); |
90
|
|
|
|
91
|
|
|
return 'PostgreSQL '.$ver['server'].' ('.$ver['server_encoding'].', date style: '.$ver['DateStyle'].', time zone: '.$ver['TimeZone'].')'; |
92
|
|
|
} |
93
|
|
|
|
94
|
|
|
/** |
95
|
|
|
* Sanitizer. |
96
|
|
|
* |
97
|
|
|
* Recursively escapes string values, optional htmlspecialchars() |
98
|
|
|
* |
99
|
|
|
* @param array|string $data array or string to escape |
100
|
|
|
* @param bool $specialchars [optional] if true, it performs a htmlspecialchars() on each value given |
101
|
|
|
* |
102
|
|
|
* @return array|string array or string. escaped. obviously. |
103
|
|
|
*/ |
104
|
|
View Code Duplication |
public function escape($data, bool $specialchars = false){ |
|
|
|
|
105
|
|
|
|
106
|
|
|
if(is_array($data)){ |
107
|
|
|
|
108
|
|
|
foreach($data as $key => $value){ |
109
|
|
|
$data[$key] = $this->escape($value, $specialchars); |
110
|
|
|
} |
111
|
|
|
|
112
|
|
|
} |
113
|
|
|
else if(is_object($data)){ |
114
|
|
|
|
115
|
|
|
foreach($data as $key => $value){ |
116
|
|
|
$data->{$key} = $this->escape($value, $specialchars); |
117
|
|
|
} |
118
|
|
|
|
119
|
|
|
} |
120
|
|
|
else{ |
121
|
|
|
|
122
|
|
|
if($specialchars){ |
123
|
|
|
$data = htmlspecialchars($data, ENT_HTML5, 'UTF-8', false); |
124
|
|
|
} |
125
|
|
|
|
126
|
|
|
$data = pg_escape_string($this->db, $data); |
127
|
|
|
} |
128
|
|
|
|
129
|
|
|
return $data; |
130
|
|
|
} |
131
|
|
|
|
132
|
|
|
/** |
133
|
|
|
* Basic SQL query for non prepared statements |
134
|
|
|
* |
135
|
|
|
* There is no escaping in here, so make sure, your SQL is clean/escaped. |
136
|
|
|
* Also, your SQL should NEVER contain user input, use prepared statements in this case. |
137
|
|
|
* |
138
|
|
|
* If the query was successful it returns either an array of results or true |
139
|
|
|
* if it was a void query. On errors, a false will be returned, obviously. |
140
|
|
|
* |
141
|
|
|
* @param string $sql The SQL statement |
142
|
|
|
* @param string $index [optional] an index column to assingn as the result's keys |
|
|
|
|
143
|
|
|
* @param bool $assoc [optional] If true, the fields are named with the respective column names, otherwise numbered |
144
|
|
|
* @param bool $fetch_array [optional] fetch the vaues as array instead of object |
145
|
|
|
* |
146
|
|
|
* @return array|bool array with results, true on void query success, otherwise false. |
147
|
|
|
* @throws \mysqli_sql_exception |
148
|
|
|
*/ |
149
|
|
|
public function raw(string $sql, string $index = null, bool $assoc = true, bool $fetch_array = false){ |
150
|
|
|
// TODO: Implement raw() method. |
151
|
|
|
return false; |
152
|
|
|
} |
153
|
|
|
|
154
|
|
|
/** |
155
|
|
|
* Prepared statements wrapper |
156
|
|
|
* |
157
|
|
|
* Does everything for you: prepares the statement and fetches the results as an object or array |
158
|
|
|
* just pass a query along with values and you're done. Not meant for multi-inserts. |
159
|
|
|
* |
160
|
|
|
* @param string $sql The SQL statement to prepare |
161
|
|
|
* @param array $values [optional] the value for each "?" in the statement - in the respective order, of course |
162
|
|
|
* @param string $index [optional] an index column to assingn as the result's keys |
|
|
|
|
163
|
|
|
* @param bool $assoc [optional] If true, the fields are named with the respective column names, otherwise numbered |
164
|
|
|
* @param bool $fetch_array [optional] fetch the vaues as array instead of object |
165
|
|
|
* |
166
|
|
|
* @return array|bool Array with results, true on void query success, otherwise false |
167
|
|
|
*/ |
168
|
|
|
public function prepared(string $sql, array $values = [], string $index = null, bool $assoc = true, bool $fetch_array = false){ |
169
|
|
|
// TODO: Implement prepared() method. |
170
|
|
|
return false; |
171
|
|
|
} |
172
|
|
|
|
173
|
|
|
/** |
174
|
|
|
* Prepared multi line insert |
175
|
|
|
* |
176
|
|
|
* Prepared statement multi insert/update |
177
|
|
|
* |
178
|
|
|
* @param string $sql The SQL statement to prepare |
179
|
|
|
* @param array $values a multidimensional array with the values, each row represents one line to insert. |
180
|
|
|
* |
181
|
|
|
* @return bool true query success, otherwise false |
182
|
|
|
*/ |
183
|
|
|
public function multi(string $sql, array $values){ |
184
|
|
|
// TODO: Implement multi() method. |
185
|
|
|
return false; |
186
|
|
|
} |
187
|
|
|
|
188
|
|
|
/** |
189
|
|
|
* Prepared multi line insert/update with callback |
190
|
|
|
* |
191
|
|
|
* @todo: multi treading |
192
|
|
|
* @see https://gist.github.com/krakjoe/6437782 |
193
|
|
|
* @see https://gist.github.com/krakjoe/9384409 |
194
|
|
|
* |
195
|
|
|
* @param string $sql The SQL statement to prepare |
196
|
|
|
* @param array $data an array with the (raw) data to insert, each row represents one line to insert. |
197
|
|
|
* @param callable|array $callback a callback that processes the values for each row. |
198
|
|
|
* |
199
|
|
|
* @return bool true query success, otherwise false |
200
|
|
|
* @throws \chillerlan\Database\DBException |
201
|
|
|
*/ |
202
|
|
|
public function multi_callback(string $sql, array $data, $callback){ |
203
|
|
|
// TODO: Implement multi_callback() method. |
204
|
|
|
return false; |
205
|
|
|
} |
206
|
|
|
|
207
|
|
|
} |
208
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.