Completed
Push — master ( db4a8c...45870c )
by Lars
16:59 queued 01:30
created

Helper::get_mysql_server_version()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 14
Code Lines 7

Duplication

Lines 14
Ratio 100 %

Code Coverage

Tests 7
CRAP Score 3.0987

Importance

Changes 0
Metric Value
dl 14
loc 14
ccs 7
cts 9
cp 0.7778
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 7
nc 4
nop 1
crap 3.0987
1
<?php
2
3
namespace voku\db;
4
5
use voku\cache\Cache;
6
use voku\helper\Phonetic;
7
8
/**
9
 * Helper: This class can handle extra functions that use the "Simple-MySQLi"-classes.
10
 *
11
 * @package   voku\db
12
 */
13
class Helper
14
{
15
  /**
16
   * Optimize tables
17
   *
18
   * @param array   $tables database table names
19
   * @param DB|null $dbConnection <p>Use <strong>null</strong> to get your first singleton instance.</p>
20
   *
21
   * @return int
22
   */
23 1 View Code Duplication
  public static function optimizeTables(array $tables = array(), DB $dbConnection = null)
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...
24
  {
25 1
    if ($dbConnection === null) {
26 1
      $dbConnection = DB::getInstance();
27 1
    }
28
29 1
    $optimized = 0;
30 1
    if (!empty($tables)) {
31 1
      foreach ($tables as $table) {
32 1
        $optimize = 'OPTIMIZE TABLE ' . $dbConnection->quote_string($table);
33 1
        $result = $dbConnection->query($optimize);
34 1
        if ($result) {
35 1
          $optimized++;
36 1
        }
37 1
      }
38 1
    }
39
40 1
    return $optimized;
41
  }
42
43
  /**
44
   * Repair tables
45
   *
46
   * @param array $tables database table names
47
   * @param DB|null $dbConnection <p>Use <strong>null</strong> to get your first singleton instance.</p>
48
   *
49
   * @return int
50
   */
51 1 View Code Duplication
  public static function repairTables(array $tables = array(), DB $dbConnection = null)
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...
52
  {
53 1
    if ($dbConnection === null) {
54 1
      $dbConnection = DB::getInstance();
55 1
    }
56
57 1
    $optimized = 0;
58 1
    if (!empty($tables)) {
59 1
      foreach ($tables as $table) {
60 1
        $optimize = 'REPAIR TABLE ' . $dbConnection->quote_string($table);
61 1
        $result = $dbConnection->query($optimize);
62 1
        if ($result) {
63 1
          $optimized++;
64 1
        }
65 1
      }
66 1
    }
67
68 1
    return $optimized;
69
  }
70
71
  /**
72
   * Check if "mysqlnd"-driver is used.
73
   *
74
   * @return bool
75
   */
76 57
  public static function isMysqlndIsUsed()
77
  {
78 57
    static $_mysqlnd_is_used = null;
79
80 57
    if ($_mysqlnd_is_used === null) {
81 1
      $_mysqlnd_is_used = (extension_loaded('mysqlnd') && function_exists('mysqli_fetch_all'));
82 1
    }
83
84 57
    return $_mysqlnd_is_used;
85
  }
86
87
  /**
88
   * Check if the current environment supports "utf8mb4".
89
   *
90
   * @param DB $dbConnection
91
   *
92
   * @return bool
93
   */
94 6
  public static function isUtf8mb4Supported(DB $dbConnection = null)
95
  {
96
    /**
97
     *  https://make.wordpress.org/core/2015/04/02/the-utf8mb4-upgrade/
98
     *
99
     * - You’re currently using the utf8 character set.
100
     * - Your MySQL server is version 5.5.3 or higher (including all 10.x versions of MariaDB).
101
     * - Your MySQL client libraries are version 5.5.3 or higher. If you’re using mysqlnd, 5.0.9 or higher.
102
     *
103
     * INFO: utf8mb4 is 100% backwards compatible with utf8.
104
     */
105
106 6
    if ($dbConnection === null) {
107
      $dbConnection = DB::getInstance();
108
    }
109
110 6
    $server_version = self::get_mysql_server_version($dbConnection);
111 6
    $client_version = self::get_mysql_client_version($dbConnection);
112
113
    if (
114
        $server_version >= 50503
115 6
        &&
116
        (
117
            (
118 6
                self::isMysqlndIsUsed() === true
119 6
                &&
120
                $client_version >= 50009
121 6
            )
122
            ||
123
            (
124
                self::isMysqlndIsUsed() === false
125
                &&
126
                $client_version >= 50503
127
            )
128
        )
129
130 6
    ) {
131 6
      return true;
132
    }
133
134
    return false;
135
  }
136
137
  /**
138
   * A phonetic search algorithms for different languages.
139
   *
140
   * INFO: if you need better performance, please save the "voku\helper\Phonetic"-output into the DB and search for it
141
   *
142
   * @param string      $searchString
143
   * @param string      $searchFieldName
144
   * @param string      $idFieldName
145
   * @param string      $language <p>en, de, fr</p>
146
   * @param string      $table
147
   * @param array       $whereArray
148
   * @param DB|null     $dbConnection <p>use <strong>null</strong> if you will use the current database-connection</p>
149
   * @param null|string $databaseName <p>use <strong>null</strong> if you will use the current database</p>
150
   * @param bool        $useCache use cache?
151
   * @param int         $cacheTTL cache-ttl in seconds
152
   *
153
   * @return array
154
   */
155 2
  public static function phoneticSearch($searchString, $searchFieldName, $idFieldName = null, $language = 'de', $table, array $whereArray = null, DB $dbConnection = null, $databaseName = null, $useCache = false, $cacheTTL = 3600)
156
  {
157
    // init
158 2
    $cacheKey = null;
159 2
    $searchString = (string)$searchString;
160 2
    $searchFieldName = (string)$searchFieldName;
161
162 2
    if ($dbConnection === null) {
163 2
      $dbConnection = DB::getInstance();
164 2
    }
165
166 2 View Code Duplication
    if ($table === '') {
167
      $debug = new Debug($dbConnection);
168
      $debug->displayError('Invalid table name, table name in empty.', false);
169
170
      return array();
171
    }
172
173 2
    if ($idFieldName === null) {
174
      $idFieldName = 'id';
175
    }
176
177 2
    $whereSQL = $dbConnection->_parseArrayPair($whereArray, 'AND');
0 ignored issues
show
Bug introduced by
It seems like $whereArray defined by parameter $whereArray on line 155 can also be of type null; however, voku\db\DB::_parseArrayPair() does only seem to accept array, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
178 2
    if ($whereSQL) {
179 2
      $whereSQL = 'AND ' . $whereSQL;
180 2
    }
181
182 2
    if ($databaseName) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $databaseName of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
183
      $databaseName = $dbConnection->quote_string(trim($databaseName)) . '.';
184
    }
185
186
    // get the row
187 2
    $query = 'SELECT ' . $dbConnection->quote_string($searchFieldName) . ', ' . $dbConnection->quote_string($idFieldName) . ' 
188 2
      FROM ' . $databaseName . $dbConnection->quote_string($table) . '
189
      WHERE 1 = 1
190 2
      ' . $whereSQL . '
191 2
    ';
192
193 2 View Code Duplication
    if ($useCache === true) {
194 1
      $cache = new Cache(null, null, false, $useCache);
195 1
      $cacheKey = 'sql-phonetic-search-' . md5($query);
196
197
      if (
198 1
          $cache->getCacheIsReady() === true
199 1
          &&
200 1
          $cache->existsItem($cacheKey)
201 1
      ) {
202 1
        return $cache->getItem($cacheKey);
203
      }
204
205 1
    } else {
206 1
      $cache = false;
207
    }
208
209 2
    $result = $dbConnection->query($query);
210
211
    // make sure the row exists
212 2
    if ($result->num_rows <= 0) {
213
      return array();
214
    }
215
216 2
    $dataToSearchIn = array();
217
    /** @noinspection LoopWhichDoesNotLoopInspection */
218
    /** @noinspection PhpAssignmentInConditionInspection */
219 2
    while ($tmpArray = $result->fetchArray()) {
220 2
      $dataToSearchIn[$tmpArray[$idFieldName]] = $tmpArray[$searchFieldName];
221 2
    }
222
223 2
    $phonetic = new Phonetic($language);
224 2
    $return = $phonetic->phonetic_matches($searchString, $dataToSearchIn);
225
226
    // save into the cache
227 View Code Duplication
    if (
228
        $cacheKey !== null
229 2
        &&
230
        $useCache === true
231 2
        &&
232
        $cache instanceof Cache
233 2
        &&
234 1
        $cache->getCacheIsReady() === true
235 2
    ) {
236 1
      $cache->setItem($cacheKey, $return, $cacheTTL);
237 1
    }
238
239 2
    return $return;
240
  }
241
242
  /**
243
   * A string that represents the MySQL client library version.
244
   *
245
   * @param DB $dbConnection
246
   *
247
   * @return string
248
   */
249 6 View Code Duplication
  public static function get_mysql_client_version(DB $dbConnection = null)
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...
250
  {
251 6
    static $_mysqli_client_version = null;
252
253 6
    if ($dbConnection === null) {
254
      $dbConnection = DB::getInstance();
255
    }
256
257 6
    if ($_mysqli_client_version === null) {
258 1
      $_mysqli_client_version = \mysqli_get_client_version($dbConnection->getLink());
259 1
    }
260
261 6
    return $_mysqli_client_version;
262
  }
263
264
265
  /**
266
   * Returns a string representing the version of the MySQL server that the MySQLi extension is connected to.
267
   *
268
   * @param DB $dbConnection
269
   *
270
   * @return string
271
   */
272 6 View Code Duplication
  public static function get_mysql_server_version(DB $dbConnection = null)
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...
273
  {
274 6
    static $_mysqli_server_version = null;
275
276 6
    if ($dbConnection === null) {
277
      $dbConnection = DB::getInstance();
278
    }
279
280 6
    if ($_mysqli_server_version === null) {
281 1
      $_mysqli_server_version = \mysqli_get_server_version($dbConnection->getLink());
282 1
    }
283
284 6
    return $_mysqli_server_version;
285
  }
286
287
  /**
288
   * Return all db-fields from a table.
289
   *
290
   * @param string      $table
291
   * @param bool        $useStaticCache
292
   * @param DB|null     $dbConnection <p>use <strong>null</strong> if you will use the current database-connection</p>
293
   * @param null|string $databaseName <p>use <strong>null</strong> if you will use the current database</p>
294
   *
295
   * @return array
296
   */
297 1
  public static function getDbFields($table, $useStaticCache = true, DB $dbConnection = null, $databaseName = null)
298
  {
299 1
    static $DB_FIELDS_CACHE = array();
300
301
    // use the static cache
302
    if (
303
        $useStaticCache === true
304 1
        &&
305 1
        isset($DB_FIELDS_CACHE[$table])
306 1
    ) {
307 1
      return $DB_FIELDS_CACHE[$table];
308
    }
309
310
    // init
311 1
    $dbFields = array();
312
313 1
    if ($dbConnection === null) {
314 1
      $dbConnection = DB::getInstance();
315 1
    }
316
317 1 View Code Duplication
    if ($table === '') {
318
      $debug = new Debug($dbConnection);
319
      $debug->displayError('Invalid table name, table name in empty.', false);
320
321
      return array();
322
    }
323
324 1
    if ($databaseName) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $databaseName of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
325
      $databaseName = $dbConnection->quote_string(trim($databaseName)) . '.';
326
    }
327
328 1
    $sql = 'SHOW COLUMNS FROM ' . $databaseName . $dbConnection->escape($table);
329 1
    $result = $dbConnection->query($sql);
330
331 1
    if ($result && $result->num_rows > 0) {
332 1
      foreach ($result->fetchAllArray() as $tmpResult) {
333 1
        $dbFields[] = $tmpResult['Field'];
334 1
      }
335 1
    }
336
337
    // add to static cache
338 1
    $DB_FIELDS_CACHE[$table] = $dbFields;
339
340 1
    return $dbFields;
341
  }
342
343
  /**
344
   * Copy row within a DB table and making updates to the columns.
345
   *
346
   * @param string  $table
347
   * @param array   $whereArray
348
   * @param array   $updateArray
349
   * @param array   $ignoreArray
350
   * @param DB|null $dbConnection <p>Use <strong>null</strong> to get your first singleton instance.</p>
351
   * @param null|string $databaseName <p>use <strong>null</strong> if you will use the current database</p>
352
   *
353
   * @return bool|int "int" (insert_id) by "<b>INSERT / REPLACE</b>"-queries<br />
354
   *                   "false" on error
355
   */
356 1
  public static function copyTableRow($table, array $whereArray, array $updateArray = array(), array $ignoreArray = array(), DB $dbConnection = null, $databaseName = null)
357
  {
358
    // init
359 1
    $table = trim($table);
360
361 1
    if ($dbConnection === null) {
362 1
      $dbConnection = DB::getInstance();
363 1
    }
364
365 1 View Code Duplication
    if ($table === '') {
366
      $debug = new Debug($dbConnection);
367
      $debug->displayError('Invalid table name, table name in empty.', false);
368
369
      return false;
370
    }
371
372 1
    $whereSQL = $dbConnection->_parseArrayPair($whereArray, 'AND');
373 1
    if ($whereSQL) {
374 1
      $whereSQL = 'AND ' . $whereSQL;
375 1
    }
376
377 1
    if ($databaseName) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $databaseName of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
378
      $databaseName = $dbConnection->quote_string(trim($databaseName)) . '.';
379
    }
380
381
    // get the row
382 1
    $query = 'SELECT * FROM ' . $databaseName . $dbConnection->quote_string($table) . '
383
      WHERE 1 = 1
384 1
      ' . $whereSQL . '
385 1
    ';
386 1
    $result = $dbConnection->query($query);
387
388
    // make sure the row exists
389 1
    if ($result->num_rows > 0) {
390
391
      /** @noinspection LoopWhichDoesNotLoopInspection */
392
      /** @noinspection PhpAssignmentInConditionInspection */
393 1
      while ($tmpArray = $result->fetchArray()) {
394
395
        // re-build a new DB query and ignore some field-names
396 1
        $bindings = array();
397 1
        $insert_keys = '';
398 1
        $insert_values = '';
399
400 1
        foreach ($tmpArray as $fieldName => $value) {
401
402 1
          if (!in_array($fieldName, $ignoreArray, true)) {
403 1
            if (array_key_exists($fieldName, $updateArray)) {
404 1
              $insert_keys .= ',' . $fieldName;
405 1
              $insert_values .= ',?';
406 1
              $bindings[] = $updateArray[$fieldName]; // INFO: do not escape non selected data
407 1
            } else {
408 1
              $insert_keys .= ',' . $fieldName;
409 1
              $insert_values .= ',?';
410 1
              $bindings[] = $value; // INFO: do not escape non selected data
411
            }
412 1
          }
413 1
        }
414
415 1
        $insert_keys = ltrim($insert_keys, ',');
416 1
        $insert_values = ltrim($insert_values, ',');
417
418
        // insert the "copied" row
419 1
        $new_query = 'INSERT INTO ' . $databaseName . $dbConnection->quote_string($table) . ' 
420 1
          (' . $insert_keys . ')
421
          VALUES 
422 1
          (' . $insert_values . ')
423 1
        ';
424 1
        return $dbConnection->query($new_query, $bindings);
425
      }
426
    }
427
428
    return false;
429
  }
430
}
431