Reputation: 1093
I am writing a program that connects to a tcp server with stream_socket_client in php. My problem is that if I echo the contents of the $client object before I perform any additional fwrites, the page hangs. Currently it will work if I send all of my requests before calling stream_get_contents, but once I call stream_get_contents, its like the client no longer responds? I would be thankful for any help given.
**EDIT This is the API I am using: https://www.onlinenic.com/cp_english/template_api/download/ONLINENIC_API2.0.pdf
**EDIT
//see full code below
//------Client creation code, precho function
function getTESTClient($address, $port)
{
$client = stream_socket_client("$address:$port", $errno, $errorMessage);
if ($client === false) {
throw new UnexpectedValueException("Failed to connect: $errorMessage");
}
return $client;
}
function precho($s)
{
echo "<pre>";
echo $s;
echo "</pre>";
}
//-------Problem code
//$loginRequest, $domainAvailableRequest, and $logoutRequest - see full code below
//-----------------------------------------
$address = "www.somesite.com";//This is where I would fill in the address
$port = "12345";//This is where I would fill in the port
$client = getTESTClient($address, $port);
//-----------------------------------------
fwrite($client, $loginRequest);
precho(htmlspecialchars(stream_get_contents($client)));
fwrite($client, $domainAvailableRequest);
precho(htmlspecialchars(stream_get_contents($client)));
fwrite($client, $logoutRequest);
precho(htmlspecialchars(stream_get_contents($client)));
fclose($client);
//-------Alternative working code, if I read all responses at once...
//*But I want to be able to read each response individually...
fwrite($client, $loginRequest);
fwrite($client, $domainAvailableRequest);
fwrite($client, $logoutRequest);
precho(htmlspecialchars(stream_get_contents($client)));
fclose($client);
Full Code:
<?php
function getDomainType($ext)
{
$domaintypes = ['com'=>0, 'net'=>0, 'org'=>807, 'biz'=>800, 'info'=>805, 'us'=>806, 'in'=>808,
'mobi'=>903, 'eu'=>902, 'asia'=>905, 'me'=>906, 'name'=>804, 'tel'=>907, 'cc'=>[600,610], 'tv'=>400,
'tw'=>302, 'uk'=>901, 'co'=>908, 'xxx'=>930, 'pw'=>940, 'club'=>740, 'bike'=>2001, 'clothing'=>2002,
'guru'=>2003, 'holdings'=>2004, 'plumbing'=>2005, 'singles'=>2006, 'ventures'=>2007, 'camera'=>2008,
'equipment'=>2009, 'estate'=>2010, 'gallery'=>2011, 'graphics'=>2012, 'lighting'=>2013, 'photography'=>2014,
'construction'=>2015, 'contractors'=>2016, 'site'=>950, 'online'=>951, 'sex'=>936,
'directory'=>2017, 'kitchen'=>2018, 'land'=>2019, 'technology'=>2020, 'today'=>2021, 'diamonds'=>2022,
'enterprises'=>2023, 'tips'=>2024, 'voyage'=>2025, 'careers'=>2026, 'photos'=>2027,
'recipes'=>2028, 'shoes'=>2029, 'cab'=>2030, 'company'=>2031, 'domains'=>2032, 'limo'=>2033,
'academy'=>2034, 'center'=>2035, 'computer'=>2036, 'management'=>2037, 'systems'=>2038,
'builders'=>2039, 'email'=>2040, 'solutions'=>2041, 'support'=>2042, 'training'=>2043, 'camp'=>2044,
'education'=>2045, 'glass'=>2046, 'institute'=>2047, 'repair'=>2048, 'coffee'=>2049, 'florist'=>2050,
'house'=>2051, 'international'=>2052, 'solar'=>2053, 'marketing'=>2054, 'viajes'=>2055, 'farm'=>2056,
'codes'=>2057, 'cheap'=>2058, 'zone'=>2059, 'agency'=>2060, 'bargains'=>2061, 'boutique'=>2062,
'cool'=>2063, 'watch'=>2064, 'works'=>2065, 'expert'=>2066, 'foundation'=>2067, 'exposed'=>2068,
'villas'=>2069, 'flights'=>2070, 'rentals'=>2071, 'cruises'=>2072, 'vacations'=>2073, 'condos'=>2074,
'properties'=>2075, 'maison'=>2076, 'tienda'=>2077, 'dating'=>2078, 'events'=>2079, 'partners'=>2080,
'productions'=>2081, 'community'=>2082, 'catering'=>2083, 'cards'=>2084, 'cleaning'=>2085, 'tools'=>2086,
'industries'=>2087, 'parts'=>2088, 'supplies'=>2089, 'supply'=>2090, 'report'=>2091, 'vision'=>2092,
'fish'=>2093, 'services'=>2094, 'capital'=>2095, 'engineering'=>2096, 'exchange'=>2097, 'gripe'=>2098,
'associates'=>2099, 'lease'=>2100, 'media'=>2101, 'pictures'=>2102, 'reisen'=>2103, 'toys'=>2104,
'university'=>2105, 'town'=>2106, 'wtf'=>2107, 'fail'=>2108, 'financial'=>2109, 'limited'=>2110,
'care'=>2111, 'clinic'=>2112, 'surgery'=>2113, 'dental'=>2114, 'tax'=>2115, 'cash'=>2116,
'fund'=>2117, 'investments'=>2118, 'furniture'=>2119, 'discount'=>2120, 'fitness'=>2121, 'schule'=>2122,
'sexy'=>2500, 'tattoo'=>2501, 'link'=>2502, 'guitars'=>2503, 'gift'=>2504, 'pics'=>2505, 'photo'=>2506,
'christmas'=>2507, 'blackfriday'=>2508, 'hiphop'=>2509, 'juegos'=>2510, 'audio'=>2511, 'click'=>2512,
'hosting'=>2513, 'property'=>2514, 'top'=>770, 'porn'=>932, 'adult'=>934, 'city'=>2129, 'ceo'=>742];
if(isset($domaintypes[strtolower($ext)]))
{
return $domaintypes[strtolower($ext)];
}
return "unknown";
}
function getTCPClient()
{
}
function getTESTClient($address, $port)
{
$client = stream_socket_client("$address:$port", $errno, $errorMessage);
if ($client === false) {
throw new UnexpectedValueException("Failed to connect: $errorMessage");
}
return $client;
}
function uniqueInvoiceID()
{
$legend = "0123456789";
$len = 22;
$result = "";
for($i=0;$i<$len;$i++)
{
$result .= $legend[rand(0,9)];
}
return "client".$result;
}
function precho($s)
{
echo "<pre>";
echo $s;
echo "</pre>";
}
$clid = "135610";//OnlineNic's test account username
$clpass = "654123";//OnlineNic's test account password
$cltrid = uniqueInvoiceID();//Client Record ID/Invoice
echo $cltrid."<br><br>";
//md5(clid + md5(clpass) + cltrid + “login”)
$checkSumLogin = md5($clid.md5($clpass).$cltrid."login");//Checksum
$checkSumLogout = md5($clid.md5($clpass).$cltrid."logout");//Checksum
$loginRequest = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>
<request>
<category>client</category>
<action>Login</action>
<params>
<param name=\"clid\">$clid</param>
</params>
<cltrid>$cltrid</cltrid>
<chksum>$checkSumLogin</chksum>
</request>";
$logoutRequest = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>
<request>
<category>client</category>
<action>Logout</action>
<params>
<param name=\"clid\">$clid</param>
</params>
<cltrid>$cltrid</cltrid>
<chksum>$checkSumLogout</chksum>
</request>";
$checkDomain = "somedomain.com";
$ext = "com";
$dType = getDomainType($ext);
$requestID = uniqueInvoiceID();
$domainAvailChecksum = md5($clid.md5($clpass).$requestID."checkdomain".$dType.$checkDomain);
$domainAvailableRequest = "<?xml version=\"1.0\"?>
<request>
<category>domain</category>
<action>CheckDomain</action>
<params>
<param name=\"domaintype\">$dType</param>
<param name=\"domain\">$checkDomain</param>
</params>
<cltrid>$requestID</cltrid>
<chksum>$domainAvailChecksum</chksum>
</request>";
$client = getTESTClient("tcp://ote.onlinenic.com", "30009");
fwrite($client, $loginRequest);
precho(htmlspecialchars(stream_get_contents($client)));
fwrite($client, $domainAvailableRequest);
precho(htmlspecialchars(stream_get_contents($client)));
fwrite($client, $logoutRequest);
precho(htmlspecialchars(stream_get_contents($client)));
fclose($client);
?>
Upvotes: 3
Views: 876
Reputation: 5668
The second parameter to stream_get_contents
is $maxlength
, the maximum number of bytes to read. When not set (or the default of -1
is passed), the entire stream is read, up to the end of the stream.
This means that stream_get_contents
will continue to read all the data from the stream until there is no more, when the stream is closed by the other end. (stream_get_contents
does not know the details of your protocol, so it can not know that it is "supposed" to stop reading after "one response" from the server; it doesn't have any concept of what that even means.)
This means, if you have a query-response protocol on your TCP connection, you will have to either stream_get_contents()
exactly the length of data you want to receive (if you know exactly what the response size will be), or you will have to read the data from the server and process it it yourself.
How exactly you do that is going to depend greatly on your protocol. If it is line-oriented, you can use fgets($client)
to retrieve one line at a time. If it is a binary protocol, you can use stream_get_contents($client, $sizeOfYourPacket)
.
Since you have an XML-based protocol, you will probably want to create a new function that handles reading responses and that understands XML, so that it knows how much data to read and when it can send the response (possibly already processed) back to your application.
Without actually having credentials, it's a little hard to see how exactly the server behaves, so beyond this, you're going to have to experiment.
Upvotes: 2