Good day) I’m building a WordPress plugin LMS allowing user to attach their completed home assignments files via AJAX to their answers. Everything works fine, except one scenario when user’s file exceeds the maximum size allowed. In this case my AJAX call returns HTML with following warning:
<b>Warning</b>: POST Content-Length of XXXXX bytes exceeds the limit of XXXXX bytes in <b>Unknown</b> on line <b>0</b><br />
As this kind of warning generated on string 0 of my script, it will die and ignore any other instructions, leaving me this ugly string as a result of my call.
You basically can live with it, as the final user will not see it (just the AJAX call will not have desired result), but still I want to know if there is a chance to jump it over and handle it nicely?
Ok, what kind of research I’ve already done:
-
I found this tutorial by Andrew Curioso, and tried to make something like this from it:
if (isset($_SERVER['CONTENT_LENGTH'])) { if ($_SERVER['CONTENT_LENGTH'] > (substr(ini_get('post_max_size'), -1) * 1024 * 1024)) { echo 'php errors is so much fun'; } }
It doesn’t give the desired effect, as my script still dies with only positive effect of echoing additional string from IF statement (besides, if you try to do something like wp_send_json(errorsArray), it will not be executed).
-
Turning off displaying errors with display_errors, error_reporting. Well, it’s not what I need here, as it still does not allow me to proceed with script and create custom error handler.
-
My WP_DEBUG is set to FALSE
What kind of advice I’m not looking for is manually editing max_upload_size, max_post_size etc. As manually editing server files is out of plugin philosophy. And anyway even if you set your max upload size to 10GB, once you will have final user trying to upload 11GB.
SO, to summarize, as we all know, this mechanism is realized on thousands of sites and apps, and I want to know how to maximize my script quality, handling this issue without overkills and bad UX.
Thank for sharing your thoughts 🙂
UPD1
Here is my AJAX call if it helps:
$('#post-assignment-answer').on('click', function (event) {
event.preventDefault();
tinymce.triggerSave();
var answerContent = tinymce.get('assignment_user_input_textarea').getContent();
var answerFile = $('#assignment-file-upload')[0].files[0];
var formData = new FormData();
formData.append('action', 'post_assignment_answer');
formData.append('security', lucid_single_assignment_params.post_assignment_answer_nonce);
formData.append('post_id', lucid_single_assignment_params.post_id);
formData.append('answer_content', answerContent);
formData.append('answer_file', answerFile);
$.ajax({
url: lucid_single_assignment_params.ajax_url,
type: 'post',
data: formData,
contentType: false,
processData: false,
success: function (result) {
console.log(result);
}
});
});
UPD2:
Added AJAX handling php
<?php
/**
* Post Assignment Answer
*
* @version 1.0.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
} // Exit if accessed directly
// Create AJAX call $result
$result = array(
'fileTypeError' => false,
'fileSizeError' => false,
'uploadError' => false
);
// Retrieving current post ID
$post_id = $_POST['post_id'];
// Retrieving WYSIWYG content
$answer_content = '';
if (! (trim($_POST['answer_content']) == '') ) {
$answer_content = wp_kses_post($_POST['answer_content']);
}
// Updating WYSIWYG meta field
update_post_meta($post_id, '_answer_content', $answer_content);
// Check if user intends to upload a file
if (!empty($_FILES['answer_file'])) {
// Adding timestamp to file name
$_FILES['answer_file']['name'] = round(microtime(true)) . '_' . $_FILES['answer_file']['name'];
$answer_file = $_FILES['answer_file'];
// Setting up uploaded file type validation
$supported_types = array(
'text/plain' // .txt
);
$arr_file_type = wp_check_filetype(basename($answer_file['name']));
$uploaded_type = $arr_file_type['type'];
// Setting up uploaded file size validation // TODO: This should be optimized
$allowed_size = 8388608;
$uploaded_size = $answer_file['size'];
// Validating, and in a case of success completing upload
if (!in_array($uploaded_type, $supported_types)) {
$result['fileTypeError'] = __('The type of file you've provided is not allowed', 'lucidlms');
} elseif ($uploaded_size > $allowed_size) {
$result['fileSizeError'] = __('The size of file you've provided is exceeding the maximum upload size', 'lucidlms');
} else {
/**
* Override the default upload path.
*
* @param array $dir
* @return array
*/
function lucidlms_assignment_upload_dir( $dir ) {
global $user_ID;
return array(
'path' => $dir['basedir'] . '/lucidlms/assignment/user' . $user_ID,
'url' => $dir['baseurl'] . '/lucidlms/assignment/user' . $user_ID,
'subdir' => ''
) + $dir;
}
// Register path override
add_filter( 'upload_dir', 'lucidlms_assignment_upload_dir' );
$upload = wp_handle_upload($answer_file, array( 'test_form' => false ));
// Set everything back to normal
remove_filter( 'upload_dir', 'lucidlms_user_upload_dir' );
if (isset($upload['error']) && $upload['error'] != 0) {
$result['uploadError'] = sprintf(__('There was an error uploading your file. The error is: %s', 'lucidlms'), $upload['error']);
} else {
// Check if there is an old version of file on the server and delete it
$existing_answer_file = get_post_meta($post_id, '_answer_file', true);
if (! empty($existing_answer_file)) {
global $user_ID;
$upload_dir = wp_upload_dir();
$existing_answer_file_name = pathinfo($existing_answer_file['file'], PATHINFO_BASENAME);
$unlink_path = $upload_dir['basedir'] . '/lucidlms/assignment/user' . $user_ID . '/' . $existing_answer_file_name;
unlink($unlink_path);
}
// Updating post meta
update_post_meta($post_id, '_answer_file', $upload);
}
}
}
wp_send_json($result);
Do read and understand what the error message is telling you:
The error is being reported at line 0 because it is being thrown before your PHP code gets to execute. So you can’t change the behaviour in the receiving PHP script.
The right approach is to check the size of the data BEFORE you upload it (i.e. in Javascript). But beware:
Javascript reports the size of individual files before they are encoded – Base64 encoding adds an overhead of around a third, plus space for other POST attribute values and names.
The values configured for post_max_size is the maximum that PHP accepts. The maximum that the webserver (e.g. apache)will accept may be lower. For a plugin, perhaps the most appropriate solution would be to allow the administrator to configure the upper limit.
Someone trying to subvert your security can easily bypass any checks in Javascript
Try this link : http://code.tutsplus.com/tutorials/uploading-files-with-ajax–net-21077
In this at upload.php page (which is the main callback function of ajax which uploads the file) you will get the size of the image uploaded in
$_FILES["images"]["size"]