PHPのお勉強!

PHP TOP

fsockopen

(PHP 4, PHP 5, PHP 7, PHP 8)

fsockopenインターネット接続もしくは Unix ドメインソケット接続をオープンする

説明

fsockopen(
    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_code0 なのに関数が false を返す場合、connect() をコールする前にエラーを発生したことを示します。 この場合、おそらくはソケットの初期化に原因があります。

error_message

エラーメッセージを表す文字列。

timeout

接続タイムアウト秒数。 null の場合は、 php.inidefault_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 拡張モジュール

add a note

User Contributed Notes 42 notes

up
23
joe at edwardsconsultants dot com
21 years ago
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);
}
?>
up
16
sir_reality2001 at yahoo dot com
20 years ago
<?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);

?>
up
11
ryan1_00 at hotmail dot com
17 years ago
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
}
}
}
}
?>
up
4
michiel at parse dot nl
20 years ago
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];
}
}
?>
up
2
huli0401 at gmail dot com
16 years ago
<?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;
?>
up
4
verran at descent-rangers dot com
22 years ago
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.
up
5
ghzero at ghzero dot de
15 years ago
note:
the default protocol - if not given - seems to be tcp://
up
4
richard dot lajaunie at cote-azur dot cci dot fr
19 years ago
<?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";
?>
up
5
Kiki_EF
19 years ago
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.]
up
6
robin at pozytron dot com
19 years ago
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.
up
3
edwin at bitstorm dot org
20 years ago
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;
}
?>