DinghornLib.php 9.7 KB
<?php

namespace addons\dinghorn\library;

/**
 *
 */
class DinghornLib
{
    // 模板数据
    public $template;

    // 要覆盖的模板数据 (参见:\application\admin\controller\dinghorn\Example.php 的 example2 方法)
    public $tpl_data;

    // 模板变量键值对,若模板变量已预先定义,则会自动获取值,无需在此传递
    public $tpl_variable;

    /**
     * 构造方法
     * @param array $template 模板数据
     * @param array $tpl_data 要覆盖的模板数据
     * @param array $tpl_variable 模板变量键值对
     */
    public function __construct($template = array(), $tpl_data = array(), $tpl_variable = array())
    {
        $this->template     = $template;
        $this->tpl_data     = $tpl_data;
        $this->tpl_variable = $tpl_variable;
    }

    /**
     * 发起请求
     * @param string $access_token 机器人的 access_token
     * @param array $post_data 请求数据
     * @return array                请求结果
     */
    public function msgSend($access_token, $post_data, $sign = false)
    {
        $remote_server = 'https://oapi.dingtalk.com/robot/send?access_token=' . $access_token;

        if ($sign) {
            $millisecond   = $this->getMillisecond();
            $sign_str      = $millisecond . "\n" . $sign;
            $sign_str      = hash_hmac('sha256', $sign_str, $sign, true);
            $sign_str      = urlencode(base64_encode($sign_str));
            $remote_server .= '&timestamp=' . $millisecond . '&sign=' . $sign_str;
        }

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $remote_server);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
        curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json;charset=utf-8'));
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($post_data));
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
        $ret = curl_exec($ch);

        if (false == $ret) {
            // curl_exec failed
            $result = ['errcode' => -2, 'errmsg' => curl_error($ch)];
        } else {
            $rsp = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            if (200 != $rsp) {
                $result = ['errcode' => -1, 'errmsg' => $rsp . ' ' . curl_error($ch)];
            } else {
                $result = json_decode($ret, true);
                if (!$result) {
                    $result = ['errcode' => -3, 'errmsg' => '转换请求结果数据失败!'];
                }
            }
        }

        curl_close($ch);
        return $result;
    }

    public function getMillisecond()
    {
        list($microsecond, $time) = explode(' ', microtime()); //' '中间是一个空格
        return (float)sprintf('%.0f', (floatval($microsecond) + floatval($time)) * 1000);
    }

    /**
     * 组装消息数据
     * @return array 组装结果
     */
    public function deal_with_msg()
    {
        $msg_data = array();
        $msgtype  = $msg_data['msgtype'] = $this->template['typelist'];

        if (isset($this->tpl_data['content'])) {
            $content = $this->analysis_variable($this->tpl_data['content']);
        } else {
            $content = $this->analysis_variable($this->template['content']);
        }

        if (isset($this->tpl_data['title'])) {
            $title = $this->analysis_variable($this->tpl_data['title']);
        } else {
            $title = $this->analysis_variable($this->template['title']);
        }

        if ($msgtype == 'text') {

            $msg_data['text'] = [
                'content' => $content
            ];
            $msg_data['at']   = $this->deal_with_at();
        } elseif ($msgtype == 'link') {

            $msg_data['link'] = [
                'title'      => $title,
                'text'       => $content,
                'picUrl'     => request()->domain() . (isset($this->tpl_data['picurl_image']) ? $this->tpl_data['picurl_image'] : cdnurl($this->template['picurl_image'])),
                'messageUrl' => isset($this->tpl_data['msg_url']) ? $this->tpl_data['msg_url'] : $this->template['msg_url'],
            ];
        } elseif ($msgtype == 'markdown') {

            $msg_data['markdown'] = [
                'title' => $title,
                'text'  => $content
            ];
            $msg_data['at']       = $this->deal_with_at();
        } elseif ($msgtype == 'actionCard_whole') {

            $msg_data['msgtype']    = 'actionCard';
            $msg_data['actionCard'] = [
                'title'          => $title,
                'text'           => $content,
                'hideAvatar'     => isset($this->tpl_data['hide_avatar']) ? $this->tpl_data['hide_avatar'] : $this->template['hide_avatar'],
                'btnOrientation' => 1,
                'singleTitle'    => isset($this->tpl_data['single_title']) ? $this->analysis_variable($this->tpl_data['single_title']) : $this->analysis_variable($this->template['single_title']),
                'singleURL'      => isset($this->tpl_data['msg_url']) ? $this->tpl_data['msg_url'] : $this->template['msg_url']
            ];
        } elseif ($msgtype == 'actionCard') {

            $btns      = isset($this->tpl_data['btns']) ? $this->tpl_data['btns'] : json_decode($this->template['btns'], true);
            $btns_temp = [];
            foreach ($btns as $key => $value) {
                $btns_temp[] = array(
                    'title'     => $this->analysis_variable($key),
                    'actionURL' => $value
                );
            }

            $msg_data['actionCard'] = [
                'title'          => $title,
                'text'           => $content,
                'hideAvatar'     => isset($this->tpl_data['hide_avatar']) ? $this->tpl_data['hide_avatar'] : $this->template['hide_avatar'],
                'btnOrientation' => isset($this->tpl_data['btn_orientation']) ? $this->tpl_data['btn_orientation'] : $this->template['btn_orientation'],
                'btns'           => $btns_temp
            ];
        } elseif ($msgtype == 'feedCard') {

            $links = isset($this->tpl_data['links']) ? $this->tpl_data['links'] : json_decode($this->template['links'], true);
            foreach ($links as $key => $value) {
                $links[$key]['title'] = $this->analysis_variable($links[$key]['title']);
            }
            $msg_data['feedCard'] = array(
                'links' => $links
            );
        }

        return $msg_data;
    }

    /**
     * 分析字符串中的自定义变量
     * @param string $str 要分析的字符串
     * @return string      解析过变量的字符串
     */
    public function analysis_variable($str)
    {
        if (!$str) {
            return '';
        }

        $variables = array();
        $match     = array();
        preg_match_all('/\${(.*?)}/', $str, $match);// 匹配到所有变量

        // 读取数据库中的模板变量
        $variable_tmp = \think\Db::name('dinghorn_variable')->where('deletetime', null)->select();
        foreach ($variable_tmp as $key => $value) {
            $value['variable_type']       = 'predefined';// 标记为预定义
            $variable_arr[$value['name']] = $value;
        }
        unset($variable_tmp);

        // 准备传递过来的模板变量
        foreach ($this->tpl_variable as $key => $value) {
            $variable_arr[$key] = [
                'variable_type'  => 'definition_now',// 标记为现在定义
                'variable_value' => $value,
            ];
        }

        foreach ($match[1] as $key => $value) {

            if (array_key_exists($value, $variable_arr)) {

                if ($variable_arr[$value]['variable_type'] == 'definition_now') {

                    $str = str_replace($match[0][$key], $variable_arr[$value]['variable_value'], $str);
                } else if ($variable_arr[$value]['variable_type'] == 'predefined') {

                    $variable_value = $this->get_variable_value($variable_arr[$value]);
                    $str            = str_replace($match[0][$key], $variable_value, $str);
                }
            }
        }

        return $str;
    }

    /**
     * 获取数据库中的模板变量的值
     * @param string $var 变量数据
     * @return string      变量值
     */
    public function get_variable_value($var)
    {
        if ($var['value_source'] == 0) {
            $var['sql'] = str_replace('__PREFIX__', config('database.prefix'), $var['sql']);
            $res        = \think\Db::query($var['sql']);

            if ($res) {
                if (is_array($res[0])) {
                    foreach ($res[0] as $key => $value) {
                        return $value;
                    }
                } else {
                    return $res[0];
                }
            } else {
                return false;
            }
        } else if ($var['value_source'] == 1) {
            return \think\Hook::exec($var['namespace'] . '\\' . $var['class'], $var['function'], $var['params']);
        }
    }

    /**
     * 组装at数据
     * @return array 组装结果
     */
    public function deal_with_at()
    {
        // 数据覆盖
        if (isset($this->tpl_data['is_atall']) || isset($this->tpl_data['at_mobiles'])) {
            $this->template['is_atall']   = $this->tpl_data['is_atall'];
            $this->template['at_mobiles'] = $this->tpl_data['at_mobiles'];
        }

        if ($this->template['is_atall']) {
            return [
                'atMobiles' => [],
                'isAtAll'   => true
            ];
        } else {
            $at_mobiles = explode(',', rtrim($this->template['at_mobiles'], ','));

            return [
                'atMobiles' => $at_mobiles,
                'isAtAll'   => false
            ];
        }
    }
}