Skip to:
Content

BuddyPress.org

Ticket #6278: 6278.07.patch

File 6278.07.patch, 52.3 KB (added by imath, 5 years ago)
  • src/bp-core/bp-core-avatars.php

    diff --git src/bp-core/bp-core-avatars.php src/bp-core/bp-core-avatars.php
    index c607bb2..44fe3c3 100644
    function bp_core_delete_existing_avatar( $args = '' ) { 
    564564 * @see bp_core_check_avatar_upload()
    565565 * @see bp_core_check_avatar_type()
    566566 *
    567  * @param array $file The appropriate entry the from $_FILES superglobal.
     567 * @param array  $file              The appropriate entry the from $_FILES superglobal.
    568568 * @param string $upload_dir_filter A filter to be applied to 'upload_dir'.
     569 *
    569570 * @return bool True on success, false on failure.
    570571 */
    571572function bp_core_avatar_handle_upload( $file, $upload_dir_filter ) {
    function bp_core_avatar_handle_upload( $file, $upload_dir_filter ) { 
    574575         * You may want to hook into this filter if you want to override this function.
    575576         * Make sure you return false.
    576577         */
    577         if ( !apply_filters( 'bp_core_pre_avatar_handle_upload', true, $file, $upload_dir_filter ) )
     578        if ( ! apply_filters( 'bp_core_pre_avatar_handle_upload', true, $file, $upload_dir_filter ) ) {
    578579                return true;
    579 
    580         require_once( ABSPATH . '/wp-admin/includes/file.php' );
    581 
    582         $uploadErrors = array(
    583                 0 => __( 'The image was uploaded successfully', 'buddypress' ),
    584                 1 => __( 'The image exceeds the maximum allowed file size of: ', 'buddypress' ) . size_format( bp_core_avatar_original_max_filesize() ),
    585                 2 => __( 'The image exceeds the maximum allowed file size of: ', 'buddypress' ) . size_format( bp_core_avatar_original_max_filesize() ),
    586                 3 => __( 'The uploaded file was only partially uploaded.', 'buddypress' ),
    587                 4 => __( 'The image was not uploaded.', 'buddypress' ),
    588                 6 => __( 'Missing a temporary folder.', 'buddypress' )
    589         );
    590 
    591         if ( ! bp_core_check_avatar_upload( $file ) ) {
    592                 bp_core_add_message( sprintf( __( 'Your upload failed. Please try again. Error was: %s', 'buddypress' ), $uploadErrors[$file['file']['error']] ), 'error' );
    593                 return false;
    594580        }
    595581
    596         if ( ! bp_core_check_avatar_size( $file ) ) {
    597                 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' );
    598                 return false;
    599         }
     582        // Setup some variables
     583        $bp          = buddypress();
     584        $upload_path = bp_core_avatar_upload_path();
    600585
    601         if ( ! bp_core_check_avatar_type( $file ) ) {
    602                 bp_core_add_message( __( 'Please upload only JPG, GIF or PNG photos.', 'buddypress' ), 'error' );
    603                 return false;
    604         }
    605 
    606         // Filter the upload location
    607         add_filter( 'upload_dir', $upload_dir_filter, 10, 0 );
    608 
    609         $bp = buddypress();
     586        // Upload the file
     587        $avatar_attachment = new BP_Attachment_Avatar();
     588        $bp->avatar_admin->original = $avatar_attachment->upload( $file, $upload_dir_filter );
    610589
    611         $bp->avatar_admin->original = wp_handle_upload( $file['file'], array( 'action'=> 'bp_avatar_upload' ) );
    612 
    613         // Remove the upload_dir filter, so that other upload URLs on the page
    614         // don't break
    615         remove_filter( 'upload_dir', $upload_dir_filter, 10, 0 );
    616 
    617         // Move the file to the correct upload location.
    618         if ( !empty( $bp->avatar_admin->original['error'] ) ) {
     590        // In case of an error, stop the process and display a feedback to the user
     591        if ( ! empty( $bp->avatar_admin->original['error'] ) ) {
    619592                bp_core_add_message( sprintf( __( 'Upload Failed! Error was: %s', 'buddypress' ), $bp->avatar_admin->original['error'] ), 'error' );
    620593                return false;
    621594        }
    622595
    623         // Get image size
    624         $size  = @getimagesize( $bp->avatar_admin->original['file'] );
    625         $error = false;
    626 
    627         // Check image size and shrink if too large
    628         if ( $size[0] > bp_core_avatar_original_max_width() ) {
    629                 $editor = wp_get_image_editor( $bp->avatar_admin->original['file'] );
    630 
    631                 if ( ! is_wp_error( $editor ) ) {
    632                         $editor->set_quality( 100 );
    633 
    634                         $resized = $editor->resize( bp_core_avatar_original_max_width(), bp_core_avatar_original_max_width(), false );
    635                         if ( ! is_wp_error( $resized ) ) {
    636                                 $thumb = $editor->save( $editor->generate_filename() );
    637                         } else {
    638                                 $error = $resized;
    639                         }
    640 
    641                         // Check for thumbnail creation errors
    642                         if ( false === $error && is_wp_error( $thumb ) ) {
    643                                 $error = $thumb;
    644                         }
    645 
    646                         // Thumbnail is good so proceed
    647                         if ( false === $error ) {
    648                                 $bp->avatar_admin->resized = $thumb;
    649                         }
    650 
    651                 } else {
    652                         $error = $editor;
    653                 }
    654 
    655                 if ( false !== $error ) {
    656                         bp_core_add_message( sprintf( __( 'Upload Failed! Error was: %s', 'buddypress' ), $error->get_error_message() ), 'error' );
    657                         return false;
    658                 }
    659         }
    660 
    661         if ( ! isset( $bp->avatar_admin->image ) )
    662                 $bp->avatar_admin->image = new stdClass();
     596        // Maybe resize
     597        $bp->avatar_admin->resized = $avatar_attachment->shrink( $bp->avatar_admin->original['file'] );
     598        $bp->avatar_admin->image   = new stdClass();
    663599
    664600        // We only want to handle one image after resize.
    665601        if ( empty( $bp->avatar_admin->resized ) ) {
    666                 $bp->avatar_admin->image->dir = str_replace( bp_core_avatar_upload_path(), '', $bp->avatar_admin->original['file'] );
     602                $bp->avatar_admin->image->file = $bp->avatar_admin->original['file'];
     603                $bp->avatar_admin->image->dir  = str_replace( $upload_path, '', $bp->avatar_admin->original['file'] );
    667604        } else {
    668                 $bp->avatar_admin->image->dir = str_replace( bp_core_avatar_upload_path(), '', $bp->avatar_admin->resized['path'] );
     605                $bp->avatar_admin->image->file = $bp->avatar_admin->resized['path'];
     606                $bp->avatar_admin->image->dir  = str_replace( $upload_path, '', $bp->avatar_admin->resized['path'] );
    669607                @unlink( $bp->avatar_admin->original['file'] );
    670608        }
    671609
    function bp_core_avatar_handle_upload( $file, $upload_dir_filter ) { 
    675613                return false;
    676614        }
    677615
    678         // If the uploaded image is smaller than the "full" dimensions, throw
    679         // a warning
    680         $uploaded_image = @getimagesize( bp_core_avatar_upload_path() . buddypress()->avatar_admin->image->dir );
    681         $full_width     = bp_core_avatar_full_width();
    682         $full_height    = bp_core_avatar_full_height();
    683         if ( isset( $uploaded_image[0] ) && $uploaded_image[0] < $full_width || $uploaded_image[1] < $full_height ) {
    684                 bp_core_add_message( sprintf( __( 'You have selected an image that is smaller than recommended. For best results, upload a picture larger than %d x %d pixels.', 'buddypress' ), $full_width, $full_height ), 'error' );
     616        // If the uploaded image is smaller than the "full" dimensions, throw a warning
     617        if ( $avatar_attachment->is_too_small( $bp->avatar_admin->image->file ) ) {
     618                bp_core_add_message( sprintf( __( 'You have selected an image that is smaller than recommended. For best results, upload a picture larger than %d x %d pixels.', 'buddypress' ), bp_core_avatar_full_width(), bp_core_avatar_full_height() ), 'error' );
    685619        }
    686620
    687621        // Set the url value for the image
    function bp_core_avatar_handle_crop( $args = '' ) { 
    738672         * You may want to hook into this filter if you want to override this function.
    739673         * Make sure you return false.
    740674         */
    741         if ( !apply_filters( 'bp_core_pre_avatar_handle_crop', true, $r ) )
     675        if ( ! apply_filters( 'bp_core_pre_avatar_handle_crop', true, $r ) ) {
    742676                return true;
    743 
    744         extract( $r, EXTR_SKIP );
    745 
    746         if ( empty( $original_file ) )
    747                 return false;
    748 
    749         $original_file = bp_core_avatar_upload_path() . $original_file;
    750 
    751         if ( !file_exists( $original_file ) )
    752                 return false;
    753 
    754         if ( empty( $item_id ) ) {
    755                 $avatar_folder_dir = apply_filters( 'bp_core_avatar_folder_dir', dirname( $original_file ), $item_id, $object, $avatar_dir );
    756         } else {
    757                 $avatar_folder_dir = apply_filters( 'bp_core_avatar_folder_dir', bp_core_avatar_upload_path() . '/' . $avatar_dir . '/' . $item_id, $item_id, $object, $avatar_dir );
    758677        }
    759678
    760         if ( !file_exists( $avatar_folder_dir ) )
    761                 return false;
    762 
    763         require_once( ABSPATH . '/wp-admin/includes/image.php' );
    764         require_once( ABSPATH . '/wp-admin/includes/file.php' );
    765 
    766         // Delete the existing avatar files for the object
    767         $existing_avatar = bp_core_fetch_avatar( array(
    768                 'object'  => $object,
    769                 'item_id' => $item_id,
    770                 'html' => false,
    771         ) );
    772 
    773         if ( ! empty( $existing_avatar ) ) {
    774                 // Check that the new avatar doesn't have the same name as the
    775                 // old one before deleting
    776                 $upload_dir           = wp_upload_dir();
    777                 $existing_avatar_path = str_replace( $upload_dir['baseurl'], '', $existing_avatar );
    778                 $new_avatar_path      = str_replace( $upload_dir['basedir'], '', $original_file );
    779 
    780                 if ( $existing_avatar_path !== $new_avatar_path ) {
    781                         bp_core_delete_existing_avatar( array( 'object' => $object, 'item_id' => $item_id, 'avatar_path' => $avatar_folder_dir ) );
    782                 }
    783         }
    784 
    785 
    786 
    787         // Make sure we at least have a width and height for cropping
    788         if ( empty( $crop_w ) ) {
    789                 $crop_w = bp_core_avatar_full_width();
    790         }
    791 
    792         if ( empty( $crop_h ) ) {
    793                 $crop_h = bp_core_avatar_full_height();
    794         }
    795 
    796         // Get the file extension
    797         $data = @getimagesize( $original_file );
    798         $ext  = $data['mime'] == 'image/png' ? 'png' : 'jpg';
    799 
    800         // Set the full and thumb filenames
    801         $full_filename  = wp_hash( $original_file . time() ) . '-bpfull.'  . $ext;
    802         $thumb_filename = wp_hash( $original_file . time() ) . '-bpthumb.' . $ext;
    803 
    804         // Crop the image
    805         $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  );
    806         $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 );
     679        // Crop the file
     680        $avatar_attachment = new BP_Attachment_Avatar();
     681        $cropped           = $avatar_attachment->crop( $r );
    807682
    808683        // Check for errors
    809         if ( empty( $full_cropped ) || empty( $thumb_cropped ) || is_wp_error( $full_cropped ) || is_wp_error( $thumb_cropped ) )
     684        if ( empty( $cropped['full'] ) || empty( $cropped['thumb'] ) || is_wp_error( $cropped['full'] ) || is_wp_error( $cropped['thumb'] ) ) {
    810685                return false;
    811 
    812         // Remove the original
    813         @unlink( $original_file );
     686        }
    814687
    815688        return true;
    816689}
    function bp_core_check_avatar_type($file) { 
    926799/**
    927800 * Fetch data from the BP root blog's upload directory.
    928801 *
    929  * Handy for multisite instances because all uploads are made on the BP root
    930  * blog and we need to query the BP root blog for the upload directory data.
    931  *
    932  * This function ensures that we only need to use {@link switch_to_blog()}
    933  * once to get what we need.
    934  *
    935802 * @since BuddyPress (1.8.0)
    936803 *
    937  * @uses wp_upload_dir()
    938  *
    939804 * @param string $type The variable we want to return from the $bp->avatars
    940805 *        object. Only 'upload_path' and 'url' are supported. Default: 'upload_path'.
    941806 * @return string The avatar upload directory path.
    function bp_core_get_upload_dir( $type = 'upload_path' ) { 
    977842
    978843                        // No cache, so query for it
    979844                        } else {
    980                                 // We need to switch to the root blog on multisite installs
    981                                 if ( is_multisite() ) {
    982                                         switch_to_blog( bp_get_root_blog_id() );
    983                                 }
    984845
    985846                                // Get upload directory information from current site
    986                                 $upload_dir = wp_upload_dir();
    987 
    988                                 // Will bail if not switched
    989                                 restore_current_blog();
     847                                $upload_dir = bp_upload_dir();
    990848
    991849                                // Stash upload directory data for later use
    992850                                $bp->avatar->upload_dir = $upload_dir;
    function bp_core_get_upload_dir( $type = 'upload_path' ) { 
    1018876/**
    1019877 * Get the absolute upload path for the WP installation.
    1020878 *
    1021  * @uses wp_upload_dir To get upload directory info
     879 * @uses bp_core_get_upload_dir() To get upload directory info
    1022880 *
    1023881 * @return string Absolute path to WP upload directory.
    1024882 */
    function bp_core_avatar_upload_path() { 
    1029887/**
    1030888 * Get the raw base URL for root site upload location.
    1031889 *
    1032  * @uses wp_upload_dir To get upload directory info.
     890 * @uses bp_core_get_upload_dir() To get upload directory info.
    1033891 *
    1034892 * @return string Full URL to current upload location.
    1035893 */
  • src/bp-core/bp-core-classes.php

    diff --git src/bp-core/bp-core-classes.php src/bp-core/bp-core-classes.php
    index 70d9084..41be065 100644
    require dirname( __FILE__ ) . '/classes/class-bp-suggestions.php'; 
    2121require dirname( __FILE__ ) . '/classes/class-bp-members-suggestions.php';
    2222require dirname( __FILE__ ) . '/classes/class-bp-recursive-query.php';
    2323require dirname( __FILE__ ) . '/classes/class-bp-media-extractor.php';
     24require dirname( __FILE__ ) . '/classes/class-bp-attachment.php';
     25require dirname( __FILE__ ) . '/classes/class-bp-attachment-avatar.php';
  • src/bp-core/bp-core-functions.php

    diff --git src/bp-core/bp-core-functions.php src/bp-core/bp-core-functions.php
    index f308211..2c246ef 100644
    function bp_core_get_suggestions( $args ) { 
    21472147
    21482148        return apply_filters( 'bp_core_get_suggestions', $retval, $args );
    21492149}
     2150
     2151/**
     2152 * Set data from the BP root blog's upload directory.
     2153 *
     2154 * Handy for multisite instances because all uploads are made on the BP root
     2155 * blog and we need to query the BP root blog for the upload directory data.
     2156 *
     2157 * This function ensures that we only need to use {@link switch_to_blog()}
     2158 * once to get what we need.
     2159 *
     2160 * @since BuddyPress (2.3.0)
     2161 *
     2162 * @uses  is_multisite()
     2163 * @uses  bp_is_root_blog()
     2164 * @uses  switch_to_blog()
     2165 * @uses  wp_upload_dir()
     2166 * @uses  restore_current_blog()
     2167 */
     2168function bp_upload_dir() {
     2169        $bp = buddypress();
     2170
     2171        if ( empty( $bp->upload_dir ) ) {
     2172                $need_switch = (bool) ( is_multisite() && ! bp_is_root_blog() );
     2173
     2174                // Maybe juggle to root blog
     2175                if ( true === $need_switch ) {
     2176                        switch_to_blog( bp_get_root_blog_id() );
     2177                }
     2178
     2179                // Get the upload directory (maybe for root blog)
     2180                $wp_upload_dir = wp_upload_dir();
     2181
     2182                // Maybe juggle back to current blog
     2183                if ( true === $need_switch ) {
     2184                        restore_current_blog();
     2185                }
     2186
     2187                // Bail if an error occurred
     2188                if ( ! empty( $wp_upload_dir['error'] ) ) {
     2189                        return false;
     2190                }
     2191
     2192                $bp->upload_dir = $wp_upload_dir;
     2193        }
     2194
     2195        return $bp->upload_dir;
     2196}
  • src/bp-core/classes/class-bp-attachment-avatar.php

    diff --git src/bp-core/classes/class-bp-attachment-avatar.php src/bp-core/classes/class-bp-attachment-avatar.php
    index e69de29..dcc63e1 100644
     
     1<?php
     2
     3/**
     4 * Core avatar attachment class
     5 *
     6 * @package BuddyPress
     7 * @subpackage Core
     8 */
     9
     10// Exit if accessed directly
     11defined( 'ABSPATH' ) || exit;
     12
     13/**
     14 * BP Attachment class to manage your avatar upload needs
     15 *
     16 * @since BuddyPress (2.3.0)
     17 */
     18class BP_Attachment_Avatar extends BP_Attachment {
     19
     20        /**
     21         * Construct Upload parameters
     22         *
     23         * @since BuddyPress (2.3.0)
     24         *
     25         * @see  BP_Attachment::__construct() for list of parameters
     26         * @uses bp_core_avatar_original_max_filesize()
     27         * @uses BP_Attachment::__construct()
     28         */
     29        public function __construct() {
     30                parent::__construct( array(
     31                        'action'                => 'bp_avatar_upload',
     32                        'file_input'            => 'file',
     33                        'original_max_filesize' => bp_core_avatar_original_max_filesize(),
     34
     35                        // Specific errors for avatars
     36                        'upload_error_strings'  => array(
     37                                9  => sprintf( __( 'That photo is too big. Please upload one smaller than %s', 'buddypress' ), size_format( bp_core_avatar_original_max_filesize() ) ),
     38                                10 => __( 'Please upload only JPG, GIF or PNG photos.', 'buddypress' ),
     39                        ),
     40                ) );
     41        }
     42
     43        /**
     44         * Set Upload Dir data for avatars
     45         *
     46         * @since BuddyPress (2.3.0)
     47         *
     48         * @uses bp_core_avatar_upload_path()
     49         * @uses bp_core_avatar_url()
     50         * @uses bp_upload_dir()
     51         */
     52        public function set_upload_dir() {
     53                if ( bp_core_avatar_upload_path() && bp_core_avatar_url() ) {
     54                        $this->upload_path = bp_core_avatar_upload_path();
     55                        $this->url         = bp_core_avatar_url();
     56                        $this->upload_dir  = bp_upload_dir();
     57                } else {
     58                        parent::set_upload_dir();
     59                }
     60        }
     61
     62        /**
     63         * Avatar specific rules
     64         *
     65         * Adds an error if the avatar size or type don't match BuddyPress needs
     66         * The error code is the index of $upload_error_strings
     67         *
     68         * @since BuddyPress (2.3.0)
     69         *
     70         * @param  array $file the temporary file attributes (before it has been moved)
     71         * @uses   bp_core_check_avatar_size()
     72         * @uses   bp_core_check_avatar_type()
     73         * @return array the file with extra errors if needed
     74         */
     75        public function validate_upload( $file = array() ) {
     76                // Bail if already an error
     77                if ( ! empty( $file['error'] ) ) {
     78                        return $file;
     79                }
     80
     81                // File size is too big
     82                if ( ! bp_core_check_avatar_size( array( 'file' => $file ) ) ) {
     83                        $file['error'] = 9;
     84
     85                // File is of invalid type
     86                } else if ( ! bp_core_check_avatar_type( array( 'file' => $file ) ) ) {
     87                        $file['error'] = 10;
     88                }
     89
     90                // Return with error code attached
     91                return $file;
     92        }
     93
     94        /**
     95         * Maybe shrink the attachment to fit maximum allowed width
     96         *
     97         * @since BuddyPress (2.3.0)
     98         *
     99         * @param string $file the absolute path to the file
     100         * @uses  bp_core_avatar_original_max_width()
     101         * @uses  wp_get_image_editor()
     102         * @return mixed
     103         */
     104        public static function shrink( $file = '' ) {
     105                // Get image size
     106                $size   = @getimagesize( $file );
     107                $retval = false;
     108
     109                // Check image size and shrink if too large
     110                if ( $size[0] > bp_core_avatar_original_max_width() ) {
     111                        $editor = wp_get_image_editor( $file );
     112
     113                        if ( ! is_wp_error( $editor ) ) {
     114                                $editor->set_quality( 100 );
     115
     116                                $resized = $editor->resize( bp_core_avatar_original_max_width(), bp_core_avatar_original_max_width(), false );
     117                                if ( ! is_wp_error( $resized ) ) {
     118                                        $thumb = $editor->save( $editor->generate_filename() );
     119                                } else {
     120                                        $retval = $resized;
     121                                }
     122
     123                                // Check for thumbnail creation errors
     124                                if ( ( false === $retval ) && is_wp_error( $thumb ) ) {
     125                                        $retval = $thumb;
     126                                }
     127
     128                                // Thumbnail is good so proceed
     129                                if ( false === $retval ) {
     130                                        $retval = $thumb;
     131                                }
     132
     133                        } else {
     134                                $retval = $editor;
     135                        }
     136                }
     137
     138                return $retval;
     139        }
     140
     141        /**
     142         * Check if the image dimensions are smaller than full avatar dimensions
     143         *
     144         * @since BuddyPress (2.3.0)
     145         *
     146         * @param string $file the absolute path to the file
     147         * @uses  bp_core_avatar_full_width()
     148         * @uses  bp_core_avatar_full_height()
     149         * @return boolean
     150         */
     151        public static function is_too_small( $file = '' ) {
     152                $uploaded_image = @getimagesize( $file );
     153                $full_width     = bp_core_avatar_full_width();
     154                $full_height    = bp_core_avatar_full_height();
     155
     156                if ( isset( $uploaded_image[0] ) && $uploaded_image[0] < $full_width || $uploaded_image[1] < $full_height ) {
     157                        return true;
     158                }
     159
     160                return false;
     161        }
     162
     163        /**
     164         * Crop the avatar
     165         *
     166         * @since BuddyPress (2.3.0)
     167         *
     168         * @see  BP_Attachment::crop for the list of parameters
     169         * @param array $args
     170         * @return array the cropped avatars (full and thumb)
     171         */
     172        public function crop( $args = array() ) {
     173                // Bail if the original file is missing
     174                if ( empty( $args['original_file'] ) ) {
     175                        return false;
     176                }
     177
     178                /**
     179                 * Original file is a relative path to the image
     180                 * eg: /avatars/1/avatar.jpg
     181                 */
     182                $relative_path = $args['original_file'];
     183                $absolute_path = $this->upload_path . $relative_path;
     184
     185                // Bail if the avatar is not available
     186                if ( ! file_exists( $absolute_path ) )  {
     187                        return false;
     188                }
     189
     190                if ( empty( $args['item_id'] ) ) {
     191                        $avatar_folder_dir = apply_filters( 'bp_core_avatar_folder_dir', dirname( $absolute_path ), $args['item_id'], $args['object'], $args['avatar_dir'] );
     192                } else {
     193                        $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'] );
     194                }
     195
     196                // Bail if the avatar folder is missing for this item_id
     197                if ( ! file_exists( $avatar_folder_dir ) ) {
     198                        return false;
     199                }
     200
     201                // Delete the existing avatar files for the object
     202                $existing_avatar = bp_core_fetch_avatar( array(
     203                        'object'  => $args['object'],
     204                        'item_id' => $args['item_id'],
     205                        'html' => false,
     206                ) );
     207
     208                /**
     209                 * Check that the new avatar doesn't have the same name as the
     210                 * old one before deleting
     211                 */
     212                if ( ! empty( $existing_avatar ) && $existing_avatar !== $this->url . $relative_path ) {
     213                        bp_core_delete_existing_avatar( array( 'object' => $args['object'], 'item_id' => $args['item_id'], 'avatar_path' => $avatar_folder_dir ) );
     214                }
     215
     216                // Make sure we at least have minimal data for cropping
     217                if ( empty( $args['crop_w'] ) ) {
     218                        $args['crop_w'] = bp_core_avatar_full_width();
     219                }
     220
     221                if ( empty( $args['crop_h'] ) ) {
     222                        $args['crop_h'] = bp_core_avatar_full_height();
     223                }
     224
     225                // Get the file extension
     226                $data = @getimagesize( $absolute_path );
     227                $ext  = $data['mime'] == 'image/png' ? 'png' : 'jpg';
     228
     229                $args['original_file'] = $absolute_path;
     230                $args['src_abs']       = false;
     231                $avatar_types = array( 'full' => '', 'thumb' => '' );
     232
     233                foreach ( $avatar_types as $key_type => $type ) {
     234                        $args['dst_w']    = bp_core_avatar_dimension( $key_type, 'width' );
     235                        $args['dst_h']    = bp_core_avatar_dimension( $key_type, 'height' );
     236                        $args['dst_file'] = $avatar_folder_dir . '/' . wp_hash( $absolute_path . time() ) . '-bp' . $key_type . '.' . $ext;
     237
     238                        $avatar_types[ $key_type ] = parent::crop( $args );
     239                }
     240
     241                // Remove the original
     242                @unlink( $absolute_path );
     243
     244                // Return the full and thumb cropped avatars
     245                return $avatar_types;
     246        }
     247}
  • src/bp-core/classes/class-bp-attachment.php

    diff --git src/bp-core/classes/class-bp-attachment.php src/bp-core/classes/class-bp-attachment.php
    index e69de29..05bd841 100644
     
     1<?php
     2
     3/**
     4 * Core attachment class.
     5 *
     6 * @package BuddyPress
     7 * @subpackage Core
     8 */
     9
     10// Exit if accessed directly
     11defined( 'ABSPATH' ) || exit;
     12
     13/**
     14 * BP Attachment class to manage your component's uploads
     15 *
     16 * @since BuddyPress (2.3.0)
     17 */
     18class BP_Attachment {
     19
     20        /** Upload properties *****************************************************/
     21
     22        /**
     23         * The file being uploaded
     24         *
     25         * @var array
     26         */
     27        public $attachment = array();
     28
     29        /**
     30         * Maximum file size in kilobytes
     31         *
     32         * @var int
     33         */
     34        public $original_max_filesize = 0;
     35
     36        /**
     37         * List of allowed file extensions
     38         * Defaults to get_allowed_mime_types()
     39         *
     40         * @var int
     41         */
     42        public $allowed_mime_types = array();
     43
     44        /**
     45         * component's upload base directory.
     46         *
     47         * @var string
     48         */
     49        public $base_dir = '';
     50
     51        /**
     52         * The upload action.
     53         *
     54         * @var string
     55         */
     56        public $action = '';
     57
     58        /**
     59         * The file input name attribute
     60         *
     61         * @var string
     62         */
     63        public $file_input = '';
     64
     65        /**
     66         * List of upload errors.
     67         *
     68         * @var array
     69         */
     70        public $upload_error_strings = array();
     71
     72        /**
     73         * List of required core files
     74         *
     75         * @var array
     76         */
     77        public $required_wp_files = array( 'file' );
     78
     79        /**
     80         * Construct Upload parameters
     81         *
     82         * @since BuddyPress (2.3.0)
     83         *
     84         * @param array $args {
     85         *     @type int    $original_max_filesize Maximum file size in kilobytes. Defaults to php.ini settings.
     86         *     @type array  $allowed_mime_types    List of allowed file extensions (eg: array( 'jpg', 'gif', 'png' ) ).
     87         *                                         Defaults to WordPress allowed mime types
     88         *     @type string $base_dir              Component's upload base directory. Defaults to WordPress 'uploads'
     89         *     @type string $action                The upload action used when uploading a file, $_POST['action'] must be set
     90         *                                         and its value must equal $action {@link wp_handle_upload()} (required)
     91         *     @type string $file_input            The name attribute used in the file input. (required)
     92         *     @type array  $upload_error_strings  A list of specific error messages (optional).
     93         *     @type array  $required_wp_files     The list of required WordPress core files. Default: array( 'file' );
     94         * }
     95         * @uses  sanitize_key()
     96         * @uses  bp_parse_args()
     97         * @uses  BP_Attachment->set_upload_error_strings()
     98         * @uses  BP_Attachment->set_upload_dir()
     99         */
     100        public function __construct( $args = '' ) {
     101                // Upload action and the file input name are required parameters
     102                if ( empty( $args['action'] ) || empty( $args['file_input'] ) ) {
     103                        return false;
     104                }
     105
     106                // Sanitize the action ID and the file input name
     107                $this->action     = sanitize_key( $args['action'] );
     108                $this->file_input = sanitize_key( $args['file_input'] );
     109
     110                /**
     111                 * Max file size defaults to php ini settings or, in the case of
     112                 * a multisite config, the root site fileupload_maxk option
     113                 */
     114                $this->original_max_filesize = (int) wp_max_upload_size();
     115
     116                $params = bp_parse_args( $args, get_class_vars( __CLASS__ ), $this->action . '_upload_params' );
     117
     118                foreach ( $params as $key => $param ) {
     119                        if ( 'upload_error_strings' === $key ) {
     120                                $this->{$key} = $this->set_upload_error_strings( $param );
     121                        } else {
     122                                $this->{$key} = $param;
     123                        }
     124                }
     125
     126                // Set the path/url and base dir for uploads
     127                $this->set_upload_dir();
     128        }
     129
     130        /**
     131         * Set upload path and url for the component.
     132         *
     133         * @since BuddyPress (2.3.0)
     134         *
     135         * @uses  bp_upload_dir()
     136         */
     137        public function set_upload_dir() {
     138                // Set the directory, path, & url variables
     139                $this->upload_dir  = bp_upload_dir();
     140
     141                if ( empty( $this->upload_dir ) ) {
     142                        return false;
     143                }
     144
     145                $this->upload_path = $this->upload_dir['basedir'];
     146                $this->url         = $this->upload_dir['baseurl'];
     147
     148                // Ensure URL is https if SSL is set/forced
     149                if ( is_ssl() ) {
     150                        $this->url = str_replace( 'http://', 'https://', $this->url );
     151                }
     152
     153                /**
     154                 * Custom base dir.
     155                 *
     156                 * If the component set this property, set the specific path, url and create the dir
     157                 */
     158                if ( ! empty( $this->base_dir ) ) {
     159                        $this->upload_path = trailingslashit( $this->upload_path ) . $this->base_dir;
     160                        $this->url         = trailingslashit( $this->url  ) . $this->base_dir;
     161
     162                        // Finally create the base dir
     163                        $this->create_dir();
     164                }
     165        }
     166
     167        /**
     168         * Set Upload error messages
     169         *
     170         * Used into the $overrides argument of BP_Attachment->upload()
     171         *
     172         * @since BuddyPress (2.3.0)
     173         *
     174         * @param array $param a list of error messages to add to BuddyPress core ones
     175         * @return array the list of upload errors
     176         */
     177        public function set_upload_error_strings( $param = array() ) {
     178                /**
     179                 * Index of the array is the error code
     180                 * Custom errors will start at 9 code
     181                 */
     182                $upload_errors = array(
     183                        0 => __( 'The file was uploaded successfully', 'buddypress' ),
     184                        1 => __( 'The uploaded file exceeds the maximum allowed file size for this site', 'buddypress' ),
     185                        2 => sprintf( __( 'The uploaded file exceeds the maximum allowed file size of: %s', 'buddypress' ), size_format( $this->original_max_filesize ) ),
     186                        3 => __( 'The uploaded file was only partially uploaded.', 'buddypress' ),
     187                        4 => __( 'No file was uploaded.', 'buddypress' ),
     188                        5 => '',
     189                        6 => __( 'Missing a temporary folder.', 'buddypress' ),
     190                        7 => __( 'Failed to write file to disk.', 'buddypress' ),
     191                        8 => __( 'File upload stopped by extension.', 'buddypress' ),
     192                );
     193
     194                if ( ! array_intersect_key( $upload_errors, (array) $param ) ) {
     195                        foreach ( $param as $key_error => $error_message ) {
     196                                $upload_errors[ $key_error ] = $error_message;
     197                        }
     198                }
     199
     200                return $upload_errors;
     201        }
     202
     203        /**
     204         * Include the WordPress core needed files
     205         *
     206         * @since BuddyPress (2.3.0)
     207         */
     208        public function includes() {
     209                foreach ( array_unique( $this->required_wp_files ) as $wp_file ) {
     210                        if ( ! file_exists( ABSPATH . "/wp-admin/includes/{$wp_file}.php" ) ) {
     211                                continue;
     212                        }
     213
     214                        require_once( ABSPATH . "/wp-admin/includes/{$wp_file}.php" );
     215                }
     216        }
     217
     218        /**
     219         * Upload the attachment
     220         *
     221         * @since BuddyPress (2.3.0)
     222         *
     223         * @param  array $file               The appropriate entry the from $_FILES superglobal.
     224         * @param  string $upload_dir_filter A specific filter to be applied to 'upload_dir' (optional).
     225         * @uses   wp_handle_upload()
     226         * @uses   apply_filters()           Call 'bp_attachment_upload_overrides' to include specific upload overrides
     227         *
     228         * @return array                     On success, returns an associative array of file attributes.
     229         *                                   On failure, returns an array containing the error message
     230         *                                   (eg: array( 'error' => $message ) )
     231         */
     232        public function upload( $file, $upload_dir_filter = '' ) {
     233                /**
     234                 * Upload action and the file input name are required parameters
     235                 * @see BP_Attachment:__construct()
     236                 */
     237                if ( empty( $this->action ) || empty( $this->file_input ) ) {
     238                        return false;
     239                }
     240
     241                /**
     242                 * Add custom rules before enabling the file upload
     243                 */
     244                add_filter( "{$this->action}_prefilter", array( $this, 'validate_upload' ), 10, 1 );
     245
     246                // Set Default overrides
     247                $overrides = array(
     248                        'action'               => $this->action,
     249                        'upload_error_strings' => $this->upload_error_strings,
     250                );
     251
     252                /**
     253                 * Add a mime override if needed
     254                 * Used to restrict uploads by extensions
     255                 */
     256                if ( ! empty( $this->allowed_mime_types ) ) {
     257                        $mime_types = $this->validate_mime_types();
     258
     259                        if ( ! empty( $mime_types ) ) {
     260                                $overrides['mimes'] = $mime_types;
     261                        }
     262                }
     263
     264                /**
     265                 * If you need to add some overrides we haven't thought of
     266                 *
     267                 * @var  array $overrides the wp_handle_upload overrides
     268                 */
     269                $overrides = apply_filters( 'bp_attachment_upload_overrides', $overrides );
     270
     271                $this->includes();
     272
     273                /**
     274                 * If the $base_dir was set when constructing the class,
     275                 * and no specific filter has been requested, use a default
     276                 * filter to create the specific $base dir
     277                 * @see  BP_Attachment->upload_dir_filter()
     278                 */
     279                if ( empty( $upload_dir_filter ) && ! empty( $this->base_dir ) ) {
     280                        $upload_dir_filter = array( $this, 'upload_dir_filter' );
     281                }
     282
     283                // Make sure the file will be uploaded in the attachment directory
     284                add_filter( 'upload_dir', $upload_dir_filter, 10, 0 );
     285
     286                // Upload the attachment
     287                $this->attachment = wp_handle_upload( $file[ $this->file_input ], $overrides );
     288
     289                // Restore WordPress Uploads data
     290                remove_filter( 'upload_dir', $upload_dir_filter, 10, 0 );
     291
     292                // Finally return the uploaded file or the error
     293                return $this->attachment;
     294        }
     295
     296        /**
     297         * Validate the allowed mime types using WordPress allowed mime types
     298         *
     299         * In case of a multisite, the mime types are already restricted by
     300         * the 'upload_filetypes' setting. BuddyPress will respect this setting.
     301         * @see check_upload_mimes()
     302         *
     303         * @since BuddyPress (2.3.0)
     304         *
     305         * @uses get_allowed_mime_types()
     306         */
     307        protected function validate_mime_types() {
     308                $wp_mimes = get_allowed_mime_types();
     309                $valid_mimes = array();
     310
     311                // Set the allowed mimes for the upload
     312                foreach ( (array) $this->allowed_mime_types as $ext ) {
     313                        foreach ( $wp_mimes as $ext_pattern => $mime ) {
     314                                if ( $ext != '' && strpos( $ext_pattern, $ext ) !== false ) {
     315                                        $valid_mimes[$ext_pattern] = $mime;
     316                                }
     317                        }
     318                }
     319                return $valid_mimes;
     320        }
     321
     322        /**
     323         * Specific upload rules
     324         *
     325         * Override this function from your child class to build your specific rules
     326         * By default, if an original_max_filesize is provided, a check will be done
     327         * on the file size.
     328         *
     329         * @see BP_Attachment_Avatar->validate_upload() for an example of use
     330         *
     331         * @since BuddyPress (2.3.0)
     332         *
     333         * @param  array $file the temporary file attributes (before it has been moved)
     334         * @return array the file
     335         */
     336        public function validate_upload( $file = array() ) {
     337                // Bail if already an error
     338                if ( ! empty( $file['error'] ) ) {
     339                        return $file;
     340                }
     341
     342                if ( ! empty( $this->original_max_filesize ) && $file['size'] > $this->original_max_filesize ) {
     343                        $file['error'] = 2;
     344                }
     345
     346                // Return the file
     347                return $file;
     348        }
     349
     350        /**
     351         * Default filter to save the attachments
     352         *
     353         * @since BuddyPress (2.3.0)
     354         *
     355         * @uses   apply_filters() call 'bp_attachment_upload_dir' to eventually override the upload location
     356         *                         regarding to context
     357         * @return array the upload directory data
     358         */
     359        public function upload_dir_filter() {
     360                /**
     361                 * Filters the component's upload directory.
     362                 *
     363                 * @since BuddyPress (2.3.0)
     364                 *
     365                 * @param array $value Array containing the path, URL, and other helpful settings.
     366                 */
     367                return apply_filters( 'bp_attachment_upload_dir', array(
     368                        'path'    => $this->upload_path,
     369                        'url'     => $this->url,
     370                        'subdir'  => false,
     371                        'basedir' => $this->upload_path,
     372                        'baseurl' => $this->url,
     373                        'error'   => false
     374                ) );
     375        }
     376
     377        /**
     378         * Create the custom base directory for the component uploads
     379         *
     380         * Override this function in your child class to run specific actions
     381         * (eg: add an .htaccess file)
     382         *
     383         * @since BuddyPress (2.3.0)
     384         *
     385         * @uses   wp_mkdir_p()
     386         */
     387        public function create_dir() {
     388                // Bail if no specific base dir is set
     389                if ( empty( $this->base_dir ) ) {
     390                        return false;
     391                }
     392
     393                // Check if upload path already exists
     394                if ( ! file_exists( $this->upload_path ) ) {
     395
     396                        // If path does not exist, attempt to create it
     397                        if ( ! wp_mkdir_p( $this->upload_path ) ) {
     398                                return false;
     399                        }
     400                }
     401
     402                // Directory exists
     403                return true;
     404        }
     405
     406        /**
     407         * Crop an image file
     408         *
     409         * @since BuddyPress (2.3.0)
     410         *
     411         * @param array $args {
     412         *     @type string $original_file The source file (absolute path) for the Attachment.
     413         *     @type int    $crop_x The start x position to crop from.
     414         *     @type int    $crop_y The start y position to crop from.
     415         *     @type int    $crop_w The width to crop.
     416         *     @type int    $crop_h The height to crop.
     417         *     @type int    $dst_w The destination width.
     418         *     @type int    $dst_h The destination height.
     419         *     @type int    $src_abs Optional. If the source crop points are absolute.
     420         *     @type string $dst_file Optional. The destination file to write to.
     421         * }
     422         * @uses wp_crop_image()
     423         * @return string|WP_Error New filepath on success, WP_Error on failure.
     424         */
     425        public function crop( $args = array() ) {
     426                $wp_error = new WP_Error();
     427
     428                $r = wp_parse_args( $args, array(
     429                        'original_file' => '',
     430                        'crop_x'        => 0,
     431                        'crop_y'        => 0,
     432                        'crop_w'        => 0,
     433                        'crop_h'        => 0,
     434                        'dst_w'         => 0,
     435                        'dst_h'         => 0,
     436                        'src_abs'       => false,
     437                        'dst_file'      => false,
     438                ) );
     439
     440                if ( empty( $r['original_file'] ) || ! file_exists( $r['original_file'] ) ) {
     441                        $wp_error->add( 'crop_error', __( 'Cropping the file failed: missing source file.', 'buddypress' ) );
     442                        return $wp_error;
     443                }
     444
     445                // Check image file pathes
     446                $path_error = __( 'Cropping the file failed: the file path is not allowed.', 'buddypress' );
     447
     448                // Make sure it's coming from an uploaded file
     449                if ( false === strpos( $r['original_file'], $this->upload_path ) ) {
     450                        $wp_error->add( 'crop_error', $path_error );
     451                        return $wp_error;
     452                }
     453
     454                /**
     455                 * If no destination file is provided, WordPress will use a default name
     456                 * and will write the file in the source file's folder.
     457                 * If a destination file is provided, we need to make sure it's going into uploads
     458                 */
     459                if ( ! empty( $r['dst_file'] ) && false === strpos( $r['dst_file'], $this->upload_path ) ) {
     460                        $wp_error->add( 'crop_error', $path_error );
     461                        return $wp_error;
     462                }
     463
     464                // Check image file types
     465                $check_types = array( 'src_file' => array( 'file' => $r['original_file'], 'error' => _x( 'source file', 'Attachment source file', 'buddypress' ) ) );
     466                if ( ! empty( $r['dst_file'] ) ) {
     467                        $check_types['dst_file'] = array( 'file' => $r['dst_file'], 'error' => _x( 'destination file', 'Attachment destination file', 'buddypress' ) );
     468                }
     469
     470                /**
     471                 * WordPress image supported types
     472                 * @see wp_attachment_is()
     473                 */
     474                $supported_image_types = array(
     475                        'jpg'  => 1,
     476                        'jpeg' => 1,
     477                        'jpe'  => 1,
     478                        'gif'  => 1,
     479                        'png'  => 1,
     480                );
     481
     482                foreach ( $check_types as $file ) {
     483                        $is_image      = wp_check_filetype( $file['file'] );
     484                        $ext           = $is_image['ext'];
     485
     486                        if ( empty( $ext ) || empty( $supported_image_types[ $ext ] ) ) {
     487                                $wp_error->add( 'crop_error', sprintf( __( 'Cropping the file failed: %s is not a supported image file.', 'buddypress' ), $file['error'] ) );
     488                                return $wp_error;
     489                        }
     490                }
     491
     492                // Add the image.php to the required WordPress files, if it's not already the case
     493                $required_files = array_flip( $this->required_wp_files );
     494                if ( ! isset( $required_files['image'] ) ) {
     495                        $this->required_wp_files[] = 'image';
     496                }
     497
     498                // Load the files
     499                $this->includes();
     500
     501                // Finally crop the image
     502                return wp_crop_image( $r['original_file'], (int) $r['crop_x'], (int) $r['crop_y'], (int) $r['crop_w'], (int) $r['crop_h'], (int) $r['dst_w'], (int) $r['dst_h'], $r['src_abs'], $r['dst_file'] );
     503        }
     504}
  • src/bp-groups/bp-groups-functions.php

    diff --git src/bp-groups/bp-groups-functions.php src/bp-groups/bp-groups-functions.php
    index 011231f..49864eb 100644
    function groups_avatar_upload_dir( $group_id = 0 ) { 
    817817                $group_id = bp_get_current_group_id();
    818818        }
    819819
    820         $path    = bp_core_avatar_upload_path() . '/group-avatars/' . $group_id;
    821         $newbdir = $path;
    822 
    823         if ( !file_exists( $path ) )
    824                 @wp_mkdir_p( $path );
    825 
    826         $newurl    = bp_core_avatar_url() . '/group-avatars/' . $group_id;
     820        $directory = 'group-avatars';
     821        $path      = bp_core_avatar_upload_path() . '/' . $directory . '/' . $group_id;
     822        $newbdir   = $path;
     823        $newurl    = bp_core_avatar_url() . '/' . $directory . '/' . $group_id;
    827824        $newburl   = $newurl;
    828         $newsubdir = '/group-avatars/' . $group_id;
     825        $newsubdir = '/' . $directory . '/' . $group_id;
    829826
    830827        /**
    831828         * Filters the avatar upload directory path for a given group.
    function groups_avatar_upload_dir( $group_id = 0 ) { 
    834831         *
    835832         * @param array $value Array of parts related to the groups avatar upload directory.
    836833         */
    837         return apply_filters( 'groups_avatar_upload_dir', array( 'path' => $path, 'url' => $newurl, 'subdir' => $newsubdir, 'basedir' => $newbdir, 'baseurl' => $newburl, 'error' => false ) );
     834        return apply_filters( 'groups_avatar_upload_dir', array(
     835                'path'    => $path,
     836                'url'     => $newurl,
     837                'subdir'  => $newsubdir,
     838                'basedir' => $newbdir,
     839                'baseurl' => $newburl,
     840                'error'   => false
     841        ) );
    838842}
    839843
    840844/** Group Member Status Checks ************************************************/
  • src/bp-members/bp-members-functions.php

    diff --git src/bp-members/bp-members-functions.php src/bp-members/bp-members-functions.php
    index 1a46340..01e9772 100644
    function bp_core_signup_avatar_upload_dir() { 
    21592159                return false;
    21602160        }
    21612161
    2162         $path  = bp_core_avatar_upload_path() . '/avatars/signups/' . $bp->signup->avatar_dir;
    2163         $newbdir = $path;
    2164 
    2165         if ( ! file_exists( $path ) ) {
    2166                 @wp_mkdir_p( $path );
    2167         }
    2168 
    2169         $newurl = bp_core_avatar_url() . '/avatars/signups/' . $bp->signup->avatar_dir;
    2170         $newburl = $newurl;
    2171         $newsubdir = '/avatars/signups/' . $bp->signup->avatar_dir;
     2162        $directory = 'avatars/signups';
     2163        $path      = bp_core_avatar_upload_path() . '/' . $directory . '/' . $bp->signup->avatar_dir;
     2164        $newbdir   = $path;
     2165        $newurl    = bp_core_avatar_url() . '/' . $directory . '/' . $bp->signup->avatar_dir;
     2166        $newburl   = $newurl;
     2167        $newsubdir = '/' . $directory . '/' . $bp->signup->avatar_dir;
    21722168
    21732169        /**
    21742170         * Filters the avatar storage directory for use during registration.
    function bp_core_signup_avatar_upload_dir() { 
    21832179                'subdir'  => $newsubdir,
    21842180                'basedir' => $newbdir,
    21852181                'baseurl' => $newburl,
    2186                 'error' => false
     2182                'error'   => false
    21872183        ) );
    21882184}
    21892185
  • src/bp-xprofile/bp-xprofile-functions.php

    diff --git src/bp-xprofile/bp-xprofile-functions.php src/bp-xprofile/bp-xprofile-functions.php
    index 16c1599..62c37ed 100644
    function xprofile_avatar_upload_dir( $directory = 'avatars', $user_id = 0 ) { 
    680680                $directory = 'avatars';
    681681        }
    682682
    683         $path    = bp_core_avatar_upload_path() . '/' . $directory. '/' . $user_id;
    684         $newbdir = $path;
    685 
    686         if ( ! file_exists( $path ) ) {
    687                 @wp_mkdir_p( $path );
    688         }
    689 
     683        $path      = bp_core_avatar_upload_path() . '/' . $directory. '/' . $user_id;
     684        $newbdir   = $path;
    690685        $newurl    = bp_core_avatar_url() . '/' . $directory. '/' . $user_id;
    691686        $newburl   = $newurl;
    692687        $newsubdir = '/' . $directory. '/' . $user_id;
  • tests/phpunit/assets/attachment-extensions.php

    diff --git tests/phpunit/assets/attachment-extensions.php tests/phpunit/assets/attachment-extensions.php
    index e69de29..117b456 100644
     
     1<?php
     2/**
     3 * The following implementations of BP_Attachment act as dummy plugins
     4 * for our unit tests
     5 */
     6class BP_Attachment_Extend extends BP_Attachment {
     7        public function __construct( $args = array() ) {
     8                return parent::__construct( $args );
     9        }
     10}
  • tests/phpunit/testcases/core/class-bp-attachment-avatar.php

    diff --git tests/phpunit/testcases/core/class-bp-attachment-avatar.php tests/phpunit/testcases/core/class-bp-attachment-avatar.php
    index e69de29..d719dd3 100644
     
     1<?php
     2
     3/**
     4 * @group core
     5 * @group avatars
     6 * @group bp_attachments
     7 * @group BP_Attachement_Avatar
     8 */
     9class BP_Tests_BP_Attachement_Avatar_TestCases extends BP_UnitTestCase {
     10        protected $displayed_user;
     11
     12        public function setUp() {
     13                parent::setUp();
     14                $bp = buddypress();
     15                $this->displayed_user = $bp->displayed_user;
     16                $bp->displayed_user = new stdClass;
     17        }
     18
     19        public function tearDown() {
     20                parent::tearDown();
     21                buddypress()->displayed_user = $this->displayed_user;
     22        }
     23
     24        public function max_filesize() {
     25                return 1000;
     26        }
     27
     28        private function clean_avatars( $type = 'user' ) {
     29                if ( 'user' === $type ) {
     30                        $avatar_dir = 'avatars';
     31                } elseif ( 'group' === $type ) {
     32                        $avatar_dir = 'group-avatars';
     33                }
     34
     35                $this->rrmdir( bp_core_avatar_upload_path() . '/' . $avatar_dir );
     36        }
     37
     38        private function rrmdir( $dir ) {
     39                $d = glob( $dir . '/*' );
     40
     41                if ( empty( $d ) ) {
     42                        return;
     43                }
     44
     45                foreach ( $d as $file ) {
     46                        if ( is_dir( $file ) ) {
     47                                $this->rrmdir( $file );
     48                        } else {
     49                                @unlink( $file );
     50                        }
     51                }
     52
     53                @rmdir( $dir );
     54        }
     55
     56        /**
     57         * @group upload
     58         */
     59        public function test_upload_user_avatar_no_error() {
     60                $reset_files = $_FILES;
     61                $reset_post = $_POST;
     62
     63                $u1 = $this->factory->user->create();
     64                buddypress()->displayed_user->id = $u1;
     65
     66                $avatar = BP_TESTS_DIR . 'assets/files/disc.png';
     67
     68                $tmp_name = wp_tempnam( $avatar );
     69
     70                copy( $avatar, $tmp_name );
     71
     72                // Upload the file
     73                $avatar_attachment = new BP_Attachment_Avatar();
     74                $_POST['action'] = $avatar_attachment->action;
     75                $_FILES[ $avatar_attachment->file_input ] = array(
     76                        'tmp_name' => $tmp_name,
     77                        'name'     => 'disc.png',
     78                        'type'     => 'image/png',
     79                        'error'    => 0,
     80                        'size'     => filesize( $avatar )
     81                );
     82
     83                $user_avatar = $avatar_attachment->upload( $_FILES, 'xprofile_avatar_upload_dir' );
     84
     85                $this->assertTrue( empty( $user_avatar['error'] ) );
     86
     87                // clean up!
     88                $this->clean_avatars();
     89                $_FILES = $reset_files;
     90                $_POST = $reset_post;
     91        }
     92
     93        /**
     94         * @group upload
     95         */
     96        public function test_upload_group_avatar_no_error() {
     97                $bp = buddypress();
     98                $reset_files = $_FILES;
     99                $reset_post = $_POST;
     100                $reset_current_group = $bp->groups->current_group;
     101
     102                $g = $this->factory->group->create();
     103
     104                $bp->groups->current_group = groups_get_group( array(
     105                        'group_id'        => $g,
     106                        'populate_extras' => true,
     107                ) );
     108
     109                $avatar = BP_TESTS_DIR . 'assets/files/disc.png';
     110
     111                $tmp_name = wp_tempnam( $avatar );
     112
     113                copy( $avatar, $tmp_name );
     114
     115                // Upload the file
     116                $avatar_attachment = new BP_Attachment_Avatar();
     117                $_POST['action'] = $avatar_attachment->action;
     118                $_FILES[ $avatar_attachment->file_input ] = array(
     119                        'tmp_name' => $tmp_name,
     120                        'name'     => 'disc.png',
     121                        'type'     => 'image/png',
     122                        'error'    => 0,
     123                        'size'     => filesize( $avatar )
     124                );
     125
     126                $group_avatar = $avatar_attachment->upload( $_FILES, 'groups_avatar_upload_dir' );
     127
     128                $this->assertTrue( empty( $group_avatar['error'] ) );
     129
     130                // clean up!
     131                $this->clean_avatars( 'group' );
     132                $bp->groups->current_group = $reset_current_group;
     133                $_FILES = $reset_files;
     134                $_POST = $reset_post;
     135        }
     136
     137        /**
     138         * @group upload
     139         */
     140        public function test_upload_user_avatar_file_size_error() {
     141                $reset_files = $_FILES;
     142                $reset_post = $_POST;
     143
     144                $u1 = $this->factory->user->create();
     145                buddypress()->displayed_user->id = $u1;
     146
     147                $avatar = BP_TESTS_DIR . 'assets/files/disc.png';
     148
     149                $tmp_name = wp_tempnam( $avatar );
     150
     151                copy( $avatar, $tmp_name );
     152
     153                add_filter( 'bp_core_avatar_original_max_filesize', array( $this, 'max_filesize' ) );
     154
     155                // Upload the file
     156                $avatar_attachment = new BP_Attachment_Avatar();
     157
     158                $_POST['action'] = $avatar_attachment->action;
     159                $_FILES[ $avatar_attachment->file_input ] = array(
     160                        'tmp_name' => $tmp_name,
     161                        'name'     => 'disc.png',
     162                        'type'     => 'image/png',
     163                        'error'    => 0,
     164                        'size'     => filesize( $avatar )
     165                );
     166
     167                $user_avatar = $avatar_attachment->upload( $_FILES, 'xprofile_avatar_upload_dir' );
     168
     169                remove_filter( 'bp_core_avatar_original_max_filesize', array( $this, 'max_filesize' ) );
     170
     171                $this->assertFalse( empty( $user_avatar['error'] ) );
     172
     173                // clean up!
     174                $_FILES = $reset_files;
     175                $_POST = $reset_post;
     176        }
     177
     178        /**
     179         * @group upload
     180         */
     181        public function test_upload_user_avatar_file_type_error() {
     182                $reset_files = $_FILES;
     183                $reset_post = $_POST;
     184
     185                $u1 = $this->factory->user->create();
     186                buddypress()->displayed_user->id = $u1;
     187
     188                $avatar = BP_TESTS_DIR . 'assets/files/buddypress_logo.pdf';
     189
     190                $tmp_name = wp_tempnam( $avatar );
     191
     192                copy( $avatar, $tmp_name );
     193
     194                // Upload the file
     195                $avatar_attachment = new BP_Attachment_Avatar();
     196                $_POST['action'] = $avatar_attachment->action;
     197                $_FILES[ $avatar_attachment->file_input ] = array(
     198                        'tmp_name' => $tmp_name,
     199                        'name'     => 'buddypress_logo.pdf',
     200                        'type'     => 'application/pdf',
     201                        'error'    => 0,
     202                        'size'     => filesize( $avatar )
     203                );
     204
     205                $user_avatar = $avatar_attachment->upload( $_FILES, 'xprofile_avatar_upload_dir' );
     206
     207                $this->assertFalse( empty( $user_avatar['error'] ) );
     208
     209                // clean up!
     210                $_FILES = $reset_files;
     211                $_POST = $reset_post;
     212        }
     213
     214        /**
     215         * @group crop
     216         */
     217        public function test_crop_avatar() {
     218                $avatar = BP_TESTS_DIR . 'assets/files/buddypress-book.jpg';
     219                $pdf    = BP_TESTS_DIR . 'assets/files/buddypress_logo.pdf';
     220
     221                $u1 = $this->factory->user->create();
     222
     223                $upload_dir = xprofile_avatar_upload_dir( 'avatars', $u1 );
     224
     225                wp_mkdir_p( $upload_dir['path'] );
     226
     227                copy( $avatar, $upload_dir['path'] . '/buddypress-book.jpg' );
     228                copy( $pdf, $upload_dir['path'] . '/buddypress_logo.pdf' );
     229
     230                $crop_args = array(
     231                        'object'        => 'user',
     232                        'avatar_dir'    => 'avatars',
     233                        'item_id'       => $u1,
     234                        'original_file' => '/avatars/' . $u1 . '/buddypress-book.jpg',
     235                );
     236
     237                $avatar_attachment = new BP_Attachment_Avatar();
     238                $cropped = $avatar_attachment->crop( $crop_args );
     239
     240                $this->assertTrue( ! empty( $cropped['full'] ) && ! is_wp_error( $cropped['full'] ) );
     241
     242                $crop_args['original_file'] = '/avatars/' . $u1 . '/buddypress_logo.pdf';
     243
     244                $cropped = $avatar_attachment->crop( $crop_args );
     245                $this->assertTrue( is_wp_error( $cropped['full'] ) );
     246
     247                // Clean up
     248                $this->clean_avatars();
     249        }
     250}
  • tests/phpunit/testcases/core/class-bp-attachment.php

    diff --git tests/phpunit/testcases/core/class-bp-attachment.php tests/phpunit/testcases/core/class-bp-attachment.php
    index e69de29..2b97b2f 100644
     
     1<?php
     2
     3include_once BP_TESTS_DIR . '/assets/attachment-extensions.php';
     4
     5/**
     6 * @group bp_attachments
     7 * @group BP_Attachement
     8 */
     9class BP_Tests_BP_Attachment_TestCases extends BP_UnitTestCase {
     10
     11        private function clean_files( $basedir = 'attachment_base_dir' ) {
     12                $upload_dir = bp_upload_dir();
     13
     14                $this->rrmdir( $upload_dir['basedir'] . '/' . $basedir );
     15        }
     16
     17        private function rrmdir( $dir ) {
     18                $d = glob( $dir . '/*' );
     19
     20                if ( empty( $d ) ) {
     21                        return;
     22                }
     23
     24                foreach ( $d as $file ) {
     25                        if ( is_dir( $file ) ) {
     26                                $this->rrmdir( $file );
     27                        } else {
     28                                @unlink( $file );
     29                        }
     30                }
     31
     32                @rmdir( $dir );
     33        }
     34
     35        public function test_construct_missing_required_parameter() {
     36                $reset_files = $_FILES;
     37                $reset_post = $_POST;
     38
     39                $_FILES['file'] = array(
     40                        'name'     => 'disc.png',
     41                        'type'     => 'image/png',
     42                        'error'    => 0,
     43                        'size'     => 10000
     44                );
     45
     46                $attachment_class = new BP_Attachment_Extend();
     47                $upload = $attachment_class->upload( $_FILES );
     48
     49                $this->assertTrue( empty( $upload ) );
     50
     51                $_FILES = $reset_files;
     52                $_POST = $reset_post;
     53        }
     54
     55        public function test_set_upload_dir() {
     56                $upload_dir = bp_upload_dir();
     57
     58                $attachment_class = new BP_Attachment_Extend( array(
     59                        'action'     => 'attachment_action',
     60                        'file_input' => 'attachment_file_input'
     61                ) );
     62
     63                $this->assertSame( $attachment_class->upload_dir, bp_upload_dir() );
     64
     65                $attachment_class = new BP_Attachment_Extend( array(
     66                        'action'     => 'attachment_action',
     67                        'file_input' => 'attachment_file_input',
     68                        'base_dir'   => 'attachment_base_dir',
     69                ) );
     70
     71                $this->assertTrue( file_exists( $upload_dir['basedir'] . '/attachment_base_dir'  ) );
     72
     73                // clean up
     74                $this->clean_files();
     75        }
     76
     77        /**
     78         * @group upload
     79         */
     80        public function test_upload() {
     81                $reset_files = $_FILES;
     82                $reset_post = $_POST;
     83
     84                $file = BP_TESTS_DIR . 'assets/files/disc.png';
     85
     86                $tmp_name = wp_tempnam( $file );
     87
     88                copy( $file, $tmp_name );
     89
     90                $attachment_class = new BP_Attachment_Extend( array(
     91                        'action'                => 'attachment_action',
     92                        'file_input'            => 'attachment_file_input',
     93                        'base_dir'                  => 'attachment_base_dir',
     94                        'original_max_filesize' => 10000,
     95                ) );
     96
     97                $_POST['action'] = $attachment_class->action;
     98                $_FILES[ $attachment_class->file_input ] = array(
     99                        'tmp_name' => $tmp_name,
     100                        'name'     => 'disc.png',
     101                        'type'     => 'image/png',
     102                        'error'    => 0,
     103                        'size'     => filesize( $file )
     104                );
     105
     106                // Error: file size
     107                $upload = $attachment_class->upload( $_FILES );
     108                $this->assertFalse( empty( $upload['error'] ) );
     109
     110                $attachment_class->allowed_mime_types    = array( 'pdf' );
     111                $attachment_class->original_max_filesize = false;
     112
     113                // Error: file type
     114                $upload = $attachment_class->upload( $_FILES );
     115                $this->assertFalse( empty( $upload['error'] ) );
     116
     117                $attachment_class->allowed_mime_types = array();
     118
     119                // Success
     120                $upload = $attachment_class->upload( $_FILES );
     121                $this->assertTrue( empty( $upload['error'] ) );
     122
     123                // clean up!
     124                $_FILES = $reset_files;
     125                $_POST = $reset_post;
     126                $this->clean_files();
     127        }
     128
     129        /**
     130         * @group crop
     131         */
     132        public function test_crop_image() {
     133                $image = BP_TESTS_DIR . 'assets/files/buddypress-book.jpg';
     134
     135                $crop_args = array(
     136                        'original_file' => $image,
     137                        'crop_x'        => 0,
     138                        'crop_y'        => 0,
     139                        'crop_w'        => 150,
     140                        'crop_h'        => 150,
     141                        'dst_w'         => 150,
     142                        'dst_h'         => 150,
     143                );
     144
     145                $attachment_class = new BP_Attachment_Extend( array(
     146                        'action'                => 'attachment_action',
     147                        'file_input'            => 'attachment_file_input',
     148                        'base_dir'                  => 'attachment_base_dir',
     149                ) );
     150                $cropped = $attachment_class->crop( $crop_args );
     151
     152                // Image must come from the upload basedir
     153                $this->assertTrue( is_wp_error( $cropped ) );
     154
     155                $crop_args['original_file'] = $attachment_class->upload_path . '/buddypress-book.jpg';
     156
     157                // Move to the base upload dir
     158                copy( $image, $crop_args['original_file'] );
     159
     160                // Image must stay in the upload basedir
     161                $crop_args['dst_file'] = BP_TESTS_DIR . 'assets/files/error.jpg';
     162                $cropped = $attachment_class->crop( $crop_args );
     163
     164                // Image must stay in the upload basedir
     165                $this->assertTrue( is_wp_error( $cropped ) );
     166
     167                unset( $crop_args['dst_file'] );
     168
     169                $cropped = $attachment_class->crop( $crop_args );
     170                $this->assertFalse( is_wp_error( $cropped ) );
     171
     172                // clean up!
     173                $this->clean_files();
     174        }
     175}
  • tests/phpunit/testcases/core/functions.php

    diff --git tests/phpunit/testcases/core/functions.php tests/phpunit/testcases/core/functions.php
    index 1ab3b45..d165739 100644
    class BP_Tests_Core_Functions extends BP_UnitTestCase { 
    572572                        date_default_timezone_set( $tz_backup );
    573573                }
    574574        }
     575
     576        /**
     577         * @group bp_attachments
     578         * @group bp_upload_dir
     579         */
     580        public function test_bp_upload_dir_ms() {
     581                if ( ! is_multisite() ) {
     582                        return;
     583                }
     584
     585                $expected_upload_dir = wp_upload_dir();
     586
     587                $b = $this->factory->blog->create();
     588
     589                switch_to_blog( $b );
     590
     591                $tested_upload_dir = bp_upload_dir();
     592
     593                restore_current_blog();
     594
     595                $this->assertSame( $expected_upload_dir, $tested_upload_dir );
     596        }
    575597}