使用套接字
fopen()函数是访问Web页面的方式之一,更复杂的手段是使用套接字。这是一个让两台计算机能够相互通信的通路。在PHP里,打开套接字的方法是使用fsockopen()。
$fp=fsockopen($url, $port, $error_number, $error_string, $timeout);
fsockopen()会建立文件指针,就像fopen()一样。这个函数接收的参数是URL、端口、一个错误数字变量、一个错误字符串变量和超时(但只有一个参数是必需的)。用通俗的语言来说,端口就是一扇门,不同的协议(通信方式)从中通过。对于Web页面来说,端口通常是80(见以下表)。错误号码和字符串变量的有趣之处在于它们并不是真正发送给函数的(因为它们没有初始值),它们是由函数返回的,表示发生了错误。最后一个参数规定了函数尝试建立连接的最长时间。
这只是计算机能够用于通信的6万多个端口里最常用的几个 | |
常用端口 | |
编号 | 主要用途 |
21 | FTP |
22 | SSH |
23 | Telnet |
25 | SMTP |
80 | Web |
81 | Web(备用) |
110 | POP |
143 | IMAP |
389 | LDAP |
443 | SSL |
在文件被成功打开之后,就可以使用fwrite()、fgets()等函数操纵数据。在介绍fsockopen()范例之前,还有一个函数需要说明:parse_url()。这个函数接收一个URL作为参数,把它的各个部分进行分解,保存到一个关联数组里:$url_pieces = parse_url($url);
URL的主要组成部分是规划、主机、端口、路径和查询,以下表展示了parse_url()如何分散下面这个URL。
http://www.wangzhanchengxu.com/index.php?m=admin
parse_url()如何分散范例URL,片段对应于#之后的任何东西。如果URL的格式是http://username:password@www.example.com,其中就会包含用户和密码的值 | |
parse_url()范例 | |
索引 | 值 |
scheme(规划) | http |
host(主机) | www.wangzhanchengxu.com |
port(端口) | 80 |
user(用户) | |
pass(密码) | |
path(路径) | index.php |
query(查询) | m=admin |
fragment(片段) |
parse_url()函数在各种情况下都很好用,后面的脚本里还将展示一个范例,届时将遍历一个URL列表,检查其中的URL是否有效。为此,一个自定义函数会对接收到的URL进行解析,然后利用fsockopen()来建立连接。服务器的HTTP响应会表明链接的有效性。(以下表列出了常见的HTTP状态代码)。
每个被请求的服务器页面都会返回一个状态代码。对于URL检验来说,我们希望看到代码200 | |
常见HTTP状态代码 | |
代码 | 含义 |
200 | 正常 |
204 | 没有内容 |
400 | 错误请求 |
401 | 未授权 |
403 | 禁止 |
404 | 没有找到 |
408 | 超时 |
500 | 内部服务程序错误 |
使用fsockopen(),通过建立一个套接字连接,这个脚本能够快速地判断给定的URL是否有效。
<?php //这个函数接受一个参数:要进行检验的URL function check_url($url){ //解析URL $url_pieces=parse_url($url); //设置正确的路径和端口值 //在对连接进行测试之前,要确定获得了正确的路径与端口。所以脚本在此把$path设置为现有路径(如果存在)或一个斜线(默认值)。 //举例来说,www.example.com/dir的路径是/dir,而www.example.com的路径就是/。 $path=(isset($url_pieces['path'])) ? $url_pieces['path'] : '/'; //对端口也进行同样的操作,其默认值是80。 $port=(isset($url_pieces['port'])) ? $url_pieces['port'] : 80; //利用fsockopen()尝试进行连接。 if($fp=@fsockopen($url_pieces['host'], $port, $errno, $errstr, 30)){ //在建立连接之后,向服务器写入一些数据。 //这些行的内容看上去似乎不那么直观,它们的基本作用就是向服务器发送一系列HTTP头标,从而对通信进行初始化。请求的类型是HEAD,它类似于GET,但服务器只会返回一个响应而不是整个页面。fsockopen()连接到服务器,而HEAD $path这一行的代码请求一个特定页面,这可以只是/,也可以是/somefolder/somepage.php。代码中的\r\n是正确设置请求格式所必需的。 $send="HEAD $path HTTP/1.1\r\n"; $send.="HOST: {$url_pieces['host']}\r\n"; $send.="CONNECTION: Close\r\n\r\n"; fwrite($fp,$send); //当指定的URL接收到头标请求时,它会以自己的HTTP头标作为响应。这段代码会读取响应里的前128个字符,然后把它们分解到一个数组。其中第二个返回的元素就是HTTP代码。 $data=fgets($fp,128); //Close the connection fclose($fp); //Return the response code list($response, $code)=explode(' ',$data); if($code==200){ return array($code,'good'); }else{ return array($code,'bad'); } }else{ return array($errstr,'bad'); } } $urls=array( 'http://www.wangzhanchengxu.com/wangzhanbj/', 'http://www.seojz.cc/', 'http://www.phpcms.cn/html/download/' ); echo '<p><strong>Validating URLs</strong></p><ul>'; //Kill the PHP time limit //建立这个套接字连接需要一定的时间,特别是在对大量URL进行检验时,通过以参数0调用set_time_limit()函数,可以让这段PHP脚本拥有足够的时间来完成自己的工作。 set_time_limit(0); foreach($urls as $url){ list($code, $class)=check_url($url); echo '<li><a href="'.$url.'" target="_blank">'.$url.'</a>(<span class="'.$class.'">'.$code.'</span>)</li>'; } echo '</ul>'; ?>
fsockopen()与fopen()相比的另一个优点是不受PHP的allow_url_fopen设置的影响。如果这个指令被设置为false,使用fopen()打开URL就会失败。这只是在PHP里使用套接字的一个范例。在实际应用中,我们可以使用PHP和套接字函数创建自己的套接字服务程序。如果你不知道为什么要这样做,就说明你可能永远不需要了解这些函数。更多信息请见www.php.net/sockets。