Cómo subir imágenes a tu web y recortarlas en una ventana modal con PHP y jQuery

He recibido varias solicitudes para explicaros cómo implementar la funcionalidad de subir imágenes y recortarlas en una ventana modal. La subida de imágenes y el recortado es una función muy importante de cualquier proyecto web que se precie. Proporciona una experiencia para los usuarios alucinante para que puedan subir sus propias imágenes y recortarlas, todo en una misma ventana modal. Por lo tanto, en este artículo, te mostraremos cómo implementar una subida de imágenes y una función de recorte dentro de una ventana modal utilizando PHP y jQuery.

Librerías que utilizaremos

  • Librería jQuery: Librería base necesaria para utilizar los plugins de jQuery
  • Bootstrap: La utilizaremos para crear el diseño de la página
  • Imgareaselect: Plugin ideal para recortar imágenes
  • Ajax form: Plugin de jQuery que utilizaremos para gestionar el envío del formulario sin recargar la página

Estructura de ficheros

  • index.php
  • change_pic.php
  • functions.js

Habiendo dicho todo esto, vamos a empezar con el tutorial.

Antes que nada, tenemos que incluir todas las librerías necesarias en el head de index.php.

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap-theme.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<script src="dist_files/jquery.imgareaselect.js" type="text/javascript"></script>
<script src="dist_files/jquery.form.js"></script>
<link rel="stylesheet" href="dist_files/imgareaselect.css">
<script src="functions.js"></script>

Ahora creamos nuestro formulario HTML en index.php para mostrar el botón Change Profile Picture y la preview de la imagen para informar al usuario de cómo quedaría la imagen.

<div>
<img class="img-circle" id="profile_picture" height="128" data-src="default.jpg" data-holder-rendered="true" style="width: 140px; height: 140px;" src="default.jpg"/>
<br><br>
<a type="button" class="btn btn-primary" id="change-profile-pic">Change Profile Picture</a>
</div>

Ahora creamos la ventana modal en index.php para la subida de la imagen y la funcionalidad de recorte.

<div id="profile_pic_modal" class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3>Change Profile Picture</h3>
</div>
<div class="modal-body">
<form id="cropimage" method="post" enctype="multipart/form-data" action="change_pic.php">
<strong>Upload Image:</strong> <br><br>
<input type="file" name="profile-pic" id="profile-pic" />
<input type="hidden" name="hdn-profile-id" id="hdn-profile-id" value="1" />
<input type="hidden" name="hdn-x1-axis" id="hdn-x1-axis" value="" />
<input type="hidden" name="hdn-y1-axis" id="hdn-y1-axis" value="" />
<input type="hidden" name="hdn-x2-axis" value="" id="hdn-x2-axis" />
<input type="hidden" name="hdn-y2-axis" value="" id="hdn-y2-axis" />
<input type="hidden" name="hdn-thumb-width" id="hdn-thumb-width" value="" />
<input type="hidden" name="hdn-thumb-height" id="hdn-thumb-height" value="" />
<input type="hidden" name="action" value="" id="action" />
<input type="hidden" name="image_name" value="" id="image_name" />
<div id='preview-profile-pic'></div>
<div id="thumbs" style="padding:5px; width:600p"></div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="button" id="save_crop" class="btn btn-primary">Crop & Save</button>
</div>
</div>
</div>
</div>

Después, mostraremos la ventana modal utilizando jQuery cuando el usuario haga clic en el botón Change Profile Picture.

jQuery('#change-profile-pic').on('click', function(e){
jQuery('#profile_pic_modal').modal({show:true});
});

Una vez hecho eso, mostraremos la imagen para el proceso de recorte en nuestra ventana modal de Bootstrap y gestionaremos el envío del formulario utilizando el plugin jQuery Form.

jQuery('#profile-pic').on('change', function() {
jQuery("#preview-profile-pic").html('');
jQuery("#preview-profile-pic").html('Uploading....');
jQuery("#cropimage").ajaxForm(
{
target: '#preview-profile-pic',
success: function() {
jQuery('img#photo').imgAreaSelect({
aspectRatio: '1:1',
onSelectEnd: getSizes,
});
jQuery('#image_name').val(jQuery('#photo').attr('file-name'));
}
}).submit();
});

Después realizaremos el recorte de la imagen llamando al método ajax saveCropImage() para guardar la imagen en el disco duro cuando se haga clic en el botón Crop & Save.

jQuery('#save_crop').on('click', function(e){
e.preventDefault();
params = {
targetUrl: 'change_pic.php?action=save',
action: 'save',
x_axis: jQuery('#hdn-x1-axis').val(),
y_axis : jQuery('#hdn-y1-axis').val(),
x2_axis: jQuery('#hdn-x2-axis').val(),
y2_axis : jQuery('#hdn-y2-axis').val(),
thumb_width : jQuery('#hdn-thumb-width').val(),
thumb_height:jQuery('#hdn-thumb-height').val()
};
saveCropImage(params);
});

Esta sería la función saveCropImage() que guardaría la imagen

function saveCropImage(params) {
jQuery.ajax({
url: params['targetUrl'],
cache: false,
dataType: "html",
data: {
action: params['action'],
id: jQuery('#hdn-profile-id').val(),
t: 'ajax',
w1:params['thumb_width'],
x1:params['x_axis'],
h1:params['thumb_height'],
y1:params['y_axis'],
x2:params['x2_axis'],
y2:params['y2_axis'],
image_name :jQuery('#image_name').val()
},
type: 'Post',
success: function (response) {
jQuery('#profile_pic_modal').modal('hide');
jQuery(".imgareaselect-border1,.imgareaselect-border2,.imgareaselect-border3,.imgareaselect-border4,.imgareaselect-border2,.imgareaselect-outer").css('display', 'none');
jQuery("#profile_picture").attr('src', response);
jQuery("#preview-profile-pic").html('');
jQuery("#profile-pic").val();
},
error: function (xhr, ajaxOptions, thrownError) {
alert('status Code:' + xhr.status + 'Error Message :' + thrownError);
}
});
}

Ahora implementaremos la subida de la imagen al servidor y guardaremos la imagen que acaba de cambiar el usuario en la tabla MySQL en el fichero change_pic.php

<?php
/* Get post details */
$post = isset($_POST) ? $_POST: array();
switch($post['action']) {
case 'save' :
saveProfilePic();
saveProfilePicTmp();
break;
default:
changeProfilePic();
}
/* Function to change profile picture */
function changeProfilePic() {
$post = isset($_POST) ? $_POST: array();
$max_width = "500";
$userId = isset($post['hdn-profile-id']) ? intval($post['hdn-profile-id']) : 0;
$path = 'images/tmp';
$valid_formats = array("jpg", "png", "gif", "jpeg");
$name = $_FILES['profile-pic']['name'];
$size = $_FILES['profile-pic']['size'];
if(strlen($name)) {
list($txt, $ext) = explode(".", $name);
if(in_array($ext,$valid_formats)) {
if($size < (1024*1024)) { $actual_image_name = 'avatar' .'_'.$userId .'.'.$ext; $filePath = $path .'/'.$actual_image_name; $tmp = $_FILES['profile-pic']['tmp_name']; if(move_uploaded_file($tmp, $filePath)) { $width = getWidth($filePath); $height = getHeight($filePath); //Scale the image if it is greater than the width set above if ($width > $max_width){
$scale = $max_width/$width;
$uploaded = resizeImage($filePath,$width,$height,$scale, $ext);
} else {
$scale = 1;
$uploaded = resizeImage($filePath,$width,$height,$scale, $ext);
}
echo "<img id='photo' file-name='".$actual_image_name."' class='' src='".$filePath.'?'.time()."' class='preview'/>";
}
else
echo "failed";
}
else
echo "Image file size max 1 MB";
}
else
echo "Invalid file format..";
}
else
echo "Please select image..!";
exit;
}
/* Function to update image */
function saveProfilePicTmp() {
$post = isset($_POST) ? $_POST: array();
$userId = isset($post['id']) ? intval($post['id']) : 0;
$path ='imagestmp';
$t_width = 300; // Maximum thumbnail width
$t_height = 300; // Maximum thumbnail height
if(isset($_POST['t']) and $_POST['t'] == "ajax") {
extract($_POST);
$imagePath = 'images/tmp/'.$_POST['image_name'];
$ratio = ($t_width/$w1);
$nw = ceil($w1 * $ratio);
$nh = ceil($h1 * $ratio);
$nimg = imagecreatetruecolor($nw,$nh);
$im_src = imagecreatefromjpeg($imagePath);
imagecopyresampled($nimg,$im_src,0,0,$x1,$y1,$nw,$nh,$w1,$h1);
imagejpeg($nimg,$imagePath,90);
}
echo $imagePath.'?'.time();;
exit(0);
}
/* Function to resize image */
function resizeImage($image,$width,$height,$scale) {
$newImageWidth = ceil($width * $scale);
$newImageHeight = ceil($height * $scale);
$newImage = imagecreatetruecolor($newImageWidth,$newImageHeight);
switch ($ext) {
case 'jpg':
case 'jpeg':
$source = imagecreatefromjpeg($image);
break;
case 'gif':
$source = imagecreatefromgif($image);
break;
case 'png':
$source = imagecreatefrompng($image);
break;
default:
$source = false;
break;
}
imagecopyresampled($newImage,$source,0,0,0,0,$newImageWidth,$newImageHeight,$width,$height);
imagejpeg($newImage,$image,90);
chmod($image, 0777);
return $image;
}
/* Function to get image height. */
function getHeight($image) {
$sizes = getimagesize($image);
$height = $sizes[1];
return $height;
}
/* Function to get image width */
function getWidth($image) {
$sizes = getimagesize($image);
$width = $sizes[0];
return $width;
}
?>

Por último, guardamos la ruta de la imagen guardada en nuestra base de datos MySQL mediante la función saveProfilePic().

/* Function to handle profile pic update*/
function saveProfilePic(){
include_once("db_connect.php");
$post = isset($_POST) ? $_POST: array();
//Handle profile picture update with MySQL update Query using $options array
if($post['id']){
$sql_query = "SELECT * FROM users WHERE uid = '".mysqli_escape_string($conn, $post['id'])."'";
$resultset = mysqli_query($conn, $sql_query) or die("database error:". mysqli_error($conn));
if(mysqli_num_rows($resultset)) {
$sql_update = "UPDATE users set profile_photo='".mysqli_escape_string($conn,$post['image_name'])."' WHERE uid = '".mysqli_escape_string($conn, $post['id'])."'";
mysqli_query($conn, $sql_update) or die("database error:". mysqli_error($conn));
}
}
}

Fuente: phpzag.com

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP