正文
socket 水泥、沙子,底层的东西
fsockopen 、 stream 水泥预制件,可以用来搭房子
curl 毛坯房,自己装修一下就能住了
水泥、沙子不但可以修房子,还能修路、修桥、大型雕塑。socket也是,不但可以用于网页传输,还能传送其他东西,可以做聊天工具、下载器、ftp…… 几乎可以用网络传送的东西都能用它写出来,当然,需要掌握的知识也不少,例如建墙你就要知道怎么让墙笔直、不易倒、防冻、隔热等等都需要自己学。
预制件你就不用管它是否笔直、结构如何、怎样隔热了,这些造的人帮你想好了,你想的就是怎样搭成你想要的形状就行。fsockopen就是, 你可以忽略socket里面的creat, connect, send, recv等等函数的用法,直接就open了。
毛坯房就更简单了,你装修就能住,最简单刷墙就行了,但想更舒适,就用更多更好的装修材料吧,但缺点就是——这是房子,你不能把它改造为渡河、 交通的用途,只能住。curl也一样,各种连接什么的都帮你做好了,底层容错处理也做了,你就传参数给它就能得到你想要的结果, 但缺点就是只能http / ftp,你想把它改成聊天工具,那就难了。
socket 是一个封装了 TCP/IP 操作的工具包。
stream_socket_client 和 fsockopen 没有本质上的区别。stream_socket_client 和 fsockopen 分属不同流派的对 socket 的封装。 stream_socket_client 属于流操作,而 fsockopen 属于文件操作。
fsockopen 是比较底层的调用,属于网络系统的socket调用,而curl经过的包装支持HTTPS认证。 fsockopen支持 HTTP POST方法, HTTP PUT方法, FTP上传, kerberos认证,HTTP上传,代理服务器, cookies,用户名/密码认证,下载文件断点续传,上载文件断点续传,http代理服务器管道( proxy tunneling), 甚至它还支持IPv6, socks5代理服务器,通过http代理服务器上传文件到FTP服务器等等,功能十分强大。fsockopen 返回的是没有处理过的数据, 包括数据的长度数据内容和数据的结束符。而curl是处理后的内容。
在用户使用时,curl 更加方便,但其参数很多,配置稍微复杂,fsockopen 则有固定的几个参数,简单,但获取结果可能需要再做处理。
上面提到的相关内容,过去都有过记录:
socket https://ibaiyang.github.io/blog/php/2019/08/27/PHP-socket编程.html
stream https://ibaiyang.github.io/blog/php/2018/06/04/PHP-Stream实现服务端.html
curl https://ibaiyang.github.io/blog/php/2016/09/08/PHP-cURL详解.html
Sockets
在PHP中,通过官方自带的Sockets扩展库,Stream 函数扩展库可以创建多种协议的服务器和客户端。Stream 函数扩展库是封装好了的Sockets扩展库,更容易使用。
通信过程:
+-------------------------------
* @socket通信整个过程
+-------------------------------
* @socket_create
* @socket_bind
* @socket_listen
* @socket_accept
* @socket_read
* @socket_write
* @socket_close
TCP协议
TCP服务端:
<?php
//确保在连接客户端时不会超时
set_time_limit(0);
$ip = '127.0.0.1';
$port = 1222;
if (($sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) < 0) {
echo "socket_create() 失败的原因是:" . socket_strerror($sock) . "\n";
}
if (($ret = socket_bind($sock, $ip, $port)) < 0) {
echo "socket_bind() 失败的原因是:" . socket_strerror($ret) . "\n";
}
if (($ret = socket_listen($sock, 4)) < 0) {
echo "socket_listen() 失败的原因是:" . socket_strerror($ret) . "\n";
}
do {
if (($msgsock = socket_accept($sock)) < 0) {
echo "socket_accept() failed: reason: " . socket_strerror($msgsock) . "\n";
break;
} else {
//发到客户端
$msg = "发送成功";
socket_write($msgsock, $msg, strlen($msg));
//接收客户端数据
$buf = socket_read($msgsock, 8192);
}
//echo $buf;
socket_close($msgsock);
} while (true);
socket_close($sock);
TCP客户端:
<?php
function tcp_client($port, $ip, $in)
{
set_time_limit(0);
//创建socket
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if ($socket < 0) {
$this->return_data(null, "socket创建失败,原因:" . socket_strerror($socket), RESPONSE_SOCKET_ERROR);
}
//进行socket连接
$result = socket_connect($socket, $ip, $port);
if ($result < 0) {
$this->return_data(null, "socket连接失败,原因:" . socket_strerror($result), RESPONSE_SOCKET_ERROR);
}
$result_data = '';
//发送socket数据到服务器
if (!socket_write($socket, $in, strlen($in))) {
$this->return_data(null, "socket发送数据失败,原因:" . socket_strerror($socket), RESPONSE_SOCKET_ERROR);
}
//获取socket返回值
while ($out = socket_read($socket, 8192)) {
$result_data = $out;
}
//关闭socket
socket_close($socket);
return $result_data;
}
UDP协议
UDP服务端:
<?php
//Reduce errors
error_reporting(~E_WARNING);
//Create a UDP socket
if (!($sock = socket_create(AF_INET, SOCK_DGRAM, 0))) {
$errorcode = socket_last_error();
$errormsg = socket_strerror($errorcode);
die("Couldn't create socket: [$errorcode] $errormsg \n");
}
echo "Socket created \n";
// Bind the source address
if (!socket_bind($sock, "127.0.0.1", 8012)) {
$errorcode = socket_last_error();
$errormsg = socket_strerror($errorcode);
die("Could not bind socket : [$errorcode] $errormsg \n");
}
echo "Socket bind OK \n";
//Do some communication, this loop can handle multiple clients
while (1) {
echo "Waiting for data ... \n";
//Receive some data
$r = socket_recvfrom($sock, $buf, 512, 0, $remote_ip, $remote_port);
echo "$remote_ip : $remote_port -- " . $buf;
//Send back the data to the client
socket_sendto($sock, "OK " . $buf, 100, 0, $remote_ip, $remote_port);
}
socket_close($sock);
UDP客户端:
<?php
//error_reporting(E_ALL | E_STRICT);
set_time_limit(0);
ob_implicit_flush();
$sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
$msg = "ping";
$len = strlen($msg);
socket_sendto($sock, $msg, $len, 0, "127.0.0.1", 8012);
$from_remote = "127.0.0.1";
$port_remote = 8012;
socket_recvfrom($sock, $buf, 65535, 0, $from_remote, $port_remote);
echo "$buf".PHP_EOL;
socket_close($sock);
参阅 https://blog.csdn.net/sinat_40957383/article/details/98616352
这里面的服务端:
<?php
error_reporting(E_ALL | E_STRICT);
set_time_limit(0);
ob_implicit_flush();
$socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
if ( $socket === false ) {
echo "socket_create() failed:reason:" . socket_strerror( socket_last_error() ) . "\n";
}
$ok = socket_bind($socket, '127.0.0.1',8012);
if ( $ok === false ) {
echo "socket_bind() failed:reason:" . socket_strerror( socket_last_error( $socket ) );
}
while ( true ) {
$from_remote = '';
$port_remote = 0;
$num = socket_recvfrom($socket, $buf, 65535, 0, $from_remote, $port_remote);
if ($num===false) {
break;
}
echo "Received $buf from remote address $from_remote and remote port $port_remote".PHP_EOL;
//sleep(1000);
$msg = random_int(4, 100);
//$msg = "Pong!";
$msg = "er".$msg;
$len = strlen($msg);
socket_sendto($socket,$msg,$len,0,$from_remote, $port_remote);
}
socket_close($socket);
?>
Stream
通信过程:
+-------------------------------
* @socket通信整个过程
+-------------------------------
* @stream_socket_server
* @stream_socket_accept
* @stream_socket_recvfrom
* @stream_socket_sendto
* @stream_get_contents
* @stream_socket_shutdown
stream_socket_client
fread
fwrite
fclose
TCP服务端:
<?php
//设置不超时
set_time_limit(0);
class SocketServer
{
public function __construct($port)
{
global $errno, $errstr;
$socket = stream_socket_server('tcp://127.0.0.1:' . $port, $errno, $errstr);
while ($conn = stream_socket_accept($socket, -1)) {
$buff = '';
$data = '';
file_put_contents('log.txt', 'SERVER-1|| server:conn->' . $conn . '; buff->' . $buff . '; data->' . $data . "\r\n", FILE_APPEND);
//读取请求数据直到遇到\r\n结束符
while (!preg_match('#\r\n#', $buff)) {
$buff = fread($conn, 1024);
file_put_contents('log.txt', 'SERVER-2|| buff:' . $buff . "\r\n", FILE_APPEND);
$data .= preg_replace('#\r\n#', '', $buff);
file_put_contents('log.txt', 'SERVER-3|| data:' . $data . "\r\n", FILE_APPEND);
}
file_put_contents('log.txt', 'SERVER-4|| data:' . $data . "\r\n", FILE_APPEND);
fwrite($conn, $data);
file_put_contents('log.txt', 'SERVER-5|| data:' . $data . "\r\n", FILE_APPEND);
fclose($conn);
}
fclose($socket);
}
}
new SocketServer(1212);
TCP客户端:
<?php
if (isset($argv[1])) {
$msg = $argv[1];
file_put_contents('log.txt', 'CLIENT-1|| msg:' . $msg . "\r\n", FILE_APPEND);
$socket = stream_socket_client('tcp://127.0.0.1:1212', $errno, $errstr);
if (!$socket) {
die($errno . $errstr);
} else {
// stream_set_blocking($socket, 0);
for ($index = 0; $index < 3; $index++) {
fwrite($socket, " client: $msg $index ");
file_put_contents('log.txt', 'CLIENT-2|| for: msg' . $msg . '; index:' . $index . "\r\n", FILE_APPEND);
usleep(100000);
}
fwrite($socket, "\r\n");
$response = fread($socket, 1024);
file_put_contents('log.txt', 'CLIENT-3|| client:time->' . date("[H:i:s] ", time()) . '; reponse->' . $response . '; msg->' . $msg . "\r\n", FILE_APPEND);
fclose($socket);
}
} else {
for ($index = 0; $index < 3; $index++) {
file_put_contents('log.txt', 'CLIENT-4|| start:' . $index . "\r\n", FILE_APPEND);
system('php ' . __FILE__ . " $index:test");
}
}
UDP客户端:
<?php
function udp_client($port, $ip, $sendMsg)
{
set_time_limit(0);
$handle = stream_socket_client("udp://{$ip}:{$port}", $errno, $errstr);
if (!$handle) {
$this->return_data(null, "连接失败,{$errno} - {$errstr}", RESPONSE_UNDATA_ERROR);
}
fwrite($handle, $sendMsg);
$result = fread($handle, 1024);
fclose($handle);
return $result;
}
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);
}
使用UDP连接:
<?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);
}
cUrl
<?php
function Get($url)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
$result = curl_exec($ch);
if ($result === false) {
// 记录日志
// write_logs("test", "Get is false", curl_error($ch));
}
curl_close($ch);
return $result;
}
function Post($url, $postData = array())
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
$result = curl_exec($ch);
if ($result === false) {
// 记录日志
// write_logs("test", "Post is false", curl_error($ch));
}
curl_close($ch);
return $result;
}
file_get_contents
那么file_get_contents呢?
file_get_contents()除了获取本地文件内容,还可以获取远程文件内容。
有些时候用 file_get_contents() 调用外部文件容易超时报错。curl 效率比 file_get_contents() 和 fsockopen() 高一些,原因是cURL会自动对DNS信息进行缓存。
file_get_contents / curl / fsockopen 在当前所请求环境下选择性操作,没有一概而论。
file_get_contents 需要php.ini里开启allow_url_fopen,请求http时,使用的是http_fopen_wrapper,不会keeplive的话curl是可以的。 file_get_contents()单个执行效率高,返回没有头的信息。
这个是读取一般文件的时候并没有什么问题,但是在读取远程文件的时候有可能就会出现问题。如果是要一个持续连接,多次请求多个页面。 那么file_get_contents和fopen就会出问题。取得的内容也可能会不对。所以做一些类似采集工作的时候,肯定就有问题了。
fsockopen 较底层,可以设置基于UDP或是TCP协议去交互,配置麻烦,不易操作。返回完整信息。
总之,file_get_contents 和 curl 能干的,socket都能干。socket能干的,curl 就不一定能干了。 file_get_contents 更多的时候只是去拉取数据。效率比较高也比较简单。
只讨论 curl 与file_get_contents 的话,有这么一些结论:
- fopen /file_get_contents 每次请求都会重新做DNS查询,并不对DNS信息进行缓存。但是cURL会自动对DNS信息进行缓存。 对同一域名下的网页或者图片的请求只需要一次DNS查询。这大大减少了DNS查询的次数。所以cURL的性能比fopen /file_get_contents 好很多。
- fopen /file_get_contents在请求HTTP时,使用的是http_fopen_wrapper,不会keeplive。而curl却可以。这样在多次请求多个链接时,curl效率会好一些。
- fopen / file_get_contents函数会受到php.ini文件中allow_url_open选项配置的影响。如果该配置关闭了,则该函数也就失效了。而curl不受该配置的影响。
- curl可以模拟多种请求,例如:POST数据,表单提交等,用户可以按照自己的需求来定制请求。而fopen / file_get_contents只能使用get方式获取数据。 PS:file_get_contents()函数获取https链接内容的时候,需要php 中mod_ssl的支持(或安装opensll)。
结论就是,curl 效率及稳定都比 file_get_contents() 要好,fsockopen 也很强大,但是比较偏底层。
HTTP工厂方法类
兼容 Curl/Socket/Stream 的 HTTP 客户端操作类:
<?php
/**
* HTTP功能工厂方法类
*
* 调用示例代码:
try {
$http = Http::factory('http://www.baidu.com', Http::TYPE_SOCK );
echo $http->get();
$http = Http::factory('http://127.0.0.1/test/i.php', Http::TYPE_SOCK );
echo $http->post('', array('user'=>'我们', 'nick'=>'ASSADF@#!32812989+-239%ASDF'), '', array('aa'=>'bb', 'cc'=>'dd'));
} catch (Exception $e) {
echo $e->getMessage();
}
*/
class Http
{
/**
* @var 使用 cURL
*/
const TYPE_cURL = 1;
/**
* @var 使用 Socket
*/
const TYPE_SOCK = 2;
/**
* @var 使用 Stream
*/
const TYPE_STREAM = 3;
/**
* 保证对象不被clone
*/
private function __clone()
{
}
/**
* 构造函数
*/
private function __construct()
{
}
/**
* HTTP工厂操作方法
*
* @param string $url 需要访问的URL
* @param int $type 需要使用的HTTP类
* @return object
*/
public static function factory($url = '', $type = self::TYPE_SOCK)
{
if ($type == '') {
$type = self::TYPE_SOCK;
}
switch ($type) {
case self::TYPE_cURL :
if (!function_exists('curl_init')) {
throw new Exception(__CLASS__ . " PHP cURL extension not install");
}
$obj = Http_Curl::getInstance($url);
break;
case self::TYPE_SOCK :
if (!function_exists('fsockopen')) {
throw new Exception(__CLASS__ . " PHP function fsockopen() not support");
}
$obj = Http_Sock::getInstance($url);
break;
case self::TYPE_STREAM :
if (!function_exists('stream_context_create')) {
throw new Exception(__CLASS__ . " PHP Stream extension not install");
}
$obj = Http_Stream::getInstance($url);
break;
default:
throw new Exception("http access type $type not support");
}
return $obj;
}
/**
* 生成一个供Cookie或HTTP GET Query的字符串
*
* @param array $data 需要生产的数据数组,必须是 Name => Value 结构
* @param string $sep 两个变量值之间分割的字符,缺省是 &
* @return string 返回生成好的Cookie查询字符串
*/
public static function makeQuery($data, $sep = '&')
{
$encoded = '';
while (list($k, $v) = each($data)) {
$encoded .= ($encoded ? "$sep" : "");
$encoded .= rawurlencode($k) . "=" . rawurlencode($v);
}
return $encoded;
}
}
Http_Curl类:
<?php
/**
* 使用cURL 作为核心操作的HTTP访问类
*
* @desc cURL 以稳定、高效、移植性强作为很重要的HTTP协议访问客户端,必须在PHP中安装 cURL 扩展才能使用本功能
*/
class Http_Curl
{
/**
* @var object 对象单例
*/
static $_instance = NULL;
/**
* @var string 需要发送的cookie信息
*/
private $cookies = '';
/**
* @var array 需要发送的头信息
*/
private $header = array();
/**
* @var string 需要访问的URL地址
*/
private $uri = '';
/**
* @var array 需要发送的数据
*/
private $vars = array();
/**
* 构造函数
*
* @param string $configFile 配置文件路径
*/
private function __construct($url)
{
$this->uri = $url;
}
/**
* 保证对象不被clone
*/
private function __clone()
{
}
/**
* 获取对象唯一实例
*
* @param string $configFile 配置文件路径
* @return object 返回本对象实例
*/
public static function getInstance($url = '')
{
if (!(self::$_instance instanceof self)) {
self::$_instance = new self($url);
}
return self::$_instance;
}
/**
* 设置需要发送的HTTP头信息
*
* @param array/string 需要设置的头信息,可以是一个 类似 array('Host: example.com', 'Accept-Language: zh-cn') 的头信息数组
* 或单一的一条类似于 'Host: example.com' 头信息字符串
* @return void
*/
public function setHeader($header)
{
if (emptyempty($header)) {
return;
}
if (is_array($header)) {
foreach ($header as $k => $v) {
$this->header[] = is_numeric($k) ? trim($v) : (trim($k) . ": " . trim($v));
}
} elseif (is_string($header)) {
$this->header[] = $header;
}
}
/**
* 设置Cookie头信息
*
* 注意:本函数只能调用一次,下次调用会覆盖上一次的设置
*
* @param string/array 需要设置的Cookie信息,一个类似于 'name1=value1&name2=value2' 的Cookie字符串信息,
* 或者是一个 array('name1'=>'value1', 'name2'=>'value2') 的一维数组
* @return void
*/
public function setCookie($cookie)
{
if (emptyempty($cookie)) {
return;
}
if (is_array($cookie)) {
$this->cookies = Http::makeQuery($cookie, ';');
} elseif (is_string($cookie)) {
$this->cookies = $cookie;
}
}
/**
* 设置要发送的数据信息
*
* 注意:本函数只能调用一次,下次调用会覆盖上一次的设置
*
* @param array 设置需要发送的数据信息,一个类似于 array('name1'=>'value1', 'name2'=>'value2') 的一维数组
* @return void
*/
public function setVar($vars)
{
if (emptyempty($vars)) {
return;
}
if (is_array($vars)) {
$this->vars = $vars;
}
}
/**
* 设置要请求的URL地址
*
* @param string $url 需要设置的URL地址
* @return void
*/
public function setUrl($url)
{
if ($url != '') {
$this->uri = $url;
}
}
/**
* 发送HTTP GET请求
*
* @param string $url 如果初始化对象的时候没有设置或者要设置不同的访问URL,可以传本参数
* @param array $vars 需要单独返送的GET变量
* @param array/string 需要设置的头信息,可以是一个 类似 array('Host: example.com', 'Accept-Language: zh-cn') 的头信息数组
* 或单一的一条类似于 'Host: example.com' 头信息字符串
* @param string/array 需要设置的Cookie信息,一个类似于 'name1=value1&name2=value2' 的Cookie字符串信息,
* 或者是一个 array('name1'=>'value1', 'name2'=>'value2') 的一维数组
* @param int $timeout 连接对方服务器访问超时时间,单位为秒
* @param array $options 当前操作类一些特殊的属性设置
* @return unknown
*/
public function get($url = '', $vars = array(), $header = array(), $cookie = '', $timeout = 5, $options = array())
{
$this->setUrl($url);
$this->setHeader($header);
$this->setCookie($cookie);
$this->setVar($vars);
return $this->send('GET', $timeout);
}
/**
* 发送HTTP POST请求
*
* @param string $url 如果初始化对象的时候没有设置或者要设置不同的访问URL,可以传本参数
* @param array $vars 需要单独返送的GET变量
* @param array/string 需要设置的头信息,可以是一个 类似 array('Host: example.com', 'Accept-Language: zh-cn') 的头信息数组
* 或单一的一条类似于 'Host: example.com' 头信息字符串
* @param string/array 需要设置的Cookie信息,一个类似于 'name1=value1&name2=value2' 的Cookie字符串信息,
* 或者是一个 array('name1'=>'value1', 'name2'=>'value2') 的一维数组
* @param int $timeout 连接对方服务器访问超时时间,单位为秒
* @param array $options 当前操作类一些特殊的属性设置
* @return unknown
*/
public function post($url = '', $vars = array(), $header = array(), $cookie = '', $timeout = 5, $options = array())
{
$this->setUrl($url);
$this->setHeader($header);
$this->setCookie($cookie);
$this->setVar($vars);
return $this->send('POST', $timeout);
}
/**
* 发送HTTP请求核心函数
*
* @param string $method 使用GET还是POST方式访问
* @param array $vars 需要另外附加发送的GET/POST数据
* @param int $timeout 连接对方服务器访问超时时间,单位为秒
* @param array $options 当前操作类一些特殊的属性设置
* @return string 返回服务器端读取的返回数据
*/
public function send($method = 'GET', $timeout = 5, $options = array())
{
//处理参数是否为空
if ($this->uri == '') {
throw new Exception(__CLASS__ . ": Access url is empty");
}
//初始化cURL
$ch = curl_init();
curl_setopt($ch, cURLOPT_HEADER, 0);
curl_setopt($ch, cURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, cURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, cURLOPT_TIMEOUT, $timeout);
//设置特殊属性
if (!emptyempty($options)) {
curl_setopt_array($ch, $options);
}
//处理GET请求参数
if ($method == 'GET' && !emptyempty($this->vars)) {
$query = Http::makeQuery($this->vars);
$parse = parse_url($this->uri);
$sep = isset($parse['query']) ? '&' : '?';
$this->uri .= $sep . $query;
}
//处理POST请求数据
if ($method == 'POST') {
curl_setopt($ch, cURLOPT_POST, 1);
curl_setopt($ch, cURLOPT_POSTFIELDS, $this->vars);
}
//设置cookie信息
if (!emptyempty($this->cookies)) {
curl_setopt($ch, cURLOPT_COOKIE, $this->cookies);
}
//设置HTTP缺省头
if (emptyempty($this->header)) {
$this->header = array(
'User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; InfoPath.1)',
//'Accept-Language: zh-cn',
//'Cache-Control: no-cache',
);
}
curl_setopt($ch, cURLOPT_HTTPHEADER, $this->header);
//发送请求读取输数据
curl_setopt($ch, cURLOPT_URL, $this->uri);
$data = curl_exec($ch);
if (($err = curl_error($ch))) {
curl_close($ch);
throw new Exception(__CLASS__ . " error: " . $err);
}
curl_close($ch);
return $data;
}
}
Http_Sock类:
<?php
/**
* 使用 Socket操作( fsockopen()函数实现 ) 作为核心操作的HTTP访问接口
*
* @desc Network/fsockopen 是PHP内置的一个Sokcet网络访问接口,必须安装/打开 fsockopen 函数本类才能工作,
* 同时确保其他相关网络环境和配置是正确的
*/
class Http_Sock
{
/**
* @var object 对象单例
*/
static $_instance = NULL;
/**
* @var string 需要发送的cookie信息
*/
private $cookies = '';
/**
* @var array 需要发送的头信息
*/
private $header = array();
/**
* @var string 需要访问的URL地址
*/
private $uri = '';
/**
* @var array 需要发送的数据
*/
private $vars = array();
/**
* 构造函数
*
* @param string $configFile 配置文件路径
*/
private function __construct($url)
{
$this->uri = $url;
}
/**
* 保证对象不被clone
*/
private function __clone()
{
}
/**
* 获取对象唯一实例
*
* @param string $configFile 配置文件路径
* @return object 返回本对象实例
*/
public static function getInstance($url = '')
{
if (!(self::$_instance instanceof self)) {
self::$_instance = new self($url);
}
return self::$_instance;
}
/**
* 设置需要发送的HTTP头信息
*
* @param array/string 需要设置的头信息,可以是一个 类似 array('Host: example.com', 'Accept-Language: zh-cn') 的头信息数组
* 或单一的一条类似于 'Host: example.com' 头信息字符串
* @return void
*/
public function setHeader($header)
{
if (emptyempty($header)) {
return;
}
if (is_array($header)) {
foreach ($header as $k => $v) {
$this->header[] = is_numeric($k) ? trim($v) : (trim($k) . ": " . trim($v));
}
} elseif (is_string($header)) {
$this->header[] = $header;
}
}
/**
* 设置Cookie头信息
*
* 注意:本函数只能调用一次,下次调用会覆盖上一次的设置
*
* @param string/array 需要设置的Cookie信息,一个类似于 'name1=value1&name2=value2' 的Cookie字符串信息,
* 或者是一个 array('name1'=>'value1', 'name2'=>'value2') 的一维数组
* @return void
*/
public function setCookie($cookie)
{
if (emptyempty($cookie)) {
return;
}
if (is_array($cookie)) {
$this->cookies = Http::makeQuery($cookie, ';');
} elseif (is_string($cookie)) {
$this->cookies = $cookie;
}
}
/**
* 设置要发送的数据信息
*
* 注意:本函数只能调用一次,下次调用会覆盖上一次的设置
*
* @param array 设置需要发送的数据信息,一个类似于 array('name1'=>'value1', 'name2'=>'value2') 的一维数组
* @return void
*/
public function setVar($vars)
{
if (emptyempty($vars)) {
return;
}
if (is_array($vars)) {
$this->vars = $vars;
}
}
/**
* 设置要请求的URL地址
*
* @param string $url 需要设置的URL地址
* @return void
*/
public function setUrl($url)
{
if ($url != '') {
$this->uri = $url;
}
}
/**
* 发送HTTP GET请求
*
* @param string $url 如果初始化对象的时候没有设置或者要设置不同的访问URL,可以传本参数
* @param array $vars 需要单独返送的GET变量
* @param array/string 需要设置的头信息,可以是一个 类似 array('Host: example.com', 'Accept-Language: zh-cn') 的头信息数组
* 或单一的一条类似于 'Host: example.com' 头信息字符串
* @param string/array 需要设置的Cookie信息,一个类似于 'name1=value1&name2=value2' 的Cookie字符串信息,
* 或者是一个 array('name1'=>'value1', 'name2'=>'value2') 的一维数组
* @param int $timeout 连接对方服务器访问超时时间,单位为秒
* @param array $options 当前操作类一些特殊的属性设置
* @return unknown
*/
public function get($url = '', $vars = array(), $header = array(), $cookie = '', $timeout = 5, $options = array())
{
$this->setUrl($url);
$this->setHeader($header);
$this->setCookie($cookie);
$this->setVar($vars);
return $this->send('GET', $timeout);
}
/**
* 发送HTTP POST请求
*
* @param string $url 如果初始化对象的时候没有设置或者要设置不同的访问URL,可以传本参数
* @param array $vars 需要单独返送的GET变量
* @param array/string 需要设置的头信息,可以是一个 类似 array('Host: example.com', 'Accept-Language: zh-cn') 的头信息数组
* 或单一的一条类似于 'Host: example.com' 头信息字符串
* @param string/array 需要设置的Cookie信息,一个类似于 'name1=value1&name2=value2' 的Cookie字符串信息,
* 或者是一个 array('name1'=>'value1', 'name2'=>'value2') 的一维数组
* @param int $timeout 连接对方服务器访问超时时间,单位为秒
* @param array $options 当前操作类一些特殊的属性设置
* @return unknown
*/
public function post($url = '', $vars = array(), $header = array(), $cookie = '', $timeout = 5, $options = array())
{
$this->setUrl($url);
$this->setHeader($header);
$this->setCookie($cookie);
$this->setVar($vars);
return $this->send('POST', $timeout);
}
/**
* 发送HTTP请求核心函数
*
* @param string $method 使用GET还是POST方式访问
* @param array $vars 需要另外附加发送的GET/POST数据
* @param int $timeout 连接对方服务器访问超时时间,单位为秒
* @param array $options 当前操作类一些特殊的属性设置
* @return string 返回服务器端读取的返回数据
*/
public function send($method = 'GET', $timeout = 5, $options = array())
{
//处理参数是否为空
if ($this->uri == '') {
throw new Exception(__CLASS__ . ": Access url is empty");
}
//处理GET请求参数
if ($method == 'GET' && !emptyempty($this->vars)) {
$query = Http::makeQuery($this->vars);
$parse = parse_url($this->uri);
$sep = isset($parse['query']) && ($parse['query'] != '') ? '&' : '?';
$this->uri .= $sep . $query;
}
//处理POST请求数据
$data = '';
if ($method == 'POST' && !emptyempty($this->vars)) {
$data = Http::makeQuery($this->vars);
$this->setHeader('Content-Type: application/x-www-form-urlencoded');
$this->setHeader('Content-Length: ' . strlen($data));
}
//解析URL地址
$url = parse_url($this->uri);
$host = $url['host'];
$port = isset($url['port']) && ($url['port'] != '') ? $url['port'] : 80;
$path = isset($url['path']) && ($url['path'] != '') ? $url['path'] : '/';
$path .= isset($url['query']) ? "?" . $url['query'] : '';
//组织HTTP请求头信息
array_unshift(&$this->header, $method . " " . $path . " HTTP/1.1");
$this->setHeader('User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; InfoPath.1)');
if (!preg_match("/^[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}$/", $host)) {
$this->setHeader("Host: " . $host);
}
if ($this->cookies != '') {
$this->setHeader("Cookie: " . $this->cookies);
}
$this->setHeader("Connection: Close");
//'Accept-Language: zh-cn',
//'Cache-Control: no-cache',
//构造请求信息
$header = '';
foreach ($this->header as $h) {
$header .= $h . "\r\n";
}
$header .= "\r\n";
if ($method == 'POST' && $data != '') {
$header .= $data . "\r\n";
}
//连接服务器发送请求数据
$ip = gethostbyname($host);
if (!($fp = fsockopen($ip, $port, &$errno, &$errstr, $timeout))) {
throw new Exception(__CLASS__ . ": Can't connect $host:$port, errno:$errno,message:$errstr");
}
fputs($fp, $header);
$lineSize = 1024;
//处理301,302跳转页面访问
$line = fgets($fp, $lineSize);
$first = preg_split("/\s/", trim($line));
if (isset($first[1]) && in_array($first[1], array('301', '302'))) {
while (!feof($fp)) {
$line = fgets($fp, $lineSize);
$second = preg_split("/\s/", trim($line));
if (ucfirst(trim($second[0])) == 'Location:' && $second[1] != '') {
$this->header = array();
return $this->get(trim($second[1]));
}
}
}
//正常读取返回数据
$buf = '';
$inheader = 1;
while (!feof($fp)) {
if ($inheader && ($line == "\n" || $line == "\r\n")) {
$inheader = 0;
}
$line = fgets($fp, $lineSize);
if ($inheader == 0) {
$buf .= $line;
}
}
fclose($fp);
return $buf;
}
}
Http_Stream类:
<?php
/**
* 使用文件流操作函数为核心操作的HTTP访问接口 (stream_context_creat()函数实现)
*
* @desc stream_* 和 fopen/file_get_contents 是PHP内置的一个流和文件操作接口,必须打开 fsockopen 函数本类才能工作,
* 同时确保其他相关网络环境和配置是正确的,包括 allow_url_fopen 等设置
*/
class Http_Stream
{
/**
* @var object 对象单例
*/
static $_instance = NULL;
/**
* @var string 需要发送的cookie信息
*/
private $cookies = '';
/**
* @var array 需要发送的头信息
*/
private $header = array();
/**
* @var string 需要访问的URL地址
*/
private $uri = '';
/**
* @var array 需要发送的数据
*/
private $vars = array();
/**
* 构造函数
*
* @param string $configFile 配置文件路径
*/
private function __construct($url)
{
$this->uri = $url;
}
/**
* 保证对象不被clone
*/
private function __clone()
{
}
/**
* 获取对象唯一实例
*
* @param string $configFile 配置文件路径
* @return object 返回本对象实例
*/
public static function getInstance($url = '')
{
if (!(self::$_instance instanceof self)) {
self::$_instance = new self($url);
}
return self::$_instance;
}
/**
* 设置需要发送的HTTP头信息
*
* @param array/string 需要设置的头信息,可以是一个 类似 array('Host: example.com', 'Accept-Language: zh-cn') 的头信息数组
* 或单一的一条类似于 'Host: example.com' 头信息字符串
* @return void
*/
public function setHeader($header)
{
if (emptyempty($header)) {
return;
}
if (is_array($header)) {
foreach ($header as $k => $v) {
$this->header[] = is_numeric($k) ? trim($v) : (trim($k) . ": " . trim($v));
}
} elseif (is_string($header)) {
$this->header[] = $header;
}
}
/**
* 设置Cookie头信息
*
* 注意:本函数只能调用一次,下次调用会覆盖上一次的设置
*
* @param string/array 需要设置的Cookie信息,一个类似于 'name1=value1&name2=value2' 的Cookie字符串信息,
* 或者是一个 array('name1'=>'value1', 'name2'=>'value2') 的一维数组
* @return void
*/
public function setCookie($cookie)
{
if (emptyempty($cookie)) {
return;
}
if (is_array($cookie)) {
$this->cookies = Http::makeQuery($cookie, ';');
} elseif (is_string($cookie)) {
$this->cookies = $cookie;
}
}
/**
* 设置要发送的数据信息
*
* 注意:本函数只能调用一次,下次调用会覆盖上一次的设置
*
* @param array 设置需要发送的数据信息,一个类似于 array('name1'=>'value1', 'name2'=>'value2') 的一维数组
* @return void
*/
public function setVar($vars)
{
if (emptyempty($vars)) {
return;
}
if (is_array($vars)) {
$this->vars = $vars;
}
}
/**
* 设置要请求的URL地址
*
* @param string $url 需要设置的URL地址
* @return void
*/
public function setUrl($url)
{
if ($url != '') {
$this->uri = $url;
}
}
/**
* 发送HTTP GET请求
*
* @param string $url 如果初始化对象的时候没有设置或者要设置不同的访问URL,可以传本参数
* @param array $vars 需要单独返送的GET变量
* @param array/string 需要设置的头信息,可以是一个 类似 array('Host: example.com', 'Accept-Language: zh-cn') 的头信息数组
* 或单一的一条类似于 'Host: example.com' 头信息字符串
* @param string/array 需要设置的Cookie信息,一个类似于 'name1=value1&name2=value2' 的Cookie字符串信息,
* 或者是一个 array('name1'=>'value1', 'name2'=>'value2') 的一维数组
* @param int $timeout 连接对方服务器访问超时时间,单位为秒
* @param array $options 当前操作类一些特殊的属性设置
* @return unknown
*/
public function get($url = '', $vars = array(), $header = array(), $cookie = '', $timeout = 5, $options = array())
{
$this->setUrl($url);
$this->setHeader($header);
$this->setCookie($cookie);
$this->setVar($vars);
return $this->send('GET', $timeout);
}
/**
* 发送HTTP POST请求
*
* @param string $url 如果初始化对象的时候没有设置或者要设置不同的访问URL,可以传本参数
* @param array $vars 需要单独返送的GET变量
* @param array/string 需要设置的头信息,可以是一个 类似 array('Host: example.com', 'Accept-Language: zh-cn') 的头信息数组
* 或单一的一条类似于 'Host: example.com' 头信息字符串
* @param string/array 需要设置的Cookie信息,一个类似于 'name1=value1&name2=value2' 的Cookie字符串信息,
* 或者是一个 array('name1'=>'value1', 'name2'=>'value2') 的一维数组
* @param int $timeout 连接对方服务器访问超时时间,单位为秒
* @param array $options 当前操作类一些特殊的属性设置
* @return unknown
*/
public function post($url = '', $vars = array(), $header = array(), $cookie = '', $timeout = 5, $options = array())
{
$this->setUrl($url);
$this->setHeader($header);
$this->setCookie($cookie);
$this->setVar($vars);
return $this->send('POST', $timeout);
}
/**
* 发送HTTP请求核心函数
*
* @param string $method 使用GET还是POST方式访问
* @param array $vars 需要另外附加发送的GET/POST数据
* @param int $timeout 连接对方服务器访问超时时间,单位为秒
* @param array $options 当前操作类一些特殊的属性设置
* @return string 返回服务器端读取的返回数据
*/
public function send($method = 'GET', $timeout = 5, $options = array())
{
//处理参数是否为空
if ($this->uri == '') {
throw new Exception(__CLASS__ . ": Access url is empty");
}
$parse = parse_url($this->uri);
$host = $parse['host'];
//处理GET请求参数
if ($method == 'GET' && !emptyempty($this->vars)) {
$query = Http::makeQuery($this->vars);
$sep = isset($parse['query']) && ($parse['query'] != '') ? '&' : '?';
$this->uri .= $sep . $query;
}
//处理POST请求数据
$data = '';
if ($method == 'POST' && !emptyempty($this->vars)) {
$data = Http::makeQuery($this->vars);
}
//设置缺省头
$this->setHeader('User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; InfoPath.1)');
if (!preg_match("/^[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}$/", $host)) {
$this->setHeader("Host: " . $host);
}
if ($this->cookies != '') {
$this->setHeader("Cookie: " . $this->cookies);
}
$this->setHeader("Connection: Close");
//'Accept-Language: zh-cn',
//'Cache-Control: no-cache',
//构造头信息
$opts = array(
'http' => array(
'method' => $method,
'timeout' => $timeout,
)
);
if ($data != '') {
$opts['http']['content'] = $data;
}
$opts['http']['header'] = '';
foreach ($this->header as $h) {
$opts['http']['header'] .= $h . "\r\n";
}
//print_r($opts);exit;
//读取扩展设置选项
if (!emptyempty($options)) {
isset($options['proxy']) ? $opts['http']['proxy'] = $options['proxy'] : '';
isset($options['max_redirects']) ? $opts['http']['max_redirects'] = $options['max_redirects'] : '';
isset($options['request_fulluri']) ? $opts['http']['request_fulluri'] = $options['request_fulluri'] : '';
}
//发送数据返回
$context = stream_context_create($opts);
if (($buf = file_get_contents($this->uri, null, $context)) === false) {
throw new Exception(__CLASS__ . ": file_get_contents(" . $this->uri . ") fail");
}
return $buf;
}
}
函数原型
stream系列
/**
* Open Internet or Unix domain socket connection
* @link https://php.net/manual/en/function.stream-socket-client.php
* @param string $remote_socket <p>
* Address to the socket to connect to.
* </p>
* @param int $errno [optional] <p>
* Will be set to the system level error number if connection fails.
* </p>
* @param string $errstr [optional] <p>
* Will be set to the system level error message if the connection fails.
* </p>
* @param float|null $timeout [optional] <p>
* Number of seconds until the connect() system call
* should timeout.
* This parameter only applies when not making asynchronous
* connection attempts.
* <p>
* To set a timeout for reading/writing data over the socket, use the
* stream_set_timeout, as the
* timeout only applies while making connecting
* the socket.
* </p>
* </p>
* @param int $flags [optional] <p>
* Bitmask field which may be set to any combination of connection flags.
* Currently the select of connection flags is limited to
* STREAM_CLIENT_CONNECT (default),
* STREAM_CLIENT_ASYNC_CONNECT and
* STREAM_CLIENT_PERSISTENT.
* </p>
* @param resource $context [optional] <p>
* A valid context resource created with stream_context_create.
* </p>
* @return resource|false On success a stream resource is returned which may
* be used together with the other file functions (such as
* fgets, fgetss,
* fwrite, fclose, and
* feof), false on failure.
*/
function stream_socket_client ($remote_socket, &$errno = null, &$errstr = null, $timeout = null, $flags = null, $context = null) {}
/**
* Create an Internet or Unix domain server socket
* @link https://php.net/manual/en/function.stream-socket-server.php
* @param string $local_socket <p>
* The type of socket created is determined by the transport specified
* using standard URL formatting: transport://target.
* </p>
* <p>
* For Internet Domain sockets (AF_INET) such as TCP and UDP, the
* target portion of the
* remote_socket parameter should consist of a
* hostname or IP address followed by a colon and a port number. For
* Unix domain sockets, the target portion should
* point to the socket file on the filesystem.
* </p>
* <p>
* Depending on the environment, Unix domain sockets may not be available.
* A list of available transports can be retrieved using
* stream_get_transports. See
* for a list of bulitin transports.
* </p>
* @param int $errno [optional] <p>
* If the optional errno and errstr
* arguments are present they will be set to indicate the actual system
* level error that occurred in the system-level socket(),
* bind(), and listen() calls. If
* the value returned in errno is
* 0 and the function returned false, it is an
* indication that the error occurred before the bind()
* call. This is most likely due to a problem initializing the socket.
* Note that the errno and
* errstr arguments will always be passed by reference.
* </p>
* @param string $errstr [optional] <p>
* See errno description.
* </p>
* @param int $flags [optional] <p>
* A bitmask field which may be set to any combination of socket creation
* flags.
* </p>
* <p>
* For UDP sockets, you must use STREAM_SERVER_BIND as
* the flags parameter.
* </p>
* @param resource $context [optional] <p>
* </p>
* @return resource|false the created stream, or false on error.
*/
function stream_socket_server ($local_socket, &$errno = null, &$errstr = null, $flags = null, $context = null) {}
/**
* Accept a connection on a socket created by <function>stream_socket_server</function>
* @link https://php.net/manual/en/function.stream-socket-accept.php
* @param resource $server_socket
* @param float $timeout [optional] <p>
* Override the default socket accept timeout. Time should be given in
* seconds.
* </p>
* @param string $peername [optional] <p>
* Will be set to the name (address) of the client which connected, if
* included and available from the selected transport.
* </p>
* <p>
* Can also be determined later using
* stream_socket_get_name.
* </p>
* @return resource|false Returns a stream to the accepted socket connection or FALSE on failure.
*/
function stream_socket_accept ($server_socket, $timeout = null, &$peername = null) {}
/**
* Sends a message to a socket, whether it is connected or not
* @link https://php.net/manual/en/function.stream-socket-sendto.php
* @param resource $socket <p>
* The socket to send data to.
* </p>
* @param string $data <p>
* The data to be sent.
* </p>
* @param int $flags [optional] <p>
* The value of flags can be any combination
* of the following:
* <table>
* possible values for flags
* <tr valign="top">
* <td>STREAM_OOB</td>
* <td>
* Process OOB (out-of-band) data.
* </td>
* </tr>
* </table>
* </p>
* @param string $address [optional] <p>
* The address specified when the socket stream was created will be used
* unless an alternate address is specified in address.
* </p>
* <p>
* If specified, it must be in dotted quad (or [ipv6]) format.
* </p>
* @return int|false a result code, as an integer.
*/
function stream_socket_sendto ($socket, $data, $flags = null, $address = null) {}
/**
* Shutdown a full-duplex connection
* @link https://php.net/manual/en/function.stream-socket-shutdown.php
* @param resource $stream <p>
* An open stream (opened with stream_socket_client,
* for example)
* </p>
* @param int $how <p>
* One of the following constants: STREAM_SHUT_RD
* (disable further receptions), STREAM_SHUT_WR
* (disable further transmissions) or
* STREAM_SHUT_RDWR (disable further receptions and
* transmissions).
* </p>
* @return bool true on success or false on failure.
* @since 5.2.1
*/
function stream_socket_shutdown ($stream, $how) {}
file系列
fsockopen():
/**
* Open Internet or Unix domain socket connection
* @link https://php.net/manual/en/function.fsockopen.php
* @param string $hostname <p>
* If you have compiled in OpenSSL support, you may prefix the
* hostname with either ssl://
* or tls:// to use an SSL or TLS client connection
* over TCP/IP to connect to the remote host.
* </p>
* @param int $port [optional] <p>
* The port number.
* </p>
* @param int &$errno [optional] <p>
* If provided, holds the system level error number that occurred in the
* system-level connect() call.
* </p>
* <p>
* If the value returned in errno is
* 0 and the function returned false, it is an
* indication that the error occurred before the
* connect() call. This is most likely due to a
* problem initializing the socket.
* </p>
* @param string &$errstr [optional] <p>
* The error message as a string.
* </p>
* @param float $timeout [optional] <p>
* The connection timeout, in seconds.
* </p>
* <p>
* If you need to set a timeout for reading/writing data over the
* socket, use stream_set_timeout, as the
* timeout parameter to
* fsockopen only applies while connecting the
* socket.
* </p>
* @return resource|false fsockopen returns a file pointer which may be used
* together with the other file functions (such as
* fgets, fgetss,
* fwrite, fclose, and
* feof). If the call fails, it will return false
*/
function fsockopen ($hostname, $port = null, &$errno = null, &$errstr = null, $timeout = null) {}
file_get_contents():
/**
* Reads entire file into a string
* @link https://php.net/manual/en/function.file-get-contents.php
* @param string $filename <p>
* Name of the file to read.
* </p>
* @param bool $use_include_path [optional] <p>
* Note: As of PHP 5 the FILE_USE_INCLUDE_PATH constant can be
* used to trigger include path search.
* </p>
* @param resource $context [optional] <p>
* A valid context resource created with
* stream_context_create. If you don't need to use a
* custom context, you can skip this parameter by &null;.
* </p>
* @param int $offset [optional] <p>
* The offset where the reading starts.
* </p>
* @param int $maxlen [optional] <p>
* Maximum length of data read. The default is to read until end
* of file is reached.
* </p>
* @return string|false The function returns the read data or false on failure.
*/
function file_get_contents ($filename, $use_include_path = false, $context = null, $offset = 0, $maxlen = null) {}
fopen():
/**
* Opens file or URL
* @link https://php.net/manual/en/function.fopen.php
* @param string $filename <p>
* If filename is of the form "scheme://...", it
* is assumed to be a URL and PHP will search for a protocol handler
* (also known as a wrapper) for that scheme. If no wrappers for that
* protocol are registered, PHP will emit a notice to help you track
* potential problems in your script and then continue as though
* filename specifies a regular file.
* </p>
* <p>
* If PHP has decided that filename specifies
* a local file, then it will try to open a stream on that file.
* The file must be accessible to PHP, so you need to ensure that
* the file access permissions allow this access.
* If you have enabled &safemode;,
* or open_basedir further
* restrictions may apply.
* </p>
* <p>
* If PHP has decided that filename specifies
* a registered protocol, and that protocol is registered as a
* network URL, PHP will check to make sure that
* allow_url_fopen is
* enabled. If it is switched off, PHP will emit a warning and
* the fopen call will fail.
* </p>
* <p>
* The list of supported protocols can be found in . Some protocols (also referred to as
* wrappers) support context
* and/or &php.ini; options. Refer to the specific page for the
* protocol in use for a list of options which can be set. (e.g.
* &php.ini; value user_agent used by the
* http wrapper).
* </p>
* <p>
* On the Windows platform, be careful to escape any backslashes
* used in the path to the file, or use forward slashes.
* </p>
* <pre>
* <?php
* $handle = fopen("c:\\folder\\resource.txt", "r");
* ?>
* </pre>
* @param string $mode <p>
* The mode parameter specifies the type of access
* you require to the stream. It may be any of the following:
* <table>
* A list of possible modes for fopen
* using mode
* <tr valign="top">
* <td>mode</td>
* <td>Description</td>
* </tr>
* <tr valign="top">
* <td>'r'</td>
* <td>
* Open for reading only; place the file pointer at the
* beginning of the file.
* </td>
* </tr>
* <tr valign="top">
* <td>'r+'</td>
* <td>
* Open for reading and writing; place the file pointer at
* the beginning of the file.
* </td>
* </tr>
* <tr valign="top">
* <td>'w'</td>
* <td>
* Open for writing only; place the file pointer at the
* beginning of the file and truncate the file to zero length.
* If the file does not exist, attempt to create it.
* </td>
* </tr>
* <tr valign="top">
* <td>'w+'</td>
* <td>
* Open for reading and writing; place the file pointer at
* the beginning of the file and truncate the file to zero
* length. If the file does not exist, attempt to create it.
* </td>
* </tr>
* <tr valign="top">
* <td>'a'</td>
* <td>
* Open for writing only; place the file pointer at the end of
* the file. If the file does not exist, attempt to create it.
* </td>
* </tr>
* <tr valign="top">
* <td>'a+'</td>
* <td>
* Open for reading and writing; place the file pointer at
* the end of the file. If the file does not exist, attempt to
* create it.
* </td>
* </tr>
* <tr valign="top">
* <td>'x'</td>
* <td>
* Create and open for writing only; place the file pointer at the
* beginning of the file. If the file already exists, the
* fopen call will fail by returning false and
* generating an error of level E_WARNING. If
* the file does not exist, attempt to create it. This is equivalent
* to specifying O_EXCL|O_CREAT flags for the
* underlying open(2) system call.
* </td>
* </tr>
* <tr valign="top">
* <td>'x+'</td>
* <td>
* Create and open for reading and writing; place the file pointer at
* the beginning of the file. If the file already exists, the
* fopen call will fail by returning false and
* generating an error of level E_WARNING. If
* the file does not exist, attempt to create it. This is equivalent
* to specifying O_EXCL|O_CREAT flags for the
* underlying open(2) system call.
* </td>
* </tr>
* </table>
* </p>
* <p>
* Different operating system families have different line-ending
* conventions. When you write a text file and want to insert a line
* break, you need to use the correct line-ending character(s) for your
* operating system. Unix based systems use \n as the
* line ending character, Windows based systems use \r\n
* as the line ending characters and Macintosh based systems use
* \r as the line ending character.
* </p>
* <p>
* If you use the wrong line ending characters when writing your files, you
* might find that other applications that open those files will "look
* funny".
* </p>
* <p>
* Windows offers a text-mode translation flag ('t')
* which will transparently translate \n to
* \r\n when working with the file. In contrast, you
* can also use 'b' to force binary mode, which will not
* translate your data. To use these flags, specify either
* 'b' or 't' as the last character
* of the mode parameter.
* </p>
* <p>
* The default translation mode depends on the SAPI and version of PHP that
* you are using, so you are encouraged to always specify the appropriate
* flag for portability reasons. You should use the 't'
* mode if you are working with plain-text files and you use
* \n to delimit your line endings in your script, but
* expect your files to be readable with applications such as notepad. You
* should use the 'b' in all other cases.
* </p>
* <p>
* If you do not specify the 'b' flag when working with binary files, you
* may experience strange problems with your data, including broken image
* files and strange problems with \r\n characters.
* </p>
* <p>
* For portability, it is strongly recommended that you always
* use the 'b' flag when opening files with fopen.
* </p>
* <p>
* Again, for portability, it is also strongly recommended that
* you re-write code that uses or relies upon the 't'
* mode so that it uses the correct line endings and
* 'b' mode instead.
* </p>
* @param bool $use_include_path [optional] <p>
* The optional third use_include_path parameter
* can be set to '1' or true if you want to search for the file in the
* include_path, too.
* </p>
* @param resource $context [optional] ¬e.context-support;
* @return resource|false a file pointer resource on success, or false on error.
*/
function fopen ($filename, $mode, $use_include_path = false, $context = null) {}
参考资料
深入浅出讲解:php的socket通信 https://www.cnblogs.com/aipiaoborensheng/p/6708963.html
php中socket、fsockopen、curl、stream 区别 https://blog.csdn.net/chadxia88_go/article/details/78465072
PHP 手册 函数参考 其它服务 网络 网络 函数 fsockopen https://www.php.net/manual/zh/function.fsockopen.php
PHP 兼容 Curl/Socket/Stream 的 HTTP 操作类 https://www.cnblogs.com/softwaredevelop/archive/2010/04/08/1707018.html
了解PHP中Stream(流)的概念与用法 http://www.nowamagic.net/librarys/veda/detail/2587
PHP常用技术(五)之socket的简单使用 https://www.cnblogs.com/qiye5757/p/9721401.html