MODX - Добавление фото пользователю

Александр Мальцев
9.4K
1
Содержание:
  1. Подготовительные шаги
  2. Правка ресурса "Редактирование данных"
  3. Создание сниппета для добавления фото
  4. Комментарии

В этой статье рассмотрим какие необходимо осуществить действия в MODX Revolution для того чтобы у авторизированного пользователя появилась возможность устанавливать себе фото.

Подготовительные шаги

Возможность загружать пользователю своё фото рассмотрим на примере ресурса "Редактирование данных". Это означает то, что перед тем как переходить к чтению материала этого урока, желательно познакомиться со статьёй MODX - Login (Личный кабинет пользователя).

Процесс добавления нового функционала в ресурс "Редактирование данных" начнём с простых вещей:

  1. Создания директории photouser в каталоге assets. Данную директорию будем использовать для хранения фото (аватарок) пользователей.
  2. Подготовки изображения, которое будет иметь пользователь пока он не загрузит своё фото. Например, для пользователей не имеющих своей собственной аватарки будем использовать изображение "default.jpg", которое поместим в папку photouser. В качестве разрешения для фото (аватарок) пользователей остановимся на значении 100x100.

MODX Login - Фото пользователя по умолчанию

После выполнения вышеописанных действий перейдём к правке ресурса "Редактирование данных" и создания сниппета для загрузки фото.

Правка ресурса "Редактирование данных"

MODX Login - Редактирование ресурса UpdateProfile


Откроем ресурс "Редактирования данных" и внесём в него следующие изменения:

  1. Добавим в вызов сниппета UpdateProfile параметр preHooks. Параметр preHooks позволит подключить дополнительную функциональность - вызов сниппета loadUserPhoto до выполнения основных действий UpdateProfile.

    Сниппет loadUserPhoto будем использоваться для выполнения на сервере следующих действий:

    • загрузки фото пользователя в директорию /assets/photouser;
    • удаления файла, содержащего фото, по запросу пользователя;
    • установки необходимого значения полю photo, перед тем как оно будет записано в профиль. Для задания необходимого значения полю photo будем использовать метод $hook->setValue().

    Примечание. В качестве имени фото пользователя будем использовать следующий шаблон.

    user[idUser].[extFile]
    //[idUser] - id пользователя
    //[extFile] - исходное расширение фото
    Например:
    user1.png - фото пользователя с id=1
    user6.jpg - фото пользователя с id=6
    

    Код вызова сниппета UpdateProfile:

    [[!UpdateProfile? &validate=`fullname:required` &preHooks=`loadUserPhoto`]]
  2. Добавим к элементу form атрибут enctype со значением "multipart/form-data". Это необходимо сделать для того чтобы форму можно было отправлять с вложениями (файлами).

    <form action="[[~[[*id]]]]" method="post" class="form-horizontal" enctype="multipart/form-data">
  3. Добавим в форму элемент input с помощью которого пользователь сможет прикреплять изображение (файл) к форме.

    <!-- Input для загрузки фото пользователя -->
    <div class="form-group">
      <label for="photo" class="col-sm-4 control-label" style="padding-top: 0px; padding-bottom: 6px;">Фото</label>
      <div class="col-sm-8" style="padding-top: 0px; padding-bottom: 6px;">
        <input type="file" id="photo" name="photo" value="[[+photo]]">
      </div>
    </div>
  4. Добавим на страницу перед формой заголовок, который будет выводить изображение пользователя и его имя. Если пользователь не имеет аватарку, то в качестве изображения будет использоваться файл default.jpg. Осуществить это в MODX Revolution можно с помощью фильтра default, который будет проверять содержимое плейсхолдера photo. Если плейсхолдер photo имеет значение, то использовать его. В противном случае выводить картинку по умолчанию.

    <!-- Блок, содержащий фото и имя пользователя -->
    <div id="crop" class="img-rounded center-block" style="height: 100px; width: 100px; overflow: hidden;">
      <img  id="img-photo" src="[[+photo:default=`/assets/photouser/default.jpg`]]">
    </div>
    <p class="lead text-center">[[+fullname]]</p>
    <hr>
  5. Добавим на страницу кнопку (элемент input с type="submit"), который будет удалять фото пользователя.

    <!-- Кнопка "Удалить фото" -->
    <input type="submit" value="Удалить фото" name="delete-photo-btn" id="login-updprof-btn" class="btn btn-primary pull-left">
  6. Напишем скрипт на языке JavaScript с использованием функций библиотеки jQuery. Данный скрипт будет показывать аватар (фото) пользователя ещё до загрузки его на сервер. Функционал скрипта основывается на File API, который появился в HTML5.
    <script>
    // После загрузки страницы
    $(function(){
      // Произошло изменение значения элемента с id = "photo"
      $('#photo').change(function(e){
        // Если браузер не поддерживает FileReader, то ничего не делаем
        if (!window.FileReader) {
          console.log('Браузер не поддерживает File API');
          return;
        }
        // Получаем выбранный файл (изображение)
        var file = e.target.files[0];
        // Выводим сообщение, что браузер не поддерживает указанный тип файла    
        if (!((file.type=='image/png') || (file.type=='image/jpeg'))) {
          $('#img-error').text('Загруженный файл не является изображением');
          return;
        }
        // Выводим сообщение, что файл имеет большой размер 
        if (file.size>=524288) {
          $('#img-error').text('Размер файла больше чем 512Кбайт');
          return;      
        }
        $('#img-error').text('');
        // Создаём экземпляр объекта FileReader, посредством которого будем читать файл
        var reader = new FileReader();
        // После успешного завершения операции чтения файла
        $(reader).on('load', function(event){
        // Указываем в качестве значения атрибута src изображения содержимое файла (картинки) 
        $('#img-photo').attr('src',event.target.result);
        // Изменяем ширину и высоту изображения
          if ($('#img-photo').width()>=$('#img-photo').height()) {
            $('#img-photo').css('height','100px');
            $('#img-photo').css('margin-left',-($('#img-photo').width()-100)/2);
          } 
          else {
            $('#img-photo').css('widht','100px');   
            $('#img-photo').css('margin-top',-($('#img-photo').height()-100)/2); 
          }
        });
        // Запускает процесс чтения файла (изображения). После завершения чтения файла его содержимое будет доступно посредством атрибута result
        reader.readAsDataURL(file);
      });
      // Перед отправкой формы на сервер...
      $("#updateProfile").submit(function(e) {
        // Проверяем значения поля photo. Если оно равно пустой строке, то данные отправляем
        if ($('#photo').val()=='') {
          return;
        }
        // Если элемент содержит некоторую строку (ошибки связанные с фото), то отменяем отправку формы
        if ( (($('#img-error').text()).length>0)) {
          e.preventDefault();
        }
      });  
    });
    </script>

В итоге ресурс "Редактирование данных" будет иметь следующий основный код:

[[!UpdateProfile? &validate=`fullname:required` &preHooks=`loadUserPhoto`]]

<script>
// После загрузки страницы
$(function(){
  // Произошло изменение значения элемента с id = "photo"
  $('#photo').change(function(e){
    // Если браузер не поддерживает FileReader, то ничего не делаем
    if (!window.FileReader) {
      console.log('Браузер не поддерживает File API');
      return;
    }
    // Получаем выбранный файл (изображение)
    var file = e.target.files[0];
    // Выводим сообщение, что браузер не поддерживает указанный тип файла    
    if (!((file.type=='image/png') || (file.type=='image/jpeg'))) {
      $('#img-error').text('Загруженный файл не является изображением');
      return;
    }
    // Выводим сообщение, что файл имеет большой размер 
    if (file.size>=524288) {
      $('#img-error').text('Размер файла больше чем 512Кбайт');
      return;      
    }
    $('#img-error').text('');
    // Создаём экземпляр объекта FileReader, посредством которого будем читать файл
    var reader = new FileReader();
    // После успешного завершения операции чтения файла
    $(reader).on('load', function(event){
    // Указываем в качестве значения атрибута src изображения содержимое файла (картинки) 
    $('#img-photo').attr('src',event.target.result);
    // Изменяем ширину и высоту изображения
      if ($('#img-photo').width()>=$('#img-photo').height()) {
        $('#img-photo').css('height','100px');
        $('#img-photo').css('margin-left',-($('#img-photo').width()-100)/2);
      } 
      else {
        $('#img-photo').css('widht','100px');   
        $('#img-photo').css('margin-top',-($('#img-photo').height()-100)/2); 
      }
    });
    // Запускает процесс чтения файла (изображения). После завершения чтения файла его содержимое будет доступно посредством атрибута result
    reader.readAsDataURL(file);
  });
  // Перед отправкой формы на сервер...
  $("#updateProfile").submit(function(e) {
    // Проверяем значения поля photo. Если оно равно пустой строке, то данные отправляем
    if ($('#photo').val()=='') {
      return;
    }
    // Если элемент содержит некоторую строку (ошибки связанные с фото), то отменяем отправку формы
    if ( (($('#img-error').text()).length>0)) {
      e.preventDefault();
    }
  });  
});
</script>


<div class="container">
  <div class="row">
    <div class="col-md-8 col-lg-6">
      <div class="panel panel-primary">
        <div class="panel-heading"><i class="glyphicon glyphicon-edit"></i> Редактирование данных</div>
        <div class="panel-body">
          <div class="updprof-error">[[+error.message]]</div>
          [[+login.update_success:is=`1`:then=`[[%login.profile_updated? &namespace=`login` &topic=`updateprofile`]]`]]
          <form id="updateProfile" action="[[~[[*id]]]]" method="post" class="form-horizontal" enctype="multipart/form-data">
            <input type="hidden" name="nospam" value="">
            <!-- Блок, содержащий фото и имя пользователя -->
            <div id="crop" class="img-rounded center-block" style="height: 100px; width: 100px; overflow: hidden;">
              <img  id="img-photo" src="[[+photo:default=`/assets/photouser/default.jpg`]]">
            </div>
            <p class="lead text-center">[[+fullname]]</p>
            <hr>
            <div class="form-group">
              <label for="fullname" class="col-sm-4 control-label">[[!%login.fullname? &namespace=`login` &topic=`updateprofile`]]</label>
              <div class="col-sm-8">
                <input type="text" name="fullname" class="form-control" id="fullname" value="[[+fullname]]">
                <span class="help-block text-error">
                  [[+error.fullname]]
                </span>        
              </div>      
            </div>
            <!-- Input для загрузки фото пользователя -->
            <div class="form-group">
              <label for="photo" class="col-sm-4 control-label" style="padding-top: 0px; padding-bottom: 6px;">Фото</label>
              <div class="col-sm-8" style="padding-top: 0px; padding-bottom: 6px;">
                <input type="file" id="photo" name="photo" value="[[+photo]]">
                <span id="img-error" class="help-block text-error"></span>  
              </div>
            </div>
            <div class="form-group">
              <label for="phone" class="col-sm-4 control-label">[[!%login.phone]]</label>
              <div class="col-sm-8">
                <input type="text" name="phone" class="form-control" id="phone" value="[[+phone]]">
                <span class="help-block text-error">
                  [[+error.phone]]
                </span>        
              </div>      
            </div> 
            <div class="form-group">
              <label for="mobilephone" class="col-sm-4 control-label">[[!%login.mobilephone]]</label>
              <div class="col-sm-8">
                <input type="text" name="mobilephone" class="form-control" id="mobilephone" value="[[+mobilephone]]">
                <span class="help-block text-error">
                  [[+error.mobilephone]]
                </span>        
              </div>      
            </div> 
            <div class="form-group">
              <label for="address" class="col-sm-4 control-label">[[!%login.address]]</label>
              <div class="col-sm-8">
                <input type="text" name="address" class="form-control" id="address" value="[[+address]]">
                <span class="help-block text-error">
                  [[+error.address]]
                </span>        
              </div>      
            </div>  
            <div class="form-group">
              <label for="country" class="col-sm-4 control-label">[[!%login.country]]</label>
              <div class="col-sm-8">
                <input type="text" name="country" class="form-control" id="country" value="[[+country]]">
                <span class="help-block text-error">
                  [[+error.country]]
                </span>        
              </div>      
            </div>   
            <div class="form-group">
              <label for="city" class="col-sm-4 control-label">[[!%login.city]]</label>
              <div class="col-sm-8">
                <input type="text" name="city" class="form-control" id="city" value="[[+city]]">
                <span class="help-block text-error">
                  [[+error.city]]
                </span>        
              </div>      
            </div>  
            <div class="form-group">
              <label for="website" class="col-sm-4 control-label">[[!%login.website]]</label>
              <div class="col-sm-8">
                <input type="text" name="website" class="form-control" id="website" value="[[+website]]">
                <span class="help-block text-error">
                  [[+error.website]]
                </span>        
              </div>      
            </div>  
            <!-- Кнопка "Удалить фото" -->
            <input type="submit" value="Удалить фото" name="delete-photo-btn" id="login-updprof-btn" class="btn btn-primary pull-left">
            <!-- Кнопка "Обновить данные" -->
            <input type="submit" value="Обновить данные" name="login-updprof-btn" id="login-updprof-btn" class="btn btn-primary pull-right">
          </form>
        </div>
      </div>
    </div>
  </div>
</div>

Страница "Редактирование данных" будет иметь следующий вид:

MODX Login - Редактирование ресурса UpdateProfile

Отображать некоторые ошибки будем непосредственно под полем, с помощью которого пользователь загружает фото:

MODX Login - Ошибки при загрузке фото

Создание сниппета для добавления фото

Создадим сниппет loadUserPhoto.

MODX Login - Создание сниппета для загрузки фото пользователя

Вставим в поле код сниппета (php) следующее содержимое:

<?php
// Получить профиль пользователя
$profile = $modx->user->getOne('Profile');
// Получить значение поля photo
$pathToPhoto = $profile->get('photo');
// Установить полю photo текущее значение
$hook->setValue('photo',$pathToPhoto);

// Запрос на удаление картинки (глобальный массив POST имеет ключ delete-photo-btn со значением отличным от NULL)
if (isset($_POST['delete-photo-btn'])) {
  // Если поле photo не пустое, то..
  if ($pathToPhoto) {
    // Сформировать полный путь к файлу (фото)
    $fullPathToPhoto = $modx->config['base_path'].$pathToPhoto;
    // Если файл (фото) есть, то удалить его
    if(file_exists($fullPathToPhoto))
      unlink($fullPathToPhoto);
    // Установить полю photo пустое значение
    $hook->setValue('photo','');
  }
}

// Запрос на обновление (глобальный массив POST имеет ключ login-updprof-btn со значением отличным от NULL)
if (isset($_POST['login-updprof-btn'])) {
  // Допустимые расширения (jpg, png, jpeg)
  $validExt = array('jpg', 'png', 'jpeg');
  // Директория для хранения фото пользователей
  $pathToPhoto = $modx->config['base_path'] . 'assets/photouser/';
  // Имя файла пользователя 
  $nameFile = $_FILES['photo']['name'];
  // Получить расширение загруженного пользователем файла в нижнем регистре
  $extFile = mb_strtolower(pathinfo($nameFile, PATHINFO_EXTENSION));
  // Временное имя, с которым принятый файл был сохранён на сервере
  $tmpFile = $_FILES['photo']['tmp_name'];
  // Если файл загружен посредством HTTP POST и ошибок в процессе загрузке не возникло, то...
  if ((is_uploaded_file($tmpFile)) && !($_FILES['photo']['error'])) {
    // Проверям соответствует ли расширение файла допустимому. Если всё хорошо, то...
    if(in_array($extFile, $validExt)) {
      // Формируем имя файлу (фото)
      $nameFilePhoto = 'user'.$modx->user->get('id') . '.' . $extFile;
      // Получаем полное имя файла (фото)
      $fullNameFilePhoto = $pathToPhoto . $nameFilePhoto;
      // Перемещаем временный файл на новое место $fullNameFilePhoto. Если всё прошло успешно, то...
      if (move_uploaded_file($tmpFile, $fullNameFilePhoto)) {
        // если файл phpthumb.class.php не был подключён, то включить его
        require_once MODX_CORE_PATH.'model/phpthumb/phpthumb.class.php';
        // Создать новый экземпляр класса phpThumb
        $phpThumb = new phpThumb();
        // Указываем исходное изображение
        $phpThumb->setSourceFilename($fullNameFilePhoto);
        // Устанавливаем ширину изображению
        $phpThumb->setParameter('w', 100);
        // Устанавливаем высоту изображению
        $phpThumb->setParameter('h', 100);
        // Задаём тип обрезки
        $phpThumb->setParameter('zc', '1');
        // Задём качество изображения
        $phpThumb->setParameter('q', '80');
        // Генерируем уменьшенное изображение. Если действие прошло успешно, то...
        if ($phpThumb->GenerateThumbnail()) {
          // Сохраняем изображение в файл $fullNameFilePhoto. Если данное действие завершилось успехом, то..
          if ($phpThumb->RenderToFile($fullNameFilePhoto)) {
            // Устанавливаем в поле photo путь к файлу 
            $hook->setValue('photo',$modx->getOption('assets_url'). 'photouser/' . $nameFilePhoto);
          }
          else {
            $modx->log(modX::LOG_LEVEL_ERROR, 'Ошибка при сохрании изображения в файл '.$fullNameFilePhoto);
          }
        }
        else {
          // Записываем полученую ошибку в журнал MODX
          $modx->log(modX::LOG_LEVEL_ERROR, print_r($phpThumb->debugmessages, 1));
        }
      }
      else {
        // Записываем в журнал что произошла ошибка при перемещении файла на новое место
        $modx->log(modX::LOG_LEVEL_ERROR, 'Ошибка при перемещении временного файла '.$tmpFile.' на новое место '.$fullNameFilePhoto);
      }
    } 
    else {
      // Записываем в журнал сообщение о том, что расширение файла не соответствует разрешённому
      $modx->log(modX::LOG_LEVEL_ERROR, 'Изображение имеет недопустимое расширение');
    }
  }
  else {
    // Записываем в журнал что произошла ошибка при загрузке файла
    $modx->log(modX::LOG_LEVEL_ERROR, 'Ошибка при загрузке файла. Код ошибки: '.$_FILES['photo']['error']);
  }
}
return true;

Скачать файлы с гитхаба

Комментарии ()

  1. Егор
    03 августа 2020, 17:20
    В снипите loadUserPhoto картинка постояно улетала в кэш браузера так как имела одно и тоже название. решил, проблему, поправив код id заменил на time() теперь у нас всегда будут уникальные имена у аватарок

    $nameFilePhoto = 'user'.$modx->user->get('id'). '_'. time(). '.'. $extFile;
    1. Александр Мальцев
      06 августа 2020, 06:07
      Да, правильно. Также можно вместо time() использовать функцию uniqid(). Она в php предназначена для генерации уникального id.
    2. Amsterdam
      16 марта 2019, 09:06
      Вот об этом речь:


      Почему то источник файлов читает путь от КОРНЯ ПАПКИ, а не от корня сайта, изза этого путь изображения формируется неверно. Почему так получается?
      1. Amsterdam
        15 марта 2019, 00:42
        Александр, доброго времени суток

        Не подскажешь? Никак не могу разобраться с источником файлов. Создаю свой собственный, указываю в basePath и baseUrlRelative путь до нужной папки, куда планируется грузить файлы. Присваиваю TVшке этот новый источник файлов на вкладке «источник файлов».

        Загружаю файл через TV, которая как и надо, открывает нужную папку, указанную в источнике. НО, проблема в том, что этот источник не выстраивает полный путь до файла, а выводит только его название, изза чего вывести его на страницу невозможно.

        Почему так получается? Бьюсь уже несколько часов, не могу понять почему такой бред выходит
        1. Александр Мальцев
          18 марта 2019, 14:47
          Доброго!
          Кроме basePath источнику файлов нужно ещё задать baseUrl, т.е. URL по которому будет доступен этот источник файлов.
          1. Amsterdam
            19 марта 2019, 09:08
            Да, так и делается, оба источника идентичны. Однако проблема имеет место быть. Как я понял, в MODx, почему то, так и есть по умолчанию. А различные плагины и сниппеты уже сами подставляют полный путь до файла.

            Какая то немного абсурдная система получается, но если я правильно понял, так оно и есть. Рад был бы ошибаться
            1. Александр Мальцев
              19 марта 2019, 14:32
              Мне кажется тут всё логично: URL файла в определённом контексте будет складываться из baseUrl + путь от корня источника файлов до картинки.
              1. Amsterdam
                19 марта 2019, 16:11
                Ну смотрите:

                baseUrl: templates/img/
                basePath: templates/img/

                В итоге при выборе картинки в файлменеджере она получает путь от корня папки, в которой находится, т.е. в пути высвечивается просто imagename.jpg, без фактического его местоположения: templates/img/imagename.jpg

                И как при таком раскладе вывести фото во фронте?
                1. Александр Мальцев
                  20 марта 2019, 14:14
                  В MODX 2.7.1 таких проблем нет. В шаблоне просто указываем имя TV, на фронте получаем полный путь.
                  Например:
                  <img src="[[*image]]" alt="">
                  
                  У TV в настройках во вкладке «Источники файлов» указывается источник файлов, который будет использован этим TV в каждом указанном контексте. Т.е. при выводе TV в указанном контексте путь до картинки будет составляться из значения baseUrl источника файлов и пути от корня источника файлов до картинки.
                  1. Amsterdam
                    21 марта 2019, 06:15
                    Да, действительно… Недосмотрел. Это в паре с MIGx происходит вышеописанная проблема. Особенно если выводить таким способом:

                    "sourceFrom":"config","sources":"[{\"MIGX_id\":\"1\",\"context\":\"web\",\"sourceid\":\"3\"}
                    Либо упрощенным, когда создаешь специальное TV и задаешь для него источник файлов, тоже не выводится корректно

                    "inputTV":"image"
                    Как с ним решить проблему, более интересный вопрос…
                    1. Александр Мальцев
                      21 марта 2019, 16:00
                      При настройке полей в MIGX есть вкладка «Mediasources». Там определяется источник.

                      Например, если вы создаёте поле «image» c «inputTVType: image», то можно указать источник «migx». А в таблице создать строку, в которой задать, какой id источника файлов использовать для конкретного контекста.
                      1. Amsterdam
                        22 марта 2019, 13:04
                        Имеете ввиду вот так?:

                        «field»:«image2»,
                        «caption»:«Image»,
                        «inputTVtype»:«image»,
                        «sourceFrom»:«migx»,
                        «sources»:"[{\«MIGX_id\»:\«1\»,\«context\»:\«web\»,\«sourceid\»:\«3\»}]

                        Где «3» — id источника файлов, присвоенного TV MIGx? Об этом речь (пример на скриншоте), или о какой то другой таблице?

                        1. Александр Мальцев
                          23 марта 2019, 14:19
                          Да, про источник самого файла (скриншот момента, но это когда используется мастер):

                          Но в качестве sourceid указать id источника файлов, который вы хотите использовать для вывода этого поля (картинки). Не обязательно он должен совпадать с id источника файлов, который используется для самого TV.
                          1. Amsterdam
                            25 марта 2019, 07:49
                            Интересно, но никак не могу найти, где расположена эта вкладка Mediasources?.. как до нее добраться, в настройках MIGx не вижу
                            1. Александр Мальцев
                              27 марта 2019, 14:01
                              Это вкладка расположена не в разделе где вы создаете TV, а в MIGX. На вкладке «Formtabs», предназначенной для создания полей.
                              Т.к. вы не используете MIGX мастер, то источник файлов указывается с помощью sourceid, как вы написали выше:
                              "sourceFrom":"migx", 
                              "sources":"[{\"MIGX_id\":\"1\",\"context\":\"web\",\"sourceid\":\"3\"}
                              
        2. Сергей
          18 декабря 2018, 19:08
          Добрый день! Скажите, а как интегрировать Login и Modxtalks, чтобы в комментариях эта фотка присутствовала?
          А то сейчас фото только в личном кабинете, а в комментариях стандартная с граватара.
          Спасибо
          1. Александр Мальцев
            21 декабря 2018, 15:02
            Добрый! Фото сохраняется в стандартное поле photo пользователя. Можете просто написать простенький сниппет, которому на вход будете передавать id пользователя, а на выходе получать url картинки. После этого данный сниппет поместить в чанк и в качестве параметра передавать ему на вход плейсхолдер, содержащий id пользователя.
          2. Дмитрий
            08 августа 2018, 16:27
            а можно сделать так. чтобы фото само обрабатывалось до нужного размера и формата. если не подошло?
            1. Александр Мальцев
              12 августа 2018, 05:10
              На сервере, это можно, например, выполнить с помощью библиотеки phpthumb.
            2. Константин
              19 мая 2018, 23:35
              Добрый вечер! Спасибо за данную инструкцию! Есть небольшая проблемка. У меня создан еще один источник файлов Images и в системных настройках выбран по-умолчанию. Значение basePath и baseUrl в нем assets/img/ Отсюда и возникают проблемы.

              Дело в том, что когда я загружаю фото, то на самом сайте в профиле пользователя, в комментариях от Tickets, аватарка отображается корректно, но в админке аватарка не отображается, так как не корректно формируются пути к ней из-за выбранного по-умолчанию другого источника файлов:

              При каждом обновлении любой страницы в админке, в журнале ошибок появляется по одной такой записи:
              [2018-05-19 23:06:59] (ERROR @ /.../public_html/core/model/phpthumb/modphpthumb.class.php : 121) phpThumb was unable to generate a thumbnail for: /.../public_html/core/cache/phpthumb/news.kos076.beget.tech__srce764e99ef2773adcc608592623680f4a_par397327b300e2532553c171cb19a456f3_dat0.jpeg
              [2018-05-19 23:06:59] (ERROR @ /.../public_html/core/model/phpthumb/modphpthumb.class.php : 133) Error outputting thumbnail:
              OutputThumbnail() failed because !is_resource($this->gdimg_output) in file "phpthumb.class.php" on line 618
              Я так понимаю, что phpthumb не может сгенерировать мою аватарку, поэтому она не отображается и сыпятся ошибки.

              При загрузке фото, в админке в профиле, там где поле Фотография пользователя, формируется путь к фото /assets/img/photouser/user1-1631743318.png (я немного изменил Ваш сниппет и указал в строке 28 $pathToPhoto = $modx->config['base_path']. 'assets/img/photouser/';), а реальный путь к фото в админке такой /.../public_html/assets/img//assets/img/photouser/user1-1631743318.png, поэтому такая проблема.

              Как переделать сниппет, чтобы учитывался любой другой источник файлов и все отображалось корректно? буду благодарен за любую помощь!
              1. Александр Мальцев
                22 мая 2018, 14:40
                Добрый! Для этого необходимо настроить пути. Например: yadi.sk/d/_LwyYrJ43WMChv
                Папку photouser в этом случае нужно переместить в /assets/img/.

                1. Benni
                  03 июня 2018, 19:00
                  Такая же проблема. Вместо аватарки в админ-панели вот что (тот же скрин что у комментария выше):

                  /connectors/system/phpthumb.php?zc=1&h=128&w=128&src=/var/www/.../public_html/domain/assets/files/images/photouser/user1.jpg?1658906912
                  При этом дефолтный источник файлов —
                  assets/files/images/
                  Как добиться такого пути —
                  /assets/img/photouser/user1.jpg?1658906912
                  ?

                  P.S.
                  На самом сайте все хорошо выводится.
                  1. Константин
                    27 мая 2018, 19:41
                    Спасибо, но не получается по Вашему. В админке аватарка теперь отображается, но на сайте ее нет. Путь к изображению на сайте примерно такой:
                    <img id="img-photo" src="photouser/user1.png">
                    Естественно, что по такому пути фото нет, так как оно загружается в:
                    assets/img/photouser/user1.png
                    Не знаю куда уже и думать. Почему не добавляется часть пути assets/img/, которую я указал в basePath и baseUrl в источнике файлов?
                    1. Александр Мальцев
                      28 мая 2018, 13:32
                      В чанке просто необходимо добавить к картинке часть пути, т.е. /assets/img/.
                      <img id="img-photo" src="/assets/img/[[+photo:default=`photouser/default.jpg`]]">
                      
                2. Pasha
                  23 мая 2017, 18:16
                  какая полезная статья! очень сократило время, спасибо!

                  А у вас на сайте используется какое дополнение для регистрации, авторизации и редактирования профиля пользователя?
                  1. cheizer
                    22 февраля 2017, 11:07
                    Спасибо, работает, но похоже требует много доработок, например таких как задать уникальное имя загружаемого файла, иначе в отчетах ошибки мол файл существует и тд, класть файл в созданную автоматом папку с именем как id пользователя и тд. Так же очищать кеш после отправки формы, иначе старый показывает часто файл. В любом случае спасибо за сниппет.

                    Но я не об этом хотел спросить, скажите пожалуйста, каким снипетом реализована у вас регистрация пользователей по методу AJAX?
                    1. Александр Мальцев
                      23 февраля 2017, 16:05
                      На основе компонента MODX Revolution Office.
                    2. Sergey
                      28 ноября 2016, 08:47
                      Всё работает кроме одного момента
                      Когда отправляешь форму с обновленной картинкой, т.е. была какая-то, установил новую и отправил
                      Сначала, при выборе новой картинки, как и положено JS устанавливает картинку новую, но после отправления формы, страница перегружается и картинка опять старая и нужно рефрешить страницу что бы показалась новая картинка. Видимо берется из кеша.
                      Как решить проблему?
                      1. Sergey
                        28 ноября 2016, 09:18
                        Нашел такое решение, надо в снипете в строке, где возвращаем путь до файла, дописать случайный параметр:

                        $hook->setValue('photo',$modx->getOption('assets_url'). 'photouser/' . $nameFilePhoto . '?' . rand());
                        тогда браузер будет думать что это новая картинка и не будет брать ее из кеша
                      2. Ми
                        14 ноября 2016, 20:03
                        Как я понимаю — это скрипт не отрабатывает.
                        1. Александр Мальцев
                          15 ноября 2016, 10:29
                          Здравствуйте. Вам необходимо к странице подключить библиотеку jQuery.
                        2. Ми
                          14 ноября 2016, 19:42
                          Доброго времени суток!
                          Огромное спасибо за создание и поддержание очень интересного, нужного ресурса.
                          При работе с данным уроком (выполнял всё как написано и перепроверял) столкнулся со следующими проблемами:
                          1. Когда изначально фото аватарки не загруженно, но мы редактируем другие параметры, а аватар не трогаем (не подгружаем), то модекс выдает ошибку
                          [2016-11-14 22:24:07] (ERROR @ /home/........../core/cache/includes/elements/modsnippet/22.include.cache.php: 87) Ошибка при загрузке файла. Код ошибки: 4
                          2. В консоле браузера весит такая ошибка
                          Uncaught ReferenceError: jQuery is not defined
                          3. Не происходит проверки изображения на максимальный размер и на соответствие формату
                          4. При загрузке фото и редактирования профиля — всё работает, но чтобы фотография поменялась над формой нужно еще раз обновить страницу.
                          5. Согласно вашему 6 пункту «Напишем скрипт на языке JavaScript с использованием функций библиотеки jQuery. Данный скрипт будет показывать аватар (фото) пользователя ещё до загрузки его на сервер. Функционал скрипта основывается на File API, который появился в HTML5.» — вот с этим тоже проблема. Файл на сервер грузится, но до загрузки его на сервер не отображается

                          Во всём остальном всё работает. Фото удаляет, изменения вносятся и работает как часы.

                          Подскажите каким образом можно поправить данные ошибки?
                          1. Александр
                            04 октября 2016, 19:04
                            Нет, не забыл.

                            1. Создания директории photouser в каталоге assets. Данную директорию будем использовать для хранения фото (аватарок) пользователей.
                            1. Артем
                              03 октября 2016, 07:14
                              Автор забыл добавить, что нужно создать папку в assets «photouser».
                              После этого фотографии успешно загружаются.
                              1. Питон
                                10 августа 2016, 08:57
                                И еще — вы не написали как выводить фотку в кабинет теперь? Добавлю — пишет — профиль обновлен, а фотка не меняется. Убрал лишние библиотеки — все равно не работает.
                                1. Александр Мальцев
                                  11 августа 2016, 13:01
                                  Если хотите это сделать на любой странице, то это будет так:
                                  [[!+modx.user.id:isloggedin:is=`1`:then=`<img src="[[!+modx.user.id:userinfo=`photo`:default=`/assets/photouser/default.jpg`]]">`:else=``]]
                                  
                                  Можно также использовать сниппет Profile:
                                  [[!Profile]]
                                  <img src="[[+photo:default=`/assets/photouser/default.jpg`]]">
                                  
                                  1. Питон
                                    11 августа 2016, 13:47
                                    Спасибо. Получилось.
                                2. Питон
                                  10 августа 2016, 08:52
                                  Долгожданно, спасибо. Но возникли сложности. Судя по всему не работает скрипт (подозреваю только у меня). Не обновляется по нажатию кнопки «Обновить» и имя файла добавляется, а самого файла нет. Подскажите в чем может быть проблема — замечал и в другом месте: примитивный скрипт отрабатывает, а что-то посолиднее нет. Может из-за конфликта с $?
                                  1. Александр Мальцев
                                    11 августа 2016, 12:23
                                    Попробуйте безопасное использование $. Для этого код скрипта необходимо обернуть в следующий контейнер:
                                    jQuery(function($) {
                                      //...
                                    });
                                    
                                    Кроме этого код скрипта, необходимо размещать после подключения библиотеки jQuery. В противном случае: если Вы разместите код до подключения библиотеки jQuery, то она (jQuery) будет недоступна.
                                    1. Питон
                                      11 августа 2016, 14:13
                                      попробовал пути менять — бесполезно. Получается, что имя файла записывается (я вижу его имя), оно сформировано правильно — user[[id]].jpd а внутри файл пустой.
                                      1. Питон
                                        11 августа 2016, 14:00
                                        Спасибо за подсказку. Пока не получилось, однако как минимум одну другую ошибку устранил у себя после переноса подключения библиотеки jQuery выше.
                                        jQuery(function($) {
                                          //...
                                        });
                                        Пробовал и такой вариант, но увы, не работает. Разбираюсь в коде скрипта и запутался с photo и img-photo. Это не одно и тоже? простите за не понимание…
                                        — И еще: может причина в этом:

                                        if (move_uploaded_file($tmpFile, $fullNameFilePhoto)) {
                                                // если файл phpthumb.class.php не был подключён, то включить его
                                                require_once MODX_CORE_PATH.'model/phpthumb/phpthumb.class.php';
                                        Тут путь относительный или полный. У меня он лежит:
                                        assets/core/model/phpthumb/phpthumb.class.php
                                        1. Александр Мальцев
                                          11 августа 2016, 14:27
                                          Если Вы сомневаетесь в наличии phpthumb.class.php то удалите следующее содержимое:
                                          if (move_uploaded_file($tmpFile, $fullNameFilePhoto)) {
                                            // <- удалить содержмое 
                                          }
                                          
                                          1. Питон
                                            11 августа 2016, 14:37
                                            Я понемногу продвигаюсь вперед. Уже точно могу сказать что был конфликт с одной из подключаемых js библиотек. Оставил только jQuery и теперь мои скрипты работают. Ваш тоже изменил свое поведение. При загрузке картинки на странице редактирования профиля она стала появляться на странице, но после нажатия на кнопку «обновить» — возвращается старая.
                                          2. Александр Мальцев
                                            11 августа 2016, 14:24
                                            img-photo — это id картинки
                                            photo — это id элемента, с помощью которого загружаем картинку
                                            1. Александр Мальцев
                                              11 августа 2016, 14:21
                                              Путь полный, т.е. до директории core которая лежит в корне сайта.
                                              .../core/model/phpthumb/phpthumb.class.php
                                              
                                              Каталога assets не должно быть.
                                        Войдите, пожайлуста, в аккаунт, чтобы оставить комментарий.