We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 9207 ☆ A M B ☆
    • 2,475 Posts
    I’m kinda dense this way... does anyone have an example of using the API for the WebLoginPE Snippet? I’d like to perform some magic on the data before saving to the DB, but I’m not sure how to tie into the API.

    Thanks!
      • 25551 ☆ A M B ☆
      • 1,231 Posts
      What kind of magic are we talking here? If you give me an idea of what you’re after I might be able to give you an idea... i have been using webloginPE for one of my sites so might be able to shed some light.
        Ross Sivills - MD AugmentBLU Edinburgh, Scotland UK
        AugmentBLU - MODX Partner

        BLUcart - MODX Revolution E-Commerce & Shopping Cart
        • 9207 ☆ A M B ☆
        • 2,475 Posts
        Thanks for the quick reply! I wanted to tie into WebLoginPE’s "OnBeforeWebSaveUser" event so I could perform PHP validation using custom regular expressions and then save the data in my own custom database tables -- the table thing is tricky... see my other post: http://modxcms.com/forums/index.php/topic,34919.msg211780.html#msg211780 for an idea of what I’m dealing with.

        As long as I can grab the data before I save it, I think I can roll my own solution... and once I see an example of how this works, I can figure out how to tweak it for other purposes. I learn by example smiley

        Thanks!
          • 29774
          • 386 Posts
          Hi again Everett

          the event hooks in webloginpe.class.php are somewhat useless unless you make some changes. Specifically you need to reference the weblogin instance if you actually want to do use methods within the class (such as wlpe->FormatMessage()) . I rewrote the hook to look like this:

          	function OnBeforeWebSaveUser($service='')
          	{
          		global $modx;
          
          		$parameters = array(
          			'wlpe'		=> &$this, // reference $wlpe instance
          			'service'	=> $service
          			);
          		$modx->invokeEvent('OnBeforeWebSaveUser', $parameters);
          	}
          


          You then need to make sure the events are invoked in the right places in the class methods (and nowhere else!). Eg at around line 419:

          
          function Register($regType, $groups, $regRequired, $notify, $notifyTpl, $notifySubject, $regSuccessId=0)
          	{
          		global $modx;
          		
          		# mcroxton -->
          		$this->OnBeforeWebSaveUser('Register');
          		if (!empty($this->Report))
          		{
          			return $this->Report;
          		}	
          		# <-- end
          
          		...
          
          


          This is my custom plugin attached to the OnBeforeWebSaveUser which does custom form validation on register and on edit profile, creating custom error messages and passing error fields as a string that can be used by jQuery to highlight individual fields:

          <?php
          /*
           plugin for WebLogin PE events
          */
          
          # note $service is passed to this plugin from the event call
          
          include ($_SERVER["DOCUMENT_ROOT"].'/assets/snippets/validation.inc.php');
          
          # custom validation
          $error= array();
          $errorTxt= array();
          $errorMessage='';
          
          # make safe
          if (isset($_POST['title'])) 		{ $_POST['title'] = sanitize_string($_POST['title'], 0, 255); 			}
          if (isset($_POST['firstname'])) 	{ $_POST['firstname'] = sanitize_string($_POST['firstname'], 0, 255); 	}
          if (isset($_POST['lastname'])) 		{ $_POST['lastname'] = sanitize_string($_POST['lastname'], 0, 255); 	}
          if (isset($_POST['suffix'])) 		{ $_POST['suffix'] = sanitize_string($_POST['suffix'], 0, 255); 		}
          if (isset($_POST['email'])) 		{ $_POST['email'] = sanitize_string($_POST['email'], 0, 255);			}	
          if (isset($_POST['telephone'])) 	{ $_POST['telephone'] = sanitize_string($_POST['telephone'], 0, 255);	}	
          if (isset($_POST['address1'])) 		{ $_POST['address1'] = sanitize_string($_POST['address1'], 0, 255); 	}
          if (isset($_POST['address2'])) 		{ $_POST['address2'] = sanitize_string($_POST['address2'], 0, 255);		}
          if (isset($_POST['city'])) 			{ $_POST['city'] = sanitize_string($_POST['city'], 0, 255);				}
          if (isset($_POST['state'])) 		{ $_POST['state'] = sanitize_string($_POST['state'], 0, 255);			}
          if (isset($_POST['zip'])) 			{ $_POST['zip'] = sanitize_string($_POST['zip'], 0, 16);				}
          if (isset($_POST['region'])) 		{ $_POST['region'] = sanitize_string($_POST['region'], 0, 2);			}
          if (isset($_POST['phone'])) 		{ $_POST['phone'] = sanitize_string($_POST['phone']);					}
          if (isset($_POST['mobilephone']))	{ $_POST['mobilephone'] = sanitize_string($_POST['mobilephone']);		}
          if (isset($_POST['occupation']))	{ $_POST['occupation'] = sanitize_string($_POST['occupation']);			}
          if (isset($_POST['privacy']))		{ $_POST['privacy'] = sanitize_string($_POST['privacy']);				}
          if (isset($_POST['tos']))			{ $_POST['tos'] = sanitize_string($_POST['tos']);						}
          
          # add fields to $_POST
          $_POST['fullname'] = $_POST['firstname'].' '.$_POST['lastname'];
          $_POST['username'] = $_POST['email'];
          
          # required fields
          if (!is_filled($_POST['title'])) {
          	$error[] = "title";
          	$errorTxt[] = "Title";
          }
          
          if (!is_filled($_POST['firstname'])) {
          	$error[] = "firstname";
          	$errorTxt[] = "First name";
          }
          
          if (!is_filled($_POST['lastname'])) {
          	$error[] = "lastname";
          	$errorTxt[] = "Last name";
          }
          
          if (!is_filled($_POST['email'])) {
          	$error[] = "email";
          	$errorTxt[] = "Email address";
          } else if(!is_email($_POST['email'])) {
          	$error[] = "email";
          	$errorTxt[] = "Email » must be a valid email address";
          }
          
          if (!is_filled($_POST['phone'])) {
          	$error[] = "phone";
          	$errorTxt[] = "Telephone";
          } else if (!is_phone($_POST['phone'])) {
          	$error[] = "phone";
          	$errorTxt[] = "Telephone » can only contain the characters 0-9()+";
          }
          
          if (!is_filled($_POST['address1'])) {
          	$error[] = "address1";
          	$errorTxt[] = "Address 1";
          }
          
          if (!is_filled($_POST['city'])) {
          	$error[] = "city";
          	$errorTxt[] = "Town/City";
          }
          
          if (!is_filled($_POST['zip'])) {
          	$error[] = "postcode";
          	$errorTxt[] = "Postcode";
          } else if (!is_ukpostcode($_POST['zip'])) {
          	$error[] = "postcode";
          	$errorTxt[] = "Postcode » must be a valid UK postcode";
          }
          
          if ($service == 'Register') {
          	if (!is_filled($_POST['privacy'])) {
          		$error[] = "privacy";
          		$errorTxt[] = "Privacy policy - please confirm that you have read and understood the policy";
          	}
          
          	if (!is_filled($_POST['tos'])) {
          		$error[] = "tos";
          		$errorTxt[] = "Terms & conditions - please confirm your agreement";
          	}
          
          	// non-required fields that if filled, should be validated...
          	if (is_filled($_POST['mobilephone'])) {
          		if (!is_phone($_POST['mobilephone'])) {
          			$error[] = "mobilephone";
          			$errorTxt[] = "Evening/mobile telephone » can only contain the characters 0-9()+";
          		}
          	}
          }
          
          if (count($error)>0) {
          	# create a string of error field ids for use by jQuery
          	for ($i=0;$i<count($error);$i++) {
          		$errorJS.="#".$error[$i];
          		if ($i<count($error)-1) {
          			$errorJS.=',';
          		}
          	}
          	# format error message
          	$errorMessage = '<strong title="'.$errorJS.'">Please correct errors</strong> The following required field(s) are missing: ';
          	for ($i=0;$i<count($errorTxt);$i++) {
          		$errorMessage .=$errorTxt[$i];
          		if ($i<count($errorTxt)-1) {
          			$errorMessage.=', ';
          		}
          	}
          	$wlpe->FormatMessage($errorMessage);
          }
          ?>
          
          
          


          My validation functions (validation.inc.php) are as follows:

          <?php
          // Validation functions
          
          // paranoid sanitization -- strip everything except the alphanumeric set plus @-.:, and whitespace
          function sanitize_string($string, $min='', $max=''){
          	$string = preg_replace("/[^a-zA-Z0-9@\,\:\.\-\s]/", "", $string);
          	$len = strlen($string);
          	// trim length
          	if((($min != '') && ($len < $min)) || (($max != '') && ($len > $max)))
          	return FALSE;
          	// Now check if string contains email headers to prevent injection attempts
          	if (!is_safe($string)) {
          		return false;
          	}
            	return $string;
          }
          
          // make int int!
          function sanitize_int($integer, $min='', $max=''){
          	$int = intval($integer);
          	if((($min != '') && ($int < $min)) || (($max != '') && ($int > $max)))
          	return FALSE;
            	return $int;
          }
          
          function is_safe($string) {
          	$badStrings = array("Content-Type:","MIME-Version:","Content-Transfer-Encoding:","bcc:","cc:");
          	foreach($badStrings as $bad){
          		if(strpos(strtolower($string), strtolower($bad)) !== false){
          			return false;
          		}
          	}
          	return true;
          }
          
          function is_filled($string) {
          	if (isset($string) && ($string != "")) {
          		return true;
          	} else return false;
          }
          
          function is_email($string) {
          	if (eregi("^[_\.0-9a-z-]+@([0-9a-z][0-9a-z-]+\.)+[a-z]{2,3}$", $string)) {
          		return true;
          	} else return false;
          }
          
          function is_phone($string) {
          	if (preg_match ("/^[0-9+\-x() ]*$/ ", $string)) { // match a string made only of 0123456789-+x() and space
          		return true;
          	} else return false;
          }
          	
          function is_name($string) {
          	if (preg_match ("/\w+\s+\w+/ ", $string)) { // match at least 2 words if we have asked for the full name in one field
          		return true;
          	} else return false;
          }
          
          function is_alphanumeric($string) { // just a-z and 0-9
          	if(!preg_match("/[^a-zA-Z0-9\.\-\\\\\\\\ ]+$/s",$string)) {
          		return true;
          	} else return false;
          }
          
          function is_ukpostcode($postcode) {
             $postcode = strtoupper(str_replace(chr(32),'',$postcode));
             $suffix = substr($postcode,-3,3);
             $prefix = substr($postcode,0,(strlen($postcode)-3));
             if (preg_match('/(^[A-Z]{1,2}[0-9]{1,2}|^[A-Z]{1,2}[0-9]{1}[A-Z]{1})$/',$prefix) && preg_match('/^[0-9]{1}[ABD-HJLNP-UW-Z]{2}$/',$suffix)) {
                return TRUE;
             } else {
                return FALSE;
             }
          }
          
          function is_ukdate($value, $format = 'dd/mm/yyyy'){
              if(strlen($value) >= 6 && strlen($format) == 10){
                 
                  // find separator. Remove all other characters from $format
                  $separator_only = str_replace(array('m','d','y'),'', $format);
                  $separator = $separator_only[0]; // separator is first character
                 
                  if($separator && strlen($separator_only) == 2){
                      // make regex
                      $regexp = str_replace('mm', '(0?[1-9]|1[0-2])', $format);
                      $regexp = str_replace('dd', '(0?[1-9]|[1-2][0-9]|3[0-1])', $regexp);
                      $regexp = str_replace('yyyy', '(19|20)?[0-9][0-9]', $regexp);
                      $regexp = str_replace($separator, "\\" . $separator, $regexp);
                      if($regexp != $value && preg_match('/'.$regexp.'\z/', $value)){
          
                          // check date
                          $arr=explode($separator,$value);
                          $day=$arr[0];
                          $month=$arr[1];
                          $year=$arr[2];
                          if(@checkdate($month, $day, $year))
                              return true;
                      }
                  }
              }
              return false;
          }
          ?>
          


            Snippets: GoogleMap | FileDetails | Related Plugin: SSL
            • 9207 ☆ A M B ☆
            • 2,475 Posts
            Ah... ok... I see how this is built now... the WebLoginPE code triggers MODx events... albeit MODx events that WebLoginPE itself added. Wow... this is a bit weird, but I think I understand the architecture here. Using the WebLoginPE API in this way is really no more complicated than writing a normal MODx Plugin.

            therebechips, I think I’ve downloaded a different version of the code than you have -- our line numbers and even samples of the functions differ. I was able to add a MODx Plugin and tie it to the OnWebSaveUser event. Now it’s just a matter of integrating my validation and hitting my insert statements and returning error messages (if any). The counterpart will be to write another plugin that fires on the OnViewUserProfile that will use a custom SQL query that joins on the other database tables.

            For what it’s worth, I had problems when I tied my validation actions to the OnBeforeWebSaveUser event; namely, the plugin fired twice instead of just once, which made for unpredictable results.

            I’m putting together a big beefy doc for the MODx wiki with my trials and tribulations... I made a lot of progress on this today, thanks to your input.
              • 9207 ☆ A M B ☆
              • 2,475 Posts
              For what it’s worth, here’s my Wiki page (very much in progress):
              http://wiki.modxcms.com/index.php/WebLoginPE
                • 4310
                • 2,310 Posts
                Excellent work grin
                  • 7231
                  • 4,205 Posts
                  Cool cool

                  WebLoginPE is a Progressively Enhanced (thus the PE),
                  I was told that PE was Pirate Edition tongue
                    [font=Verdana]Shane Sponagle | [wiki] Snippet Call Anatomy | MODx Developer Blog | [nettuts] Working With a Content Management Framework: MODx

                    Something is happening here, but you don&#39;t know what it is.
                    Do you, Mr. Jones? - [bob dylan]
                    • 9207 ☆ A M B ☆
                    • 2,475 Posts
                    Thanks, Bunk. It’s still very much in progress... I’ve almost got my custom db hooked up to this, but there are a few caveats, e.g. mapping MODx’s web_user_id back to our custom id, but I think I’ll get that handled by tomorrow and I’ll make a note on how the plugin might have to look. therebechips made some excellent contributions... I think I want to copy his method of filtering post data... it’s cleaner than mine.

                    To be continued... I need to spend some time reformatting that page, but in good time.
                      • 29774
                      • 386 Posts
                      Hi Everett

                      good work on the wiki page!

                      I just wanted to add a small further explanation to the plugin code I posted earlier. As well as formatting an error message, the plugin allows for individual field highlighting. It attaches a comma delimited list of the fields that contain errors to a title attribute inside the wlpe validation message, so you end up with markup like this:

                      <p class="info"><strong title="#firstname,#address1,#city">Please correct errors</strong>The following required field(s) are missing: First name, Address 1, City</p>
                      


                      Your form template should have fields where the names and ids are identical, eg:

                      <input type="text" name="firstname" id="firstname" />
                      <input type="text" name="address1" id="address1" />
                      <input type="text" name="city" id="city" />
                      


                      It’s therefore a simple matter to highlight those fields by adding a ’required’ class to them with some simple jQuery:

                      $($('p.info strong').attr('title')).addClass("required");
                      


                      And in the css something like this:

                      input.required { border: 1px solid red; }
                      


                      My aim was for the wlpe form validation behaviour to match eform’s, without having to actually parse the form template in PHP with regular expressions (as eform does). This is further helped by using a separate validation.inc.php file, which I can reuse for custom field validation using eform’s #FUNCTION filter.
                        Snippets: GoogleMap | FileDetails | Related Plugin: SSL