Ajax Upload Photos via HTML5 File Reader API : #BuddyPress Checkins teaser !

Crédits Photo : The Old Republic de Ryan Grove, sur Flickr

Salut,
Je suis √† fond sur la prochaine version de BP Checkins. Dans les commentaires de mon article d’introduction de ce plugin BuddyPress, il m’a notamment √©t√© demand√© de g√©rer les uploads d’images pour illustrer un checkin. Il me reste pas mal de taf sur cette nouvelle version, mais je me suis dit que le petit trick que j’utilise pour transf√©rer des photos en Ajax pouvait vous int√©resser et serait un bon teaser pour vous faire patienter ūüėČ https://vimeo.com/43250056

La d√©mo ci-dessus, dans laquelle je parle anglais (vous avez le droit de me chambrer !! / you can laugh at my ¬ę¬†frenglish¬†¬Ľ accent !!), illustre le fonctionnement du trick.

En fait, j’utilise la HTML5 File Reader API pour r√©cup√©rer l’image encod√©e en base64 avant de l’envoyer en AJAX √† mon script PHP. Dans ce script, je d√©code puis √©cris √† la fois le fichier full size et son thumbnail dans le r√©pertoire des uploads de WordPress. Astucieux non ? La seule ombre au tableau est que vous devez vous assurer de que le memory_size de votre php.ini est d’au moins 64M..

C√īt√© client

Voici un extrait de l’html et du javascript que j’utilise dans BP Checkins que vous pouvez adapter selon vos besoins

/***** html *****/
<span id="form-upcheckin">
	<input type="file" name="_checkin_pic" id="checkin_pic">
</span>
<a href="#" id="bpci-polaroid-upload" title="Attach image">
	<span>Attach image</span>
</a>

/***** javascript *****/
$('#bpci-polaroid-upload').click( function(){
	var file = $('#checkin_pic').get(0).files[0];

	//size in MO
	var max_file_size = 2;

	// check file type, we only want images */
	if ( file.type.indexOf( 'image' ) == -1 ) {
		alert( 'Please select an image file only.' );
		return false;
	}

	var name = file.name, size = file.size / 1024, type = file.type,
		sizeInMo = Math.round((size / 1024) * 100) / 100;

	// check file size
	if( sizeInMo > max_file_size ) {
		alert( 'Your image is too big, please reduce it (max file size : ' + max_file_size + 'MO)' );
		return false;
	}

	var reader = new FileReader();
	$('#bpci-polaroid-upload').addClass('bpci-loading');

	reader.onload = (function(theFile) {
		return function(e) {
			bpciImageUpload(e.target.result, type, name);
			return false;
		};
	} )(file);

	reader.readAsDataURL(file);

	return false;
} );

function bpciImageUpload( img, type, name ) {
	/**
	 * ajaxurl is already defined in BuddyPress
	 * if you're not using BuddyPress, you can define it this way :
	 * ajaxurl = "<?php echo admin_url('admin-ajax.php');?>";
	 */
	$.post( ajaxurl, {
		action: 'upload_checkin_pic',
		'_wpnonce_post_checkin': $("input#_wpnonce_post_checkin").val(), //security in bp-checkins
		encodedimg: img,
		imgtype:type,
		imgname':name
	}, function(response) {
		if( response[0] != "0" ) {
			sendToContentEditable( response[1], response[2] );
		} else {
			alert(response[1]);
		}
	}, 'json');
}

function sendToContentEditable( fullimage, resizedimage ) {
	alert('full image url: '+fullimage+' / thumbnail url: '+ resizedimage);
}

Pour en savoir plus sur les possibilit√©s de la Html5 File / File Reader API, je vous invite √† consulter cet article de html5rocks qui m’a beaucoup inspir√© ūüėČ

C√īt√© serveur

Ici, on profite de la fonction php base64_decode() pour d√©coder et √©crire le fichier au sein du r√©pertoire des uploads de WordPress. En passant, on s’assure de l’unicit√© du nom de fichier gr√Ęce √† la fonction wp_unique_filename() de WP. Avant de renvoyer la r√©ponse au client, on en profite pour √©crire le cas √©ch√©ant un thumbnail de cette image

/***** php *****/
function bp_checkins_handle_checkin_upload() {
	if( $_POST['encodedimg'] ) {
		check_admin_referer( 'post_checkin', '_wpnonce_post_checkin' ); // bp-checkins security

		$imgresponse = array();
		$uploaddir = wp_upload_dir();

		// let's decode the base64 encoded image sent
		$img = $_POST['encodedimg'];
		$img = str_replace('data:'.$_POST['imgtype'].';base64,', '', $img);
		$img = str_replace(' ', '+', $img);
		$data = base64_decode($img);
		$imgname = wp_unique_filename( $uploaddir['path'], $_POST['imgname'] );

		$filepath = $uploaddir['path'] . '/' . $imgname;
		$fileurl = $uploaddir['url'] . '/' . $imgname;

		// now we write the image in dir */
		$success = file_put_contents($filepath, $data);

		if ( $success ){
			$imgresponse[0] = "1";
			$imgresponse[1] = $fileurl;
			$size = @getimagesize( $filepath );

			// Check image size and shrink if too large
			if ( $size[0] > 100 ) {
				$thumb = image_resize( $filepath, 100, 100, true );

				// Check for thumbnail creation errors
				if ( is_wp_error( $thumb ) ) {
					$imgresponse[0] = "0";
					$imgresponse[1] = sprintf( __( 'Upload Failed! Error was: %s', 'bp-checkins' ), $thumb->get_error_message() );
					exit();
				}

				//Thumbnail is good so proceed
				$array_filepath = explode('/', $thumb);
				$image_resized = $array_filepath[count($array_filepath)-1];

				if ( !empty( $image_resized ) ) {
					$imgresponse[2] = $uploaddir['url'] . '/'. $image_resized;
				}
			}
		} else {
			$imgresponse[0] = "0";
			$imgresponse[1] = __('Upload Failed! Unable to write the image on server', 'bp-checkins');
		}
	} else {
		$imgresponse[0] = "0";
		$imgresponse[1] = __('Upload Failed! No image sent', 'bp-checkins');
	}

	// if everything is ok, we send back url to thumbnail and to full image 
	echo json_encode( $imgresponse );
	die();
}
add_action( 'wp_ajax_upload_checkin_pic', 'bp_checkins_handle_checkin_upload' );

Merci √† Jamund pour son php trick que je me suis permis d’adapter √† mon besoin

Conclusion

Dans mon plugin, avant de rendre dispo cette fonctionnalit√©, je v√©rifierai c√īt√© serveur si la valeur du php.ini pour la memory_size est bien de 64M et c√īt√© client si le navigateur prend en charge la File Reader API. Autrement, je mets √† disposition un champ pour coller l’url vers l’image…

What’s next ? Comme annonc√© en d√©but de cet article, je travaille d’arrache pied pour terminer au plus t√īt cette nouvelle version. Je m’amuse comme un petit fou avec diff√©rentes classes et fonctions BuddyPress / WordPress. Du coup, le prochain article de ce blog sera la deuxi√®me partie de ma s√©rie ¬ę¬†Etendre BuddyPress¬†¬Ľ dans laquelle je d√©crirai comment concevoir un composant BuddyPress en m’appuyant sur l’exemple de BP Checkins ūüėČ

Many Thanks to the BuddyPress Community for the feedbacks, ratings and interest in this plugin ūüôā

7 commentaires sur “Ajax Upload Photos via HTML5 File Reader API : #BuddyPress Checkins teaser !

  1. C’est tr√®s int√©ressant. M√™me si je ne comprends pas √† quoi √ßa sert, je vais m’en servir pour t√©l√©charger des fichiers.

  2. I’ve been waiting for a plugin like this for years. You rock! By the way, whens the next update going to be ready? I’m very excited about the next update.

Les commentaires sont fermés.