Passed
Push — master ( 87e63f...d6a1bd )
by Darío
02:40
created

MySQL::rollback()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * DronePHP (http://www.dronephp.com)
4
 *
5
 * @link      http://github.com/Pleets/DronePHP
6
 * @copyright Copyright (c) 2016-2018 Pleets. (http://www.pleets.org)
7
 * @license   http://www.dronephp.com/license
8
 * @author    Darío Rivera <[email protected]>
9
 */
10
11
namespace Drone\Db\Driver;
12
13
/**
14
 * MySQL class
15
 *
16
 * This is a database driver class to connect to MySQL
17
 */
18
class MySQL extends AbstractDriver implements DriverInterface
19
{
20
    /**
21
     * {@inheritDoc}
22
     *
23
     * @var object
24
     */
25
    protected $dbconn;
26
27
    /**
28
     * {@inheritDoc}
29
     *
30
     * @param array $options
31
     */
32 21
    public function __construct($options)
33
    {
34 21
        $this->driverName = 'Mysqli';
35
36 21
        if (!array_key_exists("dbchar", $options))
0 ignored issues
show
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
37
            $options["dbchar"] = "utf8";
38
39 21
        parent::__construct($options);
40
41 21
        $auto_connect = array_key_exists('auto_connect', $options) ? $options["auto_connect"] : true;
42
43 21
        if ($auto_connect)
0 ignored issues
show
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
44 11
            $this->connect();
45 21
    }
46
47
    /**
48
     * Connects to database
49
     *
50
     * @throws RuntimeException
51
     * @throws Exception\ConnectionException
52
     *
53
     * @return \mysqli
54
     */
55 18
    public function connect()
56
    {
57 18
        if (!extension_loaded('mysqli'))
0 ignored issues
show
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
58
            throw new \RuntimeException("The Mysqli extension is not loaded");
59
60 18
        if (!is_null($this->dbport) && !empty($this->dbport))
0 ignored issues
show
introduced by
The condition is_null($this->dbport) is always false.
Loading history...
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
61 18
            $conn = @new \mysqli($this->dbhost, $this->dbuser, $this->dbpass, $this->dbname, $this->dbport);
62
        else
0 ignored issues
show
Coding Style introduced by
Expected 1 space after ELSE keyword; newline found
Loading history...
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
63
            $conn = @new \mysqli($this->dbhost, $this->dbuser, $this->dbpass, $this->dbname);
64
65 18
        if ($conn->connect_errno)
66
        {
67
            /*
68
             * Use ever mysqli_connect_errno() and mysqli_connect_error()
69
             * over $this->dbconn->errno and $this->dbconn->error to prevent
70
             * the warning message "Property access is not allowed yet".
71
             */
72 2
            throw new Exception\ConnectionException(mysqli_connect_error(), mysqli_connect_errno());
73
        }
74
        else
0 ignored issues
show
Coding Style introduced by
Expected 1 space after ELSE keyword; newline found
Loading history...
75
        {
76 16
            $this->dbconn = $conn;
77 16
            $this->dbconn->set_charset($this->dbchar);
78
        }
79
80 16
        return $this->dbconn;
81
    }
82
83
    /**
84
     * Excecutes a statement
85
     *
86
     * @param string $sql
87
     * @param array $params
88
     *
89
     * @throws RuntimeException
90
     * @throws Exception\InvalidQueryException
91
     *
92
     * @return \mysqli_result
93
     */
94 23
    public function execute($sql, Array $params = [])
0 ignored issues
show
Coding Style introduced by
As per coding-style, PHP keywords should be in lowercase; expected array, but found Array.
Loading history...
95
    {
96 23
        $this->numRows = 0;
97 23
        $this->numFields = 0;
98 23
        $this->rowsAffected = 0;
99
100 23
        $this->arrayResult = null;
101
102
        # Bound variables
103 23
        if (count($params))
104
        {
105 9
            $this->result = $stmt = @$this->dbconn->prepare($sql);
106
107 9
            if (!$stmt)
108
            {
109
                $this->error($this->dbconn->errno, $this->dbconn->error);
0 ignored issues
show
Bug introduced by
The method error() does not exist on Drone\Db\Driver\MySQL. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

109
                $this->/** @scrutinizer ignore-call */ 
110
                       error($this->dbconn->errno, $this->dbconn->error);
Loading history...
110
                throw new Exception\InvalidQueryException($this->dbconn->error, $this->dbconn->errno);
111
            }
112
113 9
            $param_values = array_values($params);
114
115 9
            $n_params = count($param_values);
116 9
            $bind_values = [];
117 9
            $bind_types = "";
118
119 9
            for ($i = 0; $i < $n_params; $i++)
120
            {
121 9
                if (is_string($param_values[$i]))
0 ignored issues
show
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
122 5
                    $bind_types .= 's';
123 9
                else if(is_float($param_values[$i]))
0 ignored issues
show
Coding Style introduced by
Expected 1 space after IF keyword; 0 found
Loading history...
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
124
                    $bind_types .= 'd';
125
                # [POSSIBLE BUG] - To Future revision (What about non-string and non-decimal types ?)
126
                else
0 ignored issues
show
Coding Style introduced by
Expected 1 space after ELSE keyword; newline found
Loading history...
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
127 9
                    $bind_types .= 's';
128
129 9
                $bind_values[] = '$param_values[' . $i . ']';
130
            }
131
132 9
            $values = implode(', ', $bind_values);
133 9
            eval('$stmt->bind_param(\'' . $bind_types . '\', ' . $values . ');');
0 ignored issues
show
introduced by
The use of eval() is discouraged.
Loading history...
134
135 9
            $r = $stmt->execute();
136
        }
137
        else
0 ignored issues
show
Coding Style introduced by
Expected 1 space after ELSE keyword; newline found
Loading history...
138
        {
139 16
            $prev_error_handler = set_error_handler(['\Drone\Error\ErrorHandler', 'errorControlOperator'], E_ALL);
140
141
            // may be throw a Fatal error (Ex: Maximum execution time)
142 16
            $r = $this->result = $this->dbconn->query($sql);
143
144 16
            set_error_handler($prev_error_handler);
145
        }
146
147 23
        if (!$r)
148
        {
149 3
            $this->error($this->dbconn->errno, $this->dbconn->error);
150 3
            throw new Exception\InvalidQueryException($this->dbconn->error, $this->dbconn->errno);
151
        }
152
153 21
        $is_stmt_result = is_object($this->result) && get_class($this->result) == 'mysqli_stmt';
154
155 21
        if ($is_stmt_result)
156
        {
157 9
            $this->rowsAffected = $this->result->affected_rows;
158
159 9
            $res = $this->result->get_result();
160
161
            /*
162
             * if $res is false then there aren't results.
163
             * It is useful to prevent rollback transactions on insert statements because
164
             * insert statement do not free results.
165
             */
166 9
            if ($res)
0 ignored issues
show
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
167 2
                $this->result = $res;
168
        }
169
170
        # identify SELECT, SHOW, DESCRIBE or EXPLAIN queries
171 21
        if (is_object($this->result) && property_exists($this->result, 'num_rows'))
0 ignored issues
show
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
172 16
            $this->numRows = $this->result->num_rows;
173
        else
0 ignored issues
show
Coding Style introduced by
Expected 1 space after ELSE keyword; newline found
Loading history...
174
        {
175 13
            if (property_exists($this->dbconn, 'affected_rows') && !$is_stmt_result)
0 ignored issues
show
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
176 13
                $this->rowsAffected = $this->dbconn->affected_rows;
177
        }
178
179
        # affected_rows return the same of num_rows on select statements!
180 21
        if ($this->numRows > 0)
0 ignored issues
show
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
181 9
            $this->rowsAffected = 0;
182
183 21
        if (property_exists($this->dbconn, 'field_count'))
0 ignored issues
show
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
184 21
            $this->numFields = $this->dbconn->field_count;
185
186 21
        if ($this->transac_mode)
0 ignored issues
show
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
187 2
            $this->transac_result = is_null($this->transac_result) ? $this->result: $this->transac_result && $this->result;
0 ignored issues
show
introduced by
The condition is_null($this->transac_result) is always false.
Loading history...
188
        /*
189
         * Because mysqli_query() returns FALSE on failure, a mysqli_result object for SELECT, SHOW, DESCRIBE or EXPLAIN queries,
190
         * and TRUE for other successful queries, it should be handled to return only objects or resources.
191
         *
192
         * Ref: http://php.net/manual/en/mysqli.query.php
193
         */
194 21
        return is_bool($this->result) ? $this->dbconn : $this->result;
195
    }
196
197
    /**
198
     * {@inheritDoc}
199
     */
200 4
    public function commit()
201
    {
202 4
        return $this->dbconn->commit();
203
    }
204
205
    /**
206
     * {@inheritDoc}
207
     */
208 2
    public function rollback()
209
    {
210 2
        return $this->dbconn->rollback();
211
    }
212
213
    /**
214
     * {@inheritDoc}
215
     */
216 3
    public function disconnect()
217
    {
218 3
        parent::disconnect();
219
220 2
        if ($this->dbconn->close())
221
        {
222 2
            $this->dbconn = null;
223 2
            return true;
224
        }
225
226
        return false;
227
    }
228
229
    /**
230
     * {@inheritDoc}
231
     */
232 4
    public function autocommit($value)
233
    {
234 4
        parent::autocommit($value);
235 4
        $this->dbconn->autocommit($value);
236 4
    }
237
238
    /**
239
     * Returns an array with the rows fetched
240
     *
241
     * @throws LogicException
242
     *
243
     * @return array
244
     */
245 10
    protected function toArray()
246
    {
247 10
        $data = [];
248
249 10
        if ($this->result && !is_bool($this->result))
250
        {
251 9
            while ($row = $this->result->fetch_array(MYSQLI_BOTH))
252
            {
253 9
                $data[] = $row;
254
            }
255
        }
256
        else
0 ignored issues
show
Coding Style introduced by
Expected 1 space after ELSE keyword; newline found
Loading history...
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
257
            # This error is thrown because of 'execute' method has not been executed.
258 1
            throw new \LogicException('There are not data in the buffer!');
259
260 9
        $this->arrayResult = $data;
261
262 9
        return $data;
263
    }
264
265
    /**
266
     * By default __destruct() disconnects to database
267
     *
268
     * @return null
269
     */
270 18
    public function __destruct()
271
    {
272
        # prevent "Property access is not allowed yet" with @ on failure connections
273 18
        if ($this->dbconn !== false && !is_null($this->dbconn))
0 ignored issues
show
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
274 13
            @$this->dbconn->close();
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for close(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

274
            /** @scrutinizer ignore-unhandled */ @$this->dbconn->close();

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
275
    }
276
}