new free features!', 'tuxedo-big-file-uploads' ); ?>
capability ) ) {
wp_send_json_error();
}
update_user_option( get_current_user_id(), 'bfu_notice_dismissed', 1 );
wp_send_json_success();
}
/**
* AJAX endpoint to dismiss upgrade notice.
*
* @since 2.0
*/
public function ajax_upgrade_dismiss() {
if ( ! current_user_can( $this->capability ) ) {
wp_send_json_error();
}
update_user_option( get_current_user_id(), 'bfu_upgrade_notice_dismissed', 1 );
wp_send_json_success();
}
/**
* AJAX endpoint to dismiss subscribe notice.
*
* @since 2.0
*/
public function ajax_subscribe_dismiss() {
if ( ! current_user_can( $this->capability ) ) {
wp_send_json_error();
}
update_user_option( get_current_user_id(), 'bfu_subscribe_notice_dismissed', 1 );
wp_send_json_success();
}
/**
* AJAX chunk receiver.
*
* Ajax callback for plupload to handle chunked uploads.
* Based on code by Davit Barbakadze
* https://gist.github.com/jayarjo/5846636
*
* Mirrors /wp-admin/async-upload.php
*
* @todo Figure out a way to stop furthur chunks from uploading when there is an error in gutenberg
*
* @since 1.2.0
*/
public function ajax_chunk_receiver() {
/** Check that we have an upload and there are no errors. */
if ( empty( $_FILES ) || $_FILES['async-upload']['error'] ) {
/** Failed to move uploaded file. */
die();
}
/** Authenticate user. */
if ( ! is_user_logged_in() || ! current_user_can( 'upload_files' ) ) {
wp_die( __( 'Sorry, you are not allowed to upload files.' ) );
}
check_admin_referer( 'media-form' );
/** Check and get file chunks. */
$chunk = isset( $_REQUEST['chunk'] ) ? intval( $_REQUEST['chunk'] ) : 0; //zero index
$current_part = $chunk + 1;
$chunks = isset( $_REQUEST['chunks'] ) ? intval( $_REQUEST['chunks'] ) : 0;
/** Get file name and path + name. */
$fileName = isset( $_REQUEST['name'] ) ? $_REQUEST['name'] : $_FILES['async-upload']['name'];
$bfu_temp_dir = apply_filters( 'bfu_temp_dir', WP_CONTENT_DIR . '/bfu-temp' );
//only run on first chunk
if ( $chunk === 0 ) {
// Create temp directory if it doesn't exist
if ( ! @is_dir( $bfu_temp_dir ) ) {
wp_mkdir_p( $bfu_temp_dir );
}
// Protect temp directory from browsing.
$index_pathname = $bfu_temp_dir . '/index.php';
if ( ! file_exists( $index_pathname ) ) {
$file = fopen( $index_pathname, 'w' );
if ( false !== $file ) {
fwrite( $file, "get_upload_limit();
if ( file_exists( $filePath ) && filesize( $filePath ) + filesize( $_FILES['async-upload']['tmp_name'] ) > $tuxbfu_max_upload_size ) {
if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
error_log( "BFU: File size limit exceeded." );
}
if ( ! $chunks || $chunk == $chunks - 1 ) {
@unlink( $filePath );
if ( ! isset( $_REQUEST['short'] ) || ! isset( $_REQUEST['type'] ) ) {
echo wp_json_encode( array(
'success' => false,
'data' => array(
'message' => __( 'The file size has exceeded the maximum file size setting.', 'tuxedo-big-file-uploads' ),
'filename' => $fileName,
),
) );
wp_die();
} else {
status_header( 202 );
printf(
'
%s %s %s
',
sprintf(
'',
__( 'Dismiss' )
),
sprintf(
/* translators: %s: Name of the file that failed to upload. */
__( '“%s” has failed to upload.' ),
esc_html( $fileName )
),
__( 'The file size has exceeded the maximum file size setting.', 'tuxedo-big-file-uploads' )
);
exit;
}
}
die();
}
/** Open temp file. */
if ( $chunk == 0 ) {
$out = @fopen( $filePath, 'wb');
} elseif ( is_writable( $filePath ) ) { //
$out = @fopen( $filePath, 'ab' );
} else {
$out = false;
}
if ( $out ) {
/** Read binary input stream and append it to temp file. */
$in = @fopen( $_FILES['async-upload']['tmp_name'], 'rb' );
if ( $in ) {
while ( $buff = fread( $in, 4096 ) ) {
fwrite( $out, $buff );
}
} else {
/** Failed to open input stream. */
/** Attempt to clean up unfinished output. */
@fclose( $out );
@unlink( $filePath );
error_log( "BFU: Error reading uploaded part $current_part of $chunks." );
if ( ! isset( $_REQUEST['short'] ) || ! isset( $_REQUEST['type'] ) ) {
echo wp_json_encode(
array(
'success' => false,
'data' => array(
'message' => sprintf( __( 'There was an error reading uploaded part %d of %d.', 'tuxedo-big-file-uploads' ), $current_part, $chunks ),
'filename' => esc_html( $fileName ),
),
)
);
wp_die();
} else {
status_header( 202 );
printf(
'
%s %s %s
',
sprintf(
'',
__( 'Dismiss' )
),
sprintf(
/* translators: %s: Name of the file that failed to upload. */
__( '“%s” has failed to upload.' ),
esc_html( $fileName )
),
sprintf( __( 'There was an error reading uploaded part %d of %d.', 'tuxedo-big-file-uploads' ), $current_part, $chunks )
);
exit;
}
}
@fclose( $in );
@fclose( $out );
@unlink( $_FILES['async-upload']['tmp_name'] );
} else {
/** Failed to open output stream. */
error_log( "BFU: Failed to open output stream $filePath to write part $current_part of $chunks." );
if ( ! isset( $_REQUEST['short'] ) || ! isset( $_REQUEST['type'] ) ) {
echo wp_json_encode(
array(
'success' => false,
'data' => array(
'message' => sprintf( __( 'There was an error opening the temp file %s for writing. Available temp directory space may be exceeded or the temp file was cleaned up before the upload completed.', 'tuxedo-big-file-uploads' ), esc_html( $filePath ) ),
'filename' => esc_html( $fileName ),
),
)
);
wp_die();
} else {
status_header( 202 );
printf(
'
%s %s %s
',
sprintf(
'',
__( 'Dismiss' )
),
sprintf(
/* translators: %s: Name of the file that failed to upload. */
__( '“%s” has failed to upload.' ),
esc_html( $fileName )
),
sprintf( __( 'There was an error opening the temp file %s for writing. Available temp directory space may be exceeded or the temp file was cleaned up before the upload completed.', 'tuxedo-big-file-uploads' ), esc_html( $filePath ) )
);
exit;
}
}
/** Check if file has finished uploading all parts. */
if ( ! $chunks || $chunk == $chunks - 1 ) {
//debugging
if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
$size = file_exists( $filePath ) ? size_format( filesize( $filePath ), 3 ) : '0 B';
error_log( "BFU: Completing \"$fileName\" upload with a $size final size." );
}
/** Recreate upload in $_FILES global and pass off to WordPress. */
$_FILES['async-upload']['tmp_name'] = $filePath;
$_FILES['async-upload']['name'] = $fileName;
$_FILES['async-upload']['size'] = filesize( $_FILES['async-upload']['tmp_name'] );
$wp_filetype = wp_check_filetype_and_ext( $_FILES['async-upload']['tmp_name'], $_FILES['async-upload']['name'] );
$_FILES['async-upload']['type'] = $wp_filetype['type'];
header( 'Content-Type: text/plain; charset=' . get_option( 'blog_charset' ) );
if ( ! isset( $_REQUEST['short'] ) || ! isset( $_REQUEST['type'] ) ) { //ajax like media uploader in modal
// Compatibility with Easy Digital Downloads plugin.
if ( function_exists( 'edd_change_downloads_upload_dir' ) ) {
global $pagenow;
$pagenow = 'async-upload.php';
edd_change_downloads_upload_dir();
}
send_nosniff_header();
nocache_headers();
$this->wp_ajax_upload_attachment();
die( '0' );
} else { //non-ajax like add new media page
$post_id = 0;
if ( isset( $_REQUEST['post_id'] ) ) {
$post_id = absint( $_REQUEST['post_id'] );
if ( ! get_post( $post_id ) || ! current_user_can( 'edit_post', $post_id ) )
$post_id = 0;
}
$id = media_handle_upload( 'async-upload', $post_id, [], [ 'action' => 'wp_handle_sideload', 'test_form' => false ] );
if ( is_wp_error( $id ) ) {
printf(
'
%s %s %s
',
sprintf(
'',
__( 'Dismiss' )
),
sprintf(
/* translators: %s: Name of the file that failed to upload. */
__( '“%s” has failed to upload.' ),
esc_html( $_FILES['async-upload']['name'] )
),
esc_html( $id->get_error_message() )
);
exit;
}
if ( $_REQUEST['short'] ) {
// Short form response - attachment ID only.
echo $id;
} else {
// Long form response - big chunk of HTML.
$type = $_REQUEST['type'];
/**
* Filters the returned ID of an uploaded attachment.
*
* The dynamic portion of the hook name, `$type`, refers to the attachment type.
*
* Possible hook names include:
*
* - `async_upload_audio`
* - `async_upload_file`
* - `async_upload_image`
* - `async_upload_video`
*
* @since 2.5.0
*
* @param int $id Uploaded attachment ID.
*/
echo apply_filters( "async_upload_{$type}", $id );
}
}
}
die();
}
/**
* Copied from wp-admin/includes/ajax-actions.php because we have to override the args for
* the media_handle_upload function. As of WP 6.0.1
*/
function wp_ajax_upload_attachment() {
check_ajax_referer( 'media-form' );
/*
* This function does not use wp_send_json_success() / wp_send_json_error()
* as the html4 Plupload handler requires a text/html content-type for older IE.
* See https://core.trac.wordpress.org/ticket/31037
*/
if ( ! current_user_can( 'upload_files' ) ) {
echo wp_json_encode(
array(
'success' => false,
'data' => array(
'message' => __( 'Sorry, you are not allowed to upload files.' ),
'filename' => esc_html( $_FILES['async-upload']['name'] ),
),
)
);
wp_die();
}
if ( isset( $_REQUEST['post_id'] ) ) {
$post_id = $_REQUEST['post_id'];
if ( ! current_user_can( 'edit_post', $post_id ) ) {
echo wp_json_encode(
array(
'success' => false,
'data' => array(
'message' => __( 'Sorry, you are not allowed to attach files to this post.' ),
'filename' => esc_html( $_FILES['async-upload']['name'] ),
),
)
);
wp_die();
}
} else {
$post_id = null;
}
$post_data = ! empty( $_REQUEST['post_data'] ) ? _wp_get_allowed_postdata( _wp_translate_postdata( false, (array) $_REQUEST['post_data'] ) ) : array();
if ( is_wp_error( $post_data ) ) {
wp_die( $post_data->get_error_message() );
}
// If the context is custom header or background, make sure the uploaded file is an image.
if ( isset( $post_data['context'] ) && in_array( $post_data['context'], array( 'custom-header', 'custom-background' ), true ) ) {
$wp_filetype = wp_check_filetype_and_ext( $_FILES['async-upload']['tmp_name'], $_FILES['async-upload']['name'] );
if ( ! wp_match_mime_types( 'image', $wp_filetype['type'] ) ) {
echo wp_json_encode(
array(
'success' => false,
'data' => array(
'message' => __( 'The uploaded file is not a valid image. Please try again.' ),
'filename' => esc_html( $_FILES['async-upload']['name'] ),
),
)
);
wp_die();
}
}
//this is the modded function from wp-admin/includes/ajax-actions.php
$attachment_id = media_handle_upload( 'async-upload', $post_id, $post_data, [ 'action' => 'wp_handle_sideload', 'test_form' => false ] );
if ( is_wp_error( $attachment_id ) ) {
echo wp_json_encode(
array(
'success' => false,
'data' => array(
'message' => $attachment_id->get_error_message(),
'filename' => esc_html( $_FILES['async-upload']['name'] ),
),
)
);
wp_die();
}
if ( isset( $post_data['context'] ) && isset( $post_data['theme'] ) ) {
if ( 'custom-background' === $post_data['context'] ) {
update_post_meta( $attachment_id, '_wp_attachment_is_custom_background', $post_data['theme'] );
}
if ( 'custom-header' === $post_data['context'] ) {
update_post_meta( $attachment_id, '_wp_attachment_is_custom_header', $post_data['theme'] );
}
}
$attachment = wp_prepare_attachment_for_js( $attachment_id );
if ( ! $attachment ) {
wp_die();
}
echo wp_json_encode(
array(
'success' => true,
'data' => $attachment,
)
);
wp_die();
}
/**
* Return the maximum upload limit in bytes for the current user.
*
* @since 2.0
*
* @return integer
*/
function get_upload_limit() {
$settings = $this->get_settings();
if ( $settings['by_role'] && is_user_logged_in() ) {
$limit = 0;
$user = wp_get_current_user();
foreach ( (array) $user->roles as $role ) {
if ( isset( $settings['limits'][ $role ]['bytes'] ) && $settings['limits'][ $role ]['bytes'] > $limit ) { //choose the highest limit for the roles they have.
$limit = $settings['limits'][ $role ]['bytes'];
}
}
if ( $limit ) {
return $limit;
} else {
return $settings['limits']['all']['bytes'];
}
} else {
return $settings['limits']['all']['bytes'];
}
}
/**
* Return a cleaned up settings array with defaults if needed.
*
* @since 2.0
*
* @param false $format
*
* @return array
*/
function get_settings( $format = false ) {
$settings = get_site_option( 'tuxbfu_settings' );
if ( ! is_array( $settings ) ) {
$settings = [];
}
if ( ! isset( $settings['by_role'] ) ) {
$settings['by_role'] = false;
}
if ( ! isset( $settings['limits']['all']['bytes'] ) ) {
$old_max_upload_size = get_site_option( 'tuxbfu_max_upload_size' );
if ( $old_max_upload_size ) {
$settings['limits']['all']['bytes'] = $old_max_upload_size * MB_IN_BYTES;
} elseif ( $old_max_upload_size === 0 ) {
$settings['limits']['all']['bytes'] = GB_IN_BYTES * 5; //default to 5GB if they had unlimited set before
} else {
$settings['limits']['all']['bytes'] = $this->max_upload_size;
}
}
if ( ! isset( $settings['limits']['all']['format'] ) ) {
$settings['limits']['all']['format'] = $settings['limits']['all']['bytes'] >= GB_IN_BYTES ? 'GB' : 'MB';
}
foreach ( wp_roles()->roles as $role_key => $role ) {
if ( isset( $role['capabilities']['upload_files'] ) && $role['capabilities']['upload_files'] ) {
if ( ! isset( $settings['limits'][ $role_key ]['bytes'] ) ) {
$settings['limits'][ $role_key ]['bytes'] = $this->max_upload_size;
}
if ( ! isset( $settings['limits'][ $role_key ]['format'] ) ) {
$settings['limits'][ $role_key ]['format'] = $settings['limits'][ $role_key ]['bytes'] >= GB_IN_BYTES ? 'GB' : 'MB';
}
}
}
if ( $format ) {
foreach ( $settings['limits'] as $role_key => $value ) {
$divisor = ( $value['format'] == 'MB' ? MB_IN_BYTES : GB_IN_BYTES );
$settings['limits'][ $role_key ]['bytes'] = round( $value['bytes'] / $divisor, 1 );
}
}
return $settings;
}
/**
* Adds settings links to plugin row.
*
* @since 2.0
*/
function plugins_list_links( $actions ) {
// Build and escape the URL.
$url = esc_url( $this->settings_url() );
// Create the link.
$custom_links = [];
$custom_links['settings'] = "" . esc_html__( 'Settings', 'tuxedo-big-file-uploads' ) . '';
$custom_links['support'] = '' . esc_html__( 'Support', 'tuxedo-big-file-uploads' ) . '';
// Adds the links to the beginning of the array.
return array_merge( $custom_links, $actions );
}
/**
* Get the settings url with optional url args.
*
* @since 2.0
*
* @param array $args Optional. Same as for add_query_arg()
*
* @return string Unescaped url to settings page.
*/
function settings_url( $args = [] ) {
if ( is_multisite() ) {
$base = network_admin_url( 'settings.php?page=big_file_uploads' );
} else {
$base = admin_url( 'options-general.php?page=big_file_uploads' );
}
return add_query_arg( $args, $base );
}
/**
* Get a url to the public Infinite Uploads site.
*
* @since 2.0
*
* @param string $path Optional path on the site.
*
* @return string
*/
function api_url( $path = '' ) {
$url = trailingslashit( $this->server_root );
if ( $path && is_string( $path ) ) {
$url .= ltrim( $path, '/' );
}
return $url;
}
/**
* Registers a new settings page under Settings.
*
* @since 2.0
*/
function admin_menu() {
if ( is_multisite() ) {
$page = add_submenu_page(
'settings.php',
__( 'Big File Uploads', 'tuxedo-big-file-uploads' ),
__( 'Big File Uploads', 'tuxedo-big-file-uploads' ),
$this->capability,
'big_file_uploads',
[
$this,
'settings_page',
]
);
} else {
$page = add_options_page(
__( 'Big File Uploads', 'tuxedo-big-file-uploads' ),
__( 'Big File Uploads', 'tuxedo-big-file-uploads' ),
$this->capability,
'big_file_uploads',
[
$this,
'settings_page',
]
);
}
add_action( 'admin_print_scripts-' . $page, [ &$this, 'admin_scripts' ] );
add_action( 'admin_print_styles-' . $page, [ &$this, 'admin_styles' ] );
}
/**
* Script enqueues for the settings page.
*
* @since 2.0
*/
function admin_scripts() {
wp_enqueue_script( 'bfu-bootstrap', plugins_url( 'assets/bootstrap/js/bootstrap.bundle.min.js', __FILE__ ), [ 'jquery' ], BIG_FILE_UPLOADS_VERSION );
wp_enqueue_script( 'bfu-chartjs', plugins_url( 'assets/js/Chart.min.js', __FILE__ ), [], BIG_FILE_UPLOADS_VERSION );
wp_enqueue_script( 'bfu-js', plugins_url( 'assets/js/admin.js', __FILE__ ), [ 'bfu-bootstrap', 'bfu-chartjs' ], BIG_FILE_UPLOADS_VERSION );
$data = [];
$data['strings'] = [
'leave_confirm' => esc_html__( 'Are you sure you want to leave this tab? The current bulk action will be canceled and you will need to continue where it left off later.', 'tuxedo-big-file-uploads' ),
'ajax_error' => esc_html__( 'Too many server errors. Please try again.', 'tuxedo-big-file-uploads' ),
'leave_confirmation' => esc_html__( 'If you leave this page the sync will be interrupted and you will have to continue where you left off later.', 'tuxedo-big-file-uploads' ),
];
$data['local_types'] = $this->get_filetypes( true );
$data['default_upload_size'] = $this->max_upload_size;
wp_localize_script( 'bfu-js', 'bfu_data', $data );
//disable one time upgrade notice
$dismissed = get_user_option( 'bfu_upgrade_notice_dismissed', get_current_user_id() );
if ( ! $dismissed ) {
update_user_option( get_current_user_id(), 'bfu_upgrade_notice_dismissed', 1 );
}
}
/**
* Styles for the settings page.
*
* @since 2.0
*/
function admin_styles() {
wp_enqueue_style( 'tuxbfu-bootstrap', plugins_url( 'assets/bootstrap/css/bootstrap.min.css', __FILE__ ), false, BIG_FILE_UPLOADS_VERSION );
wp_enqueue_style( 'tuxbfu-styles', plugins_url( 'assets/css/admin.css', __FILE__ ), [ 'tuxbfu-bootstrap' ], BIG_FILE_UPLOADS_VERSION );
}
/**
* Settings page display callback.
*
* @since 2.0
*/
function settings_page() {
// check caps
if ( ! current_user_can( $this->capability ) ) {
wp_die( esc_html__( 'Permissions Error: Please refresh the page and try again.', 'tuxedo-big-file-uploads' ) );
}
$save_error = $save_success = false;
if ( isset( $_POST['bfu_settings_submit'] ) ) {
if ( ! wp_verify_nonce( $_POST['_wpnonce'], 'bfu_settings' ) ) {
wp_die( esc_html__( 'Permissions Error: Please refresh the page and try again.', 'tuxedo-big-file-uploads' ) );
}
$settings = $this->get_settings();
if ( isset( $_POST['by_role'] ) ) {
foreach ( wp_roles()->roles as $role_key => $role ) {
if ( isset( $role['capabilities']['upload_files'] ) && $role['capabilities']['upload_files'] && isset( $_POST['upload_limit'][ $role_key ] ) ) {
if ( $_POST['upload_limit'][ $role_key ] <= 0 ) {
$save_error = true;
} else {
$settings['limits'][ $role_key ]['bytes'] = absint( $_POST['upload_limit'][ $role_key ] * ( $_POST['upload_limit_format'][ $role_key ] == 'MB' ? MB_IN_BYTES : GB_IN_BYTES ) );
$settings['limits'][ $role_key ]['format'] = ( $_POST['upload_limit_format'][ $role_key ] == 'MB' ? 'MB' : 'GB' );
}
}
}
$settings['by_role'] = true;
} else {
if ( $_POST['upload_limit'] <= 0 ) {
$save_error = true;
} else {
$settings['limits']['all']['bytes'] = absint( $_POST['upload_limit'] * ( $_POST['upload_limit_format'] == 'MB' ? MB_IN_BYTES : GB_IN_BYTES ) );
$settings['limits']['all']['format'] = ( $_POST['upload_limit_format'] == 'MB' ? 'MB' : 'GB' );
}
$settings['by_role'] = false;
}
if ( ! $save_error ) {
update_site_option( 'tuxbfu_settings', $settings );
$save_success = true;
}
}
?>