Ignore NULL charset
[phpmyadmin-regexreplace.git] / libraries / config / validate.lib.php
blob92e4d070ee5e83df537bcc5b9a6dfdb330e5057f
1 <?php
2 /* vim: set expandtab sw=4 ts=4 sts=4: */
3 /**
4 * Various validation functions
6 * Validation function takes two argument: id for which it is called
7 * and array of fields' values (usually values for entire formset, as defined
8 * in forms.inc.php).
9 * The function must always return an array with an error (or error array)
10 * assigned to a form element (formset name or field path). Even if there are
11 * no errors, key must be set with an empty value.
13 * Valdiation functions are assigned in $cfg_db['_validators'] (config.values.php).
15 * @package phpMyAdmin
18 /**
19 * Returns validator list
21 * @uses ConfigFile::getDbEntry()
22 * @uses ConfigFile::getInstance()
23 * @return array
25 function PMA_config_get_validators()
27 static $validators = null;
29 if ($validators === null) {
30 $cf = ConfigFile::getInstance();
31 $validators = $cf->getDbEntry('_validators', array());
32 if (!defined('PMA_SETUP')) {
33 // not in setup script: load additional validators for user preferences
34 // we need oryginal config values not overwritten by user preferences, creating a new PMA_Config
35 // instance is a better idea than hacking into its code
36 $org_cfg = $cf->getOrgConfigObj();
37 $uvs = $cf->getDbEntry('_userValidators', array());
38 foreach ($uvs as $field => $uv_list) {
39 $uv_list = (array)$uv_list;
40 foreach ($uv_list as &$uv) {
41 if (!is_array($uv)) {
42 continue;
44 for ($i = 1; $i < count($uv); $i++) {
45 if (substr($uv[$i], 0, 6) == 'value:') {
46 $uv[$i] = PMA_array_read(substr($uv[$i], 6), $org_cfg->settings);
50 $validators[$field] = isset($validators[$field])
51 ? array_merge((array)$validators[$field], $uv_list)
52 : $uv_list;
56 return $validators;
59 /**
60 * Runs validation $validator_id on values $values and returns error list.
62 * Return values:
63 * o array, keys - field path or formset id, values - array of errors
64 * when $isPostSource is true values is an empty array to allow for error list
65 * cleanup in HTML documen
66 * o false - when no validators match name(s) given by $validator_id
68 * @uses ConfigFile::getCanonicalPath()
69 * @uses ConfigFile::getInstance()
70 * @uses PMA_config_get_validators()
71 * @param string|array $validator_id
72 * @param array $values
73 * @param bool $isPostSource tells whether $values are directly from POST request
74 * @return bool|array
76 function PMA_config_validate($validator_id, &$values, $isPostSource)
78 // find validators
79 $validator_id = (array) $validator_id;
80 $validators = PMA_config_get_validators();
81 $vids = array();
82 $cf = ConfigFile::getInstance();
83 foreach ($validator_id as &$vid) {
84 $vid = $cf->getCanonicalPath($vid);
85 if (isset($validators[$vid])) {
86 $vids[] = $vid;
89 if (empty($vids)) {
90 return false;
93 // create argument list with canonical paths and remember path mapping
94 $arguments = array();
95 $key_map = array();
96 foreach ($values as $k => $v) {
97 $k2 = $isPostSource ? str_replace('-', '/', $k) : $k;
98 $k2 = strpos($k2, '/') ? $cf->getCanonicalPath($k2) : $k2;
99 $key_map[$k2] = $k;
100 $arguments[$k2] = $v;
103 // validate
104 $result = array();
105 foreach ($vids as $vid) {
106 // call appropriate validation functions
107 foreach ((array)$validators[$vid] as $validator) {
108 $vdef = (array) $validator;
109 $vname = array_shift($vdef);
110 $args = array_merge(array($vid, &$arguments), $vdef);
111 $r = call_user_func_array($vname, $args);
113 // merge results
114 if (is_array($r)) {
115 foreach ($r as $key => $error_list) {
116 // skip empty values if $isPostSource is false
117 if (!$isPostSource && empty($error_list)) {
118 continue;
120 if (!isset($result[$key])) {
121 $result[$key] = array();
123 $result[$key] = array_merge($result[$key], (array)$error_list);
129 // restore original paths
130 $new_result = array();
131 foreach ($result as $k => $v) {
132 $k2 = isset($key_map[$k]) ? $key_map[$k] : $k;
133 $new_result[$k2] = $v;
135 return empty($new_result) ? true : $new_result;
139 * Empty error handler, used to temporarily restore PHP internal error handler
141 * @return bool
143 function PMA_null_error_handler()
145 return false;
149 * Ensures that $php_errormsg variable will be registered in case of an error
150 * and enables output buffering (when $start = true).
151 * Called with $start = false disables output buffering end restores
152 * html_errors and track_errors.
154 * @param boolean $start
156 function test_php_errormsg($start = true)
158 static $old_html_errors, $old_track_errors, $old_error_reporting;
159 static $old_display_errors;
160 if ($start) {
161 $old_html_errors = ini_get('html_errors');
162 $old_track_errors = ini_get('track_errors');
163 $old_display_errors = ini_get('display_errors');
164 $old_error_reporting = error_reporting(E_ALL);
165 ini_set('html_errors', false);
166 ini_set('track_errors', true);
167 ini_set('display_errors', true);
168 set_error_handler("PMA_null_error_handler");
169 ob_start();
170 } else {
171 ob_end_clean();
172 restore_error_handler();
173 error_reporting($old_error_reporting);
174 ini_set('html_errors', $old_html_errors);
175 ini_set('track_errors', $old_track_errors);
176 ini_set('display_errors', $old_display_errors);
181 * Test database connection
183 * @param string $extension 'mysql' or 'mysqli'
184 * @param string $connect_type 'tcp' or 'socket'
185 * @param string $host
186 * @param string $port
187 * @param string $socket
188 * @param string $user
189 * @param string $pass
190 * @param string $error_key
191 * @return bool|array
193 function test_db_connection($extension, $connect_type, $host, $port, $socket, $user, $pass = null, $error_key = 'Server')
195 // test_php_errormsg();
196 $socket = empty($socket) || $connect_type == 'tcp' ? null : ':' . $socket;
197 $port = empty($port) || $connect_type == 'socket' ? null : ':' . $port;
198 $error = null;
199 if ($extension == 'mysql') {
200 $conn = @mysql_connect($host . $socket . $port, $user, $pass);
201 if (!$conn) {
202 $error = __('Could not connect to MySQL server');
203 } else {
204 mysql_close($conn);
206 } else {
207 $conn = @mysqli_connect($host, $user, $pass, null, $port, $socket);
208 if (!$conn) {
209 $error = __('Could not connect to MySQL server');
210 } else {
211 mysqli_close($conn);
214 // test_php_errormsg(false);
215 if (isset($php_errormsg)) {
216 $error .= " - $php_errormsg";
218 return is_null($error) ? true : array($error_key => $error);
222 * Validate server config
224 * @uses test_db_connection()
225 * @param string $path
226 * @param array $values
227 * @return array
229 function validate_server($path, $values)
231 $result = array('Server' => '', 'Servers/1/user' => '', 'Servers/1/SignonSession' => '', 'Servers/1/SignonURL' => '');
232 $error = false;
233 if ($values['Servers/1/auth_type'] == 'config' && empty($values['Servers/1/user'])) {
234 $result['Servers/1/user'] = __('Empty username while using config authentication method');
235 $error = true;
237 if ($values['Servers/1/auth_type'] == 'signon' && empty($values['Servers/1/SignonSession'])) {
238 $result['Servers/1/SignonSession'] = __('Empty signon session name while using signon authentication method');
239 $error = true;
241 if ($values['Servers/1/auth_type'] == 'signon' && empty($values['Servers/1/SignonURL'])) {
242 $result['Servers/1/SignonURL'] = __('Empty signon URL while using signon authentication method');
243 $error = true;
246 if (!$error && $values['Servers/1/auth_type'] == 'config') {
247 $password = $values['Servers/1/nopassword'] ? null : $values['Servers/1/password'];
248 $test = test_db_connection($values['Servers/1/extension'], $values['Servers/1/connect_type'], $values['Servers/1/host'], $values['Servers/1/port'], $values['Servers/1/socket'], $values['Servers/1/user'], $password, 'Server');
249 if ($test !== true) {
250 $result = array_merge($result, $test);
253 return $result;
257 * Validate pmadb config
259 * @uses test_db_connection()
260 * @param string $path
261 * @param array $values
262 * @return array
264 function validate_pmadb($path, $values)
266 //$tables = array('Servers/1/bookmarktable', 'Servers/1/relation', 'Servers/1/table_info', 'Servers/1/table_coords', 'Servers/1/pdf_pages', 'Servers/1/column_info', 'Servers/1/history', 'Servers/1/designer_coords');
267 $result = array('Server_pmadb' => '', 'Servers/1/controluser' => '', 'Servers/1/controlpass' => '');
268 $error = false;
270 if ($values['Servers/1/pmadb'] == '') {
271 return $result;
274 $result = array();
275 if ($values['Servers/1/controluser'] == '') {
276 $result['Servers/1/controluser'] = __('Empty phpMyAdmin control user while using pmadb');
277 $error = true;
279 if ($values['Servers/1/controlpass'] == '') {
280 $result['Servers/1/controlpass'] = __('Empty phpMyAdmin control user password while using pmadb');
281 $error = true;
283 if (!$error) {
284 $test = test_db_connection($values['Servers/1/extension'], $values['Servers/1/connect_type'],
285 $values['Servers/1/host'], $values['Servers/1/port'], $values['Servers/1/socket'],
286 $values['Servers/1/controluser'], $values['Servers/1/controlpass'], 'Server_pmadb');
287 if ($test !== true) {
288 $result = array_merge($result, $test);
291 return $result;
296 * Validates regular expression
298 * @uses test_php_errormsg()
299 * @param string $path
300 * @param array $values
301 * @return array
303 function validate_regex($path, $values)
305 $result = array($path => '');
307 if ($values[$path] == '') {
308 return $result;
311 test_php_errormsg();
313 $matches = array();
314 // in libraries/List_Database.class.php _checkHideDatabase(),
315 // a '/' is used as the delimiter for hide_db
316 preg_match('/' . $values[$path] . '/', '', $matches);
318 test_php_errormsg(false);
320 if (isset($php_errormsg)) {
321 $error = preg_replace('/^preg_match\(\): /', '', $php_errormsg);
322 return array($path => $error);
325 return $result;
329 * Validates TrustedProxies field
331 * @param string $path
332 * @param array $values
333 * @return array
335 function validate_trusted_proxies($path, $values)
337 $result = array($path => array());
339 if (empty($values[$path])) {
340 return $result;
343 if (is_array($values[$path])) {
344 // value already processed by FormDisplay::save
345 $lines = array();
346 foreach ($values[$path] as $ip => $v) {
347 $lines[] = preg_match('/^-\d+$/', $ip)
348 ? $v
349 : $ip . ': ' . $v;
351 } else {
352 // AJAX validation
353 $lines = explode("\n", $values[$path]);
355 foreach ($lines as $line) {
356 $line = trim($line);
357 $matches = array();
358 // we catch anything that may (or may not) be an IP
359 if (!preg_match("/^(.+):(?:[ ]?)\\w+$/", $line, $matches)) {
360 $result[$path][] = __('Incorrect value') . ': ' . $line;
361 continue;
363 // now let's check whether we really have an IP address
364 if (filter_var($matches[1], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) === false
365 && filter_var($matches[1], FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === false) {
366 $ip = htmlspecialchars(trim($matches[1]));
367 $result[$path][] = sprintf(__('Incorrect IP address: %s'), $ip);
368 continue;
372 return $result;
376 * Tests integer value
378 * @param string $path
379 * @param array $values
380 * @param bool $allow_neg allow negative values
381 * @param bool $allow_zero allow zero
382 * @param int $max_value max allowed value
383 * @param string $error_string error message key: $GLOBALS["strConfig$error_lang_key"]
384 * @return string empty string if test is successful
386 function test_number($path, $values, $allow_neg, $allow_zero, $max_value, $error_string)
388 if ($values[$path] === '') {
389 return '';
392 if (intval($values[$path]) != $values[$path] || (!$allow_neg && $values[$path] < 0) || (!$allow_zero && $values[$path] == 0) || $values[$path] > $max_value) {
393 return $error_string;
396 return '';
400 * Validates port number
402 * @uses test_number()
403 * @param string $path
404 * @param array $values
405 * @return array
407 function validate_port_number($path, $values)
409 return array($path => test_number($path, $values, false, false, 65535, __('Not a valid port number')));
413 * Validates positive number
415 * @uses test_number()
416 * @param string $path
417 * @param array $values
418 * @return array
420 function validate_positive_number($path, $values)
422 return array($path => test_number($path, $values, false, false, PHP_INT_MAX, __('Not a positive number')));
426 * Validates non-negative number
428 * @uses test_number()
429 * @param string $path
430 * @param array $values
431 * @return array
433 function validate_non_negative_number($path, $values)
435 return array($path => test_number($path, $values, false, true, PHP_INT_MAX, __('Not a non-negative number')));
439 * Validates value according to given regular expression
440 * Pattern and modifiers must be a valid for PCRE <b>and</b> JavaScript RegExp
442 * @param string $path
443 * @param array $values
444 * @param string $regex
445 * @return void
447 function validate_by_regex($path, $values, $regex)
449 $result = preg_match($regex, $values[$path]);
450 return array($path => ($result ? '' : __('Incorrect value')));
454 * Validates upper bound for numeric inputs
456 * @param string $path
457 * @param array $values
458 * @param int $max_value
459 * @return array
461 function validate_upper_bound($path, $values, $max_value)
463 $result = $values[$path] <= $max_value;
464 return array($path => ($result ? '' : sprintf(__('Value must be equal or lower than %s'), $max_value)));