Ryan has posted 9 posts at DZone. View Full User Profile

Integrating PHP with Flash Collaboration Services

11.16.2009
| 17582 views |
  • submit to reddit
Adobe recently announced the availability of a framework called LiveCycle Collaboration Services (LCCS). With LCCS you can create real-time collaborative applications with Flash. It includes the ability to create applications with video chat, whiteboard collaboration, or build your own custom components that support real-time collaboration. For an introduction to LiveCycle Collaboration Services you can check out the getting started article on Collaboration Services over on Adobe Developer's Center. One of the concepts in LCCS is rooms where the collaboration takes place. Every application connects to a specific room and all of the users in that room can collaborate with each other in real-time through the application.

There are a couple of different ways that Collaboration Services integrates with PHP. The first is through authentication. Collaboration Services uses a token authentication system so you can use any back end to authenticate your users. That way instead of having to use an Adobe ID for every user, you can tie it into your own authentication system using PHP including Drupal, Joomla, or any custom system. The other integration point is using the REST APIs that Collaboration Servcies exposes to manage rooms. With the REST API and the PHP library that comes with the Collaboration Services SDK you can dynamically create and manage rooms. This gives you complete control over how and when rooms are created so that you can create specific collaboration use cases for different parts of your application and easily integrate the Flash front end with your PHP back end.

The most common case for integrating LiveCycle Collaboration Services with PHP will be using PHP to perform the authentication of your users. In order to use the external authentication method with PHP you'll need to make sure you have an AdobeID and you'll need to create a developer account for LCCS. Both of those can be done at the LCCS Developer Portal. Once you've created an account and signed in you'll see a summary of your account along with usage totals and the number of rooms you have created. You'll also see a link to download the SDK which is an AIR application that contains the library files as well as documentation and tutorials for specific tasks. To use external authentication you'll need to generate a shared secret. You will use a combination of your LCCS account information and this shared secret to authenticate users.

LiveCycle Collaboration Services uses the AdobeHSAuthenticator tag to authenticate the user who owns the account. During development, the AdobeHSAuthenticator tag takes a username/password so you can easily use your LCCS developer account information. But in production you can use the shared secret and keep your username and password on the server where the source code is never available. For PHP and some of the other major languages we have created libraries with some of the code to handle authentication. In both examples I will use this heavily and the source code can be found in the serverIntegration folder of the AFCS SDK.

LCCS has a concept of roles so that you can define who is allowed to do what on specific parts of the application or globally. For instance a "viewer" can log into the room and see content but can't change anything. A "publisher" can both log in and change things, so can collaborate with other users. The "owner" level allows the user to both contribute and control parts of the room. For instance the owner can kick out users and also change the permission of users in the room. The roles are based on a number between 0 and 100 where 0 has no access, 10 is a viewer, 50 is a publisher, and 100 is the owner. When using external authentication you need to give the user logging in a role in addition to getting their username and password.

To log in with the provided PHP libraries we simply create an instance of the AFCSAccount class to create the session and then get our authentication token from the server. In order to make the connection we need the account URL and the shared secret from the LCCS development console above as well as our LCCS developer username and password and the room we want to connect to.

To start, create a basic HTML form with some PHP for the variables we need. I find having the login page in HTML versus Flex makes it much easier to use. You get auto-complete, and other features that users with modern browsers expect.

<?php
require_once("afcs.php");

$account = "Your SDK account username from LCCS developer portal";
$room = "The room you want to connect to";
$devUsername = "Your LCCS developer account username";
$devPassword = "Your LCCS developer account password";
$secret = "The shared secret from the LCCS developer portal";

$accountURL = "http://connectnow.acrobat.com/{$account}";
$roomURL = "{$accountURL}/{$room}";

$username = "";
$displayName = "";
$role = 0;

session_start();

if( isset($_POST['submitted']))
{
// Where we run our login logic
}

?>
<html>
<head>
<title>LCCS Login</title>
</head>
<body>
<h4>Log in to your collaborative application</h4>
<form method="POST">
<b>User Name</b>
<input type="text" name="username">
<b>Password</b>
<input type="password" name="password">
<input type="hidden" name="submitted" value="true" />
<input type="submit" value="Enter Room"></td>
</form>
</body>
</html>


The form takes a username and password and when we submit it we'll use the information to authenticate our user and create a token that we can use in our application. In order to generate the token we first need to establish a session by logging in with our LCCS developer portal username and password. With that session information and a role we determine for our users we can generate a token which will be used in the actual Flex application. In this example I'm going to check for a specific username/password combo and set the role accordingly. For your example you could use other information from your user database or LDAP server to determine the role.

    if( isset($_POST['submitted']))
{
$username = $_POST['username'];
$password = $_POST['password'];

// Set our roles depending on the username/password
// This is where you would place your own authentication logic
if($username == "owner" && $password == "owner")
{
$displayName = "Owner";
$role = 100;
} else if ($username == "publisher" && $password == "publisher")
{
$displayName = "Publisher";
$role = 50;
} else if ($username = "viewer" && $password == "viewer")
{
$displayName = "Viewer";
$role = 10;
}

// set up the instance of the account using the AFCSAccount class
$account = new AFCSAccount($accountURL);

// use the developer portal login to create the session
$account->login($devUsername,$devPassword);

// retreive our session information
$session = $account->getSession($room);

// Use our user's credentials to get the token
// The method takes the secret, the username, the display name, and the role
$token = $session->getAuthenticationToken($secret, $displayName, $username, $role);
}


The library classes do most of the heavy lifting for us. Logging in to the sever with our developer portal credentials gives us an authentication token. In order to get the authentication token we use our shared secret from the developer portal, the display name we want the user to have in the room (this could be first and last name for instance) and then the username and the role (a number between 0-100). With that authentication token and the information about which room we're logging into, we start a session which allows us to get information and make changes to the room. Once the session is active the getAuthenticationToken method uses the session information and the user information to log a user into that particular room. In order to let the user start collaborating with other users we need to get that authentication token into the AdobeHSAuthenticator tag of our Flex application.

Flash and Flex have an easy way to load variables from the page on which the Flash application is embedded called Flash Vars. With a language like PHP you can easily create dynamic Flash vars and then change the behavior of a Flex application. In this case we can use that authentication token we get back from the server and embed it as a Flash var so we can use it inside of our Flex application. By default, when you create a new Flash Builder project, it creates both the SWF file that contains the Flex application as well as a lot of HTML and JavaScript to embed that SWF file on the page. The embed code is very well optimized so it's best not to change it much, so in this case we'll use some JavaScript to create a new window with our generated .html file from Flash Builder. In your PHP file, add the following code between the head tag and make sure your body tag calls the onLoad() function we're creating. This will pass our roomURL and our generated token to a new window which will contain the HTML file with our LCCS application SWF.

    <script type="text/javascript">
function onLoad() {
<?php
if (isset($token) && $role > 0) {
$message = "Successfully logged in";

print(
"win = window.open(".
"'main.html?roomURL={$roomURL}&authToken={$token}',".
"'_blank',".
"'left=0,top=0,width=800,height=600,toolbar=1,resizable=1');");
} else {
$message = "You do not have access to the room."
}
?>
}
</script>
<title>LCCS Login</title>
</head>
<body onload="onLoad();">

In order for this to work, we need to make a couple of minor changes to the HTML template file that Flash Builder uses to generate the final HTML page for the Flex project. Create a new Flash Builder project and make sure you add the correct .SWC file so you can use the LiveCycle Collaboration Service components and libraries. The link to the getting started document above has the info on how to do that. Once the project is created, drill down into the html-template folder and edit the index.template.html. By default, Flash Builder uses this html-template folder to create the embed code for both debug and final versions of a Flash Builder project. In that file there is a large if/else block that determines if we have the right version of the Flash Player or any version of Flash Player at all. In the block that runs if the correct version is found we want to make the folliowing changes.

} else if (hasRequestedVersion) {
// if we've detected an acceptable version
// embed the Flash Content SWF when all tests are passed

// Turn the url variables into flashvars
urlVariables = location.href.split('?');
flashvars = urlVariables.length > 1 ? urlVariables[1] : "";

AC_FL_RunContent(
"src", "${swf}",
"flashvars",flashvars,
"width", "${width}",
"height", "${height}",
"align", "middle",
"id", "${application}",
"quality", "high",
"bgcolor", "${bgcolor}",
"name", "${application}",
"allowScriptAccess","sameDomain",
"type", "application/x-shockwave-flash",
"pluginspage", "http://www.adobe.com/go/getflashplayer"
);


In that code all that's happening is that we're reading the variables from the URL and turning those into a string which we can pass as flashvars. You also have to make sure the flashvars are passed in by adding a "flashvars",flashvars name-value pair to the AC_FL_RunContent() method below the "src" attribute.

Now when our application runs those two variables will be passed in and we need to reference them. In our Flex application we can use the Application class to grab and set them so we can use them in the application. Instead of using the AdobeHSAuthenticator tag with a username/password we only need to pass in our authToken. The only other tag we need to complete the login process is the ConnectSessionContainer tag. I have also included some standard LCCS "pods" which are like mini-applications that enable specific collaboration scenarios. In this case we have a whiteboard, a basic text chat, and a roster so we can see who is in the room with us. Inside of our script block we also have some methods that will run depending on whether or not we've successfully authenticated. Here's the full Flex application.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute" minWidth="1024"
minHeight="768" xmlns:rtc="AfcsNameSpace"
enabled="false"
creationComplete="application1_creationCompleteHandler(event)"
xmlns:coreUI="CoreUINameSpace">
<mx:Script>
<![CDATA[
import com.adobe.rtc.events.SessionEvent;
import com.adobe.rtc.events.AuthenticationEvent;

import mx.controls.Alert;
import mx.events.FlexEvent;
import mx.utils.ObjectUtil;

[Bindable]
private var roomURL:String;
[Bindable]
private var authToken:String;


protected function application1_creationCompleteHandler(event:FlexEvent):void
{
roomURL = Application.application.parameters.roomURL;
authToken = Application.application.parameters.authToken;
cSession.login();
}


protected function auth_authenticationFailureHandler(event:AuthenticationEvent):void
{
Alert.show("There was an authentication problem. Close the window and log in again.");
}


protected function auth_authenticationSuccessHandler(event:AuthenticationEvent):void
{
Application.application.enabled = true;
}

]]>
</mx:Script>

<rtc:AdobeHSAuthenticator id="auth" authenticationKey="{authToken}"
authenticationFailure="auth_authenticationFailureHandler(event)"
authenticationSuccess="auth_authenticationSuccessHandler(event)"
/>
<rtc:ConnectSessionContainer id="cSession" width="100%" height="100%"
authenticator="{auth}"
roomURL="{roomURL}" autoLogin="true">
<mx:HBox width="100%" height="100%">
<mx:VBox width="75%" height="100%">
<coreUI:WhiteBoard id="wb" width="100%" height="80%"/>
<rtc:SimpleChat id="chat" width="100%" height="20%" />
</mx:VBox>

<rtc:Roster width="25%" height="100%" />
</mx:HBox>
</rtc:ConnectSessionContainer>
</mx:Application>


In our Application tag I've set enabled equal to false so that none of the components will be available until there is a successful log in. We're using a very powerful feature of Flex called binding to associate our Flash vars with the tags that require them. With binding any time the variable changes, any component using that variable will see that the value has changed and use the new one. In this case, we call a function as soon as the application has finished loading which grabs the Flash vars and sets them accordingly. After that happens, the login() method of our ConnectSessionContainer is called which logs us into the system.

Then we have a couple of event handlers on our AdobeHSAuthenticator tag. If the login() call is successful, we call our SuccessHandler() method and if it's not, we call the FailureHandler(). Inside the SuccesHandler() we set the enabled attribute of the application to true and then allow the users to collaborate.
Published at DZone with permission of its author, Ryan Stewart.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Edison Leon replied on Tue, 2009/11/24 - 2:04pm

A bit advance for me right now, but defenetly worth the reading and I may try the sample in a local machine. Thank you!

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.