[ Index ]

PHP Cross Reference of YOURLS

title

Body

[close]

/includes/ -> functions-infos.php (source)

   1  <?php
   2  
   3  /**
   4   * Echoes an image tag of Google Charts map from sorted array of 'country_code' => 'number of visits' (sort by DESC)
   5   *
   6   * @param array $countries  Array of 'country_code' => 'number of visits'
   7   * @param string $id        Optional HTML element ID
   8   * @return void
   9   */
  10  function yourls_stats_countries_map($countries, $id = null) {
  11  
  12      yourls_do_action( 'pre_stats_countries_map' );
  13  
  14      // if $id is null then assign a random string
  15      if( $id === null )
  16          $id = uniqid ( 'yourls_stats_map_' );
  17  
  18      $data = array_merge( array( 'Country' => 'Hits' ), $countries );
  19      $data = yourls_google_array_to_data_table( $data );
  20  
  21      $options = array(
  22          'backgroundColor' => "white",
  23          'colorAxis'       => "{colors:['A8D0ED','99C4E4','8AB8DB','7BACD2','6BA1C9','5C95C0','4D89B7','3E7DAE','2E72A5','1F669C']}",
  24          'width'           => "550",
  25          'height'          => "340",
  26          'theme'           => 'maximized'
  27      );
  28      $options = yourls_apply_filter( 'stats_countries_map_options', $options );
  29  
  30      $map = yourls_google_viz_code( 'GeoChart', $data, $options, $id );
  31  
  32      echo yourls_apply_filter( 'stats_countries_map', $map, $countries, $options, $id );
  33  }
  34  
  35  
  36  /**
  37   * Echoes an image tag of Google Charts pie from sorted array of 'data' => 'value' (sort by DESC). Optional $limit = (integer) limit list of X first countries, sorted by most visits
  38   *
  39   * @param array $data  Array of 'data' => 'value'
  40   * @param int $limit   Optional limit list of X first countries
  41   * @param int $size    Optional size of the image
  42   * @param mixed $id    Optional HTML element ID
  43   * @return void
  44   */
  45  function yourls_stats_pie($data, $limit = 10, $size = '340x220', $id = null) {
  46  
  47      yourls_do_action( 'pre_stats_pie' );
  48  
  49      // if $id is null then assign a random string
  50      if( $id === null )
  51          $id = uniqid ( 'yourls_stats_pie_' );
  52  
  53      // Trim array: $limit first item + the sum of all others
  54      if ( count( $data ) > $limit ) {
  55          $i= 0;
  56          $trim_data = array( 'Others' => 0 );
  57          foreach( $data as $item=>$value ) {
  58              $i++;
  59              if( $i <= $limit ) {
  60                  $trim_data[$item] = $value;
  61              } else {
  62                  $trim_data['Others'] += $value;
  63              }
  64          }
  65          $data = $trim_data;
  66      }
  67  
  68      // Scale items
  69      $_data = yourls_scale_data( $data );
  70  
  71      list($width, $height) = explode( 'x', $size );
  72  
  73      $options = array(
  74          'theme'  => 'maximized',
  75          'width'   => $width,
  76          'height'   => $height,
  77          'colors'    => "['A8D0ED','99C4E4','8AB8DB','7BACD2','6BA1C9','5C95C0','4D89B7','3E7DAE','2E72A5','1F669C']",
  78          'legend'     => 'none',
  79          'chartArea'   => '{top: "5%", height: "90%"}',
  80          'pieSliceText' => 'label',
  81      );
  82      $options = yourls_apply_filter( 'stats_pie_options', $options );
  83  
  84      $script_data = array_merge( array( 'Country' => 'Value' ), $_data );
  85      $script_data = yourls_google_array_to_data_table( $script_data );
  86  
  87      $pie = yourls_google_viz_code( 'PieChart', $script_data, $options, $id );
  88  
  89      echo yourls_apply_filter( 'stats_pie', $pie, $data, $limit, $size, $options, $id );
  90  }
  91  
  92  
  93  /**
  94   * Build a list of all daily values between d1/m1/y1 to d2/m2/y2.
  95   *
  96   * @param array $dates
  97   * @return array[]  Array of arrays of days, months, years
  98   */
  99  function yourls_build_list_of_days($dates) {
 100      /* Say we have an array like:
 101      $dates = array (
 102          2009 => array (
 103              '08' => array (
 104                  29 => 15,
 105                  30 => 5,
 106                  ),
 107              '09' => array (
 108                  '02' => 3,
 109                  '03' => 5,
 110                  '04' => 2,
 111                  '05' => 99,
 112                  ),
 113              ),
 114          )
 115      */
 116  
 117      if( !$dates )
 118          return array();
 119  
 120      // Get first & last years from our range. In our example: 2009 & 2009
 121      $first_year = key( $dates );
 122      $_keys      = array_keys( $dates );
 123      $last_year  = end( $_keys );
 124      reset( $dates );
 125  
 126      // Get first & last months from our range. In our example: 08 & 09
 127      $first_month = key( $dates[ $first_year ] );
 128      $_keys       = array_keys( $dates[ $last_year ] );
 129      $last_month  = end( $_keys );
 130      reset( $dates );
 131  
 132      // Get first & last days from our range. In our example: 29 & 05
 133      $first_day = key( $dates[ $first_year ][ $first_month ] );
 134      $_keys     = array_keys( $dates[ $last_year ][ $last_month ] );
 135      $last_day  = end( $_keys );
 136  
 137      unset( $_keys );
 138  
 139      // Extend to today
 140      $today = new DateTime();
 141      $today->setTime( 0, 0, 0 ); // Start of today
 142      $today_year = $today->format( 'Y' );
 143      $today_month = $today->format( 'm' );
 144      $today_day = $today->format( 'd' );
 145  
 146      // Now build a list of all years (2009), month (08 & 09) and days (all from 2009-08-29 to 2009-09-05)
 147      $list_of_years  = array();
 148      $list_of_months = array();
 149      $list_of_days   = array();
 150      for ( $year = $first_year; $year <= $today_year; $year++ ) {
 151          $_year = sprintf( '%04d', $year );
 152          $list_of_years[ $_year ] = $_year;
 153          $current_first_month = ( $year == $first_year ? $first_month : '01' );
 154          $current_last_month = ( $year == $today_year ? $today_month : '12' );
 155          for ( $month = $current_first_month; $month <= $current_last_month; $month++ ) {
 156              $_month = sprintf( '%02d', $month );
 157              $list_of_months[ $_month ] = $_month;
 158              $current_first_day = ( $year == $first_year && $month == $first_month ? $first_day : '01' );
 159              $current_last_day = ( $year == $today_year && $month == $today_month ? $today_day : yourls_days_in_month( $month, $year ) );
 160              for ( $day = $current_first_day; $day <= $current_last_day; $day++ ) {
 161                  $day = sprintf( '%02d', $day );
 162                  $key = date( 'M d, Y', mktime( 0, 0, 0, $_month, $day, $_year ) );
 163                  $list_of_days[ $key ] = isset( $dates[$_year][$_month][$day] ) ? $dates[$_year][$_month][$day] : 0;
 164              }
 165          }
 166      }
 167  
 168      return array(
 169          'list_of_days'   => $list_of_days,
 170          'list_of_months' => $list_of_months,
 171          'list_of_years'  => $list_of_years,
 172      );
 173  }
 174  
 175  
 176  /**
 177   * Echoes an image tag of Google Charts line graph from array of values (eg 'number of clicks').
 178   *
 179   * $legend1_list & legend2_list are values used for the 2 x-axis labels. $id is an HTML/JS id
 180   *
 181   * @param array $values  Array of values (eg 'number of clicks')
 182   * @param string $id     HTML element id
 183   * @return void
 184   */
 185  function yourls_stats_line($values, $id = null) {
 186  
 187      yourls_do_action( 'pre_stats_line' );
 188  
 189      // if $id is null then assign a random string
 190      if( $id === null )
 191          $id = uniqid ( 'yourls_stats_line_' );
 192  
 193      // If we have only 1 day of data, prepend a fake day with 0 hits for a prettier graph
 194      if ( count( $values ) == 1 )
 195          array_unshift( $values, 0 );
 196  
 197      // Keep only a subset of values to keep graph smooth
 198      $values = yourls_array_granularity( $values, 30 );
 199  
 200      $data = array_merge( array( 'Time' => 'Hits' ), $values );
 201      $data = yourls_google_array_to_data_table( $data );
 202  
 203      $options = array(
 204          "legend"      => "none",
 205          "pointSize"   => "3",
 206          "theme"       => "maximized",
 207          "curveType"   => "function",
 208          "width"       => 430,
 209          "height"      => 220,
 210          "hAxis"       => "{minTextSpacing: 80, maxTextLines: 1, maxAlternation: 1}",
 211          "vAxis"       => "{minValue: 0, format: '#'}",
 212          "colors"      => "['#2a85b3']",
 213      );
 214      $options = yourls_apply_filter( 'stats_line_options', $options );
 215  
 216      $lineChart = yourls_google_viz_code( 'LineChart', $data, $options, $id );
 217  
 218      echo yourls_apply_filter( 'stats_line', $lineChart, $values, $options, $id );
 219  }
 220  
 221  
 222  /**
 223   * Return the number of days in a month. From php.net.
 224   *
 225   * @param int $month
 226   * @param int $year
 227   * @return int
 228   */
 229  function yourls_days_in_month($month, $year) {
 230      // calculate number of days in a month
 231      return $month == 2 ? ( $year % 4 ? 28 : ( $year % 100 ? 29 : ( $year % 400 ? 28 : 29 ) ) ) : ( ( $month - 1 ) % 7 % 2 ? 30 : 31 );
 232  }
 233  
 234  
 235  /**
 236   * Get max value from date array of 'Aug 12, 2012' = '1337'
 237   *
 238   * @param array $list_of_days
 239   * @return array
 240   */
 241  function yourls_stats_get_best_day($list_of_days) {
 242      $max = max( $list_of_days );
 243      foreach( $list_of_days as $k=>$v ) {
 244          if ( $v == $max )
 245              return array( 'day' => $k, 'max' => $max );
 246      }
 247  }
 248  
 249  /**
 250   * Return domain of a URL
 251   *
 252   * @param string $url
 253   * @param bool $include_scheme
 254   * @return string
 255   */
 256  function yourls_get_domain(string $url, bool $include_scheme = false): string {
 257      $parse = parse_url($url);
 258  
 259      // parse_url() returns false on seriously malformed URLs
 260      if ($parse === false) {
 261          return '';
 262      }
 263  
 264      // Get host & scheme. Fall back to path if not found.
 265      $host = $parse['host'] ?? '';
 266      $scheme = $parse['scheme'] ?? '';
 267      $path = $parse['path'] ?? '';
 268      if (!$host) {
 269          $host = $path;
 270      }
 271  
 272      // Validate host: only allow valid hostname/IP characters.
 273      // IPv6 addresses are wrapped in brackets eg [::1]
 274      if ($host && !preg_match('/^(\[[\da-fA-F:]+\]|[a-zA-Z0-9._-]+)$/', $host)) {
 275          // ASCII check failed - may be an IDN hostname (eg münchen.de)
 276          if (function_exists('idn_to_ascii')) {
 277              $ascii = idn_to_ascii($host, IDNA_DEFAULT, INTL_IDNA_VARIANT_UTS46);
 278              if ($ascii === false || !preg_match('/^[a-zA-Z0-9._-]+$/', $ascii)) {
 279                  return '';
 280              }
 281              $host = $ascii;
 282          } else {
 283              // No intl extension: accept unicode letters/digits, dots and hyphens only
 284              if (!preg_match('/^[\pL\pN._-]+$/u', $host)) {
 285                  return '';
 286              }
 287          }
 288      }
 289  
 290      if ($include_scheme && $scheme) {
 291          $host = $scheme . '://' . $host;
 292      }
 293  
 294      return $host;
 295  }
 296  
 297  
 298  /**
 299   * Return favicon URL
 300   *
 301   * @param string $url
 302   * @return string
 303   */
 304  function yourls_get_favicon_url(string $url): string {
 305      return yourls_match_current_protocol( '//www.google.com/s2/favicons?domain=' . yourls_esc_url(yourls_get_domain( $url, false ) ) );
 306  }
 307  
 308  /**
 309   * Scale array of data from 0 to 100 max
 310   *
 311   * @param array $data
 312   * @return array
 313   */
 314  function yourls_scale_data($data ) {
 315      $max = max( $data );
 316      if( $max > 100 ) {
 317          foreach( $data as $k=>$v ) {
 318              $data[$k] = intval( $v / $max * 100 );
 319          }
 320      }
 321      return $data;
 322  }
 323  
 324  
 325  /**
 326   * Tweak granularity of array $array: keep only $grain values.
 327   *
 328   * This make less accurate but less messy graphs when too much values.
 329   * See https://developers.google.com/chart/image/docs/gallery/line_charts?hl=en#data-granularity
 330   *
 331   * @param array $array
 332   * @param int $grain
 333   * @param bool $preserve_max
 334   * @return array
 335   */
 336  function yourls_array_granularity($array, $grain = 100, $preserve_max = true) {
 337      if ( count( $array ) > $grain ) {
 338          $max = max( $array );
 339          $step = intval( count( $array ) / $grain );
 340          $i = 0;
 341          // Loop through each item and unset except every $step (optional preserve the max value)
 342          foreach( $array as $k=>$v ) {
 343              $i++;
 344              if ( $i % $step != 0 ) {
 345                  if ( $preserve_max == false ) {
 346                      unset( $array[$k] );
 347                  } else {
 348                      if ( $v < $max )
 349                          unset( $array[$k] );
 350                  }
 351              }
 352          }
 353      }
 354      return $array;
 355  }
 356  
 357  /**
 358   * Transform data array to data table for Google API
 359   *
 360   * @param array $data
 361   * @return string
 362   */
 363  function yourls_google_array_to_data_table(array $data): string {
 364      $str  = "var data = google.visualization.arrayToDataTable([\n";
 365      foreach( $data as $label => $values ){
 366          if( !is_array( $values ) ) {
 367              $values = array( $values );
 368          }
 369          $str .= "\t['" . yourls_esc_js($label) . "',";
 370          foreach( $values as $value ){
 371              $value = yourls_esc_url( $value );
 372              if( !is_numeric( $value ) && !str_starts_with($value, '[') && !str_starts_with($value, '{')) {
 373                  $value = "'" . yourls_esc_js($value) . "'";
 374              }
 375              $str .= "$value";
 376          }
 377          $str .= "],\n";
 378      }
 379      $str = substr( $str, 0, -2 ) . "\n"; // remove the trailing comma/return, reappend the return
 380      $str .= "]);\n"; // wrap it up
 381      return $str;
 382  }
 383  
 384  /**
 385   * Return javascript code that will display the Google Chart
 386   *
 387   * @param string $graph_type
 388   * @param string $data
 389   * @param array  $options
 390   * @param string $id
 391   * @return string
 392   */
 393  function yourls_google_viz_code($graph_type, $data, $options, $id ) {
 394      $function_name = 'yourls_graph' . $id;
 395      $code  = "\n<script id=\"$function_name\" type=\"text/javascript\">\n";
 396      $code .= "function $function_name() { \n";
 397  
 398      $code .= "$data\n";
 399  
 400      $code .= "var options = {\n";
 401      foreach( $options as $field => $value ) {
 402          if( !is_numeric( $value ) && strpos( $value, '[' ) !== 0 && strpos( $value, '{' ) !== 0 ) {
 403              $value = "\"$value\"";
 404          }
 405          $code .= "\t'$field': $value,\n";
 406      }
 407      $code  = substr( $code, 0, -2 ) . "\n"; // remove the trailing comma/return, reappend the return
 408      $code .= "\t}\n";
 409  
 410      $code .= "new google.visualization.$graph_type( document.getElementById('visualization_$id') ).draw( data, options );";
 411      $code .= "}\n";
 412      $code .= "google.setOnLoadCallback( $function_name );\n";
 413      $code .= "</script>\n";
 414      $code .= "<div id=\"visualization_$id\"></div>\n";
 415  
 416      return $code;
 417  }


Generated: Sat Jun 13 05:10:47 2026 Cross-referenced by PHPXref 0.7.1