Загрузчик изображений на PHP и HTML5 Jcrop

Загрузчик изображений на PHP и HTML5 Jcrop

02017-01-012858Денис Абдуллин

Загрузка изображений на PHP – это интересная тема, но акцент мы сделаем на другом. Важная деталь загрузки изображений – обрезка. Она должна быть привлекательной, и удобной. Кроме того, мы будем использовать HTML5 FileReader для того чтобы выполнить обрезку с Jcrop (JQuery библиотека). В результате у нас получится загрузка в 3 шага: выбор файла, обрезка и непосредственно загрузка. В момент выбора файла скрипт будет проверять тип и размер, чтобы избежать больших слишком изображений. Наконец, когда у нас уже все готово, выбрана область изображения, загружаем ее на сайт (в определенную папку). Пожалуйста, обратите внимание на то, что нужна GD библиотека, она необходима для загрузки изображений. Готовы? Давайте начнем.

Шаг 1. HTML

Во-первых, поместите стили в HEAD страницы:


Code
<!-- Стили-->
<link href="css/main.css" rel="stylesheet" type="text/css" />
<link href="css/jquery.Jcrop.min.css" rel="stylesheet" type="text/css" />

<!-- Скрипты -->
<script src="js/jquery.min.js"></script>
<script src="js/jquery.Jcrop.min.js"></script>
<script src="js/script.js"></script>

А теперь можно поставить в BODY нашу форму:


Code
<div class="bbody">

  <!-- upload form -->
  <form id="upload_form" enctype="multipart/form-data" method="post" action="upload.php" onsubmit="return checkForm()">
  <!-- hidden crop params -->
  <input type="hidden" id="x1" name="x1" />
  <input type="hidden" id="y1" name="y1" />
  <input type="hidden" id="x2" name="x2" />
  <input type="hidden" id="y2" name="y2" />

  <h2>Step1: Please select image file</h2>
  <div><input type="file" name="image_file" id="image_file" onchange="fileSelectHandler()" /></div>

  <div class="error"></div>

  <div class="step2">
  <h2>Step2: Please select a crop region</h2>
  <img id="preview" />

  <div class="info">
  <label>File size</label> <input type="text" id="filesize" name="filesize" />
  <label>Type</label> <input type="text" id="filetype" name="filetype" />
  <label>Image dimension</label> <input type="text" id="filedim" name="filedim" />
  <label>W</label> <input type="text" id="w" name="w" />
  <label>H</label> <input type="text" id="h" name="h" />
  </div>

  <input type="submit" value="Upload" />
  </div>
  </form>
</div>

Я надеюсь, что на этом этапе все предельно ясно, это обычная форма загрузки, включающая в себя скрытые места. Как только файл будет выбран, эти скрытые места будут показаны (это обрезка графики).

Шаг 2. CSS

Теперь я бы хотел дать код стиля нашей формы:

css/main.css


Code
.bheader {
  background-color: #DDDDDD;
  border-radius: 10px 10px 0 0;
  padding: 10px 0;
  text-align: center;
}
.bbody {
  color: #000;
  overflow: hidden;
  padding-bottom: 20px;
  text-align: center;

  background: -moz-linear-gradient(#ffffff, #f2f2f2);
  background: -ms-linear-gradient(#ffffff, #f2f2f2);
  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #ffffff), color-stop(100%, #f2f2f2));
  background: -webkit-linear-gradient(#ffffff, #f2f2f2);
  background: -o-linear-gradient(#ffffff, #f2f2f2);
  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f2f2f2');
  -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f2f2f2')";
  background: linear-gradient(#ffffff, #f2f2f2);
}
.bbody h2, .info, .error {
  margin: 10px 0;
}
.step2, .error {
  display: none;
}
.error {
  font-size: 18px;
  font-weight: bold;
  color: red;
}
.info {
  font-size: 14px;
}
label {
  margin: 0 5px;
}
input {
  border: 1px solid #CCCCCC;
  border-radius: 10px;
  padding: 4px 8px;
  text-align: center;
  width: 70px;
}
.jcrop-holder {
  display: inline-block;
}
input[type=submit] {
  background: #e3e3e3;
  border: 1px solid #bbb;
  border-radius: 3px;
  -webkit-box-shadow: inset 0 0 1px 1px #f6f6f6;
  box-shadow: inset 0 0 1px 1px #f6f6f6;
  color: #333;
  font: bold 12px/1 "helvetica neue", helvetica, arial, sans-serif;
  padding: 8px 0 9px;
  text-align: center;
  text-shadow: 0 1px 0 #fff;
  width: 150px;
}
input[type=submit]:hover {
  background: #d9d9d9;
  -webkit-box-shadow: inset 0 0 1px 1px #eaeaea;
  box-shadow: inset 0 0 1px 1px #eaeaea;
  color: #222;
  cursor: pointer;
}
input[type=submit]:active {
  background: #d0d0d0;
  -webkit-box-shadow: inset 0 0 1px 1px #e3e3e3;
  box-shadow: inset 0 0 1px 1px #e3e3e3;
  color: #000;
}

Шаг 3. JavaScript

Следующий шаг – это JavaScript. Комментарий ниже кода:

js/script.js


Code
// convert bytes into friendly format
function bytesToSize(bytes) {
  var sizes = ['Bytes', 'KB', 'MB'];
  if (bytes == 0) return 'n/a';
  var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)));
  return (bytes / Math.pow(1024, i)).toFixed(1) + ' ' + sizes[i];
};

// check for selected crop region
function checkForm() {
  if (parseInt($('#w').val())) return true;
  $('.error').html('Please select a crop region and then press Upload').show();
  return false;
};

// update info by cropping (onChange and onSelect events handler)
function updateInfo(e) {
  $('#x1').val(e.x);
  $('#y1').val(e.y);
  $('#x2').val(e.x2);
  $('#y2').val(e.y2);
  $('#w').val(e.w);
  $('#h').val(e.h);
};

// clear info by cropping (onRelease event handler)
function clearInfo() {
  $('.info #w').val('');
  $('.info #h').val('');
};

function fileSelectHandler() {

  // get selected file
  var oFile = $('#image_file')[0].files[0];

  // hide all errors
  $('.error').hide();

  // check for image type (jpg and png are allowed)
  var rFilter = /^(image\/jpeg|image\/png)$/i;
  if (! rFilter.test(oFile.type)) {
  $('.error').html('Please select a valid image file (jpg and png are allowed)').show();
  return;
  }

  // check for file size
  if (oFile.size > 250 * 1024) {
  $('.error').html('You have selected too big file, please select a one smaller image file').show();
  return;
  }

  // preview element
  var oImage = document.getElementById('preview');

  // prepare HTML5 FileReader
  var oReader = new FileReader();
  oReader.onload = function(e) {

  // e.target.result contains the DataURL which we can use as a source of the image
  oImage.src = e.target.result;
  oImage.onload = function () { // onload event handler

  // display step 2
  $('.step2').fadeIn(500);

  // display some basic image info
  var sResultFileSize = bytesToSize(oFile.size);
  $('#filesize').val(sResultFileSize);
  $('#filetype').val(oFile.type);
  $('#filedim').val(oImage.naturalWidth + ' x ' + oImage.naturalHeight);

  // Create variables (in this scope) to hold the Jcrop API and image size
  var jcrop_api, boundx, boundy;

  // destroy Jcrop if it is existed
  if (typeof jcrop_api != 'undefined')
  jcrop_api.destroy();

  // initialize Jcrop
  $('#preview').Jcrop({
  minSize: [32, 32], // min crop size
  aspectRatio : 1, // keep aspect ratio 1:1
  bgFade: true, // use fade effect
  bgOpacity: .3, // fade opacity
  onChange: updateInfo,
  onSelect: updateInfo,
  onRelease: clearInfo
  }, function(){

  // use the Jcrop API to get the real image size
  var bounds = this.getBounds();
  boundx = bounds[0];
  boundy = bounds[1];

  // Store the Jcrop API in the jcrop_api variable
  jcrop_api = this;
  });
  };
  };

  // read selected file as DataURL
  oReader.readAsDataURL(oFile);
}

Есть несколько общих функций в начале: bytesToSize, checkForm, updateInfo и clearInfo. Они довольно легкие. Следующая функция (fileSelectHandler) более сложная, это главная функция. Здесь можно увидеть скрипт, который проверяет формат изображений (PNG и JPG). И скрипт не пропустит картинки, имеющие вес больше 250kb. Если все верно, можно прочитать выбранный файл, используя FileReader::readAsDataURL (HTML5 функции). Как только мы обрезали изображение, нажимаем кнопку «Загрузить», чтобы загрузить результат на сервер.

Шаг 4. PHP

Скрипт позволит загрузить изображение на сервер:

upload.php


Code
function uploadImageFile() { // Note: GD library is required for this function

  if ($_SERVER['REQUEST_METHOD'] == 'POST') {
  $iWidth = $iHeight = 200; // desired image result dimensions
  $iJpgQuality = 90;

  if ($_FILES) {

  // if no errors and size less than 250kb
  if (! $_FILES['image_file']['error'] && $_FILES['image_file']['size'] < 250 * 1024) {
  if (is_uploaded_file($_FILES['image_file']['tmp_name'])) {

  // new unique filename
  $sTempFileName = 'cache/' . md5(time().rand());

  // move uploaded file into cache folder
  move_uploaded_file($_FILES['image_file']['tmp_name'], $sTempFileName);

  // change file permission to 644
  @chmod($sTempFileName, 0644);

  if (file_exists($sTempFileName) && filesize($sTempFileName) > 0) {
  $aSize = getimagesize($sTempFileName); // try to obtain image info
  if (!$aSize) {
  @unlink($sTempFileName);
  return;
  }

  // check for image type
  switch($aSize[2]) {
  case IMAGETYPE_JPEG:
  $sExt = '.jpg';

  // create a new image from file
  $vImg = @imagecreatefromjpeg($sTempFileName);
  break;
  case IMAGETYPE_PNG:
  $sExt = '.png';

  // create a new image from file
  $vImg = @imagecreatefrompng($sTempFileName);
  break;
  default:
  @unlink($sTempFileName);
  return;
  }

  // create a new true color image
  $vDstImg = @imagecreatetruecolor( $iWidth, $iHeight );

  // copy and resize part of an image with resampling
  imagecopyresampled($vDstImg, $vImg, 0, 0, (int)$_POST['x1'], (int)$_POST['y1'], $iWidth, $iHeight, (int)$_POST['w'], (int)$_POST['h']);

  // define a result image filename
  $sResultFileName = $sTempFileName . $sExt;

  // output image to file
  imagejpeg($vDstImg, $sResultFileName, $iJpgQuality);
  @unlink($sTempFileName);

  return $sResultFileName;
  }
  }
  }
  }
  }
}

$sImage = uploadImageFile();
echo '<img src="'.$sImage.'" />';

Вы видите, что проверка формата и размера происходит не только на стороне клиента, но и на стороне сервера. Таким образом, мы защищаем сайт от ненужных файлов. Пожалуйста, обратите внимание, что на выходе мы получаем небольшое изображение (200x200). В конце мы видим изображение на экране.


Создать сайт в uKit Нужен классный сайт для бизнеса?
Воспользуйтесь сервисом uKit. Никакого кода!
Чтобы оставить комментарий или отзыв под этой публикацией, войдите или зарегистрируйтесь.