最近一直在搞这个,发现网上的“权威代码”也不靠谱,比如PHP终极大神“鸟哥”的代码:http://www.laruence.com/2008/04/16/98.html 看帖子下面也很多人回应不好使,但是主体代码肯定没问题。
由于自己对http协议这块了解基本为0,所以,怎么正确的模拟头信息很纠结,鸟哥的代码之所以不能正常运行,可能也是因为头信息组装出错有问题吧。
目前我写的这个模拟post提交没有用到cookie判断等,只是简单的一个提交,请求的页面能够得到post的数据。
关于http报文组装的时候空格的个数,请参考http://mengkang.net/39.html
代码如下:
function request_by_fsockopen($url,$post_data=array()){ $url_array = parse_url($url); $hostname = $url_array['host']; $port = isset($url_array['port'])? $url_array['port'] : 80; $requestPath = $url_array['path'] ."?". $url_array['query']; $fp = fsockopen($hostname, $port, $errno, $errstr, 10); if (!$fp) { echo "$errstr ($errno)"; return false; } $method = "GET"; if(!empty($post_data)){ $method = "POST"; } $header = "$method $requestPath HTTP/1.1\r\n"; $header.="Host: $hostname\r\n"; if(!empty($post_data)){ $_post = strval(NULL); foreach($post_data as $k => $v){ $_post[]= $k."=".urlencode($v);//必须做url转码以防模拟post提交的数据中有&符而导致post参数键值对紊乱 } $_post = implode('&', $_post); $header .= "Content-Type: application/x-www-form-urlencoded\r\n";//POST数据 $header .= "Content-Length: ". strlen($_post) ."\r\n";//POST数据的长度 $header.="Connection: Close\r\n\r\n";//长连接关闭 $header .= $_post; //传递POST数据 }else{ $header.="Connection: Close\r\n\r\n";//长连接关闭 } fwrite($fp, $header); //-----------------调试代码区间----------------- /*$html = ''; while (!feof($fp)) { $html.=fgets($fp); } echo $html;*/ //-----------------调试代码区间----------------- fclose($fp); } $data = array( 'authId'=>'authcode', 'email'=>'mengkang@php.net', 'nickname'=>'周梦康', 'mailBody'=>'<h3>康哥 <span style="padding:15px">某某文章</span> 有新的留言</span></h3><p>周某人 < mengkang@php.net >在评论中说:</p><div style="border-radius: 4px;margin: 10px 0 10px;border: 1px dashed #BEB0B0;padding: 8px;background: #F0F0F0;">测试回复的内容</div><p><a href="http://m.cn/github/zhoumengkang/index.php?m=Blog&a=blog&id=21#floor26">点击链接查看</a></p>' ); echo microtime(),"\r\n"; request_by_fsockopen('http://m.cn/github/zhoumengkang/index.php?m=Comment&a=sendEmail',$data); echo microtime();
(注意:实际使用过程中大家需要注意模拟发送数据中有&
符的问题,需要先替换为其他然后在被请求端再再换回来,所以第20行的urlencode()
最好是不好省略,除非确定自己的业务逻辑不需要)
其中的调试代码
对我调试很有帮助,在确定请求成功之前,最好去掉注释,如果请求出错,会输出访问错误的提示,这个是从http://www.cnblogs.com/mxw09/archive/2011/12/30/2307019.html 学习的。需要把调试代码注释才能变为异步,否则是需要等待的。
下面是邮件发送的代码,使用的是phpmail
,添加了下请求时的验证,防止恶意请求
class CommentAction{ //发送邮件之前的验证码 protected $authId = 'baf09ebd312758607e0b8601598eea74'; //简单的加密演示 protected function auth_encode($data){ return md5($data.'zmk'); } public function sendEmail(){ //解码已编码的URL字符串 $data = array_map('urldecode',$_POST); //安全处理做 //验证是不是我自己发送的,而非别人模拟发送的 if($this->auth_encode($data['authId']) != $this->authId){ return fasle; } $this->snyc_send($data); } protected function snyc_send($data){ new MailModel($data['email'],$data['nickname'],$data['mailBody'],$data['title']); } } class MailModel { protected $mail; public function __construct($address,$nickname,$boby,$title=null) { require_once(dirname(__FILE__).'/../library/phpmailer/class.phpmailer.php'); $this->mail = new PHPMailer(); //实例化 $this->mail->IsSMTP(); // 启用SMTP $this->mail->Host = "smtp.exmail.qq.com"; //SMTP服务器 $this->mail->Port = 25; //邮件发送端口 $this->mail->SMTPAuth = true; //启用SMTP认证 $this->mail->CharSet = "UTF-8"; //字符集 $this->mail->Encoding = "base64"; //编码方式 $this->mail->Username = "i@mengkang.net"; //你的邮箱 $this->mail->Password = "xxx"; //你的密码 $this->mail->Subject = $title ? $title : '主人,北剅轩有人造访'; //邮件标题 $this->mail->From = "i@mengkang.net"; //发件人地址(也就是你的邮箱) $this->mail->FromName = "周梦康"; //发件人姓名 $this->mail->AddAddress($address,$nickname);//添加收件人(地址,昵称) $this->mail->IsHTML(true); $this->mail->Body = $boby;//内容里面必须带博客的id链接 if(!$this->mail->Send()) { echo "发送失败: " .$this->mail->ErrorInfo; } } }
fopen
打开套接字连接 就可以模拟。