Talk:Multi friend selector

From Facebook Developer Wiki

Jump to: navigation, search

Contents

[edit] Alternative, custom multi friend selector

If you don't want to send invitations, but rather have a custom, general purpose multi friend selector, apparently you can't do it with standard FBML, but you have

-- Matt

Further discussion...

--

Hi,

Any plans to make this available outside of the invitation process?

Bill

  • what does that mean?
    • I believe he means to use <fb:multi-friend-selector> outside of <fb:request-form>. This would be very useful. Just have it return an array of uid to a new page. Also, lift 20 user limit for non invitation request uses. 3629113 22:31, 22 September 2007 (PDT)
    • I also think it would be great to be able to limit the selection to just 1 friend. I have an app in the works where certain actions can only be taken on a single friend. I'd love it if I could easily have a friend selector where all friends with the app would be displayed graphically. Then the type-ahead box could be used to search for friends without the app. If a graphical friend is selected, the action is taken. Otherwise, the invitation dialog appears.

--

The way I'm reading these specs, IFRAME developers will need to give up the entire canvas page for a Facebook-controller user experience. Does this have to take up the full screen real-estate? I think you'll find that most apps have other content on the invite page (help text, your "score", etc). We should be able to IFRAME http://www.facebook.com/multi_friend_selector.php so that it consumes only a portion of the screen.

  • I'll think about the iframe-within-an-iframe idea, it sounds feasible

--

If you want to see it in action, my app is Friend Wheel. There's an "invite friends" link on the canvas page. I guess you could view the source to see how it works if you need to. Tom.

--

I think i understand how you did it.In your invite page,you put a hidden form which action is "http://www.facebook.com/multi_friend_selector.php",set the method post,and you set the target "_top",so when user click "invite your friends",this code will submit this form,and user will see an perfect invite page. Fan Xinlei


[edit] New bug introduced (found 8/22/2008...probably was happening earlier)

Well, facebook does it to us iFrame'ers again. They've changed the query string paramater being passed to the action= page. For some time the parameter name was "ids[]" and would be a comma separated list of friend ids that were sent Invites/Requests. Now it appears this is not the case anymore and no one told the developers. Apparently now they're being passed back individually as ids[0], ids[1], etc., etc. So be forewarned.


[edit] New invite suggestion

I generally like the new standardized invite mechanism but I really miss being able to show who already has the application. On that note, here's a few possible changes. 1.) Include a parameter that turns on an indicator for showing who already has the app and possibly a new sorting mechanism. 2.) As it is, it will be a pretty common thing to try to exclude IDs that have the application already. Rather than introduce the delay of the callback to Facebook to get the list of those friends that have the app, perhaps this could be added as a standard parameter (e.g., exclude_has_app = true). Or perhaps a tri-valued parameter (e.g., include_friends={with_app,without_app,both[default]}.

--steve jernigan

[edit] Images in new invite mechanism

In notifications_sendRequest we used to be able to specify a different image. Is that no longer the case? thanks, - rajat

[edit] Sending back additional params with action url?

Any suggestions on how to add additional data to be passed back when action url is called? I'm able to get back the ids that were selected by the user but the context of the original request is lost when by the time the action url is called. e.g. User Bob want to share a review about Song "the way i am" with some friends, he selects friends 123 & 456, those 2 userIds are part of the request that comes back to the action url but the identifier to the song/review that was being share is lost. It would be nice to be able to pass in some param into m_f_s.php and have just sent back as part of call to the action url.


Anybody have any information about passing additional parameters from the MFS process yet (following up on the note above)?


How are you getting back a list of friends to come back to your action URL?


The following will give you a comma-delimited list of friend IDs on your action URL:

Request.QueryString["ids[]"]

You can use name/value pairs on the action url in order to pass additional information.

[edit] Unknown User when returned to action URL

can you send fb_sig_user or auth_token in the Post back?

[edit] Sending invitation emails to friends through facebook

We have an application that uses the <fb:multi-friend-selector> to send invitations to our facebook friends. We would want to be able to send invitation emails to those friends through facebook . Is there a way we can accomplish this? Thanks.

[edit] Working sample of Multi Friend Selector for IFRAME applications

It was a bit of a struggle, but here is working PHP code that uses the new multi_friend_selector.php approach to initiating invites to your application. I am also including the code for the old style approach; the soon to be deprecated approach using $facebook->api_client->notifications_sendRequest.

The biggest challenge I encounteed is the URL signing process. It is very easy to get signing errors when trying to redirect to the multi_friend_selector.php page, due to URL and HTML encoding. In order to discover the source of the verification issues, I literally had to start with a minimalist set of arguments to the multi_friend_selector.php page, and build them up in a trial and error fashion. I discovered that using PHP functions like htmlentities() and urlencode() on the arguments and/or the URL can cause the final URL to differ from the raw aguments passed to the signature generator. If the URL passed to $facebook->redirect() is encoded in any way, it will appear to not pass the signature verification.

So here is the code that works. Like I said, adding calls to htmlentites() and urlencide() can caue the verfication to break down. I also discovered that using double quotes in the $content string also throws things off the verification.

Hopefully this article will help others out there make the switch from $facebook->api_client->notifications_sendRequest to multi_friend_selector.php.

   define( 'FB_API_KEY', 'abcdabcdabcdabcdabcdabcdabcdabcd' );
   define( 'FB_SECRET', 'abcdabcdabcdabcdabcdabcdabcdabcd' );
   define( 'FB_APPID', '0123456789' );
   define( 'FB_CANVAS_URL', 'http://apps.facebook.com/myapp/' );
   define( 'FB_APP_HOME_URL', 'http://www.mycompany.com/myapp/' );
   // Call this function to send an invitation
   // $to - a comma separated list of Facebook userids to invite.  It can be null for the NewStyle case.
   // $bNewSytle - a bool indicating whether the new style mechanism should be used (multi_friend_selector.php)
   function SendStandardInvitation($to, $bNewStyle = false)
   {
       $typeword = FB_APP_NAME;
       // Warning: double quotes in the content string will screw up the invite signature process
       $content  = FB_APP_NAME . ' let\'s you blah blah blah.  You can even blah blah blah!';
       $content .= '<fb:req-choice url=\' ' . FB_CANVAS_URL . 'Home.php\' label=\'Check out ' . FB_APP_NAME . ' />';
       $actionText = 'Spread the word!  Help your friends discover ' . FB_APP_NAME . '.';
       if ($bNewStyle)
           $bOK = SendNewRequest($to, $typeword, $content, $actionText);
       else
           $bOK = SendRequest($to, $typeword, $content);
       return $bOK;
   }
   // The new style invite approach using multi_friend_selector.php
   function SendNewRequest($to, $typeword, $content, $actionText, $bInvitation = true)
   {
       global $facebook;
       
       $bInviteAll = (!$to || $to == "" ? true : false);
       $excludeFriends = null;
       if (!$bInviteAll) // Get all friends
           $excludeFriends = $facebook->api_client->friends_get();
       else // Get all friends with the app
           $excludeFriends = $facebook->api_client->friends_getAppUsers();
       
       $excludeFriendsStr = null;
       foreach ($excludeFriends as $userid)
       {
           $pos = strpos($to, (string)$userid);
           if ($pos !== false)
               continue;
           if ($excludeFriendsStr)
               $excludeFriendsStr .= ',';
           $excludeFriendsStr .= $userid;
       }
       
       $params = array();
       $params['api_key'] = FB_API_KEY;
       $params['content'] = $content; // Don't use htmlentities() or urlencode() here
       $params['type'] = $typeword;
       $params['action'] = FB_CANVAS_URL . 'Mobilize';
       $params['actiontext'] = $actionText;
       $params['invite'] = ($bInvitation ? 'true' : 'false');
       $params['rows'] = '5';
       $params['max'] = '20';
       $params['exclude_ids'] = $excludeFriendsStr;
       $params['sig'] = $facebook->generate_sig($params, FB_SECRET);
       
       $qstring = null;
       foreach ($params as $key => $value)
       {
           if ($qstring)
               $qstring .= '&';
           $qstring .= "$key=$value";
       }
       
       $inviteUrl  = 'http://www.facebook.com/multi_friend_selector.php?';
       $facebook->redirect($inviteUrl . $qstring);
       return true;
   }
   // The old style invite approach using $facebook->api_client->notifications_sendRequest
   function SendRequest($to, $typeword, $content, $bInvitation = true)
   {
       global $facebook;
       
       $image = FB_APP_HOME_URL . 'logo.gif'; // To be shown beside the invite; resized to be 100 pixels wide
       $result = $facebook->api_client->notifications_sendRequest($to, $typeword, $content, $image, $bInvitation);
       $url = $result;
       if (isset($url) && $url)
       {
           $facebook->redirect($url . '&canvas=1&next=Home.php');
           return true;
       }
       
       $bOK = ($result && $result != "");
       return $bOK;
   }


I hope this helps.

Jim McCurdy Face To Face Software

  • I don't really get what is "Mobilize" for? Else thanks a lot for this usefull script...

680900705 02:49, 21 March 2009 (PDT)

[edit] Multi_Friend_Selector posting example for .NET

I had a hard time finding any .NET examples for Multi_Friend_Selector.php so I cobbled this one together. A querystring example would be much simpler due to ASP.NET's problems with posting and containing multiple forms; however, using post allows for more data to be passed which might be a factor if the user's exclude_id list is large. This example uses Javascript to create a new form on your ASP.NET page and then fills it with the required hidden fields to post. Not as elegant as I would have liked, but it works.

   Protected Sub btnInviteFriends_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnInviteFriends.Click
       'init multi_friend_selector parameters
       Const API_KEY As String = "12345678901234567890123456789012"
       Const SECRET As String = "12345678901234567890123456789012"
       Const ACTION As String = "http://apps.facebook.com/elevenreps/"
       Const ACTION_TEXT As String = "Invite friends to join 11reps"
       Const CONTENT As String = "11reps <fb:req-choice url=""http://apps.facebook.com/elevenreps/"" label=""Add 11reps.com"" />"   'Note: it doesn't like when you use the apostrophe ' in your content
       Const MAX As String = "20"
       Const INVITE As String = "true"
       Const TYPE As String = "11reps"
       'dertermine who already has app
       Dim strExcludeIds As String = ""
       strExcludeIds = getMembers(API_KEY, SECRET)
       'build key for signature
       Dim strConcat As String = "action=" & ACTION & "actiontext=" & ACTION_TEXT & "api_key=" & API_KEY & _
           "content=" & CONTENT & "exclude_ids=" & strExcludeIds & "invite=" & INVITE & "max=" & MAX & "type=" & TYPE & SECRET
       Dim strSig As String = getMd5Hash(strConcat)
       'create new post form
       Response.Write("<form id=""postForm"" target=""_top"" action=""http://www.facebook.com/multi_friend_selector.php"" method=""post"">")
       Response.Write("</form>")
       Dim sb As New System.Text.StringBuilder
       'build javascript to insert hidden elements into form
       sb.Append("<script language=javascript>")
       sb.Append("function setElem(form, name, value) {")
       sb.Append("var el = document.createElement(""input"");")
       sb.Append("el.type = ""hidden"";")
       sb.Append("el.name = name;")
       sb.Append("el.value = value;")
       sb.Append("form.appendChild(el);")
       sb.Append("}")
       'insert parameters into form and submit
       sb.Append("var myForm = document.forms['postForm'];")
       sb.Append("setElem(myForm, 'action', '" & ACTION & "');")
       sb.Append("setElem(myForm, 'actiontext', '" & ACTION_TEXT & "');")
       sb.Append("setElem(myForm, 'api_key', '" & API_KEY & "');")
       sb.Append("setElem(myForm, 'content', '" & CONTENT & "');")
       sb.Append("setElem(myForm, 'exclude_ids', '" & strExcludeIds & "');")
       sb.Append("setElem(myForm, 'invite', '" & INVITE & "');")
       sb.Append("setElem(myForm, 'max', '" & MAX & "');")
       sb.Append("setElem(myForm, 'type', '" & TYPE & "');")
       sb.Append("setElem(myForm, 'sig', '" & strSig & "');")
       sb.Append("myForm.submit();")
       sb.Append("</script>")
       ClientScript.RegisterClientScriptBlock(GetType(String), "addScript", sb.ToString)
       sb = Nothing
   End Sub
   Private Function getMembers(ByVal api_key As String, ByVal secret As String) As String
       Dim strExcludeIds As String = ""
       Dim _fbService As New Facebook.Components.FacebookService()
       _fbService.ApplicationKey = api_key
       _fbService.Secret = secret
       _fbService.IsDesktopApplication = False
       _fbService.SessionKey = Session("facebook_session_key")
       _fbService.UserId = Session("facebook_userId")
       Try
           Dim otherFriends As System.Collections.ObjectModel.Collection(Of Facebook.Entity.User) = _fbService.GetFriendsAppUsers
           For Each myFriend As Facebook.Entity.User In otherFriends
               strExcludeIds &= myFriend.UserId & ","
           Next
           If strExcludeIds.Length > 0 Then
               strExcludeIds.TrimEnd(",")
           End If
       Catch ex As Exception
       End Try
       Return strExcludeIds
   End Function
   Private Function getMd5Hash(ByVal input As String) As String
       'Create a new instance of the MD5CryptoServiceProvider object.
       Dim md5Hasher As System.Security.Cryptography.MD5 = System.Security.Cryptography.MD5.Create()
       'Convert the input string to a byte array and compute the hash.
       Dim data As Byte() = md5Hasher.ComputeHash(System.Text.Encoding.Default.GetBytes(input))
       'Create a new Stringbuilder to collect the bytes
       'and create a string.
       Dim sBuilder As System.Text.StringBuilder = New System.Text.StringBuilder()
       'Loop through each byte of the hashed data 
       'and format each one as a hexadecimal string.
       For i As Int32 = 0 To data.Length - 1
           sBuilder.Append(data(i).ToString("x2"))
       Next
       'Return the hexadecimal string.
       Return sBuilder.ToString()
   End Function

Good luck, Joe Kennedy, 11reps.com

[edit] multi friend selector example for java

   protected ModelAndView handleRequestInternal(HttpServletRequest request,
       HttpServletResponse response) throws Exception 
   {
       String contentStr = "You have been invited to blah blah";
       String typeStr = "exciting";
       String actionTextStr  = "Select the friends that you would like to invite";
   
       Map<String, String> mfsParams = new HashMap<String, String>();
   		
       mfsParams.put("api_key", client.getApiKey());
       mfsParams.put("content", contentStr);
       mfsParams.put("type", typeStr);
       mfsParams.put("action", facebookConfig.getCallbackUrl() + "invite.htm");
       mfsParams.put("actiontext", actionTextStr );
       
       String finalMFSUrl = buildQueryString( 
               "http://www.facebook.com/multi_friend_selector.php",
               mfsParams, facebookConfig.getSecretKey());
       
       log.debug("finalMFSUrl = [" + finalMFSUrl + "]");
       
       return new ModelAndView(new RedirectView(finalMFSUrl));
   }
   private String buildQueryString(String baseUrl, Map<String, String> mfsParams, String secretKey) 
   {
   
       // get back the list of params key=value string, need for sig calc
       List<String> params = buildParamsList(mfsParams);
       Collections.sort(params);
   
       String sig = FacebookSignatureUtil.generateSignature(params, secretKey);
   
       String queryString = baseUrl + "?";
       for (String keyvalue : params) {
           queryString += keyvalue + "&";
       }
       queryString += "sig=" + sig;
       return queryString;
   }
   private List<String> buildParamsList(Map<String, String> mfsParams) 
   {
       List<String> params = new ArrayList<String>();
       
       for (Iterator iter = mfsParams.keySet().iterator(); iter.hasNext();) {
           String key = (String) iter.next();
           String value = mfsParams.get(key);
           params.add(key + "=" + value);
       }
   
       return params;
   }

after the user does their thing, they'll be sent to the url specified in the "action" key of mfsParams with the userIds of the selected friends that the message was sent to (facebook has already taken care of sending the messages at this point). you can get those ids like this:

   String[] ids = request.getParameterValues("ids[]");
   for (int i = 0; i < ids.length; i++) {
       String id = ids[i];
       log.debug("id[" + i + "] = [" + id + "]");
   }


[edit] Action URL not called with parameters on invite sent

Hi, first thanks for the code, it work well for most part, except I dont have facebook endup on my action URL after invites having been properly sent (using the new system). When I skip the invite everything goes well, but when I validate it does not call the action URL with the parameters. My action url is in the form of :

   $params['action'] = FB_CANVAS_URL . "?action=invited&param1=good";

I tried a second way, Get or Post parameters are supposed to be passed through, but it does not happen, they get removed.

I don't land on the home page, I just lend on the right page without the parameters.

In general most calls use the "next" parameter to provide a next url to land, and here I didn't find a solution. Any idea ? Thanks

--748727835 15:11, 3 April 2009 (PDT)

Hi,

I copied completely your sample code and created a test application http://apps.facebook.com/bezisfriends/ but the only thing that I am getting is the blank page.

I don't see a form for multi selection of friends.

Can you help me please.

Bez

Are you talking about the code on the talk page above, or in the actual article itself? Pete (563683308 12:15, 15 April 2009 (PDT))
reference