[ Index ]

PHP Cross Reference of YOURLS

title

Body

[close]

/includes/Database/ -> Logger.php (source)

   1  <?php
   2  
   3  /**
   4   * Custom logger for YOURLS that logs debug messages and queries.
   5   *
   6   * Based on \Aura\Sql\Profiler\MemoryLogger
   7   *
   8   * @since 1.7.10
   9   */
  10  
  11  namespace YOURLS\Database;
  12  
  13  use Psr\Log\AbstractLogger;
  14  
  15  class Logger extends AbstractLogger {
  16      /**
  17       * Log messages.
  18       *
  19       * @var array
  20       */
  21      protected $messages = [];
  22  
  23      /**
  24       * Logs a message.
  25       *
  26       * @param string  $level    The log level (ie type of message)
  27       * @param string  $message  The log message.
  28       * @param array   $context  Data to interpolate into the message.
  29       *
  30       * The logger receives the following:
  31       *
  32       * From yourls_debug("something went wrong") :
  33       *    $level   : string 'debug'
  34       *    $message : string 'something went wrong'
  35       *    $context : array()
  36       * See yourls_debug() in includes/functions-debug.php
  37       *
  38       * From a query that triggers the internal logging of Aura SQL :
  39       *    $level   : string 'query'
  40       *    $message : string '{function} ({duration} seconds): {statement} {backtrace}'
  41       *               (which is the default $logFormat from Aura\Sql\Profiler\Profiler), we're not using it)
  42       *    $context : array(
  43       *               'function' => string 'perform'
  44       *               'duration' => float 0.0025360584259033
  45       *               'statement' => string 'SELECT `keyword`,`url` FROM `yourls_url` WHERE `url` LIKE (:url)'
  46       *               'values' => array('url' => '%rss%')
  47       *               )
  48       * See finish() in Aura\Sql\Profiler\Profiler
  49       *
  50       * @return void
  51       */
  52      public function log($level, string|\Stringable $message, array $context = []): void {
  53          // if it's an internal SQL query, format the message, otherwise store a string
  54          if($level === 'query') {
  55              // Get the real function name that called the query (not just "perform")
  56              $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 6);
  57              // We should have at index 5 "fetchSomething" (eg fetchAll, fetchOne, etc), otherwise make it "perform"
  58              $function = $backtrace[5]['function'] ?? 'perform';
  59              $context['function'] = str_starts_with($function, 'fetch') ? $function : 'perform';
  60              $this->messages[] = sprintf(
  61                  'SQL %s: %s (%s s)',
  62                  $context['function'],
  63                  $this->pretty_format($context['statement'], $context['values']),
  64                  number_format($context['duration'], 5)
  65              );
  66          } else {
  67              $this->messages[] = (string)$message;
  68          }
  69      }
  70  
  71      /**
  72       * Returns the logged messages.
  73       *
  74       * @return array
  75       */
  76      public function getMessages() {
  77          return $this->messages;
  78      }
  79  
  80      /**
  81       * Format PDO statement with bind/values replacement
  82       *
  83       * This replaces PDO binds such as 'key_name = :name' with corresponding array values, eg array('name'=>'some value')
  84       * This is merely a cosmetic replacement to allow for readability: the result WILL NOT be valid SQL! (eg no proper quotes)
  85       *
  86       * @since  1.7.3
  87       * @param  string $statement  SQL query with PDO style named placeholders
  88       * @param  array  $values     Optional array of values corresponding to placeholders
  89       * @return string             Readable SQL query with placeholders replaced
  90       */
  91      public function pretty_format($statement, array $values = array() ) {
  92          if (!$values) {
  93              return $statement;
  94          }
  95  
  96          return preg_replace_callback(
  97              '/:([^\s;)]*)/',
  98  
  99              /**
 100               * @param string $matches
 101               */
 102              function ($matches) use ($values) {
 103                  $replacement = isset( $values[$matches[1]] ) ? $values[$matches[1]] : '';
 104                  if(is_array($replacement)) {
 105                      $replacement = implode(",", $replacement);
 106                  }
 107                  return "'$replacement'";
 108              },
 109              $statement
 110          );
 111      }
 112  
 113  }


Generated: Sat Aug 8 05:10:51 2026 Cross-referenced by PHPXref 0.7.1