When running these types of sockets, typically you need to be root or else they fail (not the case with stream sockets: http://us.php.net/manual/en/function.stream-socket-server.php)
This is an example for Linux/Unix type systems to use sockets without being root. (tested on Debian and CentOS)
<?php
$user = "daemon";
$script_name = "uid"; //the name of this script
/////////////////////////////////////////////
//try creating a socket as a user other than root
echo "\n__________________________________________\n";
echo "Trying to start a socket as user $user\n";
$uid_name = posix_getpwnam($user);
$uid_name = $uid_name['uid'];
if(posix_seteuid($uid_name))
{
echo "SUCCESS: You are now $user!\n";
if($socket = @socket_create(AF_INET, SOCK_RAW, 1))
{
echo "SUCCESS: You are NOT root and created a socket! This should not happen!\n";
} else {
echo "ERROR: socket_create() failed because you're not root!\n";
}
$show_process = shell_exec("ps aux | grep -v grep | grep $script_name");
echo "Current process stats::-->\t $show_process";
} else {
exit("ERROR: seteuid($uid_name) failed!\n");
}
/////////////////////////////////////////////
//no try creating a socket as root
echo "\n__________________________________________\n";
echo "Trying to start a socket as user 'root'\n";
if(posix_seteuid(0))
{
echo "SUCCESS: You are now root!\n";
$show_process = shell_exec("ps aux | grep -v grep | grep $script_name");
echo "Current process stats::-->\t $show_process";
if($socket = @socket_create(AF_INET, SOCK_RAW, 1))
{
echo "SUCCESS: You created a socket as root and now should seteuid() to another user\n";
/////////////////////////////////////////
//now modify the socket as another user
echo "\n__________________________________________\n";
echo "Switching to user $user\n";
if(posix_seteuid($uid_name))
{
echo "SUCCESS: You are now $user!\n";
if(socket_bind($socket, 0, 8000))
{
echo "SUCCESS: socket_bind() worked as $user!\n";
} else {
echo "ERROR: Must be root to user socket_bind()\n";
}
$show_process = shell_exec("ps aux | grep -v grep | grep $script_name");
echo "Current process stats::-->\t $show_process";
socket_close($socket); //hard to error check but it does close as this user
echo "SUCCESS: You closed the socket as user $user!\n";
} else {
echo "ERROR: seteuid($uid_name) failed while socket was open!\n";
}
} else {
echo "ERROR: Socket failed for some reason!\n";
}
} else {
exit("ERROR: Changing to root failed!\n");
}
?>
socket_create
(PHP 4 >= 4.0.7, PHP 5)
socket_create — ソケット(通信時の終端)を作成する
説明
resource socket_create ( int $domain, int $type, int $protocol )通信のエンドポイント(終端)と呼ばれることもあるソケットのリソースを 作成し、返します。典型的なネットワーク接続は、2つのソケットから成り 立ちます。このとき、片方はクライアント、もう片方はサーバの役割をします。
パラメータdomainには、ソケットが利用する プロトコルファミリーを指定します。
表 294. 指定可能なアドレス/プロトコルファミリーの一覧
| プロトコル | 説明 |
|---|---|
| AF_INET | IPv4インターネットプロトコル。 このプロトコルファミリーに属すプロトコルにはよく知られている TCP と UDP があります。 |
| AF_INET6 | IPv6インターネットプロトコル。TCPとUDPがこのプロトコルファミリ の共通のプロトコルです。このプロトコルのサポートは、 PHP 5.0.0 で追加されました。 |
| AF_UNIX | ローカルでのコミュニケーションに用いられるプロトコルファミリーです。 高い効率と低いオーバーヘッドを誇るため、IPC (プロセス間通信) でよく使われます。 |
typeパラメータはソケットが利用する通信のタイプを 指定します。
表 295. 利用できるソケットのタイプ
| タイプ | 説明 |
|---|---|
| SOCK_STREAM | このタイプでは、時系列的、高信頼性、全二重、接続型のバイトスト リームが利用できます。帯域外のデータ転送メカニズムがサポートさ れている場合もあります。TCP プロトコルは、このソケットタイプに 基づきます。 |
| SOCK_DGRAM | このタイプでは、データグラム(非接続型で、信頼性の高くない 固定バイト長のメッセージ) がサポートされます。 UDP プロトコルは、このソケットタイプに基づきます。 |
| SOCK_SEQPACKET | このタイプでは、時系列的な、信頼性のある、双方向の接続指向型の 固定長データグラム転送が利用できます。 パケットを消費する側は、一つのパケット全部を一度の read コールで 読み込む必要があります。 |
| SOCK_RAW | このタイプでは、素のネットワークプロトコルを操作できます。 この特殊なソケットを使って、どのタイプのプロトコルでもユーザの手で 構築することができます。よくある使い方として、(ping や traceroute などで行われているような) ICMP リクエストの作成があります。 |
| SOCK_RDM | このタイプでは、信頼に足る、非時系列的なデータグラム転送が 利用できます。 ほとんどのオペレーティングシステムでは実装されていないでしょう。 |
protocol は、ソケット上の通信で使われる domain で指定されたファミリーに属するプロトコルを 指定します。正しい値は、getprotobyname() を使うことで取得できます。利用したいプロトコルが、TCP または UDP の場合は、定数 SOL_TCP と SOL_UDP を指定することもできます。
表 296. 共通なプロトコルの一覧
| プロトコル名 | 説明 |
|---|---|
| icmp | Internet Control Message Protocol は、主にゲートウェイやホストが、 データグラム通信におけるエラーを報告するのに使われます。 "ping" コマンド (最近のほとんどのオペーレーティングシステムに 搭載されています) が ICMP アプリケーションの一例です。 |
| udp | User Datagram Protocol は、非接続指向の、信頼性の高くない、 固定のレコード長を用いるプロトコルです。このような側面のおかげで、 UDP はプロトコルとして最小限のオーバーへッドしか要求しません。 |
| tcp | Transmission Control Protocol は、信頼性の高い、接続指向かつ ストリーム指向の全二重通信プロトコルです。TCP は、 すべてのパケットが、送信された順序で(時系列的に)受信されることを 保証します。もし、何らかの理由でパケットが通信中に失われた場合、 TCP では、送信先から通知があるまで、パケットが再送信されるように なっています。信頼性とパフォーマンス上の理由から、TCP の実装は、 下層にあるデータグラム通信レイヤーのオクテット幅を 適当な長さに決定します。このため、TCP アプリケーションは、 レコードの全部が一度に転送されない場合も考慮しなければなりません。 |
socket_create()は、 成功時に有効な記述子を返し、失敗時に FALSE を返します。 実際のエラーコードは、socket_last_error() を コールすることにより取得できます。このエラーコードをさらに socket_strerror()に渡すことにより、 エラーの内容を文字列で取得することが可能です。
注意: domain や type に 不正な値が与えられた場合、socket_create() は、これらを それぞれ AF_INET と SOCK_STREAM であるとみなし、E_WARNING メッセージを出します。
socket_accept(), socket_bind(), socket_connect(), socket_listen(), socket_last_error(), socket_strerror() も参照ください。
socket_create
04-May-2007 02:45
05-Feb-2007 08:14
here's a way to get the currency:
example getCurrency("BGN", "USD");
function getCurrency($from, $to, $cache = true) {
if ($cache && $_SESSION['currency'][$from][$to]['value'] &&
(time() - $_SESSION['currency'][$from][$to]['time']) < 3600)
return $_SESSION['currency'][$from][$to]['value'];
$host = "www.xe.com";
$port = "80";
$data = "Amount=1&From=" . strtoupper($from) . "&To=" . strtoupper($to);
$header =
"POST /ucc/convert.cgi HTTP/1.1\n" .
"Host: $host:$port\n" .
"Content-Type: application/x-www-form-urlencoded\n" .
"Content-Length: " . strlen($data) . "\n\n" .
$data . "\n";
$s = socket_create(AF_INET, SOCK_STREAM, 0);
$z = socket_connect($s, gethostbyname($host), $port);
socket_write ($s, $header, strlen($header));
while (true) {
$c = @socket_read($s, 1);
if ($c == "\n") {
if (preg_match("/$from = (.+) $to/i", $line, $matches) ||
preg_match("/<\/html>/i", $line)) break;
$line = "";
} else $line .= $c;
}
socket_close($s);
$_SESSION['currency'][$from][$to]['time'] = time();
$_SESSION['currency'][$from][$to]['value'] = str_pad(round($matches[1], 5), 7, "0");
return ($matches[1]) ? str_pad(round($matches[1], 5), 7, "0") : "0.00000";
}
21-Jan-2007 08:39
To david _at* eder #do; us:
Dependent on your system, you could, at least on LINUX, use exec with "/sbin/ifconfig eth0 | awk '/inet /{ print substr($2,9) }'" (also working for non-root users), that will work a little bit faster as your PHP function.
Though, we should keep in mind that users with safe_mode enabled are more or less forced to use the socket thing. :)
08-Aug-2006 09:46
Please be aware that RAW sockets (as used for the ping example) are restricted to root accounts on *nix systems. Since web servers hardly ever run as root, they won't work on webpages.
On Windows based servers it should work regardless.
Here's a ping function that uses sockets instead of exec(). Note: I was unable to get socket_create() to work without running from CLI as root. I've already calculated the package's checksum to simplify the code (the message is 'ping' but it doesn't actually matter).
<?php
function ping($host) {
$package = "\x08\x00\x19\x2f\x00\x00\x00\x00\x70\x69\x6e\x67";
/* create the socket, the last '1' denotes ICMP */
$socket = socket_create(AF_INET, SOCK_RAW, 1);
/* set socket receive timeout to 1 second */
socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, array("sec" => 1, "usec" => 0));
/* connect to socket */
socket_connect($socket, $host, null);
/* record start time */
list($start_usec, $start_sec) = explode(" ", microtime());
$start_time = ((float) $start_usec + (float) $start_sec);
socket_send($socket, $package, strlen($package), 0);
if(@socket_read($socket, 255)) {
list($end_usec, $end_sec) = explode(" ", microtime());
$end_time = ((float) $end_usec + (float) $end_sec);
$total_time = $end_time - $start_time;
return $total_time;
} else {
return false;
}
socket_close($socket);
}
?>
29-Oct-2005 09:48
Took me about 20 minutes to figure out the proper arguments to supply for a AF_UNIX socket. Anything else, and I would get a PHP warning about the 'type' not being supported. I hope this saves someone else time.
<?php
$socket = socket_create(AF_UNIX, SOCK_STREAM, 0);
// code
?>
26-Jan-2005 04:42
Sometimes when you are running CLI, you need to know your own ip address.
<?php
$addr = my_ip();
echo "my ip address is $addr\n";
function my_ip($dest='64.0.0.0', $port=80)
{
$socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
socket_connect($socket, $dest, $port);
socket_getsockname($socket, $addr, $port);
socket_close($socket);
return $addr;
}
?>
09-Jun-2004 12:07
Seems there aren't any examples of UDP clients out there. This is a tftp client. I hope this makes someone's life easier.
<?php
function tftp_fetch($host, $filename)
{
$socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
// create the request packet
$packet = chr(0) . chr(1) . $filename . chr(0) . 'octet' . chr(0);
// UDP is connectionless, so we just send on it.
socket_sendto($socket, $packet, strlen($packet), 0x100, $host, 69);
$buffer = '';
$port = '';
$ret = '';
do
{
// $buffer and $port both come back with information for the ack
// 516 = 4 bytes for the header + 512 bytes of data
socket_recvfrom($socket, $buffer, 516, 0, $host, $port);
// add the block number from the data packet to the ack packet
$packet = chr(0) . chr(4) . substr($buffer, 2, 2);
// send ack
socket_sendto($socket, $packet, strlen($packet), 0, $host, $port);
// append the data to the return variable
// for large files this function should take a file handle as an arg
$ret .= substr($buffer, 4);
}
while(strlen($buffer) == 516); // the first non-full packet is the last.
return $ret;
}
?>
15-Feb-2002 11:33
Okay I talked with Richard a little (via e-mail). We agree that getprotobyname() and using the constants should be the same in functionality and speed, the use of one or the other is merely coding style. Personally, we both think the constants are prettier :).
The eight different protocols are the ones implemented in PHP- not the total number in existance (RFC 1340 has 98).
All we disagree on is using 0- Richard says that "accordning to the official unix/bsd sockets 0 is more than fine." I think that since 0 is a reserved number according to RFC 1320, and when used usually refers to IP, not one of it's sub-protocols (TCP, UDP, etc.)
14-Feb-2002 06:10
Actually, you don't need to use
getprotobyname("tcp") but instead can use
the constants: SOL_TCP and SOL_UDP.
Here an extract of the source from
ext/sockets which should make this clear.
if ((pe = getprotobyname("tcp"))) {
REGISTER_LONG_CONSTANT("SOL_TCP", pe->p_proto,
CONST_CS | CONST_PERSISTENT);
}
Normally the third parameter can be set to 0. In the
original BSD Socket implementation the third parameter
(there are 8 different types, here only two) should be
IPPROTO_TCP or IPPROTO_UPD (or one of the 6 others ones).
These two parameters are though not warpped in PHP as
constants and therefore not available.
Please use SOL_TCP and SOL_UDP. e.g.:
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
Please be aware of the fact that UDP
and TCP can only be used with AF_INET which is: "Adress Family Internet". With UNIX Domain sockets TCP/UDP would make no sense!
best regards
-Richard-Moh Samar