GFAsyncUpload

The Gravity Forms GFAsyncUpload class.

Defined (1)

The class is defined in the following location(s).

/includes/upload.php  
  1. class GFAsyncUpload { 
  2.  
  3. public static function upload() { 
  4.  
  5. GFCommon::log_debug( 'GFAsyncUpload::upload(): Starting.' ); 
  6.  
  7. if ( $_SERVER['REQUEST_METHOD'] != 'POST' ) { 
  8. status_header( 404 ); 
  9. die(); 
  10.  
  11. header( 'Content-Type: text/html; charset=' . get_option( 'blog_charset' ) ); 
  12. send_nosniff_header(); 
  13. nocache_headers(); 
  14.  
  15. status_header( 200 ); 
  16.  
  17. // If the file is bigger than the server can accept then the form_id might not arrive. 
  18. // This might happen if the file is bigger than the max post size ini setting. 
  19. // Validation in the browser reduces the risk of this happening. 
  20. if ( ! isset( $_REQUEST['form_id'] ) ) { 
  21. GFCommon::log_debug( 'GFAsyncUpload::upload(): File upload aborted because the form_id was not found. The file may have been bigger than the max post size ini setting.' ); 
  22. self::die_error( 500, __( 'Failed to upload file.', 'gravityforms' ) ); 
  23.  
  24.  
  25. $form_id = absint( $_REQUEST['form_id'] ); 
  26. $form_unique_id = rgpost( 'gform_unique_id' ); 
  27. $form = GFAPI::get_form( $form_id ); 
  28.  
  29. if ( empty( $form ) || ! $form['is_active'] ) { 
  30. die(); 
  31.  
  32. if ( rgar( $form, 'requireLogin' ) ) { 
  33. if ( ! is_user_logged_in() ) { 
  34. die(); 
  35. check_admin_referer( 'gform_file_upload_' . $form_id, '_gform_file_upload_nonce_' . $form_id ); 
  36.  
  37. if ( ! ctype_alnum( $form_unique_id ) ) { 
  38. die(); 
  39.  
  40. $target_dir = GFFormsModel::get_upload_path( $form_id ) . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR; 
  41.  
  42. if ( ! is_dir( $target_dir ) ) { 
  43. if ( ! wp_mkdir_p( $target_dir ) ) { 
  44. GFCommon::log_debug( "GFAsyncUpload::upload(): Couldn't create the tmp folder: " . $target_dir ); 
  45. self::die_error( 500, __( 'Failed to upload file.', 'gravityforms' ) ); 
  46.  
  47. $time = current_time( 'mysql' ); 
  48. $y = substr( $time, 0, 4 ); 
  49. $m = substr( $time, 5, 2 ); 
  50.  
  51. //adding index.html files to all subfolders 
  52. if ( ! file_exists( GFFormsModel::get_upload_root() . '/index.html' ) ) { 
  53. GFForms::add_security_files(); 
  54. } else if ( ! file_exists( GFFormsModel::get_upload_path( $form_id ) . '/index.html' ) ) { 
  55. GFCommon::recursive_add_index_file( GFFormsModel::get_upload_path( $form_id ) ); 
  56. } else if ( ! file_exists( GFFormsModel::get_upload_path( $form_id ) . "/$y/index.html" ) ) { 
  57. GFCommon::recursive_add_index_file( GFFormsModel::get_upload_path( $form_id ) . "/$y" ); 
  58. } else { 
  59. GFCommon::recursive_add_index_file( GFFormsModel::get_upload_path( $form_id ) . "/$y/$m" ); 
  60.  
  61. if ( ! file_exists( $target_dir . '/index.html' ) ) { 
  62. GFCommon::recursive_add_index_file( $target_dir ); 
  63.  
  64. $uploaded_filename = $_FILES['file']['name']; 
  65. $file_name = isset( $_REQUEST['name'] ) ? $_REQUEST['name'] : ''; 
  66. $field_id = rgpost( 'field_id' ); 
  67. $field_id = absint( $field_id ); 
  68. $field = GFFormsModel::get_field( $form, $field_id ); 
  69.  
  70. if ( empty( $field ) || GFFormsModel::get_input_type( $field ) != 'fileupload' ) { 
  71. die(); 
  72.  
  73. $file_name = sanitize_file_name( $file_name ); 
  74. $uploaded_filename = sanitize_file_name( $uploaded_filename ); 
  75.  
  76. $allowed_extensions = ! empty( $field->allowedExtensions ) ? GFCommon::clean_extensions( explode( ', ', strtolower( $field->allowedExtensions ) ) ) : array(); 
  77.  
  78. $max_upload_size_in_bytes = $field->maxFileSize > 0 ? $field->maxFileSize * 1048576 : wp_max_upload_size(); 
  79. $max_upload_size_in_mb = $max_upload_size_in_bytes / 1048576; 
  80.  
  81. if ( $_FILES['file']['size'] > 0 && $_FILES['file']['size'] > $max_upload_size_in_bytes ) { 
  82. self::die_error( 104, sprintf( __( 'File exceeds size limit. Maximum file size: %dMB', 'gravityforms' ), $max_upload_size_in_mb ) ); 
  83.  
  84. if ( GFCommon::file_name_has_disallowed_extension( $file_name ) || GFCommon::file_name_has_disallowed_extension( $uploaded_filename ) ) { 
  85. GFCommon::log_debug( "GFAsyncUpload::upload(): Illegal file extension: {$file_name}" ); 
  86. self::die_error( 104, __( 'The uploaded file type is not allowed.', 'gravityforms' ) ); 
  87.  
  88. if ( ! empty( $allowed_extensions ) ) { 
  89. if ( ! GFCommon::match_file_extension( $file_name, $allowed_extensions ) || ! GFCommon::match_file_extension( $uploaded_filename, $allowed_extensions ) ) { 
  90. GFCommon::log_debug( "GFAsyncUpload::upload(): The uploaded file type is not allowed: {$file_name}" ); 
  91. self::die_error( 104, sprintf( __( 'The uploaded file type is not allowed. Must be one of the following: %s', 'gravityforms' ), strtolower( $field['allowedExtensions'] ) ) ); 
  92.  
  93. $whitelisting_disabled = apply_filters( 'gform_file_upload_whitelisting_disabled', false ); 
  94.  
  95. if ( empty( $allowed_extensions ) && ! $whitelisting_disabled ) { 
  96. // Whitelist the file type 
  97. $valid_uploaded_filename = GFCommon::check_type_and_ext( $_FILES['file'], $uploaded_filename ); 
  98.  
  99. if ( is_wp_error( $valid_uploaded_filename ) ) { 
  100. self::die_error( $valid_uploaded_filename->get_error_code(), $valid_uploaded_filename->get_error_message() ); 
  101.  
  102. $valid_file_name = GFCommon::check_type_and_ext( $_FILES['file'], $file_name ); 
  103.  
  104. if ( is_wp_error( $valid_uploaded_filename ) ) { 
  105. self::die_error( $valid_file_name->get_error_code(), $valid_file_name->get_error_message() ); 
  106.  
  107. $tmp_file_name = $form_unique_id . '_input_' . $field_id . '_' . $file_name; 
  108.  
  109. $tmp_file_name = sanitize_file_name( $tmp_file_name ); 
  110.  
  111. $file_path = $target_dir . $tmp_file_name; 
  112.  
  113. $cleanup_target_dir = true; // Remove old files 
  114. $max_file_age = 5 * 3600; // Temp file age in seconds 
  115.  
  116. // Remove old temp files 
  117. if ( $cleanup_target_dir ) { 
  118. if ( is_dir( $target_dir ) && ( $dir = opendir( $target_dir ) ) ) { 
  119. while ( ( $file = readdir( $dir ) ) !== false ) { 
  120. $tmp_file_path = $target_dir . $file; 
  121.  
  122. // Remove temp file if it is older than the max age and is not the current file 
  123. if ( preg_match( '/\.part$/', $file ) && ( filemtime( $tmp_file_path ) < time() - $max_file_age ) && ( $tmp_file_path != "{$file_path}.part" ) ) { 
  124. GFCommon::log_debug( 'GFAsyncUpload::upload(): Deleting file: ' . $tmp_file_path ); 
  125. @unlink( $tmp_file_path ); 
  126. closedir( $dir ); 
  127. } else { 
  128. GFCommon::log_debug( 'GFAsyncUpload::upload(): Failed to open temp directory: ' . $target_dir ); 
  129. self::die_error( 100, __( 'Failed to open temp directory.', 'gravityforms' ) ); 
  130.  
  131. if ( isset( $_SERVER['HTTP_CONTENT_TYPE'] ) ) { 
  132. $contentType = $_SERVER['HTTP_CONTENT_TYPE']; 
  133.  
  134. if ( isset( $_SERVER['CONTENT_TYPE'] ) ) { 
  135. $contentType = $_SERVER['CONTENT_TYPE']; 
  136.  
  137. $chunk = isset( $_REQUEST['chunk'] ) ? intval( $_REQUEST['chunk'] ) : 0; 
  138. $chunks = isset( $_REQUEST['chunks'] ) ? intval( $_REQUEST['chunks'] ) : 0; 
  139.  
  140. // Handle non multipart uploads older WebKit versions didn't support multipart in HTML5 
  141. if ( strpos( $contentType, 'multipart' ) !== false ) { 
  142. if ( isset( $_FILES['file']['tmp_name'] ) && is_uploaded_file( $_FILES['file']['tmp_name'] ) ) { 
  143. // Open temp file 
  144. $out = @fopen( "{$file_path}.part", $chunk == 0 ? 'wb' : 'ab' ); 
  145. if ( $out ) { 
  146. // Read binary input stream and append it to temp file 
  147. $in = @fopen( $_FILES['file']['tmp_name'], 'rb' ); 
  148.  
  149. if ( $in ) { 
  150. while ( $buff = fread( $in, 4096 ) ) { 
  151. fwrite( $out, $buff ); 
  152. } else { 
  153. self::die_error( 101, __( 'Failed to open input stream.', 'gravityforms' ) ); 
  154.  
  155. @fclose( $in ); 
  156. @fclose( $out ); 
  157. @unlink( $_FILES['file']['tmp_name'] ); 
  158. } else { 
  159. self::die_error( 102, __( 'Failed to open output stream.', 'gravityforms' ) ); 
  160. } else { 
  161. self::die_error( 103, __( 'Failed to move uploaded file.', 'gravityforms' ) ); 
  162. } else { 
  163. // Open temp file 
  164. $out = @fopen( "{$file_path}.part", $chunk == 0 ? 'wb' : 'ab' ); 
  165. if ( $out ) { 
  166. // Read binary input stream and append it to temp file 
  167. $in = @fopen( 'php://input', 'rb' ); 
  168.  
  169. if ( $in ) { 
  170. while ( $buff = fread( $in, 4096 ) ) { 
  171. fwrite( $out, $buff ); 
  172. } else { 
  173. self::die_error( 101, __( 'Failed to open input stream.', 'gravityforms' ) ); 
  174.  
  175. @fclose( $in ); 
  176. @fclose( $out ); 
  177. } else { 
  178. self::die_error( 102, __( 'Failed to open output stream.', 'gravityforms' ) ); 
  179.  
  180. // Check if file has been uploaded 
  181. if ( ! $chunks || $chunk == $chunks - 1 ) { 
  182. // Strip the temp .part suffix off 
  183. rename( "{$file_path}.part", $file_path ); 
  184.  
  185.  
  186. if ( file_exists( $file_path ) ) { 
  187. GFFormsModel::set_permissions( $file_path ); 
  188. } else { 
  189. self::die_error( 105, __( 'Upload unsuccessful', 'gravityforms' ) . ' '. $uploaded_filename ); 
  190.  
  191. $output = array( 
  192. 'status' => 'ok',  
  193. 'data' => array( 
  194. 'temp_filename' => $tmp_file_name,  
  195. 'uploaded_filename' => str_replace( "\\'", "'", urldecode( $uploaded_filename ) ) //Decoding filename to prevent file name mismatch. 
  196. ); 
  197.  
  198. $output = json_encode( $output ); 
  199.  
  200. GFCommon::log_debug( sprintf( 'GFAsyncUpload::upload(): File upload complete. temp_filename: %s uploaded_filename: %s ', $tmp_file_name, $uploaded_filename ) ); 
  201.  
  202. gf_do_action( array( 'gform_post_multifile_upload', $form['id'] ), $form, $field, $uploaded_filename, $tmp_file_name, $file_path ); 
  203.  
  204. die( $output ); 
  205.  
  206. public static function die_error( $status_code, $message ) { 
  207. $response = array(); 
  208.  
  209. $response['status'] = 'error'; 
  210. $response['error'] = array( 
  211. 'code' => $status_code,  
  212. 'message' => $message,  
  213. ); 
  214. $response_json = json_encode( $response ); 
  215. die( $response_json );