cms/drupal/modules/dblog/dblog.admin.inc
changeset 541 e756a8c72c3d
equal deleted inserted replaced
540:07239de796bb 541:e756a8c72c3d
       
     1 <?php
       
     2 
       
     3 /**
       
     4  * @file
       
     5  * Administrative page callbacks for the Database Logging module.
       
     6  */
       
     7 
       
     8 /**
       
     9  * Page callback: Displays a listing of database log messages.
       
    10  *
       
    11  * Messages are truncated at 56 chars. Full-length messages can be viewed on the
       
    12  * message details page.
       
    13  *
       
    14  * @see dblog_clear_log_form()
       
    15  * @see dblog_event()
       
    16  * @see dblog_filter_form()
       
    17  * @see dblog_menu()
       
    18  *
       
    19  * @ingroup logging_severity_levels
       
    20  */
       
    21 function dblog_overview() {
       
    22   $filter = dblog_build_filter_query();
       
    23   $rows = array();
       
    24   $classes = array(
       
    25     WATCHDOG_DEBUG     => 'dblog-debug',
       
    26     WATCHDOG_INFO      => 'dblog-info',
       
    27     WATCHDOG_NOTICE    => 'dblog-notice',
       
    28     WATCHDOG_WARNING   => 'dblog-warning',
       
    29     WATCHDOG_ERROR     => 'dblog-error',
       
    30     WATCHDOG_CRITICAL  => 'dblog-critical',
       
    31     WATCHDOG_ALERT     => 'dblog-alert',
       
    32     WATCHDOG_EMERGENCY => 'dblog-emerg',
       
    33   );
       
    34 
       
    35   $build['dblog_filter_form'] = drupal_get_form('dblog_filter_form');
       
    36   $build['dblog_clear_log_form'] = drupal_get_form('dblog_clear_log_form');
       
    37 
       
    38   $header = array(
       
    39     '', // Icon column.
       
    40     array('data' => t('Type'), 'field' => 'w.type'),
       
    41     array('data' => t('Date'), 'field' => 'w.wid', 'sort' => 'desc'),
       
    42     t('Message'),
       
    43     array('data' => t('User'), 'field' => 'u.name'),
       
    44     array('data' => t('Operations')),
       
    45   );
       
    46 
       
    47   $query = db_select('watchdog', 'w')->extend('PagerDefault')->extend('TableSort');
       
    48   $query->leftJoin('users', 'u', 'w.uid = u.uid');
       
    49   $query
       
    50     ->fields('w', array('wid', 'uid', 'severity', 'type', 'timestamp', 'message', 'variables', 'link'))
       
    51     ->addField('u', 'name');
       
    52   if (!empty($filter['where'])) {
       
    53     $query->where($filter['where'], $filter['args']);
       
    54   }
       
    55   $result = $query
       
    56     ->limit(50)
       
    57     ->orderByHeader($header)
       
    58     ->execute();
       
    59 
       
    60   foreach ($result as $dblog) {
       
    61     $rows[] = array('data' =>
       
    62       array(
       
    63         // Cells
       
    64         array('class' => 'icon'),
       
    65         t($dblog->type),
       
    66         format_date($dblog->timestamp, 'short'),
       
    67         theme('dblog_message', array('event' => $dblog, 'link' => TRUE)),
       
    68         theme('username', array('account' => $dblog)),
       
    69         filter_xss($dblog->link),
       
    70       ),
       
    71       // Attributes for tr
       
    72       'class' => array(drupal_html_class('dblog-' . $dblog->type), $classes[$dblog->severity]),
       
    73     );
       
    74   }
       
    75 
       
    76   $build['dblog_table'] = array(
       
    77     '#theme' => 'table',
       
    78     '#header' => $header,
       
    79     '#rows' => $rows,
       
    80     '#attributes' => array('id' => 'admin-dblog'),
       
    81     '#empty' => t('No log messages available.'),
       
    82   );
       
    83   $build['dblog_pager'] = array('#theme' => 'pager');
       
    84 
       
    85   return $build;
       
    86 }
       
    87 
       
    88 /**
       
    89  * Page callback: Shows the most frequent log messages of a given event type.
       
    90  *
       
    91  * Messages are not truncated on this page because events detailed herein do not
       
    92  * have links to a detailed view.
       
    93  *
       
    94  * @param string $type
       
    95  *   Type of database log events to display (e.g., 'search').
       
    96  *
       
    97  * @return array
       
    98  *   A build array in the format expected by drupal_render().
       
    99  *
       
   100  * @see dblog_menu()
       
   101  */
       
   102 function dblog_top($type) {
       
   103 
       
   104   $header = array(
       
   105     array('data' => t('Count'), 'field' => 'count', 'sort' => 'desc'),
       
   106     array('data' => t('Message'), 'field' => 'message')
       
   107   );
       
   108   $count_query = db_select('watchdog');
       
   109   $count_query->addExpression('COUNT(DISTINCT(message))');
       
   110   $count_query->condition('type', $type);
       
   111 
       
   112   $query = db_select('watchdog', 'w')->extend('PagerDefault')->extend('TableSort');
       
   113   $query->addExpression('COUNT(wid)', 'count');
       
   114   $query = $query
       
   115     ->fields('w', array('message', 'variables'))
       
   116     ->condition('w.type', $type)
       
   117     ->groupBy('message')
       
   118     ->groupBy('variables')
       
   119     ->limit(30)
       
   120     ->orderByHeader($header);
       
   121   $query->setCountQuery($count_query);
       
   122   $result = $query->execute();
       
   123 
       
   124   $rows = array();
       
   125   foreach ($result as $dblog) {
       
   126     $rows[] = array($dblog->count, theme('dblog_message', array('event' => $dblog)));
       
   127   }
       
   128 
       
   129   $build['dblog_top_table']  = array(
       
   130     '#theme' => 'table',
       
   131     '#header' => $header,
       
   132     '#rows' => $rows,
       
   133     '#empty' => t('No log messages available.'),
       
   134   );
       
   135   $build['dblog_top_pager'] = array('#theme' => 'pager');
       
   136 
       
   137   return $build;
       
   138 }
       
   139 
       
   140 /**
       
   141  * Page callback: Displays details about a specific database log message.
       
   142  *
       
   143  * @param int $id
       
   144  *   Unique ID of the database log message.
       
   145  *
       
   146  * @return array|string
       
   147  *   If the ID is located in the Database Logging table, a build array in the
       
   148  *   format expected by drupal_render(); otherwise, an empty string.
       
   149  *
       
   150  * @see dblog_menu()
       
   151  */
       
   152 function dblog_event($id) {
       
   153   $severity = watchdog_severity_levels();
       
   154   $result = db_query('SELECT w.*, u.name, u.uid FROM {watchdog} w INNER JOIN {users} u ON w.uid = u.uid WHERE w.wid = :id', array(':id' => $id))->fetchObject();
       
   155   if ($dblog = $result) {
       
   156     $rows = array(
       
   157       array(
       
   158         array('data' => t('Type'), 'header' => TRUE),
       
   159         t($dblog->type),
       
   160       ),
       
   161       array(
       
   162         array('data' => t('Date'), 'header' => TRUE),
       
   163         format_date($dblog->timestamp, 'long'),
       
   164       ),
       
   165       array(
       
   166         array('data' => t('User'), 'header' => TRUE),
       
   167         theme('username', array('account' => $dblog)),
       
   168       ),
       
   169       array(
       
   170         array('data' => t('Location'), 'header' => TRUE),
       
   171         l($dblog->location, $dblog->location),
       
   172       ),
       
   173       array(
       
   174         array('data' => t('Referrer'), 'header' => TRUE),
       
   175         l($dblog->referer, $dblog->referer),
       
   176       ),
       
   177       array(
       
   178         array('data' => t('Message'), 'header' => TRUE),
       
   179         theme('dblog_message', array('event' => $dblog)),
       
   180       ),
       
   181       array(
       
   182         array('data' => t('Severity'), 'header' => TRUE),
       
   183         $severity[$dblog->severity],
       
   184       ),
       
   185       array(
       
   186         array('data' => t('Hostname'), 'header' => TRUE),
       
   187         check_plain($dblog->hostname),
       
   188       ),
       
   189       array(
       
   190         array('data' => t('Operations'), 'header' => TRUE),
       
   191         $dblog->link,
       
   192       ),
       
   193     );
       
   194     $build['dblog_table'] = array(
       
   195       '#theme' => 'table',
       
   196       '#rows' => $rows,
       
   197       '#attributes' => array('class' => array('dblog-event')),
       
   198     );
       
   199     return $build;
       
   200   }
       
   201   else {
       
   202     return '';
       
   203   }
       
   204 }
       
   205 
       
   206 /**
       
   207  * Builds a query for database log administration filters based on session.
       
   208  *
       
   209  * @return array
       
   210  *   An associative array with keys 'where' and 'args'.
       
   211  */
       
   212 function dblog_build_filter_query() {
       
   213   if (empty($_SESSION['dblog_overview_filter'])) {
       
   214     return;
       
   215   }
       
   216 
       
   217   $filters = dblog_filters();
       
   218 
       
   219   // Build query
       
   220   $where = $args = array();
       
   221   foreach ($_SESSION['dblog_overview_filter'] as $key => $filter) {
       
   222     $filter_where = array();
       
   223     foreach ($filter as $value) {
       
   224       $filter_where[] = $filters[$key]['where'];
       
   225       $args[] = $value;
       
   226     }
       
   227     if (!empty($filter_where)) {
       
   228       $where[] = '(' . implode(' OR ', $filter_where) . ')';
       
   229     }
       
   230   }
       
   231   $where = !empty($where) ? implode(' AND ', $where) : '';
       
   232 
       
   233   return array(
       
   234     'where' => $where,
       
   235     'args' => $args,
       
   236   );
       
   237 }
       
   238 
       
   239 /**
       
   240  * Creates a list of database log administration filters that can be applied.
       
   241  *
       
   242  * @return array
       
   243  *   Associative array of filters. The top-level keys are used as the form
       
   244  *   element names for the filters, and the values are arrays with the following
       
   245  *   elements:
       
   246  *   - title: Title of the filter.
       
   247  *   - where: The filter condition.
       
   248  *   - options: Array of options for the select list for the filter.
       
   249  */
       
   250 function dblog_filters() {
       
   251   $filters = array();
       
   252 
       
   253   foreach (_dblog_get_message_types() as $type) {
       
   254     $types[$type] = t($type);
       
   255   }
       
   256 
       
   257   if (!empty($types)) {
       
   258     $filters['type'] = array(
       
   259       'title' => t('Type'),
       
   260       'where' => "w.type = ?",
       
   261       'options' => $types,
       
   262     );
       
   263   }
       
   264 
       
   265   $filters['severity'] = array(
       
   266     'title' => t('Severity'),
       
   267     'where' => 'w.severity = ?',
       
   268     'options' => watchdog_severity_levels(),
       
   269   );
       
   270 
       
   271   return $filters;
       
   272 }
       
   273 
       
   274 /**
       
   275  * Returns HTML for a log message.
       
   276  *
       
   277  * @param array $variables
       
   278  *   An associative array containing:
       
   279  *   - event: An object with at least the message and variables properties.
       
   280  *   - link: (optional) Format message as link, event->wid is required.
       
   281  *
       
   282  * @ingroup themeable
       
   283  */
       
   284 function theme_dblog_message($variables) {
       
   285   $output = '';
       
   286   $event = $variables['event'];
       
   287   // Check for required properties.
       
   288   if (isset($event->message) && isset($event->variables)) {
       
   289     // Messages without variables or user specified text.
       
   290     if ($event->variables === 'N;') {
       
   291       $output = $event->message;
       
   292     }
       
   293     // Message to translate with injected variables.
       
   294     else {
       
   295       $output = t($event->message, unserialize($event->variables));
       
   296     }
       
   297     // If the output is expected to be a link, strip all the tags and
       
   298     // special characters by using filter_xss() without any allowed tags.
       
   299     // If not, use filter_xss_admin() to allow some tags.
       
   300     if ($variables['link'] && isset($event->wid)) {
       
   301       // Truncate message to 56 chars after stripping all the tags.
       
   302       $output = truncate_utf8(filter_xss($output, array()), 56, TRUE, TRUE);
       
   303       $output = l($output, 'admin/reports/event/' . $event->wid, array('html' => TRUE));
       
   304     }
       
   305     else {
       
   306       // Prevent XSS in log detail pages.
       
   307       $output = filter_xss_admin($output);
       
   308     }
       
   309   }
       
   310   return $output;
       
   311 }
       
   312 
       
   313 /**
       
   314  * Form constructor for the database logging filter form.
       
   315  *
       
   316  * @see dblog_filter_form_validate()
       
   317  * @see dblog_filter_form_submit()
       
   318  * @see dblog_overview()
       
   319  *
       
   320  * @ingroup forms
       
   321  */
       
   322 function dblog_filter_form($form) {
       
   323   $filters = dblog_filters();
       
   324 
       
   325   $form['filters'] = array(
       
   326     '#type' => 'fieldset',
       
   327     '#title' => t('Filter log messages'),
       
   328     '#collapsible' => TRUE,
       
   329     '#collapsed' => empty($_SESSION['dblog_overview_filter']),
       
   330   );
       
   331   foreach ($filters as $key => $filter) {
       
   332     $form['filters']['status'][$key] = array(
       
   333       '#title' => $filter['title'],
       
   334       '#type' => 'select',
       
   335       '#multiple' => TRUE,
       
   336       '#size' => 8,
       
   337       '#options' => $filter['options'],
       
   338     );
       
   339     if (!empty($_SESSION['dblog_overview_filter'][$key])) {
       
   340       $form['filters']['status'][$key]['#default_value'] = $_SESSION['dblog_overview_filter'][$key];
       
   341     }
       
   342   }
       
   343 
       
   344   $form['filters']['actions'] = array(
       
   345     '#type' => 'actions',
       
   346     '#attributes' => array('class' => array('container-inline')),
       
   347   );
       
   348   $form['filters']['actions']['submit'] = array(
       
   349     '#type' => 'submit',
       
   350     '#value' => t('Filter'),
       
   351   );
       
   352   if (!empty($_SESSION['dblog_overview_filter'])) {
       
   353     $form['filters']['actions']['reset'] = array(
       
   354       '#type' => 'submit',
       
   355       '#value' => t('Reset')
       
   356     );
       
   357   }
       
   358   return $form;
       
   359 }
       
   360 
       
   361 /**
       
   362  * Form validation handler for dblog_filter_form().
       
   363  *
       
   364  * @see dblog_filter_form_submit()
       
   365  */
       
   366 function dblog_filter_form_validate($form, &$form_state) {
       
   367   if ($form_state['values']['op'] == t('Filter') && empty($form_state['values']['type']) && empty($form_state['values']['severity'])) {
       
   368     form_set_error('type', t('You must select something to filter by.'));
       
   369   }
       
   370 }
       
   371 
       
   372 /**
       
   373  * Form submission handler for dblog_filter_form().
       
   374  *
       
   375  * @see dblog_filter_form_validate()
       
   376  */
       
   377 function dblog_filter_form_submit($form, &$form_state) {
       
   378   $op = $form_state['values']['op'];
       
   379   $filters = dblog_filters();
       
   380   switch ($op) {
       
   381     case t('Filter'):
       
   382       foreach ($filters as $name => $filter) {
       
   383         if (isset($form_state['values'][$name])) {
       
   384           $_SESSION['dblog_overview_filter'][$name] = $form_state['values'][$name];
       
   385         }
       
   386       }
       
   387       break;
       
   388     case t('Reset'):
       
   389       $_SESSION['dblog_overview_filter'] = array();
       
   390       break;
       
   391   }
       
   392   return 'admin/reports/dblog';
       
   393 }
       
   394 
       
   395 /**
       
   396  * Form constructor for the form that clears out the log.
       
   397  *
       
   398  * @see dblog_clear_log_submit()
       
   399  * @ingroup forms
       
   400  */
       
   401 function dblog_clear_log_form($form) {
       
   402   $form['dblog_clear'] = array(
       
   403     '#type' => 'fieldset',
       
   404     '#title' => t('Clear log messages'),
       
   405     '#description' => t('This will permanently remove the log messages from the database.'),
       
   406     '#collapsible' => TRUE,
       
   407     '#collapsed' => TRUE,
       
   408   );
       
   409   $form['dblog_clear']['clear'] = array(
       
   410     '#type' => 'submit',
       
   411     '#value' => t('Clear log messages'),
       
   412     '#submit' => array('dblog_clear_log_submit'),
       
   413   );
       
   414 
       
   415   return $form;
       
   416 }
       
   417 
       
   418 /**
       
   419  * Form submission handler for dblog_clear_log_form().
       
   420  */
       
   421 function dblog_clear_log_submit() {
       
   422   $_SESSION['dblog_overview_filter'] = array();
       
   423   db_truncate('watchdog')->execute();
       
   424   drupal_set_message(t('Database log cleared.'));
       
   425 }