2

I need to implement Comet Chat, a facebook-chat-like third-party script, into my Craft project.

Comet Chat can connect to most CMS and PHP framework but there is no Craft integration yet, so I tried to use the "custom coded site" procedure.

http://www.cometchat.com/documentation/installing-cometchat/custom-coded-site/php-site/

Comet Chat need to access a session variable to authenticate user. Ex: $_SESSION['userid'].

The problem: Craft write its session variables with some nice sorcelery that makes outside script unable to read it.

So, the Comet Chat is not able to read the userid, even if I made a Craft plugin who writes UserID in $_SESSION['userid'].

I also tried, by the Craft cookie ($_COOKIE values are bidirectionally accessible unlike $_SESSION values, of course) to find some relation or mechanism to tells Comet Chat who's the current user in Craft, unsuccessfuly.

Perhaps some other PHP scripts or cases may need to read the Craft session, so I'm pretty sure this question can be relevant for more than Comet Chat integration.

Any ideas?

Thanks in advance!

2

So, the Comet Chat is not able to read the userid, even if I made a Craft plugin who writes UserID in $_SESSION['userid'].

To access Craft's session variables outside Craft, you need to pull the session ID from the CraftSessionId cookie, and then use that to revive the session:

$sessId = $_COOKIE[ 'CraftSessionId' ] ?: false;

if ( $sessId ) {

    session_id( $sessId );
    session_start();

    var_dump( $_SESSION );

}

The current user ID and username session variables will be named __id and __name respectively, but they'll be prefixed with a hash which isn't easily reconstructable outside of Craft (see the Yii class CWebUser, line 547).

To pull the current user's ID from session, that means you could either

a) Write a Craft plugin, which sets your own session variable with the current user's ID:

$currentUser = craft()->userSession->getUser();
$_SESSION[ 'craftUserId' ] = $currentUser ? $currentUser->id : null;

b) ...or loop through the session variables and look for a key ending in __id, with a valid integer value:

$craftUserId = false;

foreach ( $_SESSION as $key => $value ) {

    if ( substr( $key, -4 ) === '__id' && ! is_nan( intval( $value ) ) ) {
        $craftUserId = $value;
        break;
    }

}

Obviously, option a) is your safest bet, as you can never be 100% certain you won't have multiple keys ending in __id, so if you're able to write a plugin to set your own session variable, that would best.

For completions sake, here's what your CometChat getUserId() method could look like:

function getUserID() {

    $userId = 0; // Return 0 if user is not logged in

    $sessId = $_COOKIE[ 'CraftSessionId' ] ?: false;

    if ( $sessId ) {

        session_id( $sessId );
        session_start();

        $userId = $_SESSION[ 'craftUserId' ] ?: 0;

    }

    return intval( $userId );

}
  • Almost there! The problem now is the getUserID function in Comet chat already started the session so I get this: Notice: A session had already been started - ignoring session_start() in /XXXXXX/public_html/cometchat/integration.php on line 46 Notice: Undefined index: craftUserId in /XXXXXX/public_html/cometchat/integration.php on line 48 – r-ninja Apr 5 '15 at 20:59
  • Difficult to advice as CometChat's source code isn't available without purchase, but is it possible to hunt down CometChat's session_start call and put session_name( 'CraftSessionId' ) before it? Either that, or use a wrapper where you start the session yourself before including the CometChat app, I'd wager the latter will probably check for an existing session before attempting to start a new one? – Mats Mikkel Rummelhoff Apr 5 '15 at 21:06
  • Found it. Change in cometchat_init.php is required. I add it to the answer for the benefit of others. Thanks! – r-ninja Apr 5 '15 at 21:08
  • Aces. No problem! – Mats Mikkel Rummelhoff Apr 5 '15 at 21:10
3

The Matt's answer was pretty complete and worked almost, but for the benefit of others, there is the changes required files to make it works:

in integration.php

find

define('SET_SESSION_NAME','');

change for

define('SET_SESSION_NAME','CraftSessionId');

and make your getUserID functions look like

function getUserID() {
            $userId = 0; // Return 0 if user is not logged in

            if ( $_SESSION[ 'craftUserId' ] ) 
            {
                $userId = $_SESSION[ 'craftUserId' ]; // Set this session variable in a Craft plugin
            }

            return intval( $userId );
    }

and in a Craft plugin, add this to a init() function

public function init()
    {            
        craft()->on('userSession.onLogin', function(Event $event) {
            $currentUser = craft()->userSession->getUser();
            craft()->httpSession->add( 'craftUserId', $currentUser ? $currentUser->id : null );            
        });
   }

If you want to be full-padded, you can also add something to unset your CraftUserId variable onLogout event, but I don't think it's needed.

Thanks a lot to Matt and Brad who helped me out on Easter day!

1

You can write a simple Craft plugin that listens for the onLogin event, like so:

public function init()
{
    craft()->on('userSession.onLogin', function(Event $event)
    {
        $username=$event->params['username'];
        $user = craft()->users->getUserByUsernameOrEmail($username);
        $_SESSION['userid'] = $user->id;
    });
}

Note that you'll want to write to and read from $_SESSION directly here instead of going through craft()->session->add() because that will have to additional data hashing that your integration script would need to be aware of.

Craft automatically renames what the PHP session cookie is called from the default PHPSESSID to CraftSessionId.

So your Comet Chat integration script would have to use that same name before it calls session_start(), otherwise it's going to create a new session cookie with the name PHPSESSID that won't have your information in it.

Something like this from your integration script should do it:

if (!isset($_SESSION))
{
    session_name('CraftSessionId');
    session_start();
}

if (isset($_SESSION['userId]))
{
    $userId = $_SESSION['userId'];
}
  • Didn't know about session_name(). Very clean stuff! – Mats Mikkel Rummelhoff Apr 5 '15 at 21:14
  • I suppose this whole scenario makes a valid use case for us making the PHP session cookie name configurable... – Brad Bell Apr 5 '15 at 21:33
  • Not sure about the difference between session_name and session_id. In this case, both works I guess... – r-ninja Apr 5 '15 at 21:33
  • @mkweb Both works, but if you use session_name( 'CraftSessionId' ); you don't have to check for and pull the session ID from the cookie. Less code, that's all :) – Mats Mikkel Rummelhoff Apr 5 '15 at 21:35
  • @BradBell Couldn't hurt :) – Mats Mikkel Rummelhoff Apr 5 '15 at 21:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.