Question

I'm making an MSN client in PHP, which makes a persistent socket connection to one of Microsoft's servers:

//Connect to second server
$server2 = explode(":", $xfr[3]);
$socket2 = pfsockopen($server2[0], (int)$server2[1], $errno, $errstr, 999999);
$_SESSION["socket"] = $server2;
echo '<b>Connected to 2nd server.</b><br />';

This works fine, but PHP closes the connection after about a minute, and Microsoft's server signs me out of MSN. Here is the entire page chat.php:

<?php
session_start();

//Check username and password
if(!isset($_POST["username"]) || !isset($_POST["password"]) || !isset($_POST["status"]))
{
    die("Bad request");
}
$wronglogin = false;
//Yep, it's set, so let's connect to MSN

$socket = fsockopen("messenger.hotmail.com", 1863);
echo '<b>Connected to 1st server.</b><br />';
//Send MSNP version
fputs($socket, "VER 0 MSNP10 CVR0\r\n");
echo fread($socket, 5000) . '<br />';
//Send user-agent
fputs($socket, "CVR 1 0x0409 php ".phpversion()." i386 MSNMSGR 7.0.0000 MSMSGS ".$_POST["username"]."\r\n");
echo fread($socket, 5000) . '<br />';
//Send username
fputs($socket, "USR 2 TWN I ".$_POST["username"]."\r\n");
//Read XFR
$xfr = fread($socket, 5000);
echo $xfr . '<br />';
$xfr = explode(" ", $xfr);

//Connect to second server
$server2 = explode(":", $xfr[3]);
$socket2 = pfsockopen($server2[0], (int)$server2[1], $errno, $errstr, 999999);
$_SESSION["socket"] = $server2;
echo '<b>Connected to 2nd server.</b><br />';
//Send MSNP version
fputs($socket2, "VER 0 MSNP10 CVR0\r\n");
echo fread($socket2, 5000) . '<br />';
//Send user-agent
fputs($socket2, "CVR 1 0x0409 php ".phpversion()." i386 MSNMSGR 7.0.0000 MSMSGS ".$_POST["username"]."\r\n");
echo fread($socket2, 5000) . '<br />';
//Send username
fputs($socket2, "USR 2 TWN I ".$_POST["username"]."\r\n");
//Read USR
$usr = fread($socket2, 5000);
echo $usr . '<br />';
$usr = explode(" ", $usr);//This is for later usage.


//Connect to Nexus
$nexus = fsockopen("ssl://nexus.passport.com", 443);
$request_nexus = "GET /rdr/pprdr.asp HTTP/1.1\r\n";
$request_nexus .= "Host:nexus.passport.com\r\n";
$request_nexus .= "User-Agent:Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.1) Gecko/20090715 Firefox/3.5.1\r\n";
$request_nexus .= "Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";
$request_nexus .= "Accept-Language:en-us,en;q=0.5\r\n";
$request_nexus .= "Accept-Charset:ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n";
$request_nexus .= "Keep-Alive:300\r\n";
$request_nexus .= "Connection:keep-alive\r\n";
$request_nexus .= "Cache-Control:max-age=0\r\n\r\n";
fputs($nexus, $request_nexus);
//Receive nexus response
$response_nexus = fread($nexus, 5000);
echo str_replace("\n", "\n<br />", $response_nexus);
//Get passport urls
foreach(explode("\r\n", $response_nexus) as $line)
{
    if(substr($line, 0, strlen('PassportURLs:')) == 'PassportURLs:')
    {
        $PassportURLs = substr($line, strlen('PassportURLs:') + 1);
    }
}
echo $PassportURLs . '<br />';
//Get login server URL
foreach(explode(",", $PassportURLs) as $item)
{
    if(substr($item, 0, strlen('DALogin=')) == 'DALogin=')
    {
        $loginurl = substr($item, strlen('DALogin='));
    }
}
echo $loginurl . '<br />';
//Connect to login server
$loginurl_arr = explode("/", $loginurl);
$loginserver = fsockopen("ssl://" . $loginurl_arr[0], 443);
$request_login = "GET ".substr($loginurl, strlen($loginurl_arr[0]))." HTTP/1.1\r\n";
$request_login .= "Authorization: Passport1.4 OrgVerb=GET,OrgURL=http%3A%2F%2Fmessenger%2Emsn%2Ecom,sign-in=";
    $request_login .= urlencode($_POST["username"]) . ",pwd=" . urlencode($_POST["password"]) . ",";
    $request_login .= $usr[4];
$request_login .= "Host:".$loginurl_arr[0]."\r\n";
$request_login .= "User-Agent:Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.1) Gecko/20090715 Firefox/3.5.1\r\n";
$request_login .= "Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";
$request_login .= "Accept-Language:en-us,en;q=0.5\r\n";
$request_login .= "Accept-Charset:ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n";
$request_login .= "Keep-Alive:300\r\n";
$request_login .= "Connection:keep-alive\r\n";
$request_login .= "Cache-Control:max-age=0\r\n\r\n";
fputs($loginserver, $request_login, 5000);
$response_login = fread($loginserver, 5000);
echo str_replace("\n", "\n<br />", $response_login);
//Get login ticket
foreach(explode("\r\n", $response_login) as $line)
{
    if(substr($line, 0, strlen('Authentication-Info:')) == 'Authentication-Info:')
    {
        $ticket_exp = substr($line, strlen('Authentication-Info:') + 1);
        $ticket_exp = explode(",", $ticket_exp);
        foreach($ticket_exp as $item)
        {
            if(substr($item, 0, strlen('from-PP=')) == 'from-PP=')
            {
                $ticket = str_replace("'", "", substr($item, strlen('from-PP=')));
            }
        }
    }
}
echo $ticket . '<br />';
if(!isset($ticket))
{
    $wronglogin = true;
}
else
{
    //Send USR
    fputs($socket2, "USR 3 TWN S ".$ticket."\r\n");
    //Read USR
    $usr = fread($socket2, 10000);
    echo $usr . '<br />';
    echo str_replace("\n", "\n<br />", fread($socket2, 5000));
    //Sync
    fputs($socket2, "SYN 4 0 0\r\n", 5000);
    echo fread($socket2, 5000) . '<br />';
    //Set status to available
    fputs($socket2, "CHG 5 ".$_POST["status"]."\r\n", 5000);
    echo fread($socket2, 5000) . '<br />';

    //Check login
    if(!substr($usr, 0, strlen("USR 3 OK")) == "USR 3 OK")//Login not succeeded
    {
        $wronglogin = true;
    }
}






if($wronglogin)
{
    fclose($socket);
    session_destroy();
    header("Location: index.php");
}
?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>MSN.php</title>
    <script type="text/javascript" src="jquery-1.3.2.min.js"></script>
    <script type="text/javascript" src="main.js"></script>
</head>
<body>
    <div id="header">
        <input type="text" id="nickname" />
        <select id="status">
            <option value="NLN">Available</option>
            <option value="BSY">Busy</option>
            <option value="IDL">Idle</option>
            <option value="BRB">Be right back</option>
            <option value="AWY">Away</option>
            <option value="PHN">On the phone</option>
            <option value="LUN">Out to lunch</option>
            <option value="HDN">Show offline</option>
        </select>
    </div>
</body>
</html>

Here is main.js:

$(document).ready(function()
{
    //Change status
    $("#status option").click(function()
    {
        $.get("AJAX/status.php?s=" + $(this).attr("value"));
    });
});

And here is AJAX/status.php:

<?php
session_start();

$socket2 = pfsockopen($_SESSION["socket"][0], (int)$_SESSION["socket"][1]);
fputs($socket2, "CHG 0 ".$_GET["s"]." \r\n");
echo fread($socket2, 5000) . '<br />';

Everything works except that either PHP or Microsoft closes the connection. Can anyone help me with this problem? Thanks in advance.

Was it helpful?

Solution

PHP's socket streams have a default timeout of 60 seconds; you may be running into this.

Another thing to keep in mind with persistent sockets, is that the persistent socket is keyed by the connection details, so if you're always connecting to the same server for a multi-user application, you are going to end up with different users sharing connections with each other... and in the case of a messaging application, you're going to bleed from user to another. I'd strongly recommend against the use of pfsockopen here.

I think you'd be better off implementing the long-lived portion of this application as something more standalone (perhaps a PHP script that implemented a daemon process?)

Chat gateways are difficult to implement purely in stateless PHP because they tend to require a good deal of state, especially to maintain presence information.

OTHER TIPS

PHP stops the script because of the time limit.

Put this on the top of your script (chat.php):

set_time_limit(0);

That will enable the script to run forever (which is what you want).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top