View Full Version : Custom Profile Update
doc55
08-28-2019, 11:43 PM
Hi,
I'm trying to make a custom form for users to update their profile. I have the following code, which I thought it should work.
//init the vBulletin system
require_once( '/forum/includes/vb5/autoloader.php' );
vB5_Autoloader::register( '/forum' );
vB5_Frontend_Application::init( 'config.php' );
// Get logged in user ID
$vb_userid=vB::getUserContext()->fetchUserId();
//get user info
$username = $this->data['username'];
$email = $this->data['email'];
$password = $this->data['new_password'];
$data = array(
'userid' => $vb_userid,
'password' => $password,
'user' => array( 'username' => $username, 'email' => $email ),
array(),
array(),
'userfield' => false,
array(),
'',
array()
);
$response = $api->callApi( 'user', 'save', $data, false, true);
But I'm getting the following error message:
Your submission could not be processed because a security token was missing.
If this occurred unexpectedly, please inform the administrator and describe the action you performed before you received this error.
And I see the following error at the top of the page:
Notice: Undefined index: usefiles in /home/myserver/mysite.com/forum/includes/vb5/template/stylesheet.php on line 70 Notice: Undefined index: usefiles in /home/myserver/mysite.com/forum/includes/vb5/template/stylesheet.php on line 70
I appreciate if someone could help me with fixing this code.
Thanks
doc55
09-02-2019, 01:40 AM
I made some progress, but the code is still not working correctly.
Here is what I have:
// Check vBulletin user ID to make sure they are logged in and it exists.
$user_id = isset( $_COOKIE[ 'bbuserid' ] ) ? ( int )$_COOKIE[ 'bbuserid' ] : null;
if ( $user_id === null ) {
throw new Exception( 'Unable to find user id from vBulletin.' );
}
//init the vBulletin system
require_once( '/forum/core/vb/vb.php' );
vB::init();
define( "CSRF_PROTECTION", false );
require_once( '/forum/includes/vb5/autoloader.php' );
vB5_Autoloader::register( '/forum' );
vB5_Frontend_Application::init( 'config.php' );
//get user info
$current_password = $_POST[ 'form' ][ 'current_password' ];
$new_password = $_POST[ 'form' ][ 'new_password' ];
$email = $_POST[ 'form' ][ 'email' ];
$username = $_POST[ 'form' ][ 'username' ];
//Update user information
$api = Api_InterfaceAbstract::instance();
$response = $api->callApi( 'user', 'save', array(
'userid' => $user_id,
'password' => '',
'user' => array( 'email' => $email, 'username' => $username ),
'options' => array(),
'adminoptions' => array(),
'userfield' => array(),
'notificationOptions' => array(),
'hvinput' => array(),
'extra' => array(
'password' => $current_password,
'newpass' => $new_password,
'email' => $email,
'username' => $username
),
) );
vB::getDbAssertor()->update( 'user', array( 'username' => $username ), array( "userid" => $user_id ) );
Couple issues with this code are:
1- It is not updating the email address
2- You can enter wrong current password and it still runs without throwing an error.
3- Can I update the user email, password and username without the need to enter the current user?
I appreciate anyone that could help with this.
You must pass 'acnt_settings' => true to the 'extra' array. Based on the code that allows you to edit the email/password as a regular user and also includes current password verification.
You need to extract the userid from the current session returned by vBulletin and not from a cookie because I can just simply use a cookie editor to edit my bbuserid cookie to the userid of an administrator and then hijack the account.
In Omnibus
09-02-2019, 01:04 PM
You must pass 'acnt_settings' => true to the 'extra' array. Based on the code that allows you to edit the email/password as a regular user and also includes current password verification.
You need to extract the userid from the current session returned by vBulletin and not from a cookie because I can just simply use a cookie editor to edit my bbuserid cookie to the userid of an administrator and then hijack the account.
I'd like and quote this a million times if I could. There seems to be a growing trend of vBulletin customers hacking their software without any regard for security.
doc55
09-02-2019, 02:37 PM
Thank you both for your valuable feedback. I'm not a programmer and I had someone do this for me. That's why I shared it here to make sure we are doing things correctly and improve it.
I really appreciate your advice.
doc55
09-03-2019, 08:14 PM
After reading the vB API documentation, it looks like the acnt_setting should be set to 1.
So, I changed the code as you advised and I'm getting the userid from vB fetchUserinfo instead of cookies.
However, my code still not working. It is not updating the username. Also it is not verifying the current password.
What am I missing?
//init the vBulletin system
require_once( '/forum/core/vb/vb.php' );
vB::init();
define( "CSRF_PROTECTION", false );
require_once( '/forum/includes/vb5/autoloader.php' );
vB5_Autoloader::register( '/forum' );
vB5_Frontend_Application::init( 'config.php' );
$vb_userInfo = vB_Api::instance( 'user' )->fetchUserinfo();
//get user info
$vb_userid = $vb_userInfo[ 'userid' ];
$current_password = $_POST[ 'form' ][ 'current_password' ];
$new_password = $_POST[ 'form' ][ 'new_password' ];
$email = $_POST[ 'form' ][ 'email' ];
$username = $_POST[ 'form' ][ 'username' ];
//Update user information
$api = Api_InterfaceAbstract::instance();
$response = $api->callApi( 'user', 'save', array(
'userid' => $vb_userid,
'password' => '',
'user' => array( 'email' => $email, 'username' => $username ),
'options' => array(),
'adminoptions' => array(),
'userfield' => array(),
'notificationOptions' => array(),
'hvinput' => array(),
'extra' => array(
'password' => $current_password,
'newpass' => $new_password,
'email' => $email,
'username' => $username,
'acnt_setting' => 1
),
) );
vB::getDbAssertor()->update( 'user', array( 'username' => $username ), array( "userid" => $vb_userid ) );
I appreciate any feedback.
var_dump($response); to see what that is showing. If nothing happens, dump the variables one by one to make sure everything is still working as expected.
doc55
09-03-2019, 09:53 PM
Thank you Dave.
It appeared that actually my code worked (partially).
When I enter the wrong current password, it doesn't update anything, appropriately. But It is not showing any errors to the user.
the var_dump($response); showed the following:
array(2) { ["errors"]=> array(1) { [0]=> array(2) { [0]=> string(11) "badpassword" [1]=> string(40) "https://mydomain.com/forum/lostpw" } } ["userid"]=> string(2) "19" }
I know this is the error message, but I'm not sure how can I write the if statement that if there is an error, then show a message. Meaning, how can I capture this error in the php script?
The other problem is that even when I enter the correct current password, it only updates the email and password and DOES NOT update the username. I'm not sure why.
Does the new password save properly? You might have to set the 'password' key to the new password in the array.
As for showing errors, just iterate over the errors array if it's set.
Something like
if(isset($response['errors'])){
foreach($response['errors'] as $key=>$error){
echo $error[0] . '<br>';
}
}
doc55
09-03-2019, 10:32 PM
Dave,
Thanks again for your reply.
That took care of the error message. Great.
The password is updating appropriately.
However, the username is still not saving at all. Any idea why?
Also, I noticed just now that the last line is actually not needed. I ran the code without the vB::getDbAssertor and it is working exactly the same. Do you know if I need this line?
vB::getDbAssertor()->update( 'user', array( 'username' => $username ), array( "userid" => $vb_userid ) );
It's not needed as far as I can see. Now regarding the username... I'm not entirely sure but it seems that the username is not updated by making use of the save method in the user API. Not sure at the moment how that can be done.
doc55
09-03-2019, 11:52 PM
Interesting. After you said that, I went back and looked at the default profile edit page. It looks like vB does not give the option to users to change their username either. So, probably that's why we can't use this api to change the user's name. I guess I need to follow the same process and not allow users change their usernames.
So in that case and for my knowledge, why do we need the following line in the save user api?
'user' => array( 'email' => $email, 'username' => $username ),
Do we really need it? or can I change it to
'user' => array(),
--------------- Added 1567566465 at 1567566465 ---------------
OK, now I think I'm losing my mind. This is crazy. When I tested the script I posted here 10 minutes ago, it was working by updating the user's email and password, and when I was entering a wrong password, it was giving me the error message "badpassword".
Now I went back to test again (without changing anything in the code) and I'm getting the error message "enter_current_password" error message, even when I enter correct current password or wrong currect password and nothing is updating.
How in the world is this possible that I'm getting a different response?
doc55
09-05-2019, 12:20 AM
Finally, I was able to put everything together and make this thing work. Thank you both for all your help.
Now. I have one issue/question.
The following line is updating the username:
vB::getDbAssertor()->update( 'user', array( 'username' => $username ), array( "userid" => $vb_userid ) );
The only issue is that it doesn't check if the username is already in use or not and it allows duplicate usernames. So I need to first check the user table in the database and throw an error if username is duplicate.
Is there any instruction on how to search the vB database to search for data? Can you help?
delicjous
09-05-2019, 06:19 AM
You should not use "vB::getDbAssertor()->update" because this is a direct database action. There are api-functions for that.
doc55
09-05-2019, 08:43 AM
You should not use "vB::getDbAssertor()->update" because this is a direct database action. There are api-functions for that.
Thank you for your reply.
I managed to figure out how to search the database to prevent duplicate username entry by using vB::getDbAssertor()->getRow.
What is the API that I could use instead of vB::getDbAssertor()->update which will be more secure? Can you please advise?
Is it ok to use vB::getDbAssertor()->getRow in an if statement to search for the data?
Thank you again.
Thank you for your reply.
I managed to figure out how to search the database to prevent duplicate username entry by using vB::getDbAssertor()->getRow.
What is the API that I could use instead of vB::getDbAssertor()->update which will be more secure? Can you please advise?
Is it ok to use vB::getDbAssertor()->getRow in an if statement to search for the data?
That isn't what delicjous means. With vB::getDbAssertor() you are working directly in db structure (like you edit table in phpmyadmin). Yes you can, of course. And you can change in some tables some things.
But a forum is a complex build with some particularly important elements (e.g. users with conventions for name length or password security). If you edit this directly you have to implement the same logic (checks, validations, needed following changes in other tables or cache refresh ...) in your code.
So you should use exposed api calls who implement the logic for you. As a starting point http://vb5support.com/resources/api/ and for this case http://vb5support.com/resources/api/vB_Api_User.html#method_checkUsername.
I haven't done such a user update so I can't give you code. But I would go this way or start there.
And http://vb5support.com/resources/api/vB_Api_User.html#method_save could be useful for final update.
And as a general note - if you find a possible useful api call (the description sounds good) and find no examples for that (parameters, more lines example) use the vB source code.
A search for checkUsername shows 5 relevant code lines
\forum\core\vb\api\user.php
5600,18: public function checkUsername($candidate)
\forum\core\vb\api\vb4\register.php
67,38: $check = vB_Api::instance('user')->checkUsername($username);
\forum\includes\vb5\frontend\controller\registrati on.php
285,24: public function actionCheckUsername()
297,36: $result = $api->callApi('user', 'checkUsername', array('candidate' => $_REQUEST['username']));
\forum\js\signup.js
11,2351: ...
First is api implementation, last I think not relevant here. But the others - try to unterstand the methods and the logic there
doc55
09-05-2019, 09:47 AM
shka,
Thank you for your helpful post. I am just starting to use vBulletin and I'm gathering as much information as I can, so your comments are much appreciated.
I checked the cherusername api and I will be using it in my code.
However, the user save method, is not updating the username, that's why I'm using the database update.
When I checked the default profile edit page on vB, there is no option for users to change their username. So I think vB by default, doesn't allow this (except from the AdminCP) and therefore the save function doesn't updat the username. Unless I'm missing something.
<a href="http://vb5support.com/resources/api/vB_DataManager_User.html" target="_blank">http://vb5support.com/resources/api/...ager_User.html</a> with update_username and verify_username ?
delicjous
09-05-2019, 11:22 AM
As Wayne mentioned anywhere you should use the mobile-API including an API-Key!
API=> user -> saveEmailPassword
For security reasons you should not use your scripts on any live forum.
Not that I will say it is unsafe, but changing an email by give users the ability to write anything to the user->email field (even non email-strings) is not the best idea!
In Omnibus
09-05-2019, 11:36 AM
As Wayne mentioned anywhere you should use the mobile-API including an API-Key!
API=> user -> saveEmailPassword
For security reasons you should not use your scripts on any live forum.
Not that I will say it is unsafe, but changing an email by give users the ability to write anything to the user->email field (even non email-strings) is not the best idea!
Giving anyone other than a trusted administrator the ability to write anything to the database is asking for trouble. One typo from a well-intentioned user can cause an unmitigated disaster.
doc55
09-05-2019, 11:40 AM
As Wayne mentioned anywhere you should use the mobile-API including an API-Key!
API=> user -> saveEmailPassword
For security reasons you should not use your scripts on any live forum.
Not that I will say it is unsafe, but changing an email by give users the ability to write anything to the user->email field (even non email-strings) is not the best idea!
Thank you for your reply.
So, what's the difference between using API => user -> saveEmailPassword that you recommended and the API => user -> Save that I have in my script?
I have disabled the feature that users can edit their own profile on vBulletin frontend via AdminCP. That's why I think the saveEmailPassword my not work with that function being disabled.
vBulletin® v3.8.12 by vBS, Copyright ©2000-2025, vBulletin Solutions Inc.