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

Helper::get_mysql_client_version()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 10
ccs 6
cts 6
cp 1
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 5
nc 2
nop 1
crap 2
1
<?php
2
3
namespace voku\db;
4
5
/**
6
 * Helper: this handles extra functions that use the "DB"-Class
7
 *
8
 * @package   voku\db
9
 */
10
class Helper
11
{
12
  /**
13
   * Check if "mysqlnd"-driver is used.
14
   *
15
   * @return bool
16
   */
17 34
  public static function isMysqlndIsUsed()
18
  {
19 34
    static $_mysqlnd_is_used = null;
20
21 34
    if ($_mysqlnd_is_used === null) {
22 1
      $_mysqlnd_is_used = (extension_loaded('mysqlnd') && function_exists('mysqli_fetch_all'));
23 1
    }
24
25 34
    return $_mysqlnd_is_used;
26
  }
27
28
  /**
29
   * Check if the current environment supports "utf8mb4".
30
   *
31
   * @param DB $db
32
   *
33
   * @return bool
34
   */
35 7
  public static function isUtf8mb4Supported(DB $db)
36
  {
37
    /**
38
     *  https://make.wordpress.org/core/2015/04/02/the-utf8mb4-upgrade/
39
     *
40
     * - You’re currently using the utf8 character set.
41
     * - Your MySQL server is version 5.5.3 or higher (including all 10.x versions of MariaDB).
42
     * - Your MySQL client libraries are version 5.5.3 or higher. If you’re using mysqlnd, 5.0.9 or higher.
43
     *
44
     * INFO: utf8mb4 is 100% backwards compatible with utf8.
45
     */
46
47 7
    $server_version = self::get_mysql_server_version($db);
48 7
    $client_version = self::get_mysql_client_version($db);
49
50
    if (
51
        $server_version >= 50503
52 7
        &&
53
        (
54
            (
55 7
                self::isMysqlndIsUsed() === true
56 7
                &&
57
                $client_version >= 50009
58 7
            )
59
            ||
60
            (
61 7
                self::isMysqlndIsUsed() === false
62 7
                &&
63
                $client_version >= 50503
64
            )
65 7
        )
66
67 7
    ) {
68
      return true;
69
    }
70
71 7
    return false;
72
  }
73
74
  /**
75
   * A string that represents the MySQL client library version.
76
   *
77
   * @param DB $db
78
   *
79
   * @return string
80
   */
81 7
  public static function get_mysql_client_version(DB $db)
82
  {
83 7
    static $_mysqli_client_version = null;
84
85 7
    if ($_mysqli_client_version === null) {
86 1
      $_mysqli_client_version = \mysqli_get_client_version($db->getLink());
87 1
    }
88
89 7
    return $_mysqli_client_version;
90
  }
91
92
93
  /**
94
   * Returns a string representing the version of the MySQL server that the MySQLi extension is connected to.
95
   *
96
   * @param DB $db
97
   *
98
   * @return string
99
   */
100 7
  public static function get_mysql_server_version(DB $db)
101
  {
102 7
    static $_mysqli_server_version = null;
103
104 7
    if ($_mysqli_server_version === null) {
105 1
      $_mysqli_server_version = \mysqli_get_server_version($db->getLink());
106 1
    }
107
108 7
    return $_mysqli_server_version;
109
  }
110
111
  /**
112
   * Return all db-fields from a table.
113
   *
114
   * @param string      $table
115
   * @param bool        $useStaticCache
116
   * @param DB|null     $dbConnection <p>use <strong>null</strong> if you will use the current database-connection</p>
117
   * @param null|string $databaseName <p>use <strong>null</strong> if you will use the current database</p>
118
   *
119
   * @return array
120
   */
121 1
  public static function getDbFields($table, $useStaticCache = true, DB $dbConnection = null, $databaseName = null)
122
  {
123 1
    static $dbFieldsCache = array();
124
125
    // use the static cache
126
    if (
127
        $useStaticCache === true
128 1
        &&
129 1
        isset($dbFieldsCache[$table])
130 1
    ) {
131 1
      return $dbFieldsCache[$table];
132
    }
133
134
    // init
135 1
    $dbFields = array();
136
137 1
    if ($dbConnection === null) {
138 1
      $dbConnection = DB::getInstance();
139 1
    }
140
141 1
    if ($table === '') {
142
      $debug = new Debug($dbConnection);
143
      $debug->displayError('invalid table name');
144
145
      return array();
146
    }
147
148 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...
149
      $databaseName = $dbConnection->quote_string(trim($databaseName)) . '.';
150
    }
151
152 1
    $sql = 'SHOW COLUMNS FROM ' . $databaseName . $dbConnection->escape($table);
153 1
    $result = $dbConnection->query($sql);
154
155 1
    if ($result && $result->num_rows > 0) {
156 1
      foreach ($result->fetchAllArray() as $tmpResult) {
157 1
        $dbFields[] = $tmpResult['Field'];
158 1
      }
159 1
    }
160
161
    // add to static cache
162 1
    $dbFieldsCache[$table] = $dbFields;
163
164 1
    return $dbFields;
165
  }
166
167
  /**
168
   * Copy row within a DB table and making updates to the columns.
169
   *
170
   * @param string  $table
171
   * @param array   $whereArray
172
   * @param array   $updateArray
173
   * @param array   $ignoreArray
174
   * @param DB|null $dbConnection <p>Use <strong>null</strong> to get your first singleton instance.</p>
175
   * @param null|string $databaseName <p>use <strong>null</strong> if you will use the current database</p>
176
   *
177
   * @return bool|int "int" (insert_id) by "<b>INSERT / REPLACE</b>"-queries<br />
178
   *                   "false" on error
179
   */
180 1
  public static function copyTableRow($table, array $whereArray, array $updateArray = array(), array $ignoreArray = array(), DB $dbConnection = null, $databaseName = null)
181
  {
182
    // init
183 1
    $table = trim($table);
184
185 1
    if ($dbConnection === null) {
186 1
      $dbConnection = DB::getInstance();
187 1
    }
188
189 1
    if ($table === '') {
190
      $debug = new Debug($dbConnection);
191
      $debug->displayError('invalid table name');
192
193
      return false;
194
    }
195
196 1
    $whereSQL = '';
197 1
    foreach ($whereArray as $key => $value) {
198 1
      $whereSQL .= ' AND ' . $dbConnection->escape($key) . ' = ' . $dbConnection->escape($value);
199 1
    }
200
201 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...
202
      $databaseName = $dbConnection->quote_string(trim($databaseName)) . '.';
203
    }
204
205
    // get the row
206 1
    $query = 'SELECT * FROM ' . $databaseName . $dbConnection->quote_string($table) . '
207
      WHERE 1 = 1
208 1
      ' . $whereSQL . '
209 1
    ';
210 1
    $result = $dbConnection->query($query);
211
212
    // make sure the row exists
213 1
    if ($result->num_rows > 0) {
214
215
      /** @noinspection LoopWhichDoesNotLoopInspection */
216
      /** @noinspection PhpAssignmentInConditionInspection */
217 1
      while ($tmpArray = $result->fetchArray()) {
218
219
        // re-build a new DB query and ignore some field-names
220 1
        $bindings = array();
221 1
        $insert_keys = '';
222 1
        $insert_values = '';
223
224 1
        foreach ($tmpArray as $fieldName => $value) {
225
226 1
          if (!in_array($fieldName, $ignoreArray, true)) {
227 1
            if (array_key_exists($fieldName, $updateArray)) {
228 1
              $insert_keys .= ',' . $fieldName;
229 1
              $insert_values .= ',?';
230 1
              $bindings[] = $updateArray[$fieldName]; // INFO: do not escape non selected data
231 1
            } else {
232 1
              $insert_keys .= ',' . $fieldName;
233 1
              $insert_values .= ',?';
234 1
              $bindings[] = $value; // INFO: do not escape non selected data
235
            }
236 1
          }
237 1
        }
238
239 1
        $insert_keys = ltrim($insert_keys, ',');
240 1
        $insert_values = ltrim($insert_values, ',');
241
242
        // insert the "copied" row
243 1
        $new_query = 'INSERT INTO ' . $databaseName . $dbConnection->quote_string($table) . ' 
244 1
          (' . $insert_keys . ')
245
          VALUES 
246 1
          (' . $insert_values . ')
247 1
        ';
248 1
        return $dbConnection->query($new_query, $bindings);
249
      }
250
    }
251
252
    return false;
253
  }
254
}
255