PHP Conference Japan 2024

fsockopen

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

fsockopen開啟網際網路或 Unix 網域 socket 連線

說明

fsockopen(
    string $hostname,
    int $port = -1,
    int &$error_code = null,
    string &$error_message = null,
    ?float $timeout = null
): resource|false

初始化一個到 hostname 指定資源的 socket 連線。

PHP 支援網際網路和 Unix 網域的目標,如 支援的 Socket 傳輸列表所述。也可以使用 stream_get_transports() 擷取支援的傳輸列表。

預設情況下,socket 將以阻塞模式開啟。您可以使用 stream_set_blocking() 將其切換到非阻塞模式。

函式 stream_socket_client() 類似,但提供更豐富的選項,包括非阻塞連線和提供 stream context 的能力。

參數

hostname

如果已安裝 OpenSSL 支援,您可以在 hostname 前面加上 ssl://tls://,以使用 TCP/IP 上的 SSL 或 TLS 用戶端連線連線到遠端主機。

port

埠號。對於不使用埠的傳輸(例如 unix://),可以省略並跳過此參數,使用 -1

error_code

如果提供,則保存系統級別 connect() 呼叫中發生的系統級別錯誤號碼。

如果 error_code 中傳回的值為 0 且該函式傳回 false,則表示錯誤發生在 connect() 呼叫之前。這很可能是由於初始化 socket 時出現問題。

error_message

錯誤訊息,以字串表示。

timeout

連線逾時,以秒為單位。當為 null 時,將使用 default_socket_timeout php.ini 設定。

注意:

如果需要設定透過 socket 讀/寫資料的逾時,請使用 stream_set_timeout(),因為 fsockopen()timeout 參數僅在連線 socket 時適用。

傳回值

fsockopen() 傳回一個檔案指標,該指標可以與其他檔案函式(例如 fgets()fgetss()fwrite()fclose()feof())一起使用。如果呼叫失敗,它將傳回 false

錯誤/例外

如果 hostname 不是有效的網域,則會拋出 E_WARNING

變更日誌

版本 說明
8.0.0 timeout 現在可為 null。

範例

範例 #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 socket 有時會看似已開啟而沒有錯誤。只有在您讀取或寫入資料到/從 socket 時,才會顯現錯誤。這是因為 UDP 是一種「無連線」協定,這表示作業系統不會嘗試建立 socket 的連結,直到它實際上需要傳送或接收資料。

注意: 當指定數值 IPv6 位址時 (例如 fe80::1),您必須將 IP 位址放在方括號中 — 例如,tcp://[fe80::1]:80

另請參閱

新增註解

使用者提供的註解 42 則註解

23
joe at edwardsconsultants dot com
21 年前
只是給嘗試使用 https 並認為必須求助於 curl 或替代方法的使用者一個快速說明 -
您可以使用 fsockopen,只需仔細閱讀文件。基本上,他們是指對 HTTPS (SSL) 網頁請求使用 'ssl://'。

所以這適用於 authorize.net 和其他網站;甚至適用於 PayPal 的 IPN - 但是我認為最好離開該網站並處理 PayPal 的表單

<?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);
}
?>
16
sir_reality2001 at yahoo dot com
20 年前
<?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);

?>
11
ryan1_00 at hotmail dot com
17 年前
這個腳本會檢查特定的連接埠,所以您需要在伺服器上開啟正確的連接埠,它才能正常運作。

例如,如果我有一個 Windows 網域控制站,並且它正在提供 LDAP 服務,那麼可以使用以下方法檢查它是否在線上。
<?php
chkServer
("MyDC", "389");
?>

對於網頁伺服器
<?php
chkServer
("MyWebSvr", "80");
?>

等等
--------------------------------------------------------

<?php
// 透過連線到連接埠來檢查伺服器是否啟動
function chkServer($host, $port)
{
$hostip = @gethostbyname($host); // 從主機名稱解析 IP,失敗時回傳主機名稱

if ($hostip == $host) // 如果 IP 沒有被解析
{
echo
"伺服器關閉或不存在";
}
else
{
if (!
$x = @fsockopen($hostip, $port, $errno, $errstr, 5)) // 嘗試連線
{
echo
"伺服器關閉";
}
else
{
echo
"伺服器啟動";
if (
$x)
{
@
fclose($x); // 關閉連線
}
}
}
}
?>
4
michiel at parse dot nl
20 年前
以下程式碼片段可讓您擷取頁面的標題。

非常適合重寫自動 URL 偵測器,以顯示實際標題而不是 http://...

<?php
echo get_url_title("https://php.dev.org.tw/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];
}
}
?>
2
huli0401 at gmail dot com
16 年前
<?php
// 檢查新版本
$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;
?>
4
verran at descent-rangers dot com
22 年前
我花了一週的時間絞盡腦汁,試圖弄清楚如何做到這一點。

如果您使用 fsockopen 連接到沒有 EOF 的服務,或者您嘗試讀取超出 EOF 或換行符號的內容,PHP 可能會完全掛起。

在我的情況下,我試圖編寫一個與 Kali 伺服器 (www.kali.net) 通訊以取得聊天伺服器上人員列表的類別。為了防止 PHP 因為上述原因而掛起,我發現了這個。

<?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;
}
}
?>

當我發送請求封包時,我會收到一個長度為 5 的回應封包。然後我呼叫 socket_get_status() 並使用其中的 unread_bytes 鍵來得知要從 socket 讀取多少資料。效果非常好。

目前為止我只在 PHP 4.2.1 上使用過這個。
5
ghzero at ghzero dot de
15 年前
注意
如果沒有指定,預設的協定似乎是 tcp://
4
richard dot lajaunie at cote-azur dot cci dot fr
19 年前
<?php
/************************************************************
* 作者:Richard Lajaunie
* 信箱:richard.lajaunie@cote-azur.cci.fr
*
* 主題:此腳本透過 telnet 連線擷取 Cisco 3548 交換器所有連接埠上的所有 MAC 位址
*
* 基於以下腳本:xbensemhoun at t-systems dot fr
**************************************************************/

if ( array_key_exists(1, $argv) ){
$cfgServer = $argv[1];
}else{
echo
"範例:'php test.php 10.0.0.0' \n";
exit;
}

$cfgPort = 23; //連接埠,如果使用 SSH 則為 22
$cfgTimeOut = 10;

$usenet = fsockopen($cfgServer, $cfgPort, $errno, $errstr), $cfgTimeOut);

if(!
$usenet){
echo
"連線失敗\n";
exit();
}else{
echo
"已連線\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, " "); //這個空白鍵用於處理較長的輸出

// 跳過不必要的文字
$j = 0;
while (
$j<16){
fgets($usenet, 128);
$j++;
}
stream_set_timeout($usenet, 2); //設定 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, " "); // 用於下一頁
}
$info = stream_get_meta_data($usenet);
if (
$info['timed_out']) {
$j++;
}
if (
$j >2){
fputs ($usenet, "lo");
break;
}
}
}
echo
"結束。\r\n";
?>
5
Kiki_EF
19 年前
透過 Proxy 的額外 ICQ 狀態請求
<?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
"使用者為 ".icq_uin(123456789012345);
?>

謝謝

[由 danbrown AT php DOT net 編輯:基於 (rafaelbc AT matrix DOT com DOT br) 在 2009 年 5 月 23 日的筆記中提供的程式碼,該筆記已被移除。]
6
robin at pozytron dot com
19 年前
我發現,當使用 fsockopen() 和 POST 方法時,使用 HTTP/1.1 會比 HTTP/1.0 慢非常多(至少對於我查詢的伺服器,一個基於 Orion 的伺服器)。此外,使用 cURL 通常比 fsockopen() 快,儘管只快一點點。例如,以下是最近的一組數據(在每種情況下都是針對相同的確切請求)

cURL:4.2 秒
fsockopen() HTTP/1.0:4.9 秒
fsockopen() HTTP/1.1:19.9 秒(!)

我不確定為什麼會發生這種情況。也許這與我不太熟悉的 Orion 伺服器有關。然而,這不是僥倖,我仔細檢查了程式碼以確保沒有錯誤。

編輯者註:HTTP/1.1 使用持久連線導致此延遲。使用 "Connection: close" 標頭來停用它。
3
edwin at bitstorm dot org
20 年前
這是一個只擷取 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;
}
?>
5
brage (a t) jeffnappi (d.o.t) commie
21 年前
想說你們可能會喜歡這個函式,它允許你傳遞一個網址陣列來下載,並且使用非阻塞式 sockets 同時進行下載,然後以陣列形式回傳資料。

<?php
// 此函式同時連線到一組網址
// 並回傳結果陣列。

function multiHTTP ($urlArr) {
$sockets = Array(); // socket 陣列!
$urlInfo = Array(); // 資訊陣列
$retDone = Array();
$retData = Array();
$errno = Array();
$errstr = Array();
for (
$x=0;$x<count($urlArr);$x++) {
$urlInfo[$x] = parse_url($urlArr[$x]);
$urlInfo[$x][port] = ($urlInfo[$x][port]) ? $urlInfo[$x][port] : 80;
$urlInfo[$x][path] = ($urlInfo[$x][path]) ? $urlInfo[$x][path] : "/";
$sockets[$x] = fsockopen($urlInfo[$x][host], $urlInfo[$x][port],
$errno[$x], $errstr[$x], 30);
socket_set_blocking($sockets[$x],FALSE);
$query = ($urlInfo[$x][query]) ? "?" . $urlInfo[$x][query] : "";
fputs($sockets[$x],"GET " . $urlInfo[$x][path] . "$query HTTP/1.0\r\nHost: " .
$urlInfo[$x][host] . "\r\n\r\n");
}
// ok 讀取每個連線的資料
$done = false;
while (!
$done) {
for (
$x=0; $x < count($urlArr);$x++) {
if (!
feof($sockets[$x])) {
if (
$retData[$x]) {
$retData[$x] .= fgets($sockets[$x],128);
} else {
$retData[$x] = fgets($sockets[$x],128);
}
} else {
$retDone[$x] = 1;
}
}
$done = (array_sum($retDone) == count($urlArr));
}
return
$retData;
}
?>
6
Alexander Wegener
17 年前
檢查網址是否在線 (使用 http 和 https)
使用 @fgets 隱藏使用 SSL 時的警告
(錯誤:「Warning: function.fgets SSL: fatal protocol error」,http://bugs.php.net/bug.php?id=23220)

<?php

function isOnline($url) {
if (!
$url_info = parse_url($url)) {
return
false;
}

switch (
$url_info['scheme']) {
case
'https':
$scheme = 'ssl://';
$port = 443;
break;
case
'http':
default:
$scheme = '';
$port = 80;
}

$data = "";
$fid = @fsockopen($scheme . $url_info['host'], $port, $errno, $errstr, 30);
if (
$fid) {
fputs($fid, 'HEAD ' . (isset($url_info['path'])? $url_info['path']: '/') . (isset($url_info['query'])? '?' . $url_info['query']: '') . " HTTP/1.0\r\n" .
"Connection: close\r\n" .
'Host: ' . $url_info['host'] . "\r\n\r\n");
while (!
feof($fid)) {
$data .= @fgets($fid, 128);
}
fclose($fid);
return !empty(
$data);
} else {
return
false;
}
}

?>
1
GreenReaper
5 年前
PHP (或 OpenSSL) 可能不總是選擇使用例如 TLS 1.2,但您可以使用 tlsv1.2:// 強制使用它
https://docs.php.net/manual/en/migration56.openssl.php#migration56.openssl.crypto-method

這對我幫助很大,因為 Twitter 最近的 API 變更要求 TLS 1.2 以上版本。
6
nytro_rst at yahoo dot com
14 年前
一個簡單的 Proxy 清單檢查器。您可以檢查清單 ip:port,以確認該連接埠是否在該 IP 上開啟。

<?php

$fisier
= file_get_contents('proxy_list.txt'); // 讀取包含 Proxy 清單的檔案
$linii = explode("\n", $fisier); // 取得每個 Proxy
$fisier = fopen("bune.txt", "a"); // 這裡將寫入有效的 Proxy

for($i = 0; $i < count($linii) - 1; $i++) test($linii[$i]); // 測試每個 Proxy

function test($proxy)
{
global
$fisier;
$splited = explode(':',$proxy); // 分割 IP 和 Port
if($con = @fsockopen($splited[0], $splited[1], $eroare, $eroare_str, 3))
{
fwrite($fisier, $proxy . "\n"); // 檢查是否可以連線到該 IP 和 Port
print $proxy . '<br>'; // 顯示 Proxy
fclose($con); // 關閉 Socket 連線
}
}

fclose($fisier); // 關閉檔案

?>
3
saul dot dobney at dobney dot com
19 年前
如果您使用 fsockopen 來存取網頁,但在標頭中遇到重新導向 (Location:),並想如同以下程式碼片段一樣找到並追蹤重新導向

<?php
while (!feof($fp)) {
$line=fgets($fp, 1024);
if (
stristr($line,"location:")!="") {
$redirect=preg_replace("/location:/i","",$line);
}
}
?>

那麼,別忘了在嘗試追蹤這個新連結之前,先執行 <?php $redirect = trim($redirect); ?>,因為 $redirect 實際上結尾帶有 \r\n,否則在下一次迭代中不會提供有效的路徑。這是一個耗時六小時的錯誤。

Saul Dobney
1
bradland at umich dot edu
17 年前
我在使用 fopen 和 fsockopen 處理 https 時遇到問題,網址中帶有 ssl://。我在日誌中收到錯誤代碼 114。經過大量研究,我發現 MySQL 5.0.20-5.0.33 存在一些 SSL 衝突問題。它有一些函數會干擾 PHP 安裝中出現的 openssl。

http://bugs.mysql.com/bug.php?id=21930
http://bugs.mysql.com/bug.php?id=19289
1
v13+phpnet at it dot teithe dot gr
17 年前
以下函數執行 POP3 身份驗證。發生錯誤時返回 NULL,或返回 true/false 以指示使用者名稱/密碼是否匹配

$address 是伺服器的主機名稱,$ssl 是一個布林值,指示是否請求 SSL 連線。

<?php
function pop3authCheck($username, $password, $address, $ssl)
{
if (
$ssl)
$uri="ssl://$address:995";
else
$uri="tcp://$address:110";

$fp=fsockopen($uri);

if (!
$fp)
return(
NULL);

$st=fgets($fp, 512);
if (
substr($st, 0, 3)!="+OK")
{
fclose($fp);
return(
NULL);
}

$st="USER $username\n";
if (
fwrite($fp, $st)!=strlen($st))
{
fclose($fp);
return(
NULL);
}

$st=fgets($fp, 512);
if (
substr($st, 0, 3)!="+OK")
{
fclose($fp);
return(
NULL);
}

$st="PASS $password\n";
if (
fwrite($fp, $st)!=strlen($st))
{
fclose($fp);
return(
NULL);
}

$st=fgets($fp, 512);
fclose($fp);
if (
substr($st, 0, 3)=="+OK")
return(
true);
else if (
substr($st, 0, 4)=="+ERR")
return(
false);
else
return(
NULL);
}
?>
1
Duukkis
18 年前
經過多次嘗試和閱讀 http 標頭...

如果您想將 $_POST 變數和(在此例中)一個名為 userfile 的檔案發送到 $remote_server 和 $remote_url。

<?php
// 取得必要的資料
$file_name = $_FILES['userfile']['name']; // 檔案名稱
$tmp_name = $_FILES['userfile']['tmp_name']; // 暫存檔路徑
$content_type = $_FILES['userfile']['type']; // 檔案的 MIME 類型

srand((double)microtime()*1000000);
$boundary = "---------------------".substr(md5(rand(0,32000)),0,10);

// 建構標頭
$header = "POST $remote_url HTTP/1.0\r\n";
$header .= "Host: $remote_server\r\n";
$header .= "Content-type: multipart/form-data, boundary=$boundary\r\n";
// 附加 POST 變數
foreach($_POST AS $index => $value){
$data .="--$boundary\r\n";
$data .= "Content-Disposition: form-data; name=\"".$index."\"\r\n";
$data .= "\r\n".$value."\r\n";
$data .="--$boundary\r\n";
}
// 附加檔案
$data .= "--$boundary\r\n";
$content_file = join("", file($tmp_name));
$data .="Content-Disposition: form-data; name=\"userfile\"; filename=\"$file_name\"\r\n";
$data .= "Content-Type: $content_type\r\n\r\n";
$data .= "".$content_file."\r\n";
$data .="--$boundary--\r\n";
$header .= "Content-length: " . strlen($data) . "\r\n\r\n";
// 開啟連線
$fp = fsockopen($remote_server, 80);
// 然後直接傳送
fputs($fp, $header.$data);
fclose($fp);
?>
1
blazely at removetoemail netspace net au
21 年前
這裡有一個快速函式,可以建立與網頁伺服器的連線,如果在使用者定義的時間後連線中斷,或無法連線至伺服器,則會逾時。

如果指定了使用者名稱/密碼,也支援基本身份驗證。如有任何改進或批評,請寄電子郵件給我!:-)

如果伺服器完全無法連線,則會傳回資源 ID、錯誤代碼或 0。如果發生像非標準 HTTP 回應之類的奇怪狀況,則會傳回 -1。希望對某些人有幫助。

乾杯,

Ben Blazely

<?php
function connectToURL($addr, $port, $path, $user="", $pass="", $timeout="30")
{
$urlHandle = fsockopen($addr, $port, $errno, $errstr, $timeout);
if (
$urlHandle)
{
socket_set_timeout($urlHandle, $timeout);
if (
$path)
{
$urlString = "GET $path HTTP/1.0\r\nHost: $addr\r\nConnection: Keep-Alive\r\nUser-Agent: MyURLGrabber\r\n";
if (
$user)
$urlString .= "Authorization: Basic ".base64_encode("$user:$pass")."\r\n";
$urlString .= "\r\n";

fputs($urlHandle, $urlString);

$response = fgets($urlHandle);

if (
substr_count($response, "200 OK") > 0) // 檢查連線的狀態
{
$endHeader = false; // 剝除初始的標頭資訊
while ( !$endHeader)
{
if (
fgets($urlHandle) == "\r\n")
$endHeader = true;
}

return
$urlHandle; // 一切正常,傳回檔案控制代碼
}
else if (
strlen($response) < 15) // 處理奇怪的非標準回應
{
fclose($urlHandle);
return -
1;
}
else
// 處理標準錯誤回應
{
fclose($urlHandle);
return
substr($response,9,3);
}
}

return
$urlHandle;
}
else
{
return
0;
}
}
}
?>
1
dan at lovepond dot com
21 年前
這裡有一些程式碼可以協助解決 EOF 問題。
我曾經遇到一個問題,我需要剝除大量的伺服器輸入行才能取回我想要的正確資料。

<?php
$port
=4000;
$host="localhost";
$message="test";
$status=senddata($host,$port,$message);
print
"$status";

function
senddata($host,$port,$message) {

# 考慮到伺服器可能不會回傳 EOF 字元的情況
# 將資料傳送到伺服器並取回輸入

# 函式全域變數
$linenumber="2"; # 在給予輸入之前要捨棄的行數
$lineamount="1"; # 在給予輸入之後要讀取的行數

$fp = fsockopen("$host", $port, $errno, $errstr, 30);
if (!
$fp) {
echo
"$errstr ($errno)";
}
else {
for (
$i = 1; $i < $linenumber+1; $i++) {
fread ($fp,1);
$bytes_left = socket_get_status($fp);
if (
$bytes_left > 0) { fread($fp, $bytes_left[unread_bytes]); }
}
fputs($fp, "$message\r\n");
for (
$i = 1; $i < $lineamount+1; $i++) {
$status.=fread($fp,1);
$bytes_left = socket_get_status($fp);
if (
$bytes_left > 0) { $status.=fread($fp, $bytes_left[unread_bytes]); }
}
fclose ($fp);
}

return
$status;
}

?>
1
oliver dot christen at camptocamp dot com
15 年前
當下載大型檔案時,在解析資料以移除標頭部分之前,將整個伺服器回應放入記憶體中並不是非常有效率。這裡有一個簡單的方法可以在資料到達時寫入資料

<?php

// $socket 是一個有效的 fsockopen 處理程序

$out = '';
$headerendfound = false;
$fp = fopen($fileTarget, 'w');
$buffer = '';
while (!
feof($socket)) {
$out = fgets ($socket,16384);
if (
$headerendfound) {
fwrite($fp, $out);
print
'.';
}
if (!
$headerendfound) {
$buffer .= $out;
print
"searching for header\n";
$headerend = strpos($buffer, "\r\n\r\n");
if (
$headerend !== false) {
$headerendfound = true;
fwrite($fp, substr($buffer, $headerend+4));
$buffer = '';
}
}
}
fclose($fp);
fclose($socket);

?>
1
konrad dot meyer at gmail dot com
19 年前
文件範例是 GET 請求。我發現 POST 文件不足,這裡有一個函數可以輕鬆模擬提交表單資料

<?php
# $host 包括主機、路徑和檔案名稱
# 例如:"myserver.com/this/is/path/to/file.php"
# $query 是 POST 查詢資料
# 例如:"a=thisstring&number=46&string=thatstring
# $others 是您要傳送的任何額外標頭
# 例如:"Accept-Encoding: compress, gzip\r\n"
function post($host,$query,$others=''){
$path=explode('/',$host);
$host=$path[0];
unset(
$path[0]);
$path='/'.(implode('/',$path));
$post="POST $path HTTP/1.1\r\nHost: $host\r\nContent-type: application/x-www-form-urlencoded\r\n${others}User-Agent: Mozilla 4.0\r\nContent-length: ".strlen($query)."\r\nConnection: close\r\n\r\n$query";
$h=fsockopen($host,80);
fwrite($h,$post);
for(
$a=0,$r='';!$a;){
$b=fread($h,8192);
$r.=$b;
$a=(($b=='')?1:0);
}
fclose($h);
return
$r;
}
?>
3
asalamanca at redcetus dot com
21 年前
這是一個非常快速的程式,用於多次測試表單或連結。
<?php
$repeat
= 100; // 測試重複次數

$timeout = 100; // 建立連線的最大時間
$size = 16; // 將讀取的位元組數(並顯示)。設定為 0 表示讀取所有

$server = '127.0.0.1'; // IP 位址
$host = 'www.example.net'; // 網域名稱
$target = '/poll/answer.asp'; // 特定程式
$referer = 'http://www.example.com/'; // 引用頁面
$port = 80;

// 設定要取得的欄位陣列,然後建立 get 字串
$gets = array ( 'get_field_1' => 'somevalue',
'get_field_2' => 'somevalue' );

// 設定要 post 的欄位陣列,然後建立 post 字串
$posts = array ( 'post_field_1' => 'somevalue',
'post_field_2' => 'somevalue' );

// 以上都設定完成。現在程式將處理 $repeat 次數

$method = "GET";
if (
is_array( $gets ) ) {
$getValues = '?';
foreach(
$gets AS $name => $value ){
$getValues .= urlencode( $name ) . "=" . urlencode( $value ) . '&';
}
$getValues = substr( $getValues, 0, -1 );
} else {
$getValues = '';
}

if (
is_array( $posts ) ) {
foreach(
$posts AS $name => $value ){
$postValues .= urlencode( $name ) . "=" . urlencode( $value ) . '&';
}
$postValues = substr( $postValues, 0, -1 );
$method = "POST";
} else {
$postValues = '';
}

$request = "$method $target$getValues HTTP/1.1\r\n";
$request .= "Host: $host\r\n";
$request .= 'User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.2.1) ';
$request .= "Gecko/20021204\r\n";
$request .= 'Accept: text/xml,application/xml,application/xhtml+xml,';
$request .= 'text/html;q=0.9,text/plain;q=0.8,video/x-mng,image/png,';
$request .= "image/jpeg,image/gif;q=0.2,text/css,*/*;q=0.1\r\n";
$request .= "Accept-Language: en-us, en;q=0.50\r\n";
$request .= "Accept-Encoding: gzip, deflate, compress;q=0.9\r\n";
$request .= "Accept-Charset: ISO-8859-1, utf-8;q=0.66, *;q=0.66\r\n";
$request .= "Keep-Alive: 300\r\n";
$request .= "Connection: keep-alive\r\n";
$request .= "Referer: $referer\r\n";
$request .= "Cache-Control: max-age=0\r\n";

if (
$method == "POST" ) {
$lenght = strlen( $postValues );
$request .= "Content-Type: application/x-www-form-urlencoded\r\n";
$request .= "Content-Length: $lenght\r\n";
$request .= "\r\n";
$request .= $postValues;
}

for (
$i = 0; $i < $repeat; $i++ ) {
$socket = fsockopen( $server, $port, $errno, $errstr, $timeout );
fputs( $socket, $request );
if (
$size > 0 ) {
$ret = fgets( $socket, $size );
} else {
$ret = '';
while ( !
feof( $socket ) ) {
$ret .= fgets( $socket, 4096 );
}
}
fclose( $socket );
echo
"<hr> $i -- $content $ret";
}
?>

Alejandro Salamanca
2
anarchy
17 年前
DEFAULT 串流逾時時間會根據您 php.ini 檔案中的 default_socket_timeout 設定。我花了好久時間才找到這個資訊....
2
Jeremy Saintot
13 年前
這是我基於 fsockopen 的 HTTP 請求函式(GET 和 POST)

<?php
function http_request(
$verb = 'GET', /* HTTP 請求方法 (支援 GET 和 POST) */
$ip, /* 目標 IP/主機名稱 */
$port = 80, /* 目標 TCP 連接埠 */
$uri = '/', /* 目標 URI */
$getdata = array(), /* HTTP GET 資料,例如: array('var1' => 'val1', 'var2' => 'val2') */
$postdata = array(), /* HTTP POST 資料,例如: array('var1' => 'val1', 'var2' => 'val2') */
$cookie = array(), /* HTTP Cookie 資料,例如: array('var1' => 'val1', 'var2' => 'val2') */
$custom_headers = array(), /* 自訂 HTTP 標頭,例如: array('Referer: https://127.0.0.1/ */
$timeout = 1, /* Socket 連線逾時時間(秒) */
$req_hdr = false, /* 是否包含 HTTP 請求標頭 */
$res_hdr = false /* 是否包含 HTTP 回應標頭 */
)
{
$ret = '';
$verb = strtoupper($verb);
$cookie_str = '';
$getdata_str = count($getdata) ? '?' : '';
$postdata_str = '';

foreach (
$getdata as $k => $v)
$getdata_str .= urlencode($k) .'='. urlencode($v) . '&';

foreach (
$postdata as $k => $v)
$postdata_str .= urlencode($k) .'='. urlencode($v) .'&';

foreach (
$cookie as $k => $v)
$cookie_str .= urlencode($k) .'='. urlencode($v) .'; ';

$crlf = "\r\n";
$req = $verb .' '. $uri . $getdata_str .' HTTP/1.1' . $crlf;
$req .= 'Host: '. $ip . $crlf;
$req .= 'User-Agent: Mozilla/5.0 Firefox/3.6.12' . $crlf;
$req .= 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' . $crlf;
$req .= 'Accept-Language: en-us,en;q=0.5' . $crlf;
$req .= 'Accept-Encoding: deflate' . $crlf;
$req .= 'Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7' . $crlf;

foreach (
$custom_headers as $k => $v)
$req .= $k .': '. $v . $crlf;

if (!empty(
$cookie_str))
$req .= 'Cookie: '. substr($cookie_str, 0, -2) . $crlf;

if (
$verb == 'POST' && !empty($postdata_str))
{
$postdata_str = substr($postdata_str, 0, -1);
$req .= 'Content-Type: application/x-www-form-urlencoded' . $crlf;
$req .= 'Content-Length: '. strlen($postdata_str) . $crlf . $crlf;
$req .= $postdata_str;
}
else
$req .= $crlf;

if (
$req_hdr)
$ret .= $req;

if ((
$fp = @fsockopen($ip, $port, $errno, $errstr)) == false)
return
"Error $errno: $errstr\n";

stream_set_timeout($fp, 0, $timeout * 1000);

fputs($fp, $req);
while (
$line = fgets($fp)) $ret .= $line;
fclose($fp);

if (!
$res_hdr)
$ret = substr($ret, strpos($ret, "\r\n\r\n") + 4);

return
$ret;
}
?>

範例用法

<?php
echo http_request('GET', 'www.php.net');
echo
http_request('GET', 'www.php.net', 80, '/manual/en/function.phpinfo.php');
echo
http_request('GET', 'www.php.net', 80, '/manual/en/function.phpinfo.php', array('get1' => 'v_get1'), array(), array('cookie1' => 'v_cookie1'), array('X-My-Header' => 'My Value'));
?>

[由 danbrown 在 php DOT net 編輯:包含由 "Wrinkled Cheese" 於 2011 年 6 月 24 日提供的錯誤修復,以修正 $getdata foreach() 迴圈;以及由 Suat Secmen 於 2012 年 1 月 12 日提供的另一個錯誤修復,以修正 $timeout = 1000,然後 stream_set_timeout($fp, 0, $timeout * 1000),等於 1,000 秒的問題。]
1
richardaburton at hotmail dot com
21 年前
改進的 HTTP/1.1 分塊傳輸編碼範例。

以下由 Jack 提供的範例程式碼在針對較新版本的 Apache 執行時無法正常運作(我假設這曾經可以運作,但從 HTTP/1.1 規格來看,我只能假設如果它確實運作,那大多是基於運氣)。

<?php

$header
= "";
$response = "";

// 連線
if (!($request=fsockopen('example.com',80,$errno,$errstr))) exit($errstr);
else {
socket_set_timeout($request,10);
// 送出請求
fwrite($request,$post);
// 取得標頭
do $header.=fread($request,1); while (!preg_match('/\\r\\n\\r\\n$/',$header));
// 檢查分塊編碼
if (preg_match('/Transfer\\-Encoding:\\s+chunked\\r\\n/',$header))
do {
$byte = "";
$chunk_size="";
do {
$chunk_size.=$byte;
$byte=fread($request,1);
} while (
$byte!="\\r"); // 直到比對到 CR
fread($request, 1); // 也移除 LF
$chunk_size=hexdec($chunk_size); // 轉換為實際數字
$response.=fread($request,$chunk_size);
fread($request,2); // 丟棄區塊後面的 CRLF
} while ($chunk_size); // 直到到達長度為 0 的區塊(結束標記)
else {
// 檢查指定的內容長度
if (preg_match('/Content\\-Length:\\s+([0-9]*)\\r\\n/',$header,$matches)) {
$response=fread($request,$matches[1]);
} else {
// 這不是個好方法 (可能也會產生尾隨在真實內容後面的額外 CRLF???)
while (!feof($request)) $response .= fread($request, 4096);
}
}
// 關閉連線
fclose($request);
}

// 對回應進行一些有用的處理
print($header);
print(
$response);

?>

Richard.
1
iain at monitormedia dot co dot uk
22 年前
這裡示範如何使用 SMTP 發送電子郵件。這包括在發送電子郵件過程中對伺服器響應進行初步檢查。可以通過更全面的處理結果代碼來改進...或者在連接到第一個郵件交換器失敗後,繼續連接下一個郵件交換器。

<?php

function another_mail($to,$subject,$headers,$message)
{
// 可以從 php ini 取得嗎?
$from="me@example.com";
list(
$me,$mydomain) = split("@",$from);

// 現在查詢收件者的郵件交換伺服器
list($user,$domain) = split("@",$to,2);
if(
getmxrr($domain,$mx,$weight) == 0) return FALSE;

// 嘗試依權重由低到高排序
array_multisort($mx,$weight);
$success=0;

foreach(
$mx as $host) {
// 開啟 SMTP 連線
$connection = fsockopen ($host, 25, $errno, $errstr, 1);
if (!
$connection)
continue;
$res=fgets($connection,256);
if(
substr($res,0,3) != "220") break;

// 自我介紹
fputs($connection, "HELO $mydomain\n");
$res=fgets($connection,256);
if(
substr($res,0,3) != "250") break;

// 寄件者信封
fputs($connection, "MAIL FROM: $from\n");
$res=fgets($connection,256);
if(
substr($res,0,3) != "250") break;

// 收件者信封
fputs($connection, "RCPT TO: $to\n");
$res=fgets($connection,256);
if(
substr($res,0,3) != "250") break;

// 訊息
fputs($connection, "DATA\n");
$res=fgets($connection,256);
if(
substr($res,0,3) != "354") break;

// 傳送 To:、From:、Subject:、其他標頭、空行、訊息,並以單獨一行的句號結束。
fputs($connection, "To: $to\nFrom: $from\nSubject: $subject\n$headers\n\n$message\n.\n");
$res=fgets($connection,256);
if(
substr($res,0,3) != "250") break;

// 說再見
fputs($connection,"QUIT\n");
$res=fgets($connection,256);
if(
substr($res,0,3) != "221") break;

// 成功了!所以跳出嘗試所有郵件交換伺服器的迴圈。
$success=1;
break;
}
// 如果失敗時的除錯 - 視需要取消註解
// print $success?"Mail sent":"Failure: $res\n";
if($connection) {
if(
$success==0) fputs($connection, "QUIT\n");
fclose ($connection);
}
return
$success?TRUE:FALSE;
}

another_mail("recipient@example.com","My Subject","X-mailer: PHP Script\nX-another-header: Whatever","Test email body.\n\nNote if you actually put a period on a line\nby itself, the function will terminate prematurely.\n\nYou will get a partial email sent though.\n");
?>
1
xbensemhoun at t-systems dot fr
21 年前
使用 Telnet 連線 Cisco 路由器

<?php
$cfgServer
= "nnn.nnn.nnn.nnn"; //您的路由器 IP
$cfgPort = 23; //連接埠,如果是 SSH 則為 22
$cfgTimeOut = 10;

$usenet = fsockopen($cfgServer, $cfgPort, $errno, $errstr, $cfgTimeOut);

if(!
$usenet)
{
echo
"連線失敗\n";
exit();
}
else
{
echo
"已連線\n<BR>";
fputs ($usenet, "toto\r\n");
fputs ($usenet, "en\r\n");
fputs ($usenet, "tutu\r\n");
fputs ($usenet, "exit\r\n");
while (!
feof($usenet))
{
echo
". ".fgets($usenet, 128)."<BR>\n";
}
}
?>

然後您會看到
已連線
. ��������
.
. 使用者存取驗證
.
. 密碼
. testXB>en
. 密碼
. testXB#exit
.
1
Goce Dokoski
6 年前
嘗試使用 fsockopen 連接 ssl://,但它掛起很長時間,忽略 timeout 參數,最終返回 false,沒有錯誤訊息。

結果(至少)在 Windows 上它會驗證憑證,並且沒有有效的憑證儲存。

這對我有用

- 從 https://curl.haxx.se/ca/cacert.pem 下載 Mozilla 的憑證儲存
- 將其複製到 php 安裝目錄中(例如:c:\php)
- 並在 php.ini 中設定

openssl.cafile="c:\php\cacert.pem"

我的系統:Apache/2.4.29 (Win64) OpenSSL/1.0.2n PHP/5.6.38
1
p14nd4
10 年前
看來在 PHP 5.6.0 中(至少在 Debian jessie 中的版本,使用 openssl 1.0.1h-3),此函式現在*會*以多種方式驗證 SSL 憑證。首先,它似乎會因不信任的憑證而失敗(即沒有在本機信任的匹配 CA),其次,它似乎會因請求和憑證中的主機名稱不匹配而失敗。

---------
$ echo "<?php echo fsockopen(\"ssl://127.0.0.1\", 993); ?>" | php -a
Interactive mode enabled

PHP Warning
: fsockopen(): Peer certificate CN=`my.test.server' did not match expected CN=`localhost' in - on line 1
PHP Warning: fsockopen(): Failed to enable crypto in - on line 1
PHP Warning: fsockopen(): unable to connect to ssl://127.0.0.1:993 (Unknown error) in - on line 1
----------
$ echo "<?php echo fsockopen(\"ssl://my.test.server\", 993); ?>" | php -a
Interactive mode enabled

PHP Warning: fsockopen(): SSL operation failed with code 1. OpenSSL Error messages:
error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed in - on line 1
PHP Warning: fsockopen(): Failed to enable crypto in - on line 1
PHP Warning: fsockopen(): unable to connect to ssl://my.test.server:993 (Unknown error) in - on line 1
---------
#installed CA locally
---------
$ echo "<?php echo fsockopen(\"ssl://my.test.server\", 993); ?>" | php -a
Interactive mode enabled

Resource id #1
0
jszoja at gmail dot com
2 年前
透過 `unix//` 協定開啟不存在的 socket 檔案,即使使用 @ 來抑制錯誤,也會導致例外情況,例如:
<?php
$fh
= @fsockopen('unix:///var/run/file-not-exists.sock');
?>

從 PHP 7.4 遷移到 8.x 時,務必留意這點,因為使用 @ 抑制錯誤的處理方式已變更。
0
kexianbin at diyism dot com
12 年前
我的遞迴 unchunk 函式

<?php
function unchunk($result)
{return
preg_replace('/([0-9A-F]+)\r\n(.*)/sie',
'($cnt=@base_convert("\1", 16, 10))
?substr(($str=@strtr(\'\2\', array(\'\"\'=>\'"\', \'\\\\0\'=>"\x00"))), 0, $cnt).unchunk(substr($str, $cnt+2))
:""
'
,
$result
);
}
?>
0
jabeba at web dot de
16 年前
如果您必須使用代理伺服器來對您的本地網路以外的網路發出請求,您可以使用此類別

<?php
/*
*
* 未實作 Proxy 驗證;PHP 5
*
*/

class RemoteFopenViaProxy {

private
$result;
private
$proxy_name;
private
$proxy_port;
private
$request_url;

public function
get_proxy_name() {
return
$this->proxy_name;
}

public function
set_proxy_name($n) {
$this->proxy_name = $n;
}

public function
get_proxy_port() {
return
$this->proxy_port;
}

public function
set_proxy_port($p) {
$this->proxy_port = $p;
}

public function
get_request_url() {
return
$this->request_url;
}

public function
set_request_url($u) {
$this->request_url = $u;
}

public function
get_result() {
return
$this->result;
}

public function
set_result($r) {
$this->result = $r;
}

private function
get_url_via_proxy() {

$proxy_fp = fsockopen($this->get_proxy_name(), $this->get_proxy_port());

if (!
$proxy_fp) {
return
false;
}
fputs($proxy_fp, "GET " . $this->get_request_url() . " HTTP/1.0\r\nHost: " . $this->get_proxy_name() . "\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);
return
$proxy_cont;

}

private function
get_url($url) {
$fd = @ file($url);
if (
$fd) {
return
$fd;
} else {
return
false;
}
}

private function
logger($line, $file) {
$fd = fopen($file . ".log", "a+");
fwrite($fd, date("Ymd G:i:s") . " - " . $file . " - " . $line . "\n");
fclose($fd);
}

function
__construct($url, $proxy_name = "", $proxy_port = "") {

$this->set_request_url($url);
$this->set_proxy_name($proxy_name);
$this->set_proxy_port($proxy_port);

}

public function
request_via_proxy() {

$this->set_result($this->get_url_via_proxy());
if (!
$this->get_result()) {
$this->logger("FAILED: get_url_via_proxy(" . $this->get_proxy_name() . "," . $this->get_proxy_port() . "," . $this->get_request_url() . ")", "RemoteFopenViaProxyClass.log");
}
}

public function
request_without_proxy() {

$this->set_result($this->get_url($this->get_request_url()));
if (!
$this->get_result()) {
$this->logger("FAILED: get_url(" . $url . ")", "RemoteFopenViaProxyClass.log");
}
}
}
?>

使用方式如下

<?php
// 呼叫建構子
$obj = new RemoteFopenViaProxy($insert_request_url, $insert_proxy_name, $insert_proxy_port);
// 在物件產生後變更設定
$obj->set_proxy_name($insert_proxy_name);
$obj->set_proxy_port($insert_proxy_port);
$obj->set_request_url($insert_request_url);
$obj->request_via_proxy();
echo
$obj->get_result();
?>

如果在執行期間發生錯誤,此腳本會嘗試將一些有用的資訊寫入日誌檔。
-1
walter
15 年前
由於某些原因,預設的 FreeBSD 7.0 port(受限環境)會中斷 SSL URL 的 fsockopen(),回傳一個空的資料流!在我的情況下,這導致 php-cgi 完全關閉 lighttpd,而且速度很快!請避免 FreeBSD/jails/fsockopen + SSL。改用 curl_init()。
-1
gratcypalma at gmail dot com
14 年前
<?php
/*
這個腳本用於遠端管理我的 PvPGN 伺服器,以檢查使用者的電子郵件。
不是很好,但它能運作。
*/

set_time_limit(0);
$host = 'host';
$port = 'port';
$user = 'user';
$pass = 'pass';
$socket = fsockopen($host, $port) or die('無法連線至: '.$host);
$userdota = "palma";
if(
$socket)
{
sendcmd("\r",$socket);
$status = "open"; // 設定狀態為開啟

while($status=="open") //當我們連線到伺服器時
{
$line = @fgets($socket, 1024) ;
/////////////登入////////////////
if (strstr($line, "沒有訪客帳號"))
{
sendcmd($user."\r\n",$socket);
sendcmd($pass."\r\n",$socket);
}
//////////////傳送指令////////////////////
if (strstr($line,"您的唯一名稱: ".$user))
{
sendcmd("/finger ".$userdota."\r\n",$socket);
}

//////////////取得電子郵件////////////////////
if (strstr($line,"email:")) // 如果伺服器回應寫著 "email:"
{
$pattern = '/email:(.*) ,/';
preg_match($pattern, $line, $matches);
fclose($socket);
$status="close"; // 狀態關閉
$matches=str_replace(" ","", $matches);
$matches=str_replace(",is_operator:0,is_admin:0,","", $matches);
$matches=str_replace("email:","", $matches);
print
$matches[0];
$email=$matches[0];
}
if (
strstr($line,"錯誤:無效的使用者。")) // 如果伺服器回應寫著 "錯誤:無效的使用者。"
{

fclose($socket);
$status="close";
$error ="無效的使用者"; // 錯誤訊息
}

////////////登入失敗//////////////////////////
if (strstr($line, "登入失敗")) // 如果伺服器回應寫著 "登入失敗"
{
$error = "登入失敗"; // 錯誤訊息
fclose($socket);
$status="close";
}

flush(); // 關閉

}

}
function
sendcmd($cmd,$socket) // 傳送指令函數
{
fputs($socket, $cmd, strlen($cmd));
}
?>
-1
jack at jtr dot de
20 年前
這是一個用於測試網站/URI 是否可用的函式

<?php
/*
* @return boolean
* @param string $link
* @desc 檢查指定的 URL 是否可訪問 (HTTP 狀態碼:200)
*/
function url_validate( $link )
{
$url_parts = @parse_url( $link );

if ( empty(
$url_parts["host"] ) ) return( false );

if ( !empty(
$url_parts["path"] ) )
{
$documentpath = $url_parts["path"];
}
else
{
$documentpath = "/";
}

if ( !empty(
$url_parts["query"] ) )
{
$documentpath .= "?" . $url_parts["query"];
}

$host = $url_parts["host"];
$port = $url_parts["port"];
// 現在 (HTTP-)GET $documentpath 在 $host";

if (empty( $port ) ) $port = "80";
$socket = @fsockopen( $host, $port, $errno, $errstr, 30 );
if (!
$socket)
{
return(
false);
}
else
{
fwrite ($socket, "HEAD ".$documentpath." HTTP/1.0\r\nHost: $host\r\n\r\n");
$http_response = fgets( $socket, 22 );

if (
ereg("200 OK", $http_response, $regs ) )
{
return(
true);
fclose( $socket );
} else
{
// echo "HTTP-Response: $http_response<br>";
return(false);
}
}
}
?>
-1
perrya at shoalhaven dot nsw dot gov dot au
8 年前
在我的 FreeBSD 虛擬機上,使用 Joomla,我遇到錯誤

fsockopen(): 無法連線至 ssl://127.0.0.1:443 (不明錯誤)

當使用聯絡表單和模組更新程序時。

在閱讀關於憑證驗證的其他注意事項後,我安裝了 ca_root_nss 連接埠

(來自 Mozilla 中包含的憑證授權單位的根憑證
NSS 函式庫,因此也包含在 Firefox 和 Thunderbird 中。)

現在它可以運作了
-1
terminal
21 年前
試試這個。
必要時使用 AUTH。
遇到問題時請閱讀 RFC 821。

<?php

$handle
= smtp_connect($smtp_server, 25, 30, 1, 1, 1);
echo
smtp_command($handle, "EHLO $domain\r\n", 1, 1);
echo
smtp_command($handle, "MAIL FROM:<$from_mail>\r\n", 1, 1);
echo
smtp_command($handle, "RCPT TO:<$to_mail>\r\n", 1, 1);
echo
smtp_command($handle, "DATA\r\n", 1, 1);
echo
smtp_command($handle, "$message\r\n.\r\n", 1, 1);
// 不要像這樣做 - 它會掛起
// echo smtp_command($handle, "$message", 1, 1);
// echo smtp_command($handle, "\r\n.\r\n", 1, 1);
echo smtp_command($handle, "QUIT\r\n", 1, 1);
smtp_close($handle);


function
smtp_connect($host, $port, $timeout=30, $echo_command=False, $echo_response=False, $nl2br=False)
{
$errno = 0;
$errstr = 0;
if(
$echo_command)
{
if(
$nl2br) { echo nl2br("正在連線至 $host\r\n"); }
else { echo
"正在連線至 $host\r\n"; }
}
$handle = fsockopen($host, $port, $errno, $errstr, $timeout);
if(!
$handle)
{
if(
$echo_command)
{
if(
$nl2br) { echo nl2br("連線失敗\r\n"); }
else { echo
"連線失敗\r\n"; }
}
return
False;
}
if(
$echo_command)
{
if(
$nl2br) { echo nl2br("成功\r\n"); }
else { echo
"成功\r\n"; }
}
$response = fgets($handle,1);
$bytes_left = socket_get_status($handle);
if (
$bytes_left > 0) { $response .= fread($handle, $bytes_left["unread_bytes"]); }
if(
$echo_response)
{
if(
$nl2br) { echo nl2br($response); }
else { echo
$response; }
}
return
$handle;
}

function
smtp_command($handle, $command, $echo_command=False, $nl2br=False)
{
if(
$echo_command)
{
if(
$nl2br) { echo nl2br($command); }
else { echo
$command; }
}
fputs($handle, $command);
$response = fgets($handle,1);
$bytes_left = socket_get_status($handle);
if (
$bytes_left > 0) { $response .= fread($handle, $bytes_left["unread_bytes"]); }
if(
$nl2br) { return nl2br($response); }
else { return
$response; }
}

function
smtp_close($handle)
{
fclose($handle);
}
?>
-2
biguenique at yahoo dot ca
10 年前
您知道 fsockopen() 完全不會驗證 SSL 憑證嗎?為了全球整體的安全等級,我認為在手冊頁面上加上一個**大大的警告**通知會是非常好的主意!

引述 2012 年發表的廣泛研究報告「世界上最危險的程式碼:在非瀏覽器軟體中驗證 SSL 憑證」(如果他們移除了連結,請自行搜尋),第 5 頁提到:

「PHP 提供了幾種建立 SSL 連線的方法。例如,fsockopen 會開啟與遠端伺服器的原始通訊端,可以透過在 URL 中放入 “ssl://” 來連線到 SSL 伺服器。即使 fsockopen 完全不會執行任何憑證檢查,PHP 應用程式開發人員還是經常使用它來建立 SSL 連線 (請參閱第 9 節)。」

為了方便地進行適當的憑證驗證,您始終可以改用 cURL,但請小心:

「PHP 也提供了 cURL 繫結,它使用 cURL 的預設設定來建立具有適當憑證驗證的 SSL 連線。正如我們在第 7.1、7.2 和 7.3 節中所示,應用程式開發人員經常不正確地設定 cURL 選項,覆寫預設值並破壞憑證驗證。」

如需更詳細的見解,請嘗試以下程式碼:
<?php readfile("http".str_replace('+', '.', implode('/', array(":", null, "www+cs+utexas+edu", "~shmat", "shmat_ccs12.pdf")))); ?>
-1
Sherif Gayed
21 年前
以下是如何從 Proxy 伺服器後方連線到網路的方法:

<?php
/*************程式碼開始**************/
/*您的 Proxy 伺服器位址*/
$proxy = "192.168.10.1";
/*您的 Proxy 伺服器連接埠*/
$port = 8080;
/*您要連線的網址*/
$url = "https://php.dev.org.tw/";
$fp = fsockopen($proxy, $port);
fputs($fp, "GET $url HTTP/1.0\r\nHost: $proxy\r\n\r\n");
while(!
feof($fp)){
$line = fgets($fp, 4000);
print(
$line);
}
fclose($fp);
/**************程式碼結束**************/
?>
-2
mikey at badpenguins dot com
16 年前
我對於處理分塊傳輸編碼輸出的 0.02 美元看法… 具有初步的錯誤處理。

<?php
//
// Example usage...
//
$server = '127.0.0.1';
$port = '80';
$uri = '/cgi-bin/random-cgi';
$content = 'Your post content...';

$post_results = httpPost($server,$port,$uri,$content);
if (!
is_string($post_results)) {
die(
'uh oh, something went wrong');
} else {
die(
'Here are your results: ' . $post_results);
}

//
// Post provided content to an http server and optionally
// convert chunk encoded results. Returns false on errors,
// result of post on success. This example only handles http,
// not https.
//
function httpPost($ip=null,$port=80,$uri=null,$content=null) {
if (empty(
$ip)) { return false; }
if (!
is_numeric($port)) { return false; }
if (empty(
$uri)) { return false; }
if (empty(
$content)) { return false; }
// generate headers in array.
$t = array();
$t[] = 'POST ' . $uri . ' HTTP/1.1';
$t[] = 'Content-Type: text/html';
$t[] = 'Host: ' . $ip . ':' . $port;
$t[] = 'Content-Length: ' . strlen($content);
$t[] = 'Connection: close';
$t = implode("\r\n",$t) . "\r\n\r\n" . $content;
//
// Open socket, provide error report vars and timeout of 10
// seconds.
//
$fp = @fsockopen($ip,$port,$errno,$errstr,10);
// If we don't have a stream resource, abort.
if (!(get_resource_type($fp) == 'stream')) { return false; }
//
// Send headers and content.
//
if (!fwrite($fp,$t)) {
fclose($fp);
return
false;
}
//
// Read all of response into $rsp and close the socket.
//
$rsp = '';
while(!
feof($fp)) { $rsp .= fgets($fp,8192); }
fclose($fp);
//
// Call parseHttpResponse() to return the results.
//
return parseHttpResponse($rsp);
}

//
// Accepts provided http content, checks for a valid http response,
// unchunks if needed, returns http content without headers on
// success, false on any errors.
//
function parseHttpResponse($content=null) {
if (empty(
$content)) { return false; }
// split into array, headers and content.
$hunks = explode("\r\n\r\n",trim($content));
if (!
is_array($hunks) or count($hunks) < 2) {
return
false;
}
$header = $hunks[count($hunks) - 2];
$body = $hunks[count($hunks) - 1];
$headers = explode("\n",$header);
unset(
$hunks);
unset(
$header);
if (!
verifyHttpResponse($headers)) { return false; }
if (
in_array('Transfer-Encoding: chunked',$headers)) {
return
trim(unchunkHttpResponse($body));
} else {
return
trim($body);
}
}

//
// Validate http responses by checking header. Expects array of
// headers as argument. Returns boolean.
//
function validateHttpResponse($headers=null) {
if (!
is_array($headers) or count($headers) < 1) { return false; }
switch(
trim(strtolower($headers[0]))) {
case
'http/1.0 100 ok':
case
'http/1.0 200 ok':
case
'http/1.1 100 ok':
case
'http/1.1 200 ok':
return
true;
break;
}
return
false;
}

//
// Unchunk http content. Returns unchunked content on success,
// false on any errors... Borrows from code posted above by
// jbr at ya-right dot com.
//
function unchunkHttpResponse($str=null) {
if (!
is_string($str) or strlen($str) < 1) { return false; }
$eol = "\r\n";
$add = strlen($eol);
$tmp = $str;
$str = '';
do {
$tmp = ltrim($tmp);
$pos = strpos($tmp, $eol);
if (
$pos === false) { return false; }
$len = hexdec(substr($tmp,0,$pos));
if (!
is_numeric($len) or $len < 0) { return false; }
$str .= substr($tmp, ($pos + $add), $len);
$tmp = substr($tmp, ($len + $pos + $add));
$check = trim($tmp);
} while(!empty(
$check));
unset(
$tmp);
return
$str;
}

?>
To Top