Completed
Push — master ( 6895c9...01f26e )
by Lars
08:35 queued 56s
created

Prepare::get_sql()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 2
cp 0
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
crap 2
1
<?php
2
3
namespace voku\db;
4
5
use voku\helper\Bootup;
6
7
/**
8
 * Prepare: this handles the prepare-statement from "DB"-Class
9
 *
10
 * @package   voku\db
11
 */
12
final class Prepare extends \mysqli_stmt
13
{
14
15
  /**
16
   * @var string $_sql - the unchanged query string provided to the constructor
17
   */
18
  private $_sql;
19
20
  /**
21
   * @var string $_sql_with_bound_parameters - the query string with bound parameters interpolated
22
   */
23
  private $_sql_with_bound_parameters;
24
25
  /**
26
   * @var bool
27
   */
28
  private $_use_bound_parameters_interpolated = false;
29
30
  /**
31
   * @var array $_boundParams - array of arrays containing values that have been bound to the query as parameters
32
   */
33
  private $_boundParams = array();
34
35
  /**
36
   * @var DB
37
   */
38
  private $_db;
39
40
  /**
41
   * @var Debug
42
   */
43
  private $_debug;
44
45
  /**
46
   * Prepare constructor.
47
   *
48
   * @param DB     $db
49
   * @param string $query
50
   */
51 9
  public function __construct(DB $db, $query)
52
  {
53 9
    $this->_db = $db;
54 9
    $this->_debug = $db->getDebugger();
55
56 9
    parent::__construct($db->getLink(), $query);
57
58 9
    $this->prepare($query);
59 9
  }
60
61
  /**
62
   * Prepare destructor.
63
   */
64 9
  public function __destruct()
65
  {
66 9
    $this->close();
67 9
  }
68
69
  /**
70
   * Combines the values stored in $this->boundParams into one array suitable for pushing as the input arguments to
71
   * parent::bind_param when used with call_user_func_array
72
   *
73
   * @return array
74
   */
75 6
  private function _buildArguments()
76
  {
77 6
    $arguments = array();
78 6
    $arguments[0] = '';
79
80 6
    foreach ($this->_boundParams as $param) {
81 6
      $arguments[0] .= $param['type'];
82 6
      $arguments[] =& $param['value'];
83 6
    }
84
85 6
    return $arguments;
86
  }
87
88
  /**
89
   * Escapes the supplied value.
90
   *
91
   * @param array $param
92
   *
93
   * @return array 0 => "$value" escaped<br />
94
   *               1 => "$valueForSqlWithBoundParameters" for insertion into the interpolated query string
95
   */
96 6
  private function _prepareValue(&$param)
97
  {
98 6
    $type = $param['type']; // 'i', 'b', 's', 'd'
0 ignored issues
show
Unused Code Comprehensibility introduced by
64% 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.

Loading history...
99 6
    $value = $param['value'];
100
101
    /** @noinspection ReferenceMismatchInspection */
102 6
    $value = $this->_db->escape($value);
103
104 6
    if ($type === 's') {
105 4
      $valueForSqlWithBoundParameters = "'" . $value . "'";
106 6
    } elseif ($type === 'i') {
107 2
      $valueForSqlWithBoundParameters = (int)$value;
108 2
    } elseif ($type === 'd') {
109 1
      $valueForSqlWithBoundParameters = (double)$value;
110 1
    } else {
111
      $valueForSqlWithBoundParameters = $value;
112
    }
113
114 6
    return array($value, $valueForSqlWithBoundParameters);
115
  }
116
117
  /**
118
   * @return int
119
   */
120
  public function affected_rows()
121
  {
122
    return $this->affected_rows;
123
  }
124
125
  /**
126
   * This is a wrapper for "bind_param" what binds variables to a prepared statement as parameters. If you use this
127
   * wrapper, you can debug your query with e.g. "$this->get_sql_with_bound_parameters()".
128
   *
129
   * @param string $types <strong>i<strong> corresponding variable has type integer<br />
130
   *                      <strong>d</strong> corresponding variable has type double<br />
131
   *                      <strong>s</strong> corresponding variable has type string<br />
132
   *                      <strong>b</strong> corresponding variable is a blob and will be sent in packets
133
   *
134
   * INFO: We have to explicitly declare all parameters as references, otherwise it does not seem possible to pass them
135
   * on without losing the reference property.
136
   *
137
   * @param mixed  $v1
138
   * @param mixed  $v2
139
   * @param mixed  $v3
140
   * @param mixed  $v4
141
   * @param mixed  $v5
142
   * @param mixed  $v6
143
   * @param mixed  $v7
144
   * @param mixed  $v8
145
   * @param mixed  $v9
146
   * @param mixed  $v10
147
   * @param mixed  $v11
148
   * @param mixed  $v12
149
   * @param mixed  $v13
150
   * @param mixed  $v14
151
   * @param mixed  $v15
152
   * @param mixed  $v16
153
   * @param mixed  $v17
154
   * @param mixed  $v18
155
   * @param mixed  $v19
156
   * @param mixed  $v20
157
   * @param mixed  $v21
158
   * @param mixed  $v22
159
   * @param mixed  $v23
160
   * @param mixed  $v24
161
   * @param mixed  $v25
162
   * @param mixed  $v26
163
   * @param mixed  $v27
164
   * @param mixed  $v28
165
   * @param mixed  $v29
166
   * @param mixed  $v30
167
   * @param mixed  $v31
168
   * @param mixed  $v32
169
   * @param mixed  $v33
170
   * @param mixed  $v34
171
   * @param mixed  $v35
172
   *
173
   * @return mixed
174
   */
175 6
  public function bind_param_debug($types, &$v1 = null, &$v2 = null, &$v3 = null, &$v4 = null, &$v5 = null, &$v6 = null, &$v7 = null, &$v8 = null, &$v9 = null, &$v10 = null, &$v11 = null, &$v12 = null, &$v13 = null, &$v14 = null, &$v15 = null, &$v16 = null, &$v17 = null, &$v18 = null, &$v19 = null, &$v20 = null, &$v21 = null, &$v22 = null, &$v23 = null, &$v24 = null, &$v25 = null, &$v26 = null, &$v27 = null, &$v28 = null, &$v29 = null, &$v30 = null, &$v31 = null, &$v32 = null, &$v33 = null, &$v34 = null, &$v35 = null)
0 ignored issues
show
Unused Code introduced by
The parameter $v1 is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $v2 is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $v3 is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $v4 is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $v5 is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $v6 is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $v7 is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $v8 is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $v9 is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $v10 is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $v11 is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $v12 is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $v13 is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $v14 is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $v15 is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $v16 is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $v17 is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $v18 is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $v19 is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $v20 is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $v21 is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $v22 is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $v23 is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $v24 is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $v25 is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $v26 is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $v27 is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $v28 is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $v29 is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $v30 is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $v31 is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $v32 is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $v33 is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $v34 is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $v35 is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
176
  {
177 6
    $this->_use_bound_parameters_interpolated = true;
178
179
    // debug_backtrace returns arguments by reference, see comments at http://php.net/manual/de/function.func-get-args.php
180 6
    if (Bootup::is_php('5.4')) {
181
      $trace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 1);
182
    } else {
183 6
      $trace = debug_backtrace();
184
    }
185
186 6
    $args =& $trace[0]['args'];
187 6
    $types = str_split($types);
188
189 6
    $args_count = count($args) - 1;
190 6
    $types_count = count($types);
191
192 6
    if ($args_count !== $types_count) {
193
      trigger_error('Number of variables doesn\'t match number of parameters in prepared statement', E_WARNING);
194
195
      return false;
196
    }
197
198 6
    $arg = 1;
199 6
    foreach ($types as $typeInner) {
200 6
      $val =& $args[$arg];
201 6
      $this->_boundParams[] = array(
202 6
          'type'  => $typeInner,
203 6
          'value' => &$val,
204
      );
205 6
      $arg++;
206 6
    }
207
208 6
    return true;
209
  }
210
211
  /**
212
   * @inheritdoc
213
   *
214
   * @return bool
215
   */
216
  public function execute_raw()
217
  {
218
    return parent::execute();
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (execute() instead of execute_raw()). Are you sure this is correct? If so, you might want to change this to $this->execute().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
219
  }
220
221
  /**
222
   * Executes a prepared Query
223
   *
224
   * @link http://php.net/manual/en/mysqli-stmt.execute.php
225
   *
226
   * @return bool|int|Result   "Result" by "<b>SELECT</b>"-queries<br />
227
   *                           "int" (insert_id) by "<b>INSERT / REPLACE</b>"-queries<br />
228
   *                           "int" (affected_rows) by "<b>UPDATE / DELETE</b>"-queries<br />
229
   *                           "true" by e.g. "DROP"-queries<br />
230
   *                           "false" on error
231
   */
232 9
  public function execute()
233
  {
234 9
    if ($this->_use_bound_parameters_interpolated === true) {
235 6
      $this->interpolateQuery();
236 6
      call_user_func_array(array('parent', 'bind_param'), $this->_buildArguments());
237 6
    }
238
239 9
    $query_start_time = microtime(true);
240 9
    $result = parent::execute();
241 9
    $query_duration = microtime(true) - $query_start_time;
242
243 9
    if ($result === true) {
244
245
      // "INSERT" || "REPLACE"
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% 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.

Loading history...
246 7 View Code Duplication
      if (preg_match('/^\s*"?(INSERT|REPLACE)\s+/i', $this->_sql)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
247 3
        $insert_id = (int)$this->insert_id;
248 3
        $this->_debug->logQuery($this->_sql_with_bound_parameters, $query_duration, $insert_id);
249
250 3
        return $insert_id;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $insert_id; (integer) is incompatible with the return type of the parent method mysqli_stmt::execute of type boolean.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
251
      }
252
253
      // "UPDATE" || "DELETE"
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% 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.

Loading history...
254 4 View Code Duplication
      if (preg_match('/^\s*"?(UPDATE|DELETE)\s+/i', $this->_sql)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
255 2
        $affected_rows = (int)$this->affected_rows;
256 2
        $this->_debug->logQuery($this->_sql_with_bound_parameters, $query_duration, $affected_rows);
257
258 2
        return $affected_rows;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $affected_rows; (integer) is incompatible with the return type of the parent method mysqli_stmt::execute of type boolean.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
259
      }
260
261
      // "SELECT"
262 2
      if (preg_match('/^\s*"?(SELECT)\s+/i', $this->_sql)) {
263 2
        $result = $this->get_result();
0 ignored issues
show
Bug introduced by
The method get_result() does not seem to exist on object<voku\db\Prepare>.

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.

Loading history...
264 2
        $num_rows = (int)$result->num_rows;
265 2
        $this->_debug->logQuery($this->_sql_with_bound_parameters, $query_duration, $num_rows);
266
267 2
        return new Result($this->_sql_with_bound_parameters, $result);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return new \voku\db\Resu...d_parameters, $result); (voku\db\Result) is incompatible with the return type of the parent method mysqli_stmt::execute of type boolean.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
268
      }
269
270
      // log the ? query
271
      $this->_debug->logQuery($this->_sql_with_bound_parameters, $query_duration, 0);
272
273
      return true;
274
    }
275
276
    // log the error query
277 2
    $this->_debug->logQuery($this->_sql_with_bound_parameters, $query_duration, 0, true);
278
279 2
    return $this->queryErrorHandling($this->error, $this->_sql_with_bound_parameters);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->queryError...with_bound_parameters); (boolean|integer|voku\db\Result) is incompatible with the return type of the parent method mysqli_stmt::execute of type boolean.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
280
  }
281
282
  /**
283
   * Prepare an SQL statement for execution
284
   *
285
   * @link  http://php.net/manual/en/mysqli-stmt.prepare.php
286
   *
287
   * @param string $query <p>
288
   *                      The query, as a string. It must consist of a single SQL statement.
289
   *                      </p>
290
   *                      <p>
291
   *                      You can include one or more parameter markers in the SQL statement by
292
   *                      embedding question mark (?) characters at the
293
   *                      appropriate positions.
294
   *                      </p>
295
   *                      <p>
296
   *                      You should not add a terminating semicolon or \g
297
   *                      to the statement.
298
   *                      </p>
299
   *                      <p>
300
   *                      The markers are legal only in certain places in SQL statements.
301
   *                      For example, they are allowed in the VALUES() list of an INSERT statement
302
   *                      (to specify column values for a row), or in a comparison with a column in
303
   *                      a WHERE clause to specify a comparison value.
304
   *                      </p>
305
   *                      <p>
306
   *                      However, they are not allowed for identifiers (such as table or column names),
307
   *                      in the select list that names the columns to be returned by a SELECT statement),
308
   *                      or to specify both operands of a binary operator such as the =
309
   *                      equal sign. The latter restriction is necessary because it would be impossible
310
   *                      to determine the parameter type. In general, parameters are legal only in Data
311
   *                      Manipulation Language (DML) statements, and not in Data Definition Language
312
   *                      (DDL) statements.
313
   *                      </p>
314
   *
315
   * @return bool false on error
316
   * @since 5.0
317
   */
318 9
  public function prepare($query)
319
  {
320 9
    $this->_sql = $query;
321 9
    $this->_sql_with_bound_parameters = $query;
322
323 9
    if (!$this->_db->isReady()) {
324
      return false;
325
    }
326
327 9 View Code Duplication
    if (!$query || $query === '') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
328
      $this->_debug->displayError('Can\'t prepare an empty Query', false);
329
330
      return false;
331
    }
332
333 9
    $bool = parent::prepare($query);
334
335 9
    if ($bool === false) {
336 2
      $this->_debug->displayError('Can\'t prepare Query: ' . $query . ' | ' . $this->error, false);
337 2
    }
338
339 9
    return true;
340
  }
341
342
  /**
343
   * Ger the bound parameters from sql-query as array, if you use the "$this->bind_param_debug()" method.
344
   *
345
   * @return array
346
   */
347
  public function get_bound_params()
348
  {
349
    return $this->_boundParams;
350
  }
351
352
  /**
353
   * @return string
354
   */
355
  public function get_sql()
356
  {
357
    return $this->_sql;
358
  }
359
360
  /**
361
   * Get the sql-query with bound parameters, if you use the "$this->bind_param_debug()" method.
362
   *
363
   * @return string
364
   */
365 4
  public function get_sql_with_bound_parameters()
366
  {
367 4
    return $this->_sql_with_bound_parameters;
368
  }
369
370
  /**
371
   * @return int
372
   */
373
  public function insert_id()
374
  {
375
    return $this->insert_id;
376
  }
377
378
  /**
379
   * Copies $this->_sql then replaces bound markers with associated values ($this->_sql is not modified
380
   * but the resulting query string is assigned to $this->sql_bound_parameters)
381
   *
382
   * @return string $testQuery - interpolated db query string
383
   */
384 6
  private function interpolateQuery()
385
  {
386 6
    $testQuery = $this->_sql;
387 6
    if ($this->_boundParams) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->_boundParams of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
388 6
      foreach ($this->_boundParams as &$param) {
389 6
        $values = $this->_prepareValue($param);
390
391
        // set new values
392 6
        $param['value'] = $values[0];
393
        // we need to replace the question mark "?" here
394 6
        $values[1] = str_replace('?', '###simple_mysqli__prepare_question_mark###', $values[1]);
395
        // build the query (only for debugging)
396 6
        $testQuery = preg_replace("/\?/", $values[1], $testQuery, 1);
397 6
      }
398 6
      unset($param);
399 6
      $testQuery = str_replace('###simple_mysqli__prepare_question_mark###', '?', $testQuery);
400 6
    }
401 6
    $this->_sql_with_bound_parameters = $testQuery;
402
403 6
    return $testQuery;
404
  }
405
406
  /**
407
   * Error-handling for the sql-query.
408
   *
409
   * @param string $errorMsg
410
   * @param string $sql
411
   *
412
   * @throws \Exception
413
   *
414
   * @return bool
415
   */
416 2 View Code Duplication
  private function queryErrorHandling($errorMsg, $sql)
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...
417
  {
418 2
    if ($errorMsg === 'DB server has gone away' || $errorMsg === 'MySQL server has gone away') {
419
      static $reconnectCounter;
420
421
      // exit if we have more then 3 "DB server has gone away"-errors
422
      if ($reconnectCounter > 3) {
423
        $this->_debug->mailToAdmin('SQL-Fatal-Error', $errorMsg . ":\n<br />" . $sql, 5);
424
        throw new \Exception($errorMsg);
425
      }
426
427
      $this->_debug->mailToAdmin('SQL-Error', $errorMsg . ":\n<br />" . $sql);
428
429
      // reconnect
430
      $reconnectCounter++;
431
      $this->_db->reconnect(true);
432
433
      // re-run the current query
434
      return $this->execute();
435
    }
436
437 2
    $this->_debug->mailToAdmin('SQL-Warning', $errorMsg . ":\n<br />" . $sql);
438
439
    // this query returned an error, we must display it (only for dev) !!!
440 2
    $this->_debug->displayError($errorMsg . ' | ' . $sql);
441
442 2
    return false;
443
  }
444
445
}
446