From f6a5564bead6805d272d47da215aced309623198 Mon Sep 17 00:00:00 2001 From: dengbw Date: Tue, 6 Sep 2022 09:18:16 +0800 Subject: [PATCH] market_906 --- api/controllers/plan/Syt.php | 104 + .../WXconfig/liche_home_WxPay.Config.php | 29 + common/composer.json | 3 +- common/helpers/comm_helper.php | 4 +- common/libraries/market/Sylive_entity.php | 162 ++ .../Market_sylive_activity_biz_model.php | 11 + .../Market_sylive_activity_kpidata_model.php | 12 + .../market/Market_sylive_activity_model.php | 18 + .../Market_sylive_activity_user_model.php | 11 + .../market/Market_sylive_order_model.php | 35 + .../Market_sylive_organization_model.php | 17 + .../Market_sylive_subscribemsg_model.php | 12 + .../market/Market_sylive_user_model.php | 52 + .../models/market/Market_sys_admin_model.php | 17 + .../Market_sys_dictionary_data_model.php | 17 + .../market/Market_sys_dictionary_model.php | 17 + .../market/Market_sys_login_record_model.php | 17 + .../models/market/Market_sys_menu_model.php | 17 + .../Market_sys_operation_record_model.php | 17 + .../models/market/Market_sys_role_model.php | 17 + home/config/wechat.php | 4 +- home/controllers/h5/market/sylive/Act.php | 336 +++ home/controllers/h5/market/sylive/Biz.php | 266 +++ home/controllers/h5/market/sylive/Common.php | 198 ++ home/controllers/h5/market/sylive/Login.php | 99 + .../controllers/h5/market/sylive/Myqrcode.php | 33 + home/controllers/h5/market/sylive/Notify.php | 67 + home/controllers/h5/market/sylive/Stic.php | 272 +++ home/controllers/h5/market/sylive/Welcome.php | 23 + home/views/h5/market/sylive/act/index.php | 306 +++ home/views/h5/market/sylive/act/item.php | 158 ++ home/views/h5/market/sylive/act/share.php | 146 ++ home/views/h5/market/sylive/act/ucenter.php | 79 + home/views/h5/market/sylive/biz/brands.php | 192 ++ home/views/h5/market/sylive/biz/index.php | 103 + home/views/h5/market/sylive/biz/lists.php | 199 ++ home/views/h5/market/sylive/footer.php | 1 + home/views/h5/market/sylive/header.php | 17 + home/views/h5/market/sylive/login.php | 165 ++ home/views/h5/market/sylive/stic/area.php | 294 +++ home/views/h5/market/sylive/stic/index.php | 222 ++ home/views/h5/market/sylive/stic/rank.php | 83 + market/.htaccess | 6 + market/cache/index.html | 11 + market/config/app.php | 34 + market/config/autoload.php | 135 ++ market/config/config.php | 523 +++++ market/config/constants.php | 109 + market/config/database.php | 96 + market/config/doctypes.php | 24 + market/config/foreign_chars.php | 103 + market/config/hooks.php | 20 + market/config/index.html | 11 + market/config/jwt.php | 6 + market/config/memcached.php | 19 + market/config/migration.php | 84 + market/config/mimes.php | 184 ++ market/config/mongo.php | 11 + market/config/profiler.php | 14 + market/config/qiniu.php | 26 + market/config/redis.php | 11 + market/config/rest.php | 605 +++++ market/config/routes.php | 54 + market/config/smileys.php | 64 + market/config/sphinx.php | 6 + market/config/user_agents.php | 214 ++ market/controllers/Welcome.php | 16 + market/controllers/api/BaseController.php | 107 + market/controllers/api/Captcha.php | 43 + market/controllers/api/Login.php | 122 + market/controllers/api/Upload.php | 85 + market/controllers/api/auth/Password.php | 52 + market/controllers/api/auth/User.php | 52 + market/controllers/api/sylive/Activity.php | 483 ++++ market/controllers/api/sylive/Order.php | 105 + .../controllers/api/sylive/Organization.php | 116 + market/controllers/api/sylive/User.php | 169 ++ market/controllers/api/system/Dictionary.php | 105 + .../controllers/api/system/DictionaryData.php | 169 ++ market/controllers/api/system/LoginRecord.php | 58 + market/controllers/api/system/Menu.php | 136 ++ .../api/system/OperationRecord.php | 100 + market/controllers/api/system/Role.php | 135 ++ market/controllers/api/system/RoleMenu.php | 65 + market/controllers/api/system/User.php | 271 +++ market/core/HD_Controller.php | 26 + market/core/HD_Loader.php | 1584 +++++++++++++ market/core/HD_Model.php | 606 +++++ market/core/HD_Service.php | 32 + market/core/index.html | 11 + market/helpers/authorization_helper.php | 28 + market/helpers/fn_helper.php | 358 +++ market/helpers/format_helper.php | 101 + market/helpers/image_helper.php | 46 + market/helpers/index.html | 11 + market/hooks/ApiAuthHook.php | 178 ++ market/hooks/index.html | 11 + market/index.html | 11 + market/language/english/index.html | 11 + .../language/english/rest_controller_lang.php | 18 + market/language/index.html | 11 + market/language/zh/error_lang.php | 23 + market/libraries/BeforeValidException.php | 7 + market/libraries/ExpiredException.php | 7 + market/libraries/Format.php | 526 +++++ market/libraries/JWT.php | 362 +++ market/libraries/MyCaptcha.php | 141 ++ market/libraries/Mymailer.php | 104 + market/libraries/REST_Controller.php | 2075 +++++++++++++++++ .../libraries/SignatureInvalidException.php | 7 + market/libraries/Wechatmsg.php | 290 +++ market/libraries/Wetemplate.php | 347 +++ market/libraries/api/Record.php | 271 +++ market/libraries/index.html | 11 + market/logs/index.html | 11 + market/models/index.html | 11 + market/third_party/index.html | 11 + market/views/errors/cli/error_404.php | 8 + market/views/errors/cli/error_db.php | 8 + market/views/errors/cli/error_exception.php | 21 + market/views/errors/cli/error_general.php | 8 + market/views/errors/cli/error_php.php | 21 + market/views/errors/cli/index.html | 11 + market/views/errors/html/error_404.php | 64 + market/views/errors/html/error_db.php | 64 + market/views/errors/html/error_exception.php | 32 + market/views/errors/html/error_general.php | 64 + market/views/errors/html/error_php.php | 33 + market/views/errors/html/index.html | 11 + market/views/errors/index.html | 11 + market/views/welcome_message.php | 45 + www/home/css/h5/market/sylive/h5.css | 7 + www/{admin => market}/favicon.ico | Bin www/market/index.php | 318 +++ www/{admin => market}/robots.txt | 0 135 files changed, 16580 insertions(+), 4 deletions(-) create mode 100644 api/controllers/plan/Syt.php create mode 100755 api/third_party/WXconfig/liche_home_WxPay.Config.php create mode 100644 common/libraries/market/Sylive_entity.php create mode 100644 common/models/market/Market_sylive_activity_biz_model.php create mode 100644 common/models/market/Market_sylive_activity_kpidata_model.php create mode 100644 common/models/market/Market_sylive_activity_model.php create mode 100644 common/models/market/Market_sylive_activity_user_model.php create mode 100644 common/models/market/Market_sylive_order_model.php create mode 100644 common/models/market/Market_sylive_organization_model.php create mode 100644 common/models/market/Market_sylive_subscribemsg_model.php create mode 100644 common/models/market/Market_sylive_user_model.php create mode 100644 common/models/market/Market_sys_admin_model.php create mode 100644 common/models/market/Market_sys_dictionary_data_model.php create mode 100644 common/models/market/Market_sys_dictionary_model.php create mode 100644 common/models/market/Market_sys_login_record_model.php create mode 100644 common/models/market/Market_sys_menu_model.php create mode 100644 common/models/market/Market_sys_operation_record_model.php create mode 100644 common/models/market/Market_sys_role_model.php create mode 100644 home/controllers/h5/market/sylive/Act.php create mode 100644 home/controllers/h5/market/sylive/Biz.php create mode 100644 home/controllers/h5/market/sylive/Common.php create mode 100644 home/controllers/h5/market/sylive/Login.php create mode 100644 home/controllers/h5/market/sylive/Myqrcode.php create mode 100644 home/controllers/h5/market/sylive/Notify.php create mode 100644 home/controllers/h5/market/sylive/Stic.php create mode 100644 home/controllers/h5/market/sylive/Welcome.php create mode 100644 home/views/h5/market/sylive/act/index.php create mode 100644 home/views/h5/market/sylive/act/item.php create mode 100644 home/views/h5/market/sylive/act/share.php create mode 100644 home/views/h5/market/sylive/act/ucenter.php create mode 100644 home/views/h5/market/sylive/biz/brands.php create mode 100644 home/views/h5/market/sylive/biz/index.php create mode 100644 home/views/h5/market/sylive/biz/lists.php create mode 100644 home/views/h5/market/sylive/footer.php create mode 100644 home/views/h5/market/sylive/header.php create mode 100644 home/views/h5/market/sylive/login.php create mode 100644 home/views/h5/market/sylive/stic/area.php create mode 100644 home/views/h5/market/sylive/stic/index.php create mode 100644 home/views/h5/market/sylive/stic/rank.php create mode 100644 market/.htaccess create mode 100644 market/cache/index.html create mode 100644 market/config/app.php create mode 100644 market/config/autoload.php create mode 100644 market/config/config.php create mode 100644 market/config/constants.php create mode 100644 market/config/database.php create mode 100644 market/config/doctypes.php create mode 100644 market/config/foreign_chars.php create mode 100644 market/config/hooks.php create mode 100644 market/config/index.html create mode 100644 market/config/jwt.php create mode 100644 market/config/memcached.php create mode 100644 market/config/migration.php create mode 100644 market/config/mimes.php create mode 100644 market/config/mongo.php create mode 100644 market/config/profiler.php create mode 100644 market/config/qiniu.php create mode 100644 market/config/redis.php create mode 100644 market/config/rest.php create mode 100644 market/config/routes.php create mode 100644 market/config/smileys.php create mode 100644 market/config/sphinx.php create mode 100644 market/config/user_agents.php create mode 100644 market/controllers/Welcome.php create mode 100644 market/controllers/api/BaseController.php create mode 100644 market/controllers/api/Captcha.php create mode 100644 market/controllers/api/Login.php create mode 100644 market/controllers/api/Upload.php create mode 100644 market/controllers/api/auth/Password.php create mode 100644 market/controllers/api/auth/User.php create mode 100644 market/controllers/api/sylive/Activity.php create mode 100644 market/controllers/api/sylive/Order.php create mode 100644 market/controllers/api/sylive/Organization.php create mode 100644 market/controllers/api/sylive/User.php create mode 100644 market/controllers/api/system/Dictionary.php create mode 100644 market/controllers/api/system/DictionaryData.php create mode 100644 market/controllers/api/system/LoginRecord.php create mode 100644 market/controllers/api/system/Menu.php create mode 100644 market/controllers/api/system/OperationRecord.php create mode 100644 market/controllers/api/system/Role.php create mode 100644 market/controllers/api/system/RoleMenu.php create mode 100644 market/controllers/api/system/User.php create mode 100644 market/core/HD_Controller.php create mode 100644 market/core/HD_Loader.php create mode 100644 market/core/HD_Model.php create mode 100644 market/core/HD_Service.php create mode 100644 market/core/index.html create mode 100644 market/helpers/authorization_helper.php create mode 100644 market/helpers/fn_helper.php create mode 100644 market/helpers/format_helper.php create mode 100644 market/helpers/image_helper.php create mode 100644 market/helpers/index.html create mode 100644 market/hooks/ApiAuthHook.php create mode 100644 market/hooks/index.html create mode 100644 market/index.html create mode 100644 market/language/english/index.html create mode 100644 market/language/english/rest_controller_lang.php create mode 100644 market/language/index.html create mode 100644 market/language/zh/error_lang.php create mode 100644 market/libraries/BeforeValidException.php create mode 100644 market/libraries/ExpiredException.php create mode 100644 market/libraries/Format.php create mode 100644 market/libraries/JWT.php create mode 100644 market/libraries/MyCaptcha.php create mode 100644 market/libraries/Mymailer.php create mode 100644 market/libraries/REST_Controller.php create mode 100644 market/libraries/SignatureInvalidException.php create mode 100644 market/libraries/Wechatmsg.php create mode 100644 market/libraries/Wetemplate.php create mode 100644 market/libraries/api/Record.php create mode 100644 market/libraries/index.html create mode 100644 market/logs/index.html create mode 100644 market/models/index.html create mode 100644 market/third_party/index.html create mode 100644 market/views/errors/cli/error_404.php create mode 100644 market/views/errors/cli/error_db.php create mode 100644 market/views/errors/cli/error_exception.php create mode 100644 market/views/errors/cli/error_general.php create mode 100644 market/views/errors/cli/error_php.php create mode 100644 market/views/errors/cli/index.html create mode 100644 market/views/errors/html/error_404.php create mode 100644 market/views/errors/html/error_db.php create mode 100644 market/views/errors/html/error_exception.php create mode 100644 market/views/errors/html/error_general.php create mode 100644 market/views/errors/html/error_php.php create mode 100644 market/views/errors/html/index.html create mode 100644 market/views/errors/index.html create mode 100644 market/views/welcome_message.php create mode 100644 www/home/css/h5/market/sylive/h5.css rename www/{admin => market}/favicon.ico (100%) create mode 100644 www/market/index.php rename www/{admin => market}/robots.txt (100%) diff --git a/api/controllers/plan/Syt.php b/api/controllers/plan/Syt.php new file mode 100644 index 00000000..00aa8bb4 --- /dev/null +++ b/api/controllers/plan/Syt.php @@ -0,0 +1,104 @@ + options = [ + 'token' => '', + 'appid' => 'wxe66f905683582780', + 'appsecret' => '9546cd4de877be13ce203f3e6140633f', + 'encodingaeskey' => '', + 'debug' => false + ]; + } + + /** + * Notes:发送一次性订阅 + * Created on: 2020/11/30 17:02 + * Created by: dengbw + * https://hd-api-dev.xiaoyu.com/plan/syt/subscribemsg + * https://api.test.haodian.cn/plan/syt/subscribemsg + * https://api.haodian.cn/plan/syt/subscribemsg + */ + public function subscribemsg() + { + $this->load->model('market/market_sylive_subscribemsg_model','mdSytSubscribemsg'); + $date = date('Y-m-d H:i:s', strtotime('+2 minute'));//提前2分钟发送 + $where['s_time<='] = $date; + $where['status'] = 0; + $res = $this->mdSytSubscribemsg->select($where, 'id asc', 1, 200); + $log = array(); + if ($res) { + $this->load->model('market/market_sylive_activity_model','mdSytActivity'); + $wechatS = new WechatServer($this->options); + $wechatS->checkAuth(); + foreach ($res as $key => $value) { + $re_a = $this->mdSytActivity->get(array("activityId" => $value['a_id'], "status" => 0)); + if ($re_a) { + $content = '您预约“' . $re_a['title'] . '”直播已经开始啦!赶紧进入直播间观看直播领取福利吧~'; + $temp_arr = array( + 'touser' => $value['openid'], + 'template_id' => $value['template_id'], + 'url' => $value['url'], + 'scene' => $value['scene'], + 'title' => '开播提醒', + 'data' => array( + 'content' => array('value' => $content) + ) + ); + $re = $wechatS->subscribeTemplateMessage($temp_arr); + if ($re) {//errcode 0(发送成功) 43101(已发送过) + $this->mdSytSubscribemsg->update(['status' => 1], ['id' => $value['id']]); + if ($re['errcode'] == 0) { + $log[] = $value['a_id'] . '=' . $value['openid']; + } + } + } + } + } + echo '
数据库获取:'; + echo json_encode($res, JSON_UNESCAPED_UNICODE); + echo '

成功发送:'; + $log && print_r($log); + $total = count($res); + $do = count($log); + debug_log("[info] " . __FUNCTION__ . "# date:{$date}; total:{$total}; do:{$do};", $this->log_file); + } + + public function test(){ + require_once(COMMPATH . "/third_party/WeChat/WechatServer.php"); + $options = [ + 'token' => '', + 'appid' => 'wxe66f905683582780', + 'appsecret' => '9546cd4de877be13ce203f3e6140633f', + 'encodingaeskey' => '', + 'debug' => false + ]; + $wechatS = new WechatServer($options); + $token = $wechatS->checkAuth(); + $content = '您预约直播已经开始啦!赶紧进入直播间观看直播领取福利吧~'; + $temp_arr = array( + 'touser' => 'ospBg6AXMlXNdgv_rzbFvBXAD4TU', + 'template_id' => '4eHuGYK69_GTjOlzkp8HK8iJNFuKboTpO7Igc1CC_fQ', + 'url' => 'https://liche-dev.xiaoyu.com/h5/market/sylive/act?skey=aWQ9MQ', + 'scene' => 0, + 'title' => '开播提醒', + 'data' => array( + 'content' => array('value' => $content) + ) + ); + $re = $wechatS->subscribeTemplateMessage($temp_arr); + } + +} \ No newline at end of file diff --git a/api/third_party/WXconfig/liche_home_WxPay.Config.php b/api/third_party/WXconfig/liche_home_WxPay.Config.php new file mode 100755 index 00000000..1883e2ee --- /dev/null +++ b/api/third_party/WXconfig/liche_home_WxPay.Config.php @@ -0,0 +1,29 @@ + 'browse', 'subscribe' => 'subscribe', 'order' => 'orderTotal','watch' => 'watch' + ]; + + public function __construct(){ + $this->ci = &get_instance(); + $this->ci->load->model('market/market_sylive_user_model', 'user_model'); + $this->ci->load->model('market/market_sylive_activity_model'); + $this->ci->load->model('market/market_sylive_activity_biz_model','mdSytActivityBiz'); + $this->ci->load->model('market/market_sylive_activity_kpidata_model','mdSytActivityKpiData'); + $this->ci->load->model('market/market_sylive_organization_model'); + } + + /** + * @param $organizationId 机构id + * @param $level 0品牌-管理大区 1 督导-权限范围内所有门店 2 店长-门店所有权限 3 顾问-个人权限 4普通用户-没有权限 + * @return int|mixed + */ + public function get_level($organizationId,$level=0){ + if(!$organizationId){ + return 4; + } + $row = $this->ci->market_sylive_organization_model->get(['organizationId'=>$organizationId],'organizationId,parentId'); + if(!$row){ + return 4; + } + if($row['parentId']){ + $temp = $level+1; + return $this->get_level($row['parentId'],$temp); + } + return $level; + } + + /** + * 获取等级数据 + * @param $organizationId + * @param $data + * @return int + */ + public function get_level_lists($organizationId,$data=[]){ + $this->ci->load->model('market/market_sylive_organization_model'); + $row = $this->ci->market_sylive_organization_model->get(['organizationId'=>$organizationId],'organizationId,parentId,organizationName'); + if(!$row){ + return $data; + }else{ + array_unshift($data,$row); + if($row['parentId']){ + return $this->get_level_lists($row['parentId'],$data); + }else{ + return $data; + } + } + } + + /** + * Notes:添加kpi记录 + * Created on: 2021/1/13 11:20 + * Created by: dengbw + * @param $params + * @return array + */ + public function kpi_log($params) + { + if ($params['a_id'] && $params['uid'] && $params['cf_uid']) { + $user = $this->user_model->get(['userId'=>$params['cf_uid']]); + if(!$user){ + return array('code' => 0, 'msg' => '顾问不存在'); + } + $re_a = $this->ci->market_sylive_activity_model->get(array("activityId" => $params['a_id'], "status" => 0)); + $now_time = time(); + if(!in_array($params['kpi'],['subscribe','browse'])){ //无需活动开始 + if ((!$re_a || $now_time < strtotime($re_a['timeStart']) || $now_time > strtotime($re_a['timeEnd']))) { + return array('code' => 0, 'msg' => '无活动或未在活动时间内'); + } + } + $re_kpi = $this->ci->mdSytActivityKpiData->get(array("a_id" => $params['a_id'], 'uid' => $params['uid'], 'kpi' => $params['kpi'])); + if ($re_kpi) {//已添加过活动kpi(访活动只记录一次用户kpi记录) + return array('code' => 0, 'msg' => '已添加过' . $params['kpi'] . '记录'); + } + $level_lists = $this->get_level_lists($user['organizationId']); + if($level_lists){ + //获取大区id + $area_id = $level_lists[1]['organizationId']; + //获取店铺id + $biz_id = $level_lists[2]['organizationId']; + } + //增加记录 + $addData = [ + 'a_id' => $params['a_id'], + 'uid' => $params['uid'], + 'cf_uid' => $params['cf_uid'], + 'kpi' => $params['kpi'], + 'c_time' => time() + ]; + $area_id && $addData['area_id'] = $area_id; + $biz_id && $addData['biz_id'] = $biz_id; + $jsondata = array(); + $jsondata && $addData['jsondata'] = json_encode($jsondata, JSON_UNESCAPED_UNICODE); + $id = $this->ci->mdSytActivityKpiData->add($addData); + if (!$id) { + return array('code' => 0, 'msg' => '添加记录失败'); + } + if($this->map_kpi_biz[$params['kpi']] && $biz_id){//更新门店统计数据 + $up_key = $this->map_kpi_biz[$params['kpi']]; + $update[$up_key] = $this->ci->mdSytActivityKpiData->count(['a_id'=>$params['a_id'],'biz_id'=>$biz_id,'kpi'=>$params['kpi']]); + $this->ci->mdSytActivityBiz->update($update,['activityId'=>$params['a_id'],'bizId'=>$biz_id]); + } + return array('code' => 1, 'msg' => '添加记录成功'); + } else { + return array('code' => 0, 'msg' => '参数错误'); + } + } + + //排行数据 + public function top_lists($aid,$type='browse',$page=1,$size=10,$biz_id=0){ + $lists = []; + $where = [ + 'activityId' => $aid, + 'status' => 0 + ]; + $total = $this->ci->mdSytActivityBiz->count($where); + $field = $this->map_kpi_biz[$type]; + if($total && $field){ + $rows = $this->ci->mdSytActivityBiz->select($where,"{$field} desc",$page,$size); + $biz_ids = implode(',',array_column($rows,'bizId')); + $org_rows = []; + if($biz_ids){ + $org_rows = $this->ci->market_sylive_organization_model->map('organizationId','organizationName',["organizationId in ($biz_ids)"],'','','','organizationId,organizationName'); + } + foreach ($rows as $key=>$val) { + $lists[] = [ + 'ranking' => $key+1, + 'name' => $org_rows[$val['bizId']] ? $org_rows[$val['bizId']] : '', + 'num' => $val[$this->map_kpi_biz[$type]].'人', + 'tip' => $biz_id==$val['bizId'] ? '本店' : '', + ]; + } + } + $data = [ + 'total' => $total, + 'lists' => $lists + ]; + return $data; + } + + public function __get($name) + { + if ('_model' === substr($name, -6)) { + return $this->ci->$name; + } elseif ('load' == $name) { + return $this->ci->load; + } + return null; + } +} \ No newline at end of file diff --git a/common/models/market/Market_sylive_activity_biz_model.php b/common/models/market/Market_sylive_activity_biz_model.php new file mode 100644 index 00000000..e578ea3c --- /dev/null +++ b/common/models/market/Market_sylive_activity_biz_model.php @@ -0,0 +1,11 @@ +table_name, 'default'); + } +} \ No newline at end of file diff --git a/common/models/market/Market_sylive_activity_kpidata_model.php b/common/models/market/Market_sylive_activity_kpidata_model.php new file mode 100644 index 00000000..7d8bf35b --- /dev/null +++ b/common/models/market/Market_sylive_activity_kpidata_model.php @@ -0,0 +1,12 @@ +table_name, 'default'); + } +} \ No newline at end of file diff --git a/common/models/market/Market_sylive_activity_model.php b/common/models/market/Market_sylive_activity_model.php new file mode 100644 index 00000000..108babe3 --- /dev/null +++ b/common/models/market/Market_sylive_activity_model.php @@ -0,0 +1,18 @@ +table_name, 'default'); + } + +} \ No newline at end of file diff --git a/common/models/market/Market_sylive_activity_user_model.php b/common/models/market/Market_sylive_activity_user_model.php new file mode 100644 index 00000000..056d2740 --- /dev/null +++ b/common/models/market/Market_sylive_activity_user_model.php @@ -0,0 +1,11 @@ +table_name, 'default'); + } +} \ No newline at end of file diff --git a/common/models/market/Market_sylive_order_model.php b/common/models/market/Market_sylive_order_model.php new file mode 100644 index 00000000..881b15f3 --- /dev/null +++ b/common/models/market/Market_sylive_order_model.php @@ -0,0 +1,35 @@ +table_name, 'default'); + } + + /** + * Notes:支付状态 + * Created on: 2022/9/26 14:46 + * Created by: dengbw + * @param string $status + * @return array|mixed + */ + public function statusAry($status = '') + { + $arr = [0 => '未支付', 1 => '已支付']; + if (strlen($status)) { + return $arr[$status]; + } else { + return $arr; + } + } + +} \ No newline at end of file diff --git a/common/models/market/Market_sylive_organization_model.php b/common/models/market/Market_sylive_organization_model.php new file mode 100644 index 00000000..4ea875b5 --- /dev/null +++ b/common/models/market/Market_sylive_organization_model.php @@ -0,0 +1,17 @@ +table_name, 'default'); + } +} \ No newline at end of file diff --git a/common/models/market/Market_sylive_subscribemsg_model.php b/common/models/market/Market_sylive_subscribemsg_model.php new file mode 100644 index 00000000..177a97d8 --- /dev/null +++ b/common/models/market/Market_sylive_subscribemsg_model.php @@ -0,0 +1,12 @@ +table_name, 'default'); + } +} \ No newline at end of file diff --git a/common/models/market/Market_sylive_user_model.php b/common/models/market/Market_sylive_user_model.php new file mode 100644 index 00000000..cdfb3c40 --- /dev/null +++ b/common/models/market/Market_sylive_user_model.php @@ -0,0 +1,52 @@ +table_name, 'default'); + } + + /** + * Notes:用户角色 + * Created on: 2022/9/20 11:04 + * Created by: dengbw + * @param string $roleId + * @return array|mixed + */ + public function roleAry($roleId = '') + { + $arr = [1 => '品牌', 2 => '区域', 3 => '店长', 4 => '顾问']; + if (strlen($roleId)) { + return $arr[$roleId]; + } else { + return $arr; + } + } + + /** + * Notes:性别 + * Created on: 2022/9/21 14:34 + * Created by: dengbw + * @param string $sex + * @return array|mixed + */ + public function sexAry($sex = '') + { + $arr = [0 => '未知', 1 => '男', 2 => '女']; + if (strlen($sex)) { + return $arr[$sex]; + } else { + return $arr; + } + } + +} \ No newline at end of file diff --git a/common/models/market/Market_sys_admin_model.php b/common/models/market/Market_sys_admin_model.php new file mode 100644 index 00000000..a5253a86 --- /dev/null +++ b/common/models/market/Market_sys_admin_model.php @@ -0,0 +1,17 @@ +table_name, 'default'); + } +} \ No newline at end of file diff --git a/common/models/market/Market_sys_dictionary_data_model.php b/common/models/market/Market_sys_dictionary_data_model.php new file mode 100644 index 00000000..c23ae56e --- /dev/null +++ b/common/models/market/Market_sys_dictionary_data_model.php @@ -0,0 +1,17 @@ +table_name, 'default'); + } +} \ No newline at end of file diff --git a/common/models/market/Market_sys_dictionary_model.php b/common/models/market/Market_sys_dictionary_model.php new file mode 100644 index 00000000..068d0a57 --- /dev/null +++ b/common/models/market/Market_sys_dictionary_model.php @@ -0,0 +1,17 @@ +table_name, 'default'); + } +} \ No newline at end of file diff --git a/common/models/market/Market_sys_login_record_model.php b/common/models/market/Market_sys_login_record_model.php new file mode 100644 index 00000000..586157df --- /dev/null +++ b/common/models/market/Market_sys_login_record_model.php @@ -0,0 +1,17 @@ +table_name, 'default'); + } +} \ No newline at end of file diff --git a/common/models/market/Market_sys_menu_model.php b/common/models/market/Market_sys_menu_model.php new file mode 100644 index 00000000..33db7958 --- /dev/null +++ b/common/models/market/Market_sys_menu_model.php @@ -0,0 +1,17 @@ +table_name, 'default'); + } +} \ No newline at end of file diff --git a/common/models/market/Market_sys_operation_record_model.php b/common/models/market/Market_sys_operation_record_model.php new file mode 100644 index 00000000..e8aecea2 --- /dev/null +++ b/common/models/market/Market_sys_operation_record_model.php @@ -0,0 +1,17 @@ +table_name, 'default'); + } +} \ No newline at end of file diff --git a/common/models/market/Market_sys_role_model.php b/common/models/market/Market_sys_role_model.php new file mode 100644 index 00000000..67bfdec4 --- /dev/null +++ b/common/models/market/Market_sys_role_model.php @@ -0,0 +1,17 @@ +table_name, 'default'); + } +} \ No newline at end of file diff --git a/home/config/wechat.php b/home/config/wechat.php index cbe89dd2..b67009a0 100755 --- a/home/config/wechat.php +++ b/home/config/wechat.php @@ -9,4 +9,6 @@ if ( ! defined('BASEPATH')) exit('No direct script access allowed'); //狸车-服务号 $config['liche']['appid'] = 'wxe66f905683582780'; -$config['liche']['appSecret'] = '9546cd4de877be13ce203f3e6140633f'; \ No newline at end of file +$config['liche']['appSecret'] = '9546cd4de877be13ce203f3e6140633f'; +$config['liche']['token'] = 'iuvkjhz457854'; +$config['liche']['appsecret'] = 'Ay2qHzlKEpPxdMzUSy5bjJcyL5lZxotOf7JThlDKQdQ'; \ No newline at end of file diff --git a/home/controllers/h5/market/sylive/Act.php b/home/controllers/h5/market/sylive/Act.php new file mode 100644 index 00000000..47cf414d --- /dev/null +++ b/home/controllers/h5/market/sylive/Act.php @@ -0,0 +1,336 @@ +load->model('market/market_sylive_organization_model'); + $this->load->model('market/market_sylive_activity_model'); + $this->load->model('market/market_sylive_subscribemsg_model','mdSytSubscribemsg'); + $this->load->model('market/market_sylive_order_model'); + $this->load->library('market/sylive_entity'); + $this->group_id = $this->sylive_entity->get_level($this->session['org_id']); + } + + public function index(){ + $skey = $this->input->get('skey'); + if (!$skey) { + throw new Hd_exception("参数错误", 400); + } + $param = $this->myencryption->base64url_decode($skey); + $a_id = intval($param['a_id']);//活动id + if (!$a_id) { + throw new Hd_exception("参数错误", 400); + } + $row = $this->market_sylive_activity_model->get(['activityId'=>$a_id]); + if(!$row){ + throw new Hd_exception('参数错误',400); + } + $timeStart = strtotime($row['timeStart']); + $info['s_time'] = time() < $timeStart ? $timeStart-time() : 0; + $info['bg'] = $row['bgImg'] ? build_qiniu_image_url($row['bgImg']) : ''; + $info['content'] = $row['introduction']; + $act_user = $this->act_user_model->get(['userId'=>$this->uid,'activityId'=>$a_id]); + //一次性订阅 + $re_s = $this->mdSytSubscribemsg->get(array('a_id' => $a_id, 'uid' => $this->uid)); + if ($re_s) { + $subscribemsg = '已订阅直播'; + } else { + $this->load->config('wechat'); + $config = $this->config->item('liche'); + $sub_redirect_url = urlencode(http_host_com('home') . '/h5/market/sylive/act/subscribemsg?skey=' . $skey + . '&s_time=' . $row['timeStart']); + $subscribemsg = "https://mp.weixin.qq.com/mp/subscribemsg?action=get_confirm&appid={$config['appid']}&scene=0&template_id=sdJ4eXXA3OdMZVkJdOrzusYLGr0Jpz9I7WiZurgGLBs&redirect_url={$sub_redirect_url}&reserved=test#wechat_redirect"; + } + //浏览 + $params = array('a_id' => $a_id, 'uid' => $this->uid,'cf_uid' => $act_user['channelId'], 'kpi' => 'browse'); + $this->sylive_entity->kpi_log($params); + $live_status = 0; + if(time()>strtotime($row['timeStart']) && time()<=strtotime($row['timeEnd'])){ //直播期间人数 + $this->sylive_entity->kpi_log(['a_id' => $a_id, 'uid' => $this->uid,'cf_uid' => $act_user['channelId'], 'kpi' => 'watch']); + $row['liveStatus']!=1 && $this->market_sylive_activity_model->update(['liveStatus'=>1],['activityId'=>$a_id]); //更新直播间状态 + $live_status = 1; + } + if(time()>strtotime($row['timeEnd'])){ //直播结束 + $row['liveStatus']!=2 && $this->market_sylive_activity_model->update(['liveStatus'=>2],['activityId'=>$a_id]); //更新直播间状态 + $live_status = 2; + } + $share_skey = "a_id=" . $a_id . "&cf_uid=" . $this->uid . "&cf_share=" . $this->myencryption->random_string(6); + //微信分享 + $share_url = http_host_com('home') . "/h5/market/sylive/act?skey=" . $this->myencryption->base64url_encode($share_skey); + $this->load->library('Jssdk'); + $jssdk = new Jssdk('liche'); + $sign_package = $jssdk->getSignPackage(); + $share = array( + 'title' => $row['title'], + "img" => $row['bgImg'] ? build_qiniu_image_url($row['bgImg']) : '', + "desc" => '分享描述', + "url" => $share_url + ); + //直播参数 + $live_user = ['userId' => 888888888, 'userName' => '私域直播', 'pic' => '//livestatic.videocc.net/assets/wimages/missing_face.png']; + $this->load->library('PolyvApi'); + $polyv = new PolyvApi(); + $liveSdk = $polyv->getLiveSdk(); + $liveSdk['user'] = $live_user; + $info['live_status'] = $live_status; + $info['liveSdk'] = $liveSdk; + $info['skey'] = $this->myencryption->base64url_encode($share_skey); + $info['a_id'] = $a_id; + $info['org_id'] = $this->session['org_id']; + $info['subscribemsg'] = $subscribemsg; + $info['shareurl'] = $info['code'] = ''; + if($this->group_id==3||$this->group_id==2){ + $info['shareurl'] = '/h5/market/sylive/act/share?skey='.$info['skey']; + } + $info['statisticsurl'] = '/h5/market/sylive/stic?skey='.$info['skey']; + $info['channelImg'] = build_qiniu_image_url($row['channelImg']); + $this->data['info'] = $info; + $this->data['sign_package'] = $sign_package; + $this->data['share'] = $share; + $this->show_view('h5/market/sylive/act/index'); + } + + //获取最新订阅用户 + public function subscribemsg_lists(){ + $a_id = $this->input->get('a_id'); + $field = ''; + $lists = []; + $where = [ + 'a_id' => $a_id + ]; + $rows = $this->mdSytSubscribemsg->select($where,'id desc',0,30,$field); + if($rows){ + foreach ($rows as $item) { + $lists[] = [ + 'name' => substr($item['openid'], 0, 3) . "****" . substr($item['openid'], 7, 4), + 'tip' => friendly_date($item['c_time']).'订阅了直播提醒', + ]; + } + } + $data['lists'] = $lists; + $this->show_json($data,200); + } + + /** + * Notes:获取授权发送一次性订阅接口 + * Created on: 2020/11/26 17:11 + * Created by: dengbw + */ + public function subscribemsg() + { + $skey = $this->input->get('skey'); + $s_time = $this->input->get('s_time');//直播时间 + $param = $this->myencryption->base64url_decode($skey); + $a_id = intval($param['a_id']);//活动id + $action = $this->input->get('action'); + if ($s_time && $action == "confirm") { + $add_data['a_id'] = $a_id; + $add_data['openid'] = $this->input->get('openid'); + $add_data['scene'] = $this->input->get('scene'); + $re_s = $this->mdSytSubscribemsg->get($add_data); + if (!$re_s) { + $add_data['uid'] = $this->uid; + $add_data['template_id'] = $this->input->get('template_id'); + $add_data['url'] = http_host_com('home') . "/h5/market/sylive/act?skey=" . $this->myencryption->base64url_encode("a_id=" . $a_id);; + $add_data['s_time'] = $s_time; + $add_data['c_time'] = time(); + $add_data['status'] = 0; + $id = $this->mdSytSubscribemsg->add($add_data); + if ($id) { + $act_user = $this->act_user_model->get(['userId'=>$this->uid,'activityId'=>$a_id]); + //订阅用户加统计 + $params = array('a_id' => $a_id, 'uid' => $this->uid,'cf_uid' => $act_user['channelId'], 'kpi' => 'subscribe'); + $this->sylive_entity->kpi_log($params); + } + } + } + $url = http_host_com('home') . "/h5/market/sylive/act?skey={$skey}"; + redirect($url); + } + + public function share(){ + if($this->group_id!=2 && $this->group_id!=3){ + throw new Hd_exception("页面不存在", 400); + } + $skey = $this->input->get('skey'); + if (!$skey) { + throw new Hd_exception("参数错误", 400); + } + $param = $this->myencryption->base64url_decode($skey); + $a_id = intval($param['a_id']);//活动id + $row = $this->market_sylive_activity_model->get(['activityId'=>$a_id]); + if(!$row){ + throw new Hd_exception('参数错误',400); + } + $shareImg = json_decode($row['shareImg'],true); + $shareTitle = $row['shareTitle'] ? json_decode($row['shareTitle'],true) : []; + $lists = []; + if($shareImg){ + $share_skey = "a_id=" . $a_id . "&cf_uid=" . $this->uid . "&cf_share=" . $this->myencryption->random_string(6); + $share_url = http_host_com('home') . "/h5/market/sylive/act?skey=" . $this->myencryption->base64url_encode($share_skey); + $qr_code = '/h5/market/sylive/myqrcode/get?url=' . $share_url; + foreach ($shareImg as $item) { + $lists[] = [ + "img" => build_qiniu_image_url($item), + "code" => $qr_code, + 'width' => 750, + 'height' => 1130, + ]; + } + } + $user = $this->user_model->get(['userId'=>$this->uid]); + $this->data['posterTip'] = '狸车集美店李菲菲诚挚邀请您参与'; + $this->data['lists'] = $lists; + $this->data['shareTitle'] = $shareTitle; + $this->show_view('h5/market/sylive/act/share'); + } + + public function item(){ + $skey = $this->input->get('skey'); + $param = $this->myencryption->base64url_decode($skey); + $a_id = intval($param['a_id']);//活动id + $row = $this->market_sylive_activity_model->get(['activityId'=>$a_id]); + if(!$row){ + throw new Hd_exception('参数错误',400); + } + $jsondata = json_decode($row['jsondata'],true); + $item = $jsondata['item'] ? $jsondata['item'] : []; + $is_pay = $this->market_sylive_order_model->count(['item_id'=>$a_id,'status'=>1,'uid'=>$this->uid]); + $e_time = time() < strtotime($row['timeEnd']) ? strtotime($row['timeEnd']) - time() : 0; + $banner = []; + if($item['itemImg']){ + foreach ($item['itemImg'] as $value) { + $banner[] = build_qiniu_image_url($value); + } + } + $info = [ + 'title' => $item['title'] ? $item['title'] : '', + 'e_time' => $e_time, + 'price' => $item['price'] ? $item['price'] : '', + 'content' => $item['introduction'] ? $item['introduction'] : '', + 'banner' => $banner, + 'skey' => $skey, + 'is_pay' => $is_pay + ]; + $this->data['info'] = $info; + $this->show_view('h5/market/sylive/act/item'); + } + + //支付 + public function post_pay(){ + $skey = $this->input->post('skey'); + $param = $this->myencryption->base64url_decode($skey); + $a_id = intval($param['a_id']);//活动id + $row = $this->market_sylive_activity_model->get(['activityId'=>$a_id]); + if(!$row){ + $this->show_json('',400,'参数错误'); + } + $jsondata = json_decode($row['jsondata'],true); + $item = $jsondata['item'] ? $jsondata['item'] : []; + //判断是否已支付 + $o_row = $this->market_sylive_order_model->get(['item_id'=>$a_id,'status'=>1,'uid'=>$this->uid]); + if($o_row){ + $this->show_json('',400,'已支付,请勿重复支付'); + } + $pay_price = $item['price']; + if($pay_price<=0){ + $this->show_json('',400,'无需支付'); + } + $unpay = $this->market_sylive_order_model->get(['item_id'=>$a_id,'status'=>0,'uid'=>$this->uid,'expire_time>'=>time()]); + if(!$unpay){ + $this->load->helper('order'); + $unpay = [ + 'sid' => create_order_no(), + 'uid' => $this->uid, + 'item_id' => $a_id, + 'item_title' => $item['title'], + 'total_price' => $pay_price, + 'expire_time' => time()+24*60*60,//订单过期时间 + 'createTime' => date('Y-m-d H:i:s') + ]; + $oid = $this->market_sylive_order_model->add($unpay); + if(!is_numeric($oid)){ + $this->show_json('',400,'创建订单失败'); + } + } + $user = $this->user_model->get(['userId'=>$this->uid]); + $notify_url = http_host_com('home').'//h5/market/sylive/notify'; + $result = $this->pay($unpay['sid'],$unpay['total_price'],$user['openid'],$unpay['item_title'],$notify_url,$unpay['expire_time']); + if(!$result['code']){ + $this->show_json('',400,$result['msg']); + } + $this->show_json($result['data'],200,'操作成功'); + } + public function ucenter(){ + $skey = $this->input->get('skey'); + $param = $this->myencryption->base64url_decode($skey); + $a_id = intval($param['a_id']);//活动id + $row = $this->market_sylive_activity_model->get(['activityId'=>$a_id]); + if(!$row){ + throw new Hd_exception('参数错误',400); + } + $jsondata = json_decode($row['jsondata'],true); + $item = $jsondata['item'] ? $jsondata['item'] : []; + $banner = []; + if($item['itemImg']){ + foreach ($item['itemImg'] as $value) { + $banner[] = build_qiniu_image_url($value); + } + } + $order = $this->market_sylive_order_model->get(['uid'=>$this->uid,'status'=>1,'item_id'=>$a_id]); + $pay_text = $order ? '(已支付)' : '(未支付)'; + $info = [ + 'title' => $item['title'].$pay_text, + 'content' => $item['introduction'], + 'banner' => $banner, + ]; + $this->data['info'] = $info; + $this->show_view('h5/market/sylive/act/ucenter'); + } + + /** + * 支付 + * @param $trade_no + * @param $price + * @param $openid + * @param $body + * @param $notify_url 异步通知 + * @param $expire_time 过期时间 + * @param $attach + * @return bool|json数据,可直接填入js函数作为参数|mixed + * @throws WxPayException + */ + private function pay($trade_no,$price,$openid,$body,$notify_url,$expire_time,$attach=''){ + + if(!$body){return false;} + require_once APPPATH."../api/third_party/WXconfig/liche_home_WxPay.Config.php"; + require_once APPPATH."../api/third_party/WXpay/WxPay.Api.php"; + $config = new WxPayConfig(); + $wxpay = new WxPayUnifiedOrder(); + $wxpay->SetVersion('1.0'); + $wxpay->SetBody($body); //简单描述 + $attach && $wxpay->SetAttach($attach); //附加信息 + $wxpay->SetNotify_url($notify_url); + $wxpay->SetOut_trade_no($trade_no); //订单号 + $wxpay->SetTotal_fee($price * 100); //支付价格 + $wxpay->SetTime_start(date("YmdHis")); //交易起始时间 + $wxpay->SetTime_expire(date('YmdHis',$expire_time)); //交易结束时间 + $wxpay->SetTrade_type("JSAPI"); //设置交易类型 + $wxpay->SetOpenid($openid); //openid + $return = WxPayApi::unifiedOrder($config, $wxpay); //统一支付 + if($return['result_code'] == 'SUCCESS') { + $wxpay_api = new WxPayJsApiPay(); + $jsApiParameters = WxPayApi::GetJsApiParameters($return, $config, $wxpay_api); + $jsApiParameters = json_decode($jsApiParameters, true); + return ['code'=>1,'data'=>$jsApiParameters,'msg'=>'下单成功']; + }else{ + $msg = $return['return_msg'] ? $return['return_msg'].$return['err_code_des'] : $return['return_msg']; + return ['code'=>0,'data'=>[],'msg'=>$msg]; + } + } +} diff --git a/home/controllers/h5/market/sylive/Biz.php b/home/controllers/h5/market/sylive/Biz.php new file mode 100644 index 00000000..afcbaa70 --- /dev/null +++ b/home/controllers/h5/market/sylive/Biz.php @@ -0,0 +1,266 @@ +load->model('market/market_sylive_organization_model'); + $this->load->model('market/market_sylive_activity_model'); + $this->load->model('market/market_sylive_activity_kpidata_model','mdSytActivityKpiData'); + $this->load->library('market/sylive_entity'); + $this->load->library('MyEncryption'); + $this->group_id = $this->sylive_entity->get_level($this->session['org_id']); + } + + public function index(){ + if($this->group_id>3){ + throw new Hd_exception('权限不足',400); + } + $this->data['area_id'] = $this->input->get('area_id'); + $this->data['biz_id'] = $biz_id = $this->input->get('biz_id'); + $this->data['group_id'] = $this->group_id; + $row = $this->market_sylive_organization_model->get(['organizationId'=>$biz_id]); + $this->data['headimg'] = $this->liche_img; + $this->data['biz_name'] = $row['organizationName']; + $this->show_view('h5/market/sylive/biz/index'); + } + + //店铺列表 + public function lists(){ + if($this->group_id>1){ + throw new Hd_exception('权限不足',400); + } + $area_id = $this->input->get('area_id'); + $this->data['area_id'] = $area_id; + $this->data['group_id'] = $this->group_id; + $this->show_view('h5/market/sylive/biz/lists'); + } + //大区列表 + public function brands(){ + if($this->group_id!=0){ + throw new Hd_exception('权限不足',400); + } + $this->show_view('h5/market/sylive/biz/brands'); + } + //顾问 + public function detail(){ + if($this->group_id!=3){ + throw new Hd_exception('权限不足',400); + } + $this->show_view('h5/market/sylive/biz/detail'); + } + public function nav(){ + if($this->group_id>1){ + $this->show_json([],200); + } + $area_id = $this->input->get('area_id'); + $user = $this->user_model->get(['userId'=>$this->uid]); + $data = [ + 'nickname' => $user['nickname'], + 'headimg' => $this->liche_img + ]; + if($this->group_id==1 || $area_id){ //所有店铺 + !$area_id && $area_id = $this->session['org_id']; + $where = [ + 'status' => 0, + "parentId" => $area_id + ]; + $count_biz = $this->market_sylive_organization_model->count($where); //门店 + $where = [ + 'status' => 0, + "organizationId in (select organizationId from lc_market_sylive_organization where + parentId in (select organizationId from lc_market_sylive_organization where parentId={$area_id} and status=0) + )" => null + ]; + $count_gw = $this->user_model->count($where); //顾问 + $where = [ + 'status' => 0, + "activityId in (select activityId from lc_market_sylive_activity_biz where areaId={$area_id})" => null + ]; + $count_live = $this->market_sylive_activity_model->count($where); + $where = [ + 'kpi' => 'order', + "area_id" => $area_id + ]; + $count_order = $this->mdSytActivityKpiData->count($where); + $count = [ + ['title' => '门店','num' => $count_biz,'icon' => 'icon-quyu'], + ['title' => '顾问','num' => $count_gw,'icon' => 'icon-mendian'], + ['title' => '活动','num' => $count_live,'icon' => 'icon-zhibo'], + ['title' => '订单','num' => $count_order,'icon' => 'icon-dingdan'], + ]; + $tab = [ + ['id' => 1, 'title' => '门店',], + ['id' => 2, 'title' => '活动',], + ]; + }else{ //所有大区 + $count_dq = $this->market_sylive_organization_model->count(['parentId'=>$this->session['org_id'],'status'=>0]); + $where = [ + 'status' => 0, + "parentId in (select organizationId from lc_market_sylive_organization where parentId={$this->session['org_id']} and status=0) and status=0" => null + ]; + $count_biz = $this->market_sylive_organization_model->count($where); + $where = [ + 'status' => 0, + "activityId in (select activityId from lc_market_sylive_activity_biz where + areaId in (select organizationId from lc_market_sylive_organization where parentId={$this->session['org_id']} and status=0) + )" => null + ]; + $count_live = $this->market_sylive_activity_model->count($where); + $where = [ + 'kpi' => 'order', + " area_id in (select organizationId from lc_market_sylive_organization where parentId={$this->session['org_id']} and status=0)" => null + ]; + $count_order = $this->mdSytActivityKpiData->count($where); + $count = [ + ['title' => '区域','num' => $count_dq], + ['title' => '门店','num' => $count_biz], + ['title' => '活动','num' => $count_live], + ['title' => '订单','num' => $count_order], + ]; + $tab = [ + ['id' => 1, 'title' => '区域',], + ['id' => 2, 'title' => '活动',], + ]; + } + $data['count'] = $count; + $data['tab'] = $tab; + $this->show_json($data,200); + } + + //大区列表 + public function area_lists(){ + $page = $this->input->get('page'); + !$page && $page = 1; + $size = 10; + $where = [ + 'parentId' => $this->session['org_id'], + 'status' => 0, + ]; + $total = $this->market_sylive_organization_model->count($where); + $lists = []; + if($total){ + $rows = $this->market_sylive_organization_model->select($where,'sortNumber desc',$page,$size,'organizationId,parentId,organizationName'); + foreach ($rows as $val) { + $where = [ + 'status' => 0, + "activityId in (select activityId from lc_market_sylive_activity_biz where areaId={$val['organizationId']})" => null + ]; + $activitynum = $this->market_sylive_activity_model->count($where); + $temp = [ + 'title' => $val['organizationName'], + 'storenum' => $this->market_sylive_organization_model->count(['parentId'=>$val['organizationId'],'status'=>0]), + 'activitynum' => $activitynum, + 'url' => '/h5/market/sylive/biz/lists?area_id='.$val['organizationId'], + 'state' => [], + ]; + $lists[] = $temp; + } + } + $data['list'] = $lists; + $data['total'] = $total; + $this->show_json($data,200); + } + //门店列表 + public function biz_lists(){ + $area_id = $this->input->get('area_id'); + !$area_id && $area_id = 0; + $page = $this->input->get('page'); + !$page && $page = 1; + $size = 10; + $where = [ + 'status' => 0, + ]; + if($this->group_id==1){ + $where['parentId'] = $this->session['org_id']; + }else{ + $where['parentId'] = $area_id; + } + $total = $this->market_sylive_organization_model->count($where); + $lists = []; + if($total){ + $rows = $this->market_sylive_organization_model->select($where,'sortNumber desc',$page,$size,'organizationId,parentId,organizationName'); + foreach ($rows as $val) { + $where = [ + 'status' => 0, + "activityId in (select activityId from lc_market_sylive_activity_biz where bizId={$val['organizationId']})" => null + ]; + $activitynum = $this->market_sylive_activity_model->count($where); + $temp = [ + 'title' => $val['organizationName'], + 'storenum' => $this->user_model->count(['organizationId'=>$val['organizationId'],'status'=>0]), //顾问 + 'activitynum' => $activitynum, + 'url' => '/h5/market/sylive/biz?biz_id='.$val['organizationId'].'&area_id='.$area_id, + 'state' => [], + ]; + $lists[] = $temp; + } + } + $data['list'] = $lists; + $data['total'] = $total; + $this->show_json($data,200); + } + //活动列表 + public function act_list(){ + $area_id = $this->input->get('area_id'); + $biz_id = $this->input->get('biz_id'); + $page = $this->input->get('page'); + !$page && $page = 1; + $size = 10; + $where = [ + 'status' => 0, + ]; + if($this->group_id==3){ //顾问 + $where["activityId in (select activityId from lc_market_sylive_activity_biz where + bizId in (select parentId from lc_market_sylive_organization where organizationId={$this->session['org_id']} and status=0) + )"] = null; + }elseif($this->group_id==2){ //当前店铺 + $where["activityId in (select activityId from lc_market_sylive_activity_biz where bizId={$this->session['org_id']})"] = null; + }elseif($this->group_id==1) { //所有店铺 + $where["activityId in (select activityId from lc_market_sylive_activity_biz where areaId={$this->session['org_id']})"] = null; + }elseif(!$this->group_id && $biz_id){ + $where["activityId in (select activityId from lc_market_sylive_activity_biz where bizId={$biz_id})"] = null; + }elseif (!$this->group_id && $area_id) { + $where["activityId in (select activityId from lc_market_sylive_activity_biz where areaId={$area_id} and status=0)"] = null; + }else{ //所有大区 + $where["activityId in (select activityId from lc_market_sylive_activity_biz where + areaId in (select organizationId from lc_market_sylive_organization where parentId={$this->session['org_id']} and status=0) + )"] = null; + } + $total = $this->market_sylive_activity_model->count($where); + $lists = []; + if($total){ + $rows = $this->market_sylive_activity_model->select($where,'timeStart desc',$page,$size,'activityId,title,timeStart,timeEnd'); + foreach ($rows as $val) { + $s_time = strtotime($val['timeStart']); + $e_time = strtotime($val['timeEnd']); + $n_time = time(); + if($n_time>=$s_time&&$n_time<=$e_time){ + $state = ['title'=>'活动进行中','class'=>'bg-fe9538']; + }elseif($n_time<$s_time){ + $state = ['title'=>'活动预热中','class'=>'bg-ff5a5a']; + }else{ + $state = ['title'=>'活动已结束','class'=>'bg-fccba0']; + } + $skey = $this->myencryption->base64url_encode("a_id=" . $val['activityId']); + $temp = [ + 'title' => $val['title'], + 'time' => date('Y-m-d',$s_time).'~'.date('Y-m-d',$e_time), + 'url' => '/h5/market/sylive/act?skey='.$skey, + 'state' => $state, + ]; + $lists[] = $temp; + } + } + $data['list'] = $lists; + $data['total'] = $total; + $this->show_json($data,200); + } + + +} \ No newline at end of file diff --git a/home/controllers/h5/market/sylive/Common.php b/home/controllers/h5/market/sylive/Common.php new file mode 100644 index 00000000..7e1cf64c --- /dev/null +++ b/home/controllers/h5/market/sylive/Common.php @@ -0,0 +1,198 @@ +load->helper('cookie'); + $this->load->model('market/market_sylive_user_model', 'user_model'); + $this->load->model('market/market_sylive_activity_user_model', 'act_user_model'); + + $this->load->library('hd_exception'); + $this->load->library('MyEncryption'); + $ukey = get_cookie('ukey'); + if ($ukey) { + $this->session = json_decode(liche_authcode($ukey, 'DECODE', $this->secret), true); + $this->uid = $this->session['uid']; + } + } + + /** + * @param $view + */ + protected function show_view($view){ + $this->load->view('h5/market/sylive/header',$this->data); + $this->load->view($view); + $this->load->view('h5/market/sylive/footer'); + } + + /** + * @param $data + * @param int $code + * @param string $msg + * @param string $url + */ + protected function show_json($data, $code = 200, $msg = 'success', $url = '') + { + if(!isset($data['code'])){ + $data = array('data' => $data, 'code' => $code, 'msg' => $msg, 'url' => $url); + } + + exit(json_encode($data)); + } + + /** + * @param $url 回调url地址 + * @param $auth 是否信息授权 + * @return void + * @throws Hd_exception + */ + protected function set_auth($url='',$auth=0){ + $this->load->helper('url'); + $this->load->config('wechat'); + $config = $this->config->item('liche'); + $code = $this->input->get('code'); + !$url && $url = http_host_com('home').$_SERVER['REQUEST_URI']; + $auth && $url = $_SERVER['QUERY_STRING'] ? $url."&auth={$auth}" : $url."?auth={$auth}"; + if ($code) {//授权码获取微信信息 + $auth_url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid={$config['appid']}&secret={$config['appSecret']}&code={$code}&grant_type=authorization_code"; + $res = file_get_contents($auth_url); + $ret = json_decode($res, true); + $access_token = $ret['access_token']; + $openid = $ret['openid']; + $unionid = $ret['unionid']; + if($this->input->get('auth') && $access_token){ + $u_info_url = "https://api.weixin.qq.com/sns/userinfo?access_token={$access_token}&openid={$openid}&lang=zh_CN"; + $u_ret = file_get_contents($u_info_url); + $ret = json_decode($u_ret,true); + } + if(!$openid){ + debug_log("[error]# " . $res, __FUNCTION__, $this->log_dir); + throw new Hd_exception('获取用户信息失败', 400); + } + return $ret; + } elseif ($auth) {//信息授权获取用户微信昵称/头像 + $redirect_uri = urlencode($url); + $auth_url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid={$config['appid']}&redirect_uri={$redirect_uri}&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect&forcePopup=true"; + redirect($auth_url); + } elseif (!$this->session) {//静默授权获取用户openid + $redirect_uri = urlencode($url); + $auth_url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid={$config['appid']}&redirect_uri={$redirect_uri}&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect"; + redirect($auth_url); + } + } +} + +class Admin extends Common{ + const WX_SESSION = "market_wx_info"; + public function __construct(){ + parent::__construct(); + session_start(); + } + + public function _remap($method){ + try{ + if(!in_array($method,$this->white_login_method) && !$this->uid){ + $ret = $this->set_auth('',1); + $openid = $ret['openid']; + $row_wechat = $this->user_model->get(['openid' => $openid,'organizationId>'=>0,'status>='=>0]); + if(!$row_wechat){ + $_SESSION[self::WX_SESSION] = $ret; + header('Location:/h5/market/sylive/login');exit; + } + if($row_wechat['status']){ + throw new Hd_exception('该账户禁用', 400); + } + $this->uid = $row_wechat['userId']; + $session = ['uid' => $this->uid,'org_id'=>$row_wechat['organizationId']]; + $ukey = liche_authcode(json_encode($session, JSON_UNESCAPED_UNICODE), 'ENCODE', $this->secret); + set_cookie("ukey", $ukey, 86400 * 30); + $this->session = $session; + } + return $this->$method(); + } catch(Hd_exception $e){//处理异常 +// $code = $e->getCode(); + $msg = $e->getMessage(); + $data = array('heading' => 'Warning', 'message' => $msg); + return $this->load->view('errors/html/error_404',$data); + } + } + +} + +class Wx extends Common{ + public function __construct(){ + parent::__construct(); + } + + public function _remap($method){ + try{ + if(!in_array($method,$this->white_login_method) && !$this->uid){ + $ret = $this->set_auth('',1); + $openid = $ret['openid']; + $row_wechat = $this->user_model->get(['openid' => $openid,'status>='=>0]); + if($row_wechat['status']){ + throw new Hd_exception('该账户禁用', 400); + } + if(!$row_wechat){ //创建用户 + $add = array( + "openid" => $openid, + "sex" => $ret['sex'] ? 1 : 0, + "createTime" => date('Y-m-d H:i:s') + ); + $ret['nickname'] && $add['nickname'] = strval($ret['nickname']); + $ret['headimgurl'] && $add['headimg'] = strval($ret['headimgurl']); + $ret['unionid'] && $add['unionid'] = $ret['unionid']; + $this->uid = $this->user_model->add($add); + $row_wechat['organizationId'] = 0; + if (!$this->uid) { + debug_log("[error]# " . $this->mdWeixinUsers->db->last_query(), __FUNCTION__, $this->log_dir); + } + }else{ + $this->uid = $row_wechat['userId']; + } + $skey = $this->input->get('skey'); + $param = $this->myencryption->base64url_decode($skey); + $act_user = $this->act_user_model->get(['activityId'=>$param['a_id'],'userId'=>$this->uid]); + if(!$act_user && $param['a_id']){ + $act_data = [ + 'activityId' => $param['a_id'], + 'userId' => $this->uid, + "createTime" => date('Y-m-d H:i:s') + ]; + if($param['cf_uid']){ + $p_user = $this->user_model->get(['userId'=>$param['cf_uid']],'userId,organizationId'); + $p_act_user = $this->act_user_model->get(['userId'=>$param['cf_uid']],'userId,channelId'); + $p_act_user['channelId'] && $act_data['channelId'] = $p_act_user['channelId']; + if(!$p_user['channelId'] && $p_user['organizationId']>0){ + $act_data['channelId'] = $p_user['userId']; + } + $act_data['pid'] = $p_user['userId']; + } + $this->act_user_model->add($act_data); + } + $session = ['uid' => $this->uid,'org_id'=>$row_wechat['organizationId']]; + $ukey = liche_authcode(json_encode($session, JSON_UNESCAPED_UNICODE), 'ENCODE', $this->secret); + set_cookie("ukey", $ukey, 86400 * 30); + $this->session = $session; + } + return $this->$method(); + } catch(Hd_exception $e){//处理异常 +// $code = $e->getCode(); + $msg = $e->getMessage(); + $data = array('heading' => 'Warning', 'message' => $msg); + return $this->load->view('errors/html/error_404',$data); + } + } +} diff --git a/home/controllers/h5/market/sylive/Login.php b/home/controllers/h5/market/sylive/Login.php new file mode 100644 index 00000000..26e502c2 --- /dev/null +++ b/home/controllers/h5/market/sylive/Login.php @@ -0,0 +1,99 @@ +load->helper('cookie'); + $this->load->model('market/market_sylive_user_model', 'user_model'); + } + + public function index(){ + if($this->input->is_ajax_request()){ + $redis = &load_cache('redis'); + $code = $this->input->post('code'); + $mobile = $this->input->post('mobile'); + $key = "sylive_login_code_".$mobile; + if(!$code || $code!=$redis->get($key)){ + $this->show_json('',400,'请输入正确的验证码'); + } + $user=$this->user_model->get(array('mobile' => $mobile,'organizationId>'=>0)); + if($user['status']){ + $this->show_json('',400,'用户已禁用'); + } + $this->bind_openid($user); + $session = ['uid' => $user['userId'],'org_id'=>$user['organizationId']]; + $ukey = liche_authcode(json_encode($session, JSON_UNESCAPED_UNICODE), 'ENCODE', $this->secret); + set_cookie("ukey", $ukey, 86400 * 30); + $this->show_json('',200,'登录成功'); + }else{ + $this->load->view('h5/market/sylive/login'); + } + } + //绑定微信openid + private function bind_openid($user){ + $wx_info = $_SESSION[self::WX_SESSION]; + if(!$wx_info['openid']){ + return ['code' => 0,'msg' => '不存在公众号信息,无需绑定']; + } + if($user['openid']){ + return ['code' => 0,'msg' => '该用户已绑定公众号']; + } + $is_bind = $this->user_model->count(['openid'=>$wx_info['openid'],'organizationId>'=>0,'status>='=>0]); //是否绑定 + if($is_bind){ + return ['code' => 0,'msg' => '该公众号已存在绑定账号']; + } + $update = [ + 'openid' => $wx_info['openid'] + ]; + $wx_info['nickname'] && $update['nickname'] = strval($wx_info['nickname']); + $wx_info['headimgurl'] && $update['headimg'] = strval($wx_info['headimgurl']); + $wx_info['unionid'] && $update['unionid'] = $wx_info['unionid']; + $this->user_model->update($update,['userId'=>$user['userId']]); + //删除普通账户 + $this->user_model->update(['status'=>-1],['openid'=>$wx_info['openid'],'organizationId'=>0,'status>='=>0]); + return ['code' => 1,'msg' => '绑定成功']; + } + //获取验证码 + public function get_code(){ + $mobile = $this->input->post('mobile'); + if(!mobile_valid($mobile)){ + $this->show_json('',400,'请输入正确的手机号码'); + } + $user=$this->user_model->get(array('mobile' => $mobile, 'status' => 0,'organizationId>'=>0)); + if(!$user){ + $this->show_json('',400,'用户不存在'); + } + if($user['status']){ + $this->show_json('',400,'用户已禁用'); + } + $redis = &load_cache('redis'); + $key = "sylive_login_code_".$mobile; + if(!$code = $redis->get($key)){ + $this->load->helper('string'); + $code = random_string('numeric', 4); + $redis->save($key, $code, 60*5); + } + send_sms($mobile, $code); + $this->show_json('',200, '验证码已发送'); + } + + private function show_json($data, $code = 200, $msg = 'success', $url = ''){ + if(!isset($data['code'])){ + $data = array('data' => $data, 'code' => $code, 'msg' => $msg, 'url' => $url); + } + + exit(json_encode($data)); + } + + public function test(){ + $this->load->library('market/sylive_entity'); + $oid = 1; + $req = $this->sylive_entity->get_level($oid); + print_r($req); + } +} \ No newline at end of file diff --git a/home/controllers/h5/market/sylive/Myqrcode.php b/home/controllers/h5/market/sylive/Myqrcode.php new file mode 100644 index 00000000..133b97b2 --- /dev/null +++ b/home/controllers/h5/market/sylive/Myqrcode.php @@ -0,0 +1,33 @@ +input->get('url'); + if ($url) { + $errorCorrectionLevel = 'L'; //容错级别 + $matrixPointSize = 5; //生成图片大小 + //生成二维码图片 + QRcode::png($url, false, $errorCorrectionLevel, $matrixPointSize, 1); + } + } + +} \ No newline at end of file diff --git a/home/controllers/h5/market/sylive/Notify.php b/home/controllers/h5/market/sylive/Notify.php new file mode 100644 index 00000000..a91ea90a --- /dev/null +++ b/home/controllers/h5/market/sylive/Notify.php @@ -0,0 +1,67 @@ +load->model('market/market_sylive_activity_user_model', 'act_user_model'); + $this->load->model('market/market_sylive_order_model','order_model'); + $this->load->library('market/sylive_entity'); + try{ + //如果返回成功则验证签名 + $config = new WxPayConfig(); + $input = file_get_contents("php://input"); + $result = WxPayNotifyResults::Init($config, $input); + $this->notify = $result->GetValues(); + debug_log("[info] ". __FUNCTION__ . "# notify:" . json_encode($this->notify,JSON_UNESCAPED_UNICODE), $this->log_file,$this->log_dir); + }catch (WxPayException $e){ + debug_log("[error] ". __FUNCTION__ . ":".$e->getMessage(), $this->log_file,$this->log_dir); + exit(); + } + } + + //微信支付异步通知 + public function index(){ + try{ + $sid = $this->notify['out_trade_no']; + if($sid){ + debug_log("[start] ". __FUNCTION__ . ": out_trade_no:".$this->notify['out_trade_no'], $this->log_file,$this->log_dir); + $order = $this->order_model->get(array('sid'=>$sid)); + if(!$order){ + throw new Exception("{$sid}_订单不存在"); + } + if($order['status']){ + throw new Exception("{$sid}_订单已支付"); + } + if($this->notify['result_code'] != 'SUCCESS'){ //支付失败 + throw new Exception("支付失败,sid={$sid}"); + }else{ //支付成功 + $res = $this->order_model->update(['status'=>1,'pay_time'=>date('Y-m-d H:i:s')],['id'=>$order['id']]); + if($res){ + $act_user = $this->act_user_model->get(['userId'=>$order['uid'],'activityId'=>$order['item_id']]); + $sy_res = $this->sylive_entity->kpi_log(['a_id' => $order['item_id'], 'uid' => $order['uid'],'cf_uid' => $act_user['channelId'], 'kpi' => 'order']); + debug_log("[info] ". __FUNCTION__ . ":私域通增加记录-".json_encode($sy_res,JSON_UNESCAPED_UNICODE), $this->log_file,$this->log_dir); + debug_log("[success] ". __FUNCTION__ . ":操作成功", $this->log_file,$this->log_dir); + } + } + } + }catch (Exception $e){ + $msg = $e->getMessage(); + debug_log("[error] ". __FUNCTION__ . ":{$msg}", $this->log_file,$this->log_dir); + } + if($sid){ + debug_log("[finish] ". __FUNCTION__ . ": out_trade_no-".$this->notify['out_trade_no'], $this->log_file,$this->log_dir); + }else{ + debug_log("[finish] ". __FUNCTION__ . ": 参数错误-".json_encode($this->notify,JSON_UNESCAPED_UNICODE), $this->log_file,$this->log_dir); + } + echo ''; + } + +} diff --git a/home/controllers/h5/market/sylive/Stic.php b/home/controllers/h5/market/sylive/Stic.php new file mode 100644 index 00000000..a46aa8aa --- /dev/null +++ b/home/controllers/h5/market/sylive/Stic.php @@ -0,0 +1,272 @@ +load->model('market/market_sylive_organization_model'); + $this->load->model('market/market_sylive_activity_model'); + $this->load->model('market/market_sylive_activity_biz_model','mdSytActivityBiz'); + $this->load->model('market/market_sylive_activity_kpidata_model','mdSytActivityKpiData'); + $this->load->library('market/sylive_entity'); + $this->group_id = $this->sylive_entity->get_level($this->session['org_id']); + $this->data['skey'] = $this->input->get('skey'); + } + //顾问 + public function index(){ + if($this->group_id>3){ + throw new Hd_exception('权限不足',400); + } + if($this->group_id==3){ //顾问 + $param = $this->myencryption->base64url_decode($this->data['skey']); + $a_id = intval($param['a_id']);//活动id + $browse_count = $this->mdSytActivityKpiData->count(['a_id'=>$a_id,'kpi'=>'browse','cf_uid'=>$this->uid]); + $subscribe_count = $this->mdSytActivityKpiData->count(['a_id'=>$a_id,'kpi'=>'subscribe','cf_uid'=>$this->uid]); + $info['begin'] = [ + ['title' => '访问用户', 'num' => "{$browse_count}人"], + ['title' => '预约用户', 'num' => "{$subscribe_count}人"], + ['title' => '预约率', 'num' => $subscribe_count ? round($subscribe_count/$browse_count*100,2)."%" : 0], + ]; + $watch_count = $this->mdSytActivityKpiData->count(['a_id'=>$a_id,'kpi'=>'watch','cf_uid'=>$this->uid]); + $order_count = $this->mdSytActivityKpiData->count(['a_id'=>$a_id,'kpi'=>'order','cf_uid'=>$this->uid]); + $info['live'] = [ + ['title' => '观看用户', 'num' => "{$watch_count}人"], + ['title' => '下单用户', 'num' => "{$order_count}人"], + ['title' => '转化率', 'num' => $watch_count ? round($watch_count/$order_count*100,2)."%" : 0], + ]; + $this->data['info'] = $info; + $this->show_view('h5/market/sylive/stic/index'); + }else{ //门店和大区 + $this->show_view('h5/market/sylive/stic/area'); + } + } + + public function lists_ready(){ + $skey = $this->input->get('skey'); + $param = $this->myencryption->base64url_decode($skey); + $a_id = intval($param['a_id']);//活动id + $row = $this->market_sylive_activity_model->get(['activityId'=>$a_id]); + if(!$row && $this->group_id>=3){ + $this->show_json([],200); + } + $cell2 = []; + if($this->group_id<2){ //所有大区 + $where = [ + 'a_id' => $a_id, + 'kpi' => 'browse', + ]; + if($this->group_id==1){ + $org_row = $this->market_sylive_organization_model->get(['organizationId'=>$this->session['org_id']],'parentId'); + $org_id = $org_row['parentId'] ? $org_row['parentId'] : 0; + $where["area_id in (select organizationId from lc_market_sylive_organization where parentId={$org_id} and status=0)"] = null; + }else{ + $where["area_id in (select organizationId from lc_market_sylive_organization where parentId={$this->session['org_id']} and status=0)"] = null; + } + $browse_count = $this->mdSytActivityKpiData->count($where); //浏览数据 + $where['kpi'] = 'subscribe'; + $subscribe_count = $this->mdSytActivityKpiData->count($where); //预约用户 + $sql = "select count(distinct areaId) as total from lc_market_sylive_activity_biz where `activityId`={$a_id}"; + $area_count = $this->mdSytActivityBiz->db->query($sql)->row_array(); + $sql = "select count(distinct bizId) as total from lc_market_sylive_activity_biz where `activityId`={$a_id}"; + $biz_count = $this->mdSytActivityBiz->db->query($sql)->row_array(); + $where = [ + 'status' => 0, + "organizationId in (select organizationId from lc_market_sylive_organization where + parentId in (select bizId from lc_market_sylive_activity_biz where activityId={$a_id} and status=0) + )" => null + ]; + $gw_count = $this->user_model->count($where); //顾问 + $cell2 = [ + ['title' => '参与大区', 'num' => "{$area_count['total']}个"], + ['title' => '参与门店', 'num' => "{$biz_count['total']}家"], + ['title' => '参与人数', 'num' => "{$gw_count}人"], + ]; + }else{ //门店 + $where = [ + 'a_id' => $a_id, + 'kpi' => 'browse', + 'biz_id' => $this->session['org_id'] + ]; + $browse_count = $this->mdSytActivityKpiData->count($where); //浏览数据 + $where['kpi'] = 'subscribe'; + $subscribe_count = $this->mdSytActivityKpiData->count($where); //浏览数据 + } + $cell1 = [ + ['title' => '访问用户', 'num' => "{$browse_count}人"], + ['title' => '预约用户', 'num' => "{$subscribe_count}人"], + ['title' => '预约率', 'num' => $subscribe_count ? round($subscribe_count/$browse_count*100,2)."%" : 0], + ]; + $biz_id = $this->group_id==3 ? $this->session['org_id'] : 0; + $browse_lists = $this->sylive_entity->top_lists($a_id,'browse',1,10,$biz_id); + $browse = [ + 'title' => '门店浏览排行', + 'url' => '/h5/market/sylive/stic/rank?type=browse&skey='.$skey, + 'list' => $browse_lists['lists'] + ]; + $book_lists = $this->sylive_entity->top_lists($a_id,'subscribe',1,10,$biz_id); + $book = [ + 'title' => '门店预约排行', + 'url' => '/h5/market/sylive/stic/rank?type=subscribe&skey='.$skey, + 'list' => $book_lists['lists'] + ]; + $data = [ + 'cell1' => $cell1, + 'cell2' => $cell2, + 'browse' => $browse, + 'book' => $book + ]; + $this->show_json($data,200); + } + + //直播统计数据 + public function lists_live(){ + $skey = $this->input->get('skey'); + $param = $this->myencryption->base64url_decode($skey); + $a_id = intval($param['a_id']);//活动id + $row = $this->market_sylive_activity_model->get(['activityId'=>$a_id]); + if(!$row && $this->group_id>=3){ + $this->show_json([],200); + } + $cell3 = []; + if($this->group_id<2){ //所有大区 + $where = [ + 'a_id' => $a_id, + 'kpi' => 'watch', + ]; + if($this->group_id==1){ + $org_row = $this->market_sylive_organization_model->get(['organizationId'=>$this->session['org_id']],'parentId'); + $org_id = $org_row['parentId'] ? $org_row['parentId'] : 0; + $where["area_id in (select organizationId from lc_market_sylive_organization where parentId={$org_id} and status=0)"] = null; + }else{ + $where["area_id in (select organizationId from lc_market_sylive_organization where parentId={$this->session['org_id']} and status=0)"] = null; + } + $view_count = $this->mdSytActivityKpiData->count($where); //浏览数据 + $where['kpi'] = 'order'; + $order_count = $this->mdSytActivityKpiData->count($where); //预约用户 + $sql = "select count(distinct areaId) as total from lc_market_sylive_activity_biz where `activityId`={$a_id}"; + $area_count = $this->mdSytActivityBiz->db->query($sql)->row_array(); + $sql = "select count(distinct bizId) as total from lc_market_sylive_activity_biz where `activityId`={$a_id}"; + $biz_count = $this->mdSytActivityBiz->db->query($sql)->row_array(); + $where = [ + 'status' => 0, + "organizationId in (select organizationId from lc_market_sylive_organization where + parentId in (select bizId from lc_market_sylive_activity_biz where activityId={$a_id} and status=0) + )" => null + ]; + $gw_count = $this->user_model->count($where); //顾问 + $cell3 = [ + ['title' => '参与大区', 'num' => "{$area_count['total']}个"], + ['title' => '参与门店', 'num' => "{$biz_count['total']}家"], + ['title' => '参与人数', 'num' => "{$gw_count}人"], + ]; + }else{ //门店 + $where = [ + 'a_id' => $a_id, + 'kpi' => 'watch', + 'biz_id' => $this->session['org_id'] + ]; + $view_count = $this->mdSytActivityKpiData->count($where); //观看数据 + $where['kpi'] = 'order'; + $order_count = $this->mdSytActivityKpiData->count($where); //下单数据 + } + $cell1 = [ + ['title' => '观看用户', 'num' => "{$view_count}人"], + ['title' => '下单用户', 'num' => "{$order_count}人"], + ['title' => '转化率', 'num' => $order_count ? round($order_count/$view_count*100,2)."%" : 0], + ]; + $cell2 = [ + ['title' => '直播时长', 'num' => "0分钟"], + ['title' => '人均观看', 'num' => "0秒"], + ['title' => '观看次数', 'num' => "0次"], + ]; + $biz_id = $this->group_id==3 ? $this->session['org_id'] : 0; + $watch_lists = $this->sylive_entity->top_lists($a_id,'watch',1,10,$biz_id); + $view = [ + 'title' => '门店观看排行', + 'url' => '/h5/market/sylive/stic/rank?type=watch&skey='.$skey, + 'list' => $watch_lists['lists'] + ]; + $order_lists = $this->sylive_entity->top_lists($a_id,'order',1,10,$biz_id); + $order = [ + 'title' => '门店订单排行', + 'url' => '/h5/market/sylive/stic/rank?type=order&skey='.$skey, + 'list' => $order_lists['lists'] + ]; + $data = [ + 'cell1' => $cell1, + 'cell2' => $cell2, + 'cell3' => $cell3, + 'view' => $view, + 'order' => $order + ]; + $this->show_json($data,200); + } + + //排名列表 + public function rank(){ + $title_arr = [ + 'browse' => '门店浏览排行', + 'subscribe' => '门店预约排行', + 'watch' => '门店观看排行', + 'order' => '门店订单排行' + ]; + $params = $this->input->get(); + if($this->input->is_ajax_request()){ + $page = $params['page'] ? intval($params['page']) : 1; + $info = $this->myencryption->base64url_decode($params['skey']); + $a_id = intval($info['a_id']);//活动id + $biz_id = $this->group_id==3 ? $this->session['org_id'] : 0; + $type = $params['type'] ? $params['type'] : 'browse'; + $data = $this->sylive_entity->top_lists($a_id,$type,$page,10,$biz_id); + $data['title'] = $title_arr[$type]; + $this->show_json($data,200); + } + $this->data['params'] = $params; + $this->show_view('h5/market/sylive/stic/rank'); + } + + public function event(){ + $map_kpi_name = [ + 'browse' => '浏览了直播间', 'subscribe' => '订阅了直播间', 'order' => '直播间下单','watch' => '进入了直播间' + ]; + $skey = $this->input->get('skey'); + $page = $this->input->get('page'); + !$page && $page=10; + $param = $this->myencryption->base64url_decode($skey); + $a_id = intval($param['a_id']);//活动id + $where = [ + 'a_id'=>$a_id, +// 'kpi'=>'watch', + 'cf_uid'=>$this->uid + ]; + $total = $this->mdSytActivityKpiData->count($where); + $lists = []; + if($total){ + $rows = $this->mdSytActivityKpiData->select($where,'id desc',$page,10,'uid,kpi,c_time'); + $users = []; + $uids = implode(',',array_unique(array_column($rows,'uid'))); + if($uids){ + $where = [ + "userId in ($uids)" => null, + ]; + $users = $this->user_model->map('userId','nickname',$where,'','','','userId,nickname'); + } + foreach ($rows as $key => $val) { + $nickname = $users[$val['uid']] ? $users['uid'] : "用户{$val['uid']}"; + $lists[] = [ + 'nickname' => $nickname, + 'action' => $map_kpi_name[$val['kpi']], + 'time' => friendly_date($val['c_time']), + ]; + } + } + $data = [ + 'lists' => $lists, + 'total' => $total + ]; + $this->show_json($data,200); + } +} \ No newline at end of file diff --git a/home/controllers/h5/market/sylive/Welcome.php b/home/controllers/h5/market/sylive/Welcome.php new file mode 100644 index 00000000..9329f9bb --- /dev/null +++ b/home/controllers/h5/market/sylive/Welcome.php @@ -0,0 +1,23 @@ +load->library('market/sylive_entity'); + } + + public function index(){ + $group_id = $this->sylive_entity->get_level($this->session['org_id']); + if($group_id==2 || $group_id==3){ //顾问和店长 店铺首页 + header('Location:/h5/market/sylive/biz');exit; + }elseif($group_id==1){ //店铺列表 + header('Location:/h5/market/sylive/biz/lists');exit; + }else{ // 大区列表 + header('Location:/h5/market/sylive/biz/brands');exit; + } + } + +} diff --git a/home/views/h5/market/sylive/act/index.php b/home/views/h5/market/sylive/act/index.php new file mode 100644 index 00000000..77405b97 --- /dev/null +++ b/home/views/h5/market/sylive/act/index.php @@ -0,0 +1,306 @@ + + + + +
+
+ +
+
+
+
+ +
+
+
+ +
+ + +
+ + + +
我的
+
+ + +
+
+ {{item.name}} + {{item.tip}} +
+
+ {{item.name}} + {{item.tip}} +
+
+ +
+ +
+
+
+
+
+
+ +
+
长按识别二维码,关注狸车服务号。即可接收直播提醒,还有更多福利不定期放送哦~
+
+
+ 知道了 +
+ +
+
+
+ +
+ + + + + + + \ No newline at end of file diff --git a/home/views/h5/market/sylive/act/item.php b/home/views/h5/market/sylive/act/item.php new file mode 100644 index 00000000..8d9d67a0 --- /dev/null +++ b/home/views/h5/market/sylive/act/item.php @@ -0,0 +1,158 @@ + +
+
+ +
+
+
+
+ # +
+
+
+
+
+ +
+
+
{{info.title}}
+
+
+ ¥ + {{info.price}} +
+
+
+
+
+
+ + + +
+
+ + + + \ No newline at end of file diff --git a/home/views/h5/market/sylive/act/share.php b/home/views/h5/market/sylive/act/share.php new file mode 100644 index 00000000..106c5ed7 --- /dev/null +++ b/home/views/h5/market/sylive/act/share.php @@ -0,0 +1,146 @@ + + +
+
+
+
+
+
+
+ +
{{posterTip}}
+ +
+
+
+
+
+
+
+ +
+
分享文案
+
+ {{item}} + +
+
+ +
+
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+
+ + 长按图片保存到手机发送给好友 +
+
+
+
+ +
+ + \ No newline at end of file diff --git a/home/views/h5/market/sylive/act/ucenter.php b/home/views/h5/market/sylive/act/ucenter.php new file mode 100644 index 00000000..cf7e4c1e --- /dev/null +++ b/home/views/h5/market/sylive/act/ucenter.php @@ -0,0 +1,79 @@ + +
+
+ +
+
+
+
+ # +
+
+
+
+
+ +
+
+
{{info.title}}
+
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/home/views/h5/market/sylive/biz/brands.php b/home/views/h5/market/sylive/biz/brands.php new file mode 100644 index 00000000..a5a97964 --- /dev/null +++ b/home/views/h5/market/sylive/biz/brands.php @@ -0,0 +1,192 @@ + +
+
+
+
+ # + {{info.nickname}} +
+
+
+
{{item.num}}
+
+ {{item.title}} +
+
+
+
+ +
+
+ + + \ No newline at end of file diff --git a/home/views/h5/market/sylive/biz/index.php b/home/views/h5/market/sylive/biz/index.php new file mode 100644 index 00000000..96441791 --- /dev/null +++ b/home/views/h5/market/sylive/biz/index.php @@ -0,0 +1,103 @@ + +
+
+
+ +
+
+ # +
{{info.title}}
+ + +
暂无数据
+
请稍等...
+
我们是有底线的
+
+
+
+
+ + + + \ No newline at end of file diff --git a/home/views/h5/market/sylive/biz/lists.php b/home/views/h5/market/sylive/biz/lists.php new file mode 100644 index 00000000..9f989ea4 --- /dev/null +++ b/home/views/h5/market/sylive/biz/lists.php @@ -0,0 +1,199 @@ + +
+
+
+
+
+ # + {{info.nickname}} +
+ + + 切换区域 + + +
+
+
+
{{item.num}}
+ {{item.title}} +
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/home/views/h5/market/sylive/footer.php b/home/views/h5/market/sylive/footer.php new file mode 100644 index 00000000..62d09b82 --- /dev/null +++ b/home/views/h5/market/sylive/footer.php @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/home/views/h5/market/sylive/header.php b/home/views/h5/market/sylive/header.php new file mode 100644 index 00000000..f9033e1a --- /dev/null +++ b/home/views/h5/market/sylive/header.php @@ -0,0 +1,17 @@ + + + + + + + + <?=$_title?> + + + + + + + + \ No newline at end of file diff --git a/home/views/h5/market/sylive/login.php b/home/views/h5/market/sylive/login.php new file mode 100644 index 00000000..eaaaebb0 --- /dev/null +++ b/home/views/h5/market/sylive/login.php @@ -0,0 +1,165 @@ + + + + + + + + <?=$_title?> + + + + + + + + +
+
+
+
+
您好!
+
欢迎来到东风EV
+
+
+
登录
+
+ +
+
+ + +
+ + +
+
+
+
联系我们
+
400-5555-888
+
+
+
+ + + + + + diff --git a/home/views/h5/market/sylive/stic/area.php b/home/views/h5/market/sylive/stic/area.php new file mode 100644 index 00000000..10f8522d --- /dev/null +++ b/home/views/h5/market/sylive/stic/area.php @@ -0,0 +1,294 @@ + +
+
+
+
+
+
+
+ +
+
+ + +
+
+
+
+
{{item.num}}
+
{{item.title}}
+
+
+
+
+
{{item.num}}
+
{{item.title}}
+
+
+
+ +
+
+ + 查看更多 +
+
+
+
+
+ # + {{item.ranking}} + {{item.name}} + {{item.tip}} +
+
{{item.num}}
+
+
+
+
暂时无数据
+
+ +
+
+ + 查看更多 +
+
+
+
+
+ # + {{item.ranking}} + {{item.name}} + {{item.tip}} +
+
{{item.num}}
+
+
+
+
暂时无数据
+
+ +
+ + +
+
+
+
+
{{item.num}}
+
{{item.title}}
+
+
+
+
+
{{item.num}}
+
{{item.title}}
+
+
+
+
+
{{item.num}}
+
{{item.title}}
+
+
+
+ +
+
+ + 查看更多 +
+
+
+
+
+ # + {{item.ranking}} + {{item.name}} + {{item.tip}} +
+
{{item.num}}
+
+
+
+
暂时无数据
+
+ +
+
+ + 查看更多 +
+
+
+
+
+ # + {{item.ranking}} + {{item.name}} + {{item.tip}} +
+
{{item.num}}
+
+
+
+
暂时无数据
+
+
+ +
+ + + +
+
+ + + + diff --git a/home/views/h5/market/sylive/stic/index.php b/home/views/h5/market/sylive/stic/index.php new file mode 100644 index 00000000..5c17afb8 --- /dev/null +++ b/home/views/h5/market/sylive/stic/index.php @@ -0,0 +1,222 @@ + +
+
+
+
+
+
+
+ +
+
+ + +
+
+
+
+
{{item.num}}
+
{{item.title}}
+
+
+
+
+ + +
+
+
+
+
{{item.num}}
+
{{item.title}}
+
+
+
+
+ + +
+
+ +
+
+
+
+ {{item.nickname}} + {{item.action}} +
+
{{item.time}}
+
+
+ +
暂无数据
+
请稍等...
+
我们是有底线的
+
+
+ +
+ + + +
+
+ + + \ No newline at end of file diff --git a/home/views/h5/market/sylive/stic/rank.php b/home/views/h5/market/sylive/stic/rank.php new file mode 100644 index 00000000..9c845d89 --- /dev/null +++ b/home/views/h5/market/sylive/stic/rank.php @@ -0,0 +1,83 @@ + +
+
+
+
+
+
+
+ # + {{item.ranking}} + {{item.name}} + {{item.tip}} +
+
{{item.num}}
+
+
+ +
暂无数据
+
请稍等...
+
我们是有底线的
+
+
+
+
+ + + \ No newline at end of file diff --git a/market/.htaccess b/market/.htaccess new file mode 100644 index 00000000..6c63ed4c --- /dev/null +++ b/market/.htaccess @@ -0,0 +1,6 @@ + + Require all denied + + + Deny from all + \ No newline at end of file diff --git a/market/cache/index.html b/market/cache/index.html new file mode 100644 index 00000000..b702fbc3 --- /dev/null +++ b/market/cache/index.html @@ -0,0 +1,11 @@ + + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + diff --git a/market/config/app.php b/market/config/app.php new file mode 100644 index 00000000..2ddd2916 --- /dev/null +++ b/market/config/app.php @@ -0,0 +1,34 @@ + array( + 'id' => 1, + 'app_id' => 1, + 'name' => '狸车', + 'sign_key' => 'bcdb554f61e320e1d1c2e858c147e83c', + 'wx' => array( + 'appid' => 'wx98e64c11aac45966', + 'secret' => 'f8eec7be1c87a1c8e40213e144821ec3', + ), + 'model' => array('user_model' => 'app/liche/app_liche_users_model') + ), + 'licheb' => array( + 'id' => 2, + 'app_id' => 2, + 'name' => '狸车宝', + 'sign_key' => '71fd71173b776766a2ae1209d9a2c2ed', + 'wx' => array( + 'appid' => 'wx71095d4049de3ed1', + 'secret' => 'a80eb6ed68d7bae2d804fe507a4522f7', + ), + 'model' => array('user_model' => 'app/licheb/app_licheb_users_model') + ), +); diff --git a/market/config/autoload.php b/market/config/autoload.php new file mode 100644 index 00000000..71e927f8 --- /dev/null +++ b/market/config/autoload.php @@ -0,0 +1,135 @@ + 'ua'); +*/ +$autoload['libraries'] = array('database'); + +/* +| ------------------------------------------------------------------- +| Auto-load Drivers +| ------------------------------------------------------------------- +| These classes are located in system/libraries/ or in your +| application/libraries/ directory, but are also placed inside their +| own subdirectory and they extend the CI_Driver_Library class. They +| offer multiple interchangeable driver options. +| +| Prototype: +| +| $autoload['drivers'] = array('cache'); +| +| You can also supply an alternative property name to be assigned in +| the controller: +| +| $autoload['drivers'] = array('cache' => 'cch'); +| +*/ +$autoload['drivers'] = array(); + +/* +| ------------------------------------------------------------------- +| Auto-load Helper Files +| ------------------------------------------------------------------- +| Prototype: +| +| $autoload['helper'] = array('url', 'file'); +*/ +$autoload['helper'] = array('comm', 'url', 'array','order','authorization'); + +/* +| ------------------------------------------------------------------- +| Auto-load Config files +| ------------------------------------------------------------------- +| Prototype: +| +| $autoload['config'] = array('config1', 'config2'); +| +| NOTE: This item is intended for use ONLY if you have created custom +| config files. Otherwise, leave it blank. +| +*/ +$autoload['config'] = array('jwt'); + +/* +| ------------------------------------------------------------------- +| Auto-load Language files +| ------------------------------------------------------------------- +| Prototype: +| +| $autoload['language'] = array('lang1', 'lang2'); +| +| NOTE: Do not include the "_lang" part of your file. For example +| "codeigniter_lang.php" would be referenced as array('codeigniter'); +| +*/ +$autoload['language'] = array(); + +/* +| ------------------------------------------------------------------- +| Auto-load Models +| ------------------------------------------------------------------- +| Prototype: +| +| $autoload['model'] = array('first_model', 'second_model'); +| +| You can also supply an alternative model name to be assigned +| in the controller: +| +| $autoload['model'] = array('first_model' => 'first'); +*/ +$autoload['model'] = array(); diff --git a/market/config/config.php b/market/config/config.php new file mode 100644 index 00000000..d912c9e0 --- /dev/null +++ b/market/config/config.php @@ -0,0 +1,523 @@ +]+$/i +| +| DO NOT CHANGE THIS UNLESS YOU FULLY UNDERSTAND THE REPERCUSSIONS!! +| +*/ +$config['permitted_uri_chars'] = 'a-z 0-9~%.:_\-'; + +/* +|-------------------------------------------------------------------------- +| Enable Query Strings +|-------------------------------------------------------------------------- +| +| By default CodeIgniter uses search-engine friendly segment based URLs: +| example.com/who/what/where/ +| +| You can optionally enable standard query string based URLs: +| example.com?who=me&what=something&where=here +| +| Options are: TRUE or FALSE (boolean) +| +| The other items let you set the query string 'words' that will +| invoke your controllers and its functions: +| example.com/index.php?c=controller&m=function +| +| Please note that some of the helpers won't work as expected when +| this feature is enabled, since CodeIgniter is designed primarily to +| use segment based URLs. +| +*/ +$config['enable_query_strings'] = FALSE; +$config['controller_trigger'] = 'c'; +$config['function_trigger'] = 'm'; +$config['directory_trigger'] = 'd'; + +/* +|-------------------------------------------------------------------------- +| Allow $_GET array +|-------------------------------------------------------------------------- +| +| By default CodeIgniter enables access to the $_GET array. If for some +| reason you would like to disable it, set 'allow_get_array' to FALSE. +| +| WARNING: This feature is DEPRECATED and currently available only +| for backwards compatibility purposes! +| +*/ +$config['allow_get_array'] = TRUE; + +/* +|-------------------------------------------------------------------------- +| Error Logging Threshold +|-------------------------------------------------------------------------- +| +| You can enable error logging by setting a threshold over zero. The +| threshold determines what gets logged. Threshold options are: +| +| 0 = Disables logging, Error logging TURNED OFF +| 1 = Error Messages (including PHP errors) +| 2 = Debug Messages +| 3 = Informational Messages +| 4 = All Messages +| +| You can also pass an array with threshold levels to show individual error types +| +| array(2) = Debug Messages, without Error Messages +| +| For a live site you'll usually only enable Errors (1) to be logged otherwise +| your log files will fill up very fast. +| +*/ +$config['log_threshold'] = 1; + +/* +|-------------------------------------------------------------------------- +| Error Logging Directory Path +|-------------------------------------------------------------------------- +| +| Leave this BLANK unless you would like to set something other than the default +| application/logs/ directory. Use a full server path with trailing slash. +| +*/ +$config['log_path'] = ''; + +/* +|-------------------------------------------------------------------------- +| Log File Extension +|-------------------------------------------------------------------------- +| +| The default filename extension for log files. The default 'php' allows for +| protecting the log files via basic scripting, when they are to be stored +| under a publicly accessible directory. +| +| Note: Leaving it blank will default to 'php'. +| +*/ +$config['log_file_extension'] = ''; + +/* +|-------------------------------------------------------------------------- +| Log File Permissions +|-------------------------------------------------------------------------- +| +| The file system permissions to be applied on newly created log files. +| +| IMPORTANT: This MUST be an integer (no quotes) and you MUST use octal +| integer notation (i.e. 0700, 0644, etc.) +*/ +$config['log_file_permissions'] = 0644; + +/* +|-------------------------------------------------------------------------- +| Date Format for Logs +|-------------------------------------------------------------------------- +| +| Each item that is logged has an associated date. You can use PHP date +| codes to set your own date formatting +| +*/ +$config['log_date_format'] = 'Y-m-d H:i:s'; + +/* +|-------------------------------------------------------------------------- +| Error Views Directory Path +|-------------------------------------------------------------------------- +| +| Leave this BLANK unless you would like to set something other than the default +| application/views/errors/ directory. Use a full server path with trailing slash. +| +*/ +$config['error_views_path'] = ''; + +/* +|-------------------------------------------------------------------------- +| Cache Directory Path +|-------------------------------------------------------------------------- +| +| Leave this BLANK unless you would like to set something other than the default +| application/cache/ directory. Use a full server path with trailing slash. +| +*/ +$config['cache_path'] = ''; + +/* +|-------------------------------------------------------------------------- +| Cache Include Query String +|-------------------------------------------------------------------------- +| +| Whether to take the URL query string into consideration when generating +| output cache files. Valid options are: +| +| FALSE = Disabled +| TRUE = Enabled, take all query parameters into account. +| Please be aware that this may result in numerous cache +| files generated for the same page over and over again. +| array('q') = Enabled, but only take into account the specified list +| of query parameters. +| +*/ +$config['cache_query_string'] = FALSE; + +/* +|-------------------------------------------------------------------------- +| Encryption Key +|-------------------------------------------------------------------------- +| +| If you use the Encryption class, you must set an encryption key. +| See the user guide for more info. +| +| https://codeigniter.com/user_guide/libraries/encryption.html +| +*/ +$config['encryption_key'] = 'market.ai'; + +/* +|-------------------------------------------------------------------------- +| Session Variables +|-------------------------------------------------------------------------- +| +| 'sess_driver' +| +| The storage driver to use: files, database, redis, memcached +| +| 'sess_cookie_name' +| +| The session cookie name, must contain only [0-9a-z_-] characters +| +| 'sess_expiration' +| +| The number of SECONDS you want the session to last. +| Setting to 0 (zero) means expire when the browser is closed. +| +| 'sess_save_path' +| +| The location to save sessions to, driver dependent. +| +| For the 'files' driver, it's a path to a writable directory. +| WARNING: Only absolute paths are supported! +| +| For the 'database' driver, it's a table name. +| Please read up the manual for the format with other session drivers. +| +| IMPORTANT: You are REQUIRED to set a valid save path! +| +| 'sess_match_ip' +| +| Whether to match the user's IP address when reading the session data. +| +| WARNING: If you're using the database driver, don't forget to update +| your session table's PRIMARY KEY when changing this setting. +| +| 'sess_time_to_update' +| +| How many seconds between CI regenerating the session ID. +| +| 'sess_regenerate_destroy' +| +| Whether to destroy session data associated with the old session ID +| when auto-regenerating the session ID. When set to FALSE, the data +| will be later deleted by the garbage collector. +| +| Other session cookie settings are shared with the rest of the application, +| except for 'cookie_prefix' and 'cookie_httponly', which are ignored here. +| +*/ +$config['sess_driver'] = 'files'; +$config['sess_cookie_name'] = 'ci_session'; +$config['sess_expiration'] = 7200; +$config['sess_save_path'] = NULL; +$config['sess_match_ip'] = FALSE; +$config['sess_time_to_update'] = 300; +$config['sess_regenerate_destroy'] = FALSE; + +/* +|-------------------------------------------------------------------------- +| Cookie Related Variables +|-------------------------------------------------------------------------- +| +| 'cookie_prefix' = Set a cookie name prefix if you need to avoid collisions +| 'cookie_domain' = Set to .your-domain.com for site-wide cookies +| 'cookie_path' = Typically will be a forward slash +| 'cookie_secure' = Cookie will only be set if a secure HTTPS connection exists. +| 'cookie_httponly' = Cookie will only be accessible via HTTP(S) (no javascript) +| +| Note: These settings (with the exception of 'cookie_prefix' and +| 'cookie_httponly') will also affect sessions. +| +*/ +$config['cookie_prefix'] = ''; +$config['cookie_domain'] = ''; +$config['cookie_path'] = '/'; +$config['cookie_secure'] = FALSE; +$config['cookie_httponly'] = FALSE; + +/* +|-------------------------------------------------------------------------- +| Standardize newlines +|-------------------------------------------------------------------------- +| +| Determines whether to standardize newline characters in input data, +| meaning to replace \r\n, \r, \n occurrences with the PHP_EOL value. +| +| WARNING: This feature is DEPRECATED and currently available only +| for backwards compatibility purposes! +| +*/ +$config['standardize_newlines'] = FALSE; + +/* +|-------------------------------------------------------------------------- +| Global XSS Filtering +|-------------------------------------------------------------------------- +| +| Determines whether the XSS filter is always active when GET, POST or +| COOKIE data is encountered +| +| WARNING: This feature is DEPRECATED and currently available only +| for backwards compatibility purposes! +| +*/ +$config['global_xss_filtering'] = FALSE; + +/* +|-------------------------------------------------------------------------- +| Cross Site Request Forgery +|-------------------------------------------------------------------------- +| Enables a CSRF cookie token to be set. When set to TRUE, token will be +| checked on a submitted form. If you are accepting user data, it is strongly +| recommended CSRF protection be enabled. +| +| 'csrf_token_name' = The token name +| 'csrf_cookie_name' = The cookie name +| 'csrf_expire' = The number in seconds the token should expire. +| 'csrf_regenerate' = Regenerate token on every submission +| 'csrf_exclude_uris' = Array of URIs which ignore CSRF checks +*/ +$config['csrf_protection'] = FALSE; +$config['csrf_token_name'] = 'csrf_test_name'; +$config['csrf_cookie_name'] = 'csrf_cookie_name'; +$config['csrf_expire'] = 7200; +$config['csrf_regenerate'] = TRUE; +$config['csrf_exclude_uris'] = array(); + +/* +|-------------------------------------------------------------------------- +| Output Compression +|-------------------------------------------------------------------------- +| +| Enables Gzip output compression for faster page loads. When enabled, +| the output class will test whether your server supports Gzip. +| Even if it does, however, not all browsers support compression +| so enable only if you are reasonably sure your visitors can handle it. +| +| Only used if zlib.output_compression is turned off in your php.ini. +| Please do not use it together with httpd-level output compression. +| +| VERY IMPORTANT: If you are getting a blank page when compression is enabled it +| means you are prematurely outputting something to your browser. It could +| even be a line of whitespace at the end of one of your scripts. For +| compression to work, nothing can be sent before the output buffer is called +| by the output class. Do not 'echo' any values with compression enabled. +| +*/ +$config['compress_output'] = FALSE; + +/* +|-------------------------------------------------------------------------- +| Master Time Reference +|-------------------------------------------------------------------------- +| +| Options are 'local' or any PHP supported timezone. This preference tells +| the system whether to use your server's local time as the master 'now' +| reference, or convert it to the configured one timezone. See the 'date +| helper' page of the user guide for information regarding date handling. +| +*/ +$config['time_reference'] = 'local'; + +/* +|-------------------------------------------------------------------------- +| Rewrite PHP Short Tags +|-------------------------------------------------------------------------- +| +| If your PHP installation does not have short tag support enabled CI +| can rewrite the tags on-the-fly, enabling you to utilize that syntax +| in your view files. Options are TRUE or FALSE (boolean) +| +| Note: You need to have eval() enabled for this to work. +| +*/ +$config['rewrite_short_tags'] = FALSE; + +/* +|-------------------------------------------------------------------------- +| Reverse Proxy IPs +|-------------------------------------------------------------------------- +| +| If your server is behind a reverse proxy, you must whitelist the proxy +| IP addresses from which CodeIgniter should trust headers such as +| HTTP_X_FORWARDED_FOR and HTTP_CLIENT_IP in order to properly identify +| the visitor's IP address. +| +| You can use both an array or a comma-separated list of proxy addresses, +| as well as specifying whole subnets. Here are a few examples: +| +| Comma-separated: '10.0.1.200,192.168.5.0/24' +| Array: array('10.0.1.200', '192.168.5.0/24') +*/ +$config['proxy_ips'] = ''; diff --git a/market/config/constants.php b/market/config/constants.php new file mode 100644 index 00000000..6150b09a --- /dev/null +++ b/market/config/constants.php @@ -0,0 +1,109 @@ +db->last_query() and profiling of DB queries. +| When you run a query, with this setting set to TRUE (default), +| CodeIgniter will store the SQL statement for debugging purposes. +| However, this may cause high memory usage, especially if you run +| a lot of SQL queries ... disable this to avoid that problem. +| +| The $active_group variable lets you choose which connection group to +| make active. By default there is only one group (the 'default' group). +| +| The $query_builder variables lets you determine whether or not to load +| the query builder class. +*/ +$active_group = 'default'; +$query_builder = TRUE; + +$db['default'] = array( + 'dsn' => '', + 'hostname' => 'mysql:host=192.168.0.11:3308;dbname=lichedb', + 'username' => 'devuser', + 'password' => '123456', + 'database' => 'lichedb', + 'dbdriver' => 'pdo', + 'dbprefix' => 'lc_', + 'pconnect' => FALSE, + 'db_debug' => (ENVIRONMENT !== 'production'), + 'cache_on' => FALSE, + 'cachedir' => '', + 'char_set' => 'utf8mb4', + 'dbcollat' => 'utf8_general_ci', + 'swap_pre' => '', + 'encrypt' => FALSE, + 'compress' => FALSE, + 'stricton' => FALSE, + 'failover' => array(), + 'save_queries' => TRUE +); diff --git a/market/config/doctypes.php b/market/config/doctypes.php new file mode 100644 index 00000000..59a7991e --- /dev/null +++ b/market/config/doctypes.php @@ -0,0 +1,24 @@ + '', + 'xhtml1-strict' => '', + 'xhtml1-trans' => '', + 'xhtml1-frame' => '', + 'xhtml-basic11' => '', + 'html5' => '', + 'html4-strict' => '', + 'html4-trans' => '', + 'html4-frame' => '', + 'mathml1' => '', + 'mathml2' => '', + 'svg10' => '', + 'svg11' => '', + 'svg11-basic' => '', + 'svg11-tiny' => '', + 'xhtml-math-svg-xh' => '', + 'xhtml-math-svg-sh' => '', + 'xhtml-rdfa-1' => '', + 'xhtml-rdfa-2' => '' +); diff --git a/market/config/foreign_chars.php b/market/config/foreign_chars.php new file mode 100644 index 00000000..995f4830 --- /dev/null +++ b/market/config/foreign_chars.php @@ -0,0 +1,103 @@ + 'ae', + '/ö|œ/' => 'oe', + '/ü/' => 'ue', + '/Ä/' => 'Ae', + '/Ü/' => 'Ue', + '/Ö/' => 'Oe', + '/À|Á|Â|Ã|Ä|Å|Ǻ|Ā|Ă|Ą|Ǎ|Α|Ά|Ả|Ạ|Ầ|Ẫ|Ẩ|Ậ|Ằ|Ắ|Ẵ|Ẳ|Ặ|А/' => 'A', + '/à|á|â|ã|å|ǻ|ā|ă|ą|ǎ|ª|α|ά|ả|ạ|ầ|ấ|ẫ|ẩ|ậ|ằ|ắ|ẵ|ẳ|ặ|а/' => 'a', + '/Б/' => 'B', + '/б/' => 'b', + '/Ç|Ć|Ĉ|Ċ|Č/' => 'C', + '/ç|ć|ĉ|ċ|č/' => 'c', + '/Д/' => 'D', + '/д/' => 'd', + '/Ð|Ď|Đ|Δ/' => 'Dj', + '/ð|ď|đ|δ/' => 'dj', + '/È|É|Ê|Ë|Ē|Ĕ|Ė|Ę|Ě|Ε|Έ|Ẽ|Ẻ|Ẹ|Ề|Ế|Ễ|Ể|Ệ|Е|Э/' => 'E', + '/è|é|ê|ë|ē|ĕ|ė|ę|ě|έ|ε|ẽ|ẻ|ẹ|ề|ế|ễ|ể|ệ|е|э/' => 'e', + '/Ф/' => 'F', + '/ф/' => 'f', + '/Ĝ|Ğ|Ġ|Ģ|Γ|Г|Ґ/' => 'G', + '/ĝ|ğ|ġ|ģ|γ|г|ґ/' => 'g', + '/Ĥ|Ħ/' => 'H', + '/ĥ|ħ/' => 'h', + '/Ì|Í|Î|Ï|Ĩ|Ī|Ĭ|Ǐ|Į|İ|Η|Ή|Ί|Ι|Ϊ|Ỉ|Ị|И|Ы/' => 'I', + '/ì|í|î|ï|ĩ|ī|ĭ|ǐ|į|ı|η|ή|ί|ι|ϊ|ỉ|ị|и|ы|ї/' => 'i', + '/Ĵ/' => 'J', + '/ĵ/' => 'j', + '/Ķ|Κ|К/' => 'K', + '/ķ|κ|к/' => 'k', + '/Ĺ|Ļ|Ľ|Ŀ|Ł|Λ|Л/' => 'L', + '/ĺ|ļ|ľ|ŀ|ł|λ|л/' => 'l', + '/М/' => 'M', + '/м/' => 'm', + '/Ñ|Ń|Ņ|Ň|Ν|Н/' => 'N', + '/ñ|ń|ņ|ň|ʼn|ν|н/' => 'n', + '/Ò|Ó|Ô|Õ|Ō|Ŏ|Ǒ|Ő|Ơ|Ø|Ǿ|Ο|Ό|Ω|Ώ|Ỏ|Ọ|Ồ|Ố|Ỗ|Ổ|Ộ|Ờ|Ớ|Ỡ|Ở|Ợ|О/' => 'O', + '/ò|ó|ô|õ|ō|ŏ|ǒ|ő|ơ|ø|ǿ|º|ο|ό|ω|ώ|ỏ|ọ|ồ|ố|ỗ|ổ|ộ|ờ|ớ|ỡ|ở|ợ|о/' => 'o', + '/П/' => 'P', + '/п/' => 'p', + '/Ŕ|Ŗ|Ř|Ρ|Р/' => 'R', + '/ŕ|ŗ|ř|ρ|р/' => 'r', + '/Ś|Ŝ|Ş|Ș|Š|Σ|С/' => 'S', + '/ś|ŝ|ş|ș|š|ſ|σ|ς|с/' => 's', + '/Ț|Ţ|Ť|Ŧ|τ|Т/' => 'T', + '/ț|ţ|ť|ŧ|т/' => 't', + '/Þ|þ/' => 'th', + '/Ù|Ú|Û|Ũ|Ū|Ŭ|Ů|Ű|Ų|Ư|Ǔ|Ǖ|Ǘ|Ǚ|Ǜ|Ũ|Ủ|Ụ|Ừ|Ứ|Ữ|Ử|Ự|У/' => 'U', + '/ù|ú|û|ũ|ū|ŭ|ů|ű|ų|ư|ǔ|ǖ|ǘ|ǚ|ǜ|υ|ύ|ϋ|ủ|ụ|ừ|ứ|ữ|ử|ự|у/' => 'u', + '/Ƴ|Ɏ|Ỵ|Ẏ|Ӳ|Ӯ|Ў|Ý|Ÿ|Ŷ|Υ|Ύ|Ϋ|Ỳ|Ỹ|Ỷ|Ỵ|Й/' => 'Y', + '/ẙ|ʏ|ƴ|ɏ|ỵ|ẏ|ӳ|ӯ|ў|ý|ÿ|ŷ|ỳ|ỹ|ỷ|ỵ|й/' => 'y', + '/В/' => 'V', + '/в/' => 'v', + '/Ŵ/' => 'W', + '/ŵ/' => 'w', + '/Ź|Ż|Ž|Ζ|З/' => 'Z', + '/ź|ż|ž|ζ|з/' => 'z', + '/Æ|Ǽ/' => 'AE', + '/ß/' => 'ss', + '/IJ/' => 'IJ', + '/ij/' => 'ij', + '/Œ/' => 'OE', + '/ƒ/' => 'f', + '/ξ/' => 'ks', + '/π/' => 'p', + '/β/' => 'v', + '/μ/' => 'm', + '/ψ/' => 'ps', + '/Ё/' => 'Yo', + '/ё/' => 'yo', + '/Є/' => 'Ye', + '/є/' => 'ye', + '/Ї/' => 'Yi', + '/Ж/' => 'Zh', + '/ж/' => 'zh', + '/Х/' => 'Kh', + '/х/' => 'kh', + '/Ц/' => 'Ts', + '/ц/' => 'ts', + '/Ч/' => 'Ch', + '/ч/' => 'ch', + '/Ш/' => 'Sh', + '/ш/' => 'sh', + '/Щ/' => 'Shch', + '/щ/' => 'shch', + '/Ъ|ъ|Ь|ь/' => '', + '/Ю/' => 'Yu', + '/ю/' => 'yu', + '/Я/' => 'Ya', + '/я/' => 'ya' +); diff --git a/market/config/hooks.php b/market/config/hooks.php new file mode 100644 index 00000000..89daf2f4 --- /dev/null +++ b/market/config/hooks.php @@ -0,0 +1,20 @@ + 'ApiAuthHook', + 'function' => 'index', + 'filename' => 'ApiAuthHook.php', + 'filepath' => 'hooks', + 'params' => [] +); diff --git a/market/config/index.html b/market/config/index.html new file mode 100644 index 00000000..b702fbc3 --- /dev/null +++ b/market/config/index.html @@ -0,0 +1,11 @@ + + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + diff --git a/market/config/jwt.php b/market/config/jwt.php new file mode 100644 index 00000000..20710f06 --- /dev/null +++ b/market/config/jwt.php @@ -0,0 +1,6 @@ + array( + 'hostname' => '192.168.0.16', + 'port' => '12001', + 'weight' => '1', + ), +); diff --git a/market/config/migration.php b/market/config/migration.php new file mode 100644 index 00000000..4b585a65 --- /dev/null +++ b/market/config/migration.php @@ -0,0 +1,84 @@ +migration->current() this is the version that schema will +| be upgraded / downgraded to. +| +*/ +$config['migration_version'] = 0; + +/* +|-------------------------------------------------------------------------- +| Migrations Path +|-------------------------------------------------------------------------- +| +| Path to your migrations folder. +| Typically, it will be within your application path. +| Also, writing permission is required within the migrations path. +| +*/ +$config['migration_path'] = APPPATH.'migrations/'; diff --git a/market/config/mimes.php b/market/config/mimes.php new file mode 100644 index 00000000..0ec9db0a --- /dev/null +++ b/market/config/mimes.php @@ -0,0 +1,184 @@ + array('application/mac-binhex40', 'application/mac-binhex', 'application/x-binhex40', 'application/x-mac-binhex40'), + 'cpt' => 'application/mac-compactpro', + 'csv' => array('text/x-comma-separated-values', 'text/comma-separated-values', 'application/octet-stream', 'application/vnd.ms-excel', 'application/x-csv', 'text/x-csv', 'text/csv', 'application/csv', 'application/excel', 'application/vnd.msexcel', 'text/plain'), + 'bin' => array('application/macbinary', 'application/mac-binary', 'application/octet-stream', 'application/x-binary', 'application/x-macbinary'), + 'dms' => 'application/octet-stream', + 'lha' => 'application/octet-stream', + 'lzh' => 'application/octet-stream', + 'exe' => array('application/octet-stream', 'application/x-msdownload'), + 'class' => 'application/octet-stream', + 'psd' => array('application/x-photoshop', 'image/vnd.adobe.photoshop'), + 'so' => 'application/octet-stream', + 'sea' => 'application/octet-stream', + 'dll' => 'application/octet-stream', + 'oda' => 'application/oda', + 'pdf' => array('application/pdf', 'application/force-download', 'application/x-download', 'binary/octet-stream'), + 'ai' => array('application/pdf', 'application/postscript'), + 'eps' => 'application/postscript', + 'ps' => 'application/postscript', + 'smi' => 'application/smil', + 'smil' => 'application/smil', + 'mif' => 'application/vnd.mif', + 'xls' => array('application/vnd.ms-excel', 'application/msexcel', 'application/x-msexcel', 'application/x-ms-excel', 'application/x-excel', 'application/x-dos_ms_excel', 'application/xls', 'application/x-xls', 'application/excel', 'application/download', 'application/vnd.ms-office', 'application/msword'), + 'ppt' => array('application/powerpoint', 'application/vnd.ms-powerpoint', 'application/vnd.ms-office', 'application/msword'), + 'pptx' => array('application/vnd.openxmlformats-officedocument.presentationml.presentation', 'application/x-zip', 'application/zip'), + 'wbxml' => 'application/wbxml', + 'wmlc' => 'application/wmlc', + 'dcr' => 'application/x-director', + 'dir' => 'application/x-director', + 'dxr' => 'application/x-director', + 'dvi' => 'application/x-dvi', + 'gtar' => 'application/x-gtar', + 'gz' => 'application/x-gzip', + 'gzip' => 'application/x-gzip', + 'php' => array('application/x-httpd-php', 'application/php', 'application/x-php', 'text/php', 'text/x-php', 'application/x-httpd-php-source'), + 'php4' => 'application/x-httpd-php', + 'php3' => 'application/x-httpd-php', + 'phtml' => 'application/x-httpd-php', + 'phps' => 'application/x-httpd-php-source', + 'js' => array('application/x-javascript', 'text/plain'), + 'swf' => 'application/x-shockwave-flash', + 'sit' => 'application/x-stuffit', + 'tar' => 'application/x-tar', + 'tgz' => array('application/x-tar', 'application/x-gzip-compressed'), + 'z' => 'application/x-compress', + 'xhtml' => 'application/xhtml+xml', + 'xht' => 'application/xhtml+xml', + 'zip' => array('application/x-zip', 'application/zip', 'application/x-zip-compressed', 'application/s-compressed', 'multipart/x-zip'), + 'rar' => array('application/x-rar', 'application/rar', 'application/x-rar-compressed'), + 'mid' => 'audio/midi', + 'midi' => 'audio/midi', + 'mpga' => 'audio/mpeg', + 'mp2' => 'audio/mpeg', + 'mp3' => array('audio/mpeg', 'audio/mpg', 'audio/mpeg3', 'audio/mp3'), + 'aif' => array('audio/x-aiff', 'audio/aiff'), + 'aiff' => array('audio/x-aiff', 'audio/aiff'), + 'aifc' => 'audio/x-aiff', + 'ram' => 'audio/x-pn-realaudio', + 'rm' => 'audio/x-pn-realaudio', + 'rpm' => 'audio/x-pn-realaudio-plugin', + 'ra' => 'audio/x-realaudio', + 'rv' => 'video/vnd.rn-realvideo', + 'wav' => array('audio/x-wav', 'audio/wave', 'audio/wav'), + 'bmp' => array('image/bmp', 'image/x-bmp', 'image/x-bitmap', 'image/x-xbitmap', 'image/x-win-bitmap', 'image/x-windows-bmp', 'image/ms-bmp', 'image/x-ms-bmp', 'application/bmp', 'application/x-bmp', 'application/x-win-bitmap'), + 'gif' => 'image/gif', + 'jpeg' => array('image/jpeg', 'image/pjpeg'), + 'jpg' => array('image/jpeg', 'image/pjpeg'), + 'jpe' => array('image/jpeg', 'image/pjpeg'), + 'jp2' => array('image/jp2', 'video/mj2', 'image/jpx', 'image/jpm'), + 'j2k' => array('image/jp2', 'video/mj2', 'image/jpx', 'image/jpm'), + 'jpf' => array('image/jp2', 'video/mj2', 'image/jpx', 'image/jpm'), + 'jpg2' => array('image/jp2', 'video/mj2', 'image/jpx', 'image/jpm'), + 'jpx' => array('image/jp2', 'video/mj2', 'image/jpx', 'image/jpm'), + 'jpm' => array('image/jp2', 'video/mj2', 'image/jpx', 'image/jpm'), + 'mj2' => array('image/jp2', 'video/mj2', 'image/jpx', 'image/jpm'), + 'mjp2' => array('image/jp2', 'video/mj2', 'image/jpx', 'image/jpm'), + 'png' => array('image/png', 'image/x-png'), + 'tiff' => 'image/tiff', + 'tif' => 'image/tiff', + 'css' => array('text/css', 'text/plain'), + 'html' => array('text/html', 'text/plain'), + 'htm' => array('text/html', 'text/plain'), + 'shtml' => array('text/html', 'text/plain'), + 'txt' => 'text/plain', + 'text' => 'text/plain', + 'log' => array('text/plain', 'text/x-log'), + 'rtx' => 'text/richtext', + 'rtf' => 'text/rtf', + 'xml' => array('application/xml', 'text/xml', 'text/plain'), + 'xsl' => array('application/xml', 'text/xsl', 'text/xml'), + 'mpeg' => 'video/mpeg', + 'mpg' => 'video/mpeg', + 'mpe' => 'video/mpeg', + 'qt' => 'video/quicktime', + 'mov' => 'video/quicktime', + 'avi' => array('video/x-msvideo', 'video/msvideo', 'video/avi', 'application/x-troff-msvideo'), + 'movie' => 'video/x-sgi-movie', + 'doc' => array('application/msword', 'application/vnd.ms-office'), + 'docx' => array('application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/zip', 'application/msword', 'application/x-zip'), + 'dot' => array('application/msword', 'application/vnd.ms-office'), + 'dotx' => array('application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/zip', 'application/msword'), + 'xlsx' => array('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/zip', 'application/vnd.ms-excel', 'application/msword', 'application/x-zip'), + 'word' => array('application/msword', 'application/octet-stream'), + 'xl' => 'application/excel', + 'eml' => 'message/rfc822', + 'json' => array('application/json', 'text/json'), + 'pem' => array('application/x-x509-user-cert', 'application/x-pem-file', 'application/octet-stream'), + 'p10' => array('application/x-pkcs10', 'application/pkcs10'), + 'p12' => 'application/x-pkcs12', + 'p7a' => 'application/x-pkcs7-signature', + 'p7c' => array('application/pkcs7-mime', 'application/x-pkcs7-mime'), + 'p7m' => array('application/pkcs7-mime', 'application/x-pkcs7-mime'), + 'p7r' => 'application/x-pkcs7-certreqresp', + 'p7s' => 'application/pkcs7-signature', + 'crt' => array('application/x-x509-ca-cert', 'application/x-x509-user-cert', 'application/pkix-cert'), + 'crl' => array('application/pkix-crl', 'application/pkcs-crl'), + 'der' => 'application/x-x509-ca-cert', + 'kdb' => 'application/octet-stream', + 'pgp' => 'application/pgp', + 'gpg' => 'application/gpg-keys', + 'sst' => 'application/octet-stream', + 'csr' => 'application/octet-stream', + 'rsa' => 'application/x-pkcs7', + 'cer' => array('application/pkix-cert', 'application/x-x509-ca-cert'), + '3g2' => 'video/3gpp2', + '3gp' => array('video/3gp', 'video/3gpp'), + 'mp4' => 'video/mp4', + 'm4a' => 'audio/x-m4a', + 'f4v' => array('video/mp4', 'video/x-f4v'), + 'flv' => 'video/x-flv', + 'webm' => 'video/webm', + 'aac' => 'audio/x-acc', + 'm4u' => 'application/vnd.mpegurl', + 'm3u' => 'text/plain', + 'xspf' => 'application/xspf+xml', + 'vlc' => 'application/videolan', + 'wmv' => array('video/x-ms-wmv', 'video/x-ms-asf'), + 'au' => 'audio/x-au', + 'ac3' => 'audio/ac3', + 'flac' => 'audio/x-flac', + 'ogg' => array('audio/ogg', 'video/ogg', 'application/ogg'), + 'kmz' => array('application/vnd.google-earth.kmz', 'application/zip', 'application/x-zip'), + 'kml' => array('application/vnd.google-earth.kml+xml', 'application/xml', 'text/xml'), + 'ics' => 'text/calendar', + 'ical' => 'text/calendar', + 'zsh' => 'text/x-scriptzsh', + '7z' => array('application/x-7z-compressed', 'application/x-compressed', 'application/x-zip-compressed', 'application/zip', 'multipart/x-zip'), + '7zip' => array('application/x-7z-compressed', 'application/x-compressed', 'application/x-zip-compressed', 'application/zip', 'multipart/x-zip'), + 'cdr' => array('application/cdr', 'application/coreldraw', 'application/x-cdr', 'application/x-coreldraw', 'image/cdr', 'image/x-cdr', 'zz-application/zz-winassoc-cdr'), + 'wma' => array('audio/x-ms-wma', 'video/x-ms-asf'), + 'jar' => array('application/java-archive', 'application/x-java-application', 'application/x-jar', 'application/x-compressed'), + 'svg' => array('image/svg+xml', 'application/xml', 'text/xml'), + 'vcf' => 'text/x-vcard', + 'srt' => array('text/srt', 'text/plain'), + 'vtt' => array('text/vtt', 'text/plain'), + 'ico' => array('image/x-icon', 'image/x-ico', 'image/vnd.microsoft.icon'), + 'odc' => 'application/vnd.oasis.opendocument.chart', + 'otc' => 'application/vnd.oasis.opendocument.chart-template', + 'odf' => 'application/vnd.oasis.opendocument.formula', + 'otf' => 'application/vnd.oasis.opendocument.formula-template', + 'odg' => 'application/vnd.oasis.opendocument.graphics', + 'otg' => 'application/vnd.oasis.opendocument.graphics-template', + 'odi' => 'application/vnd.oasis.opendocument.image', + 'oti' => 'application/vnd.oasis.opendocument.image-template', + 'odp' => 'application/vnd.oasis.opendocument.presentation', + 'otp' => 'application/vnd.oasis.opendocument.presentation-template', + 'ods' => 'application/vnd.oasis.opendocument.spreadsheet', + 'ots' => 'application/vnd.oasis.opendocument.spreadsheet-template', + 'odt' => 'application/vnd.oasis.opendocument.text', + 'odm' => 'application/vnd.oasis.opendocument.text-master', + 'ott' => 'application/vnd.oasis.opendocument.text-template', + 'oth' => 'application/vnd.oasis.opendocument.text-web' +); diff --git a/market/config/mongo.php b/market/config/mongo.php new file mode 100644 index 00000000..20df9c11 --- /dev/null +++ b/market/config/mongo.php @@ -0,0 +1,11 @@ +function($username, $password) +| In other cases override the function _perform_library_auth in your controller +| +| For digest authentication the library function should return already a stored +| md5(username:restrealm:password) for that username +| +| e.g: md5('admin:REST API:1234') = '1e957ebc35631ab22d5bd6526bd14ea2' +| +*/ +$config['auth_library_class'] = ''; +$config['auth_library_function'] = ''; + +/* +|-------------------------------------------------------------------------- +| Override auth types for specific class/method +|-------------------------------------------------------------------------- +| +| Set specific authentication types for methods within a class (controller) +| +| Set as many config entries as needed. Any methods not set will use the default 'rest_auth' config value. +| +| e.g: +| +| $config['auth_override_class_method']['deals']['view'] = 'none'; +| $config['auth_override_class_method']['deals']['insert'] = 'digest'; +| $config['auth_override_class_method']['accounts']['user'] = 'basic'; +| $config['auth_override_class_method']['dashboard']['*'] = 'none|digest|basic'; +| +| Here 'deals', 'accounts' and 'dashboard' are controller names, 'view', 'insert' and 'user' are methods within. An asterisk may also be used to specify an authentication method for an entire classes methods. Ex: $config['auth_override_class_method']['dashboard']['*'] = 'basic'; (NOTE: leave off the '_get' or '_post' from the end of the method name) +| Acceptable values are; 'none', 'digest' and 'basic'. +| +*/ +// $config['auth_override_class_method']['deals']['view'] = 'none'; +// $config['auth_override_class_method']['deals']['insert'] = 'digest'; +// $config['auth_override_class_method']['accounts']['user'] = 'basic'; +// $config['auth_override_class_method']['dashboard']['*'] = 'basic'; + + +// ---Uncomment list line for the wildard unit test +// $config['auth_override_class_method']['wildcard_test_cases']['*'] = 'basic'; + +/* +|-------------------------------------------------------------------------- +| Override auth types for specific 'class/method/HTTP method' +|-------------------------------------------------------------------------- +| +| example: +| +| $config['auth_override_class_method_http']['deals']['view']['get'] = 'none'; +| $config['auth_override_class_method_http']['deals']['insert']['post'] = 'none'; +| $config['auth_override_class_method_http']['deals']['*']['options'] = 'none'; +*/ + +// ---Uncomment list line for the wildard unit test +// $config['auth_override_class_method_http']['wildcard_test_cases']['*']['options'] = 'basic'; + +/* +|-------------------------------------------------------------------------- +| REST Login Usernames +|-------------------------------------------------------------------------- +| +| Array of usernames and passwords for login, if ldap is configured this is ignored +| +*/ +$config['rest_valid_logins'] = ['admin' => '1234']; + +/* +|-------------------------------------------------------------------------- +| Global IP White-listing +|-------------------------------------------------------------------------- +| +| Limit connections to your REST server to White-listed IP addresses +| +| Usage: +| 1. Set to TRUE and select an auth option for extreme security (client's IP +| address must be in white-list and they must also log in) +| 2. Set to TRUE with auth set to FALSE to allow White-listed IPs access with no login +| 3. Set to FALSE but set 'auth_override_class_method' to 'white-list' to +| restrict certain methods to IPs in your white-list +| +*/ +$config['rest_ip_whitelist_enabled'] = FALSE; + +/* +|-------------------------------------------------------------------------- +| REST Handle Exceptions +|-------------------------------------------------------------------------- +| +| Handle exceptions caused by the controller +| +*/ +$config['rest_handle_exceptions'] = TRUE; + +/* +|-------------------------------------------------------------------------- +| REST IP White-list +|-------------------------------------------------------------------------- +| +| Limit connections to your REST server with a comma separated +| list of IP addresses +| +| e.g: '123.456.789.0, 987.654.32.1' +| +| 127.0.0.1 and 0.0.0.0 are allowed by default +| +*/ +$config['rest_ip_whitelist'] = ''; + +/* +|-------------------------------------------------------------------------- +| Global IP Blacklisting +|-------------------------------------------------------------------------- +| +| Prevent connections to the REST server from blacklisted IP addresses +| +| Usage: +| 1. Set to TRUE and add any IP address to 'rest_ip_blacklist' +| +*/ +$config['rest_ip_blacklist_enabled'] = FALSE; + +/* +|-------------------------------------------------------------------------- +| REST IP Blacklist +|-------------------------------------------------------------------------- +| +| Prevent connections from the following IP addresses +| +| e.g: '123.456.789.0, 987.654.32.1' +| +*/ +$config['rest_ip_blacklist'] = ''; + +/* +|-------------------------------------------------------------------------- +| REST Database Group +|-------------------------------------------------------------------------- +| +| Connect to a database group for keys, logging, etc. It will only connect +| if you have any of these features enabled +| +*/ +$config['rest_database_group'] = 'default'; + +/* +|-------------------------------------------------------------------------- +| REST API Keys Table Name +|-------------------------------------------------------------------------- +| +| The table name in your database that stores API keys +| +*/ +$config['rest_keys_table'] = 'keys'; + +/* +|-------------------------------------------------------------------------- +| REST Enable Keys +|-------------------------------------------------------------------------- +| +| When set to TRUE, the REST API will look for a column name called 'key'. +| If no key is provided, the request will result in an error. To override the +| column name see 'rest_key_column' +| +| Default table schema: +| CREATE TABLE `keys` ( +| `id` INT(11) NOT NULL AUTO_INCREMENT, +| `user_id` INT(11) NOT NULL, +| `key` VARCHAR(40) NOT NULL, +| `level` INT(2) NOT NULL, +| `ignore_limits` TINYINT(1) NOT NULL DEFAULT '0', +| `is_private_key` TINYINT(1) NOT NULL DEFAULT '0', +| `ip_addresses` TEXT NULL DEFAULT NULL, +| `date_created` INT(11) NOT NULL, +| PRIMARY KEY (`id`) +| ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +| +*/ +$config['rest_enable_keys'] = FALSE; + +/* +|-------------------------------------------------------------------------- +| REST Table Key Column Name +|-------------------------------------------------------------------------- +| +| If not using the default table schema in 'rest_enable_keys', specify the +| column name to match e.g. my_key +| +*/ +$config['rest_key_column'] = 'key'; + +/* +|-------------------------------------------------------------------------- +| REST API Limits method +|-------------------------------------------------------------------------- +| +| Specify the method used to limit the API calls +| +| Available methods are : +| $config['rest_limits_method'] = 'IP_ADDRESS'; // Put a limit per ip address +| $config['rest_limits_method'] = 'API_KEY'; // Put a limit per api key +| $config['rest_limits_method'] = 'METHOD_NAME'; // Put a limit on method calls +| $config['rest_limits_method'] = 'ROUTED_URL'; // Put a limit on the routed URL +| +*/ +$config['rest_limits_method'] = 'ROUTED_URL'; + +/* +|-------------------------------------------------------------------------- +| REST Key Length +|-------------------------------------------------------------------------- +| +| Length of the created keys. Check your default database schema on the +| maximum length allowed +| +| Note: The maximum length is 40 +| +*/ +$config['rest_key_length'] = 40; + +/* +|-------------------------------------------------------------------------- +| REST API Key Variable +|-------------------------------------------------------------------------- +| +| Custom header to specify the API key + +| Note: Custom headers with the X- prefix are deprecated as of +| 2012/06/12. See RFC 6648 specification for more details +| +*/ +$config['rest_key_name'] = 'X-API-KEY'; + +/* +|-------------------------------------------------------------------------- +| REST Enable Logging +|-------------------------------------------------------------------------- +| +| When set to TRUE, the REST API will log actions based on the column names 'key', 'date', +| 'time' and 'ip_address'. This is a general rule that can be overridden in the +| $this->method array for each controller +| +| Default table schema: +| CREATE TABLE `logs` ( +| `id` INT(11) NOT NULL AUTO_INCREMENT, +| `uri` VARCHAR(255) NOT NULL, +| `method` VARCHAR(6) NOT NULL, +| `params` TEXT DEFAULT NULL, +| `api_key` VARCHAR(40) NOT NULL, +| `ip_address` VARCHAR(45) NOT NULL, +| `time` INT(11) NOT NULL, +| `rtime` FLOAT DEFAULT NULL, +| `authorized` VARCHAR(1) NOT NULL, +| `response_code` smallint(3) DEFAULT '0', +| PRIMARY KEY (`id`) +| ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +| +*/ +$config['rest_enable_logging'] = FALSE; + +/* +|-------------------------------------------------------------------------- +| REST API Logs Table Name +|-------------------------------------------------------------------------- +| +| If not using the default table schema in 'rest_enable_logging', specify the +| table name to match e.g. my_logs +| +*/ +$config['rest_logs_table'] = 'logs'; + +/* +|-------------------------------------------------------------------------- +| REST Method Access Control +|-------------------------------------------------------------------------- +| When set to TRUE, the REST API will check the access table to see if +| the API key can access that controller. 'rest_enable_keys' must be enabled +| to use this +| +| Default table schema: +| CREATE TABLE `access` ( +| `id` INT(11) unsigned NOT NULL AUTO_INCREMENT, +| `key` VARCHAR(40) NOT NULL DEFAULT '', +| `all_access` TINYINT(1) NOT NULL DEFAULT '0', +| `controller` VARCHAR(50) NOT NULL DEFAULT '', +| `date_created` DATETIME DEFAULT NULL, +| `date_modified` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, +| PRIMARY KEY (`id`) +| ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +| +*/ +$config['rest_enable_access'] = FALSE; + +/* +|-------------------------------------------------------------------------- +| REST API Access Table Name +|-------------------------------------------------------------------------- +| +| If not using the default table schema in 'rest_enable_access', specify the +| table name to match e.g. my_access +| +*/ +$config['rest_access_table'] = 'access'; + +/* +|-------------------------------------------------------------------------- +| REST API Param Log Format +|-------------------------------------------------------------------------- +| +| When set to TRUE, the REST API log parameters will be stored in the database as JSON +| Set to FALSE to log as serialized PHP +| +*/ +$config['rest_logs_json_params'] = FALSE; + +/* +|-------------------------------------------------------------------------- +| REST Enable Limits +|-------------------------------------------------------------------------- +| +| When set to TRUE, the REST API will count the number of uses of each method +| by an API key each hour. This is a general rule that can be overridden in the +| $this->method array in each controller +| +| Default table schema: +| CREATE TABLE `limits` ( +| `id` INT(11) NOT NULL AUTO_INCREMENT, +| `uri` VARCHAR(255) NOT NULL, +| `count` INT(10) NOT NULL, +| `hour_started` INT(11) NOT NULL, +| `api_key` VARCHAR(40) NOT NULL, +| PRIMARY KEY (`id`) +| ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +| +| To specify the limits within the controller's __construct() method, add per-method +| limits with: +| +| $this->method['METHOD_NAME']['limit'] = [NUM_REQUESTS_PER_HOUR]; +| +| See application/controllers/api/example.php for examples +*/ +$config['rest_enable_limits'] = FALSE; + +/* +|-------------------------------------------------------------------------- +| REST API Limits Table Name +|-------------------------------------------------------------------------- +| +| If not using the default table schema in 'rest_enable_limits', specify the +| table name to match e.g. my_limits +| +*/ +$config['rest_limits_table'] = 'limits'; + +/* +|-------------------------------------------------------------------------- +| REST Ignore HTTP Accept +|-------------------------------------------------------------------------- +| +| Set to TRUE to ignore the HTTP Accept and speed up each request a little. +| Only do this if you are using the $this->rest_format or /format/xml in URLs +| +*/ +$config['rest_ignore_http_accept'] = FALSE; + +/* +|-------------------------------------------------------------------------- +| REST AJAX Only +|-------------------------------------------------------------------------- +| +| Set to TRUE to allow AJAX requests only. Set to FALSE to accept HTTP requests +| +| Note: If set to TRUE and the request is not AJAX, a 505 response with the +| error message 'Only AJAX requests are accepted.' will be returned. +| +| Hint: This is good for production environments +| +*/ +$config['rest_ajax_only'] = FALSE; + +/* +|-------------------------------------------------------------------------- +| REST Language File +|-------------------------------------------------------------------------- +| +| Language file to load from the language directory +| +*/ +$config['rest_language'] = 'english'; + +/* +|-------------------------------------------------------------------------- +| CORS Check +|-------------------------------------------------------------------------- +| +| Set to TRUE to enable Cross-Origin Resource Sharing (CORS). Useful if you +| are hosting your API on a different domain from the application that +| will access it through a browser +| +*/ +$config['check_cors'] = TRUE; + +/* +|-------------------------------------------------------------------------- +| CORS Allowable Headers +|-------------------------------------------------------------------------- +| +| If using CORS checks, set the allowable headers here +| +*/ +$config['allowed_cors_headers'] = [ + 'Origin', + 'X-Requested-With', + 'Content-Type', + 'Accept', + 'Access-Control-Request-Method' +]; + +/* +|-------------------------------------------------------------------------- +| CORS Allowable Methods +|-------------------------------------------------------------------------- +| +| If using CORS checks, you can set the methods you want to be allowed +| +*/ +$config['allowed_cors_methods'] = [ + 'GET', + 'POST', + 'OPTIONS', + 'PUT', + 'PATCH', + 'DELETE' +]; + +/* +|-------------------------------------------------------------------------- +| CORS Allow Any Domain +|-------------------------------------------------------------------------- +| +| Set to TRUE to enable Cross-Origin Resource Sharing (CORS) from any +| source domain +| +*/ +$config['allow_any_cors_domain'] = TRUE; + +/* +|-------------------------------------------------------------------------- +| CORS Allowable Domains +|-------------------------------------------------------------------------- +| +| Used if $config['check_cors'] is set to TRUE and $config['allow_any_cors_domain'] +| is set to FALSE. Set all the allowable domains within the array +| +| e.g. $config['allowed_origins'] = ['http://www.example.com', 'https://spa.example.com'] +| +*/ +$config['allowed_cors_origins'] = []; diff --git a/market/config/routes.php b/market/config/routes.php new file mode 100644 index 00000000..1b45740d --- /dev/null +++ b/market/config/routes.php @@ -0,0 +1,54 @@ + my_controller/index +| my-controller/my-method -> my_controller/my_method +*/ +$route['default_controller'] = 'welcome'; +$route['404_override'] = ''; +$route['translate_uri_dashes'] = FALSE; diff --git a/market/config/smileys.php b/market/config/smileys.php new file mode 100644 index 00000000..abf9a898 --- /dev/null +++ b/market/config/smileys.php @@ -0,0 +1,64 @@ + array('grin.gif', '19', '19', 'grin'), + ':lol:' => array('lol.gif', '19', '19', 'LOL'), + ':cheese:' => array('cheese.gif', '19', '19', 'cheese'), + ':)' => array('smile.gif', '19', '19', 'smile'), + ';-)' => array('wink.gif', '19', '19', 'wink'), + ';)' => array('wink.gif', '19', '19', 'wink'), + ':smirk:' => array('smirk.gif', '19', '19', 'smirk'), + ':roll:' => array('rolleyes.gif', '19', '19', 'rolleyes'), + ':-S' => array('confused.gif', '19', '19', 'confused'), + ':wow:' => array('surprise.gif', '19', '19', 'surprised'), + ':bug:' => array('bigsurprise.gif', '19', '19', 'big surprise'), + ':-P' => array('tongue_laugh.gif', '19', '19', 'tongue laugh'), + '%-P' => array('tongue_rolleye.gif', '19', '19', 'tongue rolleye'), + ';-P' => array('tongue_wink.gif', '19', '19', 'tongue wink'), + ':P' => array('raspberry.gif', '19', '19', 'raspberry'), + ':blank:' => array('blank.gif', '19', '19', 'blank stare'), + ':long:' => array('longface.gif', '19', '19', 'long face'), + ':ohh:' => array('ohh.gif', '19', '19', 'ohh'), + ':grrr:' => array('grrr.gif', '19', '19', 'grrr'), + ':gulp:' => array('gulp.gif', '19', '19', 'gulp'), + '8-/' => array('ohoh.gif', '19', '19', 'oh oh'), + ':down:' => array('downer.gif', '19', '19', 'downer'), + ':red:' => array('embarrassed.gif', '19', '19', 'red face'), + ':sick:' => array('sick.gif', '19', '19', 'sick'), + ':shut:' => array('shuteye.gif', '19', '19', 'shut eye'), + ':-/' => array('hmm.gif', '19', '19', 'hmmm'), + '>:(' => array('mad.gif', '19', '19', 'mad'), + ':mad:' => array('mad.gif', '19', '19', 'mad'), + '>:-(' => array('angry.gif', '19', '19', 'angry'), + ':angry:' => array('angry.gif', '19', '19', 'angry'), + ':zip:' => array('zip.gif', '19', '19', 'zipper'), + ':kiss:' => array('kiss.gif', '19', '19', 'kiss'), + ':ahhh:' => array('shock.gif', '19', '19', 'shock'), + ':coolsmile:' => array('shade_smile.gif', '19', '19', 'cool smile'), + ':coolsmirk:' => array('shade_smirk.gif', '19', '19', 'cool smirk'), + ':coolgrin:' => array('shade_grin.gif', '19', '19', 'cool grin'), + ':coolhmm:' => array('shade_hmm.gif', '19', '19', 'cool hmm'), + ':coolmad:' => array('shade_mad.gif', '19', '19', 'cool mad'), + ':coolcheese:' => array('shade_cheese.gif', '19', '19', 'cool cheese'), + ':vampire:' => array('vampire.gif', '19', '19', 'vampire'), + ':snake:' => array('snake.gif', '19', '19', 'snake'), + ':exclaim:' => array('exclaim.gif', '19', '19', 'exclaim'), + ':question:' => array('question.gif', '19', '19', 'question') + +); diff --git a/market/config/sphinx.php b/market/config/sphinx.php new file mode 100644 index 00000000..f40308bf --- /dev/null +++ b/market/config/sphinx.php @@ -0,0 +1,6 @@ + 'Windows 10', + 'windows nt 6.3' => 'Windows 8.1', + 'windows nt 6.2' => 'Windows 8', + 'windows nt 6.1' => 'Windows 7', + 'windows nt 6.0' => 'Windows Vista', + 'windows nt 5.2' => 'Windows 2003', + 'windows nt 5.1' => 'Windows XP', + 'windows nt 5.0' => 'Windows 2000', + 'windows nt 4.0' => 'Windows NT 4.0', + 'winnt4.0' => 'Windows NT 4.0', + 'winnt 4.0' => 'Windows NT', + 'winnt' => 'Windows NT', + 'windows 98' => 'Windows 98', + 'win98' => 'Windows 98', + 'windows 95' => 'Windows 95', + 'win95' => 'Windows 95', + 'windows phone' => 'Windows Phone', + 'windows' => 'Unknown Windows OS', + 'android' => 'Android', + 'blackberry' => 'BlackBerry', + 'iphone' => 'iOS', + 'ipad' => 'iOS', + 'ipod' => 'iOS', + 'os x' => 'Mac OS X', + 'ppc mac' => 'Power PC Mac', + 'freebsd' => 'FreeBSD', + 'ppc' => 'Macintosh', + 'linux' => 'Linux', + 'debian' => 'Debian', + 'sunos' => 'Sun Solaris', + 'beos' => 'BeOS', + 'apachebench' => 'ApacheBench', + 'aix' => 'AIX', + 'irix' => 'Irix', + 'osf' => 'DEC OSF', + 'hp-ux' => 'HP-UX', + 'netbsd' => 'NetBSD', + 'bsdi' => 'BSDi', + 'openbsd' => 'OpenBSD', + 'gnu' => 'GNU/Linux', + 'unix' => 'Unknown Unix OS', + 'symbian' => 'Symbian OS' +); + + +// The order of this array should NOT be changed. Many browsers return +// multiple browser types so we want to identify the sub-type first. +$browsers = array( + 'OPR' => 'Opera', + 'Flock' => 'Flock', + 'Edge' => 'Edge', + 'Chrome' => 'Chrome', + // Opera 10+ always reports Opera/9.80 and appends Version/ to the user agent string + 'Opera.*?Version' => 'Opera', + 'Opera' => 'Opera', + 'MSIE' => 'Internet Explorer', + 'Internet Explorer' => 'Internet Explorer', + 'Trident.* rv' => 'Internet Explorer', + 'Shiira' => 'Shiira', + 'Firefox' => 'Firefox', + 'Chimera' => 'Chimera', + 'Phoenix' => 'Phoenix', + 'Firebird' => 'Firebird', + 'Camino' => 'Camino', + 'Netscape' => 'Netscape', + 'OmniWeb' => 'OmniWeb', + 'Safari' => 'Safari', + 'Mozilla' => 'Mozilla', + 'Konqueror' => 'Konqueror', + 'icab' => 'iCab', + 'Lynx' => 'Lynx', + 'Links' => 'Links', + 'hotjava' => 'HotJava', + 'amaya' => 'Amaya', + 'IBrowse' => 'IBrowse', + 'Maxthon' => 'Maxthon', + 'Ubuntu' => 'Ubuntu Web Browser' +); + +$mobiles = array( + // legacy array, old values commented out + 'mobileexplorer' => 'Mobile Explorer', +// 'openwave' => 'Open Wave', +// 'opera mini' => 'Opera Mini', +// 'operamini' => 'Opera Mini', +// 'elaine' => 'Palm', + 'palmsource' => 'Palm', +// 'digital paths' => 'Palm', +// 'avantgo' => 'Avantgo', +// 'xiino' => 'Xiino', + 'palmscape' => 'Palmscape', +// 'nokia' => 'Nokia', +// 'ericsson' => 'Ericsson', +// 'blackberry' => 'BlackBerry', +// 'motorola' => 'Motorola' + + // Phones and Manufacturers + 'motorola' => 'Motorola', + 'nokia' => 'Nokia', + 'palm' => 'Palm', + 'iphone' => 'Apple iPhone', + 'ipad' => 'iPad', + 'ipod' => 'Apple iPod Touch', + 'sony' => 'Sony Ericsson', + 'ericsson' => 'Sony Ericsson', + 'blackberry' => 'BlackBerry', + 'cocoon' => 'O2 Cocoon', + 'blazer' => 'Treo', + 'lg' => 'LG', + 'amoi' => 'Amoi', + 'xda' => 'XDA', + 'mda' => 'MDA', + 'vario' => 'Vario', + 'htc' => 'HTC', + 'samsung' => 'Samsung', + 'sharp' => 'Sharp', + 'sie-' => 'Siemens', + 'alcatel' => 'Alcatel', + 'benq' => 'BenQ', + 'ipaq' => 'HP iPaq', + 'mot-' => 'Motorola', + 'playstation portable' => 'PlayStation Portable', + 'playstation 3' => 'PlayStation 3', + 'playstation vita' => 'PlayStation Vita', + 'hiptop' => 'Danger Hiptop', + 'nec-' => 'NEC', + 'panasonic' => 'Panasonic', + 'philips' => 'Philips', + 'sagem' => 'Sagem', + 'sanyo' => 'Sanyo', + 'spv' => 'SPV', + 'zte' => 'ZTE', + 'sendo' => 'Sendo', + 'nintendo dsi' => 'Nintendo DSi', + 'nintendo ds' => 'Nintendo DS', + 'nintendo 3ds' => 'Nintendo 3DS', + 'wii' => 'Nintendo Wii', + 'open web' => 'Open Web', + 'openweb' => 'OpenWeb', + + // Operating Systems + 'android' => 'Android', + 'symbian' => 'Symbian', + 'SymbianOS' => 'SymbianOS', + 'elaine' => 'Palm', + 'series60' => 'Symbian S60', + 'windows ce' => 'Windows CE', + + // Browsers + 'obigo' => 'Obigo', + 'netfront' => 'Netfront Browser', + 'openwave' => 'Openwave Browser', + 'mobilexplorer' => 'Mobile Explorer', + 'operamini' => 'Opera Mini', + 'opera mini' => 'Opera Mini', + 'opera mobi' => 'Opera Mobile', + 'fennec' => 'Firefox Mobile', + + // Other + 'digital paths' => 'Digital Paths', + 'avantgo' => 'AvantGo', + 'xiino' => 'Xiino', + 'novarra' => 'Novarra Transcoder', + 'vodafone' => 'Vodafone', + 'docomo' => 'NTT DoCoMo', + 'o2' => 'O2', + + // Fallback + 'mobile' => 'Generic Mobile', + 'wireless' => 'Generic Mobile', + 'j2me' => 'Generic Mobile', + 'midp' => 'Generic Mobile', + 'cldc' => 'Generic Mobile', + 'up.link' => 'Generic Mobile', + 'up.browser' => 'Generic Mobile', + 'smartphone' => 'Generic Mobile', + 'cellphone' => 'Generic Mobile' +); + +// There are hundreds of bots but these are the most common. +$robots = array( + 'googlebot' => 'Googlebot', + 'msnbot' => 'MSNBot', + 'baiduspider' => 'Baiduspider', + 'bingbot' => 'Bing', + 'slurp' => 'Inktomi Slurp', + 'yahoo' => 'Yahoo', + 'ask jeeves' => 'Ask Jeeves', + 'fastcrawler' => 'FastCrawler', + 'infoseek' => 'InfoSeek Robot 1.0', + 'lycos' => 'Lycos', + 'yandex' => 'YandexBot', + 'mediapartners-google' => 'MediaPartners Google', + 'CRAZYWEBCRAWLER' => 'Crazy Webcrawler', + 'adsbot-google' => 'AdsBot Google', + 'feedfetcher-google' => 'Feedfetcher Google', + 'curious george' => 'Curious George', + 'ia_archiver' => 'Alexa Crawler', + 'MJ12bot' => 'Majestic-12', + 'Uptimebot' => 'Uptimebot' +); diff --git a/market/controllers/Welcome.php b/market/controllers/Welcome.php new file mode 100644 index 00000000..a6a067bb --- /dev/null +++ b/market/controllers/Welcome.php @@ -0,0 +1,16 @@ +load->view('welcome_message'); + } + + public function test(){ + echo '11'; + } +} diff --git a/market/controllers/api/BaseController.php b/market/controllers/api/BaseController.php new file mode 100644 index 00000000..d3ee9c08 --- /dev/null +++ b/market/controllers/api/BaseController.php @@ -0,0 +1,107 @@ +input_param(); + $this->start_time = microtime(true); + } + + /** + * Notes:获取参数 + * Created on: 2022/9/2 16:57 + * Created by: dengbw + * @param string $key + * @return mixed + */ + function input_param($key = '') + { + if ($key) { + return $this->inputs[$key]; + } + $request = $this->input->method(); + switch ($request) { + case 'post': + case 'put': + case 'delete': + $input = json_decode(file_get_contents('php://input'), true); + break; + default: + $input = $this->input->get(); + } + $this->inputs = $input; + return $this->inputs; + } + + /** + * Notes:返回json + * Created on: 2022/9/8 15:35 + * Created by: dengbw + * @param string $message + * @param int $code + */ + public function return_json($message = '', $code = 1) + { + header('Content-Type:application/json; charset=utf-8'); + echo json_encode(['code' => $code, 'message' => $message], JSON_UNESCAPED_UNICODE); + exit(); + } + + /** + * Notes:返回response + * Created on: 2022/9/9 15:39 + * Created by: dengbw + * @param array $data + */ + public function return_response_list($data = []) + { + $this->return_response($data, '操作成功', 0, 1); + } + + /** + * Notes:返回response + * Created on: 2022/9/8 15:21 + * Created by: dengbw + * @param array $data + * @param string $message + * @param int $code + * @param int $if_list + * @param int $http_code + */ + public function return_response($data = [], $message = '操作成功', $code = 0, $if_list = 0, $http_code = REST_Controller::HTTP_OK) + { + $set_data = ['code' => $code, 'message' => $message]; + if ($if_list) {//列表显示空数据 + $set_data['data'] = $data; + } else { + $data && $set_data['data'] = $data; + } + if ($_SESSION['operation_description']) {//添加操作日志 + $this->load->library('api/record'); + $method = lcfirst(get_class($this)); + $end_time = microtime(true); + $spendTime = ($end_time - $this->start_time) * 1000; //计算差值 毫秒 + $this->record->operationRecord(['userId' => $_SESSION['userId'], 'username' => $_SESSION['username'] + , 'nickname' => $_SESSION['nickname'], 'method' => $method, 'spendTime' => $spendTime + , 'module' => $_SESSION['operation_module'], 'description' => $_SESSION['operation_description'] + , 'params' => json_encode($this->inputs, JSON_UNESCAPED_UNICODE) + , 'result' => json_encode($set_data, JSON_UNESCAPED_UNICODE)]); + } + $this->response($set_data, $http_code, TRUE); + } + +} \ No newline at end of file diff --git a/market/controllers/api/Captcha.php b/market/controllers/api/Captcha.php new file mode 100644 index 00000000..621d23ad --- /dev/null +++ b/market/controllers/api/Captcha.php @@ -0,0 +1,43 @@ +redis = &load_cache('redis'); + } + + public function index_get() + { + $this->load->library('MyCaptcha'); + $myCaptcha = new MyCaptcha(); + $re = $myCaptcha->create(5, ['width' => 16, 'height' => 20, 'pnum' => 50, 'base64' => 1]); + $code_key = $this->generateSign(); + $this->redis->save($code_key, $re['text'], 5 * 60); + $data = ['base64' => $re['base64'], 'code_key' => $code_key]; + $this->return_response($data); + } + + function generateSign() + { + $sign = md5(mt_rand() . 'mycaptchamarket'); + // 拼接上签名作为 Redis 的 key + $key = 'code_' . $sign; + if ($this->redis->exists($key)) { + // 如果生成的 Sign 已存在,就进行递归,直到生成出一个不存在的。 + return $this->generateSign(); + } + return $key; + } + +} \ No newline at end of file diff --git a/market/controllers/api/Login.php b/market/controllers/api/Login.php new file mode 100644 index 00000000..78ba5ac5 --- /dev/null +++ b/market/controllers/api/Login.php @@ -0,0 +1,122 @@ +load->model('market/Market_sys_admin_model', 'mdSysAdmin'); + $this->load->model('market/Market_sys_role_model', 'mdSysRole'); + $this->load->model('market/Market_sys_menu_model', 'mdSysMenu'); + $this->load->model('market/Market_sys_login_record_model', 'mdSysLoginRecord'); + } + + /** + * Notes:用户登录 + * Created on: 2022/9/8 14:49 + * Created by: dengbw + */ + public function index_post() + { + $username = $this->input_param('username'); + $password = $this->input_param('password'); + $code = $this->input_param('code'); + $code_key = $this->input_param('code_key'); + if (!$username) { + $this->return_json('请输入登录账号'); + } + if (!$password) { + $this->return_json('请输入登录密码'); + } + if (!$code) { + $this->return_json('请输入验证码'); + } + $redis = &load_cache('redis'); + if (!$redis->get($code_key)) { + $this->return_json('验证码已过期'); + } + if ($redis->get($code_key) != $code) { + $this->return_json('验证码错误'); + } + $re = $this->mdSysAdmin->get(["username like '{$username}'" => null, 'status' => 0]); + if (!$re) { + $this->return_json('账号不存在'); + return; + } + $this->load->library('api/record'); + if (!password_verify($password, $re['password'])) { + $message = '密码错误'; + $this->record->loginRecord(['userId' => $re['userId'], 'username' => $re['username'], 'nickname' => $re['nickname'] + , 'loginType' => 1, 'comments' => $message]); + $this->return_json($message); + } + $user = ['userId' => $re['userId'], 'username' => $re['username'], 'nickname' => $re['nickname'], 'avatar' => "https://cdn.eleadmin.com/20200610/avatar.jpg" + , 'sex' => $re['sex'], 'phone' => $re['phone'], 'introduction' => $re['introduction'], 'email' => $re['email'] + , 'enabled' => true, 'accountNonLocked' => true, 'credentialsNonExpired' => true, 'accountNonExpired' => true]; + $roles = $authorities = []; + if ($re['roleId']) { + $re_ro = $this->mdSysRole->get(['roleId' => $re['roleId'], 'status' => 0]); + if ($re_ro) { + $re_ro['userId'] = $re['userId']; + $roles[] = $re_ro; + if ($re_ro['menuIds']) { + $authorities = $this->mdSysMenu->select(["menuId in({$re_ro['menuIds']})" => null, 'status' => 0] + , 'sortNumber asc,menuId desc'); + foreach ($authorities as $k => $v) { + $authorities[$k]['menuId'] = intval($v['menuId']); + $authorities[$k]['parentId'] = intval($v['parentId']); + $authorities[$k]['menuType'] = intval($v['menuType']); + $authorities[$k]['openType'] = intval($v['openType']); + $authorities[$k]['sortNumber'] = intval($v['sortNumber']); + $authorities[$k]['hide'] = intval($v['hide']); + $authorities[$k]['meta'] = json_decode($v['meta'], true); + } + } + } + } + $user['roles'] = $roles; + $user['authorities'] = $authorities; +// $user['authorities'] = [ +// ['menuId' => 1, 'parentId' => 0, 'title' => "系统管理", 'path' => '/system', 'component' => null, 'menuType' => 0, 'sortNumber' => 1, 'authority' => null, 'icon' => 'el-icon-setting', 'hide' => 0, 'meta' => ['badge' => 'New', 'badgeColor' => 'warning'], 'deleted' => 0, 'createTime' => '2020-02-26 12:51:23', 'updateTime' => '2022-03-11 16:46:28', 'children' => null, 'checked' => null], +// ['menuId' => 2, 'parentId' => 1, 'title' => "用户管理", 'path' => '/system/user', 'component' => '/system/user', 'menuType' => 0, 'sortNumber' => 1, 'authority' => null, 'icon' => 'el-icon-_user-group', 'hide' => 0, 'meta' => null, 'deleted' => 0, 'createTime' => '2020-02-26 12:51:55', 'updateTime' => '2021-05-21 17:56:28', 'children' => null, 'checked' => null], +// ['menuId' => 7, 'parentId' => 1, 'title' => "角色管理", 'path' => '/system/role', 'component' => '/system/role', 'menuType' => 0, 'sortNumber' => 2, 'authority' => null, 'icon' => 'el-icon-postcard', 'hide' => 0, 'meta' => null, 'deleted' => 0, 'createTime' => '2020-03-13 13:29:08', 'updateTime' => '2021-05-21 17:56:34', 'children' => null, 'checked' => null], +// ['menuId' => 12, 'parentId' => 1, 'title' => "菜单管理", 'path' => '/system/menu', 'component' => '/system/menu', 'menuType' => 0, 'sortNumber' => 3, 'authority' => null, 'icon' => 'el-icon-s-operation', 'hide' => 0, 'meta' => null, 'deleted' => 0, 'createTime' => '2020-03-21 01:07:13', 'updateTime' => '2021-05-21 17:56:39', 'children' => null, 'checked' => null] +// ]; + $data['access_token'] = Authorization::generateToken($re['userId']); + $data['user'] = $user; + $this->record->loginRecord(['userId' => $re['userId'], 'username' => $re['username'], 'nickname' => $re['nickname']]); + $redis->delete($code_key);//删除验证码 + $this->return_response($data, '登录成功'); + } + + /** + * Notes: + * Created on: 2022/8/29 17:06 + * Created by: dengbw + * http://market.dev.liche.cn/api/login/test + * http://market.liche.cn/api/login/test + */ + public function test() + { + //echo config('ele_admin.API_KEY'); + $mobile = '13860164563'; + $signer = new Lcobucci\JWT\Signer\Hmac\Sha256();//加密算法 + $time = time(); + $key = new Lcobucci\JWT\Signer\Key('market'); + $token = (new Lcobucci\JWT\Builder())->issuedBy('http://market.dev.liche.cn') + ->identifiedBy('4f1g23a12aa', true)//身份验证 + ->issuedAt($time)//签发时间 + ->expiresAt($time + 60)//多长时间以后才能用token,60秒以后才能用 + ->withClaim('mobile', $mobile) + ->getToken($signer, $key);//配置项 + echo 'token=' . $token; + } +} \ No newline at end of file diff --git a/market/controllers/api/Upload.php b/market/controllers/api/Upload.php new file mode 100644 index 00000000..e83043b1 --- /dev/null +++ b/market/controllers/api/Upload.php @@ -0,0 +1,85 @@ +return_json('请选择图片'); + } + if (!$file['tmp_name']) {//太大的图片上传,这个参数会变成空的 + $this->return_json('参数错误'); + } + if (!file_exists(TEMP_PATH)) { + $oldumask = umask(0); + mkdir(TEMP_PATH, 0777, true); + umask($oldumask); + } + $tmp = TEMP_PATH . md5($file['name'] . uniqid()) . substr($file['name'], strpos($file['name'], '.', strlen($file['name']) - 1)); + move_uploaded_file($file['tmp_name'], $tmp); + if (!filesize($tmp)) { + $this->return_json('图片有点问题,换个小的试试'); + } + //上传图片到FTP + $res = $this->upload_img_qiniu($tmp, "market/"); + if (!$res) { + $this->return_json('上传失败'); + } + $data['full_url'] = build_qiniu_image_url($res['photo']); + $data['url'] = $res['photo']; + $this->return_response($data); + } + + /** + * @param string $file 上传的文件 + * @param string $path 要保存的目录 + * @param string $filename 原始文件名称 + * @return array + * @throws Exception + */ + private function upload_img_qiniu($file, $path = '', $filename = '') + { + $phoId = md5(uniqid() . mt_rand(0, 10000) . time()); + $filename = $filename ? $filename : $file; + $ext_arr = explode(".", $filename); + $ext = count($ext_arr) > 1 ? $ext_arr[count($ext_arr) - 1] : 'jpg'; + if (is_uploaded_file($file)) { + //上传图片 + $oriPath = TEMP_PATH . '/p_' . $phoId . '_ori.' . $ext; + move_uploaded_file($file, $oriPath); + } else { + $oriPath = $file; + } + $oriKey = 'p_' . $phoId . '.' . $ext; + // 上传到七牛后保存的文件名 + $photo = $path . date('Ym') . "/" . $oriKey; + //上传图片到FTP + $this->load->library('qiniu'); + $res = $this->qiniu->save($photo, file_get_contents($oriPath)); + $img_size = getimagesize($oriPath); + $file_size = filesize($oriPath); + $size = "{$img_size[0]},{$img_size[1]},{$file_size}"; + unlink($oriPath); + if ($res) { + $size = getimagesize($res['url']); + return array('photo' => $res['file'], 'size' => $size); + } else { + return array(); + } + } + +} \ No newline at end of file diff --git a/market/controllers/api/auth/Password.php b/market/controllers/api/auth/Password.php new file mode 100644 index 00000000..0bb15418 --- /dev/null +++ b/market/controllers/api/auth/Password.php @@ -0,0 +1,52 @@ +load->model('market/Market_sys_admin_model', 'mdSysAdmin'); + } + + /** + * Notes:修改密码 + * Created on: 2022/9/16 11:11 + * Created by: dengbw + */ + public function index_put() + { + $oldPassword = $this->input_param('oldPassword'); + $password = $this->input_param('password'); + $password2 = $this->input_param('password2'); + if (!$oldPassword) { + $this->return_json('请输入旧密码'); + } + if (!$password) { + $this->return_json('请输入新密码'); + } + if (!$password2) { + $this->return_json('请再次输入新密码'); + } + if (mb_strlen($password) < 4) { + $this->return_json('请输入至少4个字符的新密码'); + } + if ($password != $password2) { + $this->return_json('两次输入密码不一致'); + } + if (!password_verify($oldPassword, $_SESSION['password'])) { + $this->return_json('旧密码错误'); + } + $upDate['password'] = password_hash($password, PASSWORD_BCRYPT); + $this->mdSysAdmin->update($upDate, ['userId' => $_SESSION['userId']]); + $this->return_response(); + } + +} \ No newline at end of file diff --git a/market/controllers/api/auth/User.php b/market/controllers/api/auth/User.php new file mode 100644 index 00000000..ae21b2eb --- /dev/null +++ b/market/controllers/api/auth/User.php @@ -0,0 +1,52 @@ +load->model('market/Market_sys_role_model', 'mdSysRole'); + $this->load->model('market/Market_sys_menu_model', 'mdSysMenu'); + } + + public function index_get() + { + $re = $_SESSION; + $user = ['userId' => $re['userId'], 'username' => $re['username'], 'nickname' => $re['nickname'], 'avatar' => "https://cdn.eleadmin.com/20200610/avatar.jpg" + , 'sex' => $re['sex'], 'phone' => $re['phone'], 'introduction' => $re['introduction'], 'email' => $re['email'] + , 'enabled' => true, 'accountNonLocked' => true, 'credentialsNonExpired' => true, 'accountNonExpired' => true]; + $roles = $authorities = []; + if ($re['roleId']) { + $re_ro = $this->mdSysRole->get(['roleId' => $re['roleId'], 'status' => 0]); + if ($re_ro) { + $re_ro['userId'] = $re['userId']; + $roles[] = $re_ro; + if ($re_ro['menuIds']) { + $authorities = $this->mdSysMenu->select(["menuId in({$re_ro['menuIds']})" => null, 'status' => 0] + , 'sortNumber asc,menuId desc'); + foreach ($authorities as $k => $v) { + $authorities[$k]['menuId'] = intval($v['menuId']); + $authorities[$k]['parentId'] = intval($v['parentId']); + $authorities[$k]['menuType'] = intval($v['menuType']); + $authorities[$k]['openType'] = intval($v['openType']); + $authorities[$k]['sortNumber'] = intval($v['sortNumber']); + $authorities[$k]['hide'] = intval($v['hide']); + $authorities[$k]['meta'] = json_decode($v['meta'], true); + } + } + } + } + $user['roles'] = $roles; + $user['authorities'] = $authorities; + $this->return_response($user); + } + +} \ No newline at end of file diff --git a/market/controllers/api/sylive/Activity.php b/market/controllers/api/sylive/Activity.php new file mode 100644 index 00000000..1717ed46 --- /dev/null +++ b/market/controllers/api/sylive/Activity.php @@ -0,0 +1,483 @@ +load->model('market/Market_sylive_activity_model', 'mdSyliveActivity'); + $this->load->model('market/Market_sylive_activity_biz_model', 'mdSyliveActivityBiz'); + $this->load->model('market/Market_sylive_organization_model', 'mdSyliveOrganization'); + } + + /** + * Notes:活动管理列表 + * Created on: 2022/9/20 14:48 + * Created by: dengbw + */ + public function page_get() + { + $page = $this->input_param('page'); + $limit = $this->input_param('limit'); + $title = $this->input_param('title'); + $sort = $this->input_param('sort'); + $order = $this->input_param('order'); + !$page && $page = 1; + !$limit && $limit = 10; + $sort_order = 'activityId desc'; + if ($sort && $order) { + $sort_order = $sort . ' ' . $order; + } + $list = []; + $where['status>='] = 0; + $title && $where['title LIKE "%' . trim($title) . '%"'] = null; + $count = $this->mdSyliveActivity->count($where); + if ($count) { + $this->load->library('MyEncryption'); + $res = $this->mdSyliveActivity->select($where, $sort_order, $page, $limit); + foreach ($res as $v) { + $dateRange = [$v['timeStart'], $v['timeEnd']]; + $status = intval($v['status']); + $activityId = intval($v['activityId']); + $bgImg = $channelImg = $shareImg = $shareTitle = $bizIds = []; + $item = ['activityId' => $activityId, 'itemImg' => [], 'title' => '', 'introduction' => '', 'price' => '', 'dateRange' => '']; + $v['shareTitle'] && $shareTitle = json_decode($v['shareTitle'], true); + $jsondata = $v['jsondata'] ? json_decode($v['jsondata'], true) : []; + if ($jsondata['item']) { + $getItem = $jsondata['item']; + $item['title'] = $getItem['title']; + $item['introduction'] = $getItem['introduction']; + $item['price'] = $getItem['price']; + $item['dateRange'] = [$getItem['timeStart'], $getItem['timeEnd']]; + if ($getItem['itemImg']) { + $itemImg = []; + foreach ($getItem['itemImg'] as $k2 => $v2) { + $itemImg[] = ['uid' => $k2, 'fileUrl' => $v2, 'url' => build_qiniu_image_url($v2), 'status' => 'done']; + } + $item['itemImg'] = $itemImg; + } + } + if ($v['bgImg']) { + $bgImg = [['uid' => 1, 'fileUrl' => $v['bgImg'], 'url' => build_qiniu_image_url($v['bgImg']), 'status' => 'done']]; + } + if ($v['channelImg']) { + $channelImg = [['uid' => 1, 'fileUrl' => $v['channelImg'], 'url' => build_qiniu_image_url($v['channelImg']), 'status' => 'done']]; + } + if ($v['shareImg']) { + $getShareImg = json_decode($v['shareImg'], true); + foreach ($getShareImg as $k2 => $v2) { + $shareImg[] = ['uid' => $k2, 'fileUrl' => $v2, 'url' => build_qiniu_image_url($v2), 'status' => 'done']; + } + } + $res_biz = $this->mdSyliveActivityBiz->select(['activityId' => $activityId, 'status' => 0], 'id desc', 0, 0, 'bizId'); + if ($res_biz) { + foreach ($res_biz as $k2 => $v2) { + $bizIds[] = intval($v2['bizId']); + } + } + $url = http_host_com('home') . "/h5/market/sylive?skey=" . $this->myencryption->base64url_encode("id=" . $activityId); + $list[] = [ + 'activityId' => $activityId, 'title' => $v['title'], 'channelId' => $v['channelId'], 'bizIds' => $bizIds, + 'introduction' => $v['introduction'], 'shareTitle' => $shareTitle, 'dateRange' => $dateRange + , 'bgImg' => $bgImg, 'channelImg' => $channelImg, 'shareImg' => $shareImg, 'item' => $item, 'url' => $url + , 's_time' => $v['timeStart'], 'e_time' => $v['timeEnd'], 'status' => $status, 'createTime' => $v['createTime']]; + } + } + $date = ['list' => $list, 'count' => $count]; + $this->return_response_list($date); + } + + /** + * Notes:添加活动 + * Created on: 2022/9/21 16:46 + * Created by: dengbw + */ + public function index_post() + { + $title = $this->input_param('title'); + $channelId = $this->input_param('channelId'); + $dateRange = $this->input_param('dateRange'); + $introduction = $this->input_param('introduction'); + $shareTitle = $this->input_param('shareTitle'); + $shareImg = $this->input_param('shareImg'); + $bgImg = $this->input_param('bgImg'); + $channelImg = $this->input_param('channelImg'); + $bizIds = $this->input_param('bizIds'); + if (!$title) { + $this->return_json('请输入活动标题'); + } + if (!$bizIds) { + $this->return_json('请选择所属门店'); + } + if (!$bgImg[0]['fileUrl']) { + $this->return_json('请选择背景图'); + } + if (!$channelId) { + $this->return_json('请输入直播频道'); + } + if (!$dateRange) { + $this->return_json('请选择直播时间'); + } + if (!$introduction) { + $this->return_json('请输入活动简介'); + } + $bgImg = $bgImg[0]['fileUrl']; + $channelImg = $channelImg[0]['fileUrl'] ? $channelImg[0]['fileUrl'] : ''; + $shareTitle && $shareTitle = json_encode($shareTitle, JSON_UNESCAPED_UNICODE); + $setShareImg = ''; + if ($shareImg) { + foreach ($shareImg as $v) { + $setShareImg[] = $v['fileUrl']; + } + $setShareImg = json_encode($setShareImg, JSON_UNESCAPED_UNICODE); + } + $addDate = ['title' => $title, 'bgImg' => $bgImg, 'channelImg' => $channelImg, 'channelId' => $channelId + , 'introduction' => $introduction, 'shareTitle' => $shareTitle, 'shareImg' => $setShareImg, 'timeStart' => $dateRange[0] + , 'timeEnd' => $dateRange[1], 'status' => 1, 'createTime' => date('Y-m-d H:i:s')]; + $activityId = $this->mdSyliveActivity->add($addDate); + if (!$activityId) { + $this->return_json('添加活动失败'); + } + $bizIds = implode(',', $bizIds); + $res_org = $this->mdSyliveOrganization->select(["organizationId in({$bizIds})" => null, 'organizationType' => 3] + , 'organizationId desc', 0, 0, 'organizationId,parentId'); + $add_biz = []; + if ($res_org) { + $this->mdSyliveActivityBiz->update(['status' => -1], ["bizId not in({$bizIds})" => null, 'activityId' => $activityId, 'status' => 0]); + foreach ($res_org as $v) { + $add_biz[] = ['activityId' => $activityId, 'areaId' => $v['parentId'] + , 'bizId' => $v['organizationId'], 'createTime' => date('Y-m-d H:i:s')]; + } + //增加活动商家 + $add_biz && $this->mdSyliveActivityBiz->add_batch($add_biz); + } + $this->return_response(); + } + + /** + * Notes:活动详情 + * Created on: 2022/9/29 10:37 + * Created by: dengbw + * @param null $activityId + */ + public function index_get($activityId = null) + { + if (!$activityId) { + $this->return_json('参数错误'); + } + $re = $this->mdSyliveActivity->get(['activityId' => $activityId]); + if (!$re) { + $this->return_json('活动不存在'); + } + $this->return_response($re); + } + + /** + * Notes:修改活动 + * Created on: 2022/9/21 14:48 + * Created by: dengbw + */ + public function index_put() + { + $activityId = intval($this->input_param('activityId')); + $title = $this->input_param('title'); + $channelId = $this->input_param('channelId'); + $dateRange = $this->input_param('dateRange'); + $introduction = $this->input_param('introduction'); + $shareTitle = $this->input_param('shareTitle'); + $shareImg = $this->input_param('shareImg'); + $bgImg = $this->input_param('bgImg'); + $channelImg = $this->input_param('channelImg'); + $bizIds = $this->input_param('bizIds'); + if (!$activityId) { + $this->return_json('参数错误'); + } + if (!$title) { + $this->return_json('请输入活动标题'); + } + if (!$bizIds) { + $this->return_json('请选择所属门店'); + } + if (!$bgImg[0]['fileUrl']) { + $this->return_json('请选择背景图'); + } + if (!$channelId) { + $this->return_json('请输入直播频道'); + } + if (!$dateRange) { + $this->return_json('请选择直播时间'); + } + if (!$introduction) { + $this->return_json('请输入活动简介'); + } + $bizIds = implode(',', $bizIds); + $res_org = $this->mdSyliveOrganization->select(["organizationId in({$bizIds})" => null, 'organizationType' => 3] + , 'organizationId desc', 0, 0, 'organizationId,parentId'); + $add_biz = []; + if ($res_org) { + $this->mdSyliveActivityBiz->update(['status' => -1], ["bizId not in({$bizIds})" => null, 'activityId' => $activityId, 'status' => 0]); + foreach ($res_org as $v) { + $re_org = $this->mdSyliveActivityBiz->get(['activityId' => $activityId, 'bizId' => $v['organizationId']]); + if (!$re_org) { + $add_biz[] = ['activityId' => $activityId, 'areaId' => $v['parentId'] + , 'bizId' => $v['organizationId'], 'createTime' => date('Y-m-d H:i:s')]; + } else if ($re_org['status'] == -1) { + $this->mdSyliveActivityBiz->update(['status' => 0], ['id' => $re_org['id']]); + } + } + //增加活动商家 + $add_biz && $this->mdSyliveActivityBiz->add_batch($add_biz); + } + $bgImg = $bgImg[0]['fileUrl']; + $channelImg = $channelImg[0]['fileUrl'] ? $channelImg[0]['fileUrl'] : ''; + $shareTitle && $shareTitle = json_encode($shareTitle, JSON_UNESCAPED_UNICODE); + $setShareImg = ''; + if ($shareImg) { + foreach ($shareImg as $v) { + $setShareImg[] = $v['fileUrl']; + } + $setShareImg = json_encode($setShareImg, JSON_UNESCAPED_UNICODE); + } + $upDate = ['title' => $title, 'bgImg' => $bgImg, 'channelImg' => $channelImg, 'channelId' => $channelId, 'introduction' => $introduction, + 'shareTitle' => $shareTitle, 'shareImg' => $setShareImg, 'timeStart' => $dateRange[0], 'timeEnd' => $dateRange[1]]; + $this->mdSyliveActivity->update($upDate, ['activityId' => $activityId]); + $this->return_response(); + } + + /** + * Notes:修改商品 + * Created on: 2022/9/28 15:09 + * Created by: dengbw + */ + public function item_put() + { + $activityId = intval($this->input_param('activityId')); + $title = $this->input_param('title'); + $price = $this->input_param('price'); + $itemImg = $this->input_param('itemImg'); + $dateRange = $this->input_param('dateRange'); + $introduction = $this->input_param('introduction'); + if (!$activityId) { + $this->return_json('参数错误'); + } + $re = $this->mdSyliveActivity->get(['activityId' => $activityId]); + if (!$re) { + $this->return_json('活动不存在'); + } + $jsondata = $re['jsondata'] ? json_decode($re['jsondata'], true) : []; + $item = ['title' => $title, 'price' => $price, 'timeStart' => $dateRange[0], 'timeEnd' => $dateRange[1], 'introduction' => $introduction]; + if ($itemImg) { + $setItemImg = []; + foreach ($itemImg as $v) { + $setItemImg[] = $v['fileUrl']; + } + $item['itemImg'] = $setItemImg; + } + $jsondata['item'] = $item; + $upDate = ['jsondata' => json_encode($jsondata, JSON_UNESCAPED_UNICODE)]; + $this->mdSyliveActivity->update($upDate, ['activityId' => $activityId]); + $this->return_response(); + } + + /** + * Notes:删除活动 + * Created on: 2022/9/21 16:10 + * Created by: dengbw + * @param null $activityId + */ + public function index_delete($activityId = null) + { + if (!$activityId) { + $this->return_json('参数错误'); + } + $this->mdSyliveActivity->update(['status' => -1], ['activityId' => $activityId]); + $this->return_response(); + } + + /** + * Notes:批量删除用户 + * Created on: 2022/9/8 17:11 + * Created by: dengbw + */ + public function batch_delete() + { + $ids = $this->inputs; + if (!$ids) { + $this->return_json('参数错误'); + } + $str_ids = implode(',', $ids); + if ($str_ids) { + $this->mdSyliveActivity->update(['status' => -1], ["activityId in($str_ids)" => null]); + } + $this->return_response(); + } + + /** + * Notes:修改状态 + * Created on: 2022/9/8 16:10 + * Created by: dengbw + */ + public function status_put() + { + $activityId = $this->input_param('activityId'); + $status = $this->input_param('status'); + if (!$activityId) { + $this->return_json('参数错误'); + } + $this->mdSyliveActivity->update(['status' => $status], ['activityId' => $activityId]); + $this->return_response(); + } + + /** + * Notes:活动统计 + * Created on: 2022/9/27 10:02 + * Created by: dengbw + * @param null $activityId + */ + public function statistics_get($activityId = null) + { + $activityId = intval($activityId); + if (!$activityId) { + $this->return_json('参数错误'); + } + $this->load->model('market/Market_sylive_activity_kpidata_model', 'mdSyliveActivityKpidata'); + $this->load->model('market/Market_sylive_user_model', 'mdSyliveUser'); + $this->load->model('live/Live_polyv_session_model', 'mdPolyvSession'); + $title = ''; + $activityData = $areaData = $bizData = $consultantData = $areaAry = []; + $re = $this->mdSyliveActivity->get(['activityId' => $activityId]); + if ($re) { + $title = $re['title']; + $res_biz = $this->mdSyliveActivityBiz->select(['activityId' => $activityId, 'status' => 0], 'browse desc'); + foreach ($res_biz as $k => $v) { + $areaId = intval($v['areaId']); + $bizId = intval($v['bizId']); + $re_biz = $this->mdSyliveOrganization->get(['organizationId' => $bizId]); + if ($re_biz) { + $consultant = $this->mdSyliveActivityKpidata->count(['biz_id' => $bizId, 'a_id' => $activityId], 'distinct(cf_uid)'); + $bizData[] = ['areaId' => $areaId, 'bizId' => $bizId, + 'bizName' => $re_biz['organizationName'], 'consultant' => $consultant, 'browse' => $v['browse'], 'subscribe' => $v['subscribe'] + , 'watch' => $v['watch'], 'order' => $v['orderTotal'], 'livePV' => 35, 'watchDuration' => 10]; + if (!$areaAry[$areaId]) {//大区 + $areaAry[$areaId] = 1; + } else { + $areaAry[$areaId] += 1; + } + } + } + foreach ($areaAry as $k => $v) { + $areaId = intval($k); + $re_area = $this->mdSyliveOrganization->get(['organizationId' => $areaId]); + if ($re_area) { + $consultant = $this->mdSyliveActivityKpidata->count(['area_id' => $areaId, 'a_id' => $activityId], 'distinct(cf_uid)'); + $browse = $this->mdSyliveActivityKpidata->count(['area_id' => $areaId, 'a_id' => $activityId, 'kpi' => 'browse']); + $subscribe = $this->mdSyliveActivityKpidata->count(['area_id' => $areaId, 'a_id' => $activityId, 'kpi' => 'subscribe']); + $watch = $this->mdSyliveActivityKpidata->count(['area_id' => $areaId, 'a_id' => $activityId, 'kpi' => 'watch']); + $order = $this->mdSyliveActivityKpidata->count(['area_id' => $areaId, 'a_id' => $activityId, 'kpi' => 'order']); + $areaData[] = ['areaName' => $re_area['organizationName'], 'biz' => $v, 'consultant' => $consultant + , 'browse' => $browse, 'subscribe' => $subscribe, 'watch' => $watch, 'order' => $order + , 'livePV' => 35, 'watchDuration' => 10]; + } + } + $res_user = $this->mdSyliveActivityKpidata->select(['a_id' => $activityId], 'id desc', 0, 0, 'distinct(cf_uid) as userId'); + foreach ($res_user as $k => $v) { + $userId = intval($v['userId']); + $re_user = $this->mdSyliveUser->get(['userId' => $v['userId']]); + if ($re_user) { + $consultantName = $re_user['uname'] ? $re_user['uname'] : $re_user['nickname']; + $browse = $this->mdSyliveActivityKpidata->count(['a_id' => $activityId, 'cf_uid' => $userId, 'kpi' => 'browse']); + $subscribe = $this->mdSyliveActivityKpidata->count(['a_id' => $activityId, 'cf_uid' => $userId, 'kpi' => 'subscribe']); + $watch = $this->mdSyliveActivityKpidata->count(['a_id' => $activityId, 'cf_uid' => $userId, 'kpi' => 'watch']); + $order = $this->mdSyliveActivityKpidata->count(['a_id' => $activityId, 'cf_uid' => $userId, 'kpi' => 'order']); + $consultantData = [['consultantName' => $consultantName, 'browse' => $browse, 'subscribe' => $subscribe, 'watch' => $watch + , 'order' => $order, 'livePV' => 35, 'watchDuration' => 10]]; + } + } + $browse = $this->mdSyliveActivityKpidata->count(['a_id' => $activityId, 'kpi' => 'browse']); + $subscribe = $this->mdSyliveActivityKpidata->count(['a_id' => $activityId, 'kpi' => 'subscribe']); + $watch = $this->mdSyliveActivityKpidata->count(['a_id' => $activityId, 'kpi' => 'watch']); + $order = $this->mdSyliveActivityKpidata->count(['a_id' => $activityId, 'kpi' => 'order']); + $activityData = [['name' => '参与区域数', 'value' => count($areaData)], ['name' => '参与门店数', 'value' => count($bizData)] + , ['name' => '参与顾问数', 'value' => count($res_user)], ['name' => '浏览人数', 'value' => $browse], ['name' => '预约人数', 'value' => $subscribe] + , ['name' => '观看人数', 'value' => $watch], ['name' => '订单数', 'value' => $order], ['name' => '直播时长', 'value' => 8] + , ['name' => '观看次数', 'value' => 10], ['name' => '人均观看', 'value' => 9]]; + } + $data = ['activityId' => $activityId, 'title' => $title, 'activityData' => $activityData, 'areaData' => $areaData + , 'bizData' => $bizData, 'consultantData' => $consultantData]; + $this->return_response($data); + } + + /** + * Notes:活动订单列表 + * Created on: 2022/9/29 9:53 + * Created by: dengbw + * @param null $activityId + */ + public function order_get() + { + $this->load->model('market/Market_sylive_order_model', 'mdSyliveOrder'); + $this->load->model('market/Market_sylive_user_model', 'mdSyliveUser'); + $activityId = intval($this->input_param('activityId')); + $page = $this->input_param('page'); + $limit = $this->input_param('limit'); + $item_title = $this->input_param('item_title'); + $mobile = $this->input_param('mobile'); + $name = $this->input_param('name'); + $status = $this->input_param('status'); + $sid = $this->input_param('sid'); + $sort = $this->input_param('sort'); + $order = $this->input_param('order'); + !$page && $page = 1; + !$limit && $limit = 10; + $sort_order = 'id desc'; + if ($sort && $order) { + if ($sort == 'statusName') { + $sort_order = 'status ' . $order; + } else { + $sort_order = $sort . ' ' . $order; + } + } + $list = []; + if (!strlen($status)) { + $status = 1; + } + $where['status'] = $status; + $activityId && $where['item_id'] = $activityId; + $item_title && $where['item_title'] = $item_title; + $sid && $where['sid'] = $sid; + $str_user_ids = 0; + if ($name || $mobile) { + $where_user['status>='] = 0; + $name && $where_user["(uname LIKE '%{$name}%' OR mobile LIKE '%{$name}%')"] = null; + $mobile && $where_user['mobile'] = $mobile; + $res_user = $this->mdSyliveUser->select($where_user, 'userId desc', 0, 0, 'userId'); + $res_user && $str_user_ids = implode(',', array_unique(array_column($res_user, 'userId'))); + $where["u_id in($str_user_ids)"] = null; + } + $count = $this->mdSyliveOrder->count($where); + if ($count) { + $res = $this->mdSyliveOrder->select($where, $sort_order, $page, $limit); + $str_user_ids = implode(',', array_unique(array_column($res, 'uid'))); + $map_users = $this->mdSyliveUser->map('userId', 'uname,nickname,mobile', ["userId in({$str_user_ids})" => null]); + foreach ($res as $v) { + $name = $map_users[$v['uid']]['uname'] ? $map_users[$v['uid']]['uname'] : $map_users[$v['uid']]['nickname']; + $mobile = $map_users[$v['uid']]['mobile']; + $list[] = [ + 'id' => $v['id'], 'sid' => $v['sid'], 'name' => $name, 'mobile' => $mobile, 'item_title' => $v['item_title'] + , 'total_price' => $v['total_price'], 'pay_time' => $v['pay_time'] != '0000-00-00 00:00:00' ? $v['pay_time'] : '' + , 'statusName' => $this->mdSyliveOrder->statusAry($v['status']), 'createTime' => $v['createTime']]; + } + } + $date = ['list' => $list, 'count' => $count]; + $this->return_response_list($date); + } + +} \ No newline at end of file diff --git a/market/controllers/api/sylive/Order.php b/market/controllers/api/sylive/Order.php new file mode 100644 index 00000000..dfc4ebf9 --- /dev/null +++ b/market/controllers/api/sylive/Order.php @@ -0,0 +1,105 @@ +load->model('market/Market_sylive_order_model', 'mdSyliveOrder'); + $this->load->model('market/Market_sylive_user_model', 'mdSyliveUser'); + } + + /** + * Notes:订单管理列表 + * Created on: 2022/9/20 14:48 + * Created by: dengbw + */ + public function page_get() + { + $page = $this->input_param('page'); + $limit = $this->input_param('limit'); + $item_title = $this->input_param('item_title'); + $mobile = $this->input_param('mobile'); + $name = $this->input_param('name'); + $status = $this->input_param('status'); + $sid = $this->input_param('sid'); + $sort = $this->input_param('sort'); + $order = $this->input_param('order'); + !$page && $page = 1; + !$limit && $limit = 10; + $sort_order = 'id desc'; + if ($sort && $order) { + if ($sort == 'statusName') { + $sort_order = 'status ' . $order; + } else { + $sort_order = $sort . ' ' . $order; + } + } + $list = []; + if (!strlen($status)) { + $status = 1; + } + $where['status'] = $status; + $item_title && $where['item_title'] = $item_title; + $sid && $where['sid'] = $sid; + $str_user_ids = 0; + if ($name || $mobile) { + $where_user['status>='] = 0; + $name && $where_user["(uname LIKE '%{$name}%' OR mobile LIKE '%{$name}%')"] = null; + $mobile && $where_user['mobile'] = $mobile; + $res_user = $this->mdSyliveUser->select($where_user, 'userId desc', 0, 0, 'userId'); + $res_user && $str_user_ids = implode(',', array_unique(array_column($res_user, 'userId'))); + $where["u_id in($str_user_ids)"] = null; + } + $count = $this->mdSyliveOrder->count($where); + if ($count) { + $res = $this->mdSyliveOrder->select($where, $sort_order, $page, $limit); + $str_user_ids = implode(',', array_unique(array_column($res, 'uid'))); + $map_users = $this->mdSyliveUser->map('userId', 'uname,nickname,mobile', ["userId in({$str_user_ids})" => null]); + foreach ($res as $v) { + $name = $map_users[$v['uid']]['uname'] ? $map_users[$v['uid']]['uname'] : $map_users[$v['uid']]['nickname']; + $mobile = $map_users[$v['uid']]['mobile']; + $list[] = [ + 'id' => $v['id'], 'sid' => $v['sid'],'name' => $name, 'mobile' => $mobile, 'item_title' => $v['item_title'] + , 'total_price' => $v['total_price'], 'pay_time' => $v['pay_time'] != '0000-00-00 00:00:00' ? $v['pay_time'] : '' + , 'statusName' => $this->mdSyliveOrder->statusAry($v['status']), 'createTime' => $v['createTime']]; + } + } + $date = ['list' => $list, 'count' => $count]; + $this->return_response_list($date); + } + + /** + * Notes:修改订单 + * Created on: 2022/9/21 14:48 + * Created by: dengbw + */ + public function index_put() + { + $userId = intval($this->input_param('userId')); + $organizationId = intval($this->input_param('organizationId')); + $sex = intval($this->input_param('sex')); + $uname = $this->input_param('uname'); + if (!$userId) { + $this->return_json('参数错误'); + } + if (!$organizationId) { + $this->return_json('请选择所属机构'); + } + if (!$uname) { + $this->return_json('请输入姓名'); + } + $upDate = ['organizationId' => $organizationId, 'sex' => $sex, 'uname' => $uname]; + $this->mdSyliveOrder->update($upDate, ['userId' => $userId]); + $this->return_response(); + } + +} \ No newline at end of file diff --git a/market/controllers/api/sylive/Organization.php b/market/controllers/api/sylive/Organization.php new file mode 100644 index 00000000..8cc65eed --- /dev/null +++ b/market/controllers/api/sylive/Organization.php @@ -0,0 +1,116 @@ +load->model('market/Market_sylive_organization_model', 'mdSyliveOrganization'); + } + + /** + * Notes:获取机构 + * Created on: 2022/9/16 11:11 + * Created by: dengbw + */ + public function index_get() + { + $unOrganizationType = $this->input_param('unOrganizationType'); + $where['status>='] = 0; + $unOrganizationType && $where['organizationType<>'] = $unOrganizationType; + $sort_order = 'sortNumber asc,organizationId desc'; + $res = $this->mdSyliveOrganization->select($where, $sort_order); + foreach ($res as $k => $v) { + $res[$k]['organizationId'] = intval($v['organizationId']); + $res[$k]['parentId'] = intval($v['parentId']); + $res[$k]['sortNumber'] = intval($v['sortNumber']); + } + $this->return_response_list($res); + } + + /** + * Notes:添加机构 + * Created on: 2022/9/19 16:43 + * Created by: dengbw + */ + public function index_post() + { + $parentId = intval($this->input_param('parentId')); + $organizationName = $this->input_param('organizationName'); + $organizationFullName = $this->input_param('organizationFullName'); + $organizationType = $this->input_param('organizationType'); + $sortNumber = intval($this->input_param('sortNumber')); + $comments = $this->input_param('comments'); + if (!$organizationName) { + $this->return_json('请输入机构名称'); + } + if (!$organizationType) { + $this->return_json('请选择机构类型'); + } + !$comments && $comments = ''; + $addDate = ['parentId' => $parentId, 'organizationName' => $organizationName, 'organizationFullName' => $organizationFullName + , 'organizationType' => $organizationType, 'sortNumber' => $sortNumber, 'comments' => $comments + , 'createTime' => date('Y-m-d H:i:s')]; + $id = $this->mdSyliveOrganization->add($addDate); + if (!$id) { + $this->return_json('添加机构失败'); + } + $this->return_response(); + } + + /** + * Notes:修改机构 + * Created on: 2022/9/19 17:29 + * Created by: dengbw + */ + public function index_put() + { + $organizationId = intval($this->input_param('organizationId')); + $parentId = intval($this->input_param('parentId')); + $organizationName = $this->input_param('organizationName'); + $organizationFullName = $this->input_param('organizationFullName'); + $organizationType = $this->input_param('organizationType'); + $sortNumber = intval($this->input_param('sortNumber')); + $comments = $this->input_param('comments'); + !$comments && $comments = ''; + if (!$organizationId) { + $this->return_json('参数错误'); + } + if (!$organizationName) { + $this->return_json('请输入机构名称'); + } + if (!$organizationType) { + $this->return_json('请选择机构类型'); + } + !$comments && $comments = ''; + $upDate = ['parentId' => $parentId, 'organizationName' => $organizationName, 'organizationFullName' => $organizationFullName + , 'organizationType' => $organizationType, 'sortNumber' => $sortNumber, 'comments' => $comments]; + $this->mdSyliveOrganization->update($upDate, ['organizationId' => $organizationId]); + $this->return_response(); + } + + /** + * Notes:删除机构 + * Created on: 2022/9/19 11:08 + * Created by: dengbw + * @param null $organizationId + */ + public function index_delete($organizationId = null) + { + $organizationId = intval($organizationId); + if (!$organizationId) { + $this->return_json('参数错误'); + } + $this->mdSyliveOrganization->update(['status' => -1], ['organizationId' => $organizationId]); + $this->return_response(); + } + +} \ No newline at end of file diff --git a/market/controllers/api/sylive/User.php b/market/controllers/api/sylive/User.php new file mode 100644 index 00000000..34029449 --- /dev/null +++ b/market/controllers/api/sylive/User.php @@ -0,0 +1,169 @@ +load->model('market/Market_sylive_user_model', 'mdSyliveUser'); + } + + /** + * Notes:用户管理列表 + * Created on: 2022/9/20 14:48 + * Created by: dengbw + */ + public function page_get() + { + $page = $this->input_param('page'); + $limit = $this->input_param('limit'); + $uname = $this->input_param('uname'); + $nickname = $this->input_param('nickname'); + $sort = $this->input_param('sort'); + $order = $this->input_param('order'); + $organizationId = intval($this->input_param('organizationId')); + !$page && $page = 1; + !$limit && $limit = 10; + $sort_order = 'userId desc'; + if ($sort && $order) { + if ($sort == 'sexName') { + $sort_order = 'sex ' . $order; + } else { + $sort_order = $sort . ' ' . $order; + } + } + $list = []; + $where['status>='] = 0; + $organizationId && $where['organizationId'] = $organizationId; + $uname && $where['uname'] = $uname; + $nickname && $where['nickname'] = $nickname; + $this->load->model('market/Market_sylive_organization_model', 'mdSyliveOrganization'); + $organizationType = 0; + $re_org = $this->mdSyliveOrganization->get(['organizationId' => $organizationId]); + $re_org && $organizationType = $re_org['organizationType']; + $roleName = $this->mdSyliveUser->roleAry($organizationType); + $count = $this->mdSyliveUser->count($where); + if ($count) { + $res = $this->mdSyliveUser->select($where, $sort_order, $page, $limit); + foreach ($res as $v) { + $sexName = $this->mdSyliveUser->sexAry($v['sex']); + $status = intval($v['status']); + $list[] = [ + 'userId' => $v['userId'], 'uname' => $v['uname'], 'nickname' => $v['nickname'], 'mobile' => $v['mobile'] + , 'roleName' => $roleName, 'organizationId' => $organizationId, 'status' => $status + , 'sex' => $v['sex'], 'sexName' => $sexName, 'createTime' => $v['createTime']]; + } + } + $date = ['list' => $list, 'count' => $count]; + $this->return_response_list($date); + } + + /** + * Notes:添加用户 + * Created on: 2022/9/21 16:46 + * Created by: dengbw + */ + public function index_post() + { + $mobile = $this->input_param('mobile'); + $organizationId = intval($this->input_param('organizationId')); + $sex = intval($this->input_param('sex')); + $uname = $this->input_param('uname'); + if (!$mobile) { + $this->return_json('请输入手机号'); + } + if (!$organizationId) { + $this->return_json('请选择所属机构'); + } + if (!$uname) { + $this->return_json('请输入姓名'); + } + $re = $this->mdSyliveUser->get(['mobile' => $mobile]); + if ($re['organizationId']) { + $this->return_json('手机号已存在'); + } + $addDate = ['organizationId' => $organizationId, 'sex' => $sex, 'uname' => $uname]; + if ($re['userId']) { + $this->mdSyliveUser->update($addDate, ['userId' => $re['userId']]); + $this->return_response([], '绑定用户成功'); + } else { + $addDate['mobile'] = $mobile; + $addDate['createTime'] = date('Y-m-d H:i:s'); + $id = $this->mdSyliveUser->add($addDate); + if (!$id) { + $this->return_json('添加用户失败'); + } + $this->return_response(); + } + } + + /** + * Notes:修改用户 + * Created on: 2022/9/21 14:48 + * Created by: dengbw + */ + public function index_put() + { + $userId = intval($this->input_param('userId')); + $organizationId = intval($this->input_param('organizationId')); + $sex = intval($this->input_param('sex')); + $uname = $this->input_param('uname'); + if (!$userId) { + $this->return_json('参数错误'); + } + if (!$organizationId) { + $this->return_json('请选择所属机构'); + } + if (!$uname) { + $this->return_json('请输入姓名'); + } + $upDate = ['organizationId' => $organizationId, 'sex' => $sex, 'uname' => $uname]; + $this->mdSyliveUser->update($upDate, ['userId' => $userId]); + $this->return_response(); + } + + /** + * Notes:删除用户 + * Created on: 2022/9/21 16:10 + * Created by: dengbw + * @param null $userId + */ + public function index_delete($userId = null) + { + if (!$userId) { + $this->return_json('参数错误'); + } + $this->mdSyliveUser->update(['status' => -1], ['userId' => $userId]); + $this->return_response(); + } + + /** + * Notes:栓验字段 + * Created on: 2022/9/21 15:52 + * Created by: dengbw + */ + public function existence_get() + { + $field = $this->input_param('field'); + $value = $this->input_param('value'); + $id = $this->input_param('id'); + if (!$id) { + $where = [$field => $value]; + $field == 'mobile' && $where['organizationId>'] = 0; + $re = $this->mdSyliveUser->get([$field => $value]); + if ($re) { + $this->return_json('已存在', 0); + } + } + $this->return_json('不存在', 1); + } + +} \ No newline at end of file diff --git a/market/controllers/api/system/Dictionary.php b/market/controllers/api/system/Dictionary.php new file mode 100644 index 00000000..9cc02a62 --- /dev/null +++ b/market/controllers/api/system/Dictionary.php @@ -0,0 +1,105 @@ +load->model('market/Market_sys_dictionary_model', 'mdSysDictionary'); + } + + /** + * Notes:获取字典 + * Created on: 2022/9/19 11:11 + * Created by: dengbw + */ + public function index_get() + { + $where['status>='] = 0; + $sort_order = 'sortNumber asc,dictId desc'; + $res = $this->mdSysDictionary->select($where, $sort_order); + foreach ($res as $k => $v) { + $res[$k]['dictId'] = intval($v['dictId']); + } + $this->return_response_list($res); + } + + /** + * Notes:添加字典 + * Created on: 2022/9/19 11:01 + * Created by: dengbw + */ + public function index_post() + { + $dictName = $this->input_param('dictName'); + $dictCode = $this->input_param('dictCode'); + $sortNumber = intval($this->input_param('sortNumber')); + $comments = $this->input_param('comments'); + if (!$dictName) { + $this->return_json('请输入字典名称'); + } + if (!$dictCode) { + $this->return_json('请输入字典值'); + } + !$comments && $comments = ''; + $addDate = ['dictName' => $dictName, 'dictCode' => $dictCode, 'sortNumber' => $sortNumber, 'comments' => $comments + , 'createTime' => date('Y-m-d H:i:s')]; + $id = $this->mdSysDictionary->add($addDate); + if (!$id) { + $this->return_json('添加字典失败'); + } + $this->return_response(); + } + + /** + * Notes:修改字典 + * Created on: 2022/9/19 11:05 + * Created by: dengbw + */ + public function index_put() + { + $dictId = intval($this->input_param('dictId')); + $dictName = $this->input_param('dictName'); + $dictCode = $this->input_param('dictCode'); + $sortNumber = intval($this->input_param('sortNumber')); + $comments = $this->input_param('comments'); + if (!$dictId) { + $this->return_json('参数错误'); + } + if (!$dictName) { + $this->return_json('请输入字典名称'); + } + if (!$dictCode) { + $this->return_json('请输入字典值'); + } + !$comments && $comments = ''; + $upDate = ['dictName' => $dictName, 'dictCode' => $dictCode, 'sortNumber' => $sortNumber, 'comments' => $comments]; + $this->mdSysDictionary->update($upDate, ['dictId' => $dictId]); + $this->return_response(); + } + + /** + * Notes:删除字典 + * Created on: 2022/9/19 11:08 + * Created by: dengbw + * @param null $dictId + */ + public function index_delete($dictId = null) + { + $dictId = intval($dictId); + if (!$dictId) { + $this->return_json('参数错误'); + } + $this->mdSysDictionary->update(['status' => -1], ['dictId' => $dictId]); + $this->return_response(); + } + +} \ No newline at end of file diff --git a/market/controllers/api/system/DictionaryData.php b/market/controllers/api/system/DictionaryData.php new file mode 100644 index 00000000..99e356c4 --- /dev/null +++ b/market/controllers/api/system/DictionaryData.php @@ -0,0 +1,169 @@ +load->model('market/Market_sys_dictionary_data_model', 'mdSysDictionaryData'); + } + + /** + * Notes:字典项列表 + * Created on: 2022/9/16 11:11 + * Created by: dengbw + */ + public function page_get() + { + $dictId = $this->input_param('dictId'); + $page = $this->input_param('page'); + $limit = $this->input_param('limit'); + $sort = $this->input_param('sort'); + $order = $this->input_param('order'); + $keywords = $this->input_param('keywords'); + !$page && $page = 1; + !$limit && $limit = 10; + if (!$dictId) { + $this->return_json('参数错误'); + } + $res = []; + $sort_order = 'sortNumber asc,dictDataId desc'; + $where = ['status>=' => 0, 'dictId' => $dictId]; + if ($keywords) { + $where["dictDataName = '{$keywords}' OR dictDataCode = '{$keywords}'"] = null; + } + if ($sort && $order) { + $sort_order = $sort . ' ' . $order; + } + $count = $this->mdSysDictionaryData->count($where); + if ($count) { + $res = $this->mdSysDictionaryData->select($where, $sort_order, $page, $limit); + foreach ($res as $k => $v) { + $res[$k]['dictDataId'] = intval($v['dictDataId']); + $res[$k]['dictId'] = intval($v['dictId']); + $res[$k]['sortNumber'] = intval($v['sortNumber']); + } + } + $date = ['list' => $res, 'count' => $count]; + $this->return_response_list($date); + } + + public function index_get() + { + $dictCode = $this->input_param('dictCode'); + if (!$dictCode) { + $this->return_json('参数错误'); + } + $this->load->model('market/Market_sys_dictionary_model', 'mdSysDictionary'); + $re = $this->mdSysDictionary->get(['status>=' => 0, 'dictCode' => $dictCode]); + $res = []; + if ($re) { + $dictId = $re['dictId']; + $sort_order = 'sortNumber asc,dictDataId desc'; + $where = ['status>=' => 0, 'dictId' => $dictId]; + $res = $this->mdSysDictionaryData->select($where, $sort_order, 0, 0); + foreach ($res as $k => $v) { + $res[$k]['dictDataId'] = intval($v['dictDataId']); + $res[$k]['dictId'] = intval($v['dictId']); + $res[$k]['dictCode'] = $re['dictCode']; + $res[$k]['dictName'] = $re['dictName']; + } + } + $this->return_response_list($res); + } + + /** + * Notes:添加字典项 + * Created on: 2022/9/19 11:01 + * Created by: dengbw + */ + public function index_post() + { + $dictId = intval($this->input_param('dictId')); + $dictDataName = $this->input_param('dictDataName'); + $dictDataCode = $this->input_param('dictDataCode'); + $sortNumber = intval($this->input_param('sortNumber')); + $comments = $this->input_param('comments'); + if (!$dictDataName) { + $this->return_json('请输入字典项名称'); + } + if (!$dictDataCode) { + $this->return_json('请输入字典项值'); + } + !$comments && $comments = ''; + $addDate = ['dictId' => $dictId, 'dictDataName' => $dictDataName, 'dictDataCode' => $dictDataCode, + 'sortNumber' => $sortNumber, 'comments' => $comments, 'createTime' => date('Y-m-d H:i:s')]; + $id = $this->mdSysDictionaryData->add($addDate); + if (!$id) { + $this->return_json('添加字典项失败'); + } + $this->return_response(); + } + + /** + * Notes:修改字典项 + * Created on: 2022/9/19 11:05 + * Created by: dengbw + */ + public function index_put() + { + $dictDataId = intval($this->input_param('dictDataId')); + $dictDataName = $this->input_param('dictDataName'); + $dictDataCode = $this->input_param('dictDataCode'); + $sortNumber = intval($this->input_param('sortNumber')); + $comments = $this->input_param('comments'); + if (!$dictDataName) { + $this->return_json('请输入字典项名称'); + } + if (!$dictDataCode) { + $this->return_json('请输入字典项值'); + } + !$comments && $comments = ''; + $upDate = ['dictDataName' => $dictDataName, 'dictDataCode' => $dictDataCode, 'sortNumber' => $sortNumber, 'comments' => $comments]; + $this->mdSysDictionaryData->update($upDate, ['dictDataId' => $dictDataId]); + $this->return_response(); + } + + /** + * Notes:删除字典项 + * Created on: 2022/9/19 11:08 + * Created by: dengbw + * @param null $dictDataId + */ + public function index_delete($dictDataId = null) + { + $dictDataId = intval($dictDataId); + if (!$dictDataId) { + $this->return_json('参数错误'); + } + $this->mdSysDictionaryData->update(['status' => -1], ['dictDataId' => $dictDataId]); + $this->return_response(); + } + + /** + * Notes:批量删除字典项 + * Created on: 2022/9/19 15:35 + * Created by: dengbw + */ + public function batch_delete() + { + $ids = $this->inputs; + if (!$ids) { + $this->return_json('参数错误'); + } + $str_ids = implode(',', $ids); + if ($str_ids) { + $this->mdSysDictionaryData->update(['status' => -1], ["dictDataId in($str_ids)" => null]); + } + $this->return_response(); + } + +} \ No newline at end of file diff --git a/market/controllers/api/system/LoginRecord.php b/market/controllers/api/system/LoginRecord.php new file mode 100644 index 00000000..b1dc14f2 --- /dev/null +++ b/market/controllers/api/system/LoginRecord.php @@ -0,0 +1,58 @@ +load->model('market/Market_sys_login_record_model', 'mdSysLoginRecord'); + } + + /** + * Notes:登录日志列表 + * Created on: 2022/9/14 16:28 + * Created by: dengbw + */ + public function page_get() + { + $page = $this->input_param('page'); + $limit = $this->input_param('limit'); + $sort = $this->input_param('sort'); + $order = $this->input_param('order'); + $username = $this->input_param('username'); + $nickname = $this->input_param('nickname'); + $createTimeStart = $this->input_param('createTimeStart'); + $createTimeEnd = $this->input_param('createTimeEnd'); + !$page && $page = 1; + !$limit && $limit = 10; + $where = $list = []; + $createTimeStart && $where['createTime>='] = $createTimeStart; + $createTimeEnd && $where['createTime<='] = $createTimeEnd; + $username && $where['username'] = $username; + $nickname && $where['nickname'] = $nickname; + $sort_order = 'createTime desc'; + if ($sort && $order) { + $sort_order = $sort . ' ' . $order; + } + $count = $this->mdSysLoginRecord->count($where); + if ($count) { + $list = $this->mdSysLoginRecord->select($where, $sort_order, $page, $limit); + } + $date = ['list' => $list, 'count' => $count]; + $this->return_response_list($date); + } + + public function index_get() + { + $date = []; + $this->return_response_list($date); + } + +} \ No newline at end of file diff --git a/market/controllers/api/system/Menu.php b/market/controllers/api/system/Menu.php new file mode 100644 index 00000000..ed5295ef --- /dev/null +++ b/market/controllers/api/system/Menu.php @@ -0,0 +1,136 @@ +load->model('market/Market_sys_menu_model', 'mdSysMenu'); + } + + /** + * Notes菜单管理 + * Created on: 2022/9/9 14:48 + * Created by: dengbw + */ + public function index_get() + { + $title = $this->input_param('title'); + $path = $this->input_param('path'); + $authority = $this->input_param('authority'); + $where['status>='] = 0; + $sort_order = 'sortNumber asc,menuId desc'; + $title && $where['title'] = $title; + $path && $where['path'] = $path; + $authority && $where['authority'] = $authority; + $res = $this->mdSysMenu->select($where, $sort_order); + foreach ($res as $k => $v) { + $res[$k]['menuId'] = intval($v['menuId']); + $res[$k]['parentId'] = intval($v['parentId']); + $res[$k]['menuType'] = intval($v['menuType']); + $res[$k]['openType'] = intval($v['openType']); + $res[$k]['sortNumber'] = intval($v['sortNumber']); + $res[$k]['hide'] = intval($v['hide']); + $res[$k]['meta'] = json_decode($v['meta'], true); + } + $this->return_response_list($res); + } + + /** + * Notes:修改菜单 + * Created on: 2022/9/9 17:58 + * Created by: dengbw + */ + public function index_put() + { + $menuId = $this->input_param('menuId'); + $parentId = intval($this->input_param('parentId')); + $menuType = intval($this->input_param('menuType')); + $title = $this->input_param('title'); + $openType = intval($this->input_param('openType')); + $icon = $this->input_param('icon'); + $path = $this->input_param('path'); + $component = $this->input_param('component'); + $authority = $this->input_param('authority'); + $sortNumber = intval($this->input_param('sortNumber')); + $hide = intval($this->input_param('hide')); + $meta = $this->input_param('meta'); + if (!$menuId) { + $this->return_json('参数错误'); + } + if (!$title) { + $this->return_json('请输入菜单名称'); + } + !$icon && $icon = ''; + !$path && $path = ''; + !$component && $component = ''; + !$authority && $authority = ''; + $upDate = ['parentId' => $parentId, 'menuType' => $menuType, 'title' => $title, 'openType' => $openType, + 'icon' => $icon, 'path' => $path, 'component' => $component, 'authority' => $authority, + 'sortNumber' => $sortNumber, 'hide' => $hide]; + $upDate['meta'] = $meta ? json_encode($meta, JSON_UNESCAPED_UNICODE) : null; + $this->mdSysMenu->update($upDate, ['menuId' => $menuId]); + $this->return_response(); + } + + /** + * Notes:添加菜单 + * Created on: 2022/9/9 11:47 + * Created by: dengbw + */ + public function index_post() + { + $parentId = intval($this->input_param('parentId')); + $menuType = intval($this->input_param('menuType')); + $title = $this->input_param('title'); + $openType = intval($this->input_param('openType')); + $icon = $this->input_param('icon'); + $path = $this->input_param('path'); + $component = $this->input_param('component'); + $authority = $this->input_param('authority'); + $sortNumber = intval($this->input_param('sortNumber')); + $hide = intval($this->input_param('hide')); + $meta = $this->input_param('meta'); + if (!$title) { + $this->return_json('请输入菜单名称'); + } + !$icon && $icon = ''; + !$path && $path = ''; + !$component && $component = ''; + !$authority && $authority = ''; + $addDate = ['parentId' => $parentId, 'menuType' => $menuType, 'title' => $title, 'openType' => $openType, + 'icon' => $icon, 'path' => $path, 'component' => $component, 'authority' => $authority, + 'sortNumber' => $sortNumber, 'hide' => $hide, 'createTime' => date('Y-m-d H:i:s')]; + $meta && $addDate['meta'] = json_encode($meta, JSON_UNESCAPED_UNICODE); + $id = $this->mdSysMenu->add($addDate); + if (!$id) { + $this->return_json('添加菜单失败'); + } + $this->return_response(); + } + + /** + * Notes:删除菜单 + * Created on: 2022/9/9 16:10 + * Created by: dengbw + * @param null $menuId + */ + public function index_delete($menuId = null) + { + $menuId = intval($menuId); + if (!$menuId) { + $this->return_json('参数错误'); + } + $this->mdSysMenu->update(['status' => -1], ['menuId' => $menuId]); + $this->return_response(); + } + +} \ No newline at end of file diff --git a/market/controllers/api/system/OperationRecord.php b/market/controllers/api/system/OperationRecord.php new file mode 100644 index 00000000..76613dde --- /dev/null +++ b/market/controllers/api/system/OperationRecord.php @@ -0,0 +1,100 @@ +load->model('market/Market_sys_operation_record_model', 'mdSysOperationRecord'); + } + + /** + * Notes:操作日志列表 + * Created on: 2022/9/15 16:28 + * Created by: dengbw + */ + public function page_get() + { + $page = $this->input_param('page'); + $limit = $this->input_param('limit'); + $sort = $this->input_param('sort'); + $order = $this->input_param('order'); + $username = $this->input_param('username'); + $module = $this->input_param('module'); + $createTimeStart = $this->input_param('createTimeStart'); + $createTimeEnd = $this->input_param('createTimeEnd'); + !$page && $page = 1; + !$limit && $limit = 10; + $where = $list = []; + $createTimeStart && $where['createTime>='] = $createTimeStart; + $createTimeEnd && $where['createTime<='] = $createTimeEnd; + $username && $where['username'] = $username; + $module && $where['module'] = $module; + $sort_order = 'createTime desc'; + if ($sort && $order) { + $sort_order = $sort . ' ' . $order; + } + $count = $this->mdSysOperationRecord->count($where); + if ($count) { + $list = $this->mdSysOperationRecord->select($where, $sort_order, $page, $limit); + foreach ($list as $k => $v) { + $list[$k]['params'] = json_decode($v['params'], true); + $list[$k]['result'] = json_decode($v['result'], true); + $list[$k]['error'] = json_decode($v['error'], true); + $list[$k]['status'] = intval($v['status']); + } + } + $date = ['list' => $list, 'count' => $count]; + $this->return_response_list($date); + } + + private function dataSelect($params) + { + $page = $params['page']; + $limit = $params['limit']; + + $limit = $this->input_param('limit'); + $sort = $this->input_param('sort'); + $order = $this->input_param('order'); + $username = $this->input_param('username'); + $module = $this->input_param('module'); + $createTimeStart = $this->input_param('createTimeStart'); + $createTimeEnd = $this->input_param('createTimeEnd'); + !$page && $page = 1; + !$limit && $limit = 10; + $where = $list = []; + $createTimeStart && $where['createTime>='] = $createTimeStart; + $createTimeEnd && $where['createTime<='] = $createTimeEnd; + $username && $where['username'] = $username; + $module && $where['module'] = $module; + $sort_order = 'createTime desc'; + if ($sort && $order) { + $sort_order = $sort . ' ' . $order; + } + $count = $this->mdSysOperationRecord->count($where); + if ($count) { + $list = $this->mdSysOperationRecord->select($where, $sort_order, $page, $limit); + foreach ($list as $k => $v) { + $list[$k]['params'] = json_decode($v['params'], true); + $list[$k]['result'] = json_decode($v['result'], true); + $list[$k]['error'] = json_decode($v['error'], true); + $list[$k]['status'] = intval($v['status']); + } + } + } + + public function index_get() + { + $date = []; + $this->return_response_list($date); + } + + +} \ No newline at end of file diff --git a/market/controllers/api/system/Role.php b/market/controllers/api/system/Role.php new file mode 100644 index 00000000..10c9014c --- /dev/null +++ b/market/controllers/api/system/Role.php @@ -0,0 +1,135 @@ +load->model('market/Market_sys_role_model', 'mdSysRole'); + } + + /** + * Notes角色管理 + * Created on: 2022/9/8 14:48 + * Created by: dengbw + */ + public function index_get() + { + $page = intval($this->input_param('page')); + $limit = intval($this->input_param('limit')); + $roleName = $this->input_param('roleName'); + $roleCode = $this->input_param('roleCode'); + $comments = $this->input_param('comments'); + $sort = $this->input_param('sort'); + $order = $this->input_param('order'); + $date = $where = []; + if (!$page) { + $where['status'] = 0; + } else { + $where['status>='] = 0; + } + $sort_order = 'roleId desc'; + if ($sort && $order) { + $sort_order = $sort . ' ' . $order; + } + $roleName && $where['roleName'] = $roleName; + $roleCode && $where['roleCode'] = $roleCode; + $comments && $where['comments'] = $comments; + $res = $this->mdSysRole->select($where, $sort_order, $page, $limit); + foreach ($res as $v) { + $date[] = $v; + } + $this->return_response_list($date); + } + + /** + * Notes:修改角色 + * Created on: 2022/9/8 17:58 + * Created by: dengbw + */ + public function index_put() + { + $roleId = $this->input_param('roleId'); + $roleName = $this->input_param('roleName'); + $roleCode = $this->input_param('roleCode'); + $comments = $this->input_param('comments'); + if (!$roleId) { + $this->return_json('参数错误'); + } + if (!$roleName) { + $this->return_json('请输入角色名称'); + } + if (!$roleCode) { + $this->return_json('请输入角色标识'); + } + $upDate = ['roleName' => $roleName, 'roleCode' => $roleCode, 'comments' => $comments]; + $this->mdSysRole->update($upDate, ['roleId' => $roleId]); + $this->return_response(); + } + + /** + * Notes:添加角色 + * Created on: 2022/9/9 11:47 + * Created by: dengbw + */ + public function index_post() + { + $roleName = $this->input_param('roleName'); + $roleCode = $this->input_param('roleCode'); + $comments = $this->input_param('comments'); + if (!$roleName) { + $this->return_json('请输入角色名称'); + } + if (!$roleCode) { + $this->return_json('请输入角色标识'); + } + $addDate = ['roleName' => $roleName, 'roleCode' => $roleCode, 'comments' => $comments, 'createTime' => date('Y-m-d H:i:s')]; + $id = $this->mdSysRole->add($addDate); + if (!$id) { + $this->return_json('添加角色失败'); + } + $this->return_response(); + } + + /** + * Notes:删除用户 + * Created on: 2022/9/9 16:10 + * Created by: dengbw + * @param null $roleId + */ + public function index_delete($roleId = null) + { + if (!$roleId) { + $this->return_json('参数错误'); + } + $this->mdSysRole->update(['status' => -1], ['roleId' => $roleId]); + $this->return_response(); + } + + /** + * Notes:批量删除用户 + * Created on: 2022/9/9 17:11 + * Created by: dengbw + */ + public function batch_delete() + { + $roleIds = $this->inputs; + if (!$roleIds) { + $this->return_json('参数错误'); + } + $str_roleIds = implode(',', $roleIds); + if ($str_roleIds) { + $this->mdSysRole->update(['status' => -1], ["roleId in($str_roleIds)" => null]); + } + $this->return_response(); + } + +} \ No newline at end of file diff --git a/market/controllers/api/system/RoleMenu.php b/market/controllers/api/system/RoleMenu.php new file mode 100644 index 00000000..b5c45447 --- /dev/null +++ b/market/controllers/api/system/RoleMenu.php @@ -0,0 +1,65 @@ +load->model('market/Market_sys_role_model', 'mdSysRole'); + $this->load->model('market/Market_sys_menu_model', 'mdSysMenu'); + } + + /** + * Notes:获取角色分配的菜单 (ele-admin:/system/role-menu) + * Created on: 2022/9/13 9:47 + * Created by: dengbw + * @param $roleId + */ + public function index_get($roleId) + { + if (!$roleId) { + $this->return_json('参数错误'); + } + $re_ro = $this->mdSysRole->get(['roleId' => $roleId, 'status' => 0]); + $menuIds = $re_ro ? $re_ro['menuIds'] . ',' : ''; + $where['status>='] = 0; + $res = $this->mdSysMenu->select($where, 'sortNumber asc,menuId desc'); + foreach ($res as $k => $v) { + $res[$k]['menuId'] = intval($v['menuId']); + $res[$k]['parentId'] = intval($v['parentId']); + $res[$k]['menuType'] = intval($v['menuType']); + $res[$k]['openType'] = intval($v['openType']); + $res[$k]['sortNumber'] = intval($v['sortNumber']); + $res[$k]['hide'] = intval($v['hide']); + $res[$k]['meta'] = json_decode($v['meta'], true); + $res[$k]['children'] = ''; + $res[$k]['checked'] = strstr($menuIds, "{$v['menuId']},") ? true : false; + } + $this->return_response_list($res); + } + + /** + * Notes:修改角色菜单(ele-admin:/system/role-menu) + * Created on: 2022/9/13 11:50 + * Created by: dengbw + * @param $roleId + */ + public function index_put($roleId) + { + if (!$roleId) { + $this->return_json('参数错误'); + } + $menuIds = $this->inputs; + $menuIds = $menuIds ? implode(',', $menuIds) : ''; + $this->mdSysRole->update(['menuIds' => $menuIds], ['roleId' => $roleId]); + $this->return_response(); + } + +} \ No newline at end of file diff --git a/market/controllers/api/system/User.php b/market/controllers/api/system/User.php new file mode 100644 index 00000000..e6b9c579 --- /dev/null +++ b/market/controllers/api/system/User.php @@ -0,0 +1,271 @@ +load->model('market/Market_sys_admin_model', 'mdSysAdmin'); + $this->load->model('market/Market_sys_role_model', 'mdSysRole'); + } + + /** + * Notes:用户管理列表 + * Created on: 2022/9/8 14:48 + * Created by: dengbw + */ + public function page_get() + { + $page = $this->input_param('page'); + $limit = $this->input_param('limit'); + $username = $this->input_param('username'); + $nickname = $this->input_param('nickname'); + $sex = $this->input_param('sex'); + $sort = $this->input_param('sort'); + $order = $this->input_param('order'); + !$page && $page = 1; + !$limit && $limit = 10; + $sort_order = 'userId desc'; + if ($sort && $order) { + if ($sort == 'sexName') { + $sort_order = 'sex ' . $order; + } else { + $sort_order = $sort . ' ' . $order; + } + } + $where = $list = []; + $where['status>='] = 0; + $username && $where['username'] = $username; + $nickname && $where['nickname'] = $nickname; + $sex && $where['sex'] = $sex; + $count = $this->mdSysAdmin->count($where); + if ($count) { + $res = $this->mdSysAdmin->select($where, $sort_order, $page, $limit); + foreach ($res as $v) { + $sexName = $v['sex'] == 2 ? '女' : '男'; + $status = intval($v['status']); + $roles = []; + if ($v['roleId']) { + $re_ro = $this->mdSysRole->get(['roleId' => $v['roleId']]); + if ($re_ro) { + $re_ro['userId'] = $v['userId']; + $re_ro['deleted'] = 0; + $roles[] = $re_ro; + } + } + $list[] = [ + 'userId' => $v['userId'], 'username' => $v['username'], 'nickname' => $v['nickname'], 'phone' => $v['phone'] + , 'status' => $status, 'sex' => $v['sex'], 'sexName' => $sexName, 'birthday' => $v['birthday'] + , 'introduction' => $v['introduction'], 'email' => $v['email'], 'createTime' => $v['createTime'], 'roles' => $roles, + ]; + } + } + $date = ['list' => $list, 'count' => $count]; + $this->return_response_list($date); + } + + /** + * Notes:用户详情 + * Created on: 2022/9/21 16:15 + * Created by: dengbw + * @param null $userId + */ + public function index_get($userId = null) + { + if (!$userId) { + $this->return_json('参数错误'); + } + $re = $this->mdSysAdmin->get(['userId' => $userId]); + if (!$re) { + $this->return_json('用户不存在'); + } + $re['sexName'] = $re['sex'] == 2 ? '女' : '男'; + $re['status'] = intval($re['status']); + $roles = []; + if ($re['roleId']) { + $re_ro = $this->mdSysRole->get(['roleId' => $re['roleId']]); + $re_ro && $roles[] = $re_ro; + } + $re['roles'] = $roles; + $this->return_response($re); + } + + /** + * Notes:修改用户 + * Created on: 2022/9/8 14:48 + * Created by: dengbw + */ + public function index_put() + { + $userId = $this->input_param('userId'); + $nickname = $this->input_param('nickname'); + $phone = $this->input_param('phone'); + $sex = $this->input_param('sex'); + $birthday = $this->input_param('birthday'); + $introduction = $this->input_param('introduction'); + $email = $this->input_param('email'); + $roleIds = $this->input_param('roleIds'); + if (!$userId) { + $this->return_json('参数错误'); + } + if (!$nickname) { + $this->return_json('请输入用户名'); + } + if (!$sex) { + $this->return_json('请选择性别'); + } + if (!$roleIds) { + $this->return_json('请选择角色'); + } + $roleId = intval($roleIds[0]); + $upDate = ['nickname' => $nickname, 'phone' => $phone, 'sex' => $sex, 'birthday' => $birthday, + 'introduction' => $introduction, 'email' => $email, 'roleId' => $roleId]; + $this->mdSysAdmin->update($upDate, ['userId' => $userId]); + $this->return_response(); + } + + /** + * Notes:添加用户 + * Created on: 2022/9/8 16:46 + * Created by: dengbw + */ + public function index_post() + { + $username = $this->input_param('username'); + $nickname = $this->input_param('nickname'); + $phone = $this->input_param('phone'); + $sex = $this->input_param('sex'); + $birthday = $this->input_param('birthday'); + $introduction = $this->input_param('introduction'); + $email = $this->input_param('email'); + $roleIds = $this->input_param('roleIds'); + $password = $this->input_param('password'); + if (!$username) { + $this->return_json('请输入用户帐户'); + } + if (!$nickname) { + $this->return_json('请输入用户名'); + } + if (!$sex) { + $this->return_json('请选择性别'); + } + if (!$password) { + $this->return_json('请输入登录密码'); + } + if (!$roleIds) { + $this->return_json('请选择角色'); + } + $re = $this->mdSysAdmin->get(['username' => $username]); + if ($re) { + $this->return_json('用户帐号已存在'); + } + $roleId = intval($roleIds[0]); + $password = password_hash($password, PASSWORD_BCRYPT); + $addDate = ['username' => $username, 'nickname' => $nickname, 'phone' => $phone, 'sex' => $sex, 'birthday' => $birthday + , 'password' => $password, 'introduction' => $introduction, 'email' => $email, 'roleId' => $roleId, 'createTime' => date('Y-m-d H:i:s')]; + $id = $this->mdSysAdmin->add($addDate); + if (!$id) { + $this->return_json('添加用户失败'); + } + $this->return_response(); + } + + + /** + * Notes:修改状态 + * Created on: 2022/9/8 16:10 + * Created by: dengbw + */ + public function status_put() + { + $userId = $this->input_param('userId'); + $status = $this->input_param('status'); + if (!$userId) { + $this->return_json('参数错误'); + } + $this->mdSysAdmin->update(['status' => $status], ['userId' => $userId]); + $this->return_response(); + } + + /** + * Notes:修改密码 + * Created on: 2022/9/8 16:11 + * Created by: dengbw + */ + public function password_put() + { + $userId = $this->input_param('userId'); + $password = $this->input_param('password'); + if (!$userId) { + $this->return_json('参数错误'); + } + if (!$password) { + $this->return_json('请输入重置密码'); + } + $password = password_hash($password, PASSWORD_BCRYPT); + $this->mdSysAdmin->update(['password' => $password], ['userId' => $userId]); + $this->return_response(); + } + + /** + * Notes:删除用户 + * Created on: 2022/9/8 16:10 + * Created by: dengbw + * @param null $userId + */ + public function index_delete($userId = null) + { + if (!$userId) { + $this->return_json('参数错误'); + } + $this->mdSysAdmin->update(['status' => -1], ['userId' => $userId]); + $this->return_response(); + } + + /** + * Notes:批量删除用户 + * Created on: 2022/9/8 17:11 + * Created by: dengbw + */ + public function batch_delete() + { + $ids = $this->inputs; + if (!$ids) { + $this->return_json('参数错误'); + } + $str_ids = implode(',', $ids); + if ($str_ids) { + $this->mdSysAdmin->update(['status' => -1], ["userId in($str_ids)" => null]); + } + $this->return_response(); + } + + + /** + * Notes:栓验字段 + * Created on: 2022/9/8 15:52 + * Created by: dengbw + */ + public function existence_get() + { + $field = $this->input_param('field'); + $value = $this->input_param('value'); + $id = $this->input_param('id'); + if (!$id) { + $re = $this->mdSysAdmin->get([$field => $value]); + if ($re) { + $this->return_json('已存在', 0); + } + } + $this->return_json('不存在', 1); + } + +} \ No newline at end of file diff --git a/market/core/HD_Controller.php b/market/core/HD_Controller.php new file mode 100644 index 00000000..dedd43de --- /dev/null +++ b/market/core/HD_Controller.php @@ -0,0 +1,26 @@ + $returnData, 'code' => $code, 'msg' => $msg), JSON_UNESCAPED_UNICODE); + exit(); + } + + public function fail($returnData, $msg = 'fail', $code = 400) + { + header('Content-Type:application/json; charset=utf-8'); + echo json_encode(array('data' => $returnData, 'code' => $code, 'msg' => $msg), JSON_UNESCAPED_UNICODE); + exit(); + } + +} \ No newline at end of file diff --git a/market/core/HD_Loader.php b/market/core/HD_Loader.php new file mode 100644 index 00000000..f02d2be9 --- /dev/null +++ b/market/core/HD_Loader.php @@ -0,0 +1,1584 @@ + TRUE); + + /** + * List of paths to load libraries from + * + * @var array + */ + // add COMMPATH by 0fun + protected $_ci_library_paths = array(APPPATH, COMMPATH, BASEPATH); + + /** + * List of paths to load service from + * + * @var array + */ + // add lcc + protected $_ci_service_paths = array(APPPATH, COMMPATH); + + /** + * List of paths to load models from + * + * @var array + */ + // add COMMPATH by 0fun + protected $_ci_model_paths = array(APPPATH, COMMPATH); + + /** + * List of paths to load helpers from + * + * @var array + */ + // add COMMPATH by 0fun + protected $_ci_helper_paths = array(APPPATH, COMMPATH, BASEPATH); + + /** + * List of cached variables + * + * @var array + */ + protected $_ci_cached_vars = array(); + + /** + * List of loaded classes + * + * @var array + */ + protected $_ci_classes = array(); + + /** + * List of loaded models + * + * @var array + */ + protected $_ci_models = array(); + + /** + * List of loaded helpers + * + * @var array + */ + protected $_ci_helpers = array(); + + /** + * List of class name mappings + * + * @var array + */ + protected $_ci_varmap = array( + 'unit_test' => 'unit', + 'user_agent' => 'agent' + ); + + // -------------------------------------------------------------------- + + /** + * Class constructor + * + * Sets component load paths, gets the initial output buffering level. + * + * @return void + */ + public function __construct() + { + $this->_ci_ob_level = ob_get_level(); + $this->_ci_classes =& is_loaded(); + + log_message('info', 'Loader Class Initialized'); + } + + // -------------------------------------------------------------------- + + /** + * Initializer + * + * @todo Figure out a way to move this to the constructor + * without breaking *package_path*() methods. + * @uses CI_Loader::_ci_autoloader() + * @used-by CI_Controller::__construct() + * @return void + */ + public function initialize() + { + $this->_ci_autoloader(); + } + + // -------------------------------------------------------------------- + + /** + * Is Loaded + * + * A utility method to test if a class is in the self::$_ci_classes array. + * + * @used-by Mainly used by Form Helper function _get_validation_object(). + * + * @param string $class Class name to check for + * @return string|bool Class object name if loaded or FALSE + */ + public function is_loaded($class) + { + return array_search(ucfirst($class), $this->_ci_classes, TRUE); + } + + // -------------------------------------------------------------------- + + /** + * Library Loader + * + * Loads and instantiates libraries. + * Designed to be called from application controllers. + * + * @param mixed $library Library name + * @param array $params Optional parameters to pass to the library class constructor + * @param string $object_name An optional object name to assign to + * @return object + */ + public function library($library, $params = NULL, $object_name = NULL) + { + if (empty($library)) + { + return $this; + } + elseif (is_array($library)) + { + foreach ($library as $key => $value) + { + if (is_int($key)) + { + $this->library($value, $params); + } + else + { + $this->library($key, $params, $value); + } + } + + return $this; + } + + if ($params !== NULL && ! is_array($params)) + { + $params = NULL; + } + + $this->_ci_load_library($library, $params, $object_name); + return $this; + } + /** + * Service Loader + * + * This function lets users load and instantiate classes. + * It is designed to be called from a user's app controllers. + * + * @param string the name of the class + * @param mixed the optional parameters + * @param string an optional object name + * @return void + */ + public function service($service = '', $params = NULL, $object_name = NULL){ + if (empty($service)){ + return $this; + }elseif(is_array($service)){ + foreach($service as $class) + { + $this->service($class, $params); + } + return $this; + } + + $path = ''; + + // Is the service in a sub-folder? If so, parse out the filename and path. + if (($last_slash = strrpos($service, '/')) !== FALSE) + { + // The path is in front of the last slash + $path = substr($service, 0, ++$last_slash); + + // And the model name behind it + $service = substr($service, $last_slash); + } + + if (empty($object_name)) + { + $object_name = $service; + } + + if($this->_ci_services && is_array($this->_ci_services)){ + if (in_array($object_name, $this->_ci_services, TRUE)) + { + return $this; + } + } + $CI =& get_instance(); + if (isset($CI->$object_name)) + { + throw new RuntimeException('The service name you are loading is the name of a resource that is already being used: '.$object_name); + } + + // Note: All of the code under this condition used to be just: + // + // load_class('Service', 'core'); + // + // However, load_class() instantiates classes + // to cache them for later use and that prevents + // MY_Service from being an abstract class and is + // sub-optimal otherwise anyway. + if ( ! class_exists('CI_Service', FALSE)) + { + $app_path = APPPATH.'core'.DIRECTORY_SEPARATOR; + if (file_exists($app_path.'Service.php')) + { + require_once($app_path.'Service.php'); + if ( ! class_exists('CI_Service', FALSE)) + { + throw new RuntimeException($app_path."Service.php exists, but doesn't declare class CI_Service"); + } + + log_message('info', 'CI_Service class loaded'); + } + + $class = config_item('subclass_prefix').'Service'; + if (file_exists($app_path.$class.'.php')) + { + require_once($app_path.$class.'.php'); + if ( ! class_exists($class, FALSE)) + { + throw new RuntimeException($app_path.$class.".php exists, but doesn't declare class ".$class); + } + + log_message('info', config_item('subclass_prefix').'Service class loaded'); + } + } + $service = ucfirst($service); + + if ( ! class_exists($service, FALSE)) + { + foreach ($this->_ci_service_paths as $mod_path) + { + if ( ! file_exists($mod_path.'services/'.$path.$service.'.php')) + { + continue; + } + + require_once($mod_path.'services/'.$path.$service.'.php'); + if ( ! class_exists($service, FALSE)) + { + throw new RuntimeException($mod_path."services/".$path.$service.".php exists, but doesn't declare class ".$service); + } + + break; + } + + if ( ! class_exists($service, FALSE)) + { + throw new RuntimeException('Unable to locate the model you have specified: '.$service); + } + } + + + $this->_ci_services[] = $object_name; + if(empty($params)){ + $service = new $service(); + }else{ + $service = new $service($params); + } + $CI->$object_name = $service; + log_message('info', 'Service "'.get_class($service).'" initialized'); + return $this; + } + // -------------------------------------------------------------------- + + /** + * Model Loader + * + * Loads and instantiates models. + * + * @param mixed $model Model name + * @param string $name An optional object name to assign to + * @param bool $db_conn An optional database connection configuration to initialize + * @return object + */ + public function model($model, $name = '', $db_conn = FALSE) + { + if (empty($model)) + { + return $this; + } + elseif (is_array($model)) + { + foreach ($model as $key => $value) + { + is_int($key) ? $this->model($value, '', $db_conn) : $this->model($key, $value, $db_conn); + } + + return $this; + } + + $path = ''; + + // Is the model in a sub-folder? If so, parse out the filename and path. + if (($last_slash = strrpos($model, '/')) !== FALSE) + { + // The path is in front of the last slash + $path = substr($model, 0, ++$last_slash); + + // And the model name behind it + $model = substr($model, $last_slash); + } + + if (empty($name)) + { + $name = $model; + } + + if (in_array($name, $this->_ci_models, TRUE)) + { + return $this; + } + + $CI =& get_instance(); + if (isset($CI->$name)) + { + throw new RuntimeException('The model name you are loading is the name of a resource that is already being used: '.$name); + } + + if ($db_conn !== FALSE && ! class_exists('CI_DB', FALSE)) + { + if ($db_conn === TRUE) + { + $db_conn = ''; + } + + $this->database($db_conn, FALSE, TRUE); + } + + // Note: All of the code under this condition used to be just: + // + // load_class('Model', 'core'); + // + // However, load_class() instantiates classes + // to cache them for later use and that prevents + // MY_Model from being an abstract class and is + // sub-optimal otherwise anyway. + if ( ! class_exists('CI_Model', FALSE)) + { + $app_path = APPPATH.'core'.DIRECTORY_SEPARATOR; + if (file_exists($app_path.'Model.php')) + { + require_once($app_path.'Model.php'); + if ( ! class_exists('CI_Model', FALSE)) + { + throw new RuntimeException($app_path."Model.php exists, but doesn't declare class CI_Model"); + } + + log_message('info', 'CI_Model class loaded'); + } + elseif ( ! class_exists('CI_Model', FALSE)) + { + require_once(BASEPATH.'core'.DIRECTORY_SEPARATOR.'Model.php'); + } + + $class = config_item('subclass_prefix').'Model'; + if (file_exists($app_path.$class.'.php')) + { + require_once($app_path.$class.'.php'); + if ( ! class_exists($class, FALSE)) + { + throw new RuntimeException($app_path.$class.".php exists, but doesn't declare class ".$class); + } + + log_message('info', config_item('subclass_prefix').'Model class loaded'); + } + } + + $model = ucfirst($model); + if ( ! class_exists($model, FALSE)) + { + foreach ($this->_ci_model_paths as $mod_path) + { + if ( ! file_exists($mod_path.'models/'.$path.$model.'.php')) + { + continue; + } + + require_once($mod_path.'models/'.$path.$model.'.php'); + if ( ! class_exists($model, FALSE)) + { + throw new RuntimeException($mod_path."models/".$path.$model.".php exists, but doesn't declare class ".$model); + } + + break; + } + + if ( ! class_exists($model, FALSE)) + { + throw new RuntimeException('Unable to locate the model you have specified: '.$model); + } + } + elseif ( ! is_subclass_of($model, 'CI_Model')) + { + throw new RuntimeException("Class ".$model." already exists and doesn't extend CI_Model"); + } + + $this->_ci_models[] = $name; + $model = new $model(); + $CI->$name = $model; + log_message('info', 'Model "'.get_class($model).'" initialized'); + return $this; + } + + /** + * 根据app_id重建model + * @param $app_id + * @return $this + */ + public function rebuild_model($app_id){ + if(!$app_id){ + return $this; + } + + $CI =& get_instance(); + + $CI->config->load("app", true); + $configs = $CI->config->item('app'); + $config= array(); + foreach($configs as $v){ + if($v['app_id'] == $app_id){ + $config = $v; + break; + } + } + + $app_db = $config['db']; + if($config && $app_db){ + $GLOBALS['app_db'] = $app_db; + + $CI->load->config("dbtable", true, true); + $dbtable = $CI->config->item($app_db, "dbtable"); + $models = $this->_ci_models; + foreach($models as $model){ + $CI->$model->set_appdb($app_db, $dbtable); + } + } + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Database Loader + * + * @param mixed $params Database configuration options + * @param bool $return Whether to return the database object + * @param bool $query_builder Whether to enable Query Builder + * (overrides the configuration setting) + * + * @return object|bool Database object if $return is set to TRUE, + * FALSE on failure, CI_Loader instance in any other case + */ + public function database($params = '', $return = FALSE, $query_builder = NULL) + { + // Grab the super object + $CI =& get_instance(); + + // Do we even need to load the database class? + if ($return === FALSE && $query_builder === NULL && isset($CI->db) && is_object($CI->db) && ! empty($CI->db->conn_id)) + { + return FALSE; + } + + require_once(BASEPATH.'database/DB.php'); + + if ($return === TRUE) + { + return DB($params, $query_builder); + } + + // Initialize the db variable. Needed to prevent + // reference errors with some configurations + $CI->db = ''; + + // Load the DB class + $CI->db =& DB($params, $query_builder); + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Load the Database Utilities Class + * + * @param object $db Database object + * @param bool $return Whether to return the DB Utilities class object or not + * @return object + */ + public function dbutil($db = NULL, $return = FALSE) + { + $CI =& get_instance(); + + if ( ! is_object($db) OR ! ($db instanceof CI_DB)) + { + class_exists('CI_DB', FALSE) OR $this->database(); + $db =& $CI->db; + } + + require_once(BASEPATH.'database/DB_utility.php'); + require_once(BASEPATH.'database/drivers/'.$db->dbdriver.'/'.$db->dbdriver.'_utility.php'); + $class = 'CI_DB_'.$db->dbdriver.'_utility'; + + if ($return === TRUE) + { + return new $class($db); + } + + $CI->dbutil = new $class($db); + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Load the Database Forge Class + * + * @param object $db Database object + * @param bool $return Whether to return the DB Forge class object or not + * @return object + */ + public function dbforge($db = NULL, $return = FALSE) + { + $CI =& get_instance(); + if ( ! is_object($db) OR ! ($db instanceof CI_DB)) + { + class_exists('CI_DB', FALSE) OR $this->database(); + $db =& $CI->db; + } + + require_once(BASEPATH.'database/DB_forge.php'); + require_once(BASEPATH.'database/drivers/'.$db->dbdriver.'/'.$db->dbdriver.'_forge.php'); + + if ( ! empty($db->subdriver)) + { + $driver_path = BASEPATH.'database/drivers/'.$db->dbdriver.'/subdrivers/'.$db->dbdriver.'_'.$db->subdriver.'_forge.php'; + if (file_exists($driver_path)) + { + require_once($driver_path); + $class = 'CI_DB_'.$db->dbdriver.'_'.$db->subdriver.'_forge'; + } + } + else + { + $class = 'CI_DB_'.$db->dbdriver.'_forge'; + } + + if ($return === TRUE) + { + return new $class($db); + } + + $CI->dbforge = new $class($db); + return $this; + } + + // -------------------------------------------------------------------- + + /** + * View Loader + * + * Loads "view" files. + * + * @param string $view View name + * @param array $vars An associative array of data + * to be extracted for use in the view + * @param bool $return Whether to return the view output + * or leave it to the Output class + * @return object|string + */ + public function view($view, $vars = array(), $return = FALSE) + { + return $this->_ci_load(array('_ci_view' => $view, '_ci_vars' => $this->_ci_prepare_view_vars($vars), '_ci_return' => $return)); + } + + // -------------------------------------------------------------------- + + /** + * Generic File Loader + * + * @param string $path File path + * @param bool $return Whether to return the file output + * @return object|string + */ + public function file($path, $return = FALSE) + { + return $this->_ci_load(array('_ci_path' => $path, '_ci_return' => $return)); + } + + // -------------------------------------------------------------------- + + /** + * Set Variables + * + * Once variables are set they become available within + * the controller class and its "view" files. + * + * @param array|object|string $vars + * An associative array or object containing values + * to be set, or a value's name if string + * @param string $val Value to set, only used if $vars is a string + * @return object + */ + public function vars($vars, $val = '') + { + $vars = is_string($vars) + ? array($vars => $val) + : $this->_ci_prepare_view_vars($vars); + + foreach ($vars as $key => $val) + { + $this->_ci_cached_vars[$key] = $val; + } + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Clear Cached Variables + * + * Clears the cached variables. + * + * @return CI_Loader + */ + public function clear_vars() + { + $this->_ci_cached_vars = array(); + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Get Variable + * + * Check if a variable is set and retrieve it. + * + * @param string $key Variable name + * @return mixed The variable or NULL if not found + */ + public function get_var($key) + { + return isset($this->_ci_cached_vars[$key]) ? $this->_ci_cached_vars[$key] : NULL; + } + + // -------------------------------------------------------------------- + + /** + * Get Variables + * + * Retrieves all loaded variables. + * + * @return array + */ + public function get_vars() + { + return $this->_ci_cached_vars; + } + + // -------------------------------------------------------------------- + + /** + * Helper Loader + * + * @param string|string[] $helpers Helper name(s) + * @return object + */ + public function helper($helpers = array()) + { + is_array($helpers) OR $helpers = array($helpers); + foreach ($helpers as &$helper) + { + $filename = basename($helper); + $filepath = ($filename === $helper) ? '' : substr($helper, 0, strlen($helper) - strlen($filename)); + $filename = strtolower(preg_replace('#(_helper)?(\.php)?$#i', '', $filename)).'_helper'; + $helper = $filepath.$filename; + + if (isset($this->_ci_helpers[$helper])) + { + continue; + } + + // Is this a helper extension request? + $ext_helper = config_item('subclass_prefix').$filename; + $ext_loaded = FALSE; + foreach ($this->_ci_helper_paths as $path) + { + if (file_exists($path.'helpers/'.$ext_helper.'.php')) + { + include_once($path.'helpers/'.$ext_helper.'.php'); + $ext_loaded = TRUE; + } + } + + // If we have loaded extensions - check if the base one is here + if ($ext_loaded === TRUE) + { + $base_helper = BASEPATH.'helpers/'.$helper.'.php'; + if ( ! file_exists($base_helper)) + { + show_error('Unable to load the requested file: helpers/'.$helper.'.php'); + } + + include_once($base_helper); + $this->_ci_helpers[$helper] = TRUE; + log_message('info', 'Helper loaded: '.$helper); + continue; + } + + // No extensions found ... try loading regular helpers and/or overrides + foreach ($this->_ci_helper_paths as $path) + { + if (file_exists($path.'helpers/'.$helper.'.php')) + { + include_once($path.'helpers/'.$helper.'.php'); + + $this->_ci_helpers[$helper] = TRUE; + log_message('info', 'Helper loaded: '.$helper); + break; + } + } + + // unable to load the helper + if ( ! isset($this->_ci_helpers[$helper])) + { + show_error('Unable to load the requested file: helpers/'.$helper.'.php'); + } + } + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Load Helpers + * + * An alias for the helper() method in case the developer has + * written the plural form of it. + * + * @uses CI_Loader::helper() + * @param string|string[] $helpers Helper name(s) + * @return object + */ + public function helpers($helpers = array()) + { + return $this->helper($helpers); + } + + // -------------------------------------------------------------------- + + /** + * Language Loader + * + * Loads language files. + * + * @param string|string[] $files List of language file names to load + * @param string Language name + * @return object + */ + public function language($files, $lang = '') + { + get_instance()->lang->load($files, $lang); + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Config Loader + * + * Loads a config file (an alias for CI_Config::load()). + * + * @uses CI_Config::load() + * @param string $file Configuration file name + * @param bool $use_sections Whether configuration values should be loaded into their own section + * @param bool $fail_gracefully Whether to just return FALSE or display an error message + * @return bool TRUE if the file was loaded correctly or FALSE on failure + */ + public function config($file, $use_sections = FALSE, $fail_gracefully = FALSE) + { + return get_instance()->config->load($file, $use_sections, $fail_gracefully); + } + + // -------------------------------------------------------------------- + + /** + * Driver Loader + * + * Loads a driver library. + * + * @param string|string[] $library Driver name(s) + * @param array $params Optional parameters to pass to the driver + * @param string $object_name An optional object name to assign to + * + * @return object|bool Object or FALSE on failure if $library is a string + * and $object_name is set. CI_Loader instance otherwise. + */ + public function driver($library, $params = NULL, $object_name = NULL) + { + if (is_array($library)) + { + foreach ($library as $key => $value) + { + if (is_int($key)) + { + $this->driver($value, $params); + } + else + { + $this->driver($key, $params, $value); + } + } + + return $this; + } + elseif (empty($library)) + { + return FALSE; + } + + if ( ! class_exists('CI_Driver_Library', FALSE)) + { + // We aren't instantiating an object here, just making the base class available + require BASEPATH.'libraries/Driver.php'; + } + + // We can save the loader some time since Drivers will *always* be in a subfolder, + // and typically identically named to the library + if ( ! strpos($library, '/')) + { + $library = ucfirst($library).'/'.$library; + } + + return $this->library($library, $params, $object_name); + } + + // -------------------------------------------------------------------- + + /** + * Add Package Path + * + * Prepends a parent path to the library, model, helper and config + * path arrays. + * + * @see CI_Loader::$_ci_library_paths + * @see CI_Loader::$_ci_model_paths + * @see CI_Loader::$_ci_helper_paths + * @see CI_Config::$_config_paths + * + * @param string $path Path to add + * @param bool $view_cascade (default: TRUE) + * @return object + */ + public function add_package_path($path, $view_cascade = TRUE) + { + $path = rtrim($path, '/').'/'; + + array_unshift($this->_ci_library_paths, $path); + array_unshift($this->_ci_model_paths, $path); + array_unshift($this->_ci_helper_paths, $path); + + $this->_ci_view_paths = array($path.'views/' => $view_cascade) + $this->_ci_view_paths; + + // Add config file path + $config =& $this->_ci_get_component('config'); + $config->_config_paths[] = $path; + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Get Package Paths + * + * Return a list of all package paths. + * + * @param bool $include_base Whether to include BASEPATH (default: FALSE) + * @return array + */ + public function get_package_paths($include_base = FALSE) + { + return ($include_base === TRUE) ? $this->_ci_library_paths : $this->_ci_model_paths; + } + + // -------------------------------------------------------------------- + + /** + * Remove Package Path + * + * Remove a path from the library, model, helper and/or config + * path arrays if it exists. If no path is provided, the most recently + * added path will be removed removed. + * + * @param string $path Path to remove + * @return object + */ + public function remove_package_path($path = '') + { + $config =& $this->_ci_get_component('config'); + + if ($path === '') + { + array_shift($this->_ci_library_paths); + array_shift($this->_ci_model_paths); + array_shift($this->_ci_helper_paths); + array_shift($this->_ci_view_paths); + array_pop($config->_config_paths); + } + else + { + $path = rtrim($path, '/').'/'; + foreach (array('_ci_library_paths', '_ci_model_paths', '_ci_helper_paths') as $var) + { + if (($key = array_search($path, $this->{$var})) !== FALSE) + { + unset($this->{$var}[$key]); + } + } + + if (isset($this->_ci_view_paths[$path.'views/'])) + { + unset($this->_ci_view_paths[$path.'views/']); + } + + if (($key = array_search($path, $config->_config_paths)) !== FALSE) + { + unset($config->_config_paths[$key]); + } + } + + // make sure the application default paths are still in the array + $this->_ci_library_paths = array_unique(array_merge($this->_ci_library_paths, array(APPPATH, BASEPATH))); + $this->_ci_helper_paths = array_unique(array_merge($this->_ci_helper_paths, array(APPPATH, BASEPATH))); + $this->_ci_model_paths = array_unique(array_merge($this->_ci_model_paths, array(APPPATH))); + $this->_ci_view_paths = array_merge($this->_ci_view_paths, array(APPPATH.'views/' => TRUE)); + $config->_config_paths = array_unique(array_merge($config->_config_paths, array(APPPATH))); + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Internal CI Data Loader + * + * Used to load views and files. + * + * Variables are prefixed with _ci_ to avoid symbol collision with + * variables made available to view files. + * + * @used-by CI_Loader::view() + * @used-by CI_Loader::file() + * @param array $_ci_data Data to load + * @return object + */ + protected function _ci_load($_ci_data) + { + // Set the default data variables + foreach (array('_ci_view', '_ci_vars', '_ci_path', '_ci_return') as $_ci_val) + { + $$_ci_val = isset($_ci_data[$_ci_val]) ? $_ci_data[$_ci_val] : FALSE; + } + + $file_exists = FALSE; + + // Set the path to the requested file + if (is_string($_ci_path) && $_ci_path !== '') + { + $_ci_x = explode('/', $_ci_path); + $_ci_file = end($_ci_x); + } + else + { + $_ci_ext = pathinfo($_ci_view, PATHINFO_EXTENSION); + $_ci_file = ($_ci_ext === '') ? $_ci_view.'.php' : $_ci_view; + + foreach ($this->_ci_view_paths as $_ci_view_file => $cascade) + { + if (file_exists($_ci_view_file.$_ci_file)) + { + $_ci_path = $_ci_view_file.$_ci_file; + $file_exists = TRUE; + break; + } + + if ( ! $cascade) + { + break; + } + } + } + + if ( ! $file_exists && ! file_exists($_ci_path)) + { + show_error('Unable to load the requested file: '.$_ci_file); + } + + // This allows anything loaded using $this->load (views, files, etc.) + // to become accessible from within the Controller and Model functions. + $_ci_CI =& get_instance(); + foreach (get_object_vars($_ci_CI) as $_ci_key => $_ci_var) + { + if ( ! isset($this->$_ci_key)) + { + $this->$_ci_key =& $_ci_CI->$_ci_key; + } + } + + /* + * Extract and cache variables + * + * You can either set variables using the dedicated $this->load->vars() + * function or via the second parameter of this function. We'll merge + * the two types and cache them so that views that are embedded within + * other views can have access to these variables. + */ + empty($_ci_vars) OR $this->_ci_cached_vars = array_merge($this->_ci_cached_vars, $_ci_vars); + extract($this->_ci_cached_vars); + + /* + * Buffer the output + * + * We buffer the output for two reasons: + * 1. Speed. You get a significant speed boost. + * 2. So that the final rendered template can be post-processed by + * the output class. Why do we need post processing? For one thing, + * in order to show the elapsed page load time. Unless we can + * intercept the cms right before it's sent to the browser and + * then stop the timer it won't be accurate. + */ + ob_start(); + + // If the PHP installation does not support short tags we'll + // do a little string replacement, changing the short tags + // to standard PHP echo statements. + if ( ! is_php('5.4') && ! ini_get('short_open_tag') && config_item('rewrite_short_tags') === TRUE) + { + echo eval('?>'.preg_replace('/;*\s*\?>/', '; ?>', str_replace(' $this->_ci_ob_level + 1) + { + ob_end_flush(); + } + else + { + $_ci_CI->output->append_output(ob_get_contents()); + @ob_end_clean(); + } + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Internal CI Library Loader + * + * @used-by CI_Loader::library() + * @uses CI_Loader::_ci_init_library() + * + * @param string $class Class name to load + * @param mixed $params Optional parameters to pass to the class constructor + * @param string $object_name Optional object name to assign to + * @return void + */ + protected function _ci_load_library($class, $params = NULL, $object_name = NULL) + { + // Get the class name, and while we're at it trim any slashes. + // The directory path can be included as part of the class name, + // but we don't want a leading slash + $class = str_replace('.php', '', trim($class, '/')); + + // Was the path included with the class name? + // We look for a slash to determine this + if (($last_slash = strrpos($class, '/')) !== FALSE) + { + // Extract the path + $subdir = substr($class, 0, ++$last_slash); + + // Get the filename from the path + $class = substr($class, $last_slash); + } + else + { + $subdir = ''; + } + + $class = ucfirst($class); + + // Is this a stock library? There are a few special conditions if so ... + if (file_exists(BASEPATH.'libraries/'.$subdir.$class.'.php')) + { + return $this->_ci_load_stock_library($class, $subdir, $params, $object_name); + } + + // Safety: Was the class already loaded by a previous call? + if (class_exists($class, FALSE)) + { + $property = $object_name; + if (empty($property)) + { + $property = strtolower($class); + isset($this->_ci_varmap[$property]) && $property = $this->_ci_varmap[$property]; + } + + $CI =& get_instance(); + if (isset($CI->$property)) + { + log_message('debug', $class.' class already loaded. Second attempt ignored.'); + return; + } + + return $this->_ci_init_library($class, '', $params, $object_name); + } + + // Let's search for the requested library file and load it. + foreach ($this->_ci_library_paths as $path) + { + // BASEPATH has already been checked for + if ($path === BASEPATH) + { + continue; + } + + $filepath = $path.'libraries/'.$subdir.$class.'.php'; + // Does the file exist? No? Bummer... + if ( ! file_exists($filepath)) + { + continue; + } + + include_once($filepath); + return $this->_ci_init_library($class, '', $params, $object_name); + } + + // One last attempt. Maybe the library is in a subdirectory, but it wasn't specified? + if ($subdir === '') + { + return $this->_ci_load_library($class.'/'.$class, $params, $object_name); + } + + // If we got this far we were unable to find the requested class. + log_message('error', 'Unable to load the requested class: '.$class); + show_error('Unable to load the requested class: '.$class); + } + + // -------------------------------------------------------------------- + + /** + * Internal CI Stock Library Loader + * + * @used-by CI_Loader::_ci_load_library() + * @uses CI_Loader::_ci_init_library() + * + * @param string $library_name Library name to load + * @param string $file_path Path to the library filename, relative to libraries/ + * @param mixed $params Optional parameters to pass to the class constructor + * @param string $object_name Optional object name to assign to + * @return void + */ + protected function _ci_load_stock_library($library_name, $file_path, $params, $object_name) + { + $prefix = 'CI_'; + + if (class_exists($prefix.$library_name, FALSE)) + { + if (class_exists(config_item('subclass_prefix').$library_name, FALSE)) + { + $prefix = config_item('subclass_prefix'); + } + + $property = $object_name; + if (empty($property)) + { + $property = strtolower($library_name); + isset($this->_ci_varmap[$property]) && $property = $this->_ci_varmap[$property]; + } + + $CI =& get_instance(); + if ( ! isset($CI->$property)) + { + return $this->_ci_init_library($library_name, $prefix, $params, $object_name); + } + + log_message('debug', $library_name.' class already loaded. Second attempt ignored.'); + return; + } + + $paths = $this->_ci_library_paths; + array_pop($paths); // BASEPATH + array_pop($paths); // APPPATH (needs to be the first path checked) + array_unshift($paths, APPPATH); + + foreach ($paths as $path) + { + if (file_exists($path = $path.'libraries/'.$file_path.$library_name.'.php')) + { + // Override + include_once($path); + if (class_exists($prefix.$library_name, FALSE)) + { + return $this->_ci_init_library($library_name, $prefix, $params, $object_name); + } + + log_message('debug', $path.' exists, but does not declare '.$prefix.$library_name); + } + } + + include_once(BASEPATH.'libraries/'.$file_path.$library_name.'.php'); + + // Check for extensions + $subclass = config_item('subclass_prefix').$library_name; + foreach ($paths as $path) + { + if (file_exists($path = $path.'libraries/'.$file_path.$subclass.'.php')) + { + include_once($path); + if (class_exists($subclass, FALSE)) + { + $prefix = config_item('subclass_prefix'); + break; + } + + log_message('debug', $path.' exists, but does not declare '.$subclass); + } + } + + return $this->_ci_init_library($library_name, $prefix, $params, $object_name); + } + + // -------------------------------------------------------------------- + + /** + * Internal CI Library Instantiator + * + * @used-by CI_Loader::_ci_load_stock_library() + * @used-by CI_Loader::_ci_load_library() + * + * @param string $class Class name + * @param string $prefix Class name prefix + * @param array|null|bool $config Optional configuration to pass to the class constructor: + * FALSE to skip; + * NULL to search in config paths; + * array containing configuration data + * @param string $object_name Optional object name to assign to + * @return void + */ + protected function _ci_init_library($class, $prefix, $config = FALSE, $object_name = NULL) + { + // Is there an associated config file for this class? Note: these should always be lowercase + if ($config === NULL) + { + // Fetch the config paths containing any package paths + $config_component = $this->_ci_get_component('config'); + + if (is_array($config_component->_config_paths)) + { + $found = FALSE; + foreach ($config_component->_config_paths as $path) + { + // We test for both uppercase and lowercase, for servers that + // are case-sensitive with regard to file names. Load global first, + // override with environment next + if (file_exists($path.'config/'.strtolower($class).'.php')) + { + include($path.'config/'.strtolower($class).'.php'); + $found = TRUE; + } + elseif (file_exists($path.'config/'.ucfirst(strtolower($class)).'.php')) + { + include($path.'config/'.ucfirst(strtolower($class)).'.php'); + $found = TRUE; + } + + if (file_exists($path.'config/'.ENVIRONMENT.'/'.strtolower($class).'.php')) + { + include($path.'config/'.ENVIRONMENT.'/'.strtolower($class).'.php'); + $found = TRUE; + } + elseif (file_exists($path.'config/'.ENVIRONMENT.'/'.ucfirst(strtolower($class)).'.php')) + { + include($path.'config/'.ENVIRONMENT.'/'.ucfirst(strtolower($class)).'.php'); + $found = TRUE; + } + + // Break on the first found configuration, thus package + // files are not overridden by default paths + if ($found === TRUE) + { + break; + } + } + } + } + + $class_name = $prefix.$class; + + // Is the class name valid? + if ( ! class_exists($class_name, FALSE)) + { + log_message('error', 'Non-existent class: '.$class_name); + show_error('Non-existent class: '.$class_name); + } + + // Set the variable name we will assign the class to + // Was a custom class name supplied? If so we'll use it + if (empty($object_name)) + { + $object_name = strtolower($class); + if (isset($this->_ci_varmap[$object_name])) + { + $object_name = $this->_ci_varmap[$object_name]; + } + } + + // Don't overwrite existing properties + $CI =& get_instance(); + if (isset($CI->$object_name)) + { + if ($CI->$object_name instanceof $class_name) + { + log_message('debug', $class_name." has already been instantiated as '".$object_name."'. Second attempt aborted."); + return; + } + + show_error("Resource '".$object_name."' already exists and is not a ".$class_name." instance."); + } + + // Save the class name and object name + $this->_ci_classes[$object_name] = $class; + + // Instantiate the class + $CI->$object_name = isset($config) + ? new $class_name($config) + : new $class_name(); + } + + // -------------------------------------------------------------------- + + /** + * CI Autoloader + * + * Loads component listed in the config/autoload.php file. + * + * @used-by CI_Loader::initialize() + * @return void + */ + protected function _ci_autoloader() + { + if (file_exists(APPPATH.'config/autoload.php')) + { + include(APPPATH.'config/autoload.php'); + } + + if (file_exists(APPPATH.'config/'.ENVIRONMENT.'/autoload.php')) + { + include(APPPATH.'config/'.ENVIRONMENT.'/autoload.php'); + } + + if ( ! isset($autoload)) + { + return; + } + + // Autoload packages + if (isset($autoload['packages'])) + { + foreach ($autoload['packages'] as $package_path) + { + $this->add_package_path($package_path); + } + } + + // Load any custom config file + if (count($autoload['config']) > 0) + { + foreach ($autoload['config'] as $val) + { + $this->config($val); + } + } + + // Autoload helpers and languages + foreach (array('helper', 'language') as $type) + { + if (isset($autoload[$type]) && count($autoload[$type]) > 0) + { + $this->$type($autoload[$type]); + } + } + + // Autoload drivers + if (isset($autoload['drivers'])) + { + $this->driver($autoload['drivers']); + } + + // Load libraries + if (isset($autoload['libraries']) && count($autoload['libraries']) > 0) + { + // Load the database driver. + if (in_array('database', $autoload['libraries'])) + { + $this->database(); + $autoload['libraries'] = array_diff($autoload['libraries'], array('database')); + } + + // Load all other libraries + $this->library($autoload['libraries']); + } + + // Autoload models + if (isset($autoload['model'])) + { + $this->model($autoload['model']); + } + } + + // -------------------------------------------------------------------- + + /** + * Prepare variables for _ci_vars, to be later extract()-ed inside views + * + * Converts objects to associative arrays and filters-out internal + * variable names (i.e. keys prefixed with '_ci_'). + * + * @param mixed $vars + * @return array + */ + protected function _ci_prepare_view_vars($vars) + { + if ( ! is_array($vars)) + { + $vars = is_object($vars) + ? get_object_vars($vars) + : array(); + } + + foreach (array_keys($vars) as $key) + { + if (strncmp($key, '_ci_', 4) === 0) + { + unset($vars[$key]); + } + } + + return $vars; + } + + // -------------------------------------------------------------------- + + /** + * CI Component getter + * + * Get a reference to a specific library or model. + * + * @param string $component Component name + * @return bool + */ + protected function &_ci_get_component($component) + { + $CI =& get_instance(); + return $CI->$component; + } +} diff --git a/market/core/HD_Model.php b/market/core/HD_Model.php new file mode 100644 index 00000000..93c150ca --- /dev/null +++ b/market/core/HD_Model.php @@ -0,0 +1,606 @@ +load->config("dbtable", true, true); + $dbtable = $this->config->item($app_db, "dbtable"); + if(is_array($dbtable) && in_array($table_name, $dbtable)){ + $db_group = $GLOBALS['app_db']; + } + } + + $this->set_db($db_group); + $this->set_table_name($table_name); + } + + public function set_db($db_group = 'default') + { + if(!isset(self::$dbs[$db_group])) + { + self::$dbs[$db_group] = $this->load->database($db_group, true); + } + + $this->db = self::$dbs[$db_group]; + } + + /** + * 根据app应用表设置库 + * @param $db_group + * @param $apptabs + */ + public function set_appdb($db_group, $apptabs){ + $table_name = $this->table_name; + if(is_array($apptabs) && in_array($table_name, $apptabs)){ + $this->set_db($db_group); + } + } + + public function set_table_name($table_name) + { + $this->table_name = $table_name; + } + + /** + * 表字段列表 + * @return mixed + */ + public function fields(){ + return $this->db->list_fields($this->table_name); + } + + + /** + * 添加单条数据 + * @param $data + * @return mixed + */ + public function add($data) + { + $result = $this->db->insert($this->table_name, $data); + return $this->db->insert_id() ? $this->db->insert_id() : $result; + } + + /** + * 添加多条数据 + * @param $data_array + * @return mixed + */ + public function add_batch($data_array) + { + if(is_array($data_array)) + { + return $this->db->insert_batch($this->table_name, $data_array); + } + + return false; + } + + /** + * 修改数据 + * @param $data + * @param $where + * @return mixed + */ + public function update($data, $where) + { + foreach($data as $k => $v) + { + if($v == null) { + if(strstr($k, ' = ')) { + $field = explode(' = ', $k); + $this->db->set($field[0], $field[1], FALSE); + unset($data[$k]); + } + } + } + + $result = $this->db->update($this->table_name, $data, $where); + return $this->db->affected_rows() ? $this->db->affected_rows() : $result; + } + + /** + * 修改数据2:支持order与limit + * @param $data + * @param $where + * @param $order + * @param $limit + * @return mixed + */ + public function update2($data, $where, $order = '', $limit = 0) + { + foreach($data as $k => $v) + { + if($v == null) { + if(strstr($k, ' = ')) { + $field = explode(' = ', $k); + $this->db->set($field[0], $field[1], FALSE); + unset($data[$k]); + } + } + } + + if($order){ + $this->db->order_by($order); + } + + if($limit) { + $this->db->limit($limit); + } + + $result = $this->db->update($this->table_name, $data, $where); + return $this->db->affected_rows() ? $this->db->affected_rows() : $result; + } + + /** + * 更新或插入数据 + * @param $data + * @return mixed + */ + public function replace($data) + { + if($data) + { + $result = $this->db->replace($this->table_name, $data); + return $this->db->affected_rows() ? $this->db->affected_rows() : $result; + } + + return false; + } + + /** + * 批量插入 + * @param $data + * @return CI_DB_active_record + */ + public function replace_batch($data) + { + if($data && is_array($data[0])) + { + $keys = array_keys($data[0]); + $keys = implode(',', $keys); + + $values = array(); + foreach($data as $item) + { + $item_values = array_values($item); + foreach($item_values as &$v) + { + if(!is_numeric($v)) + { + $v = addslashes($v); + $v = "'{$v}'"; + } + } + + $item_values = implode(',', $item_values); + $values[] = "({$item_values})"; + } + + $values = implode(',', $values); + $sql = "REPLACE {$this->table_name}({$keys}) VALUES {$values}"; + + return $this->db->query($sql); + } + } + + /** + * 获取单条数据 + * @param $where + * @param string $select + * @param object $obj 自定义结果对象 + * @return mixed + */ + public function get($where, $select = '', $obj = '') + { + if($select) + { + $this->db->select($select, false); + } + + if($obj && file_exists($class = COMMPATH.'libraries/entity/'.ucfirst($obj).'.php')) + { + require_once $class; + + if (class_exists(ucfirst($obj))) + { + return $this->db->get_where($this->table_name, $where)->custom_row_object(0, $obj); + } + } + + return $this->db->get_where($this->table_name, $where)->row_array(); + } + + + /** + * 获取多条数据集 + * @param array $where + * @param string $order + * @param int $page + * @param int $page_size + * @param string $select + * @param object obj + * @return mixed + */ + public function select($where = array(), $order = '', $page = 0, $page_size = 20, $select = '', $obj = '') + { + if($select) + { + $this->db->select($select, false); + } + + if($where) + { + $this->db->where($where); + } + + if($order) + { + $this->db->order_by($order); + } + + if($page) + { + $offset = ($page - 1) * $page_size; + $limit = $page_size; + } + else + { + $offset = null; + $limit = null; + } + $this->db->from($this->table_name); + $this->db->limit($limit, $offset); + $query = $this->db->get(); + $result = $query ? $query->result_array() : []; + if($obj && file_exists($class = APPPATH.'libraries/entity/'.ucfirst($obj).'.php')) + { + require_once $class; + if(class_exists($obj)) + { + $result = $this->db->get($this->table_name, $limit, $offset)->custom_result_object($obj); + } + } + return $result; + } + + /** + * @param $groupby + * @param array $where + * @param string $order + * @param int $page + * @param int $page_size + * @param string $select + * @param string $obj + * @return mixed + */ + public function select_groupby($groupby, $where = array(), $order = '', $page = 0, $page_size = 20, $select = '', $obj = ''){ + $this->db->group_by($groupby); + + return $this->select($where, $order, $page, $page_size, $select, $obj); + } + + /** + * 获取最大值 + * @param $field + * @param array $where + * @return mixed + */ + public function max($field, $where=array()) + { + if($where) + { + $this->db->where($where); + } + + if(is_array($field)) + { + foreach($field as $v) + { + $this->db->select_max($v); + } + } + else + { + $this->db->select_max($field); + } + + return $this->db->get($this->table_name)->row_array(); + } + + /** + * 删除 + * @param array $where + * @return mixed + */ + public function delete($where = array()) + { + $result = $this->db->delete($this->table_name, $where); + return $this->db->affected_rows() ? $this->db->affected_rows() : $result; + } + + /** + * 将获取的数据集组装成map类型 + * @param string $map_key + * @param string $map_value + * @param array $where + * @param string $order + * @param int $page + * @param int $page_size + * @param string $select + * @return array + */ + public function map($map_key = 'id', $map_value = '', $where = array(), $order = '', $page = 0, $page_size = 20, $select = '') + { + $map = array(); + $list = $this->select($where, $order, $page, $page_size, $select); + + if($list) + { + foreach($list as $item) + { + //指定列, map格式为{k:v} + if($map_value) + { + //指定列存在取具体值,格式为{k:v},指定列不存在取全部列,格式为{k:{k1:v1,k2:v2}} + $map[$item[$map_key]] = null !== $item[$map_value] ? $item[$map_value] : $item; + } + else + {//不指定列,表示一个k对应多个v,格式为{k:[{k1:v1,k2:v2},{k1:v1,k2:v2}]} + $map[$item[$map_key]][] = $item; + } + } + } + + return $map; + } + + /** + * 获取总条数 + * @param array $where + * @param string $distinct + * @return mixed + */ + public function count($where = array(), $distinct = '') + { + if($where) + { + $this->db->where($where); + } + + if($distinct) + { + $this->db->distinct(); + $this->db->select($distinct, false); + } + + return $this->db->count_all_results($this->table_name); + + } + + /** + * 获取某字段总和 + * @param $field + * @param array $where + * @return mixed + */ + public function sum($field, $where = array()) + { + if(is_array($field)) + { + foreach($field as $v) + { + $this->select_sum($v); + } + } + else + { + $this->db->select_sum($field); + } + + if($where) + { + $this->db->where($where); + } + + return $this->db->get($this->table_name)->row_array(); + } + + /** + * 对方法的某个结果集做mc缓存【结果集为非对象数组】 + * @param $func + * @param array $param + * @param string $ttl + * @return mixed + */ + public function mc_cache($func, $param = array(), $ttl = 0, $skey = '') + { + if(IF_MC_CACHE) + { + $cache = & load_cache('mc'); + $cache_key = MC_CACHE_PREFIX.md5(get_called_class().'.'.$func.json_encode($param)); + $ttl = is_numeric($ttl) ? $ttl : $this->mc_cache_expire; + $result = $cache->get($cache_key); + + if($result === FALSE ) + { + $result = call_user_func_array(array($this, $func), $param); + $cache->save($cache_key, $result, $ttl); + $this->add_cache_key(get_called_class(), $func, 'mc', $cache_key, $ttl, $skey); + } + + return $result; + } + + return call_user_func_array(array($this, $func), $param); + } + + /** + * 删除某方法某个结果集的mc缓存【结果集为非对象数组】 + * @param $func + * @param array $param + * @return mixed + */ + public function un_mc_cache($func, $param = array()) + { + if(IF_MC_CACHE) + { + $cache = & load_cache('mc'); + $cache_key = MC_CACHE_PREFIX.md5(get_called_class().'.'.$func.json_encode($param)); + return $cache->delete($cache_key); + } + + return false; + } + + /** + * 对方法的某个结果集做redis缓存【结果集为非对象数组】 + * @param $func + * @param array $param + * @param bool $force + * @return array|mixed + */ + public function redis_cache($func,$param = array()) + { + if(IF_REDIS_CACHE) + { + $cache = & load_cache('redis'); + $cache_key = REDIS_CACHE_PREFIX.md5(get_called_class().'.'.$func.json_encode($param)); + + if(!$result = $cache->get($cache_key)) + { + $result = call_user_func_array(array($this, $func), $param); + $cache->save($cache_key, $result); + $this->add_cache_key(get_called_class(), $func, 'redis', $cache_key); + } + + return $result; + } + + return call_user_func_array(array($this, $func), $param); + } + + /** + * 删除某方法某个结果集的redis缓存【结果集为非对象数组】 + * @param $func + * @param array $param + * @return mixed + */ + public function un_redis_cache($func, $param = array()) + { + if(IF_REDIS_CACHE) + { + $cache = & load_cache('redis'); + $cache_key = REDIS_CACHE_PREFIX.md5(get_called_class().'.'.$func.json_encode($param)); + return $cache->delete($cache_key); + } + + return false; + } + + /** + * 对某方法某个结果集的file缓存【结果集为非对象数组】 + * @param $func + * @param array $param + * @return mixed + */ + public function file_cache($func, $param = array()) + { + if(IF_FILE_CACHE) + { + $cache = & load_cache('file'); + $cache_key = FILE_CACHE_PREFIX.get_called_class().'.'.$func.'_'.md5($param); + + if(!$result = $cache->get($cache_key)) + { + $result = call_user_func_array(array($this, $func), $param); + $cache->save($cache_key, $result, $this->file_cache_expire); + $this->add_cache_key(get_called_class(), $func, 'file', $cache_key); + } + + return $result; + } + + return call_user_func_array(array($this, $func), $param); + } + + /** + * 删除某方法某个结果集的file缓存【结果集为非对象数组】 + * @param $func + * @param array $param + * @return mixed + */ + public function un_file_cache($func, $param =array()) + { + if(IF_FILE_CACHE) + { + $cache = & load_cache('file'); + $cache_key = FILE_CACHE_PREFIX.get_called_class().'.'.$func.'_'.md5($param); + return $cache->delete($cache_key); + } + } + + /** + * 清除cache + * @param $method + * @param $type + * @return bool + */ + public function del_cache($method, $type, $skey = '') + { + $cache = & load_cache($type); + $db = $this->load->database('default', true); + $where = $skey ? array("skey like '{$skey}'" => null) : array('class' => get_called_class(), 'method' => $method, 'cache_type' => $type); + $db->where($where); + + $cache_list = $db->get('hd_cache_key')->result_array(); + + if($cache_list) + { + foreach($cache_list as $v) + { + $cache->delete($v['cache_key']); + } + } + + $db->delete('hd_cache_key', $where); + return true; + } + + private function add_cache_key($class, $method, $type, $key, $expire_time = 0, $skey = '') + { + $db = $this->load->database('default', true); + + $data = array( + 'class' => $class, + 'method' => $method, + 'cache_type' => $type, + 'cache_key' => $key, + 'expire_time' => time() + $expire_time, + 'skey' => $skey ? $skey : '' + ); + + $result = $db->insert('hd_cache_key', $data); + return $this->db->insert_id() ? $this->db->insert_id() : $result; + } +} + diff --git a/market/core/HD_Service.php b/market/core/HD_Service.php new file mode 100644 index 00000000..3d1c1ace --- /dev/null +++ b/market/core/HD_Service.php @@ -0,0 +1,32 @@ +CI = & get_instance(); + $this->log_dir = lcfirst(get_class($this)); + } + + function __get($name){ + if('_model' === substr($name, -6)){ + return $this->CI->$name; + } elseif('_service' === substr($name, -8)){ + return $this->CI->$name; + } elseif('load' == $name){ + return $this->CI->load; + } elseif('config' == $name){ + return $this->CI->config; + } elseif(isset($this->CI->$name)){ + return $this->CI->$name; + } + return null; + } +} \ No newline at end of file diff --git a/market/core/index.html b/market/core/index.html new file mode 100644 index 00000000..b702fbc3 --- /dev/null +++ b/market/core/index.html @@ -0,0 +1,11 @@ + + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + diff --git a/market/helpers/authorization_helper.php b/market/helpers/authorization_helper.php new file mode 100644 index 00000000..a4c3c580 --- /dev/null +++ b/market/helpers/authorization_helper.php @@ -0,0 +1,28 @@ +config->item('jwt_key'); + $algorithm = $CI->config->item('jwt_algorithm'); + return JWT::decode($token, $key, array($algorithm)); + } + + public static function generateToken($data) + { + $CI =& get_instance(); + $key = $CI->config->item('jwt_key'); + return JWT::encode($data, $key); + } + +} + + + diff --git a/market/helpers/fn_helper.php b/market/helpers/fn_helper.php new file mode 100644 index 00000000..4be4dfc1 --- /dev/null +++ b/market/helpers/fn_helper.php @@ -0,0 +1,358 @@ + $row) { + foreach ($row as $key => $value) { + $arrSort[$key][$uniqid] = $value; + } + } + array_multisort($arrSort[$field], constant($sort), $array); + return $array; + } +} +//post请求 + +if(!function_exists('httpPostForm')){ + /** + * 表单提交数据 + * @param $url + * @param $data + * @return array + */ + function httpPostForm($url, $data){ + $ch = curl_init(); + curl_setopt($ch, CURLOPT_POST, 1); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_HEADER, 0);//设置header + curl_setopt($ch, CURLOPT_POSTFIELDS, $data); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + //https + if (strlen($url) > 5 && strtolower(substr($url, 0, 5)) == "https") { + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); + } + $response = curl_exec($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + if ($error = curl_error($ch)) { + die($error); + } + + curl_close($ch); + + return array($httpCode, $response); + } +} + +if (!function_exists('httpPostJson')) { + /** + * @param string $url + * @param string $jsonStr + * @return array + */ + function httpPostJson($url, $jsonStr) + { + $ch = curl_init(); + curl_setopt($ch, CURLOPT_POST, 1); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_POSTFIELDS, $jsonStr); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + //https + if (strlen($url) > 5 && strtolower(substr($url, 0, 5)) == "https") { + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); + } + curl_setopt($ch, CURLOPT_HTTPHEADER, array( + 'Content-Type: application/json; charset=utf-8', + 'Content-Length: ' . strlen($jsonStr) + ) + ); + $response = curl_exec($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + if ($error = curl_error($ch)) { + die($error); + } + + curl_close($ch); + + return array($httpCode, $response); + } +} + +//request 请求 +if (!function_exists('httpRequest')) { + function httpRequest($sUrl, $data = array()) + { + $header = array('X-AUTH-APP-ID:a2nkCKjTJJNSVaeQITwmV/1zw9Dpn56Acr2Z81MOkkJ/8VapjA6oPA==', 'X-AUTH-KEY:89c9c457-7fff-41f8-9ba5-1e9154a7b972', 'companyUuid:haixifangchan_company8fee8cd09'); + if ($data) { + $sUrl = $sUrl . '?' . http_build_query($data); + } + $ch = curl_init(); + if (substr($sUrl, 0, 5) == 'https') { + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + // 跳过证书检查 + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); + // 从证书中检查SSL加密算法是否存在 + } + curl_setopt($ch, CURLINFO_HEADER_OUT, true); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_URL, $sUrl); + curl_setopt($ch, CURLOPT_HTTPHEADER, $header); + curl_setopt($ch, CURLOPT_POST, false); + $response = curl_exec($ch); + $request_header = curl_getinfo($ch, CURLINFO_HEADER_OUT); + //print_r($request_header);exit(); + if ($error = curl_error($ch)) { + die($error); + } + curl_close($ch); + return json_decode($response, 1); + + } +} + +// +if (!function_exists('uploadImg')) { + //上传图片 + function uploadImg($url, $path = 'wx/fn/') + { + + //$path = 'img/wechatapp/fn/'; 路径 + + if (!is_dir($path)){ + $oldumask = umask(0); + mkdir($path, 0777,true); + umask($oldumask); + } + //对照片处理 + $url = mb_substr($url, 0, -4); + + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30); + $file = curl_exec($ch); + curl_close($ch); + $filename = pathinfo($url, PATHINFO_BASENAME); + $filename = strtolower($filename); + $resource = fopen($path . $filename, 'a'); + fwrite($resource, $file); + fclose($resource); + + + $name = $path . $filename; + + return $name; + } +} + +/** + * 图片压缩处理 + * @param string $sFile 源图片路径 + * @param int $iWidth 自定义图片宽度 + * @param int $iHeight 自定义图片高度 + * @return string 压缩后的图片路径 + */ +if (!function_exists('getThumb')) { + function getThumb($sFile, $iWidth, $iHeight) + { + //图片公共路径 + + //判断该图片是否存在 + if (!file_exists($sFile)) return $sFile; + //判断图片格式(图片文件后缀) + $extend = explode(".", $sFile); + + $attach_fileext = strtolower($extend[count($extend) - 1]); + if (!in_array($attach_fileext, array('jpg', 'png', 'jpeg'))) { + return ''; + } + //压缩图片文件名称 + $sFileNameS = str_replace("." . $attach_fileext, "_" . $iWidth . '_' . $iHeight . '.' . $attach_fileext, $sFile); + //判断是否已压缩图片,若是则返回压缩图片路径 + if (file_exists($sFileNameS)) { + return $sFileNameS; + } + + //生成压缩图片,并存储到原图同路径下 + resizeImage($sFile, $sFileNameS, $iWidth, $iHeight); + if (!file_exists($sFileNameS)) { + return $sFile; + } + return $sFileNameS; + } +} +/** + * 生成图片 + * @param string $im 源图片路径 + * @param string $dest 目标图片路径 + * @param int $maxwidth 生成图片宽 + * @param int $maxheight 生成图片高 + */ +if (!function_exists('resizeImage')) { + + function resizeImage($im, $dest, $maxwidth, $maxheight) + { + $img = getimagesize($im); + switch ($img[2]) { + case 1: + $im = @imagecreatefromgif($im); + break; + case 2: + $im = @imagecreatefromjpeg($im); + break; + case 3: + $im = @imagecreatefrompng($im); + break; + } + + $pic_width = imagesx($im); + $pic_height = imagesy($im); + $resizewidth_tag = false; + $resizeheight_tag = false; + if (($maxwidth && $pic_width > $maxwidth) || ($maxheight && $pic_height > $maxheight)) { + if ($maxwidth && $pic_width > $maxwidth) { + $widthratio = $maxwidth / $pic_width; + $resizewidth_tag = true; + } + + if ($maxheight && $pic_height > $maxheight) { + $heightratio = $maxheight / $pic_height; + $resizeheight_tag = true; + } + + if ($resizewidth_tag && $resizeheight_tag) { + if ($widthratio < $heightratio) + $ratio = $widthratio; + else + $ratio = $heightratio; + } + + + if ($resizewidth_tag && !$resizeheight_tag) + $ratio = $widthratio; + if ($resizeheight_tag && !$resizewidth_tag) + $ratio = $heightratio; + $newwidth = $pic_width * $ratio; + $newheight = $pic_height * $ratio; + + if (function_exists("imagecopyresampled")) { + $newim = imagecreatetruecolor($newwidth, $newheight); + imagecopyresampled($newim, $im, 0, 0, 0, 0, $newwidth, $newheight, $pic_width, $pic_height); + } else { + $newim = imagecreate($newwidth, $newheight); + imagecopyresized($newim, $im, 0, 0, 0, 0, $newwidth, $newheight, $pic_width, $pic_height); + } + + imagejpeg($newim, $dest); + imagedestroy($newim); + } else { + imagejpeg($im, $dest); + } + } +} +//巧房房源图片处理 +if (!function_exists('editPhoto')) { + //图片处理 + function editPhoto($community_list) + { + + foreach ($community_list as $key => $value) { + foreach ($value as $k => $item) { + if (empty($item) || is_null($item)) { + $community_list[$key][$k] = ''; + } + //图片处理,取室内图,取不到再用户型图 + if ($value['photoList']) { + foreach ($value['photoList'] as $v) { + + if ($v['categoryName'] == 'shinei' || $v['categoryName'] == '室内图' || $v['categoryCnName'] == '室内图') { + $community_list[$key]['photoList'] = 'http://uyu.xmfish.com/thumb2/byurl/?url=' . str_replace('https://', '', $v['photoUrl']) . '|300'; + break; + } else { + $community_list[$key]['photoList'] = 'http://uyu.xmfish.com/thumb2/byurl/?url=' . str_replace('https://', '', $v['photoUrl']) . '|300'; + } + } + } + } + //photoList原先就是数组,清空获取不到值,只能进行转换 + $community_list[$key]['photo_list'][0] = $community_list[$key]['photoList']; + $community_list[$key]['photoList'] = $community_list[$key]['photo_list']; + unset($community_list[$key]['photo_list']); + //计算单价 + $community_list[$key]['unitPrice'] = str_replace(',', '', number_format($value['sellPrice'] / $value['square'], 2)); + } + + return $community_list; + } +} + + +//二维数组去重 +if (!function_exists('moreArrayUnique')) { + + function moreArrayUnique($arr = array()) + { + foreach ($arr[0] as $k => $v) { + $arr_inner_key[] = $k; + } + foreach ($arr as $k => $v) { + $v = join(",", $v); + $temp[$k] = $v; + } + $temp = array_unique($temp); + foreach ($temp as $k => $v) { + $a = explode(",", $v); + $arr_after[$k] = array_combine($arr_inner_key, $a); + } + $arr_after = array_values($arr_after); + return $arr_after; + } +} + +if (!function_exists('msectime')) { + //时间转换成毫秒 + function msectime() + { + list($msec, $sec) = explode(' ', microtime()); + $msectime = (float)sprintf('%.0f', (floatval($msec) + floatval($sec)) * 1000); + return $msectime; + } +} + +if ( ! function_exists('friendly_time') ) +{ + /** + * @param $time + * @return false|string + */ + function friendly_time($time) + { + $surplus = time() - $time; + switch (true) + { + case $surplus < 60: + return $surplus . '秒前'; + case $surplus < 3600: + return ceil($surplus / 60) . '分钟前'; + case $surplus < 3600 * 24: + return ceil($surplus / 3600) . '小时前'; + case $surplus < 3600 * 24 * 7: + return ceil($surplus / (3600 * 24)) . '天前'; + default: + return date('m月d日', $time); + } + } +} diff --git a/market/helpers/format_helper.php b/market/helpers/format_helper.php new file mode 100644 index 00000000..4cb894a4 --- /dev/null +++ b/market/helpers/format_helper.php @@ -0,0 +1,101 @@ + $data); + is_numeric($data) && $data = array('count' => $data); + is_string($data) && $data = array('result' => $data); + + if(is_array($data) && array_search(current($data), $data) === 0) + { + $data = array('list' => $data); + } + + if(empty($data)) + { + $data = array('result' => array()); + } + + return array('errCode' => '0', 'data' => $data); + } +} + +/** + * 过滤空字符 + * @param $array + * @return array + */ +if(!function_exists('_clean')) +{ + function _clean($array) + { + if(!is_array($array)) + { + return $array; + } + + foreach($array as $k => $v) + { + if($v === '' || $v === null || $v === array()) + { + unset($array[$k]); + } + elseif(is_array($v)) + { + $array[$k] = _clean($v); + } + } + + return $array; + } +} + +/** + * API 输出 + * @param $result + * @param bool $ifgzip + */ + +if(!function_exists('print_result')) +{ + function print_result($result, $ifgzip = false) + { + if(!isset($result['errCode'])) + { + $data = info_format($result); + } + else + { + $data = $result; + } + + if($ifgzip) + { + header('Content-Type: application/json'); + header('Content-Encoding: gzip'); + echo gzencode(json_encode($data, JSON_UNESCAPED_UNICODE), 6); + exit; + } + else + { + $result = json_encode($data, JSON_UNESCAPED_UNICODE); + echo $result; + exit; + } + } +} + + + + diff --git a/market/helpers/image_helper.php b/market/helpers/image_helper.php new file mode 100644 index 00000000..7c49f41f --- /dev/null +++ b/market/helpers/image_helper.php @@ -0,0 +1,46 @@ +load->library('qiniu'); + foreach ($srcs as $key => $val) + { + $filename = $ci->qiniu->getFileName($val); + $filename = $path . date('Y/m').'/'.$filename; + $file = $ci->qiniu->fetch($val, $filename); + + if (!$file) + { + $urls[$key] = ''; + continue; + } + else + { + $urls[$key] = $file['file']; + } + } + } + + return $urls; + } +} \ No newline at end of file diff --git a/market/helpers/index.html b/market/helpers/index.html new file mode 100644 index 00000000..b702fbc3 --- /dev/null +++ b/market/helpers/index.html @@ -0,0 +1,11 @@ + + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + diff --git a/market/hooks/ApiAuthHook.php b/market/hooks/ApiAuthHook.php new file mode 100644 index 00000000..71660e5d --- /dev/null +++ b/market/hooks/ApiAuthHook.php @@ -0,0 +1,178 @@ +CI = &get_instance(); + // 保护路由为 /api/* 或者 /Api/* + $this->route = '/^api/i'; + $this->auth = ',api/auth'; + $this->route_un = ['api/captcha', 'api/login', 'api/upload']; + } + + /** + * 钩子主函数 + */ + public function index() + { + $this->CI->load->helper('url'); + // $route 正则匹配是否符合 /api/* 或者 /Api/* + if (preg_match($this->route, uri_string())) { + if (!in_array(uri_string(), $this->route_un)) { + // 获取整个 request headers + $headers = $this->CI->input->request_headers(); + // headers 中是否存在 Authorization + if ($this->tokenIsExist($headers)) { + $userId = $this->validateToken($headers['Authorization']); + $this->set_session($userId); + } else { + $this->httpBadResponse( + 'The request lacks the authorization token' + ); + } + } + } + } + + private function set_session($userId) + { + $_SESSION['userId'] = intval($userId); + $this->CI->load->model('market/Market_sys_admin_model'); + $re_admin = $this->CI->Market_sys_admin_model->get(['userId' => $userId, 'status' => 0]); + if ($re_admin) { + $_SESSION = $re_admin; + } + $route = uri_string(); + if (strstr(',' . $route, $this->auth)) { + return; + } + $request = $this->CI->input->method(); + $authorityAry = explode('/', $route); //api/system/user/ + $authority_set = ''; + if ($request == 'post') { + $authority_set = 'save'; + } else if ($request == 'put') { + $authority_set = 'update'; + } else if ($request == 'delete') { + $authority_set = 'remove'; + } else if (strstr($route, '/page')) {//列表搜索权限 + $authority_set = 'list'; + } + if ($authority_set) { + $show = true; + $authority = $authorityAry[1] . ':' . $authorityAry[2] . ':' . $authority_set;//system:user:save + if ($re_admin['roleId']) { + $this->CI->load->model('market/Market_sys_role_model'); + $re_role = $this->CI->Market_sys_role_model->get(['roleId' => $re_admin['roleId'], 'status' => 0]); + if ($re_role['menuIds']) { + if (strstr($route, '/roleMenu')) {//角色分配权限 + $authority = 'system:role:' . $authority_set; + } else if (strstr($route, '/dictionaryData')) {//字典项权限 + $authority = 'system:dictionary:' . $authority_set; + } else if (strstr($route, '/sylive/user')) {//机构用户权限 + $authority = 'sylive:organization:' . $authority_set; + } + $this->CI->load->model('market/Market_sys_menu_model'); + $re_menu = $this->CI->Market_sys_menu_model->get(["menuId in({$re_role['menuIds']})" => null, 'status' => 0 + , 'authority' => $authority]); + if ($re_menu) { + $show = false; + if ($re_menu['title'] == '登录日志' || $re_menu['title'] == '操作日志') { + } else { + $_SESSION['operation_description'] = $re_menu['title'];//操作功能 + $re_menu2 = $this->CI->Market_sys_menu_model->get(["menuId" => $re_menu['parentId'], 'status' => 0]); + $_SESSION['operation_module'] = $re_menu2['title'] ? $re_menu2['title'] : $re_menu['title'];//操作模块 + } + } + } + } + $show && $this->return_json('没有访问权限', 403); + } + } + + public function return_json($message = '', $code = 1) + { + header('Content-Type:application/json; charset=utf-8'); + echo json_encode(['code' => $code, 'message' => $message], JSON_UNESCAPED_UNICODE); + exit(); + } + + /** + * 判断 headers 中是否含有 Authorization 字段 + * + * @param type $headers + * @return type boolean + */ + public function tokenIsExist($headers = array()) + { + return ( + array_key_exists('Authorization', $headers) && + !empty($headers['Authorization']) + ); + } + + /** + * Authorization 中是否有 json web token 值 + * + * @param type $headers + * @return type + */ + public function jwtIsExist($headers) + { + list($jwt) = sscanf($headers['Authorization'], 'market.com %s'); + return $jwt; + } + + /** + * 校验 json web token 的合法性 + * + * @param type $jwt + * @return boolean + */ + public function validateToken($jwt) + { + if ($jwt) { + try { + $token = Authorization::validateToken($jwt); + return $token; + } catch (Exception $ex) { + $this->httpUnauthorizedResponse($ex->getMessage()); + } + } else { + $this->httpBadResponse( + 'the token is unauthorized' + ); + } + } + + /** + * http code 400 response + * + * @param type $msg + */ + public function httpBadResponse($msg = NULL) + { + set_status_header(400, $msg); + exit(1); + } + + /** + * http code 401 response + * + * @param type $msg + */ + public function httpUnauthorizedResponse($msg = NULL) + { + set_status_header(401, $msg); + exit(1); + } + +} \ No newline at end of file diff --git a/market/hooks/index.html b/market/hooks/index.html new file mode 100644 index 00000000..b702fbc3 --- /dev/null +++ b/market/hooks/index.html @@ -0,0 +1,11 @@ + + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + diff --git a/market/index.html b/market/index.html new file mode 100644 index 00000000..b702fbc3 --- /dev/null +++ b/market/index.html @@ -0,0 +1,11 @@ + + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + diff --git a/market/language/english/index.html b/market/language/english/index.html new file mode 100644 index 00000000..b702fbc3 --- /dev/null +++ b/market/language/english/index.html @@ -0,0 +1,11 @@ + + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + diff --git a/market/language/english/rest_controller_lang.php b/market/language/english/rest_controller_lang.php new file mode 100644 index 00000000..06bf4b96 --- /dev/null +++ b/market/language/english/rest_controller_lang.php @@ -0,0 +1,18 @@ + + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + diff --git a/market/language/zh/error_lang.php b/market/language/zh/error_lang.php new file mode 100644 index 00000000..c69f7263 --- /dev/null +++ b/market/language/zh/error_lang.php @@ -0,0 +1,23 @@ +_CI = &get_instance(); + + // Load the inflector helper + $this->_CI->load->helper('inflector'); + + // If the provided data is already formatted we should probably convert it to an array + if ($from_type !== NULL) + { + if (method_exists($this, '_from_'.$from_type)) + { + $data = call_user_func([$this, '_from_'.$from_type], $data); + } + else + { + throw new Exception('Format class does not support conversion from "'.$from_type.'".'); + } + } + + // Set the member variable to the data passed + $this->_data = $data; + } + + /** + * Create an instance of the format class + * e.g: echo $this->format->factory(['foo' => 'bar'])->to_csv(); + * + * @param mixed $data Data to convert/parse + * @param string $from_type Type to convert from e.g. json, csv, html + * + * @return object Instance of the format class + */ + public function factory($data, $from_type = NULL) + { + // $class = __CLASS__; + // return new $class(); + + return new static($data, $from_type); + } + + // FORMATTING OUTPUT --------------------------------------------------------- + + /** + * Format data as an array + * + * @param mixed|NULL $data Optional data to pass, so as to override the data passed + * to the constructor + * @return array Data parsed as an array; otherwise, an empty array + */ + public function to_array($data = NULL) + { + // If no data is passed as a parameter, then use the data passed + // via the constructor + if ($data === NULL && func_num_args() === 0) + { + $data = $this->_data; + } + + // Cast as an array if not already + if (is_array($data) === FALSE) + { + $data = (array) $data; + } + + $array = []; + foreach ((array) $data as $key => $value) + { + if (is_object($value) === TRUE || is_array($value) === TRUE) + { + $array[$key] = $this->to_array($value); + } + else + { + $array[$key] = $value; + } + } + + return $array; + } + + /** + * Format data as XML + * + * @param mixed|NULL $data Optional data to pass, so as to override the data passed + * to the constructor + * @param NULL $structure + * @param string $basenode + * @return mixed + */ + public function to_xml($data = NULL, $structure = NULL, $basenode = 'xml') + { + if ($data === NULL && func_num_args() === 0) + { + $data = $this->_data; + } + + if ($structure === NULL) + { + $structure = simplexml_load_string("<$basenode />"); + } + + // Force it to be something useful + if (is_array($data) === FALSE && is_object($data) === FALSE) + { + $data = (array) $data; + } + + foreach ($data as $key => $value) + { + + //change false/true to 0/1 + if (is_bool($value)) + { + $value = (int) $value; + } + + // no numeric keys in our xml please! + if (is_numeric($key)) + { + // make string key... + $key = (singular($basenode) != $basenode) ? singular($basenode) : 'item'; + } + + // replace anything not alpha numeric + $key = preg_replace('/[^a-z_\-0-9]/i', '', $key); + + if ($key === '_attributes' && (is_array($value) || is_object($value))) + { + $attributes = $value; + if (is_object($attributes)) + { + $attributes = get_object_vars($attributes); + } + + foreach ($attributes as $attribute_name => $attribute_value) + { + $structure->addAttribute($attribute_name, $attribute_value); + } + } + // if there is another array found recursively call this function + elseif (is_array($value) || is_object($value)) + { + $node = $structure->addChild($key); + + // recursive call. + $this->to_xml($value, $node, $key); + } + else + { + // add single node. + $value = htmlspecialchars(html_entity_decode($value, ENT_QUOTES, 'UTF-8'), ENT_QUOTES, 'UTF-8'); + + $structure->addChild($key, $value); + } + } + + return $structure->asXML(); + } + + /** + * Format data as HTML + * + * @param mixed|NULL $data Optional data to pass, so as to override the data passed + * to the constructor + * @return mixed + */ + public function to_html($data = NULL) + { + // If no data is passed as a parameter, then use the data passed + // via the constructor + if ($data === NULL && func_num_args() === 0) + { + $data = $this->_data; + } + + // Cast as an array if not already + if (is_array($data) === FALSE) + { + $data = (array) $data; + } + + // Check if it's a multi-dimensional array + if (isset($data[0]) && count($data) !== count($data, COUNT_RECURSIVE)) + { + // Multi-dimensional array + $headings = array_keys($data[0]); + } + else + { + // Single array + $headings = array_keys($data); + $data = [$data]; + } + + // Load the table library + $this->_CI->load->library('table'); + + $this->_CI->table->set_heading($headings); + + foreach ($data as $row) + { + // Suppressing the "array to string conversion" notice + // Keep the "evil" @ here + $row = @array_map('strval', $row); + + $this->_CI->table->add_row($row); + } + + return $this->_CI->table->generate(); + } + + /** + * @link http://www.metashock.de/2014/02/create-csv-file-in-memory-php/ + * @param mixed|NULL $data Optional data to pass, so as to override the data passed + * to the constructor + * @param string $delimiter The optional delimiter parameter sets the field + * delimiter (one character only). NULL will use the default value (,) + * @param string $enclosure The optional enclosure parameter sets the field + * enclosure (one character only). NULL will use the default value (") + * @return string A csv string + */ + public function to_csv($data = NULL, $delimiter = ',', $enclosure = '"') + { + // Use a threshold of 1 MB (1024 * 1024) + $handle = fopen('php://temp/maxmemory:1048576', 'w'); + if ($handle === FALSE) + { + return NULL; + } + + // If no data is passed as a parameter, then use the data passed + // via the constructor + if ($data === NULL && func_num_args() === 0) + { + $data = $this->_data; + } + + // If NULL, then set as the default delimiter + if ($delimiter === NULL) + { + $delimiter = ','; + } + + // If NULL, then set as the default enclosure + if ($enclosure === NULL) + { + $enclosure = '"'; + } + + // Cast as an array if not already + if (is_array($data) === FALSE) + { + $data = (array) $data; + } + + // Check if it's a multi-dimensional array + if (isset($data[0]) && count($data) !== count($data, COUNT_RECURSIVE)) + { + // Multi-dimensional array + $headings = array_keys($data[0]); + } + else + { + // Single array + $headings = array_keys($data); + $data = [$data]; + } + + // Apply the headings + fputcsv($handle, $headings, $delimiter, $enclosure); + + foreach ($data as $record) + { + // If the record is not an array, then break. This is because the 2nd param of + // fputcsv() should be an array + if (is_array($record) === FALSE) + { + break; + } + + // Suppressing the "array to string conversion" notice. + // Keep the "evil" @ here. + $record = @ array_map('strval', $record); + + // Returns the length of the string written or FALSE + fputcsv($handle, $record, $delimiter, $enclosure); + } + + // Reset the file pointer + rewind($handle); + + // Retrieve the csv contents + $csv = stream_get_contents($handle); + + // Close the handle + fclose($handle); + + return $csv; + } + + /** + * Encode data as json + * + * @param mixed|NULL $data Optional data to pass, so as to override the data passed + * to the constructor + * @return string Json representation of a value + */ + public function to_json($data = NULL) + { + // If no data is passed as a parameter, then use the data passed + // via the constructor + if ($data === NULL && func_num_args() === 0) + { + $data = $this->_data; + } + + // Get the callback parameter (if set) + $callback = $this->_CI->input->get('callback'); + + if (empty($callback) === TRUE) + { + return json_encode($data); + } + + // We only honour a jsonp callback which are valid javascript identifiers + elseif (preg_match('/^[a-z_\$][a-z0-9\$_]*(\.[a-z_\$][a-z0-9\$_]*)*$/i', $callback)) + { + // Return the data as encoded json with a callback + return $callback.'('.json_encode($data).');'; + } + + // An invalid jsonp callback function provided. + // Though I don't believe this should be hardcoded here + $data['warning'] = 'INVALID JSONP CALLBACK: '.$callback; + + return json_encode($data); + } + + /** + * Encode data as a serialized array + * + * @param mixed|NULL $data Optional data to pass, so as to override the data passed + * to the constructor + * @return string Serialized data + */ + public function to_serialized($data = NULL) + { + // If no data is passed as a parameter, then use the data passed + // via the constructor + if ($data === NULL && func_num_args() === 0) + { + $data = $this->_data; + } + + return serialize($data); + } + + /** + * Format data using a PHP structure + * + * @param mixed|NULL $data Optional data to pass, so as to override the data passed + * to the constructor + * @return mixed String representation of a variable + */ + public function to_php($data = NULL) + { + // If no data is passed as a parameter, then use the data passed + // via the constructor + if ($data === NULL && func_num_args() === 0) + { + $data = $this->_data; + } + + return var_export($data, TRUE); + } + + // INTERNAL FUNCTIONS + + /** + * @param string $data XML string + * @return array XML element object; otherwise, empty array + */ + protected function _from_xml($data) + { + return $data ? (array) simplexml_load_string($data, 'SimpleXMLElement', LIBXML_NOCDATA) : []; + } + + /** + * @param string $data CSV string + * @param string $delimiter The optional delimiter parameter sets the field + * delimiter (one character only). NULL will use the default value (,) + * @param string $enclosure The optional enclosure parameter sets the field + * enclosure (one character only). NULL will use the default value (") + * @return array A multi-dimensional array with the outer array being the number of rows + * and the inner arrays the individual fields + */ + protected function _from_csv($data, $delimiter = ',', $enclosure = '"') + { + // If NULL, then set as the default delimiter + if ($delimiter === NULL) + { + $delimiter = ','; + } + + // If NULL, then set as the default enclosure + if ($enclosure === NULL) + { + $enclosure = '"'; + } + + return str_getcsv($data, $delimiter, $enclosure); + } + + /** + * @param string $data Encoded json string + * @return mixed Decoded json string with leading and trailing whitespace removed + */ + protected function _from_json($data) + { + return json_decode(trim($data)); + } + + /** + * @param string $data Data to unserialize + * @return mixed Unserialized data + */ + protected function _from_serialize($data) + { + return unserialize(trim($data)); + } + + /** + * @param string $data Data to trim leading and trailing whitespace + * @return string Data with leading and trailing whitespace removed + */ + protected function _from_php($data) + { + return trim($data); + } +} diff --git a/market/libraries/JWT.php b/market/libraries/JWT.php new file mode 100644 index 00000000..564a573c --- /dev/null +++ b/market/libraries/JWT.php @@ -0,0 +1,362 @@ + + * @author Anant Narayanan + * @license http://opensource.org/licenses/BSD-3-Clause 3-clause BSD + * @link https://github.com/firebase/php-jwt + */ +class JWT { + + /** + * When checking nbf, iat or expiration times, + * we want to provide some extra leeway time to + * account for clock skew. + */ + public static $leeway = 0; + + /** + * Allow the current timestamp to be specified. + * Useful for fixing a value within unit testing. + * + * Will default to PHP time() value if null. + */ + public static $timestamp = null; + public static $supported_algs = array( + 'HS256' => array('hash_hmac', 'SHA256'), + 'HS512' => array('hash_hmac', 'SHA512'), + 'HS384' => array('hash_hmac', 'SHA384'), + 'RS256' => array('openssl', 'SHA256'), + ); + + /** + * Decodes a JWT string into a PHP object. + * + * @param string $jwt The JWT + * @param string|array $key The key, or map of keys. + * If the algorithm used is asymmetric, this is the public key + * @param array $allowed_algs List of supported verification algorithms + * Supported algorithms are 'HS256', 'HS384', 'HS512' and 'RS256' + * + * @return object The JWT's payload as a PHP object + * + * @throws UnexpectedValueException Provided JWT was invalid + * @throws SignatureInvalidException Provided JWT was invalid because the signature verification failed + * @throws BeforeValidException Provided JWT is trying to be used before it's eligible as defined by 'nbf' + * @throws BeforeValidException Provided JWT is trying to be used before it's been created as defined by 'iat' + * @throws ExpiredException Provided JWT has since expired, as defined by the 'exp' claim + * + * @uses jsonDecode + * @uses urlsafeB64Decode + */ + public static function decode($jwt, $key, $allowed_algs = array()) { + $timestamp = is_null(static::$timestamp) ? time() : static::$timestamp; + + if (empty($key)) { + throw new InvalidArgumentException('Key may not be empty'); + } + if (!is_array($allowed_algs)) { + throw new InvalidArgumentException('Algorithm not allowed'); + } + $tks = explode('.', $jwt); + if (count($tks) != 3) { + throw new UnexpectedValueException('Wrong number of segments'); + } + list($headb64, $bodyb64, $cryptob64) = $tks; + if (null === ($header = static::jsonDecode(static::urlsafeB64Decode($headb64)))) { + throw new UnexpectedValueException('Invalid header encoding'); + } + if (null === $payload = static::jsonDecode(static::urlsafeB64Decode($bodyb64))) { + throw new UnexpectedValueException('Invalid claims encoding'); + } + $sig = static::urlsafeB64Decode($cryptob64); + + if (empty($header->alg)) { + throw new UnexpectedValueException('Empty algorithm'); + } + if (empty(static::$supported_algs[$header->alg])) { + throw new UnexpectedValueException('Algorithm not supported'); + } + if (!in_array($header->alg, $allowed_algs)) { + throw new UnexpectedValueException('Algorithm not allowed'); + } + if (is_array($key) || $key instanceof \ArrayAccess) { + if (isset($header->kid)) { + $key = $key[$header->kid]; + } else { + throw new UnexpectedValueException('"kid" empty, unable to lookup correct key'); + } + } + + // Check the signature + if (!static::verify("$headb64.$bodyb64", $sig, $key, $header->alg)) { + throw new SignatureInvalidException('Signature verification failed'); + } + + // Check if the nbf if it is defined. This is the time that the + // token can actually be used. If it's not yet that time, abort. + if (isset($payload->nbf) && $payload->nbf > ($timestamp + static::$leeway)) { + throw new BeforeValidException( + 'Cannot handle token prior to ' . date(DateTime::ISO8601, $payload->nbf) + ); + } + + // Check that this token has been created before 'now'. This prevents + // using tokens that have been created for later use (and haven't + // correctly used the nbf claim). + if (isset($payload->iat) && $payload->iat > ($timestamp + static::$leeway)) { + throw new BeforeValidException( + 'Cannot handle token prior to ' . date(DateTime::ISO8601, $payload->iat) + ); + } + + // Check if this token has expired. + if (isset($payload->exp) && ($timestamp - static::$leeway) >= $payload->exp) { + throw new ExpiredException('Expired token'); + } + + return $payload; + } + + /** + * Converts and signs a PHP object or array into a JWT string. + * + * @param object|array $payload PHP object or array + * @param string $key The secret key. + * If the algorithm used is asymmetric, this is the private key + * @param string $alg The signing algorithm. + * Supported algorithms are 'HS256', 'HS384', 'HS512' and 'RS256' + * @param mixed $keyId + * @param array $head An array with header elements to attach + * + * @return string A signed JWT + * + * @uses jsonEncode + * @uses urlsafeB64Encode + */ + public static function encode($payload, $key, $alg = 'HS256', $keyId = null, $head = null) { + $header = array('typ' => 'JWT', 'alg' => $alg); + if ($keyId !== null) { + $header['kid'] = $keyId; + } + if (isset($head) && is_array($head)) { + $header = array_merge($head, $header); + } + $segments = array(); + $segments[] = static::urlsafeB64Encode(static::jsonEncode($header)); + $segments[] = static::urlsafeB64Encode(static::jsonEncode($payload)); + $signing_input = implode('.', $segments); + + $signature = static::sign($signing_input, $key, $alg); + $segments[] = static::urlsafeB64Encode($signature); + + return implode('.', $segments); + } + + /** + * Sign a string with a given key and algorithm. + * + * @param string $msg The message to sign + * @param string|resource $key The secret key + * @param string $alg The signing algorithm. + * Supported algorithms are 'HS256', 'HS384', 'HS512' and 'RS256' + * + * @return string An encrypted message + * + * @throws DomainException Unsupported algorithm was specified + */ + public static function sign($msg, $key, $alg = 'HS256') { + if (empty(static::$supported_algs[$alg])) { + throw new DomainException('Algorithm not supported'); + } + list($function, $algorithm) = static::$supported_algs[$alg]; + switch ($function) { + case 'hash_hmac': + return hash_hmac($algorithm, $msg, $key, true); + case 'openssl': + $signature = ''; + $success = openssl_sign($msg, $signature, $key, $algorithm); + if (!$success) { + throw new DomainException("OpenSSL unable to sign data"); + } else { + return $signature; + } + } + } + + /** + * Verify a signature with the message, key and method. Not all methods + * are symmetric, so we must have a separate verify and sign method. + * + * @param string $msg The original message (header and body) + * @param string $signature The original signature + * @param string|resource $key For HS*, a string key works. for RS*, must be a resource of an openssl public key + * @param string $alg The algorithm + * + * @return bool + * + * @throws DomainException Invalid Algorithm or OpenSSL failure + */ + private static function verify($msg, $signature, $key, $alg) { + if (empty(static::$supported_algs[$alg])) { + throw new DomainException('Algorithm not supported'); + } + + list($function, $algorithm) = static::$supported_algs[$alg]; + switch ($function) { + case 'openssl': + $success = openssl_verify($msg, $signature, $key, $algorithm); + if (!$success) { + throw new DomainException("OpenSSL unable to verify data: " . openssl_error_string()); + } else { + return $signature; + } + case 'hash_hmac': + default: + $hash = hash_hmac($algorithm, $msg, $key, true); + if (function_exists('hash_equals')) { + return hash_equals($signature, $hash); + } + $len = min(static::safeStrlen($signature), static::safeStrlen($hash)); + + $status = 0; + for ($i = 0; $i < $len; $i++) { + $status |= (ord($signature[$i]) ^ ord($hash[$i])); + } + $status |= (static::safeStrlen($signature) ^ static::safeStrlen($hash)); + + return ($status === 0); + } + } + + /** + * Decode a JSON string into a PHP object. + * + * @param string $input JSON string + * + * @return object Object representation of JSON string + * + * @throws DomainException Provided string was invalid JSON + */ + public static function jsonDecode($input) { + if (version_compare(PHP_VERSION, '5.4.0', '>=') && !(defined('JSON_C_VERSION') && PHP_INT_SIZE > 4)) { + /** In PHP >=5.4.0, json_decode() accepts an options parameter, that allows you + * to specify that large ints (like Steam Transaction IDs) should be treated as + * strings, rather than the PHP default behaviour of converting them to floats. + */ + $obj = json_decode($input, false, 512, JSON_BIGINT_AS_STRING); + } else { + /** Not all servers will support that, however, so for older versions we must + * manually detect large ints in the JSON string and quote them (thus converting + * them to strings) before decoding, hence the preg_replace() call. + */ + $max_int_length = strlen((string) PHP_INT_MAX) - 1; + $json_without_bigints = preg_replace('/:\s*(-?\d{' . $max_int_length . ',})/', ': "$1"', $input); + $obj = json_decode($json_without_bigints); + } + + if (function_exists('json_last_error') && $errno = json_last_error()) { + static::handleJsonError($errno); + } elseif ($obj === null && $input !== 'null') { + throw new DomainException('Null result with non-null input'); + } + return $obj; + } + + /** + * Encode a PHP object into a JSON string. + * + * @param object|array $input A PHP object or array + * + * @return string JSON representation of the PHP object or array + * + * @throws DomainException Provided object could not be encoded to valid JSON + */ + public static function jsonEncode($input) { + $json = json_encode($input); + if (function_exists('json_last_error') && $errno = json_last_error()) { + static::handleJsonError($errno); + } elseif ($json === 'null' && $input !== null) { + throw new DomainException('Null result with non-null input'); + } + return $json; + } + + /** + * Decode a string with URL-safe Base64. + * + * @param string $input A Base64 encoded string + * + * @return string A decoded string + */ + public static function urlsafeB64Decode($input) { + $remainder = strlen($input) % 4; + if ($remainder) { + $padlen = 4 - $remainder; + $input .= str_repeat('=', $padlen); + } + return base64_decode(strtr($input, '-_', '+/')); + } + + /** + * Encode a string with URL-safe Base64. + * + * @param string $input The string you want encoded + * + * @return string The base64 encode of what you passed in + */ + public static function urlsafeB64Encode($input) { + return str_replace('=', '', strtr(base64_encode($input), '+/', '-_')); + } + + /** + * Helper method to create a JSON error. + * + * @param int $errno An error number from json_last_error() + * + * @return void + */ + private static function handleJsonError($errno) { + $messages = array( + JSON_ERROR_DEPTH => 'Maximum stack depth exceeded', + JSON_ERROR_CTRL_CHAR => 'Unexpected control character found', + JSON_ERROR_SYNTAX => 'Syntax error, malformed JSON' + ); + throw new DomainException( + isset($messages[$errno]) ? $messages[$errno] : 'Unknown JSON error: ' . $errno + ); + } + + /** + * Get the number of bytes in cryptographic strings. + * + * @param string + * + * @return int + */ + private static function safeStrlen($str) { + if (function_exists('mb_strlen')) { + return mb_strlen($str, '8bit'); + } + return strlen($str); + } + +} diff --git a/market/libraries/MyCaptcha.php b/market/libraries/MyCaptcha.php new file mode 100644 index 00000000..19caeebc --- /dev/null +++ b/market/libraries/MyCaptcha.php @@ -0,0 +1,141 @@ +sname = $sname == '' ? 'm_captcha' : $sname; + } + + /** 生成验证码图片 + * @param int $length 验证码长度 + * @param Array $param 參數 + * @return IMG + */ + public function create($length = 4, $param = array()) + { + if (!$param['base64']) { + Header("Content-type: image/PNG"); + } + $authnum = $this->random($length); //生成验证码字符. + + $width = isset($param['width']) ? $param['width'] : 13; //文字宽度 + $height = isset($param['height']) ? $param['height'] : 18; //文字高度 + $pnum = isset($param['pnum']) ? $param['pnum'] : 100; //干扰象素个数 + $lnum = isset($param['lnum']) ? $param['lnum'] : 2; //干扰线条数 + + if (!$param['base64']) { + $this->captcha_session($this->sname, $authnum); //将随机数写入session + } + + $pw = $width * $length + 10; + $ph = $height + 6; + + $im = imagecreate($pw, $ph); //imagecreate() 新建图像,大小为 x_size 和 y_size 的空白图像。 + $black = ImageColorAllocate($im, 238, 238, 238); //设置背景颜色 + + $values = array( + mt_rand(0, $pw), mt_rand(0, $ph), + mt_rand(0, $pw), mt_rand(0, $ph), + mt_rand(0, $pw), mt_rand(0, $ph), + mt_rand(0, $pw), mt_rand(0, $ph), + mt_rand(0, $pw), mt_rand(0, $ph), + mt_rand(0, $pw), mt_rand(0, $ph) + ); + imagefilledpolygon($im, $values, 6, ImageColorAllocate($im, mt_rand(170, 255), mt_rand(200, 255), mt_rand(210, 255))); //设置干扰多边形底图 + + /* 文字 */ + for ($i = 0; $i < strlen($authnum); $i++) { + $font = ImageColorAllocate($im, mt_rand(0, 50), mt_rand(0, 150), mt_rand(0, 200));//设置文字颜色 + $x = $i / $length * $pw + rand(1, 6); //设置随机X坐标 + $y = rand(1, $ph / 3); //设置随机Y坐标 + imagestring($im, mt_rand(4, 6), $x, $y, substr($authnum, $i, 1), $font); + } + + /* 加入干扰象素 */ + for ($i = 0; $i < $pnum; $i++) { + $dist = ImageColorAllocate($im, mt_rand(0, 255), mt_rand(0, 255), mt_rand(0, 255)); //设置杂点颜色 + imagesetpixel($im, mt_rand(0, $pw), mt_rand(0, $ph), $dist); + } + + /* 加入干扰线 */ + for ($i = 0; $i < $lnum; $i++) { + $dist = ImageColorAllocate($im, mt_rand(50, 255), mt_rand(150, 255), mt_rand(200, 255)); //设置线颜色 + imageline($im, mt_rand(0, $pw), mt_rand(0, $ph), mt_rand(0, $pw), mt_rand(0, $ph), $dist); + } + + ImagePNG($im); //以 PNG 格式将图像输出到浏览器或文件 + $content = ''; + if ($param['base64']) { + $content = ob_get_clean(); + } + ImageDestroy($im); //销毁一图像 + if ($param['base64']) { + $base64 = base64_encode($content); // base64加密后的图片 + return ['base64' => 'data:image/png;base64,' . $base64, 'text' => $authnum]; + } + } + + /** 检查验证码 + * @param String $captcha 验证码 + * @param int $flag 验证成功后 0:不清除session 1:清除session + * @return boolean + */ + public function check($captcha, $flag = 1) + { + if (empty($captcha)) { + return false; + } else { + if (strtoupper($captcha) == $this->captcha_session($this->sname)) { //检测验证码 + if ($flag == 1) { + $this->captcha_session($this->sname, ''); + } + return true; + } else { + return false; + } + } + } + + /* 产生随机数函数 + * @param int $length 需要随机生成的字符串數 + * @return String + */ + private function random($length) + { + $hash = ''; + //$chars = 'ABCDEFGHIJKLMNPQRSTUVWXYZ23456789'; + $chars = 'abcdefghijklmnpqrstuvwxyz23456789'; + $max = strlen($chars) - 1; + for ($i = 0; $i < $length; $i++) { + $hash .= $chars[mt_rand(0, $max)]; + } + return $hash; + } + + /** 验证码session处理方法 + * @param String $name captcha session name + * @param String $value + * @return String + */ + private function captcha_session($name, $value = null) + { + if (isset($value)) { + if ($value !== '') { + $_SESSION[$name] = $value; + } else { + unset($_SESSION[$name]); + } + } else { + return isset($_SESSION[$name]) ? $_SESSION[$name] : ''; + } + } +} // class end +?> \ No newline at end of file diff --git a/market/libraries/Mymailer.php b/market/libraries/Mymailer.php new file mode 100644 index 00000000..744d224e --- /dev/null +++ b/market/libraries/Mymailer.php @@ -0,0 +1,104 @@ + 'smtp.163.com', + 'port' => '25', + 'username' => '18350451617@163.com', + 'pwd' => 'lin2821808', + 'fromname' => '小鱼网', + ); + + public function __construct($params = array()) + { + $params && $this->init($params); + } + + /** + * 初始化 + * @param array $params 未设置默认server配置mail数组第一项 + * @param boolean $debug + */ + public function init($params = array(), $debug = false){ + + if($params){ + $this->host = $params['host']; + $this->port = $params['port']; + $this->username = $params['username']; + $this->pwd = $params['pwd']; + $this->fromname = $params['fromname']; + $this->debug = $debug; + } else { + $params = $this->config; + $this->host = $params['host']; + $this->port = $params['port']; + $this->username = $params['username']; + $this->pwd = $params['pwd']; + $this->fromname = $params['fromname']; + } + + $mailer = new PHPMailer(); + /* Server Settings */ + $mailer->IsSMTP(); // 使用 SMTP 方式发送邮件 + $mailer->SMTPAuth = true; //启用SMTP认证 + $mailer->Host = $this->host; //SMTP服务器 以163邮箱为例子 + $mailer->Port = $this->port; //邮件发送端口,163的是25,设置ssl连接smtp服务器的远程服务器端口号465 +// $mailer->SMTPSecure = 'ssl'; + $mailer->SMTPDebug = $this->debug;// 是否启用smtp的debug进行调试 开发环境建议开启 生产环境注释掉即可 默认关闭debug调试模式 + /* Account Settings */ + $mailer->Username = $this->username; + $mailer->Password = $this->pwd; + $mailer->From = $this->username; + /* Content Setting */ + $mailer->IsHTML(true); //支持html格式内容 + $mailer->CharSet = 'UTF-8'; + + $this->mailer = $mailer; + } + + /** + * 添加附件 + * @param $path (文件路径 + * @param string $name (指定名称 + */ + public function add_attachment($path, $name=''){ + $this->mailer->AddAttachment($path, $name); + } + + /** + * 发送邮件 + * @param $email (接收邮件地址 + * @param $title (邮件标题 + * @param $content (邮件内容 + * @return bool + */ + public function send($email, $title, $content){ + $this->mailer->FromName = $this->fromname; + $this->mailer->addAddress($email); + $this->mailer->Subject = $title; + $this->mailer->Body = $content; + + return (bool)$this->mailer->send(); // 发送邮件 + } + + public function error(){ + var_dump($this->mailer->ErrorInfo); + } +} \ No newline at end of file diff --git a/market/libraries/REST_Controller.php b/market/libraries/REST_Controller.php new file mode 100644 index 00000000..6dca8cbc --- /dev/null +++ b/market/libraries/REST_Controller.php @@ -0,0 +1,2075 @@ + 'application/json', + 'array' => 'application/json', + 'csv' => 'application/csv', + 'html' => 'text/html', + 'jsonp' => 'application/javascript', + 'php' => 'text/plain', + 'serialized' => 'application/vnd.php.serialized', + 'xml' => 'application/xml' + ]; + + /** + * Information about the current API user + * + * @var object + */ + protected $_apiuser; + + /** + * Whether or not to perform a CORS check and apply CORS headers to the request + * + * @var bool + */ + protected $check_cors = NULL; + + /** + * Enable XSS flag + * Determines whether the XSS filter is always active when + * GET, OPTIONS, HEAD, POST, PUT, DELETE and PATCH data is encountered + * Set automatically based on config setting + * + * @var bool + */ + protected $_enable_xss = FALSE; + + /** + * HTTP status codes and their respective description + * Note: Only the widely used HTTP status codes are used + * + * @var array + * @link http://www.restapitutorial.com/httpstatuscodes.html + */ + protected $http_status_codes = [ + self::HTTP_OK => 'OK', + self::HTTP_CREATED => 'CREATED', + self::HTTP_NO_CONTENT => 'NO CONTENT', + self::HTTP_NOT_MODIFIED => 'NOT MODIFIED', + self::HTTP_BAD_REQUEST => 'BAD REQUEST', + self::HTTP_UNAUTHORIZED => 'UNAUTHORIZED', + self::HTTP_FORBIDDEN => 'FORBIDDEN', + self::HTTP_NOT_FOUND => 'NOT FOUND', + self::HTTP_METHOD_NOT_ALLOWED => 'METHOD NOT ALLOWED', + self::HTTP_NOT_ACCEPTABLE => 'NOT ACCEPTABLE', + self::HTTP_CONFLICT => 'CONFLICT', + self::HTTP_INTERNAL_SERVER_ERROR => 'INTERNAL SERVER ERROR', + self::HTTP_NOT_IMPLEMENTED => 'NOT IMPLEMENTED' + ]; + + /** + * Extend this function to apply additional checking early on in the process + * + * @access protected + * @return void + */ + protected function early_checks() + { + + } + + /** + * Constructor for the REST API + * + * @access public + * @param string $config Configuration filename minus the file extension + * e.g: my_rest.php is passed as 'my_rest' + */ + public function __construct($config = 'rest') + { + parent::__construct(); + + $this->preflight_checks(); + + // Set the default value of global xss filtering. Same approach as CodeIgniter 3 + $this->_enable_xss = ($this->config->item('global_xss_filtering') === TRUE); + + // Don't try to parse template variables like {elapsed_time} and {memory_usage} + // when output is displayed for not damaging data accidentally + $this->output->parse_exec_vars = FALSE; + + // Start the timer for how long the request takes + $this->_start_rtime = microtime(TRUE); + + // Load the rest.php configuration file + $this->load->config($config); + + // At present the library is bundled with REST_Controller 2.5+, but will eventually be part of CodeIgniter (no citation) + $this->load->library('format'); + + // Determine supported output formats from configuration + $supported_formats = $this->config->item('rest_supported_formats'); + + // Validate the configuration setting output formats + if (empty($supported_formats)) { + $supported_formats = []; + } + + if (!is_array($supported_formats)) { + $supported_formats = [$supported_formats]; + } + + // Add silently the default output format if it is missing + $default_format = $this->_get_default_output_format(); + if (!in_array($default_format, $supported_formats)) { + $supported_formats[] = $default_format; + } + + // Now update $this->_supported_formats + $this->_supported_formats = array_intersect_key($this->_supported_formats, array_flip($supported_formats)); + + // Get the language + $language = $this->config->item('rest_language'); + if ($language === NULL) { + $language = 'english'; + } + + // Load the language file + $this->lang->load('rest_controller', $language, FALSE, TRUE, __DIR__ . "/../"); + + // Initialise the response, request and rest objects + $this->request = new stdClass(); + $this->response = new stdClass(); + $this->rest = new stdClass(); + + // Check to see if the current IP address is blacklisted + if ($this->config->item('rest_ip_blacklist_enabled') === TRUE) { + $this->_check_blacklist_auth(); + } + + // Determine whether the connection is HTTPS + $this->request->ssl = is_https(); + + // How is this request being made? GET, POST, PATCH, DELETE, INSERT, PUT, HEAD or OPTIONS + $this->request->method = $this->_detect_method(); + + // Check for CORS access request + $check_cors = $this->config->item('check_cors'); + if ($check_cors === TRUE) { + $this->_check_cors(); + } + + // Create an argument container if it doesn't exist e.g. _get_args + if (isset($this->{'_' . $this->request->method . '_args'}) === FALSE) { + $this->{'_' . $this->request->method . '_args'} = []; + } + + // Set up the query parameters + $this->_parse_query(); + + // Set up the GET variables + $this->_get_args = array_merge($this->_get_args, $this->uri->ruri_to_assoc()); + + // Try to find a format for the request (means we have a request body) + $this->request->format = $this->_detect_input_format(); + + // Not all methods have a body attached with them + $this->request->body = NULL; + + $this->{'_parse_' . $this->request->method}(); + + // Fix parse method return arguments null + if ($this->{'_' . $this->request->method . '_args'} === null) { + $this->{'_' . $this->request->method . '_args'} = []; + } + + // Now we know all about our request, let's try and parse the body if it exists + if ($this->request->format && $this->request->body) { + $this->request->body = $this->format->factory($this->request->body, $this->request->format)->to_array(); + // Assign payload arguments to proper method container + $this->{'_' . $this->request->method . '_args'} = $this->request->body; + } + + //get header vars + $this->_head_args = $this->input->request_headers(); + + // Merge both for one mega-args variable + $this->_args = array_merge( + $this->_get_args, $this->_options_args, $this->_patch_args, $this->_head_args, $this->_put_args, $this->_post_args, $this->_delete_args, $this->{'_' . $this->request->method . '_args'} + ); + + // Which format should the data be returned in? + $this->response->format = $this->_detect_output_format(); + + // Which language should the data be returned in? + $this->response->lang = $this->_detect_lang(); + + // Extend this function to apply additional checking early on in the process + $this->early_checks(); + + // Load DB if its enabled + if ($this->config->item('rest_database_group') && ($this->config->item('rest_enable_keys') || $this->config->item('rest_enable_logging'))) { + $this->rest->db = $this->load->database($this->config->item('rest_database_group'), TRUE); + } // Use whatever database is in use (isset returns FALSE) + elseif (property_exists($this, 'db')) { + $this->rest->db = $this->db; + } + + // Check if there is a specific auth type for the current class/method + // _auth_override_check could exit so we need $this->rest->db initialized before + $this->auth_override = $this->_auth_override_check(); + + // Checking for keys? GET TO WorK! + // Skip keys test for $config['auth_override_class_method']['class'['method'] = 'none' + if ($this->config->item('rest_enable_keys') && $this->auth_override !== TRUE) { + $this->_allow = $this->_detect_api_key(); + } + + // Only allow ajax requests + if ($this->input->is_ajax_request() === FALSE && $this->config->item('rest_ajax_only')) { + // Display an error response + $this->response([ + $this->config->item('rest_status_field_name') => FALSE, + $this->config->item('rest_message_field_name') => $this->lang->line('text_rest_ajax_only') + ], self::HTTP_NOT_ACCEPTABLE); + } + + // When there is no specific override for the current class/method, use the default auth value set in the config + if ($this->auth_override === FALSE && + (!($this->config->item('rest_enable_keys') && $this->_allow === TRUE) || + ($this->config->item('allow_auth_and_keys') === TRUE && $this->_allow === TRUE))) { + $rest_auth = strtolower($this->config->item('rest_auth')); + switch ($rest_auth) { + case 'basic': + $this->_prepare_basic_auth(); + break; + case 'digest': + $this->_prepare_digest_auth(); + break; + case 'session': + $this->_check_php_session(); + break; + } + if ($this->config->item('rest_ip_whitelist_enabled') === TRUE) { + $this->_check_whitelist_auth(); + } + } + } + + /** + * De-constructor + * + * @return void + * @author Chris Kacerguis + * @access public + */ + public function __destruct() + { + // Get the current timestamp + $this->_end_rtime = microtime(TRUE); + + // Log the loading time to the log table + if ($this->config->item('rest_enable_logging') === TRUE) { + $this->_log_access_time(); + } + } + + /** + * Checks to see if we have everything we need to run this library. + * + * @access protected + * @throws Exception + */ + protected function preflight_checks() + { + // Check to see if PHP is equal to or greater than 5.4.x + if (is_php('5.4') === FALSE) { + // CodeIgniter 3 is recommended for v5.4 or above + throw new Exception('Using PHP v' . PHP_VERSION . ', though PHP v5.4 or greater is required'); + } + + // Check to see if this is CI 3.x + if (explode('.', CI_VERSION, 2)[0] < 3) { + throw new Exception('REST Server requires CodeIgniter 3.x'); + } + } + + /** + * Requests are not made to methods directly, the request will be for + * an "object". This simply maps the object and method to the correct + * Controller method + * + * @access public + * @param string $object_called + * @param array $arguments The arguments passed to the controller method + */ + public function _remap($object_called, $arguments = []) + { + // Should we answer if not over SSL? + if ($this->config->item('force_https') && $this->request->ssl === FALSE) { + $this->response([ + $this->config->item('rest_status_field_name') => FALSE, + $this->config->item('rest_message_field_name') => $this->lang->line('text_rest_unsupported') + ], self::HTTP_FORBIDDEN); + } + + // Remove the supported format from the function name e.g. index.json => index + $object_called = preg_replace('/^(.*)\.(?:' . implode('|', array_keys($this->_supported_formats)) . ')$/', '$1', $object_called); + + $controller_method = $object_called . '_' . $this->request->method; + // Does this method exist? If not, try executing an index method + if (!method_exists($this, $controller_method)) { + $controller_method = "index_" . $this->request->method; + array_unshift($arguments, $object_called); + } + + // Do we want to log this method (if allowed by config)? + $log_method = !(isset($this->methods[$controller_method]['log']) && $this->methods[$controller_method]['log'] === FALSE); + + // Use keys for this method? + $use_key = !(isset($this->methods[$controller_method]['key']) && $this->methods[$controller_method]['key'] === FALSE); + + // They provided a key, but it wasn't valid, so get them out of here + if ($this->config->item('rest_enable_keys') && $use_key && $this->_allow === FALSE) { + if ($this->config->item('rest_enable_logging') && $log_method) { + $this->_log_request(); + } + + // fix cross site to option request error + if ($this->request->method == 'options') { + exit; + } + + $this->response([ + $this->config->item('rest_status_field_name') => FALSE, + $this->config->item('rest_message_field_name') => sprintf($this->lang->line('text_rest_invalid_api_key'), $this->rest->key) + ], self::HTTP_FORBIDDEN); + } + + // Check to see if this key has access to the requested controller + if ($this->config->item('rest_enable_keys') && $use_key && empty($this->rest->key) === FALSE && $this->_check_access() === FALSE) { + if ($this->config->item('rest_enable_logging') && $log_method) { + $this->_log_request(); + } + + $this->response([ + $this->config->item('rest_status_field_name') => FALSE, + $this->config->item('rest_message_field_name') => $this->lang->line('text_rest_api_key_unauthorized') + ], self::HTTP_UNAUTHORIZED); + } + + // Sure it exists, but can they do anything with it? + if (!method_exists($this, $controller_method)) { + $this->response([ + $this->config->item('rest_status_field_name') => FALSE, + $this->config->item('rest_message_field_name') => $this->lang->line('text_rest_unknown_method') + ], self::HTTP_METHOD_NOT_ALLOWED); + } + + // Doing key related stuff? Can only do it if they have a key right? + if ($this->config->item('rest_enable_keys') && empty($this->rest->key) === FALSE) { + // Check the limit + if ($this->config->item('rest_enable_limits') && $this->_check_limit($controller_method) === FALSE) { + $response = [$this->config->item('rest_status_field_name') => FALSE, $this->config->item('rest_message_field_name') => $this->lang->line('text_rest_api_key_time_limit')]; + $this->response($response, self::HTTP_UNAUTHORIZED); + } + + // If no level is set use 0, they probably aren't using permissions + $level = isset($this->methods[$controller_method]['level']) ? $this->methods[$controller_method]['level'] : 0; + + // If no level is set, or it is lower than/equal to the key's level + $authorized = $level <= $this->rest->level; + // IM TELLIN! + if ($this->config->item('rest_enable_logging') && $log_method) { + $this->_log_request($authorized); + } + if ($authorized === FALSE) { + // They don't have good enough perms + $response = [$this->config->item('rest_status_field_name') => FALSE, $this->config->item('rest_message_field_name') => $this->lang->line('text_rest_api_key_permissions')]; + $this->response($response, self::HTTP_UNAUTHORIZED); + } + } //check request limit by ip without login + elseif ($this->config->item('rest_limits_method') == "IP_ADDRESS" && $this->config->item('rest_enable_limits') && $this->_check_limit($controller_method) === FALSE) { + $response = [$this->config->item('rest_status_field_name') => FALSE, $this->config->item('rest_message_field_name') => $this->lang->line('text_rest_ip_address_time_limit')]; + $this->response($response, self::HTTP_UNAUTHORIZED); + } // No key stuff, but record that stuff is happening + elseif ($this->config->item('rest_enable_logging') && $log_method) { + $this->_log_request($authorized = TRUE); + } + + // Call the controller method and passed arguments + try { + call_user_func_array([$this, $controller_method], $arguments); + } catch (Exception $ex) { + if ($this->config->item('rest_handle_exceptions') === FALSE) { + throw $ex; + } + + // If the method doesn't exist, then the error will be caught and an error response shown + $_error = &load_class('Exceptions', 'core'); + $_error->show_exception($ex); + } + } + + /** + * Takes mixed data and optionally a status code, then creates the response + * + * @access public + * @param array|NULL $data Data to output to the user + * @param int|NULL $http_code HTTP status code + * running the script; otherwise, exit + */ + public function response($data = NULL, $http_code = NULL) + { + ob_start(); + // If the HTTP status is not NULL, then cast as an integer + if ($http_code !== NULL) { + // So as to be safe later on in the process + $http_code = (int)$http_code; + } + + // Set the output as NULL by default + $output = NULL; + + // If data is NULL and no HTTP status code provided, then display, error and exit + if ($data === NULL && $http_code === NULL) { + $http_code = self::HTTP_NOT_FOUND; + } // If data is not NULL and a HTTP status code provided, then continue + elseif ($data !== NULL) { + // If the format method exists, call and return the output in that format + if (method_exists($this->format, 'to_' . $this->response->format)) { + // Set the format header + $this->output->set_content_type($this->_supported_formats[$this->response->format], strtolower($this->config->item('charset'))); + $output = $this->format->factory($data)->{'to_' . $this->response->format}(); + + // An array must be parsed as a string, so as not to cause an array to string error + // Json is the most appropriate form for such a data type + if ($this->response->format === 'array') { + $output = $this->format->factory($output)->{'to_json'}(); + } + } else { + // If an array or object, then parse as a json, so as to be a 'string' + if (is_array($data) || is_object($data)) { + $data = $this->format->factory($data)->{'to_json'}(); + } + + // Format is not supported, so output the raw data as a string + $output = $data; + } + } + + // If not greater than zero, then set the HTTP status code as 200 by default + // Though perhaps 500 should be set instead, for the developer not passing a + // correct HTTP status code + $http_code > 0 || $http_code = self::HTTP_OK; + + $this->output->set_status_header($http_code); + + // JC: Log response code only if rest logging enabled + if ($this->config->item('rest_enable_logging') === TRUE) { + $this->_log_response_code($http_code); + } + + // Output the data + $this->output->set_output($output); + + ob_end_flush(); + + // Otherwise dump the output automatically + } + + /** + * Takes mixed data and optionally a status code, then creates the response + * within the buffers of the Output class. The response is sent to the client + * lately by the framework, after the current controller's method termination. + * All the hooks after the controller's method termination are executable + * + * @access public + * @param array|NULL $data Data to output to the user + * @param int|NULL $http_code HTTP status code + */ + public function set_response($data = NULL, $http_code = NULL) + { + $this->response($data, $http_code, TRUE); + } + + /** + * Get the input format e.g. json or xml + * + * @access protected + * @return string|NULL Supported input format; otherwise, NULL + */ + protected function _detect_input_format() + { + // Get the CONTENT-TYPE value from the SERVER variable + $content_type = $this->input->server('CONTENT_TYPE'); + + if (empty($content_type) === FALSE) { + // If a semi-colon exists in the string, then explode by ; and get the value of where + // the current array pointer resides. This will generally be the first element of the array + $content_type = (strpos($content_type, ';') !== FALSE ? current(explode(';', $content_type)) : $content_type); + + // Check all formats against the CONTENT-TYPE header + foreach ($this->_supported_formats as $type => $mime) { + // $type = format e.g. csv + // $mime = mime type e.g. application/csv + // If both the mime types match, then return the format + if ($content_type === $mime) { + return $type; + } + } + } + + return NULL; + } + + /** + * Gets the default format from the configuration. Fallbacks to 'json' + * if the corresponding configuration option $config['rest_default_format'] + * is missing or is empty + * + * @access protected + * @return string The default supported input format + */ + protected function _get_default_output_format() + { + $default_format = (string)$this->config->item('rest_default_format'); + return $default_format === '' ? 'json' : $default_format; + } + + /** + * Detect which format should be used to output the data + * + * @access protected + * @return mixed|NULL|string Output format + */ + protected function _detect_output_format() + { + // Concatenate formats to a regex pattern e.g. \.(csv|json|xml) + $pattern = '/\.(' . implode('|', array_keys($this->_supported_formats)) . ')($|\/)/'; + $matches = []; + + // Check if a file extension is used e.g. http://example.com/api/index.json?param1=param2 + if (preg_match($pattern, $this->uri->uri_string(), $matches)) { + return $matches[1]; + } + + // Get the format parameter named as 'format' + if (isset($this->_get_args['format'])) { + $format = strtolower($this->_get_args['format']); + + if (isset($this->_supported_formats[$format]) === TRUE) { + return $format; + } + } + + // Get the HTTP_ACCEPT server variable + $http_accept = $this->input->server('HTTP_ACCEPT'); + + // Otherwise, check the HTTP_ACCEPT server variable + if ($this->config->item('rest_ignore_http_accept') === FALSE && $http_accept !== NULL) { + // Check all formats against the HTTP_ACCEPT header + foreach (array_keys($this->_supported_formats) as $format) { + // Has this format been requested? + if (strpos($http_accept, $format) !== FALSE) { + if ($format !== 'html' && $format !== 'xml') { + // If not HTML or XML assume it's correct + return $format; + } elseif ($format === 'html' && strpos($http_accept, 'xml') === FALSE) { + // HTML or XML have shown up as a match + // If it is truly HTML, it wont want any XML + return $format; + } else if ($format === 'xml' && strpos($http_accept, 'html') === FALSE) { + // If it is truly XML, it wont want any HTML + return $format; + } + } + } + } + + // Check if the controller has a default format + if (empty($this->rest_format) === FALSE) { + return $this->rest_format; + } + + // Obtain the default format from the configuration + return $this->_get_default_output_format(); + } + + /** + * Get the HTTP request string e.g. get or post + * + * @access protected + * @return string|NULL Supported request method as a lowercase string; otherwise, NULL if not supported + */ + protected function _detect_method() + { + // Declare a variable to store the method + $method = NULL; + + // Determine whether the 'enable_emulate_request' setting is enabled + if ($this->config->item('enable_emulate_request') === TRUE) { + $method = $this->input->post('_method'); + if ($method === NULL) { + $method = $this->input->server('HTTP_X_HTTP_METHOD_OVERRIDE'); + } + + $method = strtolower($method); + } + + if (empty($method)) { + // Get the request method as a lowercase string + $method = $this->input->method(); + } + + return in_array($method, $this->allowed_http_methods) && method_exists($this, '_parse_' . $method) ? $method : 'get'; + } + + /** + * See if the user has provided an API key + * + * @access protected + * @return bool + */ + protected function _detect_api_key() + { + // Get the api key name variable set in the rest config file + $api_key_variable = $this->config->item('rest_key_name'); + + // Work out the name of the SERVER entry based on config + $key_name = 'HTTP_' . strtoupper(str_replace('-', '_', $api_key_variable)); + + $this->rest->key = NULL; + $this->rest->level = NULL; + $this->rest->user_id = NULL; + $this->rest->ignore_limits = FALSE; + + // Find the key from server or arguments + if (($key = isset($this->_args[$api_key_variable]) ? $this->_args[$api_key_variable] : $this->input->server($key_name))) { + if (!($row = $this->rest->db->where($this->config->item('rest_key_column'), $key)->get($this->config->item('rest_keys_table'))->row())) { + return FALSE; + } + + $this->rest->key = $row->{$this->config->item('rest_key_column')}; + + isset($row->user_id) && $this->rest->user_id = $row->user_id; + isset($row->level) && $this->rest->level = $row->level; + isset($row->ignore_limits) && $this->rest->ignore_limits = $row->ignore_limits; + + $this->_apiuser = $row; + + /* + * If "is private key" is enabled, compare the ip address with the list + * of valid ip addresses stored in the database + */ + if (empty($row->is_private_key) === FALSE) { + // Check for a list of valid ip addresses + if (isset($row->ip_addresses)) { + // multiple ip addresses must be separated using a comma, explode and loop + $list_ip_addresses = explode(',', $row->ip_addresses); + $found_address = FALSE; + + foreach ($list_ip_addresses as $ip_address) { + if ($this->input->ip_address() === trim($ip_address)) { + // there is a match, set the the value to TRUE and break out of the loop + $found_address = TRUE; + break; + } + } + + return $found_address; + } else { + // There should be at least one IP address for this private key + return FALSE; + } + } + + return TRUE; + } + + // No key has been sent + return FALSE; + } + + /** + * Preferred return language + * + * @access protected + * @return string|NULL The language code + */ + protected function _detect_lang() + { + $lang = $this->input->server('HTTP_ACCEPT_LANGUAGE'); + if ($lang === NULL) { + return NULL; + } + + // It appears more than one language has been sent using a comma delimiter + if (strpos($lang, ',') !== FALSE) { + $langs = explode(',', $lang); + + $return_langs = []; + foreach ($langs as $lang) { + // Remove weight and trim leading and trailing whitespace + list($lang) = explode(';', $lang); + $return_langs[] = trim($lang); + } + + return $return_langs; + } + + // Otherwise simply return as a string + return $lang; + } + + /** + * Add the request to the log table + * + * @access protected + * @param bool $authorized TRUE the user is authorized; otherwise, FALSE + * @return bool TRUE the data was inserted; otherwise, FALSE + */ + protected function _log_request($authorized = FALSE) + { + // Insert the request into the log table + $is_inserted = $this->rest->db + ->insert( + $this->config->item('rest_logs_table'), [ + 'uri' => $this->uri->uri_string(), + 'method' => $this->request->method, + 'params' => $this->_args ? ($this->config->item('rest_logs_json_params') === TRUE ? json_encode($this->_args) : serialize($this->_args)) : NULL, + 'api_key' => isset($this->rest->key) ? $this->rest->key : '', + 'ip_address' => $this->input->ip_address(), + 'time' => time(), + 'authorized' => $authorized + ]); + + // Get the last insert id to update at a later stage of the request + $this->_insert_id = $this->rest->db->insert_id(); + + return $is_inserted; + } + + /** + * Check if the requests to a controller method exceed a limit + * + * @access protected + * @param string $controller_method The method being called + * @return bool TRUE the call limit is below the threshold; otherwise, FALSE + */ + protected function _check_limit($controller_method) + { + // They are special, or it might not even have a limit + if (empty($this->rest->ignore_limits) === FALSE) { + // Everything is fine + return TRUE; + } + + $api_key = isset($this->rest->key) ? $this->rest->key : ''; + + switch ($this->config->item('rest_limits_method')) { + case 'IP_ADDRESS': + $limited_uri = 'ip-address:' . $this->input->ip_address(); + $api_key = $this->input->ip_address(); + break; + + case 'API_KEY': + $limited_uri = 'api-key:' . $api_key; + break; + + case 'METHOD_NAME': + $limited_uri = 'method-name:' . $controller_method; + break; + + case 'ROUTED_URL': + default: + $limited_uri = $this->uri->ruri_string(); + if (strpos(strrev($limited_uri), strrev($this->response->format)) === 0) { + $limited_uri = substr($limited_uri, 0, -strlen($this->response->format) - 1); + } + $limited_uri = 'uri:' . $limited_uri . ':' . $this->request->method; // It's good to differentiate GET from PUT + break; + } + + if (isset($this->methods[$controller_method]['limit']) === FALSE) { + // Everything is fine + return TRUE; + } + + // How many times can you get to this method in a defined time_limit (default: 1 hour)? + $limit = $this->methods[$controller_method]['limit']; + + $time_limit = (isset($this->methods[$controller_method]['time']) ? $this->methods[$controller_method]['time'] : 3600); // 3600 = 60 * 60 + // Get data about a keys' usage and limit to one row + $result = $this->rest->db + ->where('uri', $limited_uri) + ->where('api_key', $api_key) + ->get($this->config->item('rest_limits_table')) + ->row(); + + // No calls have been made for this key + if ($result === NULL) { + // Create a new row for the following key + $this->rest->db->insert($this->config->item('rest_limits_table'), [ + 'uri' => $limited_uri, + 'api_key' => $api_key, + 'count' => 1, + 'hour_started' => time() + ]); + } // Been a time limit (or by default an hour) since they called + elseif ($result->hour_started < (time() - $time_limit)) { + // Reset the started period and count + $this->rest->db + ->where('uri', $limited_uri) + ->where('api_key', $api_key) + ->set('hour_started', time()) + ->set('count', 1) + ->update($this->config->item('rest_limits_table')); + } // They have called within the hour, so lets update + else { + // The limit has been exceeded + if ($result->count >= $limit) { + return FALSE; + } + + // Increase the count by one + $this->rest->db + ->where('uri', $limited_uri) + ->where('api_key', $api_key) + ->set('count', 'count + 1', FALSE) + ->update($this->config->item('rest_limits_table')); + } + + return TRUE; + } + + /** + * Check if there is a specific auth type set for the current class/method/HTTP-method being called + * + * @access protected + * @return bool + */ + protected function _auth_override_check() + { + // Assign the class/method auth type override array from the config + $auth_override_class_method = $this->config->item('auth_override_class_method'); + + // Check to see if the override array is even populated + if (!empty($auth_override_class_method)) { + // Check for wildcard flag for rules for classes + if (!empty($auth_override_class_method[$this->router->class]['*'])) { // Check for class overrides + // No auth override found, prepare nothing but send back a TRUE override flag + if ($auth_override_class_method[$this->router->class]['*'] === 'none') { + return TRUE; + } + + // Basic auth override found, prepare basic + if ($auth_override_class_method[$this->router->class]['*'] === 'basic') { + $this->_prepare_basic_auth(); + + return TRUE; + } + + // Digest auth override found, prepare digest + if ($auth_override_class_method[$this->router->class]['*'] === 'digest') { + $this->_prepare_digest_auth(); + + return TRUE; + } + + // Session auth override found, check session + if ($auth_override_class_method[$this->router->class]['*'] === 'session') { + $this->_check_php_session(); + + return TRUE; + } + + // Whitelist auth override found, check client's ip against config whitelist + if ($auth_override_class_method[$this->router->class]['*'] === 'whitelist') { + $this->_check_whitelist_auth(); + + return TRUE; + } + } + + // Check to see if there's an override value set for the current class/method being called + if (!empty($auth_override_class_method[$this->router->class][$this->router->method])) { + // None auth override found, prepare nothing but send back a TRUE override flag + if ($auth_override_class_method[$this->router->class][$this->router->method] === 'none') { + return TRUE; + } + + // Basic auth override found, prepare basic + if ($auth_override_class_method[$this->router->class][$this->router->method] === 'basic') { + $this->_prepare_basic_auth(); + + return TRUE; + } + + // Digest auth override found, prepare digest + if ($auth_override_class_method[$this->router->class][$this->router->method] === 'digest') { + $this->_prepare_digest_auth(); + + return TRUE; + } + + // Session auth override found, check session + if ($auth_override_class_method[$this->router->class][$this->router->method] === 'session') { + $this->_check_php_session(); + + return TRUE; + } + + // Whitelist auth override found, check client's ip against config whitelist + if ($auth_override_class_method[$this->router->class][$this->router->method] === 'whitelist') { + $this->_check_whitelist_auth(); + + return TRUE; + } + } + } + + // Assign the class/method/HTTP-method auth type override array from the config + $auth_override_class_method_http = $this->config->item('auth_override_class_method_http'); + + // Check to see if the override array is even populated + if (!empty($auth_override_class_method_http)) { + // check for wildcard flag for rules for classes + if (!empty($auth_override_class_method_http[$this->router->class]['*'][$this->request->method])) { + // None auth override found, prepare nothing but send back a TRUE override flag + if ($auth_override_class_method_http[$this->router->class]['*'][$this->request->method] === 'none') { + return TRUE; + } + + // Basic auth override found, prepare basic + if ($auth_override_class_method_http[$this->router->class]['*'][$this->request->method] === 'basic') { + $this->_prepare_basic_auth(); + + return TRUE; + } + + // Digest auth override found, prepare digest + if ($auth_override_class_method_http[$this->router->class]['*'][$this->request->method] === 'digest') { + $this->_prepare_digest_auth(); + + return TRUE; + } + + // Session auth override found, check session + if ($auth_override_class_method_http[$this->router->class]['*'][$this->request->method] === 'session') { + $this->_check_php_session(); + + return TRUE; + } + + // Whitelist auth override found, check client's ip against config whitelist + if ($auth_override_class_method_http[$this->router->class]['*'][$this->request->method] === 'whitelist') { + $this->_check_whitelist_auth(); + + return TRUE; + } + } + + // Check to see if there's an override value set for the current class/method/HTTP-method being called + if (!empty($auth_override_class_method_http[$this->router->class][$this->router->method][$this->request->method])) { + // None auth override found, prepare nothing but send back a TRUE override flag + if ($auth_override_class_method_http[$this->router->class][$this->router->method][$this->request->method] === 'none') { + return TRUE; + } + + // Basic auth override found, prepare basic + if ($auth_override_class_method_http[$this->router->class][$this->router->method][$this->request->method] === 'basic') { + $this->_prepare_basic_auth(); + + return TRUE; + } + + // Digest auth override found, prepare digest + if ($auth_override_class_method_http[$this->router->class][$this->router->method][$this->request->method] === 'digest') { + $this->_prepare_digest_auth(); + + return TRUE; + } + + // Session auth override found, check session + if ($auth_override_class_method_http[$this->router->class][$this->router->method][$this->request->method] === 'session') { + $this->_check_php_session(); + + return TRUE; + } + + // Whitelist auth override found, check client's ip against config whitelist + if ($auth_override_class_method_http[$this->router->class][$this->router->method][$this->request->method] === 'whitelist') { + $this->_check_whitelist_auth(); + + return TRUE; + } + } + } + return FALSE; + } + + /** + * Parse the GET request arguments + * + * @access protected + * @return void + */ + protected function _parse_get() + { + // Merge both the URI segments and query parameters + $this->_get_args = array_merge($this->_get_args, $this->_query_args); + } + + /** + * Parse the POST request arguments + * + * @access protected + * @return void + */ + protected function _parse_post() + { + $this->_post_args = $_POST; + + if ($this->request->format) { + $this->request->body = $this->input->raw_input_stream; + } + } + + /** + * Parse the PUT request arguments + * + * @access protected + * @return void + */ + protected function _parse_put() + { + if ($this->request->format) { + $this->request->body = $this->input->raw_input_stream; + if ($this->request->format === 'json') { + $this->_put_args = json_decode($this->input->raw_input_stream); + } + } else if ($this->input->method() === 'put') { + // If no file type is provided, then there are probably just arguments + $this->_put_args = $this->input->input_stream(); + } + } + + /** + * Parse the HEAD request arguments + * + * @access protected + * @return void + */ + protected function _parse_head() + { + // Parse the HEAD variables + parse_str(parse_url($this->input->server('REQUEST_URI'), PHP_URL_QUERY), $head); + + // Merge both the URI segments and HEAD params + $this->_head_args = array_merge($this->_head_args, $head); + } + + /** + * Parse the OPTIONS request arguments + * + * @access protected + * @return void + */ + protected function _parse_options() + { + // Parse the OPTIONS variables + parse_str(parse_url($this->input->server('REQUEST_URI'), PHP_URL_QUERY), $options); + + // Merge both the URI segments and OPTIONS params + $this->_options_args = array_merge($this->_options_args, $options); + } + + /** + * Parse the PATCH request arguments + * + * @access protected + * @return void + */ + protected function _parse_patch() + { + // It might be a HTTP body + if ($this->request->format) { + $this->request->body = $this->input->raw_input_stream; + } else if ($this->input->method() === 'patch') { + // If no file type is provided, then there are probably just arguments + $this->_patch_args = $this->input->input_stream(); + } + } + + /** + * Parse the DELETE request arguments + * + * @access protected + * @return void + */ + protected function _parse_delete() + { + // These should exist if a DELETE request + if ($this->input->method() === 'delete') { + $this->_delete_args = $this->input->input_stream(); + } + } + + /** + * Parse the query parameters + * + * @access protected + * @return void + */ + protected function _parse_query() + { + $this->_query_args = $this->input->get(); + } + + // INPUT FUNCTION -------------------------------------------------------------- + + /** + * Retrieve a value from a GET request + * + * @access public + * @param NULL $key Key to retrieve from the GET request + * If NULL an array of arguments is returned + * @param NULL $xss_clean Whether to apply XSS filtering + * @return array|string|NULL Value from the GET request; otherwise, NULL + */ + public function get($key = NULL, $xss_clean = NULL) + { + if ($key === NULL) { + return $this->_get_args; + } + + return isset($this->_get_args[$key]) ? $this->_xss_clean($this->_get_args[$key], $xss_clean) : NULL; + } + + /** + * Retrieve a value from a OPTIONS request + * + * @access public + * @param NULL $key Key to retrieve from the OPTIONS request. + * If NULL an array of arguments is returned + * @param NULL $xss_clean Whether to apply XSS filtering + * @return array|string|NULL Value from the OPTIONS request; otherwise, NULL + */ + public function options($key = NULL, $xss_clean = NULL) + { + if ($key === NULL) { + return $this->_options_args; + } + + return isset($this->_options_args[$key]) ? $this->_xss_clean($this->_options_args[$key], $xss_clean) : NULL; + } + + /** + * Retrieve a value from a HEAD request + * + * @access public + * @param NULL $key Key to retrieve from the HEAD request + * If NULL an array of arguments is returned + * @param NULL $xss_clean Whether to apply XSS filtering + * @return array|string|NULL Value from the HEAD request; otherwise, NULL + */ + public function head($key = NULL, $xss_clean = NULL) + { + if ($key === NULL) { + return $this->_head_args; + } + + return isset($this->_head_args[$key]) ? $this->_xss_clean($this->_head_args[$key], $xss_clean) : NULL; + } + + /** + * Retrieve a value from a POST request + * + * @access public + * @param NULL $key Key to retrieve from the POST request + * If NULL an array of arguments is returned + * @param NULL $xss_clean Whether to apply XSS filtering + * @return array|string|NULL Value from the POST request; otherwise, NULL + */ + public function post($key = NULL, $xss_clean = NULL) + { + if ($key === NULL) { + return $this->_post_args; + } + + return isset($this->_post_args[$key]) ? $this->_xss_clean($this->_post_args[$key], $xss_clean) : NULL; + } + + /** + * Retrieve a value from a PUT request + * + * @access public + * @param NULL $key Key to retrieve from the PUT request + * If NULL an array of arguments is returned + * @param NULL $xss_clean Whether to apply XSS filtering + * @return array|string|NULL Value from the PUT request; otherwise, NULL + */ + public function put($key = NULL, $xss_clean = NULL) + { + if ($key === NULL) { + return $this->_put_args; + } + + return isset($this->_put_args[$key]) ? $this->_xss_clean($this->_put_args[$key], $xss_clean) : NULL; + } + + /** + * Retrieve a value from a DELETE request + * + * @access public + * @param NULL $key Key to retrieve from the DELETE request + * If NULL an array of arguments is returned + * @param NULL $xss_clean Whether to apply XSS filtering + * @return array|string|NULL Value from the DELETE request; otherwise, NULL + */ + public function delete($key = NULL, $xss_clean = NULL) + { + if ($key === NULL) { + return $this->_delete_args; + } + + return isset($this->_delete_args[$key]) ? $this->_xss_clean($this->_delete_args[$key], $xss_clean) : NULL; + } + + /** + * Retrieve a value from a PATCH request + * + * @access public + * @param NULL $key Key to retrieve from the PATCH request + * If NULL an array of arguments is returned + * @param NULL $xss_clean Whether to apply XSS filtering + * @return array|string|NULL Value from the PATCH request; otherwise, NULL + */ + public function patch($key = NULL, $xss_clean = NULL) + { + if ($key === NULL) { + return $this->_patch_args; + } + + return isset($this->_patch_args[$key]) ? $this->_xss_clean($this->_patch_args[$key], $xss_clean) : NULL; + } + + /** + * Retrieve a value from the query parameters + * + * @access public + * @param NULL $key Key to retrieve from the query parameters + * If NULL an array of arguments is returned + * @param NULL $xss_clean Whether to apply XSS filtering + * @return array|string|NULL Value from the query parameters; otherwise, NULL + */ + public function query($key = NULL, $xss_clean = NULL) + { + if ($key === NULL) { + return $this->_query_args; + } + + return isset($this->_query_args[$key]) ? $this->_xss_clean($this->_query_args[$key], $xss_clean) : NULL; + } + + /** + * Sanitizes data so that Cross Site Scripting Hacks can be + * prevented + * + * @access protected + * @param string $value Input data + * @param bool $xss_clean Whether to apply XSS filtering + * @return string + */ + protected function _xss_clean($value, $xss_clean) + { + is_bool($xss_clean) || $xss_clean = $this->_enable_xss; + + return $xss_clean === TRUE ? $this->security->xss_clean($value) : $value; + } + + /** + * Retrieve the validation errors + * + * @access public + * @return array + */ + public function validation_errors() + { + $string = strip_tags($this->form_validation->error_string()); + + return explode(PHP_EOL, trim($string, PHP_EOL)); + } + + // SECURITY FUNCTIONS --------------------------------------------------------- + + /** + * Perform LDAP Authentication + * + * @access protected + * @param string $username The username to validate + * @param string $password The password to validate + * @return bool + */ + protected function _perform_ldap_auth($username = '', $password = NULL) + { + if (empty($username)) { + log_message('debug', 'LDAP Auth: failure, empty username'); + return FALSE; + } + + log_message('debug', 'LDAP Auth: Loading configuration'); + + $this->config->load('ldap.php', TRUE); + + $ldap = [ + 'timeout' => $this->config->item('timeout', 'ldap'), + 'host' => $this->config->item('server', 'ldap'), + 'port' => $this->config->item('port', 'ldap'), + 'rdn' => $this->config->item('binduser', 'ldap'), + 'pass' => $this->config->item('bindpw', 'ldap'), + 'basedn' => $this->config->item('basedn', 'ldap'), + ]; + + log_message('debug', 'LDAP Auth: Connect to ' . (isset($ldaphost) ? $ldaphost : '[ldap not configured]')); + + // Connect to the ldap server + $ldapconn = ldap_connect($ldap['host'], $ldap['port']); + if ($ldapconn) { + log_message('debug', 'Setting timeout to ' . $ldap['timeout'] . ' seconds'); + + ldap_set_option($ldapconn, LDAP_OPT_NETWORK_TIMEOUT, $ldap['timeout']); + + log_message('debug', 'LDAP Auth: Binding to ' . $ldap['host'] . ' with dn ' . $ldap['rdn']); + + // Binding to the ldap server + $ldapbind = ldap_bind($ldapconn, $ldap['rdn'], $ldap['pass']); + + // Verify the binding + if ($ldapbind === FALSE) { + log_message('error', 'LDAP Auth: bind was unsuccessful'); + return FALSE; + } + + log_message('debug', 'LDAP Auth: bind successful'); + } + + // Search for user + if (($res_id = ldap_search($ldapconn, $ldap['basedn'], "uid=$username")) === FALSE) { + log_message('error', 'LDAP Auth: User ' . $username . ' not found in search'); + return FALSE; + } + + if (ldap_count_entries($ldapconn, $res_id) !== 1) { + log_message('error', 'LDAP Auth: Failure, username ' . $username . 'found more than once'); + return FALSE; + } + + if (($entry_id = ldap_first_entry($ldapconn, $res_id)) === FALSE) { + log_message('error', 'LDAP Auth: Failure, entry of search result could not be fetched'); + return FALSE; + } + + if (($user_dn = ldap_get_dn($ldapconn, $entry_id)) === FALSE) { + log_message('error', 'LDAP Auth: Failure, user-dn could not be fetched'); + return FALSE; + } + + // User found, could not authenticate as user + if (($link_id = ldap_bind($ldapconn, $user_dn, $password)) === FALSE) { + log_message('error', 'LDAP Auth: Failure, username/password did not match: ' . $user_dn); + return FALSE; + } + + log_message('debug', 'LDAP Auth: Success ' . $user_dn . ' authenticated successfully'); + + $this->_user_ldap_dn = $user_dn; + + ldap_close($ldapconn); + + return TRUE; + } + + /** + * Perform Library Authentication - Override this function to change the way the library is called + * + * @access protected + * @param string $username The username to validate + * @param string $password The password to validate + * @return bool + */ + protected function _perform_library_auth($username = '', $password = NULL) + { + if (empty($username)) { + log_message('error', 'Library Auth: Failure, empty username'); + return FALSE; + } + + $auth_library_class = strtolower($this->config->item('auth_library_class')); + $auth_library_function = strtolower($this->config->item('auth_library_function')); + + if (empty($auth_library_class)) { + log_message('debug', 'Library Auth: Failure, empty auth_library_class'); + return FALSE; + } + + if (empty($auth_library_function)) { + log_message('debug', 'Library Auth: Failure, empty auth_library_function'); + return FALSE; + } + + if (is_callable([$auth_library_class, $auth_library_function]) === FALSE) { + $this->load->library($auth_library_class); + } + + return $this->{$auth_library_class}->$auth_library_function($username, $password); + } + + /** + * Check if the user is logged in + * + * @access protected + * @param string $username The user's name + * @param bool|string $password The user's password + * @return bool + */ + protected function _check_login($username = NULL, $password = FALSE) + { + if (empty($username)) { + return FALSE; + } + + $auth_source = strtolower($this->config->item('auth_source')); + $rest_auth = strtolower($this->config->item('rest_auth')); + $valid_logins = $this->config->item('rest_valid_logins'); + + if (!$this->config->item('auth_source') && $rest_auth === 'digest') { + // For digest we do not have a password passed as argument + return md5($username . ':' . $this->config->item('rest_realm') . ':' . (isset($valid_logins[$username]) ? $valid_logins[$username] : '')); + } + + if ($password === FALSE) { + return FALSE; + } + + if ($auth_source === 'ldap') { + log_message('debug', "Performing LDAP authentication for $username"); + + return $this->_perform_ldap_auth($username, $password); + } + + if ($auth_source === 'library') { + log_message('debug', "Performing Library authentication for $username"); + + return $this->_perform_library_auth($username, $password); + } + + if (array_key_exists($username, $valid_logins) === FALSE) { + return FALSE; + } + + if ($valid_logins[$username] !== $password) { + return FALSE; + } + + return TRUE; + } + + /** + * Check to see if the user is logged in with a PHP session key + * + * @access protected + * @return void + */ + protected function _check_php_session() + { + // Get the auth_source config item + $key = $this->config->item('auth_source'); + + // If false, then the user isn't logged in + if (!$this->session->userdata($key)) { + // Display an error response + $this->response([ + $this->config->item('rest_status_field_name') => FALSE, + $this->config->item('rest_message_field_name') => $this->lang->line('text_rest_unauthorized') + ], self::HTTP_UNAUTHORIZED); + } + } + + /** + * Prepares for basic authentication + * + * @access protected + * @return void + */ + protected function _prepare_basic_auth() + { + // If whitelist is enabled it has the first chance to kick them out + if ($this->config->item('rest_ip_whitelist_enabled')) { + $this->_check_whitelist_auth(); + } + + // Returns NULL if the SERVER variables PHP_AUTH_USER and HTTP_AUTHENTICATION don't exist + $username = $this->input->server('PHP_AUTH_USER'); + $http_auth = $this->input->server('HTTP_AUTHENTICATION'); + + $password = NULL; + if ($username !== NULL) { + $password = $this->input->server('PHP_AUTH_PW'); + } elseif ($http_auth !== NULL) { + // If the authentication header is set as basic, then extract the username and password from + // HTTP_AUTHORIZATION e.g. my_username:my_password. This is passed in the .htaccess file + if (strpos(strtolower($http_auth), 'basic') === 0) { + // Search online for HTTP_AUTHORIZATION workaround to explain what this is doing + list($username, $password) = explode(':', base64_decode(substr($this->input->server('HTTP_AUTHORIZATION'), 6))); + } + } + + // Check if the user is logged into the system + if ($this->_check_login($username, $password) === FALSE) { + $this->_force_login(); + } + } + + /** + * Prepares for digest authentication + * + * @access protected + * @return void + */ + protected function _prepare_digest_auth() + { + // If whitelist is enabled it has the first chance to kick them out + if ($this->config->item('rest_ip_whitelist_enabled')) { + $this->_check_whitelist_auth(); + } + + // We need to test which server authentication variable to use, + // because the PHP ISAPI module in IIS acts different from CGI + $digest_string = $this->input->server('PHP_AUTH_DIGEST'); + if ($digest_string === NULL) { + $digest_string = $this->input->server('HTTP_AUTHORIZATION'); + } + + $unique_id = uniqid(); + + // The $_SESSION['error_prompted'] variable is used to ask the password + // again if none given or if the user enters wrong auth information + if (empty($digest_string)) { + $this->_force_login($unique_id); + } + + // We need to retrieve authentication data from the $digest_string variable + $matches = []; + preg_match_all('@(username|nonce|uri|nc|cnonce|qop|response)=[\'"]?([^\'",]+)@', $digest_string, $matches); + $digest = (empty($matches[1]) || empty($matches[2])) ? [] : array_combine($matches[1], $matches[2]); + + // For digest authentication the library function should return already stored md5(username:restrealm:password) for that username see rest.php::auth_library_function config + $username = $this->_check_login($digest['username'], TRUE); + if (array_key_exists('username', $digest) === FALSE || $username === FALSE) { + $this->_force_login($unique_id); + } + + $md5 = md5(strtoupper($this->request->method) . ':' . $digest['uri']); + $valid_response = md5($username . ':' . $digest['nonce'] . ':' . $digest['nc'] . ':' . $digest['cnonce'] . ':' . $digest['qop'] . ':' . $md5); + + // Check if the string don't compare (case-insensitive) + if (strcasecmp($digest['response'], $valid_response) !== 0) { + // Display an error response + $this->response([ + $this->config->item('rest_status_field_name') => FALSE, + $this->config->item('rest_message_field_name') => $this->lang->line('text_rest_invalid_credentials') + ], self::HTTP_UNAUTHORIZED); + } + } + + /** + * Checks if the client's ip is in the 'rest_ip_blacklist' config and generates a 401 response + * + * @access protected + * @return void + */ + protected function _check_blacklist_auth() + { + // Match an ip address in a blacklist e.g. 127.0.0.0, 0.0.0.0 + $pattern = sprintf('/(?:,\s*|^)\Q%s\E(?=,\s*|$)/m', $this->input->ip_address()); + + // Returns 1, 0 or FALSE (on error only). Therefore implicitly convert 1 to TRUE + if (preg_match($pattern, $this->config->item('rest_ip_blacklist'))) { + // Display an error response + $this->response([ + $this->config->item('rest_status_field_name') => FALSE, + $this->config->item('rest_message_field_name') => $this->lang->line('text_rest_ip_denied') + ], self::HTTP_UNAUTHORIZED); + } + } + + /** + * Check if the client's ip is in the 'rest_ip_whitelist' config and generates a 401 response + * + * @access protected + * @return void + */ + protected function _check_whitelist_auth() + { + $whitelist = explode(',', $this->config->item('rest_ip_whitelist')); + + array_push($whitelist, '127.0.0.1', '0.0.0.0'); + + foreach ($whitelist as &$ip) { + // As $ip is a reference, trim leading and trailing whitespace, then store the new value + // using the reference + $ip = trim($ip); + } + + if (in_array($this->input->ip_address(), $whitelist) === FALSE) { + $this->response([ + $this->config->item('rest_status_field_name') => FALSE, + $this->config->item('rest_message_field_name') => $this->lang->line('text_rest_ip_unauthorized') + ], self::HTTP_UNAUTHORIZED); + } + } + + /** + * Force logging in by setting the WWW-Authenticate header + * + * @access protected + * @param string $nonce A server-specified data string which should be uniquely generated + * each time + * @return void + */ + protected function _force_login($nonce = '') + { + $rest_auth = $this->config->item('rest_auth'); + $rest_realm = $this->config->item('rest_realm'); + if (strtolower($rest_auth) === 'basic') { + // See http://tools.ietf.org/html/rfc2617#page-5 + header('WWW-Authenticate: Basic realm="' . $rest_realm . '"'); + } elseif (strtolower($rest_auth) === 'digest') { + // See http://tools.ietf.org/html/rfc2617#page-18 + header( + 'WWW-Authenticate: Digest realm="' . $rest_realm + . '", qop="auth", nonce="' . $nonce + . '", opaque="' . md5($rest_realm) . '"'); + } + + // Display an error response + $this->response([ + $this->config->item('rest_status_field_name') => FALSE, + $this->config->item('rest_message_field_name') => $this->lang->line('text_rest_unauthorized') + ], self::HTTP_UNAUTHORIZED); + } + + /** + * Updates the log table with the total access time + * + * @access protected + * @return bool TRUE log table updated; otherwise, FALSE + * @author Chris Kacerguis + */ + protected function _log_access_time() + { + $payload['rtime'] = $this->_end_rtime - $this->_start_rtime; + + return $this->rest->db->update( + $this->config->item('rest_logs_table'), $payload, [ + 'id' => $this->_insert_id + ]); + } + + /** + * Updates the log table with HTTP response code + * + * @access protected + * @param $http_code int HTTP status code + * @return bool TRUE log table updated; otherwise, FALSE + * @author Justin Chen + */ + protected function _log_response_code($http_code) + { + $payload['response_code'] = $http_code; + + return $this->rest->db->update( + $this->config->item('rest_logs_table'), $payload, [ + 'id' => $this->_insert_id + ]); + } + + /** + * Check to see if the API key has access to the controller and methods + * + * @access protected + * @return bool TRUE the API key has access; otherwise, FALSE + */ + protected function _check_access() + { + // If we don't want to check access, just return TRUE + if ($this->config->item('rest_enable_access') === FALSE) { + return TRUE; + } + + //check if the key has all_access + $accessRow = $this->rest->db + ->where('key', $this->rest->key) + ->get($this->config->item('rest_access_table'))->row_array(); + + if (!empty($accessRow) && !empty($accessRow['all_access'])) { + return TRUE; + } + + // Fetch controller based on path and controller name + $controller = implode( + '/', [ + $this->router->directory, + $this->router->class + ]); + + // Remove any double slashes for safety + $controller = str_replace('//', '/', $controller); + + // Query the access table and get the number of results + return $this->rest->db + ->where('key', $this->rest->key) + ->where('controller', $controller) + ->get($this->config->item('rest_access_table')) + ->num_rows() > 0; + } + + /** + * Checks allowed domains, and adds appropriate headers for HTTP access control (CORS) + * + * @access protected + * @return void + */ + protected function _check_cors() + { + // Convert the config items into strings + $allowed_headers = implode(' ,', $this->config->item('allowed_cors_headers')); + $allowed_methods = implode(' ,', $this->config->item('allowed_cors_methods')); + + // If we want to allow any domain to access the API + if ($this->config->item('allow_any_cors_domain') === TRUE) { + header('Access-Control-Allow-Origin: *'); + header('Access-Control-Allow-Headers: ' . $allowed_headers); + header('Access-Control-Allow-Methods: ' . $allowed_methods); + } else { + // We're going to allow only certain domains access + // Store the HTTP Origin header + $origin = $this->input->server('HTTP_ORIGIN'); + if ($origin === NULL) { + $origin = ''; + } + + // If the origin domain is in the allowed_cors_origins list, then add the Access Control headers + if (in_array($origin, $this->config->item('allowed_cors_origins'))) { + header('Access-Control-Allow-Origin: ' . $origin); + header('Access-Control-Allow-Headers: ' . $allowed_headers); + header('Access-Control-Allow-Methods: ' . $allowed_methods); + } + } + + // If the request HTTP method is 'OPTIONS', kill the response and send it to the client + if ($this->input->method() === 'options') { + header("Access-Control-Allow-Origin: *"); + header("Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Authorization"); + header('Access-Control-Allow-Methods: GET, POST, PUT,DELETE,OPTIONS,PATCH'); + file_put_contents('option.txt', json_encode($_REQUEST)); + exit; + } + } + +} \ No newline at end of file diff --git a/market/libraries/SignatureInvalidException.php b/market/libraries/SignatureInvalidException.php new file mode 100644 index 00000000..27332b21 --- /dev/null +++ b/market/libraries/SignatureInvalidException.php @@ -0,0 +1,7 @@ +wechat = new Hdwechat($config); + $this->cf_app = $config['cf_app']; + if($config){ + $this->log_file = "wechat_msg_{$config['appid']}.log"; + } + } + + function init_wechat($config){ + $this->wechat->init($config); + } + + /** + * 初始化服务号消息模板 + * @param $id (模板ID) + * @param $appage (小程序跳转页) + * @param $appid (小程序appid, 默认当前小程序) + * @param $url (跳转外链) + */ + function init_template($id, $appage = '', $appid = '', $url = ''){ + $this->temp_id = $id; + $this->temp_appage = $appage; + $this->temp_appid = $appid; + $this->temp_url = $url; + } + + /** + * 发送服务号消息 + * @param $openid + * @param $data (消息主体) + * @return mixed + */ + function send_oa($openid, $data){ + $access_token = $this->wechat->access_token(); + if(!$access_token){ + debug_log("[error] ". __FUNCTION__ . ": not access_token; openid={$openid}", $this->log_file); + return false; + } + + $pre_url = 'https://api.weixin.qq.com/cgi-bin/message/template/send?access_token='; + $url = $pre_url . $access_token; + $post = array( + 'touser' => $openid, + 'template_id' => $this->temp_id, + 'url' => $this->temp_url ? $this->temp_url : '', + 'data' => $data + ); + if($this->temp_appage){ + $post['miniprogram'] =array( + 'appid' => $this->temp_appid, + 'pagepath' => $this->temp_appage + ); + } + + list($code, $res) = $this->curl_json($url, $post); + $ret = json_decode($res, true); + + if(40001 == $ret['errcode']){//token过期,重置后请求 + $url = $pre_url . $this->wechat->access_token(true); + list($code, $res) = $this->curl_json($url, $post); + $ret = json_decode($res, true); + } + + if($ret['errcode'] != 0){ + debug_log("[error] ". __FUNCTION__ . ": openid={$openid}", $this->log_file); + return false; + } + + return true; + } + + /** + * 发送小程序消息 + * @param $openid + * @param $data + * @return bool + */ + function send_app($openid, $data){ + $access_token = $this->wechat->access_token(); + if(!$access_token){ + debug_log("[error] ". __FUNCTION__ . ": not access_token; openid={$openid}", $this->log_file); + return false; + } + $pre_url = "https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token="; + $url = $pre_url.$access_token; + + $form_id = $this->pop_formid($openid); + if(!$form_id){ + debug_log("[error] ". __FUNCTION__ . ": not form_id; openid={$openid}", $this->log_file); + return false; + } + + $post = array( + 'touser' => $openid, + 'template_id' => $this->temp_id, + 'form_id' => $form_id, + 'page' => $this->temp_appage, + 'data' => $data + ); + + list($code, $res) = $this->curl_json($url, $post); + $ret = json_decode($res, true); + + if(40001 == $ret['errcode']){//token过期,重置后请求 + $url = $pre_url . $this->wechat->access_token(true); + list($code, $res) = $this->curl_json($url, $post); + $ret = json_decode($res, true); + } + + if($ret['errcode'] != 0){ + debug_log("[error] ". __FUNCTION__ . ": from_id={$form_id}, openid={$openid}", $this->log_file); + return false; + } + + return true; + } + + /** + * 发送小程序订阅通知 + * @param $openid + * @param $data + * @return bool + */ + function send_appsub($openid, $data){ + $access_token = $this->wechat->access_token(); + if(!$access_token){ + debug_log("[error] ". __FUNCTION__ . ":not access_token; openid={$openid}", $this->log_file); + return false; + } + + $pre_url = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token="; + $url = $pre_url.$access_token; + + $post = array( + 'touser' => $openid, + 'template_id' => $this->temp_id, + 'page' => $this->temp_appage, + 'data' => $data + ); + + list($code, $res) = $this->curl_json($url, $post); + $ret = json_decode($res, true); + + if(40001 == $ret['errcode']){//token过期,重置后请求 + $url = $pre_url . $this->wechat->access_token(true); + list($code, $res) = $this->curl_json($url, $post); + $ret = json_decode($res, true); + } + + if($ret['errcode'] != 0){ + debug_log("[error] ". __FUNCTION__ . ":openid={$openid}", $this->log_file); + return false; + } + + return true; + } + + /** + * 收集新的form_id + * @param $openid (用户ID) + * @param $form_id + * @param $expire (到期时间戳) + * @return bool + */ + public function push_formid($openid, $form_id, $expire = 0){ + //从redis获取 + $r = &load_cache('redis'); + $redis = $r->redis(); + $key = "wechat_formid_{$this->wechat->appid}_{$openid}"; + $long = 7 * 24 * 3600; + + !$expire && $expire = time() + $long; + $form = array('id' => $form_id, 'expire' => $expire); + + $ret = $redis->lPush($key, json_encode($form)); + $len = $redis->lLen($key); + //限制redis列表长度,去掉旧的 + $ret && $len > self::$max_form && $redis->rPop($key); + //更新redis有效期 + $redis->expire($key, $long); + + return false; + } + + /** + * 获取formid数量 + * @param $openid + * @return mixed + */ + function count_formid($openid){ + $key = "wechat_formid_{$this->wechat->appid}_{$openid}"; + + $r = &load_cache('redis'); + $redis = $r->redis(); + return $redis->lLen($key); + } + + /** + * 查看 + * @param $openid + * @return mixed + */ + function view_formid($openid){ + $key = "wechat_formid_{$this->wechat->appid}_{$openid}"; + $r = &load_cache('redis'); + $redis = $r->redis(); + return $redis->lRange($key, 0, -1); + } + + /** + * 弹出fromid + * @param $openid + * @return string + */ + public function pop_formid($openid){ + //从redis获取 + $r = &load_cache('redis'); + $redis = $r->redis(); + $key = "wechat_formid_{$this->wechat->appid}_{$openid}"; + + $now = time(); + while(1) {//循环获取fromid + $form = $redis->rPop($key); + $form && $form = json_decode($form, true); + if(!$form){break;} + if($form['expire'] >= $now){ + return $form['id']; + } + } + + return ''; + } + + /** + * @param $url + * @param $data + * @return array + */ + private function curl_json($url, $data){ + $data = urldecode(json_encode($data)); + debug_log("[info] ". __FUNCTION__ . ":url={$url}, data={$data}", $this->log_file); + + $ch = curl_init(); + curl_setopt($ch, CURLOPT_POST, 1); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_POSTFIELDS, $data); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + //https + if (strlen($url) > 5 && strtolower(substr($url, 0, 5)) == "https") { + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); + } + curl_setopt($ch, CURLOPT_HTTPHEADER, array( + 'Content-Type: application/json; charset=utf-8', + 'Content-Length: ' . strlen($data) + ) + ); + $response = curl_exec($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + + debug_log("[info] ". __FUNCTION__ . ":httpcode={$httpCode}, response={$response}", $this->log_file); + + return array($httpCode, $response); + } +} \ No newline at end of file diff --git a/market/libraries/Wetemplate.php b/market/libraries/Wetemplate.php new file mode 100644 index 00000000..33ad2fc1 --- /dev/null +++ b/market/libraries/Wetemplate.php @@ -0,0 +1,347 @@ + 'wxdf21b47ec5632158', + 'appsecret' => 'b319fbe508acdbc4c8d9ddaa5bd23444' + ); + + public function __construct($options = array()) { + $this->we_appid = isset($options['appid'])?$options['appid']:''; + $this->we_appsecret = isset($options['appsecret'])?$options['appsecret']:''; + + + $this->ci = & get_instance(); + } + + /** + * 初始化 + * @param int $appid (默认家加贷) + */ + public function init($appid = 1){ + switch($appid){ + case 2://小红榜 + break; + case 3://座上宾 + break; + default://家加贷 + $this->app = 'jjd'; + } + + $config = $this->config; + $this->we_appid = $config['appid']; + $this->we_appsecret = $config['appsecret']; + } + + /** + * 发送小程序消息 + * @param $key(0放款, 1消费, 2扣款, 3照片审核成功, 4照片审核失败) + * @param $openid + * @param $params + * @param string $page + * @return bool + */ + public function send_app_msg($key, $openid, $params, $page = ''){ + $template_id = self::$tmpId_arr[$key]; + $status = true; + $msg = ''; + //access_token + $access_token = $this->get_access_token(); + + if(!$access_token){ + $status = false; + $msg = 'not access_token'; + goto end; + } + + //form_id + $form_id = $this->pop_form_id($openid); + + if(!$form_id){ + $status = false; + $msg = 'not form_id'; + goto end; + } + + $sdata = array( + 'touser' => $openid, + 'template_id' => $template_id, + 'form_id' => $form_id, + 'page' => $page, + ); + + $sdata['data'] = $this->get_msg_data($key, $params); + + $result = $this->http_post(self::API_URL_PREFIX.self::APP_MSG_URL.'?access_token='. $access_token, json_encode($sdata)); + + if ($result) + { + $json = json_decode($result,true); + if ($json['errcode']) { + $status = false; + $msg = $result; + } + } + + end: + + if(!$status) {debug_log($msg, 'wechat_msg.log');} + return $status; + } + + /** + * 获取要提交的消息内容 + * @param $key + * @param $params + * @return mixed + */ + public function get_msg_data($key, $params){ + switch($key){ + case 0://放款成功 + $arr = array( + $params['time'],//日期 + $params['title'],//产品 + $params['user'],//客户 + $params['money'],//金额 + $params['descrip'],//流程阶段 + ); + break; + case 1://消费成功 + $arr = array( + $params['money'],//消费金额 + $params['balance'],//账户余额 + $params['id'],//订单号 + $params['time'],//消费时间 + $params['descrip'],//消费详情 + $params['addr'],//消费门店 + $params['shop'],//商户名称 + $params['type'],//支付方式 + $params['note'],//温馨提示 + ); + break; + case 2://扣款成功 + $arr = array( + $params['money'],//扣款金额 + $params['descrip'],//扣款原因 + $params['remark'],//备注 + ); + break; + case 3://照片审核通过 + $arr = array( + $params['title'],//审核项目 + $params['time'],//上传时间 + $params['descrip'],//审核结果 + $params['remark'],//备注信息 + ); + break; + case 4://审核不通过 + $arr = array( + $params['title'],//审核项目 + $params['time'],//上传时间 + $params['descrip'],//审核结果 + $params['note'],//拒绝理由 + $params['remark'],//备注信息 + ); + break; + default: + $arr = array(); + } + + $data = array(); + foreach($arr as $k => $v){ + $kd = $k+1; + $data["keyword{$kd}"] = array( + 'value' => $v, + ); + } + + return $data; + } + + /** + * 收集新的form_id + * @param $openid + * @param $form_id + * @param $expire (到期时间戳) + * @return bool + */ + public function push_form_id($openid, $form_id, $expire = 0){ + //从redis获取 + $r = &load_cache('redis'); + $redis = $r->redis(); + $key = "wechat_formid_{$this->we_appid}_{$openid}"; + $long = 7 * 24 * 3600; + if($this->app){ + !$expire && $expire = time() + $long; + $form = array('id' => $form_id, 'expire' => $expire); + + $ret = $redis->lPush($key, json_encode($form)); + $len = $redis->lLen($key); + //限制redis列表长度,去掉旧的 + $ret && $len > 100 && $redis->rPop($key); + //更新redis有效期 + $redis->expire($key, $long); + } + + return false; + } + + /** + * form_id数量 + * @param $openid + * @return mixed + */ + public function count_form_id($openid){ + $r = &load_cache('redis'); + $redis = $r->redis(); + $key = "wechat_formid_{$this->we_appid}_{$openid}"; + return $redis->lLen($key); + } + + /** + * 清除缓存 + * @param string $key + * @return bool + */ + public function clear($key = ''){ + if(!$key){return false;} + + $r = &load_cache('redis'); + $redis = $r->redis(); + return $redis->del($key); + } + + /** + * 获取access_token + * @return string + */ + private function get_access_token(){ + if($this->we_access_token){ return $this->we_access_token;} + + if(!$this->we_appid){ return '';} + + //从redis获取 + $r = &load_cache('redis'); + $redis = $r->redis(); + $key = "wechat_accesstoken_{$this->we_appid}"; + if($this->app){ + $access_token = $this->we_access_token = $redis->get($key); + if($access_token){return $access_token;} + } + + $url = self::API_URL_PREFIX . self::ACCESS_TOKEN_URL. "?grant_type=client_credential&appid={$this->we_appid}&secret={$this->we_appsecret}"; + $res = json_decode(file_get_contents($url), true); + $access_token = $res['access_token']; + + //存入redis + if($access_token && $this->app){ + $redis->set($key, $access_token); + $redis->expire($key, 7000); + } + + return $access_token; + } + + /** + * @param $openid + * @return int + */ + private function pop_form_id($openid){ + //从redis获取 + $r = &load_cache('redis'); + $redis = $r->redis(); + $key = "wechat_formid_{$this->we_appid}_{$openid}"; + + if($this->app){ + $now = time(); + while(1) {//循环获取fromid + $form = $redis->rPop($key); + $form && $form = json_decode($form, true); + if(!$form){break;} + if($form['expire'] >= $now){ + return $form['id']; + } + } + } + + return ''; + } + + /** + * POST 请求 + * @param string $url + * @param array|string $param + * @param boolean $post_file 是否文件上传 + * @return string content + */ + private function http_post($url, $param, $post_file = false) { + $oCurl = curl_init(); + if(stripos($url,"https://")!==FALSE){ + curl_setopt($oCurl, CURLOPT_SSL_VERIFYPEER, FALSE); + curl_setopt($oCurl, CURLOPT_SSL_VERIFYHOST, false); + curl_setopt($oCurl, CURLOPT_SSLVERSION, 1); //CURL_SSLVERSION_TLSv1 + } + if (is_string($param) || $post_file) { + $strPOST = $param; + } else { + $aPOST = array(); + foreach($param as $key=>$val){ + $aPOST[] = $key."=".urlencode($val); + } + $strPOST = join("&", $aPOST); + } + if ($post_file){ + curl_setopt ($oCurl, CURLOPT_SAFE_UPLOAD, false); + } + curl_setopt($oCurl, CURLOPT_URL, $url); + curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, 1 ); + curl_setopt($oCurl, CURLOPT_POST,true); + curl_setopt($oCurl, CURLOPT_POSTFIELDS,$strPOST); + $sContent = curl_exec($oCurl); + $aStatus = curl_getinfo($oCurl); + curl_close($oCurl); + if(intval($aStatus["http_code"])==200){ + return $sContent; + }else{ + return false; + } + } + +} \ No newline at end of file diff --git a/market/libraries/api/Record.php b/market/libraries/api/Record.php new file mode 100644 index 00000000..2166b882 --- /dev/null +++ b/market/libraries/api/Record.php @@ -0,0 +1,271 @@ +ci = &get_instance(); + $this->ci->load->model('market/Market_sys_login_record_model'); + $this->ci->load->model('market/Market_sys_operation_record_model'); + } + + /** + * Notes:新增操作日志 + * Created on: 2022/9/15 14:12 + * Created by: dengbw + * @param $data + */ + public function operationRecord($data) + { + if ($data['userId']) { + $os_device = $this->get_os_device(); + $data['url'] = uri_string(); + $data['requestMethod'] = $this->ci->input->method(); + $data['ip'] = get_client_ip(); + $data['device'] = $os_device['device']; + $data['os'] = $os_device['os']; + $data['browser'] = $this->get_browser(); + $data['createTime'] = date('Y-m-d H:i:s'); + $this->ci->Market_sys_operation_record_model->add($data); + } + } + + /** + * Notes:新增登录日志 + * Created on: 2022/9/15 14:10 + * Created by: dengbw + * @param $data + */ + public function loginRecord($data) + { + if ($data['userId']) { + $os_device = $this->get_os_device(); + $data['ip'] = get_client_ip(); + $data['device'] = $os_device['device']; + $data['os'] = $os_device['os']; + $data['browser'] = $this->get_browser(); + $data['createTime'] = date('Y-m-d H:i:s'); + $this->ci->Market_sys_login_record_model->add($data); + } + } + + /** + * Notes:获取操作系统和设备型号 + * Created on: 2022/9/15 11:59 + * Created by: dengbw + * @return array + */ + private function get_os_device() + { + $agent = $_SERVER['HTTP_USER_AGENT']; + $os = '未知操作系统'; + if (preg_match('/win/i', $agent) && strpos($agent, '95')) { + $os = 'Windows 95'; + } + if (preg_match('/win 9x/i', $agent) && strpos($agent, '4.90')) { + $os = 'Windows ME'; + } + if (preg_match('/win/i', $agent) && preg_match('/98/i', $agent)) { + $os = 'Windows 98'; + } + if (preg_match('/win/i', $agent) && preg_match('/nt/i', $agent)) { + $os = 'Windows NT'; + } + if (preg_match('/win/i', $agent) && preg_match('/nt 6.0/i', $agent)) { + $os = 'Windows Vista'; + } + if (preg_match('/win/i', $agent) && preg_match('/nt 6.1/i', $agent)) { + $os = 'Windows 7'; + } + if (preg_match('/win/i', $agent) && preg_match('/nt 6.2/i', $agent)) { + $os = 'Windows 8'; + } + if (preg_match('/win/i', $agent) && preg_match('/nt 10.0/i', $agent)) { + $os = 'Windows 10';#添加win10判断 + } + if (preg_match('/win/i', $agent) && preg_match('/nt 5.1/i', $agent)) { + $os = 'Windows XP'; + } + if (preg_match('/win/i', $agent) && preg_match('/nt 5/i', $agent)) { + $os = 'Windows 2000'; + } + if (preg_match('/win/i', $agent) && preg_match('/32/i', $agent)) { + $os = 'Windows 32'; + } + if (preg_match('/linux/i', $agent)) { + $os = 'Linux'; + } + if (preg_match('/unix/i', $agent)) { + $os = 'Unix'; + } + if (preg_match('/sun/i', $agent) && preg_match('/os/i', $agent)) { + $os = 'SunOS'; + } + if (preg_match('/ibm/i', $agent) && preg_match('/os/i', $agent)) { + $os = 'IBM OS/2'; + } + if (preg_match('/Mac/i', $agent) && preg_match('/PC/i', $agent)) { + $os = 'Macintosh'; + } + if (preg_match('/PowerPC/i', $agent)) { + $os = 'PowerPC'; + } + if (preg_match('/AIX/i', $agent)) { + $os = 'AIX'; + } + if (preg_match('/HPUX/i', $agent)) { + $os = 'HPUX'; + } + if (preg_match('/NetBSD/i', $agent)) { + $os = 'NetBSD'; + } + if (preg_match('/BSD/i', $agent)) { + $os = 'BSD'; + } + if (preg_match('/OSF1/i', $agent)) { + $os = 'OSF1'; + } + if (preg_match('/IRIX/i', $agent)) { + $os = 'IRIX'; + } + if (preg_match('/FreeBSD/i', $agent)) { + $os = 'FreeBSD'; + } + if (preg_match('/teleport/i', $agent)) { + $os = 'teleport'; + } + if (preg_match('/flashget/i', $agent)) { + $os = 'flashget'; + } + if (preg_match('/webzip/i', $agent)) { + $os = 'webzip'; + } + if (preg_match('/offline/i', $agent)) { + $os = 'offline'; + } + if (strpos($agent, 'iphone')) { + $os = 'iphone'; + } + if (strpos($agent, 'ipad')) { + $os = 'ipad'; + } + if (strpos($agent, 'android')) { + $os = 'android'; + } + if (stripos($agent, "SAMSUNG") !== false || stripos($agent, "Galaxy") !== false || strpos($agent, "GT-") !== false || strpos($agent, "SCH-") !== false || strpos($agent, "SM-") !== false) { + $os = 'android ->三星'; + } + if (stripos($agent, "Huawei") !== false || stripos($agent, "Honor") !== false || stripos($agent, "H60-") !== false || stripos($agent, "H30-") !== false) { + $os = 'android ->华为'; + } + if (stripos($agent, "Lenovo") !== false) { + $os = 'android ->联想'; + } + if (strpos($agent, "MI-ONE") !== false || strpos($agent, "MI 1S") !== false || strpos($agent, "MI 2") !== false || strpos($agent, "MI 3") !== false || strpos($agent, "MI 4") !== false || strpos($agent, "MI-4") !== false) { + $os = 'android ->小米'; + } + if (strpos($agent, "HM NOTE") !== false || strpos($agent, "HM201") !== false) { + $os = 'android ->红米'; + } + if (stripos($agent, "Coolpad") !== false || strpos($agent, "8190Q") !== false || strpos($agent, "5910") !== false) { + $os = 'android ->酷派'; + } + if (stripos($agent, "ZTE") !== false || stripos($agent, "X9180") !== false || stripos($agent, "N9180") !== false || stripos($agent, "U9180") !== false) { + $os = 'android ->中兴'; + } + if (stripos($agent, "OPPO") !== false || strpos($agent, "X9007") !== false || strpos($agent, "X907") !== false || strpos($agent, "X909") !== false || strpos($agent, "R831S") !== false || strpos($agent, "R827T") !== false || strpos($agent, "R821T") !== false || strpos($agent, "R811") !== false || strpos($agent, "R2017") !== false) { + $os = 'android ->OPPO'; + } + if (strpos($agent, "HTC") !== false || stripos($agent, "Desire") !== false) { + $os = 'android ->HTC'; + } + if (stripos($agent, "vivo") !== false) { + $os = 'android ->vivo'; + } + if (stripos($agent, "K-Touch") !== false) { + $os = 'android ->天语'; + } + if (stripos($agent, "Nubia") !== false || stripos($agent, "NX50") !== false || stripos($agent, "NX40") !== false) { + $os = 'android ->努比亚'; + } + if (strpos($agent, "M045") !== false || strpos($agent, "M032") !== false || strpos($agent, "M355") !== false) { + $os = 'android ->魅族'; + } + if (stripos($agent, "DOOV") !== false) { + $os = 'android ->朵唯'; + } + if (stripos($agent, "GFIVE") !== false) { + $os = 'android ->基伍'; + } + if (stripos($agent, "Gionee") !== false || strpos($agent, "GN") !== false) { + $os = 'android ->金立'; + } + if (stripos($agent, "HS-U") !== false || stripos($agent, "HS-E") !== false) { + $os = 'android ->海信'; + } + if (stripos($agent, "Nokia") !== false) { + $os = 'android ->诺基亚'; + } + $oss = $os ? explode(' ', $os) : []; + return ['os' => $oss[0] ? $oss[0] : $os, 'device' => $os]; + } + + /** + * Notes:获取浏览器 + * Created on: 2022/9/14 17:23 + * Created by: dengbw + * @return string + */ + private function get_browser() + { + $sys = $_SERVER['HTTP_USER_AGENT']; //获取用户代理字符串 + $exp[0] = "未知浏览器"; + $exp[1] = ""; + //stripos() 函数查找字符串在另一字符串中第一次出现的位置(不区分大小写) preg_match()执行匹配正则表达式 + if (stripos($sys, "Firefox/") > 0) { + preg_match("/Firefox\/([^;)]+)+/i", $sys, $b); + $exp[0] = "Firefox"; + $exp[1] = $b[1]; //获取火狐浏览器的版本号 + } + if (stripos($sys, "Maxthon") > 0) { + preg_match("/Maxthon\/([\d\.]+)/", $sys, $aoyou); + $exp[0] = "傲游"; + $exp[1] = $aoyou[1]; + } + if (stripos($sys, "MSIE") > 0) { + preg_match("/MSIE\s+([^;)]+)+/i", $sys, $ie); + $exp[0] = "IE"; + $exp[1] = $ie[1]; //获取IE的版本号 + } + if (stripos($sys, "OPR") > 0) { + preg_match("/OPR\/([\d\.]+)/", $sys, $opera); + $exp[0] = "Opera"; + $exp[1] = $opera[1]; + } + if (stripos($sys, "Edge") > 0) { + //win10 Edge浏览器 添加了chrome内核标记 在判断Chrome之前匹配 + preg_match("/Edge\/([\d\.]+)/", $sys, $Edge); + $exp[0] = "Edge"; + $exp[1] = $Edge[1]; + } + if (stripos($sys, "Chrome") > 0) { + preg_match("/Chrome\/([\d\.]+)/", $sys, $google); + $exp[0] = "Chrome"; + $exp[1] = $google[1]; //获取google chrome的版本号 + } + if (stripos($sys, 'rv:') > 0 && stripos($sys, 'Gecko') > 0) { + preg_match("/rv:([\d\.]+)/", $sys, $IE); + $exp[0] = "IE"; + $exp[1] = $IE[1]; + } + return $exp[0] . '(' . $exp[1] . ')'; + } + +} \ No newline at end of file diff --git a/market/libraries/index.html b/market/libraries/index.html new file mode 100644 index 00000000..b702fbc3 --- /dev/null +++ b/market/libraries/index.html @@ -0,0 +1,11 @@ + + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + diff --git a/market/logs/index.html b/market/logs/index.html new file mode 100644 index 00000000..b702fbc3 --- /dev/null +++ b/market/logs/index.html @@ -0,0 +1,11 @@ + + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + diff --git a/market/models/index.html b/market/models/index.html new file mode 100644 index 00000000..b702fbc3 --- /dev/null +++ b/market/models/index.html @@ -0,0 +1,11 @@ + + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + diff --git a/market/third_party/index.html b/market/third_party/index.html new file mode 100644 index 00000000..b702fbc3 --- /dev/null +++ b/market/third_party/index.html @@ -0,0 +1,11 @@ + + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + diff --git a/market/views/errors/cli/error_404.php b/market/views/errors/cli/error_404.php new file mode 100644 index 00000000..6984b61e --- /dev/null +++ b/market/views/errors/cli/error_404.php @@ -0,0 +1,8 @@ + + +An uncaught Exception was encountered + +Type: +Message: +Filename: getFile(), "\n"; ?> +Line Number: getLine(); ?> + + + +Backtrace: +getTrace() as $error): ?> + + File: + Line: + Function: + + + + diff --git a/market/views/errors/cli/error_general.php b/market/views/errors/cli/error_general.php new file mode 100644 index 00000000..6984b61e --- /dev/null +++ b/market/views/errors/cli/error_general.php @@ -0,0 +1,8 @@ + + +A PHP Error was encountered + +Severity: +Message: +Filename: +Line Number: + + + +Backtrace: + + + File: + Line: + Function: + + + + diff --git a/market/views/errors/cli/index.html b/market/views/errors/cli/index.html new file mode 100644 index 00000000..b702fbc3 --- /dev/null +++ b/market/views/errors/cli/index.html @@ -0,0 +1,11 @@ + + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + diff --git a/market/views/errors/html/error_404.php b/market/views/errors/html/error_404.php new file mode 100644 index 00000000..756ea9d6 --- /dev/null +++ b/market/views/errors/html/error_404.php @@ -0,0 +1,64 @@ + + + + +404 Page Not Found + + + +
+

+ +
+ + \ No newline at end of file diff --git a/market/views/errors/html/error_db.php b/market/views/errors/html/error_db.php new file mode 100644 index 00000000..f5a43f63 --- /dev/null +++ b/market/views/errors/html/error_db.php @@ -0,0 +1,64 @@ + + + + +Database Error + + + +
+

+ +
+ + \ No newline at end of file diff --git a/market/views/errors/html/error_exception.php b/market/views/errors/html/error_exception.php new file mode 100644 index 00000000..87848866 --- /dev/null +++ b/market/views/errors/html/error_exception.php @@ -0,0 +1,32 @@ + + +
+ +

An uncaught Exception was encountered

+ +

Type:

+

Message:

+

Filename: getFile(); ?>

+

Line Number: getLine(); ?>

+ + + +

Backtrace:

+ getTrace() as $error): ?> + + + +

+ File:
+ Line:
+ Function: +

+ + + + + + +
\ No newline at end of file diff --git a/market/views/errors/html/error_general.php b/market/views/errors/html/error_general.php new file mode 100644 index 00000000..fc3b2eba --- /dev/null +++ b/market/views/errors/html/error_general.php @@ -0,0 +1,64 @@ + + + + +Error + + + +
+

+ +
+ + \ No newline at end of file diff --git a/market/views/errors/html/error_php.php b/market/views/errors/html/error_php.php new file mode 100644 index 00000000..b146f9c5 --- /dev/null +++ b/market/views/errors/html/error_php.php @@ -0,0 +1,33 @@ + + +
+ +

A PHP Error was encountered

+ +

Severity:

+

Message:

+

Filename:

+

Line Number:

+ + + +

Backtrace:

+ + + + +

+ File:
+ Line:
+ Function: +

+ + + + + + + +
\ No newline at end of file diff --git a/market/views/errors/html/index.html b/market/views/errors/html/index.html new file mode 100644 index 00000000..b702fbc3 --- /dev/null +++ b/market/views/errors/html/index.html @@ -0,0 +1,11 @@ + + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + diff --git a/market/views/errors/index.html b/market/views/errors/index.html new file mode 100644 index 00000000..b702fbc3 --- /dev/null +++ b/market/views/errors/index.html @@ -0,0 +1,11 @@ + + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + diff --git a/market/views/welcome_message.php b/market/views/welcome_message.php new file mode 100644 index 00000000..d96a2668 --- /dev/null +++ b/market/views/welcome_message.php @@ -0,0 +1,45 @@ + + + + + + 狸车平台 + + + + + + + + + + + + + + + diff --git a/www/home/css/h5/market/sylive/h5.css b/www/home/css/h5/market/sylive/h5.css new file mode 100644 index 00000000..984e7282 --- /dev/null +++ b/www/home/css/h5/market/sylive/h5.css @@ -0,0 +1,7 @@ +@charset "UTF-8";/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{font-size:2em;margin:.67em 0}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-.267vw}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}template{display:none}[hidden]{display:none}/*! + * animate.css -https://daneden.github.io/animate.css/ + * Version - 3.7.2 + * Licensed under the MIT license - http://opensource.org/licenses/MIT + * + * Copyright (c) 2019 Daniel Eden + */@-webkit-keyframes bounce{20%,53%,80%,from,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1);transform:translate3d(0,0,0)}40%,43%{-webkit-animation-timing-function:cubic-bezier(.755,.05,.855,.06);animation-timing-function:cubic-bezier(.755,.05,.855,.06);transform:translate3d(0,-30px,0)}70%{-webkit-animation-timing-function:cubic-bezier(.755,.05,.855,.06);animation-timing-function:cubic-bezier(.755,.05,.855,.06);transform:translate3d(0,-15px,0)}90%{transform:translate3d(0,-4px,0)}}@keyframes bounce{20%,53%,80%,from,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1);transform:translate3d(0,0,0)}40%,43%{-webkit-animation-timing-function:cubic-bezier(.755,.05,.855,.06);animation-timing-function:cubic-bezier(.755,.05,.855,.06);transform:translate3d(0,-30px,0)}70%{-webkit-animation-timing-function:cubic-bezier(.755,.05,.855,.06);animation-timing-function:cubic-bezier(.755,.05,.855,.06);transform:translate3d(0,-15px,0)}90%{transform:translate3d(0,-4px,0)}}.bounce{-webkit-animation-name:bounce;animation-name:bounce;transform-origin:center bottom}@-webkit-keyframes flash{50%,from,to{opacity:1}25%,75%{opacity:0}}@keyframes flash{50%,from,to{opacity:1}25%,75%{opacity:0}}.flash{-webkit-animation-name:flash;animation-name:flash}@-webkit-keyframes pulse{from{transform:scale3d(1,1,1)}50%{transform:scale3d(1.05,1.05,1.05)}to{transform:scale3d(1,1,1)}}@keyframes pulse{from{transform:scale3d(1,1,1)}50%{transform:scale3d(1.05,1.05,1.05)}to{transform:scale3d(1,1,1)}}.pulse{-webkit-animation-name:pulse;animation-name:pulse}@-webkit-keyframes rubberBand{from{transform:scale3d(1,1,1)}30%{transform:scale3d(1.25,.75,1)}40%{transform:scale3d(.75,1.25,1)}50%{transform:scale3d(1.15,.85,1)}65%{transform:scale3d(.95,1.05,1)}75%{transform:scale3d(1.05,.95,1)}to{transform:scale3d(1,1,1)}}@keyframes rubberBand{from{transform:scale3d(1,1,1)}30%{transform:scale3d(1.25,.75,1)}40%{transform:scale3d(.75,1.25,1)}50%{transform:scale3d(1.15,.85,1)}65%{transform:scale3d(.95,1.05,1)}75%{transform:scale3d(1.05,.95,1)}to{transform:scale3d(1,1,1)}}.rubberBand{-webkit-animation-name:rubberBand;animation-name:rubberBand}@-webkit-keyframes shake{from,to{transform:translate3d(0,0,0)}10%,30%,50%,70%,90%{transform:translate3d(-10px,0,0)}20%,40%,60%,80%{transform:translate3d(10px,0,0)}}@keyframes shake{from,to{transform:translate3d(0,0,0)}10%,30%,50%,70%,90%{transform:translate3d(-10px,0,0)}20%,40%,60%,80%{transform:translate3d(10px,0,0)}}.shake{-webkit-animation-name:shake;animation-name:shake}@-webkit-keyframes headShake{0%{transform:translateX(0)}6.5%{transform:translateX(-6px) rotateY(-9deg)}18.5%{transform:translateX(5px) rotateY(7deg)}31.5%{transform:translateX(-3px) rotateY(-5deg)}43.5%{transform:translateX(2px) rotateY(3deg)}50%{transform:translateX(0)}}@keyframes headShake{0%{transform:translateX(0)}6.5%{transform:translateX(-6px) rotateY(-9deg)}18.5%{transform:translateX(5px) rotateY(7deg)}31.5%{transform:translateX(-3px) rotateY(-5deg)}43.5%{transform:translateX(2px) rotateY(3deg)}50%{transform:translateX(0)}}.headShake{-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out;-webkit-animation-name:headShake;animation-name:headShake}@-webkit-keyframes swing{20%{transform:rotate3d(0,0,1,15deg)}40%{transform:rotate3d(0,0,1,-10deg)}60%{transform:rotate3d(0,0,1,5deg)}80%{transform:rotate3d(0,0,1,-5deg)}to{transform:rotate3d(0,0,1,0deg)}}@keyframes swing{20%{transform:rotate3d(0,0,1,15deg)}40%{transform:rotate3d(0,0,1,-10deg)}60%{transform:rotate3d(0,0,1,5deg)}80%{transform:rotate3d(0,0,1,-5deg)}to{transform:rotate3d(0,0,1,0deg)}}.swing{transform-origin:top center;-webkit-animation-name:swing;animation-name:swing}@-webkit-keyframes tada{from{transform:scale3d(1,1,1)}10%,20%{transform:scale3d(.9,.9,.9) rotate3d(0,0,1,-3deg)}30%,50%,70%,90%{transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,3deg)}40%,60%,80%{transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,-3deg)}to{transform:scale3d(1,1,1)}}@keyframes tada{from{transform:scale3d(1,1,1)}10%,20%{transform:scale3d(.9,.9,.9) rotate3d(0,0,1,-3deg)}30%,50%,70%,90%{transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,3deg)}40%,60%,80%{transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,-3deg)}to{transform:scale3d(1,1,1)}}.tada{-webkit-animation-name:tada;animation-name:tada}@-webkit-keyframes wobble{from{transform:translate3d(0,0,0)}15%{transform:translate3d(-25%,0,0) rotate3d(0,0,1,-5deg)}30%{transform:translate3d(20%,0,0) rotate3d(0,0,1,3deg)}45%{transform:translate3d(-15%,0,0) rotate3d(0,0,1,-3deg)}60%{transform:translate3d(10%,0,0) rotate3d(0,0,1,2deg)}75%{transform:translate3d(-5%,0,0) rotate3d(0,0,1,-1deg)}to{transform:translate3d(0,0,0)}}@keyframes wobble{from{transform:translate3d(0,0,0)}15%{transform:translate3d(-25%,0,0) rotate3d(0,0,1,-5deg)}30%{transform:translate3d(20%,0,0) rotate3d(0,0,1,3deg)}45%{transform:translate3d(-15%,0,0) rotate3d(0,0,1,-3deg)}60%{transform:translate3d(10%,0,0) rotate3d(0,0,1,2deg)}75%{transform:translate3d(-5%,0,0) rotate3d(0,0,1,-1deg)}to{transform:translate3d(0,0,0)}}.wobble{-webkit-animation-name:wobble;animation-name:wobble}@-webkit-keyframes jello{11.1%,from,to{transform:translate3d(0,0,0)}22.2%{transform:skewX(-12.5deg) skewY(-12.5deg)}33.3%{transform:skewX(6.25deg) skewY(6.25deg)}44.4%{transform:skewX(-3.125deg) skewY(-3.125deg)}55.5%{transform:skewX(1.5625deg) skewY(1.5625deg)}66.6%{transform:skewX(-.78125deg) skewY(-.78125deg)}77.7%{transform:skewX(.390625deg) skewY(.390625deg)}88.8%{transform:skewX(-.1953125deg) skewY(-.1953125deg)}}@keyframes jello{11.1%,from,to{transform:translate3d(0,0,0)}22.2%{transform:skewX(-12.5deg) skewY(-12.5deg)}33.3%{transform:skewX(6.25deg) skewY(6.25deg)}44.4%{transform:skewX(-3.125deg) skewY(-3.125deg)}55.5%{transform:skewX(1.5625deg) skewY(1.5625deg)}66.6%{transform:skewX(-.78125deg) skewY(-.78125deg)}77.7%{transform:skewX(.390625deg) skewY(.390625deg)}88.8%{transform:skewX(-.1953125deg) skewY(-.1953125deg)}}.jello{-webkit-animation-name:jello;animation-name:jello;transform-origin:center}@-webkit-keyframes heartBeat{0%{transform:scale(1)}14%{transform:scale(1.3)}28%{transform:scale(1)}42%{transform:scale(1.3)}70%{transform:scale(1)}}@keyframes heartBeat{0%{transform:scale(1)}14%{transform:scale(1.3)}28%{transform:scale(1)}42%{transform:scale(1.3)}70%{transform:scale(1)}}.heartBeat{-webkit-animation-name:heartBeat;animation-name:heartBeat;-webkit-animation-duration:1.3s;animation-duration:1.3s;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}@-webkit-keyframes bounceIn{20%,40%,60%,80%,from,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;transform:scale3d(.3,.3,.3)}20%{transform:scale3d(1.1,1.1,1.1)}40%{transform:scale3d(.9,.9,.9)}60%{opacity:1;transform:scale3d(1.03,1.03,1.03)}80%{transform:scale3d(.97,.97,.97)}to{opacity:1;transform:scale3d(1,1,1)}}@keyframes bounceIn{20%,40%,60%,80%,from,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;transform:scale3d(.3,.3,.3)}20%{transform:scale3d(1.1,1.1,1.1)}40%{transform:scale3d(.9,.9,.9)}60%{opacity:1;transform:scale3d(1.03,1.03,1.03)}80%{transform:scale3d(.97,.97,.97)}to{opacity:1;transform:scale3d(1,1,1)}}.bounceIn{-webkit-animation-duration:.75s;animation-duration:.75s;-webkit-animation-name:bounceIn;animation-name:bounceIn}@-webkit-keyframes bounceInDown{60%,75%,90%,from,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;transform:translate3d(0,-3000px,0)}60%{opacity:1;transform:translate3d(0,25px,0)}75%{transform:translate3d(0,-10px,0)}90%{transform:translate3d(0,5px,0)}to{transform:translate3d(0,0,0)}}@keyframes bounceInDown{60%,75%,90%,from,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;transform:translate3d(0,-3000px,0)}60%{opacity:1;transform:translate3d(0,25px,0)}75%{transform:translate3d(0,-10px,0)}90%{transform:translate3d(0,5px,0)}to{transform:translate3d(0,0,0)}}.bounceInDown{-webkit-animation-name:bounceInDown;animation-name:bounceInDown}@-webkit-keyframes bounceInLeft{60%,75%,90%,from,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;transform:translate3d(-3000px,0,0)}60%{opacity:1;transform:translate3d(25px,0,0)}75%{transform:translate3d(-10px,0,0)}90%{transform:translate3d(5px,0,0)}to{transform:translate3d(0,0,0)}}@keyframes bounceInLeft{60%,75%,90%,from,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;transform:translate3d(-3000px,0,0)}60%{opacity:1;transform:translate3d(25px,0,0)}75%{transform:translate3d(-10px,0,0)}90%{transform:translate3d(5px,0,0)}to{transform:translate3d(0,0,0)}}.bounceInLeft{-webkit-animation-name:bounceInLeft;animation-name:bounceInLeft}@-webkit-keyframes bounceInRight{60%,75%,90%,from,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}from{opacity:0;transform:translate3d(3000px,0,0)}60%{opacity:1;transform:translate3d(-25px,0,0)}75%{transform:translate3d(10px,0,0)}90%{transform:translate3d(-5px,0,0)}to{transform:translate3d(0,0,0)}}@keyframes bounceInRight{60%,75%,90%,from,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}from{opacity:0;transform:translate3d(3000px,0,0)}60%{opacity:1;transform:translate3d(-25px,0,0)}75%{transform:translate3d(10px,0,0)}90%{transform:translate3d(-5px,0,0)}to{transform:translate3d(0,0,0)}}.bounceInRight{-webkit-animation-name:bounceInRight;animation-name:bounceInRight}@-webkit-keyframes bounceInUp{60%,75%,90%,from,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}from{opacity:0;transform:translate3d(0,3000px,0)}60%{opacity:1;transform:translate3d(0,-20px,0)}75%{transform:translate3d(0,10px,0)}90%{transform:translate3d(0,-5px,0)}to{transform:translate3d(0,0,0)}}@keyframes bounceInUp{60%,75%,90%,from,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}from{opacity:0;transform:translate3d(0,3000px,0)}60%{opacity:1;transform:translate3d(0,-20px,0)}75%{transform:translate3d(0,10px,0)}90%{transform:translate3d(0,-5px,0)}to{transform:translate3d(0,0,0)}}.bounceInUp{-webkit-animation-name:bounceInUp;animation-name:bounceInUp}@-webkit-keyframes bounceOut{20%{transform:scale3d(.9,.9,.9)}50%,55%{opacity:1;transform:scale3d(1.1,1.1,1.1)}to{opacity:0;transform:scale3d(.3,.3,.3)}}@keyframes bounceOut{20%{transform:scale3d(.9,.9,.9)}50%,55%{opacity:1;transform:scale3d(1.1,1.1,1.1)}to{opacity:0;transform:scale3d(.3,.3,.3)}}.bounceOut{-webkit-animation-duration:.75s;animation-duration:.75s;-webkit-animation-name:bounceOut;animation-name:bounceOut}@-webkit-keyframes bounceOutDown{20%{transform:translate3d(0,10px,0)}40%,45%{opacity:1;transform:translate3d(0,-20px,0)}to{opacity:0;transform:translate3d(0,2000px,0)}}@keyframes bounceOutDown{20%{transform:translate3d(0,10px,0)}40%,45%{opacity:1;transform:translate3d(0,-20px,0)}to{opacity:0;transform:translate3d(0,2000px,0)}}.bounceOutDown{-webkit-animation-name:bounceOutDown;animation-name:bounceOutDown}@-webkit-keyframes bounceOutLeft{20%{opacity:1;transform:translate3d(20px,0,0)}to{opacity:0;transform:translate3d(-2000px,0,0)}}@keyframes bounceOutLeft{20%{opacity:1;transform:translate3d(20px,0,0)}to{opacity:0;transform:translate3d(-2000px,0,0)}}.bounceOutLeft{-webkit-animation-name:bounceOutLeft;animation-name:bounceOutLeft}@-webkit-keyframes bounceOutRight{20%{opacity:1;transform:translate3d(-20px,0,0)}to{opacity:0;transform:translate3d(2000px,0,0)}}@keyframes bounceOutRight{20%{opacity:1;transform:translate3d(-20px,0,0)}to{opacity:0;transform:translate3d(2000px,0,0)}}.bounceOutRight{-webkit-animation-name:bounceOutRight;animation-name:bounceOutRight}@-webkit-keyframes bounceOutUp{20%{transform:translate3d(0,-10px,0)}40%,45%{opacity:1;transform:translate3d(0,20px,0)}to{opacity:0;transform:translate3d(0,-2000px,0)}}@keyframes bounceOutUp{20%{transform:translate3d(0,-10px,0)}40%,45%{opacity:1;transform:translate3d(0,20px,0)}to{opacity:0;transform:translate3d(0,-2000px,0)}}.bounceOutUp{-webkit-animation-name:bounceOutUp;animation-name:bounceOutUp}@-webkit-keyframes fadeIn{from{opacity:0}to{opacity:1}}@keyframes fadeIn{from{opacity:0}to{opacity:1}}.fadeIn{-webkit-animation-name:fadeIn;animation-name:fadeIn}@-webkit-keyframes fadeInDown{from{opacity:0;transform:translate3d(0,-100%,0)}to{opacity:1;transform:translate3d(0,0,0)}}@keyframes fadeInDown{from{opacity:0;transform:translate3d(0,-100%,0)}to{opacity:1;transform:translate3d(0,0,0)}}.fadeInDown{-webkit-animation-name:fadeInDown;animation-name:fadeInDown}@-webkit-keyframes fadeInDownBig{from{opacity:0;transform:translate3d(0,-2000px,0)}to{opacity:1;transform:translate3d(0,0,0)}}@keyframes fadeInDownBig{from{opacity:0;transform:translate3d(0,-2000px,0)}to{opacity:1;transform:translate3d(0,0,0)}}.fadeInDownBig{-webkit-animation-name:fadeInDownBig;animation-name:fadeInDownBig}@-webkit-keyframes fadeInLeft{from{opacity:0;transform:translate3d(-100%,0,0)}to{opacity:1;transform:translate3d(0,0,0)}}@keyframes fadeInLeft{from{opacity:0;transform:translate3d(-100%,0,0)}to{opacity:1;transform:translate3d(0,0,0)}}.fadeInLeft{-webkit-animation-name:fadeInLeft;animation-name:fadeInLeft}@-webkit-keyframes fadeInLeftBig{from{opacity:0;transform:translate3d(-2000px,0,0)}to{opacity:1;transform:translate3d(0,0,0)}}@keyframes fadeInLeftBig{from{opacity:0;transform:translate3d(-2000px,0,0)}to{opacity:1;transform:translate3d(0,0,0)}}.fadeInLeftBig{-webkit-animation-name:fadeInLeftBig;animation-name:fadeInLeftBig}@-webkit-keyframes fadeInRight{from{opacity:0;transform:translate3d(100%,0,0)}to{opacity:1;transform:translate3d(0,0,0)}}@keyframes fadeInRight{from{opacity:0;transform:translate3d(100%,0,0)}to{opacity:1;transform:translate3d(0,0,0)}}.fadeInRight{-webkit-animation-name:fadeInRight;animation-name:fadeInRight}@-webkit-keyframes fadeInRightBig{from{opacity:0;transform:translate3d(2000px,0,0)}to{opacity:1;transform:translate3d(0,0,0)}}@keyframes fadeInRightBig{from{opacity:0;transform:translate3d(2000px,0,0)}to{opacity:1;transform:translate3d(0,0,0)}}.fadeInRightBig{-webkit-animation-name:fadeInRightBig;animation-name:fadeInRightBig}@-webkit-keyframes fadeInUp{from{opacity:0;transform:translate3d(0,100%,0)}to{opacity:1;transform:translate3d(0,0,0)}}@keyframes fadeInUp{from{opacity:0;transform:translate3d(0,100%,0)}to{opacity:1;transform:translate3d(0,0,0)}}.fadeInUp{-webkit-animation-name:fadeInUp;animation-name:fadeInUp}@-webkit-keyframes fadeInUpBig{from{opacity:0;transform:translate3d(0,2000px,0)}to{opacity:1;transform:translate3d(0,0,0)}}@keyframes fadeInUpBig{from{opacity:0;transform:translate3d(0,2000px,0)}to{opacity:1;transform:translate3d(0,0,0)}}.fadeInUpBig{-webkit-animation-name:fadeInUpBig;animation-name:fadeInUpBig}@-webkit-keyframes fadeOut{from{opacity:1}to{opacity:0}}@keyframes fadeOut{from{opacity:1}to{opacity:0}}.fadeOut{-webkit-animation-name:fadeOut;animation-name:fadeOut}@-webkit-keyframes fadeOutDown{from{opacity:1}to{opacity:0;transform:translate3d(0,100%,0)}}@keyframes fadeOutDown{from{opacity:1}to{opacity:0;transform:translate3d(0,100%,0)}}.fadeOutDown{-webkit-animation-name:fadeOutDown;animation-name:fadeOutDown}@-webkit-keyframes fadeOutDownBig{from{opacity:1}to{opacity:0;transform:translate3d(0,2000px,0)}}@keyframes fadeOutDownBig{from{opacity:1}to{opacity:0;transform:translate3d(0,2000px,0)}}.fadeOutDownBig{-webkit-animation-name:fadeOutDownBig;animation-name:fadeOutDownBig}@-webkit-keyframes fadeOutLeft{from{opacity:1}to{opacity:0;transform:translate3d(-100%,0,0)}}@keyframes fadeOutLeft{from{opacity:1}to{opacity:0;transform:translate3d(-100%,0,0)}}.fadeOutLeft{-webkit-animation-name:fadeOutLeft;animation-name:fadeOutLeft}@-webkit-keyframes fadeOutLeftBig{from{opacity:1}to{opacity:0;transform:translate3d(-2000px,0,0)}}@keyframes fadeOutLeftBig{from{opacity:1}to{opacity:0;transform:translate3d(-2000px,0,0)}}.fadeOutLeftBig{-webkit-animation-name:fadeOutLeftBig;animation-name:fadeOutLeftBig}@-webkit-keyframes fadeOutRight{from{opacity:1}to{opacity:0;transform:translate3d(100%,0,0)}}@keyframes fadeOutRight{from{opacity:1}to{opacity:0;transform:translate3d(100%,0,0)}}.fadeOutRight{-webkit-animation-name:fadeOutRight;animation-name:fadeOutRight}@-webkit-keyframes fadeOutRightBig{from{opacity:1}to{opacity:0;transform:translate3d(2000px,0,0)}}@keyframes fadeOutRightBig{from{opacity:1}to{opacity:0;transform:translate3d(2000px,0,0)}}.fadeOutRightBig{-webkit-animation-name:fadeOutRightBig;animation-name:fadeOutRightBig}@-webkit-keyframes fadeOutUp{from{opacity:1}to{opacity:.2;transform:translate3d(0,-100%,0)}}@keyframes fadeOutUp{from{opacity:1}to{opacity:.2;transform:translate3d(0,-100%,0)}}.fadeOutUp{-webkit-animation-name:fadeOutUp;animation-name:fadeOutUp}@-webkit-keyframes fadeOutUpBig{from{opacity:1}to{opacity:0;transform:translate3d(0,-2000px,0)}}@keyframes fadeOutUpBig{from{opacity:1}to{opacity:0;transform:translate3d(0,-2000px,0)}}.fadeOutUpBig{-webkit-animation-name:fadeOutUpBig;animation-name:fadeOutUpBig}@-webkit-keyframes flip{from{transform:perspective(400px) scale3d(1,1,1) translate3d(0,0,0) rotate3d(0,1,0,-360deg);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}40%{transform:perspective(400px) scale3d(1,1,1) translate3d(0,0,150px) rotate3d(0,1,0,-190deg);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}50%{transform:perspective(400px) scale3d(1,1,1) translate3d(0,0,150px) rotate3d(0,1,0,-170deg);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}80%{transform:perspective(400px) scale3d(.95,.95,.95) translate3d(0,0,0) rotate3d(0,1,0,0deg);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}to{transform:perspective(400px) scale3d(1,1,1) translate3d(0,0,0) rotate3d(0,1,0,0deg);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}}@keyframes flip{from{transform:perspective(400px) scale3d(1,1,1) translate3d(0,0,0) rotate3d(0,1,0,-360deg);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}40%{transform:perspective(400px) scale3d(1,1,1) translate3d(0,0,150px) rotate3d(0,1,0,-190deg);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}50%{transform:perspective(400px) scale3d(1,1,1) translate3d(0,0,150px) rotate3d(0,1,0,-170deg);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}80%{transform:perspective(400px) scale3d(.95,.95,.95) translate3d(0,0,0) rotate3d(0,1,0,0deg);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}to{transform:perspective(400px) scale3d(1,1,1) translate3d(0,0,0) rotate3d(0,1,0,0deg);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}}.animated.flip{-webkit-backface-visibility:visible;backface-visibility:visible;-webkit-animation-name:flip;animation-name:flip}@-webkit-keyframes flipInX{from{transform:perspective(400px) rotate3d(1,0,0,90deg);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in;opacity:0}40%{transform:perspective(400px) rotate3d(1,0,0,-20deg);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}60%{transform:perspective(400px) rotate3d(1,0,0,10deg);opacity:1}80%{transform:perspective(400px) rotate3d(1,0,0,-5deg)}to{transform:perspective(400px)}}@keyframes flipInX{from{transform:perspective(400px) rotate3d(1,0,0,90deg);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in;opacity:0}40%{transform:perspective(400px) rotate3d(1,0,0,-20deg);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}60%{transform:perspective(400px) rotate3d(1,0,0,10deg);opacity:1}80%{transform:perspective(400px) rotate3d(1,0,0,-5deg)}to{transform:perspective(400px)}}.flipInX{-webkit-backface-visibility:visible!important;backface-visibility:visible!important;-webkit-animation-name:flipInX;animation-name:flipInX}@-webkit-keyframes flipInY{from{transform:perspective(400px) rotate3d(0,1,0,90deg);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in;opacity:0}40%{transform:perspective(400px) rotate3d(0,1,0,-20deg);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}60%{transform:perspective(400px) rotate3d(0,1,0,10deg);opacity:1}80%{transform:perspective(400px) rotate3d(0,1,0,-5deg)}to{transform:perspective(400px)}}@keyframes flipInY{from{transform:perspective(400px) rotate3d(0,1,0,90deg);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in;opacity:0}40%{transform:perspective(400px) rotate3d(0,1,0,-20deg);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}60%{transform:perspective(400px) rotate3d(0,1,0,10deg);opacity:1}80%{transform:perspective(400px) rotate3d(0,1,0,-5deg)}to{transform:perspective(400px)}}.flipInY{-webkit-backface-visibility:visible!important;backface-visibility:visible!important;-webkit-animation-name:flipInY;animation-name:flipInY}@-webkit-keyframes flipOutX{from{transform:perspective(400px)}30%{transform:perspective(400px) rotate3d(1,0,0,-20deg);opacity:1}to{transform:perspective(400px) rotate3d(1,0,0,90deg);opacity:0}}@keyframes flipOutX{from{transform:perspective(400px)}30%{transform:perspective(400px) rotate3d(1,0,0,-20deg);opacity:1}to{transform:perspective(400px) rotate3d(1,0,0,90deg);opacity:0}}.flipOutX{-webkit-animation-duration:.75s;animation-duration:.75s;-webkit-animation-name:flipOutX;animation-name:flipOutX;-webkit-backface-visibility:visible!important;backface-visibility:visible!important}@-webkit-keyframes flipOutY{from{transform:perspective(400px)}30%{transform:perspective(400px) rotate3d(0,1,0,-15deg);opacity:1}to{transform:perspective(400px) rotate3d(0,1,0,90deg);opacity:0}}@keyframes flipOutY{from{transform:perspective(400px)}30%{transform:perspective(400px) rotate3d(0,1,0,-15deg);opacity:1}to{transform:perspective(400px) rotate3d(0,1,0,90deg);opacity:0}}.flipOutY{-webkit-animation-duration:.75s;animation-duration:.75s;-webkit-backface-visibility:visible!important;backface-visibility:visible!important;-webkit-animation-name:flipOutY;animation-name:flipOutY}@-webkit-keyframes lightSpeedIn{from{transform:translate3d(100%,0,0) skewX(-30deg);opacity:0}60%{transform:skewX(20deg);opacity:1}80%{transform:skewX(-5deg)}to{transform:translate3d(0,0,0)}}@keyframes lightSpeedIn{from{transform:translate3d(100%,0,0) skewX(-30deg);opacity:0}60%{transform:skewX(20deg);opacity:1}80%{transform:skewX(-5deg)}to{transform:translate3d(0,0,0)}}.lightSpeedIn{-webkit-animation-name:lightSpeedIn;animation-name:lightSpeedIn;-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}@-webkit-keyframes lightSpeedOut{from{opacity:1}to{transform:translate3d(100%,0,0) skewX(30deg);opacity:0}}@keyframes lightSpeedOut{from{opacity:1}to{transform:translate3d(100%,0,0) skewX(30deg);opacity:0}}.lightSpeedOut{-webkit-animation-name:lightSpeedOut;animation-name:lightSpeedOut;-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}@-webkit-keyframes rotateIn{from{transform-origin:center;transform:rotate3d(0,0,1,-200deg);opacity:0}to{transform-origin:center;transform:translate3d(0,0,0);opacity:1}}@keyframes rotateIn{from{transform-origin:center;transform:rotate3d(0,0,1,-200deg);opacity:0}to{transform-origin:center;transform:translate3d(0,0,0);opacity:1}}.rotateIn{-webkit-animation-name:rotateIn;animation-name:rotateIn}@-webkit-keyframes rotateInDownLeft{from{transform-origin:left bottom;transform:rotate3d(0,0,1,-45deg);opacity:0}to{transform-origin:left bottom;transform:translate3d(0,0,0);opacity:1}}@keyframes rotateInDownLeft{from{transform-origin:left bottom;transform:rotate3d(0,0,1,-45deg);opacity:0}to{transform-origin:left bottom;transform:translate3d(0,0,0);opacity:1}}.rotateInDownLeft{-webkit-animation-name:rotateInDownLeft;animation-name:rotateInDownLeft}@-webkit-keyframes rotateInDownRight{from{transform-origin:right bottom;transform:rotate3d(0,0,1,45deg);opacity:0}to{transform-origin:right bottom;transform:translate3d(0,0,0);opacity:1}}@keyframes rotateInDownRight{from{transform-origin:right bottom;transform:rotate3d(0,0,1,45deg);opacity:0}to{transform-origin:right bottom;transform:translate3d(0,0,0);opacity:1}}.rotateInDownRight{-webkit-animation-name:rotateInDownRight;animation-name:rotateInDownRight}@-webkit-keyframes rotateInUpLeft{from{transform-origin:left bottom;transform:rotate3d(0,0,1,45deg);opacity:0}to{transform-origin:left bottom;transform:translate3d(0,0,0);opacity:1}}@keyframes rotateInUpLeft{from{transform-origin:left bottom;transform:rotate3d(0,0,1,45deg);opacity:0}to{transform-origin:left bottom;transform:translate3d(0,0,0);opacity:1}}.rotateInUpLeft{-webkit-animation-name:rotateInUpLeft;animation-name:rotateInUpLeft}@-webkit-keyframes rotateInUpRight{from{transform-origin:right bottom;transform:rotate3d(0,0,1,-90deg);opacity:0}to{transform-origin:right bottom;transform:translate3d(0,0,0);opacity:1}}@keyframes rotateInUpRight{from{transform-origin:right bottom;transform:rotate3d(0,0,1,-90deg);opacity:0}to{transform-origin:right bottom;transform:translate3d(0,0,0);opacity:1}}.rotateInUpRight{-webkit-animation-name:rotateInUpRight;animation-name:rotateInUpRight}@-webkit-keyframes rotateOut{from{transform-origin:center;opacity:1}to{transform-origin:center;transform:rotate3d(0,0,1,200deg);opacity:0}}@keyframes rotateOut{from{transform-origin:center;opacity:1}to{transform-origin:center;transform:rotate3d(0,0,1,200deg);opacity:0}}.rotateOut{-webkit-animation-name:rotateOut;animation-name:rotateOut}@-webkit-keyframes rotateOutDownLeft{from{transform-origin:left bottom;opacity:1}to{transform-origin:left bottom;transform:rotate3d(0,0,1,45deg);opacity:0}}@keyframes rotateOutDownLeft{from{transform-origin:left bottom;opacity:1}to{transform-origin:left bottom;transform:rotate3d(0,0,1,45deg);opacity:0}}.rotateOutDownLeft{-webkit-animation-name:rotateOutDownLeft;animation-name:rotateOutDownLeft}@-webkit-keyframes rotateOutDownRight{from{transform-origin:right bottom;opacity:1}to{transform-origin:right bottom;transform:rotate3d(0,0,1,-45deg);opacity:0}}@keyframes rotateOutDownRight{from{transform-origin:right bottom;opacity:1}to{transform-origin:right bottom;transform:rotate3d(0,0,1,-45deg);opacity:0}}.rotateOutDownRight{-webkit-animation-name:rotateOutDownRight;animation-name:rotateOutDownRight}@-webkit-keyframes rotateOutUpLeft{from{transform-origin:left bottom;opacity:1}to{transform-origin:left bottom;transform:rotate3d(0,0,1,-45deg);opacity:0}}@keyframes rotateOutUpLeft{from{transform-origin:left bottom;opacity:1}to{transform-origin:left bottom;transform:rotate3d(0,0,1,-45deg);opacity:0}}.rotateOutUpLeft{-webkit-animation-name:rotateOutUpLeft;animation-name:rotateOutUpLeft}@-webkit-keyframes rotateOutUpRight{from{transform-origin:right bottom;opacity:1}to{transform-origin:right bottom;transform:rotate3d(0,0,1,90deg);opacity:0}}@keyframes rotateOutUpRight{from{transform-origin:right bottom;opacity:1}to{transform-origin:right bottom;transform:rotate3d(0,0,1,90deg);opacity:0}}.rotateOutUpRight{-webkit-animation-name:rotateOutUpRight;animation-name:rotateOutUpRight}@-webkit-keyframes hinge{0%{transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}20%,60%{transform:rotate3d(0,0,1,80deg);transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}40%,80%{transform:rotate3d(0,0,1,60deg);transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out;opacity:1}to{transform:translate3d(0,700px,0);opacity:0}}@keyframes hinge{0%{transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}20%,60%{transform:rotate3d(0,0,1,80deg);transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}40%,80%{transform:rotate3d(0,0,1,60deg);transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out;opacity:1}to{transform:translate3d(0,700px,0);opacity:0}}.hinge{-webkit-animation-duration:2s;animation-duration:2s;-webkit-animation-name:hinge;animation-name:hinge}@-webkit-keyframes jackInTheBox{from{opacity:0;transform:scale(.1) rotate(30deg);transform-origin:center bottom}50%{transform:rotate(-10deg)}70%{transform:rotate(3deg)}to{opacity:1;transform:scale(1)}}@keyframes jackInTheBox{from{opacity:0;transform:scale(.1) rotate(30deg);transform-origin:center bottom}50%{transform:rotate(-10deg)}70%{transform:rotate(3deg)}to{opacity:1;transform:scale(1)}}.jackInTheBox{-webkit-animation-name:jackInTheBox;animation-name:jackInTheBox}@-webkit-keyframes rollIn{from{opacity:0;transform:translate3d(-100%,0,0) rotate3d(0,0,1,-120deg)}to{opacity:1;transform:translate3d(0,0,0)}}@keyframes rollIn{from{opacity:0;transform:translate3d(-100%,0,0) rotate3d(0,0,1,-120deg)}to{opacity:1;transform:translate3d(0,0,0)}}.rollIn{-webkit-animation-name:rollIn;animation-name:rollIn}@-webkit-keyframes rollOut{from{opacity:1}to{opacity:0;transform:translate3d(100%,0,0) rotate3d(0,0,1,120deg)}}@keyframes rollOut{from{opacity:1}to{opacity:0;transform:translate3d(100%,0,0) rotate3d(0,0,1,120deg)}}.rollOut{-webkit-animation-name:rollOut;animation-name:rollOut}@-webkit-keyframes zoomIn{from{opacity:0;transform:scale3d(.3,.3,.3)}50%{opacity:1}}@keyframes zoomIn{from{opacity:0;transform:scale3d(.3,.3,.3)}50%{opacity:1}}.zoomIn{-webkit-animation-name:zoomIn;animation-name:zoomIn}@-webkit-keyframes zoomInDown{from{opacity:0;transform:scale3d(.1,.1,.1) translate3d(0,-1000px,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}60%{opacity:1;transform:scale3d(.475,.475,.475) translate3d(0,60px,0);-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}@keyframes zoomInDown{from{opacity:0;transform:scale3d(.1,.1,.1) translate3d(0,-1000px,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}60%{opacity:1;transform:scale3d(.475,.475,.475) translate3d(0,60px,0);-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}.zoomInDown{-webkit-animation-name:zoomInDown;animation-name:zoomInDown}@-webkit-keyframes zoomInLeft{from{opacity:0;transform:scale3d(.1,.1,.1) translate3d(-1000px,0,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}60%{opacity:1;transform:scale3d(.475,.475,.475) translate3d(10px,0,0);-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}@keyframes zoomInLeft{from{opacity:0;transform:scale3d(.1,.1,.1) translate3d(-1000px,0,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}60%{opacity:1;transform:scale3d(.475,.475,.475) translate3d(10px,0,0);-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}.zoomInLeft{-webkit-animation-name:zoomInLeft;animation-name:zoomInLeft}@-webkit-keyframes zoomInRight{from{opacity:0;transform:scale3d(.1,.1,.1) translate3d(1000px,0,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}60%{opacity:1;transform:scale3d(.475,.475,.475) translate3d(-10px,0,0);-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}@keyframes zoomInRight{from{opacity:0;transform:scale3d(.1,.1,.1) translate3d(1000px,0,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}60%{opacity:1;transform:scale3d(.475,.475,.475) translate3d(-10px,0,0);-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}.zoomInRight{-webkit-animation-name:zoomInRight;animation-name:zoomInRight}@-webkit-keyframes zoomInUp{from{opacity:0;transform:scale3d(.1,.1,.1) translate3d(0,1000px,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}60%{opacity:1;transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}@keyframes zoomInUp{from{opacity:0;transform:scale3d(.1,.1,.1) translate3d(0,1000px,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}60%{opacity:1;transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}.zoomInUp{-webkit-animation-name:zoomInUp;animation-name:zoomInUp}@-webkit-keyframes zoomOut{from{opacity:1}50%{opacity:0;transform:scale3d(.3,.3,.3)}to{opacity:0}}@keyframes zoomOut{from{opacity:1}50%{opacity:0;transform:scale3d(.3,.3,.3)}to{opacity:0}}.zoomOut{-webkit-animation-name:zoomOut;animation-name:zoomOut}@-webkit-keyframes zoomOutDown{40%{opacity:1;transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}to{opacity:0;transform:scale3d(.1,.1,.1) translate3d(0,2000px,0);transform-origin:center bottom;-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}@keyframes zoomOutDown{40%{opacity:1;transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}to{opacity:0;transform:scale3d(.1,.1,.1) translate3d(0,2000px,0);transform-origin:center bottom;-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}.zoomOutDown{-webkit-animation-name:zoomOutDown;animation-name:zoomOutDown}@-webkit-keyframes zoomOutLeft{40%{opacity:1;transform:scale3d(.475,.475,.475) translate3d(42px,0,0)}to{opacity:0;transform:scale(.1) translate3d(-2000px,0,0);transform-origin:left center}}@keyframes zoomOutLeft{40%{opacity:1;transform:scale3d(.475,.475,.475) translate3d(42px,0,0)}to{opacity:0;transform:scale(.1) translate3d(-2000px,0,0);transform-origin:left center}}.zoomOutLeft{-webkit-animation-name:zoomOutLeft;animation-name:zoomOutLeft}@-webkit-keyframes zoomOutRight{40%{opacity:1;transform:scale3d(.475,.475,.475) translate3d(-42px,0,0)}to{opacity:0;transform:scale(.1) translate3d(2000px,0,0);transform-origin:right center}}@keyframes zoomOutRight{40%{opacity:1;transform:scale3d(.475,.475,.475) translate3d(-42px,0,0)}to{opacity:0;transform:scale(.1) translate3d(2000px,0,0);transform-origin:right center}}.zoomOutRight{-webkit-animation-name:zoomOutRight;animation-name:zoomOutRight}@-webkit-keyframes zoomOutUp{40%{opacity:1;transform:scale3d(.475,.475,.475) translate3d(0,60px,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}to{opacity:0;transform:scale3d(.1,.1,.1) translate3d(0,-2000px,0);transform-origin:center bottom;-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}@keyframes zoomOutUp{40%{opacity:1;transform:scale3d(.475,.475,.475) translate3d(0,60px,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}to{opacity:0;transform:scale3d(.1,.1,.1) translate3d(0,-2000px,0);transform-origin:center bottom;-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}.zoomOutUp{-webkit-animation-name:zoomOutUp;animation-name:zoomOutUp}@-webkit-keyframes slideInDown{from{transform:translate3d(0,-100%,0);visibility:visible}to{transform:translate3d(0,0,0)}}@keyframes slideInDown{from{transform:translate3d(0,-100%,0);visibility:visible}to{transform:translate3d(0,0,0)}}.slideInDown{-webkit-animation-name:slideInDown;animation-name:slideInDown}@-webkit-keyframes slideInLeft{from{transform:translate3d(-100%,0,0);visibility:visible}to{transform:translate3d(0,0,0)}}@keyframes slideInLeft{from{transform:translate3d(-100%,0,0);visibility:visible}to{transform:translate3d(0,0,0)}}.slideInLeft{-webkit-animation-name:slideInLeft;animation-name:slideInLeft}@-webkit-keyframes slideInRight{from{transform:translate3d(100%,0,0);visibility:visible}to{transform:translate3d(0,0,0)}}@keyframes slideInRight{from{transform:translate3d(100%,0,0);visibility:visible}to{transform:translate3d(0,0,0)}}.slideInRight{-webkit-animation-name:slideInRight;animation-name:slideInRight}@-webkit-keyframes slideInUp{from{transform:translate3d(0,100%,0);visibility:visible}to{transform:translate3d(0,0,0)}}@keyframes slideInUp{from{transform:translate3d(0,100%,0);visibility:visible}to{transform:translate3d(0,0,0)}}.slideInUp{-webkit-animation-name:slideInUp;animation-name:slideInUp}@-webkit-keyframes slideOutDown{from{transform:translate3d(0,0,0)}to{visibility:hidden;transform:translate3d(0,100%,0)}}@keyframes slideOutDown{from{transform:translate3d(0,0,0)}to{visibility:hidden;transform:translate3d(0,100%,0)}}.slideOutDown{-webkit-animation-name:slideOutDown;animation-name:slideOutDown}@-webkit-keyframes slideOutLeft{from{transform:translate3d(0,0,0)}to{visibility:hidden;transform:translate3d(-100%,0,0)}}@keyframes slideOutLeft{from{transform:translate3d(0,0,0)}to{visibility:hidden;transform:translate3d(-100%,0,0)}}.slideOutLeft{-webkit-animation-name:slideOutLeft;animation-name:slideOutLeft}@-webkit-keyframes slideOutRight{from{transform:translate3d(0,0,0)}to{visibility:hidden;transform:translate3d(100%,0,0)}}@keyframes slideOutRight{from{transform:translate3d(0,0,0)}to{visibility:hidden;transform:translate3d(100%,0,0)}}.slideOutRight{-webkit-animation-name:slideOutRight;animation-name:slideOutRight}@-webkit-keyframes slideOutUp{from{transform:translate3d(0,0,0)}to{visibility:hidden;transform:translate3d(0,-100%,0)}}@keyframes slideOutUp{from{transform:translate3d(0,0,0)}to{visibility:hidden;transform:translate3d(0,-100%,0)}}.slideOutUp{-webkit-animation-name:slideOutUp;animation-name:slideOutUp}.animated{-webkit-animation-duration:1s;animation-duration:1s;-webkit-animation-fill-mode:both;animation-fill-mode:both}.animated.infinite{-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite}.animated.delay-1s{-webkit-animation-delay:1s;animation-delay:1s}.animated.delay-2s{-webkit-animation-delay:2s;animation-delay:2s}.animated.delay-3s{-webkit-animation-delay:3s;animation-delay:3s}.animated.delay-4s{-webkit-animation-delay:4s;animation-delay:4s}.animated.delay-5s{-webkit-animation-delay:5s;animation-delay:5s}.animated.fast{-webkit-animation-duration:.8s;animation-duration:.8s}.animated.faster{-webkit-animation-duration:.5s;animation-duration:.5s}.animated.slow{-webkit-animation-duration:2s;animation-duration:2s}.animated.slower{-webkit-animation-duration:3s;animation-duration:3s}@media (print),(prefers-reduced-motion:reduce){.animated{-webkit-animation-duration:1ms!important;animation-duration:1ms!important;transition-duration:1ms!important;-webkit-animation-iteration-count:1!important;animation-iteration-count:1!important}}.bds-1-ddd{border:#ddd 1px solid}.bds-4-ddd{border:#ddd .533vw solid}.bds-1-fff{border:#fff 1px solid}.bts-1-ddd{border-top:#ddd 1px solid}.bls-1-ddd{border-left:#ddd 1px solid}.brs-1-ddd{border-right:#ddd 1px solid}.bbs-1-ddd{border-bottom:#ddd 1px solid}.bds-1-eee{border:#eee 1px solid}.bds-1-eee{border:#eee 1px solid}.bts-1-eee{border-top:#eee 1px solid}.bls-1-eee{border-left:#eee 1px solid}.brs-1-eee{border-right:#eee 1px solid}.bbs-1-eee{border-bottom:#eee 1px solid}.bds-2-ff9393{border:#ff9393 .267vw solid}.bbs-1-aaa{border-bottom:#aaa 1px solid}.bds-1-2fff{border:#2fff 1px solid}.bds-1-bbb{border:#bbb 1px solid}.bts-3-d2daff{border-top:#d2daff .4vw solid}.bls-1-c9c9c9{border-left:#c9c9c9 1px solid}.bts-20-f9f9f9{border-top:#f9f9f9 2.667vw solid}.bbs-1-fff{border-bottom:#fff 1px solid}.bbs-1-f8f4df{border-bottom:#f8f4df 1px solid}.bts-20-f2f2f2{border-top:#f2f2f2 2.667vw solid}.bds-1-ffe3af{border:#ffe3af 1px solid}.bts-1-f6b37f{border-top:#f6b37f 1px solid}.bds-1-f6b07d{border:#f6b07d 1px solid}.last-b-none:last-child{border-bottom:none}.border-none{border:none}.inner5{padding:.667vw}.inner10{padding:1.333vw}.inner20{padding:2.667vw}.inner30{padding:4vw}.inner40{padding:5.333vw}.inner50{padding:6.667vw}.ulib-r0{border-radius:0!important}.ulib-r5{border-radius:.667vw}.ulib-r10{border-radius:1.333vw}.ulib-r20{border-radius:2.667vw}.ulib-rb20{border-bottom-left-radius:2.667vw;border-bottom-right-radius:2.667vw}.ulib-r750{border-radius:100vw}.ulib-rl750{border-top-left-radius:100vw;border-bottom-left-radius:100vw}.ml0{margin-left:0}.mt0{margin-top:0}.mr0{margin-right:0}.mb0{margin-bottom:0}.pl0{padding-left:0}.pt0{padding-top:0}.pr0{padding-right:0}.pb0{padding-bottom:0}.ml5{margin-left:.667vw}.mt5{margin-top:.667vw}.mr5{margin-right:.667vw}.mb5{margin-bottom:.667vw}.pl5{padding-left:.667vw}.pt5{padding-top:.667vw}.pr5{padding-right:.667vw}.pb5{padding-bottom:.667vw}.ml10{margin-left:1.333vw}.mt10{margin-top:1.333vw}.mr10{margin-right:1.333vw}.mb10{margin-bottom:1.333vw}.pl10{padding-left:1.333vw}.pt10{padding-top:1.333vw}.pr10{padding-right:1.333vw}.pb10{padding-bottom:1.333vw}.ml15{margin-left:2vw}.mt15{margin-top:2vw}.mr15{margin-right:2vw}.mb15{margin-bottom:2vw}.pl15{padding-left:2vw}.pt15{padding-top:2vw}.pr15{padding-right:2vw}.pb15{padding-bottom:2vw}.ml20{margin-left:2.667vw}.mt20{margin-top:2.667vw}.mr20{margin-right:2.667vw}.mb20{margin-bottom:2.667vw}.pl20{padding-left:2.667vw}.pt20{padding-top:2.667vw}.pr20{padding-right:2.667vw}.pb20{padding-bottom:2.667vw}.ml25{margin-left:3.333vw}.mt25{margin-top:3.333vw}.mr25{margin-right:3.333vw}.mb25{margin-bottom:3.333vw}.pl25{padding-left:3.333vw}.pt25{padding-top:3.333vw}.pr25{padding-right:3.333vw}.pb25{padding-bottom:3.333vw}.ml30{margin-left:4vw}.mt30{margin-top:4vw}.mr30{margin-right:4vw}.mb30{margin-bottom:4vw}.pl30{padding-left:4vw}.pt30{padding-top:4vw}.pr30{padding-right:4vw}.pb30{padding-bottom:4vw}.ml35{margin-left:4.667vw}.mt35{margin-top:4.667vw}.mr35{margin-right:4.667vw}.mb35{margin-bottom:4.667vw}.pl35{padding-left:4.667vw}.pt35{padding-top:4.667vw}.pr35{padding-right:4.667vw}.pb35{padding-bottom:4.667vw}.ml40{margin-left:5.333vw}.mt40{margin-top:5.333vw}.mr40{margin-right:5.333vw}.mb40{margin-bottom:5.333vw}.pl40{padding-left:5.333vw}.pt40{padding-top:5.333vw}.pr40{padding-right:5.333vw}.pb40{padding-bottom:5.333vw}.ml45{margin-left:6vw}.mt45{margin-top:6vw}.mr45{margin-right:6vw}.mb45{margin-bottom:6vw}.pl45{padding-left:6vw}.pt45{padding-top:6vw}.pr45{padding-right:6vw}.pb45{padding-bottom:6vw}.ml50{margin-left:6.667vw}.mt50{margin-top:6.667vw}.mr50{margin-right:6.667vw}.mb50{margin-bottom:6.667vw}.pl50{padding-left:6.667vw}.pt50{padding-top:6.667vw}.pr50{padding-right:6.667vw}.pb50{padding-bottom:6.667vw}.ml55{margin-left:7.333vw}.mt55{margin-top:7.333vw}.mr55{margin-right:7.333vw}.mb55{margin-bottom:7.333vw}.pl55{padding-left:7.333vw}.pt55{padding-top:7.333vw}.pr55{padding-right:7.333vw}.pb55{padding-bottom:7.333vw}.ml60{margin-left:8vw}.mt60{margin-top:8vw}.mr60{margin-right:8vw}.mb60{margin-bottom:8vw}.pl60{padding-left:8vw}.pt60{padding-top:8vw}.pr60{padding-right:8vw}.pb60{padding-bottom:8vw}.ml65{margin-left:8.667vw}.mt65{margin-top:8.667vw}.mr65{margin-right:8.667vw}.mb65{margin-bottom:8.667vw}.pl65{padding-left:8.667vw}.pt65{padding-top:8.667vw}.pr65{padding-right:8.667vw}.pb65{padding-bottom:8.667vw}.ml70{margin-left:9.333vw}.mt70{margin-top:9.333vw}.mr70{margin-right:9.333vw}.mb70{margin-bottom:9.333vw}.pl70{padding-left:9.333vw}.pt70{padding-top:9.333vw}.pr70{padding-right:9.333vw}.pb70{padding-bottom:9.333vw}.pl80{padding-left:10.667vw}.pt80{padding-top:10.667vw}.pr80{padding-right:10.667vw}.pb80{padding-bottom:10.667vw}.pl90{padding-left:12vw}.pt90{padding-top:12vw}.pr90{padding-right:12vw}.pb90{padding-bottom:12vw}.pl100{padding-left:13.333vw}.pt100{padding-top:13.333vw}.pr100{padding-right:13.333vw}.pb100{padding-bottom:13.333vw}.pl110{padding-left:14.667vw}.pt110{padding-top:14.667vw}.pr110{padding-right:14.667vw}.pb110{padding-bottom:14.667vw}.pl120{padding-left:16vw}.pt120{padding-top:16vw}.pr120{padding-right:16vw}.pb120{padding-bottom:16vw}.pl130{padding-left:17.333vw}.pt130{padding-top:17.333vw}.pr130{padding-right:17.333vw}.pb130{padding-bottom:17.333vw}.pl140{padding-left:18.667vw}.pt140{padding-top:18.667vw}.pr140{padding-right:18.667vw}.pb140{padding-bottom:18.667vw}.pl150{padding-left:20vw}.pt150{padding-top:20vw}.pr150{padding-right:20vw}.pb150{padding-bottom:20vw}.pl200{padding-left:26.667vw}.pt200{padding-top:26.667vw}.pr200{padding-right:26.667vw}.pb200{padding-bottom:26.667vw}.pl220{padding-left:29.333vw}.pt220{padding-top:29.333vw}.pr220{padding-right:29.333vw}.pb220{padding-bottom:29.333vw}.ml1{margin-left:1px}.mt1{margin-top:1px}.mr1{margin-right:1px}.mb1{margin-bottom:1px}.ml130{margin-left:17.333vw}.mt130{margin-top:17.333vw}.mr130{margin-right:17.333vw}.mb130{margin-bottom:17.333vw}.ml70{margin-left:9.333vw}.mt70{margin-top:9.333vw}.mr70{margin-right:9.333vw}.mb70{margin-bottom:9.333vw}.ml75{margin-left:10vw}.mt75{margin-top:10vw}.mr75{margin-right:10vw}.mb75{margin-bottom:10vw}.ml80{margin-left:10.667vw}.mt80{margin-top:10.667vw}.mr80{margin-right:10.667vw}.mb80{margin-bottom:10.667vw}.ml90{margin-left:12vw}.mt90{margin-top:12vw}.mr90{margin-right:12vw}.mb90{margin-bottom:12vw}.ml95{margin-left:12.667vw}.mt95{margin-top:12.667vw}.mr95{margin-right:12.667vw}.mb95{margin-bottom:12.667vw}.ml100{margin-left:13.333vw}.mt100{margin-top:13.333vw}.mr100{margin-right:13.333vw}.mb100{margin-bottom:13.333vw}.ml110{margin-left:14.667vw}.mt110{margin-top:14.667vw}.mr110{margin-right:14.667vw}.mb110{margin-bottom:14.667vw}.ml140{margin-left:18.667vw}.mt140{margin-top:18.667vw}.mr140{margin-right:18.667vw}.mb140{margin-bottom:18.667vw}.ml160{margin-left:21.333vw}.mt160{margin-top:21.333vw}.mr160{margin-right:21.333vw}.mb160{margin-bottom:21.333vw}.ml170{margin-left:22.667vw}.mt170{margin-top:22.667vw}.mr170{margin-right:22.667vw}.mb170{margin-bottom:22.667vw}.ml180{margin-left:24vw}.mt180{margin-top:24vw}.mr180{margin-right:24vw}.mb180{margin-bottom:24vw}.ml200{margin-left:26.667vw}.mt200{margin-top:26.667vw}.mr200{margin-right:26.667vw}.mb200{margin-bottom:26.667vw}.ml210{margin-left:28vw}.mt210{margin-top:28vw}.mr210{margin-right:28vw}.mb210{margin-bottom:28vw}.ml230{margin-left:30.667vw}.mt230{margin-top:30.667vw}.mr230{margin-right:30.667vw}.mb230{margin-bottom:30.667vw}.ml260{margin-left:34.667vw}.mt260{margin-top:34.667vw}.mr260{margin-right:34.667vw}.mb260{margin-bottom:34.667vw}.ml280{margin-left:37.333vw}.mt280{margin-top:37.333vw}.mr280{margin-right:37.333vw}.mb280{margin-bottom:37.333vw}.ml310{margin-left:41.333vw}.mt310{margin-top:41.333vw}.mr310{margin-right:41.333vw}.mb310{margin-bottom:41.333vw}.ml180{margin-left:24vw}.mt180{margin-top:24vw}.mr180{margin-right:24vw}.mb180{margin-bottom:24vw}.ml430{margin-left:57.333vw}.mt430{margin-top:57.333vw}.mr430{margin-right:57.333vw}.mb430{margin-bottom:57.333vw}.btn{display:inline-block;font-size:2vw;text-align:center;border:none;vertical-align:middle;cursor:pointer;transition:all .15s ease 0s}.btn:active{box-shadow:inset 0 .4vw .667vw rgba(0,0,0,.125)}.bg-fff-op30{background-color:rgba(255,255,255,.3)}.bg-000-op10{background-color:rgba(0,0,0,.1)}.bg-000-op50{background-color:rgba(0,0,0,.5)}.bg-000-op60{background-color:rgba(0,0,0,.6)}.bg-000-op80{background-color:rgba(0,0,0,.8)}.bg-fa{background-color:#fafafa}.bg-f5{background-color:#f5f5f5}.bg-f6{background-color:#f6f6f6}.bg-f7{background-color:#f7f7f7}.bg-f8{background-color:#f8f8f8}.bg-f9{background-color:#f9f9f9}.color-000{color:#000}.bg-000{background-color:#000}.color-333{color:#333}.bg-333{background-color:#333}.color-555{color:#555}.bg-555{background-color:#555}.color-666{color:#666}.bg-666{background-color:#666}.color-888{color:#888}.bg-888{background-color:#888}.color-999{color:#999}.bg-999{background-color:#999}.color-aaa{color:#aaa}.bg-aaa{background-color:#aaa}.color-bbb{color:#bbb}.bg-bbb{background-color:#bbb}.color-ccc{color:#ccc}.bg-ccc{background-color:#ccc}.color-ddd{color:#ddd}.bg-ddd{background-color:#ddd}.color-eee{color:#eee}.bg-eee{background-color:#eee}.color-fff{color:#fff}.bg-fff{background-color:#fff}.color-ff0000{color:red}.bg-ff0000{background-color:red}.color-fe9538{color:#fe9538}.bg-fe9538{background-color:#fe9538}.color-ff5a5a{color:#ff5a5a}.bg-ff5a5a{background-color:#ff5a5a}.color-fccba0{color:#fccba0}.bg-fccba0{background-color:#fccba0}.color-fff5ec{color:#fff5ec}.bg-fff5ec{background-color:#fff5ec}.color-ad4635{color:#ad4635}.bg-ad4635{background-color:#ad4635}.clear:after,.clear:before{content:"";display:table}.clear:after{clear:both}.clear{zoom:1}.fl{float:left}.fr{float:right}.fn-clear:after,.fn-clear:before{content:"";display:table}.fn-clear:after{clear:both}.fn-clear{zoom:1}.fn-fl{float:left}.fn-fr{float:right}.fn-flex{display:flex;flex-flow:row;align-items:stretch}.fn-flex-center{align-items:center}.fn-flex-item{display:block;flex:1}.fn-flex-item[flexsize="2"]{flex:2}.fn-flex-item[flexsize="3"]{flex:3}.fn-flex-item[flexsize="4"]{flex:4}.fn-flex-item[flexsize="5"]{flex:5}.fn-flex-item[flexsize="6"]{flex:6}.fn-flex-item[flexsize="7"]{flex:7}.fn-flex-item[flexsize="8"]{flex:8}.fn-flex-item[flexsize="9"]{flex:9}.fn-flex-wrap{flex-wrap:wrap}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.block{display:block}.inline-block{display:inline-block}.fn-hide{display:none}.overflowhidden{overflow:hidden}.scroll-x{overflow-x:auto}.scroll-y{overflow-y:auto}.relative{position:relative}.absolute{position:absolute}.fixed{position:fixed}.top-0{top:0}.left-0{left:0}.bottom-0{bottom:0}.right-0{right:0}.z-index--1{z-index:-1!important}.z-index-0{z-index:0}.z-index-1{z-index:1}.z-index-2{z-index:2}.z-index-3{z-index:3}.z-index-4{z-index:4}.z-index-10{z-index:10}.box-center-middle{top:50%;left:50%;transform:translate(-50%,-50%)}.box-middle{top:50%;transform:translate(0,-50%)}.box-center{left:50%;transform:translate(-50%,0)}.box-border{box-sizing:border-box}.wp20{width:20%;box-sizing:border-box}.wp25{width:25%;box-sizing:border-box}.wp33{width:33%;box-sizing:border-box}.wp40{width:40%;box-sizing:border-box}.wp45{width:45%;box-sizing:border-box}.wp48{width:48%;box-sizing:border-box}.wp49{width:49%;box-sizing:border-box}.wp50{width:50%;box-sizing:border-box}.wp60{width:60%!important;box-sizing:border-box}.wp65{width:65%!important;box-sizing:border-box}.wp70{width:70%!important;box-sizing:border-box}.wp80{width:80%!important;box-sizing:border-box}.wp90{width:90%;box-sizing:border-box}.wp100{width:100%;box-sizing:border-box}.w100vw{width:100vw}.h100vh{height:100vh}.transition-all{transition:all ease .2s}.op90{opacity:.9}.op70{opacity:.7}.op30{opacity:.3}.op20{opacity:.2}.op0{opacity:0}.bg-size-contain{background-size:contain}.bg-size-cover{background-size:cover}.bg-size-fullwidth{background-size:100% auto}.bg-size-fullheight{background-size:auto 100%}.bg-no-repeat{background-repeat:no-repeat}.bg-repeat-x{background-repeat:repeat-x}.bg-repeat-y{background-repeat:repeat-y}.bg-pos-top{background-position:top center}.bg-pos-bottom{background-position:bottom center}.bg-pos-center{background-position:center}.box-shadow-darkGray{box-shadow:0 0 1.333vw rgba(0,0,0,.15)}.box-shadow-lightGray{box-shadow:0 0 2.667vw rgba(0,0,0,.08)}.box-shadow-green{box-shadow:0 0 2.667vw rgba(55,190,77,.15)}.box-shadow-darkGreen{box-shadow:0 0 2.667vw rgba(55,190,77,.25)}.line-height-11{line-height:1.1}.line-height-13{line-height:1.3}.line-height-15{line-height:1.5}.line-height-17{line-height:1.7}.line-height-20{line-height:2}.height-60{height:8vw}.icon-jiazai{display:inline-block;-webkit-animation:rotate linear 1.2s infinite;animation:rotate linear 1.2s infinite}@-webkit-keyframes rotate{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}.text-nowrap{width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.text-underline{text-decoration:underline}.text-through{text-decoration:line-through}.text-middle{vertical-align:middle}.text-lighter{font-weight:400}.text-bold{font-weight:600}.text-normal{font-weight:400}.text-break{word-break:break-all;word-wrap:break-word}.space-nowrap{white-space:nowrap}.space-normal{white-space:normal}.text-italic{font-style:italic}.line-clamp-2{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden}.line-clamp-3{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3;overflow:hidden}.font-12{font-size:1.6vw}.font-14{font-size:1.867vw}.font-16{font-size:2.133vw}.font-18{font-size:2.4vw}.font-20{font-size:2.667vw}.font-22{font-size:2.933vw}.font-24{font-size:3.2vw}.font-26{font-size:3.467vw}.font-28{font-size:3.733vw}.font-30{font-size:4vw}.font-32{font-size:4.267vw}.font-34{font-size:4.533vw}.font-36{font-size:4.8vw}.font-38{font-size:5.067vw}.font-40{font-size:5.333vw}.font-42{font-size:5.6vw}.font-44{font-size:5.867vw}.font-46{font-size:6.133vw}.font-48{font-size:6.4vw}.font-50{font-size:6.667vw}.font-52{font-size:6.933vw}.font-54{font-size:7.2vw}.font-56{font-size:7.467vw}.font-58{font-size:7.733vw}.font-60{font-size:8vw}.font-62{font-size:8.267vw}.font-64{font-size:8.533vw}.font-66{font-size:8.8vw}.font-68{font-size:9.067vw}.font-70{font-size:9.333vw}.font-72{font-size:9.6vw}.font-74{font-size:9.867vw}.font-76{font-size:10.133vw}.font-78{font-size:10.4vw}.font-80{font-size:10.667vw}.font-70{font-size:9.333vw}.font-80{font-size:10.667vw}.font-100{font-size:13.333vw}@font-face{font-family:iconfont;src:url(https://qs.haodian.cn/web/images/project/H5-ShiYu/iconfont/iconfont.woff2?t=16643531549461) format("woff2"),url(https://qs.haodian.cn/web/images/project/H5-ShiYu/iconfont/iconfont.woff?t=16643531549461) format("woff"),url(https://qs.haodian.cn/web/images/project/H5-ShiYu/iconfont/iconfont.ttf?t=16643531549461) format("truetype")}.iconfont{font-family:iconfont!important;font-style:normal;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.icon-zhibo:before{content:"\e633"}.icon-quyu:before{content:"\e67c"}.icon-dingdan:before{content:"\e639"}.icon-gengduo:before{content:"\e60c"}.icon-jiazai:before{content:"\eb7b"}.icon-wode:before{content:"\e6b8"}.icon-qiehuan:before{content:"\e6b9"}.icon-shuju:before{content:"\e6ba"}.icon-fenxiang:before{content:"\e6bb"}.icon-huodong:before{content:"\e6b6"}.icon-mendian:before{content:"\e6b7"}.imgsize-32X32{width:4.267vw;height:4.267vw}.imgsize-35X35{width:4.667vw;height:4.667vw}.imgsize-42X42{width:5.6vw;height:5.6vw}.imgsize-120X120{width:16vw;height:16vw}.imgsize-130X130{width:17.333vw;height:17.333vw}.imgsize-160X160{width:21.333vw;height:21.333vw}.imgsize-750X680{width:100vw;height:90.667vw}@-webkit-keyframes mDialogFadeIn{from{opacity:0}to{opacity:1}}@keyframes mDialogFadeIn{from{opacity:0}to{opacity:1}}.mDialogFadeIn{-webkit-animation-name:mDialogFadeIn;animation-name:mDialogFadeIn}@-webkit-keyframes mDialogFadeOut{from{opacity:1}to{opacity:0}}@keyframes mDialogFadeOut{from{opacity:1}to{opacity:0}}.mDialogFadeOut{-webkit-animation-name:mDialogFadeOut;animation-name:mDialogFadeOut}@-webkit-keyframes mDialogZoomIn{from{opacity:0;transform:scale3d(.3,.3,.3)}50%{opacity:1}}@keyframes mDialogZoomIn{from{opacity:0;transform:scale3d(.3,.3,.3)}50%{opacity:1}}.mDialogZoomIn{-webkit-animation-name:mDialogZoomIn;animation-name:mDialogZoomIn}@-webkit-keyframes mDialogZoomOut{from{opacity:1}50%{opacity:0;transform:scale3d(.3,.3,.3)}to{opacity:0}}@keyframes mDialogZoomOut{from{opacity:1}50%{opacity:0;transform:scale3d(.3,.3,.3)}to{opacity:0}}.mDialogZoomOut{-webkit-animation-name:mDialogZoomOut;animation-name:mDialogZoomOut}@-webkit-keyframes mDialogBigIn{0%{opacity:0;transform:scale(1.2,1.2)}100%{opacity:1;transform:scale(1,1)}}@keyframes mDialogBigIn{0%{opacity:0;transform:scale(1.2,1.2)}100%{opacity:1;transform:scale(1,1)}}.mDialogBigIn{-webkit-animation-name:mDialogBigIn;animation-name:mDialogBigIn}@-webkit-keyframes mDialogBigOut{0%{opacity:1}100%{opacity:0;transform:scale(1.2,1.2)}}@keyframes mDialogBigOut{0%{opacity:1}100%{opacity:0;transform:scale(1.2,1.2)}}.mDialogBigOut{-webkit-animation-name:mDialogBigOut;animation-name:mDialogBigOut}.mDialog-layer-container{visibility:hidden;position:fixed;-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out;box-sizing:border-box}.mDialog-layer-container *{box-sizing:border-box}.mDialog-layer-container.mDialog-layer-container-full>.mDialog-layer-title{border-radius:0}.mDialog-layer-container.mDialog-layer-container-full>.mDialog-layer-main{border-radius:0}.mDialog-layer-container.mDialog-layer-container-full>.mDialog-layer-btns{border-radius:0}.mDialog-layer-title{border-radius:2.6667vw 2.6667vw 0 0;background:#f5f5f5;clear:both;border-bottom:1px solid #d5d5d5;padding:2.6667vw;overflow:hidden;font-size:4.8vw}.mDialog-layer-main{word-break:break-all;word-wrap:break-word;overflow:hidden;font-size:4.2667vw}.mDialog-layer-main:after{content:"";display:table;clear:both}.mDialog-layer-main.mDialog-layer-main-full>div{height:100%;overflow:hidden}.mDialog-layer-main>div{position:relative}.mDialog-layer-btns{clear:both;border-top:1px solid #e8e8e8;background:#fff;border-radius:0 0 2.6667vw 2.6667vw;display:flex}.mDialog-layer-btns>.mDialog-btn{flex:1;display:block;text-align:center;position:relative;color:#007aff;font-size:4.8vw;padding:2.6667vw 0}.mDialog-layer-btns>.mDialog-btn:after{content:"";position:absolute;left:0;top:0;width:1px;height:100%;border-left:1px solid #d5d5d5;color:#d5d5d5}.mDialog-layer-btns>.mDialog-btn:active{background-color:rgba(0,0,0,.05)}.mDialog-layer-btns>.mDialog-btn:first-child:after{border-left:0}.mDialog-close{position:absolute;width:8.667vw;height:8.667vw;overflow:hidden;right:0;top:0;margin-top:-4.3333vw;margin-right:-4.3333vw;border-radius:100%;background-color:#000}.mDialog-close:before{transform:rotate(45deg);content:"";position:absolute;top:50%;left:1.3333vw;right:1.3333vw;background:#fff;height:.8vw;margin-top:-.4vw;border-radius:1.0667vw}.mDialog-close:after{transform:rotate(-45deg);content:"";position:absolute;top:50%;left:1.3333vw;right:1.3333vw;background:#fff;height:.8vw;margin-top:-.4vw;border-radius:1.0667vw}.mDialog-shade{position:fixed;left:0;top:0;right:0;bottom:0;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}.mDialog-shade.in{-webkit-animation-name:mDialogFadeIn;animation-name:mDialogFadeIn}.mDialog-shade.out{-webkit-animation-name:mDialogFadeOut;animation-name:mDialogFadeOut}.mDialog-default-section{background:#fff;font-size:4.2667vw;padding:2.6667vw}.mDialog-msg-section{background-color:rgba(0,0,0,.9);border-radius:2.6667vw;padding:4vw;color:#fff}@-webkit-keyframes line-spin-fade-loader{50%{opacity:.3}100%{opacity:1}}@keyframes line-spin-fade-loader{50%{opacity:.3}100%{opacity:1}}.mDialog-loading-section{background-color:rgba(0,0,0,.7);border-radius:2vw;padding:4vw 8vw;overflow:hidden}.mDialog-loading-section .loading-txt{font-size:4.2667vw;color:#fff;text-align:center;margin-top:2.6667vw;white-space:nowrap}.mDialog-loading-section .loading-icon{position:relative;width:16.533vw;height:16.533vw;margin:0 auto}.mDialog-loading-section .loading-icon>div{background-color:#fff;border-radius:.5333vw;-webkit-animation-fill-mode:both;animation-fill-mode:both;position:absolute;width:1.0667vw;height:4.8vw;margin-left:-.5333vw}.mDialog-loading-section .loading-icon>div:nth-child(1){top:11.733vw;left:50%;-webkit-animation:line-spin-fade-loader 1.2s .12s infinite ease-in-out;animation:line-spin-fade-loader 1.2s .12s infinite ease-in-out}.mDialog-loading-section .loading-icon>div:nth-child(2){top:10.7173vw;left:10.7173vw;transform:rotate(-45deg);transform-origin:top center;-webkit-animation:line-spin-fade-loader 1.2s .24s infinite ease-in-out;animation:line-spin-fade-loader 1.2s .24s infinite ease-in-out}.mDialog-loading-section .loading-icon>div:nth-child(3){top:8.533vw;left:11.733vw;transform-origin:top center;transform:rotate(-90deg);-webkit-animation:line-spin-fade-loader 1.2s .36s infinite ease-in-out;animation:line-spin-fade-loader 1.2s .36s infinite ease-in-out}.mDialog-loading-section .loading-icon>div:nth-child(4){top:5.816vw;left:11.733vw;transform:rotate(-135deg);transform-origin:top center;-webkit-animation:line-spin-fade-loader 1.2s .48s infinite ease-in-out;animation:line-spin-fade-loader 1.2s .48s infinite ease-in-out}.mDialog-loading-section .loading-icon>div:nth-child(5){top:0;left:50%;-webkit-animation:line-spin-fade-loader 1.2s .6s infinite ease-in-out;animation:line-spin-fade-loader 1.2s .6s infinite ease-in-out}.mDialog-loading-section .loading-icon>div:nth-child(6){top:5.816vw;left:5.816vw;transform-origin:top center;transform:rotate(135deg);-webkit-animation:line-spin-fade-loader 1.2s .72s infinite ease-in-out;animation:line-spin-fade-loader 1.2s .72s infinite ease-in-out}.mDialog-loading-section .loading-icon>div:nth-child(7){top:8.2667vw;left:4.8vw;margin-left:-.5333vw;transform:rotate(90deg);transform-origin:top center;-webkit-animation:line-spin-fade-loader 1.2s .84s infinite ease-in-out;animation:line-spin-fade-loader 1.2s .84s infinite ease-in-out}.mDialog-loading-section .loading-icon>div:nth-child(8){top:10.7173vw;left:5.816vw;margin-left:-.5333vw;transform:rotate(45deg);transform-origin:top center;-webkit-animation:line-spin-fade-loader 1.2s .96s infinite ease-in-out;animation:line-spin-fade-loader 1.2s .96s infinite ease-in-out}.mDialog-loading-section.loading-notext{padding:8vw}.mDialog-confirm-section{background:#fff;padding:5.333vw 4vw;border-radius:2.6667vw 2.6667vw 0 0}*{box-sizing:border-box;-webkit-tap-highlight-color:transparent}a,abbr,acronym,address,applet,article,aside,audio,b,big,blockquote,body,canvas,caption,center,cite,code,dd,del,details,dfn,div,dl,dt,em,fieldset,figcaption,figure,footer,form,h1,h2,h3,h4,h5,h6,header,hgroup,html,i,iframe,img,ins,kbd,label,legend,li,mark,menu,nav,object,ol,p,pre,q,s,samp,section,small,span,strike,strong,sub,summary,sup,table,tbody,td,tfoot,th,thead,time,tr,tt,u,ul,var,video{margin:0;padding:0}ol,ul{list-style:none}table{border-collapse:collapse;border-spacing:0}.clearfix:after{content:"";display:table;clear:both}input:focus,select:focus,textarea:focus{outline:0}em{font-style:normal}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{-webkit-appearance:none}input[type=search]{-webkit-appearance:textfield;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}a{text-decoration:none;color:#333}body,button,select,textarea{font-family:"微软雅黑",Tahoma,Arial,Helvetica,sans-serif}html{width:100%;background-color:#fff}body{background-color:#fff}img{max-width:100%}.container{width:100%;min-height:100vh}.login input.checkbox-input{width:4.267vw;height:4.267vw;vertical-align:-.267vw}.player{width:92vw;height:52vw}.winInfo-swiper,.winInfo-swiper .swiper-slide{height:7.467vw;line-height:7.467vw}.tab-menu{padding:1.333vw 2vw}.tab-menu.active{color:#fe9538}.glider{position:absolute;bottom:0;width:10.667vw;height:.533vw;background:#fe9538;z-index:0;transition:.25s ease-out;border-radius:750rpx}.glider-0{transform:translatex(120%)}.glider-1{transform:translatex(450%)}.w-50{width:6.667vw}.top--60{top:-8vw}.h-63{height:8.4vw}.h-260{height:34.667vw}.h-290{height:38.667vw}.line-height-63{line-height:8.4vw}.bottom-opt{position:fixed;right:5.333vw;bottom:26.667vw;width:12.8vw;height:12.8vw}.goods-banner .swiper-pagination-fraction{top:69.333vw;right:0;left:auto;width:20vw}.goods-banner .swiper-pagination-fraction .swiper-pagination-current{font-size:4.8vw}.goods-con{top:-12vw}.notice{position:absolute;left:4vw;bottom:-8vw;-webkit-animation-name:noticeac;animation-name:noticeac;-webkit-animation-duration:4s;animation-duration:4s;-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out;-webkit-animation-iteration-count:1;animation-iteration-count:1;-webkit-animation-direction:alternate;animation-direction:alternate;-webkit-animation-play-state:running;animation-play-state:running}@-webkit-keyframes noticeac{0%{bottom:-60px}70%{opacity:1}100%{bottom:220px;opacity:0}}@keyframes noticeac{0%{bottom:-60px}70%{opacity:1}100%{bottom:220px;opacity:0}}.poster{width:100vw;min-height:60vh}.poster .p-swiper{width:100vw;min-height:60vh}.poster .swiper-container{width:100%;min-height:60vh}.poster .swiper-container .swiper-slide{width:100%;min-height:60vh;background-size:contain;background-position:center;overflow-y:auto}.poster .swiper-pagination-fraction{position:fixed;top:6.667vw;bottom:auto;left:auto;right:0;width:auto;padding:2vw 4vw;background-color:rgba(0,0,0,.8);font-size:30;color:#fff}.msg{position:fixed;left:0;top:0;width:100%;height:100%;z-index:1000}.msg .msgBgPoster{position:fixed;left:0;top:0;width:100%;height:100%;background-color:rgba(0,0,0,.95)}.msg .msgBg{position:fixed;left:0;top:0;width:100%;height:100%;background-color:rgba(0,0,0,.8)}.msg .msgMain{position:fixed;left:50%;top:50%;transform:translate(-50%,-50%);z-index:9999}.msg .msgMain i.posterClose{position:absolute;top:-9.333vw;right:1.333vw;width:6.667vw;height:6.667vw;border-radius:100%;border:.4vw solid #fff}.msg .msgMain i.posterClose::after,.msg .msgMain i.posterClose::before{position:absolute;left:50%;top:50%;content:"";width:3.333vw;height:.267vw;background-color:#fff}.msg .msgMain i.posterClose::before{transform:translate(-50%,-50%) rotate(-45deg)}.msg .msgMain i.posterClose::after{transform:translate(-50%,-50%) rotate(45deg)}.msg .msgMain i.posterClose span{display:block;position:absolute;top:6.4vw;left:2.933vw;height:2.667vw;border-left:.4vw solid #fff}.msg .msgMain i.close{position:absolute;left:50%;transform:translateX(-50%);bottom:-8.267vw;width:6.667vw;height:6.667vw;border-radius:100%;border:.4vw solid #fff}.msg .msgMain i.close::after,.msg .msgMain i.close::before{position:absolute;left:50%;top:50%;content:"";width:3.333vw;height:.267vw;background-color:#fff}.msg .msgMain i.close::before{transform:translate(-50%,-50%) rotate(-45deg)}.msg .msgMain i.close::after{transform:translate(-50%,-50%) rotate(45deg)}.msg .msgMain .msgPoster{width:80vw}.msg .msgMain .postercon{max-height:120vw;overflow-y:auto}.msg .msgMain .content{width:80vw;background-color:#fff;border-radius:1.333vw;padding:5.333vw}.msg .msgMain .content .word h2{font-size:4.8vw;padding-bottom:2vw}.msg .msgMain .content .word .desc{max-height:65vh;overflow-y:auto}.msg .msgMain .content .word p{margin:0 auto;color:#333;line-height:1.7}.msg .msgMain .content .opt{text-align:center;padding-top:2.667vw}.msg .msgMain .content .opt .btn{width:80%;height:9.333vw;line-height:9.333vw;display:inline-block;background-color:#4ca6ff;color:#fff;border-radius:133.333vw;font-size:3.733vw}.msg.msg-qrcode .content{width:62.667vw;background-size:100% auto;background-position:bottom center;background-repeat:no-repeat}.msg.msg-qrcode .content .time em{color:#0074f6}.msg.msg-qrcode .content .time span{margin-left:.667vw;text-decoration:underline}.msg.msg-qrcode .content .qrcode{padding-bottom:12vw;margin:8vw auto 0;width:33.333vw}.msg.msg-qrcode .content .qrcode span{display:block;background-color:#58bafe;border-radius:1.333vw;height:6.933vw;line-height:6.933vw}.msg.msg-tips .msgMain{width:77.333vw;min-height:54.667vw;border-radius:1.333vw;background-size:100% auto;background-repeat:no-repeat;background-position:bottom center}.msg.msg-tips .hd{height:11.733vw;line-height:11.733vw;background-color:#fafafa;border-top-left-radius:1.333vw;border-top-right-radius:1.333vw}.msg.msg-tips .bd{max-height:80vw;overflow:auto;line-height:1.7}.swiper-container{position:absolute;width:100%;height:100%}.swiper-container .swiper-slide{width:100%;height:100%;background-size:contain;background-position:center}.imgshow{position:fixed;left:0;top:0;width:100%;height:100%;z-index:1000}.imgshow .msgBg{position:fixed;left:0;top:0;width:100%;height:100%;background-color:rgba(0,0,0,.6)}.imgshow i.close{position:absolute;left:50%;transform:translateX(-50%);bottom:2.667vw;width:6.667vw;height:6.667vw;border-radius:100%;border:.4vw solid #fff}.imgshow i.close::after,.imgshow i.close::before{position:absolute;left:50%;top:50%;content:"";width:3.333vw;height:.267vw;background-color:#fff}.imgshow i.close::before{transform:translate(-50%,-50%) rotate(-45deg)}.imgshow i.close::after{transform:translate(-50%,-50%) rotate(45deg)}.imgshow img{max-width:100vw;max-height:80vh} \ No newline at end of file diff --git a/www/admin/favicon.ico b/www/market/favicon.ico similarity index 100% rename from www/admin/favicon.ico rename to www/market/favicon.ico diff --git a/www/market/index.php b/www/market/index.php new file mode 100644 index 00000000..2c6746e0 --- /dev/null +++ b/www/market/index.php @@ -0,0 +1,318 @@ +=')) + { + error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED & ~E_STRICT & ~E_USER_NOTICE & ~E_USER_DEPRECATED); + } + else + { + error_reporting(E_ALL & ~E_NOTICE & ~E_STRICT & ~E_USER_NOTICE); + } + break; + + default: + header('HTTP/1.1 503 Service Unavailable.', TRUE, 503); + echo 'The application environment is not set correctly.'; + exit(1); // EXIT_ERROR +} + +/* + *--------------------------------------------------------------- + * SYSTEM DIRECTORY NAME + *--------------------------------------------------------------- + * + * This variable must contain the name of your "system" directory. + * Set the path if it is not in the same directory as this file. + */ + $system_path = '../../system'; + +/* + *--------------------------------------------------------------- + * APPLICATION DIRECTORY NAME + *--------------------------------------------------------------- + * + * If you want this front controller to use a different "application" + * directory than the default one you can set its name here. The directory + * can also be renamed or relocated anywhere on your server. If you do, + * use an absolute (full) server path. + * For more info please see the user guide: + * + * https://codeigniter.com/user_guide/general/managing_apps.html + * + * NO TRAILING SLASH! + */ + $application_folder = '../../market'; + +/* + *--------------------------------------------------------------- + * VIEW DIRECTORY NAME + *--------------------------------------------------------------- + * + * If you want to move the view directory out of the application + * directory, set the path to it here. The directory can be renamed + * and relocated anywhere on your server. If blank, it will default + * to the standard location inside your application directory. + * If you do move this, use an absolute (full) server path. + * + * NO TRAILING SLASH! + */ + $view_folder = ''; + + +/* + * -------------------------------------------------------------------- + * DEFAULT CONTROLLER + * -------------------------------------------------------------------- + * + * Normally you will set your default controller in the routes.php file. + * You can, however, force a custom routing by hard-coding a + * specific controller class/function here. For most applications, you + * WILL NOT set your routing here, but it's an option for those + * special instances where you might want to override the standard + * routing in a specific front controller that shares a common CI installation. + * + * IMPORTANT: If you set the routing here, NO OTHER controller will be + * callable. In essence, this preference limits your application to ONE + * specific controller. Leave the function name blank if you need + * to call functions dynamically via the URI. + * + * Un-comment the $routing array below to use this feature + */ + // The directory name, relative to the "controllers" directory. Leave blank + // if your controller is not in a sub-directory within the "controllers" one + // $routing['directory'] = ''; + + // The controller class file name. Example: mycontroller + // $routing['controller'] = ''; + + // The controller function you wish to be called. + // $routing['function'] = ''; + + +/* + * ------------------------------------------------------------------- + * CUSTOM CONFIG VALUES + * ------------------------------------------------------------------- + * + * The $assign_to_config array below will be passed dynamically to the + * config class when initialized. This allows you to set custom config + * items or override any default config values found in the config.php file. + * This can be handy as it permits you to share one application between + * multiple front controller files, with each file containing different + * config values. + * + * Un-comment the $assign_to_config array below to use this feature + */ + // $assign_to_config['name_of_config_item'] = 'value of config item'; + + + +// -------------------------------------------------------------------- +// END OF USER CONFIGURABLE SETTINGS. DO NOT EDIT BELOW THIS LINE +// -------------------------------------------------------------------- + +/* + * --------------------------------------------------------------- + * Resolve the system path for increased reliability + * --------------------------------------------------------------- + */ + + // Set the current directory correctly for CLI requests + if (defined('STDIN')) + { + chdir(dirname(__FILE__)); + } + + if (($_temp = realpath($system_path)) !== FALSE) + { + $system_path = $_temp.DIRECTORY_SEPARATOR; + } + else + { + // Ensure there's a trailing slash + $system_path = strtr( + rtrim($system_path, '/\\'), + '/\\', + DIRECTORY_SEPARATOR.DIRECTORY_SEPARATOR + ).DIRECTORY_SEPARATOR; + } + + // Is the system path correct? + if ( ! is_dir($system_path)) + { + header('HTTP/1.1 503 Service Unavailable.', TRUE, 503); + echo 'Your system folder path does not appear to be set correctly. Please open the following file and correct this: '.pathinfo(__FILE__, PATHINFO_BASENAME); + exit(3); // EXIT_CONFIG + } + +/* + * ------------------------------------------------------------------- + * Now that we know the path, set the main path constants + * ------------------------------------------------------------------- + */ + // The name of THIS file + define('SELF', pathinfo(__FILE__, PATHINFO_BASENAME)); + + // Path to the system directory + define('BASEPATH', $system_path); + + // Path to the front controller (this file) directory + define('FCPATH', dirname(__FILE__).DIRECTORY_SEPARATOR); + + // Name of the "system" directory + define('SYSDIR', basename(BASEPATH)); + + // Common directory by 0fun + define('COMMPATH', dirname(BASEPATH).DIRECTORY_SEPARATOR.'common'.DIRECTORY_SEPARATOR); + + // The path to the "application" directory + if (is_dir($application_folder)) + { + if (($_temp = realpath($application_folder)) !== FALSE) + { + $application_folder = $_temp; + } + else + { + $application_folder = strtr( + rtrim($application_folder, '/\\'), + '/\\', + DIRECTORY_SEPARATOR.DIRECTORY_SEPARATOR + ); + } + } + elseif (is_dir(BASEPATH.$application_folder.DIRECTORY_SEPARATOR)) + { + $application_folder = BASEPATH.strtr( + trim($application_folder, '/\\'), + '/\\', + DIRECTORY_SEPARATOR.DIRECTORY_SEPARATOR + ); + } + else + { + header('HTTP/1.1 503 Service Unavailable.', TRUE, 503); + echo 'Your application folder path does not appear to be set correctly. Please open the following file and correct this: '.SELF; + exit(3); // EXIT_CONFIG + } + + define('APPPATH', $application_folder.DIRECTORY_SEPARATOR); + + // The path to the "views" directory + if ( ! isset($view_folder[0]) && is_dir(APPPATH.'views'.DIRECTORY_SEPARATOR)) + { + $view_folder = APPPATH.'views'; + } + elseif (is_dir($view_folder)) + { + if (($_temp = realpath($view_folder)) !== FALSE) + { + $view_folder = $_temp; + } + else + { + $view_folder = strtr( + rtrim($view_folder, '/\\'), + '/\\', + DIRECTORY_SEPARATOR.DIRECTORY_SEPARATOR + ); + } + } + elseif (is_dir(APPPATH.$view_folder.DIRECTORY_SEPARATOR)) + { + $view_folder = APPPATH.strtr( + trim($view_folder, '/\\'), + '/\\', + DIRECTORY_SEPARATOR.DIRECTORY_SEPARATOR + ); + } + else + { + header('HTTP/1.1 503 Service Unavailable.', TRUE, 503); + echo 'Your view folder path does not appear to be set correctly. Please open the following file and correct this: '.SELF; + exit(3); // EXIT_CONFIG + } + + define('VIEWPATH', $view_folder.DIRECTORY_SEPARATOR); + +/* + * -------------------------------------------------------------------- + * LOAD THE BOOTSTRAP FILE + * -------------------------------------------------------------------- + * + * And away we go... + */ +require_once BASEPATH.'core/CodeIgniter.php'; diff --git a/www/admin/robots.txt b/www/market/robots.txt similarity index 100% rename from www/admin/robots.txt rename to www/market/robots.txt