2 /* vim: set expandtab sw=4 ts=4 sts=4: */
11 require_once './libraries/common.inc.php';
14 * Does the common work
16 $GLOBALS['js_include'][] = 'server_privileges.js';
17 $GLOBALS['js_include'][] = 'functions.js';
18 $GLOBALS['js_include'][] = 'jquery/jquery-ui-1.8.16.custom.js';
19 $GLOBALS['js_include'][] = 'codemirror/lib/codemirror.js';
20 $GLOBALS['js_include'][] = 'codemirror/mode/mysql/mysql.js';
21 $_add_user_error = false;
23 require './libraries/server_common.inc.php';
25 if ($GLOBALS['cfg']['AjaxEnable']) {
26 $conditional_class = 'ajax';
28 $conditional_class = '';
32 * Messages are built using the message name
34 $strPrivDescAllPrivileges = __('Includes all privileges except GRANT.');
35 $strPrivDescAlter = __('Allows altering the structure of existing tables.');
36 $strPrivDescAlterRoutine = __('Allows altering and dropping stored routines.');
37 $strPrivDescCreateDb = __('Allows creating new databases and tables.');
38 $strPrivDescCreateRoutine = __('Allows creating stored routines.');
39 $strPrivDescCreateTbl = __('Allows creating new tables.');
40 $strPrivDescCreateTmpTable = __('Allows creating temporary tables.');
41 $strPrivDescCreateUser = __('Allows creating, dropping and renaming user accounts.');
42 $strPrivDescCreateView = __('Allows creating new views.');
43 $strPrivDescDelete = __('Allows deleting data.');
44 $strPrivDescDropDb = __('Allows dropping databases and tables.');
45 $strPrivDescDropTbl = __('Allows dropping tables.');
46 $strPrivDescEvent = __('Allows to set up events for the event scheduler');
47 $strPrivDescExecute = __('Allows executing stored routines.');
48 $strPrivDescFile = __('Allows importing data from and exporting data into files.');
49 $strPrivDescGrant = __('Allows adding users and privileges without reloading the privilege tables.');
50 $strPrivDescIndex = __('Allows creating and dropping indexes.');
51 $strPrivDescInsert = __('Allows inserting and replacing data.');
52 $strPrivDescLockTables = __('Allows locking tables for the current thread.');
53 $strPrivDescMaxConnections = __('Limits the number of new connections the user may open per hour.');
54 $strPrivDescMaxQuestions = __('Limits the number of queries the user may send to the server per hour.');
55 $strPrivDescMaxUpdates = __('Limits the number of commands that change any table or database the user may execute per hour.');
56 $strPrivDescMaxUserConnections = __('Limits the number of simultaneous connections the user may have.');
57 $strPrivDescProcess = __('Allows viewing processes of all users');
58 $strPrivDescReferences = __('Has no effect in this MySQL version.');
59 $strPrivDescReload = __('Allows reloading server settings and flushing the server\'s caches.');
60 $strPrivDescReplClient = __('Allows the user to ask where the slaves / masters are.');
61 $strPrivDescReplSlave = __('Needed for the replication slaves.');
62 $strPrivDescSelect = __('Allows reading data.');
63 $strPrivDescShowDb = __('Gives access to the complete list of databases.');
64 $strPrivDescShowView = __('Allows performing SHOW CREATE VIEW queries.');
65 $strPrivDescShutdown = __('Allows shutting down the server.');
66 $strPrivDescSuper = __('Allows connecting, even if maximum number of connections is reached; required for most administrative operations like setting global variables or killing threads of other users.');
67 $strPrivDescTrigger = __('Allows creating and dropping triggers');
68 $strPrivDescUpdate = __('Allows changing data.');
69 $strPrivDescUsage = __('No privileges.');
72 * Checks if a dropdown box has been used for selecting a database / table
74 if (PMA_isValid($_REQUEST['pred_tablename'])) {
75 $tablename = $_REQUEST['pred_tablename'];
76 unset($pred_tablename);
77 } elseif (PMA_isValid($_REQUEST['tablename'])) {
78 $tablename = $_REQUEST['tablename'];
83 if (PMA_isValid($_REQUEST['pred_dbname'])) {
84 $dbname = $_REQUEST['pred_dbname'];
86 } elseif (PMA_isValid($_REQUEST['dbname'])) {
87 $dbname = $_REQUEST['dbname'];
94 $db_and_table = PMA_backquote(PMA_unescape_mysql_wildcards($dbname)) . '.';
95 if (isset($tablename)) {
96 $db_and_table .= PMA_backquote($tablename);
101 $db_and_table = '*.*';
104 // check if given $dbname is a wildcard or not
105 if (isset($dbname)) {
106 //if (preg_match('/\\\\(?:_|%)/i', $dbname)) {
107 if (preg_match('/(?<!\\\\)(?:_|%)/i', $dbname)) {
108 $dbname_is_wildcard = true;
110 $dbname_is_wildcard = false;
115 * Checks if the user is allowed to do what he tries to...
117 if (! $is_superuser) {
118 include './libraries/server_links.inc.php';
120 . PMA_getIcon('b_usrlist.png')
121 . __('Privileges') . "\n"
123 PMA_Message
::error(__('No Privileges'))->display();
124 include './libraries/footer.inc.php';
127 $random_n = mt_rand(0, 1000000); // a random number that will be appended to the id of the user forms
130 * Escapes wildcard in a database+table specification
131 * before using it in a GRANT statement.
133 * Escaping a wildcard character in a GRANT is only accepted at the global
134 * or database level, not at table level; this is why I remove
135 * the escaping character. Internally, in mysql.tables_priv.Db there are
136 * no escaping (for example test_db) but in mysql.db you'll see test\_db
137 * for a db-specific privilege.
139 * @param string $dbname Database name
140 * @param string $tablename Table name
142 * @return string the escaped (if necessary) database.table
144 function PMA_wildcardEscapeForGrant($dbname, $tablename)
147 if (! strlen($dbname)) {
148 $db_and_table = '*.*';
150 if (strlen($tablename)) {
151 $db_and_table = PMA_backquote(PMA_unescape_mysql_wildcards($dbname)) . '.';
152 $db_and_table .= PMA_backquote($tablename);
154 $db_and_table = PMA_backquote($dbname) . '.';
155 $db_and_table .= '*';
158 return $db_and_table;
162 * Generates a condition on the user name
164 * @param string $initial the user's initial
166 * @return string the generated condition
168 function PMA_rangeOfUsers($initial = '')
170 // strtolower() is used because the User field
171 // might be BINARY, so LIKE would be case sensitive
172 if (! empty($initial)) {
173 $ret = " WHERE `User` LIKE '" . PMA_sqlAddSlashes($initial, true) . "%'"
174 . " OR `User` LIKE '" . PMA_sqlAddSlashes(strtolower($initial), true) . "%'";
182 * Extracts the privilege information of a priv table row
184 * @param array $row the row
185 * @param boolean $enableHTML add <dfn> tag with tooltips
187 * @global resource $user_link the database connection
191 function PMA_extractPrivInfo($row = '', $enableHTML = false)
197 __('Allows reading data.')),
201 __('Allows inserting and replacing data.')),
205 __('Allows changing data.')),
209 __('Allows deleting data.')),
213 __('Allows creating new databases and tables.')),
217 __('Allows dropping databases and tables.')),
221 __('Allows reloading server settings and flushing the server\'s caches.')),
225 __('Allows shutting down the server.')),
229 __('Allows viewing processes of all users')),
233 __('Allows importing data from and exporting data into files.')),
237 __('Has no effect in this MySQL version.')),
241 __('Allows creating and dropping indexes.')),
245 __('Allows altering the structure of existing tables.')),
249 __('Gives access to the complete list of databases.')),
253 __('Allows connecting, even if maximum number of connections is reached; required for most administrative operations like setting global variables or killing threads of other users.')),
255 'Create_tmp_table_priv',
256 'CREATE TEMPORARY TABLES',
257 __('Allows creating temporary tables.')),
261 __('Allows locking tables for the current thread.')),
265 __('Needed for the replication slaves.')),
268 'REPLICATION CLIENT',
269 __('Allows the user to ask where the slaves / masters are.')),
273 __('Allows creating new views.')),
277 __('Allows to set up events for the event scheduler')),
281 __('Allows creating and dropping triggers')),
286 __('Allows creating new views.')),
290 __('Allows performing SHOW CREATE VIEW queries.')),
295 __('Allows performing SHOW CREATE VIEW queries.')),
297 'Create_routine_priv',
299 __('Allows creating stored routines.')),
301 'Alter_routine_priv',
303 __('Allows altering and dropping stored routines.')),
307 __('Allows creating, dropping and renaming user accounts.')),
311 __('Allows executing stored routines.')),
314 if (! empty($row) && isset($row['Table_priv'])) {
315 $row1 = PMA_DBI_fetch_single_row(
316 'SHOW COLUMNS FROM `mysql`.`tables_priv` LIKE \'Table_priv\';',
317 'ASSOC', $GLOBALS['userlink']
319 $av_grants = explode('\',\'', substr($row1['Type'], 5, strlen($row1['Type']) - 7));
321 $users_grants = explode(',', $row['Table_priv']);
322 foreach ($av_grants as $current_grant) {
323 $row[$current_grant . '_priv'] = in_array($current_grant, $users_grants) ?
'Y' : 'N';
325 unset($current_grant);
327 unset($users_grants);
330 $allPrivileges = true;
331 foreach ($grants as $current_grant) {
332 if ((! empty($row) && isset($row[$current_grant[0]]))
333 ||
(empty($row) && isset($GLOBALS[$current_grant[0]]))
335 if ((! empty($row) && $row[$current_grant[0]] == 'Y')
337 && ($GLOBALS[$current_grant[0]] == 'Y'
338 ||
(is_array($GLOBALS[$current_grant[0]])
339 && count($GLOBALS[$current_grant[0]]) == $GLOBALS['column_count']
340 && empty($GLOBALS[$current_grant[0] . '_none']))))
343 $privs[] = '<dfn title="' . $current_grant[2] . '">' . $current_grant[1] . '</dfn>';
345 $privs[] = $current_grant[1];
347 } elseif (! empty($GLOBALS[$current_grant[0]])
348 && is_array($GLOBALS[$current_grant[0]])
349 && empty($GLOBALS[$current_grant[0] . '_none'])) {
351 $priv_string = '<dfn title="' . $current_grant[2] . '">' . $current_grant[1] . '</dfn>';
353 $priv_string = $current_grant[1];
355 $privs[] = $priv_string . ' (`' . join('`, `', $GLOBALS[$current_grant[0]]) . '`)';
357 $allPrivileges = false;
363 $privs[] = '<dfn title="' . __('No privileges.') . '">USAGE</dfn>';
367 } elseif ($allPrivileges && (! isset($GLOBALS['grant_count']) ||
count($privs) == $GLOBALS['grant_count'])) {
369 $privs = array('<dfn title="' . __('Includes all privileges except GRANT.') . '">ALL PRIVILEGES</dfn>');
371 $privs = array('ALL PRIVILEGES');
375 } // end of the 'PMA_extractPrivInfo()' function
378 * Displays on which column(s) a table-specific privilege is granted
380 function PMA_display_column_privs($columns, $row, $name_for_select,
381 $priv_for_header, $name, $name_for_dfn, $name_for_current)
383 echo ' <div class="item" id="div_item_' . $name . '">' . "\n"
384 . ' <label for="select_' . $name . '_priv">' . "\n"
385 . ' <tt><dfn title="' . $name_for_dfn . '">'
386 . $priv_for_header . '</dfn></tt>' . "\n"
387 . ' </label><br />' . "\n"
388 . ' <select id="select_' . $name . '_priv" name="'
389 . $name_for_select . '[]" multiple="multiple" size="8">' . "\n";
391 foreach ($columns as $current_column => $current_column_privileges) {
392 echo ' <option value="' . htmlspecialchars($current_column) . '"';
393 if ($row[$name_for_select] == 'Y' ||
$current_column_privileges[$name_for_current]) {
394 echo ' selected="selected"';
396 echo '>' . htmlspecialchars($current_column) . '</option>' . "\n";
399 echo ' </select>' . "\n"
400 . ' <i>' . __('Or') . '</i>' . "\n"
401 . ' <label for="checkbox_' . $name_for_select
402 . '_none"><input type="checkbox"'
403 . (empty($GLOBALS['checkall']) ?
'' : ' checked="checked"')
404 . ' name="' . $name_for_select . '_none" id="checkbox_'
405 . $name_for_select . '_none" title="' . _pgettext('None privileges', 'None') . '" />'
406 . _pgettext('None privileges', 'None') . '</label>' . "\n"
412 * Displays the privileges form table
414 * @param string $db the database
415 * @param string $table the table
416 * @param boolean $submit wheather to display the submit button or not
418 * @global array $cfg the phpMyAdmin configuration
419 * @global ressource $user_link the database connection
423 function PMA_displayPrivTable($db = '*', $table = '*', $submit = true)
431 if (isset($GLOBALS['username'])) {
432 $username = $GLOBALS['username'];
433 $hostname = $GLOBALS['hostname'];
435 $sql_query = "SELECT * FROM `mysql`.`user`"
436 ." WHERE `User` = '" . PMA_sqlAddSlashes($username) . "'"
437 ." AND `Host` = '" . PMA_sqlAddSlashes($hostname) . "';";
438 } elseif ($table == '*') {
439 $sql_query = "SELECT * FROM `mysql`.`db`"
440 ." WHERE `User` = '" . PMA_sqlAddSlashes($username) . "'"
441 ." AND `Host` = '" . PMA_sqlAddSlashes($hostname) . "'"
442 ." AND '" . PMA_unescape_mysql_wildcards($db) . "'"
445 $sql_query = "SELECT `Table_priv`"
446 ." FROM `mysql`.`tables_priv`"
447 ." WHERE `User` = '" . PMA_sqlAddSlashes($username) . "'"
448 ." AND `Host` = '" . PMA_sqlAddSlashes($hostname) . "'"
449 ." AND `Db` = '" . PMA_unescape_mysql_wildcards($db) . "'"
450 ." AND `Table_name` = '" . PMA_sqlAddSlashes($table) . "';";
452 $row = PMA_DBI_fetch_single_row($sql_query);
457 $sql_query = 'SHOW COLUMNS FROM `mysql`.`user`;';
458 } elseif ($table == '*') {
459 $sql_query = 'SHOW COLUMNS FROM `mysql`.`db`;';
461 $res = PMA_DBI_query($sql_query);
462 while ($row1 = PMA_DBI_fetch_row($res)) {
463 if (substr($row1[0], 0, 4) == 'max_') {
466 $row[$row1[0]] = 'N';
469 PMA_DBI_free_result($res);
471 $row = array('Table_priv' => '');
474 if (isset($row['Table_priv'])) {
475 $row1 = PMA_DBI_fetch_single_row(
476 'SHOW COLUMNS FROM `mysql`.`tables_priv` LIKE \'Table_priv\';',
477 'ASSOC', $GLOBALS['userlink']
479 // note: in MySQL 5.0.3 we get "Create View', 'Show view';
480 // the View for Create is spelled with uppercase V
481 // the view for Show is spelled with lowercase v
482 // and there is a space between the words
484 $av_grants = explode('\',\'', substr($row1['Type'], strpos($row1['Type'], '(') +
2, strpos($row1['Type'], ')') - strpos($row1['Type'], '(') - 3));
486 $users_grants = explode(',', $row['Table_priv']);
488 foreach ($av_grants as $current_grant) {
489 $row[$current_grant . '_priv'] = in_array($current_grant, $users_grants) ?
'Y' : 'N';
491 unset($row['Table_priv'], $current_grant, $av_grants, $users_grants);
494 $res = PMA_DBI_try_query('SHOW COLUMNS FROM ' . PMA_backquote(PMA_unescape_mysql_wildcards($db)) . '.' . PMA_backquote($table) . ';');
497 while ($row1 = PMA_DBI_fetch_row($res)) {
498 $columns[$row1[0]] = array(
502 'References' => false
505 PMA_DBI_free_result($res);
509 // t a b l e - s p e c i f i c p r i v i l e g e s
510 if (! empty($columns)) {
511 $res = PMA_DBI_query(
512 'SELECT `Column_name`, `Column_priv`'
513 .' FROM `mysql`.`columns_priv`'
515 .' = \'' . PMA_sqlAddSlashes($username) . "'"
517 .' = \'' . PMA_sqlAddSlashes($hostname) . "'"
519 .' = \'' . PMA_sqlAddSlashes(PMA_unescape_mysql_wildcards($db)) . "'"
521 .' = \'' . PMA_sqlAddSlashes($table) . '\';'
524 while ($row1 = PMA_DBI_fetch_row($res)) {
525 $row1[1] = explode(',', $row1[1]);
526 foreach ($row1[1] as $current) {
527 $columns[$row1[0]][$current] = true;
530 PMA_DBI_free_result($res);
531 unset($res, $row1, $current);
533 echo '<input type="hidden" name="grant_count" value="' . count($row) . '" />' . "\n"
534 . '<input type="hidden" name="column_count" value="' . count($columns) . '" />' . "\n"
535 . '<fieldset id="fieldset_user_priv">' . "\n"
536 . ' <legend>' . __('Table-specific privileges')
537 . PMA_showHint(__('Note: MySQL privilege names are expressed in English'))
538 . '</legend>' . "\n";
542 // privs that are attached to a specific column
543 PMA_display_column_privs(
544 $columns, $row, 'Select_priv', 'SELECT',
545 'select', __('Allows reading data.'), 'Select'
548 PMA_display_column_privs(
549 $columns, $row, 'Insert_priv', 'INSERT',
550 'insert', __('Allows inserting and replacing data.'), 'Insert'
553 PMA_display_column_privs(
554 $columns, $row, 'Update_priv', 'UPDATE',
555 'update', __('Allows changing data.'), 'Update'
558 PMA_display_column_privs(
559 $columns, $row, 'References_priv', 'REFERENCES', 'references',
560 __('Has no effect in this MySQL version.'), 'References'
563 // privs that are not attached to a specific column
565 echo ' <div class="item">' . "\n";
566 foreach ($row as $current_grant => $current_grant_value) {
567 if (in_array(substr($current_grant, 0, (strlen($current_grant) - 5)),
568 array('Select', 'Insert', 'Update', 'References'))) {
571 // make a substitution to match the messages variables;
572 // also we must substitute the grant we get, because we can't generate
573 // a form variable containing blanks (those would get changed to
574 // an underscore when receiving the POST)
575 if ($current_grant == 'Create View_priv') {
576 $tmp_current_grant = 'CreateView_priv';
577 $current_grant = 'Create_view_priv';
578 } elseif ($current_grant == 'Show view_priv') {
579 $tmp_current_grant = 'ShowView_priv';
580 $current_grant = 'Show_view_priv';
582 $tmp_current_grant = $current_grant;
585 echo ' <div class="item">' . "\n"
586 . ' <input type="checkbox"'
587 . (empty($GLOBALS['checkall']) ?
'' : ' checked="checked"')
588 . ' name="' . $current_grant . '" id="checkbox_' . $current_grant
590 . ($current_grant_value == 'Y' ?
'checked="checked" ' : '')
593 echo (isset($GLOBALS['strPrivDesc' . substr($tmp_current_grant, 0, (strlen($tmp_current_grant) - 5))])
594 ?
$GLOBALS['strPrivDesc' . substr($tmp_current_grant, 0, (strlen($tmp_current_grant) - 5))]
595 : $GLOBALS['strPrivDesc' . substr($tmp_current_grant, 0, (strlen($tmp_current_grant) - 5)) . 'Tbl']) . '"/>' . "\n";
597 echo ' <label for="checkbox_' . $current_grant
598 . '"><tt><dfn title="'
599 . (isset($GLOBALS['strPrivDesc' . substr($tmp_current_grant, 0, (strlen($tmp_current_grant) - 5))])
600 ?
$GLOBALS['strPrivDesc' . substr($tmp_current_grant, 0, (strlen($tmp_current_grant) - 5))]
601 : $GLOBALS['strPrivDesc' . substr($tmp_current_grant, 0, (strlen($tmp_current_grant) - 5)) . 'Tbl'])
602 . '">' . strtoupper(substr($current_grant, 0, strlen($current_grant) - 5)) . '</dfn></tt></label>' . "\n"
606 echo ' </div>' . "\n";
608 echo ' <div class="clearfloat"></div>' . "\n";
612 // g l o b a l o r d b - s p e c i f i c
614 $privTable_names = array(0 => __('Data'), 1 => __('Structure'), 2 => __('Administration'));
617 $privTable[0] = array(
618 array('Select', 'SELECT', __('Allows reading data.')),
619 array('Insert', 'INSERT', __('Allows inserting and replacing data.')),
620 array('Update', 'UPDATE', __('Allows changing data.')),
621 array('Delete', 'DELETE', __('Allows deleting data.'))
624 $privTable[0][] = array('File', 'FILE', __('Allows importing data from and exporting data into files.'));
628 $privTable[1] = array(
629 array('Create', 'CREATE', ($table == '*' ?
__('Allows creating new databases and tables.') : __('Allows creating new tables.'))),
630 array('Alter', 'ALTER', __('Allows altering the structure of existing tables.')),
631 array('Index', 'INDEX', __('Allows creating and dropping indexes.')),
632 array('Drop', 'DROP', ($table == '*' ?
__('Allows dropping databases and tables.') : __('Allows dropping tables.'))),
633 array('Create_tmp_table', 'CREATE TEMPORARY TABLES', __('Allows creating temporary tables.')),
634 array('Show_view', 'SHOW VIEW', __('Allows performing SHOW CREATE VIEW queries.')),
635 array('Create_routine', 'CREATE ROUTINE', __('Allows creating stored routines.')),
636 array('Alter_routine', 'ALTER ROUTINE', __('Allows altering and dropping stored routines.')),
637 array('Execute', 'EXECUTE', __('Allows executing stored routines.')),
639 // this one is for a db-specific priv: Create_view_priv
640 if (isset($row['Create_view_priv'])) {
641 $privTable[1][] = array('Create_view', 'CREATE VIEW', __('Allows creating new views.'));
643 // this one is for a table-specific priv: Create View_priv
644 if (isset($row['Create View_priv'])) {
645 $privTable[1][] = array('Create View', 'CREATE VIEW', __('Allows creating new views.'));
647 if (isset($row['Event_priv'])) {
649 $privTable[1][] = array('Event', 'EVENT', __('Allows to set up events for the event scheduler'));
650 $privTable[1][] = array('Trigger', 'TRIGGER', __('Allows creating and dropping triggers'));
653 // a d m i n i s t r a t i o n
654 $privTable[2] = array(
655 array('Grant', 'GRANT', __('Allows adding users and privileges without reloading the privilege tables.')),
658 $privTable[2][] = array('Super', 'SUPER', __('Allows connecting, even if maximum number of connections is reached; required for most administrative operations like setting global variables or killing threads of other users.'));
659 $privTable[2][] = array('Process', 'PROCESS', __('Allows viewing processes of all users'));
660 $privTable[2][] = array('Reload', 'RELOAD', __('Allows reloading server settings and flushing the server\'s caches.'));
661 $privTable[2][] = array('Shutdown', 'SHUTDOWN', __('Allows shutting down the server.'));
662 $privTable[2][] = array('Show_db', 'SHOW DATABASES', __('Gives access to the complete list of databases.'));
664 $privTable[2][] = array('Lock_tables', 'LOCK TABLES', __('Allows locking tables for the current thread.'));
665 $privTable[2][] = array('References', 'REFERENCES', __('Has no effect in this MySQL version.'));
667 $privTable[2][] = array('Repl_client', 'REPLICATION CLIENT', __('Allows the user to ask where the slaves / masters are.'));
668 $privTable[2][] = array('Repl_slave', 'REPLICATION SLAVE', __('Needed for the replication slaves.'));
669 $privTable[2][] = array('Create_user', 'CREATE USER', __('Allows creating, dropping and renaming user accounts.'));
671 echo '<input type="hidden" name="grant_count" value="'
672 . (count($privTable[0]) +
count($privTable[1]) +
count($privTable[2]) - (isset($row['Grant_priv']) ?
1 : 0))
674 . '<fieldset id="fieldset_user_global_rights">' . "\n"
678 ?
__('Global privileges')
680 ?
__('Database-specific privileges')
681 : __('Table-specific privileges'))) . "\n"
682 . ' (<a href="server_privileges.php?'
683 . $GLOBALS['url_query'] . '&checkall=1" onclick="setCheckboxes(\'addUsersForm_' . $random_n . '\', true); return false;">'
684 . __('Check All') . '</a> /' . "\n"
685 . ' <a href="server_privileges.php?'
686 . $GLOBALS['url_query'] . '" onclick="setCheckboxes(\'addUsersForm_' . $random_n . '\', false); return false;">'
687 . __('Uncheck All') . '</a>)' . "\n"
688 . ' </legend>' . "\n"
689 . ' <p><small><i>' . __('Note: MySQL privilege names are expressed in English') . '</i></small></p>' . "\n";
691 // Output the Global privilege tables with checkboxes
692 foreach ($privTable as $i => $table) {
693 echo ' <fieldset>' . "\n"
694 . ' <legend>' . __($privTable_names[$i]) . '</legend>' . "\n";
695 foreach ($table as $priv) {
696 echo ' <div class="item">' . "\n"
697 . ' <input type="checkbox"'
698 . ' name="' . $priv[0] . '_priv" id="checkbox_' . $priv[0] . '_priv"'
699 . ' value="Y" title="' . $priv[2] . '"'
700 . ((! empty($GLOBALS['checkall']) ||
$row[$priv[0] . '_priv'] == 'Y') ?
' checked="checked"' : '')
702 . ' <label for="checkbox_' . $priv[0] . '_priv"><tt><dfn title="' . $priv[2] . '">'
703 . $priv[1] . '</dfn></tt></label>' . "\n"
706 echo ' </fieldset>' . "\n";
709 // The "Resource limits" box is not displayed for db-specific privs
711 echo ' <fieldset>' . "\n"
712 . ' <legend>' . __('Resource limits') . '</legend>' . "\n"
713 . ' <p><small><i>' . __('Note: Setting these options to 0 (zero) removes the limit.') . '</i></small></p>' . "\n"
714 . ' <div class="item">' . "\n"
715 . ' <label for="text_max_questions"><tt><dfn title="'
716 . __('Limits the number of queries the user may send to the server per hour.') . '">MAX QUERIES PER HOUR</dfn></tt></label>' . "\n"
717 . ' <input type="text" name="max_questions" id="text_max_questions" value="'
718 . $row['max_questions'] . '" size="11" maxlength="11" title="' . __('Limits the number of queries the user may send to the server per hour.') . '" />' . "\n"
720 . ' <div class="item">' . "\n"
721 . ' <label for="text_max_updates"><tt><dfn title="'
722 . __('Limits the number of commands that change any table or database the user may execute per hour.') . '">MAX UPDATES PER HOUR</dfn></tt></label>' . "\n"
723 . ' <input type="text" name="max_updates" id="text_max_updates" value="'
724 . $row['max_updates'] . '" size="11" maxlength="11" title="' . __('Limits the number of commands that change any table or database the user may execute per hour.') . '" />' . "\n"
726 . ' <div class="item">' . "\n"
727 . ' <label for="text_max_connections"><tt><dfn title="'
728 . __('Limits the number of new connections the user may open per hour.') . '">MAX CONNECTIONS PER HOUR</dfn></tt></label>' . "\n"
729 . ' <input type="text" name="max_connections" id="text_max_connections" value="'
730 . $row['max_connections'] . '" size="11" maxlength="11" title="' . __('Limits the number of new connections the user may open per hour.') . '" />' . "\n"
732 . ' <div class="item">' . "\n"
733 . ' <label for="text_max_user_connections"><tt><dfn title="'
734 . __('Limits the number of simultaneous connections the user may have.') . '">MAX USER_CONNECTIONS</dfn></tt></label>' . "\n"
735 . ' <input type="text" name="max_user_connections" id="text_max_user_connections" value="'
736 . $row['max_user_connections'] . '" size="11" maxlength="11" title="' . __('Limits the number of simultaneous connections the user may have.') . '" />' . "\n"
738 . ' </fieldset>' . "\n";
741 echo ' <div class="clearfloat"></div>' . "\n";
743 echo '</fieldset>' . "\n";
745 echo '<fieldset id="fieldset_user_privtable_footer" class="tblFooters">' . "\n"
746 . ' <input type="submit" name="update_privs" value="' . __('Go') . '" />' . "\n"
747 . '</fieldset>' . "\n";
749 } // end of the 'PMA_displayPrivTable()' function
753 * Displays the fields used by the "new user" form as well as the
754 * "change login information / copy user" form.
756 * @param string $mode are we creating a new user or are we just
757 * changing one? (allowed values: 'new', 'change')
759 * @global array $cfg the phpMyAdmin configuration
760 * @global ressource $user_link the database connection
764 function PMA_displayLoginInformationFields($mode = 'new')
766 // Get user/host name lengths
767 $fields_info = PMA_DBI_get_columns('mysql', 'user', null, true);
768 $username_length = 16;
769 $hostname_length = 41;
770 foreach ($fields_info as $val) {
771 if ($val['Field'] == 'User') {
772 strtok($val['Type'], '()');
775 $username_length = $v;
777 } elseif ($val['Field'] == 'Host') {
778 strtok($val['Type'], '()');
781 $hostname_length = $v;
787 if (isset($GLOBALS['username']) && strlen($GLOBALS['username']) === 0) {
788 $GLOBALS['pred_username'] = 'any';
790 echo '<fieldset id="fieldset_add_user_login">' . "\n"
791 . '<legend>' . __('Login Information') . '</legend>' . "\n"
792 . '<div class="item">' . "\n"
793 . '<label for="select_pred_username">' . "\n"
794 . ' ' . __('User name') . ':' . "\n"
796 . '<span class="options">' . "\n"
797 . ' <select name="pred_username" id="select_pred_username" title="' . __('User name') . '"' . "\n"
798 . ' onchange="if (this.value == \'any\') { username.value = \'\'; } else if (this.value == \'userdefined\') { username.focus(); username.select(); }">' . "\n"
799 . ' <option value="any"' . ((isset($GLOBALS['pred_username']) && $GLOBALS['pred_username'] == 'any') ?
' selected="selected"' : '') . '>' . __('Any user') . '</option>' . "\n"
800 . ' <option value="userdefined"' . ((! isset($GLOBALS['pred_username']) ||
$GLOBALS['pred_username'] == 'userdefined') ?
' selected="selected"' : '') . '>' . __('Use text field') . ':</option>' . "\n"
801 . ' </select>' . "\n"
803 . '<input type="text" name="username" maxlength="'
804 . $username_length . '" title="' . __('User name') . '"'
805 . (empty($GLOBALS['username'])
807 : ' value="' . htmlspecialchars(isset($GLOBALS['new_username'])
808 ?
$GLOBALS['new_username']
809 : $GLOBALS['username']) . '"')
810 . ' onchange="pred_username.value = \'userdefined\';" />' . "\n"
812 . '<div class="item">' . "\n"
813 . '<label for="select_pred_hostname">' . "\n"
814 . ' ' . __('Host') . ':' . "\n"
816 . '<span class="options">' . "\n"
817 . ' <select name="pred_hostname" id="select_pred_hostname" title="' . __('Host') . '"' . "\n";
818 $_current_user = PMA_DBI_fetch_value('SELECT USER();');
819 if (! empty($_current_user)) {
820 $thishost = str_replace("'", '', substr($_current_user, (strrpos($_current_user, '@') +
1)));
821 if ($thishost == 'localhost' ||
$thishost == '127.0.0.1') {
825 echo ' onchange="if (this.value == \'any\') { hostname.value = \'%\'; } else if (this.value == \'localhost\') { hostname.value = \'localhost\'; } '
826 . (empty($thishost) ?
'' : 'else if (this.value == \'thishost\') { hostname.value = \'' . addslashes(htmlspecialchars($thishost)) . '\'; } ')
827 . 'else if (this.value == \'hosttable\') { hostname.value = \'\'; } else if (this.value == \'userdefined\') { hostname.focus(); hostname.select(); }">' . "\n";
828 unset($_current_user);
830 // when we start editing a user, $GLOBALS['pred_hostname'] is not defined
831 if (! isset($GLOBALS['pred_hostname']) && isset($GLOBALS['hostname'])) {
832 switch (strtolower($GLOBALS['hostname'])) {
835 $GLOBALS['pred_hostname'] = 'localhost';
838 $GLOBALS['pred_hostname'] = 'any';
841 $GLOBALS['pred_hostname'] = 'userdefined';
845 echo ' <option value="any"'
846 . ((isset($GLOBALS['pred_hostname']) && $GLOBALS['pred_hostname'] == 'any')
847 ?
' selected="selected"' : '') . '>' . __('Any host')
849 . ' <option value="localhost"'
850 . ((isset($GLOBALS['pred_hostname']) && $GLOBALS['pred_hostname'] == 'localhost')
851 ?
' selected="selected"' : '') . '>' . __('Local')
852 . '</option>' . "\n";
853 if (! empty($thishost)) {
854 echo ' <option value="thishost"'
855 . ((isset($GLOBALS['pred_hostname']) && $GLOBALS['pred_hostname'] == 'thishost')
856 ?
' selected="selected"' : '') . '>' . __('This Host')
857 . '</option>' . "\n";
860 echo ' <option value="hosttable"'
861 . ((isset($GLOBALS['pred_hostname']) && $GLOBALS['pred_hostname'] == 'hosttable')
862 ?
' selected="selected"' : '') . '>' . __('Use Host Table')
864 . ' <option value="userdefined"'
865 . ((isset($GLOBALS['pred_hostname']) && $GLOBALS['pred_hostname'] == 'userdefined')
866 ?
' selected="selected"' : '')
867 . '>' . __('Use text field') . ':</option>' . "\n"
868 . ' </select>' . "\n"
870 . '<input type="text" name="hostname" maxlength="'
871 . $hostname_length . '" value="'
872 . htmlspecialchars(isset($GLOBALS['hostname']) ?
$GLOBALS['hostname'] : '')
873 . '" title="' . __('Host')
874 . '" onchange="pred_hostname.value = \'userdefined\';" />' . "\n"
875 . PMA_showHint(__('When Host table is used, this field is ignored and values stored in Host table are used instead.'))
877 . '<div class="item">' . "\n"
878 . '<label for="select_pred_password">' . "\n"
879 . ' ' . __('Password') . ':' . "\n"
881 . '<span class="options">' . "\n"
882 . ' <select name="pred_password" id="select_pred_password" title="'
883 . __('Password') . '"' . "\n"
884 . ' onchange="if (this.value == \'none\') { pma_pw.value = \'\'; pma_pw2.value = \'\'; } else if (this.value == \'userdefined\') { pma_pw.focus(); pma_pw.select(); }">' . "\n"
885 . ($mode == 'change' ?
' <option value="keep" selected="selected">' . __('Do not change the password') . '</option>' . "\n" : '')
886 . ' <option value="none"';
887 if (isset($GLOBALS['username']) && $mode != 'change') {
888 echo ' selected="selected"';
890 echo '>' . __('No Password') . '</option>' . "\n"
891 . ' <option value="userdefined"' . (isset($GLOBALS['username']) ?
'' : ' selected="selected"') . '>' . __('Use text field') . ':</option>' . "\n"
892 . ' </select>' . "\n"
894 . '<input type="password" id="text_pma_pw" name="pma_pw" title="' . __('Password') . '" onchange="pred_password.value = \'userdefined\';" />' . "\n"
896 . '<div class="item" id="div_element_before_generate_password">' . "\n"
897 . '<label for="text_pma_pw2">' . "\n"
898 . ' ' . __('Re-type') . ':' . "\n"
900 . '<span class="options"> </span>' . "\n"
901 . '<input type="password" name="pma_pw2" id="text_pma_pw2" title="' . __('Re-type') . '" onchange="pred_password.value = \'userdefined\';" />' . "\n"
903 // Generate password added here via jQuery
904 . '</fieldset>' . "\n";
905 } // end of the 'PMA_displayUserAndHostFields()' function
908 * Changes / copies a user, part I
910 if (isset($_REQUEST['change_copy'])) {
911 $user_host_condition = ' WHERE `User`'
912 .' = \'' . PMA_sqlAddSlashes($old_username) . "'"
914 .' = \'' . PMA_sqlAddSlashes($old_hostname) . '\';';
915 $row = PMA_DBI_fetch_single_row('SELECT * FROM `mysql`.`user` ' . $user_host_condition);
917 PMA_Message
::notice(__('No user found.'))->display();
918 unset($_REQUEST['change_copy']);
920 extract($row, EXTR_OVERWRITE
);
921 // Recent MySQL versions have the field "Password" in mysql.user,
922 // so the previous extract creates $Password but this script
924 if (! isset($password) && isset($Password)) {
925 $password = $Password;
934 * (Changes / copies a user, part II)
936 if (isset($_REQUEST['adduser_submit']) ||
isset($_REQUEST['change_copy'])) {
938 if ($pred_username == 'any') {
941 switch ($pred_hostname) {
946 $hostname = 'localhost';
952 $_user_name = PMA_DBI_fetch_value('SELECT USER()');
953 $hostname = substr($_user_name, (strrpos($_user_name, '@') +
1));
957 $sql = "SELECT '1' FROM `mysql`.`user`"
958 . " WHERE `User` = '" . PMA_sqlAddSlashes($username) . "'"
959 . " AND `Host` = '" . PMA_sqlAddSlashes($hostname) . "';";
960 if (PMA_DBI_fetch_value($sql) == 1) {
961 $message = PMA_Message
::error(__('The user %s already exists!'));
962 $message->addParam('[i]\'' . $username . '\'@\'' . $hostname . '\'[/i]');
963 $_REQUEST['adduser'] = true;
964 $_add_user_error = true;
967 $create_user_real = 'CREATE USER \'' . PMA_sqlAddSlashes($username) . '\'@\'' . PMA_sqlAddSlashes($hostname) . '\'';
969 $real_sql_query = 'GRANT ' . join(', ', PMA_extractPrivInfo()) . ' ON *.* TO \''
970 . PMA_sqlAddSlashes($username) . '\'@\'' . PMA_sqlAddSlashes($hostname) . '\'';
971 if ($pred_password != 'none' && $pred_password != 'keep') {
972 $sql_query = $real_sql_query . ' IDENTIFIED BY \'***\'';
973 $real_sql_query .= ' IDENTIFIED BY \'' . PMA_sqlAddSlashes($pma_pw) . '\'';
974 if (isset($create_user_real)) {
975 $create_user_show = $create_user_real . ' IDENTIFIED BY \'***\'';
976 $create_user_real .= ' IDENTIFIED BY \'' . PMA_sqlAddSlashes($pma_pw) . '\'';
979 if ($pred_password == 'keep' && ! empty($password)) {
980 $real_sql_query .= ' IDENTIFIED BY PASSWORD \'' . $password . '\'';
981 if (isset($create_user_real)) {
982 $create_user_real .= ' IDENTIFIED BY PASSWORD \'' . $password . '\'';
985 $sql_query = $real_sql_query;
986 if (isset($create_user_real)) {
987 $create_user_show = $create_user_real;
991 * @todo similar code appears twice in this script
993 if ((isset($Grant_priv) && $Grant_priv == 'Y')
994 ||
(isset($max_questions) ||
isset($max_connections)
995 ||
isset($max_updates) ||
isset($max_user_connections))
997 $real_sql_query .= ' WITH';
998 $sql_query .= ' WITH';
999 if (isset($Grant_priv) && $Grant_priv == 'Y') {
1000 $real_sql_query .= ' GRANT OPTION';
1001 $sql_query .= ' GRANT OPTION';
1003 if (isset($max_questions)) {
1004 // avoid negative values
1005 $max_questions = max(0, (int)$max_questions);
1006 $real_sql_query .= ' MAX_QUERIES_PER_HOUR ' . $max_questions;
1007 $sql_query .= ' MAX_QUERIES_PER_HOUR ' . $max_questions;
1009 if (isset($max_connections)) {
1010 $max_connections = max(0, (int)$max_connections);
1011 $real_sql_query .= ' MAX_CONNECTIONS_PER_HOUR ' . $max_connections;
1012 $sql_query .= ' MAX_CONNECTIONS_PER_HOUR ' . $max_connections;
1014 if (isset($max_updates)) {
1015 $max_updates = max(0, (int)$max_updates);
1016 $real_sql_query .= ' MAX_UPDATES_PER_HOUR ' . $max_updates;
1017 $sql_query .= ' MAX_UPDATES_PER_HOUR ' . $max_updates;
1019 if (isset($max_user_connections)) {
1020 $max_user_connections = max(0, (int)$max_user_connections);
1021 $real_sql_query .= ' MAX_USER_CONNECTIONS ' . $max_user_connections;
1022 $sql_query .= ' MAX_USER_CONNECTIONS ' . $max_user_connections;
1025 if (isset($create_user_real)) {
1026 $create_user_real .= ';';
1027 $create_user_show .= ';';
1029 $real_sql_query .= ';';
1031 if (empty($_REQUEST['change_copy'])) {
1034 if (isset($create_user_real)) {
1035 if (! PMA_DBI_try_query($create_user_real)) {
1038 $sql_query = $create_user_show . $sql_query;
1041 if ($_error ||
! PMA_DBI_try_query($real_sql_query)) {
1042 $_REQUEST['createdb'] = false;
1043 $message = PMA_Message
::rawError(PMA_DBI_getError());
1045 $message = PMA_Message
::success(__('You have added a new user.'));
1048 switch (PMA_ifSetOr($_REQUEST['createdb'], '0')) {
1050 // Create database with same name and grant all privileges
1051 $q = 'CREATE DATABASE IF NOT EXISTS '
1052 . PMA_backquote(PMA_sqlAddSlashes($username)) . ';';
1054 if (! PMA_DBI_try_query($q)) {
1055 $message = PMA_Message
::rawError(PMA_DBI_getError());
1061 * If we are not in an Ajax request, we can't reload navigation now
1063 if ($GLOBALS['is_ajax_request'] != true) {
1064 // this is needed in case tracking is on:
1065 $GLOBALS['db'] = $username;
1066 $GLOBALS['reload'] = true;
1067 PMA_reloadNavigation();
1070 $q = 'GRANT ALL PRIVILEGES ON '
1071 . PMA_backquote(PMA_sqlAddSlashes($username)) . '.* TO \''
1072 . PMA_sqlAddSlashes($username) . '\'@\'' . PMA_sqlAddSlashes($hostname) . '\';';
1074 if (! PMA_DBI_try_query($q)) {
1075 $message = PMA_Message
::rawError(PMA_DBI_getError());
1079 // Grant all privileges on wildcard name (username\_%)
1080 $q = 'GRANT ALL PRIVILEGES ON '
1081 . PMA_backquote(PMA_sqlAddSlashes($username) . '\_%') . '.* TO \''
1082 . PMA_sqlAddSlashes($username) . '\'@\'' . PMA_sqlAddSlashes($hostname) . '\';';
1084 if (! PMA_DBI_try_query($q)) {
1085 $message = PMA_Message
::rawError(PMA_DBI_getError());
1089 // Grant all privileges on the specified database to the new user
1090 $q = 'GRANT ALL PRIVILEGES ON '
1091 . PMA_backquote(PMA_sqlAddSlashes($dbname)) . '.* TO \''
1092 . PMA_sqlAddSlashes($username) . '\'@\'' . PMA_sqlAddSlashes($hostname) . '\';';
1094 if (! PMA_DBI_try_query($q)) {
1095 $message = PMA_Message
::rawError(PMA_DBI_getError());
1103 if (isset($create_user_real)) {
1104 $queries[] = $create_user_real;
1106 $queries[] = $real_sql_query;
1107 // we put the query containing the hidden password in
1108 // $queries_for_display, at the same position occupied
1109 // by the real query in $queries
1110 $tmp_count = count($queries);
1111 if (isset($create_user_real)) {
1112 $queries_for_display[$tmp_count - 2] = $create_user_show;
1114 $queries_for_display[$tmp_count - 1] = $sql_query;
1116 unset($res, $real_sql_query);
1122 * Changes / copies a user, part III
1124 if (isset($_REQUEST['change_copy'])) {
1125 $user_host_condition = ' WHERE `User`'
1126 .' = \'' . PMA_sqlAddSlashes($old_username) . "'"
1128 .' = \'' . PMA_sqlAddSlashes($old_hostname) . '\';';
1129 $res = PMA_DBI_query('SELECT * FROM `mysql`.`db`' . $user_host_condition);
1130 while ($row = PMA_DBI_fetch_assoc($res)) {
1131 $queries[] = 'GRANT ' . join(', ', PMA_extractPrivInfo($row))
1132 .' ON ' . PMA_backquote($row['Db']) . '.*'
1133 .' TO \'' . PMA_sqlAddSlashes($username) . '\'@\'' . PMA_sqlAddSlashes($hostname) . '\''
1134 . ($row['Grant_priv'] == 'Y' ?
' WITH GRANT OPTION;' : ';');
1136 PMA_DBI_free_result($res);
1137 $res = PMA_DBI_query(
1138 'SELECT `Db`, `Table_name`, `Table_priv` FROM `mysql`.`tables_priv`' . $user_host_condition,
1139 $GLOBALS['userlink'],
1142 while ($row = PMA_DBI_fetch_assoc($res)) {
1144 $res2 = PMA_DBI_QUERY(
1145 'SELECT `Column_name`, `Column_priv`'
1146 .' FROM `mysql`.`columns_priv`'
1148 .' = \'' . PMA_sqlAddSlashes($old_username) . "'"
1150 .' = \'' . PMA_sqlAddSlashes($old_hostname) . '\''
1152 .' = \'' . PMA_sqlAddSlashes($row['Db']) . "'"
1153 .' AND `Table_name`'
1154 .' = \'' . PMA_sqlAddSlashes($row['Table_name']) . "'"
1160 $tmp_privs1 = PMA_extractPrivInfo($row);
1161 $tmp_privs2 = array(
1162 'Select' => array(),
1163 'Insert' => array(),
1164 'Update' => array(),
1165 'References' => array()
1168 while ($row2 = PMA_DBI_fetch_assoc($res2)) {
1169 $tmp_array = explode(',', $row2['Column_priv']);
1170 if (in_array('Select', $tmp_array)) {
1171 $tmp_privs2['Select'][] = $row2['Column_name'];
1173 if (in_array('Insert', $tmp_array)) {
1174 $tmp_privs2['Insert'][] = $row2['Column_name'];
1176 if (in_array('Update', $tmp_array)) {
1177 $tmp_privs2['Update'][] = $row2['Column_name'];
1179 if (in_array('References', $tmp_array)) {
1180 $tmp_privs2['References'][] = $row2['Column_name'];
1184 if (count($tmp_privs2['Select']) > 0 && ! in_array('SELECT', $tmp_privs1)) {
1185 $tmp_privs1[] = 'SELECT (`' . join('`, `', $tmp_privs2['Select']) . '`)';
1187 if (count($tmp_privs2['Insert']) > 0 && ! in_array('INSERT', $tmp_privs1)) {
1188 $tmp_privs1[] = 'INSERT (`' . join('`, `', $tmp_privs2['Insert']) . '`)';
1190 if (count($tmp_privs2['Update']) > 0 && ! in_array('UPDATE', $tmp_privs1)) {
1191 $tmp_privs1[] = 'UPDATE (`' . join('`, `', $tmp_privs2['Update']) . '`)';
1193 if (count($tmp_privs2['References']) > 0 && ! in_array('REFERENCES', $tmp_privs1)) {
1194 $tmp_privs1[] = 'REFERENCES (`' . join('`, `', $tmp_privs2['References']) . '`)';
1197 $queries[] = 'GRANT ' . join(', ', $tmp_privs1)
1198 . ' ON ' . PMA_backquote($row['Db']) . '.' . PMA_backquote($row['Table_name'])
1199 . ' TO \'' . PMA_sqlAddSlashes($username) . '\'@\'' . PMA_sqlAddSlashes($hostname) . '\''
1200 . (in_array('Grant', explode(',', $row['Table_priv'])) ?
' WITH GRANT OPTION;' : ';');
1206 * Updates privileges
1208 if (! empty($update_privs)) {
1209 $db_and_table = PMA_wildcardEscapeForGrant($dbname, (isset($tablename) ?
$tablename : ''));
1211 $sql_query0 = 'REVOKE ALL PRIVILEGES ON ' . $db_and_table
1212 . ' FROM \'' . PMA_sqlAddSlashes($username) . '\'@\'' . PMA_sqlAddSlashes($hostname) . '\';';
1213 if (! isset($Grant_priv) ||
$Grant_priv != 'Y') {
1214 $sql_query1 = 'REVOKE GRANT OPTION ON ' . $db_and_table
1215 . ' FROM \'' . PMA_sqlAddSlashes($username) . '\'@\'' . PMA_sqlAddSlashes($hostname) . '\';';
1220 // Should not do a GRANT USAGE for a table-specific privilege, it
1221 // causes problems later (cannot revoke it)
1222 if (! (isset($tablename) && 'USAGE' == implode('', PMA_extractPrivInfo()))) {
1223 $sql_query2 = 'GRANT ' . join(', ', PMA_extractPrivInfo())
1224 . ' ON ' . $db_and_table
1225 . ' TO \'' . PMA_sqlAddSlashes($username) . '\'@\'' . PMA_sqlAddSlashes($hostname) . '\'';
1228 * @todo similar code appears twice in this script
1230 if ((isset($Grant_priv) && $Grant_priv == 'Y')
1231 ||
(! isset($dbname)
1232 && (isset($max_questions) ||
isset($max_connections)
1233 ||
isset($max_updates) ||
isset($max_user_connections)))
1235 $sql_query2 .= 'WITH';
1236 if (isset($Grant_priv) && $Grant_priv == 'Y') {
1237 $sql_query2 .= ' GRANT OPTION';
1239 if (isset($max_questions)) {
1240 $max_questions = max(0, (int)$max_questions);
1241 $sql_query2 .= ' MAX_QUERIES_PER_HOUR ' . $max_questions;
1243 if (isset($max_connections)) {
1244 $max_connections = max(0, (int)$max_connections);
1245 $sql_query2 .= ' MAX_CONNECTIONS_PER_HOUR ' . $max_connections;
1247 if (isset($max_updates)) {
1248 $max_updates = max(0, (int)$max_updates);
1249 $sql_query2 .= ' MAX_UPDATES_PER_HOUR ' . $max_updates;
1251 if (isset($max_user_connections)) {
1252 $max_user_connections = max(0, (int)$max_user_connections);
1253 $sql_query2 .= ' MAX_USER_CONNECTIONS ' . $max_user_connections;
1258 if (! PMA_DBI_try_query($sql_query0)) {
1259 // This might fail when the executing user does not have ALL PRIVILEGES himself.
1260 // See https://sourceforge.net/tracker/index.php?func=detail&aid=3285929&group_id=23067&atid=377408
1263 if (isset($sql_query1) && ! PMA_DBI_try_query($sql_query1)) {
1264 // this one may fail, too...
1267 if (isset($sql_query2)) {
1268 PMA_DBI_query($sql_query2);
1272 $sql_query = $sql_query0 . ' ' . $sql_query1 . ' ' . $sql_query2;
1273 $message = PMA_Message
::success(__('You have updated the privileges for %s.'));
1274 $message->addParam('\'' . htmlspecialchars($username) . '\'@\'' . htmlspecialchars($hostname) . '\'');
1279 * Revokes Privileges
1281 if (isset($_REQUEST['revokeall'])) {
1282 $db_and_table = PMA_wildcardEscapeForGrant($dbname, isset($tablename) ?
$tablename : '');
1284 $sql_query0 = 'REVOKE ALL PRIVILEGES ON ' . $db_and_table
1285 . ' FROM \'' . PMA_sqlAddSlashes($username) . '\'@\'' . PMA_sqlAddSlashes($hostname) . '\';';
1286 $sql_query1 = 'REVOKE GRANT OPTION ON ' . $db_and_table
1287 . ' FROM \'' . PMA_sqlAddSlashes($username) . '\'@\'' . PMA_sqlAddSlashes($hostname) . '\';';
1289 PMA_DBI_query($sql_query0);
1290 if (! PMA_DBI_try_query($sql_query1)) {
1291 // this one may fail, too...
1294 $sql_query = $sql_query0 . ' ' . $sql_query1;
1295 $message = PMA_Message
::success(__('You have revoked the privileges for %s'));
1296 $message->addParam('\'' . htmlspecialchars($username) . '\'@\'' . htmlspecialchars($hostname) . '\'');
1297 if (! isset($tablename)) {
1306 * Updates the password
1308 if (isset($_REQUEST['change_pw'])) {
1309 // similar logic in user_password.php
1312 if ($nopass == 0 && isset($pma_pw) && isset($pma_pw2)) {
1313 if ($pma_pw != $pma_pw2) {
1314 $message = PMA_Message
::error(__('The passwords aren\'t the same!'));
1315 } elseif (empty($pma_pw) ||
empty($pma_pw2)) {
1316 $message = PMA_Message
::error(__('The password is empty!'));
1320 // here $nopass could be == 1
1321 if (empty($message)) {
1323 $hashing_function = (! empty($pw_hash) && $pw_hash == 'old' ?
'OLD_' : '')
1326 // in $sql_query which will be displayed, hide the password
1327 $sql_query = 'SET PASSWORD FOR \'' . PMA_sqlAddSlashes($username) . '\'@\'' . PMA_sqlAddSlashes($hostname) . '\' = ' . (($pma_pw == '') ?
'\'\'' : $hashing_function . '(\'' . preg_replace('@.@s', '*', $pma_pw) . '\')');
1328 $local_query = 'SET PASSWORD FOR \'' . PMA_sqlAddSlashes($username) . '\'@\'' . PMA_sqlAddSlashes($hostname) . '\' = ' . (($pma_pw == '') ?
'\'\'' : $hashing_function . '(\'' . PMA_sqlAddSlashes($pma_pw) . '\')');
1329 PMA_DBI_try_query($local_query)
1330 or PMA_mysqlDie(PMA_DBI_getError(), $sql_query, false, $err_url);
1331 $message = PMA_Message
::success(__('The password for %s was changed successfully.'));
1332 $message->addParam('\'' . htmlspecialchars($username) . '\'@\'' . htmlspecialchars($hostname) . '\'');
1339 * (Changes / copies a user, part IV)
1342 if (isset($_REQUEST['delete']) ||
(isset($_REQUEST['change_copy']) && $_REQUEST['mode'] < 4)) {
1343 if (isset($_REQUEST['change_copy'])) {
1344 $selected_usr = array($old_username . '&#27;' . $old_hostname);
1346 $selected_usr = $_REQUEST['selected_usr'];
1349 foreach ($selected_usr as $each_user) {
1350 list($this_user, $this_host) = explode('&#27;', $each_user);
1351 $queries[] = '# ' . sprintf(__('Deleting %s'), '\'' . $this_user . '\'@\'' . $this_host . '\'') . ' ...';
1352 $queries[] = 'DROP USER \'' . PMA_sqlAddSlashes($this_user) . '\'@\'' . PMA_sqlAddSlashes($this_host) . '\';';
1354 if (isset($_REQUEST['drop_users_db'])) {
1355 $queries[] = 'DROP DATABASE IF EXISTS ' . PMA_backquote($this_user) . ';';
1356 $GLOBALS['reload'] = true;
1358 if ($GLOBALS['is_ajax_request'] != true) {
1359 PMA_reloadNavigation();
1363 if (empty($_REQUEST['change_copy'])) {
1364 if (empty($queries)) {
1365 $message = PMA_Message
::error(__('No users selected for deleting!'));
1367 if ($_REQUEST['mode'] == 3) {
1368 $queries[] = '# ' . __('Reloading the privileges') . ' ...';
1369 $queries[] = 'FLUSH PRIVILEGES;';
1371 $drop_user_error = '';
1372 foreach ($queries as $sql_query) {
1373 if ($sql_query{0} != '#') {
1374 if (! PMA_DBI_try_query($sql_query, $GLOBALS['userlink'])) {
1375 $drop_user_error .= PMA_DBI_getError() . "\n";
1379 // tracking sets this, causing the deleted db to be shown in navi
1380 unset($GLOBALS['db']);
1382 $sql_query = join("\n", $queries);
1383 if (! empty($drop_user_error)) {
1384 $message = PMA_Message
::rawError($drop_user_error);
1386 $message = PMA_Message
::success(__('The selected users have been deleted successfully.'));
1395 * Changes / copies a user, part V
1397 if (isset($_REQUEST['change_copy'])) {
1399 foreach ($queries as $sql_query) {
1400 if ($sql_query{0} != '#') {
1401 PMA_DBI_query($sql_query);
1403 // when there is a query containing a hidden password, take it
1404 // instead of the real query sent
1405 if (isset($queries_for_display[$tmp_count])) {
1406 $queries[$tmp_count] = $queries_for_display[$tmp_count];
1410 $message = PMA_Message
::success();
1411 $sql_query = join("\n", $queries);
1416 * Reloads the privilege tables into memory
1418 if (isset($_REQUEST['flush_privileges'])) {
1419 $sql_query = 'FLUSH PRIVILEGES;';
1420 PMA_DBI_query($sql_query);
1421 $message = PMA_Message
::success(__('The privileges were reloaded successfully.'));
1425 * defines some standard links
1427 $link_edit = '<a class="edit_user_anchor ' . $conditional_class . '" href="server_privileges.php?' . str_replace('%', '%%', $GLOBALS['url_query'])
1428 . '&username=%s'
1429 . '&hostname=%s'
1431 . '&tablename=%s">'
1432 . PMA_getIcon('b_usredit.png', __('Edit Privileges'))
1435 $link_revoke = '<a href="server_privileges.php?' . str_replace('%', '%%', $GLOBALS['url_query'])
1436 . '&username=%s'
1437 . '&hostname=%s'
1439 . '&tablename=%s'
1440 . '&revokeall=1">'
1441 . PMA_getIcon('b_usrdrop.png', __('Revoke'))
1444 $link_export = '<a class="export_user_anchor ' . $conditional_class . '" href="server_privileges.php?' . str_replace('%', '%%', $GLOBALS['url_query'])
1445 . '&username=%s'
1446 . '&hostname=%s'
1449 . PMA_getIcon('b_tblexport.png', __('Export'))
1453 * If we are in an Ajax request for Create User/Edit User/Revoke User/
1454 * Flush Privileges, show $message and exit.
1456 if ($GLOBALS['is_ajax_request'] && ! isset($_REQUEST['export']) && (! isset($_REQUEST['adduser']) ||
$_add_user_error) && ! isset($_REQUEST['initial']) && ! isset($_REQUEST['showall']) && ! isset($_REQUEST['edit_user_dialog']) && ! isset($_REQUEST['db_specific'])) {
1458 if (isset($sql_query)) {
1459 $extra_data['sql_query'] = PMA_showMessage(null, $sql_query);
1462 if (isset($_REQUEST['adduser_submit']) ||
isset($_REQUEST['change_copy'])) {
1464 * generate html on the fly for the new user that was just created.
1466 $new_user_string = '<tr>'."\n"
1467 .'<td> <input type="checkbox" name="selected_usr[]" id="checkbox_sel_users_" value="' . htmlspecialchars($username) . '&#27;' . htmlspecialchars($hostname) . '" /> </td>' . "\n"
1468 .'<td><label for="checkbox_sel_users_">' . (empty($username) ?
'<span style="color: #FF0000">' . __('Any') . '</span>' : htmlspecialchars($username) ) . '</label></td>' . "\n"
1469 .'<td>' . htmlspecialchars($hostname) . '</td>' . "\n";
1470 $new_user_string .= '<td>';
1472 if (! empty($password) ||
isset($pma_pw)) {
1473 $new_user_string .= __('Yes');
1475 $new_user_string .= '<span style="color: #FF0000">' . __('No') . '</span>';
1478 $new_user_string .= '</td>'."\n";
1479 $new_user_string .= '<td><tt>' . join(', ', PMA_extractPrivInfo('', true)) . '</tt></td>'; //Fill in privileges here
1480 $new_user_string .= '<td>';
1482 if ((isset($Grant_priv) && $Grant_priv == 'Y')) {
1483 $new_user_string .= __('Yes');
1485 $new_user_string .= __('No');
1488 $new_user_string .='</td>';
1490 $new_user_string .= '<td>' . sprintf($link_edit, urlencode($username), urlencode($hostname), '', '') . '</td>' . "\n";
1491 $new_user_string .= '<td>' . sprintf($link_export, urlencode($username), urlencode($hostname), (isset($initial) ?
$initial : '')) . '</td>' . "\n";
1493 $new_user_string .= '</tr>';
1495 $extra_data['new_user_string'] = $new_user_string;
1498 * Generate the string for this alphabet's initial, to update the user
1501 $new_user_initial = strtoupper(substr($username, 0, 1));
1502 $new_user_initial_string = '<a href="server_privileges.php?' . $GLOBALS['url_query'] . '&initial=' . $new_user_initial
1503 .'">' . $new_user_initial . '</a>';
1504 $extra_data['new_user_initial'] = $new_user_initial;
1505 $extra_data['new_user_initial_string'] = $new_user_initial_string;
1508 if (isset($update_privs)) {
1509 $extra_data['db_specific_privs'] = false;
1510 if (isset($dbname_is_wildcard)) {
1511 $extra_data['db_specific_privs'] = ! $dbname_is_wildcard;
1513 $new_privileges = join(', ', PMA_extractPrivInfo('', true));
1515 $extra_data['new_privileges'] = $new_privileges;
1518 if ($message instanceof PMA_Message
) {
1519 PMA_ajaxResponse($message, $message->isSuccess(), $extra_data);
1524 * Displays the links
1526 if (isset($viewing_mode) && $viewing_mode == 'db') {
1528 $url_query .= '&goto=db_operations.php';
1530 // Gets the database structure
1531 $sub_part = '_structure';
1532 include './libraries/db_info.inc.php';
1535 include './libraries/server_links.inc.php';
1543 // export user definition
1544 if (isset($_REQUEST['export'])) {
1545 $title = __('User') . ' `' . htmlspecialchars($username) . '`@`' . htmlspecialchars($hostname) . '`';
1546 $response = '<textarea cols="' . $GLOBALS['cfg']['TextareaCols'] . '" rows="' . $GLOBALS['cfg']['TextareaRows'] . '">';
1547 $grants = PMA_DBI_fetch_result("SHOW GRANTS FOR '" . PMA_sqlAddSlashes($username) . "'@'" . PMA_sqlAddSlashes($hostname) . "'");
1548 foreach ($grants as $one_grant) {
1549 $response .= $one_grant . ";\n\n";
1551 $response .= '</textarea>';
1552 unset($username, $hostname, $grants, $one_grant);
1553 if ($GLOBALS['is_ajax_request']) {
1554 PMA_ajaxResponse($response, 1, array('title' => $title));
1556 echo "<h2>$title</h2>$response";
1560 if (empty($_REQUEST['adduser']) && (! isset($checkprivs) ||
! strlen($checkprivs))) {
1561 if (! isset($username)) {
1562 // No username is given --> display the overview
1564 . PMA_getIcon('b_usrlist.png')
1565 . __('Users overview') . "\n"
1568 $sql_query = 'SELECT *,' .
1569 " IF(`Password` = _latin1 '', 'N', 'Y') AS 'Password'" .
1570 ' FROM `mysql`.`user`';
1572 $sql_query .= (isset($initial) ?
PMA_rangeOfUsers($initial) : '');
1574 $sql_query .= ' ORDER BY `User` ASC, `Host` ASC;';
1575 $res = PMA_DBI_try_query($sql_query, null, PMA_DBI_QUERY_STORE
);
1578 // the query failed! This may have two reasons:
1579 // - the user does not have enough privileges
1580 // - the privilege tables use a structure of an earlier version.
1581 // so let's try a more simple query
1583 $sql_query = 'SELECT * FROM `mysql`.`user`';
1584 $res = PMA_DBI_try_query($sql_query, null, PMA_DBI_QUERY_STORE
);
1587 PMA_Message
::error(__('No Privileges'))->display();
1588 PMA_DBI_free_result($res);
1591 // This message is hardcoded because I will replace it by
1592 // a automatic repair feature soon.
1593 $raw = 'Your privilege table structure seems to be older than'
1594 . ' this MySQL version!<br />'
1595 . 'Please run the <tt>mysql_upgrade</tt> command'
1596 . '(<tt>mysql_fix_privilege_tables</tt> on older systems)'
1597 . ' that should be included in your MySQL server distribution'
1598 . ' to solve this problem!';
1599 PMA_Message
::rawError($raw)->display();
1603 // we also want users not in table `user` but in other table
1604 $tables = PMA_DBI_fetch_result('SHOW TABLES FROM `mysql`;');
1606 $tables_to_search_for_users = array(
1607 'user', 'db', 'tables_priv', 'columns_priv', 'procs_priv',
1610 $db_rights_sqls = array();
1611 foreach ($tables_to_search_for_users as $table_search_in) {
1612 if (in_array($table_search_in, $tables)) {
1613 $db_rights_sqls[] = 'SELECT DISTINCT `User`, `Host` FROM `mysql`.`' . $table_search_in . '` ' . (isset($initial) ?
PMA_rangeOfUsers($initial) : '');
1617 $user_defaults = array(
1621 'Grant_priv' => 'N',
1622 'privs' => array('USAGE'),
1625 // for all initials, even non A-Z
1626 $array_initials = array();
1628 $db_rights = array();
1630 $db_rights_sql = '(' . implode(') UNION (', $db_rights_sqls) . ')'
1631 .' ORDER BY `User` ASC, `Host` ASC';
1633 $db_rights_result = PMA_DBI_query($db_rights_sql);
1635 while ($db_rights_row = PMA_DBI_fetch_assoc($db_rights_result)) {
1636 $db_rights_row = array_merge($user_defaults, $db_rights_row);
1637 $db_rights[$db_rights_row['User']][$db_rights_row['Host']]
1640 PMA_DBI_free_result($db_rights_result);
1641 unset($db_rights_sql, $db_rights_sqls, $db_rights_result, $db_rights_row);
1645 * Displays the initials
1646 * In an Ajax request, we don't need to show this.
1647 * Also not necassary if there is less than 20 privileges
1649 if ($GLOBALS['is_ajax_request'] != true && PMA_DBI_num_rows($res) > 20 ) {
1651 // initialize to false the letters A-Z
1652 for ($letter_counter = 1; $letter_counter < 27; $letter_counter++
) {
1653 if (! isset($array_initials[chr($letter_counter +
64)])) {
1654 $array_initials[chr($letter_counter +
64)] = false;
1658 $initials = PMA_DBI_try_query('SELECT DISTINCT UPPER(LEFT(`User`,1)) FROM `user` ORDER BY `User` ASC', null, PMA_DBI_QUERY_STORE
);
1659 while (list($tmp_initial) = PMA_DBI_fetch_row($initials)) {
1660 $array_initials[$tmp_initial] = true;
1663 // Display the initials, which can be any characters, not
1664 // just letters. For letters A-Z, we add the non-used letters
1667 uksort($array_initials, "strnatcasecmp");
1669 echo '<table id="initials_table" class="' . $conditional_class . '" <cellspacing="5"><tr>';
1670 foreach ($array_initials as $tmp_initial => $initial_was_found) {
1671 if ($initial_was_found) {
1672 echo '<td><a href="server_privileges.php?' . $GLOBALS['url_query'] . '&initial=' . urlencode($tmp_initial) . '">' . $tmp_initial . '</a></td>' . "\n";
1674 echo '<td>' . $tmp_initial . '</td>';
1677 echo '<td><a href="server_privileges.php?' . $GLOBALS['url_query'] . '&showall=1" class="nowrap">[' . __('Show all') . ']</a></td>' . "\n";
1678 echo '</tr></table>';
1682 * Display the user overview
1683 * (if less than 50 users, display them immediately)
1686 if (isset($initial) ||
isset($showall) ||
PMA_DBI_num_rows($res) < 50) {
1688 while ($row = PMA_DBI_fetch_assoc($res)) {
1689 $row['privs'] = PMA_extractPrivInfo($row, true);
1690 $db_rights[$row['User']][$row['Host']] = $row;
1692 @PMA_DBI_free_result
($res);
1695 echo '<form name="usersForm" id="usersForm" action="server_privileges.php" method="post">' . "\n"
1696 . PMA_generate_common_hidden_inputs('', '')
1697 . ' <table id="tableuserrights" class="data">' . "\n"
1699 . ' <tr><th></th>' . "\n"
1700 . ' <th>' . __('User') . '</th>' . "\n"
1701 . ' <th>' . __('Host') . '</th>' . "\n"
1702 . ' <th>' . __('Password') . '</th>' . "\n"
1703 . ' <th>' . __('Global privileges') . ' '
1704 . PMA_showHint(__('Note: MySQL privilege names are expressed in English')) . '</th>' . "\n"
1705 . ' <th>' . __('Grant') . '</th>' . "\n"
1706 . ' <th colspan="2">' . __('Action') . '</th>' . "\n";
1707 echo ' </tr>' . "\n";
1708 echo ' </thead>' . "\n";
1709 echo ' <tbody>' . "\n";
1711 $index_checkbox = -1;
1712 foreach ($db_rights as $user) {
1715 foreach ($user as $host) {
1717 echo ' <tr class="' . ($odd_row ?
'odd' : 'even') . '">' . "\n"
1718 . ' <td><input type="checkbox" name="selected_usr[]" id="checkbox_sel_users_'
1719 . $index_checkbox . '" value="'
1720 . htmlspecialchars($host['User'] . '&#27;' . $host['Host'])
1722 . (empty($GLOBALS['checkall']) ?
'' : ' checked="checked"')
1724 . ' <td><label for="checkbox_sel_users_' . $index_checkbox . '">' . (empty($host['User']) ?
'<span style="color: #FF0000">' . __('Any') . '</span>' : htmlspecialchars($host['User'])) . '</label></td>' . "\n"
1725 . ' <td>' . htmlspecialchars($host['Host']) . '</td>' . "\n";
1727 switch ($host['Password']) {
1732 echo '<span style="color: #FF0000">' . __('No') . '</span>';
1734 // this happens if this is a definition not coming from mysql.user
1736 echo '--'; // in future version, replace by "not present"
1740 . ' <td><tt>' . "\n"
1741 . ' ' . implode(',' . "\n" . ' ', $host['privs']) . "\n"
1742 . ' </tt></td>' . "\n"
1743 . ' <td>' . ($host['Grant_priv'] == 'Y' ?
__('Yes') : __('No')) . '</td>' . "\n"
1744 . ' <td align="center">';
1745 printf($link_edit, urlencode($host['User']), urlencode($host['Host']), '', '');
1747 echo '<td align="center">';
1748 printf($link_export, urlencode($host['User']), urlencode($host['Host']), (isset($initial) ?
$initial : ''));
1751 $odd_row = ! $odd_row;
1755 unset($user, $host, $odd_row);
1756 echo ' </tbody></table>' . "\n"
1757 .'<img class="selectallarrow"'
1758 .' src="' . $pmaThemeImage . 'arrow_' . $text_dir . '.png"'
1759 .' width="38" height="22"'
1760 .' alt="' . __('With selected:') . '" />' . "\n"
1761 .'<a href="server_privileges.php?' . $GLOBALS['url_query'] . '&checkall=1"'
1762 .' onclick="if (markAllRows(\'usersForm\')) return false;">'
1763 . __('Check All') . '</a>' . "\n"
1765 .'<a href="server_privileges.php?' . $GLOBALS['url_query'] . '"'
1766 .' onclick="if (unMarkAllRows(\'usersForm\')) return false;">'
1767 . __('Uncheck All') . '</a>' . "\n";
1769 // add/delete user fieldset
1770 echo ' <fieldset id="fieldset_add_user">' . "\n"
1771 . ' <a href="server_privileges.php?' . $GLOBALS['url_query'] . '&adduser=1" class="' . $conditional_class . '">' . "\n"
1772 . PMA_getIcon('b_usradd.png')
1773 . ' ' . __('Add user') . '</a>' . "\n"
1774 . ' </fieldset>' . "\n"
1775 . ' <fieldset id="fieldset_delete_user">'
1776 . ' <legend>' . "\n"
1777 . PMA_getIcon('b_usrdrop.png')
1778 . ' ' . __('Remove selected users') . '' . "\n"
1779 . ' </legend>' . "\n"
1780 . ' <input type="hidden" name="mode" value="2" />' . "\n"
1781 . '(' . __('Revoke all active privileges from the users and delete them afterwards.') . ')<br />' . "\n"
1782 . ' <input type="checkbox" title="' . __('Drop the databases that have the same names as the users.') . '" name="drop_users_db" id="checkbox_drop_users_db" />' . "\n"
1783 . ' <label for="checkbox_drop_users_db" title="' . __('Drop the databases that have the same names as the users.') . '">' . "\n"
1784 . ' ' . __('Drop the databases that have the same names as the users.') . "\n"
1785 . ' </label>' . "\n"
1786 . ' </fieldset>' . "\n"
1787 . ' <fieldset id="fieldset_delete_user_footer" class="tblFooters">' . "\n"
1788 . ' <input type="submit" name="delete" value="' . __('Go') . '" id="buttonGo" class="' . $conditional_class . '"/>' . "\n"
1789 . ' </fieldset>' . "\n"
1794 echo ' <fieldset id="fieldset_add_user">' . "\n"
1795 . ' <a href="server_privileges.php?' . $GLOBALS['url_query'] . '&adduser=1" class="' . $conditional_class . '">' . "\n"
1796 . PMA_getIcon('b_usradd.png')
1797 . ' ' . __('Add user') . '</a>' . "\n"
1798 . ' </fieldset>' . "\n";
1799 } // end if (display overview)
1801 if ($GLOBALS['is_ajax_request']) {
1805 $flushnote = new PMA_Message(__('Note: phpMyAdmin gets the users\' privileges directly from MySQL\'s privilege tables. The content of these tables may differ from the privileges the server uses, if they have been changed manually. In this case, you should %sreload the privileges%s before you continue.'), PMA_Message
::NOTICE
);
1806 $flushnote->addParam('<a href="server_privileges.php?' . $GLOBALS['url_query'] . '&flush_privileges=1" id="reload_privileges_anchor" class="' . $conditional_class . '">', false);
1807 $flushnote->addParam('</a>', false);
1808 $flushnote->display();
1814 // A user was selected -> display the user's properties
1816 // In an Ajax request, prevent cached values from showing
1817 if ($GLOBALS['is_ajax_request'] == true) {
1818 header('Cache-Control: no-cache');
1822 . PMA_getIcon('b_usredit.png')
1823 . __('Edit Privileges') . ': '
1826 if (isset($dbname)) {
1827 echo ' <i><a href="server_privileges.php?'
1828 . $GLOBALS['url_query'] . '&username=' . htmlspecialchars(urlencode($username))
1829 . '&hostname=' . htmlspecialchars(urlencode($hostname)) . '&dbname=&tablename=">\''
1830 . htmlspecialchars($username) . '\'@\'' . htmlspecialchars($hostname)
1831 . '\'</a></i>' . "\n";
1832 $url_dbname = urlencode(str_replace(array('\_', '\%'), array('_', '%'), $dbname));
1834 echo ' - ' . ($dbname_is_wildcard ?
__('Databases') : __('Database') );
1835 if (isset($tablename)) {
1836 echo ' <i><a href="server_privileges.php?' . $GLOBALS['url_query']
1837 . '&username=' . htmlspecialchars(urlencode($username)) . '&hostname=' . htmlspecialchars(urlencode($hostname))
1838 . '&dbname=' . htmlspecialchars($url_dbname) . '&tablename=">' . htmlspecialchars($dbname) . '</a></i>';
1839 echo ' - ' . __('Table') . ' <i>' . htmlspecialchars($tablename) . '</i>';
1841 echo ' <i>' . htmlspecialchars($dbname) . '</i>';
1845 echo ' <i>\'' . htmlspecialchars($username) . '\'@\'' . htmlspecialchars($hostname)
1849 echo '</h2>' . "\n";
1852 $sql = "SELECT '1' FROM `mysql`.`user`"
1853 . " WHERE `User` = '" . PMA_sqlAddSlashes($username) . "'"
1854 . " AND `Host` = '" . PMA_sqlAddSlashes($hostname) . "';";
1855 $user_does_not_exists = (bool) ! PMA_DBI_fetch_value($sql);
1857 if ($user_does_not_exists) {
1858 PMA_Message
::error(__('The selected user was not found in the privilege table.'))->display();
1859 PMA_displayLoginInformationFields();
1860 //require './libraries/footer.inc.php';
1863 echo '<form name="usersForm" id="addUsersForm_' . $random_n . '" action="server_privileges.php" method="post">' . "\n";
1865 'username' => $username,
1866 'hostname' => $hostname,
1868 if (isset($dbname)) {
1869 $_params['dbname'] = $dbname;
1870 if (isset($tablename)) {
1871 $_params['tablename'] = $tablename;
1874 echo PMA_generate_common_hidden_inputs($_params);
1876 PMA_displayPrivTable(
1877 PMA_ifSetOr($dbname, '*', 'length'),
1878 PMA_ifSetOr($tablename, '*', 'length')
1881 echo '</form>' . "\n";
1883 if (! isset($tablename) && empty($dbname_is_wildcard)) {
1885 // no table name was given, display all table specific rights
1886 // but only if $dbname contains no wildcards
1889 echo '<form action="server_privileges.php" id="db_or_table_specific_priv" method="post">' . "\n"
1890 . PMA_generate_common_hidden_inputs('', '')
1891 . '<input type="hidden" name="username" value="' . htmlspecialchars($username) . '" />' . "\n"
1892 . '<input type="hidden" name="hostname" value="' . htmlspecialchars($hostname) . '" />' . "\n"
1893 . '<fieldset>' . "\n"
1894 . '<legend>' . (! isset($dbname) ?
__('Database-specific privileges') : __('Table-specific privileges')) . '</legend>' . "\n"
1895 . '<table class="data">' . "\n"
1897 . '<tr><th>' . (! isset($dbname) ?
__('Database') : __('Table')) . '</th>' . "\n"
1898 . ' <th>' . __('Privileges') . '</th>' . "\n"
1899 . ' <th>' . __('Grant') . '</th>' . "\n"
1900 . ' <th>' . (! isset($dbname) ?
__('Table-specific privileges') : __('Column-specific privileges')) . '</th>' . "\n"
1901 . ' <th colspan="2">' . __('Action') . '</th>' . "\n"
1906 $user_host_condition = ' WHERE `User`'
1907 . ' = \'' . PMA_sqlAddSlashes($username) . "'"
1909 . ' = \'' . PMA_sqlAddSlashes($hostname) . "'";
1914 // we also want privielgs for this user not in table `db` but in other table
1915 $tables = PMA_DBI_fetch_result('SHOW TABLES FROM `mysql`;');
1916 if (! isset($dbname)) {
1918 // no db name given, so we want all privs for the given user
1920 $tables_to_search_for_users = array(
1921 'tables_priv', 'columns_priv',
1924 $db_rights_sqls = array();
1925 foreach ($tables_to_search_for_users as $table_search_in) {
1926 if (in_array($table_search_in, $tables)) {
1927 $db_rights_sqls[] = '
1928 SELECT DISTINCT `Db`
1929 FROM `mysql`.' . PMA_backquote($table_search_in)
1930 . $user_host_condition;
1934 $user_defaults = array(
1936 'Grant_priv' => 'N',
1937 'privs' => array('USAGE'),
1938 'Table_privs' => true,
1942 $db_rights = array();
1944 $db_rights_sql = '(' . implode(') UNION (', $db_rights_sqls) . ')'
1945 .' ORDER BY `Db` ASC';
1947 $db_rights_result = PMA_DBI_query($db_rights_sql);
1949 while ($db_rights_row = PMA_DBI_fetch_assoc($db_rights_result)) {
1950 $db_rights_row = array_merge($user_defaults, $db_rights_row);
1951 // only Db names in the table `mysql`.`db` uses wildcards
1952 // as we are in the db specific rights display we want
1953 // all db names escaped, also from other sources
1954 $db_rights_row['Db'] = PMA_escape_mysql_wildcards(
1955 $db_rights_row['Db']
1957 $db_rights[$db_rights_row['Db']] = $db_rights_row;
1960 PMA_DBI_free_result($db_rights_result);
1961 unset($db_rights_sql, $db_rights_sqls, $db_rights_result, $db_rights_row);
1963 $sql_query = 'SELECT * FROM `mysql`.`db`' . $user_host_condition . ' ORDER BY `Db` ASC';
1964 $res = PMA_DBI_query($sql_query);
1967 while ($row = PMA_DBI_fetch_assoc($res)) {
1968 if (isset($db_rights[$row['Db']])) {
1969 $db_rights[$row['Db']] = array_merge($db_rights[$row['Db']], $row);
1971 $db_rights[$row['Db']] = $row;
1973 // there are db specific rights for this user
1974 // so we can drop this db rights
1975 $db_rights[$row['Db']]['can_delete'] = true;
1977 PMA_DBI_free_result($res);
1982 // db name was given,
1983 // so we want all user specific rights for this db
1985 $user_host_condition .=
1987 .' LIKE \'' . PMA_sqlAddSlashes($dbname, true) . "'";
1989 $tables_to_search_for_users = array(
1993 $db_rights_sqls = array();
1994 foreach ($tables_to_search_for_users as $table_search_in) {
1995 if (in_array($table_search_in, $tables)) {
1996 $db_rights_sqls[] = '
1997 SELECT DISTINCT `Table_name`
1998 FROM `mysql`.' . PMA_backquote($table_search_in)
1999 . $user_host_condition;
2003 $user_defaults = array(
2005 'Grant_priv' => 'N',
2006 'privs' => array('USAGE'),
2007 'Column_priv' => true,
2011 $db_rights = array();
2013 $db_rights_sql = '(' . implode(') UNION (', $db_rights_sqls) . ')'
2014 .' ORDER BY `Table_name` ASC';
2016 $db_rights_result = PMA_DBI_query($db_rights_sql);
2018 while ($db_rights_row = PMA_DBI_fetch_assoc($db_rights_result)) {
2019 $db_rights_row = array_merge($user_defaults, $db_rights_row);
2020 $db_rights[$db_rights_row['Table_name']] = $db_rights_row;
2022 PMA_DBI_free_result($db_rights_result);
2023 unset($db_rights_sql, $db_rights_sqls, $db_rights_result, $db_rights_row);
2025 $sql_query = 'SELECT `Table_name`,'
2027 .' IF(`Column_priv` = _latin1 \'\', 0, 1)'
2028 .' AS \'Column_priv\''
2029 .' FROM `mysql`.`tables_priv`'
2030 . $user_host_condition
2031 .' ORDER BY `Table_name` ASC;';
2032 $res = PMA_DBI_query($sql_query);
2035 while ($row = PMA_DBI_fetch_assoc($res)) {
2036 if (isset($db_rights[$row['Table_name']])) {
2037 $db_rights[$row['Table_name']] = array_merge($db_rights[$row['Table_name']], $row);
2039 $db_rights[$row['Table_name']] = $row;
2042 PMA_DBI_free_result($res);
2048 if (count($db_rights) < 1) {
2049 echo '<tr class="odd">' . "\n"
2050 . ' <td colspan="6"><center><i>' . __('None') . '</i></center></td>' . "\n"
2054 $found_rows = array();
2055 //while ($row = PMA_DBI_fetch_assoc($res)) {
2056 foreach ($db_rights as $row) {
2057 $found_rows[] = (! isset($dbname)) ?
$row['Db'] : $row['Table_name'];
2059 echo '<tr class="' . ($odd_row ?
'odd' : 'even') . '">' . "\n"
2060 . ' <td>' . htmlspecialchars((! isset($dbname)) ?
$row['Db'] : $row['Table_name']) . '</td>' . "\n"
2061 . ' <td><tt>' . "\n"
2062 . ' ' . join(',' . "\n" . ' ', PMA_extractPrivInfo($row, true)) . "\n"
2063 . ' </tt></td>' . "\n"
2064 . ' <td>' . ((((! isset($dbname)) && $row['Grant_priv'] == 'Y') ||
(isset($dbname) && in_array('Grant', explode(',', $row['Table_priv'])))) ?
__('Yes') : __('No')) . '</td>' . "\n"
2066 if (! empty($row['Table_privs']) ||
! empty ($row['Column_priv'])) {
2075 htmlspecialchars(urlencode($username)),
2076 urlencode(htmlspecialchars($hostname)),
2077 urlencode((! isset($dbname)) ?
$row['Db'] : htmlspecialchars($dbname)),
2078 urlencode((! isset($dbname)) ?
'' : $row['Table_name'])
2082 if (! empty($row['can_delete']) ||
isset($row['Table_name']) && strlen($row['Table_name'])) {
2085 htmlspecialchars(urlencode($username)),
2086 urlencode(htmlspecialchars($hostname)),
2087 urlencode((! isset($dbname)) ?
$row['Db'] : htmlspecialchars($dbname)),
2088 urlencode((! isset($dbname)) ?
'' : $row['Table_name'])
2093 $odd_row = ! $odd_row;
2097 echo '</tbody>' . "\n"
2098 . '</table>' . "\n";
2100 if (! isset($dbname)) {
2102 // no database name was given, display select db
2104 $pred_db_array =PMA_DBI_fetch_result('SHOW DATABASES;');
2106 echo ' <label for="text_dbname">' . __('Add privileges on the following database') . ':</label>' . "\n";
2107 if (! empty($pred_db_array)) {
2108 echo ' <select name="pred_dbname" class="autosubmit">' . "\n"
2109 . ' <option value="" selected="selected">' . __('Use text field') . ':</option>' . "\n";
2110 foreach ($pred_db_array as $current_db) {
2111 $current_db = PMA_escape_mysql_wildcards($current_db);
2112 // cannot use array_diff() once, outside of the loop,
2113 // because the list of databases has special characters
2114 // already escaped in $found_rows,
2115 // contrary to the output of SHOW DATABASES
2116 if (empty($found_rows) ||
! in_array($current_db, $found_rows)) {
2117 echo ' <option value="' . htmlspecialchars($current_db) . '">'
2118 . htmlspecialchars($current_db) . '</option>' . "\n";
2121 echo ' </select>' . "\n";
2123 echo ' <input type="text" id="text_dbname" name="dbname" />' . "\n"
2124 . PMA_showHint(__('Wildcards % and _ should be escaped with a \ to use them literally'));
2126 echo ' <input type="hidden" name="dbname" value="' . htmlspecialchars($dbname) . '"/>' . "\n"
2127 . ' <label for="text_tablename">' . __('Add privileges on the following table') . ':</label>' . "\n";
2128 if ($res = @PMA_DBI_try_query
('SHOW TABLES FROM ' . PMA_backquote(PMA_unescape_mysql_wildcards($dbname)) . ';', null, PMA_DBI_QUERY_STORE
)) {
2129 $pred_tbl_array = array();
2130 while ($row = PMA_DBI_fetch_row($res)) {
2131 if (! isset($found_rows) ||
! in_array($row[0], $found_rows)) {
2132 $pred_tbl_array[] = $row[0];
2135 PMA_DBI_free_result($res);
2137 if (! empty($pred_tbl_array)) {
2138 echo ' <select name="pred_tablename" class="autosubmit">' . "\n"
2139 . ' <option value="" selected="selected">' . __('Use text field') . ':</option>' . "\n";
2140 foreach ($pred_tbl_array as $current_table) {
2141 echo ' <option value="' . htmlspecialchars($current_table) . '">' . htmlspecialchars($current_table) . '</option>' . "\n";
2143 echo ' </select>' . "\n";
2148 echo ' <input type="text" id="text_tablename" name="tablename" />' . "\n";
2150 echo '</fieldset>' . "\n";
2151 echo '<fieldset class="tblFooters">' . "\n"
2152 . ' <input type="submit" value="' . __('Go') . '" />'
2153 . '</fieldset>' . "\n"
2158 // Provide a line with links to the relevant database and table
2159 if (isset($dbname) && empty($dbname_is_wildcard)) {
2160 echo '[ ' . __('Database')
2161 . ' <a href="' . $GLOBALS['cfg']['DefaultTabDatabase'] . '?'
2162 . $GLOBALS['url_query'] . '&db=' . $url_dbname . '&reload=1">'
2163 . htmlspecialchars($dbname) . ': ' . PMA_getTitleForTarget($GLOBALS['cfg']['DefaultTabDatabase']) . "</a> ]\n";
2165 if (isset($tablename)) {
2166 echo ' [ ' . __('Table') . ' <a href="'
2167 . $GLOBALS['cfg']['DefaultTabTable'] . '?' . $GLOBALS['url_query']
2168 . '&db=' . $url_dbname . '&table=' . htmlspecialchars(urlencode($tablename))
2169 . '&reload=1">' . htmlspecialchars($tablename) . ': '
2170 . PMA_getTitleForTarget($GLOBALS['cfg']['DefaultTabTable'])
2176 if (! isset($dbname) && ! $user_does_not_exists) {
2177 include_once './libraries/display_change_password.lib.php';
2179 echo '<form action="server_privileges.php" method="post" onsubmit="return checkPassword(this);">' . "\n"
2180 . PMA_generate_common_hidden_inputs('', '')
2181 . '<input type="hidden" name="old_username" value="' . htmlspecialchars($username) . '" />' . "\n"
2182 . '<input type="hidden" name="old_hostname" value="' . htmlspecialchars($hostname) . '" />' . "\n"
2183 . '<fieldset id="fieldset_change_copy_user">' . "\n"
2184 . ' <legend>' . __('Change Login Information / Copy User') . '</legend>' . "\n";
2185 PMA_displayLoginInformationFields('change');
2186 echo ' <fieldset>' . "\n"
2187 . ' <legend>' . __('Create a new user with the same privileges and ...') . '</legend>' . "\n";
2189 '4' => __('... keep the old one.'),
2190 '1' => __('... delete the old one from the user tables.'),
2191 '2' => __('... revoke all active privileges from the old one and delete it afterwards.'),
2192 '3' => __('... delete the old one from the user tables and reload the privileges afterwards.'));
2193 PMA_display_html_radio('mode', $choices, '4', true);
2196 echo ' </fieldset>' . "\n"
2197 . '</fieldset>' . "\n"
2198 . '<fieldset id="fieldset_change_copy_user_footer" class="tblFooters">' . "\n"
2199 . ' <input type="submit" name="change_copy" value="' . __('Go') . '" />' . "\n"
2200 . '</fieldset>' . "\n"
2204 } elseif (isset($_REQUEST['adduser'])) {
2207 $GLOBALS['url_query'] .= '&adduser=1';
2209 . PMA_getIcon('b_usradd.png') . __('Add user') . "\n"
2211 . '<form name="usersForm" id="addUsersForm_' . $random_n . '" action="server_privileges.php" method="post">' . "\n"
2212 . PMA_generate_common_hidden_inputs('', '');
2213 PMA_displayLoginInformationFields('new');
2214 echo '<fieldset id="fieldset_add_user_database">' . "\n"
2215 . '<legend>' . __('Database for user') . '</legend>' . "\n";
2217 $default_choice = 0;
2219 '0' => _pgettext('Create none database for user', 'None'),
2220 '1' => __('Create database with same name and grant all privileges'),
2221 '2' => __('Grant all privileges on wildcard name (username\\_%)'));
2223 if (! empty($dbname) ) {
2224 $choices['3'] = sprintf(
2225 __('Grant all privileges on database "%s"'),
2226 htmlspecialchars($dbname)
2228 $default_choice = 3;
2229 echo '<input type="hidden" name="dbname" value="' . htmlspecialchars($dbname) . '" />' . "\n";
2232 // 4th parameter set to true to add line breaks
2233 // 5th parameter set to false to avoid htmlspecialchars() escaping in the label
2234 // since we have some HTML in some labels
2235 PMA_display_html_radio('createdb', $choices, $default_choice, true, false);
2237 unset($default_choice);
2239 echo '</fieldset>' . "\n";
2240 PMA_displayPrivTable('*', '*', false);
2241 echo ' <fieldset id="fieldset_add_user_footer" class="tblFooters">' . "\n"
2242 . ' <input type="submit" name="adduser_submit" value="' . __('Go') . '" />' . "\n"
2243 . ' </fieldset>' . "\n"
2246 // check the privileges for a particular database.
2247 $user_form = '<form id="usersForm" action="server_privileges.php"><fieldset>' . "\n"
2249 . PMA_getIcon('b_usrcheck.png')
2250 . ' ' . sprintf(__('Users having access to "%s"'), '<a href="' . $GLOBALS['cfg']['DefaultTabDatabase'] . '?' . PMA_generate_common_url($checkprivs) . '">' . htmlspecialchars($checkprivs) . '</a>') . "\n"
2251 . '</legend>' . "\n"
2252 . '<table id="dbspecificuserrights" class="data">' . "\n"
2254 . ' <tr><th>' . __('User') . '</th>' . "\n"
2255 . ' <th>' . __('Host') . '</th>' . "\n"
2256 . ' <th>' . __('Type') . '</th>' . "\n"
2257 . ' <th>' . __('Privileges') . '</th>' . "\n"
2258 . ' <th>' . __('Grant') . '</th>' . "\n"
2259 . ' <th>' . __('Action') . '</th>' . "\n"
2264 unset($row, $row1, $row2);
2266 // now, we build the table...
2279 . '`References_priv`, '
2280 . '`Create_tmp_table_priv`, '
2281 . '`Lock_tables_priv`, '
2282 . '`Create_view_priv`, '
2283 . '`Show_view_priv`, '
2284 . '`Create_routine_priv`, '
2285 . '`Alter_routine_priv`, '
2288 $list_of_compared_privileges
2289 = '`Select_priv` = \'N\''
2290 . ' AND `Insert_priv` = \'N\''
2291 . ' AND `Update_priv` = \'N\''
2292 . ' AND `Delete_priv` = \'N\''
2293 . ' AND `Create_priv` = \'N\''
2294 . ' AND `Drop_priv` = \'N\''
2295 . ' AND `Grant_priv` = \'N\''
2296 . ' AND `References_priv` = \'N\''
2297 . ' AND `Create_tmp_table_priv` = \'N\''
2298 . ' AND `Lock_tables_priv` = \'N\''
2299 . ' AND `Create_view_priv` = \'N\''
2300 . ' AND `Show_view_priv` = \'N\''
2301 . ' AND `Create_routine_priv` = \'N\''
2302 . ' AND `Alter_routine_priv` = \'N\''
2303 . ' AND `Execute_priv` = \'N\'';
2305 if (PMA_MYSQL_INT_VERSION
>= 50106) {
2306 $list_of_privileges .=
2309 $list_of_compared_privileges .=
2310 ' AND `Event_priv` = \'N\''
2311 . ' AND `Trigger_priv` = \'N\'';
2314 $sql_query = '(SELECT ' . $list_of_privileges . ', `Db`'
2315 .' FROM `mysql`.`db`'
2316 .' WHERE \'' . PMA_sqlAddSlashes($checkprivs) . "'"
2318 .' AND NOT (' . $list_of_compared_privileges. ')) '
2320 .'(SELECT ' . $list_of_privileges . ', \'*\' AS `Db`'
2321 .' FROM `mysql`.`user` '
2322 .' WHERE NOT (' . $list_of_compared_privileges . ')) '
2323 .' ORDER BY `User` ASC,'
2326 $res = PMA_DBI_query($sql_query);
2327 $row = PMA_DBI_fetch_assoc($res);
2334 // prepare the current user
2335 $current_privileges = array();
2336 $current_user = $row['User'];
2337 $current_host = $row['Host'];
2338 while ($row && $current_user == $row['User'] && $current_host == $row['Host']) {
2339 $current_privileges[] = $row;
2340 $row = PMA_DBI_fetch_assoc($res);
2342 $user_form .= ' <tr class="noclick ' . ($odd_row ?
'odd' : 'even') . '">' . "\n"
2344 if (count($current_privileges) > 1) {
2345 $user_form .= ' rowspan="' . count($current_privileges) . '"';
2347 $user_form .= '>' . (empty($current_user) ?
'<span style="color: #FF0000">' . __('Any') . '</span>' : htmlspecialchars($current_user)) . "\n"
2350 if (count($current_privileges) > 1) {
2351 $user_form .= ' rowspan="' . count($current_privileges) . '"';
2353 $user_form .= '>' . htmlspecialchars($current_host) . '</td>' . "\n";
2354 for ($i = 0; $i < count($current_privileges); $i++
) {
2355 $current = $current_privileges[$i];
2356 $user_form .= ' <td>' . "\n"
2358 if (! isset($current['Db']) ||
$current['Db'] == '*') {
2359 $user_form .= __('global');
2360 } elseif ($current['Db'] == PMA_escape_mysql_wildcards($checkprivs)) {
2361 $user_form .= __('database-specific');
2363 $user_form .= __('wildcard'). ': <tt>' . htmlspecialchars($current['Db']) . '</tt>';
2369 . ' ' . join(',' . "\n" . ' ', PMA_extractPrivInfo($current, true)) . "\n"
2373 . ' ' . ($current['Grant_priv'] == 'Y' ?
__('Yes') : __('No')) . "\n"
2376 $user_form .= sprintf(
2378 urlencode($current_user),
2379 urlencode($current_host),
2380 urlencode(! isset($current['Db']) ||
$current['Db'] == '*' ?
'' : $current['Db']),
2383 $user_form .= '</td>' . "\n"
2385 if (($i +
1) < count($current_privileges)) {
2386 $user_form .= '<tr class="noclick ' . ($odd_row ?
'odd' : 'even') . '">' . "\n";
2389 if (empty($row) && empty($row1) && empty($row2)) {
2392 $odd_row = ! $odd_row;
2395 $user_form .= ' <tr class="odd">' . "\n"
2396 . ' <td colspan="6">' . "\n"
2397 . ' ' . __('No user found.') . "\n"
2401 $user_form .= '</tbody>' . "\n"
2402 . '</table></fieldset></form>' . "\n";
2404 if ($GLOBALS['is_ajax_request'] == true) {
2405 $extra_data['user_form'] = $user_form;
2406 $message = PMA_Message
::success(__('User has been added.'));
2407 PMA_ajaxResponse($message, $message->isSuccess(), $extra_data);
2409 // Offer to create a new user for the current database
2410 $user_form .= '<fieldset id="fieldset_add_user">' . "\n"
2411 . '<legend>' . __('New') . '</legend>' . "\n"
2412 . ' <a href="server_privileges.php?' . $GLOBALS['url_query'] . '&adduser=1&dbname=' . htmlspecialchars($checkprivs) .'" rel="'.'checkprivs='.htmlspecialchars($checkprivs). '&'.$GLOBALS['url_query'] . '" class="'.$conditional_class.'" name="db_specific">' . "\n"
2413 . PMA_getIcon('b_usradd.png')
2414 . ' ' . __('Add user') . '</a>' . "\n"
2415 . '</fieldset>' . "\n";
2419 } // end if (empty($_REQUEST['adduser']) && empty($checkprivs)) ... elseif ... else ...
2423 * Displays the footer
2426 require './libraries/footer.inc.php';