fsockopen
(PHP 4, PHP 5, PHP 7, PHP 8)
fsockopen — インターネット接続もしくは Unix ドメインソケット接続をオープンする
説明
string
$hostname
,int
$port
= -1,int
&$error_code
= null
,string
&$error_message
= null
,?float
$timeout
= null
): resource|false
hostname
で指定したリソースへのソケット接続を開始します。
サポートされるソケットトランスポートのリスト に記述されているように、PHP は Internet ドメインまたは Unix ドメインをサポートします。 サポートされるトランスポートのリストは、stream_get_transports() を使って取得することもできます。
ソケットはデフォルトでブロックモードで開かれます。 socket_set_blocking() を使用して、 非ブロックモードに切換えることができます。
stream_socket_client() 関数もこれと似ていますがより豊富なオプションを持っており、 非ブロック接続をしたりストリームコンテキストを提供したりする機能があります。
パラメータ
hostname
-
OpenSSL サポートが インストール されている場合、
hostname
の前にssl://
またはtls://
を付加することにより、TCP/IP 経由でリモートホストに接続する際に SSL または TLS クライアント接続を使用することができます。 port
-
ポート番号。
unix://
のようにポートを使わないトランスポートの場合は、-1
で無視してスキップさせることができます。 error_code
-
指定した場合は、システムコール
connect()
で発生したエラーのエラー番号が格納されます。error_code
は0
なのに関数がfalse
を返す場合、connect()
をコールする前にエラーを発生したことを示します。 この場合、おそらくはソケットの初期化に原因があります。 error_message
-
エラーメッセージを表す文字列。
timeout
-
接続タイムアウト秒数。
null
の場合は、 php.ini の default_socket_timeout 設定を使います。注意:
ソケット経由でデータを読み書きする際のタイムアウトを設定する必要がある場合、 fsockopen() の
timeout
パラメータは、 ソケットに接続する間にだけ適用されるため、 socket_set_timeout() を使用してください。
戻り値
fsockopen()は、ファイルポインタを返します。
このファイルポインタは、
(fgets(), fgetss(),
fputs(), fclose(),
feof() のような)
他のファイル関数で使用可能です。
失敗した場合は false
を返します。
エラー / 例外
hostname
が有効なドメインでない場合は
E_WARNING
をスローします。
変更履歴
バージョン | 説明 |
---|---|
8.0.0 |
timeout は、nullable になりました。
|
例
例1 fsockopen() の例
<?php
$fp = fsockopen("www.example.com", 80, $errno, $errstr, 30);
if (!$fp) {
echo "$errstr ($errno)<br />\n";
} else {
$out = "GET / HTTP/1.1\r\n";
$out .= "Host: www.example.com\r\n";
$out .= "Connection: Close\r\n\r\n";
fwrite($fp, $out);
while (!feof($fp)) {
echo fgets($fp, 128);
}
fclose($fp);
}
?>
例2 UDP 接続の使用法
以下の例は、自分のマシンの UDP サービス "daytime" (ポート13) から日付と時間を取得する方法を示すものです。
<?php
$fp = fsockopen("udp://127.0.0.1", 13, $errno, $errstr);
if (!$fp) {
echo "ERROR: $errno - $errstr<br />\n";
} else {
fwrite($fp, "\n");
echo fread($fp, 26);
fclose($fp);
}
?>
注意
注意:
環境によっては Unix ドメインまたは オプションの接続タイムアウトが利用できないこともあります。
UDPソケットは、リモートホストとの接続が確立されていない場合でも、 エラーを発生せずにオープンされたように見えることが時々あります。 このエラーは、そのソケットでデータを読み書きした際にのみ明らかになります。 この原因は、UDPが"コネクションレス"のプロトコルであり、 実際にデータを送受信する必要が生じるまで、 オペレーションシステムがソケット用のリンクを確立しようとしないためです。
注意: 数値で IPv6 アドレスを指定するときは、 (例
fe80::1
) アドレスを角カッコでくくらなくてはなりません。たとえば、tcp://[fe80::1]:80
.
参考
- pfsockopen() - 持続的な Internet または Unix ドメインソケット接続をオープンする
- stream_socket_client() - インターネットドメインまたは Unix ドメインのソケット接続を開く
- stream_set_blocking() - ストリームのブロックモードを有効にする / 解除する
- stream_set_timeout() - ストリームにタイムアウトを設定する
- fgets() - ファイルポインタから 1 行取得する
- fgetss() - ファイルポインタから 1 行取り出し、HTML タグを取り除く
- fwrite() - バイナリセーフなファイル書き込み処理
- fclose() - オープンされたファイルポインタをクローズする
- feof() - ファイルポインタがファイル終端に達しているかどうか調べる
- socket_connect() - ソケット上の接続を初期化する
- Curl 拡張モジュール
User Contributed Notes 42 notes
just a quick note for users attempting https and thinking they must resort to curl or alternate methods -
you can use fsockopen, just read the docs closely. basically they are saying to use 'ssl://' for a HTTPS (SSL) web request.
so this would work for authorize.net, and others; even for that paypal IPN - however I think it would be best to leave the site and deal with paypal's form:
<?php
$host = "something.example.com";
$port = 443;
$path = "/the/url/path/file.php"; //or .dll, etc. for authnet, etc.
//you will need to setup an array of fields to post with
//then create the post string
$formdata = array ( "x_field" => "somevalue");
//build the post string
foreach($formdata AS $key => $val){
$poststring .= urlencode($key) . "=" . urlencode($val) . "&";
}
// strip off trailing ampersand
$poststring = substr($poststring, 0, -1);
$fp = fsockopen("ssl://".$host, $port, $errno, $errstr, $timeout = 30);
if(!$fp){
//error tell us
echo "$errstr ($errno)\n";
}else{
//send the server request
fputs($fp, "POST $path HTTP/1.1\r\n");
fputs($fp, "Host: $host\r\n");
fputs($fp, "Content-type: application/x-www-form-urlencoded\r\n");
fputs($fp, "Content-length: ".strlen($poststring)."\r\n");
fputs($fp, "Connection: close\r\n\r\n");
fputs($fp, $poststring . "\r\n\r\n");
//loop through the response from the server
while(!feof($fp)) {
echo fgets($fp, 4096);
}
//close fp - we are done with it
fclose($fp);
}
?>
<?php
// This script is an example of posting multiple files using
// fsockopen.
// The tricky part is making sure the HTTP headers and file boundaries are acceptable to the target webserver.
// This script is for example purposes only and could/should be improved upon.
$host='targethost';
$port=80;
$path='/test/socket/file_upload/receive_files.php';
// the file you want to upload
$file_array[0] = "dingoboy.gif"; // the file
$file_array[1] = "dingoboy2.gif"; // the file
$file_array[2] = "dingoboy3.gif"; // the file
$content_type = "image/gif"; // the file mime type
//$content_type = "text/plain";
//echo "file_array[0]:$file_array[0]<br><br>";
srand((double)microtime()*1000000);
$boundary = "---------------------------".substr(md5(rand(0,32000)),0,10);
$data = "--$boundary";
for($i=0;$i<count($file_array);$i++){
$content_file = join("", file($file_array[$i]));
$data.="
Content-Disposition: form-data; name=\"file".($i+1)."\"; filename=\"$file_array[$i]\"
Content-Type: $content_type
$content_file
--$boundary";
}
$data.="--\r\n\r\n";
$msg =
"POST $path HTTP/1.0
Content-Type: multipart/form-data; boundary=$boundary
Content-Length: ".strlen($data)."\r\n\r\n";
$result="";
// open the connection
$f = fsockopen($host, $port);
fputs($f,$msg.$data);
// get the response
while (!feof($f)) $result .= fread($f,32000);
fclose($f);
?>
This script checks specific ports so you need to have the correct port open on the server for this to work.
E.g if i have a windows domain controller and it is servering LDAP then the following would be used to check it is online:
<?php
chkServer("MyDC", "389");
?>
for a webserver:
<?php
chkServer("MyWebSvr", "80");
?>
etc etc
--------------------------------------------------------
<?php
// check if a server is up by connecting to a port
function chkServer($host, $port)
{
$hostip = @gethostbyname($host); // resloves IP from Hostname returns hostname on failure
if ($hostip == $host) // if the IP is not resloved
{
echo "Server is down or does not exist";
}
else
{
if (!$x = @fsockopen($hostip, $port, $errno, $errstr, 5)) // attempt to connect
{
echo "Server is down";
}
else
{
echo "Server is up";
if ($x)
{
@fclose($x); //close connection
}
}
}
}
?>
The following snippet allows you to retrieve the title of a page.
Great for rewriting auto-url detectors to display the actual title rather then http://...
<?php
echo get_url_title("http://www.php.net/cal.php?id=409");
function get_url_title($url, $timeout = 2)
{
$url = parse_url($url);
if(!in_array($url['scheme'],array('','http')))
return;
$fp = fsockopen ($url['host'], ($url['port'] > 0 ? $url['port'] : 80), $errno, $errstr, $timeout);
if (!$fp)
{
return;
// echo "$errstr ($errno)<br>\n";
}
else
{
fputs ($fp, "GET /".$url['path'].($url['query'] ? '?'.$url['query'] : '')." HTTP/1.0\r\nHost: ".$url['host']."\r\n\r\n");
$d = '';
while (!feof($fp))
{
$d .= fgets ($fp,2048);
if(preg_match('~(</head>|<body>|(<title>\s*(.*?)\s*</title>))~i', $d, $m))
break;
}
fclose ($fp);
return $m[3];
}
}
?>
<?php
// Check for new version
$current_version = explode('.', '1.0.00');
$minor_revision = (int) $current_version[2];
$errno = 0;
$errstr = $version_info = '';
if ($fsock = fsockopen("www.exanmple.eu", 80, $errno, $errstr, 30))
{
@fputs($fsock, "GET /ver.txt HTTP/1.1\r\n");
@fputs($fsock, "HOST: www.example.eu\r\n");
@fputs($fsock, "Connection: close\r\n\r\n");
$get_info = false;
while (!@feof($fsock))
{
if ($get_info)
{
$version_info .= @fread($fsock, 1024);
}
else
{
if (@fgets($fsock, 1024) == "\r\n")
{
$get_info = true;
}
}
}
@fclose($fsock);
$version_info = explode("\n", $version_info);
$latest_head_revision = (int) $version_info[0];
$latest_minor_revision = (int) $version_info[2];
$latest_version = (int) $version_info[0] . '.' . (int) $version_info[1] . '.' . (int) $version_info[2];
if ($latest_head_revision == 2 && $minor_revision == $latest_minor_revision)
{
$version_info = '<p style="color:green">OK</p>';
}
else
{
$version_info = '<p style="color:red">neaktualne';
$version_info .= '<br />'Latest_version_info' . $latest_version) . ' ' . sprintf(Current_version_info'. '1.0.00') . '</p>';
}
}
else
{
if ($errstr)
{
$version_info = '<p style="color:red">' . sprintf(Connect_socket_error) . '</p>';
}
else
{
$version_info = '<p>'Socket_functions_disabled'</p>';
}
}
$version_info .= '<p>'Mailing_list_subscribe_reminder'</p>';
echo $version_info;
?>
I was tearing my hair out for a week trying to figure out how to do this.
If you use fsockopen with a service that doesn't have an EOF, or you try to read beyond EOF or line break, PHP can hang completely.
In my case, I was trying to write a class that talks to Kali servers (www.kali.net) to get a list of people on the chat server. To keep PHP from hanging due to the above, I discovered this:
<?php
class kali_utils {
function games_list($kali_server_ip, $kali_server_port) {
$result = array();
$fp = fsockopen($kali_server_ip, $kali_server_port, $errno, $error, 30);
if (!$fp) {
$result["errno"] = $errno;
$result["error"] = $error;
}
else {
fputs($fp, "KALIQ");
$header = fread($fp, 5);
$bytes_left = socket_get_status($fp);
if ($bytes_left > 0) {
$result["results"] = fread($fp, $bytes_left["unread_bytes"]);
}
else {
$result["results"] = "";
}
fclose($fp);
}
return $result;
}
}
?>
When I send the request packet, I get a response packet of length 5. Then I call socket_get_status() and use the unread_bytes key from it to know how far to fread from the socket. Works very good.
I've only used this on PHP 4.2.1 so far.
<?php
/************************************************************
* Author: Richard Lajaunie
* Mail : richard.lajaunie@cote-azur.cci.fr
*
* subject : this script retreive all mac-addresses on all ports
* of a Cisco 3548 Switch by a telnet connection
*
* base on the script by: xbensemhoun at t-systems dot fr
**************************************************************/
if ( array_key_exists(1, $argv) ){
$cfgServer = $argv[1];
}else{
echo "ex: 'php test.php 10.0.0.0' \n";
exit;
}
$cfgPort = 23; //port, 22 if SSH
$cfgTimeOut = 10;
$usenet = fsockopen($cfgServer, $cfgPort, $errno, $errstr), $cfgTimeOut);
if(!$usenet){
echo "Connexion failed\n";
exit();
}else{
echo "Connected\n";
fputs ($usenet, "password\r\n");
fputs ($usenet, "en\r\n");
fputs ($usenet, "password\r\n");
fputs ($usenet, "sh mac-address-table\r\n");
fputs ($usenet, " "); // this space bar is this for long output
// this skip non essential text
$j = 0;
while ($j<16){
fgets($usenet, 128);
$j++;
}
stream_set_timeout($usenet, 2); // set the timeout for the fgets
$j = 0;
while (!feof($usenet)){
$ret = fgets($usenet, 128);
$ret = str_replace("\r", '', $ret);
$ret = str_replace("\n", "", $ret);
if (ereg("FastEthernet", $ret)){
echo "$ret \n";
}
if (ereg('--More--', $ret) ){
fputs ($usenet, " "); // for following page
}
$info = stream_get_meta_data($usenet);
if ($info['timed_out']) {
$j++;
}
if ($j >2){
fputs ($usenet, "lo");
break;
}
}
}
echo "End.\r\n";
?>
Additional ICQ status request over proxy
<?php
function icq_uin($uin)
{
if (! is_numeric($uin))
return false;
$proxy_name = 'proxy.mydomain.de';
$proxy_port = 8080;
$proxy_user = "";
$proxy_pass = "";
$proxy_cont = '';
$request_url = "http://status.icq.com/online.gif?icq=$uin";
$proxy_fp = fsockopen($proxy_name, $proxy_port);
if (!$proxy_fp)
return false;
fputs($proxy_fp, "GET $request_url HTTP/1.0\r\nHost: $proxy_name\r\n");
fputs($proxy_fp, "Proxy-Authorization: Basic ". base64_encode ("$proxy_user:$proxy_pass")."\r\n\r\n");
while(!feof($proxy_fp)){
$proxy_cont .= fread($proxy_fp,4096);
}
fclose($proxy_fp);
$proxy_cont = substr($proxy_cont, strpos($proxy_cont,"\r\n\r\n")+4);
if (strstr($proxy_cont, 'online1'))
return 'online';
if (strstr($proxy_cont, 'online0'))
return 'offline';
if (strstr($proxy_cont, 'online2'))
return 'disabled';
}
echo "User is ".icq_uin(123456789012345);
?>
Thanx
[EDIT BY danbrown AT php DOT net: Based on code provided in a note by (rafaelbc AT matrix DOT com DOT br) on 23-MAY-09, which has since been removed.]
I have found, when using fsockopen() and the POST method, that using HTTP/1.1 is VERY significantly slower than HTTP/1.0 (at least for the server I'm querying, an Orion-based server). Also, using cURL tended to be faster than fsockopen(), though only slightly. For example, here was a recent set of data (for the same exact request in each case):
cURL: 4.2sec
fsockopen() HTTP/1.0: 4.9sec
fsockopen() HTTP/1.1: 19.9sec (!)
I'm not sure why this was occurring. Perhaps it has something to do with the Orion server, which I have little experience with. However, it was not a fluke, and I double-checked the code to make sure there were no errors.
EDITORS NOTE: HTTP/1.1 uses persistent connection causing this delay. Use "Connection: close" header to disable it.
Here's a function to just fetch the contents behind an URL.
<?php
function fetchURL( $url ) {
$url_parsed = parse_url($url);
$host = $url_parsed["host"];
$port = $url_parsed["port"];
if ($port==0)
$port = 80;
$path = $url_parsed["path"];
if ($url_parsed["query"] != "")
$path .= "?".$url_parsed["query"];
$out = "GET $path HTTP/1.0\r\nHost: $host\r\n\r\n";
$fp = fsockopen($host, $port, $errno, $errstr, 30);
fwrite($fp, $out);
$body = false;
while (!feof($fp)) {
$s = fgets($fp, 1024);
if ( $body )
$in .= $s;
if ( $s == "\r\n" )
$body = true;
}
fclose($fp);
return $in;
}
?>