[ Index ]

PHP Cross Reference of BuddyPress

title

Body

[close]

/src/bp-core/classes/ -> class-bp-attachment-avatar.php (source)

   1  <?php
   2  /**
   3   * Core Avatars attachment class.
   4   *
   5   * @package BuddyPress
   6   * @subpackage Core
   7   * @since 2.3.0
   8   */
   9  
  10  // Exit if accessed directly.
  11  defined( 'ABSPATH' ) || exit;
  12  
  13  /**
  14   * BP Attachment Avatar class.
  15   *
  16   * Extends BP Attachment to manage the avatar uploads.
  17   *
  18   * @since 2.3.0
  19   */
  20  class BP_Attachment_Avatar extends BP_Attachment {
  21  
  22      /**
  23       * Construct Upload parameters.
  24       *
  25       * @since 2.3.0
  26       *
  27       * @see  BP_Attachment::__construct() for list of parameters
  28       */
  29  	public function __construct() {
  30          // Allowed avatar types.
  31          $allowed_types = bp_core_get_allowed_avatar_types();
  32  
  33          parent::__construct( array(
  34              'action'                => 'bp_avatar_upload',
  35              'file_input'            => 'file',
  36              'original_max_filesize' => bp_core_avatar_original_max_filesize(),
  37  
  38              // Specific errors for avatars.
  39              'upload_error_strings'  => array(
  40                  /* translators: %s: Max file size for the profile photo */
  41                  9  => sprintf( _x( 'That photo is too big. Please upload one smaller than %s', 'profile photo upload error', 'buddypress' ), size_format( bp_core_avatar_original_max_filesize() ) ),
  42  
  43                  /* translators: %s: comma separated list of file types allowed for the profile photo */
  44                  10 => sprintf( _nx( 'Please upload only this file type: %s.', 'Please upload only these file types: %s.', count( $allowed_types ), 'profile photo upload error', 'buddypress' ), self::get_avatar_types( $allowed_types ) ),
  45              ),
  46          ) );
  47      }
  48  
  49      /**
  50       * Gets the available avatar types.
  51       *
  52       * @since 2.3.0
  53       *
  54       * @param array $allowed_types Array of allowed avatar types.
  55       * @return string comma separated list of allowed avatar types.
  56       */
  57  	public static function get_avatar_types( $allowed_types = array() ) {
  58          $types = array_map( 'strtoupper', $allowed_types );
  59          $comma = _x( ',', 'avatar types separator', 'buddypress' );
  60          return join( $comma . ' ', $types );
  61      }
  62  
  63      /**
  64       * Set Upload Dir data for avatars.
  65       *
  66       * @since 2.3.0
  67       */
  68  	public function set_upload_dir() {
  69          if ( bp_core_avatar_upload_path() && bp_core_avatar_url() ) {
  70              $this->upload_path = bp_core_avatar_upload_path();
  71              $this->url         = bp_core_avatar_url();
  72              $this->upload_dir  = bp_upload_dir();
  73          } else {
  74              parent::set_upload_dir();
  75          }
  76      }
  77  
  78      /**
  79       * Avatar specific rules.
  80       *
  81       * Adds an error if the avatar size or type don't match BuddyPress needs.
  82       * The error code is the index of $upload_error_strings.
  83       *
  84       * @since 2.3.0
  85       *
  86       * @param array $file the temporary file attributes (before it has been moved).
  87       * @return array the file with extra errors if needed.
  88       */
  89  	public function validate_upload( $file = array() ) {
  90          // Bail if already an error.
  91          if ( ! empty( $file['error'] ) ) {
  92              return $file;
  93          }
  94  
  95          // File size is too big.
  96          if ( ! bp_core_check_avatar_size( array( 'file' => $file ) ) ) {
  97              $file['error'] = 9;
  98  
  99          // File is of invalid type.
 100          } elseif ( ! bp_core_check_avatar_type( array( 'file' => $file ) ) ) {
 101              $file['error'] = 10;
 102          }
 103  
 104          // Return with error code attached.
 105          return $file;
 106      }
 107  
 108      /**
 109       * Maybe shrink the attachment to fit maximum allowed width.
 110       *
 111       * @since 2.3.0
 112       * @since 2.4.0 Add the $ui_available_width parameter, to inform about the Avatar UI width.
 113       *
 114       * @param string $file               The absolute path to the file.
 115       * @param int    $ui_available_width Available width for the UI.
 116       * @return false|string|WP_Image_Editor|WP_Error
 117       */
 118  	public static function shrink( $file = '', $ui_available_width = 0 ) {
 119          // Get image size.
 120          $avatar_data = parent::get_image_data( $file );
 121  
 122          // Init the edit args.
 123          $edit_args = array();
 124  
 125          // Defaults to the Avatar original max width constant.
 126          $original_max_width = bp_core_avatar_original_max_width();
 127  
 128          // The ui_available_width is defined and it's smaller than the Avatar original max width.
 129          if ( ! empty( $ui_available_width ) && $ui_available_width < $original_max_width ) {
 130              /**
 131               * In this case, to make sure the content of the image will be fully displayed
 132               * during the cropping step, let's use the Avatar UI Available width.
 133               */
 134              $original_max_width = $ui_available_width;
 135  
 136              // $original_max_width has to be larger than the avatar's full width.
 137              if ( $original_max_width < bp_core_avatar_full_width() ) {
 138                  $original_max_width = bp_core_avatar_full_width();
 139              }
 140          }
 141  
 142          // Do we need to resize the image?
 143          if ( isset( $avatar_data['width'] ) && $avatar_data['width'] > $original_max_width ) {
 144              $edit_args = array(
 145                  'max_w' => $original_max_width,
 146                  'max_h' => $original_max_width,
 147              );
 148          }
 149  
 150          // Do we need to rotate the image?
 151          $angles = array(
 152              3 => 180,
 153              6 => -90,
 154              8 =>  90,
 155          );
 156  
 157          if ( isset( $avatar_data['meta']['orientation'] ) && isset( $angles[ $avatar_data['meta']['orientation'] ] ) ) {
 158              $edit_args['rotate'] = $angles[ $avatar_data['meta']['orientation'] ];
 159          }
 160  
 161          // No need to edit the avatar, original file will be used.
 162          if ( empty( $edit_args ) ) {
 163              return false;
 164  
 165          // Add the file to the edit arguments.
 166          } else {
 167              $edit_args['file'] = $file;
 168          }
 169  
 170          return parent::edit_image( 'avatar', $edit_args );
 171      }
 172  
 173      /**
 174       * Check if the image dimensions are smaller than full avatar dimensions.
 175       *
 176       * @since 2.3.0
 177       *
 178       *
 179       * @param string $file the absolute path to the file.
 180       * @return bool
 181       */
 182  	public static function is_too_small( $file = '' ) {
 183          $uploaded_image = @getimagesize( $file );
 184          $full_width     = bp_core_avatar_full_width();
 185          $full_height    = bp_core_avatar_full_height();
 186  
 187          if ( isset( $uploaded_image[0] ) && $uploaded_image[0] < $full_width || $uploaded_image[1] < $full_height ) {
 188              return true;
 189          }
 190  
 191          return false;
 192      }
 193  
 194      /**
 195       * Crop the avatar.
 196       *
 197       * @since 2.3.0
 198       *
 199       * @see  BP_Attachment::crop for the list of parameters
 200       *
 201       * @param array $args Array of arguments for the cropping.
 202       * @return array The cropped avatars (full, thumb and the timestamp).
 203       */
 204  	public function crop( $args = array() ) {
 205          // Bail if the original file is missing.
 206          if ( empty( $args['original_file'] ) ) {
 207              return false;
 208          }
 209  
 210          if ( ! bp_attachments_current_user_can( 'edit_avatar', $args ) ) {
 211              return false;
 212          }
 213  
 214          if ( 'user' === $args['object'] ) {
 215              $avatar_dir = 'avatars';
 216          } else {
 217              $avatar_dir = sanitize_key( $args['object'] ) . '-avatars';
 218          }
 219  
 220          $args['item_id'] = (int) $args['item_id'];
 221  
 222          /**
 223           * Original file is a relative path to the image
 224           * eg: /avatars/1/avatar.jpg
 225           */
 226          $relative_path = sprintf( '/%s/%s/%s', $avatar_dir, $args['item_id'], basename( $args['original_file'] ) );
 227          $absolute_path = $this->upload_path . $relative_path;
 228  
 229          // Bail if the avatar is not available.
 230          if ( ! file_exists( $absolute_path ) )  {
 231              return false;
 232          }
 233  
 234          if ( empty( $args['item_id'] ) ) {
 235  
 236              /** This filter is documented in bp-core/bp-core-avatars.php */
 237              $avatar_folder_dir = apply_filters( 'bp_core_avatar_folder_dir', dirname( $absolute_path ), $args['item_id'], $args['object'], $args['avatar_dir'] );
 238          } else {
 239  
 240              /** This filter is documented in bp-core/bp-core-avatars.php */
 241              $avatar_folder_dir = apply_filters( 'bp_core_avatar_folder_dir', $this->upload_path . '/' . $args['avatar_dir'] . '/' . $args['item_id'], $args['item_id'], $args['object'], $args['avatar_dir'] );
 242          }
 243  
 244          // Bail if the avatar folder is missing for this item_id.
 245          if ( ! file_exists( $avatar_folder_dir ) ) {
 246              return false;
 247          }
 248  
 249          // Get the existing avatar files for the object.
 250          $existing_avatar = bp_core_fetch_avatar(
 251              array(
 252                  'object'  => $args['object'],
 253                  'item_id' => $args['item_id'],
 254                  'html'    => false,
 255              )
 256          );
 257  
 258          /**
 259           * Check that the new avatar doesn't have the same name as the
 260           * old one before moving the previous one into history.
 261           */
 262          if ( ! empty( $existing_avatar ) && $existing_avatar !== $this->url . $relative_path ) {
 263              // Avatar history is disabled, simply delete the existing avatar files.
 264              if ( bp_avatar_history_is_disabled() ) {
 265                  bp_core_delete_existing_avatar(
 266                      array(
 267                          'object'      => $args['object'],
 268                          'item_id'     => $args['item_id'],
 269                          'avatar_path' => $avatar_folder_dir,
 270                      )
 271                  );
 272              } else {
 273                  // Add a new revision for the existing avatar.
 274                  $avatars = bp_attachments_list_directory_files( $avatar_folder_dir );
 275  
 276                  if ( $avatars ) {
 277                      foreach ( $avatars as $avatar_file ) {
 278                          if ( ! isset( $avatar_file->name, $avatar_file->id, $avatar_file->path ) ) {
 279                              continue;
 280                          }
 281  
 282                          $is_full  = preg_match( "/-bpfull/", $avatar_file->name );
 283                          $is_thumb = preg_match( "/-bpthumb/", $avatar_file->name );
 284  
 285                          if ( $is_full || $is_thumb ) {
 286                              $revision = $this->add_revision(
 287                                  'avatar',
 288                                  array(
 289                                      'file_abspath' => $avatar_file->path,
 290                                      'file_id'      => $avatar_file->id,
 291                                  )
 292                              );
 293  
 294                              if ( is_wp_error( $revision ) ) {
 295                                  error_log( $revision->get_error_message() );
 296                              }
 297                          }
 298                      }
 299                  }
 300              }
 301          }
 302  
 303          // Make sure we at least have minimal data for cropping.
 304          if ( empty( $args['crop_w'] ) ) {
 305              $args['crop_w'] = bp_core_avatar_full_width();
 306          }
 307  
 308          if ( empty( $args['crop_h'] ) ) {
 309              $args['crop_h'] = bp_core_avatar_full_height();
 310          }
 311  
 312          // Get the file extension.
 313          $data = @getimagesize( $absolute_path );
 314          $ext  = $data['mime'] === 'image/png' ? 'png' : 'jpg';
 315  
 316          $args['original_file'] = $absolute_path;
 317          $args['src_abs']       = false;
 318  
 319          $avatar_types = array(
 320              'full'  => '',
 321              'thumb' => '',
 322          );
 323          $timestamp   = bp_core_current_time( true, 'timestamp' );
 324  
 325          foreach ( $avatar_types as $key_type => $type ) {
 326              if ( 'thumb' === $key_type ) {
 327                  $args['dst_w'] = bp_core_avatar_thumb_width();
 328                  $args['dst_h'] = bp_core_avatar_thumb_height();
 329              } else {
 330                  $args['dst_w'] = bp_core_avatar_full_width();
 331                  $args['dst_h'] = bp_core_avatar_full_height();
 332              }
 333  
 334              $filename         = wp_unique_filename( $avatar_folder_dir, $timestamp . "-bp{$key_type}.{$ext}" );
 335              $args['dst_file'] = $avatar_folder_dir . '/' . $filename;
 336  
 337              $avatar_types[ $key_type ] = parent::crop( $args );
 338          }
 339  
 340          // Remove the original.
 341          @unlink( $absolute_path );
 342  
 343          // Return the full, thumb cropped avatars and the timestamp.
 344          return array_merge(
 345              $avatar_types,
 346              array(
 347                  'timestamp' => $timestamp,
 348              )
 349          );
 350      }
 351  
 352      /**
 353       * Get the user id to set its avatar.
 354       *
 355       * @since 2.3.0
 356       *
 357       * @return integer The user ID.
 358       */
 359  	private function get_user_id() {
 360          $bp = buddypress();
 361          $user_id = 0;
 362  
 363          if ( bp_is_user() ) {
 364              $user_id = bp_displayed_user_id();
 365          }
 366  
 367          if ( ! empty( $bp->members->admin->user_id ) ) {
 368              $user_id = $bp->members->admin->user_id;
 369          }
 370  
 371          return $user_id;
 372      }
 373  
 374      /**
 375       * Get the group id to set its avatar.
 376       *
 377       * @since 2.3.0
 378       *
 379       * @return integer The group ID.
 380       */
 381  	private function get_group_id() {
 382          $group_id = 0;
 383  
 384          if ( bp_is_group() ) {
 385              $group_id = bp_get_current_group_id();
 386          }
 387  
 388          return $group_id;
 389      }
 390  
 391      /**
 392       * Build script data for the Uploader UI.
 393       *
 394       * @since 2.3.0
 395       *
 396       * @return array The javascript localization data.
 397       */
 398  	public function script_data() {
 399          // Get default script data.
 400          $script_data = parent::script_data();
 401  
 402          // Defaults to Avatar Backbone script.
 403          $js_scripts = array( 'bp-avatar' );
 404  
 405          // Default object.
 406          $object = '';
 407  
 408          // Get the possible item ids.
 409          $user_id  = $this->get_user_id();
 410          $group_id = $this->get_group_id();
 411  
 412          if ( ! empty( $user_id ) ) {
 413              // Should we load the the Webcam Avatar javascript file.
 414              if ( bp_avatar_use_webcam() ) {
 415                  $js_scripts = array( 'bp-webcam' );
 416              }
 417  
 418              $script_data['bp_params'] = array(
 419                  'object'     => 'user',
 420                  'item_id'    => $user_id,
 421                  'has_avatar' => bp_get_user_has_avatar( $user_id ),
 422                  'nonces'  => array(
 423                      'set'    => wp_create_nonce( 'bp_avatar_cropstore' ),
 424                      'remove' => wp_create_nonce( 'bp_delete_avatar_link' ),
 425                  ),
 426              );
 427  
 428              // Set feedback messages.
 429              $script_data['feedback_messages'] = array(
 430                  1 => __( 'There was a problem cropping your profile photo.', 'buddypress' ),
 431                  2 => __( 'Your new profile photo was uploaded successfully.', 'buddypress' ),
 432                  3 => __( 'There was a problem deleting your profile photo. Please try again.', 'buddypress' ),
 433                  4 => __( 'Your profile photo was deleted successfully!', 'buddypress' ),
 434                  5 => __( 'Your profile photo was recycled successfully!', 'buddypress' ),
 435                  6 => __( 'The profile photo was permanently deleted successfully!', 'buddypress' ),
 436              );
 437          } elseif ( ! empty( $group_id ) ) {
 438              $script_data['bp_params'] = array(
 439                  'object'     => 'group',
 440                  'item_id'    => $group_id,
 441                  'has_avatar' => bp_get_group_has_avatar( $group_id ),
 442                  'nonces'     => array(
 443                      'set'    => wp_create_nonce( 'bp_avatar_cropstore' ),
 444                      'remove' => wp_create_nonce( 'bp_group_avatar_delete' ),
 445                  ),
 446              );
 447  
 448              // Set feedback messages.
 449              $script_data['feedback_messages'] = array(
 450                  1 => __( 'There was a problem cropping the group profile photo.', 'buddypress' ),
 451                  2 => __( 'The group profile photo was uploaded successfully.', 'buddypress' ),
 452                  3 => __( 'There was a problem deleting the group profile photo. Please try again.', 'buddypress' ),
 453                  4 => __( 'The group profile photo was deleted successfully!', 'buddypress' ),
 454                  5 => __( 'The group profile photo was recycled successfully!', 'buddypress' ),
 455                  6 => __( 'The group profile photo was permanently deleted successfully!', 'buddypress' ),
 456              );
 457          } else {
 458  
 459              /**
 460               * Use this filter to include specific BuddyPress params for your object.
 461               * e.g. Blavatar.
 462               *
 463               * @since 2.3.0
 464               *
 465               * @param array $value The avatar specific BuddyPress parameters.
 466               */
 467              $script_data['bp_params'] = apply_filters( 'bp_attachment_avatar_params', array() );
 468          }
 469  
 470          // Include the specific css.
 471          $script_data['extra_css'] = array( 'bp-avatar' );
 472  
 473          // Include the specific css.
 474          $script_data['extra_js']  = $js_scripts;
 475  
 476          // Set the object to contextualize the filter.
 477          if ( isset( $script_data['bp_params']['object'] ) ) {
 478              $object = $script_data['bp_params']['object'];
 479          }
 480  
 481          /**
 482           * Use this filter to override/extend the avatar script data.
 483           *
 484           * @since 2.3.0
 485           *
 486           * @param array  $script_data The avatar script data.
 487           * @param string $object      The object the avatar belongs to (eg: user or group).
 488           */
 489          return apply_filters( 'bp_attachment_avatar_script_data', $script_data, $object );
 490      }
 491  }


Generated: Sat Apr 27 01:00:55 2024 Cross-referenced by PHPXref 0.7.1