Completed
Push — master ( 612476...c205d6 )
by smiley
04:22
created

PDODriverAbstract::escape()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
1
<?php
2
/**
3
 * Class PDODriverAbstract
4
 *
5
 * @filesource   PDODriverAbstract.php
6
 * @created      04.11.2015
7
 * @package      chillerlan\Database\Drivers\PDO
8
 * @author       Smiley <[email protected]>
9
 * @copyright    2015 Smiley
10
 * @license      MIT
11
 */
12
13
namespace chillerlan\Database\Drivers\PDO;
14
15
use chillerlan\Database\DBException;
16
use chillerlan\Database\Drivers\{DBDriverAbstract, DBDriverInterface};
17
use PDO, PDOException, PDOStatement;
18
19
/**
20
 *
21
 * @see http://php.net/manual/pdo.constants.php
22
 */
23
abstract class PDODriverAbstract extends DBDriverAbstract{
24
25
	/**
26
	 * Holds the database resource object
27
	 *
28
	 * @var PDO
29
	 */
30
	protected $db;
31
32
	/**
33
	 * Some basic PDO options
34
	 *
35
	 * @see http://php.net/manual/pdo.getattribute.php PDO::getAttribute
36
	 *
37
	 * @var array
38
	 */
39
	protected $pdo_options = [
40
		PDO::ATTR_CASE              => PDO::CASE_NATURAL,
41
		PDO::ATTR_ERRMODE           => PDO::ERRMODE_EXCEPTION,
42
		PDO::ATTR_ORACLE_NULLS      => PDO::NULL_NATURAL,
43
		PDO::ATTR_STRINGIFY_FETCHES => false,
44
		PDO::ATTR_EMULATE_PREPARES  => false,
45
	];
46
47
	/**
48
	 * The PDO drivername which is being used in the DSN
49
	 *
50
	 * @var string
51
	 */
52
	protected $drivername;
53
54
	/**
55
	 * This array holds one or more key=>value pairs to set attribute values for the PDOStatement object that this
56
	 * method returns. You would most commonly use this to set the PDO::ATTR_CURSOR value to PDO::CURSOR_SCROLL to
57
	 * request a scrollable cursor.
58
	 *
59
	 * @var array
60
	 */
61
	protected $pdo_stmt_options = [];
62
63
	/**
64
	 * Returns a DSN string using the given options
65
	 *
66
	 * @link http://www.phpro.org/tutorials/Introduction-to-PHP-PDO.html#4.4
67
	 *
68
	 * @return string DSN
69
	 */
70
	protected function getDSN():string{
71
		$dsn = $this->drivername;
72
73
		if($this->options->socket){
74
			$dsn .= ':unix_socket='.$this->options->socket; // @codeCoverageIgnore
75
		}
76
		else{
77
			$dsn .= ':host='.$this->options->host;
78
			$dsn .= is_numeric($this->options->port) ? ';port='.$this->options->port : '';
79
		}
80
81
		$dsn .= ';dbname='.$this->options->database;
82
83
		return $dsn;
84
	}
85
86
	/**
87
	 * Establishes a database connection and returns the connection object
88
	 *
89
	 * @return \chillerlan\Database\Drivers\DBDriverInterface
90
	 * @throws \chillerlan\Database\DBException
91
	 */
92
	public function connect():DBDriverInterface{
93
94
		if($this->db instanceof PDO){
95
			return $this;
96
		}
97
98
		try{
99
			// @codeCoverageIgnoreStart
100
			if($this->options->use_ssl){
101
				$this->pdo_options += [
102
					PDO::MYSQL_ATTR_SSL_KEY    => $this->options->ssl_key,
103
					PDO::MYSQL_ATTR_SSL_CERT   => $this->options->ssl_cert,
104
					PDO::MYSQL_ATTR_SSL_CA     => $this->options->ssl_ca,
105
					PDO::MYSQL_ATTR_SSL_CAPATH => $this->options->ssl_capath,
106
					PDO::MYSQL_ATTR_SSL_CIPHER => $this->options->ssl_cipher,
107
				];
108
			}
109
			// @codeCoverageIgnoreEnd
110
111
			$this->db = new PDO($this->getDSN(), $this->options->username, $this->options->password, $this->pdo_options);
112
113
			return $this;
114
		}
115
		catch(\Exception $e){
116
			throw new DBException('db error: [PDODriver]: '.$e->getMessage());
117
		}
118
	}
119
120
	/**
121
	 * Closes a database connection
122
	 *
123
	 * @return bool
124
	 */
125
	public function disconnect():bool{
126
		$this->db = null;
127
128
		return true;
129
	}
130
131
	/**
132
	 * Returns info about the used php client
133
	 *
134
	 * @return string php's database client string
135
	 */
136
	public function getClientInfo():string{
137
		return $this->db->getAttribute(PDO::ATTR_CLIENT_VERSION);
138
	}
139
140
	/**
141
	 * Returns info about the database server
142
	 *
143
	 * @return string database's serverinfo string
144
	 */
145
	public function getServerInfo():string{
146
		return $this->db->getAttribute(PDO::ATTR_SERVER_INFO);
147
	}
148
149
	/**
150
	 * @param $data
151
	 *
152
	 * @return string
153
	 */
154
	public function escape($data){
155
		return $this->db->quote($data);
156
	}
157
158
	/**
159
	 * @param \PDOStatement $stmt
160
	 * @param array         $values
161
	 *
162
	 * @return void
163
	 */
164
	protected function bindParams(PDOStatement &$stmt, array $values){
165
		$param_no = 1;
166
167
		foreach($values as $v){
168
169
			switch(gettype($v)){
170
				case 'boolean': $type = PDO::PARAM_BOOL; break;
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
171
				case 'integer': $type = PDO::PARAM_INT;  break;
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
172
				case 'NULL'   : $type = PDO::PARAM_NULL; break;
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
173
				default:        $type = PDO::PARAM_STR;  break;
0 ignored issues
show
Coding Style introduced by
The default body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a default statement must start on the line immediately following the statement.

switch ($expr) {
    default:
        doSomething(); //right
        break;
}


switch ($expr) {
    default:

        doSomething(); //wrong
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
174
			}
175
176
			$stmt->bindValue($param_no, $v, $type);
177
			$param_no++;
178
		}
179
	}
180
181
	/**
182
	 * Returns the last insert id (if present)
183
	 *
184
	 * @link http://php.net/manual/pdo.lastinsertid.php
185
	 * @return string
186
	 * @codeCoverageIgnore
187
	 */
188
	protected function insertID():string{
189
		return $this->db->lastInsertId();
190
	}
191
192
	/**
193
	 * @param             $stmt
194
	 * @param string|null $index
195
	 * @param bool        $assoc
196
	 *
197
	 * @return bool|\chillerlan\Database\DBResult
198
	 */
199
	protected function __getResult($stmt, string $index = null, bool $assoc = true){
200
201
		if(is_bool($stmt)){
202
			return $stmt; // @codeCoverageIgnore
203
		}
204
205
		return $this->getResult([$stmt, 'fetch'], [$assoc ? PDO::FETCH_ASSOC : PDO::FETCH_NUM], $index, $assoc);
206
	}
207
208
	/**
209
	 * @param string      $sql
210
	 * @param string|null $index
211
	 * @param bool        $assoc
212
	 *
213
	 * @return bool|\chillerlan\Database\DBResult
214
	 */
215
	protected function __raw(string $sql, string $index = null, bool $assoc = true){
216
		return $this->__getResult($this->db->query($sql), $index, $assoc);
217
	}
218
219
	/**
220
	 * @param string      $sql
221
	 * @param array       $values
222
	 * @param string|null $index
223
	 * @param bool        $assoc
224
	 *
225
	 * @return bool|\chillerlan\Database\DBResult
226
	 */
227
	protected function __prepared(string $sql, array $values = [], string $index = null, bool $assoc = true){
228
		$stmt = $this->db->prepare($sql, $this->pdo_stmt_options);
229
230
		if(!empty($values)){
231
			$this->bindParams($stmt, $values);
232
		}
233
234
		$stmt->execute();
235
236
		return $this->__getResult($stmt, $index, $assoc);
237
	}
238
239
	/**
240
	 * @param string $sql
241
	 * @param array  $values
242
	 *
243
	 * @return bool
244
	 */
245 View Code Duplication
	protected function __multi(string $sql, array $values){
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
246
		$stmt = $this->db->prepare($sql, $this->pdo_stmt_options);
247
248
		foreach($values as $row){
249
			$this->bindParams($stmt, $row);
250
			$stmt->execute();
251
		}
252
253
		$stmt = null;
0 ignored issues
show
Unused Code introduced by
$stmt is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
254
255
		return true;
256
	}
257
258
	/**
259
	 * @param string $sql
260
	 * @param array  $data
261
	 * @param        $callback
262
	 *
263
	 * @return bool
264
	 */
265 View Code Duplication
	protected function __multi_callback(string $sql, array $data, $callback){
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
266
		$stmt = $this->db->prepare($sql, $this->pdo_stmt_options);
267
268
		foreach($data as $row){
269
			$this->bindParams($stmt, call_user_func_array($callback, [$row]));
270
			$stmt->execute();
271
		}
272
273
		$stmt = null;
0 ignored issues
show
Unused Code introduced by
$stmt is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
274
275
		return true;
276
	}
277
278
}
279