Upload Photo in MODX's User Registration

There seems a confusion for MODX's developer to set up how they can set photo uploading for registration (not on updating profile), because at that state, the user has no profile yet, while the picture's path should be saved in the user's profile database.

Another consideration to take is that this picture should be managed under the user's folder. Well, logically all users have their own private folders for documents.

In simple words, this is the how I came up with:

  1. Create the normal form, with addional "enctype" attribute (<form ... enctype="multipart/form-data" .... />) in the form tag for file uploading, and <input type="file" /> field for the photo
  2. When submitted, process the Registration, then (using preHooks) upload the photo to a temporary folder, and store that path into the user's profile.
  3. After registration process is done, then (using postHooks) move the photo to the new location under the registrant's private folder, delete the temporary file, and then update back the user's profile to save the new path.

Now I'm about to give you the practical example to give the idea.

On this example, while I'm using the Register snippet, the codes are simplified and you can add other properties or attributes to the tags as needed.

Show Me Da Code!

Register Snippet

The snippet is called like this (I'm adding a space for the "[ [" to avoid this site parses the snippet):

[ [!Register?
&preHooks=`register.preHook`
&postHooks=`register.postHook`
&placeholderPrefix=`reg.`
]]

File Input

I'm setting up the image field basically like this:

<form action="[ [~[ [*id]]]]" method="post" enctype="multipart/form-data" >
	
 <!-- other fields ... -->
	
 <input type="file" name="photo" >
 <input type="submit" name="login-register-btn " >
</form>

For sidenote, I like Jasny's photo preview when user selects a picture.

Register preHooks

I'm using the upload script from the existing post on the forum for the code, and modifying it a bit:

<?php

$output = true;

$fields = $hook->getValues();

/* User's photo */
if (!empty($fields['photo'])) {

 // valid extensions
 $extArray = array('jpg', 'jpeg', 'gif', 'png');

    // create temporary path for this form submission
 $uploadPath = 'assets/uploads/temp/';
 $targetPath = $hook->modx->config['base_path'] . $uploadPath;

 // get uploaded file names:
 $submittedFiles = array_keys($_FILES);

 // loop through files
 foreach ($submittedFiles as $sf) {

  // Get Filename and make sure its good.
  $filename = basename($_FILES[$sf]['name']);

  // Get file's extension
  $ext = pathinfo($filename, PATHINFO_EXTENSION);
  
  // case insensitive
  $ext = mb_strtolower($ext);
  
  // is the file name empty (no file uploaded)
  if ($filename != '') {

   // is this the right type of file?
   if (in_array($ext, $extArray)) {

    //create file called the user name
    $filename = mb_strtolower($filename);

    // full path to new file
    $uploadFilePath = $targetPath . $filename;

    // create directory to move file into if it doesn't exist
    @mkdir($targetPath, 0755, true);
    if (file_exists($uploadFilePath)) {

     // Change the file permissions if allowed
     chmod($uploadFilePath, 0755);

     // remove the file
     unlink($uploadFilePath);
    }

    // is the file moved to the proper folder successfully?
    if (move_uploaded_file($_FILES[$sf]['tmp_name'], $uploadFilePath)) {
     $hook->setValue($sf, $uploadPath . $filename);
     if (!chmod($uploadFilePath, 0644)) {
      /* some debug function */
     }
    } else {
     
     // File not uploaded
     $errorMsg = 'There was a problem uploading the file.';
     $hook->addError($sf, $errorMsg);
     
     // generate submission error
     $output = false; 
    }
   } else {
    
    // File type not allowed
    $errorMsg = 'Type of file not allowed.';
    $hook->addError($sf, $errorMsg);
    
    // generate submission error
    $output = false;
   }
  } else {
   
   // if no file, don't give error, but just return blank
   $hook->setValue($sf, '');
  }
 }
}

return $output;

Register postHooks

This is the most important part, where the picture is about to be moved to the user's new private folder, and we are also going to update the user's profile afterward.

<?php

/** @var modUser $user */
$user = & $fields['register.user'];
$userId = $user->get('id');

/** @var modUserProfile $profile */
$profile = & $fields['register.profile'];

if (!empty($fields['photo'])) {
 $photo = array();
 $photo['temp'] = $fields['photo'];
 $photo['basename'] = basename($photo['temp']);

 /***********************************************************************
 * XXX: IMPORTANT XXX
 *
 * Create unique path here for this profile updating.
 * You can change this as you wish.
 * The $userId variable comes from above initiation.
 *
 ***********************************************************************/

 $photo['newdir'] = 'assets/uploads/profiles/' . $userId . '/';

 $photo['newfilepath'] = $photo['newdir'] . $photo['basename'];
 $photo['target'] = $hook->modx->config['base_path'] . $photo['temp'];
 $photo['moved'] = $hook->modx->config['base_path'] . $photo['newfilepath'];

 // make the user's private directory
 mkdir($photo['newdir'], 0755, true);

 $photoUpdated = false;
 // move the photo from the temporary path to the new one
 if (!rename($photo['target'], $photo['moved'])) {

  // if "rename" function fails, try "copy" instead.
  if (!copy($photo['target'], $photo['moved'])) {
   // just dump the log report to the MODX's error log,
   // because both "rename" and "copy" functions fail
   $hook->modx->log(modX::LOG_LEVEL_ERROR, __FILE__ . ' ');
   $hook->modx->log(modX::LOG_LEVEL_ERROR, __LINE__ . ': $userId ' . $userId);
   $hook->modx->log(modX::LOG_LEVEL_ERROR, __LINE__ . ': $photo ' . print_r($photo, 1));
  } else {

   // if copy succeeded, delete the old temporary picture
   unlink($photo['target']);
   $photoUpdated = true;
  }
 } else {
  $photoUpdated = true;
 }

 if ($photoUpdated) {
  /**
   * Now we update the profile
   * The $profile variable comes from above initiation.
   */

  $profile->set('photo', $photo['newfilepath']);
  $profile->save();

  /**
   * Yeah! xPDO rocks! Simply like that!
   */
 }
}

return TRUE;

That's all. Now user can upload photo when doing registration. Enjoy!



Comments

blog comments powered by Disqus