Skip to:
Content

BuddyPress.org

Ticket #5089: bp-core-avatars.php

File bp-core-avatars.php, 31.2 KB (added by modemlooper, 13 years ago)
Line 
1<?php
2
3/**
4 * BuddyPress Avatars
5 */
6
7// Exit if accessed directly
8if ( !defined( 'ABSPATH' ) ) exit;
9
10/***
11 * Set up the constants we need for avatar support
12 */
13function bp_core_set_avatar_constants() {
14
15        if ( !defined( 'BP_AVATAR_THUMB_WIDTH' ) )
16                define( 'BP_AVATAR_THUMB_WIDTH', 50 );
17
18        if ( !defined( 'BP_AVATAR_THUMB_HEIGHT' ) )
19                define( 'BP_AVATAR_THUMB_HEIGHT', 50 );
20
21        if ( !defined( 'BP_AVATAR_FULL_WIDTH' ) )
22                define( 'BP_AVATAR_FULL_WIDTH', 150 );
23
24        if ( !defined( 'BP_AVATAR_FULL_HEIGHT' ) )
25                define( 'BP_AVATAR_FULL_HEIGHT', 150 );
26
27        if ( !defined( 'BP_AVATAR_ORIGINAL_MAX_WIDTH' ) )
28                define( 'BP_AVATAR_ORIGINAL_MAX_WIDTH', 450 );
29
30        if ( !defined( 'BP_AVATAR_ORIGINAL_MAX_FILESIZE' ) ) {
31
32                $bp = buddypress();
33
34                if ( !isset( $bp->site_options['fileupload_maxk'] ) ) {
35                        define( 'BP_AVATAR_ORIGINAL_MAX_FILESIZE', 5120000 ); // 5mb
36                } else {
37                        define( 'BP_AVATAR_ORIGINAL_MAX_FILESIZE', $bp->site_options['fileupload_maxk'] * 1024 );
38                }
39        }
40
41        if ( !defined( 'BP_AVATAR_DEFAULT' ) )
42                define( 'BP_AVATAR_DEFAULT', BP_PLUGIN_URL . 'bp-core/images/mystery-man.jpg' );
43
44        if ( !defined( 'BP_AVATAR_DEFAULT_THUMB' ) )
45                define( 'BP_AVATAR_DEFAULT_THUMB', BP_PLUGIN_URL . 'bp-core/images/mystery-man-50.jpg' );
46
47        if ( ! defined( 'BP_SHOW_AVATARS' ) ) {
48                define( 'BP_SHOW_AVATARS', bp_get_option( 'show_avatars' ) );
49        }
50}
51add_action( 'bp_init', 'bp_core_set_avatar_constants', 3 );
52
53function bp_core_set_avatar_globals() {
54        $bp = buddypress();
55
56        $bp->avatar        = new stdClass;
57        $bp->avatar->thumb = new stdClass;
58        $bp->avatar->full  = new stdClass;
59
60        // Dimensions
61        $bp->avatar->thumb->width  = BP_AVATAR_THUMB_WIDTH;
62        $bp->avatar->thumb->height = BP_AVATAR_THUMB_HEIGHT;
63        $bp->avatar->full->width   = BP_AVATAR_FULL_WIDTH;
64        $bp->avatar->full->height  = BP_AVATAR_FULL_HEIGHT;
65
66        // Upload maximums
67        $bp->avatar->original_max_width    = BP_AVATAR_ORIGINAL_MAX_WIDTH;
68        $bp->avatar->original_max_filesize = BP_AVATAR_ORIGINAL_MAX_FILESIZE;
69
70        // Defaults
71        $bp->avatar->thumb->default = BP_AVATAR_DEFAULT_THUMB;
72        $bp->avatar->full->default  = BP_AVATAR_DEFAULT;
73
74        // These have to be set on page load in order to avoid infinite filter loops at runtime
75        $bp->avatar->upload_path = bp_core_avatar_upload_path();
76        $bp->avatar->url = bp_core_avatar_url();
77
78        // Cache the root blog's show_avatars setting, to avoid unnecessary
79        // calls to switch_to_blog()
80        $bp->avatar->show_avatars = (bool) BP_SHOW_AVATARS;
81
82        // Backpat for pre-1.5
83        if ( ! defined( 'BP_AVATAR_UPLOAD_PATH' ) )
84                define( 'BP_AVATAR_UPLOAD_PATH', $bp->avatar->upload_path );
85
86        // Backpat for pre-1.5
87        if ( ! defined( 'BP_AVATAR_URL' ) )
88                define( 'BP_AVATAR_URL', $bp->avatar->url );
89
90        do_action( 'bp_core_set_avatar_globals' );
91}
92add_action( 'bp_setup_globals', 'bp_core_set_avatar_globals' );
93
94/**
95 * bp_core_fetch_avatar()
96 *
97 * Fetches an avatar from a BuddyPress object. Supports user/group/blog as
98 * default, but can be extended to include your own custom components too.
99 *
100 * @global $current_blog WordPress global containing information and settings for the current blog being viewed.
101 * @param array $args Determine the output of this function
102 * @return string Formatted HTML <img> element, or raw avatar URL based on $html arg
103 */
104function bp_core_fetch_avatar( $args = '' ) {
105
106        // If avatars are disabled for the root site, obey that request and bail
107        if ( ! buddypress()->avatar->show_avatars )
108                return;
109
110        global $current_blog;
111
112        $bp = buddypress();
113
114        // Set a few default variables
115        $def_object = 'user';
116        $def_type   = 'thumb';
117        $def_class  = 'avatar';
118
119        // Set the default variables array
120        $params = wp_parse_args( $args, array(
121                'item_id'    => false,
122                'object'     => $def_object, // user/group/blog/custom type (if you use filters)
123                'type'       => $def_type,   // thumb or full
124                'avatar_dir' => false,       // Specify a custom avatar directory for your object
125                'width'      => false,       // Custom width (int)
126                'height'     => false,       // Custom height (int)
127                'class'      => $def_class,  // Custom <img> class (string)
128                'css_id'     => false,       // Custom <img> ID (string)
129                'alt'        => '',          // Custom <img> alt (string)
130                'email'      => false,       // Pass the user email (for gravatar) to prevent querying the DB for it
131                'no_grav'    => false,       // If there is no avatar found, return false instead of a grav?
132                'html'       => true,        // Wrap the return img URL in <img />
133                'title'      => ''           // Custom <img> title (string)
134        ) );
135        extract( $params, EXTR_SKIP );
136
137        /** Set item_id ***********************************************************/
138
139        if ( empty( $item_id ) ) {
140
141                switch ( $object ) {
142
143                        case 'blog'  :
144                                $item_id = $current_blog->id;
145                                break;
146
147                        case 'group' :
148                                if ( bp_is_active( 'groups' ) ) {
149                                        $item_id = $bp->groups->current_group->id;
150                                } else {
151                                        $item_id = false;
152                                }
153
154                                break;
155
156                        case 'user'  :
157                        default      :
158                                $item_id = bp_displayed_user_id();
159                                break;
160                }
161
162                $item_id = apply_filters( 'bp_core_avatar_item_id', $item_id, $object, $params );
163
164                if ( empty( $item_id ) ) {
165                        return false;
166                }
167        }
168
169        $class = apply_filters( 'bp_core_avatar_class', $class, $item_id, $object, $params );
170
171        /** Set avatar_dir ********************************************************/
172
173        if ( empty( $avatar_dir ) ) {
174
175                switch ( $object ) {
176
177                        case 'blog'  :
178                                $avatar_dir = 'blog-avatars';
179                                break;
180
181                        case 'group' :
182                                if ( bp_is_active( 'groups' ) ) {
183                                        $avatar_dir = 'group-avatars';
184                                } else {
185                                        $avatar_dir = false;
186                                }
187
188                                break;
189
190                        case 'user'  :
191                        default      :
192                                $avatar_dir = 'avatars';
193                                break;
194                }
195
196                $avatar_dir = apply_filters( 'bp_core_avatar_dir', $avatar_dir, $object, $params );
197
198                if ( empty( $avatar_dir ) ) {
199                        return false;
200                }
201        }
202
203        /** <img> alt *************************************************************/
204
205        if ( false !== strpos( $alt, '%s' ) || false !== strpos( $alt, '%1$s' ) ) {
206
207                switch ( $object ) {
208
209                        case 'blog'  :
210                                $item_name = get_blog_option( $item_id, 'blogname' );
211                                break;
212
213                        case 'group' :
214                                $item_name = bp_get_group_name( groups_get_group( array( 'group_id' => $item_id ) ) );
215                                break;
216
217                        case 'user'  :
218                        default :
219                                $item_name = bp_core_get_user_displayname( $item_id );
220                                break;
221                }
222
223                $item_name = apply_filters( 'bp_core_avatar_alt', $item_name, $item_id, $object, $params );
224                $alt       = sprintf( $alt, $item_name );
225        }
226
227        /** Sanity Checks *********************************************************/
228
229        // Get a fallback for the 'alt' parameter
230        if ( empty( $alt ) )
231                $alt = __( 'Avatar Image', 'buddypress' );
232
233        $html_alt = ' alt="' . esc_attr( $alt ) . '"';
234
235        // Set title tag, if it's been provided
236        if ( !empty( $title ) ) {
237                $title = " title='" . esc_attr( apply_filters( 'bp_core_avatar_title', $title, $item_id, $object, $params ) ) . "'";
238        }
239
240        // Set CSS ID if passed
241        if ( !empty( $css_id ) ) {
242                $css_id = ' id="' . esc_attr( $css_id ) . '"';
243        }
244
245        // Set image width
246        if ( false !== $width ) {
247                $html_width = ' width="' . $width . '"';
248        } elseif ( 'thumb' == $type ) {
249                $html_width = ' width="' . bp_core_avatar_thumb_width() . '"';
250        } else {
251                $html_width = ' width="' . bp_core_avatar_full_width() . '"';
252        }
253
254        // Set image height
255        if ( false !== $height ) {
256                $html_height = ' height="' . $height . '"';
257        } elseif ( 'thumb' == $type ) {
258                $html_height = ' height="' . bp_core_avatar_thumb_height() . '"';
259        } else {
260                $html_height = ' height="' . bp_core_avatar_full_height() . '"';
261        }
262
263        // Set img URL and DIR based on prepopulated constants
264        $avatar_loc        = new stdClass();
265        $avatar_loc->path  = trailingslashit( bp_core_avatar_upload_path() );
266        $avatar_loc->url   = trailingslashit( bp_core_avatar_url() );
267
268        $avatar_loc->dir   = trailingslashit( $avatar_dir );
269        $avatar_folder_url = apply_filters( 'bp_core_avatar_folder_url', ( $avatar_loc->url  . $avatar_loc->dir . $item_id ), $item_id, $object, $avatar_dir );
270        $avatar_folder_dir = apply_filters( 'bp_core_avatar_folder_dir', ( $avatar_loc->path . $avatar_loc->dir . $item_id ), $item_id, $object, $avatar_dir );
271
272        // Add an identifying class
273        $class .= ' ' . $object . '-' . $item_id . '-avatar ' . sanitize_html_class( "avatar-$width" ) . ' photo';
274
275        /**
276         * Look for uploaded avatar first. Use it if it exists.
277         * Set the file names to search for, to select the full size
278         * or thumbnail image.
279         */
280        $avatar_size              = ( 'full' == $type ) ? '-bpfull' : '-bpthumb';
281        $legacy_user_avatar_name  = ( 'full' == $type ) ? '-avatar2' : '-avatar1';
282        $legacy_group_avatar_name = ( 'full' == $type ) ? '-groupavatar-full' : '-groupavatar-thumb';
283
284        // Check for directory
285        if ( file_exists( $avatar_folder_dir ) ) {
286
287                // Open directory
288                if ( $av_dir = opendir( $avatar_folder_dir ) ) {
289
290                        // Stash files in an array once to check for one that matches
291                        $avatar_files = array();
292                        while ( false !== ( $avatar_file = readdir( $av_dir ) ) ) {
293                                // Only add files to the array (skip directories)
294                                if ( 2 < strlen( $avatar_file ) ) {
295                                        $avatar_files[] = $avatar_file;
296                                }
297                        }
298
299                        // Check for array
300                        if ( 0 < count( $avatar_files ) ) {
301
302                                // Check for current avatar
303                                foreach( $avatar_files as $key => $value ) {
304                                        if ( strpos ( $value, $avatar_size )!== false ) {
305                                                $avatar_url = $avatar_folder_url . '/' . $avatar_files[$key];
306                                        }
307                                }
308
309                                // Legacy avatar check
310                                if ( !isset( $avatar_url ) ) {
311                                        foreach( $avatar_files as $key => $value ) {
312                                                if ( strpos ( $value, $legacy_user_avatar_name )!== false ) {
313                                                        $avatar_url = $avatar_folder_url . '/' . $avatar_files[$key];
314                                                }
315                                        }
316
317                                        // Legacy group avatar check
318                                        if ( !isset( $avatar_url ) ) {
319                                                foreach( $avatar_files as $key => $value ) {
320                                                        if ( strpos ( $value, $legacy_group_avatar_name )!== false ) {
321                                                                $avatar_url = $avatar_folder_url . '/' . $avatar_files[$key];
322                                                        }
323                                                }
324                                        }
325                                }
326                        }
327                }
328
329                // Close the avatar directory
330                closedir( $av_dir );
331
332                // If we found a locally uploaded avatar
333                if ( isset( $avatar_url ) ) {
334
335                        // Return it wrapped in an <img> element
336                        if ( true === $html ) {
337                                return apply_filters( 'bp_core_fetch_avatar', '<img src="' . $avatar_url . '" class="' . esc_attr( $class ) . '"' . $css_id . $html_width . $html_height . $html_alt . $title . ' />', $params, $item_id, $avatar_dir, $css_id, $html_width, $html_height, $avatar_folder_url, $avatar_folder_dir );
338
339                        // ...or only the URL
340                        } else {
341                                return apply_filters( 'bp_core_fetch_avatar_url', $avatar_url, $params );
342                        }
343                }
344        }
345
346        // If no avatars could be found, try to display a gravatar
347
348        // Skips gravatar check if $no_grav is passed
349        if ( ! apply_filters( 'bp_core_fetch_avatar_no_grav', $no_grav ) ) {
350
351                // Set gravatar size
352                if ( false !== $width ) {
353                        $grav_size = $width;
354                } else if ( 'full' == $type ) {
355                        $grav_size = bp_core_avatar_full_width();
356                } else if ( 'thumb' == $type ) {
357                        $grav_size = bp_core_avatar_thumb_width();
358                }
359
360                // Set gravatar type
361                if ( empty( $bp->grav_default->{$object} ) ) {
362                        $default_grav = 'wavatar';
363                } else if ( 'mystery' == $bp->grav_default->{$object} ) {
364                        $default_grav = apply_filters( 'bp_core_mysteryman_src', bp_core_avatar_default(), $grav_size );
365                } else {
366                        $default_grav = $bp->grav_default->{$object};
367                }
368
369                // Set gravatar object
370                if ( empty( $email ) ) {
371                        if ( 'user' == $object ) {
372                                $email = bp_core_get_user_email( $item_id );
373                        } else if ( 'group' == $object || 'blog' == $object ) {
374                                $email = "{$item_id}-{$object}@{bp_get_root_domain()}";
375                        }
376                }
377
378                // Set host based on if using ssl
379                $host = 'http://gravatar.com/avatar/';
380                if ( is_ssl() ) {
381                        $host = 'https://secure.gravatar.com/avatar/';
382                }
383
384                // Filter gravatar vars
385                $email    = apply_filters( 'bp_core_gravatar_email', $email, $item_id, $object );
386                $gravatar = apply_filters( 'bp_gravatar_url', $host ) . md5( strtolower( $email ) ) . '?d=' . $default_grav . '&amp;s=' . $grav_size;
387
388                // Gravatar rating; http://bit.ly/89QxZA
389                $rating = get_option( 'avatar_rating' );
390                if ( ! empty( $rating ) ) {
391                        $gravatar .= "&amp;r={$rating}";
392                }
393
394        // No avatar was found, and we've been told not to use a gravatar.
395        } else {
396                $gravatar = apply_filters( "bp_core_default_avatar_$object", BP_PLUGIN_URL . 'bp-core/images/mystery-man.jpg', $params );
397        }
398
399        if ( true === $html ) {
400                return apply_filters( 'bp_core_fetch_avatar', '<img src="' . $gravatar . '" class="' . esc_attr( $class ) . '"' . $css_id . $html_width . $html_height . $html_alt . $title . ' />', $params, $item_id, $avatar_dir, $css_id, $html_width, $html_height, $avatar_folder_url, $avatar_folder_dir );
401        } else {
402                return apply_filters( 'bp_core_fetch_avatar_url', $gravatar, $params );
403        }
404}
405
406/**
407 * Delete an existing avatar
408 *
409 * Accepted values for $args are:
410 *  item_id - item id which relates to the object type.
411 *  object - the objetc type user, group, blog, etc.
412 *  avatar_dir - The directory where the avatars to be uploaded.
413 *
414 * @param mixed $args
415 * @return bool Success/failure
416 */
417function bp_core_delete_existing_avatar( $args = '' ) {
418
419        $defaults = array(
420                'item_id'    => false,
421                'object'     => 'user', // user OR group OR blog OR custom type (if you use filters)
422                'avatar_dir' => false
423        );
424
425        $args = wp_parse_args( $args, $defaults );
426        extract( $args, EXTR_SKIP );
427
428        if ( empty( $item_id ) ) {
429                if ( 'user' == $object )
430                        $item_id = bp_displayed_user_id();
431                else if ( 'group' == $object )
432                        $item_id = buddypress()->groups->current_group->id;
433                else if ( 'blog' == $object )
434                        $item_id = $current_blog->id;
435
436                $item_id = apply_filters( 'bp_core_avatar_item_id', $item_id, $object );
437
438                if ( !$item_id ) return false;
439        }
440
441        if ( empty( $avatar_dir ) ) {
442                if ( 'user' == $object )
443                        $avatar_dir = 'avatars';
444                else if ( 'group' == $object )
445                        $avatar_dir = 'group-avatars';
446                else if ( 'blog' == $object )
447                        $avatar_dir = 'blog-avatars';
448
449                $avatar_dir = apply_filters( 'bp_core_avatar_dir', $avatar_dir, $object );
450
451                if ( !$avatar_dir ) return false;
452        }
453
454        $avatar_folder_dir = apply_filters( 'bp_core_avatar_folder_dir', bp_core_avatar_upload_path() . '/' . $avatar_dir . '/' . $item_id, $item_id, $object, $avatar_dir );
455
456        if ( !file_exists( $avatar_folder_dir ) )
457                return false;
458
459        if ( $av_dir = opendir( $avatar_folder_dir ) ) {
460                while ( false !== ( $avatar_file = readdir($av_dir) ) ) {
461                        if ( ( preg_match( "/-bpfull/", $avatar_file ) || preg_match( "/-bpthumb/", $avatar_file ) ) && '.' != $avatar_file && '..' != $avatar_file )
462                                @unlink( $avatar_folder_dir . '/' . $avatar_file );
463                }
464        }
465        closedir($av_dir);
466
467        @rmdir( $avatar_folder_dir );
468
469        do_action( 'bp_core_delete_existing_avatar', $args );
470
471        return true;
472}
473
474/**
475 * Handles avatar uploading.
476 *
477 * The functions starts off by checking that the file has been uploaded properly using bp_core_check_avatar_upload().
478 * It then checks that the file size is within limits, and that it has an accepted file extension (jpg, gif, png).
479 * If everything checks out, crop the image and move it to its real location.
480 *
481 * @param array $file The appropriate entry the from $_FILES superglobal.
482 * @param string $upload_dir_filter A filter to be applied to upload_dir
483 * @return bool Success/failure
484 * @see bp_core_check_avatar_upload()
485 * @see bp_core_check_avatar_type()
486 */
487function bp_core_avatar_handle_upload( $file, $upload_dir_filter ) {
488
489        //read raw image data
490        $exif = @exif_read_data( $_FILES['file']['tmp_name'] );
491
492        /***
493         * You may want to hook into this filter if you want to override this function.
494         * Make sure you return false.
495         */
496        if ( !apply_filters( 'bp_core_pre_avatar_handle_upload', true, $file, $upload_dir_filter ) )
497                return true;
498
499        require_once( ABSPATH . '/wp-admin/includes/file.php' );
500
501        $uploadErrors = array(
502                0 => __( 'The image was uploaded successfully', 'buddypress' ),
503                1 => __( 'The image exceeds the maximum allowed file size of: ', 'buddypress' ) . size_format( bp_core_avatar_original_max_filesize() ),
504                2 => __( 'The image exceeds the maximum allowed file size of: ', 'buddypress' ) . size_format( bp_core_avatar_original_max_filesize() ),
505                3 => __( 'The uploaded file was only partially uploaded.', 'buddypress' ),
506                4 => __( 'The image was not uploaded.', 'buddypress' ),
507                6 => __( 'Missing a temporary folder.', 'buddypress' )
508        );
509
510        if ( ! bp_core_check_avatar_upload( $file ) ) {
511                bp_core_add_message( sprintf( __( 'Your upload failed, please try again. Error was: %s', 'buddypress' ), $uploadErrors[$file['file']['error']] ), 'error' );
512                return false;
513        }
514
515        if ( ! bp_core_check_avatar_size( $file ) ) {
516                bp_core_add_message( sprintf( __( 'The file you uploaded is too big. Please upload a file under %s', 'buddypress' ), size_format( bp_core_avatar_original_max_filesize() ) ), 'error' );
517                return false;
518        }
519
520        if ( ! bp_core_check_avatar_type( $file ) ) {
521                bp_core_add_message( __( 'Please upload only JPG, GIF or PNG photos.', 'buddypress' ), 'error' );
522                return false;
523        }
524
525        // Filter the upload location
526        add_filter( 'upload_dir', $upload_dir_filter, 10, 0 );
527
528        $bp = buddypress();
529
530        $bp->avatar_admin->original = wp_handle_upload( $file['file'], array( 'action'=> 'bp_avatar_upload' ) );
531
532        // Remove the upload_dir filter, so that other upload URLs on the page
533        // don't break
534        remove_filter( 'upload_dir', $upload_dir_filter, 10, 0 );
535
536        // Move the file to the correct upload location.
537        if ( !empty( $bp->avatar_admin->original['error'] ) ) {
538                bp_core_add_message( sprintf( __( 'Upload Failed! Error was: %s', 'buddypress' ), $bp->avatar_admin->original['error'] ), 'error' );
539                return false;
540        }
541
542        // Get image size
543        $size  = @getimagesize( $bp->avatar_admin->original['file'] );
544        $error = false;
545
546        // Check image size and shrink if too large
547        if ( $size[0] > bp_core_avatar_original_max_width() ) {
548                $editor = wp_get_image_editor( $bp->avatar_admin->original['file'] );
549
550                if ( ! is_wp_error( $editor ) ) {
551
552                        $editor->set_quality( 100 );
553
554                        if ( wp_is_mobile() ) {
555                                //rotate images to display correct orientation from iOS
556                                if( !empty( $exif['Orientation'] ) ) {
557                                    switch( $exif['Orientation'] ) {
558                                    case 8:
559                                        $editor->rotate( 90 );
560                                    break;
561                                    case 3:
562                                        $editor->rotate( 180 );
563                                    break;
564                                    case 6:
565                                       $editor->rotate( -90 );
566                                    break;
567                                    }
568                                }
569                        }
570
571                        $resized = $editor->resize( bp_core_avatar_original_max_width(), bp_core_avatar_original_max_width(), false );
572                        if ( ! is_wp_error( $resized ) ) {
573                                $thumb = $editor->save( $editor->generate_filename() );
574                        } else {
575                                $error = $resized;
576                        }
577
578                        // Check for thumbnail creation errors
579                        if ( false === $error && is_wp_error( $thumb ) ) {
580                                $error = $thumb;
581                        }
582
583                        // Thumbnail is good so proceed
584                        if ( false === $error ) {
585                                $bp->avatar_admin->resized = $thumb;
586                        }
587
588                } else {
589                        $error = $editor;
590                }
591
592                if ( false !== $error ) {
593                        bp_core_add_message( sprintf( __( 'Upload Failed! Error was: %s', 'buddypress' ), $error->get_error_message() ), 'error' );
594                        return false;
595                }
596        }
597
598        if ( ! isset( $bp->avatar_admin->image ) )
599                $bp->avatar_admin->image = new stdClass();
600
601        // We only want to handle one image after resize.
602        if ( empty( $bp->avatar_admin->resized ) ) {
603                $bp->avatar_admin->image->dir = str_replace( bp_core_avatar_upload_path(), '', $bp->avatar_admin->original['file'] );
604        } else {
605                $bp->avatar_admin->image->dir = str_replace( bp_core_avatar_upload_path(), '', $bp->avatar_admin->resized['path'] );
606                @unlink( $bp->avatar_admin->original['file'] );
607        }
608
609        // Check for WP_Error on what should be an image
610        if ( is_wp_error( $bp->avatar_admin->image->dir ) ) {
611                bp_core_add_message( sprintf( __( 'Upload failed! Error was: %s', 'buddypress' ), $bp->avatar_admin->image->dir->get_error_message() ), 'error' );
612                return false;
613        }
614
615        // Set the url value for the image
616        $bp->avatar_admin->image->url = bp_core_avatar_url() . $bp->avatar_admin->image->dir;
617
618        return true;
619}
620
621/**
622 * Crop an uploaded avatar
623 *
624 * $args has the following parameters:
625 *  object - What component the avatar is for, e.g. "user"
626 *  avatar_dir  The absolute path to the avatar
627 *  item_id - Item ID
628 *  original_file - The absolute path to the original avatar file
629 *  crop_w - Crop width
630 *  crop_h - Crop height
631 *  crop_x - The horizontal starting point of the crop
632 *  crop_y - The vertical starting point of the crop
633 *
634 * @param mixed $args
635 * @return bool Success/failure
636 */
637function bp_core_avatar_handle_crop( $args = '' ) {
638
639        $r = wp_parse_args( $args, array(
640                'object'        => 'user',
641                'avatar_dir'    => 'avatars',
642                'item_id'       => false,
643                'original_file' => false,
644                'crop_w'        => bp_core_avatar_full_width(),
645                'crop_h'        => bp_core_avatar_full_height(),
646                'crop_x'        => 0,
647                'crop_y'        => 0
648        ) );
649
650        /***
651         * You may want to hook into this filter if you want to override this function.
652         * Make sure you return false.
653         */
654        if ( !apply_filters( 'bp_core_pre_avatar_handle_crop', true, $r ) )
655                return true;
656
657        extract( $r, EXTR_SKIP );
658
659        if ( empty( $original_file ) )
660                return false;
661
662        $original_file = bp_core_avatar_upload_path() . $original_file;
663
664        if ( !file_exists( $original_file ) )
665                return false;
666
667        if ( empty( $item_id ) ) {
668                $avatar_folder_dir = apply_filters( 'bp_core_avatar_folder_dir', dirname( $original_file ), $item_id, $object, $avatar_dir );
669        } else {
670                $avatar_folder_dir = apply_filters( 'bp_core_avatar_folder_dir', bp_core_avatar_upload_path() . '/' . $avatar_dir . '/' . $item_id, $item_id, $object, $avatar_dir );
671        }
672
673        if ( !file_exists( $avatar_folder_dir ) )
674                return false;
675
676        require_once( ABSPATH . '/wp-admin/includes/image.php' );
677        require_once( ABSPATH . '/wp-admin/includes/file.php' );
678
679        // Delete the existing avatar files for the object
680        bp_core_delete_existing_avatar( array( 'object' => $object, 'avatar_path' => $avatar_folder_dir ) );
681
682        // Make sure we at least have a width and height for cropping
683        if ( empty( $crop_w ) ) {
684                $crop_w = bp_core_avatar_full_width();
685        }
686
687        if ( empty( $crop_h ) ) {
688                $crop_h = bp_core_avatar_full_height();
689        }
690
691        // Get the file extension
692        $data = @getimagesize( $original_file );
693        $ext  = $data['mime'] == 'image/png' ? 'png' : 'jpg';
694
695        // Set the full and thumb filenames
696        $full_filename  = wp_hash( $original_file . time() ) . '-bpfull.'  . $ext;
697        $thumb_filename = wp_hash( $original_file . time() ) . '-bpthumb.' . $ext;
698
699        // Crop the image
700        $full_cropped  = wp_crop_image( $original_file, (int) $crop_x, (int) $crop_y, (int) $crop_w, (int) $crop_h, bp_core_avatar_full_width(),  bp_core_avatar_full_height(),  false, $avatar_folder_dir . '/' . $full_filename  );
701        $thumb_cropped = wp_crop_image( $original_file, (int) $crop_x, (int) $crop_y, (int) $crop_w, (int) $crop_h, bp_core_avatar_thumb_width(), bp_core_avatar_thumb_height(), false, $avatar_folder_dir . '/' . $thumb_filename );
702
703        // Check for errors
704        if ( empty( $full_cropped ) || empty( $thumb_cropped ) || is_wp_error( $full_cropped ) || is_wp_error( $thumb_cropped ) )
705                return false;
706
707        // Remove the original
708        @unlink( $original_file );
709
710        return true;
711}
712
713/**
714 * bp_core_fetch_avatar_filter()
715 *
716 * Attempts to filter get_avatar function and let BuddyPress have a go
717 * at finding an avatar that may have been uploaded locally.
718 *
719 * @global array $authordata
720 * @param string $avatar The result of get_avatar from before-filter
721 * @param int|string|object $user A user ID, email address, or comment object
722 * @param int $size Size of the avatar image (thumb/full)
723 * @param string $default URL to a default image to use if no avatar is available
724 * @param string $alt Alternate text to use in image tag. Defaults to blank
725 * @return <type>
726 */
727function bp_core_fetch_avatar_filter( $avatar, $user, $size, $default, $alt = '' ) {
728        global $pagenow;
729
730        // Do not filter if inside WordPress options page
731        if ( 'options-discussion.php' == $pagenow )
732                return $avatar;
733
734        // If passed an object, assume $user->user_id
735        if ( is_object( $user ) ) {
736                $id = $user->user_id;
737
738        // If passed a number, assume it was a $user_id
739        } else if ( is_numeric( $user ) ) {
740                $id = $user;
741
742        // If passed a string and that string returns a user, get the $id
743        } elseif ( is_string( $user ) && ( $user_by_email = get_user_by( 'email', $user ) ) ) {
744                $id = $user_by_email->ID;
745        }
746
747        // If somehow $id hasn't been assigned, return the result of get_avatar
748        if ( empty( $id ) ) {
749                return !empty( $avatar ) ? $avatar : $default;
750        }
751
752        // Image alt tag
753        if ( empty( $alt ) ) {
754                $alt = sprintf( __( 'Avatar of %s', 'buddypress' ), bp_core_get_user_displayname( $id ) );
755        }
756
757        // Let BuddyPress handle the fetching of the avatar
758        $bp_avatar = bp_core_fetch_avatar( array( 'item_id' => $id, 'width' => $size, 'height' => $size, 'alt' => $alt ) );
759
760        // If BuddyPress found an avatar, use it. If not, use the result of get_avatar
761        return ( !$bp_avatar ) ? $avatar : $bp_avatar;
762}
763add_filter( 'get_avatar', 'bp_core_fetch_avatar_filter', 10, 5 );
764
765/**
766 * Has the current avatar upload generated an error?
767 *
768 * @param array $file
769 * @return bool
770 */
771function bp_core_check_avatar_upload( $file ) {
772        if ( isset( $file['error'] ) && $file['error'] )
773                return false;
774
775        return true;
776}
777
778/**
779 * Is the file size of the current avatar upload permitted?
780 *
781 * @param array $file
782 * @return bool
783 */
784function bp_core_check_avatar_size( $file ) {
785        if ( $file['file']['size'] > bp_core_avatar_original_max_filesize() )
786                return false;
787
788        return true;
789}
790
791/**
792 * Does the current avatar upload have an allowed file type?
793 *
794 * Permitted file types are JPG, GIF and PNG.
795 *
796 * @param string $file
797 * @return bool
798 */
799function bp_core_check_avatar_type($file) {
800        if ( ( !empty( $file['file']['type'] ) && !preg_match('/(jpe?g|gif|png)$/i', $file['file']['type'] ) ) || !preg_match( '/(jpe?g|gif|png)$/i', $file['file']['name'] ) )
801                return false;
802
803        return true;
804}
805
806/**
807 * Fetches data from the BP root blog's upload directory.
808 *
809 * Handy for multisite instances because all uploads are made on the BP root
810 * blog and we need to query the BP root blog for the upload directory data.
811 *
812 * This function ensures that we only need to use {@link switch_to_blog()}
813 * once to get what we need.
814 *
815 * @since BuddyPress (1.8)
816 *
817 * @uses wp_upload_dir()
818 *
819 * @param string $type The variable we want to return from the $bp->avatars object.
820 *  Only 'upload_path' and 'url' are supported.
821 * @return string
822 */
823function bp_core_get_upload_dir( $type = 'upload_path' ) {
824        $bp = buddypress();
825
826        switch ( $type ) {
827                case 'upload_path' :
828                        $constant = 'BP_AVATAR_UPLOAD_PATH';
829                        $key      = 'basedir';
830
831                        break;
832
833                case 'url' :
834                        $constant = 'BP_AVATAR_URL';
835                        $key      = 'baseurl';
836
837                        break;
838
839                default :
840                        return false;
841
842                        break;
843        }
844
845        // See if the value has already been calculated and stashed in the $bp global
846        if ( isset( $bp->avatar->$type ) ) {
847                $retval = $bp->avatar->$type;
848        } else {
849                // If this value has been set in a constant, just use that
850                if ( defined( $constant ) ) {
851                        $retval = constant( $constant );
852                } else {
853
854                        // Use cached upload dir data if available
855                        if ( ! empty( $bp->avatar->upload_dir ) ) {
856                                $upload_dir = $bp->avatar->upload_dir;
857
858                        // No cache, so query for it
859                        } else {
860                                // We need to switch to the root blog on multisite installs
861                                if ( is_multisite() ) {
862                                        switch_to_blog( bp_get_root_blog_id() );
863                                }
864
865                                // Get upload directory information from current site
866                                $upload_dir = wp_upload_dir();
867
868                                // Will bail if not switched
869                                restore_current_blog();
870
871                                // Stash upload directory data for later use
872                                $bp->avatar->upload_dir = $upload_dir;
873                        }
874
875                        // Directory does not exist and cannot be created
876                        if ( ! empty( $upload_dir['error'] ) ) {
877                                $retval = '';
878
879                        } else {
880                                $retval = $upload_dir[$key];
881
882                                // If $key is 'baseurl', check to see if we're on SSL
883                                // Workaround for WP13941, WP15928, WP19037.
884                                if ( $key == 'baseurl' && is_ssl() ) {
885                                        $retval = str_replace( 'http://', 'https://', $retval );
886                                }
887                        }
888
889                }
890
891                // Stash in $bp for later use
892                $bp->avatar->$type = $retval;
893        }
894
895        return $retval;
896}
897
898/**
899 * bp_core_avatar_upload_path()
900 *
901 * Returns the absolute upload path for the WP installation
902 *
903 * @uses wp_upload_dir To get upload directory info
904 * @return string Absolute path to WP upload directory
905 */
906function bp_core_avatar_upload_path() {
907        return apply_filters( 'bp_core_avatar_upload_path', bp_core_get_upload_dir() );
908}
909
910/**
911 * bp_core_avatar_url()
912 *
913 * Returns the raw base URL for root site upload location
914 *
915 * @uses wp_upload_dir To get upload directory info
916 * @return string Full URL to current upload location
917 */
918function bp_core_avatar_url() {
919        return apply_filters( 'bp_core_avatar_url', bp_core_get_upload_dir( 'url' ) );
920}
921
922/**
923 * Check if a given user ID has an uploaded avatar
924 *
925 * @since BuddyPress (1.0)
926 * @param int $user_id
927 * @return boolean
928 */
929function bp_get_user_has_avatar( $user_id = 0 ) {
930
931        if ( empty( $user_id ) )
932                $user_id = bp_displayed_user_id();
933
934        $retval = false;
935        if ( bp_core_fetch_avatar( array( 'item_id' => $user_id, 'no_grav' => true, 'html' => false ) ) != bp_core_avatar_default() )
936                $retval = true;
937
938        return (bool) apply_filters( 'bp_get_user_has_avatar', $retval, $user_id );
939}
940
941/**
942 * Utility function for fetching an avatar dimension setting
943 *
944 * @package BuddyPress
945 * @since BuddyPress (1.5)
946 *
947 * @param str $type 'thumb' for thumbs, otherwise full
948 * @param str $h_or_w 'height' for height, otherwise width
949 * @return int $dim The dimension
950 */
951function bp_core_avatar_dimension( $type = 'thumb', $h_or_w = 'height' ) {
952        $bp  = buddypress();
953        $dim = isset( $bp->avatar->{$type}->{$h_or_w} ) ? (int) $bp->avatar->{$type}->{$h_or_w} : false;
954
955        return apply_filters( 'bp_core_avatar_dimension', $dim, $type, $h_or_w );
956}
957
958/**
959 * Get the avatar thumb width setting
960 *
961 * @package BuddyPress
962 * @since BuddyPress (1.5)
963 *
964 * @return int The thumb width
965 */
966function bp_core_avatar_thumb_width() {
967        return apply_filters( 'bp_core_avatar_thumb_width', bp_core_avatar_dimension( 'thumb', 'width' ) );
968}
969
970/**
971 * Get the avatar thumb height setting
972 *
973 * @package BuddyPress
974 * @since BuddyPress (1.5)
975 *
976 * @return int The thumb height
977 */
978function bp_core_avatar_thumb_height() {
979        return apply_filters( 'bp_core_avatar_thumb_height', bp_core_avatar_dimension( 'thumb', 'height' ) );
980}
981
982/**
983 * Get the avatar full width setting
984 *
985 * @package BuddyPress
986 * @since BuddyPress (1.5)
987 *
988 * @return int The full width
989 */
990function bp_core_avatar_full_width() {
991        return apply_filters( 'bp_core_avatar_full_width', bp_core_avatar_dimension( 'full', 'width' ) );
992}
993
994/**
995 * Get the avatar full height setting
996 *
997 * @package BuddyPress
998 * @since BuddyPress (1.5)
999 *
1000 * @return int The full height
1001 */
1002function bp_core_avatar_full_height() {
1003        return apply_filters( 'bp_core_avatar_full_height', bp_core_avatar_dimension( 'full', 'height' ) );
1004}
1005
1006/**
1007 * Get the max width for original avatar uploads
1008 *
1009 * @package BuddyPress
1010 * @since BuddyPress (1.5)
1011 *
1012 * @return int The width
1013 */
1014function bp_core_avatar_original_max_width() {
1015        return apply_filters( 'bp_core_avatar_original_max_width', (int) buddypress()->avatar->original_max_width );
1016}
1017
1018/**
1019 * Get the max filesize for original avatar uploads
1020 *
1021 * @package BuddyPress
1022 * @since BuddyPress (1.5)
1023 *
1024 * @return int The filesize
1025 */
1026function bp_core_avatar_original_max_filesize() {
1027        return apply_filters( 'bp_core_avatar_original_max_filesize', (int) buddypress()->avatar->original_max_filesize );
1028}
1029
1030/**
1031 * Get the default avatar
1032 *
1033 * @package BuddyPress
1034 * @since BuddyPress (1.5)
1035 *
1036 * @return int The URL of the default avatar
1037 */
1038function bp_core_avatar_default() {
1039        return apply_filters( 'bp_core_avatar_default', buddypress()->avatar->full->default );
1040}
1041
1042/**
1043 * Get the default avatar thumb
1044 *
1045 * @package BuddyPress
1046 * @since BuddyPress (1.5)
1047 *
1048 * @return int The URL of the default avatar thumb
1049 */
1050function bp_core_avatar_default_thumb() {
1051        return apply_filters( 'bp_core_avatar_thumb', buddypress()->avatar->thumb->default );
1052}