We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 26334
    • 77 Posts
    OK about a month ago I asked about this and got some useful info from the guys here and was asked to post my solution when it was done. Unfortunately due to other jobs this fell to the back burner a few times and just got it going. Original thread is here:
    http://modxcms.com/forums/index.php/topic,56921.0.html

    So here is my code. I hope you find it useful. It works on every test I have tried but always happy for feedback or suggestions.

    A few things to note.
    1) It uses OLD style sql code not XPDO. I need to get up to speed with XPDO but haven’t had the time to devote to it yet. If anyone wants to recast the old sql code here to XPDO style then PLEASE go ahead and post it back here! I (and plenty others) will be appreciative of it!

    2) I don’t really need to invent a password when creating an account for someone coming in from janrain but I figured what the heck just give them a random password and then if they use the forgot password facility at least there is something there.

    3) I put them in a user group "members" - you don’t have to do that, up to you to include them in a group or not.

    4) Obviously you need a janrain account - they will provide you with a javascript that you place on the login page and you put this snippet on the destination page - the url of which you have to include in that javascript. You will need your own api key which you get on registering with janrain and obviously I have removed my references to the contexts I use here and my domain - just edit those.

    That’s about it. Happy to answer any questions or if anyone has some feedback or suggestions over the way I have done things (ie there is a better way!) then happy to hear it.

    Hope this is helpful.

    <?php
    
    #----check if logging in or prompting for new username this equates to the return from option 4) listed below after they
    #----have tried a new username - checks for another clash and then prompts or registers them.
    if (isset($_POST['username'])) {
    		$table = 'modxr_users';
    		$condition = '`username` = "'.$_POST['username'].'"';
    		$result = $modx->db->select( '*','`'. $table.'`',$condition,'`username` ASC','0,1');
    		if( $modx->db->getRecordCount( $result ) >= 1 ) { #username exists
    		    $modx->toPlaceholder('error.username', 'Username already exists - please select another');
    		    $refresh = '';
    		    $lenth=8;
      		    $aZ09 = array_merge(range('A', 'Z'), range('a', 'z'),range(0, 9));
    		    $pwd ='';
    		    for($c=0;$c < $lenth;$c++) {
    			$pwd .= $aZ09[mt_rand(0,count($aZ09)-1)];
    		    }
    
    		    $spinner = '<div class="register">
        <div class="registerMessage">[[+error.message]]</div>
        
        <form class="form" action="/[[~[[*id]]]]" method="post">
          <table id="createAccount">
    	<input type="hidden" name="email" id="email" value="'.$_POST['email'].'" />
    	<input type="hidden" name="password" id="password" value="'.$_POST['pwd'].'" />
    	<tr>
            <td class="first">
    			<label for="username">Username</label>
    		</td>
    		<td>
            	<input type="text" name="username" id="username" value="'.$_POST['username'].'" />
                <span class="error">[[+error.username]]</span>
    		</td>
    	</tr>
    	<tr>
            <td class="first">
    			 
     		</td>
    		<td>
    			<input type="submit" value="Login" class="button green big"/>
    		</td>
    	</tr>
          </table>
        </form>
    <p>Already a member? <a href="/member/index.html"><strong>Sign In</strong></a></p>
    </div>';
    		    $modx->toPlaceholder('refresh', $refresh); 
    		    $modx->toPlaceholder('login_content', $spinner); 
    		}
    		else {
    			// option 3 - create new user, I choose to assign random password.
    				$pwd = $_POST['pwd'];
    				$user = $modx->newObject('modUser');
    				$user->fromArray(array(
    						'username' => $_POST['username']
    						,'password' => md5($pwd)
    						,'active' => 1
    				));
    				$profile = $modx->newObject('modUserProfile');
    				$profile->fromArray(array(
    						'email' => $_POST['email']
    				));
    				$user->addOne($profile, 'Profile');
    				$saved = $user->save();
    	 			$user->addSessionContext('yourcontext');
    				#---- add to usergroup.
    				$table = 'modxr_users';
    				$condition = '`username` = "'.$_POST['username'].'"';
    				$result = $modx->db->select( '*','`'. $table.'`',$condition,'`username` ASC','0,1');
    				if( $modx->db->getRecordCount( $result ) >= 1 ) { #username exists
      					$row = $modx->db->getRow( $result );
      					$uid = $row['id'];					
    				}
    				$table = 'modxr_member_groups';
    				$member_group = array();
    				$member_group['user_group'] = 5;
    				$member_group['member'] = $uid;
    				$member_group['role'] = 1;
    				$result = $modx->db->insert( $member_group,'`'. $table.'`', '');
    				$refresh = '<meta http-equiv="refresh" content="2;url=http://yourdomain.com/member/">';
    				$modx->toPlaceholder('refresh', $refresh);
    		}
    }
    else {
        $refresh = '<meta http-equiv="refresh" content="2;url=http://yourdomain.com/member/">';
        $spinner = '<center><img src="http://yourdomain.com/assets/img/load.gif"></center><br /><a href="/member/">Members page</a>';
        $modx->toPlaceholder('refresh', $refresh); 
        $modx->toPlaceholder('login_content', $spinner); 
      #--- Default response from janrain - gives you their username and email and unique id info
      #--- This code supplied by janrain --
        $rpxApiKey = 'your api key goes here';	
        if(isset($_POST['token'])) { 
    
    	/* STEP 1: Extract token POST parameter */
    	$token = $_POST['token'];
    
    	/* STEP 2: Use the token to make the auth_info API call */
    	$post_data = array('token' => $_POST['token'],
    										 'apiKey' => $rpxApiKey,
    										 'format' => 'json'); 
    
    	$curl = curl_init();
    	curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    	curl_setopt($curl, CURLOPT_URL, 'https://rpxnow.com/api/v2/auth_info');
    	curl_setopt($curl, CURLOPT_POST, true);
    	curl_setopt($curl, CURLOPT_POSTFIELDS, $post_data);
    	curl_setopt($curl, CURLOPT_HEADER, false);
    	curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
    	$raw_json = curl_exec($curl);
    	curl_close($curl);
    
    
    	/* STEP 3: Parse the JSON auth_info response */
    	$auth_info = json_decode($raw_json, true);
    
    	if ($auth_info['stat'] == 'ok') {
    	
    		/* STEP 3 Continued: Extract the 'identifier' from the response */
    		$profile = $auth_info['profile'];
    		$identifier = $profile['identifier'];
    
    		if (isset($profile['photo']))	{
    			$photo_url = $profile['photo'];
    		}
    
    		if (isset($profile['displayName']))	{
    			$name = $profile['displayName'];
    		}
    
    		if (isset($profile['email']))	{
    			$email = $profile['email'];
    		}
    
    //echo 'name = '.$name.'<br>email = '.$email.'<br>identifier = '.$identifier.'<br>';	 
    
    /* STEP 4: Use the identifier as the unique key to sign the user into your system.
    			 This will depend on your website implementation, and you should add your own
    			 code here.
    
    ---- End of janrain code from here it is mine again ---
    
    Check options for login:
    1) identifier exists - log them in
    2) identifier doesn't exist but email exists - add identifier and log them in
    3) identifier and email don't exist and username doesn't exist - create account and log them in
    4) identifier and email don't exist and username already exists - prompt for username and log them in
    */
    
    //------- user check ------
    // - Option 1)
    $table = 'modxr_users';
    $condition = '`remote_key` = "'.$identifier.'"';
    $result = $modx->db->select( '*','`'. $table.'`',$condition,'`username` ASC','0,1');
    if( $modx->db->getRecordCount( $result ) >= 1 ) { #they exist
    	#check if blocked
    	$row = $modx->db->getRow( $result );
    	$blocked = $row['blocked'];
    	$userid = $row['id'];
    	$username = $row['username'];
    	if ($blocked > 0) {
    	echo 'Blocked user';
    	exit;
    	}
    	$user = $modx->getObjectGraph('modUser', '{"Profile":{}}', array('remote_key:=' => $identifier, 'remote_key:!=' => null, 'class_key' => 'modUser'));
    	$user->addSessionContext('yourcontext');
    }
    else {
    // - Option 2)
    	$table = 'modxr_user_attributes';
    	$condition = '`email` = "'.$email.'"';
    	$result = $modx->db->select( '*','`'. $table.'`',$condition,'`email` ASC','0,1');	
    	if( $modx->db->getRecordCount( $result ) >= 1 ) { #they exist
    		#check if blocked
    		$row = $modx->db->getRow( $result );
    		$blocked = $row['blocked'];
    		$userid = $row['id'];
    		if ($blocked > 0) {
    		echo 'Blocked user';
    		exit;
    		} 
    		#update modxr_users with key
    		$table = 'modxr_users';
    		$condition = '`id` = "'.$userid.'"';
    		$tabledata['remote_key'] = $identifier;
    		$result = $modx->db->update( $tabledata,'`'. $table.'`', $condition);		
    		$user = $modx->getObjectGraph('modUser', '{"Profile":{}}', array('remote_key:=' => $identifier, 'remote_key:!=' => null, 'class_key' => 'modUser'));
    		$user->addSessionContext('yourcontext');
    	}
    	else {  #--------- Duplicate username prompt for new username
    		$table = 'modxr_users';
    		$condition = '`username` = "'.$name.'"';
    		$result = $modx->db->select( '*','`'. $table.'`',$condition,'`username` ASC','0,1');
    		if( $modx->db->getRecordCount( $result ) >= 1 ) { #username exists
    		    $modx->toPlaceholder('error.username', 'Username already exists - please select another');
    		    $refresh = '';
    		    $lenth=8;
      		    $aZ09 = array_merge(range('A', 'Z'), range('a', 'z'),range(0, 9));
    		    $pwd ='';
    		    for($c=0;$c < $lenth;$c++) {
    			$pwd .= $aZ09[mt_rand(0,count($aZ09)-1)];
    		    }
    
    		    $spinner = '<div class="register">
        <div class="registerMessage">[[+error.message]]</div>
        
        <form class="form" action="/[[~[[*id]]]]" method="post">
    <table id="createAccount">
    	<input type="hidden" name="email" id="email" value="'.$email.'" />
    	<input type="hidden" name="password" id="password" value="'.$pwd.'" />
    	<tr>
            <td class="first">
    			<label for="username">Username</label>
    		</td>
    		<td>
            	<input type="text" name="username" id="username" value="'.$name.'" />
                <span class="error">[[+error.username]]</span>
    		</td>
    	</tr>
    	<tr>
            <td class="first">
    			 
     		</td>
    		<td>
    			<input type="submit" value="Login" class="button green big"/>
    		</td>
    	</tr>
    </table>
        </form>
    <p>Already a member? <a href="/member/index.html"><strong>Sign In</strong></a></p>
    </div>';
    		    $modx->toPlaceholder('refresh', $refresh); 
    		    $modx->toPlaceholder('login_content', $spinner); 
    		}
    		else {
    			// option 3 - create new user, I choose to assign random password.
    						$aZ09 = array_merge(range('A', 'Z'), range('a', 'z'),range(0, 9));
    						$pwd ='';
    						$lenth = 8;
    						for($c=0;$c < $lenth;$c++) {
    			 			  $pwd .= $aZ09[mt_rand(0,count($aZ09)-1)];
    						} 
    						$user = $modx->newObject('modUser');
    						$user->fromArray(array(
    								'username' => $name
    								,'password' => md5($pwd)
    								,'active' => 1
    								,'remote_key' => $identifier
    						));
    						$profile = $modx->newObject('modUserProfile');
    						$profile->fromArray(array(
    								'email' => $email
    						));
    						$user->addOne($profile, 'Profile');
    						$saved = $user->save();
    			 			$user->addSessionContext('yourcontext');
    				#---- add to usergroup.
    				$table = 'modxr_users';
    				$condition = '`username` = "'.$name.'"';
    				$result = $modx->db->select( '*','`'. $table.'`',$condition,'`username` ASC','0,1');
    				if( $modx->db->getRecordCount( $result ) >= 1 ) { #username exists
      					$row = $modx->db->getRow( $result );
      					$uid = $row['id'];					
    				}
    				$table = 'modxr_member_groups';
    				$member_group = array();
    				$member_group['user_group'] = 5;
    				$member_group['member'] = $uid;
    				$member_group['role'] = 1;
    		}
    
    
    	} // else option 2)
    } // else option 1)
    
    //end:
    
    /* an error occurred - janrain code, haven't done anything with this yet*/
    } else {
    	// gracefully handle the error.	Hook this into your native error handling system.
    	echo 'An error occured: ' . $auth_info['err']['msg'];
    }
    }
    
    } #else (isset($_POST['username']) 
      • 34193
      • 330 Posts
      ok trying this out. I have replaced all yourdomain.com with my domain name and all yourcontext with web.

      It creates the user on first try but then nothing appears to happen.

      I have tried including the snippet in an existing resource and a new one with a blank template but it displays nothing. What am I missing about forwarding the user to the required page.
        • 17499 ☆ A M B ☆
        • 872 Posts
        I did not try it myself but try to change the table name from modxr to modx in the provided script.
          • 26334
          • 77 Posts
          as lossendae said make sure the database name matches up with yours - I use modxr others may use modx or something else.

          Also I redirect on a success to :

          mydomain/members/index.html

          With a 2 second delay. I found that if it was an instant redirect you weren’t logged in when you got there but if you refreshed the page you were. 2s seems to work for me, could probably be less.

          I use a spinning wait graphic there -
          http://yourdomain.com/assets/img/load.gif

          So obviously you need to either change members/index.html and the load.gif location to something meaningful on your server or set those paths up.

          Sorry I thought those things were self evident, my fault.
            • 34193
            • 330 Posts
            Quote from: scarfy96 at Nov 30, 2010, 04:49 PM

            as lossendae said make sure the database name matches up with yours - I use modxr others may use modx or something else.

            Also I redirect on a success to :

            mydomain/members/index.html

            With a 2 second delay. I found that if it was an instant redirect you weren’t logged in when you got there but if you refreshed the page you were. 2s seems to work for me, could probably be less.

            I use a spinning wait graphic there -
            http://yourdomain.com/assets/img/load.gif

            So obviously you need to either change members/index.html and the load.gif location to something meaningful on your server or set those paths up.

            Sorry I thought those things were self evident, my fault.

            Hi yes sorry I did that. As I say it creates the user but the redirect doesn’t work even with it redirecting to my own place on the site. I have set it to redirect to my start page while testing. Anything else I might have missed.
              • 26334
              • 77 Posts
              Well I am assuming you are referring to the placeholder refresh in the header of this page.

              Hmmm, seems I only did half an explanation didn’t I! OK I’ll try a bit harder.

              There are 2 place holders:
              1) spinner -> most of the time that holds a spinning graphic (loading.gif) but on instance 4) where I have to prompt for a new username as there is a clash it now contains a form to request the new username. That must be placed in the same page as this snippet call.

              2) refresh -> that either contains the meta refresh call or a blank entry. That must be placed in the header of the page that this snippet call is in. On the case of a successful login then the header will redirect you to that page, on a fail that requires more input that will be set to a blank so no refresh occurs.

              Let me know how you go.

              I am in Australia so it is only mid morning here so will be online for another 6 or so hours.
                • 26334
                • 77 Posts
                Also - testing has shown that twitter doesn’t return an email. I assume an email so this fails for a twitter login. I guess you could do an exception for that as well if you need it but we have decided just to go with facebook, yahoo, google and openid.