欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

PHP异步 fsockopen篇

程序员文章站 2024-01-28 11:26:16
...

项目中遇到发布一个信息后需要给关联用户推送模板消息,这个想都不用想肯定是要抛异步任务的

可是PHP不能异步,可怜我又不会其他语言,swoole我还没有用过,也来不及现在研究,而且还有装扩展的,实在是太麻烦

百度了下可以说是可以用fsockopen,在项目中已经实现了,今天来做下笔记

// 先看下网上找的例子
// 例1
<?php
/*利用php的系统调用,开启新的进程来实现。

php 提供了fsockopen函数,此函数的功能为初始化一个套接字连接到指定主机,默认情况下将以阻塞模式开启套接字连接。当然你可以通过stream_set_blocking()将它转换到非阻塞模式。这是关键。所以,思路就是:开启一个非阻塞的套接字连接到本机,本机收到之后作一些耗时处理。

类似这样的处理代码(文件posttest.php):*/

$fp = fsockopen($php_Path,80);
if (!$fp) {
    LMLog::error("fsockopen:err" );
} else {
    $out = "GET /album/action/album_write_friends_thread_record.php?key=&u=   HTTP/1.1\r\n";
    $out .= "Host: ".$php_Path."\r\n";
    $out .= "Connection: Close\r\n\r\n";
    stream_set_blocking($fp,true);
    stream_set_timeout($fp,1);
    fwrite($fp, $out);
    usleep(1000);
    fclose($fp);
}

/*这里,usleep(1000) 非常关键,它能保证这个请求能发出去。*/
?>

<?php
/*我们在来看处理的代码逻辑(文件album_write_friends_thread_record.php)*/

/**
 * 客户端调用服务器接口页面
 * user: guwen
 */
sleep(20);// 睡眠20s
?>

// 例2
<?php 
    
$url = 'http://www.example.com/doRequest.php'; 
$param = array( 
  'name'=>'fdipzone', 
  'gender'=>'male', 
  'age'=>30 
); 
    
doRequest($url, $param); 
    
function doRequest($url, $param=array()){ 
    
  $urlinfo = parse_url($url); 
    
  $host = $urlinfo['host']; 
  $path = $urlinfo['path']; 
  $query = isset($param)? http_build_query($param) : ''; 
    
  $port = 80; 
  $errno = 0; 
  $errstr = ''; 
  $timeout = 10; 
    
  $fp = fsockopen($host, $port, $errno, $errstr, $timeout); 
    
  $out = "POST ".$path." HTTP/1.1\r\n"; 
  $out .= "host:".$host."\r\n"; 
  $out .= "content-length:".strlen($query)."\r\n"; 
  $out .= "content-type:application/x-www-form-urlencoded\r\n"; 
  $out .= "connection:close\r\n\r\n"; 
  $out .= $query; 
    
  fputs($fp, $out); 
  fclose($fp); 
} 

	
//注意:当执行过程中,客户端连接断开或连接超时,都会有可能造成执行不完整,因此需要加上
ignore_user_abort(true); // 忽略客户端断开 
set_time_limit(0);    // 设置执行不超时

例子的原贴地址

例1 https://www.cnblogs.com/JDtech/p/6418438.html

例2 http://www.php.cn/php-weizijiaocheng-383499.html

 

下面是我在yii1的使用部分代码

<?php
/**
 * 模板消息发送api
 * User: lewiss
 * Date: 2018/8/24
 * Time: 17:12
 */

class TempController extends Api_pubController {

    public function actionIndex() {

        $limit = 50;

        $get_last_id = !empty($_GET['last_id']) ? (int)$_GET['last_id'] : 0;

        $list = Yii::app()->db->createCommand()
            ->select("user.id,user.wxopenid,member.m_name")
            ->from("{{school_member}} member")
            ->join("{{user}} user", "member.user_id=user.id")
            ->where("class_id=:class_id and member.type=3 and user.id>:last_id",
                [":class_id" => (int)$_GET['class_id'], ':last_id' => $get_last_id])
            ->order("user.id")
            ->limit($limit)
            ->queryAll();

        $data = [
            "school_id" => $_GET['school_id'],
            "class_id" => $_GET['class_id'],
            "class_name" => $_GET['class_name'],
            "teacher" => $_GET['teacher'],
            "title" => $_GET['title'],
        ];

        $school_id = Fun_filter::wwy_md5_set($_GET["school_id"]);
        $last_id = 0;
        foreach ($list as $value) {
            $last_id = $value['id'];
            $data['openid'] = $value['wxopenid'];
            $data['m_name'] = $value['m_name'];
            $data['url'] = "http://ktkids.cn/kt_edu/index.php?r=wap/default/class_trends&school_id={$school_id}&trend_id={$_GET['trend_id']}&trend_class_id={$_GET['class_id']}";
            $this->fso("/kt_edu/index.php?r=temp/send", $data);
        }

        if ($last_id) {
            $data['last_id'] = $last_id;
            $data['trend_id'] = $_GET['trend_id'];
            $this->fso('/kt_edu/index.php?r=temp', $data);
        }
    }

    public function actionSend() {
        $m_name = Yii::app()->request->getParam('m_name');
        $class_name = Yii::app()->request->getParam('class_name');
        $teacher = Yii::app()->request->getParam('teacher');
        $title = Yii::app()->request->getParam('title');
        $openid = Yii::app()->request->getParam('openid');
        $school_id = Yii::app()->request->getParam('school_id');
        $url = Yii::app()->request->getParam('url');


        $template_id = "SsiA1yYA2q6yq7lJiREgravOFf0ySAeOKkLiXxd_bl4";
        $data = array(
            '1' => array('name' => 'first', 'value' => '您好,亲爱的' . $m_name . '家长', 'color' => '#173177'),
            '2' => array('name' => 'keyword1', 'value' => $class_name, 'color' => '#173177'),
            '3' => array('name' => 'keyword2', 'value' => $teacher, 'color' => '#173177'),
            '4' => array('name' => 'keyword3', 'value' => date("Y年m月d日 H:i"), 'color' => '#173177'),
            '5' => array('name' => 'keyword4', 'value' => $title, 'color' => '#173177'),
            '6' => array('name' => 'remark', 'value' => '点击查看通知详情', 'color' => '#173177'),
        );
        $result = Fun_temp_kt::template($school_id, $template_id, $data, $openid, $url);
        Yii::log("rsp----" . json_encode($result));
    }

    private function fso($uri, $data) {
        $param = http_build_query($data);
        $host = "xxxx.cn";
        $fp = fsockopen($host, 80);
        $out = "GET {$uri}&{$param}   HTTP/1.1\r\n";
        $out .= "Host: " . $host . "\r\n";
        $out .= "Connection: Close\r\n\r\n";
        stream_set_blocking($fp, true);
        stream_set_timeout($fp, 1);
        fwrite($fp, $out);
        usleep(1000);
        fclose($fp);
    }

}

我在本地测试时候$host写127.0.0.1是没有问题,我想在服务器上写127.0.0.1也应该没有问题,因为都是请求的本机项目,不过好像失败了,不知道是不是nginx没有配置,后来改成了域名就ok了.

这里是以上代码实例的代码码云地址

https://gitee.com/JFliuxian/PhpDemo/blob/master/PHP%E5%BC%82%E6%AD%A5/PHP%E4%B8%AD%E6%96%87%E7%BD%91fsckopenPOST%E4%BE%8B%E5%AD%90.php