📜 ⬆️ ⬇️

MODx and Vbulletin 3.8.x - peace, friendship, chewing gum

What should we build a house?


Nowadays, the vbulletin forum engine is familiar to many. Someone uses it, someone quietly hates it, and someone asks the authorities for the purchase of a license.
And because of his popularity, many CMS have support for this engine, but only here in MODx I did not find a normal plug-in / snippet, and the existing ones had enough cheeses to use them.
Ladies and gentlemen, please love and favor:
The experiment was conducted on MODx version 1.0.2 and vbulletin version 3.8.1.

The quieter you go, the further you'll get


First we need to prepare, and the first one will be the forum global.php file.
I did this: copied it to global_modx.php (... / forum / global_modx.php), opened it for editing and deleted everything after 891 lines (I remind you, forum version 3.8.1) - connection styles, etc., t . The last line in my file is the call to the function verify_ip_ban ();

Note: there were problems with the global connection - it performed the exit (die (); or exit ();) in the middle of the script due to some internal checks, so I advise you to do everything on the test version for a start.
')
Now, in the index.php file, the holy of holies of MODx's, insert the following magic lines of code:

$VBDIR = "../forum/"; // , ,
$CURDIR = getcwd();
chdir($VBDIR);
require_once($VBDIR."global_modx.php");
chdir($CURDIR);

TA-dah! Already now MODx sees all forum data! In any snippet, we can use (by declaring it globally) the standard $ vbulletin object (using the print_r command ($ vbulletin); you can see all the available fields, but there are a LOT of them, and you probably only need print_r ($ vbulletin-> userinfo); ).

Continue our research, gentlemen


Now we need to introduce the issue of authorization to the site. Create a forum_login_form chunk that will copy the standard login form from the "bun":

 <! - login form ->
 <form action = "[+ forumLink +] login.php? do = login" method = "post" onsubmit = "md5hash (vb_login_password, vb_login_md5password, vb_login_md5password_utf, 0)">
 <script type = "text / javascript" src = "[+ forumLink +] clientscript / vbulletin_md5.js? v = 381"> </ script>
 <table cellpadding = "0" cellspacing = "3" border = "0">
    <tr>
       <td> <input type = "text" value = "Login" name = "vb_login_username" id = "navbar_username" accesskey = "u" tabindex = "101" onfocus = "javascript: if (this.defaultValue == this.value ) this.value = ''; else if (this.value == '') this.value = this.defaultValue; "  onblur = "javascript: if (this.defaultValue == this.value) this.value = ''; else if (this.value == '') this.value = this.defaultValue;"  class = "input" /> </ td>
       <td> <input type = "checkbox" name = "cookieuser" value = "1" tabindex = "103" id = "cb_cookieuser_navbar" accesskey = "c" /> </ td>
       <td> <label for = "cb_cookieuser_navbar"> Remember? </ label> </ td>
    </ tr>
    <tr>
        <td> <input type = "password" value = "Password" name = "vb_login_password" id = "navbar_password" tabindex = "102" onfocus = "javascript: if (this.defaultValue == this.value) this.value = ''; else if (this.value == '') this.value = this.defaultValue; "  onblur = "javascript: if (this.defaultValue == this.value) this.value = ''; else if (this.value == '') this.value = this.defaultValue;"  class = "input" /> </ td>
        <td> </ td>
        <td> <input type = "submit" class = "button" value = "Input" tabindex = "104" title = "Enter your username and password to enter, or click the 'Register' button to register."  accesskey = "s" /> </ td>
    </ tr>
 </ table>
 <input type = "hidden" name = "s" value = "" />
 <input type = "hidden" name = "securitytoken" value = "guest" />
 <input type = "hidden" name = "do" value = "login" />
 <input type = "hidden" name = "vb_login_md5password" />
 <input type = "hidden" name = "vb_login_md5password_utf" />
 </ form>
 <! - / login form ->

Pay attention to [+ forumLink +], the address will be substituted when calling the snippet for ease of management.
Note: in any case, this form is different for different styles, so it's best to cut it out of your forum and paste it into this chunk.

Next, create a forum_login_logged chunk that displays logged in users:
 <strong> Hello <a href="[+profile+""" style="white-space:nowrap;"> [+ loginName +] </a>!  </ strong> <br />
 <a href="[+action+> class="button"> Sign out. </a>

Ugums, made the view, now we will make the controller and create a login snippet, which later will replace the call to the standard WebLogin modiksovskogo:
 <? php
 global $ vbulletin, $ modx;

 $ forumlink = (isset ($ forumlink))?  $ forumlink: 'http: // PATH_TO_YOU_FORUM /';  // if the address of the forum is not specified in the parameter for calling the snippet, then we take the standard

 if ($ vbulletin-> userinfo ['userid'] == 0) {// check if the user is authorized
     //not?  display login form
     echo $ modx-> parseChunk ('forum_login_form', array ('forumLink' => $ forumlink), '[+', '+]');
    // we will check that the user is authorized on the site, but not on the forum.  and if so, then delete the session
    // todo: delete only the session of the WEB user, without touching the MANAGING session
     if (! empty ($ _ SESSION ['webInternalKey'])) {
         session_destroy (); 
         session_unset ();
     }
 }
 else {// if the user is authorized on the forum - we give information to modix
    
     // check if a user account is created on the site?
     $ sql = "SELECT id FROM". $ modx-> getFullTableName ("web_users"). "WHERE id = '". $ vbulletin-> userinfo [' userid ']. "'" ";
     $ rs = $ modx-> db-> query ($ sql);
     $ limit = $ modx-> db-> getRecordCount ($ rs);

     if ($ limit == 0) { 
         // doesn't know mods of such user
         // create
         $ sql = "INSERT INTO". $ modx-> getFullTableName ("web_users"). "(id, username, password) 
                 VALUES (". $ Vbulletin-> userinfo ['userid'].", '". $ Vbulletin-> userinfo [' username ']."', Md5 ('empty')); ";
         $ rs = $ modx-> db-> query ($ sql);      
        
         // save user attributes
         $ sql = "INSERT INTO". $ modx-> getFullTableName ("web_user_attributes"). "(internalKey, fullname, email, zip, state, country) 
                 VALUES (". $ Vbulletin-> userinfo ['userid'].", '". $ Vbulletin-> userinfo [' username ']."', '". $ Vbulletin-> userinfo [' email ']."' , '', '', ''); ";
         $ rs = $ modx-> db-> query ($ sql);
         $ sql = "INSERT INTO". $ modx-> getFullTableName ("web_groups"). "(webgroup, webuser) 
                 VALUES (2, ". $ Vbulletin-> userinfo ['userid']."); ";
         $ rs = $ modx-> db-> query ($ sql);
        
         $ modx-> logEvent (998, 1, 'Created an account on the site.', 'Created an account on the site.', 'login snippet');
     }        
    
     if (! $ modx-> userLoggedIn ()) {// Now check if user is not authorized
         // enter the forum data into the modix session
         $ _SESSION ['webShortname'] = $ vbulletin-> userinfo ['username'];
         $ _SESSION ['webFullname'] = $ vbulletin-> userinfo ['username'];
         $ _SESSION ['webEmail'] = $ vbulletin-> userinfo ['email'];
         $ _SESSION ['webValidated'] = 1;
         $ _SESSION ['webInternalKey'] = $ vbulletin-> userinfo ['userid'];
         $ _SESSION ['webValid'] = base64_encode ($ vbulletin-> userinfo ['password']);
         $ _SESSION ['webUser'] = base64_encode ($ vbulletin-> userinfo ['username']);
         $ _SESSION ['webFailedlogins'] = 0;
         $ _SESSION ['webLastlogin'] = $ vbulletin-> userinfo ['lastactivity'];
         $ _SESSION ['webnrlogins'] = 0;
         $ _SESSION ['usertype'] = 'web'; 
         $ _SESSION ['webUserGroupNames'] = '';  // reset user group names
          
         // roughly speaking we check which groups of documents the user has access to
         // and if they are changed to an already authorized user, the latter will have to "restart"
         $ dg = '';
         $ i = 0;
         $ tblug = $ modx-> getFullTableName ("web_groups");
         $ tbluga = $ modx-> getFullTableName ("webgroup_access");
         $ sql = "SELECT uga.documentgroup
                 FROM $ tblug ug
                 INNER JOIN $ tbluga uga ON uga.webgroup = ug.webgroup
                 WHERE ug.webuser = ". $ Vbulletin-> userinfo ['userid'];
         $ ds = $ modx-> db-> query ($ sql);
         while ($ row = $ modx-> db-> getRow ($ ds, 'num')) $ dg [$ i ++] = $ row [0];
         $ _SESSION ['webDocgroups'] = $ dg;
     }
     // parsim form "exit"
     echo $ modx-> parseChunk ('forum_login_logged', 
             array ('action' => $ forumlink.'login.php? do = logout & logouthash = '. $ vbulletin-> userinfo [' securitytoken '],
                   'profile' => $ forumlink.'usercp.php ',
                   'loginName' => $ vbulletin-> userinfo ['username']),
             '[+',
             '+]'
          );
  
     // part recording user activity
     if (getenv ("HTTP_CLIENT_IP")) $ ip = getenv ("HTTP_CLIENT_IP");
     else if (getenv ("HTTP_X_FORWARDED_FOR")) $ ip = getenv ("HTTP_X_FORWARDED_FOR");
     else if (getenv ("REMOTE_ADDR")) $ ip = getenv ("REMOTE_ADDR");
     else $ ip = "UNKNOWN"; $ _ SESSION ['ip'] = $ ip;

     $ itemid = isset ($ _ REQUEST ['id'])?  $ _REQUEST ['id']: 'NULL'; $ lasthittime = time (); $ a = 998;
    
     $ sql = "REPLACE INTO". $ modx-> getFullTableName ("active_users"). "(internalKey, username, lasthit, action, id, ip) values ​​(-". $ _ SESSION ['webInternalKey']. ", '" . $ _ SESSION ['webShortname']. "','". $ Lasthittime. "','". $ A. "',". $ Itemid. ",' $ Ip ')";
     $ rs = $ modx-> db-> query ($ sql);
 }
 ?> 

The code is sufficiently commented, there should be no questions; Requests made separately (and not through db-> select, db-> insert) out of habit and convenience for debugging.

Just a bit to complete euphoria


Having done everything written above, we have:


And in order to implement this bun, it remains to prescribe the [[login]] snippet call in the site templates, after which it remains only to enjoy the work done. One minus of this approach: until a forum user logs onto the site, it will be impossible to restrict his access rights to the pages, unless of course he is created in the database of such users with pens.

Unlike the BanzaiTokyo method, on the basis of which the development began and which left only the introduction of the global file on the forum in the index.php, there is no need to create a product and modules for it to control the output from the forum and registration — everything happens automatically on the site.

July 28, 2010 UPD:
Programmers who used this solution on their sites! ATTENTION! There is a vulnerability allowed to run blind-SQL:
$ itemid = isset ($ _ REQUEST ['id'])? $ _REQUEST ['id']: 'NULL'; $ lasthittime = time (); $ a = 998;
$ sql = "REPLACE INTO". $ modx-> getFullTableName ("active_users"). "(internalKey, username, lasthit, action, id, ip) values ​​(-". $ _ SESSION ['webInternalKey']. ", '" . $ _ SESSION ['webShortname']. "','". $ Lasthittime. "','". $ A. "',". $ Itemid. ",' $ Ip ')";
$ rs = $ modx-> db-> query ($ sql);

If you substitute a specific subquery into id, you can perform a comparison operation and easily match any data. Unfortunately, through this vulnerability, I was hacked ((I decided simply:
$ itemid = isset ($ _ REQUEST ['id'])? (is_numeric ($ _ REQUEST ['id'])? $ _ REQUEST ['id']: 'NULL') : 'NULL'; $ lasthittime = time (); $ a = 998;
$ sql = "REPLACE INTO". $ modx-> getFullTableName ("active_users"). "(internalKey, username, lasthit, action, id, ip) values ​​(-". $ _ SESSION ['webInternalKey']. ", '" . $ _ SESSION ['webShortname']. "','". $ Lasthittime. "','". $ A. "',". $ Itemid. ",' $ Ip ')";
$ rs = $ modx-> db-> query ($ sql);

Source: https://habr.com/ru/post/93572/


All Articles