Making WordPress.org

Changeset 12086


Ignore:
Timestamp:
09/26/2022 09:59:32 PM (2 years ago)
Author:
coffee2code
Message:

Photo Directory, Uploads: Limit photo uploads to being between 1 and 20 MB in size.

  • Add class constants for default min/max limits, and getters with filters.
  • Add MAX_FILE_SIZE hidden input to upload form.
  • Add client-side JS enforcement of limits.
  • Add server-side enforcement of limits.
Location:
sites/trunk/wordpress.org/public_html/wp-content/plugins/photo-directory
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • sites/trunk/wordpress.org/public_html/wp-content/plugins/photo-directory/assets/js/submit.js

    r11679 r12086  
    2424    }
    2525
     26    const photo_upload_field = document.getElementById('ug_photo');
     27
     28    if ( photo_upload_field ) {
     29        // Add custom validation for upload file size.
     30        photo_upload_field.addEventListener( 'change', e => {
     31            photoShowFileSizeError( photo_upload_field );
     32        } );
     33    }
     34
     35    // Check validity of form fields on submission.
    2636    photo_upload_form.addEventListener( 'submit', e => {
     37        photoShowFileSizeError( photo_upload_field );
    2738        if ( photo_upload_form.checkValidity() ) {
    2839            photo_upload_submit.disabled = true;
     
    3243}
    3344
    34 photoSubmitLoaded();
     45/**
     46 * Checks if the file selected via the file input field object is within an
     47 * acceptable file size range and sets custom validity message accordingly.
     48 *
     49 * An appropriate error message is defined if the file is too large or too small.
     50 * If there is no file selected, or the file is of sufficient size, then any
     51 * existing custom validity message is cleared.
     52 *
     53 * @param {Object} field - The HTML file input field object.
     54 */
     55function photoCheckFileSize( field ) {
     56    const MAX_SIZE = PhotoDir.max_file_size; // In bytes.
     57    const MIN_SIZE = PhotoDir.min_file_size; // In bytes.
     58
     59    const files = field.files;
     60
     61    if ( files.length > 0 ) {
     62        const file_size = files[0].size;
     63
     64        // Note: If changing the error message for either case, ensure the "// Don't show error message..."
     65        // regex in `photoShowFileSizeError()` still matches them both.
     66        if ( file_size >= MAX_SIZE ) {
     67            field.setCustomValidity( PhotoDir.err_file_too_large );
     68            return;
     69        } else if ( file_size <= MIN_SIZE ) {
     70            field.setCustomValidity( PhotoDir.err_file_too_small );
     71            return;
     72        }
     73    }
     74
     75    // No custom constraint violation.
     76    field.setCustomValidity('');
     77}
     78
     79/**
     80 * Handles the display of the error message for the file upload input.
     81 *
     82 * If the file input field has a file selected, it is checked to see if it is
     83 * too large or too small. An appropriate error message is shown in either case.
     84 * If no file is selected, or the file is of sufficient size, then no error is
     85 * shown and any existing error for the field is cleared.
     86 *
     87 * This pseudo-mimics and also works around the jQuery Validation handling that
     88 * doesn't play well with custom error reporting like this.
     89 *
     90 * @param {Object} field - The HTML file input field object.
     91 */
     92function photoShowFileSizeError( field ) {
     93    // Check field for file size validation errors.
     94    photoCheckFileSize( field );
     95
     96    const errorMessage = field.validationMessage;
     97    const errorId = `${field.id}-error`;
     98    let errorEl = document.getElementById( errorId );
     99
     100    // Don't show error message for any other error.
     101    if ( ! errorMessage || ! field.validity.customError || ! / MB\.$/.test( errorMessage ) ) {
     102        errorEl?.remove();
     103        return;
     104    }
     105
     106    if ( ! errorEl ) {
     107        errorEl = document.createElement( 'label' );
     108        field.after( errorEl );
     109    }
     110
     111    errorEl.setAttribute( 'id', errorId );
     112    errorEl.setAttribute( 'class', 'custom-error' );
     113    errorEl.setAttribute( 'for', field.id );
     114    errorEl.removeAttribute( 'style' );
     115    errorEl.innerHTML = errorMessage;
     116}
     117
     118document.addEventListener( 'DOMContentLoaded', () => {
     119    photoSubmitLoaded();
     120} );
  • sites/trunk/wordpress.org/public_html/wp-content/plugins/photo-directory/inc/uploads.php

    r12060 r12086  
    2626     */
    2727    const MAX_PENDING_SUBMISSIONS = 5;
     28
     29    /**
     30     * The default maximum allowed file size in megabytes.
     31     *
     32     * @see `get_maximum_photo_file_size()` for actually retrieving the maximum
     33     * photo size, as it may be filtered.
     34     * @var int|float
     35     */
     36    const MAX_PHOTO_FILE_SIZE = 20;
     37
     38    /**
     39     * The default minimum allowed file size in megabytes.
     40     *
     41     * @see `get_minimum_photo_file_size()` for actually retrieving the minimum
     42     * photo size, as it may be filtered.
     43     * @var int|float
     44     */
     45    const MIN_PHOTO_FILE_SIZE = 1;
    2846
    2947    /**
     
    179197
    180198    /**
     199     * Returns the maximum allowed file size.
     200     *
     201     * @param bool $in_bytes Should the value returned be in bytes instead of megabytes?
     202     * @return int|float Maximum allowed file size. Returns value in bytes by default, but
     203     *             will return value in megabytes if `$as_bytes` is false.
     204     */
     205    public static function get_maximum_photo_file_size( $as_bytes = true ) {
     206        /**
     207         * Filters the maximum allowed photo file size, in megabytes.
     208         *
     209         * @param int The maximum allowed photo file size, in megabytes.
     210         */
     211        $max_file_size = apply_filters( 'wporg_photos_max_photo_file_size', self::MAX_PHOTO_FILE_SIZE );
     212
     213        if ( $as_bytes ) {
     214            $max_file_size = round( $max_file_size * 1024 * 1024 );
     215        }
     216
     217        return $max_file_size;
     218    }
     219
     220    /**
     221     * Returns the minimum allowed file size.
     222     *
     223     * @param bool $in_bytes Should the value returned be in bytes instead of megabytes?
     224     * @return int|float Minimum allowed file size. Returns value in bytes by default, but
     225     *             will return value in megabytes if `$as_bytes` is false.
     226     */
     227    public static function get_minimum_photo_file_size( $as_bytes = true ) {
     228        /**
     229         * Filters the minimum allowed photo file size, in megabytes.
     230         *
     231         * @param int The minimum allowed photo file size, in megabytes.
     232         */
     233        $min_file_size = apply_filters( 'wporg_photos_min_photo_file_size', self::MIN_PHOTO_FILE_SIZE );
     234
     235        if ( $as_bytes ) {
     236            $min_file_size = round( $min_file_size * 1024 * 1024 );
     237        }
     238
     239        return $min_file_size;
     240    }
     241
     242    /**
    181243     * Enqueues scripts for the photo submit page.
    182244     */
     
    184246        if ( is_page( self::SUBMIT_PAGE_SLUG ) ) {
    185247            wp_enqueue_script( 'wporg-photos-submit', plugins_url( 'assets/js/submit.js', dirname( __FILE__ ) ), [], '1', true );
     248
     249            wp_localize_script(
     250                'wporg-photos-submit',
     251                'PhotoDir',
     252                [
     253                    'err_file_too_large'    => sprintf(
     254                        __( 'The selected file cannot be larger than %s MB.', 'wporg-photos' ),
     255                        self::get_maximum_photo_file_size( false )
     256                    ),
     257                    'err_file_too_small'    => sprintf(
     258                        __( 'The selected file must be larger than %s MB.', 'wporg-photos' ),
     259                        self::get_minimum_photo_file_size( false )
     260                    ),
     261                    'max_file_size' => self::get_maximum_photo_file_size(),
     262                    'min_file_size' => self::get_minimum_photo_file_size(),
     263                ]
     264            );
    186265        }
    187266    }
     
    290369                    $rejection = __( 'Your submission appears to be a duplicate of something uploaded before.', 'wporg-photos' );
    291370                    break;
     371                case 'file-too-large':
     372                    $rejection = sprintf(
     373                        __( 'The file size for your submission is too large. Please submit a photo smaller than %d MB in size.', 'wporg-photos' ),
     374                        self::get_maximum_photo_file_size( false )
     375                    );
     376                    break;
     377                case 'file-too-small':
     378                    $rejection = sprintf(
     379                        __( 'The file size for your submission is too small. Please submit a photo larger than %d MB in size.', 'wporg-photos' ),
     380                        self::get_minimum_photo_file_size( false )
     381                    );
     382                    break;
    292383                case 'insufficient-dimension':
    293384                    $rejection = sprintf( __( 'Your photo must have a width and height of at least %d pixels each.', 'wporg-photos' ), self::get_minimum_photo_dimension() );
     
    422513     */
    423514    protected static function validate_upload_form() {
     515        if ( ! empty( $_FILES['files']['error'][0] ) ) {
     516            switch ( $_FILES['files']['error'][0] ) {
     517                case UPLOAD_ERR_INI_SIZE:
     518                case UPLOAD_ERR_FORM_SIZE:
     519                    return 'file-too-large';
     520            }
     521        }
     522
    424523        if ( empty( $_FILES['files']['tmp_name'][0] ) ) {
    425524            return 'no-file-uploaded';
     
    428527        if ( ! empty( $_FILES['files']['tmp_name'] ) && count( $_FILES['files']['tmp_name'] ) > 1 ) {
    429528            return 'too-many-files';
     529        }
     530
     531        // Check file size.
     532        if ( ! empty( $_FILES['files']['size'][0] ) ) {
     533            $file_size = $_FILES['files']['size'][0];
     534            // Check if file is too large.
     535            //   (This is actually a fallback check in the event the MAX_FILE_SIZE
     536            //   directive in the upload form is missing or has been tampered with.
     537            //   Otherwise, PHP will already have invalidated a too-large upload.)
     538            if ( $file_size >= self::get_maximum_photo_file_size() ) {
     539                return 'file-too-large';
     540            }
     541            // Check if file is too small.
     542            if ( $file_size <= self::get_minimum_photo_file_size() ) {
     543                return 'file-too-small';
     544            }
    430545        }
    431546
     
    727842                $content .= '[input type="hidden" name="post_title" value=""]' . "\n";
    728843                $content .= sprintf(
     844                    '[input type="hidden" name="MAX_FILE_SIZE" value="%s"]' . "\n",
     845                    self::get_maximum_photo_file_size()
     846                );
     847                $content .= sprintf(
    729848                    '[input type="file" name="ug_photo" id="ug_photo" description="%s" required="true" aria-required="true"]' . "\n",
    730849                    esc_attr( __( 'Photo', 'wporg-photos' ) )
Note: See TracChangeset for help on using the changeset viewer.