├── .htaccess ├── README.md ├── callback └── tape_callback.php ├── common ├── AbstractInterface.php ├── Common.php ├── ConfFactory.php ├── ErrorCode.php ├── GlobalDefine.php ├── GlobalFunctions.php ├── Ini.php ├── MiniLog.php ├── Param.php ├── ParamChecker.php └── TLSSigAPIv2.php ├── conf ├── OutDefine.php ├── cdn.inc.ini └── cdn.route.ini ├── createDB.sh ├── dao ├── dao_base │ ├── dao.class.php │ └── simple_mysql_session.class.php ├── dao_live │ └── dao_live.class.php └── redis_cache.php ├── doc └── protocol.md ├── fastcgi.conf ├── index.php ├── interface.php ├── interface ├── get_cos_sign.php ├── get_user_info.php ├── get_vod_list.php ├── login.php ├── refresh.php ├── register.php ├── upload_room.php └── upload_user_info.php └── liteav_demo.nginx /.htaccess: -------------------------------------------------------------------------------- 1 | RewriteEngine on #rewriteengine???????on???off??? 2 | RewriteRule ^([a-zA-Z0-9_]){5,100}/?$ interface.php/$0 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 小直播解决方案服务端 2 | 3 | 为观众端提供直播间列表和回放列表,以及账号注册、登录、个人信息维护等功能。 4 | 5 | 6 | ### 开通直播服务 7 | 8 | #### step 1.1 开通视频直播服务 9 | 10 | 登录腾讯云官网,进入 [云直播管理控制台](https://console.cloud.tencent.com/live),如果服务还没有开通,单击【申请开通】。 11 | 12 | #### step 1.2 绑定直播域名 13 | 按照相关政策要求,您需要添加自有的**已备案域名**才能使用腾讯云的 CDN 播放功能,请参见 [域名管理](https://cloud.tencent.com/document/product/267/20381) 和 [CNAME 配置](https://cloud.tencent.com/document/product/267/30560) 进行配置。 14 | 15 | 16 | #### step 1.3 获取 SDK 的测试 License 17 | “小直播”是基于腾讯云 LiteAVSDK 实现推流和播放功能的,但您需要提前绑定 License 才能使用其提供的推流功能,您可以先按照如下步骤获取“小直播”所需要的测试 License: 18 | 19 | 1. 在 [云直播管理控制台](https://console.cloud.tencent.com/live) 中点击进入 [移动直播 License](https://console.cloud.tencent.com/live/license) 页面。 20 | 2. 填写【Package Name】为 Android 的包名,【Bundle Id】为 iOS 的 Bundle Id。 21 | 3. 单击【免费创建】,创建成功后,页面会显示生成的 License 信息。请记录 Key 和 LicenseUrl,便于在 SDK 初始化时使用。 22 | 23 | ![](https://main.qcloudimg.com/raw/b654ecd69f30ea7c5503bc15819dc01e.png) 24 | 25 | 26 | #### step 1.4 在应用管理中添加一个新的应用 27 | “小直播”是基于腾讯云 TIMSDK 实现文字聊天室和弹幕消息等互动功能的,但您需要先创建一个 IM 应用才能使用其提供的聊天室功能,您可以先按照如下步骤获取“小直播”所需要的 SDKAppID 和 SecretKey 两个重要信息: 28 | 29 | 1. 进入【云直播控制台】>【直播SDK】>【[应用管理](https://console.cloud.tencent.com/live/license/appmanage)】,单击【创建应用】,待应用创建完成后,记录其 SDKAppID 信息。 30 | 2. 单击目标应用的 SDKAppID,进入应用详情页面。 31 | 3. 选择【应用管理】页签,单击【编辑】,输入一个管理员名称(例如“admin”),单击【添加】按钮,之后再单击【确定】按钮。 32 | 4. 单击【查看密钥】,复制保存密钥信息 SecretKey。 33 | 34 | ![](https://main.qcloudimg.com/raw/2b5a8e84c9f4a79e7d98e1e2c928f113.jpg) 35 | 36 | ### 开通对象存储服务 37 |

step 2.1 申请开通对象存储服务

38 | 39 | 进入 [对象存储服务控制台](https://console.cloud.tencent.com/cos5),如果还没有服务,直接单击【创建存储桶】即可。 40 | 41 |

step 2.2 创建存储桶并获取基本信息

42 | 43 | 1. 填写名称,选择所属地域,设置访问权限为【公有读私有写】。单击【确定】创建存储桶。 44 | ![](https://main.qcloudimg.com/raw/cd92d21f4473fa86125719ca1033e65b/new_cos_dialog.jpg) 45 | 46 | 2. 单击【基础配置】,记录`存储空间名称`、`所属地域`,分别对应于后文 [修改云服务器配置信息](#STEP4_1) 中的 `COSKEY_BUCKET` 和 `COSKEY_BUCKET_REGION`。 47 | ![](https://main.qcloudimg.com/raw/fb059908dd4b13ffbf82814fbca4f020.png) 48 | 49 |

step 2.3 获取密钥信息

50 | 51 | 进入[【对象存储控制台】>【密钥管理】>【云API密钥】](https://console.cloud.tencent.com/cam/capi) 获取 `APPID`、`SecretId` 和 `SecretKey`,分别对应下文 [修改云服务器配置信息](#STEP4_1) 中的 `COSKEY_APPID`、`COSKEY_SECRETID` 和 `COSKEY_SECRETKEY`。 52 | ![](https://main.qcloudimg.com/raw/d93dccb3376fd73e6206786013cf1e73.jpg) 53 | 54 | 55 | ### 腾讯云CVM镜像部署 56 | 57 |

step 3.1 创建虚拟主机

58 | 59 | 进入 [CVM 控制台](https://console.cloud.tencent.com/cvm) ,单击【新建】开始创建云服务器。 60 | 61 | 选择【自定义配置】选择符合您需求的虚拟主机,在镜像提供栏选择【镜像市场】,并单击【从镜像市场选择】进服务市场选取镜像。选中图中的【小直播镜像】,您可以直接在搜索栏中搜索。 62 | ![](https://main.qcloudimg.com/raw/80b9e0090a65b70512a2a1c2c16c98a0.png) 63 | 64 |

step 3.2 设置云服务器

65 | 配置云服务器的访问密码,设置安全组。 66 | 67 | >!安全组一定要放开80、443服务端口 68 | >请**妥善保管 root 密码**,该密码将用于后续 [修改云服务器配置信息](#STEP4_1) 操作。 69 | 70 | ![](https://main.qcloudimg.com/raw/e24a07a47f4f7d2291889467c997eb8b.png) 71 | 72 |

step 3.3 查看云服务器信息

73 | 74 | 付款后生成云服务器。请记录外网 IP 地址,将用于后续 [配置录制回调](#STEP3_2) 和 [终端集成](#STEP5) 操作。 75 | ![](https://main.qcloudimg.com/raw/a3de2d654e9b73c7ce7b2457077fa6ad.png) 76 | 77 | 78 | #### step 3.4 准备配置文件 79 | 将以下内容粘贴到文本编辑器(如记事本),按照下方脚本中的注释填写各项内容,其中`xxxx`的部分在本文前半部分均能找到对应的值。 80 | 81 | ```bash 82 | #!/bin/bash 83 | 84 | echo " /data/live_demo_service/conf/OutDefine.php; 98 | ``` 99 | 100 | #### step 3.5 登录云服务器 101 | 102 | 1. 进入 [CVM 控制台](https://console.cloud.tencent.com/cvm) ,单击目标主机所在行【登录】。 103 | ![](https://main.qcloudimg.com/raw/f1b5c3f646e7db26f9b595642e8efd17.png) 104 | 105 | 2. 选择【标准登录方式】区域的【立即登录】,输入配置主机时设置的密码,单击【确认】。 106 | 107 | #### step 3.6 修改配置 108 | 登录成功后会进入一个网页版的控制台界面,您只需要直接将 [准备配置文件](#STEP3_4) 中准备好的文本粘贴过来,按 `Enter` 键确认即可。 109 | ![](https://main.qcloudimg.com/raw/1f6dfb3221b6d262e3ada6aa0a0305bb.png) 110 | 111 | **至此业务后台部署完成** 112 | 113 | 114 | ### 终端集成及回调设置 115 | 116 | 终端集成主要是小直播源码集成,主要是以下简单几步: 117 | 118 | #### 小直播源码下载 119 | 小直播 App 的源码位于 Github/Github 仓库中,可以在`Android/XiaoZhiBo`和`iOS/XiaoZhiBo`分别获取到 Android 和 iOS 的源码。 120 | 121 | 122 | 123 | 127 | 128 | 129 | 130 | 131 | 132 |
ZIP 包 124 | Github 125 | Gitee 126 |
DOWNLOADGithubGitee
133 | 134 | #### 替换“小直播” 中的 License 配置 135 | 136 | 我们在 step 1.3 中拿到的 LiteAVSDK 的测试版 License 在这一步可以发挥作用了,参照如下的说明替换源代码中的两行字符串(License URL 和 Key) 即可: 137 | 138 | - **iOS 版替换方案**: 139 | 打开`iOS/XiaoZhiBo/XiaoZhiBoApp/Classes/App/`目录下的 `TCGlobalConfig.h` 文件,将文件里的 `LICENCE_URL` 和 `LICENCE_KEY` 分别替换为[ step 1.3:获取 SDK 的测试 License ](#get_lvb_license)中记录的 License URL 和 Key。 140 | 141 | - **Android 版替换方案**: 142 | 打开`Android/XiaoZhiBo/app/src/main/java/com/tencent/qcloud/xiaozhibo`目录下的 `TCGlobalConfig.java` 文件,将文件里的 `LICENCE_URL` 和 `LICENCE_KEY` 分别替换为[ step 1.3:获取 SDK 的测试 License ](#get_lvb_license)中记录的 License URL 和 Key。 143 | 144 | #### 替换小直播后台服务器地址 145 | 小直播后台服务的地址为`http://云服务器公网 IP 地址`。例如`http://134.175.197.138`: 146 | - iOS: 147 | 打开`iOS/XiaoZhiBo/XiaoZhiBoApp/Classes/App/`目录下的 **TCGlobalConfig.h** 文件,将文件里的`kHttpServerAddr`改为您的小直播后台服务的地址。 148 | - Android: 149 | 打开`Android/XiaoZhiBo/app/src/main/java/com/tencent/qcloud/xiaozhibo`目录下的 **TCGlobalConfig.java** 文件,将文件里的`APP_SVR_URL`改为您的小直播后台服务的地址。 150 | 151 | `注意:如果服务器没有配置证书,这里的云主机服务器地址需要用http,而不能用https。` 152 | 153 | ### 在直播控制台配置录制回调地址 154 | 155 | 小直播 App 中的“精彩回放”功能依托于云直播的录制功能。 156 | #### step 4.1 配制录制参数 157 | 1. 在云直播菜单栏内选择【功能模板】>【[录制配置](https://console.cloud.tencent.com/live/config/record)】,单击 "+" 进行设置。 158 | ![](https://main.qcloudimg.com/raw/bdf497e5fa0f583aed7335b784ced2d0.png) 159 | 160 | 2. 设置基本信息,填写【模板名称】,并选择录制文件类型(HLS、MP4 或者 FLV),单击【保存】。 161 | 162 | 163 | #### step 4.2 配置录制回调 164 | 1. 在云直播菜单栏内选择【功能模板】>【[回调配置](https://console.cloud.tencent.com/live/config/callback)】,单击 "+" 创建回调模板。 165 | ![](https://main.qcloudimg.com/raw/ccad925aa508503eb8f51c0c8b92735d.png) 166 | 167 | 2. 填写并记录【回调密钥】,填写【录制回调】为 `http://您的云服务器公网 IP 地址/callback/tape_callback.php`,单击【保存】。 168 | ![](https://main.qcloudimg.com/raw/d31e9dcabf17fd394b56207c0d9d557a.png) 169 | 170 | #### step 4.3 应用配置到域名 171 | 1. 进入云直播控制台 [域名管理](https://console.cloud.tencent.com/live/domainmanage),单击推流域名后的【管理】。 172 | ![](https://main.qcloudimg.com/raw/dd8895666c8df59802703c23d3a611a8.png) 173 | 174 | 2. 单击【模板配置】,分别将【回调配置】和【录制配置】设置为上述步骤中新建的模板。 175 | ![](https://main.qcloudimg.com/raw/aab97213e80dfc428f7c201ec89f450b/domain_cfg.png) 176 | 177 | 178 | 179 | ## 后台源码目录结构说明 180 | ``` 181 | xiaozhibo_server_php 182 | ├── callback 183 | │ └── tape_callback.php //录制回调的处理 184 | ├── common 185 | │ ├── AbstractInterface.php //所有接口类的抽象父类,输入输出的统一处理 186 | │   ├── Common.php 187 | │   ├── ConfFactory.php //用于读取数据库配置文件 188 | │   ├── ErrorCode.php //错误码定义 189 | │   ├── GlobalDefine.php //一些全局定义 190 | │   ├── GlobalFunctions.php //通用函数,一些无用的函数清理掉 191 | │   ├── Ini.php //ini配置文件读取 192 | │   ├── MiniLog.php //日志 193 | │   ├── Param.php //输入参数检查 194 | │   ├── ParamChecker.php //输入参数检查 195 | │   └── TLSSigAPIv2.php //UserSig计算 196 | ├── conf 197 | │   ├── OutDefine.php //腾讯云账号信息配置文件 198 | │   ├── cdn.inc.ini //总配置文件 199 | │   └── cdn.route.ini //数据库配置文件 200 | ├── dao //数据库相关 201 | │   ├── dao_base 202 | │   │   └── dao.class.php //数据库对外的类 203 | │   ├── dao_live 204 | │   │   └── dao_live.class.php //数据库对外的实现类,各种sql语句在这里 205 | │   └── redis_cache.php //redis本地缓存 206 | ├── fastcgi.conf //nginx配置文件 207 | ├── index.php 208 | ├── interface 209 | │   ├── get_cos_sign.php //上传头像、封面图片用 210 | │   ├── get_user_info.php //获取用户信息,用于漫游个人信息 211 | │   ├── get_vod_list.php //获取回放列表 212 | │   ├── login.php //登录,获取token 213 | │   ├── refresh.php //刷新token 214 | │   ├── register.php //注册 215 | │   └── upload_user_info.php //更新个人信息 216 | ├── interface.php //接口处理入口 217 | └── liteav_demo.nginx //nginx配置文件 218 | ``` 219 | -------------------------------------------------------------------------------- /callback/tape_callback.php: -------------------------------------------------------------------------------- 1 | data = json_decode($request, true); 24 | if (!$this->data) { 25 | component_log(ERROR, EC_OK, " request para EC_SYSTEM_INVALID_JSON_FORMAT"); 26 | return EC_SYSTEM_INVALID_JSON_FORMAT; 27 | } 28 | 29 | if (array_key_exists("t", $this->data) 30 | && array_key_exists("sign", $this->data) 31 | && array_key_exists("event_type", $this->data) 32 | && array_key_exists("stream_id", $this->data)) { 33 | $check_t = $this->data['t']; 34 | $check_sign = $this->data['sign']; 35 | $this->event_type = $this->data['event_type']; 36 | $this->stream_id = $this->data['stream_id']; 37 | } else { 38 | component_log(ERROR, EC_OK, " request para EC_SYSTEM_INVALID_PARA"); 39 | return EC_SYSTEM_INVALID_PARA; 40 | } 41 | $md5_sign = GetCallBackSign($check_t); 42 | if (!($check_sign == $md5_sign)) { 43 | component_log(ERROR, EC_OK, " check_sign error:" . $check_sign . ":" . $md5_sign); 44 | return EC_SYSTEM_INVALID_SIGN; 45 | } 46 | if ($this->event_type == 100) { 47 | if (array_key_exists("video_id", $this->data) && 48 | array_key_exists("video_url", $this->data) && 49 | array_key_exists("start_time", $this->data) && 50 | array_key_exists("end_time", $this->data) && 51 | array_key_exists("file_format", $this->data)) { 52 | $this->video_id = $this->data['video_id']; 53 | $this->video_url = $this->data['video_url']; 54 | $this->start_time = $this->data['start_time']; 55 | $this->end_time = $this->data['end_time']; 56 | $this->format_type = $this->data['file_format']; 57 | 58 | if (!is_numeric($this->start_time) || !is_numeric($this->end_time)) { 59 | component_log(ERROR, EC_OK, " EC_SYSTEM_INVALID_PARA error"); 60 | return EC_SYSTEM_INVALID_PARA; 61 | } 62 | } else { 63 | component_log(ERROR, EC_OK, " EC_SYSTEM_INVALID_PARA error"); 64 | return EC_SYSTEM_INVALID_PARA; 65 | } 66 | } 67 | 68 | $config = getConf('ROUTE.DB'); 69 | $this->dao_live = new dao_live($config['HOST'], $config['PORT'], $config['USER'], $config['PASSWD'], $config['DBNAME']); 70 | return 0; 71 | } 72 | 73 | public function process() 74 | { 75 | component_log(INFO, EC_OK, "callback args=" . var_export($this->data, true)); 76 | $ret = $this->init(); 77 | if ($ret == 0) { 78 | $stream_id = $this->stream_id; 79 | if ($this->event_type == 100) { 80 | $duration = $this->end_time - $this->start_time; 81 | if ($duration > TAPE_DURATION_TIME) { 82 | $ret = $this->dao_live->addTapeFile($stream_id, 83 | $this->video_id, 84 | $this->video_url, 85 | $this->start_time, 86 | $this->end_time, 87 | $this->format_type); 88 | } else { 89 | $ret = 0; 90 | component_log(ERROR, EC_OK, "tape duration too short:" . strval($duration) . "|" . $stream_id . "|" . $this->video_id); 91 | } 92 | 93 | } 94 | } 95 | 96 | $result = array( 97 | 'code' => $ret, 98 | ); 99 | $json_result = json_encode($result); 100 | header("Content-Length:" . strlen($json_result)); 101 | echo $json_result; 102 | 103 | component_log(INFO, EC_OK, "process result:" . $ret); 104 | } 105 | } 106 | 107 | //process 108 | $tapecallback = new tape_callback(); 109 | $tapecallback->process(); 110 | exit(0); 111 | -------------------------------------------------------------------------------- /common/AbstractInterface.php: -------------------------------------------------------------------------------- 1 | _interfaceName; 26 | } 27 | 28 | /** 29 | * @return the $_retValue 30 | */ 31 | public function getRetValue() 32 | { 33 | return $this->_retValue; 34 | } 35 | 36 | /** 37 | * @return the $_retMsg 38 | */ 39 | public function getRetMsg() 40 | { 41 | return $this->_retMsg; 42 | } 43 | 44 | /** 45 | * @return the $_data 46 | */ 47 | public function getData() 48 | { 49 | return $this->_data; 50 | } 51 | 52 | /** 53 | * @param field_type $_interfaceName 54 | */ 55 | public function setInterfaceName($_interfaceName) 56 | { 57 | $this->_interfaceName = $_interfaceName; 58 | } 59 | 60 | /** 61 | * @param field_type $_retValue 62 | */ 63 | public function setRetValue($_retValue) 64 | { 65 | $this->_retValue = $_retValue; 66 | } 67 | 68 | /** 69 | * @param field_type $_retMsg 70 | */ 71 | public function setRetMsg($_retMsg) 72 | { 73 | $this->_retMsg = $_retMsg; 74 | } 75 | 76 | /** 77 | * @param field_type $_data 78 | */ 79 | public function setData($_data) 80 | { 81 | $this->_data = $_data; 82 | } 83 | 84 | /** 85 | * 86 | * 加载需要用到的对象 87 | */ 88 | abstract public function initialize(); 89 | /** 90 | * 91 | * 输入校验 92 | * @param array $args 输入参数 93 | */ 94 | abstract public function verifyInput(&$args); 95 | 96 | /** 97 | * 98 | * 输入校验 99 | * @param array $args 输入参数 100 | * @param String $Sign 签名 101 | */ 102 | abstract public function verifySign(&$args, $Sign); 103 | 104 | /** 105 | * 106 | * 请求处理 107 | */ 108 | abstract public function process(); 109 | 110 | public function renderOutput() 111 | { 112 | return json_encode( 113 | array( 114 | "code" => $this->_retValue, 115 | "message" => genErrMsg($this->_retValue, $this->_retMsg), 116 | "data" => (object) $this->_data, 117 | ) 118 | ); 119 | } 120 | 121 | public function setLogAppIdAndChannelId($app_id, $channel_id = "") 122 | { 123 | MiniLog::instance(ROOT_PATH . "/log/")->setAppIdAndChannelId($app_id, $channel_id); 124 | } 125 | 126 | public function _verifyInput(&$args, $rules) 127 | { 128 | if ($args == null && $rules == null) { 129 | return true; 130 | } 131 | $req = $args; 132 | $result = ParamChecker::getInstance()->checkParam($rules, $req); 133 | if (!$result['result']) { 134 | $this->_retValue = EC_INVALID_PARAM; 135 | $this->_retMsg = ParaStrFilter($result['msg']); 136 | return false; 137 | } 138 | $keys = array_keys($rules); 139 | extract($req); 140 | $this->_args = compact($keys); 141 | 142 | return true; 143 | } 144 | 145 | public function _verifySign(&$args, $Sign) 146 | { 147 | //return true; 148 | $data = json_decode($args, true); 149 | $userid = ""; 150 | if (isset($data['userid'])) { 151 | $userid = $data['userid']; 152 | } 153 | 154 | $session = redis_cache::instance()->get($userid); 155 | 156 | if ($session && isset($session['token'])) { 157 | $token = $session['token']; 158 | $localsign = md5($token . md5($args)); 159 | if (strcmp($Sign, $localsign) == 0) { 160 | return true; 161 | } 162 | } 163 | return false; 164 | } 165 | 166 | } 167 | -------------------------------------------------------------------------------- /common/Common.php: -------------------------------------------------------------------------------- 1 | loadInc(CONFIG_FILE); 23 | return ConfFactory::$conf; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /common/ErrorCode.php: -------------------------------------------------------------------------------- 1 | "OK", 24 | EC_BAD_REQUEST => "Bad Request", 25 | EC_SIGN_ERROR => "Invalid Token", 26 | EC_INVALID_PARAM => "Invalid Param", 27 | EC_DATABASE_ERROR => "Internal Server Error(db operate error)", 28 | EC_UPDATE_ERROR => "update error", 29 | EC_USER_EXIST => "user exist", 30 | EC_USER_NOT_EXIST => "user not exist", 31 | EC_USER_PWD_ERROR => "password error", 32 | EC_SYSTEM_INVALID_JSON_FORMAT => "http post body is empty or invalid json format in post body from client!", 33 | EC_SYSTEM_INVALID_PARA => "request para error", 34 | EC_SYSTEM_FREQUECY => "frequency control", 35 | 36 | ); 37 | 38 | if ($errorMsg == "") { 39 | return $errMsg[$errCode]; 40 | } 41 | 42 | return $errMsg[$errCode] . " | " . $errorMsg; 43 | } 44 | -------------------------------------------------------------------------------- /common/GlobalDefine.php: -------------------------------------------------------------------------------- 1 | checkParam($rules, $args); 11 | } 12 | 13 | define("DEBUG", "DEBUG"); 14 | define("INFO", "INFO"); 15 | define("ERROR", "ERROR"); 16 | define("STAT", "STAT"); 17 | 18 | function instance($interfaceName) 19 | { 20 | //$tmp = explode("_", $interfaceName); 21 | $dir = ''; 22 | //for($i = 0; $i < count($tmp) -1; $i++) { 23 | // $dir = $dir.'/'.strtolower($tmp[$i]); 24 | //} 25 | 26 | $file_name = dirname(__FILE__) . '/../interface/' . $dir . '/' . $interfaceName . '.php'; 27 | if (file_exists($file_name)) { 28 | require_once $file_name; 29 | if (!class_exists($interfaceName)) { 30 | interface_log(ERROR, 0, "invalid interfaceName of " . $interfaceName); 31 | return null; 32 | } else { 33 | return new $interfaceName(); 34 | } 35 | } else { 36 | interface_log(ERROR, 0, "invalid fileName of $file_name"); 37 | return null; 38 | } 39 | } 40 | 41 | function isLogLevelOff($logLevel) 42 | { 43 | $swithFile = ROOT_PATH . '/log/' . 'NO_' . $logLevel; 44 | if (file_exists($swithFile)) { 45 | return true; 46 | } else { 47 | return false; 48 | } 49 | } 50 | 51 | function _log($confName, $logLevel, $errorCode, $logMessage = "no error msg") 52 | { 53 | if (isLogLevelOff($logLevel)) { 54 | return; 55 | } 56 | 57 | $st = debug_backtrace(); 58 | 59 | $function = ''; //璋冪敤interface_log/web_log鐨勫嚱鏁板悕 60 | $file = ''; //璋冪敤interface_log/web_log鐨勬枃浠跺悕 61 | $line = ''; //璋冪敤interface_log/web_log鐨勮鍙� 62 | foreach ($st as $item) { 63 | if ($file) { 64 | $function = $item['function']; 65 | break; 66 | } 67 | if (substr($item['function'], -4) == '_log' && strlen($item['function']) > 4) { 68 | $file = $item['file']; 69 | $line = $item['line']; 70 | } 71 | } 72 | 73 | $function = $function ? $function : 'main'; 74 | 75 | $file = explode("/", rtrim($file, '/')); 76 | $file = $file[count($file) - 1]; 77 | $prefix = "[$file][$function][$line][$logLevel][$errorCode] "; 78 | //if($logLevel == INFO || $logLevel == STAT) { 79 | // $prefix = "[$logLevel]" ; 80 | //} 81 | if ($errorCode) { 82 | $logMessage = genErrMsg($errorCode, $logMessage); 83 | } 84 | 85 | $logFileName = $confName . "_" . strtolower($logLevel); 86 | MiniLog::instance(ROOT_PATH . "/log/")->log($logFileName, $prefix . $logMessage); 87 | if (isLogLevelOff("DEBUG") || $logLevel == "DEBUG") { 88 | return; 89 | } else { 90 | MiniLog::instance(ROOT_PATH . "/log/")->log($confName . "_" . "debug", $prefix . $logMessage); 91 | } 92 | } 93 | 94 | function interface_log($logLevel, $errorCode, $logMessage = "no error msg") 95 | { 96 | _log('interface', $logLevel, $errorCode, $logMessage); 97 | } 98 | 99 | function component_log($logLevel, $errorCode, $logMessage = "no error msg") 100 | { 101 | _log('component', $logLevel, $errorCode, $logMessage); 102 | } 103 | 104 | function mysql_log($logLevel, $errorCode, $logMessage = "no error msg") 105 | { 106 | _log('mysql', $logLevel, $errorCode, $logMessage); 107 | } 108 | 109 | function init_log($args) 110 | { 111 | if (array_key_exists("eventId", $args) && array_key_exists("timestamp", $args)) { 112 | MiniLog::instance(ROOT_PATH . "/log/")->setRequestInfo($args["eventId"], $args["timestamp"], $args["interface"]["interfaceName"]); 113 | } 114 | } 115 | 116 | function parseInterfaceName($args) 117 | { 118 | if (array_key_exists("Action", $args)) { 119 | return $args["Action"]; 120 | } 121 | 122 | return null; 123 | } 124 | 125 | function getConf($key) 126 | { 127 | $conf = ConfFactory::getInstance(); 128 | $keyArr = explode('.', $key); 129 | if (false === $keyArr) { 130 | return ''; 131 | } else { 132 | $keyStr = ''; 133 | foreach ($keyArr as $k => $v) { 134 | if ($k >= 2) { 135 | unset($keyArr[0]); 136 | unset($keyArr[1]); 137 | $keyStr .= "['" . implode(".", $keyArr) . "']"; 138 | break; 139 | } 140 | $keyStr .= "['" . $v . "']"; 141 | } 142 | eval("\$keyStr = \$conf$keyStr ;"); 143 | if (isset($keyStr)) { 144 | return $keyStr; 145 | } 146 | } 147 | return ''; 148 | } 149 | 150 | function genErrorResult( 151 | $retValue, $retMsg, $retData = array()) { 152 | return json_encode( 153 | array( 154 | "code" => $retValue, 155 | "message" => $retMsg, 156 | "data" => $retData, 157 | ) 158 | ); 159 | } 160 | 161 | function getCurrentTime() 162 | { 163 | date_default_timezone_set('PRC'); 164 | $secondTime = time(); 165 | return date('Y-m-d H:i:s', $secondTime); 166 | } 167 | 168 | function getMillisecond($startTime = false) 169 | { 170 | $endTime = microtime(true) * 1000; 171 | 172 | if ($startTime !== false) { 173 | $consumed = $endTime - $startTime; 174 | return round($consumed); 175 | } 176 | 177 | return $endTime; 178 | } 179 | 180 | function getTimeSpan($startDateTime, $endDateTime) 181 | { 182 | $startTime = strtotime($startDateTime); 183 | 184 | $endTime = strtotime($endDateTime); 185 | 186 | return $endTime - $startTime; 187 | } 188 | 189 | function createTxTime($now_time) 190 | { 191 | // $now_time = time(); 192 | $now_time += 3 * 60 * 60; 193 | return dechex($now_time); 194 | } 195 | 196 | function GetCallBackSign($txTime) 197 | { 198 | $md5_val = md5(API_KEY . strval($txTime)); 199 | return $md5_val; 200 | } 201 | 202 | function ParaStrFilter($str) 203 | { 204 | $str = str_replace('<', '', $str); 205 | $str = str_replace('>', '', $str); 206 | $str = str_replace('"', '', $str); 207 | $str = str_replace('&', '', $str); 208 | return trim($str); 209 | } 210 | 211 | /* 212 | * @author christbao 213 | * @param monitor_id string .....monitor_id 214 | * @param value int ...monitor. 215 | * @param type int ...............:1 ...:2 216 | */ 217 | function report_fc($monitor_id, $value, $type, $interface, $app_id, $service) 218 | { 219 | $sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); 220 | socket_set_option($sock, SOL_SOCKET, SO_RCVTIMEO, array("sec" => 0, "usec" => 5000)); 221 | socket_set_option($sock, SOL_SOCKET, SO_SNDTIMEO, array("sec" => 0, "usec" => 5000)); 222 | if ($type == 1) { 223 | $arr = array('method' => 'Attr_API', 'id' => $monitor_id, 'value' => $value, 'fc' => array 224 | ( 225 | 'service' => $service, 'appid' => $app_id, 'interface' => $interface, 226 | ), 227 | ); 228 | } else { 229 | $arr = array('method' => 'Attr_API_Set', 'id' => $monitor_id, 'value' => $value, 'fc' => array 230 | ( 231 | 'service' => $service, 'appid' => $app_id, 'interface' => $interface, 232 | ), 233 | ); 234 | } 235 | $msg = json_encode($arr); 236 | $len = strlen($msg); 237 | socket_sendto($sock, $msg, $len, 0, '127.0.0.1', 14000); 238 | $buf = ''; 239 | if (false !== ($bytes = socket_recv($sock, $buf, 2048, MSG_WAITALL))) { 240 | component_log(ERROR, $ret, "Read $bytes bytes from socket_recv(). Closing socket..."); 241 | } else { 242 | component_log(ERROR, $ret, "socket_recv() failed; reason: " . socket_strerror(socket_last_error($sock)) . "\n"); 243 | } 244 | socket_close($sock); 245 | $data = json_decode($buf, true); 246 | if (!$data) { 247 | component_log(ERROR, $ret, "json decode fail,bypass"); 248 | return true; 249 | } 250 | 251 | if ($data['fc']['errcode'] == 0) { 252 | return true; 253 | } else { 254 | return false; 255 | } 256 | 257 | } 258 | -------------------------------------------------------------------------------- /common/Ini.php: -------------------------------------------------------------------------------- 1 | _conf = array(); 37 | $this->_confInc = $this->loadFile($file); 38 | 39 | $this->_conf['PROJECT'] = $this->_confInc; 40 | 41 | if (isset($this->_confInc['COMMON']) && isset($this->_confInc['COMMON']['INC'])) { 42 | $inc = $this->_confInc['COMMON']['INC']; 43 | } else { 44 | $inc = ''; 45 | } 46 | 47 | $conf = array(); 48 | if (!empty($this->_confInc)) { 49 | if (isset($this->_confInc[$inc]) && !empty($this->_confInc[$inc])) { 50 | foreach ($this->_confInc[$inc] as $k => $v) { 51 | $pattern = "%(#|;|(//)).*%"; 52 | $v = preg_replace($pattern, "", $v); 53 | $v = trim($v); 54 | $k = trim($k); 55 | $this->_confFile[$k] = $v; //后者会覆盖前者 56 | $this->_conf[$k] = $this->loadFile(ROOT_PATH . '/' . $v, $process_sections); 57 | } 58 | } 59 | } 60 | return $this->_conf; 61 | } 62 | 63 | /** 64 | * 获取配置项 65 | * 66 | * @params string $key key字符串,规则是k1.k2.k3,则表示引用配置$conf中的$conf[inc中的key][section作为key][真正的key] 67 | * @return mix 根据配置的具体情况,可能返回字符串,也可能返回数组 68 | */ 69 | public function get($key) 70 | { 71 | $keyArr = explode('.', $key); 72 | if (false === $keyArr) { 73 | return ''; 74 | } else { 75 | $keyStr = ''; 76 | foreach ($keyArr as $k => $v) { 77 | if ($k >= 2) { 78 | unset($keyArr[0]); 79 | unset($keyArr[1]); 80 | $keyStr .= "['" . implode(".", $keyArr) . "']"; 81 | break; 82 | } 83 | $keyStr .= "['" . $v . "']"; 84 | } 85 | eval("\$keyStr = \$this->_conf$keyStr ;"); 86 | if (isset($keyStr)) { 87 | return $keyStr; 88 | } 89 | } 90 | return ''; 91 | } 92 | 93 | /** 94 | * 清空配置 95 | * -- 清空已经加载的配置 96 | */ 97 | public function cleanUp() 98 | { 99 | $this->_confFile = array(); 100 | $this->_conf = array(); 101 | } 102 | }; 103 | 104 | //end of script 105 | -------------------------------------------------------------------------------- /common/MiniLog.php: -------------------------------------------------------------------------------- 1 | _path = $path; 20 | $this->_pid = getmypid(); 21 | $this->_eventId = rand(); 22 | $this->_timestamp = time(); 23 | $this->_appid = -1; 24 | $this->_channelId = ""; 25 | $this->_interfaceName = ""; 26 | } 27 | 28 | private function __clone() 29 | { 30 | 31 | } 32 | 33 | public static function instance($path = '/tmp/') 34 | { 35 | if (!(self::$_instance instanceof self)) { 36 | self::$_instance = new self($path); 37 | } 38 | 39 | return self::$_instance; 40 | } 41 | 42 | public function setRequestInfo($eventId, $timestamp, $interfaceName) 43 | { 44 | $this->_eventId = $eventId; 45 | $this->_timestamp = $timestamp; 46 | $this->_interfaceName = $interfaceName; 47 | } 48 | 49 | public function setAppIdAndChannelId($app_id, $channel_id) 50 | { 51 | $this->_appid = $app_id; 52 | $this->_channelId = $channel_id; 53 | } 54 | 55 | private function getHandle($channelName) 56 | { 57 | if ($this->_handleArr[$channelName]) { 58 | return $this->_handleArr[$channelName]; 59 | } 60 | date_default_timezone_set('PRC'); 61 | $nowTime = time(); 62 | $logSuffix = date('Ymd', $nowTime); 63 | $fileName = $this->_path . '/' . $channelName . $logSuffix . ".log.php"; // saxongao added 64 | $dirName = dirname($fileName); 65 | if (!is_dir($dirName)) { 66 | mkdir($dirName, 0777); 67 | chmod($dirName, 0777); 68 | } 69 | $str = urldecode("%E5%87%BA%E4%BA%8E%E5%AE%89%E5%85%A8%E8%80%83%E8%99%91%EF%BC%8C%E8%AF%B7%E7%94%A8%E6%96%87%E6%9C%AC%E7%BC%96%E8%BE%91%E5%99%A8%E6%89%93%E5%BC%80%E6%9F%A5%E7%9C%8B%EF%BC%9B%"); 70 | $safeString = file_exists($fileName) ? false : "\n