Skip to content

Instantly share code, notes, and snippets.

@RalfAlbert
Last active May 18, 2018 19:23
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save RalfAlbert/5521518 to your computer and use it in GitHub Desktop.
Save RalfAlbert/5521518 to your computer and use it in GitHub Desktop.
WordPress: Simple class to handle file uploads to the wp-content directory and creating an attachment post
<?php
class File_Upload
{
/**
* Index key from upload form
* @var string
*/
public $index_key = '';
/**
* Copy of superglobal array $_FILES
* @var array
*/
public $files = array();
/**
* Array with url, filepath and mimetype after uploading
* @var array
*/
public $filedata = array();
/**
* Error object containing errors as WP_Error
* @var onject
*/
public $errors = null;
/**
* Constructor
* Setup files array and guess index key
*/
public function __construct(){
if ( isset( $_FILES ) && ! empty( $_FILES ) ) {
$this->files = $_FILES;
$this->guess_index_key();
}
}
/**
* Set/overwrites the index key
* Converts $name with type casting (string)
*
* @param string $name Name of the index key
* @return string ::name Name of the stored index key
*/
public function set_field_name_for_file( $name = '' ) {
$this->index_key = ( ! empty( $name ) ) ? (string) $name : '';
return $this->index_key;
}
/**
* Converts uploaded file into WordPress attachment
*
* @return boolean Whether if the attachment was created (true) or not (false)
*/
public function create_attachment(){
// move the uploaded file from temp folder and create basic data
$this->filedata = $this->handle_uploaded_file();
// if moving fails, stop here
if ( empty( $this->filedata ) || is_wp_error( $this->filedata ) ) {
$code = 'createerror';
$msg = 'Could not create attachment';
if ( is_wp_error( $this->filedata ) ) {
$this->errors = $this->filedata;
$this->filedata = array();
$this->errors->add( $code, $msg );
} else {
$this->errors = new WP_Error( $code, $msg );
}
return $this->errors;
}
/*
* For Production
* Check if $imagedata contains the expected (and needed)
* values. Every method could fail and return malicious data!!
*/
extract( $this->filedata );
// create the attachment data array
$attachment = array(
'guid' => $url,
'post_mime_type' => $type,
'post_title' => sanitize_key( basename( $file ) ),
'post_content' => '',
'post_status' => 'inherit'
);
// insert attachment (posttype attachment)
$attach_id = wp_insert_attachment( $attachment, $file );
// you must first include the image.php file
// for the function wp_generate_attachment_metadata() to work
require_once( ABSPATH . 'wp-admin/includes/image.php' );
/*
* For Production
* Check $attach_data, wp_generate_attachment_metadata() could fail
* Check if wp_update_attachment_metadata() fails (returns false),
* return an error object with WP_Error()
*/
$attach_data = wp_generate_attachment_metadata( $attach_id, $file );
wp_update_attachment_metadata( $attach_id, $attach_data );
return $attach_id;
}
/**
* Handles the upload
*
* @return array|object $return_data Array with informations about the uploaded file on success. WP_Error object on failure
*/
protected function handle_uploaded_file() {
// stop if something went wrong
if ( ! isset( $this->files[$this->index_key]['tmp_name'] ) || empty( $this->files[$this->index_key]['tmp_name'] ) ) {
$code = ( isset( $this->files[$this->index_key]['error'] ) ) ?
$this->files[$this->index_key]['error'] : 0;
$msg = $this->guess_upload_error( $code );
return new WP_Error( 'uploaderror', 'Upload failed with message: ' . $msg );
}
/*
* For Production
* You should really, really check the file extension and filetype ($movedfile['type'])
* on EVERY upload. If you do not, it is possible to upload EVERY kind of
* file including malicious code.
*
*/
if ( ! function_exists( 'wp_handle_upload' ) )
require_once( ABSPATH . 'wp-admin/includes/file.php' );
$movedfile = wp_handle_upload( $this->files[$this->index_key], array( 'test_form' => false ) );
return $movedfile;
}
/**
* Try to fetch the first index from $_FILES
*
* @return boolean Whether if a key was found or not
*/
protected function guess_index_key() {
$keys = array_keys( $_FILES );
if ( ! empty( $keys ) ) {
$this->index_key = $keys[0];
return true;
}
return false;
}
protected function guess_upload_error( $err = 0 ) {
$errcodes = array(
'Unknown error',
'The uploaded file exceeds the upload_max_filesize directive in php.ini.',
'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.',
'The uploaded file was only partially uploaded.',
'No file was uploaded.',
'Missing a temporary folder.',
'Failed to write file to disk.',
'A PHP extension stopped the file upload. PHP does not provide a way to ascertain which extension caused the file upload to stop; examining the list of loaded extensions with phpinfo() may help.'
);
return ( isset( $errcodes[$err] ) ) ?
$errcodes[$err] : 'Unknown error';
}
}
<?php
if ( empty ( $_FILES ) ) {
global $pagenow;
$url = admin_url( $pagenow );
?>
<!-- The data encoding type, enctype, MUST be specified as below -->
<form enctype="multipart/form-data" action="<?php echo $url; ?>" method="POST">
<!-- MAX_FILE_SIZE must precede the file input field -->
<input type="hidden" name="MAX_FILE_SIZE" value="30000" />
<!-- Name of input element determines name in $_FILES array -->
Send this file: <input name="userfile" type="file" />
<input type="submit" value="Send File" />
</form>
<?php
} else {
$imageupload = new File_Upload();
$attachment_id = $imageupload->create_attachment();
if ( is_wp_error( $attachment_id ) ) {
echo '<ol>';
foreach ( $attachment_id->get_error_messages() as $err )
printf( '<li>%s</li>', $err );
echo '</ol>';
} else {
// check if the upload was successfull
$attachment = get_post( $attachment_id );
$image_url = $attachment->guid;
printf( '<p><img src="%s"></p>', $image_url );
}
}
@antongorodezkiy
Copy link

Good job, thank you!

And I also added multiple files support in fork https://gist.github.com/antongorodezkiy/10be9f726d827f920aaa

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment