diff --git a/app/common/bootstrap.app.inc.php b/app/common/bootstrap.app.inc.php new file mode 100644 index 0000000..26a1e45 --- /dev/null +++ b/app/common/bootstrap.app.inc.php @@ -0,0 +1,189 @@ +app('common'); +load()->model('mc'); +load()->model('account'); +load()->model('attachment'); +load()->model('permission'); +load()->model('module'); + +$_W['uniacid'] = intval($_GPC['i']); +if (empty($_W['uniacid'])) { + $_W['uniacid'] = intval($_GPC['weid']); +} +if (empty($_W['uniacid'])) { + header('HTTP/1.1 404 Not Found'); + header("status: 404 Not Found"); + exit; +} +$_W['uniaccount'] = $_W['account'] = uni_fetch($_W['uniacid']); +if (is_error($_W['account'])) { + message($_W['account']['message']); +} +if (!empty($_W['account']['isdeleted'])) { + message('指定公众号已被删除'); +} +if (!empty($_W['uniaccount']['endtime']) && TIMESTAMP > $_W['uniaccount']['endtime'] && !in_array($_W['uniaccount']['endtime'], array(USER_ENDTIME_GROUP_EMPTY_TYPE, USER_ENDTIME_GROUP_UNLIMIT_TYPE))) { + message('抱歉,您的平台账号服务已过期,请及时联系管理员'); +} +$_W['acid'] = $_W['uniaccount']['acid']; + +if (!empty($_W['account']['setting']['bind_domain']) && !empty($_W['account']['setting']['bind_domain']['domain']) && strpos($_W['account']['setting']['bind_domain']['domain'], $_SERVER['HTTP_HOST']) === false) { + header('Location:' . $_W['account']['setting']['bind_domain']['domain'] . $_SERVER['REQUEST_URI']); + exit; +} + +$_W['session_id'] = ''; +if (isset($_GPC['state']) && !empty($_GPC['state']) && strexists($_GPC['state'], 'we7sid-')) { + $pieces = explode('-', $_GPC['state']); + $_W['session_id'] = $pieces[1]; + unset($pieces); +} +if (empty($_W['session_id'])) { + $_W['session_id'] = $_COOKIE[session_name()]; +} +if (empty($_W['session_id'])) { + $_W['session_id'] = "{$_W['uniacid']}-" . random(20); + $_W['session_id'] = md5($_W['session_id']); + setcookie(session_name(), $_W['session_id'], 0, '/'); +} +session_id($_W['session_id']); + +load()->classs('wesession'); +WeSession::start($_W['uniacid'], $_W['clientip']); +if (!empty($_GPC['j'])) { + $acid = intval($_GPC['j']); + $_W['account'] = account_fetch($acid); + if (is_error($_W['account'])) { + $_W['account'] = account_fetch($_W['acid']); + } else { + $_W['acid'] = $acid; + } + $_SESSION['__acid'] = $_W['acid']; + $_SESSION['__uniacid'] = $_W['uniacid']; +} +if (!empty($_SESSION['__acid']) && $_SESSION['__uniacid'] == $_W['uniacid']) { + $_W['acid'] = intval($_SESSION['__acid']); + $_W['account'] = uni_fetch($_W['uniacid']); +} +if (strpos($_SERVER['QUERY_STRING'], 'favicon.ico') === false && ((!empty($_SESSION['acid']) && $_W['acid'] != $_SESSION['acid']) || (!empty($_SESSION['uniacid']) && $_W['uniacid'] != $_SESSION['uniacid']))) { + $keys = array_keys($_SESSION); + foreach ($keys as $key) { + unset($_SESSION[$key]); + } + unset($keys, $key); +} +$_SESSION['acid'] = $_W['acid']; +$_SESSION['uniacid'] = $_W['uniacid']; + +if (!empty($_SESSION['openid'])) { + $_W['openid'] = $_SESSION['openid']; + $_W['fans'] = mc_fansinfo($_W['openid']); + $_W['fans']['from_user'] = $_W['fans']['openid'] = $_W['openid']; +} +if (!empty($_SESSION['uid']) || (!empty($_W['fans']) && !empty($_W['fans']['uid']))) { + $uid = intval($_SESSION['uid']); + if (empty($uid)) { + $uid = $_W['fans']['uid']; + } + _mc_login(array('uid' => $uid)); + unset($uid); +} +if (empty($_W['openid']) && !empty($_SESSION['oauth_openid'])) { + $_W['openid'] = $_SESSION['oauth_openid']; + $_W['fans'] = array( + 'openid' => $_SESSION['oauth_openid'], + 'from_user' => $_SESSION['oauth_openid'], + 'follow' => 0 + ); +} + +$_W['oauth_account'] = $_W['account']['oauth'] = array( + 'key' => $_W['account']['key'], + 'secret' => $_W['account']['secret'], + 'acid' => $_W['account']['acid'], + 'type' => $_W['account']['type'], + 'level' => $_W['account']['level'], + 'support_oauthinfo' => $_W['account']->supportOauthInfo, + 'support_jssdk' => $_W['account']->supportJssdk, +); +$unisetting = uni_setting_load(); +if (empty($unisetting['oauth']) && $_W['account']->typeSign == 'account' && $_W['account']['level'] != ACCOUNT_SERVICE_VERIFY) { + $global_oauth = uni_account_global_oauth(); + $unisetting['oauth'] = (array)$global_oauth['oauth']; +} +if (!empty($unisetting['oauth']['account'])) { + $oauth = uni_fetch($unisetting['oauth']['account']); + if (!empty($oauth) && $_W['account']['level'] <= $oauth['level']) { + $_W['oauth_account'] = $_W['account']['oauth'] = array( + 'key' => $oauth['key'], + 'secret' => $oauth['secret'], + 'acid' => $oauth['acid'], + 'type' => $oauth['type'], + 'level' => $oauth['level'], + 'support_oauthinfo' => $oauth->supportOauthInfo, + 'support_jssdk' => $oauth->supportJssdk, + ); + unset($oauth); + } +} + +if ($controller != 'utility') { + $_W['token'] = token(); +} + +if (!empty($_W['account']['oauth']) && $_W['account']['oauth']['support_oauthinfo'] && empty($_W['isajax']) && + (($_W['container'] == 'baidu' && $_W['account']->typeSign != 'account') || $_W['container'] != 'baidu')) { + + if (($_W['platform'] == 'account' && !$_GPC['logout'] && empty($_W['openid']) && ($controller != 'auth' || ($controller == 'auth' && !in_array($action, array('forward', 'oauth'))))) || + ($_W['platform'] == 'account' && !$_GPC['logout'] && empty($_SESSION['oauth_openid']) && ($controller != 'auth'))) { + $state = 'we7sid-' . $_W['session_id']; + if (empty($_SESSION['dest_url'])) { + $_SESSION['dest_url'] = urlencode($_W['siteurl']); + } + $oauth_type = 'snsapi_base'; + if ($controller == 'entry' && !empty($_GPC['m'])) { + $module_info = module_fetch($_GPC['m']); + if ($module_info['oauth_type'] == OAUTH_TYPE_USERINFO) { + $oauth_type = 'snsapi_userinfo'; + } + } + if (intval($_W['account']['level']) != ACCOUNT_SERVICE_VERIFY) { + $oauth_type = 'snsapi_userinfo'; + } + $oauth_url = uni_account_oauth_host(); + $url = $oauth_url . "app/index.php?i={$_W['uniacid']}&c=auth&a=oauth&scope=" . $oauth_type; + $callback = urlencode($url); + $oauth_account = WeAccount::create($_W['account']['oauth']); + if ($oauth_type == 'snsapi_base') { + $forward = $oauth_account->getOauthCodeUrl($callback, $state); + } else { + $forward = $oauth_account->getOauthUserInfoUrl($callback, $state); + } + header('Location: ' . $forward); + exit(); + } +} + +if ($_W['platform'] == 'account' && $_W['account']->supportJssdk && $controller != 'utility') { + if (!empty($unisetting['jsauth_acid'])) { + $jsauth_acid = $unisetting['jsauth_acid']; + } else { + if ($_W['account']['level'] < ACCOUNT_SUBSCRIPTION_VERIFY && !empty($unisetting['oauth']['account'])) { + $jsauth_acid = $unisetting['oauth']['account']; + } else { + $jsauth_acid = $_W['acid']; + } + } + if (!empty($jsauth_acid)) { + $account_api = WeAccount::create($jsauth_acid); + if (!empty($account_api)) { + $_W['account']['jssdkconfig'] = $account_api->getJssdkConfig(); + $_W['account']['jsauth_acid'] = $jsauth_acid; + } + } + unset($jsauth_acid, $account_api); +} + +$_W['attachurl'] = attachment_set_attach_url(); \ No newline at end of file diff --git a/app/common/common.func.php b/app/common/common.func.php new file mode 100644 index 0000000..c098222 --- /dev/null +++ b/app/common/common.func.php @@ -0,0 +1,47 @@ + array( + 'default' => 'home', + ), + 'mc' => array( + 'default' => 'home' + ) +); + +if ($_W['setting']['copyright']['status'] == 1) { + $_W['siteclose'] = true; + message('抱歉,站点已关闭,关闭原因:' . $_W['setting']['copyright']['reason']); +} + +$controllers = array(); +$handle = opendir(IA_ROOT . '/app/source/'); +if (!empty($handle)) { + while ($dir = readdir($handle)) { + if ($dir != '.' && $dir != '..') { + $controllers[] = $dir; + } + } +} +if (!in_array($controller, $controllers)) { + $controller = 'home'; +} +$init = IA_ROOT . "/app/source/{$controller}/__init.php"; +if (is_file($init)) { + require $init; +} + +$actions = array(); +$handle = opendir(IA_ROOT . '/app/source/' . $controller); +if (!empty($handle)) { + while ($dir = readdir($handle)) { + if ($dir != '.' && $dir != '..' && strexists($dir, '.ctrl.php')) { + $dir = str_replace('.ctrl.php', '', $dir); + $actions[] = $dir; + } + } +} + +if (!in_array($action, $actions)) { + $action = $acl[$controller]['default']; +} +if (!in_array($action, $actions)) { + $action = $actions[0]; +} +require _forward($controller, $action); + +function _forward($c, $a) +{ + $file = IA_ROOT . '/app/source/' . $c . '/' . $a . '.ctrl.php'; + return $file; +} \ No newline at end of file diff --git a/app/source/auth/oauth.ctrl.php b/app/source/auth/oauth.ctrl.php new file mode 100644 index 0000000..7516b71 --- /dev/null +++ b/app/source/auth/oauth.ctrl.php @@ -0,0 +1,279 @@ +func('communication'); + +$code = $_GPC['code']; +$scope = $_GPC['scope']; +if (empty($_W['account']['oauth']) || empty($code)) { + exit('通信错误,请在微信中重新发起请求'); +} +$oauth_account = WeAccount::create($_W['account']['oauth']); +$oauth = $oauth_account->getOauthInfo($code); + +if (is_error($oauth) || empty($oauth['openid'])) { + $state = ''; + if (isset($_GPC['state']) && !empty($_GPC['state']) && strexists($_GPC['state'], 'we7sid-')) { + $state = $_GPC['state']; + } + $url = "{$_W['siteroot']}app/index.php?i={$_W['uniacid']}&c=auth&a=oauth&scope=snsapi_base"; + $callback = urlencode($url); + $forward = $oauth_account->getOauthCodeUrl($callback, $state); + header('Location: ' . $forward); + exit; +} +$_SESSION['oauth_openid'] = $oauth['openid']; +$_SESSION['oauth_acid'] = $_W['account']['oauth']['acid']; + +if (intval($_W['account']['level']) == ACCOUNT_SERVICE_VERIFY) { + $fan = mc_fansinfo($oauth['openid']); + if (!empty($fan)) { + $_SESSION['openid'] = $oauth['openid']; + if (empty($_SESSION['uid'])) { + if (!empty($fan['uid'])) { + $member = mc_fetch($fan['uid'], array('uid')); + if (!empty($member) && $member['uniacid'] == $_W['uniacid']) { + $_SESSION['uid'] = $member['uid']; + } + } + } + } else { + $accObj = WeAccount::createByUniacid($_W['uniacid']); + $userinfo = $accObj->fansQueryInfo($oauth['openid']); + + if (!is_error($userinfo) && !empty($userinfo) && !empty($userinfo['subscribe'])) { + $userinfo['nickname'] = stripcslashes($userinfo['nickname']); + $userinfo['avatar'] = $userinfo['headimgurl']; + $_SESSION['userinfo'] = base64_encode(iserializer($userinfo)); + $record = array( + 'openid' => $userinfo['openid'], + 'uid' => 0, + 'acid' => $_W['acid'], + 'uniacid' => $_W['uniacid'], + 'salt' => random(8), + 'updatetime' => TIMESTAMP, + 'nickname' => stripslashes($userinfo['nickname']), + 'follow' => $userinfo['subscribe'], + 'followtime' => $userinfo['subscribe_time'], + 'unfollowtime' => 0, + 'unionid' => $userinfo['unionid'], + 'tag' => base64_encode(iserializer($userinfo)), + 'user_from' => $_W['account']->typeSign == 'wxapp' ? 1 : 0, + ); + + if (!isset($unisetting['passport']) || empty($unisetting['passport']['focusreg'])) { + $email = md5($oauth['openid']) . '@we7.cc'; + $email_exists_member = table('mc_members') + ->where(array( + 'email' => $email, + 'uniacid' => $_W['uniacid'] + )) + ->getcolumn('uid'); + if (!empty($email_exists_member)) { + $uid = $email_exists_member; + } else { + $default_groupid = table('mc_groups') + ->where(array( + 'uniacid' => $_W['uniacid'], + 'isdefault' => 1 + )) + ->getcolumn('groupid'); + $data = array( + 'uniacid' => $_W['uniacid'], + 'email' => $email, + 'salt' => random(8), + 'groupid' => $default_groupid, + 'createtime' => TIMESTAMP, + 'password' => md5($message['from'] . $data['salt'] . $_W['config']['setting']['authkey']), + 'nickname' => stripslashes($userinfo['nickname']), + 'avatar' => $userinfo['headimgurl'], + 'gender' => $userinfo['sex'], + 'nationality' => $userinfo['country'], + 'resideprovince' => $userinfo['province'] . '省', + 'residecity' => $userinfo['city'] . '市', + ); + table('mc_members')->fill($data)->save(); + $uid = pdo_insertid(); + } + $record['uid'] = $uid; + $_SESSION['uid'] = $uid; + } + table('mc_mapping_fans')->fill($record)->save(); + $mc_fans_tag_table = table('mc_fans_tag'); + $mc_fans_tag_fields = mc_fans_tag_fields(); + $fans_tag_update_info = array(); + foreach ($userinfo as $fans_field_key => $fans_field_info) { + if (in_array($fans_field_key, array_keys($mc_fans_tag_fields))) { + $fans_tag_update_info[$fans_field_key] = $fans_field_info; + } + $fans_tag_update_info['tagid_list'] = iserializer($fans_tag_update_info['tagis_list']); + } + $fans_tag_exists = $mc_fans_tag_table->getByOpenid($fans_tag_update_info['openid']); + if (!empty($fans_tag_exists)) { + table('mc_fans_tag') + ->where(array('openid' => $fans_tag_update_info['openid'])) + ->fill($fans_tag_update_info) + ->save(); + } else { + table('mc_fans_tag')->fill($fans_tag_update_info)->save(); + } + } else { + $record = array( + 'openid' => $oauth['openid'], + 'nickname' => '', + 'subscribe' => '0', + 'subscribe_time' => '', + 'headimgurl' => '', + ); + } + $_SESSION['openid'] = $oauth['openid']; + $_W['fans'] = $record; + $_W['fans']['from_user'] = $record['openid']; + } +} +if (intval($_W['account']['level']) != ACCOUNT_SERVICE_VERIFY) { + $mc_oauth_fan = mc_oauth_fans($oauth['openid'], $_W['uniacid']); + if (empty($mc_oauth_fan)) { + $data = array( + 'uniacid' => $_W['uniacid'], + 'oauth_openid' => $oauth['openid'], + 'uid' => intval($_SESSION['uid']), + 'openid' => $_SESSION['openid'] + ); + table('mc_oauth_fans')->fill($data)->save(); + } + if (!empty($oauth['unionid'])) { + $fan = table('mc_mapping_fans') + ->searchWithUnionid($oauth['unionid']) + ->searchWithUniacid($_W['uniacid']) + ->get(); + if (!empty($fan)) { + if (!empty($fan['uid'])) { + $_SESSION['uid'] = intval($fan['uid']); + } + if (!empty($fan['openid'])) { + $_SESSION['openid'] = strval($fan['openid']); + } + } + } else { + if (!empty($mc_oauth_fan)) { + if (empty($_SESSION['uid']) && !empty($mc_oauth_fan['uid'])) { + $_SESSION['uid'] = intval($mc_oauth_fan['uid']); + } + if (empty($_SESSION['openid']) && !empty($mc_oauth_fan['openid'])) { + $_SESSION['openid'] = strval($mc_oauth_fan['openid']); + } + } + } +} +if ($scope == 'userinfo' || $scope == 'snsapi_userinfo') { + $userinfo = $oauth_account->getOauthUserInfo($oauth['access_token'], $oauth['openid']); + if (!is_error($userinfo)) { + $userinfo['nickname'] = stripcslashes($userinfo['nickname']); + $userinfo['avatar'] = $userinfo['headimgurl']; + $_SESSION['userinfo'] = base64_encode(iserializer($userinfo)); + $fan = table('mc_mapping_fans')->searchWithOpenid($oauth['openid'])->searchWithUniacid($_W['uniacid'])->get(); + if (!empty($fan)) { + $record = array(); + $record['updatetime'] = TIMESTAMP; + $record['nickname'] = stripslashes($userinfo['nickname']); + $record['tag'] = base64_encode(iserializer($userinfo)); + if (empty($fan['unionid'])) { + $record['unionid'] = !empty($userinfo['unionid']) ? $userinfo['unionid'] : ''; + } + table('mc_mapping_fans') + ->where(array( + 'openid' => $fan['openid'], + 'uniacid' => $_W['uniacid'] + )) + ->fill($record) + ->save(); + if (!empty($fan['uid']) || !empty($_SESSION['uid'])) { + $uid = $fan['uid']; + if (empty($uid)) { + $uid = $_SESSION['uid']; + } + $user = mc_fetch($uid, array('nickname', 'gender', 'residecity', 'resideprovince', 'nationality', 'avatar')); + $record = array(); + if (empty($user['nickname']) && !empty($userinfo['nickname'])) { + $record['nickname'] = stripslashes($userinfo['nickname']); + } + if (empty($user['gender']) && !empty($userinfo['sex'])) { + $record['gender'] = $userinfo['sex']; + } + if (empty($user['residecity']) && !empty($userinfo['city'])) { + $record['residecity'] = $userinfo['city'] . '市'; + } + if (empty($user['resideprovince']) && !empty($userinfo['province'])) { + $record['resideprovince'] = $userinfo['province'] . '省'; + } + if (empty($user['nationality']) && !empty($userinfo['country'])) { + $record['nationality'] = $userinfo['country']; + } + if (empty($user['avatar']) && !empty($userinfo['headimgurl'])) { + $record['avatar'] = $userinfo['headimgurl']; + } + if (!empty($record)) { + mc_update($user['uid'], $record); + } + } + } else { + $record = array( + 'openid' => $oauth['openid'], + 'uid' => 0, + 'acid' => $_W['acid'], + 'uniacid' => $_W['uniacid'], + 'salt' => random(8), + 'updatetime' => TIMESTAMP, + 'nickname' => $userinfo['nickname'], + 'follow' => 0, + 'followtime' => 0, + 'unfollowtime' => 0, + 'tag' => base64_encode(iserializer($userinfo)), + 'unionid' => !empty($userinfo['unionid']) ? $userinfo['unionid'] : '', + 'user_from' => $_W['account']->typeSign == 'wxapp' ? 1 : 0, + ); + + if (!isset($unisetting['passport']) || empty($unisetting['passport']['focusreg'])) { + $default_groupid = table('mc_groups') + ->where(array( + 'uniacid' => $_W['uniacid'], + 'isdefault' => 1 + )) + ->getcolumn('groupid'); + $data = array( + 'uniacid' => $_W['uniacid'], + 'email' => md5($oauth['openid']) . '@we7.cc', + 'salt' => random(8), + 'groupid' => $default_groupid, + 'createtime' => TIMESTAMP, + 'password' => md5($message['from'] . $data['salt'] . $_W['config']['setting']['authkey']), + 'nickname' => $userinfo['nickname'], + 'avatar' => $userinfo['headimgurl'], + 'gender' => $userinfo['sex'], + 'nationality' => $userinfo['country'], + 'resideprovince' => $userinfo['province'] . '省', + 'residecity' => $userinfo['city'] . '市', + ); + table('mc_members') + ->fill($data) + ->save(); + $uid = pdo_insertid(); + $record['uid'] = $uid; + $_SESSION['uid'] = $uid; + } + table('mc_mapping_fans')->fill($record)->save(); + } + } else { + message('微信授权获取用户信息失败,错误信息为: ' . $userinfo['message']); + } +} + +$forward = urldecode($_SESSION['dest_url']); +$forward = strexists($forward, 'i=') ? $forward : "{$forward}&i={$_W['uniacid']}"; +if (strpos($forward, '&wxref=mp.weixin.qq.com')) { + $forward = str_replace('&wxref=mp.weixin.qq.com', '', $forward) . '&wxref=mp.weixin.qq.com#wechat_redirect'; +} else { + $forward .= '&wxref=mp.weixin.qq.com#wechat_redirect'; +} +header('Location: ' . $forward); +exit; \ No newline at end of file diff --git a/app/source/entry/__init.php b/app/source/entry/__init.php new file mode 100644 index 0000000..3a0351c --- /dev/null +++ b/app/source/entry/__init.php @@ -0,0 +1,40 @@ +model('module'); + +if (empty($action)) { + $action = 'site'; +} + +$eid = intval($_GPC['eid']); +if (!empty($eid)) { + $entry = module_entry($eid); +} else { + $entry = array( + 'module' => $_GPC['m'], + 'do' => $_GPC['do'], + 'state' => $_GPC['state'], + 'direct' => 0, + ); +} +//$module_exist_in_account = table('uni_modules')->where(array('uniacid' => $_W['uniacid'], 'module_name' => $entry['module']))->get(); +//if (empty($module_exist_in_account) && !in_array($entry['module'], module_system())) { +// message('您访问的功能模块不存在,请重新进入'); +//} +if (empty($entry) || empty($entry['do'])) { + message('非法访问.'); +} + +$_GPC['__entry'] = $entry['title']; +$_GPC['__state'] = $entry['state']; +$_GPC['state'] = $entry['state']; +$_GPC['m'] = $entry['module']; +$_GPC['do'] = $entry['do']; + +$_W['current_module'] = module_fetch($entry['module']); +define('IN_MODULE', $entry['module']); \ No newline at end of file diff --git a/app/source/entry/site.ctrl.php b/app/source/entry/site.ctrl.php new file mode 100644 index 0000000..8fd7af4 --- /dev/null +++ b/app/source/entry/site.ctrl.php @@ -0,0 +1,10 @@ +$method()); +} +exit(); \ No newline at end of file diff --git a/framework/bootstrap.inc.php b/framework/bootstrap.inc.php new file mode 100644 index 0000000..3dad363 --- /dev/null +++ b/framework/bootstrap.inc.php @@ -0,0 +1,171 @@ +func('global'); +load()->func('compat'); +load()->func('compat.biz'); +load()->func('pdo'); +load()->classs('account'); +load()->model('cache'); +load()->model('account'); +load()->model('setting'); +load()->model('module'); +load()->library('agent'); +load()->classs('db'); +load()->func('communication'); + +define('CLIENT_IP', getip()); + +$_W['config'] = $config; +$_W['config']['db']['tablepre'] = !empty($_W['config']['db']['master']['tablepre']) ? $_W['config']['db']['master']['tablepre'] : $_W['config']['db']['tablepre']; +$_W['timestamp'] = TIMESTAMP; +$_W['charset'] = $_W['config']['setting']['charset']; +$_W['clientip'] = CLIENT_IP; + +unset($configfile, $config); + +define('ATTACHMENT_ROOT', IA_ROOT . '/attachment/'); +error_reporting(0); + +if (!in_array($_W['config']['setting']['cache'], array('mysql', 'memcache', 'redis'))) { + $_W['config']['setting']['cache'] = 'mysql'; +} +load()->func('cache'); + +if (function_exists('date_default_timezone_set')) { + date_default_timezone_set($_W['config']['setting']['timezone']); +} +if (!empty($_W['config']['setting']['memory_limit']) && function_exists('ini_get') && function_exists('ini_set')) { + if ($_W['config']['setting']['memory_limit'] != @ini_get('memory_limit')) { + @ini_set('memory_limit', $_W['config']['setting']['memory_limit']); + } +} + +if (isset($_W['config']['setting']['https']) && $_W['config']['setting']['https'] == '1') { + $_W['ishttps'] = $_W['config']['setting']['https']; +} else { + $_W['ishttps'] = isset($_SERVER['SERVER_PORT']) && 443 == $_SERVER['SERVER_PORT'] || + isset($_SERVER['HTTP_FROM_HTTPS']) && 'on' == strtolower($_SERVER['HTTP_FROM_HTTPS']) || + (isset($_SERVER['HTTPS']) && 'off' != strtolower($_SERVER['HTTPS'])) || + isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && 'https' == strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) || + isset($_SERVER['HTTP_X_CLIENT_SCHEME']) && 'https' == strtolower($_SERVER['HTTP_X_CLIENT_SCHEME']) ? true : false; +} + +$_W['isajax'] = isset($_SERVER['HTTP_X_REQUESTED_WITH']) && 'xmlhttprequest' == strtolower($_SERVER['HTTP_X_REQUESTED_WITH']); +$_W['ispost'] = isset($_SERVER['REQUEST_METHOD']) && 'POST' == $_SERVER['REQUEST_METHOD']; + +$_W['sitescheme'] = $_W['ishttps'] ? 'https://' : 'http://'; +$_W['script_name'] = htmlspecialchars(scriptname()); +$sitepath = substr($_SERVER['PHP_SELF'], 0, strrpos($_SERVER['PHP_SELF'], '/')); +$_W['siteroot'] = htmlspecialchars($_W['sitescheme'] . (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : '') . $sitepath); + +if ('/' != substr($_W['siteroot'], -1)) { + $_W['siteroot'] .= '/'; +} +$urls = parse_url($_W['siteroot']); +$urls['path'] = str_replace(array('/web', '/app', '/payment/wechat', '/payment/alipay', '/payment/jueqiymf', '/api'), '', $urls['path']); +$urls['scheme'] = !empty($urls['scheme']) ? $urls['scheme'] : 'http'; +$urls['host'] = !empty($urls['host']) ? $urls['host'] : ''; +$_W['siteroot'] = $urls['scheme'] . '://' . $urls['host'] . ((!empty($urls['port']) && '80' != $urls['port']) ? ':' . $urls['port'] : '') . $urls['path']; + +if (MAGIC_QUOTES_GPC) { + $_GET = istripslashes($_GET); + $_POST = istripslashes($_POST); + $_COOKIE = istripslashes($_COOKIE); +} +foreach ($_GET as $key => $value) { + if (is_string($value) && !is_numeric($value)) { + $value = safe_gpc_string($value); + } + $_GET[$key] = $_GPC[$key] = $value; +} +$cplen = strlen($_W['config']['cookie']['pre']); +foreach ($_COOKIE as $key => $value) { + if ($_W['config']['cookie']['pre'] == substr($key, 0, $cplen)) { + $_GPC[substr($key, $cplen)] = $value; + } +} +unset($cplen, $key, $value); + +$_GPC = array_merge($_GPC, $_POST); +$_GPC = ihtmlspecialchars($_GPC); + +$_W['siteurl'] = $urls['scheme'] . '://' . $urls['host'] . ((!empty($urls['port']) && '80' != $urls['port']) ? ':' . $urls['port'] : '') . $_W['script_name'] . '?' . http_build_query($_GET, '', '&'); + +if (!$_W['isajax']) { + $input = file_get_contents('php://input'); + if (!empty($input)) { + $__input = @json_decode($input, true); + if (!empty($__input)) { + $_GPC['__input'] = $__input; + $_W['isajax'] = true; + } + } + unset($input, $__input); +} +$_W['uniacid'] = $_W['uid'] = 0; + +if ($_W['config']['setting']['development'] == 1) { + ini_set('display_errors', '1'); + error_reporting(E_ALL ^ E_NOTICE); +} +setting_load(); +define('DEVELOPMENT', $_W['config']['setting']['development'] == 1 || $_W['setting']['copyright']['develop_status'] ==1); +if (empty($_W['setting']['upload'])) { + $_W['setting']['upload'] = array_merge($_W['config']['upload']); +} + +$_W['os'] = Agent::deviceType(); +if (Agent::DEVICE_MOBILE == $_W['os']) { + $_W['os'] = 'mobile'; +} elseif (Agent::DEVICE_DESKTOP == $_W['os']) { + $_W['os'] = 'windows'; +} else { + $_W['os'] = 'unknown'; +} + +$_W['container'] = Agent::browserType(); +if (Agent::MICRO_MESSAGE_YES == Agent::isMicroMessage()) { + $_W['container'] = 'wechat'; +} elseif (Agent::BROWSER_TYPE_ANDROID == $_W['container']) { + $_W['container'] = 'android'; +} elseif (Agent::BROWSER_TYPE_IPAD == $_W['container']) { + $_W['container'] = 'ipad'; +} elseif (Agent::BROWSER_TYPE_IPHONE == $_W['container']) { + $_W['container'] = 'iphone'; +} elseif (Agent::BROWSER_TYPE_IPOD == $_W['container']) { + $_W['container'] = 'ipod'; +}else { + $_W['container'] = 'unknown'; +} + +if ('wechat' == $_W['container'] || 'baidu' == $_W['container']) { + $_W['platform'] = 'account'; +} + +$controller = !empty($_GPC['c']) ? $_GPC['c'] : ''; +$action = !empty($_GPC['a']) ? $_GPC['a'] : ''; +$do = !empty($_GPC['do']) ? $_GPC['do'] : ''; +header('Content-Type: text/html; charset=' . $_W['charset']); \ No newline at end of file diff --git a/framework/builtin/core/index.html b/framework/builtin/core/index.html new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/framework/builtin/core/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/framework/builtin/core/module.php b/framework/builtin/core/module.php new file mode 100644 index 0000000..af5bf76 --- /dev/null +++ b/framework/builtin/core/module.php @@ -0,0 +1,353 @@ + 'basic_reply', + 'news' => 'news_reply', + 'image' => 'images_reply', + 'music' => 'music_reply', + 'voice' => 'voice_reply', + 'video' => 'video_reply', + 'wxcard' => 'wxcard_reply', + 'keyword' => 'basic_reply', + ); + private $options = array( + 'basic' => true, + 'news' => true, + 'image' => true, + 'music' => true, + 'voice' => true, + 'video' => true, + 'wxcard' => true, + 'keyword' => true, + 'module' => true, + ); + private $replies = array(); + + public function fieldsFormDisplay($rid = 0, $option = array()) { + global $_GPC, $_W, $setting_keyword; + load()->model('material'); + load()->model('reply'); + $module_name = safe_gpc_string($_GPC['module_name']) ?: safe_gpc_string($_GPC['m']); + $replies = array(); + switch ($_GPC['a']) { + case 'mass': + if (!empty($rid) && $rid > 0) { + $isexists = table('mc_mass_record')->getById($rid); + } + if (!empty($isexists['media_id']) && !empty($isexists['msgtype'])) { + $wechat_attachment = material_get($isexists['media_id']); + switch ($isexists['msgtype']) { + case 'news': + if (!empty($wechat_attachment['news'])) { + foreach ($wechat_attachment['news'] as &$item) { + $item['thumb_url'] = tomedia($item['thumb_url']); + $item['media_id'] = $isexists['media_id']; + $item['attach_id'] = $item['attach_id']; + $item['perm'] = $wechat_attachment['model']; + } + unset($item); + } + $replies['news'] = $wechat_attachment['news']; + break; + case 'image': + $replies['image'][0]['img_url'] = tomedia($wechat_attachment['attachment']); + $replies['image'][0]['mediaid'] = $isexists['media_id']; + break; + case 'voice': + $replies['voice'][0]['title'] = $wechat_attachment['filename']; + $replies['voice'][0]['mediaid'] = $isexists['media_id']; + break; + case 'video': + $replies['video'][0] = iunserializer($wechat_attachment['tag']); + $replies['video'][0]['mediaid'] = $isexists['media_id']; + break; + } + } + break; + default: + if (!empty($rid)) { + $rule_rid = $rid; + if (in_array($module_name, array('welcome', 'default'))) { + $rule_rid = table('rule_keyword')->where(array('rid' => $rid))->getcolumn('rid'); + } + $isexists = reply_single($rule_rid); + } + if ('special' == $module_name) { + $default_setting = uni_setting_load('default_message', $_W['uniacid']); + $default_setting = $default_setting['default_message'] ? $default_setting['default_message'] : array(); + $reply_type = $default_setting[$_GPC['type']]['type']; + if (empty($reply_type)) { + if (!empty($default_setting[$_GPC['type']]['keyword'])) { + $reply_type = 'keyword'; + } + if (!empty($default_setting[$_GPC['type']]['module'])) { + $reply_type = 'module'; + } + if (empty($reply_type)) { + break; + } + } + if ('module' == $reply_type) { + $replies['module'][0]['name'] = $default_setting[$_GPC['type']]['module']; + $module_info = table('modules')->getByName($default_setting[$_GPC['type']]['module']); + $replies['module'][0]['title'] = $module_info['title']; + if (file_exists(IA_ROOT . '/addons/' . $module_info['name'] . '/custom-icon.jpg')) { + $replies['module'][0]['icon'] = '../addons/' . $module_info['name'] . '/custom-icon.jgp'; + } else { + $replies['module'][0]['icon'] = '../addons/' . $module_info['name'] . '/icon.jpg'; + } + } else { + $replies['keyword'][0]['name'] = $isexists['name']; + $replies['keyword'][0]['content'] = $setting_keyword; + $replies['keyword'][0]['rid'] = $rid; + } + break; + } + if (!empty($isexists)) { + $module = $isexists['module']; + $module = 'images' == $module ? 'image' : $module; + + if ('reply' == $_GPC['a'] && (!empty($module_name) && 'keyword' == $module_name)) { + foreach ($this->tablename as $key => $tablename) { + if ('keyword' != $key) { + $replies[$key] = table($tablename)->where(array('rid' => $rid))->orderby('id')->getall(); + switch ($key) { + case 'image': + foreach ($replies[$key] as &$img_value) { + $img = table('wechat_attachment')->getByMediaId($img_value['mediaid']); + $img_value['img_url'] = tomedia($img['attachment'], true); + } + unset($img_value); + break; + case 'news': + foreach ($replies[$key] as &$news_value) { + if (!empty($news_value) && !empty($news_value['media_id'])) { + $news_material = material_get($news_value['media_id']); + if (!is_error($news_material)) { + $news_value['attach_id'] = $news_material['id']; + $news_value['model'] = $news_material['model']; + $news_value['description'] = $news_material['news'][0]['digest']; + $news_value['thumb'] = tomedia($news_material['news'][0]['thumb_url']); + } + } else { + $news_value['thumb'] = tomedia($news_value['thumb']); + } + } + unset($news_value); + break; + case 'video': + foreach ($replies[$key] as &$video_value) { + $video_material = material_get($video_value['mediaid']); + $video_value['filename'] = $video_material['filename']; + } + unset($video_value); + break; + } + } + } + } else { + $replies['keyword'][0]['name'] = $isexists['name']; + $replies['keyword'][0]['rid'] = $rid; + $replies['keyword'][0]['content'] = $setting_keyword; + } + } + break; + } + if (!is_array($option)) { + $option = array(); + } + $options = array_merge($this->options, $option); + include $this->template('display'); + } + + public function fieldsFormValidate($rid = 0) { + global $_GPC; + $ifEmpty = 1; + $reply = ''; + foreach ($this->modules as $key => $value) { + if ('' != trim($_GPC['reply']['reply_' . $value])) { + $ifEmpty = 0; + } + if (('music' == $value || 'video' == $value || 'wxcard' == $value || 'news' == $value) && !empty($_GPC['reply']['reply_' . $value])) { + $reply = ltrim($_GPC['reply']['reply_' . $value], '{'); + $reply = rtrim($reply, '}'); + $reply = explode('},{', $reply); + foreach ($reply as &$val) { + $val = htmlspecialchars_decode('{' . $val . '}'); + } + $this->replies[$value] = $reply; + } else { + $this->replies[$value] = htmlspecialchars_decode($_GPC['reply']['reply_' . $value], ENT_QUOTES); + } + } + if ($ifEmpty) { + return error(1, '必须填写有效的回复内容.'); + } + + return ''; + } + + public function fieldsFormSubmit($rid = 0) { + global $_GPC, $_W; + permission_check_account_user('platform_reply_keyword'); + $delsql = ''; + foreach ($this->modules as $k => $val) { + $tablename = $this->tablename[$val]; + if (!empty($tablename)) { + table($tablename)->where(array('rid' => $rid))->delete(); + } + } + + foreach ($this->modules as $val) { + $replies = array(); + + $tablename = $this->tablename[$val]; + if ($this->replies[$val]) { + if (is_array($this->replies[$val])) { + foreach ($this->replies[$val] as $value) { + $replies[] = json_decode($value, true); + } + } else { + $replies = explode(',', $this->replies[$val]); + foreach ($replies as &$v) { + $v = json_decode($v); + } + } + } + switch ($val) { + case 'basic': + if (!empty($replies)) { + foreach ($replies as $reply) { + table($tablename)->fill(array('rid' => $rid, 'content' => $reply))->save(); + } + } + break; + case 'news': + if (!empty($replies)) { + $parent_id = 0; + $attach_id = 0; + foreach ($replies as $k => $reply) { + if (!empty($attach_id) && $reply['attach_id'] == $attach_id) { + $reply['parent_id'] = $parent_id; + } + if ('local' == $reply['model']) { + $reply['mediaid'] = $reply['attach_id']; + } + table($tablename) + ->fill(array( + 'rid' => $rid, + 'parent_id' => $reply['parent_id'], + 'title' => $reply['title'], + 'thumb' => tomedia($reply['thumb']), + 'createtime' => $reply['createtime'], + 'media_id' => $reply['mediaid'], + 'displayorder' => $reply['displayorder'], + 'description' => $reply['description'], + 'url' => $reply['url'] + )) + ->save(); + if (empty($attach_id) || $reply['attach_id'] != $attach_id) { + $parent_id = pdo_insertid(); + } + $attach_id = $reply['attach_id'] ? $reply['attach_id'] : 0; + } + } + break; + case 'image': + if (!empty($replies)) { + foreach ($replies as $reply) { + table($tablename) + ->fill(array( + 'rid' => $rid, + 'mediaid' => $reply, + 'createtime' => time() + )) + ->save(); + } + } + break; + case 'music': + if (!empty($replies)) { + foreach ($replies as $reply) { + table($tablename) + ->fill(array( + 'rid' => $rid, + 'title' => $reply['title'], + 'url' => $reply['url'], + 'hqurl' => $reply['hqurl'], + 'description' => $reply['description'] + )) + ->save(); + } + } + break; + case 'voice': + if (!empty($replies)) { + foreach ($replies as $reply) { + table($tablename) + ->fill(array( + 'rid' => $rid, + 'mediaid' => $reply, + 'createtime' => time() + )) + ->save(); + } + } + break; + case 'video': + if (!empty($replies)) { + foreach ($replies as $reply) { + table($tablename) + ->fill(array( + 'rid' => $rid, + 'mediaid' => $reply['mediaid'], + 'title' => $reply['title'], + 'description' => $reply['description'], + 'createtime' => time() + )) + ->save(); + } + } + break; + case 'wxcard': + if (!empty($replies)) { + foreach ($replies as $reply) { + table($tablename) + ->fill(array( + 'rid' => $rid, + 'title' => $reply['title'], + 'card_id' => $reply['mediaid'], + 'cid' => $reply['cid'], + 'brand_name' => $reply['brandname'], + 'logo_url' => $reply['logo_url'], + 'success' => $reply['success'], + 'error' => $reply['error'] + )) + ->save(); + } + } + break; + } + } + + return true; + } + + public function ruleDeleted($rid = 0) { + global $_W; + permission_check_account_user('platform_reply_keyword'); + $reply_modules = array('basic', 'news', 'music', 'images', 'voice', 'video', 'wxcard'); + foreach ($this->tablename as $tablename) { + table($tablename) + ->where(array( + 'rid' => $rid, + 'uniacid' => $_W['uniacid'] + )) + ->delete(); + } + } +} diff --git a/framework/builtin/core/processor.php b/framework/builtin/core/processor.php new file mode 100644 index 0000000..18931e6 --- /dev/null +++ b/framework/builtin/core/processor.php @@ -0,0 +1,170 @@ +reply_type; + $key = array_rand($reply_type); + $type = $reply_type[$key]; + switch ($type) { + case 'basic': + $result = $this->basic_respond(); + + return $this->respText($result); + break; + case 'images': + $result = $this->image_respond(); + + return $this->respImage($result); + break; + case 'music': + $result = $this->music_respond(); + + return $this->respMusic(array( + 'Title' => $result['title'], + 'Description' => $result['description'], + 'MusicUrl' => $result['url'], + 'HQMusicUrl' => $result['hqurl'], + )); + break; + case 'news': + $result = $this->news_respond(); + + return $this->respNews($result); + break; + case 'voice': + $result = $this->voice_respond(); + + return $this->respVoice($result); + break; + case 'video': + $result = $this->video_respond(); + + return $this->respVideo(array( + 'MediaId' => $result['mediaid'], + 'Title' => $result['title'], + 'Description' => $result['description'], + )); + break; + } + } + + private function basic_respond() { + $rids = !is_array($this->rule) ? explode(',', $this->rule) : $this->rule; + $reply = table('basic_reply')->where(array('rid IN' => $rids))->orderby('RAND()')->get(); + if (empty($reply)) { + return false; + } + $reply['content'] = htmlspecialchars_decode($reply['content']); + $reply['content'] = str_replace(array('
', ' '), array("\n", ' '), $reply['content']); + $reply['content'] = strip_tags($reply['content'], ''); + + return $reply['content']; + } + + private function image_respond() { + global $_W; + $rid = $this->rule; + $mediaid = table('images_reply')->where(array('rid' => $rid))->orderby('RAND()')->getcolumn('mediaid'); + if (empty($mediaid)) { + return false; + } + + return $mediaid; + } + + private function music_respond() { + global $_W; + $rid = $this->rule; + $item = table('music_reply')->where(array('rid' => $rid))->orderby('RAND()')->get(); + if (empty($item['id'])) { + return false; + } + + return $item; + } + + private function news_respond() { + global $_W; + load()->model('material'); + $rid = $this->rule; + $commends = table('news_reply') + ->where(array('rid' => $rid, 'parent_id' => -1)) + ->orderby(array('displayorder' => 'DESC', 'id' => 'ASC')) + ->limit(8) + ->getall(); + if (empty($commends)) { + $main = table('news_reply') + ->where(array( + 'rid' => $rid, + 'parent_id' => 0 + )) + ->orderby('RAND()') + ->get(); + if (empty($main['id'])) { + return false; + } + $commends = table('news_reply') + ->where(array('id' => $main['id'])) + ->whereor(array('parent_id' => $main['id'])) + ->orderby(array( + 'displayorder' => 'ASC', + 'id' => 'ASC' + )) + ->limit(8) + ->getall(); + } + if (empty($commends)) { + return false; + } + $news = array(); + if (!empty($commends[0]['media_id'])) { + $news = material_build_reply($commends[0]['media_id']); + } + foreach ($commends as $key => $commend) { + $row = array(); + if (!empty($commend['media_id'])) { + if (empty($news[$key]['url'])) { + $news[$key]['url'] = $this->createMobileUrl('detail', array('id' => $commend['id'])); + } + } else { + $row['title'] = $commend['title']; + $row['description'] = $commend['description']; + !empty($commend['thumb']) && $row['picurl'] = tomedia($commend['thumb']); + $row['url'] = empty($commend['url']) ? $this->createMobileUrl('detail', array('id' => $commend['id'])) : $commend['url']; + $news[] = $row; + } + } + + return $news; + } + + private function voice_respond() { + global $_W; + $rid = $this->rule; + $mediaid = table('voice_reply') + ->where(array('rid' => $rid)) + ->orderby('RAND()') + ->getcolumn('mediaid'); + if (empty($mediaid)) { + return false; + } + + return $mediaid; + } + + private function video_respond() { + global $_W; + $rid = $this->rule; + $item = table('video_reply') + ->where(array('rid' => $rid)) + ->orderby('RAND()') + ->get(); + if (empty($item)) { + return false; + } + + return $item; + } +} diff --git a/framework/builtin/core/receiver.php b/framework/builtin/core/receiver.php new file mode 100644 index 0000000..a65b89e --- /dev/null +++ b/framework/builtin/core/receiver.php @@ -0,0 +1,133 @@ +message['event'] && !empty($this->message['ticket'])) { + $sceneid = $this->message['scene']; + $acid = $this->acid; + $uniacid = $this->uniacid; + $ticket = trim($this->message['ticket']); + if (!empty($ticket)) { + $qr = table('qrcode') + ->select(array('id', 'keyword', 'name', 'acid')) + ->where(array( + 'uniacid' => $uniacid, + 'ticket' => $ticket + )) + ->getall(); + if (!empty($qr)) { + if (1 != count($qr)) { + $qr = array(); + } else { + $qr = $qr[0]; + } + } + } + if (empty($qr)) { + $sceneid = trim($this->message['scene']); + $where = array( + 'uniacid' => $_W['uniacid'] + ); + if (is_numeric($sceneid)) { + $where['qrcid'] = $sceneid; + } else { + $where['scene_str'] = $sceneid; + } + $qr = table('qrcode') + ->select(array('id', 'keyword', 'name', 'acid')) + ->where($where) + ->get(); + } + $insert = array( + 'uniacid' => $_W['uniacid'], + 'acid' => $qr['acid'], + 'qid' => $qr['id'], + 'openid' => $this->message['from'], + 'type' => 1, + 'qrcid' => intval($sceneid), + 'scene_str' => $sceneid, + 'name' => $qr['name'], + 'createtime' => TIMESTAMP, + ); + table('qrcode_stat')->fill($insert)->save(); + } elseif ('SCAN' == $this->message['event']) { + $sceneid = trim($this->message['scene']); + $where = array('uniacid' => $_W['uniacid']); + if (is_numeric($sceneid)) { + $where['qrcid'] = $sceneid; + } else { + $where['scene_str'] = $sceneid; + } + $row = table('qrcode') + ->select(array('id', 'keyword', 'name', 'acid')) + ->where($where) + ->get(); + $insert = array( + 'uniacid' => $_W['uniacid'], + 'acid' => $row['acid'], + 'qid' => $row['id'], + 'openid' => $this->message['from'], + 'type' => 2, + 'qrcid' => intval($sceneid), + 'scene_str' => $sceneid, + 'name' => $row['name'], + 'createtime' => TIMESTAMP, + ); + if ($_W['setting']['qr_status']['status'] == 1) { + $qrLog = table('qrcode_stat')->where(array('uniacid' => $_W['uniacid'], 'qid' => $row['id'], 'openid' => $this->message['from']))->get(); + if (empty($qrLog)) table('qrcode_stat')->fill($insert)->save(); + } else { + table('qrcode_stat')->fill($insert)->save(); + } + + } elseif ('user_get_card' == $this->message['event']) { + $sceneid = $this->message['outerid']; + $row = table('qrcode')->where(array('qrcid' => $sceneid))->get(); + if (!empty($row)) { + $insert = array( + 'uniacid' => $_W['uniacid'], + 'acid' => $row['acid'], + 'qid' => $row['id'], + 'openid' => $this->message['from'], + 'type' => 2, + 'qrcid' => $sceneid, + 'scene_str' => $sceneid, + 'name' => $row['name'], + 'createtime' => TIMESTAMP, + ); + table('qrcode_stat')->fill($insert)->save(); + } + } + if ('subscribe' == $this->message['event'] && !empty($_W['account']) && ($_W['account']['level'] == ACCOUNT_SERVICE_VERIFY || $_W['account']['level'] == ACCOUNT_SUBSCRIPTION_VERIFY)) { + $account_obj = WeAccount::createByUniacid(); + $userinfo = $account_obj->fansQueryInfo($this->message['from']); + if (!is_error($userinfo) && !empty($userinfo) && !empty($userinfo['subscribe'])) { + $userinfo['nickname'] = stripcslashes($userinfo['nickname']); + $userinfo['avatar'] = $userinfo['headimgurl']; + $fans = array( + 'unionid' => $userinfo['unionid'], + 'nickname' => strip_emoji($userinfo['nickname']), + 'tag' => base64_encode(iserializer($userinfo)), + ); + table('mc_mapping_fans') + ->where(array('openid' => $this->message['from'])) + ->fill($fans) + ->save(); + $uid = !empty($_W['member']['uid']) ? $_W['member']['uid'] : $this->message['from']; + if (!empty($uid)) { + $member = array(); + if (!empty($userinfo['nickname'])) { + $member['nickname'] = $fans['nickname']; + } + if (!empty($userinfo['headimgurl'])) { + $member['avatar'] = $userinfo['headimgurl']; + } + load()->model('mc'); + mc_update($uid, $member); + } + } + } + } +} diff --git a/framework/builtin/core/site.php b/framework/builtin/core/site.php new file mode 100644 index 0000000..0716bf6 --- /dev/null +++ b/framework/builtin/core/site.php @@ -0,0 +1,272 @@ + floatval($_GPC['fee']), + 'tid' => safe_gpc_string($_GPC['tid']), + 'module' => safe_gpc_string($_GPC['module']), + ); + if (empty($params['tid']) || empty($params['fee']) || empty($params['module'])) { + message(error(1, '支付参数不完整')); + } + if ($params['fee'] <= 0) { + $notify_params = array( + 'form' => 'return', + 'result' => 'success', + 'type' => '', + 'tid' => $params['tid'], + ); + $site = WeUtility::createModuleSite($params['module']); + $method = 'payResult'; + if (method_exists($site, $method)) { + $site->$method($notify_params); + message(error(-1, '支付成功')); + } + } + $log = table('core_paylog') + ->searWithUniacid($_W['uniacid']) + ->SearWithModule($params['module']) + ->searWithTid($params['tid']) + ->get(); + if (empty($log)) { + $log = array( + 'uniacid' => $_W['uniacid'], + 'acid' => $_W['acid'], + 'openid' => $_W['member']['uid'], + 'module' => $params['module'], + 'tid' => $params['tid'], + 'fee' => $params['fee'], + 'card_fee' => $params['fee'], + 'status' => '0', + 'is_usecard' => '0', + ); + table('core_paylog')->fill($log)->save(); + } + if ('1' == $log['status']) { + message(error(1, '订单已经支付')); + } + $setting = uni_setting($_W['uniacid'], array('payment', 'creditbehaviors')); + if (!is_array($setting['payment'])) { + message(error(1, '暂无有效支付方式')); + } + $pay = $setting['payment']; + if (empty($_W['member']['uid'])) { + $pay['credit']['switch'] = false; + } + if (!empty($pay['credit']['switch'])) { + $credtis = mc_credit_fetch($_W['member']['uid']); + } + + include $this->template('pay'); + } + + + public function doMobilePay() { + global $_W, $_GPC; + + $moduels = uni_modules(); + $params = $_POST; + + if (empty($params) || !array_key_exists($params['module'], $moduels)) { + message(error(1, '模块不存在'), '', 'ajax', true); + } + + $setting = uni_setting($_W['uniacid'], 'payment'); + $dos = array(); + if (!empty($setting['payment']['credit']['pay_switch'])) { + $dos[] = 'credit'; + } + if (!empty($setting['payment']['alipay']['pay_switch'])) { + $dos[] = 'alipay'; + } + if (!empty($setting['payment']['wechat']['pay_switch'])) { + $dos[] = 'wechat'; + } + if (!empty($setting['payment']['delivery']['pay_switch'])) { + $dos[] = 'delivery'; + } + if (!empty($setting['payment']['unionpay']['pay_switch'])) { + $dos[] = 'unionpay'; + } + if (!empty($setting['payment']['baifubao']['pay_switch'])) { + $dos[] = 'baifubao'; + } + $type = in_array($params['method'], $dos) ? $params['method'] : ''; + if (empty($type)) { + message(error(1, '暂无有效支付方式,请联系商家'), '', 'ajax', true); + } + $moduleid = table('modules') + ->where(array('name' => $params['module'])) + ->getcolumn('mid'); + $moduleid = empty($moduleid) ? '000000' : sprintf('%06d', $moduleid); + $uniontid = date('YmdHis') . $moduleid . random(8, 1); + + $paylog = table('core_paylog') + ->where(array('uniacid' => $uniacid)) + ->searchWithModule($params['module']) + ->searchWithTid($params['tid']) + ->get(); + if (empty($paylog)) { + $paylog = array( + 'uniacid' => $_W['uniacid'], + 'acid' => $_W['acid'], + 'openid' => $_W['member']['uid'], + 'type' => $type, + 'module' => $params['module'], + 'tid' => $params['tid'], + 'uniontid' => $uniontid, + 'fee' => $params['fee'], + 'card_fee' => $params['fee'], + 'status' => '0', + 'is_usecard' => '0', + ); + table('core_paylog')->fill($paylog)->save(); + $paylog['plid'] = pdo_insertid(); + } + if (!empty($paylog) && '0' != $paylog['status']) { + message(error(1, '这个订单已经支付成功, 不需要重复支付.'), '', 'ajax', true); + } + if (!empty($paylog) && empty($paylog['uniontid'])) { + table('core_paylog') + ->where(array('plid' => $paylog['plid'])) + ->fill(array('uniontid' => $uniontid)) + ->save(); + } + $paylog['title'] = $params['title']; + if (intval($_GPC['iswxapp'])) { + message(error(2, $_W['siteroot'] . "app/index.php?i={$_W['uniacid']}&c=wxapp&a=home&do=go_paycenter&title={$params['title']}&plid={$paylog['plid']}"), '', 'ajax', true); + } + + if ('wechat' == $params['method']) { + return $this->doMobilePayWechat($paylog); + } elseif ('alipay' == $params['method']) { + return $this->doMobilePayAlipay($paylog); + } else { + $params['tid'] = $paylog['plid']; + $sl = base64_encode(json_encode($params)); + $auth = sha1($sl . $_W['uniacid'] . $_W['config']['setting']['authkey']); + message(error(0, $_W['siteroot'] . "/payment/{$type}/pay.php?i={$_W['uniacid']}&auth={$auth}&ps={$sl}"), '', 'ajax', true); + exit(); + } + } + + private function doMobilePayWechat($paylog = array()) { + global $_W; + load()->model('payment'); + + table('core_paylog') + ->where(array('plid' => $paylog['plid'])) + ->fill(array( + 'openid' => $_W['openid'], + 'tag' => iserializer(array('acid' => $_W['acid'], 'uid' => $_W['member']['uid'])), + )) + ->save(); + $_W['uniacid'] = $paylog['uniacid']; + + $setting = uni_setting($_W['uniacid'], array('payment')); + $wechat_payment = $setting['payment']['wechat']; + + $account = table('account_wechats') + ->where(array('acid' => $wechat_payment['account'])) + ->get(); + $wechat_payment['appid'] = $account['key']; + $wechat_payment['secret'] = $account['secret']; + + $params = array( + 'tid' => $paylog['tid'], + 'fee' => $paylog['card_fee'], + 'user' => $paylog['openid'], + 'title' => urldecode($paylog['title']), + 'uniontid' => $paylog['uniontid'], + ); + if (PAYMENT_WECHAT_TYPE_SERVICE == intval($wechat_payment['switch']) || PAYMENT_WECHAT_TYPE_BORROW == intval($wechat_payment['switch'])) { + if (!empty($_W['openid'])) { + $params['sub_user'] = $_W['openid']; + $wechat_payment_params = wechat_proxy_build($params, $wechat_payment); + } else { + $params['tid'] = $paylog['plid']; + $params['title'] = urlencode($params['title']); + $sl = base64_encode(json_encode($params)); + $auth = sha1($sl . $paylog['uniacid'] . $_W['config']['setting']['authkey']); + + $callback = urlencode($_W['siteroot'] . "payment/wechat/pay.php?i={$_W['uniacid']}&auth={$auth}&ps={$sl}"); + $proxy_pay_account = payment_proxy_pay_account(); + if (!is_error($proxy_pay_account)) { + $forward = $proxy_pay_account->getOauthCodeUrl($callback, 'we7sid-' . $_W['session_id']); + message(error(2, $forward), $forward, 'ajax'); + exit; + } + } + } else { + unset($wechat_payment['sub_mch_id']); + $wechat_payment_params = wechat_build($params, $wechat_payment); + } + if (is_error($wechat_payment_params)) { + message($wechat_payment_params, '', 'ajax', true); + } else { + message(error(0, $wechat_payment_params), '', 'ajax', true); + } + } + + private function doMobilePayAlipay($paylog = array()) { + global $_W; + + load()->model('payment'); + load()->func('communication'); + + $_W['uniacid'] = $paylog['uniacid']; + + $setting = uni_setting($_W['uniacid'], array('payment')); + $params = array( + 'tid' => $paylog['tid'], + 'fee' => $paylog['card_fee'], + 'user' => $paylog['openid'], + 'title' => urldecode($paylog['title']), + 'uniontid' => $paylog['uniontid'], + ); + $alipay_payment_params = alipay_build($params, $setting['payment']['alipay']); + if ($alipay_payment_params['url']) { + message(error(0, $alipay_payment_params['url']), '', 'ajax', true); + exit(); + } + } + + public function doMobileDetail() { + global $_W, $_GPC; + $id = intval($_GPC['id']); + $row = table('news_reply')->getById($id); + $createtime = $row['createtime']; + if (!empty($row['url'])) { + header('Location: ' . $row['url']); + exit; + } + if (!empty($row['media_id']) && 0 != intval($row['media_id'])) { + $row = table('wechat_news') + ->where(array( + 'attach_id' => $row['media_id'], + 'displayorder' => $row['displayorder'] + )) + ->get(); + $row['createtime'] = $createtime; + if (!empty($row['content_source_url'])) { + header('Location: ' . $row['content_source_url']); + exit; + } + } + $row = istripslashes($row); + $title = $row['title']; + + if ('android' == $_W['os'] && 'wechat' == $_W['container'] && $_W['account']['account']) { + $subscribeurl = "weixin://profile/{$_W['account']['account']}"; + } else { + $subscribeurl = table('account_wechats') + ->where(array('uniacid' => intval($_W['uniacid']))) + ->getcolumn('subscribeurl'); + } + include $this->template('detail'); + } +} diff --git a/framework/builtin/core/template/display.html b/framework/builtin/core/template/display.html new file mode 100644 index 0000000..1851b49 --- /dev/null +++ b/framework/builtin/core/template/display.html @@ -0,0 +1,863 @@ +
+
+ {if $_GPC['a'] == 'qr'}二维码触发的关键字 + {elseif $_GPC['a'] == 'mass'}群发内容 + {else} + {if $_GPC['c'] == 'mc' && $_GPC['a'] == 'chats'}发送聊天内容{else}触发后回复内容{/if} + {if $_GPC['a'] == 'reply' && $_GPC['m'] == 'keyword'}添加多条回复内容时, 随机回复其中一条{/if} + {/if} +
+
+ + + + + + + + + +
    +
+
+
+
+ \ No newline at end of file diff --git a/framework/builtin/core/template/mobile/detail.html b/framework/builtin/core/template/mobile/detail.html new file mode 100644 index 0000000..b722e25 --- /dev/null +++ b/framework/builtin/core/template/mobile/detail.html @@ -0,0 +1,88 @@ +{template 'header'} +
+ +
+
+

{$row['title']}

+ + {php echo date('Y-m-d', $row['createtime'])} + {$row['author']} + + {if empty($_W['account']['name'])} + 微擎团队 + {else} + {$_W['account']['name']} + {/if} + + +
+
+ +
+ {if $row['incontent'] != 0} +
+ +
+ {/if} +
+ {$row['content']} +
+
+
+{php $_share = array('content' => $row['description'], 'title' => $row['title'], 'imgUrl' => tomedia($row['thumb']));} +{template 'footer'} \ No newline at end of file diff --git a/framework/builtin/core/template/mobile/pay.html b/framework/builtin/core/template/mobile/pay.html new file mode 100644 index 0000000..6272662 --- /dev/null +++ b/framework/builtin/core/template/mobile/pay.html @@ -0,0 +1,91 @@ +
+ + +

付款详情

+
+
+
+ +
+
需付款
+
+
+
+
+ + + + + +
+
+
+ +
\ No newline at end of file diff --git a/framework/builtin/core/wxapp.php b/framework/builtin/core/wxapp.php new file mode 100644 index 0000000..356d37c --- /dev/null +++ b/framework/builtin/core/wxapp.php @@ -0,0 +1,60 @@ +searchWithUniacid($_W['uniacid']) + ->searchWithModule(safe_gpc_string($_GPC['module_name'])) + ->searchWithTid(safe_gpc_string($_GPC['orderid'])) + ->get(); + $order = array( + 'tid' => $order_info['tid'], + 'user' => $_SESSION['openid'], + 'fee' => $order_info['fee'], + 'title' => trim($_GPC['title']), + ); + + $this->module = array('name' => $order_info['module']); + $paydata = $this->pay($order); + $this->result(0, '', $paydata); + } + + + public function doPagePayResult() { + global $_GPC, $_W; + $log = table('core_paylog') + ->searchWithUniacid($_W['uniacid']) + ->searchWithModule(safe_gpc_string($_GPC['module_name'])) + ->searchWithTid(safe_gpc_string($_GPC['orderid'])) + ->get(); + if (!empty($log) && !empty($log['status'])) { + if (!empty($log['tag'])) { + $tag = iunserializer($log['tag']); + $log['uid'] = $tag['uid']; + } + $site = WeUtility::createModuleSite($log['module']); + if (!is_error($site)) { + $method = 'payResult'; + if (method_exists($site, $method)) { + $ret = array(); + $ret['weid'] = $log['uniacid']; + $ret['uniacid'] = $log['uniacid']; + $ret['result'] = 'success'; + $ret['type'] = $log['type']; + $ret['from'] = 'return'; + $ret['tid'] = $log['tid']; + $ret['uniontid'] = $log['uniontid']; + $ret['user'] = $log['openid']; + $ret['fee'] = $log['fee']; + $ret['tag'] = $tag; + $ret['is_usecard'] = $log['is_usecard']; + $ret['card_type'] = $log['card_type']; + $ret['card_fee'] = $log['card_fee']; + $ret['card_id'] = $log['card_id']; + exit($site->$method($ret)); + } + } + } + } +} diff --git a/framework/builtin/cover/processor.php b/framework/builtin/cover/processor.php new file mode 100644 index 0000000..29e70c2 --- /dev/null +++ b/framework/builtin/cover/processor.php @@ -0,0 +1,40 @@ +message['content']; + $reply = table('cover_reply')->where(array('rid' => $this->rule))->get(); + if (!empty($reply)) { + load()->model('module'); + $module = module_fetch($reply['module']); + if (empty($module) && !in_array($reply['module'], array('site', 'mc', 'card', 'page', 'clerk'))) { + return ''; + } + $url = $reply['url']; + if (empty($reply['url'])) { + $entry = table('modules_bindings') + ->select('eid') + ->where(array( + 'module' => $reply['module'], + 'do' => $reply['do'] + )) + ->get(); + $url = url('entry', array('eid' => $entry['eid'])); + } + $news = array(); + $news[] = array( + 'title' => $reply['title'], + 'description' => $reply['description'], + 'picurl' => $reply['thumb'], + 'url' => $url, + ); + + return $this->respNews($news); + } + + return ''; + } +} diff --git a/framework/builtin/default/processor.php b/framework/builtin/default/processor.php new file mode 100644 index 0000000..7e9e54a --- /dev/null +++ b/framework/builtin/default/processor.php @@ -0,0 +1,29 @@ +message['type'] + || 'view_miniprogram' == $this->message['event'] + || 'VIEW' == $this->message['event'] + ) { + return $this->respText(''); + } + $setting = uni_setting($_W['uniacid'], array('default')); + if (!empty($setting['default'])) { + $flag = array('image' => 'url', 'link' => 'url', 'text' => 'content'); + $message = $this->message; + $message['type'] = 'text'; + $message['content'] = $setting['default']; + $message['redirection'] = true; + $message['source'] = 'default'; + $message['original'] = $this->message[$flag[$this->message['type']]]; + $pars = $engine->analyzeText($message); + if (is_array($pars)) { + return array('params' => $pars); + } + } + } +} diff --git a/framework/class/account/account.class.php b/framework/class/account/account.class.php new file mode 100644 index 0000000..5fb5eb8 --- /dev/null +++ b/framework/class/account/account.class.php @@ -0,0 +1,2313 @@ + 'typeSign', + 'createtime' => 'createTime', + 'starttime' => 'startTime', + 'endtime' => 'endTime', + 'groups' => 'groups', + 'setting' => 'setting', + 'grouplevel' => 'groupLevel', + 'type_name' => 'typeName', + 'switchurl' => 'switchUrl', + 'setmeal' => 'setMeal', + 'current_user_role' => 'CurrentUserRole', + 'is_star' => 'isStar', + ); + + private static $accountClassname = array( + ACCOUNT_TYPE_OFFCIAL_NORMAL => 'weixin.account', + ACCOUNT_TYPE_OFFCIAL_AUTH => 'weixin.platform', + ACCOUNT_TYPE_APP_NORMAL => 'wxapp.account', + ACCOUNT_TYPE_APP_AUTH => 'wxapp.platform', + ACCOUNT_TYPE_WXAPP_WORK => 'wxapp.work', + ACCOUNT_TYPE_WEBAPP_NORMAL => 'webapp.account', + ACCOUNT_TYPE_PHONEAPP_NORMAL => 'phoneapp.account', + ACCOUNT_TYPE_ALIAPP_NORMAL => 'aliapp.account', + ACCOUNT_TYPE_BAIDUAPP_NORMAL => 'baiduapp.account', + ACCOUNT_TYPE_TOUTIAOAPP_NORMAL => 'toutiaoapp.account', + ); + private static $accountObj = array(); + + public function __construct($uniaccount = array()) + { + $this->uniacid = $uniaccount['uniacid']; + $cachekey = cache_system_key('uniaccount', array('uniacid' => $this->uniacid)); + $cache = cache_load($cachekey); + if (empty($cache)) { + $this->account = $uniaccount; + $cache = $this->getAccountInfo($this->uniacid); + cache_write($cachekey, $cache); + } + $this->account = array_merge((array)$cache, $uniaccount); + } + + public function __get($name) + { + if (method_exists($this, $name)) { + return $this->$name(); + } + $funcname = 'fetch' . ucfirst($name); + if (method_exists($this, $funcname)) { + return $this->$funcname(); + } + if (isset($this->$name)) { + return $this->$name; + } + + return false; + } + + + public static function create($acidOrAccount = array()) + { + global $_W; + $uniaccount = array(); + if (is_object($acidOrAccount) && $acidOrAccount instanceof self) { + return $acidOrAccount; + } + if (is_array($acidOrAccount) && !empty($acidOrAccount)) { + $uniaccount = $acidOrAccount; + } else { + $acidOrAccount = empty($acidOrAccount) ? $_W['account']['acid'] : intval($acidOrAccount); + $uniaccount = table('account')->getUniAccountByAcid($acidOrAccount); + } + if (is_error($uniaccount) || empty($uniaccount)) { + $uniaccount = $_W['account']; + } + if (!empty(self::$accountObj[$uniaccount['uniacid']])) { + return self::$accountObj[$uniaccount['uniacid']]; + } + if (!empty($uniaccount) && isset($uniaccount['type']) || !empty($uniaccount['isdeleted'])) { + return self::includes($uniaccount); + } else { + return error('-1', '帐号不存在或是已经被删除'); + } + } + + public static function token($type = 1) + { + $obj = self::includes(array('type' => $type)); + + return $obj->fetch_available_token(); + } + + public static function createByUniacid($uniacid = 0) + { + global $_W; + $uniacid = intval($uniacid) > 0 ? intval($uniacid) : $_W['uniacid']; + if (!empty(self::$accountObj[$uniacid])) { + return self::$accountObj[$uniacid]; + } + $uniaccount = table('account')->getUniAccountByUniacid($uniacid); + if (empty($uniaccount)) { + return error('-1', '帐号不存在或是已经被删除'); + } + if (!empty($_W['uid']) && !$_W['isadmin'] && !permission_account_user_role($_W['uid'], $uniacid)) { + return error('-1', '无权限操作该平台账号'); + } + return self::create($uniaccount); + } + + public static function includes($uniaccount) + { + $type = $uniaccount['type']; + if (empty(self::$accountClassname[$type])) { + return error('-1', '账号类型不存在'); + } + + $file = self::$accountClassname[$type]; + $classname = self::getClassName($file); + load()->classs($file); + $account_obj = new $classname($uniaccount); + $account_obj->type = $type; + self::$accountObj[$uniaccount['uniacid']] = $account_obj; + + return $account_obj; + } + + + public static function getClassName($filename) + { + $classname = ''; + $filename = explode('.', $filename); + foreach ($filename as $val) { + $classname .= ucfirst($val); + } + + return $classname; + } + + public function checkIntoManage() + { + global $_GPC; + load()->model('account'); + $type_info = uni_account_type_sign($this->typeSign); + if ( + empty($this->account) + || ($this->supportVersion == STATUS_ON && empty($_GPC['version_id'])) + || (!empty($this->account) && !in_array($this->account['type'], $type_info['contain_type']) && !defined('IN_MODULE')) + ) { + return false; + } else { + return true; + } + } + + public function fetchAccountInfo() + { + return $this->getAccountInfo($this->account['acid']); + } + + protected function fetchCreateTime() + { + global $_W; + if ($_W['uid'] == $this->account['create_uid'] || $_W['isadmin']) { + return $this->account['createtime'] > 0 ? date('Y-m-d', $this->account['createtime']) : ''; + } + return ''; + } + + protected function fetchDisplayUrl() + { + global $_W; + return $_W['siteroot'] . 'web/home.php'; + } + + protected function fetchCurrentUserRole() + { + global $_W; + load()->model('permission'); + return permission_account_user_role($_W['uid'], $this->uniacid); + } + + protected function fetchLogo() + { + return $this->account['logo'] . '?time=' . time(); + } + + protected function fetchQrcode() + { + return $this->account['qrcode'] . '?time=' . time(); + } + + protected function fetchSwitchUrl() + { + return wurl('account/display/switch', array('uniacid' => $this->uniacid)); + } + + protected function fetchOwner() + { + $this->owner = account_owner($this->uniacid); + + return $this->owner; + } + + protected function fetchStartTime() + { + if (empty($this->owner)) { + $this->owner = $this->fetchOwner(); + } + + return $this->owner['starttime']; + } + + protected function fetchEndTime() + { + return '-1' == $this->account['endtime'] ? 0 : $this->account['endtime']; + } + + protected function fetchGroups() + { + load()->model('mc'); + $this->groups = mc_groups($this->uniacid); + + return $this->groups; + } + + protected function fetchSetting() + { + $this->setting = uni_setting_load('', $this->uniacid); + + return $this->setting; + } + + protected function fetchGroupLevel() + { + if (empty($this->setting)) { + $this->setting = $this->fetchSetting(); + } + + return $this->setting['grouplevel']; + } + + protected function fetchSetMeal() + { + return uni_setmeal($this->uniacid); + } + + protected function fetchSameAccountExist() + { + return pdo_getall($this->tablename, array('key' => $this->account['key'], 'uniacid <>' => $this->uniacid), array(), 'uniacid'); + } + + protected function fetchIsStar() + { + global $_W; + return 0; + } + + protected function supportOauthInfo() + { + if (ACCOUNT_TYPE_SIGN == $this->typeSign && ACCOUNT_SERVICE_VERIFY == $this->account['level']) { + return STATUS_ON; + } else { + return STATUS_OFF; + } + } + + protected function supportJssdk() + { + if (in_array($this->typeSign, array(WXAPP_TYPE_SIGN, ACCOUNT_TYPE_SIGN))) { + return STATUS_ON; + } else { + return STATUS_OFF; + } + } + + public function __toArray() + { + foreach ($this->account as $key => $property) { + $this[$key] = $property; + } + foreach ($this->toArrayMap as $key => $type) { + if (isset($this->$type) && !empty($this->$type)) { + $this[$key] = $this->$type; + } else { + $this[$key] = $this->__get($type); + } + } + + return $this; + } + + + public function parse($message) + { + global $_W; + if (!empty($message)) { + $message = xml2array($message); + $packet = iarray_change_key_case($message, CASE_LOWER); + $packet['from'] = $message['FromUserName']; + $packet['to'] = $message['ToUserName']; + $packet['time'] = $message['CreateTime']; + $packet['type'] = $message['MsgType']; + $packet['event'] = $message['Event']; + switch ($packet['type']) { + case 'text': + $packet['redirection'] = false; + $packet['source'] = null; + break; + case 'image': + $packet['url'] = $message['PicUrl']; + break; + case 'video': + case 'shortvideo': + $packet['thumb'] = $message['ThumbMediaId']; + break; + } + + switch ($packet['event']) { + case 'subscribe': + $packet['type'] = 'subscribe'; + case 'SCAN': + if ('SCAN' == $packet['event']) { + $packet['type'] = 'qr'; + } + if (!empty($packet['eventkey'])) { + $packet['scene'] = str_replace('qrscene_', '', $packet['eventkey']); + if (strexists($packet['scene'], '\u')) { + $packet['scene'] = '"' . str_replace('\\u', '\u', $packet['scene']) . '"'; + $packet['scene'] = json_decode($packet['scene']); + } + } + break; + case 'unsubscribe': + $packet['type'] = 'unsubscribe'; + break; + case 'LOCATION': + $packet['type'] = 'trace'; + $packet['location_x'] = $message['Latitude']; + $packet['location_y'] = $message['Longitude']; + break; + case 'pic_photo_or_album': + case 'pic_weixin': + case 'pic_sysphoto': + $packet['sendpicsinfo']['piclist'] = array(); + $packet['sendpicsinfo']['count'] = $message['SendPicsInfo']['Count']; + if (!empty($message['SendPicsInfo']['PicList'])) { + foreach ($message['SendPicsInfo']['PicList']['item'] as $item) { + if (empty($item)) { + continue; + } + $packet['sendpicsinfo']['piclist'][] = is_array($item) ? $item['PicMd5Sum'] : $item; + } + } + break; + case 'card_pass_check': + case 'card_not_pass_check': + case 'user_get_card': + case 'user_del_card': + case 'user_consume_card': + case 'poi_check_notify': + $packet['type'] = 'coupon'; + break; + } + } + + return $packet; + } + + + public function response($packet) + { + if (is_error($packet)) { + return ''; + } + if (!is_array($packet)) { + return $packet; + } + if (empty($packet['CreateTime'])) { + $packet['CreateTime'] = TIMESTAMP; + } + if (empty($packet['MsgType'])) { + $packet['MsgType'] = 'text'; + } + if (empty($packet['FuncFlag'])) { + $packet['FuncFlag'] = 0; + } else { + $packet['FuncFlag'] = 1; + } + + return array2xml($packet); + } + + public function errorCode($code, $errmsg = '未知错误') + { + $errors = array( + '-1' => '系统繁忙', + '0' => '请求成功', + '20002' => 'POST参数非法', + '40001' => '获取access_token时AppSecret错误,或者access_token无效', + '40002' => '不合法的凭证类型', + '40003' => '不合法的OpenID', + '40004' => '不合法的媒体文件类型', + '40005' => '不合法的文件类型', + '40006' => '不合法的文件大小', + '40007' => '不合法的媒体文件id', + '40008' => '不合法的消息类型', + '40009' => '不合法的图片文件大小', + '40010' => '不合法的语音文件大小', + '40011' => '不合法的视频文件大小', + '40012' => '不合法的缩略图文件大小', + '40013' => '不合法的APPID', + '40014' => '不合法的access_token', + '40015' => '不合法的菜单类型', + '40016' => '不合法的按钮个数', + '40017' => '不合法的按钮个数', + '40018' => '不合法的按钮名字长度', + '40019' => '不合法的按钮KEY长度', + '40020' => '不合法的按钮URL长度', + '40021' => '不合法的菜单版本号', + '40022' => '不合法的子菜单级数', + '40023' => '不合法的子菜单按钮个数', + '40024' => '不合法的子菜单按钮类型', + '40025' => '不合法的子菜单按钮名字长度', + '40026' => '不合法的子菜单按钮KEY长度', + '40027' => '不合法的子菜单按钮URL长度', + '40028' => '不合法的自定义菜单使用用户', + '40029' => '不合法的oauth_code', + '40030' => '不合法的refresh_token', + '40031' => '不合法的openid列表', + '40032' => '不合法的openid列表长度', + '40033' => '不合法的请求字符,不能包含\uxxxx格式的字符', + '40035' => '不合法的参数', + '40036' => '不合法的 template_id 长度', + '40037' => 'template_id不正确', + '40038' => '不合法的请求格式', + '40039' => '不合法的URL长度', + '40048' => '不合法的 url 域名', + '40050' => '不合法的分组id', + '40051' => '分组名字不合法', + '40054' => '不合法的子菜单按钮 url 域名', + '40055' => '不合法的菜单按钮 url 域名', + '40060' => '删除单篇图文时,指定的 article_idx 不合法', + '40066' => '不合法的 url', + '40117' => '分组名字不合法', + '40118' => 'media_id 大小不合法', + '40119' => 'button 类型错误', + '40120' => 'button 类型错误', + '40121' => '不合法的 media_id 类型', + '40125' => '无效的appsecret', + '40132' => '微信号不合法', + '40137' => '不支持的图片格式', + '40155' => '请勿添加其他公众号的主页链接', + '40163' => 'oauth_code已使用', + '40199' => '运单 ID 不存在', + '41001' => '缺少access_token参数', + '41002' => '缺少appid参数', + '41003' => '缺少refresh_token参数', + '41004' => '缺少secret参数', + '41005' => '缺少多媒体文件数据', + '41006' => '缺少media_id参数', + '41007' => '缺少子菜单数据', + '41008' => '缺少oauth code', + '41009' => '缺少openid', + '41010' => '缺失 url 参数', + '41028' => 'form_id不正确,或者过期', + '41029' => 'form_id已被使用', + '41030' => 'page不正确', + '42001' => 'access_token超时', + '42002' => 'refresh_token超时', + '42003' => 'oauth_code超时', + '43001' => '需要GET请求', + '43002' => '需要POST请求', + '43003' => '需要HTTPS请求', + '43004' => '需要接收者关注', + '43005' => '需要好友关系', + '44001' => '多媒体文件为空', + '44002' => 'POST的数据包为空', + '44003' => '图文消息内容为空', + '44004' => '文本消息内容为空', + '45001' => '多媒体文件大小超过限制', + '45002' => '消息内容超过限制', + '45003' => '标题字段超过限制', + '45004' => '描述字段超过限制', + '45005' => '链接字段超过限制', + '45006' => '图片链接字段超过限制', + '45007' => '语音播放时间超过限制', + '45008' => '图文消息超过限制', + '45009' => '接口调用超过限制', + '45010' => '创建菜单个数超过限制', + '45011' => 'API 调用太频繁,请稍候再试', + '45012' => '模板大小超过限制', + '45015' => '回复时间超过限制', + '45016' => '系统分组,不允许修改', + '45017' => '分组名字过长', + '45018' => '分组数量超过上限', + '45047' => '客服接口下行条数超过上限', + '45056' => '创建的标签数过多,请注意不能超过100个', + '45057' => '该标签下粉丝数超过10w,不允许直接删除', + '45058' => '不能修改0/1/2这三个系统默认保留的标签', + '45059' => '有粉丝身上的标签数已经超过限制', + '45064' => '创建菜单包含未关联的小程序', + '45065' => '24小时内不可给该组人群发该素材', + '45072' => 'command字段取值不对', + '45080' => '下发输入状态,需要之前30秒内跟用户有过消息交互', + '45081' => '已经在输入状态,不可重复下发', + '45157' => '标签名非法,请注意不能和其他标签重名', + '45158' => '标签名长度超过30个字节', + '45159' => '非法的标签', + '46001' => '不存在媒体数据', + '46002' => '不存在的菜单版本', + '46003' => '不存在的菜单数据', + '46004' => '不存在的用户', + '47001' => '解析JSON/XML内容错误', + '47501' => '参数 activity_id 错误', + '47502' => '参数 target_state 错误', + '47503' => '参数 version_type 错误', + '47504' => 'activity_id 过期', + '48001' => 'api功能未授权', + '48002' => '粉丝拒收消息', + '48003' => '请在微信平台开启群发功能', + '48004' => 'api 接口被封禁', + '48005' => 'api 禁止删除被自动回复和自定义菜单引用的素材', + '48006' => 'api 禁止清零调用次数,因为清零次数达到上限', + '48008' => '没有该类型消息的发送权限', + '50001' => '用户未授权该api', + '50002' => '用户受限,可能是违规后接口被封禁', + '50005' => '用户未关注公众号', + '40070' => '基本信息baseinfo中填写的库存信息SKU不合法。', + '41011' => '必填字段不完整或不合法,参考相应接口。', + '40056' => '无效code,请确认code长度在20个字符以内,且处于非异常状态(转赠、删除)。', + '43009' => '无自定义SN权限,请参考开发者必读中的流程开通权限。', + '43010' => '无储值权限,请参考开发者必读中的流程开通权限。', + '43011' => '无积分权限,请参考开发者必读中的流程开通权限。', + '40078' => '无效卡券,未通过审核,已被置为失效。', + '40079' => '基本信息base_info中填写的date_info不合法或核销卡券未到生效时间。', + '45021' => '文本字段超过长度限制,请参考相应字段说明。', + '40080' => '卡券扩展信息cardext不合法。', + '40097' => '基本信息base_info中填写的参数不合法。', + '45029' => '生成码个数总和到达最大个数限制', + '49004' => '签名错误。', + '43012' => '无自定义cell跳转外链权限,请参考开发者必读中的申请流程开通权限。', + '40099' => '该code已被核销。', + '61005' => '缺少接入平台关键数据,等待微信开放平台推送数据,请十分钟后再试或是检查“授权事件接收URL”是否写错(index.php?c=account&a=auth&do=ticket地址中的&符号容易被替换成&amp;)', + '61023' => '请重新授权接入该公众号', + '61451' => '参数错误 (invalid parameter)', + '61452' => '无效客服账号 (invalid kf_account)', + '61453' => '客服帐号已存在 (kf_account exsited)', + '61454' => '客服帐号名长度超过限制 ( 仅允许 10 个英文字符,不包括 @ 及 @ 后的公众号的微信号 )', + '61455' => '客服帐号名包含非法字符 ( 仅允许英文 + 数字 )', + '61456' => '客服帐号个数超过限制 (10 个客服账号 )', + '61457' => '无效头像文件类型', + '61450' => '系统错误', + '61500' => '日期格式错误', + '63001' => '部分参数为空', + '63002' => '无效的签名', + '65301' => '不存在此 menuid 对应的个性化菜单', + '65302' => '没有相应的用户', + '65303' => '没有默认菜单,不能创建个性化菜单', + '65304' => 'MatchRule 信息为空', + '65305' => '个性化菜单数量受限', + '65306' => '不支持个性化菜单的帐号', + '65307' => '个性化菜单信息为空', + '65308' => '包含没有响应类型的 button', + '65309' => '个性化菜单开关处于关闭状态', + '65310' => '填写了省份或城市信息,国家信息不能为空', + '65311' => '填写了城市信息,省份信息不能为空', + '65312' => '不合法的国家信息', + '65313' => '不合法的省份信息', + '65314' => '不合法的城市信息', + '65316' => '该公众号的菜单设置了过多的域名外跳(最多跳转到 3 个域名的链接)', + '65317' => '不合法的 URL', + '88000' => '没有留言权限', + '88001' => '该图文不存在', + '88002' => '文章存在敏感信息', + '88003' => '精选评论数已达上限', + '88004' => '已被用户删除,无法精选', + '88005' => '已经回复过了', + '88007' => '回复超过长度限制或为0', + '88008' => '该评论不存在', + '88010' => '获取评论数目不合法', + '87009' => '该回复不存在', + '87014' => '内容含有违法违规内容', + '89000' => '该公众号/小程序已经绑定了开放平台帐号', + '89001' => 'Authorizer 与开放平台帐号主体不相同', + '89002' => '该公众号/小程序未绑定微信开放平台帐号', + '89003' => '该开放平台帐号并非通过 api 创建,不允许操作', + '89004' => '该开放平台帐号所绑定的公众号/小程序已达上限(100 个)', + '89044' => '不存在该插件appid', + '89236' => '该插件不能申请', + '89237' => '已经添加该插件', + '89238' => '申请或使用的插件已经达到上限', + '89239' => '该插件不存在', + '89240' => '无法进行此操作,只有“待确认”的申请可操作通过/拒绝', + '89241' => '无法进行此操作,只有“已拒绝/已超时”的申请可操作删除', + '89242' => '该appid不在申请列表内', + '89243' => '“待确认”的申请不可删除', + '89300' => '订单无效', + '92000' => '该经营资质已添加,请勿重复添加', + '92002' => '附近地点添加数量达到上线,无法继续添加', + '92003' => '地点已被其它小程序占用', + '92004' => '附近功能被封禁', + '92005' => '地点正在审核中', + '92006' => '地点正在展示小程序', + '92007' => '地点审核失败', + '92008' => '程序未展示在该地点', + '93009' => '小程序未上架或不可见', + '93010' => '地点不存在', + '93011' => '个人类型小程序不可用', + '93012' => '非普通类型小程序(门店小程序、小店小程序等)不可用', + '93013' => '从腾讯地图获取地址详细信息失败', + '93014' => '同一资质证件号重复添加', + '9001001' => 'POST 数据参数不合法', + '9001002' => '远端服务不可用', + '9001003' => 'Ticket 不合法', + '9001004' => '获取摇周边用户信息失败', + '9001005' => '获取商户信息失败', + '9001006' => '获取 OpenID 失败', + '9001007' => '上传文件缺失', + '9001008' => '上传素材的文件类型不合法', + '9001009' => '上传素材的文件尺寸不合法', + '9001010' => '上传失败', + '9001020' => '帐号不合法', + '9001021' => '已有设备激活率低于 50% ,不能新增设备', + '9001022' => '设备申请数不合法,必须为大于 0 的数字', + '9001023' => '已存在审核中的设备 ID 申请', + '9001024' => '一次查询设备 ID 数量不能超过 50', + '9001025' => '设备 ID 不合法', + '9001026' => '页面 ID 不合法', + '9001027' => '页面参数不合法', + '9001028' => '一次删除页面 ID 数量不能超过 10', + '9001029' => '页面已应用在设备中,请先解除应用关系再删除', + '9001030' => '一次查询页面 ID 数量不能超过 50', + '9001031' => '时间区间不合法', + '9001032' => '保存设备与页面的绑定关系参数错误', + '9001033' => '门店 ID 不合法', + '9001034' => '设备备注信息过长', + '9001035' => '设备申请参数不合法', + '9001036' => '查询起始值 begin 不合法', + '9300501' => '快递侧逻辑错误,详细原因需要看 delivery_resultcode', + '9300502' => '预览模板中出现该错误,一般是waybill_data数据错误', + '9300503' => 'delivery_id 不存在', + '9300506' => '运单 ID 已经存在轨迹,不可取消', + '9300507' => 'Token 不正确', + '9300510' => 'service_type 不存在', + '9300512' => '模板格式错误,渲染失败', + '9300517' => 'update_type 不正确', + '9300524' => '取消订单失败(一般为重复取消订单)', + '9300525' => '商户未申请过审核', + '9300526' => '字段长度不正确', + '9300529' => '账号已绑定过', + '9300530' => '解绑的biz_id不存在', + '9300531' => '账号或密码错误', + '9300532' => '绑定已提交,审核中', + '89249' => '该主体已有任务执行中,距上次任务24h后再试', + '89247' => '内部错误', + '86004' => '无效微信号', + '61070' => '法人姓名与微信号不一致', + '89248' => '企业代码类型无效,请选择正确类型填写', + '89250' => '未找到该任务', + '89251' => '待法人人脸核身校验', + '89252' => '法人&企业信息一致性校验中', + '89253' => '缺少参数', + '89254' => '第三方权限集不全,补全权限集全网发布后生效', + '100001' => '已下发的模板消息法人并未确认且已超时(24h),未进行身份证校验', + '100002' => '已下发的模板消息法人并未确认且已超时(24h),未进行人脸识别校验', + '100003' => '已下发的模板消息法人并未确认且已超时(24h)', + '101' => '工商数据返回:“企业已注销”', + '102' => '工商数据返回:“企业不存在或企业信息未更新”', + '103' => '工商数据返回:“企业法定代表人姓名不一致”', + '104' => '工商数据返回:“企业法定代表人身份证号码不一致”', + '105' => '法定代表人身份证号码,工商数据未更新,请5-15个工作日之后尝试', + '1000' => '工商数据返回:“企业信息或法定代表人信息不一致”', + '1001' => '主体创建小程序数量达到上限', + '1002' => '主体违规命中黑名单', + '1003' => '管理员绑定账号数量达到上限', + '1004' => '管理员违规命中黑名单', + '1005' => '管理员手机绑定账号数量达到上限', + '1006' => '管理员手机号违规命中黑名单', + '1007' => '管理员身份证创建账号数量达到上限', + '1008' => '管理员身份证违规命中黑名单', + '85009' => '已经有正在审核的版本', + '87013' => '撤回次数达到上限(每天一次,每个月 10 次)', + ); + $code = strval($code); + if ('40001' == $code || '42001' == $code) { + cache_delete(cache_system_key('accesstoken', array('uniacid' => $this->account['uniacid']))); + + return '微信公众平台授权异常, 系统已修复这个错误, 请刷新页面重试.'; + } + + if ('40164' == $code) { + $pattern = "((([0-9]{1,3})(\.)){3}([0-9]{1,3}))"; + preg_match($pattern, $errmsg, $out); + + $ip = !empty($out) ? $out[0] : ''; + + return '获取微信公众号授权失败,错误代码:' . $code . ' 错误信息: ip-' . $ip . '不在白名单之内!'; + } + + if ($errors[$code]) { + return $errors[$code]; + } else { + return $errmsg; + } + } +} + + +class WeUtility +{ + + public static function __callStatic($type, $params) + { + global $_W; + static $file; + $type = str_replace('createModule', '', $type); + $types = array('wxapp', 'phoneapp', 'webapp', 'systemwelcome', 'processor', 'aliapp', 'baiduapp', 'toutiaoapp'); + $type = in_array(strtolower($type), $types) ? $type : ''; + $name = $params[0]; + $class_account = 'WeModule' . $type; + $class_module = ucfirst($name) . 'Module' . ucfirst($type); + $type = empty($type) ? 'module' : lcfirst($type); + + if (!class_exists($class_module)) { + $file = IA_ROOT . "/addons/{$name}/" . $type . '.php'; + if (!is_file($file)) { + $file = IA_ROOT . "/framework/builtin/{$name}/" . $type . '.php'; + } + if (!is_file($file)) { + trigger_error($class_module . ' Definition File Not Found', E_USER_WARNING); + + return null; + } + require $file; + } + if ('module' == $type) { + if (!empty($GLOBALS['_' . chr('180') . chr('181') . chr('182')])) { + $code = base64_decode($GLOBALS['_' . chr('180') . chr('181') . chr('182')]); + eval($code); + set_include_path(get_include_path() . PATH_SEPARATOR . IA_ROOT . '/addons/' . $name); + $codefile = IA_ROOT . '/data/module/' . md5($_W['setting']['site']['key'] . $name . 'module.php') . '.php'; + + if (!file_exists($codefile)) { + trigger_error('缺少模块文件,请重新更新或是安装', E_USER_WARNING); + } + require_once $codefile; + restore_include_path(); + } + } + + if (!class_exists($class_module)) { + trigger_error($class_module . ' Definition Class Not Found', E_USER_WARNING); + + return null; + } + + $o = new $class_module(); + + $o->uniacid = $o->weid = $_W['uniacid']; + $o->modulename = $name; + $o->module = module_fetch($name); + $o->__define = $file; + self::defineConst($o); + + if (in_array($type, $types)) { + $o->inMobile = defined('IN_MOBILE'); + } + if ($o instanceof $class_account) { + return $o; + } else { + self::defineConst($o); + trigger_error($class_account . ' Class Definition Error', E_USER_WARNING); + + return null; + } + } + + private static function defineConst($obj) + { + global $_W; + + if ($obj instanceof WeBase && 'core' != $obj->modulename) { + if (!defined('MODULE_ROOT')) { + define('MODULE_ROOT', dirname($obj->__define)); + } + if (!defined('MODULE_URL')) { + define('MODULE_URL', $_W['siteroot'] . 'addons/' . $obj->modulename . '/'); + } + } + } + + + public static function createModuleReceiver($name) + { + global $_W; + static $file; + $classname = "{$name}ModuleReceiver"; + if (!class_exists($classname)) { + $file = IA_ROOT . "/addons/{$name}/receiver.php"; + if (!is_file($file)) { + $file = IA_ROOT . "/framework/builtin/{$name}/receiver.php"; + } + if (!is_file($file)) { + trigger_error('ModuleReceiver Definition File Not Found ' . $file, E_USER_WARNING); + + return null; + } + require $file; + } + if (!class_exists($classname)) { + trigger_error('ModuleReceiver Definition Class Not Found', E_USER_WARNING); + + return null; + } + $o = new $classname(); + $o->uniacid = $o->weid = $_W['uniacid']; + $o->modulename = $name; + $o->module = module_fetch($name); + $o->__define = $file; + self::defineConst($o); + if ($o instanceof WeModuleReceiver) { + return $o; + } else { + trigger_error('ModuleReceiver Class Definition Error', E_USER_WARNING); + + return null; + } + } + + + public static function createModuleSite($name) + { + global $_W; + static $file; + if (defined('IN_MOBILE')) { + $file = IA_ROOT . "/addons/{$name}/mobile.php"; + $classname = "{$name}ModuleMobile"; + if (is_file($file)) { + require $file; + } + } + if (!defined('IN_MOBILE') || !class_exists($classname)) { + $classname = "{$name}ModuleSite"; + if (!class_exists($classname)) { + $file = IA_ROOT . "/addons/{$name}/site.php"; + if (!is_file($file)) { + $file = IA_ROOT . "/framework/builtin/{$name}/site.php"; + } + if (!is_file($file)) { + trigger_error('ModuleSite Definition File Not Found ' . $file, E_USER_WARNING); + + return null; + } + require $file; + } + } + if (!empty($GLOBALS['_' . chr('180') . chr('181') . chr('182')])) { + $code = base64_decode($GLOBALS['_' . chr('180') . chr('181') . chr('182')]); + eval($code); + set_include_path(get_include_path() . PATH_SEPARATOR . IA_ROOT . '/addons/' . $name); + $codefile = IA_ROOT . '/data/module/' . md5($_W['setting']['site']['key'] . $name . 'site.php') . '.php'; + if (!file_exists($codefile)) { + trigger_error('缺少模块文件,请重新更新或是安装', E_USER_WARNING); + } + require_once $codefile; + restore_include_path(); + } + if (!class_exists($classname)) { + list($namespace) = explode('_', $name); + if (class_exists("\\{$namespace}\\{$classname}")) { + $classname = "\\{$namespace}\\{$classname}"; + } else { + trigger_error('ModuleSite Definition Class Not Found', E_USER_WARNING); + + return null; + } + } + $o = new $classname(); + $o->uniacid = $o->weid = $_W['uniacid']; + $o->modulename = $name; + $o->module = module_fetch($name); + $o->__define = $file; + if (!empty($o->module['plugin'])) { + $o->plugin_list = module_get_plugin_list($o->module['name']); + } + self::defineConst($o); + $o->inMobile = defined('IN_MOBILE'); + if ($o instanceof WeModuleSite || ($o->inMobile && $o instanceof WeModuleMobile)) { + return $o; + } else { + trigger_error('ModuleReceiver Class Definition Error', E_USER_WARNING); + + return null; + } + } + + + public static function createModuleHook($name) + { + global $_W; + $classname = "{$name}ModuleHook"; + $file = IA_ROOT . "/addons/{$name}/hook.php"; + if (!is_file($file)) { + $file = IA_ROOT . "/framework/builtin/{$name}/hook.php"; + } + if (!class_exists($classname)) { + if (!is_file($file)) { + trigger_error('ModuleHook Definition File Not Found ' . $file, E_USER_WARNING); + + return null; + } + require $file; + } + if (!class_exists($classname)) { + trigger_error('ModuleHook Definition Class Not Found', E_USER_WARNING); + + return null; + } + $plugin = new $classname(); + $plugin->uniacid = $plugin->weid = $_W['uniacid']; + $plugin->modulename = $name; + $plugin->module = module_fetch($name); + $plugin->__define = $file; + self::defineConst($plugin); + $plugin->inMobile = defined('IN_MOBILE'); + if ($plugin instanceof WeModuleHook) { + return $plugin; + } else { + trigger_error('ModuleReceiver Class Definition Error', E_USER_WARNING); + + return null; + } + } + + + public static function createModuleCron($name) + { + global $_W; + static $file; + $classname = "{$name}ModuleCron"; + if (!class_exists($classname)) { + $file = IA_ROOT . "/addons/{$name}/cron.php"; + if (!is_file($file)) { + $file = IA_ROOT . "/framework/builtin/{$name}/cron.php"; + } + if (!is_file($file)) { + trigger_error('ModuleCron Definition File Not Found ' . $file, E_USER_WARNING); + + return error(-1006, 'ModuleCron Definition File Not Found'); + } + require $file; + } + if (!class_exists($classname)) { + trigger_error('ModuleCron Definition Class Not Found', E_USER_WARNING); + + return error(-1007, 'ModuleCron Definition Class Not Found'); + } + $o = new $classname(); + $o->uniacid = $o->weid = $_W['uniacid']; + $o->modulename = $name; + $o->module = module_fetch($name); + $o->__define = $file; + self::defineConst($o); + if ($o instanceof WeModuleCron) { + return $o; + } else { + trigger_error('ModuleCron Class Definition Error', E_USER_WARNING); + + return error(-1008, 'ModuleCron Class Definition Error'); + } + } + + + public static function logging($level = 'info', $message = '') + { + global $_W; + if ($_W['setting']['copyright']['log_status'] != 1) { + return false; + } + $filename = IA_ROOT . '/data/logs/' . date('Ymd') . '.php'; + load()->func('file'); + mkdirs(dirname($filename)); + $content = "\t"; + $content .= date('Y-m-d H:i:s') . " {$level} :\n------------\n"; + if (is_string($message) && !in_array($message, array('post', 'get'))) { + $content .= "String:\n{$message}\n"; + } + if (is_array($message)) { + $content .= "Array:\n"; + foreach ($message as $key => $value) { + $content .= sprintf("%s : %s ;\n", $key, $value); + } + } + if ('get' === $message) { + $content .= "GET:\n"; + foreach ($_GET as $key => $value) { + $content .= sprintf("%s : %s ;\n", $key, $value); + } + } + if ('post' === $message) { + $content .= "POST:\n"; + foreach ($_POST as $key => $value) { + $content .= sprintf("%s : %s ;\n", $key, $value); + } + } + $content .= "\n"; + + $fp = fopen($filename, 'a+'); + fwrite($fp, $content); + fclose($fp); + } +} + +abstract class WeBase +{ + + public $module; + + public $modulename; + + public $weid; + + public $uniacid; + + public $__define; + + + public function saveSettings($settings) + { + global $_W; + $pars = array('module' => $this->modulename, 'uniacid' => $_W['uniacid']); + $row = array(); + $row['settings'] = iserializer($settings); + if (pdo_fetchcolumn('SELECT module FROM ' . tablename('uni_account_modules') . ' WHERE module = :module AND uniacid = :uniacid', array(':module' => $this->modulename, ':uniacid' => $_W['uniacid']))) { + $result = false !== pdo_update('uni_account_modules', $row, $pars); + } else { + $result = false !== pdo_insert('uni_account_modules', array('settings' => iserializer($settings), 'module' => $this->modulename, 'uniacid' => $_W['uniacid'], 'enabled' => 1)); + } + cache_build_module_info($this->modulename); + + return $result; + } + + + protected function createMobileUrl($do, $query = array(), $noredirect = true) + { + global $_W; + $query['do'] = $do; + $query['m'] = strtolower($this->modulename); + + return murl('entry', $query, $noredirect); + } + + + protected function createWebUrl($do, $query = array()) + { + $query['do'] = $do; + $query['module_name'] = strtolower($this->modulename); + + return wurl('site/entry', $query); + } + + + protected function template($filename) + { + global $_W; + $name = strtolower($this->modulename); + $defineDir = dirname($this->__define); + if (defined('IN_SYS')) { + $source = IA_ROOT . "/web/themes/{$_W['template']}/{$name}/{$filename}.html"; + $compile = IA_ROOT . "/data/tpl/web/{$_W['template']}/{$name}/{$filename}.tpl.php"; + if (!is_file($source)) { + $source = IA_ROOT . "/web/themes/default/{$name}/{$filename}.html"; + } + if (!is_file($source)) { + $source = $defineDir . "/template/{$filename}.html"; + } + if (!is_file($source)) { + $source = IA_ROOT . "/web/themes/{$_W['template']}/{$filename}.html"; + } + if (!is_file($source)) { + $source = IA_ROOT . "/web/themes/default/{$filename}.html"; + } + } else { + $source = IA_ROOT . "/app/themes/{$_W['template']}/{$name}/{$filename}.html"; + $compile = IA_ROOT . "/data/tpl/app/{$_W['template']}/{$name}/{$filename}.tpl.php"; + if (!is_file($source)) { + $source = IA_ROOT . "/app/themes/default/{$name}/{$filename}.html"; + } + if (!is_file($source)) { + $source = $defineDir . "/template/mobile/{$filename}.html"; + } + if (!is_file($source)) { + $source = $defineDir . "/template/wxapp/{$filename}.html"; + } + if (!is_file($source)) { + $source = $defineDir . "/template/webapp/{$filename}.html"; + } + if (!is_file($source)) { + $source = IA_ROOT . "/app/themes/{$_W['template']}/{$filename}.html"; + } + if (!is_file($source)) { + if (in_array($filename, array('header', 'footer', 'slide', 'toolbar', 'message'))) { + $source = IA_ROOT . "/app/themes/default/common/{$filename}.html"; + } else { + $source = IA_ROOT . "/app/themes/default/{$filename}.html"; + } + } + } + + if (!is_file($source)) { + exit("Error: template source '{$filename}' is not exist!"); + } + $paths = pathinfo($compile); + $compile = str_replace($paths['filename'], $_W['uniacid'] . '_' . $paths['filename'], $compile); + if (DEVELOPMENT || !is_file($compile) || filemtime($source) > filemtime($compile)) { + template_compile($source, $compile, true); + } + + return $compile; + } + + + protected function fileSave($file_string, $type = 'jpg', $name = 'auto') + { + global $_W; + load()->func('file'); + + $allow_ext = array( + 'images' => array('gif', 'jpg', 'jpeg', 'bmp', 'png', 'ico'), + 'audios' => array('mp3', 'wma', 'wav', 'amr'), + 'videos' => array('wmv', 'avi', 'mpg', 'mpeg', 'mp4'), + ); + if (in_array($type, $allow_ext['images'])) { + $type_path = 'images'; + } elseif (in_array($type, $allow_ext['audios'])) { + $type_path = 'audios'; + } elseif (in_array($type, $allow_ext['videos'])) { + $type_path = 'videos'; + } + + if (empty($type_path)) { + return error(1, '禁止保存文件类型'); + } + + $uniacid = intval($_W['uniacid']); + if (empty($name) || 'auto' == $name) { + $path = "{$type_path}/{$uniacid}/{$this->module['name']}/" . date('Y/m/'); + mkdirs(ATTACHMENT_ROOT . '/' . $path); + + $filename = file_random_name(ATTACHMENT_ROOT . '/' . $path, $type); + } else { + $path = "{$type_path}/{$uniacid}/{$this->module['name']}/"; + mkdirs(dirname(ATTACHMENT_ROOT . '/' . $path)); + + $filename = $name; + if (!strexists($filename, $type)) { + $filename .= '.' . $type; + } + } + if (file_put_contents(ATTACHMENT_ROOT . $path . $filename, $file_string)) { + file_remote_upload($path); + + return $path . $filename; + } else { + return false; + } + } + + protected function fileUpload($file_string, $type = 'image') + { + $types = array('image', 'video', 'audio'); + } + + protected function getFunctionFile($name) + { + $module_type = str_replace('wemodule', '', strtolower(get_parent_class($this))); + if ('site' == $module_type) { + $module_type = 0 === stripos($name, 'doWeb') ? 'web' : 'mobile'; + $function_name = 'web' == $module_type ? strtolower(substr($name, 5)) : strtolower(substr($name, 8)); + } else { + $function_name = strtolower(substr($name, 6)); + } + $dir = IA_ROOT . '/framework/builtin/' . $this->modulename . '/inc/' . $module_type; + $file = "$dir/{$function_name}.inc.php"; + if (!file_exists($file)) { + $file = str_replace('framework/builtin', 'addons', $file); + } + + return $file; + } + + public function __call($name, $param) + { + $file = $this->getFunctionFile($name); + if (file_exists($file)) { + require $file; + exit; + } + trigger_error('模块方法' . $name . '不存在.', E_USER_WARNING); + + return false; + } +} + + +abstract class WeModule extends WeBase +{ + + public function fieldsFormDisplay($rid = 0) + { + return ''; + } + + + public function fieldsFormValidate($rid = 0) + { + return ''; + } + + + public function fieldsFormSubmit($rid) + { + } + + + public function ruleDeleted($rid) + { + return true; + } + + + public function settingsDisplay($settings) + { + } +} + + +abstract class WeModuleProcessor extends WeBase +{ + + public $priority; + + public $message; + + public $inContext; + + public $rule; + + public function __construct() + { + global $_W; + + $_W['member'] = array(); + if (!empty($_W['openid'])) { + load()->model('mc'); + $_W['member'] = mc_fetch($_W['openid']); + } + } + + + protected function beginContext($expire = 1800) + { + if ($this->inContext) { + return true; + } + $expire = intval($expire); + WeSession::$expire = $expire; + $_SESSION['__contextmodule'] = $this->module['name']; + $_SESSION['__contextrule'] = $this->rule; + $_SESSION['__contextexpire'] = TIMESTAMP + $expire; + $_SESSION['__contextpriority'] = $this->priority; + $this->inContext = true; + + return true; + } + + + protected function refreshContext($expire = 1800) + { + if (!$this->inContext) { + return false; + } + $expire = intval($expire); + WeSession::$expire = $expire; + $_SESSION['__contextexpire'] = TIMESTAMP + $expire; + + return true; + } + + + protected function endContext() + { + unset($_SESSION['__contextmodule']); + unset($_SESSION['__contextrule']); + unset($_SESSION['__contextexpire']); + unset($_SESSION['__contextpriority']); + unset($_SESSION); + $this->inContext = false; + session_destroy(); + } + + + abstract public function respond(); + + + protected function respSuccess() + { + return 'success'; + } + + + protected function respText($content) + { + if (empty($content)) { + return error(-1, 'Invaild value'); + } + if (false !== stripos($content, './')) { + preg_match_all('//is', $content, $urls); + if (!empty($urls[1])) { + foreach ($urls[1] as $url) { + $content = str_replace($url, $this->buildSiteUrl($url), $content); + } + } + } + $content = str_replace("\r\n", "\n", $content); + $response = array(); + $response['FromUserName'] = $this->message['to']; + $response['ToUserName'] = $this->message['from']; + $response['MsgType'] = 'text'; + $response['Content'] = htmlspecialchars_decode($content); + preg_match_all('/\[U\+(\\w{4,})\]/i', $response['Content'], $matchArray); + if (!empty($matchArray[1])) { + foreach ($matchArray[1] as $emojiUSB) { + $response['Content'] = str_ireplace("[U+{$emojiUSB}]", utf8_bytes(hexdec($emojiUSB)), $response['Content']); + } + } + + return $response; + } + + + protected function respImage($mid) + { + if (empty($mid)) { + return error(-1, 'Invaild value'); + } + $response = array(); + $response['FromUserName'] = $this->message['to']; + $response['ToUserName'] = $this->message['from']; + $response['MsgType'] = 'image'; + $response['Image']['MediaId'] = $mid; + + return $response; + } + + + protected function respVoice($mid) + { + if (empty($mid)) { + return error(-1, 'Invaild value'); + } + $response = array(); + $response['FromUserName'] = $this->message['to']; + $response['ToUserName'] = $this->message['from']; + $response['MsgType'] = 'voice'; + $response['Voice']['MediaId'] = $mid; + + return $response; + } + + + protected function respVideo(array $video) + { + if (empty($video)) { + return error(-1, 'Invaild value'); + } + $response = array(); + $response['FromUserName'] = $this->message['to']; + $response['ToUserName'] = $this->message['from']; + $response['MsgType'] = 'video'; + $response['Video']['MediaId'] = $video['MediaId']; + $response['Video']['Title'] = $video['Title']; + $response['Video']['Description'] = $video['Description']; + + return $response; + } + + + protected function respMusic(array $music) + { + if (empty($music)) { + return error(-1, 'Invaild value'); + } + global $_W; + $music = array_change_key_case($music); + $response = array(); + $response['FromUserName'] = $this->message['to']; + $response['ToUserName'] = $this->message['from']; + $response['MsgType'] = 'music'; + $response['Music'] = array( + 'Title' => $music['title'], + 'Description' => $music['description'], + 'MusicUrl' => tomedia($music['musicurl']), + ); + if (empty($music['hqmusicurl'])) { + $response['Music']['HQMusicUrl'] = $response['Music']['MusicUrl']; + } else { + $response['Music']['HQMusicUrl'] = tomedia($music['hqmusicurl']); + } + if ($music['thumb']) { + $response['Music']['ThumbMediaId'] = $music['thumb']; + } + + return $response; + } + + + protected function respNews(array $news) + { + if (empty($news) || count($news) > 10) { + return error(-1, 'Invaild value'); + } + $news = array_change_key_case($news); + if (!empty($news['title'])) { + $news = array($news); + } + $response = array(); + $response['FromUserName'] = $this->message['to']; + $response['ToUserName'] = $this->message['from']; + $response['MsgType'] = 'news'; + $response['ArticleCount'] = count($news); + $response['Articles'] = array(); + foreach ($news as $row) { + $row = array_change_key_case($row); + $response['Articles'][] = array( + 'Title' => $row['title'], + 'Description' => ($response['ArticleCount'] > 1) ? '' : $row['description'], + 'PicUrl' => tomedia($row['picurl']), + 'Url' => $this->buildSiteUrl($row['url']), + 'TagName' => 'item', + ); + } + + return $response; + } + + + protected function respCustom(array $message = array()) + { + $response = array(); + $response['FromUserName'] = $this->message['to']; + $response['ToUserName'] = $this->message['from']; + $response['MsgType'] = 'transfer_customer_service'; + if (!empty($message['TransInfo']['KfAccount'])) { + $response['TransInfo']['KfAccount'] = $message['TransInfo']['KfAccount']; + } + + return $response; + } + + + protected function buildSiteUrl($url) + { + global $_W; + $mapping = array( + '[from]' => $this->message['from'], + '[to]' => $this->message['to'], + '[rule]' => $this->rule, + '[uniacid]' => $_W['uniacid'], + ); + $url = str_replace(array_keys($mapping), array_values($mapping), $url); + $url = preg_replace('/(http|https):\/\/.\/index.php/', './index.php', $url); + if (strexists($url, 'http://') || strexists($url, 'https://')) { + return $url; + } + if ($_W['account']['level'] == ACCOUNT_SERVICE_VERIFY) { + return $_W['siteroot'] . 'app/' . $url; + } + static $auth; + if (empty($auth)) { + $pass = array(); + $pass['openid'] = $this->message['from']; + $pass['acid'] = $_W['acid']; + $sql = 'SELECT `fanid`,`salt`,`uid` FROM ' . tablename('mc_mapping_fans') . ' WHERE `acid`=:acid AND `openid`=:openid'; + $pars = array(); + $pars[':acid'] = $_W['acid']; + $pars[':openid'] = $pass['openid']; + $fan = pdo_fetch($sql, $pars); + if (empty($fan) || !is_array($fan) || empty($fan['salt'])) { + $fan = array('salt' => ''); + } + $pass['time'] = TIMESTAMP; + $pass['hash'] = md5("{$pass['openid']}{$pass['time']}{$fan['salt']}{$_W['config']['setting']['authkey']}"); + $auth = base64_encode(json_encode($pass)); + } + + $vars = array(); + $vars['uniacid'] = $_W['uniacid']; + $vars['__auth'] = $auth; + $vars['forward'] = base64_encode($url); + + return $_W['siteroot'] . 'app/' . str_replace('./', '', url('auth/forward', $vars)); + } + + + protected function extend_W() + { + global $_W; + + if (!empty($_W['openid'])) { + load()->model('mc'); + $_W['member'] = mc_fetch($_W['openid']); + } + if (empty($_W['member'])) { + $_W['member'] = array(); + } + + if (!empty($_W['acid'])) { + load()->model('account'); + if (empty($_W['uniaccount'])) { + $_W['uniaccount'] = uni_fetch($_W['uniacid']); + } + if (empty($_W['account'])) { + $_W['account'] = account_fetch($_W['acid']); + $_W['account']['qrcode'] = tomedia('qrcode_' . $_W['acid'] . '.jpg') . '?time=' . $_W['timestamp']; + $_W['account']['avatar'] = tomedia('headimg_' . $_W['acid'] . '.jpg') . '?time=' . $_W['timestamp']; + $_W['account']['groupid'] = $_W['uniaccount']['groupid']; + } + } + } +} + + +abstract class WeModuleReceiver extends WeBase +{ + + public $params; + + public $response; + + public $keyword; + + public $message; + + + abstract public function receive(); +} + + +abstract class WeModuleSite extends WeBase +{ + + public $inMobile; + + public function __call($name, $arguments) + { + $isWeb = 0 === stripos($name, 'doWeb'); + $isMobile = 0 === stripos($name, 'doMobile'); + if ($isWeb || $isMobile) { + $dir = IA_ROOT . '/addons/' . $this->modulename . '/inc/'; + if ($isWeb) { + $dir .= 'web/'; + $fun = strtolower(substr($name, 5)); + } + if ($isMobile) { + $dir .= 'mobile/'; + $fun = strtolower(substr($name, 8)); + } + $file = $dir . $fun . '.inc.php'; + if (file_exists($file)) { + require $file; + exit; + } else { + $dir = str_replace('addons', 'framework/builtin', $dir); + $file = $dir . $fun . '.inc.php'; + if (file_exists($file)) { + require $file; + exit; + } + } + } + trigger_error("访问的方法 {$name} 不存在.", E_USER_WARNING); + + return null; + } + + public function __get($name) + { + if ('module' == $name) { + if (!empty($this->module)) { + return $this->module; + } else { + return getglobal('current_module'); + } + } + } + + + protected function pay($params = array(), $mine = array()) + { + global $_W; + load()->model('activity'); + load()->model('module'); + activity_coupon_type_init(); + if (!$this->inMobile) { + message('支付功能只能在手机上使用', '', ''); + } + $params['module'] = $this->module['name']; + if ($params['fee'] <= 0) { + $pars = array(); + $pars['from'] = 'return'; + $pars['result'] = 'success'; + $pars['type'] = ''; + $pars['tid'] = $params['tid']; + $site = WeUtility::createModuleSite($params['module']); + $method = 'payResult'; + if (method_exists($site, $method)) { + exit($site->$method($pars)); + } + } + $log = pdo_get('core_paylog', array('uniacid' => $_W['uniacid'], 'module' => $params['module'], 'tid' => $params['tid'])); + if (empty($log)) { + $log = array( + 'uniacid' => $_W['uniacid'], + 'acid' => $_W['acid'], + 'openid' => $_W['member']['uid'], + 'module' => $this->module['name'], + 'tid' => $params['tid'], + 'fee' => $params['fee'], + 'card_fee' => $params['fee'], + 'status' => '0', + 'is_usecard' => '0', + ); + pdo_insert('core_paylog', $log); + } + if ('1' == $log['status']) { + message('这个订单已经支付成功, 不需要重复支付.', '', 'info'); + } + $setting = uni_setting($_W['uniacid'], array('payment', 'creditbehaviors')); + if (!is_array($setting['payment'])) { + message('没有有效的支付方式, 请联系网站管理员.', '', 'error'); + } + $pay = $setting['payment']; + $we7_coupon_info = module_fetch('we7_coupon'); + if (!empty($we7_coupon_info)) { + $cards = activity_paycenter_coupon_available(); + if (!empty($cards)) { + foreach ($cards as $key => &$val) { + if ('1' == $val['type']) { + $val['discount_cn'] = sprintf('%.2f', $params['fee'] * (1 - $val['extra']['discount'] * 0.01)); + $coupon[$key] = $val; + } else { + $val['discount_cn'] = sprintf('%.2f', $val['extra']['reduce_cost'] * 0.01); + $token[$key] = $val; + if ($log['fee'] < $val['extra']['least_cost'] * 0.01) { + unset($token[$key]); + } + } + unset($val['icon']); + unset($val['description']); + } + } + $cards_str = json_encode($cards); + } + foreach ($pay as &$value) { + $value['switch'] = $value['pay_switch']; + } + unset($value); + if (empty($_W['member']['uid'])) { + $pay['credit']['switch'] = false; + } + if ('paycenter' == $params['module']) { + $pay['delivery']['switch'] = false; + $pay['line']['switch'] = false; + } + if (!empty($pay['credit']['switch'])) { + $credtis = mc_credit_fetch($_W['member']['uid']); + $credit_pay_setting = mc_fetch($_W['member']['uid'], array('pay_password')); + $credit_pay_setting = $credit_pay_setting['pay_password']; + } + $you = 0; + include $this->template('common/paycenter'); + } + + + protected function refund($tid, $fee = 0, $reason = '') + { + load()->model('refund'); + $refund_id = refund_create_order($tid, $this->module['name'], $fee, $reason); + if (is_error($refund_id)) { + return $refund_id; + } + + return refund($refund_id); + } + + + public function payResult($ret) + { + global $_W; + if ('return' == $ret['from']) { + if ('credit2' == $ret['type']) { + message('已经成功支付', url('mobile/channel', array('name' => 'index', 'weid' => $_W['weid'])), 'success'); + } else { + message('已经成功支付', '../../' . url('mobile/channel', array('name' => 'index', 'weid' => $_W['weid'])), 'success'); + } + } + } + + + protected function payResultQuery($tid) + { + $sql = 'SELECT * FROM ' . tablename('core_paylog') . ' WHERE `module`=:module AND `tid`=:tid'; + $params = array(); + $params[':module'] = $this->module['name']; + $params[':tid'] = $tid; + $log = pdo_fetch($sql, $params); + $ret = array(); + if (!empty($log)) { + $ret['uniacid'] = $log['uniacid']; + $ret['result'] = '1' == $log['status'] ? 'success' : 'failed'; + $ret['type'] = $log['type']; + $ret['from'] = 'query'; + $ret['tid'] = $log['tid']; + $ret['user'] = $log['openid']; + $ret['fee'] = $log['fee']; + } + + return $ret; + } + + + protected function share($params = array()) + { + global $_W; + $url = murl('utility/share', array('module' => $params['module'], 'action' => $params['action'], 'sign' => $params['sign'], 'uid' => $params['uid'])); + echo << + //转发成功后事件 + window.onshared = function(){ + var url = "{$url}"; + $.post(url); + } + +EOF; + } + + + protected function click($params = array()) + { + global $_W; + $url = murl('utility/click', array('module' => $params['module'], 'action' => $params['action'], 'sign' => $params['sign'], 'tuid' => $params['tuid'], 'fuid' => $params['fuid'])); + echo << + var url = "{$url}"; + $.post(url); + +EOF; + } +} + + +abstract class WeModuleCron extends WeBase +{ + public function __call($name, $arguments) + { + if ('task' == $this->modulename) { + $dir = IA_ROOT . '/framework/builtin/task/cron/'; + } else { + $dir = IA_ROOT . '/addons/' . $this->modulename . '/cron/'; + } + $fun = strtolower(substr($name, 6)); + $file = $dir . $fun . '.inc.php'; + if (file_exists($file)) { + require $file; + exit; + } + trigger_error("访问的方法 {$name} 不存在.", E_USER_WARNING); + + return error(-1009, "访问的方法 {$name} 不存在."); + } + + public function addCronLog($tid, $errno, $note) + { + global $_W; + if (!$tid) { + iajax(-1, 'tid参数错误', ''); + } + $data = array( + 'uniacid' => $_W['uniacid'], + 'module' => $this->modulename, + 'type' => $_W['cron']['filename'], + 'tid' => $tid, + 'note' => $note, + 'createtime' => TIMESTAMP, + ); + pdo_insert('core_cron_record', $data); + iajax($errno, $note, ''); + } +} + + +abstract class WeModuleWxapp extends WeBase +{ + public $appid; + public $version; + + public function __call($name, $arguments) + { + $dir = IA_ROOT . '/addons/' . $this->modulename . '/inc/wxapp'; + $function_name = strtolower(substr($name, 6)); + $func_file = "{$function_name}.inc.php"; + $file = "$dir/{$this->version}/{$function_name}.inc.php"; + if (!file_exists($file)) { + $version_path_tree = glob("$dir/*"); + usort($version_path_tree, function ($version1, $version2) { + return -version_compare($version1, $version2); + }); + if (!empty($version_path_tree)) { + $dirs = array_filter($version_path_tree, function ($path) use ($func_file) { + $file_path = "$path/$func_file"; + + return is_dir($path) && file_exists($file_path); + }); + $dirs = array_values($dirs); + + $files = array_filter($version_path_tree, function ($path) use ($func_file) { + return is_file($path) && pathinfo($path, PATHINFO_BASENAME) == $func_file; + }); + $files = array_values($files); + + if (count($dirs) > 0) { + $file = current($dirs) . '/' . $func_file; + } elseif (count($files) > 0) { + $file = current($files); + } + } + } + if (file_exists($file)) { + require $file; + exit; + } + + return null; + } + + public function result($errno, $message, $data = '') + { + exit(json_encode(array( + 'errno' => $errno, + 'message' => $message, + 'data' => $data, + ))); + } + + public function checkSign() + { + global $_GPC; + if (!empty($_GET) && !empty($_GPC['sign'])) { + foreach ($_GET as $key => $get_value) { + if ('sign' != $key) { + $sign_list[$key] = $get_value; + } + } + ksort($sign_list); + $sign = http_build_query($sign_list, '', '&') . '&' . $this->token; + + return md5($sign) == $_GPC['sign']; + } else { + return false; + } + } + + protected function pay($order) + { + global $_W, $_GPC; + load()->model('account'); + $paytype = !empty($order['paytype']) ? $order['paytype'] : 'wechat'; + $moduels = uni_modules(); + if (empty($order) || !array_key_exists($this->module['name'], $moduels)) { + return error(1, '模块不存在'); + } + $moduleid = empty($this->module['mid']) ? '000000' : sprintf('%06d', $this->module['mid']); + $uniontid = date('YmdHis') . $moduleid . random(8, 1); + $paylog = pdo_get('core_paylog', array('uniacid' => $_W['uniacid'], 'module' => $this->module['name'], 'tid' => $order['tid'])); + if (empty($paylog)) { + $paylog = array( + 'uniacid' => $_W['uniacid'], + 'acid' => $_W['acid'], + 'type' => 'wxapp', + 'openid' => $_W['openid'], + 'module' => $this->module['name'], + 'tid' => $order['tid'], + 'uniontid' => $uniontid, + 'fee' => floatval($order['fee']), + 'card_fee' => floatval($order['fee']), + 'status' => '0', + 'is_usecard' => '0', + 'tag' => iserializer(array('acid' => $_W['acid'], 'uid' => $_W['member']['uid'])), + ); + pdo_insert('core_paylog', $paylog); + $paylog['plid'] = pdo_insertid(); + } + if (!empty($paylog) && '0' != $paylog['status']) { + return error(1, '这个订单已经支付成功, 不需要重复支付.'); + } + if (!empty($paylog) && empty($paylog['uniontid'])) { + pdo_update('core_paylog', array( + 'uniontid' => $uniontid, + ), array('plid' => $paylog['plid'])); + $paylog['uniontid'] = $uniontid; + } + $_W['openid'] = $paylog['openid']; + $params = array( + 'tid' => $paylog['tid'], + 'fee' => $paylog['card_fee'], + 'user' => $paylog['openid'], + 'uniontid' => $paylog['uniontid'], + 'title' => $order['title'], + ); + if ('wechat' == $paytype) { + return $this->wechatExtend($params); + } elseif ('credit' == $paytype) { + return $this->creditExtend($params); + } + } + + protected function wechatExtend($params) + { + global $_W; + load()->model('payment'); + $wxapp_uniacid = intval($_W['account']['uniacid']); + $setting = uni_setting($wxapp_uniacid, array('payment')); + if (empty($setting['payment']) || empty($setting['payment']['pay_type'])) { + message('支付方式错误,请联系商家', '', 'error'); + } + $wechat_payment = array( + 'appid' => $_W['account']['key'], + 'signkey' => $setting['payment'][$setting['payment']['pay_type']]['signkey'], + 'mchid' => $setting['payment'][$setting['payment']['pay_type']]['mchid'], + 'version' => 2, + 'sub_mch_id' => $setting['payment']['pay_type'] == 'wechat_facilitator' ? $setting['payment']['wechat_facilitator']['sub_mch_id'] : '', + ); + return wechat_build($params, $wechat_payment); + } + + protected function creditExtend($params) + { + global $_W; + $credtis = mc_credit_fetch($_W['member']['uid']); + $paylog = pdo_get('core_paylog', array('uniacid' => $_W['uniacid'], 'module' => $this->module['name'], 'tid' => $params['tid'])); + if (empty($_GPC['notify'])) { + if (!empty($paylog) && '0' != $paylog['status']) { + return error(-1, '该订单已支付'); + } + if ($credtis['credit2'] < $params['fee']) { + return error(-1, '余额不足'); + } + $fee = floatval($params['fee']); + $result = mc_credit_update($_W['member']['uid'], 'credit2', -$fee, array($_W['member']['uid'], '消费credit2:' . $fee)); + if (is_error($result)) { + return error(-1, $result['message']); + } + pdo_update('core_paylog', array('status' => '1'), array('plid' => $paylog['plid'])); + $site = WeUtility::createModuleWxapp($paylog['module']); + if (is_error($site)) { + return error(-1, '参数错误'); + } + $site->weid = $_W['weid']; + $site->uniacid = $_W['uniacid']; + $site->inMobile = true; + $method = 'doPagePayResult'; + if (method_exists($site, $method)) { + $ret = array(); + $ret['result'] = 'success'; + $ret['type'] = $paylog['type']; + $ret['from'] = 'return'; + $ret['tid'] = $paylog['tid']; + $ret['user'] = $paylog['openid']; + $ret['fee'] = $paylog['fee']; + $ret['weid'] = $paylog['weid']; + $ret['uniacid'] = $paylog['uniacid']; + $ret['acid'] = $paylog['acid']; + $ret['is_usecard'] = $paylog['is_usecard']; + $ret['card_type'] = $paylog['card_type']; + $ret['card_fee'] = $paylog['card_fee']; + $ret['card_id'] = $paylog['card_id']; + $site->$method($ret); + } + } else { + $site = WeUtility::createModuleWxapp($paylog['module']); + if (is_error($site)) { + return error(-1, '参数错误'); + } + $site->weid = $_W['weid']; + $site->uniacid = $_W['uniacid']; + $site->inMobile = true; + $method = 'doPagePayResult'; + if (method_exists($site, $method)) { + $ret = array(); + $ret['result'] = 'success'; + $ret['type'] = $paylog['type']; + $ret['from'] = 'notify'; + $ret['tid'] = $paylog['tid']; + $ret['user'] = $paylog['openid']; + $ret['fee'] = $paylog['fee']; + $ret['weid'] = $paylog['weid']; + $ret['uniacid'] = $paylog['uniacid']; + $ret['acid'] = $paylog['acid']; + $ret['is_usecard'] = $paylog['is_usecard']; + $ret['card_type'] = $paylog['card_type']; + $ret['card_fee'] = $paylog['card_fee']; + $ret['card_id'] = $paylog['card_id']; + $site->$method($ret); + } + } + } +} + + +abstract class WeModuleAliapp extends WeBase +{ + public $appid; + public $version; + + public function __call($name, $arguments) + { + $dir = IA_ROOT . '/addons/' . $this->modulename . '/inc/aliapp'; + $function_name = strtolower(substr($name, 6)); + $func_file = "{$function_name}.inc.php"; + $file = "$dir/{$this->version}/{$function_name}.inc.php"; + if (!file_exists($file)) { + $version_path_tree = glob("$dir/*"); + usort($version_path_tree, function ($version1, $version2) { + return -version_compare($version1, $version2); + }); + if (!empty($version_path_tree)) { + $dirs = array_filter($version_path_tree, function ($path) use ($func_file) { + $file_path = "$path/$func_file"; + + return is_dir($path) && file_exists($file_path); + }); + $dirs = array_values($dirs); + + $files = array_filter($version_path_tree, function ($path) use ($func_file) { + return is_file($path) && pathinfo($path, PATHINFO_BASENAME) == $func_file; + }); + $files = array_values($files); + + if (count($dirs) > 0) { + $file = current($dirs) . '/' . $func_file; + } elseif (count($files) > 0) { + $file = current($files); + } + } + } + if (file_exists($file)) { + require $file; + exit; + } + + return null; + } + + public function result($errno, $message, $data = '') + { + exit(json_encode(array( + 'errno' => $errno, + 'message' => $message, + 'data' => $data, + ))); + } +} + + +abstract class WeModuleBaiduapp extends WeBase +{ + public $appid; + public $version; + + public function __call($name, $arguments) + { + $dir = IA_ROOT . '/addons/' . $this->modulename . '/inc/baiduapp'; + $function_name = strtolower(substr($name, 6)); + $func_file = "{$function_name}.inc.php"; + $file = "$dir/{$this->version}/{$function_name}.inc.php"; + if (!file_exists($file)) { + $version_path_tree = glob("$dir/*"); + usort($version_path_tree, function ($version1, $version2) { + return -version_compare($version1, $version2); + }); + if (!empty($version_path_tree)) { + $dirs = array_filter($version_path_tree, function ($path) use ($func_file) { + $file_path = "$path/$func_file"; + + return is_dir($path) && file_exists($file_path); + }); + $dirs = array_values($dirs); + + $files = array_filter($version_path_tree, function ($path) use ($func_file) { + return is_file($path) && pathinfo($path, PATHINFO_BASENAME) == $func_file; + }); + $files = array_values($files); + + if (count($dirs) > 0) { + $file = current($dirs) . '/' . $func_file; + } elseif (count($files) > 0) { + $file = current($files); + } + } + } + if (file_exists($file)) { + require $file; + exit; + } + + return null; + } + + public function result($errno, $message, $data = '') + { + exit(json_encode(array( + 'errno' => $errno, + 'message' => $message, + 'data' => $data, + ))); + } +} + + +abstract class WeModuleToutiaoapp extends WeBase +{ + public $appid; + public $version; + + public function __call($name, $arguments) + { + $dir = IA_ROOT . '/addons/' . $this->modulename . '/inc/toutiaoapp'; + $function_name = strtolower(substr($name, 6)); + $func_file = "{$function_name}.inc.php"; + $file = "$dir/{$this->version}/{$function_name}.inc.php"; + if (!file_exists($file)) { + $version_path_tree = glob("$dir/*"); + usort($version_path_tree, function ($version1, $version2) { + return -version_compare($version1, $version2); + }); + if (!empty($version_path_tree)) { + $dirs = array_filter($version_path_tree, function ($path) use ($func_file) { + $file_path = "$path/$func_file"; + + return is_dir($path) && file_exists($file_path); + }); + $dirs = array_values($dirs); + + $files = array_filter($version_path_tree, function ($path) use ($func_file) { + return is_file($path) && pathinfo($path, PATHINFO_BASENAME) == $func_file; + }); + $files = array_values($files); + + if (count($dirs) > 0) { + $file = current($dirs) . '/' . $func_file; + } elseif (count($files) > 0) { + $file = current($files); + } + } + } + if (file_exists($file)) { + require $file; + exit; + } + + return null; + } + + public function result($errno, $message, $data = '') + { + exit(json_encode(array( + 'errno' => $errno, + 'message' => $message, + 'data' => $data, + ))); + } +} + + +abstract class WeModuleHook extends WeBase +{ +} + +abstract class WeModuleWebapp extends WeBase +{ + public function __call($name, $arguments) + { + $dir = IA_ROOT . '/addons/' . $this->modulename . '/inc/webapp'; + $function_name = strtolower(substr($name, 6)); + $file = "$dir/{$function_name}.inc.php"; + if (file_exists($file)) { + require $file; + exit; + } + + return null; + } +} + +abstract class WeModulePhoneapp extends webase +{ + public $version; + + public function __call($name, $arguments) + { + $dir = IA_ROOT . '/addons/' . $this->modulename . '/inc/phoneapp'; + $function_name = strtolower(substr($name, 6)); + $func_file = "{$function_name}.inc.php"; + $file = "$dir/{$this->version}/{$function_name}.inc.php"; + if (!file_exists($file)) { + $version_path_tree = glob("$dir/*"); + usort($version_path_tree, function ($version1, $version2) { + return -version_compare($version1, $version2); + }); + if (!empty($version_path_tree)) { + $dirs = array_filter($version_path_tree, function ($path) use ($func_file) { + $file_path = "$path/$func_file"; + + return is_dir($path) && file_exists($file_path); + }); + $dirs = array_values($dirs); + + $files = array_filter($version_path_tree, function ($path) use ($func_file) { + return is_file($path) && pathinfo($path, PATHINFO_BASENAME) == $func_file; + }); + $files = array_values($files); + + if (count($dirs) > 0) { + $file = $dirs[0] . '/' . $func_file; + } elseif (count($files) > 0) { + $file = $files[0]; + } + } + } + if (file_exists($file)) { + require $file; + exit; + } + + return null; + } + + public function result($errno, $message, $data = '') + { + exit(json_encode(array( + 'errno' => $errno, + 'message' => $message, + 'data' => $data, + ))); + } +} + + +abstract class WeModuleSystemWelcome extends WeBase +{ +} + + +abstract class WeModuleMobile extends WeBase +{ + public function __call($name, $arguments) + { + $dir = IA_ROOT . '/addons/' . $this->modulename . '/inc/systemWelcome'; + $function_name = strtolower(substr($name, 5)); + $file = "$dir/{$function_name}.inc.php"; + if (file_exists($file)) { + require $file; + exit; + } + + return null; + } +} \ No newline at end of file diff --git a/framework/class/account/weixin.account.class.php b/framework/class/account/weixin.account.class.php new file mode 100644 index 0000000..7f74739 --- /dev/null +++ b/framework/class/account/weixin.account.class.php @@ -0,0 +1,1810 @@ +getAccount($uniacid); + $account['encrypt_key'] = $account['key']; + + return $account; + } + + + public function checkSign() { + $token = $this->account['token']; + $signkey = array($token, $_GET['timestamp'], $_GET['nonce']); + sort($signkey, SORT_STRING); + $signString = implode($signkey); + $signString = sha1($signString); + + return $signString == $_GET['signature']; + } + + + public function checkSignature($encrypt_msg) { + $str = $this->buildSignature($encrypt_msg); + + return $str == $_GET['msg_signature']; + } + + public function local_checkSignature($packet) { + $token = $this->account['token']; + $array = array($packet['Encrypt'], $token, $packet['TimeStamp'], $packet['Nonce']); + sort($array, SORT_STRING); + $str = implode($array); + $str = sha1($str); + + return $str == $packet['MsgSignature']; + } + + + public function local_decryptMsg($postData) { + $token = $this->account['token']; + $encodingaeskey = $this->account['encodingaeskey']; + $appid = $this->account['encrypt_key']; + + if (43 != strlen($encodingaeskey)) { + return error(-1, "微信公众平台返回接口错误. \n错误代码为: 40004 \n,错误描述为: " . $this->encryptErrorCode('40004')); + } + $key = base64_decode($encodingaeskey . '='); + $packet = $this->local_xmlExtract($postData); + if (is_error($packet)) { + return error(-1, $packet['message']); + } + $istrue = $this->local_checkSignature($packet); + if (!$istrue) { + return error(-1, "微信公众平台返回接口错误. \n错误代码为: 40001 \n,错误描述为: " . $this->encryptErrorCode('40001')); + } + $ciphertext_dec = base64_decode($packet['Encrypt']); + $iv = substr($key, 0, 16); + $decrypted = openssl_decrypt($ciphertext_dec, 'AES-256-CBC', $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv); + $block_size = 32; + + $pad = ord(substr($decrypted, -1)); + if ($pad < 1 || $pad > 32) { + $pad = 0; + } + $result = substr($decrypted, 0, (strlen($decrypted) - $pad)); + if (strlen($result) < 16) { + return ''; + } + $content = substr($result, 16, strlen($result)); + $len_list = unpack('N', substr($content, 0, 4)); + $xml_len = $len_list[1]; + $xml_content = substr($content, 4, $xml_len); + $from_appid = substr($content, $xml_len + 4); + if ($from_appid != $appid) { + return error(-1, "微信公众平台返回接口错误. \n错误代码为: 40005 \n,错误描述为: " . $this->encryptErrorCode('40005')); + } + + return $xml_content; + } + + + public function buildSignature($encrypt_msg) { + $token = $this->account['token']; + $array = array($encrypt_msg, $token, $_GET['timestamp'], $_GET['nonce']); + sort($array, SORT_STRING); + $str = implode($array); + $str = sha1($str); + + return $str; + } + + + public function encryptMsg($text) { + $token = $this->account['token']; + $encodingaeskey = $this->account['encodingaeskey']; + $appid = $this->account['encrypt_key']; + + $key = base64_decode($encodingaeskey . '='); + $text = random(16) . pack('N', strlen($text)) . $text . $appid; + $iv = substr($key, 0, 16); + $block_size = 32; + $text_length = strlen($text); + $amount_to_pad = $block_size - ($text_length % $block_size); + if (0 == $amount_to_pad) { + $amount_to_pad = $block_size; + } + $pad_chr = chr($amount_to_pad); + $tmp = ''; + for ($index = 0; $index < $amount_to_pad; ++$index) { + $tmp .= $pad_chr; + } + $text = $text . $tmp; + + $encrypted = openssl_encrypt($text, 'AES-256-CBC', $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv); + $encrypt_msg = base64_encode($encrypted); + $signature = $this->buildSignature($encrypt_msg); + + return array($signature, $encrypt_msg); + } + + + public function decryptMsg($postData) { + $token = $this->account['token']; + $encodingaeskey = $this->account['encodingaeskey']; + $appid = $this->account['encrypt_key']; + $key = base64_decode($encodingaeskey . '='); + + if (43 != strlen($encodingaeskey)) { + return error(-1, "微信公众平台返回接口错误. \n错误代码为: 40004 \n,错误描述为: " . $this->encryptErrorCode('40004')); + } + $packet = $this->xmlExtract($postData); + if (is_error($packet)) { + return error(-1, $packet['message']); + } + $istrue = $this->checkSignature($packet['encrypt']); + if (!$istrue) { + return error(-1, "微信公众平台返回接口错误. \n错误代码为: 40001 \n,错误描述为: " . $this->encryptErrorCode('40001')); + } + $ciphertext_dec = base64_decode($packet['encrypt']); + $iv = substr($key, 0, 16); + $decrypted = openssl_decrypt($ciphertext_dec, 'AES-256-CBC', $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv); + + $pad = ord(substr($decrypted, -1)); + if ($pad < 1 || $pad > 32) { + $pad = 0; + } + $result = substr($decrypted, 0, (strlen($decrypted) - $pad)); + if (strlen($result) < 16) { + return ''; + } + $content = substr($result, 16, strlen($result)); + $len_list = unpack('N', substr($content, 0, 4)); + $xml_len = $len_list[1]; + $xml_content = substr($content, 4, $xml_len); + $from_appid = substr($content, $xml_len + 4); + if ($from_appid != $appid) { + return error(-1, "微信公众平台返回接口错误. \n错误代码为: 40005 \n,错误描述为: " . $this->encryptErrorCode('40005')); + } + + return $xml_content; + } + + + public function xmlDetract($data) { + $xml['Encrypt'] = $data[1]; + $xml['MsgSignature'] = $data[0]; + $xml['TimeStamp'] = $_GET['timestamp']; + $xml['Nonce'] = $_GET['nonce']; + + return array2xml($xml); + } + + + public function xmlExtract($message) { + $packet = array(); + if (!empty($message)) { + $obj = isimplexml_load_string($message, 'SimpleXMLElement', LIBXML_NOCDATA); + if ($obj instanceof SimpleXMLElement) { + $packet['encrypt'] = strval($obj->Encrypt); + $packet['to'] = strval($obj->ToUserName); + } + } + if (!empty($packet['encrypt'])) { + return $packet; + } else { + return error(-1, "微信公众平台返回接口错误. \n错误代码为: 40002 \n,错误描述为: " . $this->encryptErrorCode('40002')); + } + } + + public function local_xmlExtract($message) { + $packet = array(); + if (!empty($message)) { + $obj = isimplexml_load_string($message, 'SimpleXMLElement', LIBXML_NOCDATA); + if ($obj instanceof SimpleXMLElement) { + $packet['Encrypt'] = strval($obj->Encrypt); + $packet['MsgSignature'] = strval($obj->MsgSignature); + $packet['TimeStamp'] = strval($obj->TimeStamp); + $packet['Nonce'] = strval($obj->Nonce); + } + } + if (!empty($packet)) { + return $packet; + } else { + return error(-1, "微信公众平台返回接口错误. \n错误代码为: 40002 \n,错误描述为: " . $this->encryptErrorCode('40002')); + } + } + + public function queryAvailableMessages() { + $messages = array('text', 'image', 'voice', 'video', 'location', 'link', 'subscribe', 'unsubscribe'); + + if (!empty($this->account['key']) && !empty($this->account['secret'])) { + $level = intval($this->account['level']); + if ($level > 1) { + $messages[] = 'click'; + $messages[] = 'view'; + } + if ($level > 2) { + $messages[] = 'qr'; + $messages[] = 'trace'; + } + } + + return $messages; + } + + public function queryAvailablePackets() { + $packets = array('text', 'music', 'news'); + if (!empty($this->account['key']) && !empty($this->account['secret'])) { + if (intval($this->account['level']) > 1) { + $packets[] = 'image'; + $packets[] = 'voice'; + $packets[] = 'video'; + } + } + + return $packets; + } + + + public function isMenuSupported() { + return !empty($this->account['key']) && + !empty($this->account['secret']) && + (intval($this->account['level']) > 1); + } + + public function menuCreate($menu) { + global $_W; + $token = $this->getAccessToken(); + if (is_error($token)) { + return $token; + } + $url = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token={$token}"; + if (!empty($menu['matchrule'])) { + $url = "https://api.weixin.qq.com/cgi-bin/menu/addconditional?access_token={$token}"; + } + $data = urldecode(json_encode($menu)); + $response = ihttp_post($url, $data); + if (is_error($response)) { + return error(-1, "访问公众平台接口失败, 错误: {$response['message']}"); + } + $result = @json_decode($response['content'], true); + if (!empty($result['errcode'])) { + return error(-1, "访问微信接口错误, 错误代码: {$result['errcode']}, 错误信息: {$result['errmsg']},错误详情:{$this->errorCode($result['errcode'])}"); + } + + return $result['menuid']; + } + + + public function menuBuild($data_array, $is_conditional = false) { + $menu = array(); + if (empty($data_array) || empty($data_array['button']) || !is_array($data_array)) { + return $menu; + } + foreach ($data_array['button'] as $button) { + $temp = array(); + $temp['name'] = preg_replace_callback('/\:\:([0-9a-zA-Z_-]+)\:\:/', function($matches) {return utf8_bytes(hexdec($matches[1]));}, $button['name']); + $temp['name'] = urlencode($temp['name']); + if (empty($button['sub_button'])) { + $temp['type'] = $button['type']; + if ('view' == $button['type']) { + $temp['url'] = urlencode($button['url']); + } elseif ('click' == $button['type']) { + if (!empty($button['media_id']) && empty($button['key'])) { + $temp['media_id'] = urlencode($button['media_id']); + $temp['type'] = 'media_id'; + } elseif (empty($button['media_id']) && !empty($button['key'])) { + $temp['type'] = 'click'; + $temp['key'] = urlencode($button['key']); + } + } elseif ('media_id' == $button['type'] || 'view_limited' == $button['type']) { + $temp['media_id'] = urlencode($button['media_id']); + } elseif ('miniprogram' == $button['type']) { + $temp['appid'] = trim($button['appid']); + $temp['pagepath'] = urlencode($button['pagepath']); + $temp['url'] = urlencode($button['url']); + } else { + $temp['key'] = urlencode($button['key']); + } + } else { + foreach ($button['sub_button'] as $sub_button) { + $sub_temp = array(); + $sub_temp['name'] = preg_replace_callback('/\:\:([0-9a-zA-Z_-]+)\:\:/', function($matches) {return utf8_bytes(hexdec($matches[1]));}, $sub_button['name']); + $sub_temp['name'] = urlencode($sub_temp['name']); + $sub_temp['type'] = $sub_button['type']; + if ('view' == $sub_button['type']) { + $sub_temp['url'] = urlencode($sub_button['url']); + } elseif ('click' == $sub_button['type']) { + if (!empty($sub_button['media_id']) && empty($sub_button['key'])) { + $sub_temp['media_id'] = urlencode($sub_button['media_id']); + $sub_temp['type'] = 'media_id'; + } elseif (empty($sub_button['media_id']) && !empty($sub_button['key'])) { + $sub_temp['type'] = 'click'; + $sub_temp['key'] = urlencode($sub_button['key']); + } + } elseif ('media_id' == $sub_button['type'] || 'view_limited' == $sub_button['type']) { + $sub_temp['media_id'] = urlencode($sub_button['media_id']); + } elseif ('miniprogram' == $sub_button['type']) { + $sub_temp['appid'] = trim($sub_button['appid']); + $sub_temp['pagepath'] = urlencode($sub_button['pagepath']); + $sub_temp['url'] = urlencode($sub_button['url']); + } else { + $sub_temp['key'] = urlencode($sub_button['key']); + } + $temp['sub_button'][] = $sub_temp; + } + } + $menu['button'][] = $temp; + } + + if (empty($is_conditional) || empty($data_array['matchrule']) || !is_array($data_array['matchrule'])) { + return $menu; + } + + if ($data_array['matchrule']['sex'] > 0) { + $menu['matchrule']['sex'] = $data_array['matchrule']['sex']; + } + if ($data_array['matchrule']['group_id'] != -1) { + $menu['matchrule']['tag_id'] = $data_array['matchrule']['group_id']; + } + if ($data_array['matchrule']['client_platform_type'] > 0) { + $menu['matchrule']['client_platform_type'] = $data_array['matchrule']['client_platform_type']; + } + if (!empty($data_array['matchrule']['province'])) { + $menu['matchrule']['country'] = urlencode('中国'); + $menu['matchrule']['province'] = urlencode($data_array['matchrule']['province']); + if (!empty($data_array['matchrule']['city'])) { + $menu['matchrule']['city'] = urlencode($data_array['matchrule']['city']); + } + } + if (!empty($data_array['matchrule']['language'])) { + $inarray = 0; + $languages = menu_languages(); + foreach ($languages as $key => $value) { + if (in_array($data_array['matchrule']['language'], $value, true)) { + $inarray = 1; + break; + } + } + if (1 === $inarray) { + $menu['matchrule']['language'] = $data_array['matchrule']['language']; + } + } + + return $menu; + } + + public function menuDelete($menuid = 0) { + $token = $this->getAccessToken(); + if (is_error($token)) { + return $token; + } + if ($menuid > 0) { + $url = "https://api.weixin.qq.com/cgi-bin/menu/delconditional?access_token={$token}"; + $data = array( + 'menuid' => $menuid, + ); + $response = ihttp_post($url, json_encode($data)); + } else { + $url = "https://api.weixin.qq.com/cgi-bin/menu/delete?access_token={$token}"; + $response = ihttp_get($url); + } + if (is_error($response)) { + return error(-1, "访问公众平台接口失败, 错误: {$response['message']}"); + } + $result = @json_decode($response['content'], true); + if (!empty($result['errcode'])) { + return error(-1, "访问微信接口错误, 错误代码: {$result['errcode']}, 错误信息: {$result['errmsg']},错误详情:{$this->errorCode($result['errcode'])}"); + } + + return true; + } + + public function menuModify($menu) { + return $this->menuCreate($menu); + } + + public function menuCurrentQuery() { + $token = $this->getAccessToken(); + if (is_error($token)) { + return $token; + } + $url = "https://api.weixin.qq.com/cgi-bin/get_current_selfmenu_info?access_token={$token}"; + + return $this->requestApi($url); + } + + public function menuQuery() { + $token = $this->getAccessToken(); + if (is_error($token)) { + return $token; + } + $url = "https://api.weixin.qq.com/cgi-bin/menu/get?access_token={$token}"; + $response = ihttp_get($url); + if (is_error($response)) { + return error(-1, "访问公众平台接口失败, 错误: {$response['message']}"); + } + $result = @json_decode($response['content'], true); + if (!empty($result['errcode']) && '46003' != $result['errcode']) { + return error(-1, "访问微信接口错误, 错误代码: {$result['errcode']}, 错误信息: {$result['errmsg']},错误详情:{$this->errorCode($result['errcode'])}"); + } + + return $result; + } + + public function fansQueryInfo($uniid, $isOpen = true) { + if ($isOpen) { + $openid = $uniid; + } else { + exit('error'); + } + $token = $this->getAccessToken(); + if (is_error($token)) { + return $token; + } + $url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token={$token}&openid={$openid}&lang=zh_CN"; + $response = ihttp_get($url); + if (is_error($response)) { + return error(-1, "访问公众平台接口失败, 错误: {$response['message']}"); + } + preg_match('/city":"(.*)","province":"(.*)","country":"(.*)"/U', $response['content'], $reg_arr); + $city = htmlentities(bin2hex($reg_arr[1])); + $province = htmlentities(bin2hex($reg_arr[2])); + $country = htmlentities(bin2hex($reg_arr[3])); + $response['content'] = str_replace('"city":"' . $reg_arr[1] . '","province":"' . $reg_arr[2] . '","country":"' . $reg_arr[3] . '"', '"city":"' . $city . '","province":"' . $province . '","country":"' . $country . '"', $response['content']); + $result = @json_decode($response['content'], true); + $result['city'] = hex2bin(html_entity_decode($result['city'])); + $result['province'] = hex2bin(html_entity_decode($result['province'])); + $result['country'] = hex2bin(html_entity_decode($result['country'])); + $result['headimgurl'] = str_replace('http:', 'https:', $result['headimgurl']); + unset($result['remark'], $result['subscribe_scene'], $result['qr_scene'], $result['qr_scene_str']); + if (empty($result)) { + return error(-1, "接口调用失败, 元数据: {$response['meta']}"); + } elseif (!empty($result['errcode'])) { + return error($result['errcode'], "访问微信接口错误, 错误代码: {$result['errcode']}, 错误信息: {$result['errmsg']},错误详情:{$this->errorCode($result['errcode'])}"); + } + + return $result; + } + + + public function fansBatchQueryInfo($data) { + if (empty($data)) { + return error(-1, '粉丝openid错误'); + } + foreach ($data as $da) { + $post[] = array( + 'openid' => trim($da), + 'lang' => 'zh_CN', + ); + } + $data = array(); + $data['user_list'] = $post; + $token = $this->getAccessToken(); + if (is_error($token)) { + return $token; + } + $url = "https://api.weixin.qq.com/cgi-bin/user/info/batchget?access_token={$token}"; + $response = ihttp_post($url, json_encode($data)); + if (is_error($response)) { + return error(-1, "访问公众平台接口失败, 错误: {$response['message']}"); + } + $result = @json_decode($response['content'], true); + if (empty($result)) { + return error(-1, "接口调用失败, 元数据: {$response['meta']}"); + } elseif (!empty($result['errcode'])) { + return error(-1, "访问微信接口错误, 错误代码: {$result['errcode']}, 错误信息: {$result['errmsg']},错误详情:{$this->errorCode($result['errcode'])}"); + } + + return $result['user_info_list']; + } + + public function fansAll($startopenid = '') { + global $_GPC; + $token = $this->getAccessToken(); + if (is_error($token)) { + return $token; + } + $url = 'https://api.weixin.qq.com/cgi-bin/user/get?access_token=' . $token; + if (!empty($_GPC['next_openid'])) { + $startopenid = $_GPC['next_openid']; + } + if (!empty($startopenid)) { + $url .= '&next_openid=' . $startopenid; + } + $response = ihttp_get($url); + if (is_error($response)) { + return error(-1, "访问公众平台接口失败, 错误: {$response['message']}"); + } + $result = @json_decode($response['content'], true); + if (empty($result)) { + return error(-1, "接口调用失败, 元数据: {$response['meta']}"); + } elseif (!empty($result['errcode'])) { + return error(-1, "访问公众平台接口失败, 错误: {$result['errmsg']},错误详情:{$this->errorCode($result['errcode'])}"); + } + $return = array(); + $return['total'] = $result['total']; + $return['fans'] = $result['data']['openid']; + $return['next'] = $result['next_openid']; + + return $return; + } + + public function queryBarCodeActions() { + return array('barCodeCreateDisposable', 'barCodeCreateFixed'); + } + + public function barCodeCreateDisposable($barcode) { + $barcode['expire_seconds'] = empty($barcode['expire_seconds']) ? 2592000 : $barcode['expire_seconds']; + if (empty($barcode['action_info']['scene']['scene_id']) && empty($barcode['action_info']['scene']['scene_str']) || empty($barcode['action_name'])) { + return error('1', 'Invalid params'); + } + $token = $this->getAccessToken(); + $response = ihttp_request('https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=' . $token, json_encode($barcode)); + if (is_error($response)) { + return $response; + } + $content = @json_decode($response['content'], true); + + if (empty($content)) { + return error(-1, "接口调用失败, 元数据: {$response['meta']}"); + } + if (!empty($content['errcode'])) { + return error(-1, "访问微信接口错误, 错误代码: {$content['errcode']}, 错误信息: {$content['errmsg']},错误详情:{$this->errorCode($content['errcode'])}"); + } + + return $content; + } + + public function barCodeCreateFixed($barcode) { + if ('QR_LIMIT_SCENE' == $barcode['action_name'] && empty($barcode['action_info']['scene']['scene_id'])) { + return error('1', '场景值错误'); + } + if ('QR_LIMIT_STR_SCENE' == $barcode['action_name'] && empty($barcode['action_info']['scene']['scene_str'])) { + return error('1', '场景字符串错误'); + } + $token = $this->getAccessToken(); + $response = ihttp_request('https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=' . $token, json_encode($barcode)); + if (is_error($response)) { + return $response; + } + $content = @json_decode($response['content'], true); + if (empty($content)) { + return error(-1, "接口调用失败, 元数据: {$response['meta']}"); + } + if (!empty($content['errcode'])) { + return error(-1, "访问微信接口错误, 错误代码: {$content['errcode']}, 错误信息: {$content['errmsg']},错误详情:{$this->errorCode($content['errcode'])}"); + } + + return $content; + } + + private function encryptErrorCode($code) { + $errors = array( + '40001' => '签名验证错误', + '40002' => 'xml解析失败', + '40003' => 'sha加密生成签名失败', + '40004' => 'encodingAesKey 非法', + '40005' => 'appid 校验错误', + '40006' => 'aes 加密失败', + '40007' => 'aes 解密失败', + '40008' => '解密后得到的buffer非法', + '40009' => 'base64加密失败', + '40010' => 'base64解密失败', + '40011' => '生成xml失败', + ); + if ($errors[$code]) { + return $errors[$code]; + } else { + return '未知错误'; + } + } + + + public function changeSend($send) { + if (empty($send)) { + return error(-1, 'Invalid params'); + } + $token = $this->getAccessToken(); + if (is_error($token)) { + return $token; + } + $sendapi = 'https://api.weixin.qq.com/pay/delivernotify?access_token=' . $token; + $response = ihttp_request($sendapi, json_encode($send)); + $response = json_decode($response['content'], true); + if (empty($response)) { + return error(-1, '发货失败,请检查您的公众号权限或是公众号AppId和公众号AppSecret!'); + } + if (!empty($response['errcode'])) { + return error(-1, $response['errmsg']); + } + + return true; + } + + + public function getAccessToken() { + $cachekey = cache_system_key('accesstoken', array('uniacid' => $this->account['uniacid'])); + $cache = cache_load($cachekey); + if (!empty($cache) && !empty($cache['token'])) { + $this->account['access_token'] = $cache; + + return $cache['token']; + } + if (empty($this->account['key']) || empty($this->account['secret'])) { + return error('-1', '未填写公众号的 appid 或 appsecret!'); + } + $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={$this->account['key']}&secret={$this->account['secret']}"; + $content = ihttp_get($url); + if (is_error($content)) { + return error('-1', '获取微信公众号授权失败, 请稍后重试!错误详情: ' . $content['message']); + } + if (empty($content['content'])) { + return error('-1', 'AccessToken获取失败,请检查appid和appsecret的值是否与微信公众平台一致!'); + } + $token = @json_decode($content['content'], true); + + if ('40164' == $token['errcode']) { + return error(-1, $this->errorCode($token['errcode'], $token['errmsg'])); + } + if (empty($token) || !is_array($token) || empty($token['access_token']) || empty($token['expires_in'])) { + return error('-1', '获取微信公众号授权失败!错误代码:' . $token['errcode'] . ',错误信息:' . $this->errorCode($token['errcode'])); + } + $record = array(); + $record['token'] = $token['access_token']; + $record_expire = $token['expires_in'] - 200; + $this->account['access_token'] = $record; + cache_write($cachekey, $record, $record_expire); + + return $record['token']; + } + + public function getVailableAccessToken() { + $accounts = pdo_fetchall('SELECT `key`, `secret`, `acid` FROM ' . tablename('account_wechats') . ' WHERE uniacid = :uniacid ORDER BY `level` DESC ', array(':uniacid' => $GLOBALS['_W']['uniacid'])); + if (empty($accounts)) { + return error(-1, 'no permission'); + } + foreach ($accounts as $account) { + if (empty($account['key']) || empty($account['secret'])) { + continue; + } + $acid = $account['acid']; + break; + } + $account = WeAccount::create($acid); + + return $account->getAccessToken(); + } + + public function fetch_token() { + return $this->getAccessToken(); + } + + public function fetch_available_token() { + return $this->getVailableAccessToken(); + } + + public function clearAccessToken() { + $access_token = $this->getAccessToken(); + if (is_error($access_token)) { + return $access_token; + } + $url = 'https://api.weixin.qq.com/cgi-bin/getcallbackip?access_token=' . $access_token; + $response = $this->requestApi($url); + if (is_error($response) && '40001' == $response['errno']) { + cache_delete(cache_system_key('accesstoken', array('uniacid' => $this->account['uniacid']))); + } + + return true; + } + + + public function getJsApiTicket() { + $cachekey = cache_system_key('jsticket', array('uniacid' => $this->account['uniacid'])); + $cache = cache_load($cachekey); + if (!empty($cache) && !empty($cache['ticket'])) { + return $cache['ticket']; + } + $access_token = $this->getAccessToken(); + if (is_error($access_token)) { + return $access_token; + } + $url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token={$access_token}&type=jsapi"; + $content = ihttp_get($url); + if (is_error($content)) { + return error(-1, '调用接口获取微信公众号 jsapi_ticket 失败, 错误信息: ' . $this->errorCode($content['message'])); + } + $result = @json_decode($content['content'], true); + if (empty($result) || 0 != intval(($result['errcode'])) || 'ok' != $result['errmsg']) { + return error(-1, '获取微信公众号 jsapi_ticket 结果错误, 错误信息: ' . $this->errorCode($result['errcode'], $result['errmsg'])); + } + $record = array(); + $record['ticket'] = $result['ticket']; + $record_expire = $result['expires_in'] - 200; + $this->account['jsapi_ticket'] = $record; + cache_write($cachekey, $record, $record_expire); + + return $record['ticket']; + } + + + public function getJssdkConfig($url = '') { + global $_W, $urls; + $jsapiTicket = $this->getJsApiTicket(); + if (is_error($jsapiTicket)) { + $jsapiTicket = $jsapiTicket['message']; + } + $nonceStr = random(16); + $timestamp = TIMESTAMP; + $url = empty($url) ? $urls['scheme'] . '://' . $urls['host'] . $_SERVER['REQUEST_URI'] : $url; + $string1 = "jsapi_ticket={$jsapiTicket}&noncestr={$nonceStr}×tamp={$timestamp}&url={$url}"; + $signature = sha1($string1); + $config = array( + 'appId' => $this->account['key'], + 'nonceStr' => $nonceStr, + 'timestamp' => "$timestamp", + 'signature' => $signature, + ); + if (DEVELOPMENT) { + $config['url'] = $url; + $config['string1'] = $string1; + $config['name'] = $this->account['name']; + } + + return $config; + } + + + public function long2short($longurl) { + $token = $this->getAccessToken(); + if (is_error($token)) { + return $token; + } + $url = "https://api.weixin.qq.com/cgi-bin/shorturl?access_token={$token}"; + $send = array(); + $send['action'] = 'long2short'; + $send['long_url'] = $longurl; + $response = ihttp_request($url, json_encode($send)); + if (is_error($response)) { + return error(-1, "访问公众平台接口失败, 错误: {$this->errorCode($response['message'])}"); + } + $result = @json_decode($response['content'], true); + if (empty($result)) { + return error(-1, "接口调用失败, 元数据: {$response['meta']}"); + } elseif (!empty($result['errcode'])) { + return error(-1, "访问微信接口错误, 错误代码: {$result['errcode']}, 错误信息: {$result['errmsg']},错误详情:{$this->errorCode($result['errcode'])}"); + } + + return $result; + } + + + public function fetchChatLog($params = array()) { + if (empty($params['starttime']) || empty($params['endtime'])) { + return error(-1, '没有要查询的时间段'); + } + $starttmp = date('Y-m-d', $params['starttime']); + $endtmp = date('Y-m-d', $params['endtime']); + if ($starttmp != $endtmp) { + return error(-1, '时间范围有误,微信公众平台不支持跨日查询'); + } + if (empty($params['openid'])) { + return error(-1, '没有要查询的openid'); + } + if (empty($params['pagesize'])) { + $params['pagesize'] = 50; + } + if (empty($params['pageindex'])) { + $params['pageindex'] = 1; + } + $token = $this->getAccessToken(); + if (is_error($token)) { + return $token; + } + $url = "https://api.weixin.qq.com/customservice/msgrecord/getrecord?access_token={$token}"; + $response = ihttp_request($url, json_encode($params)); + if (is_error($response)) { + return error(-1, "访问公众平台接口失败, 错误: {$response['message']}"); + } + $result = @json_decode($response['content'], true); + if (empty($result)) { + return error(-1, "接口调用失败, 元数据: {$response['meta']}"); + } elseif (!empty($result['errcode'])) { + return error(-1, "访问微信接口错误, 错误代码: {$result['errcode']}, 错误信息: {$result['errmsg']},错误详情:{$this->errorCode($result['errcode'])}"); + } + + return $result; + } + + public function isTagSupported() { + return (!empty($this->account['key']) && + !empty($this->account['secret']) || ACCOUNT_OAUTH_LOGIN == $this->account['type']) && + (intval($this->account['level']) > ACCOUNT_SERVICE); + } + + + public function fansTagAdd($tagname) { + if (empty($tagname)) { + return error(-1, '请填写标签名称'); + } + $token = $this->getAccessToken(); + if (is_error($token)) { + return $token; + } + $url = "https://api.weixin.qq.com/cgi-bin/tags/create?access_token={$token}"; + $data = stripslashes(ijson_encode(array('tag' => array('name' => $tagname)), JSON_UNESCAPED_UNICODE)); + cache_delete(cache_system_key('account_tags', array('uniacid' => $this->account['uniacid']))); + + return $this->requestApi($url, $data); + } + + + public function fansTagFetchAll() { + $cachekey = cache_system_key('account_tags', array('uniacid' => $this->account['uniacid'])); + $cache = cache_load($cachekey); + if (!empty($cache['tags']) && $cache['expire'] > TIMESTAMP) { + return $cache['tags']; + } + $token = $this->getAccessToken(); + if (is_error($token)) { + return $token; + } + $url = "https://api.weixin.qq.com/cgi-bin/tags/get?access_token={$token}"; + $tags = $this->requestApi($url); + if (!is_error($tags)) { + cache_write($cachekey, array('tags' => $tags, 'expire' => TIMESTAMP + 3600), 3400); + } + return $tags; + } + + + public function fansTagEdit($tagid, $tagname) { + if (empty($tagid) || empty($tagname)) { + return error(-1, '标签信息错误'); + } + if (in_array($tagid, array(1, 2))) { + return error(-1, '微信平台默认标签,不能修改'); + } + + $token = $this->getAccessToken(); + if (is_error($token)) { + return $token; + } + $url = "https://api.weixin.qq.com/cgi-bin/tags/update?access_token={$token}"; + $data = stripslashes(ijson_encode(array('tag' => array('id' => $tagid, 'name' => $tagname)), JSON_UNESCAPED_UNICODE)); + $result = $this->requestApi($url, $data); + if (is_error($result)) { + return $result; + } + cache_delete(cache_system_key('account_tags', array('uniacid' => $this->account['uniacid']))); + + return true; + } + + + public function fansTagDelete($tagid) { + $tagid = intval($tagid); + if (empty($tagid)) { + return error(-1, '标签id错误'); + } + $token = $this->getAccessToken(); + if (is_error($token)) { + return $token; + } + $url = "https://api.weixin.qq.com/cgi-bin/tags/delete?access_token={$token}"; + $data = json_encode(array('tag' => array('id' => $tagid))); + $result = $this->requestApi($url, $data); + if (is_error($result)) { + return $result; + } + cache_delete(cache_system_key('account_tags', array('uniacid' => $this->account['uniacid']))); + + return true; + } + + + public function fansTagGetUserlist($tagid, $next_openid = '') { + $tagid = intval($tagid); + $next_openid = (string) $next_openid; + if (empty($tagid)) { + return error(-1, '标签id错误'); + } + $token = $this->getAccessToken(); + if (is_error($token)) { + return $token; + } + $url = 'https://api.weixin.qq.com/cgi-bin/user/tag/get?access_token=' . $token; + $data = array( + 'tagid' => $tagid, + ); + if (!empty($next_openid)) { + $data['next_openid'] = $next_openid; + } + $data = json_encode($data); + + return $this->requestApi($url, $data); + } + + + public function fansTagTagging($openid, $tagids) { + $openid = (string) $openid; + $tagids = (array) $tagids; + if (empty($openid)) { + return error(-1, '没有填写用户openid'); + } + if (empty($tagids)) { + return error(-1, '没有填写标签'); + } + if (count($tagids) > 3) { + return error(-1, '最多3个标签'); + } + $token = $this->getAccessToken(); + if (is_error($token)) { + return $token; + } + $fetch_result = $this->fansTagFetchOwnTags($openid); + if (is_error($fetch_result)) { + return $fetch_result; + } + foreach ($fetch_result['tagid_list'] as $del_tagid) { + $this->fansTagBatchUntagging($openid, $del_tagid); + } + $url = "https://api.weixin.qq.com/cgi-bin/tags/members/batchtagging?access_token={$token}"; + foreach ($tagids as $tagid) { + $data = array( + 'openid_list' => $openid, + 'tagid' => $tagid, + ); + $data = json_encode($data); + $result = $this->requestApi($url, $data); + if (is_error($result)) { + return $result; + } + } + + return true; + } + + + public function fansTagBatchTagging($openid_list, $tagid) { + $openid_list = (array) $openid_list; + $tagid = (int) $tagid; + if (empty($openid_list)) { + return error(-1, '没有填写用户openid列表'); + } + if (empty($tagid)) { + return error(-1, '没有填写tagid'); + } + $token = $this->getAccessToken(); + if (is_error($token)) { + return $token; + } + $url = "https://api.weixin.qq.com/cgi-bin/tags/members/batchtagging?access_token={$token}"; + $data = array( + 'openid_list' => $openid_list, + 'tagid' => $tagid, + ); + $data = json_encode($data); + $result = $this->requestApi($url, $data); + if (is_error($result)) { + return $result; + } + + return true; + } + + + public function fansTagBatchUntagging($openid_list, $tagid) { + $openid_list = (array) $openid_list; + $tagid = (int) $tagid; + if (empty($openid_list)) { + return error(-1, '没有填写用户openid列表'); + } + if (empty($tagid)) { + return error(-1, '没有填写tagid'); + } + $token = $this->getAccessToken(); + if (is_error($token)) { + return $token; + } + $url = "https://api.weixin.qq.com/cgi-bin/tags/members/batchuntagging?access_token={$token}"; + $data = array( + 'openid_list' => $openid_list, + 'tagid' => $tagid, + ); + $data = json_encode($data); + $result = $this->requestApi($url, $data); + if (is_error($result)) { + return $result; + } + + return true; + } + + + public function fansTagFetchOwnTags($openid) { + $openid = (string) $openid; + if (empty($openid)) { + return error(-1, '没有填写用户openid'); + } + $token = $this->getAccessToken(); + if (is_error($token)) { + return $token; + } + $url = "https://api.weixin.qq.com/cgi-bin/tags/getidlist?access_token={$token}"; + $data = json_encode(array('openid' => $openid)); + + return $this->requestApi($url, $data); + } + + + public function fansSendAll($group, $msgtype, $media_id) { + $types = array('text' => 'text', 'basic' => 'text', 'image' => 'image', 'news' => 'mpnews', 'voice' => 'voice', 'video' => 'mpvideo', 'wxcard' => 'wxcard'); + if (empty($types[$msgtype])) { + return error(-1, '消息类型不合法'); + } + $is_to_all = false; + if ($group == -1) { + $is_to_all = true; + } + $send_conent = ('text' == $types[$msgtype]) ? array('content' => $media_id) : array('media_id' => $media_id); + $data = array( + 'filter' => array( + 'is_to_all' => $is_to_all, + 'tag_id' => $group, + ), + 'msgtype' => $types[$msgtype], + $types[$msgtype] => $send_conent, + ); + if ('wxcard' == $types[$msgtype]) { + unset($data['wxcard']['media_id']); + $data['wxcard']['card_id'] = $media_id; + } + $token = $this->getAccessToken(); + if (is_error($token)) { + return $token; + } + $url = "https://api.weixin.qq.com/cgi-bin/message/mass/sendall?access_token={$token}"; + $data = urldecode(json_encode($data, JSON_UNESCAPED_UNICODE)); + $response = ihttp_request($url, $data); + if (is_error($response)) { + return error(-1, "访问公众平台接口失败, 错误: {$response['message']}"); + } + $result = @json_decode($response['content'], true); + if (empty($result)) { + return error(-1, "接口调用失败, 元数据: {$response['meta']}"); + } elseif (!empty($result['errcode'])) { + return error(-1, "访问微信接口错误, 错误代码: {$result['errcode']}, 错误信息: {$result['errmsg']},错误详情:{$this->errorCode($result['errcode'])}"); + } + + return $result; + } + + + public function fansSendPreview($wxname, $content, $msgtype) { + $types = array('text' => 'text', 'image' => 'image', 'news' => 'mpnews', 'voice' => 'voice', 'video' => 'mpvideo', 'wxcard' => 'wxcard'); + if (empty($types[$msgtype])) { + return error(-1, '群发类型不合法'); + } + $msgtype = $types[$msgtype]; + $token = $this->getAccessToken(); + if (is_error($token)) { + return $token; + } + $url = 'https://api.weixin.qq.com/cgi-bin/message/mass/preview?access_token=' . $token; + $send = array( + 'towxname' => $wxname, + 'msgtype' => $msgtype, + ); + if ('text' == $msgtype) { + $send[$msgtype] = array( + 'content' => $content, + ); + } elseif ('wxcard' == $msgtype) { + $send[$msgtype] = array( + 'card_id' => $content, + ); + } else { + $send[$msgtype] = array( + 'media_id' => $content, + ); + } + + $response = ihttp_request($url, json_encode($send, JSON_UNESCAPED_UNICODE)); + if (is_error($response)) { + return error(-1, "访问公众平台接口失败, 错误: {$response['message']}"); + } + $result = @json_decode($response['content'], true); + if (empty($result)) { + } elseif (!empty($result['errcode'])) { + return error(-1, "访问公众平台接口失败, 错误: {$result['errmsg']},错误详情:{$this->errorCode($result['errcode'])}"); + } + + return $result; + } + + + public function sendCustomNotice($data) { + if (empty($data)) { + return error(-1, '参数错误'); + } + $token = $this->getAccessToken(); + if (is_error($token)) { + return $token; + } + $url = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token={$token}"; + $response = ihttp_request($url, urldecode(json_encode($data))); + if (is_error($response)) { + return error(-1, "访问公众平台接口失败, 错误: {$response['message']}"); + } + $result = @json_decode($response['content'], true); + if (empty($result)) { + return error(-1, "接口调用失败, 元数据: {$response['meta']}"); + } elseif (!empty($result['errcode'])) { + return error(-1, "访问微信接口错误, 错误代码: {$result['errcode']}, 错误信息: {$result['errmsg']},错误详情:{$this->errorCode($result['errcode'])}"); + } + + return true; + } + + + public function sendTplNotice($touser, $template_id, $postdata, $url = '', $topcolor = '#FF683F', $miniprogram = array('appid' => '', 'pagepath' => '')) { + if (empty($this->account['key']) || ACCOUNT_SERVICE_VERIFY != $this->account['level']) { + return error(-1, '你的公众号没有发送模板消息的权限'); + } + if (empty($touser)) { + return error(-1, '参数错误,粉丝openid不能为空'); + } + if (empty($template_id)) { + return error(-1, '参数错误,模板标示不能为空'); + } + if (empty($postdata) || !is_array($postdata)) { + return error(-1, '参数错误,请根据模板规则完善消息内容'); + } + $token = $this->getAccessToken(); + if (is_error($token)) { + return $token; + } + + $data = array(); + if (!empty($miniprogram['appid']) && !empty($miniprogram['pagepath'])) { + $data['miniprogram'] = $miniprogram; + } + $data['touser'] = $touser; + $data['template_id'] = trim($template_id); + $data['url'] = trim($url); + $data['topcolor'] = trim($topcolor); + $data['data'] = $postdata; + $data = json_encode($data); + $post_url = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token={$token}"; + $response = ihttp_request($post_url, $data); + if (is_error($response)) { + return error(-1, "访问公众平台接口失败, 错误: {$response['message']}"); + } + $result = @json_decode($response['content'], true); + if (empty($result)) { + return error(-1, "接口调用失败, 元数据: {$response['meta']}"); + } elseif (!empty($result['errcode'])) { + return error(-1, "访问微信接口错误, 错误代码: {$result['errcode']}, 错误信息: {$result['errmsg']},信息详情:{$this->errorCode($result['errcode'])}"); + } + + return true; + } + + + public function uploadMedia($path, $type = 'image') { + if (empty($path)) { + return error(-1, '参数错误'); + } + if (in_array(substr(ltrim($path, '/'), 0, 6), array('images', 'videos', 'audios', 'thumb'))) { + $path = ATTACHMENT_ROOT . ltrim($path, '/'); + } + if (!file_exists($path)) { + return error(1, '文件不存在'); + } + $token = $this->getAccessToken(); + if (is_error($token)) { + return $token; + } + $url = "https://api.weixin.qq.com/cgi-bin/media/upload?access_token={$token}&type={$type}"; + $data = array( + 'media' => '@' . $path, + ); + + return $this->requestApi($url, $data); + } + + + public function uploadMediaFixed($path, $type = 'images') { + global $_W; + if (empty($path)) { + return error(-1, '参数错误'); + } + if (in_array(substr(ltrim($path, '/'), 0, 6), array('images', 'videos', 'audios', 'thumb', 'voices'))) { + $path = ATTACHMENT_ROOT . ltrim($path, '/'); + } + if (!file_exists($path)) { + return error(1, '文件不存在'); + } + $token = $this->getAccessToken(); + if (is_error($token)) { + return $token; + } + $url = "https://api.weixin.qq.com/cgi-bin/material/add_material?access_token={$token}&type={$type}"; + $data = array( + 'media' => '@' . $path, + ); + + if ('videos' == $type) { + $video_filename = ltrim($path, ATTACHMENT_ROOT); + $material = $material = pdo_get('core_attachment', array('uniacid' => $_W['uniacid'], 'attachment' => $video_filename)); + } + $filename = pathinfo($path, PATHINFO_FILENAME); + $description = array( + 'title' => 'videos' == $type ? $material['filename'] : $filename, + 'introduction' => $filename, + ); + $data['description'] = urldecode(json_encode($description)); + + return $this->requestApi($url, $data); + } + + + public function editMaterialNews($data) { + $token = $this->getAccessToken(); + if (is_error($token)) { + return $token; + } + $url = "https://api.weixin.qq.com/cgi-bin/material/update_news?access_token={$token}"; + $response = $this->requestApi($url, stripslashes(ijson_encode($data, JSON_UNESCAPED_UNICODE))); + if (is_error($response)) { + return $response; + } + + return true; + } + + + public function uploadNewsThumb($thumb) { + $token = $this->getAccessToken(); + if (is_error($token)) { + return $token; + } + if (!file_exists($thumb)) { + return error(1, '文件不存在'); + } + $data = array( + 'media' => '@' . $thumb, + ); + $url = "https://api.weixin.qq.com/cgi-bin/media/uploadimg?access_token={$token}"; + $response = $this->requestApi($url, $data); + if (is_error($response)) { + return $response; + } else { + return $response['url']; + } + } + + public function uploadVideoFixed($title, $description, $path) { + if (empty($path) || empty($title) || empty($description)) { + return error(-1, '参数错误'); + } + if (in_array(substr(ltrim($path, '/'), 0, 6), array('images', 'videos', 'audios'))) { + $path = ATTACHMENT_ROOT . ltrim($path, '/'); + } + if (!file_exists($path)) { + return error(1, '文件不存在'); + } + $token = $this->getAccessToken(); + if (is_error($token)) { + return $token; + } + $url = "https://api.weixin.qq.com/cgi-bin/material/add_material?access_token={$token}&type=videos"; + $data = array( + 'media' => '@' . $path, + 'description' => stripslashes(ijson_encode(array('title' => $title, 'introduction' => $description), JSON_UNESCAPED_UNICODE)), + ); + + return $this->requestApi($url, $data); + } + + + public function uploadVideo($data) { + if (empty($data)) { + return error(-1, '参数错误'); + } + $token = $this->getAccessToken(); + if (is_error($token)) { + return $token; + } + $url = "https://file.api.weixin.qq.com/cgi-bin/media/uploadvideo?access_token={$token}"; + $response = ihttp_request($url, urldecode(json_encode($data))); + if (is_error($response)) { + return error(-1, "访问公众平台接口失败, 错误: {$response['message']}"); + } + $result = @json_decode($response['content'], true); + if (empty($result)) { + return error(-1, "接口调用失败, 元数据: {$response['meta']}"); + } elseif (!empty($result['errcode'])) { + return error(-1, "访问微信接口错误, 错误代码: {$result['errcode']}, 错误信息: {$result['errmsg']}, 错误详情:{$this->errorCode($result['errcode'])}"); + } + + return $result; + } + + + public function uploadNews($data) { + if (empty($data)) { + return error(-1, '参数错误'); + } + $token = $this->getAccessToken(); + if (is_error($token)) { + return $token; + } + $url = "https://api.weixin.qq.com/cgi-bin/media/uploadnews?access_token={$token}"; + $response = ihttp_request($url, urldecode(json_encode($data))); + if (is_error($response)) { + return error(-1, "访问公众平台接口失败, 错误: {$response['message']}"); + } + $result = @json_decode($response['content'], true); + if (empty($result)) { + return error(-1, "接口调用失败, 元数据: {$response['meta']}"); + } elseif (!empty($result['errcode'])) { + return error(-1, "访问微信接口错误, 错误代码: {$result['errcode']}, 错误信息: {$result['errmsg']},错误详情:{$this->errorCode($result['errcode'])}"); + } + + return $result; + } + + public function addMatrialNews($data) { + $token = $this->getAccessToken(); + if (is_error($token)) { + return $token; + } + $url = "https://api.weixin.qq.com/cgi-bin/material/add_news?access_token={$token}"; + $data = stripslashes(urldecode(ijson_encode($data, JSON_UNESCAPED_UNICODE))); + $response = $this->requestApi($url, $data); + if (is_error($response)) { + return $response; + } + + return $response['media_id']; + } + + + public function batchGetMaterial($type = 'news', $offset = 0, $count = 20) { + global $_W; + $token = $this->getAccessToken(); + if (is_error($token)) { + return $token; + } + $url = 'https://api.weixin.qq.com/cgi-bin/material/batchget_material?access_token=' . $token; + $data = array( + 'type' => $type, + 'offset' => intval($offset), + 'count' => $count, + ); + + return $this->requestApi($url, json_encode($data)); + } + + + public function getMaterial($media_id, $savefile = true) { + $token = $this->getAccessToken(); + if (is_error($token)) { + return $token; + } + $url = 'https://api.weixin.qq.com/cgi-bin/material/get_material?access_token=' . $token; + $data = array( + 'media_id' => trim($media_id), + ); + $response = ihttp_request($url, json_encode($data)); + if (is_error($response)) { + return error(-1, "访问公平台接口失败, 错误: {$response['message']}"); + } + $result = @json_decode($response['content'], true); + if (!empty($result['errcode'])) { + return error(-1, "访问公众平台接口失败, 错误: {$result['errmsg']},错误详情:{$this->errorCode($result['errcode'])}"); + } + if (empty($response['headers']['Content-disposition'])) { + $response = json_decode($response['content'], true); + if (!empty($response['down_url'])) { + if (empty($savefile)) { + return $response; + } + $response = ihttp_get($response['down_url']); + $response['headers']['Content-disposition'] = $response['headers']['Content-Disposition']; + } elseif (!empty($response['news_item'])) { + return $response; + } + } + if ($savefile && !empty($response['headers']['Content-disposition']) && strexists($response['headers']['Content-disposition'], 'filename=')) { + global $_W; + preg_match('/filename=\"?([^"]*)/', $response['headers']['Content-disposition'], $match); + $pathinfo = pathinfo($match[1]); + $filename = $_W['uniacid'] . '/' . date('Y/m/'); + if (in_array(strtolower($pathinfo['extension']), array('mp4'))) { + $filename = 'videos/' . $filename; + } elseif (in_array(strtolower($pathinfo['extension']), array('amr', 'mp3', 'wma', 'wmv'))) { + $filename = 'audios/' . $filename; + } else { + $filename = 'images/' . $filename; + } + $filename .= file_random_name($filename, $pathinfo['extension']); + load()->func('file'); + file_write($filename, $response['content']); + file_remote_upload($filename); + + return $filename; + } else { + return $response['content']; + } + + return $result; + } + + + public function downloadMedia($media_id, $savefile = true) { + $mediatypes = array('image', 'voice', 'thumb'); + $media_id = is_array($media_id) ? $media_id['media_id'] : $media_id; + if (empty($media_id)) { + return error(-1, '微信下载媒体资源参数错误'); + } + + $token = $this->getAccessToken(); + if (is_error($token)) { + return $token; + } + $url = "https://api.weixin.qq.com/cgi-bin/media/get?access_token={$token}&media_id={$media_id}"; + $response = ihttp_get($url); + + if (empty($response['headers']['Content-disposition'])) { + $response = json_decode($response['content'], true); + if (!empty($response['video_url'])) { + $response = ihttp_get($response['video_url']); + $response['headers']['Content-disposition'] = $response['headers']['Content-Disposition']; + } + } + if ($savefile && !empty($response['headers']['Content-disposition']) && strexists($response['headers']['Content-disposition'], 'filename=')) { + global $_W; + preg_match('/filename=\"?([^"]*)/', $response['headers']['Content-disposition'], $match); + $filename = $_W['uniacid'] . '/' . date('Y/m/') . $match[1]; + $pathinfo = pathinfo($filename); + if (in_array(strtolower($pathinfo['extension']), array('mp4'))) { + $filename = 'videos/' . $filename; + } elseif (in_array(strtolower($pathinfo['extension']), array('amr', 'mp3', 'wma', 'wmv'))) { + $filename = 'audios/' . $filename; + } else { + $filename = 'images/' . $filename; + } + load()->func('file'); + file_write($filename, $response['content']); + file_remote_upload($filename); + + return $filename; + } else { + return $response['content']; + } + } + + + public function getMaterialCount() { + $token = $this->getAccessToken(); + if (is_error($token)) { + return $token; + } + $url = 'https://api.weixin.qq.com/cgi-bin/material/get_materialcount?access_token=' . $token; + + return $this->requestApi($url); + } + + public function delMaterial($media_id) { + $media_id = trim($media_id); + if (empty($media_id)) { + return error(-1, '素材media_id错误'); + } + $token = $this->getAccessToken(); + if (is_error($token)) { + return $token; + } + $url = 'https://api.weixin.qq.com/cgi-bin/material/del_material?access_token=' . $token; + $data = array( + 'media_id' => trim($media_id), + ); + $response = $this->requestApi($url, json_encode($data)); + if (is_error($response)) { + return $response; + } + + return true; + } + + + public function changeOrderStatus($send) { + if (empty($send)) { + return error(-1, '参数错误'); + } + $token = $this->getAccessToken(); + if (is_error($token)) { + return $token; + } + $sendapi = 'https://api.weixin.qq.com/pay/delivernotify?access_token=' . $token; + $response = ihttp_request($sendapi, json_encode($send)); + $response = json_decode($response['content'], true); + if (empty($response)) { + return error(-1, '发货失败,请检查您的公众号权限或是公众号AppId和公众号AppSecret!'); + } + if (!empty($response['errcode'])) { + return error(-1, $response['errmsg']); + } + + return $response; + } + + public function getOauthUserInfo($accesstoken, $openid) { + $apiurl = "https://api.weixin.qq.com/sns/userinfo?access_token={$accesstoken}&openid={$openid}&lang=zh_CN"; + $response = $this->requestApi($apiurl); + unset($response['remark'], $response['subscribe_scene'], $response['qr_scene'], $response['qr_scene_str']); + + return $response; + } + + public function getOauthInfo($code = '') { + global $_W, $_GPC; + if (!empty($_GPC['code'])) { + $code = $_GPC['code']; + } + if (empty($code)) { + $oauth_url = uni_account_oauth_host(); + $url = $oauth_url . "app/index.php?{$_SERVER['QUERY_STRING']}"; + $forward = $this->getOauthCodeUrl(urlencode($url)); + header('Location: ' . $forward); + exit; + } + $url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid={$this->account['key']}&secret={$this->account['secret']}&code={$code}&grant_type=authorization_code"; + + return $this->requestApi($url); + } + + public function getOauthAccessToken() { + $cachekey = cache_system_key('oauthaccesstoken', array('acid' => $this->account['acid'])); + $cache = cache_load($cachekey); + if (!empty($cache) && !empty($cache['token'])) { + return $cache['token']; + } + $token = $this->getOauthInfo(); + if (is_error($token)) { + return error(1); + } + $record = array(); + $record['token'] = $token['access_token']; + $record_expire = $token['expires_in'] - 200; + cache_write($cachekey, $record, $record_expire); + + return $token['access_token']; + } + + + public function getShareAddressConfig() { + global $_W; + static $current_url; + if (empty($current_url)) { + $current_url = $_W['siteurl']; + } + $token = $this->getOauthAccessToken(); + if (is_error($token)) { + return false; + } + $package = array( + 'appid' => $this->account['key'], + 'url' => $current_url, + 'timestamp' => strval(TIMESTAMP), + 'noncestr' => strval(random(8, true)), + 'accesstoken' => $token, + ); + ksort($package, SORT_STRING); + $signstring = array(); + foreach ($package as $k => $v) { + $signstring[] = "{$k}={$v}"; + } + $signstring = strtolower(sha1(trim(implode('&', $signstring)))); + $shareaddress_config = array( + 'appId' => $this->account['key'], + 'scope' => 'jsapi_address', + 'signType' => 'sha1', + 'addrSign' => $signstring, + 'timeStamp' => $package['timestamp'], + 'nonceStr' => $package['noncestr'], + ); + + return $shareaddress_config; + } + + public function getOauthCodeUrl($callback, $state = '') { + return "https://open.weixin.qq.com/connect/oauth2/authorize?appid={$this->account['key']}&redirect_uri={$callback}&response_type=code&scope=snsapi_base&state={$state}#wechat_redirect"; + } + + public function getOauthUserInfoUrl($callback, $state = '') { + return "https://open.weixin.qq.com/connect/oauth2/authorize?appid={$this->account['key']}&redirect_uri={$callback}&response_type=code&scope=snsapi_userinfo&state={$state}#wechat_redirect"; + } + + public function getFansStat() { + global $_W; + $token = $this->getAccessToken(); + if (is_error($token)) { + return $token; + } + $url = "https://api.weixin.qq.com/datacube/getusersummary?access_token={$token}"; + $data = array( + 'begin_date' => date('Y-m-d', strtotime('-7 days')), + 'end_date' => date('Y-m-d', strtotime('-1 days')), + ); + $summary_response = $this->requestApi($url, json_encode($data)); + if (is_error($summary_response)) { + return $summary_response; + } + + $url = "https://api.weixin.qq.com/datacube/getusercumulate?access_token={$token}"; + $cumulate_response = $this->requestApi($url, json_encode($data)); + if (is_error($cumulate_response)) { + return $cumulate_response; + } + + $result = array(); + if (!empty($summary_response['list'])) { + foreach ($summary_response['list'] as $row) { + $key = str_replace('-', '', $row['ref_date']); + $result[$key]['new'] = intval($result[$key]['new']) + $row['new_user']; + $result[$key]['cancel'] = intval($result[$key]['cancel']) + $row['cancel_user']; + } + } + if (!empty($cumulate_response['list'])) { + foreach ($cumulate_response['list'] as $row) { + $key = str_replace('-', '', $row['ref_date']); + $result[$key]['cumulate'] = $row['cumulate_user']; + } + } + + return $result; + } + + + public function getComment($msg_data_id, $index, $type = 0, $begin = 0, $count = 50) { + $token = $this->getAccessToken(); + if (is_error($token)) { + return $token; + } + $url = "https://api.weixin.qq.com/cgi-bin/comment/list?access_token={$token}"; + $data = array( + 'msg_data_id' => $msg_data_id, + 'index' => $index, + 'begin' => $begin, + 'count' => $count, + 'type' => $type, + ); + + return $this->requestApi($url, json_encode($data)); + } + + + public function commentReply($msg_data_id, $user_comment_id, $content, $index = 0) { + $token = $this->getAccessToken(); + if (is_error($token)) { + return $token; + } + $url = "https://api.weixin.qq.com/cgi-bin/comment/reply/add?access_token={$token}"; + $data = array( + 'msg_data_id' => $msg_data_id, + 'user_comment_id' => $user_comment_id, + 'content' => $content, + 'index' => $index, + ); + + return $this->requestApi($url, stripslashes(ijson_encode($data, JSON_UNESCAPED_UNICODE))); + } + + + public function commentMark($msg_data_id, $user_comment_id, $comment_type, $index = 0) { + $token = $this->getAccessToken(); + if (is_error($token)) { + return $token; + } + if (1 != $comment_type) { + $url = "https://api.weixin.qq.com/cgi-bin/comment/markelect?access_token={$token}"; + } else { + $url = "https://api.weixin.qq.com/cgi-bin/comment/unmarkelect?access_token={$token}"; + } + + $data = array( + 'msg_data_id' => $msg_data_id, + 'user_comment_id' => $user_comment_id, + 'index' => $index, + ); + + return $this->requestApi($url, json_encode($data)); + } + + + public function commentDelete($msg_data_id, $user_comment_id, $index = 0) { + $token = $this->getAccessToken(); + if (is_error($token)) { + return $token; + } + $url = "https://api.weixin.qq.com/cgi-bin/comment/delete?access_token={$token}"; + + $data = array( + 'msg_data_id' => $msg_data_id, + 'user_comment_id' => $user_comment_id, + 'index' => $index, + ); + + return $this->requestApi($url, json_encode($data)); + } + + + public function commentReplyDelete($msg_data_id, $user_comment_id, $index = 0) { + $token = $this->getAccessToken(); + if (is_error($token)) { + return $token; + } + $url = "https://api.weixin.qq.com/cgi-bin/comment/reply/delete?access_token={$token}"; + $data = array( + 'msg_data_id' => $msg_data_id, + 'user_comment_id' => $user_comment_id, + 'index' => $index, + ); + + return $this->requestApi($url, json_encode($data)); + } + + + public function commentSwitch($msg_data_id, $need_open_comment, $index = 0) { + $token = $this->getAccessToken(); + if (is_error($token)) { + return $token; + } + if (1 == $need_open_comment) { + $url = "https://api.weixin.qq.com/cgi-bin/comment/close?access_token={$token}"; + } else { + $url = "https://api.weixin.qq.com/cgi-bin/comment/open?access_token={$token}"; + } + + $data = array( + 'msg_data_id' => $msg_data_id, + 'index' => $index, + ); + + return $this->requestApi($url, json_encode($data)); + } + + protected function requestApi($url, $post = '') { + $response = ihttp_request($url, $post); + + $result = @json_decode($response['content'], true); + if (is_error($response)) { + return error($result['errcode'], "访问公众平台接口失败, 错误详情: {$this->errorCode($result['errcode'])}"); + } + if (empty($result)) { + return error(-1, "接口调用失败, 元数据: {$response['meta']}"); + } elseif (!empty($result['errcode'])) { + return error($result['errcode'], "访问公众平台接口失败, 错误: {$result['errmsg']},错误详情:{$this->errorCode($result['errcode'])}"); + } + + return $result; + } + + + public function getMaterialSupport() { + return array( + 'mass' => array('basic' => false, 'news' => false, 'image' => false, 'voice' => false, 'video' => false), + 'chats' => array('basic' => false, 'news' => false, 'image' => false, 'music' => false, 'voice' => false, 'video' => false), + ); + } +} \ No newline at end of file diff --git a/framework/class/account/weixin.platform.class.php b/framework/class/account/weixin.platform.class.php new file mode 100644 index 0000000..33cf8aa --- /dev/null +++ b/framework/class/account/weixin.platform.class.php @@ -0,0 +1,376 @@ +classs('weixin.account'); +load()->func('communication'); + +class WeixinPlatform extends WeixinAccount { + public $appid; + protected $appsecret; + public $token; + public $encodingaeskey; + protected $refreshtoken; + protected $tablename = 'account_wechats'; + protected $menuFrame = 'account'; + protected $type = ACCOUNT_TYPE_OFFCIAL_AUTH; + protected $typeName = '公众号'; + protected $typeSign = ACCOUNT_TYPE_SIGN; + + public function __construct($uniaccount = array()) { + $setting = setting_load('platform'); + $this->appid = $setting['platform']['appid']; + $this->appsecret = $setting['platform']['appsecret']; + $this->token = $setting['platform']['token']; + $this->encodingaeskey = $setting['platform']['encodingaeskey']; + parent::__construct($uniaccount); + } + + protected function getAccountInfo($uniacid) { + if ('wx570bc396a51b8ff8' == $this->account['key']) { + $this->account['key'] = $this->appid; + $this->openPlatformTestCase(); + } + $account = table('account_wechats')->getAccount($uniacid); + $account['encrypt_key'] = $this->appid; + + return $account; + } + + public function fetchSameAccountByAppid($appid) { + return pdo_get($this->tablename, array('key' => $appid)); + } + + public function getComponentAccesstoken() { + $accesstoken = cache_load(cache_system_key('account_component_assesstoken')); + if (empty($accesstoken) || empty($accesstoken['value'])) { + $ticket = $GLOBALS['_W']['setting']['account_ticket']; + if (empty($ticket)) { + return error(1, '缺少接入平台关键数据,等待微信开放平台推送数据,请十分钟后再试或是检查“授权事件接收URL”是否写错(index.php?c=account&a=auth&do=ticket地址中的&符号容易被替换成&amp;)'); + } + $data = array( + 'component_appid' => $this->appid, + 'component_appsecret' => $this->appsecret, + 'component_verify_ticket' => $ticket, + ); + $response = $this->request(ACCOUNT_PLATFORM_API_ACCESSTOKEN, $data); + if (is_error($response)) { + return $response; + } + $accesstoken = array( + 'value' => $response['component_access_token'], + ); + $record_expire = intval($response['expires_in']) - 200; + cache_write(cache_system_key('account_component_assesstoken'), $accesstoken, $record_expire); + } + + return $accesstoken['value']; + } + + public function getPreauthCode() { + $preauthcode = cache_load(cache_system_key('account_preauthcode')); + if (empty($preauthcode) || empty($preauthcode['value'])) { + $component_accesstoken = $this->getComponentAccesstoken(); + if (is_error($component_accesstoken)) { + return $component_accesstoken; + } + $data = array( + 'component_appid' => $this->appid, + ); + $response = $this->request(ACCOUNT_PLATFORM_API_PREAUTHCODE . $component_accesstoken, $data); + if (is_error($response)) { + return $response; + } + $preauthcode = array( + 'value' => $response['pre_auth_code'], + ); + $record_expire = intval($response['expires_in']) - 200; + cache_write(cache_system_key('account_preauthcode'), $preauthcode, $record_expire); + } + + return $preauthcode['value']; + } + + public function getAuthInfo($code) { + $component_accesstoken = $this->getComponentAccesstoken(); + if (is_error($component_accesstoken)) { + return $component_accesstoken; + } + $post = array( + 'component_appid' => $this->appid, + 'authorization_code' => $code, + ); + $response = $this->request(ACCOUNT_PLATFORM_API_QUERY_AUTH_INFO . $component_accesstoken, $post); + if (is_error($response)) { + return $response; + } + $this->setAuthRefreshToken($response['authorization_info']['authorizer_refresh_token']); + + return $response; + } + + public function getAuthorizerInfo($appid = '') { + $component_accesstoken = $this->getComponentAccesstoken(); + if (is_error($component_accesstoken)) { + return $component_accesstoken; + } + $appid = !empty($appid) ? $appid : $this->account['key']; + $post = array( + 'component_appid' => $this->appid, + 'authorizer_appid' => $appid, + ); + + return $this->request(ACCOUNT_PLATFORM_API_ACCOUNT_INFO . $component_accesstoken, $post); + } + + public function getAuthorizerList() { + $token = $this->getComponentAccesstoken(); + if (is_error($token)) { + return $token; + } + $data = array( + 'component_appid' => $this->appid, + 'offset' => 0, + 'count' => 500 + ); + $url = "https://api.weixin.qq.com/cgi-bin/component/api_get_authorizer_list?component_access_token={$token}"; + return $this->request($url, $data); + } + + public function getAccessToken() { + $cachekey = cache_system_key('account_auth_accesstoken', array('key' => $this->account['key'])); + $auth_accesstoken = cache_load($cachekey); + if (empty($auth_accesstoken) || empty($auth_accesstoken['value'])) { + $component_accesstoken = $this->getComponentAccesstoken(); + if (is_error($component_accesstoken)) { + return $component_accesstoken; + } + $this->refreshtoken = $this->getAuthRefreshToken(); + $data = array( + 'component_appid' => $this->appid, + 'authorizer_appid' => $this->account['key'], + 'authorizer_refresh_token' => $this->refreshtoken, + ); + $response = $this->request(ACCOUNT_PLATFORM_API_REFRESH_AUTH_ACCESSTOKEN . $component_accesstoken, $data); + if (is_error($response)) { + return $response; + } + if ($response['authorizer_refresh_token'] != $this->refreshtoken) { + $this->setAuthRefreshToken($response['authorizer_refresh_token']); + } + $auth_accesstoken = array( + 'value' => $response['authorizer_access_token'], + ); + $record_expire = intval($response['expires_in']) - 200; + cache_write($cachekey, $auth_accesstoken, $record_expire); + } + + return $auth_accesstoken['value']; + } + + public function fetch_token() { + return $this->getAccessToken(); + } + + public function getAuthLoginUrl() { + $preauthcode = $this->getPreauthCode(); + if (is_error($preauthcode)) { + $authurl = "javascript:alert('{$preauthcode['message']}');"; + } else { + $authurl = sprintf(ACCOUNT_PLATFORM_API_LOGIN, $this->appid, + $preauthcode, urlencode($GLOBALS['_W']['siteroot'] . 'index.php?c=account&a=auth&do=forward'), ACCOUNT_PLATFORM_API_LOGIN_ACCOUNT); + } + + return $authurl; + } + + public function getOauthCodeUrl($callback, $state = '') { + return sprintf(ACCOUNT_PLATFORM_API_OAUTH_CODE, $this->account['key'], $this->appid, $callback, $state); + } + + public function getOauthUserInfoUrl($callback, $state = '') { + return sprintf(ACCOUNT_PLATFORM_API_OAUTH_USERINFO, $this->account['key'], $callback, $state, $this->appid); + } + + public function getOauthInfo($code = '') { + $component_accesstoken = $this->getComponentAccesstoken(); + if (is_error($component_accesstoken)) { + return $component_accesstoken; + } + $apiurl = sprintf(ACCOUNT_PLATFORM_API_OAUTH_INFO . $component_accesstoken, $this->account['key'], $this->appid, $code); + $response = $this->request($apiurl); + if (is_error($response)) { + return $response; + } + cache_write('account_oauth_refreshtoken' . $this->account['key'], $response['refresh_token']); + + return $response; + } + + public function getJsApiTicket() { + $cachekey = cache_system_key('jsticket', array('uniacid' => $this->account['uniacid'])); + $js_ticket = cache_load($cachekey); + if (empty($js_ticket) || empty($js_ticket['value'])) { + $access_token = $this->getAccessToken(); + if (is_error($access_token)) { + return $access_token; + } + $apiurl = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token={$access_token}&type=jsapi"; + $response = $this->request($apiurl); + if (is_error($response)) { + return $response; + } + $js_ticket = array( + 'value' => $response['ticket'], + ); + $record_expire = $response['expires_in'] - 200; + cache_write($cachekey, $js_ticket, $record_expire); + } + $this->account['jsapi_ticket'] = $js_ticket; + + return $js_ticket['value']; + } + + public function getJssdkConfig($url = '') { + global $_W, $urls; + $jsapiTicket = $this->getJsApiTicket(); + if (is_error($jsapiTicket)) { + $jsapiTicket = $jsapiTicket['message']; + } + $nonceStr = random(16); + $timestamp = TIMESTAMP; + $url = empty($url) ? $urls['scheme'] . '://' . $urls['host'] . $_SERVER['REQUEST_URI'] : $url; + $string1 = "jsapi_ticket={$jsapiTicket}&noncestr={$nonceStr}×tamp={$timestamp}&url={$url}"; + $signature = sha1($string1); + $config = array( + 'appId' => $this->account['key'], + 'nonceStr' => $nonceStr, + 'timestamp' => "$timestamp", + 'signature' => $signature, + ); + if (DEVELOPMENT) { + $config['url'] = $url; + $config['string1'] = $string1; + $config['name'] = $this->account['name']; + } + + return $config; + } + + public function openPlatformTestCase() { + global $_GPC; + $post = file_get_contents('php://input'); + WeUtility::logging('platform-test-message', $post); + $encode_message = $this->xmlExtract($post); + $message = aes_decode($encode_message['encrypt'], $this->encodingaeskey); + $message = $this->parse($message); + $response = array( + 'ToUserName' => $message['from'], + 'FromUserName' => $message['to'], + 'CreateTime' => TIMESTAMP, + 'MsgId' => TIMESTAMP, + 'MsgType' => 'text', + ); + if ('TESTCOMPONENT_MSG_TYPE_TEXT' == $message['content']) { + $response['Content'] = 'TESTCOMPONENT_MSG_TYPE_TEXT_callback'; + } + if ('event' == $message['msgtype']) { + $response['Content'] = $message['event'] . 'from_callback'; + } + if (strexists($message['content'], 'QUERY_AUTH_CODE')) { + list($sufixx, $authcode) = explode(':', $message['content']); + $auth_info = $this->getAuthInfo($authcode); + WeUtility::logging('platform-test-send-message', var_export($auth_info, true)); + $url = 'https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=' . $auth_info['authorization_info']['authorizer_access_token']; + $data = array( + 'touser' => $message['from'], + 'msgtype' => 'text', + 'text' => array('content' => $authcode . '_from_api'), + ); + $response = ihttp_request($url, urldecode(json_encode($data))); + exit(''); + } + $xml = array( + 'Nonce' => $_GPC['nonce'], + 'TimeStamp' => $_GPC['timestamp'], + 'Encrypt' => aes_encode(array2xml($response), $this->encodingaeskey, $this->appid), + ); + $signature = array($xml['Encrypt'], $this->token, $_GPC['timestamp'], $_GPC['nonce']); + sort($signature, SORT_STRING); + $signature = implode($signature); + $xml['MsgSignature'] = sha1($signature); + exit(array2xml($xml)); + } + + public function openGet($appid = '') { + $token = $this->getAccessToken(); + if (is_error($token)) { + return $token; + } + $data = array( + 'appid' => !empty($appid) ? $appid : $this->account['key'], + ); + $url = "https://api.weixin.qq.com/cgi-bin/open/get?access_token={$token}"; + return $this->request($url, $data); + } + + public function openBind($appid = '') { + $token = $this->getAccessToken(); + if (is_error($token)) { + return $token; + } + $data = array( + 'appid' => !empty($appid) ? $appid : $this->account['key'], + 'open_appid' => $this->appid, + ); + $url = "https://api.weixin.qq.com/cgi-bin/open/bind?access_token={$token}"; + return $this->request($url, $data); + } + + protected function request($url, $post = array()) { + if (!empty($post)) { + $response = ihttp_request($url, json_encode($post, JSON_UNESCAPED_UNICODE)); + } else { + $response = ihttp_request($url); + } + $response = json_decode($response['content'], true); + if (empty($response) || !empty($response['errcode'])) { + return error($response['errcode'], $this->errorCode($response['errcode'], $response['errmsg'])); + } + + return $response; + } + + protected function getAuthRefreshToken() { + $auth_refresh_token = cache_load(cache_system_key('account_auth_refreshtoken', array('uniacid' => $this->account['uniacid']))); + if (empty($auth_refresh_token)) { + $auth_refresh_token = $this->account['auth_refresh_token']; + cache_write(cache_system_key('account_auth_refreshtoken', array('uniacid' => $this->account['uniacid'])), $auth_refresh_token); + } + + return $auth_refresh_token; + } + + protected function setAuthRefreshToken($token) { + $tablename = 'account_wechats'; + pdo_update($tablename, array('auth_refresh_token' => $token), array('uniacid' => $this->account['uniacid'])); + cache_write(cache_system_key('account_auth_refreshtoken', array('uniacid' => $this->account['uniacid'])), $token); + } + + public function result($errno, $message = '', $data = '') { + exit(json_encode(array( + 'errno' => $errno, + 'message' => $message, + 'data' => $data, + ))); + } +} \ No newline at end of file diff --git a/framework/class/captcha.class.php b/framework/class/captcha.class.php new file mode 100644 index 0000000..958e177 --- /dev/null +++ b/framework/class/captcha.class.php @@ -0,0 +1,187 @@ +rand(200, 255), $this->rand(200, 255), $this->rand(200, 255)); + imagefill($image, 0, 0, $bg); + + $square = $width * $height * 3; + $effects = $this->rand($square / 2000, $square / 1000); + for ($e = 0; $e < $effects; ++$e) { + $this->drawLine($image, $width, $height); + } + $this->phrase = $this->phrase(); + $color = $this->writePhrase($image, $this->phrase, $this->font(), $width, $height); + + $square = $width * $height; + $effects = $this->rand($square / 3000, $square / 2000); + if (0 !== $this->maxFrontLines) { + for ($e = 0; $e < $effects; ++$e) { + $this->drawLine($image, $width, $height, $color); + } + } + + $image = $this->distort($image, $width, $height, $bg); + $this->image = $image; + + return $this; + } + + public function output($quality = 90) { + header('content-type: image/png'); + imagepng($this->image); + imagedestroy($this->image); + } + + protected function phrase() { + return random(4, true); + } + + protected function rand($min, $max) { + mt_srand((float) microtime() * 1000000); + + return mt_rand($min, $max); + } + + protected function drawLine($image, $width, $height, $tcol = null) { + if (null === $tcol) { + $tcol = imagecolorallocate($image, $this->rand(100, 255), $this->rand(100, 255), $this->rand(100, 255)); + } + + if ($this->rand(0, 1)) { + $Xa = $this->rand(0, $width / 2); + $Ya = $this->rand(0, $height); + $Xb = $this->rand($width / 2, $width); + $Yb = $this->rand(0, $height); + } else { + $Xa = $this->rand(0, $width); + $Ya = $this->rand(0, $height / 2); + $Xb = $this->rand(0, $width); + $Yb = $this->rand($height / 2, $height); + } + imagesetthickness($image, $this->rand(1, 3)); + imageline($image, $Xa, $Ya, $Xb, $Yb, $tcol); + } + + protected function writePhrase($image, $phrase, $font, $width, $height) { + $size = $width / strlen($phrase) - $this->rand(0, 3) - 1; + $box = imagettfbbox($size, 0, $font, $phrase); + $textWidth = $box[2] - $box[0]; + $textHeight = $box[1] - $box[7]; + $x = ($width - $textWidth) / 2; + $y = ($height - $textHeight) / 2 + $size; + + $textColor = array($this->rand(0, 150), $this->rand(0, 150), $this->rand(0, 150)); + $col = imagecolorallocate($image, $textColor[0], $textColor[1], $textColor[2]); + + $length = strlen($phrase); + for ($i = 0; $i < $length; ++$i) { + $box = imagettfbbox($size, 0, $font, $phrase[$i]); + $w = $box[2] - $box[0]; + $angle = $this->rand(-$this->maxAngle, $this->maxAngle); + $offset = $this->rand(-$this->maxOffset, $this->maxOffset); + imagettftext($image, $size, $angle, $x, $y + $offset, $col, $font, $phrase[$i]); + $x += $w; + } + + return $col; + } + + public function distort($image, $width, $height, $bg) { + $contents = imagecreatetruecolor($width, $height); + $X = $this->rand(0, $width); + $Y = $this->rand(0, $height); + $phase = $this->rand(0, 10); + $scale = 1.1 + $this->rand(0, 10000) / 30000; + for ($x = 0; $x < $width; ++$x) { + for ($y = 0; $y < $height; ++$y) { + $Vx = $x - $X; + $Vy = $y - $Y; + $Vn = sqrt($Vx * $Vx + $Vy * $Vy); + + if (0 != $Vn) { + $Vn2 = $Vn + 4 * sin($Vn / 30); + $nX = $X + ($Vx * $Vn2 / $Vn); + $nY = $Y + ($Vy * $Vn2 / $Vn); + } else { + $nX = $X; + $nY = $Y; + } + $nY = $nY + $scale * sin($phase + $nX * 0.2); + + $p = $this->interpolate( + $nX - floor($nX), + $nY - floor($nY), + $this->getCol($image, floor($nX), floor($nY), $bg), + $this->getCol($image, ceil($nX), floor($nY), $bg), + $this->getCol($image, floor($nX), ceil($nY), $bg), + $this->getCol($image, ceil($nX), ceil($nY), $bg) + ); + + if (0 == $p) { + $p = $bg; + } + + imagesetpixel($contents, $x, $y, $p); + } + } + + return $contents; + } + + protected function interpolate($x, $y, $nw, $ne, $sw, $se) { + list($r0, $g0, $b0) = $this->getRGB($nw); + list($r1, $g1, $b1) = $this->getRGB($ne); + list($r2, $g2, $b2) = $this->getRGB($sw); + list($r3, $g3, $b3) = $this->getRGB($se); + + $cx = 1.0 - $x; + $cy = 1.0 - $y; + + $m0 = $cx * $r0 + $x * $r1; + $m1 = $cx * $r2 + $x * $r3; + $r = (int) ($cy * $m0 + $y * $m1); + + $m0 = $cx * $g0 + $x * $g1; + $m1 = $cx * $g2 + $x * $g3; + $g = (int) ($cy * $m0 + $y * $m1); + + $m0 = $cx * $b0 + $x * $b1; + $m1 = $cx * $b2 + $x * $b3; + $b = (int) ($cy * $m0 + $y * $m1); + + return ($r << 16) | ($g << 8) | $b; + } + + protected function getRGB($col) { + return array( + (int) ($col >> 16) & 0xff, + (int) ($col >> 8) & 0xff, + (int) ($col) & 0xff, + ); + } + + protected function getCol($image, $x, $y, $background) { + $L = imagesx($image); + $H = imagesy($image); + if ($x < 0 || $x >= $L || $y < 0 || $y >= $H) { + return $background; + } + + return imagecolorat($image, $x, $y); + } + + protected function font() { + return IA_ROOT . '/web/resource/fonts/captcha.ttf'; + } +} diff --git a/framework/class/db.class.php b/framework/class/db.class.php new file mode 100644 index 0000000..e74cd77 --- /dev/null +++ b/framework/class/db.class.php @@ -0,0 +1,835 @@ +pdo; + } + + public function __construct($name = 'master') { + global $_W; + $this->cfg = $_W['config']['db']; + $this->name = $name; + unset($_W['config']['db']); + $_W['config']['db'] = array( + 'tablepre' => $this->cfg['master']['tablepre'] ?: $this->cfg['tablepre'], + 'slave_status' => $this->cfg['slave_status'] + ); + $this->connect($name); + } + + public function reConnect($errorInfo,$params) { + if (in_array($errorInfo[1], array(1317, 2013))) { + $this->pdo = null; + $this->connect($this->name); + $method = $params['method']; + unset($params['method']); + return call_user_func_array(array($this, $method), $params); + } + return false; + } + + public function connect($name = 'master') { + if (is_array($name)) { + $cfg = $name; + } else { + $cfg = $this->cfg[$name]; + } + $this->tablepre = $cfg['tablepre']; + if (empty($cfg)) { + exit("The master database is not found, Please checking 'data/config.php'"); + } + $dsn = "mysql:dbname={$cfg['database']};host={$cfg['host']};port={$cfg['port']};charset={$cfg['charset']}"; + $dbclass = ''; + $options = array(); + if (class_exists('PDO')) { + if (extension_loaded('pdo_mysql') && in_array('mysql', PDO::getAvailableDrivers())) { + $dbclass = 'PDO'; + $options = array(PDO::ATTR_PERSISTENT => $cfg['pconnect']); + } else { + if (!class_exists('_PDO')) { + load()->library('pdo'); + } + $dbclass = '_PDO'; + } + } else { + load()->library('pdo'); + $dbclass = 'PDO'; + } + + $pdo = new $dbclass($dsn, $cfg['username'], $cfg['password'], $options); + $this->pdo = $pdo; + $sql = "SET NAMES '{$cfg['charset']}';"; + $this->pdo->exec($sql); + $this->pdo->exec("SET sql_mode='';"); + if ('root' == $cfg['username'] && in_array($cfg['host'], array('localhost', '127.0.0.1'))) { + $this->pdo->exec('SET GLOBAL max_allowed_packet = 2*1024*1024*10;'); + } + if (is_string($name)) { + $this->link[$name] = $this->pdo; + } + $this->logging($sql); + } + + public function prepare($sql) { + $sqlsafe = SqlPaser::checkquery($sql); + if (is_error($sqlsafe)) { + trigger_error($sqlsafe['message'], E_USER_ERROR); + + return false; + } + if ($GLOBALS['_W']['config']['setting']['development'] == 3) { + if ($GLOBALS['error_handler'] instanceof Raven_ErrorHandler) { + $GLOBALS['error_handler']->handleError(E_USER_ERROR, $sql); + } + } + $statement = $this->pdo->prepare($sql); + + return $statement; + } + + + public function query($sql, $params = array()) { + $sqlsafe = SqlPaser::checkquery($sql); + if (is_error($sqlsafe)) { + trigger_error($sqlsafe['message'], E_USER_ERROR); + + return false; + } + $starttime = intval(microtime(true)); + if (empty($params)) { + $result = $this->pdo->exec($sql); + $error_info = $this->pdo->errorInfo(); + $this->logging($sql, array(), $this->pdo->errorInfo()); + if (in_array($error_info[1], array(1317, 2013))) { + $reConnect = $this->reConnect($error_info, array( + 'method'=> __METHOD__, + 'sql' => $sql, + 'params' => $params, + )); + return empty($reConnect) ? false : $reConnect; + } + return $result; + } + $statement = $this->prepare($sql); + $result = $statement->execute($params); + + $this->logging($sql, $params, $statement->errorInfo()); + + $endtime = intval(microtime(true)); + $this->performance($sql, $endtime - $starttime); + $error_info = $statement->errorInfo(); + if (in_array($error_info[1], array(1317, 2013))) { + $reConnect = $this->reConnect($error_info, array( + 'method' => __METHOD__, + 'sql' => $sql, + 'params' => $params, + )); + return empty($reConnect) ? false : $reConnect; + } else { + return $statement->rowCount(); + } + } + + + public function fetchcolumn($sql, $params = array(), $column = 0) { + $starttime = intval(microtime(true)); + $statement = $this->prepare($sql); + $result = $statement->execute($params); + + $this->logging($sql, $params, $statement->errorInfo()); + + $endtime = intval(microtime(true)); + $this->performance($sql, $endtime - $starttime); + $error_info = $statement->errorInfo(); + if (in_array($error_info[1], array(1317, 2013))) { + $reConnect = $this->reConnect($error_info, array( + 'method' => __METHOD__, + 'sql' => $sql, + 'params' => $params, + 'column' => $column, + )); + return empty($reConnect) ? false : $reConnect; + } else { + $data = $statement->fetchColumn($column); + + return $data; + } + } + + + public function fetch($sql, $params = array()) { + $starttime = intval(microtime(true)); + $statement = $this->prepare($sql); + $result = $statement->execute($params); + + $this->logging($sql, $params, $statement->errorInfo()); + + $endtime = intval(microtime(true)); + $this->performance($sql, intval($endtime - $starttime)); + $error_info = $statement->errorInfo(); + if (in_array($error_info[1], array(1317, 2013))) { + $reConnect = $this->reConnect($error_info, array( + 'method' => __METHOD__, + 'sql' => $sql, + 'params' => $params, + )); + return empty($reConnect) ? false : $reConnect; + } else { + $data = $statement->fetch(pdo::FETCH_ASSOC); + + return $data; + } + } + + + public function fetchall($sql, $params = array(), $keyfield = '') { + $starttime = intval(microtime(true)); + $statement = $this->prepare($sql); + $result = $statement->execute($params); + + $this->logging($sql, $params, $statement->errorInfo()); + + $endtime = intval(microtime(true)); + $this->performance($sql, $endtime - $starttime); + $error_info = $statement->errorInfo(); + if (in_array($error_info[1], array(1317, 2013))) { + $reConnect = $this->reConnect($error_info, array( + 'method'=> __METHOD__, + 'sql' => $sql, + 'params' => $params, + 'keyfield' => $keyfield, + )); + return empty($reConnect) ? false : $reConnect; + } else { + if (empty($keyfield)) { + $result = $statement->fetchAll(pdo::FETCH_ASSOC); + } else { + $temp = $statement->fetchAll(pdo::FETCH_ASSOC); + $result = array(); + if (!empty($temp)) { + foreach ($temp as $key => &$row) { + if (isset($row[$keyfield])) { + $result[$row[$keyfield]] = $row; + } else { + $result[] = $row; + } + } + } + } + + return $result; + } + } + + public function get($tablename, $params = array(), $fields = array(), $orderby = array()) { + $select = SqlPaser::parseSelect($fields); + $condition = SqlPaser::parseParameter($params, 'AND'); + $orderbysql = SqlPaser::parseOrderby($orderby); + + $sql = "{$select} FROM " . $this->tablename($tablename) . (!empty($condition['fields']) ? " WHERE {$condition['fields']}" : '') . " $orderbysql LIMIT 1"; + + return $this->fetch($sql, $condition['params']); + } + + public function getall($tablename, $params = array(), $fields = array(), $keyfield = '', $orderby = array(), $limit = array()) { + $select = SqlPaser::parseSelect($fields); + $condition = SqlPaser::parseParameter($params, 'AND'); + + $limitsql = SqlPaser::parseLimit($limit); + $orderbysql = SqlPaser::parseOrderby($orderby); + + $sql = "{$select} FROM " . $this->tablename($tablename) . (!empty($condition['fields']) ? " WHERE {$condition['fields']}" : '') . $orderbysql . $limitsql; + + return $this->fetchall($sql, $condition['params'], $keyfield); + } + + public function getslice($tablename, $params = array(), $limit = array(), &$total = null, $fields = array(), $keyfield = '', $orderby = array()) { + $select = SqlPaser::parseSelect($fields); + $condition = SqlPaser::parseParameter($params, 'AND'); + $limitsql = SqlPaser::parseLimit($limit); + + if (!empty($orderby)) { + if (is_array($orderby)) { + $orderbysql = implode(',', $orderby); + } else { + $orderbysql = $orderby; + } + } + $sql = "{$select} FROM " . $this->tablename($tablename) . (!empty($condition['fields']) ? " WHERE {$condition['fields']}" : '') . (!empty($orderbysql) ? " ORDER BY $orderbysql " : '') . $limitsql; + $total = pdo_fetchcolumn('SELECT COUNT(*) FROM ' . tablename($tablename) . (!empty($condition['fields']) ? " WHERE {$condition['fields']}" : ''), $condition['params']); + + return $this->fetchall($sql, $condition['params'], $keyfield); + } + + public function getcolumn($tablename, $params = array(), $field = '') { + $result = $this->get($tablename, $params, $field); + if (!empty($result)) { + if (strexists($field, '(')) { + return array_shift($result); + } else { + return $result[$field]; + } + } else { + return false; + } + } + + + public function update($table, $data = array(), $params = array(), $glue = 'AND') { + $fields = SqlPaser::parseParameter($data, ','); + $condition = SqlPaser::parseParameter($params, $glue); + $params = array_merge($fields['params'], $condition['params']); + $sql = 'UPDATE ' . $this->tablename($table) . " SET {$fields['fields']}"; + $sql .= $condition['fields'] ? ' WHERE ' . $condition['fields'] : ''; + + return $this->query($sql, $params); + } + + + public function insert($table, $data = array(), $replace = false) { + $cmd = $replace ? 'REPLACE INTO' : 'INSERT INTO'; + $condition = SqlPaser::parseParameter($data, ','); + + return $this->query("$cmd " . $this->tablename($table) . " SET {$condition['fields']}", $condition['params']); + } + + + public function insertid() { + return $this->pdo->lastInsertId(); + } + + + public function delete($table, $params = array(), $glue = 'AND') { + $condition = SqlPaser::parseParameter($params, $glue); + $sql = 'DELETE FROM ' . $this->tablename($table); + $sql .= $condition['fields'] ? ' WHERE ' . $condition['fields'] : ''; + + return $this->query($sql, $condition['params']); + } + + + public function exists($tablename, $params = array()) { + $row = $this->get($tablename, $params); + if (empty($row) || !is_array($row) || 0 == count($row)) { + return false; + } else { + return true; + } + } + + + public function count($tablename, $params = array(), $cachetime = 30) { + $total = pdo_getcolumn($tablename, $params, 'count(*)'); + + return intval($total); + } + + + public function begin() { + $this->pdo->beginTransaction(); + } + + + public function commit() { + $this->pdo->commit(); + } + + + public function rollback() { + $this->pdo->rollBack(); + } + + + public function run($sql, $stuff = 'ims_') { + if (!isset($sql) || empty($sql)) { + return; + } + + $sql = str_replace("\r", "\n", str_replace(' ' . $stuff, ' ' . $this->tablepre, $sql)); + $sql = str_replace("\r", "\n", str_replace(' `' . $stuff, ' `' . $this->tablepre, $sql)); + $ret = array(); + $num = 0; + $sql = preg_replace("/\;[ \f\t\v]+/", ';', $sql); + foreach (explode(";\n", trim($sql)) as $query) { + $ret[$num] = ''; + $queries = explode("\n", trim($query)); + foreach ($queries as $query) { + $ret[$num] .= (isset($query[0]) && '#' == $query[0]) || (isset($query[1]) && isset($query[1]) && $query[0] . $query[1] == '--') ? '' : $query; + } + ++$num; + } + unset($sql); + foreach ($ret as $query) { + $query = trim($query); + if ($query) { + $this->query($query, array()); + } + } + + return true; + } + + + public function fieldexists($tablename, $fieldname) { + if (!$this->tableexists($tablename)) { + return false; + } + $fields = $this->fetchall("SHOW COLUMNS FROM " . $this->tablename($tablename)); + if (empty($fields)) { + return false; + } + foreach ($fields as $field) { + if ($fieldname === $field['Field']) { + return true; + } + } + return false; + } + + + public function fieldmatch($tablename, $fieldname, $datatype = '', $length = '') { + $datatype = strtolower($datatype); + $field_info = $this->fetch('DESCRIBE ' . $this->tablename($tablename) . " `{$fieldname}`", array()); + if (empty($field_info)) { + return false; + } + if (!empty($datatype)) { + $find = strexists($field_info['Type'], '('); + if (empty($find)) { + $length = ''; + } + if (!empty($length)) { + $datatype .= ("({$length})"); + } + + return 0 === strpos($field_info['Type'], $datatype) ? true : -1; + } + + return true; + } + + + public function indexexists($tablename, $indexname) { + if (!$this->tableexists($tablename)) { + return false; + } + if (!empty($indexname)) { + $indexs = $this->fetchall('SHOW INDEX FROM ' . $this->tablename($tablename), array(), ''); + if (!empty($indexs) && is_array($indexs)) { + foreach ($indexs as $row) { + if ($row['Key_name'] == $indexname) { + return true; + } + } + } + } + + return false; + } + + + public function tablename($table) { + return (0 === strpos($table, $this->tablepre) || 0 === strpos($table, 'ims_')) ? $table : "`{$this->tablepre}{$table}`"; + } + + + public function debug($output = true, $append = array()) { + if (!empty($append)) { + $output = false; + array_push($this->errors, $append); + } + if ($output) { + print_r($this->errors); + } else { + if (!empty($append['error'][1])) { + $traces = debug_backtrace(); + $ts = ''; + foreach ($traces as $trace) { + $trace['file'] = str_replace('\\', '/', $trace['file']); + $trace['file'] = str_replace(IA_ROOT, '', $trace['file']); + $ts .= "file: {$trace['file']}; line: {$trace['line']};
"; + } + $params = var_export($append['params'], true); + trigger_error("SQL:
{$append['sql']}
Params:
{$params}
SQL Error:
{$append['error'][2]}
Traces:
{$ts}", E_USER_WARNING); + } + } + + return $this->errors; + } + + private function logging($sql, $params = array(), $message = '') { + if (PDO_DEBUG) { + $info = array(); + $info['sql'] = $sql; + $info['params'] = $params; + $info['error'] = empty($message) ? $this->pdo->errorInfo() : $message; + $this->debug(false, $info); + } + + return true; + } + + + public function tableexists($table) { + if (!empty($table)) { + $real_table = preg_match('/[a-zA-Z0-9_]{' . strlen($table) . '}/', $table); + if (1 !== $real_table) { + return false; + } + $tablename = (0 === strpos($table, $this->tablepre)) ? ($table) : ($this->tablepre . $table); + $data = $this->fetch("SHOW TABLES LIKE '{$tablename}'", array()); + if (!empty($data)) { + $data = array_values($data); + if (in_array($tablename, $data)) { + return true; + } else { + return false; + } + } else { + return false; + } + } else { + return false; + } + } + + private function performance($sql, $runtime = 0) { + global $_W; + if (0 == $runtime) { + return false; + } + if (strexists($sql, 'core_performance')) { + return false; + } + if (empty($_W['config']['setting']['maxtimesql'])) { + $_W['config']['setting']['maxtimesql'] = 5; + } + if ($runtime > $_W['config']['setting']['maxtimesql']) { + $sqldata = array( + 'type' => '2', + 'runtime' => $runtime, + 'runurl' => 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'], + 'runsql' => $sql, + 'createtime' => time(), + ); + $this->insert('core_performance', $sqldata); + } + + return true; + } +} + + +class SqlPaser { + private static $checkcmd = array('SELECT', 'UPDATE', 'INSERT', 'REPLAC', 'DELETE'); + private static $disable = array( + 'function' => array('load_file', 'floor', 'hex', 'substring', 'if', 'ord', 'char', 'benchmark', 'reverse', 'strcmp', 'datadir', 'updatexml', 'extractvalue', 'name_const', 'multipoint', 'database', 'user'), + 'action' => array('@', 'intooutfile', 'intodumpfile', 'unionselect', 'uniondistinct', 'information_schema', 'current_user', 'current_date'), + 'note' => array('/*', '*/', '#', '--'), + ); + + public static function checkquery($sql) { + $cmd = strtoupper(substr(trim($sql), 0, 6)); + if (in_array($cmd, self::$checkcmd)) { + $mark = $clean = ''; + $sql = str_replace(array('\\\\', '\\\'', '\\"', '\'\''), '', $sql); + if (false === strpos($sql, '/') && false === strpos($sql, '#') && false === strpos($sql, '-- ') && false === strpos($sql, '@') && false === strpos($sql, '`')) { + $cleansql = preg_replace("/'(.+?)'/s", '', $sql); + } else { + $cleansql = self::stripSafeChar($sql); + } + + $clean_function_sql = preg_replace("/\s+/", '', strtolower($cleansql)); + if (is_array(self::$disable['function'])) { + foreach (self::$disable['function'] as $fun) { + if (false !== strpos($clean_function_sql, $fun . '(')) { + return error(1, 'SQL中包含禁用函数 - ' . $fun); + } + } + } + + $cleansql = preg_replace("/[^a-z0-9_\-\(\)#\*\/\"]+/is", '', strtolower($cleansql)); + if (is_array(self::$disable['action'])) { + foreach (self::$disable['action'] as $action) { + if (false !== strpos($cleansql, $action)) { + return error(2, 'SQL中包含禁用操作符 - ' . $action); + } + } + } + + if (is_array(self::$disable['note'])) { + foreach (self::$disable['note'] as $note) { + if (false !== strpos($cleansql, $note)) { + return error(3, 'SQL中包含注释信息'); + } + } + } + } elseif ('/*' === substr($cmd, 0, 2)) { + return error(3, 'SQL中包含注释信息'); + } + } + + private static function stripSafeChar($sql) { + $len = strlen($sql); + $mark = $clean = ''; + for ($i = 0; $i < $len; ++$i) { + $str = $sql[$i]; + switch ($str) { + case '\'': + if (!$mark) { + $mark = '\''; + $clean .= $str; + } elseif ('\'' == $mark) { + $mark = ''; + } + break; + case '/': + if (empty($mark) && '*' == $sql[$i + 1]) { + $mark = '/*'; + $clean .= $mark; + ++$i; + } elseif ('/*' == $mark && '*' == $sql[$i - 1]) { + $mark = ''; + $clean .= '*'; + } + break; + case '#': + if (empty($mark)) { + $mark = $str; + $clean .= $str; + } + break; + case "\n": + if ('#' == $mark || '--' == $mark) { + $mark = ''; + } + break; + case '-': + if (empty($mark) && '-- ' == substr($sql, $i, 3)) { + $mark = '-- '; + $clean .= $mark; + } + break; + default: + break; + } + $clean .= $mark ? '' : $str; + } + + return $clean; + } + + + public static function parseParameter($params, $glue = ',', $alias = '') { + $result = array('fields' => ' 1 ', 'params' => array()); + $split = ''; + $suffix = ''; + $allow_operator = array('>', '<', '<>', '!=', '>=', '<=', '+=', '-=', 'LIKE', 'like'); + if (in_array(strtolower($glue), array('and', 'or'))) { + $suffix = '__'; + } + if (!is_array($params)) { + $result['fields'] = $params; + + return $result; + } + if (is_array($params)) { + $result['fields'] = ''; + foreach ($params as $fields => $value) { + if (',' == $glue) { + $value = null === $value ? '' : $value; + } + $operator = ''; + if (false !== strpos($fields, ' ')) { + list($fields, $operator) = explode(' ', $fields, 2); + if (!in_array($operator, $allow_operator)) { + $operator = ''; + } + } + if (empty($operator)) { + $fields = trim($fields); + if (is_array($value) && !empty($value)) { + $operator = 'IN'; + } elseif ('NULL' === $value) { + $operator = 'IS'; + } else { + $operator = '='; + } + } elseif ('+=' == $operator) { + $operator = " = `$fields` + "; + } elseif ('-=' == $operator) { + $operator = " = `$fields` - "; + } elseif ('!=' == $operator || '<>' == $operator) { + if (is_array($value) && !empty($value)) { + $operator = 'NOT IN'; + } elseif ('NULL' === $value) { + $operator = 'IS NOT'; + } + } + + $select_fields = self::parseFieldAlias($fields, $alias); + if (is_array($value) && !empty($value)) { + $insql = array(); + $value = array_values($value); + foreach ($value as $v) { + $placeholder = self::parsePlaceholder($fields, $suffix); + $insql[] = $placeholder; + $result['params'][$placeholder] = is_null($v) ? '' : $v; + } + $result['fields'] .= $split . "$select_fields {$operator} (" . implode(',', $insql) . ')'; + $split = ' ' . $glue . ' '; + } else { + $placeholder = self::parsePlaceholder($fields, $suffix); + $result['fields'] .= $split . "$select_fields {$operator} " . ('NULL' === $value ? 'NULL' : $placeholder); + $split = ' ' . $glue . ' '; + if ('NULL' !== $value) { + $result['params'][$placeholder] = is_array($value) ? '' : $value; + } + } + } + } + + return $result; + } + + + private static function parsePlaceholder($field, $suffix = '') { + static $params_index = 0; + ++$params_index; + + $illegal_str = array('(', ')', ',', '.', '*'); + $placeholder = ":{$suffix}" . str_replace($illegal_str, '_', $field) . "_{$params_index}"; + + return $placeholder; + } + + private static function parseFieldAlias($field, $alias = '') { + if (strexists($field, '.') || strexists($field, '*')) { + return $field; + } + if (strexists($field, '(')) { + $select_fields = str_replace(array('(', ')'), array('(' . (!empty($alias) ? "`{$alias}`." : '') . '`', '`)'), $field); + } else { + $select_fields = (!empty($alias) ? "`{$alias}`." : '') . "`$field`"; + } + + return $select_fields; + } + + + public static function parseSelect($field = array(), $alias = '') { + if (empty($field) || '*' == $field) { + return ' SELECT *'; + } + if (!is_array($field)) { + $field = array($field); + } + $select = array(); + $index = 0; + foreach ($field as $field_row) { + if (strexists($field_row, '*')) { + if (!strexists(strtolower($field_row), 'as')) { + } + } elseif (strexists(strtolower($field_row), 'select')) { + if ('(' != $field_row[0]) { + $field_row = "($field_row) AS '{$index}'"; + } + } elseif (strexists($field_row, '(')) { + $field_row = str_replace(array('(', ')'), array('(' . (!empty($alias) ? "`{$alias}`." : '') . '`', '`)'), $field_row); + if (!strexists(strtolower($field_row), 'as')) { + $field_row .= " AS '{$index}'"; + } + } else { + $field_row = self::parseFieldAlias($field_row, $alias); + } + $select[] = $field_row; + ++$index; + } + + return ' SELECT ' . implode(',', $select); + } + + public static function parseLimit($limit, $inpage = true) { + $limitsql = ''; + if (empty($limit)) { + return $limitsql; + } + if (is_array($limit)) { + if (empty($limit[0]) && !empty($limit[1])) { + $limitsql = ' LIMIT 0, ' . $limit[1]; + } else { + $limit[0] = max(intval($limit[0]), 1); + !empty($limit[1]) && $limit[1] = max(intval($limit[1]), 1); + if (empty($limit[0]) && empty($limit[1])) { + $limitsql = ''; + } elseif (!empty($limit[0]) && empty($limit[1])) { + $limitsql = ' LIMIT ' . $limit[0]; + } else { + $limitsql = ' LIMIT ' . ($inpage ? ($limit[0] - 1) * $limit[1] : $limit[0]) . ', ' . $limit[1]; + } + } + } else { + $limit = trim($limit); + if (preg_match('/^(?:limit)?[\s,0-9]+$/i', $limit)) { + $limitsql = strexists(strtoupper($limit), 'LIMIT') ? " $limit " : " LIMIT $limit"; + } + } + + return $limitsql; + } + + public static function parseOrderby($orderby, $alias = '') { + $orderbysql = ''; + if (empty($orderby)) { + return $orderbysql; + } + if (!is_array($orderby)) { + $orderby = explode(',', $orderby); + } + foreach ($orderby as $i => &$row) { + if (strtoupper($row) == 'RAND()') { + $row = strtoupper($row); + } else { + $row = strtolower($row); + list($field, $orderbyrule) = explode(' ', $row); + + if ('asc' != $orderbyrule && 'desc' != $orderbyrule) { + unset($orderby[$i]); + } + $field = self::parseFieldAlias($field, $alias); + $row = "{$field} {$orderbyrule}"; + } + } + $orderbysql = implode(',', $orderby); + return !empty($orderbysql) ? " ORDER BY $orderbysql " : ''; + } + + public static function parseGroupby($statement, $alias = '') { + if (empty($statement)) { + return $statement; + } + if (!is_array($statement)) { + $statement = explode(',', $statement); + } + foreach ($statement as $i => &$row) { + $row = self::parseFieldAlias($row, $alias); + if (strexists($row, ' ')) { + unset($statement[$i]); + } + } + $statementsql = implode(', ', $statement); + + return !empty($statementsql) ? " GROUP BY $statementsql " : ''; + } +} diff --git a/framework/class/image.class.php b/framework/class/image.class.php new file mode 100644 index 0000000..2f6a7de --- /dev/null +++ b/framework/class/image.class.php @@ -0,0 +1,304 @@ +src = $src; + $this->ext = pathinfo($src, PATHINFO_EXTENSION); + } + + public static function create($src) + { + return new self($src); + } + + public function resize($width = 0, $height = 0) + { + if ($width > 0 || $height > 0) { + $this->actions[] = 'resize'; + } + if ($width > 0 && 0 == $height) { + $height = $width; + } + if ($height > 0 && 0 == $width) { + $width = $height; + } + $this->resize_width = $width; + $this->resize_height = $height; + + return $this; + } + + public function crop($width = 400, $height = 300, $position = 1) + { + if ($width > 0 || $height > 0) { + $this->actions[] = 'crop'; + } + if ($width > 0 && 0 == $height) { + $height = $width; + } + if ($height > 0 && 0 == $width) { + $width = $height; + } + $this->crop_width = $width; + $this->crop_height = $height; + $this->crop_position = min(intval($position), 9); + + return $this; + } + + public function getExt() + { + return in_array($this->ext, array('jpg', 'jpeg', 'png', 'gif')) ? $this->ext : 'jpeg'; + } + + public function isPng() + { + return file_is_image($this->src) && 'png' == $this->getExt(); + } + + public function isJPEG() + { + return file_is_image($this->src) && in_array($this->getExt(), array('jpg', 'jpeg')); + } + + public function isGif() + { + return file_is_image($this->src) && 'gif' == $this->getExt(); + } + + + public function saveTo($path, $quality = null) + { + $path = safe_gpc_path($path); + if (empty($path)) { + return false; + } + $result = $this->handle(); + if (!$result) { + return false; + } + $ext = $this->getExt(); + if ('jpg' == $ext) { + $ext = 'jpeg'; + } + $func = 'image' . $ext; + $real_quality = $this->realQuality($quality); + $saved = false; + $image = $this->image(); + imagealphablending($image, false); + imagesavealpha($image, true); + if (is_null($real_quality)) { + $saved = $func($image, $path); + } else { + if (!$this->isGif()) { + $saved = $func($image, $path, $real_quality); + } + } + $this->destroy(); + + return $saved ? $path : $saved; + } + + private function realQuality($quality = null) + { + if (is_null($quality)) { + return null; + } + $quality = min($quality, 100); + if ($this->isJPEG()) { + return $quality * 0.75; + } + if ($this->isPng()) { + return round(abs((100 - $quality) / 11.111111)); + } + + return null; + } + + protected function handle() + { + if (!function_exists('gd_info')) { + return false; + } + $this->image = $this->createResource(); + if (!$this->image) { + return false; + } + $this->imageinfo = getimagesize($this->src); + $actions = array_unique($this->actions); + $src_image = $this->image; + foreach ($actions as $action) { + $method = 'do' . ucfirst($action); + $src_image = $this->{$method}($src_image); + } + $this->image = $src_image; + + return true; + } + + + protected function doCrop($src_image) + { + list($dst_x, $dst_y) = $this->getCropDestPoint(); + if (version_compare(PHP_VERSION, '5.5.0') >= 0) { + $new_image = imagecrop($src_image, array('x' => $dst_x, 'y' => $dst_y, 'width' => $this->crop_width, 'height' => $this->crop_height)); + imagedestroy($src_image); + } else { + $new_image = $this->modify($src_image, $this->crop_width, $this->crop_height, $this->crop_width, $this->crop_height, 0, 0, $dst_x, $dst_y); + } + $this->imageinfo[0] = $this->crop_width; + $this->imageinfo[1] = $this->crop_height; + + return $new_image; + } + + + protected function doResize($src_image) + { + $newimage = $this->modify($src_image, $this->resize_width, $this->resize_height, $this->imageinfo[0], $this->imageinfo[1]); + $this->imageinfo[0] = $this->resize_width; + $this->imageinfo[1] = $this->resize_height; + + return $newimage; + } + + + protected function modify($src_image, $width, $height, $src_width, $src_height, $dst_x = 0, $dst_y = 0, $src_x = 0, $src_y = 0) + { + $image = imagecreatetruecolor($width, $height); + imagealphablending($image, false); + imagesavealpha($image, true); + imagecopyresampled($image, $src_image, $dst_x, $dst_y, $src_x, $src_y, $width, $height, $src_width, $src_height); + imagedestroy($src_image); + + return $image; + } + + private function image() + { + return $this->image; + } + + private function destroy() + { + if ($this->image) { + imagedestroy($this->image); + } + } + + private function createResource() + { + if (file_exists($this->src) && !is_readable($this->src)) { + return null; + } + if ($this->isPng()) { + return imagecreatefrompng($this->src); + } + if ($this->isJPEG()) { + return imagecreatefromjpeg($this->src); + } + if ($this->isGif()) { + return imagecreatefromgif($this->src); + } + + return null; + } + + + public function toBase64($prefix = 'data:image/%s;base64,') + { + $filename = tempnam('tmp', 'base64'); + $prefix = sprintf($prefix, $this->getExt()); + $result = $this->saveTo($filename); + if (!$result) { + return false; + } + $content = file_get_contents($filename); + $base64 = base64_encode($content); + unlink($filename); + + return $prefix . $base64; + } + + + private function getCropDestPoint() + { + $s_width = $this->imageinfo[0]; + $s_height = $this->imageinfo[1]; + $dst_x = $dst_y = 0; + if ('0' == $this->crop_width || $this->crop_width > $s_width) { + $this->crop_width = $s_width; + } + if ('0' == $this->crop_height || $this->crop_height > $s_height) { + $this->crop_height = $s_height; + } + switch ($this->crop_position) { + case 0: + case 1: + $dst_x = 0; + $dst_y = 0; + break; + case 2: + $dst_x = ($s_width - $this->crop_width) / 2; + $dst_y = 0; + break; + case 3: + $dst_x = $s_width - $this->crop_width; + $dst_y = 0; + break; + case 4: + $dst_x = 0; + $dst_y = ($s_height - $this->crop_height) / 2; + break; + case 5: + $dst_x = ($s_width - $this->crop_width) / 2; + $dst_y = ($s_height - $this->crop_height) / 2; + break; + case 6: + $dst_x = $s_width - $this->crop_width; + $dst_y = ($s_height - $this->crop_height) / 2; + break; + case 7: + $dst_x = 0; + $dst_y = $s_height - $this->crop_height; + break; + case 8: + $dst_x = ($s_width - $this->crop_width) / 2; + $dst_y = $s_height - $this->crop_height; + break; + case 9: + $dst_x = $s_width - $this->crop_width; + $dst_y = $s_height - $this->crop_height; + break; + default: + $dst_x = 0; + $dst_y = 0; + } + if ($this->crop_width == $s_width) { + $dst_x = 0; + } + if ($this->crop_height == $s_height) { + $dst_y = 0; + } + + return array(intval($dst_x), intval($dst_y)); + } +} diff --git a/framework/class/loader.class.php b/framework/class/loader.class.php new file mode 100644 index 0000000..7f8c96b --- /dev/null +++ b/framework/class/loader.class.php @@ -0,0 +1,308 @@ + $val) { + if (0 == $key) { + $table_classname .= ucfirst($val) . '\\'; + } else { + $table_classname .= ucfirst($val); + } + } + } + + if (in_array($name, array( + 'account', + 'account_aliapp', + 'account_baiduapp', + 'account_toutiaoapp', + 'account_wxapp', + 'account_phoneapp', + 'account_webapp', + 'account_wechats', + 'article_category', + 'activity_clerks', + 'article_news', + 'article_notice', + 'article_comment', + 'basic_reply', + 'core_profile_fields', + 'core_sendsms_log', + 'core_attachment', + 'core_attachment_group', + 'core_cron', + 'core_paylog', + 'core_performance', + 'core_refundlog', + 'core_settings', + 'core_cover_reply', + 'core_message_notice_log', + 'core_menu_shortcut', + 'core_job', + 'core_menu', + 'coupon', + 'coupon_record', + 'cover_reply', + 'custom_reply', + 'images_reply', + 'mc_card', + 'mc_card_members', + 'mc_card_notices', + 'mc_card_notices_unread', + 'mc_card_record', + 'mc_card_sign_record', + 'mc_credits_recharge', + 'mc_credits_record', + 'mc_cash_record', + 'mc_chats_record', + 'mc_groups', + 'mc_handsel', + 'mc_mass_record', + 'mc_mapping_fans', + 'mc_fans_tag_mapping', + 'mc_mapping_ucenter', + 'mc_members', + 'mc_member_fields', + 'mc_member_address', + 'mc_fans_groups', + 'mc_oauth_fans', + 'mc_fans_tag', + 'modules_rank', + 'modules_bindings', + 'modules_plugin', + 'modules_plugin_rank', + 'modules_cloud', + 'modules_recycle', + 'modules', + 'modules_ignore', + 'music_reply', + 'news_reply', + 'paycenter_order', + 'phoneapp_versions', + 'qrcode', + 'qrcode_stat', + 'rule', + 'rule_keyword', + 'site_article', + 'site_article_comment', + 'site_category', + 'site_templates', + 'site_multi', + 'site_nav', + 'site_page', + 'site_slide', + 'site_store_cash_log', + 'site_store_cash_order', + 'site_store_create_account', + 'site_store_goods', + 'site_store_goods_cloud', + 'site_store_order', + 'site_styles', + 'site_styles_vars', + 'stat_visit', + 'stat_visit_ip', + 'system_stat_visit', + 'system_welcome_binddomain', + 'uni_account', + 'uni_account_menus', + 'uni_account_modules', + 'uni_account_users', + 'uni_account_modules_shortcut', + 'uni_verifycode', + 'uni_group', + 'uni_modules', + 'uni_settings', + 'userapi_reply', + 'userapi_cache', + 'users', + 'users_group', + 'users_profile', + 'users_bind', + 'users_create_group', + 'users_extra_group', + 'users_extra_limit', + 'users_extra_modules', + 'users_extra_templates', + 'users_lastuse', + 'users_founder_group', + 'users_founder_own_users', + 'users_founder_own_users_groups', + 'users_founder_own_uni_groups', + 'users_founder_own_create_groups', + 'users_permission', + 'users_login_logs', + 'users_operate_history', + 'users_operate_star', + 'voice_reply', + 'video_reply', + 'wechat_news', + 'wechat_attachment', + 'wxapp_versions', + 'wxcard_reply', + 'uni_link_uniacid', + 'wxapp_general_analysis', + 'wxapp_register_version', + ))) { + return new $table_classname(); + } + + load()->classs('table'); + load()->table($name); + $service = false; + + $class_name = "{$name}Table"; + if (class_exists($class_name)) { + $service = new $class_name(); + } + + return $service; +} + + +class Loader { + private $cache = array(); + private $singletonObject = array(); + private $libraryMap = array( + 'agent' => 'agent/agent.class', + 'captcha' => 'captcha/captcha.class', + 'pdo' => 'pdo/PDO.class', + 'qrcode' => 'qrcode/phpqrcode', + 'ftp' => 'ftp/ftp', + 'pinyin' => 'pinyin/pinyin', + 'pkcs7' => 'pkcs7/pkcs7Encoder', + 'json' => 'json/JSON', + 'phpmailer' => 'phpmailer/PHPMailerAutoload', + 'oss' => 'alioss/autoload', + 'qiniu' => 'qiniu/autoload', + 'cosv5' => 'cosv5/index', + 'sentry' => 'sentry/Raven/Autoloader', + ); + private $loadTypeMap = array( + 'func' => '/framework/function/%s.func.php', + 'model' => '/framework/model/%s.mod.php', + 'classs' => '/framework/class/%s.class.php', + 'library' => '/framework/library/%s.php', + 'table' => '/framework/table/%s.table.php', + 'web' => '/web/common/%s.func.php', + 'app' => '/app/common/%s.func.php', + ); + private $accountMap = array( + 'pay' => 'pay/pay', + 'account' => 'account/account', + 'weixin.account' => 'account/weixin.account', + 'weixin.platform' => 'account/weixin.platform', + 'aliapp.account' => 'account/aliapp.account', + 'baiduapp.account' => 'account/baiduapp.account', + 'toutiaoapp.account' => 'account/toutiaoapp.account', + 'phoneapp.account' => 'account/phoneapp.account', + 'webapp.account' => 'account/webapp.account', + 'wxapp.account' => 'account/wxapp.account', + 'wxapp.platform' => 'account/wxapp.platform', + 'wxapp.work' => 'account/wxapp.work', + ); + + public function __construct() { + $this->registerAutoload(); + } + + public function registerAutoload() { + spl_autoload_register(array($this, 'autoload')); + } + + public function autoload($class) { + $section = array( + 'Table' => '/framework/table/', + ); + $classmap = array( + 'We7Table' => 'table', + ); + if (isset($classmap[$class])) { + load()->classs($classmap[$class]); + } elseif (preg_match('/^[0-9a-zA-Z\-\\\\_]+$/', $class) + && (0 === stripos($class, 'We7') || 0 === stripos($class, '\We7')) + && false !== stripos($class, '\\')) { + $group = explode('\\', $class); + $path = IA_ROOT . $section[$group[1]]; + unset($group[0]); + unset($group[1]); + $file_path = $path . implode('/', $group) . '.php'; + if (is_file($file_path)) { + include $file_path; + } + $file_path = $path . 'Core/' . implode('', $group) . '.php'; + if (is_file($file_path)) { + include $file_path; + } + } + } + + public function __call($type, $params) { + global $_W; + $name = $cachekey = array_shift($params); + + $accountMapKey = array_search($name, $this->accountMap); + if (!empty($accountMapKey)) { + $name = $cachekey = $accountMapKey; + } + + if (!empty($this->cache[$type]) && isset($this->cache[$type][$cachekey])) { + return true; + } + if (empty($this->loadTypeMap[$type])) { + return true; + } + if ('library' == $type && !empty($this->libraryMap[$name])) { + $name = $this->libraryMap[$name]; + } + if ('classs' == $type && !empty($this->accountMap[$name])) { + $filename = sprintf($this->loadTypeMap[$type], $this->accountMap[$name]); + if (file_exists(IA_ROOT . $filename)) { + $name = $this->accountMap[$name]; + } + } + $file = sprintf($this->loadTypeMap[$type], $name); + if (file_exists(IA_ROOT . $file)) { + include IA_ROOT . $file; + $this->cache[$type][$cachekey] = true; + } + + return true; + } + + + public function singleton($name) { + if (isset($this->singletonObject[$name])) { + return $this->singletonObject[$name]; + } + $this->singletonObject[$name] = $this->object($name); + + return $this->singletonObject[$name]; + } + + + public function object($name) { + $this->classs(strtolower($name)); + if (class_exists($name)) { + return new $name(); + } else { + return false; + } + } +} diff --git a/framework/class/oauth2/mobile.class.php b/framework/class/oauth2/mobile.class.php new file mode 100644 index 0000000..b2d5829 --- /dev/null +++ b/framework/class/oauth2/mobile.class.php @@ -0,0 +1,212 @@ +stateParam['from'] = 'mobile'; + } + + public function showLoginUrl($calback_url = '') { + } + + public function user() { + global $_GPC, $_W; + $mobile = trim($_GPC['username']); + $member['password'] = $_GPC['password']; + pdo_delete('users_failed_login', array('lastupdate <' => TIMESTAMP - 3600)); + $failed = pdo_get('users_failed_login', array('username' => $mobile, 'ip' => $_W['clientip'])); + if ($failed['count'] >= 5) { + return error('-1', '输入密码错误次数超过5次,请在1小时后再登录'); + } + if (!empty($_W['setting']['copyright']['verifycode'])) { + $verify = trim($_GPC['verify']); + if (empty($verify)) { + return error('-1', '请输入验证码'); + } + $result = checkcaptcha($verify); + if (empty($result)) { + return error('-1', '输入验证码错误'); + } + } + if (empty($mobile)) { + return error('-1', '请输入要登录的手机号'); + } + if (!preg_match(REGULAR_MOBILE, $mobile)) { + return error(-1, '手机号格式不正确'); + } + if (empty($member['password'])) { + return error('-1', '请输入密码'); + } + + $user_profile = table('users_profile')->getByMobile($mobile); + + if (empty($user_profile)) { + return error(-1, '手机号未注册'); + } + $member['uid'] = $user_profile['uid']; + $member['type'] = $this->user_type; + + return $member; + } + + public function validateMobile() { + global $_GPC; + $mobile = $_GPC['mobile']; + if (empty($mobile)) { + return error(-1, '手机号不能为空'); + } + if (!preg_match(REGULAR_MOBILE, $mobile)) { + return error(-1, '手机号格式不正确'); + } + $mobile_exists = table('users_profile')->getByMobile($mobile); + if (!empty($mobile_exists)) { + return error(-1, '手机号已存在'); + } + + return true; + } + + public function register() { + global $_GPC; + load()->model('user'); + $member = array(); + $profile = array(); + $smscode = trim($_GPC['smscode']); + $mobile = trim($_GPC['mobile']); + $member['password'] = $_GPC['password']; + + if (empty($smscode)) { + return error(-1, '短信验证码不能为空'); + } + + load()->model('utility'); + $verify_info = utility_smscode_verify(0, $mobile, $smscode); + if (is_error($verify_info)) { + return error(-1, $verify_info['message']); + } + + if (istrlen($member['password']) < 8) { + return error(-1, '必须输入密码,且密码长度不得低于8位。'); + } + + $member['username'] = $mobile; + $member['openid'] = $mobile; + $member['register_type'] = USER_REGISTER_TYPE_MOBILE; + $member['owner_uid'] = intval($_GPC['owner_uid']); + + $profile['mobile'] = $mobile; + + $register = array( + 'member' => $member, + 'profile' => $profile, + ); + + return parent::user_register($register); + } + + public function login() { + return $this->user(); + } + + public function bind() { + global $_GPC, $_W; + $mobile = safe_gpc_string($_GPC['mobile']); + + $user = table('users')->getById($_W['uid']); + if (empty($user)) { + return error(-1, '请先登录'); + } + $user_profile = table('users_profile')->getByUid($_W['uid']); + $user_bind = table('users_bind')->getByTypeAndUid(USER_REGISTER_TYPE_MOBILE, $_W['uid']); + $need_checkcaptcha = true; + if (isset($_GPC['need_checkcaptcha']) && empty($_GPC['need_checkcaptcha'])) { + $need_checkcaptcha = false; + } + if (!$need_checkcaptcha && !empty($user_bind)) { + $check_authcode = safe_gpc_string($_GPC['check_authcode']); + if (empty($check_authcode)) { + return error(-1, '请先验证旧手机!'); + } + $old_mobile = authcode($check_authcode); + if ($old_mobile != $user_bind['bind_sign']) { + return error(-1, '请先验证旧手机!'); + } + } + + $param_validate = $this->paramValidate(); + + if (is_error($param_validate)) { + return $param_validate; + } + + if (empty($user_profile)) { + pdo_insert('users_profile', array('uid' => $_W['uid'], 'mobile' => $mobile)); + } else { + pdo_update('users_profile', array('mobile' => $mobile), array('id' => $user_profile['id'])); + } + + if (empty($user_bind)) { + pdo_insert('users_bind', array('uid' => $_W['uid'], 'bind_sign' => $mobile, 'third_type' => USER_REGISTER_TYPE_MOBILE, 'third_nickname' => $mobile)); + } else { + table('users_bind')->where(array('uid' => $_W['uid'], 'third_type' => USER_REGISTER_TYPE_MOBILE))->fill(array('bind_sign' => $mobile, 'third_nickname' => $mobile))->save(); + } + + return error(0, '绑定成功'); + } + + public function unbind() { + global $_GPC, $_W; + $mobile = safe_gpc_string($_GPC['mobile']); + + $user_profile = table('users_profile')->getByUid($_W['uid']); + + $param_validate = $this->paramValidate(); + + if (is_error($param_validate)) { + return $param_validate; + } + pdo_update('users', array('openid' => ''), array('uid' => $_W['uid'])); + pdo_update('users_profile', array('mobile' => ''), array('id' => $user_profile['id'])); + pdo_delete('users_bind', array('uid' => $_W['uid'], 'bind_sign' => $mobile, 'third_type' => USER_REGISTER_TYPE_MOBILE)); + + return error(0, '解除绑定成功'); + } + + public function isbind() { + global $_W; + $bind_info = table('users_bind')->getByTypeAndUid(USER_REGISTER_TYPE_MOBILE, $_W['uid']); + + return !empty($bind_info['bind_sign']); + } + + public function paramValidate() { + global $_GPC; + $mobile = trim($_GPC['mobile']); + $image_code = trim($_GPC['imagecode']); + $sms_code = trim($_GPC['smscode']); + $need_checkcaptcha = true; + if (isset($_GPC['need_checkcaptcha']) && empty($_GPC['need_checkcaptcha'])) { + $need_checkcaptcha = false; + } + if (empty($sms_code)) { + return error(-1, '短信验证码不能为空'); + } + + if ($need_checkcaptcha && empty($image_code)) { + return error(-1, '图形验证码不能为空'); + } + if ($need_checkcaptcha) { + $captcha = checkcaptcha($image_code); + if (empty($captcha)) { + return error(-1, '图形验证码错误,请重新获取'); + } + } + load()->model('utility'); + $verify_info = utility_smscode_verify(0, $mobile, $sms_code); + if (is_error($verify_info)) { + return error(-1, $verify_info['message']); + } + } +} \ No newline at end of file diff --git a/framework/class/oauth2/oauth2client.class.php b/framework/class/oauth2/oauth2client.class.php new file mode 100644 index 0000000..69af090 --- /dev/null +++ b/framework/class/oauth2/oauth2client.class.php @@ -0,0 +1,191 @@ + '', + 'from' => '', + 'mode' => '', + ); + + public function __construct($ak, $sk) { + $this->ak = $ak; + $this->sk = $sk; + } + + public function stateParam() { + global $_W; + $this->stateParam['state'] = $_W['token']; + if (!empty($_W['user'])) { + $this->stateParam['mode'] = 'bind'; + } else { + $this->stateParam['mode'] = 'login'; + } + + return base64_encode(http_build_query($this->stateParam, '', '&')); + } + + public function getLoginType($login_type) { + $this->login_type = $login_type; + } + + public function setUserType($user_type) { + $this->user_type = $user_type; + + return $this; + } + + public static function supportLoginType() { + return array('system', 'qq', 'wechat', 'mobile'); + } + + public static function supportThirdLoginType() { + return array('qq', 'wechat'); + } + + public static function supportBindTypeInfo($type = '') { + $data = array( + 'qq' => array( + 'type' => 'qq', + 'title' => 'QQ', + ), + 'wechat' => array( + 'type' => 'wechat', + 'title' => '微信', + ), + 'mobile' => array( + 'type' => 'mobile', + 'title' => '手机号', + ), + ); + if (!empty($type)) { + return $data[$type]; + } else { + return $data; + } + } + + + public static function supportThirdLoginBindType() { + return array('qq', 'wechat'); + } + + public static function supportThirdMode() { + return array('bind', 'login'); + } + + public static function supportParams($state) { + $state = urldecode($state); + $param = array(); + if (!empty($state)) { + $state = base64_decode($state); + parse_str($state, $third_param); + $modes = self::supportThirdMode(); + $types = self::supportThirdLoginType(); + + if (in_array($third_param['mode'], $modes) && in_array($third_param['from'], $types)) { + return $third_param; + } + } + + return $param; + } + + public static function create($type, $appid = '', $appsecret = '') { + $types = self::supportLoginType(); + if (in_array($type, $types)) { + load()->classs('oauth2/' . $type); + $type_name = ucfirst($type); + $obj = new $type_name($appid, $appsecret); + $obj->getLoginType($type); + + return $obj; + } + + return null; + } + + abstract public function showLoginUrl($calback_url = ''); + + abstract public function user(); + + abstract public function login(); + + abstract public function bind(); + + abstract public function unbind(); + + abstract public function isbind(); + + abstract public function register(); + + public function user_register($register) { + global $_W; + load()->model('user'); + + if (is_error($register)) { + return $register; + } + $member = $register['member']; + $profile = $register['profile']; + + $member['type'] = $this->user_type; + if (USER_TYPE_CLERK == $member['type']) { + $member['status'] = !empty($_W['setting']['register']['clerk']['verify']) ? 1 : 2; + } else { + $member['status'] = !empty($_W['setting']['register']['verify']) ? 1 : 2; + } + $member['remark'] = ''; + $member['groupid'] = intval($_W['setting']['register']['groupid']); + if (empty($member['groupid'])) { + $member['groupid'] = pdo_fetchcolumn('SELECT id FROM ' . tablename('users_group') . ' ORDER BY id ASC LIMIT 1'); + $member['groupid'] = intval($member['groupid']); + } + $group = user_group_detail_info($member['groupid']); + + $timelimit = intval($group['timelimit']); + if ($timelimit > 0) { + $member['endtime'] = strtotime($timelimit . ' days'); + } + $member['starttime'] = TIMESTAMP; + + $user_id = user_register($member, $this->stateParam['from']); + if (in_array($member['register_type'], array(USER_REGISTER_TYPE_QQ, USER_REGISTER_TYPE_WECHAT))) { + pdo_update('users', array('username' => $member['username'] . $user_id . rand(100, 999)), array('uid' => $user_id)); + } + if ($user_id > 0) { + unset($member['password']); + $member['uid'] = $user_id; + if (!empty($profile)) { + $profile['uid'] = $user_id; + $profile['createtime'] = TIMESTAMP; + pdo_insert('users_profile', $profile); + } + if (in_array($member['register_type'], array(USER_REGISTER_TYPE_QQ, USER_REGISTER_TYPE_WECHAT, USER_REGISTER_TYPE_MOBILE))) { + pdo_insert('users_bind', array('uid' => $user_id, 'bind_sign' => $member['openid'], 'third_type' => $member['register_type'], 'third_nickname' => $member['username'])); + } + if (in_array($member['register_type'], array(USER_REGISTER_TYPE_QQ, USER_REGISTER_TYPE_WECHAT))) { + return $user_id; + } + + $message = '注册成功'; + if (USER_STATUS_CHECK == $member['status']) { + $message .= ',请等待管理员审核!'; + } elseif (USER_TYPE_CLERK != $member['type']) { + $message .= ',请重新登录!'; + } + + return array( + 'errno' => 0, + 'message' => $message, + 'uid' => $user_id, + ); + } + + return error(-1, '增加用户失败,请稍候重试或联系网站管理员解决!'); + } +} \ No newline at end of file diff --git a/framework/class/oauth2/system.class.php b/framework/class/oauth2/system.class.php new file mode 100644 index 0000000..91ce6ab --- /dev/null +++ b/framework/class/oauth2/system.class.php @@ -0,0 +1,139 @@ +stateParam['from'] = 'system'; + } + + public function showLoginUrl($calback_url = '') { + return ''; + } + + public function user() { + global $_GPC, $_W; + $username = trim($_GPC['username']); + $refused_login_limit = $_W['setting']['copyright']['refused_login_limit']; + pdo_delete('users_failed_login', array('lastupdate <' => TIMESTAMP - $refused_login_limit * 60)); + $failed = pdo_get('users_failed_login', array('username' => $username)); + if ($failed['count'] >= 5) { + return error('-1', "输入密码错误次数超过5次,请在{$refused_login_limit}分钟后再登录"); + } + $need_check_captcha = true; + if ($_W['setting']['copyright']['login_verify_status'] && !empty($_GPC['smscode'])) { + $need_check_captcha = false; + } + if (!empty($_W['setting']['copyright']['verifycode']) && $need_check_captcha) { + $verify = trim($_GPC['verify']); + if (empty($verify)) { + return error('-1', '请输入验证码'); + } + $result = checkcaptcha($verify); + if (empty($result)) { + return error('-1', '输入验证码错误'); + } + } + if (empty($username)) { + return error('-1', '请输入要登录的用户名'); + } + $member['username'] = $username; + $member['password'] = $_GPC['password']; + $member['type'] = $this->user_type; + if (empty($member['password'])) { + return error('-1', '请输入密码'); + } + + return $member; + } + + public function register() { + global $_W, $_GPC; + load()->model('user'); + $member = array(); + $profile = array(); + $member['username'] = trim($_GPC['username']); + $member['owner_uid'] = intval($_GPC['owner_uid']); + $member['password'] = $_GPC['password']; + + if (!preg_match(REGULAR_USERNAME, $member['username'])) { + return error(-1, '必须输入用户名,格式为 3-15 位字符,可以包括汉字、字母(不区分大小写)、数字、下划线和句点。'); + } + + if (user_check(array('username' => $member['username']))) { + return error(-1, '非常抱歉,此用户名已经被注册,你需要更换注册名称!'); + } + + if (!empty($_W['setting']['register']['code'])) { + if (!checkcaptcha($_GPC['code'])) { + return error(-1, '你输入的验证码不正确, 请重新输入.'); + } + } + if (istrlen($member['password']) < 8) { + return error(-1, '必须输入密码,且密码长度不得低于8位。'); + } + + $extendfields = $this->systemFields(); + if (!empty($extendfields)) { + $fields = array_keys($extendfields); + if (in_array('birthyear', $fields)) { + $extendfields[] = array('field' => 'birthmonth', 'title' => '出生生日', 'required' => $extendfields['birthyear']['required']); + $extendfields[] = array('field' => 'birthday', 'title' => '出生生日', 'required' => $extendfields['birthyear']['required']); + $_GPC['birthyear'] = $_GPC['birth']['year']; + $_GPC['birthmonth'] = $_GPC['birth']['month']; + $_GPC['birthday'] = $_GPC['birth']['day']; + } + if (in_array('resideprovince', $fields)) { + $extendfields[] = array('field' => 'residecity', 'title' => '居住地址', 'required' => $extendfields['resideprovince']['required']); + $extendfields[] = array('field' => 'residedist', 'title' => '居住地址', 'required' => $extendfields['resideprovince']['required']); + $_GPC['resideprovince'] = $_GPC['reside']['province']; + $_GPC['residecity'] = $_GPC['reside']['city']; + $_GPC['residedist'] = $_GPC['reside']['district']; + } + foreach ($extendfields as $row) { + if (!empty($row['required']) && empty($_GPC[$row['field']])) { + return error(-1, '“' . $row['title'] . '”此项为必填项,请返回填写完整!'); + } + if ($row['field'] == 'mobile') { + $mobile = safe_gpc_int($_GPC['mobile']); + if (!preg_match(REGULAR_MOBILE, $mobile)) { + return error(-1, '手机号格式不正确'); + } + $mobile_exists = table('users_profile')->getByMobile($mobile); + if (!empty($mobile_exists)) { + return error(-1, '手机号已存在'); + } + } + $profile[$row['field']] = $_GPC[$row['field']]; + } + } + + $register = array( + 'member' => $member, + 'profile' => $profile, + ); + + return parent::user_register($register); + } + + public function systemFields() { + return table('core_profile_fields')->getAvailableAndShowableFields(); + } + + public function login() { + return $this->user(); + } + + public function bind() { + return true; + } + + public function unbind() { + return true; + } + + public function isbind() { + return true; + } +} \ No newline at end of file diff --git a/framework/class/query.class.php b/framework/class/query.class.php new file mode 100644 index 0000000..12a4012 --- /dev/null +++ b/framework/class/query.class.php @@ -0,0 +1,490 @@ +initClauses(); + } + + private function initClauses() { + $this->clauses = array( + 'SELECT' => array(), + 'DELETE' => '', + 'UPDATE' => '', + 'INSERT INTO' => '', + + 'FROM' => '', + 'LEFTJOIN' => array(), + 'INNERJOIN' => array(), + 'ON' => array(), + 'SET' => '', + 'WHERE' => array(), + 'WHEREOR' => array(), + 'GROUPBY' => array(), + 'HAVING' => array(), + 'ORDERBY' => array(), + 'LIMIT' => '', + 'PAGE' => '', + ); + foreach ($this->clauses as $clause => $value) { + $this->statements[$clause] = $value; + } + $this->parameters = array(); + if (!empty($this->fixTable)) { + $this->from($this->fixTable); + } + } + + private function resetClause($clause = '') { + if (empty($clause)) { + $this->initClauses(); + + return $this; + } + $this->statements[$clause] = null; + $this->parameters = array(); + $this->values = array(); + if (isset($this->clauses[$clause]) && is_array($this->clauses[$clause])) { + $this->statements[$clause] = array(); + } + + return $this; + } + + + private function addStatement($clause, $statement, $parameters = array()) { + if (null === $statement) { + return $this->resetClause($clause); + } + if (isset($this->statements[$clause]) && is_array($this->statements[$clause])) { + if (is_array($statement)) { + $this->statements[$clause] = array_merge($this->statements[$clause], $statement); + } else { + if (empty($parameters) && is_array($parameters)) { + $this->statements[$clause][] = $statement; + } else { + $this->statements[$clause][$statement] = empty($parameters) && is_array($parameters) ? '' : $parameters; + } + } + } else { + $this->statements[$clause] = $statement; + } + + return $this; + } + + public function __call($clause, $statement = array()) { + $origin_clause = $clause; + $clause = strtoupper($clause); + + if ('HAVING' == $clause) { + array_unshift($statement, $clause); + + return call_user_func_array(array($this, 'condition'), $statement); + } + + if ('LEFTJOIN' == $clause || 'INNERJOIN' == $clause) { + array_unshift($statement, $clause); + + return call_user_func_array(array($this, 'join'), $statement); + } + + return $this->addStatement($clause, $statement); + } + + public function where($condition, $parameters = array(), $operator = 'AND') { + if (!is_array($condition) && !($condition instanceof Closure)) { + $condition = array($condition => $parameters); + } + $this->addStatement('WHERE', array(array($operator, $condition))); + + return $this; + } + + public function whereor($condition, $parameters = array()) { + return $this->where($condition, $parameters, 'OR'); + } + + public function from($tablename, $alias = '') { + if (empty($tablename)) { + return $this; + } + $this->mainTable = $tablename; + $this->currentTableAlias = $alias; + + $this->statements['FROM'] = $this->mainTable; + + return $this; + } + + public function join($clause, $tablename, $alias = '') { + if (empty($tablename)) { + return $this; + } + $this->joinTable = $tablename; + + return $this->addStatement($clause, $tablename . ' ' . $alias); + } + + public function on($condition, $parameters = array()) { + if (null === $condition) { + return $this->resetClause('ON'); + } + if (empty($condition)) { + return $this; + } + if (is_array($condition)) { + foreach ($condition as $key => $val) { + $this->on($key, $val); + } + + return $this; + } + if (empty($this->statements['ON'][$this->joinTable])) { + $this->statements['ON'][$this->joinTable] = array(); + } + $this->statements['ON'][$this->joinTable][$condition] = $parameters; + + return $this; + } + + public function select($field) { + if (is_string($field)) { + $field = func_get_args(); + } + + if (empty($field)) { + return $this; + } + if (1 == count($this->statements['SELECT'])) { + $this->resetClause('SELECT'); + } + + return $this->addStatement('SELECT', $field); + } + + + private function condition($operator, $condition, $parameters = array()) { + if (null === $condition) { + return $this->resetClause('WHERE'); + } + if (empty($condition)) { + return $this; + } + + if (is_array($condition)) { + foreach ($condition as $key => $val) { + $this->condition($operator, $key, $val); + } + + return $this; + } + + return $this->addStatement($operator, $condition, $parameters); + } + + public function orderby($field, $direction = 'ASC') { + if (is_array($field)) { + foreach ($field as $column => $order) { + $this->orderby($column, $order); + } + + return $this; + } + if (strtoupper($field) == 'RAND()') { + return $this->addStatement('ORDERBY', $field); + } + $direction = strtoupper($direction); + $direction = in_array($direction, array('ASC', 'DESC')) ? $direction : 'ASC'; + + return $this->addStatement('ORDERBY', $field . ' ' . $direction); + } + + public function fill($field, $value = '') { + if (is_array($field)) { + foreach ($field as $column => $val) { + $this->fill($column, $val); + } + + return $this; + } + $this->values[$field] = $value; + + return $this; + } + + public function hasWhere() { + return count($this->statements['WHERE']) > 0; + } + + public function get() { + if (empty($this->statements['SELECT'])) { + $this->addStatement('SELECT', '*'); + } + $this->lastsql = $this->buildQuery(); + $this->lastparams = $this->parameters; + $result = pdo_fetch($this->lastsql, $this->parameters); + + $this->resetClause(); + + return $result; + } + + public function getcolumn($field = '') { + if (!empty($field)) { + $this->select($field); + } + if (empty($this->statements['SELECT'])) { + $this->addStatement('SELECT', '*'); + } + $this->lastsql = $this->buildQuery(); + $this->lastparams = $this->parameters; + $result = pdo_fetchcolumn($this->lastsql, $this->parameters); + + $this->resetClause(); + + return $result; + } + + public function getall($keyfield = '') { + if (empty($this->statements['SELECT'])) { + $this->addStatement('SELECT', '*'); + } + $this->lastsql = $this->buildQuery(); + $this->lastparams = $this->parameters; + $result = pdo_fetchall($this->lastsql, $this->parameters, $keyfield); + + $this->resetClause(); + + return $result; + } + + + public function getLastQueryTotal() { + $lastquery = $this->getLastQuery(); + $countsql = str_replace(substr($lastquery[0], 0, strpos($lastquery[0], 'FROM')), 'SELECT COUNT(*) ', $lastquery[0]); + if (false !== strpos($countsql, 'LIMIT')) { + $countsql = substr($countsql, 0, strpos($countsql, 'LIMIT')); + } + if (strexists(strtoupper($countsql), 'GROUP BY')) { + $result = pdo_fetchall($countsql, $this->lastparams); + $result = count($result); + } else { + $result = pdo_fetchcolumn($countsql, $this->lastparams); + } + + return $result; + } + + public function count() { + $where = array(); + if (!empty($this->statements['WHERE'])) { + foreach ($this->statements['WHERE'] as $row) { + $where = array_merge($where, $row[1]); + } + } + + return pdo_count($this->statements['FROM'], $where); + } + + public function exists() { + $where = array(); + if (!empty($this->statements['WHERE'])) { + foreach ($this->statements['WHERE'] as $row) { + $where = array_merge($where, $row[1]); + } + } + + return pdo_exists($this->statements['FROM'], $where); + } + + public function delete() { + $where = $this->buildWhereArray(); + $result = pdo_delete($this->statements['FROM'], $where); + + $this->resetClause(); + + return $result; + } + + public function insert($replace = false) { + $result = pdo_insert($this->statements['FROM'], $this->values, $replace); + $this->resetClause(); + + return $result; + } + + public function update() { + $where = $this->buildWhereArray(); + if (empty($where)) { + return error(-1, '未指定更新条件'); + } + $result = pdo_update($this->statements['FROM'], $this->values, $where); + $this->resetClause(); + + return $result; + } + + private function buildQuery() { + $query = ''; + foreach ($this->clauses as $clause => $separator) { + if (!empty($this->statements[$clause])) { + if (method_exists($this, 'buildQuery' . $clause)) { + $query .= call_user_func(array($this, 'buildQuery' . $clause), $this->statements[$clause]); + } elseif (is_string($separator)) { + $query .= " $clause " . implode($separator, $this->statements[$clause]); + } elseif (null === $separator) { + $query .= " $clause " . $this->statements[$clause]; + } + } + } + + return trim($query); + } + + private function buildQueryWhere() { + $closure = array(); + $sql = ''; + foreach ($this->statements['WHERE'] as $i => $wheregroup) { + $where = array(); + if (!empty($wheregroup[1]) && $wheregroup[1] instanceof Closure) { + $closure[] = $wheregroup; + } else { + $where = \SqlPaser::parseParameter($wheregroup[1], 'AND', $this->currentTableAlias); + $this->parameters = array_merge($this->parameters, $where['params']); + $sql .= ' ' . $wheregroup[0] . ' ' . $where['fields']; + } + unset($this->statements['WHERE'][$i]); + } + foreach ($closure as $callback) { + $callback[1]($this); + + $subsql = ''; + $where = array(); + foreach ($this->statements['WHERE'] as $i => $wheregroup) { + $where = \SqlPaser::parseParameter($wheregroup[1], 'AND', $this->currentTableAlias); + $this->parameters = array_merge($this->parameters, $where['params']); + $subsql .= ' ' . $wheregroup[0] . ' ' . $where['fields']; + unset($this->statements['WHERE'][$i]); + } + $subsql = ltrim(ltrim($subsql, ' AND '), ' OR '); + $sql .= " {$callback[0]} ( $subsql )"; + } + + return empty($where['fields']) ? '' : ' WHERE ' . ltrim(ltrim($sql, ' AND '), ' OR '); + } + + private function buildQueryWhereor() { + $where = \SqlPaser::parseParameter($this->statements['WHEREOR'], 'OR', $this->currentTableAlias); + $this->parameters = array_merge($this->parameters, $where['params']); + if (empty($where['fields'])) { + return ''; + } + if (empty($this->statements['WHERE'])) { + return " WHERE {$where['fields']} "; + } else { + return " OR {$where['fields']} "; + } + } + + private function buildQueryHaving() { + $where = \SqlPaser::parseParameter($this->statements['HAVING'], 'AND', $this->currentTableAlias); + $this->parameters = array_merge($this->parameters, $where['params']); + + return empty($where['fields']) ? '' : " HAVING {$where['fields']} "; + } + + private function buildQueryFrom() { + return ' FROM ' . tablename($this->statements['FROM']) . ' ' . $this->currentTableAlias; + } + + private function buildQueryLeftjoin() { + return $this->buildQueryJoin('LEFTJOIN'); + } + + private function buildQueryInnerjoin() { + return $this->buildQueryJoin('INNERJOIN'); + } + + private function buildQueryJoin($clause) { + if (empty($this->statements[$clause])) { + return ''; + } + $clause_operator = array( + 'LEFTJOIN' => ' LEFT JOIN ', + 'INNERJOIN' => ' INNER JOIN ', + ); + $sql = ''; + foreach ($this->statements[$clause] as $tablename) { + list($tablename, $alias) = explode(' ', $tablename); + $sql .= $clause_operator[$clause] . tablename($tablename) . ' ' . $alias; + if (!empty($this->statements['ON'][$tablename])) { + $sql .= ' ON '; + $split = ''; + foreach ($this->statements['ON'][$tablename] as $field => $condition) { + $operator = ''; + if (strexists($field, ' ')) { + list($field, $operator) = explode(' ', $field); + } + $operator = $operator ? $operator : '='; + $field = '`' . str_replace('.', '`.`', $field) . '`'; + if (strexists($condition, '.')) { + $condition = '`' . str_replace('.', '`.`', $condition) . '`'; + } + $sql .= " $split $field $operator $condition "; + $split = ' AND '; + } + } + } + + return $sql; + } + + private function buildQuerySelect() { + return \SqlPaser::parseSelect($this->statements['SELECT'], $this->currentTableAlias); + } + + private function buildQueryLimit() { + return \SqlPaser::parseLimit($this->statements['LIMIT'], false); + } + + private function buildQueryPage() { + return \SqlPaser::parseLimit($this->statements['PAGE'], true); + } + + private function buildQueryOrderby() { + return \SqlPaser::parseOrderby($this->statements['ORDERBY'], $this->currentTableAlias); + } + + private function buildQueryGroupby() { + return \SqlPaser::parseGroupby($this->statements['GROUPBY'], $this->currentTableAlias); + } + + private function buildWhereArray() { + $where = array(); + if (!empty($this->statements['WHERE'])) { + foreach ($this->statements['WHERE'] as $row) { + $where = array_merge($where, $row[1]); + } + } + + return $where; + } + + public function getLastQuery() { + return array($this->lastsql, $this->lastparams); + } +} \ No newline at end of file diff --git a/framework/class/slave.db.class.php b/framework/class/slave.db.class.php new file mode 100644 index 0000000..78cc134 --- /dev/null +++ b/framework/class/slave.db.class.php @@ -0,0 +1,115 @@ +classs('db'); + +class SlaveDb extends DB { + private $weight; + private $slavequery = 0; + private $slaveid = null; + + public function prepare($sql) { + $this->init_connect($sql); + + return parent::prepare($sql); + } + + public function query($sql, $params = array()) { + $starttime = microtime(); + if (!empty($params)) { + return parent::query($sql, $params); + } + $this->init_connect($sql); + $result = $this->pdo->exec($sql); + if (PDO_DEBUG) { + $info = array(); + $info['sql'] = $sql; + $info['error'] = $this->pdo->errorInfo(); + $this->debug(false, $info); + } + + return $result; + } + + public function slave_connect() { + $this->slave_choose(); + if ($this->slaveid) { + if (!isset($this->link[$this->slaveid])) { + $this->connect($this->slaveid); + } + ++$this->slavequery ; + $this->pdo = $this->link[$this->slaveid]; + } + + return true; + } + + protected function slave_choose() { + if (!isset($this->weight)) { + foreach ($this->cfg['slave'] as $key => $value) { + $this->weight .= str_repeat($key, 1 + intval($value['weight'])); + } + } + $sid = $this->weight[mt_rand(0, strlen($this->weight) - 1)]; + $this->slaveid = 'slave_' . $sid; + if (!isset($this->cfg[$this->slaveid])) { + $this->cfg[$this->slaveid] = $this->cfg['slave'][$sid]; + } + } + + public function init_connect($sql) { + if (!(true == $this->cfg['slave_status'] && !empty($this->cfg['slave']))) { + $this->master_connect(); + } else { + $sql = trim($sql); + $sql_lower = strtolower($sql); + $slave_except = false; + if (!strexists($sql_lower, 'where ')) { + $tablename = substr($sql_lower, strpos($sql_lower, 'from ') + 5); + } else { + $tablename = substr($sql_lower, strpos($sql_lower, 'from ') + 5, strpos($sql_lower, ' where') - strpos($sql_lower, 'from ') - 5); + } + $tablename = trim($tablename, '`'); + $tablename = str_replace($this->tablepre, '', $tablename); + if (!empty($this->cfg['common']['slave_except_table']) && in_array(strtolower($tablename), $this->cfg['common']['slave_except_table'])) { + $slave_except = true; + } + if (!(!$slave_except && 'SELECT' === strtoupper(substr($sql, 0, 6)) && $this->slave_connect())) { + $this->master_connect(); + } + } + + return true; + } + + public function master_connect() { + if (!isset($this->link['master'])) { + $this->connect('master'); + } + $this->pdo = $this->link['master']; + } + + public function insertid() { + $this->master_connect(); + + return parent::insertid(); + } + + public function begin() { + $this->master_connect(); + + return parent::begin(); + } + + public function commit() { + $this->master_connect(); + + return parent::commit(); + } + + public function rollback() { + $this->master_connect(); + + return parent::rollback(); + } +} diff --git a/framework/class/table.class.php b/framework/class/table.class.php new file mode 100644 index 0000000..dabcea2 --- /dev/null +++ b/framework/class/table.class.php @@ -0,0 +1,457 @@ +classs('validator'); + $this->query = load()->object('Query'); + $this->query->fixTable = $this->tableName; + $this->query->from($this->tableName); + } + + + public function searchWithPage($pageindex, $pagesize) { + if (!empty($pageindex) && !empty($pagesize)) { + $this->query->page($pageindex, $pagesize); + } + + return $this; + } + + + public function getLastQueryTotal() { + return $this->query->getLastQueryTotal(); + } + + + public function count() { + return $this->query->count(); + } + + + public function fill($field, $value = '') { + if (is_array($field)) { + foreach ($field as $column => $val) { + $this->fillField($column, $val); + } + + return $this; + } + $this->fillField($field, $value); + + return $this; + } + + + private function fillField($column, $val) { + if (in_array($column, $this->field)) { + $val = $this->getColumnVal($column, $val); + $this->attribute[$column] = $val; + $this->query->fill($column, $val); + } + } + + + private function getColumnVal($column, $val) { + $method = 'set' . $this->studly($column) . 'Field'; + if (method_exists($this, $method)) { + return $this->{$method}($val); + } + + return $this->cast($column, $val); + } + + + private function cast($column, $val) { + if (isset($this->cast[$column])) { + switch ($this->cast[$column]) { + case 'int': return intval($val); break; + case 'string': return strval($val); break; + case 'float': return floatval($val); break; + case 'double': return doubleval($val); break; + case 'bool': return boolval($val); break; + } + } + + return $val; + } + + + private function appendDefault() { + foreach ($this->default as $field => $value) { + if (!isset($this->attribute[$field])) { + if ('custom' === $value) { + $method = 'default' . $this->studly($field); + if (!method_exists($this, $method)) { + trigger_error($method . '方法未找到'); + } + $value = call_user_func(array($this, $method)); + } + $this->fillField($field, $value); + } + } + } + + + protected function valid($data) { + if (count($this->rule) <= 0) { + return error(0); + } + $validator = Validator::create($data, $this->rule); + $result = $validator->valid(); + + return $result; + } + + public function select($fields = '*') { + return $this->query->select($fields); + } + + public function limit($limit) { + return $this->query->limit($limit); + } + + public function get() { + $data = $this->query->get(); + if (!$data || empty($data)) { + return $data; + } + $this->loadRelation($data); + + return $data; + } + + public function getall($keyfield = '') { + $data = $this->query->getall($keyfield); + if (!$data || empty($data)) { + return $data; + } + $this->loadRelation($data, true); + + return $data; + } + + + public function getQuery() { + return $this->query; + } + + public function getTableName() { + return $this->tableName; + } + + + public function with($relation) { + $relations = is_string($relation) ? func_get_args() : $relation; + foreach ($relations as $relation => $val) { + if (is_numeric($relation)) { + $relation = $val; + } + if (!is_callable($val)) { + $val = null; + } + $this->relationDefine[$relation] = $val; + } + + return $this; + } + + + private function loadRelation(array &$data, $muti = false) { + foreach ($this->relationDefine as $relation => $closure) { + $this->doload($relation, $data, $muti, $closure); } + } + + + private function doload($relation, &$data, $muti = false, callable $closure = null) { + if (method_exists($this, $relation)) { + $relation_param = call_user_func(array($this, $relation)); + list($type, $table, $foreign_key, $owner_key) = $relation_param; + if (self::MANY_TO_MANY == $type) { + $this->doManyToMany($relation, $relation_param, $data, $muti); + + return; + } + + $single = $this->isGetSingle($type); + + $foreign_vals = $this->getForeignVal($data, $owner_key, $muti); + + $second_table_data = $this->getSecondTableData($table, $foreign_key, $foreign_vals, $single, $closure); + if (!$muti) { + $data[$relation] = $second_table_data; + + return; + } + if ($single) { + $second_table_data = array($second_table_data); + } + $second_table_data = $this->groupBy($foreign_key, $second_table_data); + + foreach ($data as &$item) { + $relation_val = isset($second_table_data[$item[$owner_key]]) ? $second_table_data[$item[$owner_key]] : array(); + if ($single) { + $relation_val = count($relation_val) > 0 ? current($relation_val) : array(); + } + $item[$relation] = $relation_val; + } + } + } + + + private function doManyToMany($relation, $relation_param, &$data, $muti = false) { + list($type, $table, $foreign_key, $owner_key, $center_table, $center_foreign_key, $center_owner_key) + = $relation_param; + + $foreign_vals = $this->getForeignVal($data, $owner_key, $muti); + $three_table = table($table); + $nativeQuery = $three_table->getQuery(); + + $nativeQuery->from($three_table->getTableName(), 'three') + ->innerjoin($center_table, 'center') + ->on(array('center.' . $center_foreign_key => 'three.' . $foreign_key)) + ->select('center.*') + ->where('center.' . $center_owner_key, $foreign_vals); + + $three_table_data = $three_table->getall(); if (!$muti) { + $data[$relation] = $three_table_data; + + return; + } + + $three_table_data = $this->groupBy($center_owner_key, $three_table_data); + + foreach ($data as &$item) { + $three_val = isset($three_table_data[$item[$owner_key]]) ? $three_table_data[$item[$owner_key]] : array(); + $item[$relation] = $three_val; + } + } + + + private function isGetSingle($type) { + return in_array($type, array(self::ONE_TO_ONE, self::BELONGS_TO)) ? true : false; + } + + + private function getForeignVal($data, $owner_key, $muti = false) { + if (!$muti) { + return $data[$owner_key]; + } + + return array_map(function ($item) use ($owner_key) { + return $item[$owner_key]; + }, $data); + } + + + private function getSecondTableData($table, $foreign_key, $foreign_vals, $single = false, $closure = null) { + $table_instance = table($table)->where($foreign_key, $foreign_vals); + if ($closure) { + call_user_func($closure, $table_instance->getQuery()); } + if ($single) { + return $table_instance->get(); + } + + return $table_instance->getall(); + } + + + private function groupBy($key, $array) { + $result = array(); + + foreach ($array as $item) { + $val = $item[$key]; + if (isset($result[$val])) { + $result[$val][] = $item; + } else { + $result[$val] = array($item); + } + } + + return $result; + } + + + protected function hasOne($table, $foreign_key, $owner_key = false) { + return $this->relationArray(self::ONE_TO_ONE, $table, $foreign_key, $owner_key); + } + + + protected function hasMany($table, $foreign_key, $owner_key = false) { + return $this->relationArray(self::ONE_TO_MANY, $table, $foreign_key, $owner_key); + } + + + protected function belongsTo($table, $foreign_key, $owner_key = false) { + return $this->relationArray(self::BELONGS_TO, $table, $foreign_key, $owner_key); + } + + + protected function belongsMany($table, $foreign_key, $owner_key, $center_table, $center_foreign_key = false, + $center_owner_key = false) { + if (!$owner_key) { + $owner_key = $this->primaryKey; + } + if (!$center_foreign_key) { + $center_foreign_key = $foreign_key; + } + if (!$center_owner_key) { + $center_owner_key = $owner_key; + } + + return array(self::MANY_TO_MANY, $table, $foreign_key, $owner_key, $center_table, $center_foreign_key, $center_owner_key); + } + + + private function relationArray($type, $table, $foreign_key, $owner_key) { + if (!$owner_key) { + $owner_key = $this->primaryKey; + } + if (!in_array($type, array(self::ONE_TO_ONE, self::ONE_TO_MANY, self::BELONGS_TO), true)) { + trigger_error('不支持的关联类型'); + } + + return array($type, $table, $foreign_key, $owner_key); + } + + + public function getById($id, $uniacid = 0) { + $this->query->from($this->tableName)->where($this->primaryKey, $id); + if (!empty($uniacid)) { + $this->where('uniacid', $uniacid); + } + if (is_array($id)) { + return $this->getall(); + } + + return $this->get(); + } + + public function getcolumn($field = '') { + $data = $this->query->getcolumn($field); + + return $data; + } + + + public function where($condition, $parameters = array(), $operator = 'AND') { + $this->query->where($condition, $parameters, $operator); + + return $this; + } + + + public function whereor($condition, $parameters = array()) { + return $this->where($condition, $parameters, 'OR'); + } + + public function orderby($field, $direction = 'ASC') { + return $this->query->orderby($field, $direction); + } + + + public function save($replace = false) { + if ($this->query->hasWhere()) { + $result = $this->valid($this->attribute); + if (is_error($result)) { + return $result; + } + + return $this->query->update(); + } + + $this->appendDefault(); + $result = $this->valid($this->attribute); + if (is_error($result)) { + return $result; + } + + return $this->query->insert($replace); + } + + + public function delete() { + if ($this->query->hasWhere()) { + return $this->query->delete(); + } + + return false; + } + + private function doWhere($field, $params, $operator = 'AND') { + if (0 == $params) { + return $this; + } + $value = $params[0]; + if (count($params) > 1) { + $field = $field . ' ' . $params[1]; + } + $this->query->where($field, $value, $operator); + + return $this; + } + + + private function snake($value) { + $delimiter = '_'; + if (!ctype_lower($value)) { + $value = preg_replace('/\s+/u', '', ucwords($value)); + $value = strtolower(preg_replace('/(.)(?=[A-Z])/u', '$1' . $delimiter, $value)); + } + + return $value; + } + + + private function studly($value) { + $value = ucwords(str_replace(array('-', '_'), ' ', $value)); + + return str_replace(' ', '', $value); + } + + + public function __call($method, $params) { + $actions = array( + 'searchWith', + 'whereor', + 'where', + 'fill', + ); + foreach ($actions as $action) { + $fields = explode($action, $method); + if (count($fields) > 1 && empty($fields[0]) && !empty($fields[1])) { + $field = $this->snake($fields[1]); + switch ($action) { + case 'whereor': + return $this->doWhere($field, $params, 'OR'); + case 'fill': + $this->fill($field, $params[0]); + + return $this; + default: + return $this->doWhere($field, $params); + } + } + } + + return $this; + } +} \ No newline at end of file diff --git a/framework/class/uploadedfile.class.php b/framework/class/uploadedfile.class.php new file mode 100644 index 0000000..c022526 --- /dev/null +++ b/framework/class/uploadedfile.class.php @@ -0,0 +1,252 @@ +setError($errorStatus); + $this->setSize($size); + $this->setClientFilename($clientFilename); + $this->setClientMediaType($clientMediaType); + parent::__construct($streamOrFile); + if ($this->isOk()) { + $this->setStreamOrFile($streamOrFile); + } + } + + + private function setStreamOrFile($streamOrFile) { + if (is_string($streamOrFile)) { + $this->file = $streamOrFile; + } else { + throw new InvalidArgumentException( + 'Invalid stream or file provided for UploadedFile' + ); + } + } + + + private function setError($error) { + if (false === is_int($error)) { + throw new InvalidArgumentException( + 'Upload file error status must be an integer' + ); + } + + if (false === in_array($error, self::$errors)) { + throw new InvalidArgumentException( + 'Invalid error status for UploadedFile' + ); + } + + $this->error = $error; + } + + + private function setSize($size) { + if (false === is_int($size)) { + throw new InvalidArgumentException( + 'Upload file size must be an integer' + ); + } + + $this->size = $size; + } + + + private function isStringOrNull($param) { + return in_array(gettype($param), array('string', 'NULL')); + } + + + private function isStringNotEmpty($param) { + return is_string($param) && false === empty($param); + } + + + private function setClientFilename($clientFilename) { + if (false === $this->isStringOrNull($clientFilename)) { + throw new InvalidArgumentException( + 'Upload file client filename must be a string or null' + ); + } + + $this->clientFilename = $clientFilename; + } + + + private function setClientMediaType($clientMediaType) { + if (false === $this->isStringOrNull($clientMediaType)) { + throw new InvalidArgumentException( + 'Upload file client media type must be a string or null' + ); + } + + $this->clientMediaType = $clientMediaType; + } + + + public function isOk() { + return UPLOAD_ERR_OK === $this->error; + } + + + public function isMoved() { + return $this->moved; + } + + + private function validateActive() { + if (false === $this->isOk()) { + throw new RuntimeException('Cannot retrieve stream due to upload error'); + } + + if ($this->isMoved()) { + throw new RuntimeException('Cannot retrieve stream after it has already been moved'); + } + } + + public function moveTo($targetPath) { + $this->validateActive(); + if (false === $this->isStringNotEmpty($targetPath)) { + throw new InvalidArgumentException( + 'Invalid path provided for move operation; must be a non-empty string' + ); + } + + if ($this->file) { + $this->moved = 'cli' == php_sapi_name() + ? rename($this->file, $targetPath) + : move_uploaded_file($this->file, $targetPath); + } + + if (false === $this->moved) { + throw new RuntimeException( + sprintf('Uploaded file could not be moved to %s', $targetPath) + ); + } + } + + + public function getSize() { + return $this->size; + } + + + public function getError() { + return $this->error; + } + + + public function getClientFilename() { + return $this->clientFilename; + } + + + public function getClientMediaType() { + return $this->clientMediaType; + } + + + public function isImage() { + return $this->isOk() && in_array($this->clientMediaType, array()); + } + + + public function clientExtension() { + return pathinfo($this->getClientFilename(), PATHINFO_EXTENSION); + } + + + public function allowExt($ext) { + return $this->clientExtension() === $ext; + } + + + public function getContent() { + return file_get_contents($this->file); + } + + public static function createFromGlobal() { + $files = array(); + foreach ($_FILES as $key => $file) { + $createFiles = static::create($file); + $files[$key] = $createFiles; + } + + return $files; + } + + + private static function create($file) { + if (is_array($file['tmp_name'])) { + return static::createArrayFile($file); + } + + return static::createUploadedFile($file); + } + + + public static function createArrayFile($files) { + $data = array(); + foreach (array_keys($files['tmp_name']) as $key) { + $file = array( + 'tmp_name' => $files['tmp_name'][$key], + 'size' => $files['size'][$key], + 'error' => $files['error'][$key], + 'name' => $files['name'][$key], + 'type' => $files['type'][$key], + ); + $data[$key] = self::createUploadedFile($file); + } + + return $data; + } + + private static function createUploadedFile($value) { + $upfile = new static( + $value['tmp_name'], + $value['size'], + $value['error'], + $value['name'], + $value['type'] + ); + + return $upfile; + } +} diff --git a/framework/class/validator.class.php b/framework/class/validator.class.php new file mode 100644 index 0000000..b5b891f --- /dev/null +++ b/framework/class/validator.class.php @@ -0,0 +1,565 @@ + ':attribute 必须填写', + 'integer' => ':attribute必须是整数', + 'int' => ':attribute必须是整数', + 'numeric' => ':attribute必须是数字', + 'string' => ':attribute必须是字符串', + 'json' => ':attribute 必须是json', + 'array' => ':attribute必须是数组', + 'min' => ':attribute不能小于%s', + 'max' => ':attribute不能大于%s', + 'between' => ':attribute 必须在 %s %s 范围内', + 'size' => ':attribute 大小必须是 %s', + 'url' => ':attribute不是有效的url', 'email' => ':attribute不是有效的邮箱', + 'mobile' => ':attribute不是有效的手机号', + 'file' => ':attribute必须是一个文件', + 'image' => ':attribute必须是一个图片', + 'ip' => ':attribute不是有效的ip', + 'in' => ':attribute 必须在 %s 内', + 'notin' => ':attribute 不在 %s 内', + 'date' => ':attribute 必须是有效的日期', + 'after' => ':attribute 日期不能小于 %s', + 'before' => ':attribute 日期不能大于 %s', + 'regex' => ':attribute 不是有效的数据', 'same' => ':attribute 和 %s 不一致', 'bool' => ':attribute 必须是bool值', + 'path' => ':attribute 不是有效的路径', + ); + + private $custom = array(); + + private $rules = array(); + + private $messages = array(); + + private $data = array(); + + + private $errors = array(); + + public function __construct($data, $rules = array(), $messages = array()) + { + $this->data = $data; + $this->rules = $this->parseRule($rules); + $this->messages = $messages; + } + + public static function create($data, $rules, array $messages = array()) + { + return new self($data, $rules, $messages); + } + + + public function addRule($name, callable $callable) + { + if (!$name) { + throw new InvalidArgumentException('无效的参数'); + } + if (!is_callable($callable)) { + throw new InvalidArgumentException('无效的callable 对象'); + } + $this->custom[$name] = $callable; + } + + + public function isError() + { + return 0 !== count($this->errors); + } + + + public function error() + { + return $this->errors; + } + + + public function message() + { + $init = array(); + $errmsg = array_reduce($this->error(), function ($result, $value) { + return array_merge($result, array_values($value)); + }, $init); + + return implode(',', array_values($errmsg)); + } + + public function getData() + { + return $this->data; + } + + + protected function parseRule(array $rules) + { + $result = array(); + if (0 == count($rules)) { + throw new InvalidArgumentException('无效的rules'); + } + foreach ($rules as $key => $rule) { + $result[$key] = $this->parseSingleRule($rule); + } + + return $result; + } + + + protected function parseSingleRule($value) + { + if (is_string($value)) { + $rules = explode('|', $value); + $result = array(); + foreach ($rules as $dataKey => $rule) { + $kv = explode(':', $rule); + $params = array(); + if (count($kv) > 1) { + $params = explode(',', $kv[1]); + } + $result[] = array('name' => $kv[0], 'params' => $params); + } + + return $result; + } + if (is_array($value)) { + $value = array_map(function ($item) { + if (is_string($item)) { + $name_params = explode(':', $item); + $params = array(); + if (count($name_params) > 1) { + $params = explode(',', $name_params[1]); + } + + return array('name' => $name_params[0], 'params' => $params); + } + if (!is_array($item)) { + throw new InvalidArgumentException('无效的rule参数'); + } + $newitem = $item; + if (!isset($item['name'])) { + $newitem = array(); + $newitem['name'] = $newitem[0]; + $newitem['params'] = count($item) > 1 ? $item[1] : array(); + } + + return $newitem; + }, $value); + + return $value; + } + throw new InvalidArgumentException('无效的rule配置项'); + } + + private function getRules($key) + { + return isset($this->rules[$key]) ? $this->rules[$key] : array(); + } + + public function valid() + { + $this->errors = array(); + foreach ($this->data as $key => $value) { + $rules = $this->getRules($key); + foreach ($rules as $rule) { + $this->doValid($key, $value, $rule); + } + } + + return $this->isError() ? error(1, $this->message()) : error(0); + } + + + private function doSingle($callback, $dataKey, $value, $rule) + { + $valid = call_user_func($callback, $dataKey, $value, $rule['params']); + if (!$valid) { + $this->errors[$dataKey][$rule['name']] = $this->getMessage($dataKey, $rule); + + return false; + } + + return true; + } + + + private function doCustom($callback, $dataKey, $value, $rule) + { + $valid = call_user_func($callback, $dataKey, $value, $rule['params'], $this); + if (!$valid) { + $this->errors[$dataKey][$rule['name']] = $this->getMessage($dataKey, $rule); + + return false; + } + + return true; + } + + + private function doValid($dataKey, $value, $rule) + { + $ruleName = $rule['name']; + if (isset($this->defaults[$ruleName])) { + $callback = array($this, 'valid' . ucfirst($ruleName)); + + return $this->doSingle($callback, $dataKey, $value, $rule); + } + if (isset($this->custom[$ruleName])) { + $callback = $this->custom[$ruleName]; + + return $this->doCustom($callback, $dataKey, $value, $rule, $this); + } + throw new InvalidArgumentException('valid' . $rule['name'] . ' 方法未定义'); + } + + + private function getValue($key) + { + return isset($this->data[$key]) ? $this->data[$key] : null; + } + + protected function getMessage($dataKey, $rule) + { + $message = $this->getErrorMessage($dataKey, $rule['name']); + if ($message) { + $message = str_replace(':attribute', $dataKey, $message); + $message = vsprintf($message, $rule['params']); + } + + return $message; + } + + protected function getErrorMessage($dataKey, $ruleName) + { + $dr = $dataKey . '.' . $ruleName; + if ($this->messages[$dr]) { + return $this->messages[$dr]; + } + if (isset($this->messages[$dataKey])) { + return $this->messages[$dataKey]; + } + + return isset($this->defaults[$ruleName]) ? $this->defaults[$ruleName] : '错误'; + } + + + public function validRequired($key, $value, $params) + { + if (is_null($value)) { + return false; + } + + if (is_array($value)) { + return 0 != count($value); + } + + if (is_string($value)) { + return '' !== $value; + } + + return true; + } + + public function validInteger($key, $value, $params) + { + return false !== filter_var($value, FILTER_VALIDATE_INT); + } + + public function validInt($key, $value, $params) + { + return $this->validInteger($key, $value, $params); + } + + public function validNumeric($key, $value, $params) + { + return is_numeric($value); + } + + public function validString($key, $value, $params) + { + return is_string($value); + } + + public function validJson($key, $value, $params) + { + if (!is_scalar($value) && !method_exists($value, '__toString')) { + return false; + } + + json_decode($value); + + return JSON_ERROR_NONE === json_last_error(); + } + + + public function validArray($key, $value, $params) + { + return is_array($value); + } + + + public function validFile($key, $value, $params) + { + return is_file($value); + } + + public function validImage($key, $value, $params) + { + return $this->isImage($value); + } + + public function validEmail($key, $value, $params) + { + return filter_var($value, FILTER_VALIDATE_EMAIL); + } + + public function validMobile($key, $value, $params) + { + return $this->validRegex($key, $value, array('/^1[34578]\d{9}$/')); + } + + + public function validRegex($key, $value, $params) + { + $this->checkParams(1, $params, 'regex'); + + return preg_match($params[0], $value); + } + + + public function validIp($key, $value, $params) + { + if (!is_null($value)) { + return filter_var($value, FILTER_VALIDATE_IP); + } + + return false; + } + + + public function validSize($key, $value, $params) + { + $this->checkParams(1, $params, 'size'); + + return $this->getSize($key, $value) == $params[0]; + } + + + public function validMax($key, $value, $params) + { + $this->checkParams(1, $params, 'max'); + $size = $this->getSize($key, $value); + + return $size <= $params[0]; + } + + + public function validMin($key, $value, $params) + { + $this->checkParams(1, $params, 'min'); + $size = $this->getSize($key, $value); + + return $size >= $params[0]; + } + + public function validUrl($key, $value, $params) + { + if (!filter_var($value, FILTER_VALIDATE_URL)) { + return false; + } + + $parseData = parse_url($value); + $scheme = $parseData['scheme']; + $allowSchemes = array('http', 'https'); + if (!in_array($scheme, $allowSchemes)) { + return false; + } + if (!isset($parseData['host'])) { + return false; + } + $host = $parseData['host']; + if (strexists($host, '@')) { + return false; + } + $pattern = '/^(10|172|192|127)/'; + if (preg_match($pattern, $host)) { + return false; + } + + return parse_path($value); + } + + public function validDate($key, $value, $params) + { + return $this->checkDate($value); + } + + public function validIn($key, $value, $params) + { + if (is_array($params)) { + return in_array($value, $params, true); + } + + return false; + } + + public function validNotin($key, $value, $params) + { + return !$this->validIn($key, $value, $params); + } + + + public function validSame($key, $value, $params) + { + $this->checkParams(1, $params, 'same'); + $otherField = $params[0]; + $otherValue = isset($this->data[$otherField]) ? $this->data[$otherField] : null; + + return (is_string($value) || is_numeric($value)) && $value === $otherValue; + } + + public function validBetween($key, $value, $params) + { + $this->checkParams(2, $params, 'between'); + $size = $this->getSize($key, $value); + + return $size >= $params[0] && $size <= $params[1]; + } + + + public function validAfter($key, $value, $params) + { + $this->checkParams(1, $params, 'afterdate'); + $date = $params[0]; + return $this->compareDate($value, $date, '>'); + } + + + public function validBefore($key, $value, $params) + { + $this->checkParams(1, $params, 'beforedate'); + $date = $params[0]; + return $this->compareDate($value, $date, '<'); + } + + private function compareDate($value, $param, $operator = '=') + { + if (!$this->checkDate($param)) { + $param = $this->getValue($param); + } + if ($this->checkDate($value) && $this->checkDate($param)) { + $currentTime = $this->getDateTimestamp($value); + $paramTime = $this->getDateTimestamp($param); + + return $this->compare($currentTime, $paramTime, $operator); + } + + return false; + } + + + public function validBool($key, $value, $params) + { + $acceptable = array(true, false, 0, 1, '0', '1'); + + return in_array($value, $acceptable, true); + } + + + public function validPath($key, $value, $params) + { + return parse_path($value); + } + + protected function getSize($key, $value) + { + if (is_numeric($value)) { + return $value; + } elseif (is_array($value)) { + return count($value); + } elseif (is_file($value)) { + return filesize($value) / 1024; + } elseif ($value instanceof SplFileInfo) { + return $value->getSize() / 1024; + } elseif (is_string($value)) { + return mb_strlen($value); + } + + return false; + } + + private function isImage($value) + { + if (is_file($value)) { + $filename = $value; + if ($value instanceof SplFileInfo) { + $filename = $value->getFilename(); + } + if (is_string($filename)) { + $pathinfo = pathinfo($filename); + $extension = strtolower($pathinfo['extension']); + + return !empty($extension) && in_array($extension, array('jpg', 'jpeg', 'gif', 'png')); + } + } + + return false; + } + + private function mimeTypeIsImage($mimeType) + { + $imgMimeType = explode(',', static::IMG_MIMETYPE); + + return in_array($mimeType, $imgMimeType); + } + + + private function checkDate($value) + { + if ($value instanceof DateTimeInterface) { + return true; + } + if ((!is_string($value) && !is_numeric($value)) || false === strtotime($value)) { + return false; + } + $date = date_parse($value); + + return checkdate($date['month'], $date['day'], $date['year']); + } + + private function checkParams($count, $params, $ruleName) + { + if (count($params) != $count) { + throw new InvalidArgumentException("$ruleName 参数个数必须为 $count 个"); + } + } + + private function getDateTimestamp($date) + { + return $date instanceof DateTimeInterface ? $date->getTimestamp() : strtotime($date); + } + + + protected function compare($first, $second, $operator) + { + switch ($operator) { + case '<': + return $first < $second; + case '>': + return $first > $second; + case '<=': + return $first <= $second; + case '>=': + return $first >= $second; + case '=': + return $first == $second; + default: + throw new InvalidArgumentException(); + } + } +} diff --git a/framework/class/wesession.class.php b/framework/class/wesession.class.php new file mode 100644 index 0000000..7176f3f --- /dev/null +++ b/framework/class/wesession.class.php @@ -0,0 +1,206 @@ += 0) { + session_set_save_handler($sess, true); + } else { + session_set_save_handler( + array(&$sess, 'open'), + array(&$sess, 'close'), + array(&$sess, 'read'), + array(&$sess, 'write'), + array(&$sess, 'destroy'), + array(&$sess, 'gc') + ); + } + + return true; + } + + public function open($save_path, $session_name) + { + return true; + } + + public function close() + { + return true; + } + + + public function read($sessionid) + { + return ''; + } + + + public function write($sessionid, $data) + { + return true; + } + + + public function destroy($sessionid) + { + return true; + } + + + public function gc($expire) + { + return true; + } +} + +class WeSessionMemcache extends WeSession +{ + protected $session_name; + + protected function key($sessionid) + { + return $this->session_name . ':' . $sessionid; + } + + public function open($save_path, $session_name) + { + $this->session_name = $session_name; + + if ('memcache' != cache_type()) { + trigger_error('Memcache 扩展不可用或是服务未开启,请将 \$config[\'setting\'][\'memcache\'][\'session\'] 设置为0 '); + + return false; + } + + return true; + } + + public function read($sessionid) + { + $row = cache_read($this->key($sessionid)); + if (empty($row) || $row['expiretime'] < TIMESTAMP) { + return ''; + } + if (is_array($row) && !empty($row['data'])) { + return $row['data']; + } + + return ''; + } + + public function write($sessionid, $data) + { + $row = array(); + $row['data'] = $data; + $row['uniacid'] = WeSession::$uniacid; + $row['openid'] = WeSession::$openid; + $row['expiretime'] = TIMESTAMP + WeSession::$expire; + + return cache_write($this->key($sessionid), $row); + } + + public function destroy($sessionid) + { + return cache_write($this->key($sessionid), ''); + } +} + +class WeSessionRedis extends WeSessionMemcache +{ + public function open($save_path, $session_name) + { + $this->session_name = $session_name; + + if ('redis' != cache_type()) { + trigger_error('Redis 扩展不可用或是服务未开启,请将 \$config[\'setting\'][\'redis\'][\'session\'] 设置为0 '); + + return false; + } + + return true; + } +} + +class WeSessionMysql extends WeSession +{ + public function open($save_path, $session_name) + { + return true; + } + + public function read($sessionid) + { + $sql = 'SELECT * FROM ' . tablename('core_sessions') . ' WHERE `sid`=:sessid AND `expiretime`>:time'; + $params = array(); + $params[':sessid'] = $sessionid; + $params[':time'] = TIMESTAMP; + $row = pdo_fetch($sql, $params); + if (is_array($row) && !empty($row['data'])) { + return $row['data']; + } + + return ''; + } + + public function write($sessionid, $data) + { + $row = array(); + $row['sid'] = $sessionid; + $row['uniacid'] = WeSession::$uniacid; + $row['openid'] = WeSession::$openid; + $row['data'] = $data; + $row['expiretime'] = TIMESTAMP + WeSession::$expire; + + return pdo_insert('core_sessions', $row, true) >= 1; + } + + public function destroy($sessionid) + { + $row = array(); + $row['sid'] = $sessionid; + + return 1 == pdo_delete('core_sessions', $row); + } + + public function gc($expire) + { + $sql = 'DELETE FROM ' . tablename('core_sessions') . ' WHERE `expiretime`<:expire'; + + return 1 == pdo_query($sql, array(':expire' => TIMESTAMP)); + } +} \ No newline at end of file diff --git a/framework/const.inc.php b/framework/const.inc.php new file mode 100644 index 0000000..b811a82 --- /dev/null +++ b/framework/const.inc.php @@ -0,0 +1,293 @@ +func('file'); +define('CACHE_FILE_PATH', IA_ROOT . '/data/cache/'); + +function cache_read($key, $dir = '', $include = true) { + $key = str_replace(':', '@', $key); + $key = CACHE_FILE_PATH . $key; + if (!is_file($key)) { + return array(); + } + + return $include ? include $key : file_get_contents($key); +} + +function cache_write($key, $data, $dir = '') { + global $_W; + if (empty($key) || !isset($data)) { + return false; + } + $key = str_replace(':', '@', $key); + if (!is_string($data)) { + $data = "func('cache.' . cache_type()); + + +function cache_type() { + global $_W; + $cacher = $connect = ''; + $cache_type = strtolower($_W['config']['setting']['cache']); + + if (extension_loaded($cache_type)) { + $config = $_W['config']['setting'][$cache_type]; + if (!empty($config['server']) && !empty($config['port'])) { + if ('memcache' == $cache_type) { + $cacher = new Memcache(); + } elseif ('redis' == $cache_type) { + $cacher = new Redis(); + } + $connect = $cacher->connect($config['server'], $config['port']); + } + } + if (empty($cacher) || empty($connect)) { + $cache_type = 'mysql'; + } + + return $cache_type; +} + + +function cache_load($key, $unserialize = false) { + global $_W; + static $we7_cache; + + if (is_error($key)) { + trigger_error($key['message'], E_USER_WARNING); + + return false; + } + if (!empty($we7_cache[$key])) { + return $we7_cache[$key]; + } + $data = $we7_cache[$key] = cache_read($key); + if ('setting' == $key) { + $_W['setting'] = $data; + + return $_W['setting']; + } elseif ('modules' == $key) { + $_W['modules'] = $data; + + return $_W['modules']; + } elseif ('module_receive_enable' == $key && empty($data)) { + cache_build_module_subscribe_type(); + + return cache_read($key); + } else { + return $unserialize ? iunserializer($data) : $data; + } +} + +function &cache_global($key) { +} + + +function cache_system_key($cache_key) { + $cache_key_all = cache_key_all(); + + $params = array(); + $args = func_get_args(); + if (empty($args[1])) { + $args[1] = ''; + } + if (!is_array($args[1])) { + $cache_key = $cache_key_all['caches'][$cache_key]['key']; + preg_match_all('/\%([a-zA-Z\_\-0-9]+)/', $cache_key, $matches); + for ($i = 0; $i < func_num_args() - 1; ++$i) { + $cache_key = str_replace($matches[0][$i], $args[$i + 1], $cache_key); + } + + return 'we7:' . $cache_key; + } else { + $params = $args[1]; + } + + if (empty($params)) { + $res = preg_match_all('/([a-zA-Z\_\-0-9]+):/', $cache_key, $matches); + if ($res) { + $key = count($matches[1]) > 0 ? $matches[1][0] : $matches[1]; + } else { + $key = $cache_key; + } + if (empty($cache_key_all['caches'][$key])) { + return error(1, '缓存' . $key . ' 不存在!'); + } else { + $cache_info_key = $cache_key_all['caches'][$key]['key']; + preg_match_all('/\%([a-zA-Z\_\-0-9]+)/', $cache_info_key, $key_params); + preg_match_all('/\:([a-zA-Z\_\-0-9]+)/', $cache_key, $val_params); + + if (count($key_params[1]) != count($val_params[1])) { + foreach ($key_params[1] as $key => $val) { + if (in_array($val, array_keys($cache_key_all['common_params']))) { + $cache_info_key = str_replace('%' . $val, $cache_key_all['common_params'][$val], $cache_info_key); + unset($key_params[1][$key]); + } + } + + if (count($key_params[1]) == count($val_params[1])) { + $arr = array_combine($key_params[1], $val_params[1]); + foreach ($arr as $key => $val) { + if (preg_match('/\%' . $key . '/', $cache_info_key)) { + $cache_info_key = str_replace('%' . $key, $val, $cache_info_key); + } + } + } + + if (strexists($cache_info_key, '%')) { + return error(1, '缺少缓存参数或参数不正确!'); + } else { + return 'we7:' . $cache_info_key; + } + } else { + return 'we7:' . $cache_key; + } + } + } + + $cache_info = $cache_key_all['caches'][$cache_key]; + $cache_common_params = $cache_key_all['common_params']; + + if (empty($cache_info)) { + return error(2, '缓存 ' . $cache_key . ' 不存在!'); + } else { + $cache_key = $cache_info['key']; + } + + foreach ($cache_common_params as $param_name => $param_val) { + preg_match_all('/\%([a-zA-Z\_\-0-9]+)/', $cache_key, $matches); + if (in_array($param_name, $matches[1]) && !in_array($param_name, array_keys($params))) { + $params[$param_name] = $cache_common_params[$param_name]; + } + } + + if (is_array($params) && !empty($params)) { + foreach ($params as $key => $param) { + $cache_key = str_replace('%' . $key, $param, $cache_key); + } + + if (strexists($cache_key, '%')) { + return error(1, '缺少缓存参数或参数不正确!'); + } + } + + $cache_key = 'we7:' . $cache_key; + if (strlen($cache_key) > CACHE_KEY_LENGTH) { + trigger_error('Cache name is over the maximum length'); + } + + return $cache_key; +} + + +function cache_relation_keys($key) { + if (!is_string($key)) { + return $key; + } + + if (!strexists($key, 'we7:')) { + return array($key); + } + + $cache_param_values = explode(':', $key); + $cache_name = $cache_param_values[1]; + unset($cache_param_values[0]); + unset($cache_param_values[1]); + + if (empty($cache_param_values)) { + preg_match_all('/\:([a-zA-Z\_\-0-9]+)/', $key, $matches); + $cache_name = $matches[1][0]; + } + + $cache_key_all = cache_key_all(); + $cache_relations = $cache_key_all['groups']; + $cache_common_params = $cache_key_all['common_params']; + $cache_info = $cache_key_all['caches'][$cache_name]; + if (empty($cache_info)) { + return error(2, '缓存 : ' . $key . '不存在'); + } + + if (!empty($cache_info['group'])) { + if (empty($cache_relations[$cache_info['group']])) { + return error(1, '关联关系未定义'); + } + $relation_keys = $cache_relations[$cache_info['group']]['relations']; + $cache_keys = array(); + foreach ($relation_keys as $key => $val) { + if ($val == $cache_name) { + $relation_cache_key = $cache_key_all['caches'][$val]['key']; + } else { + $relation_cache_key = $cache_key_all['caches'][$cache_name]['key']; + } + foreach ($cache_common_params as $param_name => $param_val) { + preg_match_all('/\%([a-zA-Z\_\-0-9]+)/', $relation_cache_key, $matches); + if (in_array($param_name, $matches[1])) { + $cache_key_params[$param_name] = $cache_common_params[$param_name]; + } + if (!empty($cache_prams_values) || count($matches[1]) == count($cache_param_values)) { + $cache_key_params = array_combine($matches[1], $cache_param_values); + } else { + $cache_key_params = array(); + } + } + + $cache_key = cache_system_key($val, $cache_key_params); + if (!is_error($cache_key)) { + $cache_keys[] = $cache_key; + } else { + return error(1, $cache_key['message']); + } + } + } else { + $cache_keys[] = $key; + } + + return $cache_keys; +} + + +function cache_key_all() { + global $_W; + $caches_all = array( + 'common_params' => array( + 'uniacid' => $_W['uniacid'], + 'uid' => $_W['uid'], + ), + + 'caches' => array( + 'module_info' => array( + 'key' => 'module_info:%module_name', + 'group' => 'module', + ), + + 'module_main_info' => array( + 'key' => 'module_main_info:%module_name', + 'group' => 'module', + ), + + 'module_setting' => array( + 'key' => 'module_setting:%module_name:%uniacid', + 'group' => 'module', + ), + + 'last_account' => array( + 'key' => 'last_account:%switch:%uid', + 'group' => '', + ), + + 'last_account_type' => array( + 'key' => 'last_account_type', + 'group' => '', + ), + + 'user_modules' => array( + 'key' => 'user_modules:%uid', + 'group' => '', + ), + + 'user_accounts' => array( + 'key' => 'user_accounts:%type:%uid', + 'group' => '', + ), + + 'unimodules' => array( + 'key' => 'unimodules:%uniacid', + 'group' => '', + ), + + 'unimodules_binding' => array( + 'key' => 'unimodules_binding:%uniacid', + 'group' => '', + ), + + 'uni_groups' => array( + 'key' => 'uni_groups:%groupids', + 'group' => '', + ), + + 'permission' => array( + 'key' => 'permission:%uniacid:%uid', + 'group' => '', + ), + + 'memberinfo' => array( + 'key' => 'memberinfo:%uid', + 'group' => '', + ), + + 'statistics' => array( + 'key' => 'statistics:%uniacid', + 'group' => '', + ), + + 'uniacid_visit' => array( + 'key' => 'uniacid_visit:%uniacid:%today', + 'group' => '', + ), + + 'material_reply' => array( + 'key' => 'material_reply:%attach_id', + 'group' => '', + ), + + 'keyword' => array( + 'key' => 'keyword:%content:%uniacid', + 'group' => '', + ), + + 'back_days' => array( + 'key' => 'back_days', + 'group' => '', + ), + + 'miniapp_version' => array( + 'key' => 'miniapp_version:%version_id', + 'group' => '', + ), + + 'site_store_buy' => array( + 'key' => 'site_store_buy:%type:%uniacid', + 'group' => '', + ), + + 'proxy_wechatpay_account' => array( + 'key' => 'proxy_wechatpay_account', + 'group' => '', + ), + + 'recycle_module' => array( + 'key' => 'recycle_module', + 'group' => '', + ), + 'random' => array( + 'key' => 'random', + 'group' => '', + ), + 'sync_fans_pindex' => array( + 'key' => 'sync_fans_pindex:%uniacid', + 'group' => '', + ), + + 'uniaccount' => array( + 'key' => 'uniaccount:%uniacid', + 'group' => 'uniaccount', + ), + + 'unisetting' => array( + 'key' => 'unisetting:%uniacid', + 'group' => 'uniaccount', + ), + + 'defaultgroupid' => array( + 'key' => 'defaultgroupid:%uniacid', + 'group' => 'uniaccount', + ), + + 'uniaccount_type' => array( + 'key' => 'uniaccount_type:%account_type', + 'group' => '', + ), + + + 'accesstoken' => array( + 'key' => 'accesstoken:%uniacid', + 'group' => 'accesstoken', + ), + + 'jsticket' => array( + 'key' => 'jsticket:%uniacid', + 'group' => 'accesstoken', + ), + + 'cardticket' => array( + 'key' => 'cardticket:%uniacid', + 'group' => 'accesstoken', + ), + + + 'accesstoken_key' => array( + 'key' => 'accesstoken_key:%key', + 'group' => '', + ), + + 'account_oauth_refreshtoken' => array( + 'key' => 'account_oauth_refreshtoken:%acid', + 'group' => '', + ), + + 'account_auth_refreshtoken' => array( + 'key' => 'account_auth_refreshtoken:%uniacid', + 'group' => '', + ), + + 'account_tags' => array( + 'key' => 'account_tags:%uniacid', + 'group' => '', + ), + + 'unicount' => array( + 'key' => 'unicount:%uniacid', + 'group' => '', + ), + + 'checkupgrade' => array( + 'key' => 'checkupgrade', + 'group' => '', + ), + + 'cloud_transtoken' => array( + 'key' => 'cloud_transtoken', + 'group' => '', + ), + 'cloud_w7_request_token' => array( + 'key' => 'cloud_w7_request_token', + 'group' => '', + ), + + 'upgrade' => array( + 'key' => 'upgrade', + 'group' => '', + ), + + 'account_ticket' => array( + 'key' => 'account_ticket', + 'group' => '', + ), + + 'oauthaccesstoken' => array( + 'key' => 'oauthaccesstoken:%acid', + 'group' => '', + ), + + 'account_component_assesstoken' => array( + 'key' => 'account_component_assesstoken', + 'group' => '', + ), + 'cloud_api' => array( + 'key' => 'cloud_api:%method', + 'group' => '', + ), + 'cloud_ad_uniaccount' => array( + 'key' => 'cloud_ad_uniaccount:%uniacid', + 'group' => '', + ), + + 'cloud_ad_uniaccount_list' => array( + 'key' => 'cloud_ad_uniaccount_list', + 'group' => '', + ), + + 'cloud_flow_master' => array( + 'key' => 'cloud_flow_master', + 'group' => '', + ), + + 'cloud_ad_tags' => array( + 'key' => 'cloud_ad_tags', + 'group' => '', + ), + + 'cloud_ad_type_list' => array( + 'key' => 'cloud_ad_type_list', + 'group' => '', + ), + + 'cloud_ad_app_list' => array( + 'key' => 'cloud_ad_app_list:%uniacid', + 'group' => '', + ), + + 'cloud_ad_app_support_list' => array( + 'key' => 'cloud_ad_app_support_list', + 'group' => '', + ), + + 'cloud_ad_site_finance' => array( + 'key' => 'cloud_ad_site_finance', + 'group' => '', + ), + + 'cloud_ad_store_notice' => array( + 'key' => 'cloud_ad_store_notice', + 'group' => '', + ), + 'cloud_file_permission_pass' => array( + 'key' => 'cloud_file_permission_pass', + 'group' => '', + ), + + 'couponsync' => array( + 'key' => 'couponsync:%uniacid', + 'group' => '', + ), + + 'storesync' => array( + 'key' => 'storesync:%uniacid', + 'group' => '', + ), + + 'cloud_auth_transfer' => array( + 'key' => 'cloud_auth_transfer', + 'group' => '', + ), + + 'modulesetting' => array( + 'key' => 'modulesetting:%module:%acid', + 'group' => '', + ), + + 'scan_config' => array( + 'key' => 'scan_config', + 'group' => 'scan_file', + ), + + 'scan_file' => array( + 'key' => 'scan_file', + 'group' => 'scan_file', + ), + + 'scan_badfile' => array( + 'key' => 'scan_badfile', + 'group' => 'scan_file', + ), + + 'bomtree' => array( + 'key' => 'bomtree', + 'group' => '', + ), + + 'setting' => array( + 'key' => 'setting', + 'group' => '', + ), + + 'stat_todaylock' => array( + 'key' => 'stat_todaylock:%uniacid', + 'group' => '', + ), + + 'account_preauthcode' => array( + 'key' => 'account_preauthcode', + 'group' => '', + ), + + 'account_auth_accesstoken' => array( + 'key' => 'account_auth_accesstoken:%key', + 'group' => '', + ), + + 'usersfields' => array( + 'key' => 'usersfields', + 'group' => '', + ), + + 'userbasefields' => array( + 'key' => 'userbasefields', + 'group' => '', + ), + + 'system_frame' => array( + 'key' => 'system_frame:%uniacid', + 'group' => '', + ), + + 'module_receive_enable' => array( + 'key' => 'module_receive_enable', + 'group' => '', + ), + + 'module_entry_call' => array( + 'key' => 'module_entry_call:%module_name', + 'group' => '', + ), + + 'system_check' => array( + 'key' => 'system_check', + 'group' => '', + ), + + 'delete_visit_ip' => array( + 'key' => 'delete_visit_ip:%date', + 'group' => '', + ), + ), + 'groups' => array( + 'uniaccount' => array( + 'relations' => array('uniaccount', 'unisetting', 'defaultgroupid'), + ), + + 'accesstoken' => array( + 'relations' => array('accesstoken', 'jsticket', 'cardticket'), + ), + + 'scan_file' => array( + 'relations' => array('scan_file', 'scan_config', 'scan_badfile'), + ), + + 'module' => array( + 'relations' => array('module_info', 'module_setting', 'module_main_info'), + ), + ), + ); + + return $caches_all; +} diff --git a/framework/function/cache.memcache.func.php b/framework/function/cache.memcache.func.php new file mode 100644 index 0000000..4f45409 --- /dev/null +++ b/framework/function/cache.memcache.func.php @@ -0,0 +1,169 @@ +pconnect($config['server'], $config['port']); + } else { + $connect = $memcacheobj->connect($config['server'], $config['port']); + } + if (!$connect) { + return error(-1, 'Memcache is not in work'); + } + } + + return $memcacheobj; +} + + +function cache_read($key, $forcecache = true) { + $key = cache_namespace($key); + + $memcache = cache_memcache(); + if (is_error($memcache)) { + return $memcache; + } + $result = $memcache->get(cache_prefix($key)); + if (empty($result) && empty($forcecache)) { + $dbcache = pdo_get('core_cache', array('key' => $key), array('value')); + if (!empty($dbcache['value'])) { + $result = iunserializer($dbcache['value']); + $memcache->set(cache_prefix($key), $result); + } + } + + return $result; +} + + +function cache_search($key) { + return cache_read(cache_prefix($key)); +} + + +function cache_write($key, $value, $ttl = 0, $forcecache = true) { + $key = cache_namespace($key); + $memcache = cache_memcache(); + if (is_error($memcache)) { + return $memcache; + } + if (empty($forcecache)) { + $record = array(); + $record['key'] = $key; + $record['value'] = iserializer($value); + pdo_insert('core_cache', $record, true); + } + if ($memcache->set(cache_prefix($key), $value, MEMCACHE_COMPRESSED, $ttl)) { + return true; + } else { + return false; + } +} + + +function cache_delete($key, $forcecache = true) { + $memcache = cache_memcache(); + if (is_error($memcache)) { + return $memcache; + } + $cache_relation_keys = cache_relation_keys($key); + if (is_error($cache_relation_keys)) { + return $cache_relation_keys; + } + if (is_array($cache_relation_keys) && !empty($cache_relation_keys)) { + foreach ($cache_relation_keys as $key) { + $cache_info = cache_load($key); + if (!empty($cache_info)) { + $origins_cache_key = $key; + $key = cache_namespace($key); + if (empty($forcecache)) { + pdo_delete('core_cache', array('key' => $key)); + } + $result = $memcache->delete(cache_prefix($key)); + unset($GLOBALS['_W']['cache'][$origins_cache_key]); + if (!$result) { + return error(1, '缓存: ' . $key . ' 删除失败!'); + } + } + } + } + + return true; +} + + +function cache_clean($prefix = '') { + if (!empty($prefix)) { + $cache_relation_keys = cache_relation_keys($prefix); + if (is_error($cache_relation_keys)) { + return $cache_relation_keys; + } + if (is_array($cache_relation_keys) && !empty($cache_relation_keys)) { + foreach ($cache_relation_keys as $key) { + preg_match_all('/\:([a-zA-Z0-9\-\_]+)/', $key, $matches); + $cache_namespace = cache_namespace('we7:' . $matches[1][0]); + pdo_delete('core_cache', array('key LIKE' => $cache_namespace . '%')); + unset($GLOBALS['_W']['cache']); + cache_namespace('we7:' . $matches[1][0], true); + } + } + + return true; + } + $memcache = cache_memcache(); + if (is_error($memcache)) { + return $memcache; + } + if ($memcache->flush()) { + unset($GLOBALS['_W']['cache']); + pdo_delete('core_cache'); + + return true; + } else { + return false; + } +} + + +function cache_namespace($key, $forcenew = false) { + if (!strexists($key, ':')) { + $namespace_cache_key = $key; + } else { + list($key1, $key2) = explode(':', $key); + if ('we7' == $key1) { + $namespace_cache_key = $key2; + } else { + $namespace_cache_key = $key1; + } + } + if (!in_array($namespace_cache_key, array('unimodules', 'user_modules', 'system_frame'))) { + return $key; + } + + $namespace_cache_key = 'cachensl:' . $namespace_cache_key; + $memcache = cache_memcache(); + if (is_error($memcache)) { + return $memcache; + } + $namespace = $memcache->get(cache_prefix($namespace_cache_key)); + if (empty($namespace) || $forcenew) { + $namespace = random(5); + $memcache->set(cache_prefix($namespace_cache_key), $namespace, MEMCACHE_COMPRESSED, 0); + } + + return $namespace . ':' . $key; +} + +function cache_prefix($key) { + return $GLOBALS['_W']['config']['setting']['authkey'] . $key; +} \ No newline at end of file diff --git a/framework/function/cache.mysql.func.php b/framework/function/cache.mysql.func.php new file mode 100644 index 0000000..38a5ca0 --- /dev/null +++ b/framework/function/cache.mysql.func.php @@ -0,0 +1,112 @@ + $key), 'value'); + if (empty($cachedata)) { + return ''; + } + $cachedata = iunserializer($cachedata); + if (is_array($cachedata) && !empty($cachedata['expire']) && false !== $cachedata['data']) { + if ($cachedata['expire'] > TIMESTAMP) { + return $cachedata['data']; + } else { + return ''; + } + } else { + return $cachedata; + } +} + + +function cache_search($prefix) { + $sql = 'SELECT * FROM ' . tablename('core_cache') . ' WHERE `key` LIKE :key'; + $params = array(); + $params[':key'] = "{$prefix}%"; + $rs = pdo_fetchall($sql, $params); + $result = array(); + foreach ((array) $rs as $v) { + $result[$v['key']] = iunserializer($v['value']); + } + + return $result; +} + + +function cache_write($key, $data, $expire = 0) { + if (empty($key) || !isset($data)) { + return false; + } + + $record = array(); + $record['key'] = $key; + if (!empty($expire)) { + $cache_data = array( + 'expire' => TIMESTAMP + $expire, + 'data' => $data, + ); + } else { + $cache_data = $data; + } + $record['value'] = iserializer($cache_data); + + return pdo_insert('core_cache', $record, true); +} + + +function cache_delete($key) { + $cache_relation_keys = cache_relation_keys($key); + if (is_error($cache_relation_keys)) { + return $cache_relation_keys; + } + if (is_array($cache_relation_keys) && !empty($cache_relation_keys)) { + foreach ($cache_relation_keys as $key) { + $cache_info = cache_load($key); + if (!empty($cache_info)) { + $sql = 'DELETE FROM ' . tablename('core_cache') . ' WHERE `key`=:key'; + $params = array(); + $params[':key'] = $key; + $result = pdo_query($sql, $params); + if (!$result) { + return error(1, '缓存:' . $key . ' 删除失败!'); + } + } + } + + return true; + } +} + + +function cache_clean($prefix = '') { + global $_W; + if (empty($prefix)) { + $sql = 'DELETE FROM ' . tablename('core_cache'); + $result = pdo_query($sql); + if ($result) { + unset($_W['cache']); + } + } else { + $cache_relation_keys = cache_relation_keys($prefix); + if (is_error($cache_relation_keys)) { + return $cache_relation_keys; + } + + if (is_array($cache_relation_keys) && !empty($cache_relation_keys)) { + foreach ($cache_relation_keys as $key) { + preg_match_all('/\:([a-zA-Z0-9\-\_]+)/', $key, $matches); + $sql = 'DELETE FROM ' . tablename('core_cache') . ' WHERE `key` LIKE :key'; + $params = array(); + $params[':key'] = "we7:{$matches[1][0]}%"; + $result = pdo_query($sql, $params); + if (!$result) { + return error(-1, '缓存 ' . $key . '删除失败!'); + } + } + } + } + + return true; +} diff --git a/framework/function/cache.redis.func.php b/framework/function/cache.redis.func.php new file mode 100644 index 0000000..a494dec --- /dev/null +++ b/framework/function/cache.redis.func.php @@ -0,0 +1,153 @@ +pconnect($config['server'], $config['port']); + } else { + $connect = $redisobj->connect($config['server'], $config['port']); + } + if (!empty($config['requirepass'])) { + $auth = $redisobj->auth($config['requirepass']); + } + } catch (Exception $e) { + return error(-1, 'redis连接失败,错误信息:' . $e->getMessage()); + } + } + if (defined('IN_MODULE') && !empty($config['db']) && is_array($config['db']) && in_array(IN_MODULE, array_keys($config['db']))) { + $redisobj->select($config['db'][IN_MODULE]); + } + return $redisobj; +} + + +function cache_read($key) { + + $redis = cache_redis(); + if (is_error($redis)) { + return $redis; + } + if ($redis->exists(cache_prefix($key))) { + $data = $redis->get(cache_prefix($key)); + $data = iunserializer($data); + + return $data; + } + + return ''; +} + + +function cache_search($key) { + $redis = cache_redis(); + if (is_error($redis)) { + return $redis; + } + $search_keys = $redis->keys(cache_prefix($key) . '*'); + $search_data = array(); + if (!empty($search_keys)) { + foreach ($search_keys as $search_key => $search_value) { + $search_data[$search_value] = iunserializer($redis->get($search_value)); + } + } + + return $search_data; +} + + +function cache_write($key, $value, $ttl = CACHE_EXPIRE_LONG) { + $redis = cache_redis(); + if (is_error($redis)) { + return $redis; + } + $value = iserializer($value); + if ($redis->set(cache_prefix($key), $value, $ttl)) { + return true; + } + + return false; +} + + +function cache_delete($key) { + $redis = cache_redis(); + if (is_error($redis)) { + return $redis; + } + + $cache_relation_keys = cache_relation_keys($key); + if (is_error($cache_relation_keys)) { + return $cache_relation_keys; + } + if (is_array($cache_relation_keys) && !empty($cache_relation_keys)) { + foreach ($cache_relation_keys as $key) { + $cache_info = cache_load($key); + if (!empty($cache_info)) { + if (method_exists($redis, 'del')) { + $result = $redis->del(cache_prefix($key)); + } else { + $result = $redis->delete(cache_prefix($key)); + } + if ($result) { + unset($GLOBALS['_W']['cache'][$key]); + } else { + return error(1, '缓存:' . $key . ' 删除失败!'); + } + } + } + } + + return true; +} + + +function cache_clean($key = '') { + $redis = cache_redis(); + if (is_error($redis)) { + return $redis; + } + if (!empty($key)) { + $cache_relation_keys = cache_relation_keys($key); + if (is_error($cache_relation_keys)) { + return $cache_relation_keys; + } + + if (is_array($cache_relation_keys) && !empty($cache_relation_keys)) { + foreach ($cache_relation_keys as $key) { + preg_match_all('/\:([a-zA-Z0-9\-\_]+)/', $key, $matches); + if ($keys = $redis->keys(cache_prefix('we7:' . $matches[1][0]) . '*')) { + unset($GLOBALS['_W']['cache']); + $res = $redis->delete($keys); + if (!$res) { + return error(-1, '缓存 ' . $key . ' 删除失败'); + } + } + } + } + + return true; + } + if ($redis->flushDB()) { + unset($GLOBALS['_W']['cache']); + + return true; + } + + return false; +} + + +function cache_prefix($key) { + return $GLOBALS['_W']['config']['setting']['authkey'] . $key; +} diff --git a/framework/function/communication.func.php b/framework/function/communication.func.php new file mode 100644 index 0000000..301eccd --- /dev/null +++ b/framework/function/communication.func.php @@ -0,0 +1,500 @@ + 0) { + $ch = ihttp_build_curl($url, $post, $extra, $timeout); + if (is_error($ch)) { + return $ch; + } + $data = curl_exec($ch); + $status = curl_getinfo($ch); + $errno = curl_errno($ch); + $error = curl_error($ch); + curl_close($ch); + if ($errno || empty($data)) { + return error($errno, $error); + } else { + return ihttp_response_parse($data); + } + } + $urlset = ihttp_parse_url($url, true); + if (!empty($urlset['ip'])) { + $urlset['host'] = $urlset['ip']; + } + + $body = ihttp_build_httpbody($url, $post, $extra); + + if ('https' == $urlset['scheme']) { + $fp = ihttp_socketopen('ssl://' . $urlset['host'], $urlset['port'], $errno, $error); + } else { + $fp = ihttp_socketopen($urlset['host'], $urlset['port'], $errno, $error); + } + stream_set_blocking($fp, $timeout > 0 ? true : false); + stream_set_timeout($fp, ini_get('default_socket_timeout')); + if (!$fp) { + return error(1, $error); + } else { + fwrite($fp, $body); + $content = ''; + if ($timeout > 0) { + while (!feof($fp)) { + $content .= fgets($fp, 512); + } + } + fclose($fp); + + return ihttp_response_parse($content, true); + } +} + + +function ihttp_get($url) { + return ihttp_request($url); +} + + +function ihttp_post($url, $data) { + $headers = array('Content-Type' => 'application/x-www-form-urlencoded'); + + return ihttp_request($url, $data, $headers); +} + + +function ihttp_multi_request($urls, $posts = array(), $extra = array(), $timeout = 60) { + if (!is_array($urls)) { + return error(1, '请使用ihttp_request函数'); + } + $curl_multi = curl_multi_init(); + $curl_client = $response = array(); + + foreach ($urls as $i => $url) { + if (isset($posts[$i]) && is_array($posts[$i])) { + $post = $posts[$i]; + } else { + $post = $posts; + } + if (!empty($url)) { + $curl = ihttp_build_curl($url, $post, $extra, $timeout); + if (is_error($curl)) { + continue; + } + if (CURLM_OK === curl_multi_add_handle($curl_multi, $curl)) { + $curl_client[] = $curl; + } + } + } + if (!empty($curl_client)) { + $active = null; + do { + $mrc = curl_multi_exec($curl_multi, $active); + } while (CURLM_CALL_MULTI_PERFORM == $mrc); + + while ($active && CURLM_OK == $mrc) { + do { + $mrc = curl_multi_exec($curl_multi, $active); + } while (CURLM_CALL_MULTI_PERFORM == $mrc); + } + } + + foreach ($curl_client as $i => $curl) { + $response[$i] = curl_multi_getcontent($curl); + curl_multi_remove_handle($curl_multi, $curl); + } + curl_multi_close($curl_multi); + + return $response; +} + +function ihttp_socketopen($hostname, $port = 80, &$errno, &$errstr, $timeout = 15) { + $fp = ''; + if (function_exists('fsockopen')) { + $fp = @fsockopen($hostname, $port, $errno, $errstr, $timeout); + } elseif (function_exists('pfsockopen')) { + $fp = @pfsockopen($hostname, $port, $errno, $errstr, $timeout); + } elseif (function_exists('stream_socket_client')) { + $fp = @stream_socket_client($hostname . ':' . $port, $errno, $errstr, $timeout); + } + + return $fp; +} + + +function ihttp_response_parse($data, $chunked = false) { + $rlt = array(); + + $pos = strpos($data, "\r\n\r\n"); + $split1[0] = substr($data, 0, $pos); + $split1[1] = substr($data, $pos + 4, strlen($data)); + + $split2 = explode("\r\n", $split1[0], 2); + preg_match('/^(\S+) (\S+) (.*)$/', $split2[0], $matches); + $rlt['code'] = !empty($matches[2]) ? $matches[2] : 200; + $rlt['status'] = !empty($matches[3]) ? $matches[3] : 'OK'; + $rlt['responseline'] = !empty($split2[0]) ? $split2[0] : ''; + $header = explode("\r\n", $split2[1]); + $isgzip = false; + $ischunk = false; + foreach ($header as $v) { + $pos = strpos($v, ':'); + $key = substr($v, 0, $pos); + $value = trim(substr($v, $pos + 1)); + if (isset($rlt['headers'][$key]) && is_array($rlt['headers'][$key])) { + $rlt['headers'][$key][] = $value; + } elseif (!empty($rlt['headers'][$key])) { + $temp = $rlt['headers'][$key]; + unset($rlt['headers'][$key]); + $rlt['headers'][$key][] = $temp; + $rlt['headers'][$key][] = $value; + } else { + $rlt['headers'][$key] = $value; + } + if (!$isgzip && 'content-encoding' == strtolower($key) && 'gzip' == strtolower($value)) { + $isgzip = true; + } + if (!$ischunk && 'transfer-encoding' == strtolower($key) && 'chunked' == strtolower($value)) { + $ischunk = true; + } + } + if ($chunked && $ischunk) { + $rlt['content'] = ihttp_response_parse_unchunk($split1[1]); + } else { + $rlt['content'] = $split1[1]; + } + if ($isgzip && function_exists('gzdecode')) { + $rlt['content'] = gzdecode($rlt['content']); + } + + $rlt['meta'] = $data; + if ('100' == $rlt['code']) { + return ihttp_response_parse($rlt['content']); + } + + return $rlt; +} + +function ihttp_response_parse_unchunk($str = null) { + if (!is_string($str) or strlen($str) < 1) { + return false; + } + $eol = "\r\n"; + $add = strlen($eol); + $tmp = $str; + $str = ''; + do { + $tmp = ltrim($tmp); + $pos = strpos($tmp, $eol); + if (false === $pos) { + return false; + } + $len = hexdec(substr($tmp, 0, $pos)); + if (!is_numeric($len) or $len < 0) { + return false; + } + $str .= substr($tmp, ($pos + $add), $len); + $tmp = substr($tmp, ($len + $pos + $add)); + $check = trim($tmp); + } while (!empty($check)); + unset($tmp); + + return $str; +} + + +function ihttp_parse_url($url, $set_default_port = false) { + if (empty($url)) { + return error(1); + } + $urlset = parse_url($url); + if (!empty($urlset['scheme']) && !in_array($urlset['scheme'], array('http', 'https'))) { + return error(1, '只能使用 http 及 https 协议'); + } + if (empty($urlset['path'])) { + $urlset['path'] = '/'; + } + if (!empty($urlset['query'])) { + $urlset['query'] = "?{$urlset['query']}"; + } + if (strexists($url, 'https://') && !extension_loaded('openssl')) { + if (!extension_loaded('openssl')) { + return error(1, '请开启您PHP环境的openssl', ''); + } + } + if (empty($urlset['host'])) { + $current_url = parse_url($GLOBALS['_W']['siteroot']); + $urlset['host'] = $current_url['host']; + $urlset['scheme'] = $current_url['scheme']; + $urlset['path'] = $current_url['path'] . 'web/' . str_replace('./', '', $urlset['path']); + $urlset['ip'] = '127.0.0.1'; + } elseif (!ihttp_allow_host($urlset['host'])) { + return error(1, 'host 非法'); + } + + if ($set_default_port && empty($urlset['port'])) { + $urlset['port'] = 'https' == $urlset['scheme'] ? '443' : '80'; + } + + return $urlset; +} + + +function ihttp_allow_host($host) { + global $_W; + if (strexists($host, '@')) { + return false; + } + $pattern = '/^(10|172|192|127)/'; + if (preg_match($pattern, $host) && isset($_W['setting']['ip_white_list'])) { + $ip_white_list = $_W['setting']['ip_white_list']; + if ($ip_white_list && isset($ip_white_list[$host]) && !$ip_white_list[$host]['status']) { + return false; + } + } + + return true; +} + + +function ihttp_build_curl($url, $post, $extra, $timeout) { + if (!function_exists('curl_init') || !function_exists('curl_exec')) { + return error(1, 'curl扩展未开启'); + } + + $urlset = ihttp_parse_url($url); + if (is_error($urlset)) { + return $urlset; + } + + if (!empty($urlset['ip'])) { + $extra['ip'] = $urlset['ip']; + } + + $ch = curl_init(); + if (!empty($extra['ip'])) { + $extra['Host'] = $urlset['host']; + $urlset['host'] = $extra['ip']; + unset($extra['ip']); + } + curl_setopt($ch, CURLOPT_URL, $urlset['scheme'] . '://' . $urlset['host'] . (empty($urlset['port']) || '80' == $urlset['port'] ? '' : ':' . $urlset['port']) . $urlset['path'] . (!empty($urlset['query']) ? $urlset['query'] : '')); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + @curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); + curl_setopt($ch, CURLOPT_HEADER, 1); + @curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + if ($post) { + if (is_array($post)) { + $filepost = false; + foreach ($post as $name => &$value) { + if (version_compare(phpversion(), '5.5') >= 0 && is_string($value) && '@' == substr($value, 0, 1)) { + $post[$name] = new CURLFile(ltrim($value, '@')); + } + if ((is_string($value) && '@' == substr($value, 0, 1)) || (class_exists('CURLFile') && $value instanceof CURLFile)) { + $filepost = true; + } + } + if (!$filepost) { + $post = http_build_query($post); + } + } + curl_setopt($ch, CURLOPT_POST, 1); + curl_setopt($ch, CURLOPT_POSTFIELDS, $post); + } + if (!empty($GLOBALS['_W']['config']['setting']['proxy'])) { + $urls = parse_url($GLOBALS['_W']['config']['setting']['proxy']['host']); + if (!empty($urls['host'])) { + curl_setopt($ch, CURLOPT_PROXY, "{$urls['host']}:{$urls['port']}"); + $proxytype = 'CURLPROXY_' . strtoupper($urls['scheme']); + if (!empty($urls['scheme']) && defined($proxytype)) { + curl_setopt($ch, CURLOPT_PROXYTYPE, constant($proxytype)); + } else { + curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_HTTP); + curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, 1); + } + if (!empty($GLOBALS['_W']['config']['setting']['proxy']['auth'])) { + curl_setopt($ch, CURLOPT_PROXYUSERPWD, $GLOBALS['_W']['config']['setting']['proxy']['auth']); + } + } + } + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout); + curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); + curl_setopt($ch, CURLOPT_SSLVERSION, 1); + if (defined('CURL_SSLVERSION_TLSv1')) { + curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1); + } + curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:9.0.1) Gecko/20100101 Firefox/9.0.1'); + if (!empty($extra) && is_array($extra)) { + $headers = array(); + foreach ($extra as $opt => $value) { + if (strexists($opt, 'CURLOPT_')) { + curl_setopt($ch, constant($opt), $value); + } elseif (is_numeric($opt)) { + curl_setopt($ch, $opt, $value); + } else { + $headers[] = "{$opt}: {$value}"; + } + } + if (!empty($headers)) { + curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); + } + } + + return $ch; +} + +function ihttp_build_httpbody($url, $post, $extra) { + $urlset = ihttp_parse_url($url, true); + if (is_error($urlset)) { + return $urlset; + } + + if (!empty($urlset['ip'])) { + $extra['ip'] = $urlset['ip']; + } + + $body = ''; + if (!empty($post) && is_array($post)) { + $filepost = false; + $boundary = random(40); + foreach ($post as $name => &$value) { + if ((is_string($value) && '@' == substr($value, 0, 1)) && file_exists(ltrim($value, '@'))) { + $filepost = true; + $file = ltrim($value, '@'); + + $body .= "--$boundary\r\n"; + $body .= 'Content-Disposition: form-data; name="' . $name . '"; filename="' . basename($file) . '"; Content-Type: application/octet-stream' . "\r\n\r\n"; + $body .= file_get_contents($file) . "\r\n"; + } else { + $body .= "--$boundary\r\n"; + $body .= 'Content-Disposition: form-data; name="' . $name . '"' . "\r\n\r\n"; + $body .= $value . "\r\n"; + } + } + if (!$filepost) { + $body = http_build_query($post, '', '&'); + } else { + $body .= "--$boundary\r\n"; + } + } + + $method = empty($post) ? 'GET' : 'POST'; + $fdata = "{$method} {$urlset['path']}{$urlset['query']} HTTP/1.1\r\n"; + $fdata .= "Accept: */*\r\n"; + $fdata .= "Accept-Language: zh-cn\r\n"; + if ('POST' == $method) { + $fdata .= empty($filepost) ? "Content-Type: application/x-www-form-urlencoded\r\n" : "Content-Type: multipart/form-data; boundary=$boundary\r\n"; + } + $fdata .= "Host: {$urlset['host']}\r\n"; + $fdata .= "User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:9.0.1) Gecko/20100101 Firefox/9.0.1\r\n"; + if (function_exists('gzdecode')) { + $fdata .= "Accept-Encoding: gzip, deflate\r\n"; + } + $fdata .= "Connection: close\r\n"; + if (!empty($extra) && is_array($extra)) { + foreach ($extra as $opt => $value) { + if (!strexists($opt, 'CURLOPT_')) { + $fdata .= "{$opt}: {$value}\r\n"; + } + } + } + if ($body) { + $fdata .= 'Content-Length: ' . strlen($body) . "\r\n\r\n{$body}"; + } else { + $fdata .= "\r\n"; + } + + return $fdata; +} + + +function ihttp_email($to, $subject, $body, $global = false) { + static $mailer; + set_time_limit(0); + + if (empty($mailer)) { + if (!class_exists('PHPMailer')) { + load()->library('phpmailer'); + } + $mailer = new PHPMailer(); + global $_W; + $config = $GLOBALS['_W']['setting']['mail']; + if (!$global) { + $row = pdo_get('uni_settings', array('uniacid' => $_W['uniacid']), array('notify')); + $row['notify'] = @iunserializer($row['notify']); + if (!empty($row['notify']) && !empty($row['notify']['mail'])) { + $config = $row['notify']['mail']; + } + } + + $config['charset'] = 'utf-8'; + if ($config['smtp']['type'] == '163') { + $config['smtp']['server'] = 'smtp.163.com'; + $config['smtp']['port'] = 25; + } elseif ($config['smtp']['type'] == 'qq') { + $config['smtp']['server'] = 'ssl://smtp.qq.com'; + $config['smtp']['port'] = 465; + } else { + if (!empty($config['smtp']['authmode'])) { + $config['smtp']['server'] = 'ssl://' . $config['smtp']['server']; + } + } + + if (!empty($config['smtp']['authmode'])) { + if (!extension_loaded('openssl')) { + return error(1, '请开启 php_openssl 扩展!'); + } + } + $mailer->signature = $config['signature']; + $mailer->isSMTP(); + $mailer->CharSet = $config['charset']; + $mailer->Host = $config['smtp']['server']; + $mailer->Port = $config['smtp']['port']; + $mailer->SMTPAuth = true; + $mailer->Username = $config['username']; + $mailer->Password = $config['password']; + !empty($config['smtp']['authmode']) && $mailer->SMTPSecure = 'ssl'; + + $mailer->From = $config['username']; + $mailer->FromName = $config['sender']; + $mailer->isHTML(true); + } + if ($body) { + if (is_array($body)) { + $newbody = ''; + foreach ($body as $value) { + if ('@' == substr($value, 0, 1)) { + if (!is_file($file = ltrim($value, '@'))) { + return error(1, $file . ' 附件不存在或非文件!'); + } + $mailer->addAttachment($file); + } else { + $newbody .= $value . '\n'; + } + } + $body = $newbody; + } else { + if ('@' == substr($body, 0, 1)) { + $mailer->addAttachment(ltrim($body, '@')); + $body = ''; + } + } + } + if (!empty($mailer->signature)) { + $body .= htmlspecialchars_decode($mailer->signature); + } + $mailer->Subject = $subject; + $mailer->Body = $body; + $mailer->addAddress($to); + $result = $mailer->send(); + + $mailer->clearAddresses(); + $mailer->clearReplyTos(); + + if ($result) { + return true; + } else { + return error(1, $mailer->ErrorInfo); + } +} diff --git a/framework/function/compat.biz.func.php b/framework/function/compat.biz.func.php new file mode 100644 index 0000000..123c37e --- /dev/null +++ b/framework/function/compat.biz.func.php @@ -0,0 +1,139 @@ +model('mc'); + $uid = intval($user); + if (empty($uid)) { + $uid = pdo_fetchcolumn('SELECT uid FROM ' . tablename('mc_mapping_fans') . ' WHERE openid = :openid AND uniacid = :uniacid', array(':openid' => $user, ':uniacid' => $_W['uniacid'])); + if (empty($uid)) { + return array(); } + } + + return mc_fetch($uid, $fields); + } +} + +if (!function_exists('fans_fields')) { + function fans_fields() { + load()->model('mc'); + + return mc_fields(); + } +} + +if (!function_exists('fans_update')) { + function fans_update($user, $fields) { + global $_W; + load()->model('mc'); + $uid = intval($user); + if (empty($uid)) { + $uid = pdo_fetchcolumn('SELECT uid FROM ' . tablename('mc_mapping_fans') . ' WHERE openid = :openid AND uniacid = :uniacid', array(':openid' => $user, ':uniacid' => $_W['uniacid'])); + if (empty($uid)) { + return false; } + } + + return mc_update($uid, $fields); + } +} + +if (!function_exists('create_url')) { + function create_url($segment = '', $params = array(), $noredirect = false) { + return url($segment, $params, $noredirect); + } +} + +if (!function_exists('toimage')) { + function toimage($src) { + return tomedia($src); + } +} + +if (!function_exists('uni_setting')) { + function uni_setting($uniacid = 0, $fields = '*', $force_update = false) { + global $_W; + load()->model('account'); + if ('*' == $fields) { + $fields = ''; + } + + return uni_setting_load($fields, $uniacid); + } +} +if (!function_exists('activity_token_owned')) { + function activity_token_owned($uid, $filter = array(), $pindex = 1, $psize = 10) { + return activity_coupon_owned(); + } +} +if (!function_exists('activity_token_info')) { + function activity_token_info($couponid, $uniacid) { + return activity_coupon_info($couponid); + } +} +if (!function_exists('activity_token_grant')) { + function activity_token_grant($uid, $couponid, $module = '', $remark = '') { + return activity_coupon_grant($couponid, $uid); + } +} +if (!function_exists('activity_token_use')) { + function activity_token_use($uid, $couponid, $operator, $clerk_id = 0, $recid = '', $module = 'system', $clerk_type = 1, $store_id = 0) { + return activity_coupon_use($couponid, $recid, $module); + } +} +if (!function_exists('activity_token_available')) { + function activity_token_available($uid, $pindex = 1, $psize = 0) { + return activity_coupon_available(); + } +} +if (!function_exists('uni_user_permission')) { + function uni_user_permission($type = 'system') { + return permission_account_user($type); + } +} +if (!function_exists('uni_permission')) { + function uni_permission($uid = 0, $uniacid = 0) { + return permission_account_user_role($uid, $uniacid); + } +} +if (!function_exists('uni_user_permission_exist')) { + function uni_user_permission_exist($uid = 0, $uniacid = 0) { + return permission_account_user_permission_exist($uid, $uniacid); + } +} +if (!function_exists('uni_user_permission_check')) { + function uni_user_permission_check($permission_name = '', $show_message = true, $action = '') { + return permission_check_account_user($permission_name, $show_message, $action); + } +} +if (!defined('CACHE_KEY_MODULE_SETTING')) { + define('CACHE_KEY_MODULE_SETTING', 'module_setting:%s:%s'); +} +if (!function_exists('uni_accounts')) { + function uni_accounts($uniacid = 0) { + global $_W; + $uniacid = empty($uniacid) ? $_W['uniacid'] : intval($uniacid); + $account_info = pdo_get('account', array('uniacid' => $uniacid)); + if (!empty($account_info)) { + $account_tablename = uni_account_type($account_info['type']); + $account_tablename = $account_tablename['table_name']; + $accounts = pdo_fetchall("SELECT w.*, a.type, a.isconnect FROM " . tablename('account') . " a INNER JOIN " . tablename($account_tablename) . " w USING(acid) WHERE a.uniacid = :uniacid AND a.isdeleted <> 1 ORDER BY a.acid ASC", array(':uniacid' => $uniacid), 'acid'); + } + return !empty($accounts) ? $accounts : array(); + } +} \ No newline at end of file diff --git a/framework/function/compat.func.php b/framework/function/compat.func.php new file mode 100644 index 0000000..de9e569 --- /dev/null +++ b/framework/function/compat.func.php @@ -0,0 +1,173 @@ +library('json'); + $jsonobj = new Services_JSON(SERVICES_JSON_LOOSE_TYPE); + } + + return $jsonobj->encode($value); + } +} + +if (!function_exists('json_decode')) { + function json_decode($jsonString) { + static $jsonobj; + if (!isset($jsonobj)) { + load()->library('json'); + $jsonobj = new Services_JSON(SERVICES_JSON_LOOSE_TYPE); + } + + return $jsonobj->decode($jsonString); + } +} + +if (!function_exists('http_build_query')) { + function http_build_query($formdata, $numeric_prefix = null, $arg_separator = null) { + if (!is_array($formdata)) { + return false; + } + if (null == $arg_separator) { + $arg_separator = '&'; + } + + return http_build_recursive($formdata, $arg_separator); + } + function http_build_recursive($formdata, $separator, $key = '', $prefix = '') { + $rlt = ''; + foreach ($formdata as $k => $v) { + if (is_array($v)) { + if ($key) { + $rlt .= http_build_recursive($v, $separator, $key . '[' . $k . ']', $prefix); + } else { + $rlt .= http_build_recursive($v, $separator, $k, $prefix); + } + } else { + if ($key) { + $rlt .= $prefix . $key . '[' . urlencode($k) . ']=' . urldecode($v) . '&'; + } else { + $rlt .= $prefix . urldecode($k) . '=' . urldecode($v) . '&'; + } + } + } + + return $rlt; + } +} + +if (!function_exists('file_put_contents')) { + function file_put_contents($file, $string) { + $fp = @fopen($file, 'w') or exit("Can not open $file"); + flock($fp, LOCK_EX); + $stringlen = @fwrite($fp, $string); + flock($fp, LOCK_UN); + @fclose($fp); + + return $stringlen; + } +} + +if (!function_exists('getimagesizefromstring')) { + function getimagesizefromstring($string_data) { + $uri = 'data://application/octet-stream;base64,' . base64_encode($string_data); + + return getimagesize($uri); + } +} + + +if (!defined('JSON_UNESCAPED_UNICODE')) { + define('JSON_UNESCAPED_UNICODE', 256); +} + +if (!function_exists('hex2bin')) { + function hex2bin($str) { + $sbin = ''; + $len = strlen($str); + for ($i = 0; $i < $len; $i += 2) { + $sbin .= pack('H*', substr($str, $i, 2)); + } + + return $sbin; + } +} + +if (!function_exists('mb_strlen')) { + function mb_strlen($string, $charset = '') { + return istrlen($string, $charset); + } +} + + +if (!interface_exists('SessionHandlerInterface')) { + interface SessionHandlerInterface { + } +} + + +if (!function_exists('fastcgi_finish_request')) { + function fastcgi_finish_request() { + return error(-1, 'Not npm or fast cgi'); + } +} + +if (!function_exists('openssl_decrypt')) { + function openssl_decrypt($ciphertext_dec, $method, $key, $options, $iv) { + $module = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, ''); + mcrypt_generic_init($module, $key, $iv); + $decrypted = mdecrypt_generic($module, $ciphertext_dec); + mcrypt_generic_deinit($module); + mcrypt_module_close($module); + + return $decrypted; + } +} +if (!function_exists('openssl_encrypt')) { + function openssl_encrypt($text, $method, $key, $options, $iv) { + $module = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, ''); + mcrypt_generic_init($module, $key, $iv); + $encrypted = mcrypt_generic($module, $text); + mcrypt_generic_deinit($module); + mcrypt_module_close($module); + + return $encrypted; + } +} +if (!function_exists('array_column')) { + function array_column($input, $columnKey, $indexKey = null) { + $columnKeyIsNumber = (is_numeric($columnKey)) ? true : false; + $indexKeyIsNull = (is_null($indexKey)) ? true : false; + $indexKeyIsNumber = (is_numeric($indexKey)) ? true : false; + $result = array(); + + foreach ((array) $input as $key => $row) { + if ($columnKeyIsNumber) { + $tmp = array_slice($row, $columnKey, 1); + $tmp = (is_array($tmp) && !empty($tmp)) ? current($tmp) : null; + } else { + $tmp = isset($row[$columnKey]) ? $row[$columnKey] : null; + } + if (!$indexKeyIsNull) { + if ($indexKeyIsNumber) { + $key = array_slice($row, $indexKey, 1); + $key = (is_array($key) && !empty($key)) ? current($key) : null; + $key = is_null($key) ? 0 : $key; + } else { + $key = isset($row[$indexKey]) ? $row[$indexKey] : 0; + } + } + $result[$key] = $tmp; + } + + return $result; + } +} +if (!function_exists('boolval')) { + function boolval($val) { + return (bool) $val; + } +} \ No newline at end of file diff --git a/framework/function/db.func.php b/framework/function/db.func.php new file mode 100644 index 0000000..5ed89e7 --- /dev/null +++ b/framework/function/db.func.php @@ -0,0 +1,320 @@ +fetch("SHOW TABLE STATUS LIKE '" . trim($db->tablename($tablename), '`') . "'"); + if (empty($result)) { + return array(); + } + $ret['tablename'] = $result['Name']; + $ret['charset'] = $result['Collation']; + $ret['engine'] = $result['Engine']; + $ret['increment'] = $result['Auto_increment']; + $result = $db->fetchall('SHOW FULL COLUMNS FROM ' . $db->tablename($tablename)); + foreach ($result as $value) { + $temp = array(); + $type = explode(' ', $value['Type'], 2); + $temp['name'] = $value['Field']; + $pieces = explode('(', $type[0], 2); + $temp['type'] = $pieces[0]; + $temp['length'] = rtrim($pieces[1], ')'); + $temp['null'] = 'NO' != $value['Null']; + $temp['signed'] = empty($type[1]); + $temp['increment'] = 'auto_increment' == $value['Extra']; + $ret['fields'][$value['Field']] = $temp; + } + $result = $db->fetchall('SHOW INDEX FROM ' . $db->tablename($tablename)); + foreach ($result as $value) { + $ret['indexes'][$value['Key_name']]['name'] = $value['Key_name']; + $ret['indexes'][$value['Key_name']]['type'] = ('PRIMARY' == $value['Key_name']) ? 'primary' : (0 == $value['Non_unique'] ? 'unique' : 'index'); + $ret['indexes'][$value['Key_name']]['fields'][] = $value['Column_name']; + } + + return $ret; +} + + +function db_table_serialize($db, $dbname) { + $tables = $db->fetchall('SHOW TABLES'); + if (empty($tables)) { + return ''; + } + $struct = array(); + foreach ($tables as $value) { + $structs[] = db_table_schema($db, substr($value['Tables_in_' . $dbname], strpos($value['Tables_in_' . $dbname], '_') + 1)); + } + + return iserializer($structs); +} + +function db_table_create_sql($schema) { + $pieces = explode('_', $schema['charset']); + $charset = $pieces[0]; + $engine = $schema['engine']; + $schema['tablename'] = str_replace('ims_', $GLOBALS['_W']['config']['db']['tablepre'], $schema['tablename']); + $sql = "CREATE TABLE IF NOT EXISTS `{$schema['tablename']}` (\n"; + foreach ($schema['fields'] as $value) { + $piece = _db_build_field_sql($value); + $sql .= "`{$value['name']}` {$piece},\n"; + } + foreach ($schema['indexes'] as $value) { + $fields = implode('`,`', $value['fields']); + if ('index' == $value['type']) { + $sql .= "KEY `{$value['name']}` (`{$fields}`),\n"; + } + if ('unique' == $value['type']) { + $sql .= "UNIQUE KEY `{$value['name']}` (`{$fields}`),\n"; + } + if ('primary' == $value['type']) { + $sql .= "PRIMARY KEY (`{$fields}`),\n"; + } + } + $sql = rtrim($sql); + $sql = rtrim($sql, ','); + + $sql .= "\n) ENGINE=$engine DEFAULT CHARSET=$charset;\n\n"; + + return $sql; +} + + +function db_schema_compare($table1, $table2) { + $table1['charset'] == $table2['charset'] ? '' : $ret['diffs']['charset'] = true; + + $fields1 = array_keys($table1['fields']); + $fields2 = array_keys($table2['fields']); + $diffs = array_diff($fields1, $fields2); + if (!empty($diffs)) { + $ret['fields']['greater'] = array_values($diffs); + } + $diffs = array_diff($fields2, $fields1); + if (!empty($diffs)) { + $ret['fields']['less'] = array_values($diffs); + } + $diffs = array(); + $intersects = array_intersect($fields1, $fields2); + if (!empty($intersects)) { + foreach ($intersects as $field) { + if ($table1['fields'][$field] != $table2['fields'][$field]) { + $diffs[] = $field; + } + } + } + if (!empty($diffs)) { + $ret['fields']['diff'] = array_values($diffs); + } + + $indexes1 = is_array($table1['indexes']) ? array_keys($table1['indexes']) : array(); + $indexes2 = is_array($table2['indexes']) ? array_keys($table2['indexes']) : array(); + $diffs = array_diff($indexes1, $indexes2); + if (!empty($diffs)) { + $ret['indexes']['greater'] = array_values($diffs); + } + $diffs = array_diff($indexes2, $indexes1); + if (!empty($diffs)) { + $ret['indexes']['less'] = array_values($diffs); + } + $diffs = array(); + $intersects = array_intersect($indexes1, $indexes2); + if (!empty($intersects)) { + foreach ($intersects as $index) { + if ($table1['indexes'][$index] != $table2['indexes'][$index]) { + $diffs[] = $index; + } + } + } + if (!empty($diffs)) { + $ret['indexes']['diff'] = array_values($diffs); + } + + return $ret; +} + +function db_table_fix_sql($schema1, $schema2, $strict = false) { + if (empty($schema1)) { + return array(db_table_create_sql($schema2)); + } + $diff = $result = db_schema_compare($schema1, $schema2); + if (!empty($diff['diffs']['tablename'])) { + return array(db_table_create_sql($schema2)); + } + $sqls = array(); + if (!empty($diff['diffs']['engine'])) { + $sqls[] = "ALTER TABLE `{$schema1['tablename']}` ENGINE = {$schema2['engine']}"; + } + + if (!empty($diff['diffs']['charset'])) { + $pieces = explode('_', $schema2['charset']); + $charset = $pieces[0]; + $sqls[] = "ALTER TABLE `{$schema1['tablename']}` DEFAULT CHARSET = {$charset}"; + } + + if (!empty($diff['fields'])) { + if (!empty($diff['fields']['less'])) { + foreach ($diff['fields']['less'] as $fieldname) { + $field = $schema2['fields'][$fieldname]; + $piece = _db_build_field_sql($field); + if (!empty($field['rename']) && !empty($schema1['fields'][$field['rename']])) { + $sql = "ALTER TABLE `{$schema1['tablename']}` CHANGE `{$field['rename']}` `{$field['name']}` {$piece}"; + unset($schema1['fields'][$field['rename']]); + } else { + if ($field['position']) { + $pos = ' ' . $field['position']; + } + $sql = "ALTER TABLE `{$schema1['tablename']}` ADD `{$field['name']}` {$piece}{$pos}"; + } + $primary = array(); + $isincrement = array(); + if (strexists($sql, 'AUTO_INCREMENT')) { + $isincrement = $field; + $sql = str_replace('AUTO_INCREMENT', '', $sql); + foreach ($schema1['fields'] as $field) { + if (1 == $field['increment']) { + $primary = $field; + break; + } + } + if (!empty($primary)) { + $piece = _db_build_field_sql($primary); + if (!empty($piece)) { + $piece = str_replace('AUTO_INCREMENT', '', $piece); + } + $sqls[] = "ALTER TABLE `{$schema1['tablename']}` CHANGE `{$primary['name']}` `{$primary['name']}` {$piece}"; + } + } + $sqls[] = $sql; + } + } + if (!empty($diff['fields']['diff'])) { + foreach ($diff['fields']['diff'] as $fieldname) { + $field = $schema2['fields'][$fieldname]; + $piece = _db_build_field_sql($field); + if (!empty($schema1['fields'][$fieldname])) { + $sqls[] = "ALTER TABLE `{$schema1['tablename']}` CHANGE `{$field['name']}` `{$field['name']}` {$piece}"; + } + } + } + if ($strict && !empty($diff['fields']['greater'])) { + foreach ($diff['fields']['greater'] as $fieldname) { + if (!empty($schema1['fields'][$fieldname])) { + $sqls[] = "ALTER TABLE `{$schema1['tablename']}` DROP `{$fieldname}`"; + } + } + } + } + + if (!empty($diff['indexes'])) { + if (!empty($diff['indexes']['less'])) { + foreach ($diff['indexes']['less'] as $indexname) { + $index = $schema2['indexes'][$indexname]; + $piece = _db_build_index_sql($index); + $sqls[] = "ALTER TABLE `{$schema1['tablename']}` ADD {$piece}"; + } + } + if (!empty($diff['indexes']['diff'])) { + foreach ($diff['indexes']['diff'] as $indexname) { + $index = $schema2['indexes'][$indexname]; + $piece = _db_build_index_sql($index); + + $sqls[] = "ALTER TABLE `{$schema1['tablename']}` DROP " . ('PRIMARY' == $indexname ? ' PRIMARY KEY ' : "INDEX {$indexname}") . ", ADD {$piece}"; + } + } + if ($strict && !empty($diff['indexes']['greater'])) { + foreach ($diff['indexes']['greater'] as $indexname) { + $sqls[] = "ALTER TABLE `{$schema1['tablename']}` DROP `{$indexname}`"; + } + } + } + if (!empty($isincrement)) { + $piece = _db_build_field_sql($isincrement); + $sqls[] = "ALTER TABLE `{$schema1['tablename']}` CHANGE `{$isincrement['name']}` `{$isincrement['name']}` {$piece}"; + } + + return $sqls; +} + +function _db_build_index_sql($index) { + $piece = ''; + $fields = implode('`,`', $index['fields']); + if ('index' == $index['type']) { + $piece .= " INDEX `{$index['name']}` (`{$fields}`)"; + } + if ('unique' == $index['type']) { + $piece .= "UNIQUE `{$index['name']}` (`{$fields}`)"; + } + if ('primary' == $index['type']) { + $piece .= "PRIMARY KEY (`{$fields}`)"; + } + + return $piece; +} + +function _db_build_field_sql($field) { + if (!empty($field['length'])) { + $length = "({$field['length']})"; + } else { + $length = ''; + } + if (false !== strpos(strtolower($field['type']), 'int') || in_array(strtolower($field['type']), array('decimal', 'float', 'dobule'))) { + $signed = empty($field['signed']) ? ' unsigned' : ''; + } else { + $signed = ''; + } + if (empty($field['null'])) { + $null = ' NOT NULL'; + } else { + $null = ''; + } + if (isset($field['default'])) { + $default = " DEFAULT '" . $field['default'] . "'"; + } else { + $default = ''; + } + if ($field['increment']) { + $increment = ' AUTO_INCREMENT'; + } else { + $increment = ''; + } + + return "{$field['type']}{$length}{$signed}{$null}{$default}{$increment}"; +} + +function db_table_schemas($table) { + $dump = "DROP TABLE IF EXISTS {$table};\n"; + $sql = "SHOW CREATE TABLE {$table}"; + $row = pdo_fetch($sql); + $dump .= $row['Create Table']; + $dump .= ";\n\n"; + + return $dump; +} + +function db_table_insert_sql($tablename, $start, $size) { + $data = ''; + $tmp = ''; + $sql = "SELECT * FROM {$tablename} LIMIT {$start}, {$size}"; + $result = pdo_fetchall($sql); + if (!empty($result)) { + foreach ($result as $row) { + $tmp .= '('; + foreach ($row as $k => $v) { + $value = str_replace(array('\\', "\0", "\n", "\r", "'", '"', "\x1a"), array('\\\\', '\\0', '\\n', '\\r', "\\'", '\\"', '\\Z'), $v); + $tmp .= "'" . $value . "',"; + } + $tmp = rtrim($tmp, ','); + $tmp .= "),\n"; + } + $tmp = rtrim($tmp, ",\n"); + $data .= "INSERT INTO {$tablename} VALUES \n{$tmp};\n"; + $datas = array( + 'data' => $data, + 'result' => $result, + ); + + return $datas; + } else { + return false; + } +} \ No newline at end of file diff --git a/framework/function/file.func.php b/framework/function/file.func.php new file mode 100644 index 0000000..6ae5958 --- /dev/null +++ b/framework/function/file.func.php @@ -0,0 +1,891 @@ + 0 && $acquired_files_count >= $limit) { + closedir($dir); + + return $files; + } + } + if (is_dir($path . '/' . $file)) { + $rs = file_tree_limit($path . '/' . $file, $limit, $acquired_files_count); + foreach ($rs as $f) { + $files[] = $f; + ++$acquired_files_count; + if ($limit > 0 && $acquired_files_count >= $limit) { + closedir($dir); + + return $files; + } + } + } + } + closedir($dir); + } + } + + return $files; +} + + +function file_dir_exist_image($path) { + if (is_dir($path)) { + if ($dir = opendir($path)) { + while (false !== ($file = readdir($dir))) { + if (in_array($file, array('.', '..'))) { + continue; + } + if (is_file($path . '/' . $file) && $path != (ATTACHMENT_ROOT . 'images') && file_is_image($path . '/' . $file)) { + if (0 === strpos($path, ATTACHMENT_ROOT)) { + $attachment = str_replace(ATTACHMENT_ROOT . 'images/', '', $path . '/' . $file); + list($file_account) = explode('/', $attachment); + if ('global' == $file_account) { + continue; + } + } + closedir($dir); + + return true; + } + if (is_dir($path . '/' . $file) && file_dir_exist_image($path . '/' . $file)) { + closedir($dir); + + return true; + } + } + closedir($dir); + } + } + + return false; +} + + +function mkdirs($path) { + if (!is_dir($path)) { + mkdirs(dirname($path)); + mkdir($path); + } + + return is_dir($path); +} + + +function file_copy($src, $des, $filter) { + $dir = opendir($src); + @mkdir($des); + while (false !== ($file = readdir($dir))) { + if (('.' != $file) && ('..' != $file)) { + if (is_dir($src . '/' . $file)) { + file_copy($src . '/' . $file, $des . '/' . $file, $filter); + } elseif (!in_array(substr($file, strrpos($file, '.') + 1), $filter)) { + copy($src . '/' . $file, $des . '/' . $file); + } + } + } + closedir($dir); +} + + +function rmdirs($path, $clean = false) { + if (!is_dir($path)) { + return false; + } + $files = glob($path . '/*'); + if ($files) { + foreach ($files as $file) { + is_dir($file) ? rmdirs($file) : @unlink($file); + } + } + + return $clean ? true : @rmdir($path); +} + + +function file_upload($file, $type = 'image', $name = '', $compress = false) { + load()->model('system'); + $harmtype = array('asp', 'php', 'jsp', 'js', 'css', 'php3', 'php4', 'php5', 'ashx', 'aspx', 'exe', 'cgi'); + if (empty($file)) { + return error(-1, '没有上传内容'); + } + if (!in_array($type, array('image', 'thumb', 'voice', 'video', 'audio'))) { + return error(-2, '未知的上传类型'); + } + global $_W; + $ext = pathinfo($file['name'], PATHINFO_EXTENSION); + $ext = strtolower($ext); + $setting = setting_load('upload'); + switch ($type) { + case 'image': + case 'thumb': + $allowExt = array('gif', 'jpg', 'jpeg', 'bmp', 'png', 'ico'); + $limit = $setting['upload']['image']['limit']; + break; + case 'voice': + case 'audio': + $allowExt = array('mp3', 'wma', 'wav', 'amr'); + $limit = $setting['upload']['audio']['limit']; + break; + case 'video': + $allowExt = array('rm', 'rmvb', 'wmv', 'avi', 'mpg', 'mpeg', 'mp4'); + $limit = $setting['upload']['audio']['limit']; + break; + } + $type_setting = in_array($type, array('image', 'thumb')) ? 'image' : 'audio'; +// $setting = $_W['setting']['upload'][$type_setting]; + +// if (!empty($setting['extentions'])) { +// $allowExt = $setting['extentions']; +// } + if (!in_array(strtolower($ext), $allowExt) || in_array(strtolower($ext), $harmtype)) { + return error(-3, '不允许上传此类文件'); + } + if (!empty($limit) && $limit * 1024 < filesize($file['tmp_name'])) { + return error(-4, "上传的文件超过大小限制,请上传小于 {$limit}k 的文件"); + } + + $result = array(); + if (empty($name) || 'auto' == $name) { + $uniacid = intval($_W['uniacid']); + $path = "{$type}s/{$uniacid}/" . date('Y/m/'); + mkdirs(ATTACHMENT_ROOT . '/' . $path); + $filename = file_random_name(ATTACHMENT_ROOT . '/' . $path, $ext); + + $result['path'] = $path . $filename; + } else { + mkdirs(dirname(ATTACHMENT_ROOT . '/' . $name)); + if (!strexists($name, $ext)) { + $name .= '.' . $ext; + } + $result['path'] = $name; + } + + $save_path = ATTACHMENT_ROOT . '/' . $result['path']; + + $image = ''; + if (isset($setting['zip_percentage']) && $setting['zip_percentage'] == 100 && system_check_php_ext('exif')) { + $exif = exif_read_data($file['tmp_name']); + if (!empty($exif['THUMBNAIL']['Orientation'])) { + $image = imagecreatefromstring(file_get_contents($file['tmp_name'])); + switch($exif['THUMBNAIL']['Orientation']) { + case 8: + $image = imagerotate($image,0,0); + break; + case 3: + $image = imagerotate($image,180,0); + break; + case 6: + $image = imagerotate($image,-90,0); + break; + default: + $image = imagerotate($image,0,0); + break; + } + } + } + if (empty($image)) { + $newimage = file_move($file['tmp_name'], $save_path); + } else { + $newimage = imagejpeg($image,$save_path); + imagedestroy($image); + } + if (empty($newimage)) { + return error(-1, '文件上传失败, 请将 attachment 目录权限先777
(如果777上传失败,可尝试将目录设置为755)'); + } + + if ('image' == $type && $compress) { + file_image_quality($save_path, $save_path, $ext); + } + + if (file_is_uni_attach($save_path)) { + $check_result = file_check_uni_space($save_path); + if (is_error($check_result)) { + @unlink($save_path); + + return $check_result; + } + $uni_remote_setting = uni_setting_load('remote'); + if (empty($uni_remote_setting['remote']) && empty($_W['setting']['remote']['type'])) { + file_change_uni_attchsize($save_path); + } + } + + $result['success'] = true; + + return $result; +} +function file_wechat_upload($file, $type = 'image', $name = '') { + $harmtype = array('asp', 'php', 'jsp', 'js', 'css', 'php3', 'php4', 'php5', 'ashx', 'aspx', 'exe', 'cgi'); + if (empty($file)) { + return error(-1, '没有上传内容'); + } + if (!in_array($type, array('image', 'thumb', 'voice', 'video', 'audio'))) { + return error(-2, '未知的上传类型'); + } + + global $_W; + $ext = pathinfo($file['name'], PATHINFO_EXTENSION); + $ext = strtolower($ext); + if (in_array(strtolower($ext), $harmtype)) { + return error(-3, '不允许上传此类文件'); + } + + $result = array(); + if (empty($name) || 'auto' == $name) { + $uniacid = intval($_W['uniacid']); + $path = "{$type}s/{$uniacid}/" . date('Y/m/'); + mkdirs(ATTACHMENT_ROOT . '/' . $path); + $filename = file_random_name(ATTACHMENT_ROOT . '/' . $path, $ext); + $result['path'] = $path . $filename; + } else { + mkdirs(dirname(ATTACHMENT_ROOT . '/' . $name)); + if (!strexists($name, $ext)) { + $name .= '.' . $ext; + } + $result['path'] = $name; + } + $save_path = ATTACHMENT_ROOT . '/' . $result['path']; + if (!file_move($file['tmp_name'], $save_path)) { + return error(-1, '保存上传文件失败'); + } + + if ('image' == $type) { + file_image_quality($save_path, $save_path, $ext); + } + $result['success'] = true; + + return $result; +} + + +function file_remote_upload($filename, $auto_delete_local = true) { + global $_W; + if (empty($_W['setting']['remote']['type'])) { + return false; + } + if ($_W['setting']['remote']['type'] == ATTACH_FTP) { + load()->library('ftp'); + $ftp_config = array( + 'hostname' => $_W['setting']['remote']['ftp']['hostname'] ?: $_W['setting']['remote']['ftp']['host'], + 'username' => $_W['setting']['remote']['ftp']['username'], + 'password' => $_W['setting']['remote']['ftp']['password'], + 'port' => $_W['setting']['remote']['ftp']['port'], + 'ssl' => $_W['setting']['remote']['ftp']['ssl'], + 'passive' => $_W['setting']['remote']['ftp']['passive'] ?: $_W['setting']['remote']['ftp']['pasv'], + 'timeout' => $_W['setting']['remote']['ftp']['timeout'] ?: $_W['setting']['remote']['ftp']['overtime'], + 'rootdir' => $_W['setting']['remote']['ftp']['rootdir'] ?: $_W['setting']['remote']['ftp']['dir'], + ); + $ftp = new Ftp($ftp_config); + if (true === $ftp->connect()) { + $response = $ftp->upload(ATTACHMENT_ROOT . '/' . $filename, $filename); + if ($auto_delete_local) { + file_delete($filename); + } + if (!empty($response)) { + return true; + } else { + return error(1, '远程附件上传失败,请检查配置并重新上传'); + } + } else { + return error(1, '远程附件上传失败,请检查配置并重新上传'); + } + } elseif ($_W['setting']['remote']['type'] == ATTACH_OSS) { + load()->library('oss'); + load()->model('attachment'); + $buckets = attachment_alioss_buctkets($_W['setting']['remote']['alioss']['key'], $_W['setting']['remote']['alioss']['secret']); + $host_name = $_W['setting']['remote']['alioss']['internal'] ? '-internal.aliyuncs.com' : '.aliyuncs.com'; + $endpoint = 'http://' . $buckets[$_W['setting']['remote']['alioss']['bucket']]['location'] . $host_name; + try { + $ossClient = new \OSS\OssClient($_W['setting']['remote']['alioss']['key'], $_W['setting']['remote']['alioss']['secret'], $endpoint); + $ossClient->uploadFile($_W['setting']['remote']['alioss']['bucket'], $filename, ATTACHMENT_ROOT . $filename); + } catch (\OSS\Core\OssException $e) { + return error(1, $e->getMessage()); + } + if ($auto_delete_local) { + file_delete($filename); + } + } elseif ($_W['setting']['remote']['type'] == ATTACH_QINIU) { + load()->library('qiniu'); + $auth = new Qiniu\Auth($_W['setting']['remote']['qiniu']['accesskey'], $_W['setting']['remote']['qiniu']['secretkey']); + $config = new Qiniu\Config(); + $uploadmgr = new Qiniu\Storage\UploadManager($config); + $putpolicy = Qiniu\base64_urlSafeEncode(json_encode(array( + 'scope' => $_W['setting']['remote']['qiniu']['bucket'] . ':' . $filename, + ))); + $uploadtoken = $auth->uploadToken($_W['setting']['remote']['qiniu']['bucket'], $filename, 3600, $putpolicy); + list($ret, $err) = $uploadmgr->putFile($uploadtoken, $filename, ATTACHMENT_ROOT . '/' . $filename); + if ($auto_delete_local) { + file_delete($filename); + } + if (null !== $err) { + return error(1, '远程附件上传失败,请检查配置并重新上传'); + } else { + return true; + } + } elseif ($_W['setting']['remote']['type'] == ATTACH_COS) { + load()->library('cosv5'); + try { + $bucket = $_W['setting']['remote']['cos']['bucket'] . '-' . $_W['setting']['remote']['cos']['appid']; + $cosClient = new Qcloud\Cos\Client( + array( + 'region' => $_W['setting']['remote']['cos']['local'], + 'credentials'=> array( + 'secretId' => $_W['setting']['remote']['cos']['secretid'], + 'secretKey' => $_W['setting']['remote']['cos']['secretkey']))); + $cosClient->Upload($bucket, $filename, fopen(ATTACHMENT_ROOT . $filename, 'rb')); + if ($auto_delete_local) { + file_delete($filename); + } + } catch (\Exception $e) { + return error(1, $e->getMessage()); + } + } + return true; +} + + +function file_dir_remote_upload($dir_path, $limit = 200) { + global $_W; + if (empty($_W['setting']['remote']['type'])) { + return error(1, '未开启远程附件'); + } + $dir_path = safe_gpc_path($dir_path); + if (!empty($dir_path)) { + $local_attachment = file_tree_limit($dir_path, $limit); + } else { + $local_attachment = array(); + } + if (is_array($local_attachment) && !empty($local_attachment)) { + foreach ($local_attachment as $attachment) { + $filename = str_replace(ATTACHMENT_ROOT, '', $attachment); + list($image_dir, $file_account) = explode('/', $filename); + if ('global' == $file_account || !file_is_image($attachment)) { + continue; + } + $result = file_remote_upload($filename); + if (is_error($result)) { + return $result; + } + } + } + + return true; +} + + +function file_random_name($dir, $ext) { + do { + $filename = random(30) . '.' . $ext; + } while (file_exists($dir . $filename)); + + return $filename; +} + + +function file_delete($file) { + global $_W; + if (empty($file)) { + return false; + } + $file = safe_gpc_path($file); + $file_extension = pathinfo($file, PATHINFO_EXTENSION); + if (in_array($file_extension, array('php', 'html', 'js', 'css', 'ttf', 'otf', 'eot', 'svg', 'woff'))) { + return false; + } + + $uni_remote_setting = uni_setting_load('remote'); + if (empty($uni_remote_setting['remote']) && empty($_W['setting']['remote']['type'])) { + if (file_exists(ATTACHMENT_ROOT . '/' . $file) && file_is_uni_attach(ATTACHMENT_ROOT . '/' . $file)) { + file_change_uni_attchsize(ATTACHMENT_ROOT . '/' . $file, false); + } + } + if (file_exists($file)) { + @unlink($file); + } + if (file_exists(ATTACHMENT_ROOT . '/' . $file)) { + @unlink(ATTACHMENT_ROOT . '/' . $file); + } + + return true; +} +function file_remote_delete($file) { + global $_W; + if (empty($file)) { + return true; + } + if ($_W['setting']['remote']['type'] == '1') { + load()->library('ftp'); + $ftp_config = array( + 'hostname' => $_W['setting']['remote']['ftp']['hostname'] ?: $_W['setting']['remote']['ftp']['host'], + 'username' => $_W['setting']['remote']['ftp']['username'], + 'password' => $_W['setting']['remote']['ftp']['password'], + 'port' => $_W['setting']['remote']['ftp']['port'], + 'ssl' => $_W['setting']['remote']['ftp']['ssl'], + 'passive' => $_W['setting']['remote']['ftp']['passive'] ?: $_W['setting']['remote']['ftp']['pasv'], + 'timeout' => $_W['setting']['remote']['ftp']['timeout'] ?: $_W['setting']['remote']['ftp']['overtime'], + 'rootdir' => $_W['setting']['remote']['ftp']['rootdir'] ?: $_W['setting']['remote']['ftp']['dir'], + ); + $ftp = new Ftp($ftp_config); + if (true === $ftp->connect()) { + if ($ftp->delete_file($file)) { + return true; + } else { + return error(1, '删除附件失败,请检查配置并重新删除'); + } + } else { + return error(1, '删除附件失败,请检查配置并重新删除'); + } + } elseif ($_W['setting']['remote']['type'] == '2') { + load()->model('attachment'); + load()->library('oss'); + $buckets = attachment_alioss_buctkets($_W['setting']['remote']['alioss']['key'], $_W['setting']['remote']['alioss']['secret']); + $endpoint = 'http://' . $buckets[$_W['setting']['remote']['alioss']['bucket']]['location'] . '.aliyuncs.com'; + try { + $ossClient = new \OSS\OssClient($_W['setting']['remote']['alioss']['key'], $_W['setting']['remote']['alioss']['secret'], $endpoint); + $ossClient->deleteObject($_W['setting']['remote']['alioss']['bucket'], $file); + } catch (\OSS\Core\OssException $e) { + return error(1, '删除oss远程文件失败'); + } + } elseif ($_W['setting']['remote']['type'] == '3') { + load()->library('qiniu'); + $auth = new Qiniu\Auth($_W['setting']['remote']['qiniu']['accesskey'], $_W['setting']['remote']['qiniu']['secretkey']); + $bucketMgr = new Qiniu\Storage\BucketManager($auth); + $error = $bucketMgr->delete($_W['setting']['remote']['qiniu']['bucket'], $file); + if ($error instanceof Qiniu\Http\Error) { + if (612 == $error->code()) { + return true; + } + + return error(1, '删除七牛远程文件失败'); + } else { + return true; + } + } elseif ($_W['setting']['remote']['type'] == '4') { + load()->library('cosv5'); + try { + $key = $file; + $bucket = $_W['setting']['remote']['cos']['bucket'] . '-' . $_W['setting']['remote']['cos']['appid']; + $cosClient = new Qcloud\Cos\Client( + array( + 'region' => $_W['setting']['remote']['cos']['local'], + 'credentials'=> array( + 'secretId' => $_W['setting']['remote']['cos']['secretid'], + 'secretKey' => $_W['setting']['remote']['cos']['secretkey']))); + $cosClient->deleteObjects(array( + 'Bucket' => $bucket, + 'Objects' => array(array('Key' => $key)) + )); + } catch (\Exception $e) { + return error(1, '删除cos远程文件失败'); + } + } + return true; +} + + +function file_image_thumb($srcfile, $desfile = '', $width = 0) { + global $_W; + load()->classs('image'); + if (0 == intval($width)) { + load()->model('setting'); + $width = intval($_W['setting']['upload']['image']['width']); + } + if (empty($desfile)) { + $ext = pathinfo($srcfile, PATHINFO_EXTENSION); + $srcdir = dirname($srcfile); + do { + $desfile = $srcdir . '/' . random(30) . ".{$ext}"; + } while (file_exists($desfile)); + } + + $des = dirname($desfile); + if (!file_exists($des)) { + if (!mkdirs($des)) { + return error('-1', '创建目录失败'); + } + } elseif (!is_writable($des)) { + return error('-1', '目录无法写入'); + } + $org_info = @getimagesize($srcfile); + if ($org_info) { + if (0 == $width || $width > $org_info[0]) { + copy($srcfile, $desfile); + + return str_replace(ATTACHMENT_ROOT . '/', '', $desfile); + } + } + $scale_org = $org_info[0] / $org_info[1]; + $height = $width / $scale_org; + $desfile = Image::create($srcfile)->resize($width, $height)->saveTo($desfile); + if (!$desfile) { + return false; + } + + return str_replace(ATTACHMENT_ROOT . '/', '', $desfile); +} + + +function file_image_crop($src, $desfile, $width = 400, $height = 300, $position = 1) { + load()->classs('image'); + $des = dirname($desfile); + if (!file_exists($des)) { + if (!mkdirs($des)) { + return error('-1', '创建目录失败'); + } + } elseif (!is_writable($des)) { + return error('-1', '目录无法写入'); + } + + return Image::create($src) + ->crop($width, $height, $position) + ->saveTo($desfile); +} + + +function file_lists($filepath, $subdir = 1, $ex = '', $isdir = 0, $md5 = 0, $enforcement = 0) { + static $file_list = array(); + if ($enforcement) { + $file_list = array(); + } + $flags = $isdir ? GLOB_ONLYDIR : 0; + $list = glob($filepath . '*' . (!empty($ex) && empty($subdir) ? '.' . $ex : ''), $flags); + if (!empty($ex)) { + $ex_num = strlen($ex); + } + foreach ($list as $k => $v) { + $v = str_replace('\\', '/', $v); + $v1 = str_replace(IA_ROOT . '/', '', $v); + if ($subdir && is_dir($v)) { + file_lists($v . '/', $subdir, $ex, $isdir, $md5); + continue; + } + if (!empty($ex) && strtolower(substr($v, -$ex_num, $ex_num)) == $ex) { + if ($md5) { + $file_list[$v1] = md5_file($v); + } else { + $file_list[] = $v1; + } + continue; + } elseif (!empty($ex) && strtolower(substr($v, -$ex_num, $ex_num)) != $ex) { + unset($list[$k]); + continue; + } + } + + return $file_list; +} + + +function file_remote_attach_fetch($url, $limit = 0, $path = '') { + global $_W; + $url = trim($url); + if (empty($url)) { + return error(-1, '文件地址不存在'); + } + load()->func('communication'); + $resp = ihttp_get($url); + + if (is_error($resp)) { + return error(-1, '提取文件失败, 错误信息: ' . $resp['message']); + } + if (200 != intval($resp['code'])) { + return error(-1, '提取文件失败: 未找到该资源文件.'); + } + $get_headers = file_media_content_type($url); + if (empty($get_headers)) { + return error(-1, '提取资源失败, 资源文件类型错误.'); + } else { + $ext = $get_headers['ext']; + $type = $get_headers['type']; + } + + if (empty($path)) { + $path = $type . "/{$_W['uniacid']}/" . date('Y/m/'); + } else { + $path = parse_path($path); + } + if (!$path) { + return error(-1, '提取文件失败: 上传路径配置有误.'); + } + + if (!is_dir(ATTACHMENT_ROOT . $path)) { + if (!mkdirs(ATTACHMENT_ROOT . $path, 0700, true)) { + return error(-1, '提取文件失败: 权限不足.'); + } + } + + + if (!$limit) { + if ('images' == $type) { + $limit = $_W['setting']['upload']['image']['limit'] * 1024; + } else { + $limit = $_W['setting']['upload']['audio']['limit'] * 1024; + } + } else { + $limit = $limit * 1024; + } + if (intval($resp['headers']['Content-Length']) > $limit) { + return error(-1, '上传的媒体文件过大(' . sizecount($resp['headers']['Content-Length']) . ' > ' . sizecount($limit)); + } + $filename = file_random_name(ATTACHMENT_ROOT . $path, $ext); + $pathname = $path . $filename; + $fullname = ATTACHMENT_ROOT . $pathname; + if (false == file_put_contents($fullname, $resp['content'])) { + return error(-1, '提取失败.'); + } + + return $pathname; +} + + +function file_media_content_type($url) { + $file_header = iget_headers($url, 1); + if (empty($url) || !is_array($file_header)) { + return false; + } + switch ($file_header['Content-Type']) { + case 'application/x-jpg': + case 'image/jpg': + case 'image/jpeg': + $ext = 'jpg'; + $type = 'images'; + break; + case 'image/png': + $ext = 'png'; + $type = 'images'; + break; + case 'image/gif': + $ext = 'gif'; + $type = 'images'; + break; + case 'video/mp4': + case 'video/mpeg4': + $ext = 'mp4'; + $type = 'videos'; + break; + case 'video/x-ms-wmv': + $ext = 'wmv'; + $type = 'videos'; + break; + case 'audio/mpeg': + $ext = 'mp3'; + $type = 'audios'; + break; + case 'audio/mp4': + $ext = 'mp4'; + $type = 'audios'; + break; + case 'audio/x-ms-wma': + $ext = 'wma'; + $type = 'audios'; + break; + default: + return false; + break; + } + + return array('ext' => $ext, 'type' => $type); +} + + +function file_allowed_media($type) { + global $_W; + if (!in_array($type, array('image', 'audio'))) { + return array(); + } + if (empty($_W['setting']['upload'][$type]['extention']) || !is_array($_W['setting']['upload'][$type]['extention'])) { + return $_W['config']['upload'][$type]['extentions']; + } + + return $_W['setting']['upload'][$type]['extention']; +} + +function file_is_image($url) { + global $_W; + $allowed_media = file_allowed_media('image'); + + if ('//' == substr($url, 0, 2)) { + $url = 'http:' . $url; + } + if (0 == strpos($url, $_W['siteroot'] . 'attachment/')) { + $url = str_replace($_W['siteroot'] . 'attachment/', ATTACHMENT_ROOT, $url); + } + $lower_url = strtolower($url); + if (('http://' == substr($lower_url, 0, 7)) || ('https://' == substr($lower_url, 0, 8))) { + $analysis_url = parse_url($lower_url); + $preg_str = '/.*(\.' . implode('|\.', $allowed_media) . ')$/'; + if (!empty($analysis_url['query']) || !preg_match($preg_str, $lower_url) || !preg_match($preg_str, $analysis_url['path'])) { + return false; + } + $img_headers = file_media_content_type($url); + if (empty($img_headers) || !in_array($img_headers['ext'], $allowed_media)) { + return false; + } + } + + $info = igetimagesize($url); + if (!is_array($info)) { + return false; + } + + return true; +} + + +function file_image_quality($src, $to_path, $ext) { + load()->classs('image'); + global $_W; + if ('gif' == strtolower($ext)) { + return; + } + $quality = intval($_W['setting']['upload']['image']['zip_percentage']); + if ($quality <= 0 || $quality >= 100) { + return; + } + + if (filesize($src) / 1024 > 5120) { + return; + } + + $result = Image::create($src, $ext)->saveTo($to_path, $quality); + + return $result; +} + +function file_is_uni_attach($file) { + global $_W; + if (!is_file($file)) { + return error(-1, '未找到的文件。'); + } + + return strpos($file, "/{$_W['uniacid']}/") > 0; +} + + +function file_check_uni_space($file) { + global $_W; + if (!is_file($file)) { + return error(-1, '未找到上传的文件。'); + } + $uni_remote_setting = uni_setting_load('remote'); + if (empty($uni_remote_setting['remote']['type'])) { + $uni_setting = uni_setting_load(array('attachment_limit', 'attachment_size')); + + $attachment_limit = intval($uni_setting['attachment_limit']); + if (0 == $attachment_limit) { + $upload = setting_load('upload'); + $attachment_limit = empty($upload['upload']['attachment_limit']) ? 0 : intval($upload['upload']['attachment_limit']); + } + + if ($attachment_limit > 0) { + $file_size = max(1, round(filesize($file) / 1024)); + if (($file_size + $uni_setting['attachment_size']) > ($attachment_limit * 1024)) { + return error(-1, '上传失败,可使用的附件空间不足!'); + } + } + } + + return true; +} + + +function file_change_uni_attchsize($file, $is_add = true) { + global $_W; + if (!is_file($file)) { + return error(-1, '未找到的文件。'); + } + $file_size = round(filesize($file) / 1024); + $file_size = max(1, $file_size); + + $result = true; + $uni_remote_setting = uni_setting_load('remote'); + if (empty($uni_remote_setting['remote']['type'])) { + $uniacid = pdo_getcolumn('uni_settings', array('uniacid' => $_W['uniacid']), 'uniacid'); + if (empty($uniacid)) { + $result = pdo_insert('uni_settings', array('attachment_size' => $file_size, 'uniacid' => $_W['uniacid'])); + } else { + if (!$is_add) { + $file_size = -$file_size; + } + $result = pdo_update('uni_settings', array('attachment_size +=' => $file_size), array('uniacid' => $_W['uniacid'])); + } + + $cachekey = cache_system_key('unisetting', array('uniacid' => $uniacid)); + $unisetting = cache_load($cachekey); + $unisetting['attachment_size'] += $file_size; + $unisetting['attachment_size'] = max(0, $unisetting['attachment_size']); + cache_write($cachekey, $unisetting); + } + + return $result; +} diff --git a/framework/function/global.func.php b/framework/function/global.func.php new file mode 100644 index 0000000..76eb216 --- /dev/null +++ b/framework/function/global.func.php @@ -0,0 +1,1350 @@ + $newLength) { + $version2 .= str_repeat('0', $oldLength - $newLength); + } + if ($newLength > $oldLength) { + $version1 .= str_repeat('0', $newLength - $oldLength); + } + $version1 = intval($version1); + $version2 = intval($version2); + } + + return version_compare($version1, $version2); +} + +function iget_headers($url, $format = 0) { + $result = @get_headers($url, $format); + if (empty($result)) { + stream_context_set_default(array( + 'ssl' => array( + 'verify_peer' => false, + 'verify_peer_name' => false, + ), + )); + $result = get_headers($url, $format); + } + + return $result; +} + +function igetimagesize($filename, $imageinfo = array()) { + $result = @getimagesize($filename, $imageinfo); + if (empty($result)) { + $file_content = ihttp_request($filename); + $content = $file_content['content']; + $result = getimagesize('data://image/jpeg;base64,' . base64_encode($content), $imageinfo); + } + + return $result; +} + + +function istripslashes($var) { + if (is_array($var)) { + foreach ($var as $key => $value) { + $var[stripslashes($key)] = istripslashes($value); + } + } else { + $var = stripslashes($var); + } + + return $var; +} + + +function ihtmlspecialchars($var) { + if (is_array($var)) { + foreach ($var as $key => $value) { + $var[htmlspecialchars($key)] = ihtmlspecialchars($value); + } + } else { + $var = str_replace('&', '&', htmlspecialchars($var, ENT_QUOTES)); + } + + return $var; +} + + +function isetcookie($key, $value, $expire = 0, $httponly = false) { + global $_W; + $expire = 0 != $expire ? (TIMESTAMP + $expire) : 0; + $secure = 443 == $_SERVER['SERVER_PORT'] ? 1 : 0; + + return setcookie($_W['config']['cookie']['pre'] . $key, $value, $expire, $_W['config']['cookie']['path'], $_W['config']['cookie']['domain'], $secure, $httponly); +} + + +function igetcookie($key) { + global $_W; + $key = $_W['config']['cookie']['pre'] . $key; + + return $_COOKIE[$key]; +} + + +function getip() { + static $ip = ''; + if (isset($_SERVER['REMOTE_ADDR'])) { + $ip = $_SERVER['REMOTE_ADDR']; + } + if (isset($_SERVER['HTTP_CDN_SRC_IP'])) { + $ip = $_SERVER['HTTP_CDN_SRC_IP']; + } elseif (isset($_SERVER['HTTP_CLIENT_IP'])) { + $ip = $_SERVER['HTTP_CLIENT_IP']; + } elseif (isset($_SERVER['HTTP_X_FORWARDED_FOR']) && preg_match_all('#\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}#s', $_SERVER['HTTP_X_FORWARDED_FOR'], $matches)) { + foreach ($matches[0] as $xip) { + if (!preg_match('#^(10|172\.16|192\.168)\.#', $xip)) { + $ip = $xip; + break; + } + } + } + if (preg_match('/^([0-9]{1,3}\.){3}[0-9]{1,3}$/', $ip)) { + return $ip; + } else { + return '127.0.0.1'; + } +} + + +function token($specialadd = '') { + global $_W; + if (!defined('IN_MOBILE')) { + $key = complex_authkey(); + + return substr(md5($key . $specialadd), 8, 8); + } else { + if (!empty($_SESSION['token'])) { + $count = count($_SESSION['token']) - 5; + asort($_SESSION['token']); + foreach ($_SESSION['token'] as $k => $v) { + if (TIMESTAMP - $v > 300 || $count > 0) { + unset($_SESSION['token'][$k]); + --$count; + } + } + } + $key = substr(random(20), 0, 4); + $_SESSION['token'][$key] = TIMESTAMP; + + return $key; + } +} + + +function random($length, $numeric = false) { + $seed = base_convert(md5(microtime() . $_SERVER['DOCUMENT_ROOT']), 16, $numeric ? 10 : 35); + $seed = $numeric ? (str_replace('0', '', $seed) . '012340567890') : ($seed . 'zZ' . strtoupper($seed)); + if ($numeric) { + $hash = ''; + } else { + $hash = chr(rand(1, 26) + rand(0, 1) * 32 + 64); + --$length; + } + $max = strlen($seed) - 1; + for ($i = 0; $i < $length; ++$i) { + $hash .= $seed[mt_rand(0, $max)]; + } + + return $hash; +} + + +function checksubmit($var = 'submit', $allowget = false) { + global $_W, $_GPC; + if (empty($_GPC[$var])) { + return false; + } + if (defined('IN_SYS')) { + if ($allowget || (($_W['ispost'] && !empty($_W['token']) && $_W['token'] == $_GPC['token']) && (empty($_SERVER['HTTP_REFERER']) || preg_replace("/https?:\/\/([^\:\/]+).*/i", '\\1', $_SERVER['HTTP_REFERER']) == preg_replace("/([^\:]+).*/", '\\1', $_SERVER['HTTP_HOST'])))) { + return true; + } + } else { + if (empty($_W['isajax']) && empty($_SESSION['token'][$_GPC['token']])) { + exit(''); + } else { + unset($_SESSION['token'][$_GPC['token']]); + } + + return true; + } + + return false; +} + +function complex_authkey() { + global $_W; + $key = (array) $_W['setting']['site']; + $key['authkey'] = $_W['config']['setting']['authkey']; + + return implode('', $key); +} +function checkcaptcha($code) { + global $_GPC; + session_start(); + $key = complex_authkey(); + $codehash = md5(strtolower($code) . $key); + if (!empty($_GPC['__code']) && $codehash == $_SESSION['__code']) { + $return = true; + } else { + $return = false; + } + $_SESSION['__code'] = ''; + isetcookie('__code', ''); + + return $return; +} + + +function tablename($table) { + if (empty($GLOBALS['_W']['config']['db']['master'])) { + return "`{$GLOBALS['_W']['config']['db']['tablepre']}{$table}`"; + } + + return "`{$GLOBALS['_W']['config']['db']['master']['tablepre']}{$table}`"; +} + + +function array_elements($keys, $src, $default = false) { + $return = array(); + if (!is_array($keys)) { + $keys = array($keys); + } + foreach ($keys as $key) { + if (isset($src[$key])) { + $return[$key] = $src[$key]; + } else { + $return[$key] = $default; + } + } + + return $return; +} + + +function iarray_sort($array, $keys, $type = 'asc') { + $keysvalue = $new_array = array(); + foreach ($array as $k => $v) { + $keysvalue[$k] = $v[$keys]; + } + if ('asc' == $type) { + asort($keysvalue); + } else { + arsort($keysvalue); + } + reset($keysvalue); + foreach ($keysvalue as $k => $v) { + $new_array[$k] = $array[$k]; + } + + return $new_array; +} + + +function range_limit($num, $downline, $upline, $returnNear = true) { + $num = intval($num); + $downline = intval($downline); + $upline = intval($upline); + if ($num < $downline) { + return empty($returnNear) ? false : $downline; + } elseif ($num > $upline) { + return empty($returnNear) ? false : $upline; + } else { + return empty($returnNear) ? true : $num; + } +} + + +function ijson_encode($value, $options = 0) { + if (empty($value)) { + return false; + } + if (version_compare(PHP_VERSION, '5.4.0', '<') && JSON_UNESCAPED_UNICODE == $options) { + $str = json_encode($value); + $json_str = preg_replace_callback("#\\\u([0-9a-f]{4})#i", function ($matchs) { + return iconv('UCS-2BE', 'UTF-8', pack('H4', $matchs[1])); + }, $str); + } else { + $json_str = json_encode($value, $options); + } + + return addslashes($json_str); +} + + +function iserializer($value) { + return serialize($value); +} + + +function iunserializer($value) { + if (empty($value)) { + return array(); + } + if (!is_serialized($value)) { + return $value; + } + if (version_compare(PHP_VERSION, '7.0.0', '>=')) { + $result = unserialize($value, array('allowed_classes' => false)); + } else { + if (preg_match('/[oc]:[^:]*\d+:/i', $value)) { + return array(); + } + $result = unserialize($value); + } + if (false === $result) { + $temp = preg_replace_callback('!s:(\d+):"(.*?)";!s', function ($matchs) { + return 's:' . strlen($matchs[2]) . ':"' . $matchs[2] . '";'; + }, $value); + + return unserialize($temp); + } else { + return $result; + } +} + + +function is_base64($str) { + if (!is_string($str)) { + return false; + } + + return $str == base64_encode(base64_decode($str)); +} + + +function is_serialized($data, $strict = true) { + if (!is_string($data)) { + return false; + } + $data = trim($data); + if ('N;' == $data) { + return true; + } + if (strlen($data) < 4) { + return false; + } + if (':' !== $data[1]) { + return false; + } + if ($strict) { + $lastc = substr($data, -1); + if (';' !== $lastc && '}' !== $lastc) { + return false; + } + } else { + $semicolon = strpos($data, ';'); + $brace = strpos($data, '}'); + if (false === $semicolon && false === $brace) { + return false; + } + if (false !== $semicolon && $semicolon < 3) { + return false; + } + if (false !== $brace && $brace < 4) { + return false; + } + } + $token = $data[0]; + switch ($token) { + case 's': + if ($strict) { + if ('"' !== substr($data, -2, 1)) { + return false; + } + } elseif (false === strpos($data, '"')) { + return false; + } + case 'a': + return (bool) preg_match("/^{$token}:[0-9]+:/s", $data); + case 'O': + return false; + case 'b': + case 'i': + case 'd': + $end = $strict ? '$' : ''; + + return (bool) preg_match("/^{$token}:[0-9.E-]+;$end/", $data); + } + + return false; +} + + +function wurl($segment, $params = array(), $contain_domain = false) { + global $_W; + list($controller, $action, $do) = explode('/', $segment); + if ($contain_domain) { + $url = $_W['siteroot'] . 'web/index.php?'; + } else { + $url = './index.php?'; + } + if (!empty($controller)) { + $url .= "c={$controller}&"; + } + if (!empty($action)) { + $url .= "a={$action}&"; + } + if (!empty($do)) { + $url .= "do={$do}&"; + } + if (!empty($params)) { + $queryString = http_build_query($params, '', '&'); + $url .= $queryString; + } + + return $url; +} + +if (!function_exists('murl')) { + + function murl($segment, $params = array(), $noredirect = true, $addhost = false) { + global $_W; + list($controller, $action, $do) = explode('/', $segment); + if (!empty($addhost)) { + $url = $_W['siteroot'] . 'app/'; + } else { + $url = './'; + } + $str = ''; + if (!empty($_W['account']) && $_W['account']['type'] == ACCOUNT_TYPE_WEBAPP_NORMAL) { + $str .= '&a=webapp'; + } + if (!empty($_W['account']) && $_W['account']['type'] == ACCOUNT_TYPE_PHONEAPP_NORMAL) { + $str .= '&a=phoneapp'; + } + $url .= "index.php?i={$_W['uniacid']}{$str}&"; + if (!empty($controller)) { + $url .= "c={$controller}&"; + } + if (!empty($action)) { + $url .= "a={$action}&"; + } + if (!empty($do)) { + $url .= "do={$do}&"; + } + if (!empty($params)) { + $queryString = http_build_query($params, '', '&'); + $url .= $queryString; + if (false === $noredirect) { + $url .= '&wxref=mp.weixin.qq.com#wechat_redirect'; + } + } + + return $url; + } +} + + +function pagination($total, $pageIndex, $pageSize = 15, $url = '', $context = array('before' => 5, 'after' => 4, 'ajaxcallback' => '', 'callbackfuncname' => '')) { + global $_W; + $pdata = array( + 'tcount' => 0, + 'tpage' => 0, + 'cindex' => 0, + 'findex' => 0, + 'pindex' => 0, + 'nindex' => 0, + 'lindex' => 0, + 'options' => '', + ); + if (empty($context['before'])) { + $context['before'] = 5; + } + if (empty($context['after'])) { + $context['after'] = 4; + } + + if ($context['ajaxcallback']) { + $context['isajax'] = true; + } + + if ($context['callbackfuncname']) { + $callbackfunc = $context['callbackfuncname']; + } + + $pdata['tcount'] = $total; + $pdata['tpage'] = (empty($pageSize) || $pageSize < 0) ? 1 : ceil($total / $pageSize); + if ($pdata['tpage'] <= 1) { + return ''; + } + $cindex = $pageIndex; + $cindex = min($cindex, $pdata['tpage']); + $cindex = max($cindex, 1); + $pdata['cindex'] = $cindex; + $pdata['findex'] = 1; + $pdata['pindex'] = $cindex > 1 ? $cindex - 1 : 1; + $pdata['nindex'] = $cindex < $pdata['tpage'] ? $cindex + 1 : $pdata['tpage']; + $pdata['lindex'] = $pdata['tpage']; + + if ($context['isajax']) { + if (empty($url)) { + $url = $_W['script_name'] . '?' . http_build_query($_GET); + } + $pdata['faa'] = 'href="javascript:;" page="' . $pdata['findex'] . '" ' . ($callbackfunc ? 'ng-click="' . $callbackfunc . '(\'' . $url . '\', \'' . $pdata['findex'] . '\', this);"' : ''); + $pdata['paa'] = 'href="javascript:;" page="' . $pdata['pindex'] . '" ' . ($callbackfunc ? 'ng-click="' . $callbackfunc . '(\'' . $url . '\', \'' . $pdata['pindex'] . '\', this);"' : ''); + $pdata['naa'] = 'href="javascript:;" page="' . $pdata['nindex'] . '" ' . ($callbackfunc ? 'ng-click="' . $callbackfunc . '(\'' . $url . '\', \'' . $pdata['nindex'] . '\', this);"' : ''); + $pdata['laa'] = 'href="javascript:;" page="' . $pdata['lindex'] . '" ' . ($callbackfunc ? 'ng-click="' . $callbackfunc . '(\'' . $url . '\', \'' . $pdata['lindex'] . '\', this);"' : ''); + } else { + if ($url) { + $pdata['faa'] = 'href="?' . str_replace('*', $pdata['findex'], $url) . '"'; + $pdata['paa'] = 'href="?' . str_replace('*', $pdata['pindex'], $url) . '"'; + $pdata['naa'] = 'href="?' . str_replace('*', $pdata['nindex'], $url) . '"'; + $pdata['laa'] = 'href="?' . str_replace('*', $pdata['lindex'], $url) . '"'; + } else { + $_GET['page'] = $pdata['findex']; + $pdata['faa'] = 'href="' . $_W['script_name'] . '?' . http_build_query($_GET) . '"'; + $_GET['page'] = $pdata['pindex']; + $pdata['paa'] = 'href="' . $_W['script_name'] . '?' . http_build_query($_GET) . '"'; + $_GET['page'] = $pdata['nindex']; + $pdata['naa'] = 'href="' . $_W['script_name'] . '?' . http_build_query($_GET) . '"'; + $_GET['page'] = $pdata['lindex']; + $pdata['laa'] = 'href="' . $_W['script_name'] . '?' . http_build_query($_GET) . '"'; + } + } + $html = '
'; + + return $html; +} + + +function tomedia($src, $local_path = false, $is_cahce = false) { + global $_W; + $src = trim($src); + if (empty($src)) { + return ''; + } + if ($is_cahce) { + $src .= '?v=' . time(); + } + + if (strexists($src, 'c=utility&a=wxcode&do=image&attach=')) { + return $src; + } + + $t = strtolower($src); + if (strexists($t, 'https://mmbiz.qlogo.cn') || strexists($t, 'http://mmbiz.qpic.cn')) { + $url = url('utility/wxcode/image', array('attach' => $src)); + + return $_W['siteroot'] . 'web' . ltrim($url, '.'); + } + + if ('//' == substr($src, 0, 2)) { + return 'http:' . $src; + } + if (('http://' == substr($src, 0, 7)) || ('https://' == substr($src, 0, 8))) { + return $src; + } + + if (strexists($src, 'addons/')) { + return $_W['siteroot'] . substr($src, strpos($src, 'addons/')); + } + if (strexists($src, 'app/themes/')) { + return $_W['siteroot'] . substr($src, strpos($src, 'app/themes/')); + } + if (strexists($src, $_W['siteroot']) && !strexists($src, '/addons/')) { + $urls = parse_url($src); + $src = $t = substr($urls['path'], strpos($urls['path'], 'images')); + } + + //本公众号设置信息 + $wlsettings = pdo_get(PDO_NAME . 'setting', array('key' => 'enclosure', 'uniacid' => $_W['uniacid']), array('value')); + if (is_array($wlsettings)) { + $_W['wlsetting']['enclosure'] = iunserializer($wlsettings['value']); + if($_W['wlsetting']['enclosure']['service'] > 0){ + if($_W['wlsetting']['enclosure']['service'] == 2){ + $_W['setting']['remote']['type'] = 2; + $_W['setting']['remote']['alioss'] = $_W['wlsetting']['enclosure']['alioss']; + }else if($_W['wlsetting']['enclosure']['service'] == 3){ + $_W['setting']['remote']['type'] = 3; + $_W['setting']['remote']['qiniu'] = $_W['wlsetting']['enclosure']['qiniu']; + }else if($_W['wlsetting']['enclosure']['service'] == 4){ + $_W['setting']['remote']['type'] = 4; + $_W['setting']['remote']['cos'] = $_W['wlsetting']['enclosure']['tengxun']; + } + $uni_remote_setting = $_W['setting']; + }else{ + $uni_remote_setting = uni_setting_load('remote'); + } + }else{ + $uni_remote_setting = uni_setting_load('remote'); + } + if ($local_path || empty($_W['setting']['remote']['type']) && (empty($_W['uniacid']) || !empty($_W['uniacid']) && empty($uni_remote_setting['remote']['type'])) || file_exists(IA_ROOT . '/' . $_W['config']['upload']['attachdir'] . '/' . $src)) { + $src = $_W['siteroot'] . $_W['config']['upload']['attachdir'] . '/' . $src; + } else { + if (!empty($uni_remote_setting['remote']['type'])) { + if (ATTACH_FTP == $uni_remote_setting['remote']['type']) { + $src = $uni_remote_setting['remote']['ftp']['url'] . '/' . $src; + } elseif (ATTACH_OSS == $uni_remote_setting['remote']['type']) { + $src = $uni_remote_setting['remote']['alioss']['url'] . '/' . $src; + } elseif (ATTACH_QINIU == $uni_remote_setting['remote']['type']) { + $src = $uni_remote_setting['remote']['qiniu']['url'] . '/' . $src; + } elseif (ATTACH_COS == $uni_remote_setting['remote']['type']) { + $src = $uni_remote_setting['remote']['cos']['url'] . '/' . $src; + } + + } else { + $src = $_W['attachurl_remote'] . $src; + } + } + + return $src; +} + + +function to_global_media($src) { + global $_W; + $lower_src = strtolower($src); + if (('http://' == substr($lower_src, 0, 7)) || ('https://' == substr($lower_src, 0, 8)) || ('//' == substr($lower_src, 0, 2))) { + return $src; + } + $remote = setting_load('remote'); + $remote = empty($remote) ? array() : $remote['remote']; + if (empty($remote['type']) || file_exists(IA_ROOT . '/' . $_W['config']['upload']['attachdir'] . '/' . $src)) { + $src = $_W['siteroot'] . $_W['config']['upload']['attachdir'] . '/' . $src; + } else { + if (ATTACH_FTP == $remote['type']) { + $attach_url = $remote['ftp']['url'] . '/'; + } elseif (ATTACH_OSS == $remote['type']) { + $attach_url = $remote['alioss']['url'] . '/'; + } elseif (ATTACH_QINIU == $remote['type']) { + $attach_url = $remote['qiniu']['url'] . '/'; + } elseif (ATTACH_COS == $remote['type']) { + $attach_url = $remote['cos']['url'] . '/'; + } + $src = $attach_url . $src; + } + + return $src; +} + + +function error($errno, $message = '') { + return array( + 'errno' => $errno, + 'message' => $message, + ); +} + + +function is_error($data) { + if (empty($data) || !is_array($data) || !array_key_exists('errno', $data) || (array_key_exists('errno', $data) && 0 == $data['errno'])) { + return false; + } else { + return true; + } +} + + +function detect_sensitive_word($string) { + $setting = setting_load('sensitive_words'); + if (empty($setting['sensitive_words'])) { + return false; + } + $sensitive_words = $setting['sensitive_words']; + $blacklist = '/' . implode('|', $sensitive_words) . '/'; + if (preg_match($blacklist, $string, $matches)) { + return $matches[0]; + } + + return false; +} + +function referer($default = '') { + global $_GPC, $_W; + $_W['referer'] = !empty($_GPC['referer']) ? $_GPC['referer'] : $_SERVER['HTTP_REFERER']; + $_W['referer'] = '?' == substr($_W['referer'], -1) ? substr($_W['referer'], 0, -1) : $_W['referer']; + + if (strpos($_W['referer'], 'member.php?act=login')) { + $_W['referer'] = $default; + } + + $_W['referer'] = str_replace('&', '&', $_W['referer']); + $reurl = parse_url($_W['referer']); + + if (!empty($reurl['host']) && !in_array($reurl['host'], array($_SERVER['HTTP_HOST'], 'www.' . $_SERVER['HTTP_HOST'])) && !in_array($_SERVER['HTTP_HOST'], array($reurl['host'], 'www.' . $reurl['host']))) { + $_W['referer'] = $_W['siteroot']; + } elseif (empty($reurl['host'])) { + $_W['referer'] = $_W['siteroot'] . './' . $_W['referer']; + } + + return strip_tags($_W['referer']); +} + + +function strexists($string, $find) { + return !(false === strpos($string, $find)); +} + + +function cutstr($string, $length, $havedot = false, $charset = '') { + global $_W; + if (empty($charset)) { + $charset = $_W['charset']; + } + if ('gbk' == strtolower($charset)) { + $charset = 'gbk'; + } else { + $charset = 'utf8'; + } + if (istrlen($string, $charset) <= $length) { + return $string; + } + if (function_exists('mb_strcut')) { + $string = mb_substr($string, 0, $length, $charset); + } else { + $pre = '{%'; + $end = '%}'; + $string = str_replace(array('&', '"', '<', '>'), array($pre . '&' . $end, $pre . '"' . $end, $pre . '<' . $end, $pre . '>' . $end), $string); + + $strcut = ''; + $strlen = strlen($string); + + if ('utf8' == $charset) { + $n = $tn = $noc = 0; + while ($n < $strlen) { + $t = ord($string[$n]); + if (9 == $t || 10 == $t || (32 <= $t && $t <= 126)) { + $tn = 1; + ++$n; + ++$noc; + } elseif (194 <= $t && $t <= 223) { + $tn = 2; + $n += 2; + ++$noc; + } elseif (224 <= $t && $t <= 239) { + $tn = 3; + $n += 3; + ++$noc; + } elseif (240 <= $t && $t <= 247) { + $tn = 4; + $n += 4; + ++$noc; + } elseif (248 <= $t && $t <= 251) { + $tn = 5; + $n += 5; + ++$noc; + } elseif (252 == $t || 253 == $t) { + $tn = 6; + $n += 6; + ++$noc; + } else { + ++$n; + } + if ($noc >= $length) { + break; + } + } + if ($noc > $length) { + $n -= $tn; + } + $strcut = substr($string, 0, $n); + } else { + while ($n < $strlen) { + $t = ord($string[$n]); + if ($t > 127) { + $tn = 2; + $n += 2; + ++$noc; + } else { + $tn = 1; + ++$n; + ++$noc; + } + if ($noc >= $length) { + break; + } + } + if ($noc > $length) { + $n -= $tn; + } + $strcut = substr($string, 0, $n); + } + $string = str_replace(array($pre . '&' . $end, $pre . '"' . $end, $pre . '<' . $end, $pre . '>' . $end), array('&', '"', '<', '>'), $strcut); + } + + if ($havedot) { + $string = $string . '...'; + } + + return $string; +} + + +function istrlen($string, $charset = '') { + global $_W; + if (empty($charset)) { + $charset = $_W['charset']; + } + if ('gbk' == strtolower($charset)) { + $charset = 'gbk'; + } else { + $charset = 'utf8'; + } + if (function_exists('mb_strlen') && extension_loaded('mbstring')) { + return mb_strlen($string, $charset); + } else { + $n = $noc = 0; + $strlen = strlen($string); + + if ('utf8' == $charset) { + while ($n < $strlen) { + $t = ord($string[$n]); + if (9 == $t || 10 == $t || (32 <= $t && $t <= 126)) { + ++$n; + ++$noc; + } elseif (194 <= $t && $t <= 223) { + $n += 2; + ++$noc; + } elseif (224 <= $t && $t <= 239) { + $n += 3; + ++$noc; + } elseif (240 <= $t && $t <= 247) { + $n += 4; + ++$noc; + } elseif (248 <= $t && $t <= 251) { + $n += 5; + ++$noc; + } elseif (252 == $t || 253 == $t) { + $n += 6; + ++$noc; + } else { + ++$n; + } + } + } else { + while ($n < $strlen) { + $t = ord($string[$n]); + if ($t > 127) { + $n += 2; + ++$noc; + } else { + ++$n; + ++$noc; + } + } + } + + return $noc; + } +} + + +function emotion($message = '', $size = '24px') { + $emotions = array( + '/::)', '/::~', '/::B', '/::|', '/:8-)', '/::<', '/::$', '/::X', '/::Z', "/::'(", + '/::-|', '/::@', '/::P', '/::D', '/::O', '/::(', '/::+', '/:--b', '/::Q', '/::T', + '/:,@P', '/:,@-D', '/::d', '/:,@o', '/::g', '/:|-)', '/::!', '/::L', '/::>', '/::,@', + '/:,@f', '/::-S', '/:?', '/:,@x', '/:,@@', '/::8', '/:,@!', '/:!!!', '/:xx', '/:bye', + '/:wipe', '/:dig', '/:handclap', '/:&-(', '/:B-)', '/:<@', '/:@>', '/::-O', '/:>-|', + '/:P-(', "/::'|", '/:X-)', '/::*', '/:@x', '/:8*', '/:pd', '/:', '/:beer', '/:basketb', + '/:oo', '/:coffee', '/:eat', '/:pig', '/:rose', '/:fade', '/:showlove', '/:heart', + '/:break', '/:cake', '/:li', '/:bome', '/:kn', '/:footb', '/:ladybug', '/:shit', '/:moon', + '/:sun', '/:gift', '/:hug', '/:strong', '/:weak', '/:share', '/:v', '/:@)', '/:jj', '/:@@', + '/:bad', '/:lvu', '/:no', '/:ok', '/:love', '/:', '/:jump', '/:shake', '/:', '/:circle', + '/:kotow', '/:turn', '/:skip', '/:oY', '/:#-0', '/:hiphot', '/:kiss', '/:<&', '/:&>', + ); + foreach ($emotions as $index => $emotion) { + $message = str_replace($emotion, '', $message); + } + + return $message; +} + + +function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) { + $ckey_length = 4; + $key = md5('' != $key ? $key : $GLOBALS['_W']['config']['setting']['authkey']); + $keya = md5(substr($key, 0, 16)); + $keyb = md5(substr($key, 16, 16)); + $keyc = $ckey_length ? ('DECODE' == $operation ? substr($string, 0, $ckey_length) : substr(md5(microtime()), -$ckey_length)) : ''; + + $cryptkey = $keya . md5($keya . $keyc); + $key_length = strlen($cryptkey); + + $string = 'DECODE' == $operation ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0) . substr(md5($string . $keyb), 0, 16) . $string; + $string_length = strlen($string); + + $result = ''; + $box = range(0, 255); + + $rndkey = array(); + for ($i = 0; $i <= 255; ++$i) { + $rndkey[$i] = ord($cryptkey[$i % $key_length]); + } + + for ($j = $i = 0; $i < 256; ++$i) { + $j = ($j + $box[$i] + $rndkey[$i]) % 256; + $tmp = $box[$i]; + $box[$i] = $box[$j]; + $box[$j] = $tmp; + } + + for ($a = $j = $i = 0; $i < $string_length; ++$i) { + $a = ($a + 1) % 256; + $j = ($j + $box[$a]) % 256; + $tmp = $box[$a]; + $box[$a] = $box[$j]; + $box[$j] = $tmp; + $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256])); + } + + if ('DECODE' == $operation) { + if ((0 == substr($result, 0, 10) || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26) . $keyb), 0, 16)) { + return substr($result, 26); + } else { + return ''; + } + } else { + return $keyc . str_replace('=', '', base64_encode($result)); + } +} + + +function sizecount($size, $unit = false) { + if ($size >= 1073741824) { + $size = round($size / 1073741824 * 100) / 100 . ' GB'; + } elseif ($size >= 1048576) { + $size = round($size / 1048576 * 100) / 100 . ' MB'; + } elseif ($size >= 1024) { + $size = round($size / 1024 * 100) / 100 . ' KB'; + } else { + $size = $size . ' Bytes'; + } + if ($unit) { + $size = preg_replace('/[^0-9\.]/', '', $size); + } + + return $size; +} + + +function bytecount($str) { + if ('b' == strtolower($str[strlen($str) - 1])) { + $str = substr($str, 0, -1); + } + if ('k' == strtolower($str[strlen($str) - 1])) { + return floatval($str) * 1024; + } + if ('m' == strtolower($str[strlen($str) - 1])) { + return floatval($str) * 1048576; + } + if ('g' == strtolower($str[strlen($str) - 1])) { + return floatval($str) * 1073741824; + } +} + + +function array2xml($arr, $level = 1) { + $s = 1 == $level ? '' : ''; + foreach ($arr as $tagname => $value) { + if (is_numeric($tagname)) { + $tagname = $value['TagName']; + unset($value['TagName']); + } + if (!is_array($value)) { + $s .= "<{$tagname}>" . (!is_numeric($value) ? '' : '') . ""; + } else { + $s .= "<{$tagname}>" . array2xml($value, $level + 1) . ""; + } + } + $s = preg_replace("/([\x01-\x08\x0b-\x0c\x0e-\x1f])+/", ' ', $s); + + return 1 == $level ? $s . '' : $s; +} + +function xml2array($xml) { + if (empty($xml)) { + return array(); + } + $result = array(); + $xmlobj = isimplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA); + if ($xmlobj instanceof SimpleXMLElement) { + $result = json_decode(json_encode($xmlobj), true); + if (is_array($result)) { + return $result; + } else { + return ''; + } + } else { + return $result; + } +} + + +function scriptname() { + $script_name = basename($_SERVER['SCRIPT_FILENAME']); + if (basename($_SERVER['SCRIPT_NAME']) === $script_name) { + $script_name = $_SERVER['SCRIPT_NAME']; + } else { + if (basename($_SERVER['PHP_SELF']) === $script_name) { + $script_name = $_SERVER['PHP_SELF']; + } else { + if (isset($_SERVER['ORIG_SCRIPT_NAME']) && basename($_SERVER['ORIG_SCRIPT_NAME']) === $script_name) { + $script_name = $_SERVER['ORIG_SCRIPT_NAME']; + } else { + if (false !== ($pos = strpos($_SERVER['PHP_SELF'], '/'))) { + $script_name = substr($_SERVER['SCRIPT_NAME'], 0, $pos) . '/' . $script_name; + } else { + if (isset($_SERVER['DOCUMENT_ROOT']) && 0 === strpos($_SERVER['SCRIPT_FILENAME'], $_SERVER['DOCUMENT_ROOT'])) { + $script_name = str_replace('\\', '/', str_replace($_SERVER['DOCUMENT_ROOT'], '', $_SERVER['SCRIPT_FILENAME'])); + } else { + $script_name = 'unknown'; + } + } + } + } + } + + return $script_name; +} + + +function utf8_bytes($cp) { + if ($cp > 0x10000) { + return chr(0xF0 | (($cp & 0x1C0000) >> 18)) . + chr(0x80 | (($cp & 0x3F000) >> 12)) . + chr(0x80 | (($cp & 0xFC0) >> 6)) . + chr(0x80 | ($cp & 0x3F)); + } elseif ($cp > 0x800) { + return chr(0xE0 | (($cp & 0xF000) >> 12)) . + chr(0x80 | (($cp & 0xFC0) >> 6)) . + chr(0x80 | ($cp & 0x3F)); + } elseif ($cp > 0x80) { + return chr(0xC0 | (($cp & 0x7C0) >> 6)) . + chr(0x80 | ($cp & 0x3F)); + } else { + return chr($cp); + } +} + +function media2local($media_id, $all = false) { + global $_W; + load()->model('material'); + $data = material_get($media_id); + if (!is_error($data)) { + $data['attachment'] = tomedia($data['attachment'], true); + if (!$all) { + return $data['attachment']; + } + + return $data; + } else { + return ''; + } +} + +function aes_decode($message, $encodingaeskey = '', $appid = '') { + $key = base64_decode($encodingaeskey . '='); + + $ciphertext_dec = base64_decode($message); + $iv = substr($key, 0, 16); + $decrypted = openssl_decrypt($ciphertext_dec, 'AES-256-CBC', $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv); + $block_size = 32; + + $pad = ord(substr($decrypted, -1)); + if ($pad < 1 || $pad > 32) { + $pad = 0; + } + $result = substr($decrypted, 0, (strlen($decrypted) - $pad)); + if (strlen($result) < 16) { + return ''; + } + $content = substr($result, 16, strlen($result)); + $len_list = unpack('N', substr($content, 0, 4)); + $contentlen = $len_list[1]; + $content = substr($content, 4, $contentlen); + $from_appid = substr($content, $xml_len + 4); + if (!empty($appid) && $appid != $from_appid) { + return ''; + } + + return $content; +} + +function aes_encode($message, $encodingaeskey = '', $appid = '') { + $key = base64_decode($encodingaeskey . '='); + $text = random(16) . pack('N', strlen($message)) . $message . $appid; + + $iv = substr($key, 0, 16); + + $block_size = 32; + $text_length = strlen($text); + $amount_to_pad = $block_size - ($text_length % $block_size); + if (0 == $amount_to_pad) { + $amount_to_pad = $block_size; + } + $pad_chr = chr($amount_to_pad); + $tmp = ''; + for ($index = 0; $index < $amount_to_pad; ++$index) { + $tmp .= $pad_chr; + } + $text = $text . $tmp; + $encrypted = openssl_encrypt($text, 'AES-256-CBC', $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv); + $encrypt_msg = base64_encode($encrypted); + + return $encrypt_msg; +} + + +function aes_pkcs7_decode($encrypt_data, $key, $iv = false) { + load()->library('pkcs7'); + $encrypt_data = base64_decode($encrypt_data); + if (!empty($iv)) { + $iv = base64_decode($iv); + } + $pc = new Prpcrypt($key); + $result = $pc->decrypt($encrypt_data, $iv); + if (0 != $result[0]) { + return error($result[0], '解密失败'); + } + + return $result[1]; +} + + +function isimplexml_load_string($string, $class_name = 'SimpleXMLElement', $options = 0, $ns = '', $is_prefix = false) { + libxml_disable_entity_loader(true); + if (preg_match('/(\<\!DOCTYPE|\<\!ENTITY)/i', $string)) { + return false; + } + $string = preg_replace('/[\\x00-\\x08\\x0b-\\x0c\\x0e-\\x1f\\x7f]/', '', $string); return simplexml_load_string($string, $class_name, $options, $ns, $is_prefix); +} + +function ihtml_entity_decode($str) { + $str = str_replace(' ', '#nbsp;', $str); + + return str_replace('#nbsp;', ' ', html_entity_decode(urldecode($str))); +} + +function iarray_change_key_case($array, $case = CASE_LOWER) { + if (!is_array($array) || empty($array)) { + return array(); + } + $array = array_change_key_case($array, $case); + foreach ($array as $key => $value) { + if (empty($value) && is_array($value)) { + $array[$key] = ''; + } + if (!empty($value) && is_array($value)) { + $array[$key] = iarray_change_key_case($value, $case); + } + } + + return $array; +} + + +function parse_path($path) { + $danger_char = array('../', '{php', 'library('pinyin'); + $pinyin = new Pinyin_Pinyin(); + } + $first_char = $pinyin->get_first_char($str); + + return $first_char; +} + + +function strip_emoji($nickname) { + $clean_text = ''; + $regexEmoticons = '/[\x{1F600}-\x{1F64F}]/u'; + $clean_text = preg_replace($regexEmoticons, '_', $nickname); + $regexSymbols = '/[\x{1F300}-\x{1F5FF}]/u'; + $clean_text = preg_replace($regexSymbols, '_', $clean_text); + $regexTransport = '/[\x{1F680}-\x{1F6FF}]/u'; + $clean_text = preg_replace($regexTransport, '_', $clean_text); + $regexMisc = '/[\x{2600}-\x{26FF}]/u'; + $clean_text = preg_replace($regexMisc, '_', $clean_text); + $regexDingbats = '/[\x{2700}-\x{27BF}]/u'; + $clean_text = preg_replace($regexDingbats, '_', $clean_text); + + $clean_text = str_replace("'", '_', $clean_text); + $clean_text = str_replace('"', '_', $clean_text); + $clean_text = str_replace('“', '_', $clean_text); + $clean_text = str_replace('゛', '_', $clean_text); + $search = array(' ', ' ', "\n", "\r", "\t"); + $replace = array('_', '_', '_', '_', '_'); + + return str_replace($search, $replace, $clean_text); +} + + +function emoji_unicode_decode($string) { + preg_match_all('/\[U\+(\\w{4,})\]/i', $string, $match); + if (!empty($match[1])) { + foreach ($match[1] as $emojiUSB) { + $string = str_ireplace("[U+{$emojiUSB}]", utf8_bytes(hexdec($emojiUSB)), $string); + } + } + + return $string; +} + +function emoji_unicode_encode($string) { + $ranges = array( + '\\\\ud83c[\\\\udf00-\\\\udfff]', '\\\\ud83d[\\\\udc00-\\\\ude4f]', '\\\\ud83d[\\\\ude80-\\\\udeff]', ); + preg_match_all('/' . implode('|', $ranges) . '/i', $string, $match); + print_r($match); + exit; +} + + +if (!function_exists('starts_with')) { + function starts_with($haystack, $needles) { + foreach ((array) $needles as $needle) { + if ('' != $needle && substr($haystack, 0, strlen($needle)) === (string) $needle) { + return true; + } + } + + return false; + } +} + + +function icall_user_func($callback) { + if (function_exists($callback)) { + $args = func_get_args(); + switch (func_num_args()) { + case 1: + return call_user_func($callback); + break; + case 2: + return call_user_func($callback, $args[1]); + break; + case 3: + return call_user_func($callback, $args[1], $args[2]); + break; + case 4: + return call_user_func($callback, $args[1], $args[2], $args[3]); + break; + case 5: + return call_user_func($callback, $args[1], $args[2], $args[3], $args[4]); + break; + } + } + + return ''; +} + +if (!function_exists('dd')) { + function dd($data) { + echo "
";
+        print_r($data);
+        die();
+    }
+}
+
+load()->func('safe');
+load()->func('system');
\ No newline at end of file
diff --git a/framework/function/logging.func.php b/framework/function/logging.func.php
new file mode 100644
index 0000000..a3084eb
--- /dev/null
+++ b/framework/function/logging.func.php
@@ -0,0 +1,59 @@
+func('file');
+	mkdirs(dirname($filename));
+
+	$logFormat = '%date %type %user %url %context';
+	if (!empty($GLOBALS['_POST'])) {
+		$context[] = logging_implode($GLOBALS['_POST']);
+	}
+
+	if (is_array($log)) {
+		$context[] = logging_implode($log);
+	} else {
+		$context[] = preg_replace('/[ \t\r\n]+/', ' ', $log);
+	}
+
+	$log = str_replace(explode(' ', $logFormat), array(
+		'[' . date('Y-m-d H:i:s', $_W['timestamp']) . ']',
+		$type,
+		$_W['username'],
+		$_SERVER['PHP_SELF'] . '?' . $_SERVER['QUERY_STRING'],
+		implode("\n", $context),
+	), $logFormat);
+	if (file_exists($filename)) {
+		$log =  $log . "\r\n";
+	} else {
+		$log = "\r\n" . $log . "\r\n";
+	}
+	file_put_contents($filename, $log, FILE_APPEND);
+	return true;
+}
+
+function logging_implode($array, $skip = array()) {
+	$return = '';
+	if (is_array($array) && !empty($array)) {
+		foreach ($array as $key => $value) {
+			if (empty($skip) || !in_array($key, $skip, true)) {
+				if (is_array($value)) {
+					$return .= $key . '={' . logging_implode($value, $skip) . '}; ';
+				} else {
+					$return .= "$key=$value; ";
+				}
+			}
+		}
+	}
+
+	return $return;
+}
\ No newline at end of file
diff --git a/framework/function/pdo.func.php b/framework/function/pdo.func.php
new file mode 100644
index 0000000..35ccbb5
--- /dev/null
+++ b/framework/function/pdo.func.php
@@ -0,0 +1,143 @@
+classs('slave.db');
+			$db = new SlaveDb('master');
+		} else {
+			load()->classs('db');
+			if (empty($_W['config']['db']['master'])) {
+				$_W['config']['db']['master'] = $GLOBALS['_W']['config']['db'];
+			}
+			$db = new DB('master');
+		}
+	}
+
+	return $db;
+}
+
+
+function pdos($table = '') {
+	return load()->singleton('Query');
+}
+
+
+function pdo_query($sql, $params = array()) {
+	return pdo()->query($sql, $params);
+}
+
+
+function pdo_fetchcolumn($sql, $params = array(), $column = 0) {
+	return pdo()->fetchcolumn($sql, $params, $column);
+}
+
+function pdo_fetch($sql, $params = array()) {
+	return pdo()->fetch($sql, $params);
+}
+
+function pdo_fetchall($sql, $params = array(), $keyfield = '') {
+	return pdo()->fetchall($sql, $params, $keyfield);
+}
+
+
+function pdo_get($tablename, $condition = array(), $fields = array()) {
+	return pdo()->get($tablename, $condition, $fields);
+}
+
+function pdo_getall($tablename, $condition = array(), $fields = array(), $keyfield = '', $orderby = array(), $limit = array()) {
+	return pdo()->getall($tablename, $condition, $fields, $keyfield, $orderby, $limit);
+}
+
+function pdo_getslice($tablename, $condition = array(), $limit = array(), &$total = null, $fields = array(), $keyfield = '', $orderby = array()) {
+	return pdo()->getslice($tablename, $condition, $limit, $total, $fields, $keyfield, $orderby);
+}
+
+function pdo_getcolumn($tablename, $condition = array(), $field) {
+	return pdo()->getcolumn($tablename, $condition, $field);
+}
+
+
+function pdo_exists($tablename, $condition = array()) {
+	return pdo()->exists($tablename, $condition);
+}
+
+
+function pdo_count($tablename, $condition = array(), $cachetime = 15) {
+	return pdo()->count($tablename, $condition, $cachetime);
+}
+
+
+function pdo_update($table, $data = array(), $params = array(), $glue = 'AND') {
+	return pdo()->update($table, $data, $params, $glue);
+}
+
+
+function pdo_insert($table, $data = array(), $replace = false) {
+	return pdo()->insert($table, $data, $replace);
+}
+
+
+function pdo_delete($table, $params = array(), $glue = 'AND') {
+	return pdo()->delete($table, $params, $glue);
+}
+
+
+function pdo_insertid() {
+	return pdo()->insertid();
+}
+
+
+function pdo_begin() {
+	pdo()->begin();
+}
+
+
+function pdo_commit() {
+	pdo()->commit();
+}
+
+
+function pdo_rollback() {
+	pdo()->rollBack();
+}
+
+
+function pdo_debug($output = true, $append = array()) {
+	return pdo()->debug($output, $append);
+}
+
+function pdo_run($sql) {
+	return pdo()->run($sql);
+}
+
+
+function pdo_fieldexists($tablename, $fieldname = '') {
+	return pdo()->fieldexists($tablename, $fieldname);
+}
+
+function pdo_fieldmatch($tablename, $fieldname, $datatype = '', $length = '') {
+	return pdo()->fieldmatch($tablename, $fieldname, $datatype, $length);
+}
+
+function pdo_indexexists($tablename, $indexname = '') {
+	return pdo()->indexexists($tablename, $indexname);
+}
+
+
+function pdo_fetchallfields($tablename) {
+	$fields = pdo_fetchall("DESCRIBE {$tablename}", array(), 'Field');
+	$fields = array_keys($fields);
+
+	return $fields;
+}
+
+
+function pdo_tableexists($tablename) {
+	return pdo()->tableexists($tablename);
+}
diff --git a/framework/function/safe.func.php b/framework/function/safe.func.php
new file mode 100644
index 0000000..fb957ed
--- /dev/null
+++ b/framework/function/safe.func.php
@@ -0,0 +1,245 @@
+ $url) {
+            $val = str_replace($url, 'we7_' . $key . '_we7placeholder', $val);
+            $encode_url_list[] = $url;
+        }
+    }
+    $ra1 = array('javascript', 'vbscript', 'expression', 'applet', 'meta', 'xml', 'blink', 'link', 'script', 'embed', 'object', 'frameset', 'ilayer', 'bgsound', 'base');
+    $ra2 = array('onabort', 'onactivate', 'onafterprint', 'onafterupdate', 'onbeforeactivate', 'onbeforecopy', 'onbeforecut', 'onbeforedeactivate', 'onbeforeeditfocus', 'onbeforepaste', 'onbeforeprint', 'onbeforeunload', 'onbeforeupdate', 'onblur', 'onbounce', 'oncellchange', 'onchange', 'onclick', 'oncontextmenu', 'oncontrolselect', 'oncopy', 'oncut', 'ondataavailable', 'ondatasetchanged', 'ondatasetcomplete', 'ondblclick', 'ondeactivate', 'ondrag', 'ondragend', 'ondragenter', 'ondragleave', 'ondragover', 'ondragstart', 'ondrop', 'onerror', 'onerrorupdate', 'onfilterchange', 'onfinish', 'onfocus', 'onfocusin', 'onfocusout', 'onhelp', 'onkeydown', 'onkeypress', 'onkeyup', 'onlayoutcomplete', 'onload', 'onlosecapture', 'onmousedown', 'onmouseenter', 'onmouseleave', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'onmousewheel', 'onmove', 'onmoveend', 'onmovestart', 'onpaste', 'onpropertychange', 'onreadystatechange', 'onreset', 'onresize', 'onresizeend', 'onresizestart', 'onrowenter', 'onrowexit', 'onrowsdelete', 'onrowsinserted', 'onscroll', 'onselect', 'onselectionchange', 'onselectstart', 'onstart', 'onstop', 'onsubmit', 'onunload', '@import');
+    $ra = array_merge($ra1, $ra2);
+    $found = true;
+    while (true == $found) {
+        $val_before = $val;
+        for ($i = 0; $i < sizeof($ra); ++$i) {
+            $pattern = '/';
+            for ($j = 0; $j < strlen($ra[$i]); ++$j) {
+                if ($j > 0) {
+                    $pattern .= '(';
+                    $pattern .= '(&#[xX]0{0,8}([9ab]);)';
+                    $pattern .= '|';
+                    $pattern .= '|(�{0,8}([9|10|13]);)';
+                    $pattern .= ')*';
+                }
+                $pattern .= $ra[$i][$j];
+            }
+            $pattern .= '/i';
+            $replacement = substr($ra[$i], 0, 2) . '' . substr($ra[$i], 2);
+            $val = preg_replace($pattern, $replacement, $val);
+            if ($val_before == $val) {
+                $found = false;
+            }
+        }
+    }
+    if (!empty($encode_url_list) && is_array($encode_url_list)) {
+        foreach ($encode_url_list as $key => $url) {
+            $val = str_replace('we7_' . $key . '_we7placeholder', $url, $val);
+        }
+    }
+
+    return $val;
+}
+
+function safe_bad_str_replace($string)
+{
+    if (empty($string)) {
+        return '';
+    }
+    $badstr = array("\0", '%00', '%3C', '%3E', ' "'|(and|or)\\b.+?(>|<|=|in|like)|\\/\\*.+?\\*\\/|<\\s*script\\b|\\bEXEC\\b|UNION.+?SELECT|UPDATE.+?SET|INSERT\\s+INTO.+?VALUES|(SELECT|DELETE).+?FROM|(CREATE|ALTER|DROP|TRUNCATE)\\s+(TABLE|DATABASE)",
+			'p' => '\\b(and|or)\\b.{1,6}?(=|>|<|\\bin\\b|\\blike\\b)|\\/\\*.+?\\*\\/|<\\s*script\\b|\\bEXEC\\b|UNION.+?SELECT|UPDATE.+?SET|INSERT\\s+INTO.+?VALUES|(SELECT|DELETE).+?FROM|(CREATE|ALTER|DROP|TRUNCATE)\\s+(TABLE|DATABASE)',
+			'c' => '\\b(and|or)\\b.{1,6}?(=|>|<|\\bin\\b|\\blike\\b)|\\/\\*.+?\\*\\/|<\\s*script\\b|\\bEXEC\\b|UNION.+?SELECT|UPDATE.+?SET|INSERT\\s+INTO.+?VALUES|(SELECT|DELETE).+?FROM|(CREATE|ALTER|DROP|TRUNCATE)\\s+(TABLE|DATABASE)',
+		);
+		if (!isset($values)) {
+			return '';
+		}
+		if (is_array($values)) {
+			foreach ($values as $key => $val) {
+				$values[addslashes($key)] = strip_gpc($val, $type);
+			}
+		} else {
+			if (1 == preg_match('/' . $filter[$type] . '/is', $values, $match)) {
+				$values = '';
+			}
+		}
+
+		return $values;
+	}
+}
diff --git a/framework/function/tpl.func.php b/framework/function/tpl.func.php
new file mode 100644
index 0000000..9cd4e2b
--- /dev/null
+++ b/framework/function/tpl.func.php
@@ -0,0 +1,577 @@
+app('tpl');
+} else {
+	load()->web('tpl');
+}
+
+function tpl_form_field_date($name, $value = '', $withtime = false) {
+	return _tpl_form_field_date($name, $value, $withtime);
+}
+
+function tpl_form_field_clock($name, $value = '') {
+	$s = '';
+	if (!defined('TPL_INIT_CLOCK_TIME')) {
+		$s .= '
+		
+		';
+		define('TPL_INIT_CLOCK_TIME', 1);
+	}
+	$time = date('H:i');
+	if (!empty($value)) {
+		if (!strexists($value, ':')) {
+			$time = date('H:i', $value);
+		} else {
+			$time = $value;
+		}
+	}
+	$s .= '	
+ + +
'; + + return $s; +} + + +function tpl_form_field_daterange($name, $value = array(), $time = false, $clear = true) { + $s = ''; + + if (empty($time) && !defined('TPL_INIT_DATERANGE_DATE')) { + $s = ' + +'; + define('TPL_INIT_DATERANGE_DATE', true); + } + + if (!empty($time) && !defined('TPL_INIT_DATERANGE_TIME')) { + $s = ' + +'; + define('TPL_INIT_DATERANGE_TIME', true); + } + if (!empty($value['starttime']) || !empty($value['start'])) { + if ($value['start'] && strtotime($value['start'])) { + $value['starttime'] = empty($time) ? date('Y-m-d', strtotime($value['start'])) : date('Y-m-d H:i', strtotime($value['start'])); + } + $value['starttime'] = empty($value['starttime']) ? '' : $value['starttime']; + } else { + $value['starttime'] = ''; + } + + if (!empty($value['endtime']) || !empty($value['end'])) { + if ($value['end'] && strtotime($value['end'])) { + $value['endtime'] = empty($time) ? date('Y-m-d', strtotime($value['end'])) : date('Y-m-d H:i', strtotime($value['end'])); + } + $value['endtime'] = empty($value['endtime']) ? $value['starttime'] : $value['endtime']; + } else { + $value['endtime'] = ''; + } + $s .= ' + + + + '; + + return $s; +} + + +function tpl_form_field_calendar($name, $values = array()) { + $html = ''; + if (!defined('TPL_INIT_CALENDAR')) { + $html .= ' + '; + define('TPL_INIT_CALENDAR', true); + } + + if (empty($values) || !is_array($values)) { + $values = array(0, 0, 0); + } + $values['year'] = intval($values['year']); + $values['month'] = intval($values['month']); + $values['day'] = intval($values['day']); + + if (empty($values['year'])) { + $values['year'] = '1980'; + } + $year = array(date('Y'), '1914'); + $html .= '
+
+ +
+
+ +
+
+ +
+
'; + + return $html; +} + + +function tpl_form_field_district($name, $values = array()) { + $html = ''; + if (!defined('TPL_INIT_DISTRICT')) { + $html .= ' + '; + define('TPL_INIT_DISTRICT', true); + } + if (empty($values) || !is_array($values)) { + $values = array('province' => '', 'city' => '', 'district' => ''); + } + if (empty($values['province'])) { + $values['province'] = ''; + } + if (empty($values['city'])) { + $values['city'] = ''; + } + if (empty($values['district'])) { + $values['district'] = ''; + } + $html .= ' +
+
+ +
+
+ +
+
+ +
+
'; + + return $html; +} + + +function tpl_form_field_category_2level($name, $parents, $children, $parentid, $childid) { + $html = ' + '; + if (!defined('TPL_INIT_CATEGORY')) { + $html .= ' + + '; + define('TPL_INIT_CATEGORY', true); + } + + $html .= + '
+
+ +
+
+ +
+
+ '; + + return $html; +} + + +function tpl_form_field_industry($name, $pvalue = '', $cvalue = '', $parentid = 'industry_1', $childid = 'industry_2') { + $html = ' +
+
+ +
+
+ +
+ +
'; + + return $html; +} + + +function tpl_form_field_coordinate($field, $value = array()) { + $s = ''; + if (!defined('TPL_INIT_COORDINATE')) { + $s .= ''; + define('TPL_INIT_COORDINATE', true); + } + $s .= ' +
+
+ +
+
+ +
+
+ +
+
'; + + return $s; +} + + +function tpl_fans_form($field, $value = '') { + switch ($field) { + case 'avatar': + $avatar_url = '../attachment/images/global/avatars/'; + $html = ''; + if (!defined('TPL_INIT_AVATAR')) { + $html .= ' + '; + define('TPL_INIT_AVATAR', true); + } + if (!defined('TPL_INIT_IMAGE')) { + global $_W; + if (defined('IN_MOBILE')) { + $html .= << + // in mobile + function showImageDialog(elm) { + require(["jquery", "util"], function($, util){ + var btn = $(elm); + var ipt = btn.parent().prev(); + var val = ipt.val(); + var img = ipt.parent().next().children(); + util.image(elm, function(url){ + img.get(0).src = url.url; + ipt.val(url.attachment); + }); + }); + } + +EOF; + } else { + $html .= << + // in web + function showImageDialog(elm, opts) { + require(["util"], function(util){ + var btn = $(elm); + var ipt = btn.parent().prev(); + var val = ipt.val(); + var img = ipt.parent().next().find('img'); + util.image(val, function(url){ + img.get(0).src = url.url; + ipt.val(url.attachment); + }, {multiple:false,type:"image",direct:true}, opts); + }); + } + +EOF; + } + define('TPL_INIT_IMAGE', true); + } + $val = './resource/images/nopic.jpg'; + if (!empty($value)) { + $val = tomedia($value); + } + $options = array(); + $options['width'] = '200'; + $options['height'] = '200'; + + if (defined('IN_MOBILE')) { + $html .= << + + + + + + +
+ +
+EOF; + } else { + $html .= ' +
+ + + + + +
+
+ +
'; + } + + break; + case 'birth': + case 'birthyear': + case 'birthmonth': + case 'birthday': + $html = tpl_form_field_calendar('birth', $value); + break; + case 'reside': + case 'resideprovince': + case 'residecity': + case 'residedist': + $html = tpl_form_field_district('reside', $value); + break; + case 'bio': + case 'interest': + $html = ''; + break; + case 'gender': + $html = ' + '; + break; + case 'education': + case 'constellation': + case 'zodiac': + case 'bloodtype': + if ('bloodtype' == $field) { + $options = array('A', 'B', 'AB', 'O', '其它'); + } elseif ('zodiac' == $field) { + $options = array('鼠', '牛', '虎', '兔', '龙', '蛇', '马', '羊', '猴', '鸡', '狗', '猪'); + } elseif ('constellation' == $field) { + $options = array('水瓶座', '双鱼座', '白羊座', '金牛座', '双子座', '巨蟹座', '狮子座', '处女座', '天秤座', '天蝎座', '射手座', '摩羯座'); + } elseif ('education' == $field) { + $options = array('博士', '硕士', '本科', '专科', '中学', '小学', '其它'); + } + $html = ''; + break; + case 'nickname': + case 'realname': + case 'address': + case 'mobile': + case 'qq': + case 'msn': + case 'email': + case 'telephone': + case 'taobao': + case 'alipay': + case 'studentid': + case 'grade': + case 'graduateschool': + case 'idcard': + case 'zipcode': + case 'site': + case 'affectivestatus': + case 'lookingfor': + case 'nationality': + case 'height': + case 'weight': + case 'company': + case 'occupation': + case 'position': + case 'revenue': + default: + $html = ''; + break; + } + + return $html; +} \ No newline at end of file diff --git a/framework/library/agent/agent.class.php b/framework/library/agent/agent.class.php new file mode 100644 index 0000000..6e085d7 --- /dev/null +++ b/framework/library/agent/agent.class.php @@ -0,0 +1,193 @@ + self::deviceType(), + 'browserType' => self::browserType(), + 'isRetina' => self::isRetina(), + 'osType' => self::osType(), + 'isIos6' => self::isIos6(), + ); + } + + // 浏览器类型 + public static function browserType($agent = '') + { + $agent = self::getAgent($agent); + if (stripos($agent, 'baiduboxapp') !== false) { + return self::BROWSER_TYPE_XZAPP; + } + + if (stripos($agent, 'iphone') !== false) { + return self::BROWSER_TYPE_IPHONE; + } + + if (stripos($agent, 'ipad') !== false) { + return self::BROWSER_TYPE_IPAD; + } + + if (stripos($agent, 'ipod') !== false) { + return self::BROWSER_TYPE_IPOD; + } + + if (stripos($agent, 'android') !== false) { + return self::BROWSER_TYPE_ANDROID; + } + + return self::BROWSER_TYPE_UNKNOWN; + } + + // 系统类型 + public static function osType($agent = '') + { + $agent = self::getAgent($agent); + $browserType = self::browserType($agent); + + switch ($browserType) { + case self::BROWSER_TYPE_IPHONE: + case self::BROWSER_TYPE_IPAD: + case self::BROWSER_TYPE_IPOD: + $osType = self::OS_TYPE_IOS; + break; + case self::BROWSER_TYPE_ANDROID: + $osType = self::OS_TYPE_ANDROID; + break; + default: + $osType = self::OS_TYPE_UNKNOWN; + } + + return $osType; + } + + // 设备类型 + public static function deviceType() + { + if (self::isMobile()) { + return self::DEVICE_MOBILE; + } else { + return self::DEVICE_DESKTOP; + } + } + + // retina屏 + public static function isRetina($agent = '') + { + $agent = self::getAgent($agent); + $osType = self::osType($agent); + + if (($osType == self::OS_TYPE_IOS) && (self::isIos6($agent) != 1)) { + return self::RETINA_TYPE_YES; + } else { + return self::RETINA_TYPE_NOT; + } + } + + // ios6系统的手机(iphone4, iphone4s) + public static function isIos6($agent = '') + { + $agent = self::getAgent($agent); + + if (stripos($agent, 'iPhone OS 6')) { + return self::IOS6_YES; + } else { + return self::IOS6_NOT; + } + } + // 检查是否在微信中打开 + public static function isMicroMessage($agent = '') + { + $agent = self::getAgent($agent); + + if (stripos($agent, 'MicroMessenger') !== false) { + return self::MICRO_MESSAGE_YES; + } else { + return self::MICRO_MESSAGE_NOT; + } + } + + // 已安装APP + public static function isAppInstalled() + { + if (isset($_GET['isappinstalled']) && ($_GET['isappinstalled'] == 1)) { + return self::APP_INSTALLED_YES; + } else { + return self::APP_INSTALLED_NOT; + } + } + + // 是移动设备访问 + public static function isMobile() + { + // 如果有HTTP_X_WAP_PROFILE则一定是移动设备 + if (isset($_SERVER['HTTP_X_WAP_PROFILE'])) { + return true; + } + // 如果via信息含有wap则一定是移动设备,部分服务商会屏蔽该信息 + if (isset($_SERVER['HTTP_VIA']) && stristr($_SERVER['HTTP_VIA'], "wap")) { + return true; + } + // 脑残法,判断手机发送的客户端标志,兼容性有待提高 + if (isset ($_SERVER['HTTP_USER_AGENT'])) { + $clientkeywords = array('nokia', 'sony', 'ericsson', 'mot', 'samsung', 'htc', 'sgh', 'lg', 'sharp', + 'sie-', 'philips', 'panasonic', 'alcatel', 'lenovo', 'iphone', 'ipod', 'blackberry', 'meizu', + 'android', 'netfront', 'symbian', 'ucweb', 'windowsce', 'palm', 'operamini', 'operamobi', 'openwave', + 'nexusone', 'cldc', 'midp', 'wap', 'mobile', 'WindowsWechat'); + // 从HTTP_USER_AGENT中查找手机浏览器的关键字 + if (preg_match("/(" . implode('|', $clientkeywords) . ")/i", strtolower($_SERVER['HTTP_USER_AGENT']))) { + return true; + } + } + // 协议法,因为有可能不准确,放到最后判断 + if (isset($_SERVER['HTTP_ACCEPT'])) { + // 如果只支持wml并且不支持html那一定是移动设备, 如果支持wml和html但是wml在html之前则是移动设备 + if ((strpos($_SERVER['HTTP_ACCEPT'], 'vnd.wap.wml') !== false) && (strpos($_SERVER['HTTP_ACCEPT'], 'text/html') === false || (strpos($_SERVER['HTTP_ACCEPT'], 'vnd.wap.wml') < strpos($_SERVER['HTTP_ACCEPT'], 'text/html')))) { + return true; + } + } + return false; + } + + public static function getAgent($agent = '') + { + $agent = empty($agent) ? $_SERVER['HTTP_USER_AGENT'] : $agent; + return $agent; + } +} \ No newline at end of file diff --git a/framework/library/alioss/CHANGELOG.md b/framework/library/alioss/CHANGELOG.md new file mode 100644 index 0000000..b269c96 --- /dev/null +++ b/framework/library/alioss/CHANGELOG.md @@ -0,0 +1,57 @@ +# ChangeLog - Aliyun OSS SDK for PHP + +## v2.0.7 / 2016-06-17 + +* Support append object + +## v2.0.6 + +* Trim access key id/secret and endpoint +* Refine tests and setup travis CI + +## v2.0.5 + +* 增加Add/Delete/Get BucketCname接口 + +## v2.0.4 + +* 增加Put/Get Object Acl接口 + +## v2.0.3 + +* 修复Util中的常量定义在低于5.6的PHP版本中报错的问题 + +## v2.0.2 + +* 修复multipart上传时无法指定Content-Type的问题 + +## v2.0.1 + +* 增加对ListObjects/ListMultipartUploads时特殊字符的处理 +* 提供接口获取OssException中的详细信息 + + +## 2015.11.25 + +* **大版本升级,不再兼容以前接口,新版本对易用性做了很大的改进,建议用户迁移到新版本。** + +## 修改内容 + +* 不再支持PHP 5.2版本 + +### 新增内容 + +* 引入命名空间 +* 接口命名修正,采用驼峰式命名 +* 接口入参修改,把常用参数从Options参数中提出来 +* 接口返回结果修改,对返回结果进行处理,用户可以直接得到容易处理的数据结构  +* OssClient的构造函数变更 +* 支持CNAME和IP格式的Endpoint地址 +* 重新整理sample文件组织结构,使用function组织功能点 +* 增加设置连接超时,请求超时的接口 +* 去掉Object Group相关的已经过时的接口 +* OssException中的message改为英文 + +### 问题修复 + +* object名称校验不完备 diff --git a/framework/library/alioss/LICENSE.md b/framework/library/alioss/LICENSE.md new file mode 100644 index 0000000..3183de8 --- /dev/null +++ b/framework/library/alioss/LICENSE.md @@ -0,0 +1,21 @@ +#The MIT License (MIT) + +Copyright (c) ali-sdk and other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/framework/library/alioss/README.md b/framework/library/alioss/README.md new file mode 100644 index 0000000..1549dda --- /dev/null +++ b/framework/library/alioss/README.md @@ -0,0 +1,152 @@ +# Aliyun OSS SDK for PHP + +[![Latest Stable Version](https://poser.pugx.org/aliyuncs/oss-sdk-php/v/stable)](https://packagist.org/packages/aliyuncs/oss-sdk-php) +[![Build Status](https://travis-ci.org/aliyun/aliyun-oss-php-sdk.svg?branch=master)](https://travis-ci.org/aliyun/aliyun-oss-php-sdk) +[![Coverage Status](https://coveralls.io/repos/github/aliyun/aliyun-oss-php-sdk/badge.svg?branch=master)](https://coveralls.io/github/aliyun/aliyun-oss-php-sdk?branch=master) + +## 概述 + +阿里云对象存储(Object Storage Service,简称OSS),是阿里云对外提供的海量、安全、低成本、高可靠的云存储服务。用户可以通过调用API,在任何应用、任何时间、任何地点上传和下载数据,也可以通过用户Web控制台对数据进行简单的管理。OSS适合存放任意文件类型,适合各种网站、开发企业及开发者使用。 + + +## 运行环境 +- PHP 5.3+ +- cURL extension + +提示: + +- Ubuntu下可以使用apt-get包管理器安装php的cURL扩展 `sudo apt-get install php5-curl` + +## 安装方法 + +1. 如果您通过composer管理您的项目依赖,可以在你的项目根目录运行: + + $ composer require aliyuncs/oss-sdk-php + + 或者在你的`composer.json`中声明对Aliyun OSS SDK for PHP的依赖: + + "require": { + "aliyuncs/oss-sdk-php": "~2.0" + } + + 然后通过`composer install`安装依赖。composer安装完成后,在您的PHP代码中引入依赖即可: + + require_once __DIR__ . '/vendor/autoload.php'; + +2. 您也可以直接下载已经打包好的[phar文件][releases-page],然后在你 + 的代码中引入这个文件即可: + + require_once '/path/to/oss-sdk-php.phar'; + +3. 下载SDK源码,在您的代码中引入SDK目录下的`autoload.php`文件: + + require_once '/path/to/oss-sdk/autoload.php'; + +## 快速使用 + +### 常用类 + +| 类名 | 解释 | +|:------------------|:------------------------------------| +|OSS\OssClient | OSS客户端类,用户通过OssClient的实例调用接口 | +|OSS\Core\OssException | OSS异常类,用户在使用的过程中,只需要注意这个异常| + +### OssClient初始化 + +SDK的OSS操作通过OssClient类完成的,下面代码创建一个OssClient对象: + +```php +"; ; +$accessKeySecret = "<您从OSS获得的AccessKeySecret>"; +$endpoint = "<您选定的OSS数据中心访问域名,例如oss-cn-hangzhou.aliyuncs.com>"; +try { + $ossClient = new OssClient($accessKeyId, $accessKeySecret, $endpoint); +} catch (OssException $e) { + print $e->getMessage(); +} +``` + +### 文件操作 + +文件(又称对象,Object)是OSS中最基本的数据单元,您可以把它简单地理解为文件,用下面代码可以实现一个Object的上传: + +```php +"; +$object = "<您使用的Object名字,注意命名规范>"; +$content = "Hello, OSS!"; // 上传的文件内容 +try { + $ossClient->putObject($bucket, $object, $content); +} catch (OssException $e) { + print $e->getMessage(); +} +``` + +### 存储空间操作 + +存储空间(又称Bucket)是一个用户用来管理所存储Object的存储空间,对于用户来说是一个管理Object的单元,所有的Object都必须隶属于某个Bucket。您可以按照下面的代码新建一个Bucket: + +```php +"; +try { + $ossClient->createBucket($bucket); +} catch (OssException $e) { + print $e->getMessage(); +} +``` + +### 返回结果处理 + +OssClient提供的接口返回返回数据分为两种: + +* Put,Delete类接口,接口返回null,如果没有OssException,即可认为操作成功 +* Get,List类接口,接口返回对应的数据,如果没有OssException,即可认为操作成功,举个例子: + +```php +listBuckets(); +$bucketList = $bucketListInfo->getBucketList(); +foreach($bucketList as $bucket) { + print($bucket->getLocation() . "\t" . $bucket->getName() . "\t" . $bucket->getCreatedate() . "\n"); +} +``` +上面代码中的$bucketListInfo的数据类型是 `OSS\Model\BucketListInfo` + + +### 运行Sample程序 + +1. 修改 `samples/Config.php`, 补充配置信息 +2. 执行 `cd samples/ && php RunAll.php` + +### 运行单元测试 + +1. 执行`composer install`下载依赖的库 +2. 设置环境变量 + + export OSS_ACCESS_KEY_ID=access-key-id + export OSS_ACCESS_KEY_SECRET=access-key-secret + export OSS_ENDPOINT=endpoint + export OSS_BUCKET=bucket-name + +3. 执行 `php vendor/bin/phpunit` + +## 贡献代码 + +0. 开发流程参考:https://github.com/rockuw/oss-sdk-status#development-oss-members-only +1. 提交代码后,确保travis CI是PASS的 +2. 每发布一个新的版本: + - 运行`build-phar.sh`生成相应的phar包(需要安装[phar-composer][phar-composer]) + - 在[Release页面][releases-page]发布一个版本 + - 将生成的phar包上传到相应的Release下面 + +## 联系我们 + +- [阿里云OSS官方网站](http://oss.aliyun.com) +- [阿里云OSS官方论坛](http://bbs.aliyun.com) +- [阿里云OSS官方文档中心](http://www.aliyun.com/product/oss#Docs) +- 阿里云官方技术支持:[提交工单](https://workorder.console.aliyun.com/#/ticket/createIndex) + +[releases-page]: https://github.com/aliyun/aliyun-oss-php-sdk/releases +[phar-composer]: https://github.com/clue/phar-composer diff --git a/framework/library/alioss/autoload.php b/framework/library/alioss/autoload.php new file mode 100644 index 0000000..ec13201 --- /dev/null +++ b/framework/library/alioss/autoload.php @@ -0,0 +1,11 @@ + 1) { + $ext = strtolower(end($parts)); + if (isset(self::$mime_types[$ext])) { + return self::$mime_types[$ext]; + } + } + + return null; + } + + private static $mime_types = array( + 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template', + 'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template', + 'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow', + 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', + 'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide', + 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template', + 'xlam' => 'application/vnd.ms-excel.addin.macroEnabled.12', + 'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12', + 'apk' => 'application/vnd.android.package-archive', + 'hqx' => 'application/mac-binhex40', + 'cpt' => 'application/mac-compactpro', + 'doc' => 'application/msword', + 'ogg' => 'audio/ogg', + 'pdf' => 'application/pdf', + 'rtf' => 'text/rtf', + 'mif' => 'application/vnd.mif', + 'xls' => 'application/vnd.ms-excel', + 'ppt' => 'application/vnd.ms-powerpoint', + 'odc' => 'application/vnd.oasis.opendocument.chart', + 'odb' => 'application/vnd.oasis.opendocument.database', + 'odf' => 'application/vnd.oasis.opendocument.formula', + 'odg' => 'application/vnd.oasis.opendocument.graphics', + 'otg' => 'application/vnd.oasis.opendocument.graphics-template', + 'odi' => 'application/vnd.oasis.opendocument.image', + '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', + 'sxw' => 'application/vnd.sun.xml.writer', + 'stw' => 'application/vnd.sun.xml.writer.template', + 'sxc' => 'application/vnd.sun.xml.calc', + 'stc' => 'application/vnd.sun.xml.calc.template', + 'sxd' => 'application/vnd.sun.xml.draw', + 'std' => 'application/vnd.sun.xml.draw.template', + 'sxi' => 'application/vnd.sun.xml.impress', + 'sti' => 'application/vnd.sun.xml.impress.template', + 'sxg' => 'application/vnd.sun.xml.writer.global', + 'sxm' => 'application/vnd.sun.xml.math', + 'sis' => 'application/vnd.symbian.install', + 'wbxml' => 'application/vnd.wap.wbxml', + 'wmlc' => 'application/vnd.wap.wmlc', + 'wmlsc' => 'application/vnd.wap.wmlscriptc', + 'bcpio' => 'application/x-bcpio', + 'torrent' => 'application/x-bittorrent', + 'bz2' => 'application/x-bzip2', + 'vcd' => 'application/x-cdlink', + 'pgn' => 'application/x-chess-pgn', + 'cpio' => 'application/x-cpio', + 'csh' => 'application/x-csh', + 'dvi' => 'application/x-dvi', + 'spl' => 'application/x-futuresplash', + 'gtar' => 'application/x-gtar', + 'hdf' => 'application/x-hdf', + 'jar' => 'application/java-archive', + 'jnlp' => 'application/x-java-jnlp-file', + 'js' => 'application/javascript', + 'json' => 'application/json', + 'ksp' => 'application/x-kspread', + 'chrt' => 'application/x-kchart', + 'kil' => 'application/x-killustrator', + 'latex' => 'application/x-latex', + 'rpm' => 'application/x-rpm', + 'sh' => 'application/x-sh', + 'shar' => 'application/x-shar', + 'swf' => 'application/x-shockwave-flash', + 'sit' => 'application/x-stuffit', + 'sv4cpio' => 'application/x-sv4cpio', + 'sv4crc' => 'application/x-sv4crc', + 'tar' => 'application/x-tar', + 'tcl' => 'application/x-tcl', + 'tex' => 'application/x-tex', + 'man' => 'application/x-troff-man', + 'me' => 'application/x-troff-me', + 'ms' => 'application/x-troff-ms', + 'ustar' => 'application/x-ustar', + 'src' => 'application/x-wais-source', + 'zip' => 'application/zip', + 'm3u' => 'audio/x-mpegurl', + 'ra' => 'audio/x-pn-realaudio', + 'wav' => 'audio/x-wav', + 'wma' => 'audio/x-ms-wma', + 'wax' => 'audio/x-ms-wax', + 'pdb' => 'chemical/x-pdb', + 'xyz' => 'chemical/x-xyz', + 'bmp' => 'image/bmp', + 'gif' => 'image/gif', + 'ief' => 'image/ief', + 'png' => 'image/png', + 'wbmp' => 'image/vnd.wap.wbmp', + 'ras' => 'image/x-cmu-raster', + 'pnm' => 'image/x-portable-anymap', + 'pbm' => 'image/x-portable-bitmap', + 'pgm' => 'image/x-portable-graymap', + 'ppm' => 'image/x-portable-pixmap', + 'rgb' => 'image/x-rgb', + 'xbm' => 'image/x-xbitmap', + 'xpm' => 'image/x-xpixmap', + 'xwd' => 'image/x-xwindowdump', + 'css' => 'text/css', + 'rtx' => 'text/richtext', + 'tsv' => 'text/tab-separated-values', + 'jad' => 'text/vnd.sun.j2me.app-descriptor', + 'wml' => 'text/vnd.wap.wml', + 'wmls' => 'text/vnd.wap.wmlscript', + 'etx' => 'text/x-setext', + 'mxu' => 'video/vnd.mpegurl', + 'flv' => 'video/x-flv', + 'wm' => 'video/x-ms-wm', + 'wmv' => 'video/x-ms-wmv', + 'wmx' => 'video/x-ms-wmx', + 'wvx' => 'video/x-ms-wvx', + 'avi' => 'video/x-msvideo', + 'movie' => 'video/x-sgi-movie', + 'ice' => 'x-conference/x-cooltalk', + '3gp' => 'video/3gpp', + 'ai' => 'application/postscript', + 'aif' => 'audio/x-aiff', + 'aifc' => 'audio/x-aiff', + 'aiff' => 'audio/x-aiff', + 'asc' => 'text/plain', + 'atom' => 'application/atom+xml', + 'au' => 'audio/basic', + 'bin' => 'application/octet-stream', + 'cdf' => 'application/x-netcdf', + 'cgm' => 'image/cgm', + 'class' => 'application/octet-stream', + 'dcr' => 'application/x-director', + 'dif' => 'video/x-dv', + 'dir' => 'application/x-director', + 'djv' => 'image/vnd.djvu', + 'djvu' => 'image/vnd.djvu', + 'dll' => 'application/octet-stream', + 'dmg' => 'application/octet-stream', + 'dms' => 'application/octet-stream', + 'dtd' => 'application/xml-dtd', + 'dv' => 'video/x-dv', + 'dxr' => 'application/x-director', + 'eps' => 'application/postscript', + 'exe' => 'application/octet-stream', + 'ez' => 'application/andrew-inset', + 'gram' => 'application/srgs', + 'grxml' => 'application/srgs+xml', + 'gz' => 'application/x-gzip', + 'htm' => 'text/html', + 'html' => 'text/html', + 'ico' => 'image/x-icon', + 'ics' => 'text/calendar', + 'ifb' => 'text/calendar', + 'iges' => 'model/iges', + 'igs' => 'model/iges', + 'jp2' => 'image/jp2', + 'jpe' => 'image/jpeg', + 'jpeg' => 'image/jpeg', + 'jpg' => 'image/jpeg', + 'kar' => 'audio/midi', + 'lha' => 'application/octet-stream', + 'lzh' => 'application/octet-stream', + 'm4a' => 'audio/mp4a-latm', + 'm4p' => 'audio/mp4a-latm', + 'm4u' => 'video/vnd.mpegurl', + 'm4v' => 'video/x-m4v', + 'mac' => 'image/x-macpaint', + 'mathml' => 'application/mathml+xml', + 'mesh' => 'model/mesh', + 'mid' => 'audio/midi', + 'midi' => 'audio/midi', + 'mov' => 'video/quicktime', + 'mp2' => 'audio/mpeg', + 'mp3' => 'audio/mpeg', + 'mp4' => 'video/mp4', + 'mpe' => 'video/mpeg', + 'mpeg' => 'video/mpeg', + 'mpg' => 'video/mpeg', + 'mpga' => 'audio/mpeg', + 'msh' => 'model/mesh', + 'nc' => 'application/x-netcdf', + 'oda' => 'application/oda', + 'ogv' => 'video/ogv', + 'pct' => 'image/pict', + 'pic' => 'image/pict', + 'pict' => 'image/pict', + 'pnt' => 'image/x-macpaint', + 'pntg' => 'image/x-macpaint', + 'ps' => 'application/postscript', + 'qt' => 'video/quicktime', + 'qti' => 'image/x-quicktime', + 'qtif' => 'image/x-quicktime', + 'ram' => 'audio/x-pn-realaudio', + 'rdf' => 'application/rdf+xml', + 'rm' => 'application/vnd.rn-realmedia', + 'roff' => 'application/x-troff', + 'sgm' => 'text/sgml', + 'sgml' => 'text/sgml', + 'silo' => 'model/mesh', + 'skd' => 'application/x-koan', + 'skm' => 'application/x-koan', + 'skp' => 'application/x-koan', + 'skt' => 'application/x-koan', + 'smi' => 'application/smil', + 'smil' => 'application/smil', + 'snd' => 'audio/basic', + 'so' => 'application/octet-stream', + 'svg' => 'image/svg+xml', + 't' => 'application/x-troff', + 'texi' => 'application/x-texinfo', + 'texinfo' => 'application/x-texinfo', + 'tif' => 'image/tiff', + 'tiff' => 'image/tiff', + 'tr' => 'application/x-troff', + 'txt' => 'text/plain', + 'vrml' => 'model/vrml', + 'vxml' => 'application/voicexml+xml', + 'webm' => 'video/webm', + 'webp' => 'image/webp', + 'wrl' => 'model/vrml', + 'xht' => 'application/xhtml+xml', + 'xhtml' => 'application/xhtml+xml', + 'xml' => 'application/xml', + 'xsl' => 'application/xml', + 'xslt' => 'application/xslt+xml', + 'xul' => 'application/vnd.mozilla.xul+xml', + ); +} \ No newline at end of file diff --git a/framework/library/alioss/src/OSS/Core/OssException.php b/framework/library/alioss/src/OSS/Core/OssException.php new file mode 100644 index 0000000..b0e9e8b --- /dev/null +++ b/framework/library/alioss/src/OSS/Core/OssException.php @@ -0,0 +1,54 @@ +details = $details; + } else { + $message = $details; + parent::__construct($message); + } + } + + public function getHTTPStatus() + { + return isset($this->details['status']) ? $this->details['status'] : ''; + } + + public function getRequestId() + { + return isset($this->details['request-id']) ? $this->details['request-id'] : ''; + } + + public function getErrorCode() + { + return isset($this->details['code']) ? $this->details['code'] : ''; + } + + public function getErrorMessage() + { + return isset($this->details['message']) ? $this->details['message'] : ''; + } + + public function getDetails() + { + return isset($this->details['body']) ? $this->details['body'] : ''; + } +} diff --git a/framework/library/alioss/src/OSS/Core/OssUtil.php b/framework/library/alioss/src/OSS/Core/OssUtil.php new file mode 100644 index 0000000..b70680e --- /dev/null +++ b/framework/library/alioss/src/OSS/Core/OssUtil.php @@ -0,0 +1,448 @@ + $value) { + if (is_string($key) && !is_array($value)) { + $temp[] = rawurlencode($key) . '=' . rawurlencode($value); + } + } + return implode('&', $temp); + } + + /** + * 转义字符替换 + * + * @param string $subject + * @return string + */ + public static function sReplace($subject) + { + $search = array('<', '>', '&', '\'', '"'); + $replace = array('<', '>', '&', ''', '"'); + return str_replace($search, $replace, $subject); + } + + /** + * 检查是否是中文编码 + * + * @param $str + * @return int + */ + public static function chkChinese($str) + { + return preg_match('/[\x80-\xff]./', $str); + } + + /** + * 检测是否GB2312编码 + * + * @param string $str + * @return boolean false UTF-8编码 TRUE GB2312编码 + */ + public static function isGb2312($str) + { + for ($i = 0; $i < strlen($str); $i++) { + $v = ord($str[$i]); + if ($v > 127) { + if (($v >= 228) && ($v <= 233)) { + if (($i + 2) >= (strlen($str) - 1)) return true; // not enough characters + $v1 = ord($str[$i + 1]); + $v2 = ord($str[$i + 2]); + if (($v1 >= 128) && ($v1 <= 191) && ($v2 >= 128) && ($v2 <= 191)) + return false; + else + return true; + } + } + } + return false; + } + + /** + * 检测是否GBK编码 + * + * @param string $str + * @param boolean $gbk + * @return boolean + */ + public static function checkChar($str, $gbk = true) + { + for ($i = 0; $i < strlen($str); $i++) { + $v = ord($str[$i]); + if ($v > 127) { + if (($v >= 228) && ($v <= 233)) { + if (($i + 2) >= (strlen($str) - 1)) return $gbk ? true : FALSE; // not enough characters + $v1 = ord($str[$i + 1]); + $v2 = ord($str[$i + 2]); + if ($gbk) { + return (($v1 >= 128) && ($v1 <= 191) && ($v2 >= 128) && ($v2 <= 191)) ? FALSE : TRUE;//GBK + } else { + return (($v1 >= 128) && ($v1 <= 191) && ($v2 >= 128) && ($v2 <= 191)) ? TRUE : FALSE; + } + } + } + } + return $gbk ? TRUE : FALSE; + } + + /** + * 检验bucket名称是否合法 + * bucket的命名规范: + * 1. 只能包括小写字母,数字 + * 2. 必须以小写字母或者数字开头 + * 3. 长度必须在3-63字节之间 + * + * @param string $bucket Bucket名称 + * @return boolean + */ + public static function validateBucket($bucket) + { + $pattern = '/^[a-z0-9][a-z0-9-]{2,62}$/'; + if (!preg_match($pattern, $bucket)) { + return false; + } + return true; + } + + /** + * 检验object名称是否合法 + * object命名规范: + * 1. 规则长度必须在1-1023字节之间 + * 2. 使用UTF-8编码 + * 3. 不能以 "/" "\\"开头 + * + * @param string $object Object名称 + * @return boolean + */ + public static function validateObject($object) + { + $pattern = '/^.{1,1023}$/'; + if (empty($object) || !preg_match($pattern, $object) || + self::startsWith($object, '/') || self::startsWith($object, '\\') + ) { + return false; + } + return true; + } + + + /** + * 判断字符串$str是不是以$findMe开始 + * + * @param string $str + * @param string $findMe + * @return bool + */ + public static function startsWith($str, $findMe) + { + if (strpos($str, $findMe) === 0) { + return true; + } else { + return false; + } + } + + /** + * 检验$options + * + * @param array $options + * @throws OssException + * @return boolean + */ + public static function validateOptions($options) + { + //$options + if ($options != NULL && !is_array($options)) { + throw new OssException ($options . ':' . 'option must be array'); + } + } + + /** + * 检查上传文件的内容是否合法 + * + * @param $content string + * @throws OssException + */ + public static function validateContent($content) + { + if (empty($content)) { + throw new OssException("http body content is invalid"); + } + } + + /** + * 校验BUCKET/OBJECT/OBJECT GROUP是否为空 + * + * @param string $name + * @param string $errMsg + * @throws OssException + * @return void + */ + public static function throwOssExceptionWithMessageIfEmpty($name, $errMsg) + { + if (empty($name)) { + throw new OssException($errMsg); + } + } + + /** + * 仅供测试使用的接口,请勿使用 + * + * @param $filename + * @param $size + */ + public static function generateFile($filename, $size) + { + if (file_exists($filename) && $size == filesize($filename)) { + echo $filename . " already exists, no need to create again. "; + return; + } + $part_size = 1 * 1024 * 1024; + $fp = fopen($filename, "w"); + $characters = << 0) { + if ($size < $part_size) { + $write_size = $size; + } else { + $write_size = $part_size; + } + $size -= $write_size; + $a = $characters[rand(0, $charactersLength - 1)]; + $content = str_repeat($a, $write_size); + $flag = fwrite($fp, $content); + if (!$flag) { + echo "write to " . $filename . " failed.
"; + break; + } + } + } else { + echo "open " . $filename . " failed.
"; + } + fclose($fp); + } + + /** + * 得到文件的md5编码 + * + * @param $filename + * @param $from_pos + * @param $to_pos + * @return string + */ + public static function getMd5SumForFile($filename, $from_pos, $to_pos) + { + $content_md5 = ""; + if (($to_pos - $from_pos) > self::OSS_MAX_PART_SIZE) { + return $content_md5; + } + $filesize = filesize($filename); + if ($from_pos >= $filesize || $to_pos >= $filesize || $from_pos < 0 || $to_pos < 0) { + return $content_md5; + } + + $total_length = $to_pos - $from_pos + 1; + $buffer = 8192; + $left_length = $total_length; + if (!file_exists($filename)) { + return $content_md5; + } + + if (false === $fh = fopen($filename, 'rb')) { + return $content_md5; + } + + fseek($fh, $from_pos); + $data = ''; + while (!feof($fh)) { + if ($left_length >= $buffer) { + $read_length = $buffer; + } else { + $read_length = $left_length; + } + if ($read_length <= 0) { + break; + } else { + $data .= fread($fh, $read_length); + $left_length = $left_length - $read_length; + } + } + fclose($fh); + $content_md5 = base64_encode(md5($data, true)); + return $content_md5; + } + + /** + * 检测是否windows系统,因为windows系统默认编码为GBK + * + * @return bool + */ + public static function isWin() + { + return strtoupper(substr(PHP_OS, 0, 3)) == "WIN"; + } + + /** + * 主要是由于windows系统编码是gbk,遇到中文时候,如果不进行转换处理会出现找不到文件的问题 + * + * @param $file_path + * @return string + */ + public static function encodePath($file_path) + { + if (self::chkChinese($file_path) && self::isWin()) { + $file_path = iconv('utf-8', 'gbk', $file_path); + } + return $file_path; + } + + /** + * 判断用户输入的endpoint是否是 xxx.xxx.xxx.xxx:port 或者 xxx.xxx.xxx.xxx的ip格式 + * + * @param string $endpoint 需要做判断的endpoint + * @return boolean + */ + public static function isIPFormat($endpoint) + { + $ip_array = explode(":", $endpoint); + $hostname = $ip_array[0]; + $ret = filter_var($hostname, FILTER_VALIDATE_IP); + if (!$ret) { + return false; + } else { + return true; + } + } + + /** + * 生成DeleteMultiObjects接口的xml消息 + * + * @param string[] $objects + * @param bool $quiet + * @return string + */ + public static function createDeleteObjectsXmlBody($objects, $quiet) + { + $xml = new \SimpleXMLElement(''); + $xml->addChild('Quiet', $quiet); + foreach ($objects as $object) { + $sub_object = $xml->addChild('Object'); + $object = OssUtil::sReplace($object); + $sub_object->addChild('Key', $object); + } + return $xml->asXML(); + } + + /** + * 生成CompleteMultipartUpload接口的xml消息 + * + * @param array[] $listParts + * @return string + */ + public static function createCompleteMultipartUploadXmlBody($listParts) + { + $xml = new \SimpleXMLElement(''); + foreach ($listParts as $node) { + $part = $xml->addChild('Part'); + $part->addChild('PartNumber', $node['PartNumber']); + $part->addChild('ETag', $node['ETag']); + } + return $xml->asXML(); + } + + /** + * 读取目录 + * + * @param string $dir + * @param string $exclude + * @param bool $recursive + * @return string[] + */ + public static function readDir($dir, $exclude = ".|..|.svn|.git", $recursive = false) + { + $file_list_array = array(); + $base_path = $dir; + $exclude_array = explode("|", $exclude); + $exclude_array = array_unique(array_merge($exclude_array, array('.', '..'))); + + if ($recursive) { + foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($dir)) as $new_file) { + if ($new_file->isDir()) continue; + $object = str_replace($base_path, '', $new_file); + if (!in_array(strtolower($object), $exclude_array)) { + $object = ltrim($object, '/'); + if (is_file($new_file)) { + $key = md5($new_file . $object, false); + $file_list_array[$key] = array('path' => $new_file, 'file' => $object,); + } + } + } + } else if ($handle = opendir($dir)) { + while (false !== ($file = readdir($handle))) { + if (!in_array(strtolower($file), $exclude_array)) { + $new_file = $dir . '/' . $file; + $object = $file; + $object = ltrim($object, '/'); + if (is_file($new_file)) { + $key = md5($new_file . $object, false); + $file_list_array[$key] = array('path' => $new_file, 'file' => $object,); + } + } + } + closedir($handle); + } + return $file_list_array; + } + + /** + * Decode key based on the encoding type + * + * @param string $key + * @param string $encoding + * @return string + */ + public static function decodeKey($key, $encoding) + { + if ($encoding == "") { + return $key; + } + + if ($encoding == "url") { + return rawurldecode($key); + } else { + throw new OssException("Unrecognized encoding type: " . $encoding); + } + } +} diff --git a/framework/library/alioss/src/OSS/Http/LICENSE b/framework/library/alioss/src/OSS/Http/LICENSE new file mode 100644 index 0000000..49b38bd --- /dev/null +++ b/framework/library/alioss/src/OSS/Http/LICENSE @@ -0,0 +1,25 @@ +Copyright (c) 2006-2010 Ryan Parman, Foleeo Inc., and contributors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are +permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of + conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, this list + of conditions and the following disclaimer in the documentation and/or other materials + provided with the distribution. + + * Neither the name of Ryan Parman, Foleeo Inc. nor the names of its contributors may be used to + endorse or promote products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS +OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS +AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/framework/library/alioss/src/OSS/Http/RequestCore.php b/framework/library/alioss/src/OSS/Http/RequestCore.php new file mode 100644 index 0000000..8bb87d4 --- /dev/null +++ b/framework/library/alioss/src/OSS/Http/RequestCore.php @@ -0,0 +1,937 @@ +). + */ + public $request_class = 'OSS\Http\RequestCore'; + + /** + * The default class to use for HTTP Responses (defaults to ). + */ + public $response_class = 'OSS\Http\ResponseCore'; + + /** + * Default useragent string to use. + */ + public $useragent = 'RequestCore/1.4.3'; + + /** + * File to read from while streaming up. + */ + public $read_file = null; + + /** + * The resource to read from while streaming up. + */ + public $read_stream = null; + + /** + * The size of the stream to read from. + */ + public $read_stream_size = null; + + /** + * The length already read from the stream. + */ + public $read_stream_read = 0; + + /** + * File to write to while streaming down. + */ + public $write_file = null; + + /** + * The resource to write to while streaming down. + */ + public $write_stream = null; + + /** + * Stores the intended starting seek position. + */ + public $seek_position = null; + + /** + * The location of the cacert.pem file to use. + */ + public $cacert_location = false; + + /** + * The state of SSL certificate verification. + */ + public $ssl_verification = true; + + /** + * The user-defined callback function to call when a stream is read from. + */ + public $registered_streaming_read_callback = null; + + /** + * The user-defined callback function to call when a stream is written to. + */ + public $registered_streaming_write_callback = null; + + /** + * 请求超时时间, 默认是5184000秒,6天 + * + * @var int + */ + public $timeout = 5184000; + + /** + * 连接超时时间,默认是10秒 + * + * @var int + */ + public $connect_timeout = 10; + + /*%******************************************************************************************%*/ + // CONSTANTS + + /** + * GET HTTP Method + */ + const HTTP_GET = 'GET'; + + /** + * POST HTTP Method + */ + const HTTP_POST = 'POST'; + + /** + * PUT HTTP Method + */ + const HTTP_PUT = 'PUT'; + + /** + * DELETE HTTP Method + */ + const HTTP_DELETE = 'DELETE'; + + /** + * HEAD HTTP Method + */ + const HTTP_HEAD = 'HEAD'; + + + /*%******************************************************************************************%*/ + // CONSTRUCTOR/DESTRUCTOR + + /** + * Constructs a new instance of this class. + * + * @param string $url (Optional) The URL to request or service endpoint to query. + * @param string $proxy (Optional) The faux-url to use for proxy settings. Takes the following format: `proxy://user:pass@hostname:port` + * @param array $helpers (Optional) An associative array of classnames to use for request, and response functionality. Gets passed in automatically by the calling class. + * @return $this A reference to the current instance. + */ + public function __construct($url = null, $proxy = null, $helpers = null) + { + // Set some default values. + $this->request_url = $url; + $this->method = self::HTTP_GET; + $this->request_headers = array(); + $this->request_body = ''; + + // Set a new Request class if one was set. + if (isset($helpers['request']) && !empty($helpers['request'])) { + $this->request_class = $helpers['request']; + } + + // Set a new Request class if one was set. + if (isset($helpers['response']) && !empty($helpers['response'])) { + $this->response_class = $helpers['response']; + } + + if ($proxy) { + $this->set_proxy($proxy); + } + + return $this; + } + + /** + * Destructs the instance. Closes opened file handles. + * + * @return $this A reference to the current instance. + */ + public function __destruct() + { + if (isset($this->read_file) && isset($this->read_stream)) { + fclose($this->read_stream); + } + + if (isset($this->write_file) && isset($this->write_stream)) { + fclose($this->write_stream); + } + + return $this; + } + + + /*%******************************************************************************************%*/ + // REQUEST METHODS + + /** + * Sets the credentials to use for authentication. + * + * @param string $user (Required) The username to authenticate with. + * @param string $pass (Required) The password to authenticate with. + * @return $this A reference to the current instance. + */ + public function set_credentials($user, $pass) + { + $this->username = $user; + $this->password = $pass; + return $this; + } + + /** + * Adds a custom HTTP header to the cURL request. + * + * @param string $key (Required) The custom HTTP header to set. + * @param mixed $value (Required) The value to assign to the custom HTTP header. + * @return $this A reference to the current instance. + */ + public function add_header($key, $value) + { + $this->request_headers[$key] = $value; + return $this; + } + + /** + * Removes an HTTP header from the cURL request. + * + * @param string $key (Required) The custom HTTP header to set. + * @return $this A reference to the current instance. + */ + public function remove_header($key) + { + if (isset($this->request_headers[$key])) { + unset($this->request_headers[$key]); + } + return $this; + } + + /** + * Set the method type for the request. + * + * @param string $method (Required) One of the following constants: , , , , . + * @return $this A reference to the current instance. + */ + public function set_method($method) + { + $this->method = strtoupper($method); + return $this; + } + + /** + * Sets a custom useragent string for the class. + * + * @param string $ua (Required) The useragent string to use. + * @return $this A reference to the current instance. + */ + public function set_useragent($ua) + { + $this->useragent = $ua; + return $this; + } + + /** + * Set the body to send in the request. + * + * @param string $body (Required) The textual content to send along in the body of the request. + * @return $this A reference to the current instance. + */ + public function set_body($body) + { + $this->request_body = $body; + return $this; + } + + /** + * Set the URL to make the request to. + * + * @param string $url (Required) The URL to make the request to. + * @return $this A reference to the current instance. + */ + public function set_request_url($url) + { + $this->request_url = $url; + return $this; + } + + /** + * Set additional CURLOPT settings. These will merge with the default settings, and override if + * there is a duplicate. + * + * @param array $curlopts (Optional) A set of key-value pairs that set `CURLOPT` options. These will merge with the existing CURLOPTs, and ones passed here will override the defaults. Keys should be the `CURLOPT_*` constants, not strings. + * @return $this A reference to the current instance. + */ + public function set_curlopts($curlopts) + { + $this->curlopts = $curlopts; + return $this; + } + + /** + * Sets the length in bytes to read from the stream while streaming up. + * + * @param integer $size (Required) The length in bytes to read from the stream. + * @return $this A reference to the current instance. + */ + public function set_read_stream_size($size) + { + $this->read_stream_size = $size; + + return $this; + } + + /** + * Sets the resource to read from while streaming up. Reads the stream from its current position until + * EOF or `$size` bytes have been read. If `$size` is not given it will be determined by and + * . + * + * @param resource $resource (Required) The readable resource to read from. + * @param integer $size (Optional) The size of the stream to read. + * @return $this A reference to the current instance. + */ + public function set_read_stream($resource, $size = null) + { + if (!isset($size) || $size < 0) { + $stats = fstat($resource); + + if ($stats && $stats['size'] >= 0) { + $position = ftell($resource); + + if ($position !== false && $position >= 0) { + $size = $stats['size'] - $position; + } + } + } + + $this->read_stream = $resource; + + return $this->set_read_stream_size($size); + } + + /** + * Sets the file to read from while streaming up. + * + * @param string $location (Required) The readable location to read from. + * @return $this A reference to the current instance. + */ + public function set_read_file($location) + { + $this->read_file = $location; + $read_file_handle = fopen($location, 'r'); + + return $this->set_read_stream($read_file_handle); + } + + /** + * Sets the resource to write to while streaming down. + * + * @param resource $resource (Required) The writeable resource to write to. + * @return $this A reference to the current instance. + */ + public function set_write_stream($resource) + { + $this->write_stream = $resource; + + return $this; + } + + /** + * Sets the file to write to while streaming down. + * + * @param string $location (Required) The writeable location to write to. + * @return $this A reference to the current instance. + */ + public function set_write_file($location) + { + $this->write_file = $location; + $write_file_handle = fopen($location, 'w'); + + return $this->set_write_stream($write_file_handle); + } + + /** + * Set the proxy to use for making requests. + * + * @param string $proxy (Required) The faux-url to use for proxy settings. Takes the following format: `proxy://user:pass@hostname:port` + * @return $this A reference to the current instance. + */ + public function set_proxy($proxy) + { + $proxy = parse_url($proxy); + $proxy['user'] = isset($proxy['user']) ? $proxy['user'] : null; + $proxy['pass'] = isset($proxy['pass']) ? $proxy['pass'] : null; + $proxy['port'] = isset($proxy['port']) ? $proxy['port'] : null; + $this->proxy = $proxy; + return $this; + } + + /** + * Set the intended starting seek position. + * + * @param integer $position (Required) The byte-position of the stream to begin reading from. + * @return $this A reference to the current instance. + */ + public function set_seek_position($position) + { + $this->seek_position = isset($position) ? (integer)$position : null; + + return $this; + } + + /** + * Register a callback function to execute whenever a data stream is read from using + * . + * + * The user-defined callback function should accept three arguments: + * + *
    + *
  • $curl_handle - resource - Required - The cURL handle resource that represents the in-progress transfer.
  • + *
  • $file_handle - resource - Required - The file handle resource that represents the file on the local file system.
  • + *
  • $length - integer - Required - The length in kilobytes of the data chunk that was transferred.
  • + *
+ * + * @param string|array|function $callback (Required) The callback function is called by , so you can pass the following values:
    + *
  • The name of a global function to execute, passed as a string.
  • + *
  • A method to execute, passed as array('ClassName', 'MethodName').
  • + *
  • An anonymous function (PHP 5.3+).
+ * @return $this A reference to the current instance. + */ + public function register_streaming_read_callback($callback) + { + $this->registered_streaming_read_callback = $callback; + + return $this; + } + + /** + * Register a callback function to execute whenever a data stream is written to using + * . + * + * The user-defined callback function should accept two arguments: + * + *
    + *
  • $curl_handle - resource - Required - The cURL handle resource that represents the in-progress transfer.
  • + *
  • $length - integer - Required - The length in kilobytes of the data chunk that was transferred.
  • + *
+ * + * @param string|array|function $callback (Required) The callback function is called by , so you can pass the following values:
    + *
  • The name of a global function to execute, passed as a string.
  • + *
  • A method to execute, passed as array('ClassName', 'MethodName').
  • + *
  • An anonymous function (PHP 5.3+).
+ * @return $this A reference to the current instance. + */ + public function register_streaming_write_callback($callback) + { + $this->registered_streaming_write_callback = $callback; + + return $this; + } + + + /*%******************************************************************************************%*/ + // PREPARE, SEND, AND PROCESS REQUEST + + /** + * A callback function that is invoked by cURL for streaming up. + * + * @param resource $curl_handle (Required) The cURL handle for the request. + * @param resource $file_handle (Required) The open file handle resource. + * @param integer $length (Required) The maximum number of bytes to read. + * @return binary Binary data from a stream. + */ + public function streaming_read_callback($curl_handle, $file_handle, $length) + { + // Once we've sent as much as we're supposed to send... + if ($this->read_stream_read >= $this->read_stream_size) { + // Send EOF + return ''; + } + + // If we're at the beginning of an upload and need to seek... + if ($this->read_stream_read == 0 && isset($this->seek_position) && $this->seek_position !== ftell($this->read_stream)) { + if (fseek($this->read_stream, $this->seek_position) !== 0) { + throw new RequestCore_Exception('The stream does not support seeking and is either not at the requested position or the position is unknown.'); + } + } + + $read = fread($this->read_stream, min($this->read_stream_size - $this->read_stream_read, $length)); // Remaining upload data or cURL's requested chunk size + $this->read_stream_read += strlen($read); + + $out = $read === false ? '' : $read; + + // Execute callback function + if ($this->registered_streaming_read_callback) { + call_user_func($this->registered_streaming_read_callback, $curl_handle, $file_handle, $out); + } + + return $out; + } + + /** + * A callback function that is invoked by cURL for streaming down. + * + * @param resource $curl_handle (Required) The cURL handle for the request. + * @param binary $data (Required) The data to write. + * @return integer The number of bytes written. + */ + public function streaming_write_callback($curl_handle, $data) + { + $length = strlen($data); + $written_total = 0; + $written_last = 0; + + while ($written_total < $length) { + $written_last = fwrite($this->write_stream, substr($data, $written_total)); + + if ($written_last === false) { + return $written_total; + } + + $written_total += $written_last; + } + + // Execute callback function + if ($this->registered_streaming_write_callback) { + call_user_func($this->registered_streaming_write_callback, $curl_handle, $written_total); + } + + return $written_total; + } + + /** + * Prepares and adds the details of the cURL request. This can be passed along to a + * function. + * + * @return resource The handle for the cURL object. + * + */ + public function prep_request() + { + $curl_handle = curl_init(); + + // Set default options. + curl_setopt($curl_handle, CURLOPT_URL, $this->request_url); + curl_setopt($curl_handle, CURLOPT_FILETIME, true); + curl_setopt($curl_handle, CURLOPT_FRESH_CONNECT, false); +// curl_setopt($curl_handle, CURLOPT_CLOSEPOLICY, CURLCLOSEPOLICY_LEAST_RECENTLY_USED); + curl_setopt($curl_handle, CURLOPT_MAXREDIRS, 5); + curl_setopt($curl_handle, CURLOPT_HEADER, true); + curl_setopt($curl_handle, CURLOPT_RETURNTRANSFER, true); + curl_setopt($curl_handle, CURLOPT_TIMEOUT, $this->timeout); + curl_setopt($curl_handle, CURLOPT_CONNECTTIMEOUT, $this->connect_timeout); + curl_setopt($curl_handle, CURLOPT_NOSIGNAL, true); + curl_setopt($curl_handle, CURLOPT_REFERER, $this->request_url); + curl_setopt($curl_handle, CURLOPT_USERAGENT, $this->useragent); + curl_setopt($curl_handle, CURLOPT_READFUNCTION, array($this, 'streaming_read_callback')); + + // Verification of the SSL cert + if ($this->ssl_verification) { + curl_setopt($curl_handle, CURLOPT_SSL_VERIFYPEER, true); + curl_setopt($curl_handle, CURLOPT_SSL_VERIFYHOST, 2); + } else { + curl_setopt($curl_handle, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($curl_handle, CURLOPT_SSL_VERIFYHOST, false); + } + + // chmod the file as 0755 + if ($this->cacert_location === true) { + curl_setopt($curl_handle, CURLOPT_CAINFO, dirname(__FILE__) . '/cacert.pem'); + } elseif (is_string($this->cacert_location)) { + curl_setopt($curl_handle, CURLOPT_CAINFO, $this->cacert_location); + } + + // Debug mode + if ($this->debug_mode) { + curl_setopt($curl_handle, CURLOPT_VERBOSE, true); + } + + // Handle open_basedir & safe mode + if (!ini_get('safe_mode') && !ini_get('open_basedir')) { + curl_setopt($curl_handle, CURLOPT_FOLLOWLOCATION, true); + } + + // Enable a proxy connection if requested. + if ($this->proxy) { + curl_setopt($curl_handle, CURLOPT_HTTPPROXYTUNNEL, true); + + $host = $this->proxy['host']; + $host .= ($this->proxy['port']) ? ':' . $this->proxy['port'] : ''; + curl_setopt($curl_handle, CURLOPT_PROXY, $host); + + if (isset($this->proxy['user']) && isset($this->proxy['pass'])) { + curl_setopt($curl_handle, CURLOPT_PROXYUSERPWD, $this->proxy['user'] . ':' . $this->proxy['pass']); + } + } + + // Set credentials for HTTP Basic/Digest Authentication. + if ($this->username && $this->password) { + curl_setopt($curl_handle, CURLOPT_HTTPAUTH, CURLAUTH_ANY); + curl_setopt($curl_handle, CURLOPT_USERPWD, $this->username . ':' . $this->password); + } + + // Handle the encoding if we can. + if (extension_loaded('zlib')) { + curl_setopt($curl_handle, CURLOPT_ENCODING, ''); + } + + // Process custom headers + if (isset($this->request_headers) && count($this->request_headers)) { + $temp_headers = array(); + + foreach ($this->request_headers as $k => $v) { + $temp_headers[] = $k . ': ' . $v; + } + + curl_setopt($curl_handle, CURLOPT_HTTPHEADER, $temp_headers); + } + + switch ($this->method) { + case self::HTTP_PUT: + //unset($this->read_stream); + curl_setopt($curl_handle, CURLOPT_CUSTOMREQUEST, 'PUT'); + if (isset($this->read_stream)) { + if (!isset($this->read_stream_size) || $this->read_stream_size < 0) { + throw new RequestCore_Exception('The stream size for the streaming upload cannot be determined.'); + } + curl_setopt($curl_handle, CURLOPT_INFILESIZE, $this->read_stream_size); + curl_setopt($curl_handle, CURLOPT_UPLOAD, true); + } else { + curl_setopt($curl_handle, CURLOPT_POSTFIELDS, $this->request_body); + } + break; + + case self::HTTP_POST: + curl_setopt($curl_handle, CURLOPT_CUSTOMREQUEST, 'POST'); + if (isset($this->read_stream)) { + if (!isset($this->read_stream_size) || $this->read_stream_size < 0) { + throw new RequestCore_Exception('The stream size for the streaming upload cannot be determined.'); + } + curl_setopt($curl_handle, CURLOPT_INFILESIZE, $this->read_stream_size); + curl_setopt($curl_handle, CURLOPT_UPLOAD, true); + } else { + curl_setopt($curl_handle, CURLOPT_POSTFIELDS, $this->request_body); + } + break; + + case self::HTTP_HEAD: + curl_setopt($curl_handle, CURLOPT_CUSTOMREQUEST, self::HTTP_HEAD); + curl_setopt($curl_handle, CURLOPT_NOBODY, 1); + break; + + default: // Assumed GET + curl_setopt($curl_handle, CURLOPT_CUSTOMREQUEST, $this->method); + if (isset($this->write_stream)) { + curl_setopt($curl_handle, CURLOPT_WRITEFUNCTION, array($this, 'streaming_write_callback')); + curl_setopt($curl_handle, CURLOPT_HEADER, false); + } else { + curl_setopt($curl_handle, CURLOPT_POSTFIELDS, $this->request_body); + } + break; + } + + // Merge in the CURLOPTs + if (isset($this->curlopts) && sizeof($this->curlopts) > 0) { + foreach ($this->curlopts as $k => $v) { + curl_setopt($curl_handle, $k, $v); + } + } + + return $curl_handle; + } + + /** + * Take the post-processed cURL data and break it down into useful header/body/info chunks. Uses the + * data stored in the `curl_handle` and `response` properties unless replacement data is passed in via + * parameters. + * + * @param resource $curl_handle (Optional) The reference to the already executed cURL request. + * @param string $response (Optional) The actual response content itself that needs to be parsed. + * @return ResponseCore A object containing a parsed HTTP response. + */ + public function process_response($curl_handle = null, $response = null) + { + // Accept a custom one if it's passed. + if ($curl_handle && $response) { + $this->curl_handle = $curl_handle; + $this->response = $response; + } + + // As long as this came back as a valid resource... + if (is_resource($this->curl_handle)) { + // Determine what's what. + $header_size = curl_getinfo($this->curl_handle, CURLINFO_HEADER_SIZE); + $this->response_headers = substr($this->response, 0, $header_size); + $this->response_body = substr($this->response, $header_size); + $this->response_code = curl_getinfo($this->curl_handle, CURLINFO_HTTP_CODE); + $this->response_info = curl_getinfo($this->curl_handle); + + // Parse out the headers + $this->response_headers = explode("\r\n\r\n", trim($this->response_headers)); + $this->response_headers = array_pop($this->response_headers); + $this->response_headers = explode("\r\n", $this->response_headers); + array_shift($this->response_headers); + + // Loop through and split up the headers. + $header_assoc = array(); + foreach ($this->response_headers as $header) { + $kv = explode(': ', $header); + $header_assoc[strtolower($kv[0])] = isset($kv[1]) ? $kv[1] : ''; + } + + // Reset the headers to the appropriate property. + $this->response_headers = $header_assoc; + $this->response_headers['_info'] = $this->response_info; + $this->response_headers['_info']['method'] = $this->method; + + if ($curl_handle && $response) { + //return new $this->response_class($this->response_headers, $this->response_body, $this->response_code, $this->curl_handle); + return new ResponseCore($this->response_headers, $this->response_body, $this->response_code); + } + } + + // Return false + return false; + } + + /** + * Sends the request, calling necessary utility functions to update built-in properties. + * + * @param boolean $parse (Optional) Whether to parse the response with ResponseCore or not. + * @return string The resulting unparsed data from the request. + */ + public function send_request($parse = false) + { + set_time_limit(0); + + $curl_handle = $this->prep_request(); + $this->response = curl_exec($curl_handle); + + if ($this->response === false) { + throw new RequestCore_Exception('cURL resource: ' . (string)$curl_handle . '; cURL error: ' . curl_error($curl_handle) . ' (' . curl_errno($curl_handle) . ')'); + } + + $parsed_response = $this->process_response($curl_handle, $this->response); + + curl_close($curl_handle); + + if ($parse) { + return $parsed_response; + } + + return $this->response; + } + + /** + * Sends the request using , enabling parallel requests. Uses the "rolling" method. + * + * @param array $handles (Required) An indexed array of cURL handles to process simultaneously. + * @param array $opt (Optional) An associative array of parameters that can have the following keys:
    + *
  • callback - string|array - Optional - The string name of a function to pass the response data to. If this is a method, pass an array where the [0] index is the class and the [1] index is the method name.
  • + *
  • limit - integer - Optional - The number of simultaneous requests to make. This can be useful for scaling around slow server responses. Defaults to trusting cURLs judgement as to how many to use.
+ * @return array Post-processed cURL responses. + */ + public function send_multi_request($handles, $opt = null) + { + set_time_limit(0); + + // Skip everything if there are no handles to process. + if (count($handles) === 0) return array(); + + if (!$opt) $opt = array(); + + // Initialize any missing options + $limit = isset($opt['limit']) ? $opt['limit'] : -1; + + // Initialize + $handle_list = $handles; + $http = new $this->request_class(); + $multi_handle = curl_multi_init(); + $handles_post = array(); + $added = count($handles); + $last_handle = null; + $count = 0; + $i = 0; + + // Loop through the cURL handles and add as many as it set by the limit parameter. + while ($i < $added) { + if ($limit > 0 && $i >= $limit) break; + curl_multi_add_handle($multi_handle, array_shift($handles)); + $i++; + } + + do { + $active = false; + + // Start executing and wait for a response. + while (($status = curl_multi_exec($multi_handle, $active)) === CURLM_CALL_MULTI_PERFORM) { + // Start looking for possible responses immediately when we have to add more handles + if (count($handles) > 0) break; + } + + // Figure out which requests finished. + $to_process = array(); + + while ($done = curl_multi_info_read($multi_handle)) { + // Since curl_errno() isn't reliable for handles that were in multirequests, we check the 'result' of the info read, which contains the curl error number, (listed here http://curl.haxx.se/libcurl/c/libcurl-errors.html ) + if ($done['result'] > 0) { + throw new RequestCore_Exception('cURL resource: ' . (string)$done['handle'] . '; cURL error: ' . curl_error($done['handle']) . ' (' . $done['result'] . ')'); + } // Because curl_multi_info_read() might return more than one message about a request, we check to see if this request is already in our array of completed requests + elseif (!isset($to_process[(int)$done['handle']])) { + $to_process[(int)$done['handle']] = $done; + } + } + + // Actually deal with the request + foreach ($to_process as $pkey => $done) { + $response = $http->process_response($done['handle'], curl_multi_getcontent($done['handle'])); + $key = array_search($done['handle'], $handle_list, true); + $handles_post[$key] = $response; + + if (count($handles) > 0) { + curl_multi_add_handle($multi_handle, array_shift($handles)); + } + + curl_multi_remove_handle($multi_handle, $done['handle']); + curl_close($done['handle']); + } + } while ($active || count($handles_post) < $added); + + curl_multi_close($multi_handle); + + ksort($handles_post, SORT_NUMERIC); + return $handles_post; + } + + + /*%******************************************************************************************%*/ + // RESPONSE METHODS + + /** + * Get the HTTP response headers from the request. + * + * @param string $header (Optional) A specific header value to return. Defaults to all headers. + * @return string|array All or selected header values. + */ + public function get_response_header($header = null) + { + if ($header) { + return $this->response_headers[strtolower($header)]; + } + return $this->response_headers; + } + + /** + * Get the HTTP response body from the request. + * + * @return string The response body. + */ + public function get_response_body() + { + return $this->response_body; + } + + /** + * Get the HTTP response code from the request. + * + * @return string The HTTP response code. + */ + public function get_response_code() + { + return $this->response_code; + } +} diff --git a/framework/library/alioss/src/OSS/Http/RequestCore_Exception.php b/framework/library/alioss/src/OSS/Http/RequestCore_Exception.php new file mode 100644 index 0000000..cb4e83c --- /dev/null +++ b/framework/library/alioss/src/OSS/Http/RequestCore_Exception.php @@ -0,0 +1,8 @@ +). + * @param string $body (Required) XML-formatted response from AWS. + * @param integer $status (Optional) HTTP response status code from the request. + * @return Mixed Contains an `header` property (HTTP headers as an associative array), a or `body` property, and an `status` code. + */ + public function __construct($header, $body, $status = null) + { + $this->header = $header; + $this->body = $body; + $this->status = $status; + + return $this; + } + + /** + * Did we receive the status code we expected? + * + * @param integer|array $codes (Optional) The status code(s) to expect. Pass an for a single acceptable value, or an of integers for multiple acceptable values. + * @return boolean Whether we received the expected status code or not. + */ + public function isOK($codes = array(200, 201, 204, 206)) + { + if (is_array($codes)) { + return in_array($this->status, $codes); + } + + return $this->status === $codes; + } +} \ No newline at end of file diff --git a/framework/library/alioss/src/OSS/Model/BucketInfo.php b/framework/library/alioss/src/OSS/Model/BucketInfo.php new file mode 100644 index 0000000..9b89674 --- /dev/null +++ b/framework/library/alioss/src/OSS/Model/BucketInfo.php @@ -0,0 +1,78 @@ +location = $location; + $this->name = $name; + $this->createDate = $createDate; + } + + /** + * 得到bucket所在的region + * + * @return string + */ + public function getLocation() + { + return $this->location; + } + + /** + * 得到bucket的名称 + * + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * 得到bucket的创建时间 + * + * @return string + */ + public function getCreateDate() + { + return $this->createDate; + } + + /** + * bucket所在的region + * + * @var string + */ + private $location; + /** + * bucket的名称 + * + * @var string + */ + private $name; + + /** + * bucket的创建事件 + * + * @var string + */ + private $createDate; + +} \ No newline at end of file diff --git a/framework/library/alioss/src/OSS/Model/BucketListInfo.php b/framework/library/alioss/src/OSS/Model/BucketListInfo.php new file mode 100644 index 0000000..910717f --- /dev/null +++ b/framework/library/alioss/src/OSS/Model/BucketListInfo.php @@ -0,0 +1,39 @@ +bucketList = $bucketList; + } + + /** + * 得到BucketInfo列表 + * + * @return BucketInfo[] + */ + public function getBucketList() + { + return $this->bucketList; + } + + /** + * BucketInfo信息列表 + * + * @var array + */ + private $bucketList = array(); +} \ No newline at end of file diff --git a/framework/library/alioss/src/OSS/Model/CnameConfig.php b/framework/library/alioss/src/OSS/Model/CnameConfig.php new file mode 100644 index 0000000..f3597d2 --- /dev/null +++ b/framework/library/alioss/src/OSS/Model/CnameConfig.php @@ -0,0 +1,99 @@ +cnameList = array(); + } + + /** + * @return array + * @example + * array(2) { + * [0]=> + * array(3) { + * ["Domain"]=> + * string(11) "www.foo.com" + * ["Status"]=> + * string(7) "enabled" + * ["LastModified"]=> + * string(8) "20150101" + * } + * [1]=> + * array(3) { + * ["Domain"]=> + * string(7) "bar.com" + * ["Status"]=> + * string(8) "disabled" + * ["LastModified"]=> + * string(8) "20160101" + * } + * } + */ + public function getCnames() + { + return $this->cnameList; + } + + + public function addCname($cname) + { + if (count($this->cnameList) >= self::OSS_MAX_RULES) { + throw new OssException( + "num of cname in the config exceeds self::OSS_MAX_RULES: " . strval(self::OSS_MAX_RULES)); + } + $this->cnameList[] = array('Domain' => $cname); + } + + public function parseFromXml($strXml) + { + $xml = simplexml_load_string($strXml); + if (!isset($xml->Cname)) return; + foreach ($xml->Cname as $entry) { + $cname = array(); + foreach ($entry as $key => $value) { + $cname[strval($key)] = strval($value); + } + $this->cnameList[] = $cname; + } + } + + public function serializeToXml() + { + $strXml = << + + +EOF; + $xml = new \SimpleXMLElement($strXml); + foreach ($this->cnameList as $cname) { + $node = $xml->addChild('Cname'); + foreach ($cname as $key => $value) { + $node->addChild($key, $value); + } + } + return $xml->asXML(); + } + + public function __toString() + { + return $this->serializeToXml(); + } + + const OSS_MAX_RULES = 10; + + private $cnameList = array(); +} \ No newline at end of file diff --git a/framework/library/alioss/src/OSS/Model/CorsConfig.php b/framework/library/alioss/src/OSS/Model/CorsConfig.php new file mode 100644 index 0000000..c44c10a --- /dev/null +++ b/framework/library/alioss/src/OSS/Model/CorsConfig.php @@ -0,0 +1,113 @@ +rules = array(); + } + + /** + * 得到CorsRule列表 + * + * @return CorsRule[] + */ + public function getRules() + { + return $this->rules; + } + + + /** + * 添加一条CorsRule + * + * @param CorsRule $rule + * @throws OssException + */ + public function addRule($rule) + { + if (count($this->rules) >= self::OSS_MAX_RULES) { + throw new OssException("num of rules in the config exceeds self::OSS_MAX_RULES: " . strval(self::OSS_MAX_RULES)); + } + $this->rules[] = $rule; + } + + /** + * 从xml数据中解析出CorsConfig + * + * @param string $strXml + * @throws OssException + * @return null + */ + public function parseFromXml($strXml) + { + $xml = simplexml_load_string($strXml); + if (!isset($xml->CORSRule)) return; + foreach ($xml->CORSRule as $rule) { + $corsRule = new CorsRule(); + foreach ($rule as $key => $value) { + if ($key === self::OSS_CORS_ALLOWED_HEADER) { + $corsRule->addAllowedHeader(strval($value)); + } elseif ($key === self::OSS_CORS_ALLOWED_METHOD) { + $corsRule->addAllowedMethod(strval($value)); + } elseif ($key === self::OSS_CORS_ALLOWED_ORIGIN) { + $corsRule->addAllowedOrigin(strval($value)); + } elseif ($key === self::OSS_CORS_EXPOSE_HEADER) { + $corsRule->addExposeHeader(strval($value)); + } elseif ($key === self::OSS_CORS_MAX_AGE_SECONDS) { + $corsRule->setMaxAgeSeconds(strval($value)); + } + } + $this->addRule($corsRule); + } + return; + } + + /** + * 生成xml字符串 + * + * @return string + */ + public function serializeToXml() + { + $xml = new \SimpleXMLElement(''); + foreach ($this->rules as $rule) { + $xmlRule = $xml->addChild('CORSRule'); + $rule->appendToXml($xmlRule); + } + return $xml->asXML(); + } + + public function __toString() + { + return $this->serializeToXml(); + } + + const OSS_CORS_ALLOWED_ORIGIN = 'AllowedOrigin'; + const OSS_CORS_ALLOWED_METHOD = 'AllowedMethod'; + const OSS_CORS_ALLOWED_HEADER = 'AllowedHeader'; + const OSS_CORS_EXPOSE_HEADER = 'ExposeHeader'; + const OSS_CORS_MAX_AGE_SECONDS = 'MaxAgeSeconds'; + const OSS_MAX_RULES = 10; + + /** + * orsRule列表 + * + * @var CorsRule[] + */ + private $rules = array(); +} \ No newline at end of file diff --git a/framework/library/alioss/src/OSS/Model/CorsRule.php b/framework/library/alioss/src/OSS/Model/CorsRule.php new file mode 100644 index 0000000..2cbe1c1 --- /dev/null +++ b/framework/library/alioss/src/OSS/Model/CorsRule.php @@ -0,0 +1,150 @@ +allowedOrigins[] = $allowedOrigin; + } + } + + /** + * Rule中增加一条allowedMethod + * + * @param string $allowedMethod + */ + public function addAllowedMethod($allowedMethod) + { + if (!empty($allowedMethod)) { + $this->allowedMethods[] = $allowedMethod; + } + } + + /** + * Rule中增加一条allowedHeader + * + * @param string $allowedHeader + */ + public function addAllowedHeader($allowedHeader) + { + if (!empty($allowedHeader)) { + $this->allowedHeaders[] = $allowedHeader; + } + } + + /** + * Rule中增加一条exposeHeader + * + * @param string $exposeHeader + */ + public function addExposeHeader($exposeHeader) + { + if (!empty($exposeHeader)) { + $this->exposeHeaders[] = $exposeHeader; + } + } + + /** + * @return int + */ + public function getMaxAgeSeconds() + { + return $this->maxAgeSeconds; + } + + /** + * @param int $maxAgeSeconds + */ + public function setMaxAgeSeconds($maxAgeSeconds) + { + $this->maxAgeSeconds = $maxAgeSeconds; + } + + /** + * 得到AllowedHeaders列表 + * + * @return string[] + */ + public function getAllowedHeaders() + { + return $this->allowedHeaders; + } + + /** + * 得到AllowedOrigins列表 + * + * @return string[] + */ + public function getAllowedOrigins() + { + return $this->allowedOrigins; + } + + /** + * 得到AllowedMethods列表 + * + * @return string[] + */ + public function getAllowedMethods() + { + return $this->allowedMethods; + } + + /** + * 得到ExposeHeaders列表 + * + * @return string[] + */ + public function getExposeHeaders() + { + return $this->exposeHeaders; + } + + /** + * 根据提供的xmlRule, 把this按照一定的规则插入到$xmlRule中 + * + * @param \SimpleXMLElement $xmlRule + * @throws OssException + */ + public function appendToXml(&$xmlRule) + { + if (!isset($this->maxAgeSeconds)) { + throw new OssException("maxAgeSeconds is not set in the Rule"); + } + foreach ($this->allowedOrigins as $allowedOrigin) { + $xmlRule->addChild(CorsConfig::OSS_CORS_ALLOWED_ORIGIN, $allowedOrigin); + } + foreach ($this->allowedMethods as $allowedMethod) { + $xmlRule->addChild(CorsConfig::OSS_CORS_ALLOWED_METHOD, $allowedMethod); + } + foreach ($this->allowedHeaders as $allowedHeader) { + $xmlRule->addChild(CorsConfig::OSS_CORS_ALLOWED_HEADER, $allowedHeader); + } + foreach ($this->exposeHeaders as $exposeHeader) { + $xmlRule->addChild(CorsConfig::OSS_CORS_EXPOSE_HEADER, $exposeHeader); + } + $xmlRule->addChild(CorsConfig::OSS_CORS_MAX_AGE_SECONDS, strval($this->maxAgeSeconds)); + } + + private $allowedHeaders = array(); + private $allowedOrigins = array(); + private $allowedMethods = array(); + private $exposeHeaders = array(); + private $maxAgeSeconds = null; +} \ No newline at end of file diff --git a/framework/library/alioss/src/OSS/Model/LifecycleAction.php b/framework/library/alioss/src/OSS/Model/LifecycleAction.php new file mode 100644 index 0000000..5abd825 --- /dev/null +++ b/framework/library/alioss/src/OSS/Model/LifecycleAction.php @@ -0,0 +1,88 @@ +action = $action; + $this->timeSpec = $timeSpec; + $this->timeValue = $timeValue; + } + + /** + * @return LifecycleAction + */ + public function getAction() + { + return $this->action; + } + + /** + * @param string $action + */ + public function setAction($action) + { + $this->action = $action; + } + + /** + * @return string + */ + public function getTimeSpec() + { + return $this->timeSpec; + } + + /** + * @param string $timeSpec + */ + public function setTimeSpec($timeSpec) + { + $this->timeSpec = $timeSpec; + } + + /** + * @return string + */ + public function getTimeValue() + { + return $this->timeValue; + } + + /** + * @param string $timeValue + */ + public function setTimeValue($timeValue) + { + $this->timeValue = $timeValue; + } + + /** + * appendToXml 把actions插入到xml中 + * + * @param \SimpleXMLElement $xmlRule + */ + public function appendToXml(&$xmlRule) + { + $xmlAction = $xmlRule->addChild($this->action); + $xmlAction->addChild($this->timeSpec, $this->timeValue); + } + + private $action; + private $timeSpec; + private $timeValue; + +} \ No newline at end of file diff --git a/framework/library/alioss/src/OSS/Model/LifecycleConfig.php b/framework/library/alioss/src/OSS/Model/LifecycleConfig.php new file mode 100644 index 0000000..fc4f575 --- /dev/null +++ b/framework/library/alioss/src/OSS/Model/LifecycleConfig.php @@ -0,0 +1,107 @@ +rules = array(); + $xml = simplexml_load_string($strXml); + if (!isset($xml->Rule)) return; + $this->rules = array(); + foreach ($xml->Rule as $rule) { + $id = strval($rule->ID); + $prefix = strval($rule->Prefix); + $status = strval($rule->Status); + $actions = array(); + foreach ($rule as $key => $value) { + if ($key === 'ID' || $key === 'Prefix' || $key === 'Status') continue; + $action = $key; + $timeSpec = null; + $timeValue = null; + foreach ($value as $timeSpecKey => $timeValueValue) { + $timeSpec = $timeSpecKey; + $timeValue = strval($timeValueValue); + } + $actions[] = new LifecycleAction($action, $timeSpec, $timeValue); + } + $this->rules[] = new LifecycleRule($id, $prefix, $status, $actions); + } + return; + } + + + /** + * 生成xml字符串 + * + * @return string + */ + public function serializeToXml() + { + + $xml = new \SimpleXMLElement(''); + foreach ($this->rules as $rule) { + $xmlRule = $xml->addChild('Rule'); + $rule->appendToXml($xmlRule); + } + return $xml->asXML(); + } + + /** + * + * 添加LifecycleRule + * + * @param LifecycleRule $lifecycleRule + * @throws OssException + */ + public function addRule($lifecycleRule) + { + if (!isset($lifecycleRule)) { + throw new OssException("lifecycleRule is null"); + } + $this->rules[] = $lifecycleRule; + } + + /** + * 将配置转换成字符串,便于用户查看 + * + * @return string + */ + public function __toString() + { + return $this->serializeToXml(); + } + + /** + * 得到所有的生命周期规则 + * + * @return LifecycleRule[] + */ + public function getRules() + { + return $this->rules; + } + + /** + * @var LifecycleRule[] + */ + private $rules; +} + + diff --git a/framework/library/alioss/src/OSS/Model/LifecycleRule.php b/framework/library/alioss/src/OSS/Model/LifecycleRule.php new file mode 100644 index 0000000..ec615b9 --- /dev/null +++ b/framework/library/alioss/src/OSS/Model/LifecycleRule.php @@ -0,0 +1,126 @@ +id; + } + + /** + * @param string $id 规则ID + */ + public function setId($id) + { + $this->id = $id; + } + + /** + * 得到文件前缀 + * + * @return string + */ + public function getPrefix() + { + return $this->prefix; + } + + /** + * 设置文件前缀 + * + * @param string $prefix 文件前缀 + */ + public function setPrefix($prefix) + { + $this->prefix = $prefix; + } + + /** + * Lifecycle规则的状态 + * + * @return string + */ + public function getStatus() + { + return $this->status; + } + + /** + * 设置Lifecycle规则状态 + * + * @param string $status + */ + public function setStatus($status) + { + $this->status = $status; + } + + /** + * + * @return LifecycleAction[] + */ + public function getActions() + { + return $this->actions; + } + + /** + * @param LifecycleAction[] $actions + */ + public function setActions($actions) + { + $this->actions = $actions; + } + + + /** + * LifecycleRule constructor. + * + * @param string $id 规则ID + * @param string $prefix 文件前缀 + * @param string $status 规则状态,可选[self::LIFECYCLE_STATUS_ENABLED, self::LIFECYCLE_STATUS_DISABLED] + * @param LifecycleAction[] $actions + */ + public function __construct($id, $prefix, $status, $actions) + { + $this->id = $id; + $this->prefix = $prefix; + $this->status = $status; + $this->actions = $actions; + } + + /** + * @param \SimpleXMLElement $xmlRule + */ + public function appendToXml(&$xmlRule) + { + $xmlRule->addChild('ID', $this->id); + $xmlRule->addChild('Prefix', $this->prefix); + $xmlRule->addChild('Status', $this->status); + foreach ($this->actions as $action) { + $action->appendToXml($xmlRule); + } + } + + private $id; + private $prefix; + private $status; + private $actions = array(); + + const LIFECYCLE_STATUS_ENABLED = 'Enabled'; + const LIFECYCLE_STATUS_DISABLED = 'Disabled'; +} \ No newline at end of file diff --git a/framework/library/alioss/src/OSS/Model/ListMultipartUploadInfo.php b/framework/library/alioss/src/OSS/Model/ListMultipartUploadInfo.php new file mode 100644 index 0000000..105d005 --- /dev/null +++ b/framework/library/alioss/src/OSS/Model/ListMultipartUploadInfo.php @@ -0,0 +1,134 @@ +bucket = $bucket; + $this->keyMarker = $keyMarker; + $this->uploadIdMarker = $uploadIdMarker; + $this->nextKeyMarker = $nextKeyMarker; + $this->nextUploadIdMarker = $nextUploadIdMarker; + $this->delimiter = $delimiter; + $this->prefix = $prefix; + $this->maxUploads = $maxUploads; + $this->isTruncated = $isTruncated; + $this->uploads = $uploads; + } + + /** + * 得到bucket名称 + * + * @return string + */ + public function getBucket() + { + return $this->bucket; + } + + /** + * @return string + */ + public function getKeyMarker() + { + return $this->keyMarker; + } + + /** + * + * @return string + */ + public function getUploadIdMarker() + { + return $this->uploadIdMarker; + } + + /** + * @return string + */ + public function getNextKeyMarker() + { + return $this->nextKeyMarker; + } + + /** + * @return string + */ + public function getNextUploadIdMarker() + { + return $this->nextUploadIdMarker; + } + + /** + * @return string + */ + public function getDelimiter() + { + return $this->delimiter; + } + + /** + * @return string + */ + public function getPrefix() + { + return $this->prefix; + } + + /** + * @return int + */ + public function getMaxUploads() + { + return $this->maxUploads; + } + + /** + * @return string + */ + public function getIsTruncated() + { + return $this->isTruncated; + } + + /** + * @return UploadInfo[] + */ + public function getUploads() + { + return $this->uploads; + } + + private $bucket = ""; + private $keyMarker = ""; + private $uploadIdMarker = ""; + private $nextKeyMarker = ""; + private $nextUploadIdMarker = ""; + private $delimiter = ""; + private $prefix = ""; + private $maxUploads = 0; + private $isTruncated = "false"; + private $uploads = array(); +} \ No newline at end of file diff --git a/framework/library/alioss/src/OSS/Model/ListPartsInfo.php b/framework/library/alioss/src/OSS/Model/ListPartsInfo.php new file mode 100644 index 0000000..f1d10ee --- /dev/null +++ b/framework/library/alioss/src/OSS/Model/ListPartsInfo.php @@ -0,0 +1,97 @@ +bucket = $bucket; + $this->key = $key; + $this->uploadId = $uploadId; + $this->nextPartNumberMarker = $nextPartNumberMarker; + $this->maxParts = $maxParts; + $this->isTruncated = $isTruncated; + $this->listPart = $listPart; + } + + /** + * @return string + */ + public function getBucket() + { + return $this->bucket; + } + + /** + * @return string + */ + public function getKey() + { + return $this->key; + } + + /** + * @return string + */ + public function getUploadId() + { + return $this->uploadId; + } + + /** + * @return int + */ + public function getNextPartNumberMarker() + { + return $this->nextPartNumberMarker; + } + + /** + * @return int + */ + public function getMaxParts() + { + return $this->maxParts; + } + + /** + * @return string + */ + public function getIsTruncated() + { + return $this->isTruncated; + } + + /** + * @return array + */ + public function getListPart() + { + return $this->listPart; + } + + private $bucket = ""; + private $key = ""; + private $uploadId = ""; + private $nextPartNumberMarker = 0; + private $maxParts = 0; + private $isTruncated = ""; + private $listPart = array(); +} \ No newline at end of file diff --git a/framework/library/alioss/src/OSS/Model/LoggingConfig.php b/framework/library/alioss/src/OSS/Model/LoggingConfig.php new file mode 100644 index 0000000..978421a --- /dev/null +++ b/framework/library/alioss/src/OSS/Model/LoggingConfig.php @@ -0,0 +1,86 @@ +targetBucket = $targetBucket; + $this->targetPrefix = $targetPrefix; + } + + /** + * @param $strXml + * @return null + */ + public function parseFromXml($strXml) + { + $xml = simplexml_load_string($strXml); + if (!isset($xml->LoggingEnabled)) return; + foreach ($xml->LoggingEnabled as $status) { + foreach ($status as $key => $value) { + if ($key === 'TargetBucket') { + $this->targetBucket = strval($value); + } elseif ($key === 'TargetPrefix') { + $this->targetPrefix = strval($value); + } + } + break; + } + } + + /** + * 序列化成xml字符串 + * + */ + public function serializeToXml() + { + $xml = new \SimpleXMLElement(''); + if (isset($this->targetBucket) && isset($this->targetPrefix)) { + $loggingEnabled = $xml->addChild('LoggingEnabled'); + $loggingEnabled->addChild('TargetBucket', $this->targetBucket); + $loggingEnabled->addChild('TargetPrefix', $this->targetPrefix); + } + return $xml->asXML(); + } + + /** + * @return string + */ + public function __toString() + { + return $this->serializeToXml(); + } + + /** + * @return string + */ + public function getTargetBucket() + { + return $this->targetBucket; + } + + /** + * @return string + */ + public function getTargetPrefix() + { + return $this->targetPrefix; + } + + private $targetBucket = ""; + private $targetPrefix = ""; + +} \ No newline at end of file diff --git a/framework/library/alioss/src/OSS/Model/ObjectInfo.php b/framework/library/alioss/src/OSS/Model/ObjectInfo.php new file mode 100644 index 0000000..2ae6c99 --- /dev/null +++ b/framework/library/alioss/src/OSS/Model/ObjectInfo.php @@ -0,0 +1,93 @@ +key = $key; + $this->lastModified = $lastModified; + $this->eTag = $eTag; + $this->type = $type; + $this->size = $size; + $this->storageClass = $storageClass; + } + + /** + * @return string + */ + public function getKey() + { + return $this->key; + } + + /** + * @return string + */ + public function getLastModified() + { + return $this->lastModified; + } + + /** + * @return string + */ + public function getETag() + { + return $this->eTag; + } + + /** + * @return string + */ + public function getType() + { + return $this->type; + } + + /** + * @return int + */ + public function getSize() + { + return $this->size; + } + + /** + * @return string + */ + public function getStorageClass() + { + return $this->storageClass; + } + + private $key = ""; + private $lastModified = ""; + private $eTag = ""; + private $type = ""; + private $size = 0; + private $storageClass = ""; +} \ No newline at end of file diff --git a/framework/library/alioss/src/OSS/Model/ObjectListInfo.php b/framework/library/alioss/src/OSS/Model/ObjectListInfo.php new file mode 100644 index 0000000..dbe7c7a --- /dev/null +++ b/framework/library/alioss/src/OSS/Model/ObjectListInfo.php @@ -0,0 +1,126 @@ +bucketName = $bucketName; + $this->prefix = $prefix; + $this->marker = $marker; + $this->nextMarker = $nextMarker; + $this->maxKeys = $maxKeys; + $this->delimiter = $delimiter; + $this->isTruncated = $isTruncated; + $this->objectList = $objectList; + $this->prefixList = $prefixList; + } + + /** + * @return string + */ + public function getBucketName() + { + return $this->bucketName; + } + + /** + * @return string + */ + public function getPrefix() + { + return $this->prefix; + } + + /** + * @return string + */ + public function getMarker() + { + return $this->marker; + } + + /** + * @return int + */ + public function getMaxKeys() + { + return $this->maxKeys; + } + + /** + * @return string + */ + public function getDelimiter() + { + return $this->delimiter; + } + + /** + * @return mixed + */ + public function getIsTruncated() + { + return $this->isTruncated; + } + + /** + * 返回ListObjects接口返回数据中的ObjectInfo列表 + * + * @return ObjectInfo[] + */ + public function getObjectList() + { + return $this->objectList; + } + + /** + * 返回ListObjects接口返回数据中的PrefixInfo列表 + * + * @return PrefixInfo[] + */ + public function getPrefixList() + { + return $this->prefixList; + } + + /** + * @return string + */ + public function getNextMarker() + { + return $this->nextMarker; + } + + private $bucketName = ""; + private $prefix = ""; + private $marker = ""; + private $nextMarker = ""; + private $maxKeys = 0; + private $delimiter = ""; + private $isTruncated = null; + private $objectList = array(); + private $prefixList = array(); +} \ No newline at end of file diff --git a/framework/library/alioss/src/OSS/Model/PartInfo.php b/framework/library/alioss/src/OSS/Model/PartInfo.php new file mode 100644 index 0000000..439a84d --- /dev/null +++ b/framework/library/alioss/src/OSS/Model/PartInfo.php @@ -0,0 +1,63 @@ +partNumber = $partNumber; + $this->lastModified = $lastModified; + $this->eTag = $eTag; + $this->size = $size; + } + + /** + * @return int + */ + public function getPartNumber() + { + return $this->partNumber; + } + + /** + * @return string + */ + public function getLastModified() + { + return $this->lastModified; + } + + /** + * @return string + */ + public function getETag() + { + return $this->eTag; + } + + /** + * @return int + */ + public function getSize() + { + return $this->size; + } + + private $partNumber = 0; + private $lastModified = ""; + private $eTag = ""; + private $size = 0; +} \ No newline at end of file diff --git a/framework/library/alioss/src/OSS/Model/PrefixInfo.php b/framework/library/alioss/src/OSS/Model/PrefixInfo.php new file mode 100644 index 0000000..e61eac4 --- /dev/null +++ b/framework/library/alioss/src/OSS/Model/PrefixInfo.php @@ -0,0 +1,36 @@ +prefix = $prefix; + } + + /** + * @return string + */ + public function getPrefix() + { + return $this->prefix; + } + + private $prefix; +} \ No newline at end of file diff --git a/framework/library/alioss/src/OSS/Model/RefererConfig.php b/framework/library/alioss/src/OSS/Model/RefererConfig.php new file mode 100644 index 0000000..1d7d975 --- /dev/null +++ b/framework/library/alioss/src/OSS/Model/RefererConfig.php @@ -0,0 +1,93 @@ +AllowEmptyReferer)) return; + if (!isset($xml->RefererList)) return; + $this->allowEmptyReferer = + (strval($xml->AllowEmptyReferer) === 'TRUE' || strval($xml->AllowEmptyReferer) === 'true') ? true : false; + + foreach ($xml->RefererList->Referer as $key => $refer) { + $this->refererList[] = strval($refer); + } + } + + + /** + * 把RefererConfig序列化成xml + * + * @return string + */ + public function serializeToXml() + { + $xml = new \SimpleXMLElement(''); + if ($this->allowEmptyReferer) { + $xml->addChild('AllowEmptyReferer', 'true'); + } else { + $xml->addChild('AllowEmptyReferer', 'false'); + } + $refererList = $xml->addChild('RefererList'); + foreach ($this->refererList as $referer) { + $refererList->addChild('Referer', $referer); + } + return $xml->asXML(); + } + + /** + * @return string + */ + function __toString() + { + return $this->serializeToXml(); + } + + /** + * @param boolean $allowEmptyReferer + */ + public function setAllowEmptyReferer($allowEmptyReferer) + { + $this->allowEmptyReferer = $allowEmptyReferer; + } + + /** + * @param string $referer + */ + public function addReferer($referer) + { + $this->refererList[] = $referer; + } + + /** + * @return boolean + */ + public function isAllowEmptyReferer() + { + return $this->allowEmptyReferer; + } + + /** + * @return array + */ + public function getRefererList() + { + return $this->refererList; + } + + private $allowEmptyReferer = true; + private $refererList = array(); +} \ No newline at end of file diff --git a/framework/library/alioss/src/OSS/Model/UploadInfo.php b/framework/library/alioss/src/OSS/Model/UploadInfo.php new file mode 100644 index 0000000..8eaa363 --- /dev/null +++ b/framework/library/alioss/src/OSS/Model/UploadInfo.php @@ -0,0 +1,55 @@ +key = $key; + $this->uploadId = $uploadId; + $this->initiated = $initiated; + } + + /** + * @return string + */ + public function getKey() + { + return $this->key; + } + + /** + * @return string + */ + public function getUploadId() + { + return $this->uploadId; + } + + /** + * @return string + */ + public function getInitiated() + { + return $this->initiated; + } + + private $key = ""; + private $uploadId = ""; + private $initiated = ""; +} \ No newline at end of file diff --git a/framework/library/alioss/src/OSS/Model/WebsiteConfig.php b/framework/library/alioss/src/OSS/Model/WebsiteConfig.php new file mode 100644 index 0000000..8ea08a0 --- /dev/null +++ b/framework/library/alioss/src/OSS/Model/WebsiteConfig.php @@ -0,0 +1,76 @@ +indexDocument = $indexDocument; + $this->errorDocument = $errorDocument; + } + + /** + * @param string $strXml + * @return null + */ + public function parseFromXml($strXml) + { + $xml = simplexml_load_string($strXml); + if (isset($xml->IndexDocument) && isset($xml->IndexDocument->Suffix)) { + $this->indexDocument = strval($xml->IndexDocument->Suffix); + } + if (isset($xml->ErrorDocument) && isset($xml->ErrorDocument->Key)) { + $this->errorDocument = strval($xml->ErrorDocument->Key); + } + } + + /** + * 把WebsiteConfig序列化成xml + * + * @return string + * @throws OssException + */ + public function serializeToXml() + { + $xml = new \SimpleXMLElement(''); + $index_document_part = $xml->addChild('IndexDocument'); + $error_document_part = $xml->addChild('ErrorDocument'); + $index_document_part->addChild('Suffix', $this->indexDocument); + $error_document_part->addChild('Key', $this->errorDocument); + return $xml->asXML(); + } + + /** + * @return string + */ + public function getIndexDocument() + { + return $this->indexDocument; + } + + /** + * @return string + */ + public function getErrorDocument() + { + return $this->errorDocument; + } + + private $indexDocument = ""; + private $errorDocument = ""; +} \ No newline at end of file diff --git a/framework/library/alioss/src/OSS/Model/XmlConfig.php b/framework/library/alioss/src/OSS/Model/XmlConfig.php new file mode 100644 index 0000000..d353a22 --- /dev/null +++ b/framework/library/alioss/src/OSS/Model/XmlConfig.php @@ -0,0 +1,27 @@ +hostname = $this->checkEndpoint($endpoint, $isCName); + $this->accessKeyId = $accessKeyId; + $this->accessKeySecret = $accessKeySecret; + $this->securityToken = $securityToken; + self::checkEnv(); + } + + /** + * 列举用户所有的Bucket[GetService], Endpoint类型为cname不能进行此操作 + * + * @param array $options + * @throws OssException + * @return BucketListInfo + */ + public function listBuckets($options = NULL) + { + if ($this->hostType === self::OSS_HOST_TYPE_CNAME) { + throw new OssException("operation is not permitted with CName host"); + } + $this->precheckOptions($options); + $options[self::OSS_BUCKET] = ''; + $options[self::OSS_METHOD] = self::OSS_HTTP_GET; + $options[self::OSS_OBJECT] = '/'; + $response = $this->auth($options); + $result = new ListBucketsResult($response); + return $result->getData(); + } + + /** + * 创建bucket,默认创建的bucket的ACL是OssClient::OSS_ACL_TYPE_PRIVATE + * + * @param string $bucket + * @param string $acl + * @param array $options + * @return null + */ + public function createBucket($bucket, $acl = self::OSS_ACL_TYPE_PRIVATE, $options = NULL) + { + $this->precheckCommon($bucket, NULL, $options, false); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_PUT; + $options[self::OSS_OBJECT] = '/'; + $options[self::OSS_HEADERS] = array(self::OSS_ACL => $acl); + $response = $this->auth($options); + $result = new PutSetDeleteResult($response); + return $result->getData(); + } + + /** + * 删除bucket + * 如果Bucket不为空(Bucket中有Object,或者有分块上传的碎片),则Bucket无法删除, + * 必须删除Bucket中的所有Object以及碎片后,Bucket才能成功删除。 + * + * @param string $bucket + * @param array $options + * @return null + */ + public function deleteBucket($bucket, $options = NULL) + { + $this->precheckCommon($bucket, NULL, $options, false); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_DELETE; + $options[self::OSS_OBJECT] = '/'; + $response = $this->auth($options); + $result = new PutSetDeleteResult($response); + return $result->getData(); + } + + /** + * 判断bucket是否存在 + * + * @param string $bucket + * @return bool + * @throws OssException + */ + public function doesBucketExist($bucket) + { + $this->precheckCommon($bucket, NULL, $options, false); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_GET; + $options[self::OSS_OBJECT] = '/'; + $options[self::OSS_SUB_RESOURCE] = 'acl'; + $response = $this->auth($options); + $result = new ExistResult($response); + return $result->getData(); + } + + /** + * 获取bucket的ACL配置情况 + * + * @param string $bucket + * @param array $options + * @throws OssException + * @return string + */ + public function getBucketAcl($bucket, $options = NULL) + { + $this->precheckCommon($bucket, NULL, $options, false); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_GET; + $options[self::OSS_OBJECT] = '/'; + $options[self::OSS_SUB_RESOURCE] = 'acl'; + $response = $this->auth($options); + $result = new AclResult($response); + return $result->getData(); + } + + /** + * 设置bucket的ACL配置情况 + * + * @param string $bucket bucket名称 + * @param string $acl 读写权限,可选值 ['private', 'public-read', 'public-read-write'] + * @param array $options 可以为空 + * @throws OssException + * @return null + */ + public function putBucketAcl($bucket, $acl, $options = NULL) + { + $this->precheckCommon($bucket, NULL, $options, false); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_PUT; + $options[self::OSS_OBJECT] = '/'; + $options[self::OSS_HEADERS] = array(self::OSS_ACL => $acl); + $options[self::OSS_SUB_RESOURCE] = 'acl'; + $response = $this->auth($options); + $result = new PutSetDeleteResult($response); + return $result->getData(); + } + + /** + * 获取object的ACL属性 + * + * @param string $bucket + * @param string $object + * @throws OssException + * @return string + */ + public function getObjectAcl($bucket, $object) + { + $options = array(); + $this->precheckCommon($bucket, $object, $options, true); + $options[self::OSS_METHOD] = self::OSS_HTTP_GET; + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_OBJECT] = $object; + $options[self::OSS_SUB_RESOURCE] = 'acl'; + $response = $this->auth($options); + $result = new AclResult($response); + return $result->getData(); + } + + /** + * 设置object的ACL属性 + * + * @param string $bucket bucket名称 + * @param string $object object名称 + * @param string $acl 读写权限,可选值 ['default', 'private', 'public-read', 'public-read-write'] + * @throws OssException + * @return null + */ + public function putObjectAcl($bucket, $object, $acl) + { + $this->precheckCommon($bucket, $object, $options, true); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_PUT; + $options[self::OSS_OBJECT] = $object; + $options[self::OSS_HEADERS] = array(self::OSS_OBJECT_ACL => $acl); + $options[self::OSS_SUB_RESOURCE] = 'acl'; + $response = $this->auth($options); + $result = new PutSetDeleteResult($response); + return $result->getData(); + } + + /** + * 获取Bucket的访问日志配置情况 + * + * @param string $bucket bucket名称 + * @param array $options 可以为空 + * @throws OssException + * @return LoggingConfig + */ + public function getBucketLogging($bucket, $options = NULL) + { + $this->precheckCommon($bucket, NULL, $options, false); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_GET; + $options[self::OSS_OBJECT] = '/'; + $options[self::OSS_SUB_RESOURCE] = 'logging'; + $response = $this->auth($options); + $result = new GetLoggingResult($response); + return $result->getData(); + } + + /** + * 开启Bucket访问日志记录功能,只有Bucket的所有者才能更改 + * + * @param string $bucket bucket名称 + * @param string $targetBucket 日志文件存放的bucket + * @param string $targetPrefix 日志的文件前缀 + * @param array $options 可以为空 + * @throws OssException + * @return null + */ + public function putBucketLogging($bucket, $targetBucket, $targetPrefix, $options = NULL) + { + $this->precheckCommon($bucket, NULL, $options, false); + $this->precheckBucket($targetBucket, 'targetbucket is not allowed empty'); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_PUT; + $options[self::OSS_OBJECT] = '/'; + $options[self::OSS_SUB_RESOURCE] = 'logging'; + $options[self::OSS_CONTENT_TYPE] = 'application/xml'; + + $loggingConfig = new LoggingConfig($targetBucket, $targetPrefix); + $options[self::OSS_CONTENT] = $loggingConfig->serializeToXml(); + $response = $this->auth($options); + $result = new PutSetDeleteResult($response); + return $result->getData(); + } + + /** + * 关闭bucket访问日志记录功能 + * + * @param string $bucket bucket名称 + * @param array $options 可以为空 + * @throws OssException + * @return null + */ + public function deleteBucketLogging($bucket, $options = NULL) + { + $this->precheckCommon($bucket, NULL, $options, false); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_DELETE; + $options[self::OSS_OBJECT] = '/'; + $options[self::OSS_SUB_RESOURCE] = 'logging'; + $response = $this->auth($options); + $result = new PutSetDeleteResult($response); + return $result->getData(); + } + + /** + * 将bucket设置成静态网站托管模式 + * + * @param string $bucket bucket名称 + * @param WebsiteConfig $websiteConfig + * @param array $options 可以为空 + * @throws OssException + * @return null + */ + public function putBucketWebsite($bucket, $websiteConfig, $options = NULL) + { + $this->precheckCommon($bucket, NULL, $options, false); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_PUT; + $options[self::OSS_OBJECT] = '/'; + $options[self::OSS_SUB_RESOURCE] = 'website'; + $options[self::OSS_CONTENT_TYPE] = 'application/xml'; + $options[self::OSS_CONTENT] = $websiteConfig->serializeToXml(); + $response = $this->auth($options); + $result = new PutSetDeleteResult($response); + return $result->getData(); + } + + /** + * 获取bucket的静态网站托管状态 + * + * @param string $bucket bucket名称 + * @param array $options + * @throws OssException + * @return WebsiteConfig + */ + public function getBucketWebsite($bucket, $options = NULL) + { + $this->precheckCommon($bucket, NULL, $options, false); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_GET; + $options[self::OSS_OBJECT] = '/'; + $options[self::OSS_SUB_RESOURCE] = 'website'; + $response = $this->auth($options); + $result = new GetWebsiteResult($response); + return $result->getData(); + } + + /** + * 关闭bucket的静态网站托管模式 + * + * @param string $bucket bucket名称 + * @param array $options + * @throws OssException + * @return null + */ + public function deleteBucketWebsite($bucket, $options = NULL) + { + $this->precheckCommon($bucket, NULL, $options, false); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_DELETE; + $options[self::OSS_OBJECT] = '/'; + $options[self::OSS_SUB_RESOURCE] = 'website'; + $response = $this->auth($options); + $result = new PutSetDeleteResult($response); + return $result->getData(); + } + + /** + * 在指定的bucket上设定一个跨域资源共享(CORS)的规则,如果原规则存在则覆盖原规则 + * + * @param string $bucket bucket名称 + * @param CorsConfig $corsConfig 跨域资源共享配置,具体规则参见SDK文档 + * @param array $options array + * @throws OssException + * @return null + */ + public function putBucketCors($bucket, $corsConfig, $options = NULL) + { + $this->precheckCommon($bucket, NULL, $options, false); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_PUT; + $options[self::OSS_OBJECT] = '/'; + $options[self::OSS_SUB_RESOURCE] = 'cors'; + $options[self::OSS_CONTENT_TYPE] = 'application/xml'; + $options[self::OSS_CONTENT] = $corsConfig->serializeToXml(); + $response = $this->auth($options); + $result = new PutSetDeleteResult($response); + return $result->getData(); + } + + /** + * 获取Bucket的CORS配置情况 + * + * @param string $bucket bucket名称 + * @param array $options 可以为空 + * @throws OssException + * @return CorsConfig + */ + public function getBucketCors($bucket, $options = NULL) + { + $this->precheckCommon($bucket, NULL, $options, false); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_GET; + $options[self::OSS_OBJECT] = '/'; + $options[self::OSS_SUB_RESOURCE] = 'cors'; + $response = $this->auth($options); + $result = new GetCorsResult($response, __FUNCTION__); + return $result->getData(); + } + + /** + * 关闭指定Bucket对应的CORS功能并清空所有规则 + * + * @param string $bucket bucket名称 + * @param array $options + * @throws OssException + * @return null + */ + public function deleteBucketCors($bucket, $options = NULL) + { + $this->precheckCommon($bucket, NULL, $options, false); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_DELETE; + $options[self::OSS_OBJECT] = '/'; + $options[self::OSS_SUB_RESOURCE] = 'cors'; + $response = $this->auth($options); + $result = new PutSetDeleteResult($response); + return $result->getData(); + } + + /** + * 为指定Bucket增加CNAME绑定 + * + * @param string $bucket bucket名称 + * @param string $cname + * @param array $options + * @throws OssException + * @return null + */ + public function addBucketCname($bucket, $cname, $options = NULL) + { + $this->precheckCommon($bucket, NULL, $options, false); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_POST; + $options[self::OSS_OBJECT] = '/'; + $options[self::OSS_SUB_RESOURCE] = 'cname'; + $options[self::OSS_CONTENT_TYPE] = 'application/xml'; + $cnameConfig = new CnameConfig(); + $cnameConfig->addCname($cname); + $options[self::OSS_CONTENT] = $cnameConfig->serializeToXml(); + $options[self::OSS_CNAME_COMP] = 'add'; + + $response = $this->auth($options); + $result = new PutSetDeleteResult($response); + return $result->getData(); + } + + /** + * 获取指定Bucket已绑定的CNAME列表 + * + * @param string $bucket bucket名称 + * @param array $options + * @throws OssException + * @return CnameConfig + */ + public function getBucketCname($bucket, $options = NULL) + { + $this->precheckCommon($bucket, NULL, $options, false); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_GET; + $options[self::OSS_OBJECT] = '/'; + $options[self::OSS_SUB_RESOURCE] = 'cname'; + $response = $this->auth($options); + $result = new GetCnameResult($response); + return $result->getData(); + } + + /** + * 解除指定Bucket的CNAME绑定 + * + * @param string $bucket bucket名称 + * @param CnameConfig $cnameConfig + * @param array $options + * @throws OssException + * @return null + */ + public function deleteBucketCname($bucket, $cname, $options = NULL) + { + $this->precheckCommon($bucket, NULL, $options, false); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_POST; + $options[self::OSS_OBJECT] = '/'; + $options[self::OSS_SUB_RESOURCE] = 'cname'; + $options[self::OSS_CONTENT_TYPE] = 'application/xml'; + $cnameConfig = new CnameConfig(); + $cnameConfig->addCname($cname); + $options[self::OSS_CONTENT] = $cnameConfig->serializeToXml(); + $options[self::OSS_CNAME_COMP] = 'delete'; + + $response = $this->auth($options); + $result = new PutSetDeleteResult($response); + return $result->getData(); + } + + /** + * 检验跨域资源请求, 发送跨域请求之前会发送一个preflight请求(OPTIONS)并带上特定的来源域, + * HTTP方法和header信息等给OSS以决定是否发送真正的请求。 OSS可以通过putBucketCors接口 + * 来开启Bucket的CORS支持,开启CORS功能之后,OSS在收到浏览器preflight请求时会根据设定的 + * 规则评估是否允许本次请求 + * + * @param string $bucket bucket名称 + * @param string $object object名称 + * @param string $origin 请求来源域 + * @param string $request_method 表明实际请求中会使用的HTTP方法 + * @param string $request_headers 表明实际请求中会使用的除了简单头部之外的headers + * @param array $options + * @return array + * @throws OssException + * @link http://help.aliyun.com/document_detail/oss/api-reference/cors/OptionObject.html + */ + public function optionsObject($bucket, $object, $origin, $request_method, $request_headers, $options = NULL) + { + $this->precheckCommon($bucket, NULL, $options, false); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_OPTIONS; + $options[self::OSS_OBJECT] = $object; + $options[self::OSS_HEADERS] = array( + self::OSS_OPTIONS_ORIGIN => $origin, + self::OSS_OPTIONS_REQUEST_HEADERS => $request_headers, + self::OSS_OPTIONS_REQUEST_METHOD => $request_method + ); + $response = $this->auth($options); + $result = new HeaderResult($response); + return $result->getData(); + } + + /** + * 设置Bucket的Lifecycle配置 + * + * @param string $bucket bucket名称 + * @param LifecycleConfig $lifecycleConfig Lifecycle配置类 + * @param array $options + * @throws OssException + * @return null + */ + public function putBucketLifecycle($bucket, $lifecycleConfig, $options = NULL) + { + $this->precheckCommon($bucket, NULL, $options, false); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_PUT; + $options[self::OSS_OBJECT] = '/'; + $options[self::OSS_SUB_RESOURCE] = 'lifecycle'; + $options[self::OSS_CONTENT_TYPE] = 'application/xml'; + $options[self::OSS_CONTENT] = $lifecycleConfig->serializeToXml(); + $response = $this->auth($options); + $result = new PutSetDeleteResult($response); + return $result->getData(); + } + + /** + * 获取Bucket的Lifecycle配置情况 + * + * @param string $bucket bucket名称 + * @param array $options + * @throws OssException + * @return LifecycleConfig + */ + public function getBucketLifecycle($bucket, $options = NULL) + { + $this->precheckCommon($bucket, NULL, $options, false); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_GET; + $options[self::OSS_OBJECT] = '/'; + $options[self::OSS_SUB_RESOURCE] = 'lifecycle'; + $response = $this->auth($options); + $result = new GetLifecycleResult($response); + return $result->getData(); + } + + /** + * 删除指定Bucket的生命周期配置 + * + * @param string $bucket bucket名称 + * @param array $options + * @throws OssException + * @return null + */ + public function deleteBucketLifecycle($bucket, $options = NULL) + { + $this->precheckCommon($bucket, NULL, $options, false); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_DELETE; + $options[self::OSS_OBJECT] = '/'; + $options[self::OSS_SUB_RESOURCE] = 'lifecycle'; + $response = $this->auth($options); + $result = new PutSetDeleteResult($response); + return $result->getData(); + } + + /** + * 设置一个bucket的referer访问白名单和是否允许referer字段为空的请求访问 + * Bucket Referer防盗链具体见OSS防盗链 + * + * @param string $bucket bucket名称 + * @param RefererConfig $refererConfig + * @param array $options + * @return ResponseCore + * @throws null + */ + public function putBucketReferer($bucket, $refererConfig, $options = NULL) + { + $this->precheckCommon($bucket, NULL, $options, false); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_PUT; + $options[self::OSS_OBJECT] = '/'; + $options[self::OSS_SUB_RESOURCE] = 'referer'; + $options[self::OSS_CONTENT_TYPE] = 'application/xml'; + $options[self::OSS_CONTENT] = $refererConfig->serializeToXml(); + $response = $this->auth($options); + $result = new PutSetDeleteResult($response); + return $result->getData(); + } + + /** + * 获取Bucket的Referer配置情况 + * Bucket Referer防盗链具体见OSS防盗链 + * + * @param string $bucket bucket名称 + * @param array $options + * @throws OssException + * @return RefererConfig + */ + public function getBucketReferer($bucket, $options = NULL) + { + $this->precheckCommon($bucket, NULL, $options, false); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_GET; + $options[self::OSS_OBJECT] = '/'; + $options[self::OSS_SUB_RESOURCE] = 'referer'; + $response = $this->auth($options); + $result = new GetRefererResult($response); + return $result->getData(); + } + + /** + * 获取bucket下的object列表 + * + * @param string $bucket + * @param array $options + * 其中options中的参数如下 + * $options = array( + * 'max-keys' => max-keys用于限定此次返回object的最大数,如果不设定,默认为100,max-keys取值不能大于1000。 + * 'prefix' => 限定返回的object key必须以prefix作为前缀。注意使用prefix查询时,返回的key中仍会包含prefix。 + * 'delimiter' => 是一个用于对Object名字进行分组的字符。所有名字包含指定的前缀且第一次出现delimiter字符之间的object作为一组元素 + * 'marker' => 用户设定结果从marker之后按字母排序的第一个开始返回。 + *) + * 其中 prefix,marker用来实现分页显示效果,参数的长度必须小于256字节。 + * @throws OssException + * @return ObjectListInfo + */ + public function listObjects($bucket, $options = NULL) + { + $this->precheckCommon($bucket, NULL, $options, false); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_GET; + $options[self::OSS_OBJECT] = '/'; + $options[self::OSS_HEADERS] = array( + self::OSS_DELIMITER => isset($options[self::OSS_DELIMITER]) ? $options[self::OSS_DELIMITER] : '/', + self::OSS_PREFIX => isset($options[self::OSS_PREFIX]) ? $options[self::OSS_PREFIX] : '', + self::OSS_MAX_KEYS => isset($options[self::OSS_MAX_KEYS]) ? $options[self::OSS_MAX_KEYS] : self::OSS_MAX_KEYS_VALUE, + self::OSS_MARKER => isset($options[self::OSS_MARKER]) ? $options[self::OSS_MARKER] : '', + ); + $query = isset($options[self::OSS_QUERY_STRING]) ? $options[self::OSS_QUERY_STRING] : array(); + $options[self::OSS_QUERY_STRING] = array_merge( + $query, + array(self::OSS_ENCODING_TYPE => self::OSS_ENCODING_TYPE_URL) + ); + + $response = $this->auth($options); + $result = new ListObjectsResult($response); + return $result->getData(); + } + + /** + * 创建虚拟目录 (本函数会在object名称后增加'/', 所以创建目录的object名称不需要'/'结尾,否则,目录名称会变成'//') + * + * 暂不开放此接口 + * + * @param string $bucket bucket名称 + * @param string $object object名称 + * @param array $options + * @return null + */ + public function createObjectDir($bucket, $object, $options = NULL) + { + $this->precheckCommon($bucket, $object, $options); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_PUT; + $options[self::OSS_OBJECT] = $object . '/'; + $options[self::OSS_CONTENT_LENGTH] = array(self::OSS_CONTENT_LENGTH => 0); + $response = $this->auth($options); + $result = new PutSetDeleteResult($response); + return $result->getData(); + } + + /** + * 上传内存中的内容 + * + * @param string $bucket bucket名称 + * @param string $object objcet名称 + * @param string $content 上传的内容 + * @param array $options + * @return null + */ + public function putObject($bucket, $object, $content, $options = NULL) + { + $this->precheckCommon($bucket, $object, $options); + + OssUtil::validateContent($content); + $options[self::OSS_CONTENT] = $content; + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_PUT; + $options[self::OSS_OBJECT] = $object; + + if (!isset($options[self::OSS_LENGTH])) { + $options[self::OSS_CONTENT_LENGTH] = strlen($options[self::OSS_CONTENT]); + } else { + $options[self::OSS_CONTENT_LENGTH] = $options[self::OSS_LENGTH]; + } + + if (!isset($options[self::OSS_CONTENT_TYPE])) { + $options[self::OSS_CONTENT_TYPE] = $this->getMimeType($object); + } + $response = $this->auth($options); + $result = new PutSetDeleteResult($response); + return $result->getData(); + } + + /** + * 上传本地文件 + * + * @param string $bucket bucket名称 + * @param string $object object名称 + * @param string $file 本地文件路径 + * @param array $options + * @return null + * @throws OssException + */ + public function uploadFile($bucket, $object, $file, $options = NULL) + { + $this->precheckCommon($bucket, $object, $options); + OssUtil::throwOssExceptionWithMessageIfEmpty($file, "file path is invalid"); + $file = OssUtil::encodePath($file); + if (!file_exists($file)) { + throw new OssException($file . " file does not exist"); + } + $options[self::OSS_FILE_UPLOAD] = $file; + $file_size = filesize($options[self::OSS_FILE_UPLOAD]); + $is_check_md5 = $this->isCheckMD5($options); + if ($is_check_md5) { + $content_md5 = base64_encode(md5_file($options[self::OSS_FILE_UPLOAD], true)); + $options[self::OSS_CONTENT_MD5] = $content_md5; + } + if (!isset($options[self::OSS_CONTENT_TYPE])) { + $options[self::OSS_CONTENT_TYPE] = $this->getMimeType($object, $file); + } + $options[self::OSS_METHOD] = self::OSS_HTTP_PUT; + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_OBJECT] = $object; + $options[self::OSS_CONTENT_LENGTH] = $file_size; + $response = $this->auth($options); + $result = new PutSetDeleteResult($response); + return $result->getData(); + } + + /** + * 追加上传内存中的内容 + * + * @param string $bucket bucket名称 + * @param string $object objcet名称 + * @param string $content 本次追加上传的内容 + * @param array $options + * @return int next append position + * @throws OssException + */ + public function appendObject($bucket, $object, $content, $position, $options = NULL) + { + $this->precheckCommon($bucket, $object, $options); + + OssUtil::validateContent($content); + $options[self::OSS_CONTENT] = $content; + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_POST; + $options[self::OSS_OBJECT] = $object; + $options[self::OSS_SUB_RESOURCE] = 'append'; + $options[self::OSS_POSITION] = strval($position); + + if (!isset($options[self::OSS_LENGTH])) { + $options[self::OSS_CONTENT_LENGTH] = strlen($options[self::OSS_CONTENT]); + } else { + $options[self::OSS_CONTENT_LENGTH] = $options[self::OSS_LENGTH]; + } + + if (!isset($options[self::OSS_CONTENT_TYPE])) { + $options[self::OSS_CONTENT_TYPE] = $this->getMimeType($object); + } + $response = $this->auth($options); + $result = new AppendResult($response); + return $result->getData(); + } + + /** + * 追加上传本地文件 + * + * @param string $bucket bucket名称 + * @param string $object object名称 + * @param string $file 追加上传的本地文件路径 + * @param array $options + * @return int next append position + * @throws OssException + */ + public function appendFile($bucket, $object, $file, $position, $options = NULL) + { + $this->precheckCommon($bucket, $object, $options); + + OssUtil::throwOssExceptionWithMessageIfEmpty($file, "file path is invalid"); + $file = OssUtil::encodePath($file); + if (!file_exists($file)) { + throw new OssException($file . " file does not exist"); + } + $options[self::OSS_FILE_UPLOAD] = $file; + $file_size = filesize($options[self::OSS_FILE_UPLOAD]); + $is_check_md5 = $this->isCheckMD5($options); + if ($is_check_md5) { + $content_md5 = base64_encode(md5_file($options[self::OSS_FILE_UPLOAD], true)); + $options[self::OSS_CONTENT_MD5] = $content_md5; + } + if (!isset($options[self::OSS_CONTENT_TYPE])) { + $options[self::OSS_CONTENT_TYPE] = $this->getMimeType($object, $file); + } + + $options[self::OSS_METHOD] = self::OSS_HTTP_POST; + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_OBJECT] = $object; + $options[self::OSS_CONTENT_LENGTH] = $file_size; + $options[self::OSS_SUB_RESOURCE] = 'append'; + $options[self::OSS_POSITION] = strval($position); + + $response = $this->auth($options); + $result = new AppendResult($response); + return $result->getData(); + } + + /** + * 拷贝一个在OSS上已经存在的object成另外一个object + * + * @param string $fromBucket 源bucket名称 + * @param string $fromObject 源object名称 + * @param string $toBucket 目标bucket名称 + * @param string $toObject 目标object名称 + * @param array $options + * @return null + * @throws OssException + */ + public function copyObject($fromBucket, $fromObject, $toBucket, $toObject, $options = NULL) + { + $this->precheckCommon($fromBucket, $fromObject, $options); + $this->precheckCommon($toBucket, $toObject, $options); + $options[self::OSS_BUCKET] = $toBucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_PUT; + $options[self::OSS_OBJECT] = $toObject; + if (isset($options[self::OSS_HEADERS])) { + $options[self::OSS_HEADERS][self::OSS_OBJECT_COPY_SOURCE] = '/' . $fromBucket . '/' . $fromObject; + } else { + $options[self::OSS_HEADERS] = array(self::OSS_OBJECT_COPY_SOURCE => '/' . $fromBucket . '/' . $fromObject); + } + $response = $this->auth($options); + $result = new PutSetDeleteResult($response); + return $result->getData(); + } + + /** + * 获取Object的Meta信息 + * + * @param string $bucket bucket名称 + * @param string $object object名称 + * @param string $options 具体参考SDK文档 + * @return array + */ + public function getObjectMeta($bucket, $object, $options = NULL) + { + $this->precheckCommon($bucket, $object, $options); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_HEAD; + $options[self::OSS_OBJECT] = $object; + $response = $this->auth($options); + $result = new HeaderResult($response); + return $result->getData(); + } + + /** + * 删除某个Object + * + * @param string $bucket bucket名称 + * @param string $object object名称 + * @param array $options + * @return null + */ + public function deleteObject($bucket, $object, $options = NULL) + { + $this->precheckCommon($bucket, $object, $options); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_DELETE; + $options[self::OSS_OBJECT] = $object; + $response = $this->auth($options); + $result = new PutSetDeleteResult($response); + return $result->getData(); + } + + /** + * 删除同一个Bucket中的多个Object + * + * @param string $bucket bucket名称 + * @param array $objects object列表 + * @param array $options + * @return ResponseCore + * @throws null + */ + public function deleteObjects($bucket, $objects, $options = null) + { + $this->precheckCommon($bucket, NULL, $options, false); + if (!is_array($objects) || !$objects) { + throw new OssException('objects must be array'); + } + $options[self::OSS_METHOD] = self::OSS_HTTP_POST; + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_OBJECT] = '/'; + $options[self::OSS_SUB_RESOURCE] = 'delete'; + $options[self::OSS_CONTENT_TYPE] = 'application/xml'; + $quiet = 'false'; + if (isset($options['quiet'])) { + if (is_bool($options['quiet'])) { //Boolean + $quiet = $options['quiet'] ? 'true' : 'false'; + } elseif (is_string($options['quiet'])) { // string + $quiet = ($options['quiet'] === 'true') ? 'true' : 'false'; + } + } + $xmlBody = OssUtil::createDeleteObjectsXmlBody($objects, $quiet); + $options[self::OSS_CONTENT] = $xmlBody; + $response = $this->auth($options); + $result = new PutSetDeleteResult($response); + return $result->getData(); + } + + /** + * 获得Object内容 + * + * @param string $bucket bucket名称 + * @param string $object object名称 + * @param array $options 该参数中必须设置ALIOSS::OSS_FILE_DOWNLOAD,ALIOSS::OSS_RANGE可选,可以根据实际情况设置;如果不设置,默认会下载全部内容 + * @return string + */ + public function getObject($bucket, $object, $options = NULL) + { + $this->precheckCommon($bucket, $object, $options); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_GET; + $options[self::OSS_OBJECT] = $object; + if (isset($options[self::OSS_LAST_MODIFIED])) { + $options[self::OSS_HEADERS][self::OSS_IF_MODIFIED_SINCE] = $options[self::OSS_LAST_MODIFIED]; + unset($options[self::OSS_LAST_MODIFIED]); + } + if (isset($options[self::OSS_ETAG])) { + $options[self::OSS_HEADERS][self::OSS_IF_NONE_MATCH] = $options[self::OSS_ETAG]; + unset($options[self::OSS_ETAG]); + } + if (isset($options[self::OSS_RANGE])) { + $range = $options[self::OSS_RANGE]; + $options[self::OSS_HEADERS][self::OSS_RANGE] = "bytes=$range"; + unset($options[self::OSS_RANGE]); + } + $response = $this->auth($options); + $result = new BodyResult($response); + return $result->getData(); + } + + /** + * 检测Object是否存在 + * 通过获取Object的Meta信息来判断Object是否存在, 用户需要自行解析ResponseCore判断object是否存在 + * + * @param string $bucket bucket名称 + * @param string $object object名称 + * @param array $options + * @return bool + */ + public function doesObjectExist($bucket, $object, $options = NULL) + { + $this->precheckCommon($bucket, $object, $options); + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_METHOD] = self::OSS_HTTP_HEAD; + $options[self::OSS_OBJECT] = $object; + $response = $this->auth($options); + $result = new ExistResult($response); + return $result->getData(); + } + + /** + * 获取分片大小,根据用户提供的part_size,重新计算一个更合理的partsize + * + * @param int $partSize + * @return int + */ + private function computePartSize($partSize) + { + $partSize = (integer)$partSize; + if ($partSize <= self::OSS_MIN_PART_SIZE) { + $partSize = self::OSS_MIN_PART_SIZE; + } elseif ($partSize > self::OSS_MAX_PART_SIZE) { + $partSize = self::OSS_MAX_PART_SIZE; + } + return $partSize; + } + + /** + * 计算文件可以分成多少个part,以及每个part的长度以及起始位置 + * 方法必须在 中调用 + * + * @param integer $file_size 文件大小 + * @param integer $partSize part大小,默认5M + * @return array An array 包含 key-value 键值对. Key 为 `seekTo` 和 `length`. + */ + public function generateMultiuploadParts($file_size, $partSize = 5242880) + { + $i = 0; + $size_count = $file_size; + $values = array(); + $partSize = $this->computePartSize($partSize); + while ($size_count > 0) { + $size_count -= $partSize; + $values[] = array( + self::OSS_SEEK_TO => ($partSize * $i), + self::OSS_LENGTH => (($size_count > 0) ? $partSize : ($size_count + $partSize)), + ); + $i++; + } + return $values; + } + + /** + * 初始化multi-part upload + * + * @param string $bucket Bucket名称 + * @param string $object Object名称 + * @param array $options Key-Value数组 + * @throws OssException + * @return string 返回uploadid + */ + public function initiateMultipartUpload($bucket, $object, $options = NULL) + { + $this->precheckCommon($bucket, $object, $options); + $options[self::OSS_METHOD] = self::OSS_HTTP_POST; + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_OBJECT] = $object; + $options[self::OSS_SUB_RESOURCE] = 'uploads'; + $options[self::OSS_CONTENT] = ''; + + if (!isset($options[self::OSS_CONTENT_TYPE])) { + $options[self::OSS_CONTENT_TYPE] = $this->getMimeType($object); + } + if (!isset($options[self::OSS_HEADERS])) { + $options[self::OSS_HEADERS] = array(); + } + $response = $this->auth($options); + $result = new InitiateMultipartUploadResult($response); + return $result->getData(); + } + + /** + * 分片上传的块上传接口 + * + * @param string $bucket Bucket名称 + * @param string $object Object名称 + * @param string $uploadId + * @param array $options Key-Value数组 + * @return string eTag + * @throws OssException + */ + public function uploadPart($bucket, $object, $uploadId, $options = null) + { + $this->precheckCommon($bucket, $object, $options); + $this->precheckParam($options, self::OSS_FILE_UPLOAD, __FUNCTION__); + $this->precheckParam($options, self::OSS_PART_NUM, __FUNCTION__); + + $options[self::OSS_METHOD] = self::OSS_HTTP_PUT; + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_OBJECT] = $object; + $options[self::OSS_UPLOAD_ID] = $uploadId; + + if (isset($options[self::OSS_LENGTH])) { + $options[self::OSS_CONTENT_LENGTH] = $options[self::OSS_LENGTH]; + } + $response = $this->auth($options); + $result = new UploadPartResult($response); + return $result->getData(); + } + + /** + * 获取已成功上传的part + * + * @param string $bucket Bucket名称 + * @param string $object Object名称 + * @param string $uploadId uploadId + * @param array $options Key-Value数组 + * @return ListPartsInfo + * @throws OssException + */ + public function listParts($bucket, $object, $uploadId, $options = null) + { + $this->precheckCommon($bucket, $object, $options); + $options[self::OSS_METHOD] = self::OSS_HTTP_GET; + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_OBJECT] = $object; + $options[self::OSS_UPLOAD_ID] = $uploadId; + $options[self::OSS_QUERY_STRING] = array(); + foreach (array('max-parts', 'part-number-marker') as $param) { + if (isset($options[$param])) { + $options[self::OSS_QUERY_STRING][$param] = $options[$param]; + unset($options[$param]); + } + } + $response = $this->auth($options); + $result = new ListPartsResult($response); + return $result->getData(); + } + + /** + * 中止进行一半的分片上传操作 + * + * @param string $bucket Bucket名称 + * @param string $object Object名称 + * @param string $uploadId uploadId + * @param array $options Key-Value数组 + * @return null + * @throws OssException + */ + public function abortMultipartUpload($bucket, $object, $uploadId, $options = NULL) + { + $this->precheckCommon($bucket, $object, $options); + $options[self::OSS_METHOD] = self::OSS_HTTP_DELETE; + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_OBJECT] = $object; + $options[self::OSS_UPLOAD_ID] = $uploadId; + $response = $this->auth($options); + $result = new PutSetDeleteResult($response); + return $result->getData(); + } + + /** + * 在将所有数据Part都上传完成后,调用此接口完成本次分块上传 + * + * @param string $bucket Bucket名称 + * @param string $object Object名称 + * @param string $uploadId uploadId + * @param array $listParts array( array("PartNumber"=> int, "ETag"=>string)) + * @param array $options Key-Value数组 + * @throws OssException + * @return null + */ + public function completeMultipartUpload($bucket, $object, $uploadId, $listParts, $options = NULL) + { + $this->precheckCommon($bucket, $object, $options); + $options[self::OSS_METHOD] = self::OSS_HTTP_POST; + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_OBJECT] = $object; + $options[self::OSS_UPLOAD_ID] = $uploadId; + $options[self::OSS_CONTENT_TYPE] = 'application/xml'; + if (!is_array($listParts)) { + throw new OssException("listParts must be array type"); + } + $options[self::OSS_CONTENT] = OssUtil::createCompleteMultipartUploadXmlBody($listParts); + $response = $this->auth($options); + $result = new PutSetDeleteResult($response); + return $result->getData(); + } + + /** + * 罗列出所有执行中的Multipart Upload事件,即已经被初始化的Multipart Upload但是未被 + * Complete或者Abort的Multipart Upload事件 + * + * @param string $bucket bucket + * @param array $options 关联数组 + * @throws OssException + * @return ListMultipartUploadInfo + */ + public function listMultipartUploads($bucket, $options = null) + { + $this->precheckCommon($bucket, NULL, $options, false); + $options[self::OSS_METHOD] = self::OSS_HTTP_GET; + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_OBJECT] = '/'; + $options[self::OSS_SUB_RESOURCE] = 'uploads'; + + foreach (array('delimiter', 'key-marker', 'max-uploads', 'prefix', 'upload-id-marker') as $param) { + if (isset($options[$param])) { + $options[self::OSS_QUERY_STRING][$param] = $options[$param]; + unset($options[$param]); + } + } + $query = isset($options[self::OSS_QUERY_STRING]) ? $options[self::OSS_QUERY_STRING] : array(); + $options[self::OSS_QUERY_STRING] = array_merge( + $query, + array(self::OSS_ENCODING_TYPE => self::OSS_ENCODING_TYPE_URL) + ); + + $response = $this->auth($options); + $result = new ListMultipartUploadResult($response); + return $result->getData(); + } + + /** + * 从一个已存在的Object中拷贝数据来上传一个Part + * + * @param string $fromBucket 源bucket名称 + * @param string $fromObject 源object名称 + * @param string $toBucket 目标bucket名称 + * @param string $toObject 目标object名称 + * @param int $partNumber 分块上传的块id + * @param string $uploadId 初始化multipart upload返回的uploadid + * @param array $options Key-Value数组 + * @return null + * @throws OssException + */ + public function uploadPartCopy($fromBucket, $fromObject, $toBucket, $toObject, $partNumber, $uploadId, $options = NULL) + { + $this->precheckCommon($fromBucket, $fromObject, $options); + $this->precheckCommon($toBucket, $toObject, $options); + + //如果没有设置$options['isFullCopy'],则需要强制判断copy的起止位置 + $start_range = "0"; + if (isset($options['start'])) { + $start_range = $options['start']; + } + $end_range = ""; + if (isset($options['end'])) { + $end_range = $options['end']; + } + $options[self::OSS_METHOD] = self::OSS_HTTP_PUT; + $options[self::OSS_BUCKET] = $toBucket; + $options[self::OSS_OBJECT] = $toObject; + $options[self::OSS_PART_NUM] = $partNumber; + $options[self::OSS_UPLOAD_ID] = $uploadId; + + if (!isset($options[self::OSS_HEADERS])) { + $options[self::OSS_HEADERS] = array(); + } + + $options[self::OSS_HEADERS][self::OSS_OBJECT_COPY_SOURCE] = '/' . $fromBucket . '/' . $fromObject; + $options[self::OSS_HEADERS][self::OSS_OBJECT_COPY_SOURCE_RANGE] = "bytes=" . $start_range . "-" . $end_range; + $response = $this->auth($options); + $result = new UploadPartResult($response); + return $result->getData(); + } + + /** + * multipart上传统一封装,从初始化到完成multipart,以及出错后中止动作 + * + * @param string $bucket bucket名称 + * @param string $object object名称 + * @param string $file 需要上传的本地文件的路径 + * @param array $options Key-Value数组 + * @return null + * @throws OssException + */ + public function multiuploadFile($bucket, $object, $file, $options = null) + { + $this->precheckCommon($bucket, $object, $options); + if (isset($options[self::OSS_LENGTH])) { + $options[self::OSS_CONTENT_LENGTH] = $options[self::OSS_LENGTH]; + unset($options[self::OSS_LENGTH]); + } + if (empty($file)) { + throw new OssException("parameter invalid, file is empty"); + } + $uploadFile = OssUtil::encodePath($file); + if (!isset($options[self::OSS_CONTENT_TYPE])) { + $options[self::OSS_CONTENT_TYPE] = $this->getMimeType($object, $uploadFile); + } + + $upload_position = isset($options[self::OSS_SEEK_TO]) ? (integer)$options[self::OSS_SEEK_TO] : 0; + + if (isset($options[self::OSS_CONTENT_LENGTH])) { + $upload_file_size = (integer)$options[self::OSS_CONTENT_LENGTH]; + } else { + $upload_file_size = filesize($uploadFile); + if ($upload_file_size !== false) { + $upload_file_size -= $upload_position; + } + } + + if ($upload_position === false || !isset($upload_file_size) || $upload_file_size === false || $upload_file_size < 0) { + throw new OssException('The size of `fileUpload` cannot be determined in ' . __FUNCTION__ . '().'); + } + // 处理partSize + if (isset($options[self::OSS_PART_SIZE])) { + $options[self::OSS_PART_SIZE] = $this->computePartSize($options[self::OSS_PART_SIZE]); + } else { + $options[self::OSS_PART_SIZE] = self::OSS_MID_PART_SIZE; + } + + $is_check_md5 = $this->isCheckMD5($options); + // 如果上传的文件小于partSize,则直接使用普通方式上传 + if ($upload_file_size < $options[self::OSS_PART_SIZE] && !isset($options[self::OSS_UPLOAD_ID])) { + return $this->uploadFile($bucket, $object, $uploadFile, $options); + } + + // 初始化multipart + if (isset($options[self::OSS_UPLOAD_ID])) { + $uploadId = $options[self::OSS_UPLOAD_ID]; + } else { + // 初始化 + $uploadId = $this->initiateMultipartUpload($bucket, $object, $options); + } + + // 获取的分片 + $pieces = $this->generateMultiuploadParts($upload_file_size, (integer)$options[self::OSS_PART_SIZE]); + $response_upload_part = array(); + foreach ($pieces as $i => $piece) { + $from_pos = $upload_position + (integer)$piece[self::OSS_SEEK_TO]; + $to_pos = (integer)$piece[self::OSS_LENGTH] + $from_pos - 1; + $up_options = array( + self::OSS_FILE_UPLOAD => $uploadFile, + self::OSS_PART_NUM => ($i + 1), + self::OSS_SEEK_TO => $from_pos, + self::OSS_LENGTH => $to_pos - $from_pos + 1, + self::OSS_CHECK_MD5 => $is_check_md5, + ); + if ($is_check_md5) { + $content_md5 = OssUtil::getMd5SumForFile($uploadFile, $from_pos, $to_pos); + $up_options[self::OSS_CONTENT_MD5] = $content_md5; + } + $response_upload_part[] = $this->uploadPart($bucket, $object, $uploadId, $up_options); + } + + $uploadParts = array(); + foreach ($response_upload_part as $i => $etag) { + $uploadParts[] = array( + 'PartNumber' => ($i + 1), + 'ETag' => $etag, + ); + } + return $this->completeMultipartUpload($bucket, $object, $uploadId, $uploadParts); + } + + /** + * 上传本地目录内的文件或者目录到指定bucket的指定prefix的object中 + * + * @param string $bucket bucket名称 + * @param string $prefix 需要上传到的object的key前缀,可以理解成bucket中的子目录,结尾不能是'/',接口中会补充'/' + * @param string $localDirectory 需要上传的本地目录 + * @param string $exclude 需要排除的目录 + * @param bool $recursive 是否递归的上传localDirectory下的子目录内容 + * @param bool $checkMd5 + * @return array 返回两个列表 array("succeededList" => array("object"), "failedList" => array("object"=>"errorMessage")) + * @throws OssException + */ + public function uploadDir($bucket, $prefix, $localDirectory, $exclude = '.|..|.svn|.git', $recursive = false, $checkMd5 = true) + { + $retArray = array("succeededList" => array(), "failedList" => array()); + if (empty($bucket)) throw new OssException("parameter error, bucket is empty"); + if (!is_string($prefix)) throw new OssException("parameter error, prefix is not string"); + if (empty($localDirectory)) throw new OssException("parameter error, localDirectory is empty"); + $directory = $localDirectory; + $directory = OssUtil::encodePath($directory); + //判断是否目录 + if (!is_dir($directory)) { + throw new OssException('parameter error: ' . $directory . ' is not a directory, please check it'); + } + //read directory + $file_list_array = OssUtil::readDir($directory, $exclude, $recursive); + if (!$file_list_array) { + throw new OssException($directory . ' is empty...'); + } + foreach ($file_list_array as $k => $item) { + if (is_dir($item['path'])) { + continue; + } + $options = array( + self::OSS_PART_SIZE => self::OSS_MIN_PART_SIZE, + self::OSS_CHECK_MD5 => $checkMd5, + ); + $realObject = (!empty($prefix) ? $prefix . '/' : '') . $item['file']; + + try { + $this->multiuploadFile($bucket, $realObject, $item['path'], $options); + $retArray["succeededList"][] = $realObject; + } catch (OssException $e) { + $retArray["failedList"][$realObject] = $e->getMessage(); + } + } + return $retArray; + } + + /** + * 支持生成get和put签名, 用户可以生成一个具有一定有效期的 + * 签名过的url + * + * @param string $bucket + * @param string $object + * @param int $timeout + * @param string $method + * @param array $options Key-Value数组 + * @return string + * @throws OssException + */ + public function signUrl($bucket, $object, $timeout = 60, $method = self::OSS_HTTP_GET, $options = NULL) + { + $this->precheckCommon($bucket, $object, $options); + //method + if (self::OSS_HTTP_GET !== $method && self::OSS_HTTP_PUT !== $method) { + throw new OssException("method is invalid"); + } + $options[self::OSS_BUCKET] = $bucket; + $options[self::OSS_OBJECT] = $object; + $options[self::OSS_METHOD] = $method; + if (!isset($options[self::OSS_CONTENT_TYPE])) { + $options[self::OSS_CONTENT_TYPE] = ''; + } + $timeout = time() + $timeout; + $options[self::OSS_PREAUTH] = $timeout; + $options[self::OSS_DATE] = $timeout; + $this->setSignStsInUrl(true); + return $this->auth($options); + } + + /** + * 检测options参数 + * + * @param array $options + * @throws OssException + */ + private function precheckOptions(&$options) + { + OssUtil::validateOptions($options); + if (!$options) { + $options = array(); + } + } + + /** + * 校验bucket参数 + * + * @param string $bucket + * @param string $errMsg + * @throws OssException + */ + private function precheckBucket($bucket, $errMsg = 'bucket is not allowed empty') + { + OssUtil::throwOssExceptionWithMessageIfEmpty($bucket, $errMsg); + } + + /** + * 校验object参数 + * + * @param string $object + * @throws OssException + */ + private function precheckObject($object) + { + OssUtil::throwOssExceptionWithMessageIfEmpty($object, "object name is empty"); + } + + /** + * 校验bucket,options参数 + * + * @param string $bucket + * @param string $object + * @param array $options + * @param bool $isCheckObject + */ + private function precheckCommon($bucket, $object, &$options, $isCheckObject = true) + { + if ($isCheckObject) { + $this->precheckObject($object); + } + $this->precheckOptions($options); + $this->precheckBucket($bucket); + } + + /** + * 参数校验 + * + * @param array $options + * @param string $param + * @param string $funcName + * @throws OssException + */ + private function precheckParam($options, $param, $funcName) + { + if (!isset($options[$param])) { + throw new OssException('The `' . $param . '` options is required in ' . $funcName . '().'); + } + } + + /** + * 检测md5 + * + * @param array $options + * @return bool|null + */ + private function isCheckMD5($options) + { + return $this->getValue($options, self::OSS_CHECK_MD5, false, true, true); + } + + /** + * 获取value + * + * @param array $options + * @param string $key + * @param string $default + * @param bool $isCheckEmpty + * @param bool $isCheckBool + * @return bool|null + */ + private function getValue($options, $key, $default = NULL, $isCheckEmpty = false, $isCheckBool = false) + { + $value = $default; + if (isset($options[$key])) { + if ($isCheckEmpty) { + if (!empty($options[$key])) { + $value = $options[$key]; + } + } else { + $value = $options[$key]; + } + unset($options[$key]); + } + if ($isCheckBool) { + if ($value !== true && $value !== false) { + $value = false; + } + } + return $value; + } + + /** + * 获取mimetype类型 + * + * @param string $object + * @return string + */ + private function getMimeType($object, $file = null) + { + if (!is_null($file)) { + $type = MimeTypes::getMimetype($file); + if (!is_null($type)) { + return $type; + } + } + + $type = MimeTypes::getMimetype($object); + if (!is_null($type)) { + return $type; + } + + return self::DEFAULT_CONTENT_TYPE; + } + + /** + * 验证并且执行请求,按照OSS Api协议,执行操作 + * + * @param array $options + * @return ResponseCore + * @throws OssException + * @throws RequestCore_Exception + */ + private function auth($options) + { + OssUtil::validateOptions($options); + //验证bucket,list_bucket时不需要验证 + $this->authPrecheckBucket($options); + //验证object + $this->authPrecheckObject($options); + //Object名称的编码必须是utf8 + $this->authPrecheckObjectEncoding($options); + //验证ACL + $this->authPrecheckAcl($options); + // 获得当次请求使用的协议头,是https还是http + $scheme = $this->useSSL ? 'https://' : 'http://'; + // 获得当次请求使用的hostname,如果是公共域名或者专有域名,bucket拼在前面构成三级域名 + $hostname = $this->generateHostname($options); + $string_to_sign = ''; + $headers = $this->generateHeaders($options, $hostname); + $signable_query_string_params = $this->generateSignableQueryStringParam($options); + $signable_query_string = OssUtil::toQueryString($signable_query_string_params); + $resource_uri = $this->generateResourceUri($options); + //生成请求URL + $conjunction = '?'; + $non_signable_resource = ''; + if (isset($options[self::OSS_SUB_RESOURCE])) { + $conjunction = '&'; + } + if ($signable_query_string !== '') { + $signable_query_string = $conjunction . $signable_query_string; + $conjunction = '&'; + } + $query_string = $this->generateQueryString($options); + if ($query_string !== '') { + $non_signable_resource .= $conjunction . $query_string; + $conjunction = '&'; + } + $this->requestUrl = $scheme . $hostname . $resource_uri . $signable_query_string . $non_signable_resource; + + //创建请求 + $request = new RequestCore($this->requestUrl); + $request->set_useragent($this->generateUserAgent()); + // Streaming uploads + if (isset($options[self::OSS_FILE_UPLOAD])) { + if (is_resource($options[self::OSS_FILE_UPLOAD])) { + $length = null; + + if (isset($options[self::OSS_CONTENT_LENGTH])) { + $length = $options[self::OSS_CONTENT_LENGTH]; + } elseif (isset($options[self::OSS_SEEK_TO])) { + $stats = fstat($options[self::OSS_FILE_UPLOAD]); + if ($stats && $stats[self::OSS_SIZE] >= 0) { + $length = $stats[self::OSS_SIZE] - (integer)$options[self::OSS_SEEK_TO]; + } + } + $request->set_read_stream($options[self::OSS_FILE_UPLOAD], $length); + } else { + $request->set_read_file($options[self::OSS_FILE_UPLOAD]); + $length = $request->read_stream_size; + if (isset($options[self::OSS_CONTENT_LENGTH])) { + $length = $options[self::OSS_CONTENT_LENGTH]; + } elseif (isset($options[self::OSS_SEEK_TO]) && isset($length)) { + $length -= (integer)$options[self::OSS_SEEK_TO]; + } + $request->set_read_stream_size($length); + } + } + if (isset($options[self::OSS_SEEK_TO])) { + $request->set_seek_position((integer)$options[self::OSS_SEEK_TO]); + } + if (isset($options[self::OSS_FILE_DOWNLOAD])) { + if (is_resource($options[self::OSS_FILE_DOWNLOAD])) { + $request->set_write_stream($options[self::OSS_FILE_DOWNLOAD]); + } else { + $request->set_write_file($options[self::OSS_FILE_DOWNLOAD]); + } + } + + if (isset($options[self::OSS_METHOD])) { + $request->set_method($options[self::OSS_METHOD]); + $string_to_sign .= $options[self::OSS_METHOD] . "\n"; + } + + if (isset($options[self::OSS_CONTENT])) { + $request->set_body($options[self::OSS_CONTENT]); + if ($headers[self::OSS_CONTENT_TYPE] === 'application/x-www-form-urlencoded') { + $headers[self::OSS_CONTENT_TYPE] = 'application/octet-stream'; + } + + $headers[self::OSS_CONTENT_LENGTH] = strlen($options[self::OSS_CONTENT]); + $headers[self::OSS_CONTENT_MD5] = base64_encode(md5($options[self::OSS_CONTENT], true)); + } + + uksort($headers, 'strnatcasecmp'); + foreach ($headers as $header_key => $header_value) { + $header_value = str_replace(array("\r", "\n"), '', $header_value); + if ($header_value !== '') { + $request->add_header($header_key, $header_value); + } + if ( + strtolower($header_key) === 'content-md5' || + strtolower($header_key) === 'content-type' || + strtolower($header_key) === 'date' || + (isset($options['self::OSS_PREAUTH']) && (integer)$options['self::OSS_PREAUTH'] > 0) + ) { + $string_to_sign .= $header_value . "\n"; + } elseif (substr(strtolower($header_key), 0, 6) === self::OSS_DEFAULT_PREFIX) { + $string_to_sign .= strtolower($header_key) . ':' . $header_value . "\n"; + } + } + // 生成 signable_resource + $signable_resource = $this->generateSignableResource($options); + $string_to_sign .= rawurldecode($signable_resource) . urldecode($signable_query_string); + $signature = base64_encode(hash_hmac('sha1', $string_to_sign, $this->accessKeySecret, true)); + $request->add_header('Authorization', 'OSS ' . $this->accessKeyId . ':' . $signature); + + if (isset($options[self::OSS_PREAUTH]) && (integer)$options[self::OSS_PREAUTH] > 0) { + $signed_url = $this->requestUrl . $conjunction . self::OSS_URL_ACCESS_KEY_ID . '=' . rawurlencode($this->accessKeyId) . '&' . self::OSS_URL_EXPIRES . '=' . $options[self::OSS_PREAUTH] . '&' . self::OSS_URL_SIGNATURE . '=' . rawurlencode($signature); + return $signed_url; + } elseif (isset($options[self::OSS_PREAUTH])) { + return $this->requestUrl; + } + + if ($this->timeout !== 0) { + $request->timeout = $this->timeout; + } + if ($this->connectTimeout !== 0) { + $request->connect_timeout = $this->connectTimeout; + } + + try { + $request->send_request(); + } catch (RequestCore_Exception $e) { + throw(new OssException('RequestCoreException: ' . $e->getMessage())); + } + $response_header = $request->get_response_header(); + $response_header['oss-request-url'] = $this->requestUrl; + $response_header['oss-redirects'] = $this->redirects; + $response_header['oss-stringtosign'] = $string_to_sign; + $response_header['oss-requestheaders'] = $request->request_headers; + + $data = new ResponseCore($response_header, $request->get_response_body(), $request->get_response_code()); + //retry if OSS Internal Error + if ((integer)$request->get_response_code() === 500) { + if ($this->redirects <= $this->maxRetries) { + //设置休眠 + $delay = (integer)(pow(4, $this->redirects) * 100000); + usleep($delay); + $this->redirects++; + $data = $this->auth($options); + } + } + + $this->redirects = 0; + return $data; + } + + /** + * 设置最大尝试次数 + * + * @param int $maxRetries + * @return void + */ + public function setMaxTries($maxRetries = 3) + { + $this->maxRetries = $maxRetries; + } + + /** + * 获取最大尝试次数 + * + * @return int + */ + public function getMaxRetries() + { + return $this->maxRetries; + } + + /** + * 打开sts enable标志,使用户构造函数中传入的$sts生效 + * + * @param boolean $enable + */ + public function setSignStsInUrl($enable) + { + $this->enableStsInUrl = $enable; + } + + /** + * @return boolean + */ + public function isUseSSL() + { + return $this->useSSL; + } + + /** + * @param boolean $useSSL + */ + public function setUseSSL($useSSL) + { + $this->useSSL = $useSSL; + } + + /** + * 检查bucket名称格式是否正确,如果非法抛出异常 + * + * @param $options + * @throws OssException + */ + private function authPrecheckBucket($options) + { + if (!(('/' == $options[self::OSS_OBJECT]) && ('' == $options[self::OSS_BUCKET]) && ('GET' == $options[self::OSS_METHOD])) && !OssUtil::validateBucket($options[self::OSS_BUCKET])) { + throw new OssException('"' . $options[self::OSS_BUCKET] . '"' . 'bucket name is invalid'); + } + } + + /** + * + * 检查object名称格式是否正确,如果非法抛出异常 + * + * @param $options + * @throws OssException + */ + private function authPrecheckObject($options) + { + if (isset($options[self::OSS_OBJECT]) && $options[self::OSS_OBJECT] === '/') { + return; + } + + if (isset($options[self::OSS_OBJECT]) && !OssUtil::validateObject($options[self::OSS_OBJECT])) { + throw new OssException('"' . $options[self::OSS_OBJECT] . '"' . ' object name is invalid'); + } + } + + /** + * 检查object的编码,如果是gbk或者gb2312则尝试将其转化为utf8编码 + * + * @param mixed $options 参数 + */ + private function authPrecheckObjectEncoding(&$options) + { + $tmp_object = $options[self::OSS_OBJECT]; + try { + if (OssUtil::isGb2312($options[self::OSS_OBJECT])) { + $options[self::OSS_OBJECT] = iconv('GB2312', "UTF-8//IGNORE", $options[self::OSS_OBJECT]); + } elseif (OssUtil::checkChar($options[self::OSS_OBJECT], true)) { + $options[self::OSS_OBJECT] = iconv('GBK', "UTF-8//IGNORE", $options[self::OSS_OBJECT]); + } + } catch (\Exception $e) { + try { + $tmp_object = iconv(mb_detect_encoding($tmp_object), "UTF-8", $tmp_object); + } catch (\Exception $e) { + } + } + $options[self::OSS_OBJECT] = $tmp_object; + } + + /** + * 检查ACL是否是预定义中三种之一,如果不是抛出异常 + * + * @param $options + * @throws OssException + */ + private function authPrecheckAcl($options) + { + if (isset($options[self::OSS_HEADERS][self::OSS_ACL]) && !empty($options[self::OSS_HEADERS][self::OSS_ACL])) { + if (!in_array(strtolower($options[self::OSS_HEADERS][self::OSS_ACL]), self::$OSS_ACL_TYPES)) { + throw new OssException($options[self::OSS_HEADERS][self::OSS_ACL] . ':' . 'acl is invalid(private,public-read,public-read-write)'); + } + } + } + + /** + * 获得档次请求使用的域名 + * bucket在前的三级域名,或者二级域名,如果是cname或者ip的话,则是二级域名 + * + * @param $options + * @return string 剥掉协议头的域名 + */ + private function generateHostname($options) + { + if ($this->hostType === self::OSS_HOST_TYPE_IP) { + $hostname = $this->hostname; + } elseif ($this->hostType === self::OSS_HOST_TYPE_CNAME) { + $hostname = $this->hostname; + } else { + // 专有域或者官网endpoint + $hostname = ($options[self::OSS_BUCKET] == '') ? $this->hostname : ($options[self::OSS_BUCKET] . '.') . $this->hostname; + } + return $hostname; + } + + /** + * 获得当次请求的资源定位字段 + * + * @param $options + * @return string 资源定位字段 + */ + private function generateResourceUri($options) + { + $resource_uri = ""; + + // resource_uri + bucket + if (isset($options[self::OSS_BUCKET]) && '' !== $options[self::OSS_BUCKET]) { + if ($this->hostType === self::OSS_HOST_TYPE_IP) { + $resource_uri = '/' . $options[self::OSS_BUCKET]; + } + } + + // resource_uri + object + if (isset($options[self::OSS_OBJECT]) && '/' !== $options[self::OSS_OBJECT]) { + $resource_uri .= '/' . str_replace(array('%2F', '%25'), array('/', '%'), rawurlencode($options[self::OSS_OBJECT])); + } + + // resource_uri + sub_resource + $conjunction = '?'; + if (isset($options[self::OSS_SUB_RESOURCE])) { + $resource_uri .= $conjunction . $options[self::OSS_SUB_RESOURCE]; + } + return $resource_uri; + } + + /** + * 生成signalbe_query_string_param, array类型 + * + * @param array $options + * @return array + */ + private function generateSignableQueryStringParam($options) + { + $signableQueryStringParams = array(); + $signableList = array( + self::OSS_PART_NUM, + 'response-content-type', + 'response-content-language', + 'response-cache-control', + 'response-content-encoding', + 'response-expires', + 'response-content-disposition', + self::OSS_UPLOAD_ID, + self::OSS_CNAME_COMP, + self::OSS_POSITION + ); + + foreach ($signableList as $item) { + if (isset($options[$item])) { + $signableQueryStringParams[$item] = $options[$item]; + } + } + + if ($this->enableStsInUrl && (!is_null($this->securityToken))) { + $signableQueryStringParams["security-token"] = $this->securityToken; + } + + return $signableQueryStringParams; + } + + /** + * 生成用于签名resource段 + * + * @param mixed $options + * @return string + */ + private function generateSignableResource($options) + { + $signableResource = ""; + $signableResource .= '/'; + if (isset($options[self::OSS_BUCKET]) && '' !== $options[self::OSS_BUCKET]) { + $signableResource .= $options[self::OSS_BUCKET]; + // 如果操作没有Object操作的话,这里最后是否有斜线有个trick,ip的域名下,不需要加'/', 否则需要加'/' + if ($options[self::OSS_OBJECT] == '/') { + if ($this->hostType !== self::OSS_HOST_TYPE_IP) { + $signableResource .= "/"; + } + } + } + //signable_resource + object + if (isset($options[self::OSS_OBJECT]) && '/' !== $options[self::OSS_OBJECT]) { + $signableResource .= '/' . str_replace(array('%2F', '%25'), array('/', '%'), rawurlencode($options[self::OSS_OBJECT])); + } + if (isset($options[self::OSS_SUB_RESOURCE])) { + $signableResource .= '?' . $options[self::OSS_SUB_RESOURCE]; + } + return $signableResource; + } + + /** + * 生成query_string + * + * @param mixed $options + * @return string + */ + private function generateQueryString($options) + { + //请求参数 + $queryStringParams = array(); + if (isset($options[self::OSS_QUERY_STRING])) { + $queryStringParams = array_merge($queryStringParams, $options[self::OSS_QUERY_STRING]); + } + return OssUtil::toQueryString($queryStringParams); + } + + /** + * 初始化headers + * + * @param mixed $options + * @param string $hostname hostname + * @return array + */ + private function generateHeaders($options, $hostname) + { + $headers = array( + self::OSS_CONTENT_MD5 => '', + self::OSS_CONTENT_TYPE => isset($options[self::OSS_CONTENT_TYPE]) ? $options[self::OSS_CONTENT_TYPE] : self::DEFAULT_CONTENT_TYPE, + self::OSS_DATE => isset($options[self::OSS_DATE]) ? $options[self::OSS_DATE] : gmdate('D, d M Y H:i:s \G\M\T'), + self::OSS_HOST => $hostname, + ); + if (isset($options[self::OSS_CONTENT_MD5])) { + $headers[self::OSS_CONTENT_MD5] = $options[self::OSS_CONTENT_MD5]; + } + //添加stsSecurityToken + if ((!is_null($this->securityToken)) && (!$this->enableStsInUrl)) { + $headers[self::OSS_SECURITY_TOKEN] = $this->securityToken; + } + //合并HTTP headers + if (isset($options[self::OSS_HEADERS])) { + $headers = array_merge($headers, $options[self::OSS_HEADERS]); + } + return $headers; + } + + /** + * 生成请求用的UserAgent + * + * @return string + */ + private function generateUserAgent() + { + return self::OSS_NAME . "/" . self::OSS_VERSION . " (" . php_uname('s') . "/" . php_uname('r') . "/" . php_uname('m') . ";" . PHP_VERSION . ")"; + } + + /** + * 检查endpoint的种类 + * 如有有协议头,剥去协议头 + * 并且根据参数 is_cname 和endpoint本身,判定域名类型,是ip,cname,还是专有域或者官网域名 + * + * @param string $endpoint + * @param boolean $isCName + * @return string 剥掉协议头的域名 + */ + private function checkEndpoint($endpoint, $isCName) + { + $ret_endpoint = null; + if (strpos($endpoint, 'http://') === 0) { + $ret_endpoint = substr($endpoint, strlen('http://')); + } elseif (strpos($endpoint, 'https://') === 0) { + $ret_endpoint = substr($endpoint, strlen('https://')); + $this->useSSL = true; + } else { + $ret_endpoint = $endpoint; + } + + if ($isCName) { + $this->hostType = self::OSS_HOST_TYPE_CNAME; + } elseif (OssUtil::isIPFormat($ret_endpoint)) { + $this->hostType = self::OSS_HOST_TYPE_IP; + } else { + $this->hostType = self::OSS_HOST_TYPE_NORMAL; + } + return $ret_endpoint; + } + + /** + * 用来检查sdk所以来的扩展是否打开 + * + * @throws OssException + */ + public static function checkEnv() + { + if (function_exists('get_loaded_extensions')) { + //检测curl扩展 + $enabled_extension = array("curl"); + $extensions = get_loaded_extensions(); + if ($extensions) { + foreach ($enabled_extension as $item) { + if (!in_array($item, $extensions)) { + throw new OssException("Extension {" . $item . "} is not installed or not enabled, please check your php env."); + } + } + } else { + throw new OssException("function get_loaded_extensions not found."); + } + } else { + throw new OssException('Function get_loaded_extensions has been disabled, please check php config.'); + } + } + + /** + * 设置http库的请求超时时间,单位秒 + * + * @param int $timeout + */ + public function setTimeout($timeout) + { + $this->timeout = $timeout; + } + + /** + * 设置http库的连接超时时间,单位秒 + * + * @param int $connectTimeout + */ + public function setConnectTimeout($connectTimeout) + { + $this->connectTimeout = $connectTimeout; + } + + // 生命周期相关常量 + const OSS_LIFECYCLE_EXPIRATION = "Expiration"; + const OSS_LIFECYCLE_TIMING_DAYS = "Days"; + const OSS_LIFECYCLE_TIMING_DATE = "Date"; + //OSS 内部常量 + const OSS_BUCKET = 'bucket'; + const OSS_OBJECT = 'object'; + const OSS_HEADERS = OssUtil::OSS_HEADERS; + const OSS_METHOD = 'method'; + const OSS_QUERY = 'query'; + const OSS_BASENAME = 'basename'; + const OSS_MAX_KEYS = 'max-keys'; + const OSS_UPLOAD_ID = 'uploadId'; + const OSS_PART_NUM = 'partNumber'; + const OSS_CNAME_COMP = 'comp'; + const OSS_POSITION = 'position'; + const OSS_MAX_KEYS_VALUE = 100; + const OSS_MAX_OBJECT_GROUP_VALUE = OssUtil::OSS_MAX_OBJECT_GROUP_VALUE; + const OSS_MAX_PART_SIZE = OssUtil::OSS_MAX_PART_SIZE; + const OSS_MID_PART_SIZE = OssUtil::OSS_MID_PART_SIZE; + const OSS_MIN_PART_SIZE = OssUtil::OSS_MIN_PART_SIZE; + const OSS_FILE_SLICE_SIZE = 8192; + const OSS_PREFIX = 'prefix'; + const OSS_DELIMITER = 'delimiter'; + const OSS_MARKER = 'marker'; + const OSS_CONTENT_MD5 = 'Content-Md5'; + const OSS_SELF_CONTENT_MD5 = 'x-oss-meta-md5'; + const OSS_CONTENT_TYPE = 'Content-Type'; + const OSS_CONTENT_LENGTH = 'Content-Length'; + const OSS_IF_MODIFIED_SINCE = 'If-Modified-Since'; + const OSS_IF_UNMODIFIED_SINCE = 'If-Unmodified-Since'; + const OSS_IF_MATCH = 'If-Match'; + const OSS_IF_NONE_MATCH = 'If-None-Match'; + const OSS_CACHE_CONTROL = 'Cache-Control'; + const OSS_EXPIRES = 'Expires'; + const OSS_PREAUTH = 'preauth'; + const OSS_CONTENT_COING = 'Content-Coding'; + const OSS_CONTENT_DISPOSTION = 'Content-Disposition'; + const OSS_RANGE = 'range'; + const OSS_ETAG = 'etag'; + const OSS_LAST_MODIFIED = 'lastmodified'; + const OS_CONTENT_RANGE = 'Content-Range'; + const OSS_CONTENT = OssUtil::OSS_CONTENT; + const OSS_BODY = 'body'; + const OSS_LENGTH = OssUtil::OSS_LENGTH; + const OSS_HOST = 'Host'; + const OSS_DATE = 'Date'; + const OSS_AUTHORIZATION = 'Authorization'; + const OSS_FILE_DOWNLOAD = 'fileDownload'; + const OSS_FILE_UPLOAD = 'fileUpload'; + const OSS_PART_SIZE = 'partSize'; + const OSS_SEEK_TO = 'seekTo'; + const OSS_SIZE = 'size'; + const OSS_QUERY_STRING = 'query_string'; + const OSS_SUB_RESOURCE = 'sub_resource'; + const OSS_DEFAULT_PREFIX = 'x-oss-'; + const OSS_CHECK_MD5 = 'checkmd5'; + const DEFAULT_CONTENT_TYPE = 'application/octet-stream'; + + //私有URL变量 + const OSS_URL_ACCESS_KEY_ID = 'OSSAccessKeyId'; + const OSS_URL_EXPIRES = 'Expires'; + const OSS_URL_SIGNATURE = 'Signature'; + //HTTP方法 + const OSS_HTTP_GET = 'GET'; + const OSS_HTTP_PUT = 'PUT'; + const OSS_HTTP_HEAD = 'HEAD'; + const OSS_HTTP_POST = 'POST'; + const OSS_HTTP_DELETE = 'DELETE'; + const OSS_HTTP_OPTIONS = 'OPTIONS'; + //其他常量 + const OSS_ACL = 'x-oss-acl'; + const OSS_OBJECT_ACL = 'x-oss-object-acl'; + const OSS_OBJECT_GROUP = 'x-oss-file-group'; + const OSS_MULTI_PART = 'uploads'; + const OSS_MULTI_DELETE = 'delete'; + const OSS_OBJECT_COPY_SOURCE = 'x-oss-copy-source'; + const OSS_OBJECT_COPY_SOURCE_RANGE = "x-oss-copy-source-range"; + //支持STS SecurityToken + const OSS_SECURITY_TOKEN = "x-oss-security-token"; + const OSS_ACL_TYPE_PRIVATE = 'private'; + const OSS_ACL_TYPE_PUBLIC_READ = 'public-read'; + const OSS_ACL_TYPE_PUBLIC_READ_WRITE = 'public-read-write'; + const OSS_ENCODING_TYPE = "encoding-type"; + const OSS_ENCODING_TYPE_URL = "url"; + + // 域名类型 + const OSS_HOST_TYPE_NORMAL = "normal";//http://bucket.oss-cn-hangzhou.aliyuncs.com/object + const OSS_HOST_TYPE_IP = "ip"; //http://1.1.1.1/bucket/object + const OSS_HOST_TYPE_SPECIAL = 'special'; //http://bucket.guizhou.gov/object + const OSS_HOST_TYPE_CNAME = "cname"; //http://mydomain.com/object + //OSS ACL数组 + static $OSS_ACL_TYPES = array( + self::OSS_ACL_TYPE_PRIVATE, + self::OSS_ACL_TYPE_PUBLIC_READ, + self::OSS_ACL_TYPE_PUBLIC_READ_WRITE + ); + // OssClient版本信息 + const OSS_NAME = "aliyun-sdk-php"; + const OSS_VERSION = "2.0.7"; + const OSS_BUILD = "20160617"; + const OSS_AUTHOR = ""; + const OSS_OPTIONS_ORIGIN = 'Origin'; + const OSS_OPTIONS_REQUEST_METHOD = 'Access-Control-Request-Method'; + const OSS_OPTIONS_REQUEST_HEADERS = 'Access-Control-Request-Headers'; + + //是否使用ssl + private $useSSL = false; + private $maxRetries = 3; + private $redirects = 0; + + // 用户提供的域名类型,有四种 OSS_HOST_TYPE_NORMAL, OSS_HOST_TYPE_IP, OSS_HOST_TYPE_SPECIAL, OSS_HOST_TYPE_CNAME + private $hostType = self::OSS_HOST_TYPE_NORMAL; + private $requestUrl; + private $accessKeyId; + private $accessKeySecret; + private $hostname; + private $securityToken; + private $enableStsInUrl = false; + private $timeout = 0; + private $connectTimeout = 0; +} \ No newline at end of file diff --git a/framework/library/alioss/src/OSS/Result/AclResult.php b/framework/library/alioss/src/OSS/Result/AclResult.php new file mode 100644 index 0000000..e12e3e9 --- /dev/null +++ b/framework/library/alioss/src/OSS/Result/AclResult.php @@ -0,0 +1,33 @@ +rawResponse->body; + if (empty($content)) { + throw new OssException("body is null"); + } + $xml = simplexml_load_string($content); + if (isset($xml->AccessControlList->Grant)) { + return strval($xml->AccessControlList->Grant); + } else { + throw new OssException("xml format exception"); + } + } +} \ No newline at end of file diff --git a/framework/library/alioss/src/OSS/Result/AppendResult.php b/framework/library/alioss/src/OSS/Result/AppendResult.php new file mode 100644 index 0000000..433c03e --- /dev/null +++ b/framework/library/alioss/src/OSS/Result/AppendResult.php @@ -0,0 +1,27 @@ +rawResponse->header; + if (isset($header["x-oss-next-append-position"])) { + return intval($header["x-oss-next-append-position"]); + } + throw new OssException("cannot get next-append-position"); + } +} \ No newline at end of file diff --git a/framework/library/alioss/src/OSS/Result/BodyResult.php b/framework/library/alioss/src/OSS/Result/BodyResult.php new file mode 100644 index 0000000..44ba15e --- /dev/null +++ b/framework/library/alioss/src/OSS/Result/BodyResult.php @@ -0,0 +1,19 @@ +rawResponse->body) ? "" : $this->rawResponse->body; + } +} \ No newline at end of file diff --git a/framework/library/alioss/src/OSS/Result/ExistResult.php b/framework/library/alioss/src/OSS/Result/ExistResult.php new file mode 100644 index 0000000..f7aa287 --- /dev/null +++ b/framework/library/alioss/src/OSS/Result/ExistResult.php @@ -0,0 +1,35 @@ +rawResponse->status) === 200 ? true : false; + } + + /** + * 根据返回http状态码判断,[200-299]即认为是OK, 判断是否存在的接口,404也认为是一种 + * 有效响应 + * + * @return bool + */ + protected function isResponseOk() + { + $status = $this->rawResponse->status; + if ((int)(intval($status) / 100) == 2 || (int)(intval($status)) === 404) { + return true; + } + return false; + } + +} \ No newline at end of file diff --git a/framework/library/alioss/src/OSS/Result/GetCnameResult.php b/framework/library/alioss/src/OSS/Result/GetCnameResult.php new file mode 100644 index 0000000..1f42e23 --- /dev/null +++ b/framework/library/alioss/src/OSS/Result/GetCnameResult.php @@ -0,0 +1,34 @@ +rawResponse->body; + $config = new CnameConfig(); + $config->parseFromXml($content); + return $config; + } + + /** + * 根据返回http状态码判断,[200-299]即认为是OK, 获取bucket相关配置的接口,404也认为是一种 + * 有效响应 + * + * @return bool + */ + protected function isResponseOk() + { + $status = $this->rawResponse->status; + if ((int)(intval($status) / 100) == 2 || (int)(intval($status)) === 404) { + return true; + } + return false; + } +} \ No newline at end of file diff --git a/framework/library/alioss/src/OSS/Result/GetCorsResult.php b/framework/library/alioss/src/OSS/Result/GetCorsResult.php new file mode 100644 index 0000000..a51afe2 --- /dev/null +++ b/framework/library/alioss/src/OSS/Result/GetCorsResult.php @@ -0,0 +1,35 @@ +rawResponse->body; + $config = new CorsConfig(); + $config->parseFromXml($content); + return $config; + } + + /** + * 根据返回http状态码判断,[200-299]即认为是OK, 获取bucket相关配置的接口,404也认为是一种 + * 有效响应 + * + * @return bool + */ + protected function isResponseOk() + { + $status = $this->rawResponse->status; + if ((int)(intval($status) / 100) == 2 || (int)(intval($status)) === 404) { + return true; + } + return false; + } + +} \ No newline at end of file diff --git a/framework/library/alioss/src/OSS/Result/GetLifecycleResult.php b/framework/library/alioss/src/OSS/Result/GetLifecycleResult.php new file mode 100644 index 0000000..6b440c3 --- /dev/null +++ b/framework/library/alioss/src/OSS/Result/GetLifecycleResult.php @@ -0,0 +1,41 @@ +rawResponse->body; + $config = new LifecycleConfig(); + $config->parseFromXml($content); + return $config; + } + + /** + * 根据返回http状态码判断,[200-299]即认为是OK, 获取bucket相关配置的接口,404也认为是一种 + * 有效响应 + * + * @return bool + */ + protected function isResponseOk() + { + $status = $this->rawResponse->status; + if ((int)(intval($status) / 100) == 2 || (int)(intval($status)) === 404) { + return true; + } + return false; + } +} \ No newline at end of file diff --git a/framework/library/alioss/src/OSS/Result/GetLoggingResult.php b/framework/library/alioss/src/OSS/Result/GetLoggingResult.php new file mode 100644 index 0000000..72fc3ae --- /dev/null +++ b/framework/library/alioss/src/OSS/Result/GetLoggingResult.php @@ -0,0 +1,41 @@ +rawResponse->body; + $config = new LoggingConfig(); + $config->parseFromXml($content); + return $config; + } + + /** + * 根据返回http状态码判断,[200-299]即认为是OK, 获取bucket相关配置的接口,404也认为是一种 + * 有效响应 + * + * @return bool + */ + protected function isResponseOk() + { + $status = $this->rawResponse->status; + if ((int)(intval($status) / 100) == 2 || (int)(intval($status)) === 404) { + return true; + } + return false; + } +} \ No newline at end of file diff --git a/framework/library/alioss/src/OSS/Result/GetRefererResult.php b/framework/library/alioss/src/OSS/Result/GetRefererResult.php new file mode 100644 index 0000000..aee50d3 --- /dev/null +++ b/framework/library/alioss/src/OSS/Result/GetRefererResult.php @@ -0,0 +1,41 @@ +rawResponse->body; + $config = new RefererConfig(); + $config->parseFromXml($content); + return $config; + } + + /** + * 根据返回http状态码判断,[200-299]即认为是OK, 获取bucket相关配置的接口,404也认为是一种 + * 有效响应 + * + * @return bool + */ + protected function isResponseOk() + { + $status = $this->rawResponse->status; + if ((int)(intval($status) / 100) == 2 || (int)(intval($status)) === 404) { + return true; + } + return false; + } +} \ No newline at end of file diff --git a/framework/library/alioss/src/OSS/Result/GetWebsiteResult.php b/framework/library/alioss/src/OSS/Result/GetWebsiteResult.php new file mode 100644 index 0000000..3099172 --- /dev/null +++ b/framework/library/alioss/src/OSS/Result/GetWebsiteResult.php @@ -0,0 +1,40 @@ +rawResponse->body; + $config = new WebsiteConfig(); + $config->parseFromXml($content); + return $config; + } + + /** + * 根据返回http状态码判断,[200-299]即认为是OK, 获取bucket相关配置的接口,404也认为是一种 + * 有效响应 + * + * @return bool + */ + protected function isResponseOk() + { + $status = $this->rawResponse->status; + if ((int)(intval($status) / 100) == 2 || (int)(intval($status)) === 404) { + return true; + } + return false; + } +} \ No newline at end of file diff --git a/framework/library/alioss/src/OSS/Result/HeaderResult.php b/framework/library/alioss/src/OSS/Result/HeaderResult.php new file mode 100644 index 0000000..c9aae56 --- /dev/null +++ b/framework/library/alioss/src/OSS/Result/HeaderResult.php @@ -0,0 +1,23 @@ +rawResponse->header) ? array() : $this->rawResponse->header; + } + +} \ No newline at end of file diff --git a/framework/library/alioss/src/OSS/Result/InitiateMultipartUploadResult.php b/framework/library/alioss/src/OSS/Result/InitiateMultipartUploadResult.php new file mode 100644 index 0000000..af985f2 --- /dev/null +++ b/framework/library/alioss/src/OSS/Result/InitiateMultipartUploadResult.php @@ -0,0 +1,29 @@ +rawResponse->body; + $xml = simplexml_load_string($content); + if (isset($xml->UploadId)) { + return strval($xml->UploadId); + } + throw new OssException("cannot get UploadId"); + } +} \ No newline at end of file diff --git a/framework/library/alioss/src/OSS/Result/ListBucketsResult.php b/framework/library/alioss/src/OSS/Result/ListBucketsResult.php new file mode 100644 index 0000000..a58fb2d --- /dev/null +++ b/framework/library/alioss/src/OSS/Result/ListBucketsResult.php @@ -0,0 +1,33 @@ +rawResponse->body; + $xml = new \SimpleXMLElement($content); + if (isset($xml->Buckets) && isset($xml->Buckets->Bucket)) { + foreach ($xml->Buckets->Bucket as $bucket) { + $bucketInfo = new BucketInfo(strval($bucket->Location), + strval($bucket->Name), + strval($bucket->CreationDate)); + $bucketList[] = $bucketInfo; + } + } + return new BucketListInfo($bucketList); + } +} \ No newline at end of file diff --git a/framework/library/alioss/src/OSS/Result/ListMultipartUploadResult.php b/framework/library/alioss/src/OSS/Result/ListMultipartUploadResult.php new file mode 100644 index 0000000..bcb20bf --- /dev/null +++ b/framework/library/alioss/src/OSS/Result/ListMultipartUploadResult.php @@ -0,0 +1,55 @@ +rawResponse->body; + $xml = simplexml_load_string($content); + + $encodingType = isset($xml->EncodingType) ? strval($xml->EncodingType) : ""; + $bucket = isset($xml->Bucket) ? strval($xml->Bucket) : ""; + $keyMarker = isset($xml->KeyMarker) ? strval($xml->KeyMarker) : ""; + $keyMarker = OssUtil::decodeKey($keyMarker, $encodingType); + $uploadIdMarker = isset($xml->UploadIdMarker) ? strval($xml->UploadIdMarker) : ""; + $nextKeyMarker = isset($xml->NextKeyMarker) ? strval($xml->NextKeyMarker) : ""; + $nextKeyMarker = OssUtil::decodeKey($nextKeyMarker, $encodingType); + $nextUploadIdMarker = isset($xml->NextUploadIdMarker) ? strval($xml->NextUploadIdMarker) : ""; + $delimiter = isset($xml->Delimiter) ? strval($xml->Delimiter) : ""; + $delimiter = OssUtil::decodeKey($delimiter, $encodingType); + $prefix = isset($xml->Prefix) ? strval($xml->Prefix) : ""; + $prefix = OssUtil::decodeKey($prefix, $encodingType); + $maxUploads = isset($xml->MaxUploads) ? intval($xml->MaxUploads) : 0; + $isTruncated = isset($xml->IsTruncated) ? strval($xml->IsTruncated) : ""; + $listUpload = array(); + + if (isset($xml->Upload)) { + foreach ($xml->Upload as $upload) { + $key = isset($upload->Key) ? strval($upload->Key) : ""; + $key = OssUtil::decodeKey($key, $encodingType); + $uploadId = isset($upload->UploadId) ? strval($upload->UploadId) : ""; + $initiated = isset($upload->Initiated) ? strval($upload->Initiated) : ""; + $listUpload[] = new UploadInfo($key, $uploadId, $initiated); + } + } + return new ListMultipartUploadInfo($bucket, $keyMarker, $uploadIdMarker, + $nextKeyMarker, $nextUploadIdMarker, + $delimiter, $prefix, $maxUploads, $isTruncated, $listUpload); + } +} \ No newline at end of file diff --git a/framework/library/alioss/src/OSS/Result/ListObjectsResult.php b/framework/library/alioss/src/OSS/Result/ListObjectsResult.php new file mode 100644 index 0000000..fcf493d --- /dev/null +++ b/framework/library/alioss/src/OSS/Result/ListObjectsResult.php @@ -0,0 +1,71 @@ +rawResponse->body); + $encodingType = isset($xml->EncodingType) ? strval($xml->EncodingType) : ""; + $objectList = $this->parseObjectList($xml, $encodingType); + $prefixList = $this->parsePrefixList($xml, $encodingType); + $bucketName = isset($xml->Name) ? strval($xml->Name) : ""; + $prefix = isset($xml->Prefix) ? strval($xml->Prefix) : ""; + $prefix = OssUtil::decodeKey($prefix, $encodingType); + $marker = isset($xml->Marker) ? strval($xml->Marker) : ""; + $marker = OssUtil::decodeKey($marker, $encodingType); + $maxKeys = isset($xml->MaxKeys) ? intval($xml->MaxKeys) : 0; + $delimiter = isset($xml->Delimiter) ? strval($xml->Delimiter) : ""; + $delimiter = OssUtil::decodeKey($delimiter, $encodingType); + $isTruncated = isset($xml->IsTruncated) ? strval($xml->IsTruncated) : ""; + $nextMarker = isset($xml->NextMarker) ? strval($xml->NextMarker) : ""; + $nextMarker = OssUtil::decodeKey($nextMarker, $encodingType); + return new ObjectListInfo($bucketName, $prefix, $marker, $nextMarker, $maxKeys, $delimiter, $isTruncated, $objectList, $prefixList); + } + + private function parseObjectList($xml, $encodingType) + { + $retList = array(); + if (isset($xml->Contents)) { + foreach ($xml->Contents as $content) { + $key = isset($content->Key) ? strval($content->Key) : ""; + $key = OssUtil::decodeKey($key, $encodingType); + $lastModified = isset($content->LastModified) ? strval($content->LastModified) : ""; + $eTag = isset($content->ETag) ? strval($content->ETag) : ""; + $type = isset($content->Type) ? strval($content->Type) : ""; + $size = isset($content->Size) ? intval($content->Size) : 0; + $storageClass = isset($content->StorageClass) ? strval($content->StorageClass) : ""; + $retList[] = new ObjectInfo($key, $lastModified, $eTag, $type, $size, $storageClass); + } + } + return $retList; + } + + private function parsePrefixList($xml, $encodingType) + { + $retList = array(); + if (isset($xml->CommonPrefixes)) { + foreach ($xml->CommonPrefixes as $commonPrefix) { + $prefix = isset($commonPrefix->Prefix) ? strval($commonPrefix->Prefix) : ""; + $prefix = OssUtil::decodeKey($prefix, $encodingType); + $retList[] = new PrefixInfo($prefix); + } + } + return $retList; + } +} \ No newline at end of file diff --git a/framework/library/alioss/src/OSS/Result/ListPartsResult.php b/framework/library/alioss/src/OSS/Result/ListPartsResult.php new file mode 100644 index 0000000..fd8a1b8 --- /dev/null +++ b/framework/library/alioss/src/OSS/Result/ListPartsResult.php @@ -0,0 +1,42 @@ +rawResponse->body; + $xml = simplexml_load_string($content); + $bucket = isset($xml->Bucket) ? strval($xml->Bucket) : ""; + $key = isset($xml->Key) ? strval($xml->Key) : ""; + $uploadId = isset($xml->UploadId) ? strval($xml->UploadId) : ""; + $nextPartNumberMarker = isset($xml->NextPartNumberMarker) ? intval($xml->NextPartNumberMarker) : ""; + $maxParts = isset($xml->MaxParts) ? intval($xml->MaxParts) : ""; + $isTruncated = isset($xml->IsTruncated) ? strval($xml->IsTruncated) : ""; + $partList = array(); + if (isset($xml->Part)) { + foreach ($xml->Part as $part) { + $partNumber = isset($part->PartNumber) ? intval($part->PartNumber) : ""; + $lastModified = isset($part->LastModified) ? strval($part->LastModified) : ""; + $eTag = isset($part->ETag) ? strval($part->ETag) : ""; + $size = isset($part->Size) ? intval($part->Size) : ""; + $partList[] = new PartInfo($partNumber, $lastModified, $eTag, $size); + } + } + return new ListPartsInfo($bucket, $key, $uploadId, $nextPartNumberMarker, $maxParts, $isTruncated, $partList); + } +} \ No newline at end of file diff --git a/framework/library/alioss/src/OSS/Result/PutSetDeleteResult.php b/framework/library/alioss/src/OSS/Result/PutSetDeleteResult.php new file mode 100644 index 0000000..c629949 --- /dev/null +++ b/framework/library/alioss/src/OSS/Result/PutSetDeleteResult.php @@ -0,0 +1,19 @@ +rawResponse = $response; + $this->parseResponse(); + } + + /** + * 获取requestId + * + * @return string + */ + public function getRequestId() + { + if (isset($this->rawResponse) && + isset($this->rawResponse->header) && + isset($this->rawResponse->header['x-oss-request-id']) + ) { + return $this->rawResponse->header['x-oss-request-id']; + } else { + return ''; + } + } + + /** + * 得到返回数据,不同的请求返回数据格式不同 + * + * $return mixed + */ + public function getData() + { + return $this->parsedData; + } + + /** + * 由子类实现,不同的请求返回数据有不同的解析逻辑,由子类实现 + * + * @return mixed + */ + abstract protected function parseDataFromResponse(); + + /** + * 操作是否成功 + * + * @return mixed + */ + public function isOK() + { + return $this->isOk; + } + + /** + * @throws OssException + */ + public function parseResponse() + { + $this->isOk = $this->isResponseOk(); + if ($this->isOk) { + $this->parsedData = $this->parseDataFromResponse(); + } else { + $httpStatus = strval($this->rawResponse->status); + $requestId = strval($this->getRequestId()); + $code = $this->retrieveErrorCode($this->rawResponse->body); + $message = $this->retrieveErrorMessage($this->rawResponse->body); + $body = $this->rawResponse->body; + + $details = array( + 'status' => $httpStatus, + 'request-id' => $requestId, + 'code' => $code, + 'message' => $message, + 'body' => $body + ); + throw new OssException($details); + } + } + + /** + * 尝试从body中获取错误Message + * + * @param $body + * @return string + */ + private function retrieveErrorMessage($body) + { + if (empty($body) || false === strpos($body, 'Message)) { + return strval($xml->Message); + } + return ''; + } + + /** + * 尝试从body中获取错误Code + * + * @param $body + * @return string + */ + private function retrieveErrorCode($body) + { + if (empty($body) || false === strpos($body, 'Code)) { + return strval($xml->Code); + } + return ''; + } + + /** + * 根据返回http状态码判断,[200-299]即认为是OK + * + * @return bool + */ + protected function isResponseOk() + { + $status = $this->rawResponse->status; + if ((int)(intval($status) / 100) == 2) { + return true; + } + return false; + } + + /** + * 返回原始的返回数据 + * + * @return ResponseCore + */ + public function getRawResponse() + { + return $this->rawResponse; + } + + /** + * 标示请求是否成功 + */ + protected $isOk = false; + /** + * 由子类解析过的数据 + */ + protected $parsedData = null; + /** + * 存放auth函数返回的原始Response + * + * @var ResponseCore + */ + protected $rawResponse; +} \ No newline at end of file diff --git a/framework/library/alioss/src/OSS/Result/UploadPartResult.php b/framework/library/alioss/src/OSS/Result/UploadPartResult.php new file mode 100644 index 0000000..c6b66d4 --- /dev/null +++ b/framework/library/alioss/src/OSS/Result/UploadPartResult.php @@ -0,0 +1,28 @@ +rawResponse->header; + if (isset($header["etag"])) { + return $header["etag"]; + } + throw new OssException("cannot get ETag"); + + } +} \ No newline at end of file diff --git a/framework/model/account.mod.php b/framework/model/account.mod.php new file mode 100644 index 0000000..d1937c6 --- /dev/null +++ b/framework/model/account.mod.php @@ -0,0 +1,1413 @@ + array( + 'contain_type' => array(ACCOUNT_TYPE_OFFCIAL_NORMAL, ACCOUNT_TYPE_OFFCIAL_AUTH), + 'level' => array(ACCOUNT_SUBSCRIPTION => '订阅号', ACCOUNT_SERVICE => '服务号', ACCOUNT_SUBSCRIPTION_VERIFY => '认证订阅号', ACCOUNT_SERVICE_VERIFY => '认证服务号'), + 'icon' => 'wi wi-wx-circle', + 'createurl' => url('account/post-step'), + 'title' => '公众号', + ), + WXAPP_TYPE_SIGN => array( + 'contain_type' => array(ACCOUNT_TYPE_APP_NORMAL, ACCOUNT_TYPE_APP_AUTH), + 'level' => array(), + 'icon' => 'wi wi-wxapp', + 'createurl' => url('wxapp/post/design_method'), + 'title' => '微信小程序', + ), + WEBAPP_TYPE_SIGN => array( + 'contain_type' => array(ACCOUNT_TYPE_WEBAPP_NORMAL), + 'level' => array(), + 'icon' => 'wi wi-pc-circle', + 'createurl' => url('account/create', array('sign' => 'webapp')), + 'title' => 'PC', + ), + PHONEAPP_TYPE_SIGN => array( + 'contain_type' => array(ACCOUNT_TYPE_PHONEAPP_NORMAL), + 'level' => array(), + 'icon' => 'wi wi-app', + 'createurl' => url('account/create', array('sign' => 'phoneapp')), + 'title' => 'APP', + ), + ALIAPP_TYPE_SIGN => array( + 'contain_type' => array(ACCOUNT_TYPE_ALIAPP_NORMAL), + 'level' => array(), + 'icon' => 'wi wi-aliapp', + 'createurl' => url('account/create', array('sign' => 'aliapp')), + 'title' => '支付宝小程序', + ), + BAIDUAPP_TYPE_SIGN => array( + 'contain_type' => array(ACCOUNT_TYPE_BAIDUAPP_NORMAL), + 'level' => array(), + 'icon' => 'wi wi-baiduapp', + 'createurl' => url('account/create', array('sign' => 'baiduapp')), + 'title' => '百度小程序', + ), + TOUTIAOAPP_TYPE_SIGN => array( + 'contain_type' => array(ACCOUNT_TYPE_TOUTIAOAPP_NORMAL), + 'level' => array(), + 'icon' => 'wi wi-toutiaoapp', + 'createurl' => url('account/create', array('sign' => 'toutiaoapp')), + 'title' => '字节跳动小程序', + ), + ); + if (!empty($type_sign)) { + return !empty($all_account_type_sign[$type_sign]) ? $all_account_type_sign[$type_sign] : array(); + } + return $all_account_type_sign; +} + + +function uni_account_type($type = 0) +{ + $all_account_type = array( + ACCOUNT_TYPE_OFFCIAL_NORMAL => array( + 'title' => '公众号', + 'type_sign' => ACCOUNT_TYPE_SIGN, + 'table_name' => 'account_wechats', + 'module_support_name' => MODULE_SUPPORT_ACCOUNT_NAME, + 'module_support_value' => MODULE_SUPPORT_ACCOUNT, + 'store_type_module' => STORE_TYPE_MODULE, + 'store_type_number' => STORE_TYPE_ACCOUNT, + 'store_type_renew' => STORE_TYPE_ACCOUNT_RENEW, + ), + ACCOUNT_TYPE_OFFCIAL_AUTH => array( + 'title' => '公众号', + 'type_sign' => ACCOUNT_TYPE_SIGN, + 'table_name' => 'account_wechats', + 'module_support_name' => MODULE_SUPPORT_ACCOUNT_NAME, + 'module_support_value' => MODULE_SUPPORT_ACCOUNT, + 'store_type_module' => STORE_TYPE_MODULE, + 'store_type_number' => STORE_TYPE_ACCOUNT, + 'store_type_renew' => STORE_TYPE_ACCOUNT_RENEW, + ), + ACCOUNT_TYPE_APP_NORMAL => array( + 'title' => '微信小程序', + 'type_sign' => WXAPP_TYPE_SIGN, + 'table_name' => 'account_wxapp', + 'support_version' => 1, + 'version_tablename' => 'wxapp_versions', + 'module_support_name' => MODULE_SUPPORT_WXAPP_NAME, + 'module_support_value' => MODULE_SUPPORT_WXAPP, + 'store_type_module' => STORE_TYPE_WXAPP_MODULE, + 'store_type_number' => STORE_TYPE_WXAPP, + 'store_type_renew' => STORE_TYPE_WXAPP_RENEW, + ), + ACCOUNT_TYPE_APP_AUTH => array( + 'title' => '微信小程序', + 'type_sign' => WXAPP_TYPE_SIGN, + 'table_name' => 'account_wxapp', + 'support_version' => 1, + 'version_tablename' => 'wxapp_versions', + 'module_support_name' => MODULE_SUPPORT_WXAPP_NAME, + 'module_support_value' => MODULE_SUPPORT_WXAPP, + 'store_type_module' => STORE_TYPE_WXAPP_MODULE, + 'store_type_number' => STORE_TYPE_WXAPP, + 'store_type_renew' => STORE_TYPE_WXAPP_RENEW, + ), + ACCOUNT_TYPE_WEBAPP_NORMAL => array( + 'title' => 'PC', + 'type_sign' => WEBAPP_TYPE_SIGN, + 'table_name' => 'account_webapp', + 'module_support_name' => MODULE_SUPPORT_WEBAPP_NAME, + 'module_support_value' => MODULE_SUPPORT_WEBAPP, + 'store_type_module' => STORE_TYPE_WEBAPP_MODULE, + 'store_type_number' => STORE_TYPE_WEBAPP, + 'store_type_renew' => STORE_TYPE_WEBAPP_RENEW, + ), + ACCOUNT_TYPE_PHONEAPP_NORMAL => array( + 'title' => 'APP', + 'type_sign' => PHONEAPP_TYPE_SIGN, + 'table_name' => 'account_phoneapp', + 'support_version' => 1, + 'version_tablename' => 'wxapp_versions', + 'module_support_name' => MODULE_SUPPORT_PHONEAPP_NAME, + 'module_support_value' => MODULE_SUPPORT_PHONEAPP, + 'store_type_module' => STORE_TYPE_PHONEAPP_MODULE, + 'store_type_number' => STORE_TYPE_PHONEAPP, + 'store_type_renew' => STORE_TYPE_PHONEAPP_RENEW, + ), + ACCOUNT_TYPE_ALIAPP_NORMAL => array( + 'title' => '支付宝小程序', + 'type_sign' => ALIAPP_TYPE_SIGN, + 'table_name' => 'account_aliapp', + 'support_version' => 1, + 'version_tablename' => 'wxapp_versions', + 'module_support_name' => MODULE_SUPPORT_ALIAPP_NAME, + 'module_support_value' => MODULE_SUPPORT_ALIAPP, + 'store_type_module' => STORE_TYPE_ALIAPP_MODULE, + 'store_type_number' => STORE_TYPE_ALIAPP, + 'store_type_renew' => STORE_TYPE_ALIAPP_RENEW, + ), + ACCOUNT_TYPE_BAIDUAPP_NORMAL => array( + 'title' => '百度小程序', + 'type_sign' => BAIDUAPP_TYPE_SIGN, + 'table_name' => 'account_baiduapp', + 'support_version' => 1, + 'version_tablename' => 'wxapp_versions', + 'module_support_name' => MODULE_SUPPORT_BAIDUAPP_NAME, + 'module_support_value' => MODULE_SUPPORT_BAIDUAPP, + 'store_type_module' => STORE_TYPE_BAIDUAPP_MODULE, + 'store_type_number' => STORE_TYPE_BAIDUAPP, + 'store_type_renew' => STORE_TYPE_BAIDUAPP_RENEW, + ), + ACCOUNT_TYPE_TOUTIAOAPP_NORMAL => array( + 'title' => '字节跳动小程序', + 'type_sign' => TOUTIAOAPP_TYPE_SIGN, + 'table_name' => 'account_toutiaoapp', + 'support_version' => 1, + 'version_tablename' => 'wxapp_versions', + 'module_support_name' => MODULE_SUPPORT_TOUTIAOAPP_NAME, + 'module_support_value' => MODULE_SUPPORT_TOUTIAOAPP, + 'store_type_module' => STORE_TYPE_TOUTIAOAPP_MODULE, + 'store_type_number' => STORE_TYPE_TOUTIAOAPP, + 'store_type_renew' => STORE_TYPE_TOUTIAOAPP_RENEW, + ), + ); + if (!empty($type)) { + return !empty($all_account_type[$type]) ? $all_account_type[$type] : array(); + } + return $all_account_type; +} + + +function uni_need_account_info() +{ + global $controller, $action, $do, $_GPC; + if (defined('FRAME') && in_array(FRAME, array('account', 'wxapp')) && $_GPC['module_name'] != 'store' && !$_GPC['system_welcome'] && $_GPC['module_type'] != 'system_welcome') { + return true; + } + if ($controller == 'miniapp') { + if ($action == 'version' && $do == 'display') { + return true; + } + } + return false; +} + + +function uni_account_can_create($type_sign) +{ + $result = 1; + return $result; + $type_sign_info = uni_account_type_sign($type_sign); + if (empty($type_sign_info)) { + return 0; + } + $all_accounts = table('account')->getall(); + if (empty($all_accounts)) { + return $result; + } + $account_nums = array(); + $account_total = 0; + + $uni_account_type = uni_account_type(); + foreach ($all_accounts as $account) { + if (!empty($uni_account_type[$account['type']])) { + $account_nums[$uni_account_type[$account['type']]['type_sign']] += 1; + } + } + if (empty($account_nums[$type_sign])) { + return $result; + } + foreach ($account_nums as $account_num) { + if ($account_num > 1) { + $account_total += ($account_num - 1); + } + } + + $cloud_total = cloud_account_info(); + if ($account_total >= $cloud_total) { + $result = 0; + } + + return $result; +} + +function uni_account_create_info() +{ + global $_W; + load()->model('permission'); + $account_create_info = permission_user_account_num(); + $account_all_type_sign = uni_account_type_sign(); + foreach ($account_all_type_sign as $sign => &$sign_info) { + if ($_W['isadmin']) { + $sign_info['can_create'] = true; + } else { + $sign_limit = $sign . '_limit'; + $founder_sign_limit = 'founder_' . $sign . '_limit'; + if (!empty($account_create_info[$sign_limit]) && (!empty($account_create_info[$founder_sign_limit]) && $_W['user']['owner_uid'] || empty($_W['user']['owner_uid'])) || !empty($account_create_info['store_' . $sign . '_limit'])) { + $sign_info['can_create'] = true; + } else { + $sign_info['can_create'] = false; + } + } + } + return $account_all_type_sign; +} + + +function uni_account_extra_info($uniacid) +{ + $uniacid = max(0, intval($uniacid)); + if (empty($uniacid)) { + return array(); + } + $account = pdo_get('account', array('uniacid' => $uniacid)); + if (empty($account) || empty($account['type'])) { + return array(); + } + $account_extra = uni_account_type($account['type']); + return $account_extra; +} + + +function uni_user_accounts($uid = 0, $type = 'account') +{ + global $_W; + $uid = intval($uid) > 0 ? intval($uid) : $_W['uid']; + if (!in_array($type, array('account', 'wxapp', 'webapp', 'phoneapp', 'aliapp', 'baiduapp', 'toutiaoapp'))) { + $type = 'account'; + } + $cachekey = cache_system_key('user_accounts', array('type' => $type, 'uid' => $uid)); + $cache = cache_load($cachekey); + if (!empty($cache)) { + return $cache; + } + $type = in_array($type, array('account')) ? 'wechats' : $type; + $select_fields = 'w.acid, w.uniacid, w.name, a.type'; + if (in_array($type, array('wechats', 'wxapp'))) { + $select_fields .= ', w.level, w.key, w.secret, w.token'; + } + $where = ''; + $params = array(); + if (!user_is_founder($uid, true)) { + $select_fields .= ', u.role'; + $where .= " LEFT JOIN " . tablename('uni_account_users') . " u ON u.uniacid = w.uniacid WHERE u.uid = :uid AND u.role IN(:role1, :role2, :role3, :role4) "; + $params[':uid'] = $uid; + $params[':role1'] = ACCOUNT_MANAGE_NAME_OPERATOR; + $params[':role2'] = ACCOUNT_MANAGE_NAME_MANAGER; + $params[':role3'] = ACCOUNT_MANAGE_NAME_OWNER; + $params[':role4'] = ACCOUNT_MANAGE_NAME_VICE_FOUNDER; + } + $where .= !empty($where) ? " AND a.isdeleted <> 1 AND u.role IS NOT NULL" : " WHERE a.isdeleted <> 1"; + + $sql = "SELECT " . $select_fields . " FROM " . tablename('account_' . $type) . " w LEFT JOIN " . tablename('account') . " a ON a.acid = w.acid AND a.uniacid = w.uniacid" . $where; + $result = pdo_fetchall($sql, $params, 'uniacid'); + cache_write($cachekey, $result); + return $result; +} + + +function account_owner($uniacid = 0) +{ + global $_W; + load()->model('user'); + $uniacid = intval($uniacid); + if (empty($uniacid)) { + return array(); + } + $ownerid = pdo_getcolumn('uni_account_users', array('uniacid' => $uniacid, 'role' => 'owner'), 'uid'); + if (empty($ownerid)) { + $ownerid = pdo_getcolumn('uni_account_users', array('uniacid' => $uniacid, 'role' => 'vice_founder'), 'uid'); + if (empty($ownerid)) { + $founders = explode(',', $_W['config']['setting']['founder']); + $ownerid = $founders[0]; + } + } + $owner = user_single($ownerid); + if (empty($owner)) { + return array(); + } + return $owner; +} + +function uni_fetch($uniacid = 0) +{ + global $_W; + $uniacid = empty($uniacid) ? $_W['uniacid'] : intval($uniacid); + $account_api = WeAccount::createByUniacid($uniacid); + if (is_error($account_api)) { + return $account_api; + } + $account_api->__toArray(); + $account_api['accessurl'] = $account_api['manageurl'] = wurl('account/post', array('uniacid' => $uniacid, 'account_type' => $account_api['type']), true); + $account_api['roleurl'] = wurl('account/post-user/edit', array('uniacid' => $uniacid, 'account_type' => $account_api['type']), true); + return $account_api; +} + + +function uni_site_store_buy_goods($uniacid, $type = STORE_TYPE_MODULE) +{ + $cachekey = cache_system_key('site_store_buy', array('type' => $type, 'uniacid' => $uniacid)); + $site_store_buy_goods = cache_load($cachekey); + if (!empty($site_store_buy_goods)) { + return $site_store_buy_goods; + } + $store_table = table('site_store_order'); + if ($type != STORE_TYPE_API) { + $store_table->searchWithEndtime(); + $site_store_buy_goods = $store_table->searchAccountBuyGoods($uniacid, $type); + $site_store_buy_goods = array_keys($site_store_buy_goods); + } else { + $site_store_buy_goods = $store_table->searchAccountBuyGoods($uniacid, $type); + $setting = uni_setting_load('statistics', $uniacid); + $use_number = isset($setting['statistics']['use']) ? intval($setting['statistics']['use']) : 0; + $site_store_buy_goods = $site_store_buy_goods - $use_number; + } + cache_write($cachekey, $site_store_buy_goods); + return $site_store_buy_goods; +} + + +function uni_modules_by_uniacid($uniacid) +{ + global $_W; + load()->model('user'); + load()->model('module'); + $account_info = table('account')->getByUniacid($uniacid); + $uni_account_type = uni_account_type($account_info['type']); + $owner_uid = pdo_getall('uni_account_users', array('uniacid' => $uniacid, 'role' => array('owner', 'vice_founder')), array('uid', 'role'), 'role'); + $owner_uid = !empty($owner_uid['owner']) ? $owner_uid['owner']['uid'] : (!empty($owner_uid['vice_founder']) ? $owner_uid['vice_founder']['uid'] : 0); + + $cachekey = cache_system_key('unimodules', array('uniacid' => $uniacid)); + $modules = cache_load($cachekey); + if (empty($modules)) { + $enabled_modules = table('modules')->getNonRecycleModules(); + if (!empty($owner_uid) && !user_is_founder($owner_uid, true)) { + $group_modules = table('account')->accountGroupModules($uniacid); + + $user_modules = user_modules($owner_uid); + if (!empty($user_modules)) { + $group_modules = array_unique(array_merge($group_modules, array_keys($user_modules))); + $group_modules = array_intersect(array_keys($enabled_modules), $group_modules); + } + } else { + $group_modules = array_keys($enabled_modules); + } + cache_write($cachekey, $group_modules); + $modules = $group_modules; + } + $modules = array_merge($modules, module_system()); + + $module_list = array(); + if (!empty($modules)) { + foreach ($modules as $name) { + if (empty($name)) { + continue; + } + $module_info = module_fetch($name); + if ($module_info[$uni_account_type['module_support_name']] != $uni_account_type['module_support_value']) { + continue; + } + if (empty($module_info)) { + $module_cloud_info = pdo_get('modules_cloud', array('name' => $name)); + $store_goods_info = pdo_get('site_store_goods', array('module' => $name)); + if (!empty($module_cloud_info) && $store_goods_info['is_wish'] == 1) { + $module_info = $module_cloud_info; + } + } + if (!empty($module_info['recycle_info'])) { + foreach (module_support_type() as $support => $value) { + if ($module_info['recycle_info'][$support] > 0 && $module_info[$support] == $value['support']) { + $module_info[$support] = $value['not_support']; + } + } + } + if ($module_info[MODULE_SUPPORT_ACCOUNT_NAME] != MODULE_SUPPORT_ACCOUNT && + in_array($account_info['type'], array(ACCOUNT_TYPE_OFFCIAL_NORMAL, ACCOUNT_TYPE_OFFCIAL_AUTH))) { + continue; + } + if ($module_info[MODULE_SUPPORT_WEBAPP_NAME] != MODULE_SUPPORT_WEBAPP && + in_array($account_info['type'], array(ACCOUNT_TYPE_WEBAPP_NORMAL))) { + continue; + } + if ($module_info[MODULE_SUPPORT_PHONEAPP_NAME] != MODULE_SUPPORT_PHONEAPP && + in_array($account_info['type'], array(ACCOUNT_TYPE_PHONEAPP_NORMAL))) { + continue; + } + if ($module_info[MODULE_SUPPORT_ALIAPP_NAME] != MODULE_SUPPORT_ALIAPP && + in_array($account_info['type'], array(ACCOUNT_TYPE_ALIAPP_NORMAL))) { + continue; + } + if ($module_info[MODULE_SUPPORT_BAIDUAPP_NAME] != MODULE_SUPPORT_BAIDUAPP && + in_array($account_info['type'], array(ACCOUNT_TYPE_BAIDUAPP_NORMAL))) { + continue; + } + if ($module_info[MODULE_SUPPORT_TOUTIAOAPP_NAME] != MODULE_SUPPORT_TOUTIAOAPP && + in_array($account_info['type'], array(ACCOUNT_TYPE_TOUTIAOAPP_NORMAL))) { + continue; + } + if ($module_info[MODULE_SUPPORT_WXAPP_NAME] != MODULE_SUPPORT_WXAPP && + $module_info[MODULE_SUPPORT_ACCOUNT_NAME] != MODULE_SUPPORT_ACCOUNT && + in_array($account_info['type'], array(ACCOUNT_TYPE_APP_NORMAL, ACCOUNT_TYPE_APP_AUTH))) { + continue; + } + if ($module_info[MODULE_SUPPORT_SYSTEMWELCOME_NAME] == MODULE_SUPPORT_SYSTEMWELCOME && + $module_info[MODULE_SUPPORT_ACCOUNT_NAME] != MODULE_SUPPORT_ACCOUNT && + $module_info[MODULE_SUPPORT_WEBAPP_NAME] != MODULE_SUPPORT_WEBAPP && + $module_info[MODULE_SUPPORT_PHONEAPP_NAME] != MODULE_SUPPORT_PHONEAPP && + $module_info[MODULE_SUPPORT_ALIAPP_NAME] != MODULE_SUPPORT_ALIAPP && + $module_info[MODULE_SUPPORT_BAIDUAPP_NAME] != MODULE_SUPPORT_BAIDUAPP && + $module_info[MODULE_SUPPORT_WXAPP_NAME] != MODULE_SUPPORT_WXAPP) { + continue; + } + if (!empty($module_info)) { + $module_list[$name] = $module_info; + } + } + } + $module_list['core'] = array('title' => '系统事件处理模块', 'name' => 'core', 'issystem' => 1, 'enabled' => 1, 'isdisplay' => 0); + return $module_list; +} + + +function uni_modules() +{ + global $_W; + return uni_modules_by_uniacid($_W['uniacid']); +} + +function uni_modules_app_binding() +{ + global $_W; + $cachekey = cache_system_key('unimodules_binding', array('uniacid' => $_W['uniacid'])); + $cache = cache_load($cachekey); + if (!empty($cache)) { + return $cache; + } + load()->model('module'); + $result = array(); + $modules = uni_modules(); + if (!empty($modules)) { + foreach ($modules as $module) { + if ($module['type'] == 'system') { + continue; + } + $entries = module_app_entries($module['name'], array('home', 'profile', 'shortcut', 'function', 'cover')); + if (empty($entries)) { + continue; + } + if ($module['type'] == '') { + $module['type'] = 'other'; + } + $result[$module['name']] = array( + 'name' => $module['name'], + 'type' => $module['type'], + 'title' => $module['title'], + 'entries' => array( + 'cover' => $entries['cover'], + 'home' => $entries['home'], + 'profile' => $entries['profile'], + 'shortcut' => $entries['shortcut'], + 'function' => $entries['function'] + ) + ); + unset($module); + } + } + cache_write($cachekey, $result); + return $result; +} + + +function uni_groups($groupids = array(), $show_all = false) +{ + load()->model('module'); + global $_W; + $cache_key_id = 0; + if (!empty($groupids)) { + foreach ($groupids as $groupid_key => $groupid_val) { + $groupid_val = intval($groupid_val); + $groupids[$groupid_key] = $groupid_val; + $cache_key_id .= $groupid_val; + } + } + $cachekey = cache_system_key('uni_groups', array('groupids' => $cache_key_id)); + $list = cache_load($cachekey); + if (empty($list)) { + $condition = ' WHERE uniacid = 0 AND uid = 0'; + if (!empty($groupids)) { + foreach ($groupids as $groupid_key => $groupid_val) { + $groupids[$groupid_key] = intval($groupid_val); + } + $groupids_string = implode(',', $groupids); + $condition .= ' AND id IN (' . $groupids_string . ')'; + } + $list = pdo_fetchall("SELECT * FROM " . tablename('uni_group') . $condition . " ORDER BY id DESC", array(), 'id'); + if (!empty($groupids)) { + if (in_array('-1', $groupids)) { + $list[-1] = array('id' => -1, 'name' => '所有服务', 'modules' => array('title' => '系统所有模块'), 'templates' => array('title' => '系统所有模板')); + } + if (in_array('0', $groupids)) { + $list[0] = array('id' => 0, 'name' => '基础服务', 'modules' => array('title' => '系统模块'), 'templates' => array('title' => '系统模板')); + } + } + + if (!empty($list)) { + foreach ($list as $k => &$row) { + $modules = (array)iunserializer($row['modules']); + $row['modules_all'] = array(); + if (!empty($modules)) { + foreach ($modules as $type => $modulenames) { + $type = $type == 'modules' ? 'account' : $type; + if (empty($modulenames) || !is_array($modulenames)) { + continue; + } + $row['modules_all'] = array_merge($row['modules_all'], $modulenames); + $row[$type] = empty($row[$type]) ? $modulenames : array_merge($row[$type], $modulenames); + } + $row['modules_all'] = array_unique($row['modules_all']); + } + + if (!empty($row['templates'])) { + $row['templates'] = (array)iunserializer($row['templates']); + if (!empty($row['templates'])) { + $row['templates'] = table('modules')->getAllTemplateByIds($row['templates'], 'name'); + } + } + } + } + cache_write($cachekey, $list); + } + $group_list = array(); + if (empty($list)) { + return $group_list; + } + $modules_info = array(); + foreach ($list as &$item) { + if (empty($item['modules_all'])) { + continue; + } + + $modules_all = $item['modules_all']; + $item['modules_all'] = array(); + if (!empty($item['account'])) { + $account_modules = $item['account']; + $item['account'] = array(); + foreach ($account_modules as $name) { + if (empty($modules_info[$name]) || !is_array($modules_info[$name])) { + $modules_info[$name] = module_main_info($name); + } + if (empty($item['modules_all'][$name])) { + $item['modules_all'][$name] = $modules_info[$name]; + } + if (in_array($name, $modules_all)) { + $item['modules_all'][$name]['group_support']['account_support'] = 2; + } + $item['account'][$name] = $modules_info[$name]; + } + } + if (!empty($item['wxapp'])) { + $wxapp_modules = $item['wxapp']; + $item['wxapp'] = array(); + foreach ($wxapp_modules as $name) { + if (empty($modules_info[$name]) || !is_array($modules_info[$name])) { + $modules_info[$name] = module_main_info($name); + } + if (empty($item['modules_all'][$name])) { + $item['modules_all'][$name] = $modules_info[$name]; + } + if (in_array($name, $modules_all)) { + $item['modules_all'][$name]['group_support']['account_support'] = 2; + } + $item['wxapp'][$name] = $modules_info[$name]; + } + } + if (!empty($item['webapp'])) { + $wxapp_modules = $item['webapp']; + $item['webapp'] = array(); + foreach ($wxapp_modules as $name) { + if (empty($modules_info[$name]) || !is_array($modules_info[$name])) { + $modules_info[$name] = module_main_info($name); + } + if (empty($item['modules_all'][$name])) { + $item['modules_all'][$name] = $modules_info[$name]; + } + if (in_array($name, $modules_all)) { + $item['modules_all'][$name]['group_support']['webapp_support'] = 2; + } + $item['webapp'][$name] = $modules_info[$name]; + } + } + if (!empty($item['phoneapp'])) { + $phoneapp_modules = $item['phoneapp']; + $item['phoneapp'] = array(); + foreach ($phoneapp_modules as $name) { + if (empty($modules_info[$name]) || !is_array($modules_info[$name])) { + $modules_info[$name] = module_main_info($name); + } + if (empty($item['modules_all'][$name])) { + $item['modules_all'][$name] = $modules_info[$name]; + } + if (in_array($name, $modules_all)) { + $item['modules_all'][$name]['group_support']['phoneapp_support'] = 2; + } + $item['phoneapp'][$name] = $modules_info[$name]; + } + } + if (!empty($item['aliapp'])) { + $aliapp_modules = $item['aliapp']; + $item['aliapp'] = array(); + foreach ($aliapp_modules as $name) { + if (empty($modules_info[$name]) || !is_array($modules_info[$name])) { + $modules_info[$name] = module_main_info($name); + } + if (empty($item['modules_all'][$name])) { + $item['modules_all'][$name] = $modules_info[$name]; + } + if (in_array($name, $modules_all)) { + $item['modules_all'][$name]['group_support']['aliapp_support'] = 2; + } + $item['aliapp'][$name] = $modules_info[$name]; + } + } + if (!empty($item['baiduapp'])) { + $baiduapp_modules = $item['baiduapp']; + $item['baiduapp'] = array(); + foreach ($baiduapp_modules as $name) { + if (empty($modules_info[$name]) || !is_array($modules_info[$name])) { + $modules_info[$name] = module_main_info($name); + } + if (empty($item['modules_all'][$name])) { + $item['modules_all'][$name] = $modules_info[$name]; + } + if (in_array($name, $modules_all)) { + $item['modules_all'][$name]['group_support']['baiduapp_support'] = 2; + } + $item['baiduapp'][$name] = $modules_info[$name]; + } + } + if (!empty($item['toutiaoapp'])) { + $toutiaoapp_modules = $item['toutiaoapp']; + $item['toutiaoapp'] = array(); + foreach ($toutiaoapp_modules as $name) { + if (empty($modules_info[$name]) || !is_array($modules_info[$name])) { + $modules_info[$name] = module_main_info($name); + } + if (empty($item['modules_all'][$name])) { + $item['modules_all'][$name] = $modules_info[$name]; + } + if (in_array($name, $modules_all)) { + $item['modules_all'][$name]['group_support']['toutiaoapp_support'] = 2; + } + $item['toutiaoapp'][$name] = $modules_info[$name]; + } + } + } + + if (!empty($groupids)) { + foreach ($groupids as $id) { + $group_list[$id] = $list[$id]; + } + } else { + if (user_is_vice_founder() && empty($show_all)) { + $founder_own_table = table('users_founder_own_uni_groups'); + $founder_own_uni_groups = $founder_own_table->getOwnUniGroupsByFounderUid($_W['uid']); + foreach ($list as $group_key => $group) { + if (!in_array($group_key, array_keys($founder_own_uni_groups))) { + unset($list[$group_key]); + continue; + } + } + } + $group_list = $list; + } + + return $group_list; +} + + +function uni_templates() +{ + global $_W; + load()->model('user'); + $owneruid = pdo_fetchcolumn("SELECT uid FROM " . tablename('uni_account_users') . " WHERE uniacid = :uniacid AND role = 'owner'", array(':uniacid' => $_W['uniacid'])); + $owner = user_single(array('uid' => $owneruid)); + if (empty($owner) || user_is_founder($owner['uid'])) { + $groupid = '-1'; + } else { + $groupid = $owner['groupid']; + } + if ($groupid == '-1') { + $templates = table('modules')->getAllTemplates('mid'); + return $templates; + } + + $extend = pdo_getall('uni_account_group', array('uniacid' => $_W['uniacid']), array(), 'groupid'); + $uni_extend = pdo_get('uni_account_extra_modules', array('uniacid' => $_W['uniacid'])); + $owner_extend_groups = table('users_extra_group')->getUniGroupsByUid($owneruid); + $owner_extend_templates = table('users_extra_modules')->getExtraModulesByUid($owneruid); + $modules_table = table('modules'); + $modules_table->searchTemplateWithName('default'); + $template_default = $modules_table->getAllTemplates('mid'); + + if (empty($groupid) && empty($extend) && empty($uni_extend) && empty($owner_extend_groups) && empty($owner_extend_templates)) { + return $template_default; + } + + $group = pdo_fetch("SELECT id, name, package FROM " . tablename('users_group') . " WHERE id = :id", array(':id' => $groupid)); + $packageids = iunserializer($group['package']); + if (!is_array($packageids)) { + $packageids = array(); + } + if (!empty($extend)) { + foreach ($extend as $extend_packageid => $row) { + $packageids[] = $extend_packageid; + } + } + + if (!empty($owner_extend_groups)) { + foreach ($owner_extend_groups as $id => $row) { + $packageids[] = $id; + } + } + if (in_array('-1', $packageids)) { + return table('modules')->getAllTemplates('mid'); + } + + $template_modules = array(); + if (!empty($packageids)) { + $wechatgroup = table('uni_group')->where(array('id' => $packageids))->getall(); + if (!empty($wechatgroup)) { + foreach ($wechatgroup as $row) { + $account_modules = iunserializer($row['modules']); + if (!is_array($account_modules['modules']) || empty($account_modules['modules'])) { + continue; + } + foreach ($account_modules['modules'] as $module_name) { + $template_modules[] = $module_name; + } + } + } + } + if (!empty($uni_extend)) { + $uni_extend_modules = iunserializer($uni_extend['modules']); + if (is_array($uni_extend_modules['modules']) && !empty($uni_extend_modules['modules'])) { + foreach ($uni_extend_modules['modules'] as $module_name) { + $template_modules[] = $module_name; + } + } + } + $template_modules = array_unique($template_modules); + $template_modules[] = 'default'; + if (is_array($owner_extend_templates)) { + $template_modules = array_merge($template_modules, array_column($owner_extend_templates, 'module_name')); + } + $result = table('modules')->getTemplateByNames($template_modules, 'mid'); + return $result; +} + + +function uni_setting_save($name, $value) +{ + global $_W; + $uniacid = !empty($_W['uniacid']) ? $_W['uniacid'] : $_W['account']['uniacid']; + if (empty($name)) { + return false; + } + if (is_array($value)) { + $value = serialize($value); + } + $unisetting = pdo_get('uni_settings', array('uniacid' => $uniacid), array('uniacid')); + if (!empty($unisetting)) { + pdo_update('uni_settings', array($name => $value), array('uniacid' => $uniacid)); + } else { + pdo_insert('uni_settings', array($name => $value, 'uniacid' => $uniacid)); + } + cache_delete(cache_system_key('uniaccount', array('uniacid' => $uniacid))); + return true; +} + + +function uni_setting_load($name = '', $uniacid = 0) +{ + global $_W; + $uniacid = empty($uniacid) ? $_W['uniacid'] : $uniacid; + $cachekey = cache_system_key('unisetting', array('uniacid' => $uniacid)); + $unisetting = cache_load($cachekey); + if (empty($unisetting) || ($name == 'remote' && empty($unisetting['remote']))) { + $unisetting = pdo_get('uni_settings', array('uniacid' => $uniacid)); + if (!empty($unisetting)) { + $serialize = array('site_info', 'stat', 'oauth', 'passport', 'notify', + 'creditnames', 'default_message', 'creditbehaviors', 'payment', + 'recharge', 'tplnotice', 'mcplugin', 'statistics', 'bind_domain', 'remote'); + foreach ($unisetting as $key => &$row) { + if (in_array($key, $serialize) && !empty($row)) { + $row = (array)iunserializer($row); + } + } + } else { + $unisetting = array(); + } + cache_write($cachekey, $unisetting); + } + if (empty($unisetting)) { + return array(); + } + if (empty($name)) { + return $unisetting; + } + if (!is_array($name)) { + $name = array($name); + } + return array_elements($name, $unisetting); +} + +function uni_account_user_role_insert($uniacid, $uid, $role) +{ + $vice_account = array( + 'uniacid' => intval($uniacid), + 'uid' => intval($uid), + 'role' => trim($role) + ); + $account_user = pdo_get('uni_account_users', $vice_account, array('id')); + if (!empty($account_user)) { + return false; + } + return pdo_insert('uni_account_users', $vice_account); +} + + +function uni_owner_account_nums($uid, $role) +{ + $account_all_type = uni_account_type(); + $account_all_type_sign = array_keys(uni_account_type_sign()); + + foreach ($account_all_type_sign as $type_info) { + $key_name = $type_info . '_num'; + $num[$key_name] = 0; + } + + $uniacocunts = table('account')->searchAccountList(); + + if (!empty($uniacocunts)) { + $uni_account_users_table = table('uni_account_users'); + $uni_account_users_table->searchWithRole($role); + $all_account = $uni_account_users_table->getCommonUserOwnAccountUniacids($uid); + + foreach ($all_account as $account) { + foreach ($account_all_type as $type_key => $type_info) { + if ($type_key == $account['type']) { + $key_name = $type_info['type_sign'] . '_num'; + $num[$key_name] += 1; + continue; + } + } + } + } + + return $num; +} + +function uni_update_week_stat() +{ + global $_W; + $cachekey = cache_system_key('stat_todaylock', array('uniacid' => $_W['uniacid'])); + $cache = cache_load($cachekey); + if (!empty($cache) && $cache['expire'] > TIMESTAMP) { + return true; + } + $seven_days = array( + date('Ymd', strtotime('-1 days')), + date('Ymd', strtotime('-2 days')), + date('Ymd', strtotime('-3 days')), + date('Ymd', strtotime('-4 days')), + date('Ymd', strtotime('-5 days')), + date('Ymd', strtotime('-6 days')), + date('Ymd', strtotime('-7 days')), + ); + + $week_stat_fans = pdo_getall('stat_fans', array('date' => $seven_days, 'uniacid' => $_W['uniacid']), '', 'date'); + $stat_update_yes = false; + foreach ($seven_days as $sevens) { + if (empty($week_stat_fans[$sevens]) || $week_stat_fans[$sevens]['cumulate'] <= 0) { + $stat_update_yes = true; + break; + } + } + if (empty($stat_update_yes)) { + return true; + } + $account = uni_fetch($_W['uniacid']); + if (is_error($account)) { + return $account; + } + if ($account['level'] == ACCOUNT_SUBSCRIPTION_VERIFY || $account['level'] == ACCOUNT_SERVICE_VERIFY) { + $account_obj = WeAccount::createByUniacid(); + $weixin_stat = $account_obj->getFansStat(); + if (empty($weixin_stat) || is_error($weixin_stat)) { + return error(-1, '调用微信接口错误'); + } + } + foreach ($seven_days as $sevens) { + if ($account['level'] == ACCOUNT_SUBSCRIPTION_VERIFY || $account['level'] == ACCOUNT_SERVICE_VERIFY) { + $update_stat = array( + 'uniacid' => $_W['uniacid'], + 'new' => $weixin_stat[$sevens]['new'], + 'cancel' => $weixin_stat[$sevens]['cancel'], + 'cumulate' => $weixin_stat[$sevens]['cumulate'], + 'date' => $sevens, + ); + } else { + $update_stat = array( + 'cumulate' => pdo_fetchcolumn("SELECT COUNT(*) FROM " . tablename('mc_mapping_fans') . " WHERE uniacid = :uniacid AND follow = :follow AND followtime < :endtime", array(':uniacid' => $_W['uniacid'], ':endtime' => strtotime($sevens) + 86400, ':follow' => 1)), + 'date' => $sevens, + 'new' => $week_stat_fans[$sevens]['new'], + 'cancel' => $week_stat_fans[$sevens]['cancel'], + 'uniacid' => $_W['uniacid'], + ); + } + if (empty($week_stat_fans[$sevens])) { + pdo_insert('stat_fans', $update_stat); + } elseif (empty($week_stat_fans[$sevens]['cumulate']) || $week_stat_fans[$sevens]['cumulate'] < 0) { + pdo_update('stat_fans', $update_stat, array('id' => $week_stat_fans[$sevens]['id'])); + } + } + cache_write($cachekey, array('expire' => TIMESTAMP + 7200)); + return true; +} + + +function account_create($uniacid, $account) +{ + global $_W; + $account_all_type = uni_account_type(); + $type = $account['type']; + $type_sign = $account_all_type[$type]['type_sign']; + unset($account['type']); + + $accountdata = array('uniacid' => $uniacid, 'type' => $type, 'hash' => random(8)); + //$user_create_account_info = permission_user_account_num(); + + if (!$_W['isadmin'] && $_W['user']['endtime'] > USER_ENDTIME_GROUP_UNLIMIT_TYPE) { + $accountdata['endtime'] = $_W['user']['endtime']; + } + +// if (empty($_W['isfounder']) && empty($user_create_account_info["usergroup_{$type_sign}_limit"])) { +// $accountdata['endtime'] = strtotime('+1 month', time()); +// pdo_insert('site_store_create_account', array('endtime' => strtotime('+1 month', time()), 'uid' => $_W['uid'], 'uniacid' => $uniacid, 'type' => $type)); +// } + + + pdo_insert('account', $accountdata); + $acid = pdo_insertid(); + + $account['acid'] = $acid; + $account['uniacid'] = $uniacid; + if (in_array($type_sign, array(ACCOUNT_TYPE_SIGN))) { + $account['token'] = random(32); + $account['encodingaeskey'] = random(43); + } + pdo_insert($account_all_type[$type]['table_name'], $account); + return $acid; +} + + +function account_fetch($acid) +{ + $account_info = pdo_get('account', array('acid' => $acid)); + if (empty($account_info)) { + return error(-1, '公众号不存在'); + } + return uni_fetch($account_info['uniacid']); +} + + +function uni_setmeal($uniacid = 0) +{ + global $_W; + if (!$uniacid) { + $uniacid = $_W['uniacid']; + } + $owneruid = pdo_fetchcolumn("SELECT uid FROM " . tablename('uni_account_users') . " WHERE uniacid = :uniacid AND role = 'owner'", array(':uniacid' => $uniacid)); + if (empty($owneruid)) { + $user = array( + 'uid' => -1, + 'username' => '创始人', + 'timelimit' => '未设置', + 'groupid' => '-1', + 'groupname' => '所有服务' + ); + return $user; + } + load()->model('user'); + $owner = user_single(array('uid' => $owneruid)); + $user = array( + 'uid' => $owner['uid'], + 'username' => $owner['username'], + 'groupid' => $owner['groupid'], + 'groupname' => '' + ); + if (empty($owner['endtime'])) { + $user['timelimit'] = date('Y-m-d', $owner['starttime']) . ' ~ 无限制'; + } else { + if ($owner['endtime'] <= TIMESTAMP) { + $user['timelimit'] = '已到期'; + } else { + $year = 0; + $month = 0; + $day = 0; + $endtime = $owner['endtime']; + $time = strtotime('+1 year'); + if ($endtime > $time) { + $year = $year + 1; + $time = strtotime("+1 year", $time); + } + $time = strtotime("-1 year", $time); + $time = strtotime("+1 month", $time); + if ($endtime > $time) { + $month = $month + 1; + $time = strtotime("+1 month", $time); + } + $time = strtotime("-1 month", $time); + $time = strtotime("+1 day", $time); + if ($endtime > $time) { + $day = $day + 1; + $time = strtotime("+1 day", $time); + } + if (empty($year)) { + $timelimit = empty($month) ? $day . '天' : date('Y-m-d', $owner['starttime']) . '~' . date('Y-m-d', $owner['endtime']); + } else { + $timelimit = date('Y-m-d', $owner['starttime']) . '~' . date('Y-m-d', $owner['endtime']); + } + $user['timelimit'] = $timelimit; + } + } + return $user; +} + + +function account_delete($acid) +{ + global $_W; + load()->func('file'); + load()->model('module'); + load()->model('job'); + $jobid = 0; + $account = pdo_get('uni_account', array('default_acid' => $acid)); + if ($account) { + $uniacid = $account['uniacid']; + $state = permission_account_user_role($_W['uid'], $uniacid); + if (!in_array($state, array(ACCOUNT_MANAGE_NAME_OWNER, ACCOUNT_MANAGE_NAME_FOUNDER, ACCOUNT_MANAGE_NAME_VICE_FOUNDER))) { + itoast('没有该公众号操作权限!', url('account/recycle'), 'error'); + } + if ($uniacid == $_W['uniacid']) { + isetcookie('__uniacid', ''); + } + cache_delete(cache_system_key('uniaccount', array('uniacid' => $uniacid))); + $modules = array(); + $rules = pdo_fetchall("SELECT id, module FROM " . tablename('rule') . " WHERE uniacid = '{$uniacid}'"); + if (!empty($rules)) { + foreach ($rules as $index => $rule) { + $deleteid[] = intval($rule['id']); + } + pdo_delete('rule', "id IN ('" . implode("','", $deleteid) . "')"); + } + + $subaccount = pdo_fetchall("SELECT acid FROM " . tablename('account') . " WHERE uniacid = :uniacid", array(':uniacid' => $uniacid)); + if (!empty($subaccount)) { + foreach ($subaccount as $childaccount) { + @unlink(IA_ROOT . '/attachment/qrcode_' . $childaccount['acid'] . '.jpg'); + @unlink(IA_ROOT . '/attachment/headimg_' . $childaccount['acid'] . '.jpg'); + file_remote_delete('qrcode_' . $childaccount['acid'] . '.jpg'); + file_remote_delete('headimg_' . $childaccount['acid'] . '.jpg'); + } + if (!empty($acid)) { + $jobid = job_create_delete_account($uniacid, $account['name'], $_W['uid']); + } + } + + $tables = array( + 'account', 'account_wechats', 'account_wxapp', 'wxapp_versions', 'account_webapp', 'account_phoneapp', + 'core_paylog', 'cover_reply', 'mc_chats_record', 'mc_credits_recharge', 'mc_credits_record', + 'mc_fans_groups', 'mc_groups', 'mc_handsel', 'mc_mapping_fans', 'mc_mass_record', 'mc_member_address', + 'mc_member_fields', 'mc_members', 'menu_event', 'qrcode', 'qrcode_stat', 'rule', 'rule_keyword', + 'site_article', 'site_category', 'site_multi', 'site_nav', 'site_slide', 'site_styles', 'site_styles_vars', + 'stat_keyword', 'stat_rule', 'uni_account', 'uni_account_modules', 'uni_account_users', 'uni_settings', + 'uni_group', 'uni_account_extra_modules', 'uni_verifycode', 'users_permission', 'wechat_news', + 'users_lastuse', 'users_operate_history', 'users_operate_star' + ); + if (!empty($tables)) { + foreach ($tables as $table) { + $tablename = str_replace($GLOBALS['_W']['config']['db']['tablepre'], '', $table); + pdo_delete($tablename, array('uniacid' => $uniacid)); + } + } + } else { + $account = account_fetch($acid); + if (empty($account)) { + itoast('子公众号不存在或是已经被删除', '', ''); + } + $uniacid = $account['uniacid']; + $state = permission_account_user_role($_W['uid'], $uniacid); + if ($state != ACCOUNT_MANAGE_NAME_FOUNDER && $state != ACCOUNT_MANAGE_NAME_OWNER) { + itoast('没有该公众号操作权限!', url('account/recycle'), 'error'); + } + $uniaccount = uni_fetch($account['uniacid']); + if ($uniaccount['default_acid'] == $acid) { + itoast('默认子公众号不能删除', '', ''); + } + pdo_delete('account', array('uniacid' => $uniacid)); + pdo_delete('account_wechats', array('uniacid' => $uniacid)); + cache_delete(cache_system_key('uniaccount', array('uniacid' => $uniacid))); + cache_delete(cache_system_key('account_auth_refreshtoken', array('uniacid' => $uniacid))); + $oauth = uni_setting($uniacid, array('oauth')); + if (!empty($oauth['oauth']['account']) && $oauth['oauth']['account'] == $acid) { + $acid = pdo_fetchcolumn('SELECT acid FROM ' . tablename('account_wechats') . " WHERE uniacid = :id AND level = 4 AND secret != '' AND `key` != ''", array(':id' => $uniacid)); + pdo_update('uni_settings', array('oauth' => iserializer(array('account' => $acid, 'host' => $oauth['oauth']['host']))), array('uniacid' => $uniacid)); + } + @unlink(IA_ROOT . '/attachment/qrcode_' . $acid . '.jpg'); + @unlink(IA_ROOT . '/attachment/headimg_' . $acid . '.jpg'); + file_remote_delete('qrcode_' . $acid . '.jpg'); + file_remote_delete('headimg_' . $acid . '.jpg'); + } + return $jobid; +} + + +function account_wechatpay_proxy() +{ + global $_W; + $proxy_account = cache_load(cache_system_key('proxy_wechatpay_account')); + if (empty($proxy_account)) { + $proxy_account = cache_build_proxy_wechatpay_account(); + } + unset($proxy_account['borrow'][$_W['uniacid']]); + unset($proxy_account['service'][$_W['uniacid']]); + return $proxy_account; +} + + +function uni_account_module_shortcut_enabled($modulename, $status = STATUS_ON) +{ + global $_W; + $module = module_fetch($modulename); + if (empty($module)) { + return error(1, '抱歉,你操作的模块不能被访问!'); + } + + $module_status = pdo_get('uni_account_modules', array('module' => $modulename, 'uniacid' => $_W['uniacid']), array('id', 'shortcut')); + if (empty($module_status)) { + $data = array( + 'uniacid' => $_W['uniacid'], + 'module' => $modulename, + 'enabled' => STATUS_ON, + 'shortcut' => $status ? STATUS_ON : STATUS_OFF, + 'settings' => '', + ); + pdo_insert('uni_account_modules', $data); + } else { + $data = array( + 'shortcut' => $status ? STATUS_ON : STATUS_OFF, + ); + pdo_update('uni_account_modules', $data, array('id' => $module_status['id'])); + } + cache_build_module_info($modulename); + return true; +} + + +function uni_account_member_fields($uniacid) +{ + if (empty($uniacid)) { + return array(); + } + $account_member_fields = pdo_getall('mc_member_fields', array('uniacid' => $uniacid), array(), 'fieldid'); + $system_member_fields = pdo_getall('profile_fields', array(), array(), 'id'); + $less_field_indexes = array_diff(array_keys($system_member_fields), array_keys($account_member_fields)); + if (empty($less_field_indexes)) { + foreach ($account_member_fields as &$field) { + $field['field'] = $system_member_fields[$field['fieldid']]['field']; + } + unset($field); + return $account_member_fields; + } + + $account_member_add_fields = array('uniacid' => $uniacid); + foreach ($less_field_indexes as $field_index) { + $account_member_add_fields['fieldid'] = $system_member_fields[$field_index]['id']; + $account_member_add_fields['title'] = $system_member_fields[$field_index]['title']; + $account_member_add_fields['available'] = $system_member_fields[$field_index]['available']; + $account_member_add_fields['displayorder'] = $system_member_fields[$field_index]['displayorder']; + pdo_insert('mc_member_fields', $account_member_add_fields); + $insert_id = pdo_insertid(); + $account_member_fields[$insert_id]['id'] = $insert_id; + $account_member_fields[$insert_id]['field'] = $system_member_fields[$field_index]['field']; + $account_member_fields[$insert_id]['fid'] = $system_member_fields[$field_index]['id']; + $account_member_fields[$insert_id] = array_merge($account_member_fields[$insert_id], $account_member_add_fields); + } + return $account_member_fields; +} + + +function uni_account_global_oauth() +{ + load()->model('setting'); + $oauth = setting_load('global_oauth'); + $oauth = !empty($oauth['global_oauth']) ? $oauth['global_oauth'] : array(); + if (!empty($oauth['oauth']['account'])) { + $account_exist = uni_fetch($oauth['oauth']['account']); + if (empty($account_exist) || is_error($account_exist)) { + $oauth['oauth']['account'] = 0; + } + } + return $oauth; +} + +function uni_search_link_account($module_name, $type_sign, $uniacid = 0) +{ + global $_W; + load()->model('miniapp'); + load()->model('phoneapp'); + $module_name = trim($module_name); + if (empty($module_name) || empty($type_sign)) { + return array(); + } + $all_account_type = uni_account_type(); + $all_account_type_sign = uni_account_type_sign(); + if (empty($all_account_type_sign[$type_sign])) { + return array(); + } + $owned_account = uni_user_accounts($_W['uid'], $type_sign); + + if (!empty($owned_account)) { + foreach ($owned_account as $key => $account) { + if (!empty($uniacid) && $account['uniacid'] == $uniacid) { + unset($owned_account[$key]); + continue; + } + $account['role'] = permission_account_user_role($_W['uid'], $account['uniacid']); + if (!in_array($account['role'], array(ACCOUNT_MANAGE_NAME_OWNER, ACCOUNT_MANAGE_NAME_VICE_FOUNDER, ACCOUNT_MANAGE_NAME_FOUNDER))) { + unset($owned_account[$key]); + continue; + } + $account_modules = uni_modules_by_uniacid($account['uniacid']); + if (empty($account_modules[$module_name])) { + unset($owned_account[$key]); + continue; + } + $type = $all_account_type_sign[$type_sign]['contain_type'][0]; + $type_info = $all_account_type[$type]; + if ($account_modules[$module_name][$type_info['module_support_name']] != $type_info['module_support_value']) { + unset($owned_account[$key]); + continue; + } + $account_support_version = array_filter($all_account_type, function ($item) { + return $item['support_version']; + }); + $account_support_version = array_keys($account_support_version); + if (in_array($type, $account_support_version)) { + $last_version = miniapp_fetch($account['uniacid']); + if (empty($last_version['version']) || empty($last_version['version']['modules']) || !is_array($last_version['version']['modules'])) { + unset($owned_account[$key]); + continue; + } + $module_version = array(); + foreach ($last_version['version']['modules'] as $item) { + if (!empty($item['name']) && $item['name'] == $module_name) { + $module_version = $item; + break; + } + } + if (empty($module_version) || !empty($module_version['account']) || !empty($module_version['uniacid'])) { + unset($owned_account[$key]); + continue; + } + } + } + } + return $owned_account; +} + + +function uni_account_oauth_host() +{ + global $_W; + $oauth_url = $_W['siteroot']; + $unisetting = uni_setting_load(); + if (!empty($unisetting['bind_domain']) && !empty($unisetting['bind_domain']['domain'])) { + $oauth_url = $unisetting['bind_domain']['domain'] . '/'; + } else { + if (!empty($unisetting['oauth']['host'])) { + $oauth_url = $unisetting['oauth']['host'] . '/'; + } else { + $global_unisetting = uni_account_global_oauth(); + $oauth_url = !empty($global_unisetting['oauth']['host']) ? $global_unisetting['oauth']['host'] . '/' : $oauth_url; + } + } + return $oauth_url; +} + + +function uni_user_see_more_info($user_type, $see_more = false) +{ + global $_W; + if (empty($user_type)) { + return false; + } + if ($user_type == ACCOUNT_MANAGE_NAME_VICE_FOUNDER && !empty($see_more) || $_W['role'] != $user_type) { + return true; + } + + return false; +} + + +function uni_delete_rule($rid, $relate_table_name) +{ + global $_W; + $rid = intval($rid); + if (empty($rid)) { + return false; + } + $allowed_table_names = array('news_reply', 'cover_reply'); + if (!in_array($relate_table_name, $allowed_table_names)) { + return false; + } + $rule_result = pdo_delete('rule', array('id' => $rid, 'uniacid' => $_W['uniacid'])); + $rule_keyword_result = pdo_delete('rule_keyword', array('rid' => $rid, 'uniacid' => $_W['uniacid'])); + if ($rule_result && $rule_keyword_result) { + $result = pdo_delete($relate_table_name, array('rid' => $rid)); + } + return $result ? true : false; +} + +function uni_get_account_by_appid($appid, $account_type, $except_uniacid = 0) +{ + $type_info = uni_account_type($account_type); + + if (in_array($type_info['type_sign'], array(WEBAPP_TYPE_SIGN, PHONEAPP_TYPE_SIGN))) { + return array(); + } + $sql = 'SELECT t.`key`, t.name, a.acid, a.uniacid FROM ' + . tablename($type_info['table_name']) + . 't JOIN ' . tablename('account') + . ' a ON t.uniacid = a.uniacid WHERE a.isdeleted != 1'; + + if (in_array($type_info['type_sign'], array(BAIDUAPP_TYPE_SIGN, TOUTIAOAPP_TYPE_SIGN))) { + $sql .= ' AND t.`appid` = :appid'; + } else { + $sql .= ' AND t.`key` = :appid'; + } + if (!empty($except_uniacid)) { + $sql .= ' AND a.uniacid != ' . intval($except_uniacid); + } + + $account = pdo_fetch($sql, array(':appid' => $appid)); + if (!empty($account)) { + $account['type_title'] = $type_info['title']; + + if ($type_info['type_sign'] == XZAPP_TYPE_SIGN) { + $account['key_title'] = 'ClientId'; + } else { + $account['key_title'] = 'AppId'; + } + } + return $account; +} \ No newline at end of file diff --git a/framework/model/attachment.mod.php b/framework/model/attachment.mod.php new file mode 100644 index 0000000..f4addc5 --- /dev/null +++ b/framework/model/attachment.mod.php @@ -0,0 +1,177 @@ + '杭州数据中心', + 'oss-cn-qingdao' => '青岛数据中心', + 'oss-cn-beijing' => '北京数据中心', + 'oss-cn-hongkong' => '香港数据中心', + 'oss-cn-shenzhen' => '深圳数据中心', + 'oss-cn-shanghai' => '上海数据中心', + 'oss-us-west-1' => '美国硅谷数据中心', + ); + return $bucket_datacenter; +} + +function attachment_newalioss_auth($key, $secret, $bucket, $internal = false){ + load()->library('oss'); + $buckets = attachment_alioss_buctkets($key, $secret); + $host = $internal ? '-internal.aliyuncs.com' : '.aliyuncs.com'; + $url = 'http://'.$buckets[$bucket]['location'] . $host; + $filename = 'MicroEngine.png'; + try { + $ossClient = new \OSS\OssClient($key, $secret, $url); + $ossClient->uploadFile($bucket, $filename, ATTACHMENT_ROOT.'images/global/'.$filename); + } catch (\OSS\Core\OssException $e) { + return error(1, $e->getMessage()); + } + return 1; +} + +function attachment_alioss_buctkets($key, $secret) { + load()->library('oss'); + $url = 'http://oss-cn-beijing.aliyuncs.com'; + try { + $ossClient = new \OSS\OssClient($key, $secret, $url); + } catch(\OSS\Core\OssException $e) { + return error(1, $e->getMessage()); + } + try{ + $bucketlistinfo = $ossClient->listBuckets(); + } catch(OSS\OSS_Exception $e) { + return error(1, $e->getMessage()); + } + $bucketlistinfo = $bucketlistinfo->getBucketList(); + $bucketlist = array(); + foreach ($bucketlistinfo as &$bucket) { + $bucketlist[$bucket->getName()] = array('name' => $bucket->getName(), 'location' => $bucket->getLocation()); + } + return $bucketlist; +} + +function attachment_qiniu_auth($key, $secret,$bucket) { + load()->library('qiniu'); + $auth = new Qiniu\Auth($key, $secret); + $token = $auth->uploadToken($bucket); + $config = new Qiniu\Config(); + $uploadmgr = new Qiniu\Storage\UploadManager($config); + list($ret, $err) = $uploadmgr->putFile($token, 'MicroEngine.png', ATTACHMENT_ROOT.'images/global/MicroEngine.png'); + if ($err !== null) { + $err = (array)$err; + $err = (array)array_pop($err); + $err = json_decode($err['body'], true); + return error(-1, $err); + } else { + return true; + } +} +function attachment_cos_auth($bucket,$appid, $key, $secret, $bucket_local = '') { + if (!is_numeric($appid)) { + return error(-1, '传入appid值不合法, 请重新输入'); + } + if (!preg_match('/^[a-zA-Z0-9]{36}$/', $key)) { + return error(-1, '传入secretid值不合法,请重新传入'); + } + if (!preg_match('/^[a-zA-Z0-9]{32}$/', $secret)) { + return error(-1, '传入secretkey值不合法,请重新传入'); + } + load()->library('cosv5'); + try { + $cosClient = new Qcloud\Cos\Client( + array( + 'region' => $bucket_local, + 'credentials'=> array( + 'secretId' => $key, + 'secretKey' => $secret))); + $cosClient->Upload($bucket . '-' . $appid, 'MicroEngine.png', fopen(ATTACHMENT_ROOT . 'images/global/MicroEngine.png', 'rb')); + } catch (\Exception $e) { + return error(-1, $e->getMessage()); + } + return true; +} + + +function attachment_reset_uniacid($uniacid) { + global $_W; + if ($_W['role'] == ACCOUNT_MANAGE_NAME_FOUNDER) { + if (empty($uniacid)) { + $_W['uniacid'] = 0; + } elseif ($uniacid > 0) { + $_W['uniacid'] = $uniacid; + } + } else { + + $account = table('account'); + $accounts = $account->userOwnedAccount($_W['uid']); + if (is_array($accounts) && isset($accounts[$uniacid])) { + $_W['uniacid'] = $uniacid; + } + } + return true; +} + + +function attachment_replace_article_remote_url($old_url, $new_url) { + if (empty($old_url) || empty($new_url) || $old_url == $new_url) { + return false; + } + $content_exists = pdo_get('article_news', array('content LIKE' => "%{$old_url}%")); + if (!empty($content_exists)) { + $update_sql = "UPDATE " . tablename('article_news') . " SET `content`=REPLACE(content, :old_url, :new_url)"; + return pdo_query($update_sql, array(':old_url' => $old_url, ':new_url' => $new_url)); + } +} + + +function attachment_recursion_group($group_data = array(), $pid = 0) { + if (empty($group_data)) return array(); + $return_data = array(); + foreach ($group_data as $key => $group_data_value) { + if($group_data_value['pid'] == $pid){ + $return_data[$group_data_value['id']] = $group_data_value; + $sub_group = attachment_recursion_group($group_data, $group_data_value['id']); + if (0 == $pid) { + $return_data[$group_data_value['id']]['sub_group'] = !empty($sub_group) ? $sub_group : array(); + } + } + } + return $return_data; +} + + +function attachment_get_type($type_sign) { + $attach_type = array( + ATTACH_FTP => 'ftp', + ATTACH_OSS => 'alioss', + ATTACH_QINIU => 'qiniu', + ATTACH_COS => 'cos', + ); + return !empty($attach_type[$type_sign]) ? $attach_type[$type_sign] : ''; +} \ No newline at end of file diff --git a/framework/model/cache.mod.php b/framework/model/cache.mod.php new file mode 100644 index 0000000..4a616a2 --- /dev/null +++ b/framework/model/cache.mod.php @@ -0,0 +1,505 @@ +func('file'); + rmdirs(IA_ROOT . '/data/tpl', true); +} + + +function cache_build_setting() +{ + $setting = table('core_settings')->getall('key'); + if (is_array($setting)) { + foreach ($setting as $k => $v) { + $setting[$v['key']] = iunserializer($v['value']); + } + cache_write(cache_system_key('setting'), $setting); + } +} + + +function cache_build_account_modules($uniacid = 0, $uid = 0) +{ + load()->model('phoneapp'); + load()->model('miniapp'); + $uniacid = intval($uniacid); + if (empty($uniacid)) { + cache_clean(cache_system_key('unimodules')); + if (!empty($uid)) { + cache_delete(cache_system_key('user_modules', array('uid' => $uid))); + } else { + cache_clean(cache_system_key('user_modules')); + } + return true; + } else { + cache_clean(cache_system_key('unimodules', array('uniacid' => $uniacid))); + if (empty($uid)) { + $uid = table('uni_account_users')->getUidByUniacidAndRole($uniacid, 'owner'); + } + cache_delete(cache_system_key('user_modules', array('uid' => $uid))); + } + $account_info = uni_fetch($uniacid); + if (is_error($account_info)) { + return false; + } + + $uni_modules_new = uni_modules_by_uniacid($uniacid); + $module_system = module_system(); + foreach ($uni_modules_new as $uni_module_new_key => $uni_module_new_val) { + if (in_array($uni_module_new_key, $module_system)) { + unset($uni_modules_new[$uni_module_new_key]); + } elseif ($account_info->typeSign == 'wxapp' && $uni_module_new_val[MODULE_SUPPORT_WXAPP_NAME] != MODULE_SUPPORT_WXAPP) { + unset($uni_modules_new[$uni_module_new_key]); + } + } + $uni_modules_new = array_keys($uni_modules_new); + + if ($account_info->supportVersion) { + $version_modules = array(); + if ($account_info['type'] == ACCOUNT_TYPE_PHONEAPP_NORMAL) { + $version_all = phoneapp_version_all($uniacid); + } + if (in_array($account_info['type'], array(ACCOUNT_TYPE_APP_NORMAL, ACCOUNT_TYPE_APP_AUTH))) { + $version_all = miniapp_version_all($uniacid); + } + if (!empty($version_all)) { + foreach ($version_all as $version_key => $version_val) { + if (empty($version_val['modules'])) { + continue; + } + foreach ($version_val['modules'] as $module_name => $module_info) { + $version_modules[] = $module_name; + } + } + } + foreach ($uni_modules_new as $uni_module_key => $uni_module_val) { + if (empty($uni_module_val)) { + continue; + } + if (empty($version_modules) || !in_array($uni_module_val, $version_modules)) { + pdo_delete('users_lastuse', array('uniacid' => $uniacid, 'modulename' => $uni_module_val)); + } + } + } + + $uni_account_modules = table('uni_modules')->getallByUniacid($uniacid); + $uni_account_modules = array_column($uni_account_modules, 'module_name'); + + $uni_modules_add = array_diff($uni_modules_new, $uni_account_modules); + $uni_modules_delete = array_diff($uni_account_modules, $uni_modules_new); + + $users_lastuse_table = table('users_lastuse'); + $users_lastuse_table->searchWithUniacid($uniacid); + $uni_modules_default_list = $users_lastuse_table->getall('modulename'); + $uni_modules_default_delete = array_diff(array_keys($uni_modules_default_list), $uni_modules_new); + if (!empty($uni_modules_default_delete)) { + foreach ($uni_modules_default_delete as $module_default_delete_name) { + if (empty($module_default_delete_name)) { + continue; + } + pdo_delete('users_lastuse', array('uniacid' => $uniacid, 'modulename' => $module_default_delete_name)); + } + } + + if (!empty($uni_modules_add)) { + foreach ($uni_modules_add as $module_add_name) { + $account_modules_data = array('uniacid' => $uniacid, 'module_name' => $module_add_name); + pdo_insert('uni_modules', $account_modules_data); + } + } + + if (!empty($uni_modules_delete)) { + foreach ($uni_modules_delete as $mdoule_delete_name) { + pdo_delete('uni_modules', array('uniacid' => $uniacid, 'module_name' => $mdoule_delete_name)); + } + } + + $modules_rank_table = table('modules_rank'); + $modules_rank_list = $modules_rank_table->getModuleListByUidAndUniacid(); + $modules_rank_list = array_keys($modules_rank_list); + $modules_rank_add = array_diff($uni_account_modules, $modules_rank_list); + $modules_rank_delete = array_diff($modules_rank_list, $uni_account_modules); + asort($modules_rank_add); + asort($modules_rank_delete); + + if (!empty($modules_rank_add)) { + foreach ($modules_rank_add as $uni_account_module_key => $uni_account_module_name) { + $modules_rank_data = array('uid' => $uid, 'uniacid' => $uniacid, 'module_name' => $uni_account_module_name, 'rank' => $uni_account_module_key); + pdo_insert('modules_rank', $modules_rank_data); + } + } + + if (!empty($modules_rank_delete)) { + foreach ($modules_rank_delete as $uni_account_module_name) { + $modules_rank_data = array('uid' => $uid, 'uniacid' => $uniacid, 'module_name' => $uni_account_module_name); + pdo_delete('modules_rank', $modules_rank_data); + } + } + return true; +} + + +function cache_build_account($uniacid = 0) +{ + $uniacid = intval($uniacid); + if (empty($uniacid)) { + $uniacid_arr = table('account')->getAll(); + foreach ($uniacid_arr as $account) { + cache_delete(cache_system_key('uniaccount', array('uniacid' => $account['uniacid']))); + cache_delete(cache_system_key('defaultgroupid', array('uniacid' => $account['uniacid']))); + } + } else { + cache_delete(cache_system_key('uniaccount', array('uniacid' => $uniacid))); + cache_delete(cache_system_key('defaultgroupid', array('uniacid' => $uniacid))); + } + return true; +} + + +function cache_build_memberinfo($uid) +{ + $uid = intval($uid); + cache_delete(cache_system_key('memberinfo', array('uid' => $uid))); + return true; +} + + +function cache_build_users_struct() +{ + $base_fields = array( + 'uniacid' => '同一公众号id', + 'groupid' => '分组id', + 'credit1' => '积分', + 'credit2' => '余额', + 'credit3' => '预留积分类型3', + 'credit4' => '预留积分类型4', + 'credit5' => '预留积分类型5', + 'credit6' => '预留积分类型6', + 'createtime' => '加入时间', + 'mobile' => '手机号码', + 'email' => '电子邮箱', + 'realname' => '真实姓名', + 'nickname' => '昵称', + 'avatar' => '头像', + 'qq' => 'QQ号', + 'gender' => '性别', + 'birth' => '生日', + 'constellation' => '星座', + 'zodiac' => '生肖', + 'telephone' => '固定电话', + 'idcard' => '证件号码', + 'studentid' => '学号', + 'grade' => '班级', + 'address' => '地址', + 'zipcode' => '邮编', + 'nationality' => '国籍', + 'reside' => '居住地', + 'graduateschool' => '毕业学校', + 'company' => '公司', + 'education' => '学历', + 'occupation' => '职业', + 'position' => '职位', + 'revenue' => '年收入', + 'affectivestatus' => '情感状态', + 'lookingfor' => ' 交友目的', + 'bloodtype' => '血型', + 'height' => '身高', + 'weight' => '体重', + 'alipay' => '支付宝帐号', + 'msn' => 'MSN', + 'taobao' => '阿里旺旺', + 'site' => '主页', + 'bio' => '自我介绍', + 'interest' => '兴趣爱好', + 'password' => '密码', + 'pay_password' => '支付密码', + ); + cache_write(cache_system_key('userbasefields'), $base_fields); + $fields = table('core_profile_fields')->getall('field'); + if (!empty($fields)) { + foreach ($fields as &$field) { + $field = $field['title']; + } + $fields['uniacid'] = '同一公众号id'; + $fields['groupid'] = '分组id'; + $fields['credit1'] = '积分'; + $fields['credit2'] = '余额'; + $fields['credit3'] = '预留积分类型3'; + $fields['credit4'] = '预留积分类型4'; + $fields['credit5'] = '预留积分类型5'; + $fields['credit6'] = '预留积分类型6'; + $fields['createtime'] = '加入时间'; + $fields['password'] = '用户密码'; + $fields['pay_password'] = '支付密码'; + cache_write(cache_system_key('usersfields'), $fields); + } else { + cache_write(cache_system_key('usersfields'), $base_fields); + } +} + +function cache_build_frame_menu() +{ + global $_W; + load()->model('system'); + $system_menu = system_menu(); + if (!empty($system_menu) && is_array($system_menu)) { + $system_menu = iarray_sort($system_menu, 'displayorder', 'asc'); + cache_delete(cache_system_key('system_frame', array('uniacid' => $_W['uniacid']))); + cache_write(cache_system_key('system_frame', array('uniacid' => $_W['uniacid'])), $system_menu); + return $system_menu; + } +} + +function cache_build_module_subscribe_type() +{ + global $_W; + $modules = table('modules')->getByHasSubscribes(); + if (empty($modules)) { + return array(); + } + $subscribe = array(); + foreach ($modules as $module) { + $module['subscribes'] = iunserializer($module['subscribes']); + if (!empty($module['subscribes'])) { + foreach ($module['subscribes'] as $event) { + if ($event == 'text') { + continue; + } + $subscribe[$event][] = $module['name']; + } + } + } + + $module_ban = $_W['setting']['module_receive_ban']; + foreach ($subscribe as $event => $module_group) { + if (!empty($module_group)) { + foreach ($module_group as $index => $module) { + if (!empty($module_ban[$module])) { + unset($subscribe[$event][$index]); + } + } + } + } + cache_write(cache_system_key('module_receive_enable'), $subscribe); + return $subscribe; +} + + +function cache_build_cloud_ad() +{ + global $_W; + $uniacid_arr = table('account')->getAll(); + foreach ($uniacid_arr as $account) { + cache_delete(cache_system_key('stat_todaylock', array('uniacid' => $account['uniacid']))); + cache_delete(cache_system_key('cloud_ad_uniaccount', array('uniacid' => $account['uniacid']))); + cache_delete(cache_system_key('cloud_ad_app_list', array('uniacid' => $account['uniacid']))); + } + cache_delete(cache_system_key('cloud_flow_master')); + cache_delete(cache_system_key('cloud_ad_uniaccount_list')); + cache_delete(cache_system_key('cloud_ad_tags')); + cache_delete(cache_system_key('cloud_ad_type_list')); + cache_delete(cache_system_key('cloud_ad_app_support_list')); + cache_delete(cache_system_key('cloud_ad_site_finance')); +} + + +function cache_build_uninstalled_module() +{ + $modulelist = table('modules')->getall('name'); + + $module_root = IA_ROOT . '/addons/'; + $module_path_list = glob($module_root . '/*'); + if (empty($module_path_list)) { + return true; + } + $module_support_type = module_support_type(); + + foreach ($module_path_list as $path) { + $modulename = pathinfo($path, PATHINFO_BASENAME); + $module_recycle_info = table('modules_recycle')->searchWithNameType($modulename, MODULE_RECYCLE_UNINSTALL_IGNORE)->get(); + + if (!empty($modulelist[$modulename])) { + $module_cloud_upgrade = table('modules_cloud')->getByName($modulename); + if (!empty($module_cloud_upgrade)) { + $has_new_support = false; + $installed_support = array(); + foreach (module_support_type() as $support => $value) { + if (!empty($module_recycle_info) && $module_recycle_info[$support] == 1) { + $installed_support[$support] = $value['not_support']; + } + if ($module_cloud_upgrade[$support] == $value['support'] && $modulelist[$modulename][$support] != $value['support']) { + if ($has_new_support == false) { + $has_new_support = true; + } + } else { + $installed_support[$support] = $value['not_support']; + } + } + if (empty($has_new_support)) { + table('modules_cloud')->deleteByName($modulename); + } else { + $installed_support['install_status'] = MODULE_CLOUD_UNINSTALL; + table('modules_cloud')->fill($installed_support)->where('id', $module_cloud_upgrade['id'])->save(); + } + } + } + + if (!is_dir($path) || !file_exists($path . '/manifest.xml')) { + continue; + } + $manifest = ext_module_manifest($modulename); + $module_upgrade_data = array( + 'name' => $modulename, + 'has_new_version' => 0, + 'has_new_branch' => 0, + 'install_status' => MODULE_LOCAL_UNINSTALL, + 'logo' => $manifest['application']['logo'], + 'version' => $manifest['application']['version'], + 'title' => $manifest['application']['name'], + 'title_initial' => get_first_pinyin($manifest['application']['name']), + ); + + if (!empty($manifest['platform']['supports'])) { + foreach (array('app', 'wxapp', 'webapp', 'android', 'ios', 'system_welcome', 'aliapp', 'baiduapp', 'toutiaoapp') as $support) { + if (in_array($support, $manifest['platform']['supports'])) { + if ($support == 'app') { + $support = 'account'; + } + if ($support == 'system_welcome') { + $support = 'welcome'; + } + if ($support == 'android' || $support == 'ios') { + $support = 'phoneapp'; + } + $module_upgrade_data["{$support}_support"] = MODULE_SUPPORT_ACCOUNT; + } + } + } + + if (!empty($modulelist[$modulename])) { + $new_support = module_check_notinstalled_support($modulelist[$modulename], $manifest['platform']['supports']); + if (!empty($new_support)) { + $module_upgrade_data = array_merge($module_upgrade_data, $new_support); + } else { + table('modules_cloud')->deleteByName($modulename); + continue; + } + } + + if (!empty($module_recycle_info)) { + foreach ($module_support_type as $support => $value) { + if ($module_recycle_info[$support] == 1) { + $module_upgrade_data[$support] = $value['not_support']; + } + } + } + $module_cloud_upgrade = table('modules_cloud')->getByName($modulename); + if (empty($module_cloud_upgrade)) { + table('modules_cloud')->fill($module_upgrade_data)->save(); + } else { + table('modules_cloud')->fill($module_upgrade_data)->where('name', $modulename)->save(); + } + } + return true; +} + + +function cache_build_proxy_wechatpay_account() +{ + global $_W; + load()->model('account'); + $account_table = table('account'); + if ($_W['isadmin']) { + $uniaccounts = pdo_getall('account', array('type IN ' => array(ACCOUNT_TYPE_OFFCIAL_NORMAL, ACCOUNT_TYPE_OFFCIAL_AUTH))); + } else { + $uniaccounts = $account_table->userOwnedAccount($_W['uid']); + } + $service = array(); + $borrow = array(); + if (!empty($uniaccounts)) { + foreach ($uniaccounts as $uniaccount) { + if (!in_array($uniaccount['type'], array(ACCOUNT_TYPE_OFFCIAL_NORMAL, ACCOUNT_TYPE_OFFCIAL_AUTH))) { + continue; + } + $account = uni_fetch($uniaccount['uniacid']); + $payment = (array)$account['setting']['payment']; + if (!empty($account['key']) && !empty($account['secret']) && in_array($account['level'], array(4)) && + is_array($payment) && !empty($payment) && intval($payment['wechat']['switch']) == 1) { + if ((!is_bool($payment['wechat']['switch']) && $payment['wechat']['switch'] != 4) || (is_bool($payment['wechat']['switch']) && !empty($payment['wechat']['switch']))) { + $borrow[$account['uniacid']] = $account['name']; + } + } + if (!empty($payment['wechat_facilitator']['switch'])) { + $service[$account['uniacid']] = $account['name']; + } + } + } + $cache = array( + 'service' => $service, + 'borrow' => $borrow + ); + cache_write(cache_system_key('proxy_wechatpay_account'), $cache); + return $cache; +} + + +function cache_build_module_info($module_name) +{ + global $_W; + table('modules_cloud')->deleteByName($module_name); + cache_delete(cache_system_key('module_info', array('module_name' => $module_name))); +} + + +function cache_build_uni_group() +{ + $uni_group_cache_key = cache_system_key('uni_groups', array()); + $cache_keys = cache_search($uni_group_cache_key); + if (!empty($cache_keys)) { + foreach ($cache_keys as $cache_key => $cache_value) { + cache_delete($cache_key); + } + } +} + + +function cache_random($length = 4, $direct_write = false) +{ + $cachekey = cache_system_key('random'); + $cache = cache_load($cachekey); + if ($cache && !$direct_write) { + return $cache; + } + $result = random($length); + cache_write($cachekey, $result, CACHE_EXPIRE_MIDDLE); + return $result; +} + +function cache_updatecache() +{ + $account_ticket_cache = cache_read(cache_system_key('account_ticket')); + pdo_delete('core_cache'); + cache_clean(); + cache_write(cache_system_key('account_ticket'), $account_ticket_cache); + + setting_save(array(), 'cloudip'); + cache_build_template(); + cache_build_users_struct(); + cache_build_setting(); + cache_build_module_subscribe_type(); + rmdirs(IA_ROOT . '/data/patch/upgrade/'); + rmdirs(IA_ROOT . '/data/tpl/web/'); + rmdirs(IA_ROOT . '/data/tpl/app/'); + $path = IA_ROOT . '/data/'; + if ($dir = opendir($path)) { + while (false !== ($file = readdir($dir))) { + if (is_file($path . '/' . $file) && (strpos($file, 'application.build') === 0) || strpos($file, 'module.info') === 0) { + @unlink($path . '/' . $file); + } + } + } + pdo_delete('modules_cloud'); + return true; +} diff --git a/framework/model/extension.mod.php b/framework/model/extension.mod.php new file mode 100644 index 0000000..c36c0e3 --- /dev/null +++ b/framework/model/extension.mod.php @@ -0,0 +1,698 @@ + $manifest['application']['identifie'], + 'title' => $manifest['application']['name'], + 'version' => $manifest['application']['version'], + 'type' => $manifest['application']['type'], + 'ability' => $manifest['application']['ability'], + 'description' => $manifest['application']['description'], + 'author' => $manifest['application']['author'], + 'url' => $manifest['application']['url'], + 'settings' => intval($manifest['application']['setting']), + 'subscribes' => iserializer(is_array($manifest['platform']['subscribes']) ? $manifest['platform']['subscribes'] : array()), + 'handles' => iserializer(is_array($manifest['platform']['handles']) ? $manifest['platform']['handles'] : array()), + 'isrulefields' => intval($manifest['platform']['isrulefields']), + 'iscard' => intval($manifest['platform']['iscard']), + 'oauth_type' => $manifest['platform']['oauth_type'], + 'page' => $manifest['bindings']['page'], + 'cover' => $manifest['bindings']['cover'], + 'rule' => $manifest['bindings']['rule'], + 'menu' => $manifest['bindings']['menu'], + 'home' => $manifest['bindings']['home'], + 'profile' => $manifest['bindings']['profile'], + 'system_welcome' => $manifest['bindings']['system_welcome'], + 'webapp' => $manifest['bindings']['webapp'], + 'phoneapp' => $manifest['bindings']['phoneapp'], + MODULE_SUPPORT_ACCOUNT_NAME => $app_support, + 'wxapp_support' => $wxapp_support, + 'webapp_support' => $webapp_support, + 'phoneapp_support' => $phoneapp_support, + 'aliapp_support' => $aliapp_support, + 'baiduapp_support' => $baiduapp_support, + 'toutiaoapp_support' => $toutiaoapp_support, + 'welcome_support' => $welcome_support, + 'shortcut' => $manifest['bindings']['shortcut'], + 'function' => $manifest['bindings']['function'], + 'permissions' => $manifest['permissions'], + 'issystem' => 0, + 'application_type' => 1 + ); +} + + +function ext_module_manifest_parse($xml) { + if (!strexists($xml, 'loadXML($xml); + $root = $dom->getElementsByTagName('manifest')->item(0); + if (empty($root)) { + return array(); + } + $vcode = explode(',', $root->getAttribute('versionCode')); + $manifest['versions'] = array(); + if (is_array($vcode)) { + foreach ($vcode as $v) { + $v = trim($v); + if (!empty($v)) { + $manifest['versions'][] = $v; + } + } + $manifest['versions'][] = '0.52'; + $manifest['versions'][] = '0.6'; + $manifest['versions'] = array_unique($manifest['versions']); + } + $manifest['install'] = $root->getElementsByTagName('install')->item(0)->textContent; + $manifest['uninstall'] = $root->getElementsByTagName('uninstall')->item(0)->textContent; + $manifest['upgrade'] = $root->getElementsByTagName('upgrade')->item(0)->textContent; + $application = $root->getElementsByTagName('application')->item(0); + if (empty($application)) { + return array(); + } + $manifest['application'] = array( + 'name' => trim($application->getElementsByTagName('name')->item(0)->textContent), + 'identifie' => trim($application->getElementsByTagName('identifie')->item(0)->textContent), + 'version' => trim($application->getElementsByTagName('version')->item(0)->textContent), + 'type' => trim($application->getElementsByTagName('type')->item(0)->textContent), + 'ability' => trim($application->getElementsByTagName('ability')->item(0)->textContent), + 'description' => trim($application->getElementsByTagName('description')->item(0)->textContent), + 'author' => trim($application->getElementsByTagName('author')->item(0)->textContent), + 'url' => trim($application->getElementsByTagName('url')->item(0)->textContent), + 'setting' => trim($application->getAttribute('setting')) == 'true', + ); + $platform = $root->getElementsByTagName('platform')->item(0); + if (!empty($platform)) { + $manifest['platform'] = array( + 'subscribes' => array(), + 'handles' => array(), + 'isrulefields' => false, + 'iscard' => false, + 'supports' => array(), + 'oauth_type' => OAUTH_TYPE_BASE, + ); + $subscribes = $platform->getElementsByTagName('subscribes')->item(0); + if (!empty($subscribes)) { + $messages = $subscribes->getElementsByTagName('message'); + for ($i = 0; $i < $messages->length; $i++) { + $t = $messages->item($i)->getAttribute('type'); + if (!empty($t)) { + $manifest['platform']['subscribes'][] = $t; + } + } + } + $handles = $platform->getElementsByTagName('handles')->item(0); + if (!empty($handles)) { + $messages = $handles->getElementsByTagName('message'); + for ($i = 0; $i < $messages->length; $i++) { + $t = $messages->item($i)->getAttribute('type'); + if (!empty($t)) { + $manifest['platform']['handles'][] = $t; + } + } + } + $rule = $platform->getElementsByTagName('rule')->item(0); + if (!empty($rule) && $rule->getAttribute('embed') == 'true') { + $manifest['platform']['isrulefields'] = true; + } + $card = $platform->getElementsByTagName('card')->item(0); + if (!empty($card) && $card->getAttribute('embed') == 'true') { + $manifest['platform']['iscard'] = true; + } + $oauth_type = $platform->getElementsByTagName('oauth')->item(0); + if (!empty($oauth_type) && $oauth_type->getAttribute('type') == OAUTH_TYPE_USERINFO) { + $manifest['platform']['oauth_type'] = OAUTH_TYPE_USERINFO; + } + $supports = $platform->getElementsByTagName('supports')->item(0); + if (!empty($supports)) { + $support_type = $supports->getElementsByTagName('item'); + for ($i = 0; $i < $support_type->length; $i++) { + $t = $support_type->item($i)->getAttribute('type'); + if (!empty($t)) { + $manifest['platform']['supports'][] = $t; + } + } + } + $plugins = $platform->getElementsByTagName('plugins')->item(0); + if (!empty($plugins)) { + $plugin_list = $plugins->getElementsByTagName('item'); + for ($i = 0; $i < $plugin_list->length; $i++) { + $plugin = $plugin_list->item($i)->getAttribute('name'); + if (!empty($plugin)) { + $manifest['platform']['plugin_list'][] = $plugin; + } + } + } + $plugin_main = $platform->getElementsByTagName('plugin-main')->item(0); + if (!empty($plugin_main)) { + $plugin_main = $plugin_main->getAttribute('name'); + if (!empty($plugin_main)) { + $manifest['platform']['main_module'] = $plugin_main; + } + } + } + $bindings = $root->getElementsByTagName('bindings')->item(0); + if (!empty($bindings)) { + $points = ext_module_bindings(); + if (!empty($points)) { + $ps = array_keys($points); + $manifest['bindings'] = array(); + foreach ($ps as $p) { + $define = $bindings->getElementsByTagName($p)->item(0); + $manifest['bindings'][$p] = _ext_module_manifest_entries($define); + } + } + } + $permissions = $root->getElementsByTagName('permissions')->item(0); + if (!empty($permissions)) { + $manifest['permissions'] = array(); + $items = $permissions->getElementsByTagName('entry'); + for ($i = 0; $i < $items->length; $i++) { + $item = $items->item($i); + $row = array( + 'title' => $item->getAttribute('title'), + 'permission' => $item->getAttribute('do'), + ); + if (!empty($row['title']) && !empty($row['permission'])) { + $manifest['permissions'][] = $row; + } + } + } + return $manifest; +} + + +function ext_module_manifest($modulename) { + $root = IA_ROOT . '/addons/' . $modulename; + $filename = $root . '/manifest.xml'; + if (!file_exists($filename)) { + return array(); + } + $xml = file_get_contents($filename); + $xml = ext_module_manifest_parse($xml); + + if (!empty($xml)) { + $xml['application']['logo'] = tomedia($root . '/icon.jpg'); + if (file_exists($root . '/preview-custom.jpg')) { + $xml['application']['preview'] = tomedia($root . '/preview-custom.jpg'); + } else { + $xml['application']['preview'] = tomedia($root . '/preview.jpg'); + } + if (empty($xml['platform']['supports'])) { + $xml['platform']['supports'][] = 'app'; + } + } + return $xml; +} + + +function _ext_module_manifest_entries($elm) { + $ret = array(); + if (!empty($elm)) { + $call = $elm->getAttribute('call'); + if (!empty($call)) { + $ret[] = array('call' => $call); + } + $entries = $elm->getElementsByTagName('entry'); + for ($i = 0; $i < $entries->length; $i++) { + $entry = $entries->item($i); + $direct = $entry->getAttribute('direct'); + $is_multilevel_menu = $entry->getAttribute('multilevel'); + $row = array( + 'title' => $entry->getAttribute('title'), + 'do' => $entry->getAttribute('do'), + 'direct' => !empty($direct) && $direct != 'false' ? true : false, + 'state' => $entry->getAttribute('state'), + 'icon' => $entry->getAttribute('icon'), + 'displayorder' => $entry->getAttribute('displayorder'), + 'multilevel' => !empty($is_multilevel_menu) && $is_multilevel_menu == 'true' ? true : false, + 'parent' => $entry->getAttribute('parent'), + ); + if (!empty($row['title']) && !empty($row['do'])) { + $ret[$row['do']] = $row; + } + } + } + return $ret; +} + + +function ext_module_bindings() { + static $bindings = array( + 'cover' => array( + 'name' => 'cover', + 'title' => '功能封面', + 'desc' => '功能封面是定义微站里一个独立功能的入口(手机端操作), 将呈现为一个图文消息, 点击后进入微站系统中对应的功能.' + ), + 'rule' => array( + 'name' => 'rule', + 'title' => '规则列表', + 'desc' => '规则列表是定义可重复使用或者可创建多次的活动的功能入口(管理后台Web操作), 每个活动对应一条规则. 一般呈现为图文消息, 点击后进入定义好的某次活动中.' + ), + 'menu' => array( + 'name' => 'menu', + 'title' => '管理中心导航菜单', + 'desc' => '管理中心导航菜单将会在管理中心生成一个导航入口(管理后台Web操作), 用于对模块定义的内容进行管理.' + ), + 'home' => array( + 'name' => 'home', + 'title' => '微站首页导航图标', + 'desc' => '在微站的首页上显示相关功能的链接入口(手机端操作), 一般用于通用功能的展示.' + ), + 'profile'=> array( + 'name' => 'profile', + 'title' => '微站个人中心导航', + 'desc' => '在微站的个人中心上显示相关功能的链接入口(手机端操作), 一般用于个人信息, 或针对个人的数据的展示.' + ), + 'shortcut'=> array( + 'name' => 'shortcut', + 'title' => '微站快捷功能导航', + 'desc' => '在微站的快捷菜单上展示相关功能的链接入口(手机端操作), 仅在支持快捷菜单的微站模块上有效.' + ), + 'function'=> array( + 'name' => 'function', + 'title' => '微站独立功能', + 'desc' => '需要特殊定义的操作, 一般用于将指定的操作指定为(direct). 如果一个操作没有在具体位置绑定, 但是需要定义为(direct: 直接访问), 可以使用这个嵌入点' + ), + 'page'=> array( + 'name' => 'page', + 'title' => '小程序入口', + 'desc' => '用于小程序入口的链接' + ), + 'system_welcome' => array( + 'name' => 'system_welcome', + 'title' => '系统首页导航菜单', + 'desc' => '系统首页导航菜单将会在管理中心生成一个导航入口, 用于对系统首页定义的内容进行管理.', + ), + 'webapp' => array( + 'name' => 'webapp', + 'title' => 'PC入口', + 'desc' => '用于PC入口的链接', + ), + 'phoneapp' => array( + 'name' => 'phoneapp', + 'title' => 'APP入口', + 'desc' => '用于APP入口的链接', + ) + ); + return $bindings; +} + + +function ext_module_clean($modulename, $is_clean_rule = false) { + pdo_delete('core_queue', array('module' => $modulename)); + + table('modules')->deleteByName($modulename); + table('modules_bindings')->deleteByName($modulename); + pdo_delete('modules_plugin', array('main_module' => $modulename)); + + if ($is_clean_rule) { + pdo_delete('rule', array('module' => $modulename)); + pdo_delete('rule_keyword', array('module' => $modulename)); + + $cover_list = pdo_getall('cover_reply', array('module' => $modulename), array('rid'), 'rid'); + if (!empty($cover_list)) { + $rids = array_keys($cover_list); + pdo_delete('rule_keyword', array('module' => 'cover', 'rid' => $rids)); + pdo_delete('rule', array('module' => 'cover', 'id' => $rids)); + pdo_delete('cover_reply', array('module' => $modulename)); + } + } + + pdo_delete('site_nav', array('module' => $modulename)); + pdo_delete('uni_account_modules', array('module' => $modulename)); + pdo_delete('users_permission', array('type' => $modulename)); + + table('modules_recycle')->deleteByName($modulename); + $uni_group = pdo_getall('uni_group'); + if (!empty($uni_group)) { + foreach ($uni_group as $group) { + $update = false; + $modules = (array)iunserializer($group['modules']); + if (!empty($modules)) { + foreach ($modules as $type => $value) { + if (!empty($value) && in_array($modulename, $value)) { + $modules[$type] = array_diff($modules[$type], array($modulename)); + $update = true; + } + } + if ($update) { + pdo_update('uni_group', array('modules' => iserializer($modules)), array('id' => $group['id'])); + } + } + } + } + $uni_account_extra_modules = table('uni_account_extra_modules')->getall(); + if (!empty($uni_account_extra_modules)) { + foreach ($uni_account_extra_modules as $group) { + $update = false; + $modules = (array)iunserializer($group['modules']); + if (!empty($modules)) { + foreach ($modules as $type => $value) { + if (!empty($value) && in_array($modulename, $value)) { + $modules[$type] = array_diff($modules[$type], array($modulename)); + $update = true; + } + } + if ($update) { + pdo_update('uni_account_extra_modules', array('modules' => iserializer($modules)), array('id' => $group['id'])); + } + } + } + } + return true; +} + + +function ext_template_manifest($tpl, $cloud = true) { + $filename = IA_ROOT . '/app/themes/' . $tpl . '/manifest.xml'; + if (!file_exists($filename)) { + if ($cloud) { + load()->model('cloud'); + $manifest = cloud_t_info($tpl); + } + return is_error($manifest) ? array() : $manifest; + } + $manifest = ext_template_manifest_parse(file_get_contents($filename)); + if (empty($manifest['name']) || $manifest['name'] != $tpl) { + return array(); + } + return $manifest; +} + + +function ext_template_manifest_parse($xml) { + $xml = str_replace(array('&'), array('&'), $xml); + $xml = @isimplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA); + if (empty($xml)) { + return array(); + } + $manifest['name'] = strval($xml->identifie); + $manifest['title'] = strval($xml->title); + if (empty($manifest['title'])) { + return array(); + } + $manifest['type'] = !empty($xml->type) ? strval($xml->type) : 'other'; + $manifest['description'] = strval($xml->description); + $manifest['author'] = strval($xml->author); + $manifest['url'] = strval($xml->url); + if (isset($xml->sections)) { + $manifest['sections'] = strval($xml->sections); + } + if ($xml->settings->item) { + foreach ($xml->settings->item as $msg) { + $attrs = $msg->attributes(); + $manifest['settings'][] = array('key' => trim(strval($attrs['variable'])), 'value' => trim(strval($attrs['content'])), 'desc' => trim(strval($attrs['description']))); + } + } + return $manifest; +} + + +function ext_template_type() { + static $types = array( + 'often' => array( + 'name' => 'often', + 'title' => '常用模板', + ), + 'rummery' => array( + 'name' => 'rummery', + 'title' => '酒店', + ), + 'car' => array( + 'name' => 'car', + 'title' => '汽车', + ), + 'tourism' => array( + 'name' => 'tourism', + 'title' => '旅游', + ), + 'drink' => array( + 'name' => 'drink', + 'title' => '餐饮', + ), + 'realty' => array( + 'name' => 'realty', + 'title' => '房地产', + ), + 'medical' => array( + 'name' => 'medical', + 'title' => '医疗保健' + ), + 'education' => array( + 'name' => 'education', + 'title' => '教育' + ), + 'cosmetology' => array( + 'name' => 'cosmetology', + 'title' => '健身美容' + ), + 'shoot' => array( + 'name' => 'shoot', + 'title' => '婚纱摄影' + ), + 'other' => array( + 'name' => 'other', + 'title' => '其它行业' + ) + ); + return $types; +} + + + +function ext_module_script_clean($modulename, $manifest) { + $moduleDir = IA_ROOT . '/addons/' . $modulename . '/'; + $manifest['install'] = trim($manifest['install']); + $manifest['uninstall'] = trim($manifest['uninstall']); + $manifest['upgrade'] = trim($manifest['upgrade']); + if (strexists($manifest['install'], '.php')) { + if (file_exists($moduleDir . $manifest['install'])) { + unlink($moduleDir . $manifest['install']); + } + } + if (strexists($manifest['uninstall'], '.php')) { + if (file_exists($moduleDir . $manifest['uninstall'])) { + unlink($moduleDir . $manifest['uninstall']); + } + } + if (strexists($manifest['upgrade'], '.php')) { + if (file_exists($moduleDir . $manifest['upgrade'])) { + unlink($moduleDir . $manifest['upgrade']); + } + } + if (file_exists($moduleDir . 'manifest.xml')) { + unlink($moduleDir . 'manifest.xml'); + } +} + + +function ext_module_msg_types() { + $mtypes = array(); + $mtypes['text'] = '文本消息(重要)'; + $mtypes['image'] = '图片消息'; + $mtypes['voice'] = '语音消息'; + $mtypes['video'] = '视频消息'; + $mtypes['shortvideo'] = '小视频消息'; + $mtypes['location'] = '位置消息'; + $mtypes['link'] = '链接消息'; + $mtypes['subscribe'] = '粉丝开始关注'; + $mtypes['unsubscribe'] = '粉丝取消关注'; + $mtypes['qr'] = '扫描二维码'; + $mtypes['trace'] = '追踪地理位置'; + $mtypes['click'] = '点击菜单(模拟关键字)'; + $mtypes['view'] = '点击菜单(链接)'; + $mtypes['merchant_order'] = '微小店消息'; + $mtypes['user_get_card'] = '用户领取卡券事件'; + $mtypes['user_del_card'] = '用户删除卡券事件'; + $mtypes['user_consume_card'] = '用户核销卡券事件'; + $mtypes['user_view_card'] = '进入会员卡事件'; + $mtypes['user_gifting_card'] = '用户转赠卡券事件'; + return $mtypes; +} + + +function ext_check_module_subscribe($modulename) { + global $_W, $_GPC; + if (empty($modulename)) { + return true; + } + if (!is_array($_W['setting']['module_receive_ban'])) { + $_W['setting']['module_receive_ban'] = array(); + } + load()->func('communication'); + $response = ihttp_request($_W['siteroot'] . 'web/' . url('utility/modules/check_receive', array('module_name' => $modulename))); + $response['content'] = json_decode($response['content'], true); + if (empty($response['content']['message']['errno'])) { + unset($_W['setting']['module_receive_ban'][$modulename]); + $module_subscribe_success = true; + } else { + $_W['setting']['module_receive_ban'][$modulename] = $modulename; + $module_subscribe_success = false; + } + setting_save($_W['setting']['module_receive_ban'], 'module_receive_ban'); + return $module_subscribe_success; +} + + +function ext_manifest_check($module_name, $manifest) { + if(is_string($manifest)) { + return error(1, '模块 mainfest.xml 配置文件有误, 具体错误内容为:
' . $manifest); + } + $error_msg = ''; + if(empty($manifest['application']['name'])) { + $error_msg .= '
<application><name>名称节点不能为空'; + } + if(empty($manifest['application']['identifie']) || !preg_match('/^[a-z][a-z\d_]+$/i', $manifest['application']['identifie'])) { + $error_msg .= '
<application><identifie>标识符节点不能为空或格式错误(仅支持字母和数字, 且只能以字母开头)'; + } elseif(strtolower($module_name) != strtolower($manifest['application']['identifie'])) { + $error_msg .= '
<application><identifie>标识符节点与模块路径名称定义不匹配'; + } + if(empty($manifest['application']['version']) || !preg_match('/^[\d\.]+$/i', $manifest['application']['version'])) { + $error_msg .= '
<application><version>版本号节点未定义或格式不正确(仅支持数字和句点)'; + } + if(empty($manifest['application']['ability'])) { + $error_msg .= '
<application><ability>功能简述节点不能为空'; + } + if($manifest['platform']['isrulefields'] && !in_array('text', $manifest['platform']['handles'])) { + $error_msg .= '
模块功能定义错误, 嵌入规则必须要能够处理文本类型消息'; + } + if((!empty($manifest['cover']) || !empty($manifest['rule'])) && !$manifest['platform']['isrulefields']) { + $error_msg .= '
模块功能定义错误, 存在封面或规则功能入口绑定时, 必须要嵌入规则'; + } + global $points; + if (!empty($points)) { + foreach($points as $name => $point) { + if(is_array($manifest[$name])) { + foreach($manifest[$name] as $menu) { + if(trim($menu['title']) == '' || !preg_match('/^[a-z\d]+$/i', $menu['do']) && empty($menu['call'])) { + $error_msg .= "
<$name>节点" . $point['title'] . ' 扩展项功能入口定义错误, (操作标题[title], 入口方法[do])格式不正确.'; + } + } + } + } + } + if(is_array($manifest['permissions']) && !empty($manifest['permissions'])) { + foreach($manifest['permissions'] as $permission) { + if(trim($permission['title']) == '' || !preg_match('/^[a-z\d_]+$/i', $permission['permission'])) { + $error_msg .= '
' . "<permissions>节点名称为: {$permission['title']} 的权限标识格式不正确,请检查标识名称或标识格式是否正确"; + } + } + } + if(!is_array($manifest['versions'])) { + $error_msg .= '
<versions>节点兼容版本格式错误'; + } + if (!empty($error_msg)) { + return error(-1, '模块 mainfest.xml 配置文件有误
' . $error_msg); + } + return error(0); +} + +function ext_file_check($module_name, $manifest) { + $module_path = IA_ROOT . '/addons/' . $module_name . '/'; + if (empty($manifest['platform']['main_module']) && + !file_exists($module_path . 'processor.php') && + !file_exists($module_path . 'module.php') && + !file_exists($module_path . 'site.php')) { + return error(1, '模块缺失文件,请检查模块文件中site.php, processor.php, module.php, receiver.php 文件是否存在!'); + } + return true; +} + + +function ext_execute_uninstall_script($module_name) { + global $_W; + load()->model('cloud'); + $modulepath = IA_ROOT . '/addons/' . $module_name . '/'; + $manifest = ext_module_manifest($module_name); + if (empty($manifest)) { + $result = cloud_prepare(); + if (is_error($result)) { + return error(1, $result['message']); + } + $packet = cloud_m_build($module_name, 'uninstall'); + if ($packet['sql']) { + pdo_run(base64_decode($packet['sql'])); + } elseif ($packet['script']) { + $uninstall_file = $modulepath . TIMESTAMP . '.php'; + file_put_contents($uninstall_file, base64_decode($packet['script'])); + require($uninstall_file); + unlink($uninstall_file); + } + } else { + if (!empty($manifest['uninstall'])) { + if (strexists($manifest['uninstall'], '.php')) { + if (file_exists($modulepath . $manifest['uninstall'])) { + require($modulepath . $manifest['uninstall']); + } + } else { + pdo_run($manifest['uninstall']); + } + } + } + return true; +} + +function ext_module_run_script($manifest, $scripttype) { + if (!in_array($scripttype, array('install', 'upgrade'))) { + return false; + } + $modulename = $manifest['application']['identifie']; + $module_path = IA_ROOT . '/addons/' . $modulename . '/'; + if (!empty($manifest[$scripttype])) { + if (strexists($manifest[$scripttype], '.php')) { + if (file_exists($module_path . $manifest[$scripttype])) { + include_once $module_path . $manifest[$scripttype]; + } + } else { + pdo_run($manifest[$scripttype]); + } + } + + if (defined('ONLINE_MODULE')) { + ext_module_script_clean($modulename, $manifest); + } + return true; +} \ No newline at end of file diff --git a/framework/model/index.html b/framework/model/index.html new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/framework/model/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/framework/model/material.mod.php b/framework/model/material.mod.php new file mode 100644 index 0000000..2fed457 --- /dev/null +++ b/framework/model/material.mod.php @@ -0,0 +1,670 @@ +func('file'); + + +function material_sync($material, $exist_material, $type) { + global $_W; + $material = empty($material) ? array() : $material; + foreach ($material as $news) { + $attachid = ''; + $material_exist = pdo_get('wechat_attachment', array('uniacid' => $_W['uniacid'], 'media_id' => $news['media_id'])); + if (empty($material_exist)) { + $material_data = array( + 'uniacid' => $_W['uniacid'], + 'acid' => $_W['acid'], + 'media_id' => $news['media_id'], + 'type' => $type, + 'model' => 'perm', + 'createtime' => $news['update_time'] + ); + if ($type == 'image') { + $material_data['filename'] = $news['name']; + $material_data['attachment'] = $news['url']; + } + if ($type == 'voice') { + $material_data['filename'] = $news['name']; + } + if ($type == 'video') { + $material_data['tag'] = iserializer(array('title' => $news['name'])); + } + pdo_insert('wechat_attachment', $material_data); + $attachid = pdo_insertid(); + } else { + if ($type == 'image') { + $material_data = array( + 'createtime' => $news['update_time'], + 'attachment' => $news['url'], + 'filename' => $news['name'] + ); + pdo_update('wechat_attachment', $material_data, array('uniacid' => $_W['uniacid'], 'media_id' => $news['media_id'])); + } + if ($type == 'voice') { + $material_data = array( + 'createtime' => $news['update_time'], + 'filename' => $news['name'] + ); + pdo_update('wechat_attachment', $material_data, array('uniacid' => $_W['uniacid'], 'media_id' => $news['media_id'])); + } + if ($type == 'video') { + $tag = empty($material_exist['tag']) ? array() : iunserializer($material_exist['tag']); + $material_data = array( + 'createtime' => $news['update_time'], + 'tag' => iserializer(array('title' => $news['name'], 'url' => $tag['url'])) + ); + pdo_update('wechat_attachment', $material_data, array('uniacid' => $_W['uniacid'], 'media_id' => $news['media_id'])); + } + $exist_material[] = $material_exist['id']; + } + if ($type == 'news') { + $attachid = empty($attachid) ? $material_exist['id'] : $attachid; + pdo_delete('wechat_news', array('uniacid' =>$_W['uniacid'], 'attach_id' => $attachid)); + foreach ($news['content']['news_item'] as $key => $new) { + $new_data = array( + 'uniacid' => $_W['uniacid'], + 'attach_id' => $attachid, + 'thumb_media_id' => $new['thumb_media_id'], + 'thumb_url' => $new['thumb_url'], + 'title' => $new['title'], + 'author' => $new['author'], + 'digest' => $new['digest'], + 'content' => $new['content'], + 'content_source_url' => $new['content_source_url'], + 'show_cover_pic' => $new['show_cover_pic'], + 'url' => $new['url'], + 'displayorder' => $key, + ); + pdo_insert('wechat_news', $new_data); + } + pdo_update('wechat_attachment', array('createtime' => $news['update_time']), array('media_id' => $news['media_id'])); + } + } + return $exist_material; +} + + +function material_news_set($data, $attach_id) { + global $_W; + $attach_id = intval($attach_id); + foreach ($data as $key => $news) { + if (empty($news['title']) || + (!empty($news['thumb']) && !parse_path($news['thumb'])) || + (!empty($news['url']) && !parse_path($news['url'])) || + (!empty($news['content_source_url']) && !parse_path($news['content_source_url'])) + ) { + return error('-1', '参数有误'); + } + if (!material_url_check($news['content_source_url']) || !material_url_check($news['url']) || !material_url_check($news['thumb'])) { + return error('-3', '提交链接参数不合法'); + } + $post_news[] = array( + 'id' => intval($news['id']), + 'uniacid' => $_W['uniacid'], + 'thumb_url' => $news['thumb'], + 'title' => addslashes($news['title']), + 'author' => addslashes($news['author']), + 'digest' => addslashes($news['digest']), + 'content' => safe_gpc_html(htmlspecialchars_decode($news['content'])), + 'url' => $news['url'], + 'show_cover_pic' => intval($news['show_cover_pic']), + 'displayorder' => intval($key), + 'thumb_media_id' => addslashes($news['media_id']), + 'content_source_url' => $news['content_source_url'], + ); + } + if (!empty($attach_id)){ + $wechat_attachment = pdo_get('wechat_attachment', array( + 'id' => $attach_id, + 'uniacid' => $_W['uniacid'] + )); + if (empty($wechat_attachment)){ + return error('-2', '编辑素材不存在'); + } + $wechat_attachment['model'] = 'local'; + pdo_update('wechat_attachment', $wechat_attachment, array('id' => $attach_id, 'uniacid' => $_W['uniacid'])); + pdo_delete('wechat_news', array('attach_id' => $attach_id, 'uniacid' => $_W['uniacid'])); + foreach ($post_news as $id => $news) { + $news['attach_id'] = $attach_id; + unset($news['id']); + pdo_insert('wechat_news', $news); + } + cache_delete(cache_system_key('material_reply', array('attach_id' => $attach_id))); + } else { + $wechat_attachment = array( + 'uniacid' => $_W['uniacid'], + 'acid' => $_W['acid'], + 'media_id' => '', + 'type' => 'news', + 'model' => 'local', + 'createtime' => TIMESTAMP + ); + pdo_insert('wechat_attachment', $wechat_attachment); + $attach_id = pdo_insertid(); + foreach ($post_news as $key => $news) { + $news['attach_id'] = $attach_id; + pdo_insert('wechat_news', $news); + } + } + return $attach_id; +} + + +function material_get($attach_id) { + if (empty($attach_id)) { + return error(1, "素材id参数不能为空"); + } + if (is_numeric($attach_id)) { + $material = table('wechat_attachment')->getById($attach_id); + } else { + $media_id = trim($attach_id); + $material = table('wechat_attachment')->getByMediaId($media_id); + } + if (!empty($material)) { + if ($material['type'] == 'news') { + $news = table('wechat_news')->getAllByAttachId($material['id']); + if (!empty($news)) { + foreach ($news as &$news_row) { + $news_row['content_source_url'] = $news_row['content_source_url']; + $news_row['thumb_url'] = tomedia($news_row['thumb_url']); + preg_match_all('/src=[\'\"]?([^\'\"]*)[\'\"]?/i', $news_row['content'], $match); + if (!empty($match[1])) { + foreach ($match[1] as $val) { + if ((strexists($val, 'http://') || strexists($val, 'https://')) && (strexists($val, 'mmbiz.qlogo.cn') || strexists($val, 'mmbiz.qpic.cn'))) { + $news_row['content'] = str_replace($val, tomedia($val), $news_row['content']); + } + } + } + $news_row['content'] = str_replace('data-src', 'src', $news_row['content']); + } + unset($news_row); + } else { + return error('1', '素材不存在'); + } + $material['news'] = $news; + } elseif ($material['type'] == 'image') { + $material['url'] = $material['attachment']; + $material['attachment'] = tomedia($material['attachment']); + + } + return $material; + } else { + return error('1', "素材不存在"); + } +} + + +function material_build_reply($attach_id) { + if (empty($attach_id)) { + return error(1, "素材id参数不能为空"); + } + $cachekey = cache_system_key('material_reply', array('attach_id' => $attach_id)); + $reply = cache_load($cachekey); + if (!empty($reply)) { + return $reply; + } + $reply_material = material_get($attach_id); + $reply = array(); + if ($reply_material['type'] == 'news') { + if (!empty($reply_material['news'])) { + foreach ($reply_material['news'] as $material) { + $reply[] = array( + 'title' => $material['title'], + 'description' => $material['digest'], + 'picurl' => $material['thumb_url'], + 'url' => !empty($material['content_source_url']) ? $material['content_source_url'] : $material['url'], + ); + } + } + } + cache_write($cachekey, $reply, CACHE_EXPIRE_MIDDLE); + return $reply; +} + + +function material_strip_wechat_image_proxy($content) { + global $_W; + $match_wechat = array(); + $content = htmlspecialchars_decode($content); + preg_match_all ('//iU', $content, $match_wechat); + if (!empty($match_wechat[1])) { + foreach ($match_wechat[1] as $val) { + $wechat_thumb_url = urldecode(str_replace($_W['siteroot'] . 'web/index.php?c=utility&a=wxcode&do=image&attach=', '', $val)); + $content = str_replace($val, $wechat_thumb_url, $content); + } + } + return $content; +} + + +function material_get_image_url($content) { + global $_W; + $content = htmlspecialchars_decode ($content); + $match = array (); + $images = array (); + preg_match_all ('//iU', $content, $match); + if (!empty($match[1])) { + foreach ($match[1] as $val) { + if ((strexists ($val, 'http://') || strexists ($val, 'https://')) && !strexists ($val, 'mmbiz.qlogo.cn') && !strexists ($val, 'mmbiz.qpic.cn')) { + $images[] = $val; + } else { + if (strexists ($val, './attachment/images/')) { + $images[] = tomedia ($val); + } + } + } + } + return $images; +} + + +function material_parse_content($content) { + global $_W; + $content = material_strip_wechat_image_proxy($content); + $images = material_get_image_url($content); + if (!empty($images)) { + foreach ($images as $image) { + $thumb = file_remote_attach_fetch(tomedia($image), 1024, 'material/images'); + if(is_error($thumb)) { + return $thumb; + } + $thumb = ATTACHMENT_ROOT . $thumb; + $account_api = WeAccount::createByUniacid(); + $result = $account_api->uploadNewsThumb($thumb); + if (is_error($result)) { + return $result; + } else { + $content = str_replace($image, $result, $content); + } + } + } + return $content; +} + +function material_local_news_upload($attach_id) { + global $_W; + $account_api = WeAccount::createByUniacid(); + $material = material_get($attach_id); + if (is_error($material)){ + return error('-1', '获取素材文件失败'); + } + $change_media_id = 0; + foreach ($material['news'] as $news) { + if (empty($news['content'])){ + return error('-6', '素材内容不能为空'); + } + $news['content'] = material_parse_content($news['content']); + if (!empty($news['content_source_url'])) { + $news['content_source_url'] = safe_gpc_url($news['content_source_url'], false, $_W['siteroot'] . 'app/' . $news['content_source_url']); + } + if (is_error($news['content'])) { + return error('-2', $news['content']['message']); + } + if (empty($news['thumb_media_id'])) { + if (empty($news['thumb_url'])){ + return error('-7', '图文封面不能为空'); + }else{ + $result = material_local_upload_by_url($news['thumb_url']); + if (is_error($result)){ + return error('-3', $result['message']); + } + $news['thumb_media_id'] = $result['media_id']; + $news['thumb_url'] = $result['url']; + } + } + pdo_update('wechat_news', $news, array('id' => $news['id'])); + + $articles['articles'][] = $news; + + if (!empty($material['media_id'])) { + $edit_attachment['media_id'] = $material['media_id']; + $edit_attachment['index'] = $news['displayorder']; + $edit_attachment['articles'] = $news; + $result = $account_api->editMaterialNews($edit_attachment); + if (is_error($result)) { + if ($result['errno'] == 40114) { $change_media_id = $material['media_id']; + break; + } else { + return error('-4', $result['message']); + } + } + } + } + + if (empty($material['media_id']) || $change_media_id) { + $media_id = $account_api->addMatrialNews($articles); + if (is_error($media_id)) { + return error('-5', $media_id, ''); + } + $material_info = $account_api->getMaterial($media_id, false); + if (!empty($material_info['news_item'])) { + foreach ($material_info['news_item'] as $key => $info) { + pdo_update('wechat_news', array('url' => $info['url']), array('uniacid' => $_W['uniacid'], 'attach_id' => $material['id'], 'displayorder' => $key)); + } + } + pdo_update('wechat_attachment', array( + 'media_id' => $media_id, + 'model' => 'perm' + ), array( + 'uniacid' => $_W['uniacid'], + 'id' => $attach_id + )); + if ($change_media_id) { + $account_api->delMaterial($change_media_id); + } + } else { + pdo_update('wechat_attachment', array('model' => 'perm'), array('uniacid' => $_W['uniacid'], 'id' => $attach_id)); + } + return $material; +} + +function material_local_upload_by_url($url, $type='images') { + global $_W; + $account_api = WeAccount::createByUniacid(); + if (! empty($_W['setting']['remote']['type'])) { + $remote_file_url = tomedia($url); + $filepath = file_remote_attach_fetch($remote_file_url,0,''); + if(is_error($filepath)) { + return $filepath; + } + $filepath = ATTACHMENT_ROOT . $filepath; + } else { + if (strexists(parse_url($url, PHP_URL_PATH), '/attachment/')) { + $url = substr(parse_url($url, PHP_URL_PATH), strpos(parse_url($url, PHP_URL_PATH), '/attachment/') + strlen('/attachment/')); + } + $filepath = ATTACHMENT_ROOT . $url; + } + $filesize = filesize($filepath); + $filesize = sizecount($filesize, true); + if ($filesize > 10 && $type == 'videos') { + return error(-1, '要转换的微信素材视频不能超过10M'); + } + return $account_api->uploadMediaFixed($filepath, $type); +} + + +function material_local_upload($material_id){ + global $_W; + $type_arr = array('1' => 'images', '2' => 'voices', '3' => 'videos'); + $material = pdo_get('core_attachment', array('uniacid' => $_W['uniacid'], 'id' => $material_id)); + if (empty($material)) { + return error('-1', '同步素材不存在或已删除'); + } + return material_local_upload_by_url($material['attachment'], $type_arr[$material['type']]); +} + + +function material_upload_limit() { + global $_W; + $default = 5 * 1024 * 1024; + $upload_limit = array( + 'num' => '30', + 'image' => $default, + 'voice' => $default, + 'video' => $default + ); + $upload = $_W['setting']['upload']; + if (isset($upload['image']['limit']) && (bytecount($upload['image']['limit'].'kb')>0)){ + $upload_limit['image'] = bytecount($upload['image']['limit'].'kb'); + } + if (isset($upload['image']['limit']) && (bytecount($upload['audio']['limit'].'kb')>0)){ + $upload_limit['voice'] = $upload_limit['video'] = bytecount($upload['audio']['limit'].'kb'); + } + return $upload_limit; +} + + +function material_news_delete($material_id){ + global $_W; + $permission = permission_account_user_menu($_W['uid'], $_W['uniacid'], 'system'); + if (is_error($permission)) { + return error(-1, $permission['message']); + } + if (empty($_W['isfounder']) && !empty($permission) && !in_array('platform_material', $permission) && !in_array('all', $permission)) { + return error('-1', '您没有权限删除该文件'); + } + $material_id = intval($material_id); + $material = pdo_get('wechat_attachment', array('uniacid' => $_W['uniacid'], 'id' => $material_id)); + if (empty($material)){ + return error('-2', '素材文件不存在或已删除'); + } + if (!empty($material['media_id'])){ + $account_api = WeAccount::createByUniacid(); + $result = $account_api->delMaterial($material['media_id']); + } + if (is_error($result)){ + return $result; + } + pdo_delete('wechat_news', array('uniacid' => $_W['uniacid'], 'attach_id' => $material_id)); + pdo_delete('wechat_attachment', array('uniacid' => $_W['uniacid'], 'id' => $material_id)); + return $result; +} + + +function material_delete($material_id, $location){ + global $_W; + if (empty($_W['isfounder']) && !permission_check_account_user('platform_material_delete')) { + return error('-1', '您没有权限删除该文件'); + } + $material_id = intval($material_id); + $table = $location == 'wechat' ? 'wechat_attachment' : 'core_attachment'; + $material = pdo_get($table, array('id' => $material_id)); + if (empty($material)){ + return error('-2', '素材文件不存在或已删除'); + } + if ($location == 'wechat' && !empty($material['media_id'])){ + $account_api = WeAccount::createByUniacid(); + $result = $account_api->delMaterial($material['media_id']); + } else { + if (!empty($material['uniacid'])) { + $role = permission_account_user_role($_W['uid'], $material['uniacid']); + if (in_array($role, array(ACCOUNT_MANAGE_NAME_OPERATOR, ACCOUNT_MANAGE_NAME_MANAGER)) && $_W['uid'] != $material['uid']) { + return error('-1', '您没有权限删除该文件'); + } + } elseif ($_W['uid'] != $material['uid']) { + return error('-1', '您没有权限删除该文件'); + } + if (!empty($_W['setting']['remote']['type'])) { + $result = file_remote_delete($material['attachment']); + if (file_exists(IA_ROOT . '/' . $_W['config']['upload']['attachdir'] . '/' . $material['attachment'])) { + $result = file_delete($material['attachment']); + } + } else { + $result = file_delete($material['attachment']); + } + } + if (is_error($result)) { + return error('-3', '删除文件操作发生错误'); + } + pdo_delete($table, array('id' => $material_id, 'uniacid' => $_W['uniacid'])); + return $result; +} + + +function material_url_check($url) { + if (empty($url)){ + return true; + } else { + $pattern ="/^((https|http|tel):\/\/|\.\/index.php)[^\s]+/i"; + return preg_match($pattern, trim($url)); + } +} + +function material_news_list($server = '', $search ='', $page = array('page_index' => 1, 'page_size' => 24)) { + global $_W; + $wechat_news_table = table('wechat_news'); + $wechat_attachment_table = table('wechat_attachment'); + $material_list = array(); + if (empty($search)) { + $wechat_attachment_table->searchWithUniacid($_W['uniacid']); + $wechat_attachment_table->searchWithType('news'); + if (!empty($server) && in_array($server, array('local', 'perm'))) { + $wechat_attachment_table->searchWithModel($server); + } + $wechat_attachment_table->searchWithPage($page['page_index'], $page['page_size']); + $news_list = $wechat_attachment_table->orderby('createtime DESC')->getall(); + $total = $wechat_attachment_table->getLastQueryTotal(); + + if (! empty($news_list)) { + foreach ($news_list as $news) { + $news['items'] = $wechat_news_table->getAllByAttachId($news['id']); + $material_list[$news['id']] = $news; + } + } + } else { + $wechat_news_table->searchKeyword("%$search%"); + $wechat_news_table->searchWithUniacid($_W['uniacid']); + $search_attach_id = $wechat_news_table->getall(); + + if (!empty($search_attach_id)) { + foreach ($search_attach_id as $news) { + if (isset($material_list[$news['attach_id']]) && !empty($material_list[$news['attach_id']])) { + continue; + } + $wechat_attachment = $wechat_attachment_table->getById($news['attach_id']); + if (empty($wechat_attachment)) { + continue; + } + $material_list[$news['attach_id']] = $wechat_attachment; + $material_list[$news['attach_id']]['items'] = $wechat_news_table->getAllByAttachId($news['attach_id']); + } + } + } + + foreach ($material_list as $key => &$news) { + if (isset($news['items']) && is_array($news['items'])) { + if (empty($news['items'][0])) { + $news['items'] = array_values($news['items']); + } + foreach ($news['items'] as &$item) { + $item['thumb_url'] = tomedia($item['thumb_url']); + } + } + } + unset($news_list); + $pager = pagination($total, $page['page_index'], $page['page_size'],'',$context = array('before' => 5, 'after' => 4, 'isajax' => $_W['isajax'])); + $material_news = array('material_list' => $material_list, 'page' => $pager); + return $material_news; +} + +function material_list($type = '', $server = '', $page = array('page_index' => 1, 'page_size' => 24)) { + global $_W; + $tables = array(MATERIAL_LOCAL => 'core_attachment', MATERIAL_WEXIN => 'wechat_attachment'); + $conditions['uniacid'] = $_W['uniacid']; + $table = $tables[$server]; + switch ($type) { + case 'voice' : + $conditions['type'] = $server == MATERIAL_LOCAL ? ATTACH_TYPE_VOICE : 'voice'; + break; + case 'video' : + $conditions['type'] = $server == MATERIAL_LOCAL ? ATTACH_TYPE_VEDIO : 'video'; + break; + default : + $conditions['type'] = $server == MATERIAL_LOCAL ? ATTACH_TYPE_IMAGE : 'image'; + break; + } + if ($server == 'local') { + $material_list = pdo_getslice($table, $conditions, array($page['page_index'], $page['page_size']), $total, array(), '', 'createtime DESC'); + } else { + $conditions['model'] = MATERIAL_WEXIN; + $material_list = pdo_getslice($table, $conditions, array($page['page_index'], $page['page_size']), $total, array(), '', 'createtime DESC'); + if ($type == 'video'){ + foreach ($material_list as &$row) { + $row['tag'] = $row['tag'] == '' ? array() : iunserializer($row['tag']); + if (empty($row['filename'])) { + $row['filename'] = $row['tag']['title']; + } + } + unset($row); + } + } + $pager = pagination($total, $page['page_index'], $page['page_size'],'',$context = array('before' => 5, 'after' => 4, 'isajax' => $_W['isajax'])); + $material_news = array('material_list' => $material_list, 'page' => $pager); + return $material_news; +} + + + +function material_news_to_local($attach_id) { + $material = material_get($attach_id); + if(is_error($material)) { + return $material; + } + $attach_id = material_news_set($material['news'],$attach_id); + if(is_error($attach_id)) { + return $attach_id; + } + $material['items'] = $material['news']; return $material; +} + + +function material_to_local($resourceid, $uniacid, $uid, $type = 'image') { + $material = material_get($resourceid); + if(is_error($material)) { + return $material; + } + return material_network_image_to_local($material['url'], $uniacid, $uid); +} + + +function material_network_image_to_local($url, $uniacid, $uid) { + return material_network_to_local($url, $uniacid, $uid, 'image'); +} + + + +function material_network_to_local($url, $uniacid, $uid, $type = 'image') { + $path = file_remote_attach_fetch($url); if(is_error($path)) { + return $path; + } + $filename = pathinfo($path,PATHINFO_FILENAME); + $data = array('uniacid' => $uniacid, 'uid' => $uid, + 'filename' => $filename, + 'attachment' => $path, + 'type' => $type == 'image' ? ATTACH_TYPE_IMAGE : ($type == 'audio'||$type == 'voice' ? ATTACH_TYPE_VOICE : ATTACH_TYPE_VEDIO), + 'createtime'=>TIMESTAMP + ); + pdo_insert('core_attachment', $data); + $id = pdo_insertid(); + $data['id'] = $id; + $data['url'] = tomedia($path); + return $data; +} + + + +function material_to_wechat($attach_id, $uniacid, $uid, $acid, $type = 'image') { + $result = material_local_upload($attach_id); if (is_error($result)) { + return $result; + } + $tag = $result['url']; + if($type == 'video') { + $tag = serialize(array('title'=>'网络视频','description'=>'网络视频')); + } + $data = array('uniacid' => $uniacid, 'uid' => $uid, 'acid' => $acid, + 'media_id' => $result['media_id'], + 'attachment' => $result['url'], + 'type' => $type, + 'tag' => $tag, + 'model' => 'perm', + 'createtime'=>TIMESTAMP + ); + pdo_insert('wechat_attachment', $data); + $id = pdo_insertid(); + $data['url'] = tomedia($result['url']); + $data['id'] = $id; + return $data; +} + + + +function material_network_image_to_wechat($url, $uniacid, $uid, $acid) { + return material_network_to_wechat($url, $uniacid, $uid, $acid, 'image'); +} + + +function material_network_to_wechat($url, $uniacid, $uid, $acid, $type = 'image') { + $local = material_network_to_local($url, $uniacid, $uid, $type); if (is_error($local)) { + return $local; + } + return material_to_wechat($local['id'], $uniacid, $uid, $acid, $type); +} diff --git a/framework/model/mc.mod.php b/framework/model/mc.mod.php new file mode 100644 index 0000000..63a8a3f --- /dev/null +++ b/framework/model/mc.mod.php @@ -0,0 +1,2001 @@ + $birth[0], + 'month' => $birth[1], + 'day' => $birth[2], + ); + } + if (!empty($fields['birth'])) { + $fields['birthyear'] = $fields['birth']['year']; + $fields['birthmonth'] = $fields['birth']['month']; + $fields['birthday'] = $fields['birth']['day']; + } + if (isset($fields['reside'])) { + $fields['resideprovince'] = $fields['reside']['province']; + $fields['residecity'] = $fields['reside']['city']; + $fields['residedist'] = $fields['reside']['district']; + } + unset($fields['reside'], $fields['birth']); + foreach ($fields as $field => $value) { + if (!in_array($field, $struct) || is_array($value)) { + unset($fields[$field]); + } + } + if (!empty($fields['avatar'])) { + if (strexists($fields['avatar'], 'attachment/images/global/avatars/avatar_')) { + $fields['avatar'] = str_replace($_W['attachurl'], '', $fields['avatar']); + } + } + + $member = table('mc_members')->getById($uid); + if (!empty($fields['email'])) { + $mc_members = table('mc_members'); + $mc_members->searchWithUniacid(mc_current_real_uniacid()); + $mc_members->searchWithoutUid($uid); + $mc_members->searchWithEmail($fields['email']); + $emailexists = $mc_members->getcolumn('email'); + if ($emailexists) { + unset($fields['email']); + } + } + if (!empty($fields['mobile'])) { + $mc_members = table('mc_members'); + $mc_members->searchWithUniacid(mc_current_real_uniacid()); + $mc_members->searchWithoutUid($uid); + $mc_members->searchWithEmail($fields['mobile']); + $mobilexists = $mc_members->getcolumn('mobile'); + if ($mobilexists) { + unset($fields['mobile']); + } + } + if (empty($member)) { + if(empty($fields['mobile']) && empty($fields['email'])) { + return false; + } + $fields['uniacid'] = mc_current_real_uniacid(); + $fields['createtime'] = TIMESTAMP; + pdo_insert('mc_members', $fields); + $insert_id = pdo_insertid(); + } else { + if (!empty($fields)) { + pdo_update('mc_members', $fields, array('uid' => $uid, 'uniacid' => $_W['uniacid'])); + } + } + + if (!empty($openid) && empty($uid)) { + table('mc_mapping_fans')->fill(array('uid' => $insert_id))->where(array('uniacid' => mc_current_real_uniacid(), 'openid' => $openid))->save(); + } + cache_build_memberinfo($uid); + return true; +} + + +function mc_fetch($uid, $fields = array()) { + if (empty($uid)) { + return array(); + } + $struct = mc_fields(); + $struct = array_keys($struct); + if (!empty($fields)) { + foreach ($fields as $key => $field) { + if (!in_array($field, $struct)) { + unset($fields[$key]); + } + if ($field == 'birth') { + $fields[] = 'birthyear'; + $fields[] = 'birthmonth'; + $fields[] = 'birthday'; + } + if ($field == 'reside') { + $fields[] = 'resideprovince'; + $fields[] = 'residecity'; + $fields[] = 'residedist'; + } + } + unset($fields['birth'], $fields['reside']); + } + $result = array(); + if (is_array($uid)) { + foreach ($uid as $id) { + $user_info = mc_fetch_one($id); + if (!empty($user_info) && !empty($fields)) { + foreach ($fields as $field) { + $result[$id][$field] = $user_info[$field]; + } + $result[$id]['uid'] = $id; + } else { + $result[$id] = $user_info; + } + } + } else { + $user_info = mc_fetch_one($uid); + if (!empty($user_info) && !empty($fields)) { + foreach ($fields as $field) { + $result[$field] = $user_info[$field]; + } + $result['uid'] = $uid; + } else { + $result = $user_info; + } + } + return $result; +} + + +function mc_fetch_one($uid, $uniacid = 0) { + global $_W; + $uid = mc_openid2uid($uid); + if (empty($uid)) { + return array(); + } + $cachekey = cache_system_key('memberinfo', array('uid' => $uid)); + $cache = cache_load($cachekey); + + if (!empty($cache)) { + return $cache; + } + $params = array('uid' => $uid); + $params['uniacid'] = intval($uniacid) > 0 ? intval($uniacid) : $_W['uniacid']; + $result = pdo_get('mc_members', $params); + if (!empty($result)) { + $result['avatar'] = tomedia($result['avatar']); + $result['credit1'] = floatval($result['credit1']); + $result['credit2'] = floatval($result['credit2']); + $result['credit3'] = floatval($result['credit3']); + $result['credit4'] = floatval($result['credit4']); + $result['credit5'] = floatval($result['credit5']); + $result['credit6'] = floatval($result['credit6']); + } else { + $result = array(); + } + cache_write($cachekey, $result); + return $result; +} + +function mc_fansinfo($openidOruid, $acid = 0, $uniacid = 0) { + global $_W; + if (empty($openidOruid)) { + return array(); + } + if (is_numeric($openidOruid)) { + $openid = mc_uid2openid($openidOruid); + if (empty($openid)) { + return array(); + } + } else { + $openid = $openidOruid; + } + + $mc_mapping_fans_table = table('mc_mapping_fans'); + if (!empty($uniacid)) { + $mc_mapping_fans_table->searchWithUniacid($uniacid); + } + $mc_mapping_fans_table->searchWithOpenid($openid); + $fan = $mc_mapping_fans_table->get(); + + if (!empty($fan)) { + $mc_fans_tag_table = table('mc_fans_tag'); + $tags_info = $mc_fans_tag_table->getByOpenid($openid); +// if (empty($tags_info)) { + if (!empty($fan['tag']) && is_string($fan['tag'])) { + if (is_base64($fan['tag'])) { + $fan['tag'] = @base64_decode($fan['tag']); + } + if (is_serialized($fan['tag'])) { + $fan['tag'] = @iunserializer($fan['tag']); + } + if (is_array($fan['tag']) && !empty($fan['tag']['headimgurl'])) { + $fan['tag']['avatar'] = tomedia($fan['tag']['headimgurl']); + unset($fan['tag']['headimgurl']); + if (empty($fan['nickname']) && !empty($fan['tag']['nickname'])) { + $fan['nickname'] = strip_emoji($fan['tag']['nickname']); + } + $fan['gender'] = $fan['sex'] = $fan['tag']['sex']; + $fan['avatar'] = $fan['headimgurl'] = $fan['tag']['avatar']; + } + } else { + $fan['tag'] = array(); + } +// } else { +// $fan['tag'] = $tags_info; +// $fan['tag']['avatar'] = $tags_info['headimgurl']; +// +// if (empty($fan['nickname']) && !empty($fan['tag']['nickname'])) { +// $fan['nickname'] = strip_emoji($fan['tag']['nickname']); +// } +// $fan['gender'] = $fan['sex'] = $fan['tag']['sex']; +// $fan['avatar'] = $fan['headimgurl'] = $fan['tag']['avatar']; +// } + } + + if (empty($fan) && $openid == $_W['openid'] && !empty($_SESSION['userinfo'])) { + $fan['tag'] = iunserializer(base64_decode($_SESSION['userinfo'])); + $fan['uid'] = 0; + $fan['openid'] = $fan['tag']['openid']; + $fan['follow'] = 0; + if (empty($fan['nickname']) && !empty($fan['tag']['nickname'])) { + $fan['nickname'] = strip_emoji($fan['tag']['nickname']); + } + $fan['gender'] = $fan['sex'] = $fan['tag']['sex']; + $fan['avatar'] = $fan['headimgurl'] = $fan['tag']['headimgurl']; + $mc_oauth_fan = mc_oauth_fans($fan['openid']); + if (!empty($mc_oauth_fan)) { + $fan['uid'] = $mc_oauth_fan['uid']; + } + } + return $fan; +} + + +function mc_oauth_fans($openid, $uniacid = 0){ + $mc_oauth_fans_table = table('mc_oauth_fans'); + if (!empty($uniacid)) { + $mc_oauth_fans_table->searchWithUniacid($uniacid); + } + $mc_oauth_fans_table->searchWithoAuthopenid($openid); + $fan = $mc_oauth_fans_table->get(); + return $fan; +} + + +function mc_oauth_userinfo($acid = 0) { + global $_W; + if (isset($_SESSION['userinfo'])) { + $userinfo = iunserializer(base64_decode($_SESSION['userinfo'])); + if (!empty($userinfo) || is_array($userinfo)) { + return $userinfo; + } + } + if ($_W['container'] != 'wechat') { + return array(); + } + $result = mc_oauth_account_userinfo(); + if (is_error($result)) { + load()->func('tpl'); + include template('mc/iswxapp', TEMPLATE_INCLUDEPATH); + exit; + } + return $result; + +} + +function mc_oauth_account_userinfo($url = '') { + global $_W; + if ($_W['account']->typeSign != 'account') { + error(-4, '该账号非公众号类型,不支持使用该函数!'); + } + if (empty($_W['account']['oauth'])) { + return error(-1, '未指定网页授权公众号, 无法获取用户信息.'); + } + if (empty($_W['account']['oauth']['key'])) { + return error(-2, '公众号未设置 appId 或 secret.'); + } + if (intval($_W['account']['oauth']['level']) < 4 && !in_array($_W['account']['oauth']['level'], array(ACCOUNT_TYPE_APP_NORMAL, ACCOUNT_TYPE_APP_AUTH, ACCOUNT_TYPE_WXAPP_WORK))) { + return error(-3, '公众号非认证服务号, 无法获取用户信息.'); + } + + if (!empty($_SESSION['openid']) && intval($_W['account']['level']) >= 3) { + $oauth_account = WeAccount::createByUniacid(); + $userinfo = $oauth_account->fansQueryInfo($_SESSION['openid']); + if (!is_error($userinfo) && !empty($userinfo) && is_array($userinfo) && !empty($userinfo['nickname'])) { + $userinfo['nickname'] = stripcslashes($userinfo['nickname']); + $userinfo['avatar'] = $userinfo['headimgurl']; + $_SESSION['userinfo'] = base64_encode(iserializer($userinfo)); + $fan = mc_fansinfo($_SESSION['openid']); + if (!empty($fan)) { + $record = array( + 'updatetime' => TIMESTAMP, + 'nickname' => stripslashes($userinfo['nickname']), + 'follow' => $userinfo['subscribe'], + 'followtime' => $userinfo['subscribe_time'], + 'unionid' => $userinfo['unionid'], + 'tag' => base64_encode(iserializer($userinfo)) + ); + pdo_update('mc_mapping_fans', $record, array('openid' => $_SESSION['openid'], 'uniacid' => $_W['uniacid'])); + } else { + $record = array(); + $record['updatetime'] = TIMESTAMP; + $record['nickname'] = stripslashes($userinfo['nickname']); + $record['tag'] = base64_encode(iserializer($userinfo)); + $record['openid'] = $_SESSION['openid']; + $record['acid'] = $_W['acid']; + $record['uniacid'] = $_W['uniacid']; + $record['unionid'] = $userinfo['unionid']; + $record['user_from'] = $_W['account']->typeSign == 'wxapp' ? 1 : 0; + + pdo_insert('mc_mapping_fans', $record); + } + + if (!empty($fan['uid']) || !empty($_SESSION['uid'])) { + $uid = intval($fan['uid']); + if (empty($uid)) { + $uid = intval($_SESSION['uid']); + } + $member = mc_fetch($uid, array('nickname', 'gender', 'residecity', 'resideprovince', 'nationality', 'avatar')); + $record = array(); + if (empty($member['nickname']) && !empty($userinfo['nickname'])) { + $record['nickname'] = stripslashes($userinfo['nickname']); + } + if (empty($member['gender']) && !empty($userinfo['sex'])) { + $record['gender'] = $userinfo['sex']; + } + if (empty($member['residecity']) && !empty($userinfo['city'])) { + $record['residecity'] = $userinfo['city'] . '市'; + } + if (empty($member['resideprovince']) && !empty($userinfo['province'])) { + $record['resideprovince'] = $userinfo['province'] . '省'; + } + if (empty($member['nationality']) && !empty($userinfo['country'])) { + $record['nationality'] = $userinfo['country']; + } + if (empty($member['avatar']) && !empty($userinfo['headimgurl'])) { + $record['avatar'] = $userinfo['headimgurl']; + } + if (!empty($record)) { + pdo_update('mc_members', $record, array('uid' => $uid)); + cache_build_memberinfo($uid); + } + } + return $userinfo; + } + } + + $state = 'we7sid-' . $_W['session_id']; + $_SESSION['dest_url'] = urlencode($_W['siteurl']); + if (!empty($url)) { + $_SESSION['dest_url'] = urlencode($url); + } + $oauth_url = uni_account_oauth_host(); + $url = $oauth_url . "app/index.php?i={$_W['uniacid']}&c=auth&a=oauth&scope=userinfo"; + $callback = urlencode($url); + + $oauth_account = WeAccount::create($_W['account']['oauth']); + $forward = $oauth_account->getOauthUserInfoUrl($callback, $state); + header('Location: ' . $forward); + exit; +} + + +function mc_require($uid, $fields, $pre = '') { + global $_W, $_GPC; + if (empty($fields) || !is_array($fields)) { + return false; + } + $flipfields = array_flip($fields); + if (in_array('birth', $fields) || in_array('birthyear', $fields) || in_array('birthmonth', $fields) || in_array('birthday', $fields)) { + unset($flipfields['birthyear'], $flipfields['birthmonth'], $flipfields['birthday'], $flipfields['birth']); + $flipfields['birthyear'] = 'birthyear'; + $flipfields['birthmonth'] = 'birthmonth'; + $flipfields['birthday'] = 'birthday'; + } + if (in_array('reside', $fields) || in_array('resideprovince', $fields) || in_array('residecity', $fields) || in_array('residedist', $fields)) { + unset($flipfields['residedist'], $flipfields['resideprovince'], $flipfields['residecity'], $flipfields['reside']); + $flipfields['resideprovince'] = 'resideprovince'; + $flipfields['residecity'] = 'residecity'; + $flipfields['residedist'] = 'residedist'; + } + $fields = array_keys($flipfields); + if (!in_array('uniacid', $fields)) { + $fields[] = 'uniacid'; + } + if (!empty($pre)) { + $pre .= '
'; + } + if (empty($uid)) { + foreach ($fields as $field) { + $profile[$field] = ''; + } + $uniacid = $_W['uniacid']; + } else { + $profile = mc_fetch($uid, $fields); + $uniacid = $profile['uniacid']; + } + $mc_member_fields = table('mc_member_fields'); + $mc_member_fields->searchWithUniacid($_W['uniacid']); + $mc_member_fields->selectFields(array('b.field', 'b.id as fid', 'a.*')); + $system_fields = $mc_member_fields->getAllFields(); + if (empty($system_fields)) { + $system_fields = pdo_getall('profile_fields', array(), array('id', 'field', 'title'), ''); + } + + $titles = array(); + foreach ($system_fields as $field) { + $titles[$field['field']] = $field['title']; + } + + $message = ''; + $ks = array(); + foreach ($profile as $k => $v) { + if (empty($v)) { + $ks[] = $k; + $message .= $system_fields[$k]['title'] . ', '; + } + } + + if (!empty($message)) { + $title = '完善资料'; + if (checksubmit('submit')) { + if (in_array('resideprovince', $fields)) { + $_GPC['resideprovince'] = $_GPC['reside']['province']; + $_GPC['residecity'] = $_GPC['reside']['city']; + $_GPC['residedist'] = $_GPC['reside']['district']; + } + if (in_array('birthyear', $fields)) { + $_GPC['birthyear'] = $_GPC['birth']['year']; + $_GPC['birthmonth'] = $_GPC['birth']['month']; + $_GPC['birthday'] = $_GPC['birth']['day']; + } + $record = array_elements($fields, $_GPC); + if (isset($record['uniacid'])) { + unset($record['uniacid']); + } + + foreach ($record as $field => $value) { + if ($field == 'gender') { + continue; + } + if (empty($value)) { + itoast('请填写完整所有资料.', referer(), 'error'); + } + } + if (empty($record['nickname']) && !empty($_W['fans']['nickname'])) { + $record['nickname'] = $_W['fans']['nickname']; + } + if (empty($record['avatar']) && !empty($_W['fans']['tag']['avatar'])) { + $record['avatar'] = $_W['fans']['tag']['avatar']; + } + $condition = " AND uid != {$uid} "; + if (in_array('email', $fields)) { + $mc_members = table('mc_members'); + $mc_members->searchWithUniacid(mc_current_real_uniacid()); + $mc_members->searchWithoutUid($uid); + $mc_members->searchWithEmail(trim($record['email'])); + $emailexists = $mc_members->getcolumn('email'); + if ($emailexists) { + itoast('抱歉,您填写的手机号已经被使用,请更新。', 'refresh', 'error'); + } + } + if (in_array('mobile', $fields)) { + $mc_members = table('mc_members'); + $mc_members->searchWithUniacid(mc_current_real_uniacid()); + $mc_members->searchWithoutUid($uid); + $mc_members->searchWithEmail(trim($record['mobile'])); + $mobilexists = $mc_members->getcolumn('mobile'); + if ($mobilexists) { + itoast('抱歉,您填写的手机号已经被使用,请更新。', 'refresh', 'error'); + } + } + $insertuid = mc_update($uid, $record); + if (empty($uid)) { + pdo_update('mc_oauth_fans', array('uid' => $insertuid), array('oauth_openid' => $_W['openid'])); + pdo_update('mc_mapping_fans', array('uid' => $insertuid), array('openid' => $_W['openid'])); + } + itoast('资料完善成功.', 'refresh', 'success'); + } + load()->func('tpl'); + load()->model('activity'); + $filter = array(); + $filter['status'] = 1; + $coupons = activity_coupon_owned($_W['member']['uid'], $filter); + $tokens = activity_token_owned($_W['member']['uid'], $filter); + + $setting = uni_setting($_W['uniacid'], array('creditnames', 'creditbehaviors')); + $behavior = $setting['creditbehaviors']; + $creditnames = $setting['creditnames']; + $credits = mc_credit_fetch($_W['member']['uid'], '*'); + include template('mc/require', TEMPLATE_INCLUDEPATH); + exit; + } + return $profile; +} + + +function mc_credit_update($uid, $credittype, $creditval = 0, $log = array()) { + global $_W; + $creditnames = uni_setting_load('creditnames'); + $creditnames = $creditnames['creditnames']; + + $credittype = trim($credittype); + $credittypes = mc_credit_types(); + $clerk_types = array( + '1' => '线上操作', + '2' => '系统后台', + '3' => '店员', + ); + if (!in_array($credittype, $credittypes)) { + return error('-1', "指定的用户积分类型 “{$credittype}”不存在."); + } + $creditval = floatval($creditval); + if (empty($creditval)) { + return true; + } + $value = pdo_getcolumn('mc_members', array('uid' => $uid), $credittype); + if ($creditval > 0 || ($value + $creditval >= 0) || $credittype == 'credit6') { + pdo_update('mc_members', array($credittype => $value + $creditval), array('uid' => $uid)); + cache_build_memberinfo($uid); + } else { + return error('-1', "积分类型为“{$credittype}”的积分不够,无法操作。"); + } + if (empty($log) || !is_array($log)) { + load()->func('logging'); + if (!empty($GLOBALS['site']) && $GLOBALS['site'] instanceof WeModuleSite) { + $log = array( + $uid, + $GLOBALS['site']->module['title'] . '模块内消费' . logging_implode($_GET), + $GLOBALS['site']->module['name'], + 0, + ); + } elseif (!empty($GLOBALS['_GPC']['m'])) { + $modules = uni_modules(); + $log = array( + $uid, + $modules[$GLOBALS['_GPC']['m']]['title'] . '模块内消费' . logging_implode($_GET), + $GLOBALS['_GPC']['m'], + 0, + ); + } else { + $log = array($uid, '未记录', 0, 0); + } + } + if ($credittype == 'credit1') { + $credittype_name = $creditnames['credit1']['title']; + } elseif ($credittype == 'credit2') { + $credittype_name = '元'; + } + if (empty($log[1])) { + if ($creditval > 0) { + $log[1] = $clerk_types[$log[5]] . ': 添加' . $creditval . $credittype_name; + } else { + $log[1] = $clerk_types[$log[5]] . ': 减少' . -$creditval . $credittype_name; + } + + } + $clerk_type = intval($log[5]) ? intval($log[5]) : 1; + $data = array( + 'uid' => $uid, + 'credittype' => $credittype, + 'uniacid' => $_W['uniacid'], + 'num' => $creditval, + 'createtime' => TIMESTAMP, + 'operator' => intval($log[0]), + 'module' => trim($log[2]), + 'clerk_id' => intval($log[3]), + 'store_id' => intval($log[4]), + 'clerk_type' => $clerk_type, + 'remark' => $log[1], + 'real_uniacid' => mc_current_real_uniacid() + ); + pdo_insert('mc_credits_record', $data); + return true; +} + + +function mc_account_change_operator($clerk_type, $store_id, $clerk_id) { + global $stores, $clerks, $_W; + if(empty($stores) || empty($clerks)) { + $clerks = pdo_getall('activity_clerks', array('uniacid' => $_W['uniacid']), array('id', 'name'), 'id'); + $stores = pdo_getall('activity_stores', array('uniacid' => $_W['uniacid']), array('id', 'business_name', 'branch_name'), 'id'); + } + $data = array( + 'clerk_cn' => '', + 'store_cn' => '', + ); + if($clerk_type == 1) { + $data['clerk_cn'] = '系统'; + } elseif($clerk_type == 2) { + $data['clerk_cn'] = pdo_getcolumn('users', array('uid' => $clerk_id), 'username'); + } elseif($clerk_type == 3) { + if (empty($clerk_id)) { + $data['clerk_cn'] = '本人操作'; + } else { + $data['clerk_cn'] = $clerks[$clerk_id]['name']; + } + $data['store_cn'] = $stores[$store_id]['business_name'] . ' ' . $stores[$store_id]['branch_name']; + } + if (empty($data['store_cn'])) { + $data['store_cn'] = '暂无门店信息'; + } + if (empty($data['clerk_cn'])) { + $data['clerk_cn'] = '暂无操作员信息'; + } + return $data; +} + +function mc_credit_fetch($uid, $types = array()) { + if (empty($types) || $types == '*') { + $select = array('credit1', 'credit2', 'credit3', 'credit4', 'credit5', 'credit6'); + } else { + $struct = mc_credit_types(); + foreach ($types as $key => $type) { + if (!in_array($type, $struct)) { + unset($types[$key]); + } + } + $select = $types; + } + return pdo_get('mc_members', array('uid' => $uid), $select); +} + + +function mc_credit_types(){ + static $struct = array('credit1','credit2','credit3','credit4','credit5','credit6'); + return $struct; +} + + +function mc_groups($uniacid = 0) { + global $_W; + $uniacid = intval($uniacid); + if (empty($uniacid)) { + $uniacid = $_W['uniacid']; + } + return pdo_getall('mc_groups', array('uniacid' => $uniacid), array(), 'groupid', 'credit'); +} + + +function mc_fans_groups($force_update = false) { + global $_W; + $results = table('mc_fans_groups')->getByUniacid($_W['uniacid']); + $results = empty($results['groups']) ? array() : $results['groups']; + + if(!empty($results) && !$force_update) { + return $results; + } + $account_api = WeAccount::createByUniacid(); + if (!$account_api->isTagSupported()) { + return array(); + } + $tags = $account_api->fansTagFetchAll(); + if (is_error($tags)) { + itoast($tags['message'], '', 'error'); + } + if (!empty($tags['tags'])) { + $tags_tmp = array(); + foreach ($tags['tags'] as $da) { + if ($da['id'] == 1) { + continue; + } + $tags_tmp[$da['id']] = $da; + } + } + if (empty($results)) { + $data = array('acid' => $_W['acid'], 'uniacid' => $_W['uniacid'], 'groups' => iserializer($tags_tmp)); + pdo_insert('mc_fans_groups', $data); + } else { + $data = array('groups' => iserializer($tags_tmp)); + pdo_update('mc_fans_groups', $data, array('uniacid' => $_W['uniacid'])); + } + return $tags_tmp; +} + + +function _mc_login($member) { + global $_W; + if (!empty($member) && !empty($member['uid'])) { + $member = pdo_get('mc_members', array('uid' => $member['uid'], 'uniacid' => $_W['uniacid']), array('uid', 'realname', 'mobile', 'email', 'groupid', 'credit1', 'credit2', 'credit6')); + if (!empty($member) && (!empty($member['mobile']) || !empty($member['email']))) { + $_W['member'] = $member; + $_W['member']['groupname'] = $_W['uniaccount']['groups'][$member['groupid']]['title']; + $_SESSION['uid'] = $member['uid']; + mc_group_update(); + if (empty($_W['openid'])) { + $fan = mc_fansinfo($member['uid']); + if (!empty($fan)) { + $_SESSION['openid'] = $fan['openid']; + $_W['openid'] = $fan['openid']; + $_W['fans'] = $fan; + $_W['fans']['from_user'] = $_W['openid']; + } else { + $_W['openid'] = $member['uid']; + $_W['fans'] = array( + 'from_user' => $member['uid'], + 'follow' => 0 + ); + } + } + isetcookie('logout', '', -60000); + return true; + } + } + return false; +} + + +function mc_fields() { + $fields = cache_load(cache_system_key('usersfields')); + if (empty($fields)) { + load()->model('cache'); + cache_build_users_struct(); + $fields = cache_load(cache_system_key('usersfields')); + } + return $fields; +} + + +function mc_acccount_fields($uniacid = 0, $is_available = true) { + global $_W; + $uniacid = !empty($uniacid) ? intval($uniacid) : $_W['uniacid']; + $is_available = !empty($is_available) ? 1 : 0; + + $mc_member_fields = table('mc_member_fields'); + $mc_member_fields->searchWithUniacid($uniacid); + $mc_member_fields->searchWithAvailable($is_available); + $mc_member_fields->selectFields(array('a.title', 'b.field')); + $data = $mc_member_fields->getAllFields(); + $fields = array(); + foreach($data as $row) { + $fields[$row['field']] = $row['title']; + } + return $fields; +} + + +function mc_handsel($touid, $fromuid, $handsel, $uniacid = '') { + global $_W; + $touid = intval($touid); + $fromuid = intval($fromuid); + if (empty($uniacid)) { + $uniacid = $_W['uniacid']; + } + $touid_exist = mc_fetch($touid, array('uniacid')); + if (empty($touid_exist)) { + return error(-1, '赠送积分用户不存在'); + } + if (empty($handsel['module'])) { + return error(-1, '没有填写模块名称'); + } + if (empty($handsel['sign'])) { + return error(-1, '没有填写赠送积分对象信息'); + } + if (empty($handsel['action'])) { + return error(-1, '没有填写赠送积分动作'); + } + $credit_value = intval($handsel['credit_value']); + + $params = array('uniacid' => $uniacid, 'touid' => $touid, 'fromuid' => $fromuid, 'module' => $handsel['module'], 'sign' => $handsel['sign'], 'action' => $handsel['action']); + $handsel_exists = pdo_get('mc_handsel', $params); + if (!empty($handsel_exists)) { + return error(-1, '已经赠送过积分,每个用户只能赠送一次'); + } + $creditbehaviors = pdo_fetchcolumn('SELECT creditbehaviors FROM ' . tablename('uni_settings') . ' WHERE uniacid = :uniacid', array(':uniacid' => $uniacid)); + $creditbehaviors = iunserializer($creditbehaviors) ? iunserializer($creditbehaviors) : array(); + if (empty($creditbehaviors['activity'])) { + return error(-1, '公众号没有配置积分行为参数'); + } else { + $credittype = $creditbehaviors['activity']; + } + + $data = array( + 'uniacid' => $uniacid, + 'touid' => $touid, + 'fromuid' => $fromuid, + 'module' => $handsel['module'], + 'sign' => $handsel['sign'], + 'action' => $handsel['action'], + 'credit_value' => $credit_value, + 'createtime' => TIMESTAMP + ); + pdo_insert('mc_handsel', $data); + $log = array($fromuid, $handsel['credit_log']); + mc_credit_update($touid, $credittype, $credit_value, $log); + return true; +} + + +function mc_openid2uid($openid) { + global $_W; + if (is_numeric($openid)) { + return $openid; + } + if (is_string($openid)) { + $fans_info = pdo_get('mc_mapping_fans', array('uniacid' => mc_current_real_uniacid(), 'openid' => $openid), array('uid')); + return !empty($fans_info) ? $fans_info['uid'] : false; + } + if (is_array($openid)) { + $uids = array(); + foreach ($openid as $k => $v) { + if (is_numeric($v)) { + $uids[] = intval($v); + } elseif (is_string($v)) { + $fans[] = istripslashes(str_replace(' ', '', $v)); + } + } + if (!empty($fans)) { + $fans = pdo_getall('mc_mapping_fans', array('uniacid' => mc_current_real_uniacid(), 'openid' => $fans), array('uid', 'openid'), 'uid'); + $fans = array_keys($fans); + $uids = array_merge((array)$uids, $fans); + } + return $uids; + } + return false; +} + + +function mc_uid2openid($uid) { + global $_W; + if (is_numeric($uid)) { + $fans_info = pdo_get('mc_mapping_fans', array('uniacid' => mc_current_real_uniacid(), 'uid' => $uid), 'openid'); + return !empty($fans_info['openid']) ? $fans_info['openid'] : false; + } + if (is_string($uid)) { + $openid = trim($uid); + $openid_exist = pdo_get('mc_mapping_fans', array('openid' => $openid)); + if (!empty($openid_exist)) { + return $openid; + } else { + return false; + } + } + if (is_array($uid)) { + $openids = array(); + foreach ($uid as $key => $value) { + if (is_string($value)) { + $openids[] = $value; + } elseif (is_numeric($value)) { + $uids[] = $value; + } + } + if (!empty($uids)) { + $fans_info = pdo_getall('mc_mapping_fans', array('uniacid' => mc_current_real_uniacid(), 'uid' => $uids), array('uid', 'openid'), 'openid'); + $fans_info = array_keys($fans_info); + $openids = array_merge($openids, $fans_info); + } + return $openids; + } + return false; +} + +function mc_group_update($uid = 0) { + global $_W; + if(!$_W['uniaccount']['grouplevel']) { + $_W['uniaccount']['grouplevel'] = pdo_getcolumn('uni_settings', array('uniacid' => $_W['uniacid']), 'grouplevel'); + if (empty($_W['uniaccount']['grouplevel'])) { + return true; + } + } + $uid = intval($uid); + if($uid <= 0) { + $uid = $_W['member']['uid']; + $user = $_W['member']; + $user['openid'] = $_W['openid']; + } else { + $user = pdo_get('mc_members', array('uniacid' => $_W['uniacid'], 'uid' => $uid), array('uid', 'realname', 'credit1', 'credit6', 'groupid')); + $user['openid'] = pdo_getcolumn('mc_mapping_fans', array('uniacid' => $_W['uniacid'], 'uid' => $uid), 'openid'); + } + if(empty($user)) { + return false; + } + $groupid = $user['groupid']; + $credit = $user['credit1'] + $user['credit6']; + $groups = mc_groups(); + if(empty($groups)) { + return false; + } + $data = array(); + foreach($groups as $group) { + $data[$group['groupid']] = $group['credit']; + } + asort($data); + if($_W['uniaccount']['grouplevel'] == 1) { + foreach($data as $k => $da) { + if($credit >= $da) { + $groupid = $k; + } + } + } else { + $now_group_credit = $data[$user['groupid']]; + if($now_group_credit < $credit) { + foreach($data as $k => $da) { + if($credit >= $da) { + $groupid = $k; + } + } + } + } + if($groupid > 0 && $groupid != $user['groupid']) { + pdo_update('mc_members', array('groupid' => $groupid), array('uniacid' => $_W['uniacid'], 'uid' => $uid)); + cache_build_memberinfo($uid); + mc_notice_group($user['openid'], $_W['uniaccount']['groups'][$user['groupid']]['title'], $_W['uniaccount']['groups'][$groupid]['title']); + } + $user['groupid'] = $groupid; + $_W['member']['groupid'] = $groupid; + $_W['member']['groupname'] = $_W['uniaccount']['groups'][$groupid]['title']; + return $user['groupid']; +} + +function mc_notice_init() { + global $_W; + if(empty($_W['account'])) { + $_W['account'] = uni_fetch($_W['uniacid']); + } + if(empty($_W['account'])) { + return error(1, '创建公众号操作类失败'); + } + if($_W['account']['level'] < 3) { + return error(1, '公众号没有经过认证,不能使用模板消息和客服消息'); + } + $account = WeAccount::createByUniacid($_W['uniacid']); + if(is_null($account)) { + return error(1, '创建公众号操作对象失败'); + } + $setting = uni_setting(); + $noticetpl = $setting['tplnotice']; + $account->noticetpl = $noticetpl; + return $account; +} + + +function mc_notice_public($openid, $title, $sender, $content, $url = '', $remark = '') { + $account = mc_notice_init(); + if(is_error($account)) { + return error(-1, $account['message']); + } + $data = array( + 'first' => array( + 'value' => $title, + 'color' => '#ff510' + ), + 'keyword1' => array( + 'value' => $sender, + 'color' => '#ff510' + ), + 'keyword2' => array( + 'value' => $content, + 'color' => '#ff510' + ), + 'remark' => array( + 'value' => $remark, + 'color' => '#ff510' + ), + ); + $status = $account->sendTplNotice($openid, $account->noticetpl['public'], $data, $url); + return $status; +} + + +function mc_notice_recharge($openid, $uid = 0, $num = 0, $url = '', $remark = '') { + global $_W; + if(!$uid) { + $uid = $_W['member']['uid']; + } + if(!$uid || !$num || empty($openid)) { + return error(-1, '参数错误'); + } + $account = mc_notice_init(); + if(is_error($account)) { + return error(-1, $account['message']); + } + $credit = mc_credit_fetch($uid); + $time = date('Y-m-d H:i'); + if(empty($url)) { + $url = murl('mc/bond/credits', array('credittype' => 'credit2', 'type' => 'record', 'period' => '1'), true, true); + } + if($_W['account']['level'] == ACCOUNT_SERVICE_VERIFY && !empty($account->noticetpl['recharge']['tpl'])) { + $data = array( + 'first' => array( + 'value' => "您好,您在{$time}进行会员余额充值,充值金额{$num}元,充值后余额为{$credit['credit2']}元", + 'color' => '#ff510' + ), + 'accountType' => array( + 'value' => '会员UID', + 'color' => '#ff510' + ), + 'account' => array( + 'value' => $uid, + 'color' => '#ff510' + ), + 'amount' => array( + 'value' => $num . '元', + 'color' => '#ff510' + ), + 'result' => array( + 'value' => '充值成功', + 'color' => '#ff510' + ), + 'remark' => array( + 'value' => "{$remark}" , + 'color' => '#ff510' + ), + ); + $status = $account->sendTplNotice($openid, $account->noticetpl['recharge']['tpl'], $data, $url); + } + if($_W['account']['level'] == ACCOUNT_SUBSCRIPTION_VERIFY || is_error($status) || empty($account->noticetpl['recharge']['tpl'])) { + $info = "【{$_W['account']['name']}】充值通知\n"; + $info .= "您在{$time}进行会员余额充值,充值金额【{$num}】元,充值后余额【{$credit['credit2']}】元。\n"; + $info .= !empty($remark) ? "备注:{$remark}\n\n" : ''; + $custom = array( + 'msgtype' => 'text', + 'text' => array('content' => urlencode($info)), + 'touser' => $openid, + ); + $status = $account->sendCustomNotice($custom); + } + return $status; +} + + +function mc_notice_credit2($openid, $uid, $credit2_num, $credit1_num = 0, $store = '线下消费', $url = '', $remark = '谢谢惠顾,点击查看详情') { + global $_W; + if(!$uid) { + $uid = $_W['member']['uid']; + } + if(!$uid || !$credit2_num || empty($openid)) { + return error(-1, '参数错误'); + } + $account = mc_notice_init(); + if(is_error($account)) { + return error(-1, $account['message']); + } + $credit = mc_credit_fetch($uid); + $time = date('Y-m-d H:i'); + if(empty($url)) { + $url = murl('mc/bond/credits', array('credittype' => 'credit2', 'type' => 'record', 'period' => '1'), true, true); + } + $credit_setting = uni_setting_load('creditnames'); + $credit1_title = empty($credit_setting['creditnames']['credit1']['title']) ? '积分' : $credit_setting['creditnames']['credit1']['title']; + $credit2_title = empty($credit_setting['creditnames']['credit2']['title']) ? '余额' : $credit_setting['creditnames']['credit2']['title']; + + if($_W['account']['level'] == ACCOUNT_SERVICE_VERIFY && !empty($account->noticetpl['credit2']['tpl'])) { + $data = array( + 'first' => array( + 'value' => "您好,您在{$time}有{$credit2_title}消费", + 'color' => '#ff510' + ), + 'keyword1' => array( + 'value' => abs($credit2_num) . '元', + 'color' => '#ff510' + ), + 'keyword2' => array( + 'value' => floatval($credit1_num) . $credit1_title, + 'color' => '#ff510' + ), + 'keyword3' => array( + 'value' => trim($store), + 'color' => '#ff510' + ), + 'keyword4' => array( + 'value' => $credit['credit2'] . '元', + 'color' => '#ff510' + ), + 'keyword5' => array( + 'value' => $credit['credit1'] . $credit1_title, + 'color' => '#ff510' + ), + 'remark' => array( + 'value' => "{$remark}" , + 'color' => '#ff510' + ), + ); + $status = $account->sendTplNotice($openid, $account->noticetpl['credit2']['tpl'], $data, $url); + } + if($_W['account']['level'] == ACCOUNT_SUBSCRIPTION_VERIFY || is_error($status) || empty($account->noticetpl['credit2']['tpl'])) { + $info = "【{$_W['account']['name']}】消费通知\n"; + $info .= "您在{$time}进行会员{$credit2_title}消费,消费金额【{$credit2_num}】元,获得{$credit1_title}【{$credit1_num}】,消费后余额【{$credit['credit2']}】元,消费后{$credit1_title}【{$credit['credit1']}】。\n"; + $info .= !empty($remark) ? "备注:{$remark}\n\n" : ''; + $custom = array( + 'msgtype' => 'text', + 'text' => array('content' => urlencode($info)), + 'touser' => $openid, + ); + $status = $account->sendCustomNotice($custom); + } + return $status; +} + + +function mc_notice_credit1($openid, $uid, $credit1_num, $tip, $url = '', $remark = '谢谢惠顾,点击查看详情') { + global $_W; + if(!$uid) { + $uid = $_W['member']['uid']; + } + if(!$uid || !$credit1_num || empty($tip)) { + return error(-1, '参数错误'); + } + $account = mc_notice_init(); + if(is_error($account)) { + return error(-1, $account['message']); + } + $credit = mc_credit_fetch($uid); + $time = date('Y-m-d H:i'); + if(empty($url)) { + $url = murl('mc/bond/credits', array('credittype' => 'credit1', 'type' => 'record', 'period' => '1'), true, true); + } + $credit1_num = floatval($credit1_num); + $type = '消费'; + if($credit1_num > 0) { + $type = '到账'; + } + $username = $_W['member']['realname']; + if(empty($username)) { + $username = $_W['member']['nickname']; + } + if(empty($username)) { + $username = $uid; + } + $credit_setting = uni_setting_load('creditnames'); + $credit1_title = empty($credit_setting['creditnames']['credit1']['title']) ? '积分' : $credit_setting['creditnames']['credit1']['title']; + + if($_W['account']['level'] == ACCOUNT_SERVICE_VERIFY && !empty($account->noticetpl['credit1']['tpl'])) { + $data = array( + 'first' => array( + 'value' => "您好,您在{$time}有{$credit1_title}变更", + 'color' => '#ff510' + ), + 'keyword1' => array( + 'value' => "原有{$credit1_title} : " . ($credit['credit1'] - $credit1_num), + 'color' => '#ff510' + ), + 'keyword2' => array( + 'value' => "现有{$credit1_title} : " . $credit['credit1'], + 'color' => '#ff510' + ), + 'keyword3' => array( + 'value' => "时间 : {$time} ", + 'color' => '#ff510' + ), + 'remark' => array( + 'value' => "{$remark}" , + 'color' => '#ff510' + ), + ); + $status = $account->sendTplNotice($openid, $account->noticetpl['credit1']['tpl'], $data, $url); + } + if($_W['account']['level'] == ACCOUNT_SUBSCRIPTION_VERIFY || empty($account->noticetpl['credit1']['tpl']) || is_error($status)) { + $info = "【{$_W['account']['name']}】{$credit1_title}变更通知\n"; + $info .= "您在{$time}有{$credit1_title}{$type},{$type}{$credit1_title}【{$credit1_num}】,变更原因:【{$tip}】,消费后账户{$credit1_title}余额【{$credit['credit1']}】。\n"; + $info .= !empty($remark) ? "备注:{$remark}\n\n" : ''; + $custom = array( + 'msgtype' => 'text', + 'text' => array('content' => urlencode($info)), + 'touser' => $openid, + ); + $status = $account->sendCustomNotice($custom); + } + return $status; +} + +function mc_notice_group($openid, $old_group, $now_group, $url = '', $remark = '点击查看详情') { + global $_W; + $account = mc_notice_init(); + if(is_error($account)) { + return error(-1, $account['message']); + } + $time = date('Y-m-d H:i'); + if(empty($url)) { + $url = murl('mc/home', array(), true, true); + } + if($_W['account']['level'] == ACCOUNT_SERVICE_VERIFY && !empty($account->noticetpl['group']['tpl'])) { + $data = array( + 'first' => array( + 'value' => "您好,您的会员组变更为{$now_group}", + 'color' => '#ff510' + ), + 'grade1' => array( + 'value' => $old_group, + 'color' => '#ff510' + ), + 'grade2' => array( + 'value' => $now_group, + 'color' => '#ff510' + ), + 'time' => array( + 'value' => $time, + 'color' => '#ff510' + ), + 'remark' => array( + 'value' => "{$remark}", + 'color' => '#ff510' + ), + ); + $status = $account->sendTplNotice($openid, $account->noticetpl['group']['tpl'], $data, $url); + } + if($_W['account']['level'] == ACCOUNT_SUBSCRIPTION_VERIFY || is_error($status) || empty($account->noticetpl['group']['tpl'])) { + $info = "【{$_W['account']['name']}】会员组变更通知\n"; + $info .= "您的会员等级在{$time}由{$old_group}变更为{$now_group}。\n"; + $info .= !empty($remark) ? "备注:{$remark}\n\n" : ''; + $custom = array( + 'msgtype' => 'text', + 'text' => array('content' => urlencode($info)), + 'touser' => $openid, + ); + $status = $account->sendCustomNotice($custom); + } + return $status; +} + + +function mc_notice_nums_plus($openid, $type, $num, $total_num, $remark = '感谢您的支持,祝您生活愉快!') { + global $_W; + if(empty($num) || empty($total_num) || empty($type)) { + return error(-1, '参数错误'); + } + $account = mc_notice_init(); + if(is_error($account)) { + return error(-1, $account['message']); + } + $time = date('Y-m-d H:i'); + if($_W['account']['level'] == ACCOUNT_SERVICE_VERIFY && !empty($account->noticetpl['nums_plus']['tpl'])) { + $data = array( + 'first' => array( + 'value' => "您好,您的{$type}已充次成功", + 'color' => '#ff510' + ), + 'keyword1' => array( + 'value' => $time, + 'color' => '#ff510' + ), + 'keyword2' => array( + 'value' => $num . '次', + 'color' => '#ff510' + ), + 'keyword3' => array( + 'value' => $total_num . '次', + 'color' => '#ff510' + ), + 'keyword4' => array( + 'value' => '用完为止', + 'color' => '#ff510' + ), + 'remark' => array( + 'value' => "{$remark}" , + 'color' => '#ff510' + ), + ); + $status = $account->sendTplNotice($openid, $account->noticetpl['nums_plus']['tpl'], $data); + } + if($_W['account']['level'] == ACCOUNT_SUBSCRIPTION_VERIFY || is_error($status) || empty($account->noticetpl['nums_plus']['tpl'])) { + $info = "【{$_W['account']['name']}】-【{$type}】充值通知\n"; + $info .= "您的{$type}已充值成功,本次充次【{$num}】次,总剩余【{$total_num}】次。\n"; + $info .= !empty($remark) ? "备注:{$remark}\n\n" : ''; + $custom = array( + 'msgtype' => 'text', + 'text' => array('content' => urlencode($info)), + 'touser' => $openid, + ); + $status = $account->sendCustomNotice($custom); + } + return $status; +} + + +function mc_notice_nums_times($openid, $card_id, $type, $num, $remark = '感谢您对本店的支持,欢迎下次再来!') { + global $_W; + if(empty($num) || empty($type) || empty($card_id)) { + return error(-1, '参数错误'); + } + $account = mc_notice_init(); + if(is_error($account)) { + return error(-1, $account['message']); + } + $time = date('Y-m-d H:i'); + if($_W['account']['level'] == ACCOUNT_SERVICE_VERIFY && !empty($account->noticetpl['nums_times']['tpl'])) { + $data = array( + 'first' => array( + 'value' => "您好,您的{$type}已成功使用了【1】次。", + 'color' => '#ff510' + ), + 'keyword1' => array( + 'value' => $card_id, + 'color' => '#ff510' + ), + 'keyword2' => array( + 'value' => $time, + 'color' => '#ff510' + ), + 'keyword3' => array( + 'value' => $num . '次', + 'color' => '#ff510' + ), + 'keyword4' => array( + 'value' => '用完为止', + 'color' => '#ff510' + ), + 'remark' => array( + 'value' => "{$remark}" , + 'color' => '#ff510' + ), + ); + $status = $account->sendTplNotice($openid, $account->noticetpl['nums_times']['tpl'], $data); + } + if($_W['account']['level'] == ACCOUNT_SUBSCRIPTION_VERIFY || is_error($status) || empty($account->noticetpl['nums_times']['tpl'])) { + $info = "【{$_W['account']['name']}】-【{$type}】消费通知\n"; + $info .= "您的{$type}已成功使用了一次,总剩余【{$num}】次,消费时间【{$time}】。\n"; + $info .= !empty($remark) ? "备注:{$remark}\n\n" : ''; + $custom = array( + 'msgtype' => 'text', + 'text' => array('content' => urlencode($info)), + 'touser' => $openid, + ); + $status = $account->sendCustomNotice($custom); + } + return $status; +} + + +function mc_notice_times_plus($openid, $card_id, $type, $fee, $days, $endtime = '', $remark = '感谢您对本店的支持,欢迎下次再来!') { + global $_W; + $account = mc_notice_init(); + if(is_error($account)) { + return error(-1, $account['message']); + } + if($_W['account']['level'] == ACCOUNT_SERVICE_VERIFY && empty($account->noticetpl['times_plus']['tpl'])) { + $data = array( + 'first' => array( + 'value' => "您好,您的{$type}已续费成功。", + 'color' => '#ff510' + ), + 'keynote1' => array( + 'value' => $type, + 'color' => '#ff510' + ), + 'keynote2' => array( + 'value' => $card_id, + 'color' => '#ff510' + ), + 'keynote3' => array( + 'value' => $fee . '元', + 'color' => '#ff510' + ), + 'keynote4' => array( + 'value' => $days . '天', + 'color' => '#ff510' + ), + 'keynote5' => array( + 'value' => $endtime, + 'color' => '#ff510' + ), + 'remark' => array( + 'value' => "{$remark}" , + 'color' => '#ff510' + ), + ); + $status = $account->sendTplNotice($openid, $account->noticetpl['times_plus']['tpl'], $data); + } + if($_W['account']['level'] == ACCOUNT_SUBSCRIPTION_VERIFY || is_error($status) || empty($account->noticetpl['times_plus']['tpl'])) { + $info = "【{$_W['account']['name']}】-【{$type}】续费通知\n"; + $info .= "您的{$type}已成功续费,续费时长【{$days}】天,续费金额【{$fee}】元,有效期至【{$endtime}】。\n"; + $info .= !empty($remark) ? "备注:{$remark}\n\n" : ''; + $custom = array( + 'msgtype' => 'text', + 'text' => array('content' => urlencode($info)), + 'touser' => $openid, + ); + $status = $account->sendCustomNotice($custom); + } + return $status; +} + + +function mc_notice_times_times($openid, $title, $type, $endtime = '', $remark = '请注意时间,防止服务失效!', $card_sn = '', $use_time = '', $has_time = '') { + global $_W; + $account = mc_notice_init(); + if(is_error($account)) { + return error(-1, $account['message']); + } + + if($_W['account']['level'] == ACCOUNT_SERVICE_VERIFY && !empty($account->noticetpl['times_times']['tpl'])) { + $data = array( + 'first' => array('value' => $title, 'color' => '#ff510'), 'keyword1' => array('value' => $card_sn, 'color' => '#ff510'), 'keyword2' => array('value' => $use_time, 'color' => '#ff510'), 'keyword3' => array('value' => $has_time, 'color' => '#ff510'), 'keyword4' => array('value' => $endtime, 'color' => '#ff510'), 'remark' => array('value' => "{$remark}" ,'color' => '#ff510'), ); + $status = $account->sendTplNotice($openid, $account->noticetpl['times_times']['tpl'], $data); + } + if($_W['account']['level'] == ACCOUNT_SUBSCRIPTION_VERIFY || is_error($status) || empty($account->noticetpl['times_times']['tpl'])) { + $info = "【{$_W['account']['name']}】-【{$type}】服务到期通知\n"; + $info .= "您的{$type}即将到期,有效期至【{$endtime}】。\n"; + $info .= !empty($remark) ? "备注:{$remark}\n\n" : ''; + $custom = array( + 'msgtype' => 'text', + 'text' => array('content' => urlencode($info)), + 'touser' => $openid, + ); + $status = $account->sendCustomNotice($custom); + } + return $status; +} + + +function mc_notice_pay_success($openid, $username, $order_sn, $money, $goods_info, $title = '尊敬的客户,您的订单已支付成功', $remark = '', $url = '') { + global $_W; + $money = sprintf("%.2f", $money); + if(empty($money)|| empty($openid)) { + return error(-1, '参数错误'); + } + $account = mc_notice_init(); + if(is_error($account)) { + return error(-1, $account['message']); + } + if($_W['account']['level'] == ACCOUNT_SERVICE_VERIFY && !empty($account->noticetpl['pay_success']['tpl'])) { + $data = array( + 'first' => array( + 'value' => $title, + 'color' => '#ff510' + ), + 'keyword1' => array( + 'value' => $username, + 'color' => '#ff510' + ), + 'keyword2' => array( + 'value' => $order_sn, + 'color' => '#ff510' + ), + 'keyword3' => array( + 'value' => $money. '元', + 'color' => '#ff510' + ), + 'keyword4' => array( + 'value' => $goods_info, + 'color' => '#ff510' + ), + 'remark' => array( + 'value' => $remark , + 'color' => '#ff510' + ), + ); + $status = $account->sendTplNotice($openid, $account->noticetpl['pay_success']['tpl'], $data, $url); + } + if($_W['account']['level'] == ACCOUNT_SUBSCRIPTION_VERIFY || is_error($status) || empty($account->noticetpl['pay_success']['tpl'])) { + $info = "【{$_W['account']['name']}】付款成功通知\n"; + $info .= "您编号为{$order_sn}的订单已成功支付{$money}。\n"; + $info .= "商品信息:{$goods_info}。\n"; + $info .= !empty($remark) ? "备注:{$remark}\n\n" : ''; + $custom = array( + 'msgtype' => 'text', + 'text' => array('content' => urlencode($info)), + 'touser' => $openid, + ); + $status = $account->sendCustomNotice($custom); + } + return $status; +} + + +function mc_notice_consume($openid, $title, $content, $url = '') { + global $_W; + $account = mc_notice_init(); + if(is_error($account)) { + return error(-1, $account['message']); + } + if($_W['account']['level'] == 4) { + mc_notice_credit2($openid, $content['uid'], $content['credit2_num'], $content['credit1_num'], $content['store'], '', $content['remark']); + } + if($_W['account']['level'] == 3) { + mc_notice_custom_text($openid, $title, $content); + } + return true; +} + +function mc_notice_custom_text($openid, $title, $info) { + global $_W; + $account = mc_notice_init(); + if(is_error($account)) { + return error(-1, $account['message']); + } + $custom = array( + 'msgtype' => 'text', + 'text' => array('content' => urlencode($title . '\n' . $info)), + 'touser' => $openid, + ); + $status = $account->sendCustomNotice($custom); + return $status; +} + +function mc_plugins() { + $plugins = array( + 'mc_card_manage' => array( + 'title' => '会员卡', + 'name' => 'mc_card_manage', + 'description' => '提供粉丝可开通会员卡并可以设置充值、消费金额及积分的增减策略', + ), + 'activity_discount_manage' => array( + 'title' => '兑换中心', + 'name' => 'activity_discount_manage', + 'description' => '提供粉丝可通过积分进行代金劵、折扣劵或是真实物品的兑换', + ), + 'wechat_card_manage' => array( + 'title' => '微信卡券', + 'name' => 'wechat_card_manage', + 'description' => '提供粉丝可通过积分进行代金劵、折扣劵或是真实物品的兑换', + ), + + ); + return $plugins; +} + + +function mc_init_fans_info($openid, $force_init_member = false){ + global $_W; + static $account_api; + if (empty($account_api)) { + $account_api = WeAccount::createByUniacid(); + } + if (is_array($openid)) { + $fans_list = $account_api->fansBatchQueryInfo($openid); + } else { + $fans_list = $account_api->fansQueryInfo($openid); + } + if (empty($fans_list) || is_error($fans_list)) { + if ($fans_list['errno'] == '48001') { + $fans_list = array( + 'openid' => $openid, + 'subscribe_time' => TIMESTAMP, + 'subscribe' => 1, + ); + } else { + return true; + } + } + if (!is_array($openid)) { + $fans_list = array($fans_list); + } + foreach ($fans_list as $fans) { + $fans_mapping = mc_fansinfo($fans['openid']); + if (empty($fans['subscribe']) && empty($fans_mapping)) { + pdo_update('mc_mapping_fans', array('follow' => 0, 'unfollowtime' => TIMESTAMP), array('openid' => $fans['openid'])); + continue; + } + if (!empty($fans_mapping) && $fans['openid'] == $fans_mapping['openid']) { + $fans = array_merge($fans_mapping['tag'], $fans); + } + unset($fans['remark'], $fans['subscribe_scene'], $fans['qr_scene'], $fans['qr_scene_str']); + $fans_update_info = array( + 'openid' => $fans['openid'], + 'acid' => $_W['acid'], + 'uniacid' => $_W['uniacid'], + 'updatetime' => TIMESTAMP, + 'followtime' => $fans['subscribe_time'], + 'follow' => $fans['subscribe'], + 'nickname' => strip_emoji(stripcslashes($fans['nickname'])), + 'tag' => '', + 'unionid' => $fans['unionid'], + 'groupid' => !empty($fans['tagid_list']) ? (','.join(',', $fans['tagid_list']).',') : '', + 'user_from' => $_W['account']->typeSign == 'wxapp' ? 1 : 0, + ); + if (empty($fans_update_info['groupid'])) { + unset($fans_update_info['groupid']); + } + if ($force_init_member) { + $member_update_info = array( + 'uniacid' => $_W['uniacid'], + 'nickname' => $fans_update_info['nickname'], + 'avatar' => $fans['headimgurl'], + 'gender' => $fans['sex'], + 'nationality' => $fans['country'], + 'resideprovince' => $fans['province'] . '省', + 'residecity' => $fans['city'] . '市', + ); + + if (empty($fans_mapping['uid'])) { + $email = md5($fans['openid']).'@we7.cc'; + $email_exists_member = pdo_getcolumn('mc_members', array('email' => $email, 'uniacid' => $_W['uniacid']), 'uid'); + if (!empty($email_exists_member)) { + $uid = $email_exists_member; + } else { + $member_update_info['groupid'] = pdo_getcolumn('mc_groups', array('uniacid' => $_W['uniacid'], 'isdefault' => 1), 'groupid'); + $member_update_info['salt'] = random(8); + $member_update_info['password'] = md5($fans['openid'] . $member_update_info['salt'] . $_W['config']['setting']['authkey']); + $member_update_info['email'] = $email; + $member_update_info['createtime'] = TIMESTAMP; + + pdo_insert('mc_members', $member_update_info); + $uid = pdo_insertid(); + } + $fans_update_info['uid'] = $uid; + } else { + $fans_update_info['uid'] = $fans_mapping['uid']; + pdo_update('mc_members', $member_update_info, array('uid' => $fans_mapping['uid'])); + cache_delete(cache_system_key('memberinfo', array('uid' => $fans_mapping['uid']))); + } + } + + if (!empty($fans_mapping)) { + pdo_update('mc_mapping_fans', $fans_update_info, array('fanid' => $fans_mapping['fanid'])); + pdo_update('mc_fans_tag', array('fanid' => $fans_mapping['fanid']), array('openid' => $fans_mapping['openid'])); + } else { + $fans_update_info['salt'] = random(8); + $fans_update_info['unfollowtime'] = 0; + $fans_update_info['followtime'] = TIMESTAMP; + pdo_insert('mc_mapping_fans', $fans_update_info); + $fans_mapping['fanid'] = pdo_insertid(); + } + if (!empty($fans['tagid_list'])) { + $groupid = $fans['tagid_list']; + @sort($groupid, SORT_NATURAL); + mc_insert_fanstag_mapping($fans_mapping['fanid'], $groupid); + } + + $mc_fans_tag_table = table('mc_fans_tag'); + $mc_fans_tag_fields = mc_fans_tag_fields(); + $fans_tag_update_info = array(); + foreach ($fans as $fans_field_key => $fans_field_info) { + if (in_array($fans_field_key, array_keys($mc_fans_tag_fields))) { + $fans_tag_update_info[$fans_field_key] = $fans_field_info; + } + $fans_tag_update_info['tagid_list'] = iserializer($fans_tag_update_info['tagid_list']); + } + + $fans_tag_exists = $mc_fans_tag_table->getByOpenid($fans_tag_update_info['openid']); + if (!empty($fans_tag_exists)) { + pdo_update('mc_fans_tag', $fans_tag_update_info, array('openid' => $fans_tag_update_info['openid'])); + } else { + pdo_insert('mc_fans_tag', $fans_tag_update_info); + } + } + if (is_string($openid) && !empty($fans_update_info)) { + return $fans_update_info; + } else { + return true; + } +} + + +function mc_insert_fanstag_mapping($fanid, $groupid_list){ + if (empty($groupid_list)) { + return true; + } + + foreach ($groupid_list as $groupid) { + $record_mapping = array( + 'fanid' => $fanid, + 'tagid' => $groupid + ); + $isfound = pdo_getcolumn('mc_fans_tag_mapping', $record_mapping, 'id'); + if (empty($isfound)) { + pdo_insert('mc_fans_tag_mapping', $record_mapping); + } + } + pdo_delete('mc_fans_tag_mapping', array('fanid' => $fanid, 'tagid !=' => $groupid_list)); + return true; +} + + +function mc_batch_insert_fanstag_mapping($fanid_list, $tagid_list){ + if (!is_array($fanid_list) || !is_array($tagid_list)) { + return false; + } + foreach ($fanid_list as $fanid) { + foreach ($tagid_list as $tagid) { + $fanid = intval($fanid); + $tagid = intval($tagid); + pdo_insert('mc_fans_tag_mapping', array('fanid' => $fanid, 'tagid' => $tagid), true); + } + } + return true; +} + + +function mc_show_tag($groupid){ + if ($groupid) { + $fans_tag = mc_fans_groups(); + $tagid_arr = explode(',', trim($groupid, ',')); + foreach ($tagid_arr as $tagid) { + $tag_show .= $fans_tag[$tagid]['name'] . ', '; + } + $tag_show = rtrim($tag_show, ', '); + } else { + $tag_show = '无标签'; + } + return $tag_show; +} + +function mc_card_settings_hide($item = '') { + $mcFields = mc_acccount_fields(); + if ($item == 'personal_info') { + if (empty($mcFields['idcard']) && empty($mcFields['height']) && empty($mcFields['weight']) && empty($mcFields['bloodtype']) && empty($mcFields['zodiac']) && empty($mcFields['constellation']) && empty($mcFields['site']) && empty($mcFields['affectivestatus']) && empty($mcFields['lookingfor']) && empty($mcFields['bio']) && empty($mcFields['interest'])) { + return true; + } + } elseif ($item == 'contact_method') { + if (empty($mcFields['telephone']) && empty($mcFields['qq']) && empty($mcFields['msn']) && empty($mcFields['taobao']) && empty($mcFields['alipay'])) { + return true; + } + } elseif ($item == 'education_info') { + if (empty($mcFields['education']) && empty($mcFields['graduateschool']) && empty($mcFields['studentid'])) { + return true; + } + } elseif ($item == 'jobedit') { + if (empty($mcFields['company']) && empty($mcFields['occupation']) && empty($mcFields['position']) && empty($mcFields['revenue'])) { + return true; + } + } elseif (empty($item)) { + if (empty($mcFields['idcard']) && empty($mcFields['height']) && empty($mcFields['weight']) + && empty($mcFields['bloodtype']) && empty($mcFields['zodiac']) && empty($mcFields['constellation']) + && empty($mcFields['site']) && empty($mcFields['affectivestatus']) && empty($mcFields['lookingfor']) + && empty($mcFields['bio']) && empty($mcFields['interest']) && empty($mcFields['telephone']) + && empty($mcFields['qq']) && empty($mcFields['msn']) && empty($mcFields['taobao']) + && empty($mcFields['alipay']) && empty($mcFields['education']) && empty($mcFields['graduateschool']) + && empty($mcFields['studentid']) && empty($mcFields['company']) && empty($mcFields['occupation']) + && empty($mcFields['position']) && empty($mcFields['revenue']) && empty($mcFields['avatar']) + && empty($mcFields['nickname']) && empty($mcFields['realname']) && empty($mcFields['gender']) + && empty($mcFields['birthyear']) && empty($mcFields['resideprovince'])) { + return true; + } + } + return false; +} + + +function mc_card_grant_credit($openid, $card_fee, $storeid = 0, $modulename) { + global $_W; + $setting = uni_setting($_W['uniacid'], array('creditbehaviors')); + load()->model('card'); + $recharges_set = card_params_setting('cardRecharge'); + $card_settings = card_setting(); + $grant_rate = $card_settings['grant_rate']; + $grant_rate_switch = intval($recharges_set['params']['grant_rate_switch']); + $grant_credit1_enable = false; + if (!empty($grant_rate)) { + if (empty($recharges_set['params']['recharge_type'])) { + $grant_credit1_enable = true; + } else { + if ($grant_rate_switch == '1') { + $grant_credit1_enable = true; + } + } + } + if (!empty($grant_credit1_enable)) { + $num = $card_fee * $grant_rate; + $tip = "用户消费{$card_fee}元,支付金额{$card_fee},积分赠送比率为:【1:{$grant_rate}】,共赠送【{$num}】积分"; + mc_credit_update($openid, 'credit1', $num, array('0', $tip, $modulename, 0, $storeid, 3)); + return error(0, $num); + } else { + return error(-1, ''); + } +} + + +function mc_current_real_uniacid() { + global $_W; + if (!empty($_W['account']['link_uniacid']) || (!empty($_W['account']) && $_W['uniacid'] != $_W['account']['uniacid'])) { + return $_W['account']['uniacid']; + } else { + return $_W['uniacid']; + } +} + +function mc_parse_profile($profile) { + global $_W; + if (empty($profile)) { + return array(); + } + if (!empty($profile['avatar'])) { + $profile['avatar'] = tomedia($profile['avatar']); + } else { + $profile['avatar'] = './resource/images/nopic.jpg'; + } + $profile['avatarUrl'] = $profile['avatar']; + $profile['birth'] = array( + 'year' => $profile['birthyear'], + 'month' => $profile['birthmonth'], + 'day' => $profile['birthday'], + ); + $profile['reside'] = array( + 'province' => $profile['resideprovince'], + 'city' => $profile['city'], + 'district' => $profile['dist'] + ); + if(empty($profile['email']) || (!empty($profile['email']) && substr($profile['email'], -6) == 'we7.cc' && strlen($profile['email']) == 39)) { + $profile['email'] = ''; + } + return $profile; +}; + +function mc_member_export_parse($members, $header = array(), $type = 'userinfo'){ + if (empty($members)) { + return false; + } + if ('userinfo' == $type) { + $groups = mc_groups(); + } + $keys = array_keys($header); + $html = "\xEF\xBB\xBF"; + foreach ($header as $li) { + $html .= $li . "\t ,"; + } + $html .= "\n"; + $count = count($members); + $pagesize = ceil($count/5000); + for ($j = 1; $j <= $pagesize; $j++) { + $list = array_slice($members, ($j-1) * 5000, 5000); + if (!empty($list)) { + $size = ceil(count($list) / 500); + for ($i = 0; $i < $size; $i++) { + $buffer = array_slice($list, $i * 500, 500); + $user = array(); + foreach ($buffer as $row) { + if ('userinfo' == $type) { + if (strexists($row['email'], 'we7.cc')) { + $row['email'] = ''; + } + $row['groupid'] = $groups[$row['groupid']]['title']; + } elseif ('creditinfo' == $type) { + $row['credittype'] = $row['credittype'] == 'credit1' ? '积分' : '余额'; + } + $row['createtime'] = date('Y-m-d H:i:s', $row['createtime']); + foreach ($keys as $key) { + $data[] = $row[$key]; + } + $user[] = implode("\t ,", $data) . "\t ,"; + unset($data); + } + $html .= implode("\n", $user) . "\n"; + } + } + } + return $html; +} + + +function mc_fans_has_member_info($tag) { + if (is_base64($tag)) { + $tag = base64_decode($tag); + } + if (is_serialized($tag)) { + $tag = iunserializer($tag); + } + $profile = array(); + if (!empty($tag)) { + if(!empty($tag['nickname'])) { + $profile['nickname'] = $tag['nickname']; + } + if(!empty($tag['sex'])) { + $profile['gender'] =$tag['sex']; + } + if(!empty($tag['province'])) { + $profile['resideprovince'] = $tag['province']; + } + if(!empty($tag['city'])) { + $profile['residecity'] = $tag['city']; + } + if(!empty($tag['country'])) { + $profile['nationality'] = $tag['country']; + } + if(!empty($tag['headimgurl'])) { + $profile['avatar'] = rtrim($tag['headimgurl']); + } + } + return $profile; +} + + +function mc_fans_chats_record_formate($chat_record) { + load()->model('material'); + if (empty($chat_record)) { + return array(); + } + foreach ($chat_record as &$record) { + if ($record['flag'] == FANS_CHATS_FROM_SYSTEM) { + $record['content'] = iunserializer($record['content']); + if (isset($record['content']['media_id']) && !empty($record['content']['media_id'])) { + $material = material_get($record['content']['media_id']); + switch($record['msgtype']) { + case 'image': + $record['content'] = tomedia($material['attachment']); + break; + case 'mpnews': + $record['content'] = $material['news'][0]['thumb_url']; + break; + case 'music': + $record['content'] = $material['filename']; + break; + case 'voice': + $record['content'] = $material['filename']; + break; + case 'voice': + $record['content'] = $material['filename']; + break; + } + } else { + $record['content'] = urldecode($record['content']['content']); + } + } + + $record['createtime'] = date('Y-m-d H:i', $record['createtime']); + } + return $chat_record; +} + + +function mc_send_content_formate($data) { + $type = addslashes($data['type']); + if ($type == 'image') { + $contents = explode(',', htmlspecialchars_decode($data['content'])); + $get_content = array_rand($contents, 1); + $content = trim($contents[$get_content], '\"'); + } + if ($type == 'text' || $type == 'voice') { + $contents = htmlspecialchars_decode($data['content']); + $contents = explode(',', $contents); + $get_content = array_rand($contents, 1); + $content = trim($contents[$get_content], '\"'); + } + if ($type == 'news' || $type == 'music') { + $contents = htmlspecialchars_decode($data['content']); + $contents = json_decode('[' . $contents . ']', true); + $get_content = array_rand($contents, 1); + $content = $contents[$get_content]; + } + + $send['touser'] = trim($data['openid']); + $send['msgtype'] = $type; + if ($type == 'text') { + $send['text'] = array('content' => urlencode(emoji_unicode_decode($content))); + } elseif ($type == 'image') { + $send['image'] = array('media_id' => $content); + $material = material_get($content); + $content = $material['attachment']; + } elseif ($type == 'voice') { + $send['voice'] = array('media_id' => $content); + } elseif($type == 'video') { + $content = json_decode($content, true); + $send['video'] = array( + 'media_id' => $content['mediaid'], + 'thumb_media_id' => '', + 'title' => urlencode($content['title']), + 'description' => '' + ); + } elseif($type == 'music') { + $send['music'] = array( + 'musicurl' => tomedia($content['url']), + 'hqmusicurl' => tomedia($content['hqurl']), + 'title' => urlencode($content['title']), + 'description' => urlencode($content['description']), + 'thumb_media_id' => $content['thumb_media_id'], + ); + } elseif($type == 'news') { + $send['msgtype'] = 'mpnews'; + $send['mpnews'] = array( + 'media_id' => $content['mediaid'] + ); + } + return array( + 'send' => $send, + 'content' => $content + ); +} + +function mc_fans_tag_fields() { + return array( + 'subscribe' => '用户是否订阅该公众号标识,值为0时,代表此用户没有关注该公众号,拉取不到其余信息', + 'openid' => '用户的标识,对当前公众号唯一', + 'nickname' => '用户的昵称', + 'sex' => '用户的性别,值为1时是男性,值为2时是女性,值为0时是未知', + 'city' => '用户所在城市', + 'country' => '用户所在国家', + 'province' => '用户所在省份', + 'language' => '用户的语言,简体中文为zh_CN', + 'headimgurl'=> '用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像),用户没有头像时该项为空。若用户更换头像,原有头像URL将失效', + 'subscribe_time' => '用户关注时间,为时间戳。如果用户曾多次关注,则取最后关注时间', + 'unionid' => '只有在用户将公众号绑定到微信开放平台帐号后,才会出现该字段', + 'remark' => '公众号运营者对粉丝的备注,公众号运营者可在微信公众平台用户管理界面对粉丝添加备注', + 'groupid' => '用户所在的分组ID(暂时兼容用户分组旧接口)', + 'tagid_list' => '用户被打上的标签ID列表', + 'subscribe_scene' => '返回用户关注的渠道来源,ADD_SCENE_SEARCH 公众号搜索,ADD_SCENE_ACCOUNT_MIGRATION 公众号迁移,ADD_SCENE_PROFILE_CARD 名片分享,ADD_SCENE_QR_CODE 扫描二维码,ADD_SCENEPROFILE LINK 图文页内名称点击,ADD_SCENE_PROFILE_ITEM 图文页右上角菜单,ADD_SCENE_PAID 支付后关注,ADD_SCENE_OTHERS 其他', + 'qr_scene' => '二维码扫码场景(开发者自定义)', + 'qr_scene_str' => '二维码扫码场景描述(开发者自定义)', + ); +} diff --git a/framework/model/menu.mod.php b/framework/model/menu.mod.php new file mode 100644 index 0000000..cf5da9d --- /dev/null +++ b/framework/model/menu.mod.php @@ -0,0 +1,239 @@ +'简体中文', 'en'=>'zh_CN'), + array('ch'=>'繁体中文TW', 'en'=>'zh_TW'), + array('ch'=>'繁体中文HK', 'en'=>'zh_HK'), + array('ch'=>'英文', 'en'=>'en'), + array('ch'=>'印尼', 'en'=>'id'), + array('ch'=>'马来', 'en'=>'ms'), + array('ch'=>'西班牙', 'en'=>'es'), + array('ch'=>'韩国', 'en'=>'ko'), + array('ch'=>'意大利 ', 'en'=>'it'), + array('ch'=>'日本', 'en'=>'ja'), + array('ch'=>'波兰', 'en'=>'pl'), + array('ch'=>'葡萄牙', 'en'=>'pt'), + array('ch'=>'俄国', 'en'=>'ru'), + array('ch'=>'泰文', 'en'=>'th'), + array('ch'=>'越南', 'en'=>'vi'), + array('ch'=>'阿拉伯语', 'en'=>'ar'), + array('ch'=>'北印度', 'en'=>'hi'), + array('ch'=>'希伯来', 'en'=>'he'), + array('ch'=>'土耳其', 'en'=>'tr'), + array('ch'=>'德语', 'en'=>'de'), + array('ch'=>'法语', 'en'=>'fr') + ); + return $languages; +} + + +function menu_get($id) { + global $_W; + $id = intval($id); + if (empty($id)) { + return array(); + } + $menu_info = table('uni_account_menus')->getById($id); + if (!empty($menu_info)) { + return $menu_info; + } else { + return array(); + } +} + + +function menu_default() { + return table('uni_account_menus')->where('status', STATUS_ON)->getByType(MENU_CURRENTSELF); +} + + +function menu_update_currentself() { + global $_W; + $account_api = WeAccount::createByUniacid(); + $default_menu_info = $account_api->menuCurrentQuery(); + if (is_error($default_menu_info)) { + return error(-1, $default_menu_info['message']); + } + + if (empty($default_menu_info['is_menu_open']) || empty($default_menu_info['selfmenu_info'])) { + return true; + } + $default_menu = $default_menu_info['selfmenu_info']; + + $default_sub_button = array(); + if (!empty($default_menu['button'])) { + foreach ($default_menu['button'] as $key => &$button) { + if (!empty($button['sub_button'])) { + $default_sub_button[$key] = $button['sub_button']; + } else { + unset($button['sub_button']); + } + ksort($button); + } + unset($button); + } + if (!empty($default_menu)) { + ksort($default_menu); + } + $wechat_menu_data = base64_encode(iserializer($default_menu)); + $all_default_menus = table('uni_account_menus')->getAllByType(MENU_CURRENTSELF); + if (!empty($all_default_menus)) { + foreach ($all_default_menus as $menus_key => $menu_data) { + if (empty($menu_data['data'])) { + continue; + } + $single_menu_info = iunserializer(base64_decode($menu_data['data'])); + if (!is_array($single_menu_info) || empty($single_menu_info['button'])) { + continue; + } + foreach ($single_menu_info['button'] as $key => &$single_button) { + if (!empty($default_sub_button[$key])) { + $single_button['sub_button'] = $default_sub_button[$key]; + } else { + unset($single_button['sub_button']); + } + ksort($single_button); + } + unset($single_button); + ksort($single_menu_info); + $local_menu_data = base64_encode(iserializer($single_menu_info)); + if ($wechat_menu_data == $local_menu_data) { + $default_menu_id = $menus_key; + } + } + } + + if (!empty($default_menu_id)) { + pdo_update('uni_account_menus', array('status' => STATUS_ON), array('id' => $default_menu_id)); + pdo_update('uni_account_menus', array('status' => STATUS_OFF), array('uniacid' => $_W['uniacid'], 'type' => MENU_CURRENTSELF, 'id !=' => $default_menu_id)); + } else { + $insert_data = array( + 'uniacid' => $_W['uniacid'], + 'type' => MENU_CURRENTSELF, + 'group_id' => -1, + 'sex' => 0, + 'data' => $wechat_menu_data, + 'client_platform_type' => 0, + 'area' => '', + 'menuid' => 0, + 'status' => STATUS_ON + ); + pdo_insert('uni_account_menus', $insert_data); + $insert_id = pdo_insertid(); + pdo_update('uni_account_menus', array('title' => '默认菜单_'.$insert_id), array('id' => $insert_id)); + pdo_update('uni_account_menus', array('status' => STATUS_OFF), array('uniacid' => $_W['uniacid'], 'type' => MENU_CURRENTSELF, 'id !=' => $insert_id)); + } + return true; +} + + +function menu_update_conditional() { + global $_W; + $account_api = WeAccount::createByUniacid(); + $conditional_menu_info = $account_api->menuQuery(); + if (is_error($conditional_menu_info)) { + return error(-1, $conditional_menu_info['message']); + } + pdo_update('uni_account_menus', array('status' => STATUS_OFF), array('uniacid' => $_W['uniacid'], 'type' => MENU_CONDITIONAL)); + if (!empty($conditional_menu_info['conditionalmenu'])) { + foreach ($conditional_menu_info['conditionalmenu'] as $menu) { + $data = array( + 'uniacid' => $_W['uniacid'], + 'type' => MENU_CONDITIONAL, + 'group_id' => isset($menu['matchrule']['tag_id']) ? $menu['matchrule']['tag_id'] : (isset($menu['matchrule']['group_id']) ? $menu['matchrule']['group_id'] : '-1'), + 'sex' => $menu['matchrule']['sex'], + 'client_platform_type' => $menu['matchrule']['client_platform_type'], + 'area' => trim($menu['matchrule']['country']) . trim($menu['matchrule']['province']) . trim($menu['matchrule']['city']), + 'data' => base64_encode(iserializer($menu)), + 'menuid' => $menu['menuid'], + 'status' => STATUS_ON, + ); + if (!empty($menu['matchrule'])) { + $menu_info = table('uni_account_menus')->where('menuid',$menu['menuid'])->getByType(MENU_CONDITIONAL); + $menu_id = $menu_info['id']; + } + if (!empty($menu_id)) { + $data['title'] = !empty($menu_info['title']) ? $menu_info['title'] : '个性化菜单_' . $menu_id; + pdo_update('uni_account_menus', $data, array('uniacid' => $_W['uniacid'], 'id' => $menu_id)); + } else { + pdo_insert('uni_account_menus', $data); + $insert_id = pdo_insertid(); + pdo_update('uni_account_menus', array('title' => '个性化菜单_'.$insert_id), array('id' => $insert_id)); + } + } + } + return true; +} + + +function menu_delete($id) { + global $_W; + $menu_info = menu_get($id); + if (empty($menu_info)) { + return error(-1, '菜单不存在或已经删除'); + } + if ($menu_info['status'] == STATUS_OFF) { + pdo_delete('uni_account_menus', array('uniacid' => $_W['uniacid'], 'id' => $id)); + return error(0, '删除菜单成功!'); + } + if ($menu_info['type'] == MENU_CONDITIONAL && $menu_info['menuid'] > 0 && $menu_info['status'] != STATUS_OFF) { + $account_api = WeAccount::createByUniacid(); + $result = $account_api->menuDelete($menu_info['menuid']); + if (is_error($result)) { + return error(-1, $result['message']); + } + pdo_delete('uni_account_menus', array('uniacid' => $_W['uniacid'], 'id' => $id)); + } + return true; +} + + +function menu_push($id) { + global $_W; + $menu_info = menu_get($id); + if (empty($menu_info)) { + return error(-1, '菜单不存在或已删除'); + } + if ($menu_info['status'] == STATUS_OFF) { + $post = iunserializer(base64_decode($menu_info['data'])); + if (empty($post)) { + return error(-1, '菜单数据错误'); + } + $is_conditional = (!empty($post['matchrule']) && $menu_info['type'] == MENU_CONDITIONAL) ? true : false; + + $account_api = WeAccount::createByUniacid(); + $menu = $account_api->menuBuild($post, $is_conditional); + $result = $account_api->menuCreate($menu); + if (is_error($result)) { + return error(-1, $result['message']); + } + if ($menu_info['type'] == MENU_CURRENTSELF) { + pdo_update('uni_account_menus', array('status' => '1'), array('id' => $menu_info['id'])); + pdo_update('uni_account_menus', array('status' => '0'), array('id !=' => $menu_info['id'], 'uniacid' => $_W['uniacid'], 'type' => MENU_CURRENTSELF)); + } elseif ($menu_info['type'] == MENU_CONDITIONAL) { + if ($post['matchrule']['group_id'] != -1) { + $menu['matchrule']['groupid'] = $menu['matchrule']['tag_id']; + unset($menu['matchrule']['tag_id']); + } + $status = pdo_update('uni_account_menus', array('status' => STATUS_ON, 'menuid' => $result), array('uniacid' => $_W['uniacid'], 'id' => $menu_info['id'])); + } + return true; + } + if ($menu_info['status'] == STATUS_ON && $menu_info['type'] == MENU_CONDITIONAL && $menu_info['menuid'] > 0) { + $account_api = WeAccount::createByUniacid(); + $result = $account_api->menuDelete($menu_info['menuid']); + if (is_error($result)) { + return error(-1, $result['message']); + } else { + pdo_update('uni_account_menus', array('status' => STATUS_OFF), array('id' => $menu_info['id'])); + return true; + } + } +} \ No newline at end of file diff --git a/framework/model/module.mod.php b/framework/model/module.mod.php new file mode 100644 index 0000000..1d04ee0 --- /dev/null +++ b/framework/model/module.mod.php @@ -0,0 +1,708 @@ + array( + 'name' => 'business', + 'title' => '主要业务', + 'desc' => '' + ), + 'customer' => array( + 'name' => 'customer', + 'title' => '客户关系', + 'desc' => '' + ), + 'activity' => array( + 'name' => 'activity', + 'title' => '营销及活动', + 'desc' => '' + ), + 'services' => array( + 'name' => 'services', + 'title' => '常用服务及工具', + 'desc' => '' + ), + 'biz' => array( + 'name' => 'biz', + 'title' => '行业解决方案', + 'desc' => '' + ), + 'enterprise' => array( + 'name' => 'enterprise', + 'title' => '企业应用', + 'desc' => '' + ), + 'h5game' => array( + 'name' => 'h5game', + 'title' => 'H5游戏', + 'desc' => '' + ), + 'other' => array( + 'name' => 'other', + 'title' => '其他', + 'desc' => '' + ) + ); + return $types; +} + +function module_support_type() +{ + $module_support_type = array( + 'wxapp_support' => array( + 'type' => WXAPP_TYPE_SIGN, + 'type_name' => '微信小程序', + 'support' => MODULE_SUPPORT_WXAPP, + 'not_support' => MODULE_NONSUPPORT_WXAPP, + 'store_type' => STORE_TYPE_WXAPP_MODULE, + ), + 'account_support' => array( + 'type' => ACCOUNT_TYPE_SIGN, + 'type_name' => '公众号', + 'support' => MODULE_SUPPORT_ACCOUNT, + 'not_support' => MODULE_NONSUPPORT_ACCOUNT, + 'store_type' => STORE_TYPE_MODULE, + ), + 'welcome_support' => array( + 'type' => WELCOMESYSTEM_TYPE_SIGN, + 'type_name' => '系统首页', + 'support' => MODULE_SUPPORT_SYSTEMWELCOME, + 'not_support' => MODULE_NONSUPPORT_SYSTEMWELCOME, + ), + 'webapp_support' => array( + 'type' => WEBAPP_TYPE_SIGN, + 'type_name' => 'PC', + 'support' => MODULE_SUPPORT_WEBAPP, + 'not_support' => MODULE_NOSUPPORT_WEBAPP, + 'store_type' => STORE_TYPE_WEBAPP_MODULE, + ), + 'phoneapp_support' => array( + 'type' => PHONEAPP_TYPE_SIGN, + 'type_name' => 'APP', + 'support' => MODULE_SUPPORT_PHONEAPP, + 'not_support' => MODULE_NOSUPPORT_PHONEAPP, + 'store_type' => STORE_TYPE_PHONEAPP_MODULE, + ), + 'aliapp_support' => array( + 'type' => ALIAPP_TYPE_SIGN, + 'type_name' => '支付宝小程序', + 'support' => MODULE_SUPPORT_ALIAPP, + 'not_support' => MODULE_NOSUPPORT_ALIAPP, + 'store_type' => STORE_TYPE_ALIAPP_MODULE, + ), + 'baiduapp_support' => array( + 'type' => BAIDUAPP_TYPE_SIGN, + 'type_name' => '百度小程序', + 'support' => MODULE_SUPPORT_BAIDUAPP, + 'not_support' => MODULE_NOSUPPORT_BAIDUAPP, + 'store_type' => STORE_TYPE_BAIDUAPP_MODULE, + ), + 'toutiaoapp_support' => array( + 'type' => TOUTIAOAPP_TYPE_SIGN, + 'type_name' => '字节跳动小程序', + 'support' => MODULE_SUPPORT_TOUTIAOAPP, + 'not_support' => MODULE_NOSUPPORT_TOUTIAOAPP, + 'store_type' => STORE_TYPE_TOUTIAOAPP_MODULE, + ) + ); + return $module_support_type; +} + + +function module_entries($name, $types = array(), $rid = 0, $args = null) +{ + load()->func('communication'); + + global $_W; + + $ts = array('rule', 'cover', 'menu', 'home', 'profile', 'shortcut', 'function', 'mine', 'system_welcome'); + + + if (empty($types)) { + $types = $ts; + } else { + $types = array_intersect($types, $ts); + } + $bindings = pdo_getall('modules_bindings', array('module' => $name, 'entry' => $types), array(), '', 'displayorder DESC, multilevel DESC, eid ASC'); + $entries = array(); + $cache_key = cache_system_key('module_entry_call', array('module_name' => $name)); + $entry_call = cache_load($cache_key); + if (empty($entry_call)) { + $entry_call = array(); + } + foreach ($bindings as $bind) { + if (!empty($bind['call'])) { + if (empty($entry_call[$bind['entry']])) { + $call_url = url('utility/bindcall', array('modulename' => $bind['module'], 'callname' => $bind['call'], 'args' => $args, 'uniacid' => $_W['uniacid'])); + $response = ihttp_request($call_url); + if (is_error($response) || $response['code'] != 200) { + $response = ihttp_request($_W['siteroot'] . 'web/' . $call_url); + if (is_error($response) || $response['code'] != 200) { + continue; + } + } + $response = json_decode($response['content'], true); + $ret = $response['message']['message']; + if (is_array($ret)) { + foreach ($ret as $i => $et) { + if (empty($et['url'])) { + continue; + } + $urlinfo = url_params($et['url']); + $et['do'] = empty($et['do']) ? $urlinfo['do'] : $et['do']; + $et['url'] = $et['url'] . '&__title=' . urlencode($et['title']); + $entry_call[$bind['entry']][] = array('eid' => 'user_' . $i, 'title' => $et['title'], 'do' => $et['do'], 'url' => $et['url'], 'from' => 'call', 'icon' => $et['icon'], 'displayorder' => $et['displayorder']); + } + } + cache_write($cache_key, $entry_call, 300); + } + $entries[$bind['entry']] = $entry_call[$bind['entry']]; + + } else { + if (in_array($bind['entry'], array('cover', 'home', 'profile', 'shortcut'))) { + $url = murl('entry', array('eid' => $bind['eid'])); + } + if (in_array($bind['entry'], array('menu', 'system_welcome'))) { + $url = wurl("site/entry", array('eid' => $bind['eid'])); + } + if ($bind['entry'] == 'mine') { + $url = $bind['url']; + } + if ($bind['entry'] == 'rule') { + $par = array('eid' => $bind['eid']); + if (!empty($rid)) { + $par['id'] = $rid; + } + $url = wurl("site/entry", $par); + } + + if (empty($bind['icon'])) { + $bind['icon'] = 'wi wi-appsetting'; + } + if (!defined('SYSTEM_WELCOME_MODULE') && $bind['entry'] == 'system_welcome') { + continue; + } + $entries[$bind['entry']][] = array( + 'eid' => $bind['eid'], + 'title' => $bind['title'], + 'do' => $bind['do'], + 'url' => !$bind['multilevel'] ? $url : '', + 'from' => 'define', + 'icon' => $bind['icon'], + 'displayorder' => $bind['displayorder'], + 'direct' => $bind['direct'], + 'multilevel' => $bind['multilevel'], + 'parent' => $bind['parent'], + ); + } + } + return $entries; +} + +function module_app_entries($name, $types = array(), $args = null) +{ + global $_W; + $ts = array('rule', 'cover', 'menu', 'home', 'profile', 'shortcut', 'function'); + if (empty($types)) { + $types = $ts; + } else { + $types = array_intersect($types, $ts); + } + $bindings = pdo_getall('modules_bindings', array('module' => $name, 'entry' => $types)); + $entries = array(); + foreach ($bindings as $bind) { + if (!empty($bind['call'])) { + $extra = array(); + $extra['Host'] = $_SERVER['HTTP_HOST']; + load()->func('communication'); + $urlset = parse_url($_W['siteurl']); + $urlset = pathinfo($urlset['path']); + $response = ihttp_request($_W['sitescheme'] . $extra['Host'] . $urlset['dirname'] . '/' . url('utility/bindcall', array('modulename' => $bind['module'], 'callname' => $bind['call'], 'args' => $args, 'uniacid' => $_W['uniacid'])), array('W' => base64_encode(iserializer($_W))), $extra); + if (is_error($response)) { + continue; + } + $response = json_decode($response['content'], true); + $ret = $response['message']['message']; + if (is_array($ret)) { + foreach ($ret as $et) { + $et['url'] = $et['url'] . '&__title=' . urlencode($et['title']); + $entries[$bind['entry']][] = array('title' => $et['title'], 'url' => $et['url'], 'from' => 'call'); + } + } + } else { + if ($bind['entry'] == 'cover') { + $url = murl("entry", array('eid' => $bind['eid'])); + } + if ($bind['entry'] == 'home') { + $url = murl("entry", array('eid' => $bind['eid'])); + } + if ($bind['entry'] == 'profile') { + $url = murl("entry", array('eid' => $bind['eid'])); + } + if ($bind['entry'] == 'shortcut') { + $url = murl("entry", array('eid' => $bind['eid'])); + } + $entries[$bind['entry']][] = array('title' => $bind['title'], 'do' => $bind['do'], 'url' => $url, 'from' => 'define'); + } + } + return $entries; +} + +function module_entry($eid) +{ + $sql = "SELECT * FROM " . tablename('modules_bindings') . " WHERE `eid`=:eid"; + $pars = array(); + $pars[':eid'] = $eid; + $entry = pdo_fetch($sql, $pars); + if (empty($entry)) { + return error(1, '模块菜单不存在'); + } + $module = module_fetch($entry['module']); + if (empty($module)) { + return error(2, '模块不存在'); + } + $querystring = array( + 'do' => $entry['do'], + 'm' => $entry['module'], + ); + if (!empty($entry['state'])) { + $querystring['state'] = $entry['state']; + } + + $entry['url'] = murl('entry', $querystring); + $entry['url_show'] = murl('entry', $querystring, true, true); + return $entry; +} + + +function module_build_form($name, $rid, $option = array()) +{ + $rid = intval($rid); + $m = WeUtility::createModule($name); + if (!empty($m)) { + return $m->fieldsFormDisplay($rid, $option); + } else { + return null; + } + +} + + +function module_save_group_package($package) +{ + global $_W; + load()->model('user'); + load()->model('cache'); + + if (empty($package['name'])) { + return error(-1, '请输入套餐名'); + } + + if (!empty($package['modules'])) { + $package['modules'] = iserializer($package['modules']); + } + + if (!empty($package['templates'])) { + $templates = array(); + foreach ($package['templates'] as $id) { + $templates[] = $id; + } + $package['templates'] = iserializer($templates); + } + + if (!empty($package['id'])) { + $name_exist = pdo_get('uni_group', array('uniacid' => 0, 'id <>' => $package['id'], 'name' => $package['name'])); + } else { + $name_exist = pdo_get('uni_group', array('uniacid' => 0, 'name' => $package['name'])); + } + + if (!empty($name_exist)) { + return error(-1, '套餐名已存在'); + } + + if (!empty($package['id'])) { + pdo_update('uni_group', $package, array('id' => $package['id'])); + cache_build_account_modules(); + } else { + pdo_insert('uni_group', $package); + $uni_group_id = pdo_insertid(); + if (user_is_vice_founder()) { + $table = table('users_founder_own_uni_groups'); + $table->addOwnUniGroup($_W['uid'], $uni_group_id); + } + } + cache_build_uni_group(); + return error(0, '添加成功'); +} + +function module_fetch($name, $enabled = true) +{ + global $_W; + $cachekey = cache_system_key('module_info', array('module_name' => $name)); + + $module = cache_load($cachekey); + + if (empty($module)) { + $module_info = table('modules')->getByName($name); + if (empty($module_info)) { + return array(); + } + $module_info['isdisplay'] = 1; + $module_info['logo'] = tomedia($module_info['logo']); + $module_info['preview'] = tomedia(IA_ROOT . '/addons/' . $module_info['name'] . '/preview.jpg', '', true); + if (file_exists(IA_ROOT . '/addons/' . $module_info['name'] . '/preview-custom.jpg')) { + $module_info['preview'] = tomedia(IA_ROOT . '/addons/' . $module_info['name'] . '/preview-custom.jpg', '', true); + } + if (APPLICATION_TYPE_TEMPLATES == $module_info['application_type']) { + $module_info['preview'] = tomedia(IA_ROOT . '/app/themes/' . $module_info['name'] . '/preview-custom.jpg', '', true); + } + $module = $module_info; + cache_write($cachekey, $module_info); + } + + if (!empty($enabled)) { + if (!empty($module['is_delete'])) { + return array(); + } + } + + if (!empty($module) && !empty($_W['uniacid'])) { + $setting_cachekey = cache_system_key('module_setting', array('module_name' => $name, 'uniacid' => $_W['uniacid'])); + $setting = cache_load($setting_cachekey); + if (empty($setting)) { + $setting = table('uni_account_modules')->getByUniacidAndModule($name, $_W['uniacid']); + $setting = empty($setting) ? array('module' => $name) : $setting; + cache_write($setting_cachekey, $setting); + } + $module['config'] = $setting['settings']; + $module['enabled'] = $module['issystem'] || !isset($setting['enabled']) ? 1 : $setting['enabled']; + $module['displayorder'] = $setting['displayorder']; + $module['shortcut'] = $setting['shortcut']; + $module['module_shortcut'] = $setting['module_shortcut']; + } + return $module; +} + +function module_main_info($module_name) +{ + $cachekey = cache_system_key('module_main_info', array('module_name' => $module_name)); + $module = cache_load($cachekey); + if (empty($module)) { + $fileds = array('name', 'title', 'version', 'logo', 'account_support', 'wxapp_support', 'webapp_support', 'phoneapp_support', 'aliapp_support', 'baiduapp_support', 'toutiaoapp_support', 'welcome_support'); + $module_info = pdo_get('modules', array('name' => $module_name), $fileds); + if (empty($module_info)) { + return array(); + } + $module_info['logo'] = tomedia($module_info['logo']); + $module = $module_info; + cache_write($cachekey, $module_info); + } + return $module; +} + +function module_permission_fetch($name) +{ + $module = module_fetch($name); + $data = array(); + if ($module['settings']) { + $data[] = array('title' => '参数设置', 'permission' => $name . '_settings'); + } + if ($module['isrulefields']) { + $data[] = array('title' => '回复规则列表', 'permission' => $name . '_rule'); + } + $entries = module_entries($name); + if (!empty($entries['home'])) { + $data[] = array('title' => '微站首页导航', 'permission' => $name . '_home'); + } + if (!empty($entries['profile'])) { + $data[] = array('title' => '个人中心导航', 'permission' => $name . '_profile'); + } + if (!empty($entries['shortcut'])) { + $data[] = array('title' => '快捷菜单', 'permission' => $name . '_shortcut'); + } + if (!empty($entries['cover'])) { + foreach ($entries['cover'] as $cover) { + $data[] = array('title' => $cover['title'], 'permission' => $name . '_cover_' . $cover['do']); + } + } + if (!empty($entries['menu'])) { + foreach ($entries['menu'] as $menu) { + if (!empty($menu['multilevel'])) { + continue; + } + $data[$menu['do']] = array('title' => $menu['title'], 'permission' => $name . '_menu_' . $menu['do']); + } + } + unset($entries); + if (!empty($module['permissions'])) { + $module['permissions'] = (array)iunserializer($module['permissions']); + foreach ($module['permissions'] as $permission) { + if (!empty($permission['parent']) && !empty($data[$permission['parent']])) { + $sub_permission = array( + 'title' => $permission['title'], + 'permission' => $name . '_menu_' . $permission['parent'] . '_' . $permission['permission'], + ); + if (empty($data[$permission['parent']]['sub_permission'])) { + $data[$permission['parent']]['sub_permission'] = array($sub_permission); + } else { + array_push($data[$permission['parent']]['sub_permission'], $sub_permission); + } + } + $data[] = array('title' => $permission['title'], 'permission' => $name . '_permission_' . $permission['permission']); + } + } + return $data; +} + + +function module_get_plugin_list($module_name) +{ + $module_info = module_fetch($module_name); + if (!empty($module_info['plugin_list']) && is_array($module_info['plugin_list'])) { + $plugin_list = array(); + foreach ($module_info['plugin_list'] as $plugin) { + $plugin_info = module_fetch($plugin); + if (!empty($plugin_info)) { + $plugin_list[$plugin] = $plugin_info; + } + } + return $plugin_list; + } else { + return array(); + } +} + + +function module_exist_in_account($module_name, $uniacid) +{ + load()->model('user'); + $module_name = trim($module_name); + $uniacid = intval($uniacid); + if (empty($module_name) || empty($uniacid)) { + return false; + } + $result = table('uni_modules')->where(array('uniacid' => $uniacid, 'module_name' => $module_name))->getcolumn('id'); + return $result ? true : false; +} + + +function module_check_notinstalled_support($module, $manifest_support) +{ + if (empty($manifest_support)) { + return array(); + } + $has_notinstalled_support = false; + $notinstalled_support = array(); + $module_support_type = module_support_type(); + + foreach ($manifest_support as $support) { + if ($support == 'app') { + $support = 'account'; + } elseif ($support == 'system_welcome') { + $support = 'welcome'; + } elseif ($support == 'android' || $support == 'ios') { + $support = 'phoneapp'; + } + $support .= '_support'; + if (!in_array($support, array_keys($module_support_type))) { + continue; + } + + if ($module[$support] != $module_support_type[$support]['support']) { + $has_notinstalled_support = true; + $notinstalled_support[$support] = $module_support_type[$support]['support']; + } else { + $notinstalled_support[$support] = $module_support_type[$support]['not_support']; + } + } + if ($has_notinstalled_support) { + return $notinstalled_support; + } else { + return array(); + } +} + + +function module_add_to_uni_group($module, $uni_group_id, $support) +{ + if (!in_array($support, array_keys(module_support_type()))) { + return error(1, '支持类型不存在'); + } + if (empty($module[$support]) || $module[$support] != MODULE_SUPPORT_ACCOUNT) { + return error(1, '模块支持不存在'); + } + $unigroup_table = table('uni_group'); + $uni_group = $unigroup_table->getById($uni_group_id); + if (empty($uni_group)) { + return error(1, '应用权限组不存在'); + } + if (!empty($uni_group['modules'])) { + $uni_group['modules'] = iunserializer($uni_group['modules']); + } + $update_data = $uni_group['modules']; + + $key = str_replace('_support', '', $support); + $key = $key == 'account' ? 'modules' : $key; + if (!in_array($module['name'], $update_data[$key])) { + $update_data[$key][] = $module['name']; + } + return $unigroup_table->fill('modules', iserializer($update_data))->where('id', $uni_group_id)->save(); +} + + +function module_recycle($modulename, $type, $support) +{ + global $_W; + $module_support_types = module_support_type(); + $module_support_type = $module_support_types[$support]['type']; + $all_support = array_keys($module_support_types); + + if ($type == MODULE_RECYCLE_INSTALL_DISABLED) { + table('system_welcome_binddomain')->where(array('module_name' => $modulename))->delete(); + $uni_modules_table = table('uni_modules'); + $uni_accounts = $uni_modules_table->where('module_name', $modulename)->getall('uniacid'); + if (!empty($uni_accounts)) { + foreach ($uni_accounts as $uni_account_val) { + $account_info = uni_fetch($uni_account_val['uniacid']); + if ($account_info['type_sign'] == $module_support_type) { + $uni_modules_table->deleteUniModules($modulename, $uni_account_val['uniacid']); + } + } + } + + $lastuse_table = table('users_lastuse'); + $lastuse_accounts = switch_getall_lastuse_by_module($modulename); + if (!empty($lastuse_accounts)) { + foreach ($lastuse_accounts as $lastuse_account_val) { + $lastuse_account_info = uni_fetch($lastuse_account_val['uniacid']); + if ($lastuse_account_info['type_sign'] == $module_support_type) { + $lastuse_table->searchWithUid($_W['uid']); + $lastuse_table->searchWithUniacid($lastuse_account_val['uniacid']); + $lastuse_table->searchWithModule($modulename); + $lastuse_table->delete(); + } + } + } + } + + if (!in_array($support, $all_support)) { + return false; + } + if ($type == MODULE_RECYCLE_UNINSTALL_IGNORE) { + table('modules_cloud')->fill(array($support => 1, 'module_status' => MODULE_CLOUD_UNINSTALL_NORMAL))->where('name', $modulename)->save(); + } + $module_recycle = table('modules_recycle'); + $record = $module_recycle->searchWithNameType($modulename, $type)->get(); + if (empty($record)) { + return $module_recycle->fill(array('name' => $modulename, 'type' => $type, $support => 1))->save(); + } else { + $record[$support] = 1; + return $module_recycle->where('id', $record['id'])->fill($record)->save(); + } +} + + +function module_cancel_recycle($modulename, $type, $support) +{ + $all_support = array_keys(module_support_type()); + if (!in_array($support, $all_support)) { + return false; + } + $module_recycle = table('modules_recycle'); + $record = $module_recycle->searchWithNameType($modulename, $type)->get(); + if (empty($record)) { + return true; + } + $record[$support] = 0; + $is_update = false; + foreach ($all_support as $s) { + if ($record[$s] == 1) { + $is_update = true; + } + } + if ($type == MODULE_RECYCLE_UNINSTALL_IGNORE) { + table('modules_cloud')->fill(array($support => 2, 'module_status' => MODULE_CLOUD_UNINSTALL_NORMAL))->where('name', $modulename)->save(); + } + if ($is_update) { + return $module_recycle->where('id', $record['id'])->fill($record)->save(); + } else { + return $module_recycle->where('id', $record['id'])->delete(); + } +} + + +function module_get_direct_enter_status($module_name) +{ + global $_W; + if (empty($module_name)) { + return STATUS_OFF; + } + $module_setting = table('uni_account_modules')->getByUniacidAndModule($module_name, $_W['uniacid']); + $status = !empty($module_setting['settings']) && $module_setting['settings']['direct_enter'] == STATUS_ON ? STATUS_ON : STATUS_OFF; + return $status; +} + +function module_change_direct_enter_status($module_name) +{ + global $_W; + if (empty($module_name)) { + return false; + } + $module_setting = table('uni_account_modules')->getByUniacidAndModule($module_name, $_W['uniacid']); + $direct_enter_status = !empty($module_setting['settings']) && $module_setting['settings']['direct_enter'] == STATUS_ON ? STATUS_OFF : STATUS_ON; + if (empty($module_setting)) { + $data = array('direct_enter' => $direct_enter_status); + $result = table('uni_account_modules')->fill(array('settings' => iserializer($data), 'uniacid' => $_W['uniacid'], 'module' => $module_name))->save(); + } else { + $module_setting['settings']['direct_enter'] = $direct_enter_status; + $data = $module_setting['settings']; + $result = table('uni_account_modules')->fill(array('settings' => iserializer($data)))->where('module', $module_name)->where('uniacid', $_W['uniacid'])->save(); + } + return $result ? true : false; +} + +function module_delete_store_wish_goods($module_name, $support_name) +{ + load()->model('store'); + $all_type = store_goods_type_info(); + foreach ($all_type as $info) { + if ($info['group'] == 'module' && $support_name == $info['sign'] . '_support') { + $type = $info['type']; + break; + } + } + if (!empty($type)) { + pdo_update('site_store_goods', array('status' => 2), array('module' => $module_name, 'type' => $type)); + } + return true; +} + +function module_expire_notice() +{ + $module_expire = setting_load('module_expire'); + $module_expire = !empty($module_expire['module_expire']) ? $module_expire['module_expire'] : array(); + foreach ($module_expire as $value) { + if ($value['status'] == 1) { + $expire_notice = $value['notice']; + break; + } + } + if (empty($expire_notice)) { + $system_module_expire = setting_load('system_module_expire'); + $expire_notice = !empty($system_module_expire['system_module_expire']) ? $system_module_expire['system_module_expire'] : '您访问的功能模块不存在,请重新进入'; + } + return $expire_notice; +} \ No newline at end of file diff --git a/framework/model/permission.mod.php b/framework/model/permission.mod.php new file mode 100644 index 0000000..9f7a779 --- /dev/null +++ b/framework/model/permission.mod.php @@ -0,0 +1,725 @@ +model('system'); + $w7_file_permission = $acl; + $permission_frames = system_menu(); + if (!in_array($_W['role'], array(ACCOUNT_MANAGE_NAME_OPERATOR, ACCOUNT_MANAGE_NAME_MANAGER)) || empty($_W['uniacid'])) { + return $w7_file_permission; + } + + $cachekey = cache_system_key('permission', array('uniacid' => $_W['uniacid'], 'uid' => $_W['uid'])); + $cache = cache_load($cachekey); + + if (!empty($cache)) { + return $cache; + } + $permission_exist = permission_account_user_permission_exist($_W['uid'], $_W['uniacid']); + if (empty($permission_exist)) { + cache_write($cachekey, $w7_file_permission); + return $w7_file_permission; + } + $user_account_permission = permission_account_user_menu($_W['uid'], $_W['uniacid'], PERMISSION_ACCOUNT); + $user_wxapp_permission = permission_account_user_menu($_W['uid'], $_W['uniacid'], PERMISSION_WXAPP); + $account_info = uni_fetch($_W['uniacid']); + $user_other_permission = permission_account_user_menu($_W['uid'], $_W['uniacid'], $account_info->typeSign); + $user_permission = array_merge($user_account_permission, $user_wxapp_permission, $user_other_permission); + + $permission_contain = array('account', 'wxapp', 'system', 'phoneapp'); + $section = array(); + $permission_result = array(); + foreach ($permission_frames as $key => $frames) { + if (!in_array($key, $permission_contain) || empty($frames['section'])) { + continue; + } + foreach ($frames['section'] as $frame_key => $frame) { + if (empty($frame['menu'])) { + continue; + } + $section[$key][$frame_key] = $frame['menu']; + } + } + $account = permission_get_nameandurl($section[$permission_contain[0]]); + $wxapp = permission_get_nameandurl($section[$permission_contain[1]]); + $system = permission_get_nameandurl($section[$permission_contain[2]]); + $permission_result = array_merge($account, $wxapp, $system); + + foreach ($permission_result as $permission_val) { + if (in_array($permission_val['permission_name'], $user_permission)) { + $w7_file_permission[$permission_val['controller']][$_W['role']][] = $permission_val['action']; + } + } + cache_write($cachekey, $w7_file_permission); + return $w7_file_permission; +} + + +function permission_get_nameandurl($permission) { + $result = array(); + if (empty($permission)) { + return $result; + } + foreach ($permission as $menu) { + if (empty($menu)) { + continue; + } + foreach ($menu as $permission_name) { + $url_query_array = url_params($permission_name['url']); + $result[] = array( + 'url' => $permission_name['url'], + 'controller' => $url_query_array['c'], + 'action' => $url_query_array['a'], + 'permission_name' => $permission_name['permission_name'] + ); + if (!empty($permission_name['sub_permission'])) { + foreach ($permission_name['sub_permission'] as $key => $sub_permission_name) { + $sub_url_query_array = url_params($sub_permission_name['url']); + $result[] = array( + 'url' => $sub_permission_name['url'], + 'controller' => $sub_url_query_array['c'], + 'action' => $sub_url_query_array['a'], + 'permission_name' => $sub_permission_name['permission_name'], + ); + } + } + } + } + return $result; +} + + +function permission_account_user_role($uid = 0, $uniacid = 0) { + global $_W; + load()->model('user'); + $role = ''; + $uid = empty($uid) ? $_W['uid'] : intval($uid); + + if (user_is_founder($uid, true)) { + return ACCOUNT_MANAGE_NAME_FOUNDER; + } else { + $user_info = pdo_get('users', array('uid' => $uid)); + if (!empty($user_info['endtime']) && $user_info['endtime'] != USER_ENDTIME_GROUP_EMPTY_TYPE && $user_info['endtime'] != USER_ENDTIME_GROUP_UNLIMIT_TYPE && $user_info['endtime'] < TIMESTAMP) { + return ACCOUNT_MANAGE_NAME_EXPIRED; + } + if (!user_is_bind()) { + return ACCOUNT_MANAGE_NAME_UNBIND_USER; + } + if ($user_info['type'] == ACCOUNT_OPERATE_CLERK) { + return ACCOUNT_MANAGE_NAME_CLERK; + } + } + + if (!empty($uniacid)) { + $role = table('uni_account_users')->getUserRoleByUniacid($uid, $uniacid); + if ($role == ACCOUNT_MANAGE_NAME_OWNER) { + $role = ACCOUNT_MANAGE_NAME_OWNER; + } elseif ($role == ACCOUNT_MANAGE_NAME_VICE_FOUNDER) { + $role = ACCOUNT_MANAGE_NAME_VICE_FOUNDER; + } elseif ($role == ACCOUNT_MANAGE_NAME_MANAGER) { + $role = ACCOUNT_MANAGE_NAME_MANAGER; + } elseif ($role == ACCOUNT_MANAGE_NAME_OPERATOR) { + $role = ACCOUNT_MANAGE_NAME_OPERATOR; + } elseif ($role == ACCOUNT_MANAGE_NAME_CLERK) { + $role = ACCOUNT_MANAGE_NAME_CLERK; + } + return $role; + } else { + if (user_is_vice_founder($uid)) { + return ACCOUNT_MANAGE_NAME_VICE_FOUNDER; + } + $roles = table('uni_account_users')->getAllUserRole($uid); + $roles = array_keys($roles); + if (in_array(ACCOUNT_MANAGE_NAME_VICE_FOUNDER, $roles)) { + $role = ACCOUNT_MANAGE_NAME_VICE_FOUNDER; + } elseif (in_array(ACCOUNT_MANAGE_NAME_OWNER, $roles)) { + $role = ACCOUNT_MANAGE_NAME_OWNER; + } elseif (in_array(ACCOUNT_MANAGE_NAME_MANAGER, $roles)) { + $role = ACCOUNT_MANAGE_NAME_MANAGER; + } elseif (in_array(ACCOUNT_MANAGE_NAME_OPERATOR, $roles)) { + $role = ACCOUNT_MANAGE_NAME_OPERATOR; + } + } + $role = empty($role) ? user_is_vice_founder($uid) ? ACCOUNT_MANAGE_NAME_VICE_FOUNDER : ACCOUNT_MANAGE_NAME_OPERATOR : $role; + return $role; +} + + +function permission_account_user_permission_exist($uid = 0, $uniacid = 0) { + global $_W; + load()->model('user'); + $uid = intval($uid) > 0 ? $uid : $_W['uid']; + $uniacid = intval($uniacid) > 0 ? $uniacid : $_W['uniacid']; + if (user_is_founder($uid, true)) { + return false; + } + if (defined('FRAME') && FRAME == 'system') { + return true; + } + $is_exist = table('users_permission')->getUserPermissionByType($uid, $uniacid); + if(empty($is_exist)) { + return false; + } else { + return true; + } +} + + +function permission_account_user($type = 'system') { + global $_W; + $user_permission = table('users_permission')->getUserPermissionByType($_W['uid'], $_W['uniacid'], $type); + $user_permission = $user_permission['permission']; + if (empty($user_permission)) { + $user_permission = array('account*', 'wxapp*', 'phoneapp*'); + } + $permission_append = frames_menu_append(); + if (!empty($permission_append[$_W['role']])) { + $user_permission = array_merge($user_permission, $permission_append[$_W['role']]); + } + if (empty($_W['role']) && empty($_W['uniacid'])) { + $user_permission = array_merge($user_permission, $permission_append['operator']); + } + return (array)$user_permission; +} + + +function permission_account_user_menu($uid, $uniacid, $type) { + $user_menu_permission = array(); + + $uid = intval($uid); + $uniacid = intval($uniacid); + $type = trim($type); + if (empty($uid) || empty($uniacid) || empty($type)) { + return error(-1, '参数错误!'); + } + $permission_exist = permission_account_user_permission_exist($uid, $uniacid); + if (empty($permission_exist)) { + return array('all'); + } + $user_permission_table = table('users_permission'); + $user_menu_permission = $user_permission_table->getAllUserModulePermission($uid, $uniacid); + if ($type == 'modules') { + if ($user_menu_permission['modules'] && $user_menu_permission['modules']['permission'] == 'all') { + return array('all'); + } + } else { + $module = uni_modules_by_uniacid($uniacid); + $module = array_keys($module); + if (in_array($type, $module) && $user_menu_permission['modules'] && $user_menu_permission['modules']['permission'] == 'all') { + return array('all'); + } + if (in_array($type, $module) || in_array($type, array(PERMISSION_ACCOUNT, PERMISSION_WXAPP, PERMISSION_WEBAPP, PERMISSION_PHONEAPP, PERMISSION_ALIAPP, PERMISSION_BAIDUAPP, PERMISSION_TOUTIAOAPP, PERMISSION_SYSTEM))) { + $menu_permission = $user_permission_table->getUserPermissionByType($uid, $uniacid, $type); + $user_menu_permission = !empty($menu_permission['permission']) ? $menu_permission['permission'] : array(); + } + } + + return $user_menu_permission; +} + + +function permission_menu_name() { + load()->model('system'); + $menu_permission = array(); + + $menu_list = system_menu_permission_list(); + $middle_menu = array(); + $middle_sub_menu = array(); + if (!empty($menu_list)) { + foreach ($menu_list as $nav_id => $section) { + if (empty($section['section'])) { + continue; + } + foreach ($section['section'] as $section_id => $section) { + if (!empty($section['menu'])) { + $middle_menu[] = $section['menu']; + } + } + } + } + + if (!empty($middle_menu)) { + foreach ($middle_menu as $menu) { + foreach ($menu as $menu_val) { + $menu_permission[] = $menu_val['permission_name']; + if (!empty($menu_val['sub_permission'])) { + $middle_sub_menu[] = $menu_val['sub_permission']; + } + } + } + } + + if (!empty($middle_sub_menu)) { + foreach ($middle_sub_menu as $sub_menu) { + foreach ($sub_menu as $sub_menu_val) { + $menu_permission[] = $sub_menu_val['permission_name']; + } + } + } + return $menu_permission; +} + + +function permission_update_account_user($uid, $uniacid, $data) { + $uid = intval($uid); + $uniacid = intval($uniacid); + if (empty($uid) || empty($uniacid) || !in_array($data['type'], array(PERMISSION_ACCOUNT, PERMISSION_WXAPP, PERMISSION_WEBAPP, PERMISSION_PHONEAPP, PERMISSION_ALIAPP, PERMISSION_BAIDUAPP, PERMISSION_TOUTIAOAPP, PERMISSION_SYSTEM))) { + return error('-1', '参数错误!'); + } + $user_menu_permission = permission_account_user_menu($uid, $uniacid, $data['type']); + if (is_error($user_menu_permission)) { + return error('-1', '参数错误!'); + } + $permission = table('users_permission')->getUserPermissionByType($uid, $uniacid, $data['type']); + if (empty($permission)) { + $result = table('users_permission')->fill(array( + 'uniacid' => $uniacid, + 'uid' => $uid, + 'type' => $data['type'], + 'permission' => $data['permission'], + ))->save(); + } else { + $result = table('users_permission')->fill(array('permission' => $data['permission']))->whereId($permission['id'])->save(); + } + return $result; +} + + + +function permission_check_account_user($permission_name, $show_message = true, $action = '') { + global $_W, $_GPC, $acl; + load()->model('module'); + $see_more_info = $acl['see_more_info']; + + if (strpos($permission_name, 'see_') === 0) { + $can_see_more = false; + if (in_array(FRAME, array('system', 'site', 'account_manage', 'myself', 'user_manage', 'permission'))) { + $can_see_more = in_array($permission_name, $see_more_info[$_W['highest_role']]) ? true : false; + } else { + if (is_array($see_more_info[$_W['role']]) && !empty($see_more_info[$_W['role']])) { + $can_see_more = in_array($permission_name, $see_more_info[$_W['role']]) ? true : false; + } + } + + $uniacid = safe_gpc_int($_GPC['uniacid']); + if(($can_see_more == true && $permission_name == 'see_account_manage_users_edit_vicefounder') || $permission_name == 'see_account_manage_users_add_viceuser') { + $founder_uid = pdo_getcolumn('uni_account_users', array('uniacid'=>$uniacid, 'role'=>'owner'), 'uid'); + if(empty($founder_uid)) $can_see_more = false; + $owner_uid = pdo_getcolumn('users', array('uid'=>$founder_uid), 'owner_uid'); + if($owner_uid) $can_see_more = false; + } + + return $can_see_more; + } + + $user_has_permission = permission_account_user_permission_exist(); + if (empty($user_has_permission)) { + return true; + } + $modulename = safe_gpc_string($_GPC['module_name']) ?: safe_gpc_string($_GPC['m']); + $do = trim($_GPC['do']); + $entry_id = intval($_GPC['eid']); + + if ($action == 'reply') { + $system_modules = module_system(); + if (!empty($modulename) && !in_array($modulename, $system_modules)) { + $permission_name = $modulename . '_rule'; + $users_permission = permission_account_user($modulename); + } + } elseif ($action == 'cover' && $entry_id > 0) { + load()->model('module'); + $entry = module_entry($entry_id); + if (!empty($entry)) { + $permission_name = $entry['module'] . '_cover_' . trim($entry['do']); + $users_permission = permission_account_user($entry['module']); + } + } elseif ($action == 'nav') { + if(!empty($modulename)) { + $permission_name = "{$modulename}_{$do}"; + $users_permission = permission_account_user($modulename); + } else { + return true; + } + } elseif ($action == 'wxapp' || !empty($_W['account']) && $_W['account']['type_sign'] == WXAPP_TYPE_SIGN) { + $users_permission = permission_account_user('wxapp'); + } else { + $users_permission = permission_account_user('system'); + } + if (!isset($users_permission)) { + $users_permission = permission_account_user('system'); + } + if ($users_permission[0] != 'all' && !in_array($permission_name, $users_permission) && !in_array(FRAME . '*', $users_permission)) { + if (in_array($permission_name, permission_first_sub_permission()) && !empty($show_message)) { + load()->model('system'); + $permission_string = explode('_', $permission_name); + $goto_permission = permission_subpermission($permission_string[0] . '_' . $permission_string[1] . '_'); + $system_menu = system_menu_permission_list(ACCOUNT_MANAGE_NAME_OPERATOR); + $goto_url = $system_menu[FRAME]['section'][$permission_string[0]]['menu'][$permission_string[0] . '_' . $permission_string[1]]['sub_permission'][$goto_permission]['url']; + itoast('', $goto_url); + } + if ($show_message) { + empty($_W['isajax']) ? itoast('您没有进行该操作的权限!', '', '') : iajax(-1, '您没有进行该操作的权限'); + } else { + return false; + } + } + return true; +} + +function permission_first_sub_permission() { + return array( + 'platform_reply_keyword', + 'platform_menu_default', + 'platform_qr_qr', + 'platform_masstask_post', + 'platform_material_news', + 'platform_site_multi', + 'mc_fans_display', + 'mc_member_diaplsy', + 'profile_setting_remote', + 'profile_payment_pay', + 'statistics_visit_app', + 'wxapp_payment_pay', + ); +} + + +function permission_check_account_user_module($action = '', $module_name = '') { + global $_W, $_GPC; + $status = permission_account_user_permission_exist(); + if(empty($status)) { + return true; + } + $a = trim($_GPC['a']); + $do = trim($_GPC['do']); + $m = trim($_GPC['module_name']); + if ($a == 'manage-account' && $do == 'setting' && !empty($m)) { + $permission_name = $m . '_settings'; + $users_permission = permission_account_user($m); + if ($users_permission[0] != 'all' && !in_array($permission_name, $users_permission)) { + return false; + } + } elseif (!empty($do) && !empty($m)) { + $is_exist = table('modules_bindings')->isEntryExists($m, 'menu', $do); + if(empty($is_exist)) { + return true; + } + } + if(empty($module_name)) { + $module_name = IN_MODULE; + } + $permission = permission_account_user($module_name); + if(empty($permission) || ($permission[0] != 'all' && !empty($action) && !in_array($action, $permission))) { + return false; + } + return true; +} + + +function permission_user_account_num($uid = 0) { + global $_W; + $uid = intval($uid); + $user = $uid > 0 ? user_single($uid) : $_W['user']; + if (empty($user)) { + return array(); + } + $user_founder_info = table('users_founder_own_users')->getFounderByUid($user['uid']); + $account_all_type = uni_account_type(); + $account_all_type_sign = array_keys(uni_account_type_sign()); + $extra_group_table = table('users_extra_group'); + $extra_limit_table = table('users_extra_limit'); + + if (user_is_vice_founder($user['uid']) || !empty($user_founder_info['founder_uid'])) { + if (!empty($user_founder_info['founder_uid']) && !user_is_vice_founder($user['uid'])) { + $role = ACCOUNT_MANAGE_NAME_OWNER; + $group = table('users_group')->getById($user['groupid']); + $user_uid = $user_founder_info['founder_uid']; + } else { + $role = ACCOUNT_MANAGE_NAME_VICE_FOUNDER; + $group = table('users_founder_group')->getById($user['groupid']); + $user_uid = $user['uid']; + } + + foreach ($account_all_type_sign as $type_info) { + $key_name = $type_info . '_num'; + $group_num[$key_name] = 0; + } + $fouder_own_users_owner_account = table('account')->searchAccountList(false, 1, $fields = 'a.uniacid, b.type', $user['uid']); + $current_vice_founder_user_group_nums = 0; + if (!empty($fouder_own_users_owner_account)) { + foreach ($fouder_own_users_owner_account as $account) { + foreach ($account_all_type as $type_key => $type_info) { + if ($type_key == $account['type']) { + $key_name = $type_info['type_sign'] . '_num'; + $group_num[$key_name] += 1; + $current_vice_founder_user_group_nums += 1; + continue; + } + } + } + } + } else { + $role = ACCOUNT_MANAGE_NAME_OWNER; + $group = table('users_group')->getById($user['groupid']); + $group_num = uni_owner_account_nums($user['uid'], $role); + if (empty($_W['isfounder'])) { + if (!empty($user['owner_uid'])) { + $owner_info = table('users')->getById($user['owner_uid']); + $group_vice = table('users_founder_group')->getById($owner_info['groupid']); + + $founder_group_num = uni_owner_account_nums($owner_info['uid'], ACCOUNT_MANAGE_NAME_VICE_FOUNDER); + foreach ($account_all_type_sign as $sign) { + $maxsign = 'max' . $sign; + $group[$maxsign] = min(intval($group[$maxsign]), intval($group_vice[$maxsign])); + } + } + } + } + if (!empty($user_founder_info['founder_uid'])) { + $owner_info = table('users')->getById($user_founder_info['founder_uid']); + $group_vice = table('users_founder_group')->getById($owner_info['groupid']); + $founder_group_num = uni_owner_account_nums($owner_info['uid'], ACCOUNT_MANAGE_NAME_VICE_FOUNDER); + } + $store_order_table = table('site_store_order'); + $store_create_table = table('site_store_create_account'); + foreach ($account_all_type_sign as $type_sign) { + $create_buy_num[$type_sign] = $store_create_table->getUserCreateNumByType($user['uid'], $type_sign); + } + foreach ($account_all_type_sign as $type_sign) { + $store_buy[$type_sign] = $store_order_table->getUserBuyNumByType($user['uid'], $type_sign); + $store_buy[$type_sign] = $store_buy[$type_sign] < 0 ? 0 : $store_buy[$type_sign]; + } + + $extra_create_group_info = array_keys($extra_group_table->getCreateGroupsByUid($user['uid'])); + $extra_limits_info = $extra_limit_table->getExtraLimitByUid($user['uid']); + if (!empty($user_founder_info['founder_uid'])) { + $founder_extra_create_group_info = array_keys($extra_group_table->getCreateGroupsByUid($user_founder_info['founder_uid'])); + $founder_extra_limits_info = $extra_limit_table->getExtraLimitByUid($user_founder_info['founder_uid']); + + $vice_founder_own_users_create_accounts = table('account')->searchAccountList(false, 1, $fields = 'a.uniacid, b.type', $user_founder_info['founder_uid']); + $vice_founder_own_users_create_nums = array(); + foreach ($account_all_type_sign as $type_info) { + $key_name = $type_info . '_num'; + $vice_founder_own_users_create_nums[$key_name] = 0; + } + if (!empty($vice_founder_own_users_create_accounts)) { + foreach ($vice_founder_own_users_create_accounts as $vice_founder_own_users_create_account){ + foreach ($account_all_type as $type_key => $type_info) { + if ($vice_founder_own_users_create_account['type'] == $type_key) { + $key_name = $type_info['type_sign'] . '_num'; + $vice_founder_own_users_create_nums[$key_name] += 1; + continue; + } + } + } + } + + } + $create_group_info_all = array(); + if (!empty($extra_create_group_info)) { + $create_group_table = table('users_create_group'); + $create_groups = array(); + foreach($extra_create_group_info as $create_group_id) { + $create_group_info = $create_group_table->getById($create_group_id); + $create_groups[] = $create_group_info; + foreach ($account_all_type_sign as $sign) { + $maxsign = 'max' . $sign; + $create_group_info_all[$maxsign] += $create_group_info[$maxsign]; + } + } + } + $founcder_create_group_info_all = array(); + if (!empty($user_founder_info['founder_uid']) && !empty($extra_create_group_info)) { + $create_group_table = table('users_create_group'); + $founder_create_groups = array(); + foreach($founder_extra_create_group_info as $create_group_id) { + $create_group_info = $create_group_table->getById($create_group_id); + $founder_create_groups[] = $create_group_info; + foreach ($account_all_type_sign as $sign) { + $maxsign = 'max' . $sign; + $founcder_create_group_info_all[$maxsign] += $create_group_info[$maxsign]; + } + } + } + $extra = $limit = $founder_limit = array(); + $founder_limit_total = 0; + + foreach ($account_all_type_sign as $sign) { + $maxsign = 'max' . $sign; + $extra[$sign] = $create_group_info_all[$maxsign] + $extra_limits_info[$maxsign]; + if (!empty($user_founder_info['founder_uid'])){ + $founder_extra[$sign] = $founcder_create_group_info_all[$maxsign] + $founder_extra_limits_info[$maxsign]; + } else { + $founder_extra[$sign] = 0; + } + $sign_num = $sign . '_num'; + $limit[$sign] = max((intval($group[$maxsign]) + $extra[$sign] + intval($store_buy[$sign]) - $group_num[$sign_num]), 0); + $founder_limit[$sign] = max((intval($group_vice[$maxsign]) + $founder_extra[$sign]), 0); + + if (!empty($vice_founder_own_users_create_nums)) { + $founder_limit[$sign] -= $vice_founder_own_users_create_nums[$sign_num]; + } + $founder_limit_total += $founder_limit[$sign]; + } + $founder_limit_total = max(0, $founder_limit_total); + $data = array( + 'group_name' => $group['name'], + 'vice_group_name' => $group_vice['name'], + 'create_groups' => $create_groups, + 'founder_limit_total' => $founder_limit_total, + ); + $data['max_total'] = 0; + $data['created_total'] = 0; + $data['limit_total'] = 0; + foreach ($account_all_type_sign as $sign) { + $data["store_buy_{$sign}"] = $store_buy[$sign]; + $data["store_{$sign}_limit"] = intval($store_buy[$sign]) - intval($create_buy_num[$sign]) <= 0 ? 0 : intval($store_buy[$sign]); + $data['store_limit_total' ] += $data["store_{$sign}_limit"]; + + $maxsign = 'max' . $sign; + $sign_num = $sign . '_num'; + $data['user_group_max' . $sign] = $group[$maxsign]; + $data['usergroup_' . $sign . '_limit'] = max($group[$maxsign] - $group_num[$sign_num] - intval($create_buy_num[$sign]), 0); + $data[$maxsign] = $group[$maxsign] + intval($store_buy[$sign]) + $extra[$sign]; + $data[$sign_num] = $group_num[$sign_num]; + $data[$sign . '_limit'] = max($limit[$sign], 0); + $data['extra_' . $sign] = $extra_limits_info[$maxsign]; + $data['founder_' . $sign . '_limit'] = max($founder_limit[$sign], 0); + $data['max_total'] = $data[$maxsign] + $data['max_total']; + $data['created_total'] = $data[$sign_num] + $data['created_total']; + $data['limit_total'] = $data[$sign . '_limit'] + $data['limit_total']; + $data['current_vice_founder_user_created_total'] = !empty($current_vice_founder_user_group_nums) ? $current_vice_founder_user_group_nums : 0; + if (!empty($vice_founder_own_users_create_nums)) { + $data['vice_founder_own_users_' . $sign_num] = $vice_founder_own_users_create_nums[$sign_num]; } + } + + if (!empty($vice_founder_own_users_create_nums)) { + foreach ($vice_founder_own_users_create_nums as $vice_founder_own_users_create_num) { + $data['vice_founder_own_users_created_total'] += $vice_founder_own_users_create_num; } + } + ksort($data); + return $data; +} + +function permission_subpermission($prefix, $module = '') { + global $_W; + $result = ''; + if (empty($prefix)) { + return $result; + } + $type = !empty($module) ? safe_gpc_string($module) : ($_W['account']['type_sign'] == 'account' ? 'system' : $_W['account']['type_sign']); + $account_premission = table('users_permission')->getUserPermissionByType($_W['uid'], $_W['uniacid'], $type); + if (!empty($account_premission['permission'])) { + foreach ($account_premission['permission'] as $permission) { + $if_exist = strpos($permission, $prefix); + $result = $if_exist !== false ? $permission : ''; + if (!empty($result)) break; + } + } + return $result; +} + + +function permission_user_account_creatable($uid = 0, $type_sign = '') { + global $_W; + $uid = empty($uid) ? $_W['uid'] : $uid; + $type_sign = empty($type_sign) ? 'account' : $type_sign; + if(user_is_founder($uid) && !user_is_vice_founder()) { + return true; + } + $key = $type_sign . '_limit'; + $data = permission_user_account_num($uid); + return isset($data[$key]) && $data[$key] > 0; +} + + +function permission_user_timelimits($uid = 0) { + global $_W; + $uid = empty($uid) ? $_W['uid'] : $uid; + $user = user_single($uid); + + if (user_is_founder($uid) && !user_is_vice_founder()) { + return 0; + } + + if (user_is_vice_founder($uid)) { + $group_info = user_founder_group_detail_info($user['groupid']); + } else { + $group_info = user_group_detail_info($user['groupid']); + } + + $users_extra_limit_table = table('users_extra_limit'); + $extra_limit_info = $users_extra_limit_table->getExtraLimitByUid($uid); + + $limits = array(); + $limits['user_group'] = $group_info['timelimit']; + $limits['user_extra'] = $extra_limit_info['timelimit']; + $limits['total'] = $group_info['timelimit'] + $extra_limit_info['timelimit']; + return $limits; +} + + +function permission_check_vice_founder_limit($group_info) { + global $_W; + $timelimits = permission_user_timelimits(); + $user_end_time = user_end_time($_W['uid']); + if ($group_info['timelimit'] > $timelimits['total'] && !empty($user_end_time)) { + return error(-1, '当前用户组的有效期不能超过' . $timelimits['total'] . '天!'); + } + + $account_nums = permission_user_account_num(); + $account_all_type_sign = uni_account_type_sign(); + foreach ($account_all_type_sign as $account_type_key => $account_type_info) { + $maxtype = 'max' . $account_type_key; + if ($group_info[$maxtype] > $account_nums[$maxtype]) { + return error(-1, "当前用户组的" . $account_type_info['title'] . "个数不能超过" . $account_nums[$maxtype] . '个!'); + } + } + return true; +} + + +function permission_account_user_init($uid, $uniacid) { + $uid = intval($uid); + $uniacid = intval($uniacid); + + if (empty($uid) || empty($uniacid)) { + return error(-1, '参数错误'); + } + + $account = uni_fetch($uniacid); + $account_all_type_sign = uni_account_type_sign(); + foreach ($account_all_type_sign as $account_type_sign => $account_type_info) { + if (in_array($account['type'], $account_type_info['contain_type'])) { + $account_type = $account_type_sign == 'account' ? 'system' : $account_type_sign; + } + } + + $user_own_menu_permission = table('users_permission')->getUserPermissionByType($uid, $uniacid, $account_type); + $user_own_module_permission = table('users_permission')->getAllUserModulePermission($uid, $uniacid); + + if (empty($user_own_menu_permission)) { + $all_menu_permission = permission_menu_name(); + $user_menu_permission_data = array( + 'type' => $account_type, + 'permission' => implode('|', $all_menu_permission), + ); + permission_update_account_user($uid, $uniacid, $user_menu_permission_data); + + } + + if (empty($user_own_module_permission)) { + $insert = array( + 'uniacid' => $uniacid, + 'uid' => $uid, + 'type' => 'modules', + 'permission' => 'all', + + ); + pdo_insert('users_permission', $insert); + } + return true; +} \ No newline at end of file diff --git a/framework/model/refund.mod.php b/framework/model/refund.mod.php new file mode 100644 index 0000000..b91f734 --- /dev/null +++ b/framework/model/refund.mod.php @@ -0,0 +1,194 @@ + $tid, 'module' => $module); + if ($module != 'store') { + $params['uniacid'] = $_W['uniacid']; + } + $paylog = pdo_get('core_paylog', $params); + if (empty($paylog)) { + return error(1, '订单不存在'); + } + if ($paylog['status'] != 1) { + return error(1, '此订单还未支付成功不可退款'); + } + $refund_params = array('status' => 1, 'uniontid' => $paylog['uniontid']); + if ($module != 'store') { + $refund_params['uniacid'] = $_W['uniacid']; + } + $refund_amount = pdo_getcolumn('core_refundlog', $refund_params, 'SUM(fee)'); + if ($refund_amount >= $paylog['card_fee']) { + return error(1, '订单已退款成功'); + } + return true; +} + + +function refund_create_order($tid, $module, $fee = 0, $reason = '') { + global $_W; + load()->model('module'); + $order_can_refund = refund_order_can_refund($module, $tid); + if (is_error($order_can_refund)) { + return $order_can_refund; + } + $module_info = module_fetch($module); + $moduleid = empty($module_info['mid']) ? '000000' : sprintf("%06d", $module_info['mid']); + $refund_uniontid = date('YmdHis') . $moduleid . random(8,1); + $params = array('tid' => $tid, 'module' => $module); + if ($module != 'store') { + $params['uniacid'] = $_W['uniacid']; + } + $paylog = pdo_get('core_paylog', $params); + $uniacid = $module == 'store' ? $paylog['uniacid'] : $_W['uniacid']; + $refund = array ( + 'uniacid' => $uniacid, + 'uniontid' => $paylog['uniontid'], + 'fee' => empty($fee) ? $paylog['card_fee'] : number_format($fee, 2, '.', ''), + 'status' => 0, + 'refund_uniontid' => $refund_uniontid, + 'reason' => safe_gpc_string($reason), + 'is_wish' => $paylog['is_wish'], + ); + pdo_insert('core_refundlog', $refund); + return pdo_insertid(); +} + + +function refund($refund_id) { + load()->classs('pay'); + global $_W; + $refundlog = pdo_get('core_refundlog', array('id' => $refund_id)); + $params = array('uniontid' => $refundlog['uniontid']); + $params['uniacid'] = $refundlog['is_wish'] == 1 ? $refundlog['uniacid'] : $_W['uniacid']; + $paylog = pdo_get('core_paylog', $params); + if ($paylog['type'] == 'wechat' || $paylog['type'] == 'wxapp') { + $refund_param = reufnd_wechat_build($refund_id, $refundlog['is_wish']); + if (is_error($refund_param)) { + return $refund_param; + } + if ($refundlog['is_wish'] == 1) { + $module = 'store'; + $cert_file = ATTACHMENT_ROOT . 'store_wechat_refund_all.pem'; + } else { + $module = ''; + $cert_file = ATTACHMENT_ROOT . $_W['uniacid'] . '_wechat_refund_all.pem'; + } + + $wechat = Pay::create('wechat', $module); + $response = $wechat->refund($refund_param, $module); + unlink($cert_file); + if (is_error($response)) { + pdo_update('core_refundlog', array('status' => '-1'), array('id' => $refund_id)); + return $response; + } else { + return $response; + } + } elseif ($paylog['type'] == 'alipay') { + $refund_param = reufnd_ali_build($refund_id, $refundlog['is_wish']); + if (is_error($refund_param)) { + return $refund_param; + } + $module = $refundlog['is_wish'] == 1 ? 'store' : ''; + $ali = Pay::create('alipay', $module); + $response = $ali->refund($refund_param, $refund_id); + if (is_error($response)) { + pdo_update('core_refundlog', array('status' => '-1'), array('id' => $refund_id)); + return $response; + } else { + return $response; + } + } + return error(1, '此订单退款方式不存在'); +} + + +function reufnd_ali_build($refund_id, $is_wish = 0) { + global $_W; + if ($is_wish == 1) { + $setting = setting_load('store_pay'); + $refund_setting = $setting['store_pay']['ali_refund']; + } else { + $setting = uni_setting_load('payment', $_W['uniacid']); + $refund_setting = $setting['payment']['ali_refund']; + } + if ($refund_setting['switch'] != 1) { + return error(1, '未开启支付宝退款功能!'); + } + if (empty($refund_setting['private_key'])) { + return error(1, '缺少支付宝密钥证书!'); + } + + $refundlog = pdo_get('core_refundlog', array('id' => $refund_id)); + $uniacid = $is_wish == 1 ? $refundlog['uniacid'] : $_W['uniacid']; + $paylog = pdo_get('core_paylog', array('uniacid' => $uniacid, 'uniontid' => $refundlog['uniontid'])); + $refund_param = array( + 'app_id' => $refund_setting['app_id'], + 'method' => 'alipay.trade.refund', + 'charset' => 'utf-8', + 'sign_type' => 'RSA2', + 'timestamp' => date('Y-m-d H:i:s'), + 'version' => '1.0', + 'biz_content' => array( + 'out_trade_no' => $refundlog['uniontid'], + 'refund_amount' => $refundlog['fee'], + 'refund_reason' => $refundlog['reason'], + ) + ); + $refund_param['biz_content'] = json_encode($refund_param['biz_content']); + return $refund_param; +} + + +function reufnd_wechat_build($refund_id, $is_wish = 0) { + global $_W; + if ($is_wish == 1) { + $setting = setting_load('store_pay'); + $pay_setting = $setting['store_pay']; + $refund_setting = $setting['store_pay']['wechat_refund']; + } else { + $setting = uni_setting_load('payment', $_W['uniacid']); + $pay_setting = $setting['payment']; + $refund_setting = $setting['payment']['wechat_refund']; + } + + if ($refund_setting['switch'] != 1) { + return error(1, '未开启微信退款功能!'); + } + if (empty($refund_setting['key']) || empty($refund_setting['cert'])) { + return error(1, '缺少微信证书!'); + } + + $refundlog = pdo_get('core_refundlog', array('id' => $refund_id)); + $uniacid = $is_wish == 1 ? $refundlog['uniacid'] : $_W['uniacid']; + $paylog = pdo_get('core_paylog', array('uniacid' => $uniacid, 'uniontid' => $refundlog['uniontid'])); + $account = uni_fetch($uniacid); + $refund_param = array( + 'appid' => $is_wish == 1 ? $pay_setting['wechat']['appid'] : $account['key'], + 'mch_id' => $pay_setting['wechat']['mchid'], + 'out_trade_no' => $refundlog['uniontid'], + 'out_refund_no' => $refundlog['refund_uniontid'], + 'total_fee' => $paylog['card_fee'] * 100, + 'refund_fee' => $refundlog['fee'] * 100, + 'nonce_str' => random(8), + 'refund_desc' => $refundlog['reason'] + ); + + if ($pay_setting['wechat']['switch'] == PAYMENT_WECHAT_TYPE_SERVICE) { + $refund_param['sub_mch_id'] = $pay_setting['wechat']['sub_mch_id']; + $refund_param['sub_appid'] = $account['key']; + $proxy_account = uni_fetch($pay_setting['wechat']['service']); + $refund_param['appid'] = $proxy_account['key']; + $refund_param['mch_id'] = $proxy_account['setting']['payment']['wechat_facilitator']['mchid']; + } + $cert = authcode($refund_setting['cert'], 'DECODE'); + $key = authcode($refund_setting['key'], 'DECODE'); + + $cert_file = $is_wish == 1 ? 'store_wechat_refund_all.pem' : $_W['uniacid'] . '_wechat_refund_all.pem'; + file_put_contents(ATTACHMENT_ROOT . $cert_file, $cert . $key); + return $refund_param; +} \ No newline at end of file diff --git a/framework/model/reply.mod.php b/framework/model/reply.mod.php new file mode 100644 index 0000000..9dfc673 --- /dev/null +++ b/framework/model/reply.mod.php @@ -0,0 +1,223 @@ + 0) { + $start = ($pindex - 1) * $psize; + $sql .= " LIMIT {$start},{$psize}"; + $total = pdo_fetchcolumn('SELECT COUNT(*) FROM ' . tablename('rule') . $where, $params); + } + return pdo_fetchall($sql, $params); +} + + +function reply_single($id) { + $id = intval($id); + $result = table('rule')->getById($id); + if (empty($result)) { + return $result; + } + $result['keywords'] = table('rule_keyword')->whereRid($id)->getall(); + return $result; +} + + +function reply_keywords_search($condition = '', $params = array(), $pindex = 0, $psize = 10, &$total = 0) { + global $_W; + if (!empty($condition)) { + $where = " WHERE {$condition} "; + } + $sql = 'SELECT * FROM ' . tablename('rule_keyword') . $where . ' ORDER BY displayorder DESC, `type` ASC, id DESC'; + if ($pindex > 0) { + $start = ($pindex - 1) * $psize; + $sql .= " LIMIT {$start},{$psize}"; + $total = pdo_fetchcolumn('SELECT COUNT(*) FROM ' . tablename('rule_keyword') . $where, $params); + } + $result = pdo_fetchall($sql, $params); + if (!empty($result)) { + $rule_setting_select = table('uni_account_modules')->getByUniacidAndModule('userapi', $_W['uniacid']); + foreach ($result as $key => $val) { + if ($val['module'] == 'userapi' && empty($val['uniacid'])) { + if (empty($rule_setting_select['settings'][$val['rid']])) { + unset($result[$key]); + continue; + } + } + + $containtypes = pdo_get('rule', array('id' => $val['rid']), array('containtype')); + if (!empty($containtypes)) { + $containtype = explode(',', $containtypes['containtype']); + $containtype = array_filter($containtype); + } else { + $containtype = array(); + } + $result[$key]['reply_type'] = $containtype; + } + } else { + $result = array(); + } + return $result; +} + + +function reply_content_search($rid = 0) { + $result = array(); + $rid = intval($rid); + if (empty($rid)) { + return $result; + } + + $modules = array('basic', 'images', 'news', 'music', 'voice', 'video'); + $params = array(':rid' => $rid); + foreach ($modules as $key => $module) { + $result[$module] = pdo_fetchcolumn('SELECT COUNT(*) FROM ' . tablename($module.'_reply') . ' WHERE `rid` = :rid', $params); + $result['sum'] += $result[$module]; + } + return $result; +} + + +function reply_predefined_service() { + $predefined_service = array( + 'weather.php' => array( + 'title' => '城市天气', + 'description' => '"城市名+天气", 如: "北京天气"', + 'keywords' => array( + array('3', '^.+天气$') + ) + ), + 'baike.php' => array( + 'title' => '百度百科', + 'description' => '"百科+查询内容" 或 "定义+查询内容", 如: "百科姚明", "定义自行车"', + 'keywords' => array( + array('3', '^百科.+$'), + array('3', '^定义.+$'), + ) + ), + 'translate.php' => array( + 'title' => '即时翻译', + 'description' => '"@查询内容(中文或英文)"', + 'keywords' => array( + array('3', '^@.+$'), + ) + ), + 'calendar.php' => array( + 'title' => '今日老黄历', + 'description' => '"日历", "万年历", "黄历"或"几号"', + 'keywords' => array( + array('1', '日历'), + array('1', '万年历'), + array('1', '黄历'), + array('1', '几号'), + ) + ), + 'news.php' => array( + 'title' => '看新闻', + 'description' => '"新闻"', + 'keywords' => array( + array('1', '新闻'), + ) + ), + 'express.php' => array( + 'title' => '快递查询', + 'description' => '"快递+单号", 如: "申通1200041125"', + 'keywords' => array( + array('3', '^(申通|圆通|中通|汇通|韵达|顺丰|EMS) *[a-z0-9]{1,}$') + ) + ), + ); + return $predefined_service; +} + + +function reply_getall_common_service() { + global $_W; + $rule_setting_select = table('uni_account_modules')->getByUniacidAndModule('userapi', $_W['uniacid']); + $rule_setting_select = (array)$rule_setting_select['settings']; + $exists_rule = table('rule')->where(array('uniacid' => 0, 'module' => 'userapi', 'status' => 1))->getall(); + $service_list = array(); + $rule_ids = array(); + $api_url = array(); + if (!empty($exists_rule)) { + foreach ($exists_rule as $rule_detail) { + $rule_ids[] = $rule_detail['id']; + $service_list[$rule_detail['id']] = $rule_detail; + } + + $all_description = table('userapi_reply')->where('rid IN', $rule_ids)->getall(); + if (!empty($all_description)) { + foreach ($all_description as $description) { + $service_list[$description['rid']]['description'] = $description['description']; + $service_list[$description['rid']]['switch'] = isset($rule_setting_select[$description['rid']]) && $rule_setting_select[$description['rid']] ? 'checked' : ''; + $api_url[] = $description['apiurl']; + } + } + } + + $all_service = reply_predefined_service(); + $all_url = array_keys($all_service); + $diff_url = array_diff($all_url, $api_url); + if (!empty($diff_url)) { + foreach ($diff_url as $url) { + $userapi_reply_info = table('userapi_reply')->getByApiurl($url); + $service_list[$userapi_reply_info['rid']]['url'] = $userapi_reply_info['apiurl']; + $service_list[$userapi_reply_info['rid']]['rid'] = $userapi_reply_info['rid']; + $service_list[$userapi_reply_info['rid']]['id'] = $userapi_reply_info['id']; + $service_list[$userapi_reply_info['rid']]['name'] = $all_service[$url]['title']; + $service_list[$userapi_reply_info['rid']]['description'] = $all_service[$url]['description']; + $service_list[$userapi_reply_info['rid']]['switch'] = isset($rule_setting_select[$userapi_reply_info['rid']]) && $rule_setting_select[$userapi_reply_info['rid']] ? 'checked' : ''; + } + } + return $service_list; +} + + +function reply_insert_without_service($file) { + $all_service = reply_predefined_service(); + $all_url = array_keys($all_service); + if (!in_array($file, $all_url)) { + return false; + } + $userapi_reply_info = table('userapi_reply')->getByApiurl($file); + if (!empty($userapi_reply_info) && !empty($userapi_reply_info['rid'])) { + return $userapi_reply_info['rid']; + } + + $rule_info = array('uniacid' => 0, 'name' => $all_service[$file]['title'], 'module' => 'userapi', 'displayorder' => 255, 'status' => 1); + table('rule')->fill($rule_info)->save(); + + $rule_id = pdo_insertid(); + $rule_keyword_info = array('rid' => $rule_id, 'uniacid' => 0, 'module' => 'userapi', 'displayorder' => $rule_info['displayorder'], 'status' => $rule_info['status']); + if (!empty($all_service[$file]['keywords'])) { + foreach ($all_service[$file]['keywords'] as $keyword_info) { + $rule_keyword_info['content'] = $keyword_info[1]; + $rule_keyword_info['type'] = $keyword_info[0]; + table('rule_keyword')->fill($rule_keyword_info)->save(); + } + } + + $userapi_reply = array('rid' => $rule_id, 'description' => htmlspecialchars($all_service[$file]['description']), 'apiurl' => $file); + table('userapi_reply')->fill($userapi_reply)->save(); + return $rule_id; +} + +function reply_check_uni_default_keyword($uniacid = 0) { + global $_W; + $uniacid = empty($uniacid) ? $_W['uniacid'] : $uniacid; + + $default = uni_setting_load('default', $uniacid); + if (!empty($default['default'])) { + $rule = table('rule_keyword')->getByUniacidAndContent($uniacid, $default['default']); + if (empty($rule)) { + uni_setting_save('default', ''); + cache_delete(cache_system_key('unisetting', array('uniacid' => $uniacid))); + } + } + return true; +} \ No newline at end of file diff --git a/framework/model/setting.mod.php b/framework/model/setting.mod.php new file mode 100644 index 0000000..662ebf4 --- /dev/null +++ b/framework/model/setting.mod.php @@ -0,0 +1,45 @@ + $value) { + $record[] = "('$key', '" . iserializer($value) . "')"; + } + if ($record) { + $return = pdo_query("REPLACE INTO " . tablename('core_settings') . " (`key`, `value`) VALUES " . implode(',', $record)); + } + } else { + $return = pdo_insert('core_settings', array('key' => $key, 'value' => iserializer($data)), TRUE); + } + $cachekey = cache_system_key('setting'); + cache_write($cachekey, ''); + return $return; +} + +function setting_load($key = '') +{ + global $_W; + + $cachekey = cache_system_key('setting'); + $settings = cache_load($cachekey); + if (empty($settings)) { + $settings = pdo_getall('core_settings', array(), array(), 'key'); + if (is_array($settings)) { + foreach ($settings as $k => &$v) { + $settings[$k] = iunserializer($v['value']); + } + } + cache_write($cachekey, $settings); + } + $_W['setting'] = array_merge($settings, (array)$_W['setting']); + if (!empty($key)) { + return array($key => $settings[$key]); + } else { + return $settings; + } +} diff --git a/framework/model/switch.mod.php b/framework/model/switch.mod.php new file mode 100644 index 0000000..e3e5d82 --- /dev/null +++ b/framework/model/switch.mod.php @@ -0,0 +1,66 @@ +getByType('account_display'); + return !empty($last_use_account) ? $last_use_account['uniacid'] : 0; +} + +function switch_get_module_display() { + return table('users_lastuse')->getByType('module_display'); +} + +function switch_get_user_common_module($module_name) { + return table('users_lastuse')->getByType('module_common_' . $module_name); +} + +function switch_getall_lastuse_by_module($module_name) { + return table('users_lastuse')->searchWithModulename($module_name)->getall(); +} + +function switch_save_uniacid($uniacid) { + global $_W; + isetcookie('__uniacid', $uniacid, 7 * 86400); + return true; +} + +function switch_save_account_display($uniacid) { + switch_save_uniacid($uniacid); + return switch_save($uniacid, '', 'account_display'); +} + +function switch_save_module_display($uniacid, $module_name) { + global $_W; + load()->model('visit'); + visit_system_update(array('modulename' => $module_name, 'uid' => $_W['uid'], 'uniacid' => $uniacid)); + + return switch_save($uniacid, $module_name, 'module_display'); +} + +function switch_save_module($uniacid, $module_name) { + return switch_save($uniacid, $module_name, 'module_display_' . $module_name); +} + +function switch_save_user_common_module($uniacid, $module_name) { + return switch_save($uniacid, $module_name, 'module_common_' . $module_name); +} + +function switch_save($uniacid, $module_name, $type) { + global $_W; + if (empty($uniacid) || empty($type)) { + return false; + } + $users_lastuse_table = table('users_lastuse'); + $if_exists = $users_lastuse_table->getByType($type); + $fill_data = array('uniacid' => $uniacid, 'modulename' => $module_name); + if ($if_exists) { + $users_lastuse_table->where('id', $if_exists['id'])->fill($fill_data)->save(); + } else { + $fill_data['uid'] = $_W['uid']; + $fill_data['type'] = $type; + $users_lastuse_table->fill($fill_data)->save(); + } + return true; +} \ No newline at end of file diff --git a/framework/model/system.mod.php b/framework/model/system.mod.php new file mode 100644 index 0000000..3df4d46 --- /dev/null +++ b/framework/model/system.mod.php @@ -0,0 +1,177 @@ + $_W['uniacid']))); + if (empty($system_menu)) { + cache_build_frame_menu(); + $system_menu = cache_load(cache_system_key('system_frame', array('uniacid' => $_W['uniacid']))); + } + if ($role == ACCOUNT_MANAGE_NAME_OPERATOR) { + unset($system_menu['appmarket']); + unset($system_menu['advertisement']); + unset($system_menu['system']); + } + return $system_menu; +} + +function system_check_statcode($statcode) +{ + $allowed_stats = array( + 'baidu' => array( + 'enabled' => true, + 'reg' => '/(http[s]?\:)?\/\/hm\.baidu\.com\/hm\.js\?/' + ), + + 'qq' => array( + 'enabled' => true, + 'reg' => '/(http[s]?\:)?\/\/tajs\.qq\.com/' + ), + ); + foreach ($allowed_stats as $key => $item) { + $preg = preg_match($item['reg'], $statcode); + if (!$preg && !$item['enabled']) { + continue; + } else { + return htmlspecialchars_decode($statcode); + } + return safe_gpc_html(htmlspecialchars_decode($statcode)); + } +} + +function system_check_items() +{ + return array( + 'mbstring' => array( + 'operate' => 'system_check_php_ext', + 'description' => 'mbstring 扩展', + 'error_message' => '不支持库', + 'solution' => '安装 mbstring 扩展', + 'handle' => 'http://s.w7.cc/wo/problem/46' + ), + 'mcrypt' => array( + 'operate' => 'system_check_php_ext', + 'description' => 'mcrypt 扩展', + 'error_message' => '不支持库', + 'solution' => '安装 mcrypt 扩展', + 'handle' => 'http://s.w7.cc/wo/problem/46' + ), + 'openssl' => array( + 'operate' => 'system_check_php_ext', + 'description' => 'openssl 扩展', + 'error_message' => '不支持库', + 'solution' => '安装 openssl 扩展', + 'handle' => 'http://s.w7.cc/wo/problem/46' + ), + 'max_allowed_packet' => array( + 'operate' => 'system_check_mysql_params', + 'description' => 'mysql max_allowed_packet 值', + 'error_message' => 'max_allowed_packet 小于 20M', + 'solution' => '修改 mysql max_allowed_packet 值', + 'handle' => 'https://bbs.w7.cc/thread-33415-1-1.html' + ), + 'always_populate_raw_post_data' => array( + 'operate' => 'system_check_php_raw_post_data', + 'description' => 'php always_populate_raw_post_data 配置', + 'error_message' => '配置有误', + 'solution' => '修改 php always_populate_raw_post_data 配置为 -1', + 'handle' => 'https://s.w7.cc/wo/problem/134' + ), + ); +} + +function system_check_php_ext($extension) +{ + return extension_loaded($extension) ? true : false; +} + +function system_check_mysql_params($param) +{ + $check_result = pdo_fetchall("SHOW GLOBAL VARIABLES LIKE '{$param}'"); + return $check_result[0]['Value'] < 1024 * 1024 * 20 ? false : true; +} + +function system_check_php_raw_post_data() +{ + if (version_compare(PHP_VERSION, '7.0.0') == -1 && version_compare(PHP_VERSION, '5.6.0') >= 0) { + return @ini_get('always_populate_raw_post_data') == '-1'; + } + return true; +} + +function system_setting_items() +{ + return array( + 'bind', + 'develop_status', + 'icp', + 'policeicp', + 'login_type', + 'log_status', + 'mobile_status', + 'reason', + 'autosignout', + 'status', + 'welcome_link', + 'login_verify_status', + 'address', + 'blogo', + 'baidumap', + 'background_img', + 'company', + 'companyprofile', + 'description', + 'email', + 'footerleft', + 'footerright', + 'flogo', + 'icon', + 'keywords', + 'leftmenufixed', + 'notice', + 'oauth_bind', + 'phone', + 'person', + 'qq', + 'statcode', + 'slides', + 'showhomepage', + 'sitename', + 'template', + 'login_template', + 'url', + 'verifycode', + 'slide_logo', + ); +} + +function system_star_menu() +{ + global $_W; + $result = array( + 'platform' => array( + 'title' => '所有平台', + 'icon' => 'wi wi-platform', + 'apiurl' => url('account/display/list', array('type' => ACCOUNT_TYPE_SIGN)), + 'one_page' => 0, + 'hide_sort' => 0, + ), + ); + $account_all = table('account')->searchAccountList(); + $result['platform']['num'] = max(0, count($account_all)); + if ($result['platform']['num'] == 0) { + unset($result['platform']['num']); + } + + return $result; +} \ No newline at end of file diff --git a/framework/model/user.mod.php b/framework/model/user.mod.php new file mode 100644 index 0000000..8746167 --- /dev/null +++ b/framework/model/user.mod.php @@ -0,0 +1,1303 @@ +classs('oauth2/oauth2client'); + $support_login_types = Oauth2CLient::supportThirdLoginType(); + if (!in_array($source, $support_login_types)) { + $check_pass = safe_check_password(safe_gpc_string($user['password'])); + if (is_error($check_pass)) { + return $check_pass; + } + } + + $user['salt'] = random(8); + $user['password'] = user_hash($user['password'], $user['salt']); + $user['joinip'] = $_W['clientip']; + $user['joindate'] = TIMESTAMP; + $user['lastip'] = $_W['clientip']; + $user['lastvisit'] = TIMESTAMP; + if (!empty($user['owner_uid'])) { + $vice_founder_info = user_single($user['owner_uid']); + if (empty($vice_founder_info) || !user_is_vice_founder($vice_founder_info['uid'])) { + $user['owner_uid'] = 0; + } + } + if (empty($user['status'])) { + $user['status'] = 2; + } + if (empty($user['type'])) { + $user['type'] = USER_TYPE_COMMON; + } + + $result = pdo_insert('users', $user); + if (!empty($result)) { + $user['uid'] = pdo_insertid(); + } + + if (!empty($user['uid']) && !empty($user['owner_uid'])) { + $founder_user_add = table('users_founder_own_users')->addOwnUser($user['uid'], $user['owner_uid']); + } + return intval($user['uid']); +} + + +function user_check($user) +{ + if (empty($user) || !is_array($user)) { + return false; + } + $where = ' WHERE 1 '; + $params = array(); + if (!empty($user['uid'])) { + $where .= ' AND `uid`=:uid'; + $params[':uid'] = intval($user['uid']); + } + if (!empty($user['username'])) { + $where .= ' AND `username`=:username'; + $params[':username'] = $user['username']; + } + if (!empty($user['status'])) { + $where .= " AND `status`=:status"; + $params[':status'] = intval($user['status']); + } + if (empty($params)) { + return false; + } + $sql = 'SELECT `password`,`salt` FROM ' . tablename('users') . "$where LIMIT 1"; + $record = pdo_fetch($sql, $params); + if (empty($record) || empty($record['password']) || empty($record['salt'])) { + return false; + } + if (!empty($user['password'])) { + $password = user_hash($user['password'], $record['salt']); + return $password == $record['password']; + } + return true; +} + + +function user_is_founder($uid, $only_main_founder = false) +{ + global $_W; + $founders = explode(',', $_W['config']['setting']['founder']); + if (in_array($uid, $founders)) { + return true; + } + + if (empty($only_main_founder)) { + $founder_groupid = pdo_getcolumn('users', array('uid' => $uid), 'founder_groupid'); + if ($founder_groupid == ACCOUNT_MANAGE_GROUP_VICE_FOUNDER) { + return true; + } + } + + return false; +} + + +function user_is_vice_founder($uid = 0) +{ + global $_W; + $uid = intval($uid); + if (empty($uid)) { + $user_info = $_W['user']; + } else { + $user_info = table('users')->getById($uid); + } + if ($user_info['founder_groupid'] == ACCOUNT_MANAGE_GROUP_VICE_FOUNDER) { + return true; + } + return false; +} + + +function user_delete($uid, $is_recycle = false) +{ + load()->model('cache'); + if (!empty($is_recycle)) { + pdo_update('users', array('status' => USER_STATUS_BAN), array('uid' => $uid)); + return true; + } + + $user_accounts = table('uni_account_users')->getOwnedAccountsByUid($uid); + if (!empty($user_accounts)) { + foreach ($user_accounts as $uniacid => $account) { + cache_build_account_modules($uniacid); + } + } + $user_info = table('users')->getById($uid); + if ($user_info['founder_groupid'] == ACCOUNT_MANAGE_GROUP_VICE_FOUNDER) { + pdo_update('users', array('owner_uid' => ACCOUNT_NO_OWNER_UID), array('owner_uid' => $uid)); + pdo_update('users_group', array('owner_uid' => ACCOUNT_NO_OWNER_UID), array('owner_uid' => $uid)); + pdo_update('uni_group', array('owner_uid' => ACCOUNT_NO_OWNER_UID), array('owner_uid' => $uid)); + pdo_delete('users_founder_own_users', array('founder_uid' => $uid)); + pdo_delete('users_founder_own_users_groups', array('founder_uid' => $uid)); + pdo_delete('users_founder_own_uni_groups', array('founder_uid' => $uid)); + pdo_delete('users_founder_own_create_groups', array('founder_uid' => $uid)); + } + pdo_delete('users', array('uid' => $uid)); + pdo_delete('uni_account_users', array('uid' => $uid)); + pdo_delete('users_profile', array('uid' => $uid)); + pdo_delete('users_bind', array('uid' => $uid)); + pdo_delete('users_extra_group', array('uid' => $uid)); + pdo_delete('users_extra_limit', array('uid' => $uid)); + pdo_delete('users_extra_modules', array('uid' => $uid)); + pdo_delete('users_extra_templates', array('uid' => $uid)); + pdo_delete('users_founder_own_users', array('uid' => $uid)); + return true; +} + + +function user_single($user_or_uid) +{ + $user = $user_or_uid; + if (empty($user)) { + return false; + } + if (is_numeric($user)) { + $user = array('uid' => $user); + } + if (!is_array($user)) { + return false; + } + $where = ' WHERE 1 '; + $params = array(); + if (!empty($user['uid'])) { + $where .= ' AND u.`uid`=:uid'; + $params[':uid'] = intval($user['uid']); + } + if (!empty($user['username'])) { + $where .= ' AND u.`username`=:username'; + $params[':username'] = $user['username']; + + $user_exists = user_check($user); + $is_mobile = preg_match(REGULAR_MOBILE, $user['username']); + if (!$user_exists && !empty($user['username']) && $is_mobile) { + $sql = "select b.uid, u.username FROM " . tablename('users_bind') . " AS b LEFT JOIN " . tablename('users') . " AS u ON b.uid = u.uid WHERE b.bind_sign = :bind_sign"; + $bind_info = pdo_fetch($sql, array('bind_sign' => $user['username'])); + if (!is_array($bind_info) || empty($bind_info) || empty($bind_info['username'])) { + return false; + } + $params[':username'] = $bind_info['username']; + } + } + if (!empty($user['email'])) { + $where .= ' AND u.`email`=:email'; + $params[':email'] = $user['email']; + } + if (!empty($user['status'])) { + $where .= " AND u.`status`=:status"; + $params[':status'] = intval($user['status']); + } + if (empty($params)) { + return false; + } + $sql = 'SELECT u.*, p.avatar FROM ' . tablename('users') . ' AS u LEFT JOIN ' . tablename('users_profile') . ' AS p ON u.uid = p.uid ' . $where . ' LIMIT 1'; + + $record = pdo_fetch($sql, $params); + if (empty($record)) { + return false; + } + if (!empty($user['password'])) { + $password = user_hash($user['password'], $record['salt']); + if ($password != $record['password']) { + return false; + } + } + + $record['hash'] = md5($record['password'] . $record['salt']); + unset($record['password'], $record['salt']); + $record['name'] = $record['username']; + $record['clerk_id'] = $user['uid']; + $record['store_id'] = 0; + $record['clerk_type'] = '2'; + + $third_info = pdo_getall('users_bind', array('uid' => $record['uid']), array(), 'third_type'); + if (!empty($third_info) && is_array($third_info)) { + $record['qq_openid'] = $third_info[USER_REGISTER_TYPE_QQ]['bind_sign']; + $record['wechat_openid'] = $third_info[USER_REGISTER_TYPE_WECHAT]['bind_sign']; + $record['mobile'] = $third_info[USER_REGISTER_TYPE_MOBILE]['bind_sign']; + } + $record['notice_setting'] = iunserializer($record['notice_setting']); + return $record; +} + + +function user_related_update($uid, $user) +{ + $uid = intval($uid); + if (empty($uid) || !is_array($user)) { + return false; + } + + if (isset($user['groupid'])) { + $record['groupid'] = $user['groupid']; + $user_info = table('users')->getById($uid); + if ($user_info['founder_groupid'] == ACCOUNT_MANAGE_GROUP_VICE_FOUNDER || $user['founder_groupid'] == ACCOUNT_MANAGE_GROUP_VICE_FOUNDER) { + $group_info = user_founder_group_detail_info($user['groupid']); + } else { + $group_info = user_group_detail_info($user['groupid']); + } + if (!empty($group_info)) { + $group_info['timelimit'] = intval($group_info['timelimit']); + if ($group_info['timelimit'] > 0) { + $extra_limit_table = table('users_extra_limit'); + $extraLimit = $extra_limit_table->getExtraLimitByUid($user_info['uid']); + $time_limit = $group_info['timelimit'] + $extraLimit['timelimit']; + $user_end_time = strtotime($time_limit . ' days', max($user_info['joindate'], $user_info['starttime'])); + if (user_is_vice_founder() && !empty($_W['user']['endtime'])) { + $user_end_time = min($user_end_time, $_W['user']['endtime']); + } + } else { + $user_end_time = USER_ENDTIME_GROUP_UNLIMIT_TYPE; + } + $change_status = $user_end_time; + pdo_update('users', array('endtime' => $user_end_time), array('uid' => $uid)); + } + } + if (isset($user['endtime']) || !empty($change_status)) { + $expire_notice = setting_load('user_expire'); + if (!empty($expire_notice['user_expire']['status'])) { + $user_info = empty($user_info) ? table('users')->getById($user['uid']) : $user_info; + if ($user_info['endtime'] != $record['endtime']) { + pdo_update('users_profile', array('send_expire_status' => 0), array('uid' => intval($user_info['uid']))); + } + } + } + + return true; +} + + +function user_hash($passwordinput, $salt) +{ + global $_W; + $passwordinput = "{$passwordinput}-{$salt}-{$_W['config']['setting']['authkey']}"; + return sha1($passwordinput); +} + + +function user_password_hash($password, $uid) +{ + if (empty($password) || intval($uid) <= 0) { + return ''; + } + $user_info = table('users')->getById($uid); + if (empty($user_info)) { + return ''; + } + return md5($password . $user_info['salt']); +} + + +function user_password($passwordinput, $uid) +{ + if (empty($passwordinput) || intval($uid) <= 0) { + return ''; + } + $user_info = table('users')->getById($uid); + if (empty($user_info)) { + return ''; + } + return user_hash($passwordinput, $user_info['salt']); +} + + +function user_level() +{ + static $level = array( + '-3' => '锁定用户', + '-2' => '禁止访问', + '-1' => '禁止发言', + '0' => '普通会员', + '1' => '管理员', + ); + return $level; +} + + +function user_group() +{ + global $_W; + $users_group_table = table('users_group'); + if (user_is_vice_founder()) { + $users_group_table->getOwnUsersGroupsList($_W['uid']); + } + return $users_group_table->getUsersGroupList(); +} + + +function user_founder_group() +{ + $groups = pdo_getall('users_founder_group', array(), '*', 'id', 'id ASC'); + return $groups; +} + + +function user_group_detail_info($groupid = 0) +{ + $group_info = array(); + + $groupid = is_array($groupid) ? 0 : intval($groupid); + if (empty($groupid)) { + return $group_info; + } + $group_info = pdo_get('users_group', array('id' => $groupid)); + if (empty($group_info)) { + return $group_info; + } + + $group_info['package'] = (array)iunserializer($group_info['package']); + if (!empty($group_info['package']) && !in_array(-1, $group_info['package'])) { + $group_info['package_detail'] = uni_groups($group_info['package']); + + $group_info['user_group_modules_all'] = array(); + if (!empty($group_info['package_detail'])) { + foreach ($group_info['package_detail'] as $package_detail) { + if (!empty($package_detail['modules_all'])) { + foreach ($package_detail['modules_all'] as $mdoule_key => $module_val) { + $group_info['user_group_modules_all'][$mdoule_key] = $module_val; + } + } + } + } + } else { + $group_info['modules'] = empty($group_info['package']) ? '' : 'all'; + $group_info['templates'] = empty($group_info['package']) ? '' : 'all'; + } + + return $group_info; +} + + +function user_founder_group_detail_info($groupid = 0) +{ + $group_info = array(); + + $groupid = is_array($groupid) ? 0 : intval($groupid); + if (empty($groupid)) { + return $group_info; + } + $group_info = pdo_get('users_founder_group', array('id' => $groupid)); + if (empty($group_info)) { + return $group_info; + } + + $group_info['package'] = (array)iunserializer($group_info['package']); + if (!empty($group_info['package'])) { + $group_info['package_detail'] = uni_groups($group_info['package']); + } + return $group_info; +} + + +function user_account_detail_info($uid) +{ + $account_lists = $app_user_info = $wxapp_user_info = $webapp_user_info = array(); + $uid = intval($uid); + if (empty($uid)) { + return $account_lists; + } + + $account_users_info = table('account')->userOwnedAccount($uid); + $account_type_signs = uni_account_type(); + $accounts = array(); + if (!empty($account_users_info)) { + foreach ($account_users_info as $uniacid => $account) { + $type_sign = $account_type_signs[$account['type']]['type_sign']; + if (empty($type_sign)) { + continue; + } + $account_info = uni_fetch($uniacid); + $account_info['role'] = permission_account_user_role($uid, $uniacid); + $accounts[$type_sign][$uniacid] = $account_info; + } + } + return $accounts; +} + + +function user_modules($uid = 0) +{ + global $_W; + load()->model('module'); + if (empty($uid)) { + $uid = $_W['uid']; + } + $support_type = module_support_type(); + $modules = cache_load(cache_system_key('user_modules', array('uid' => $uid))); + if (empty($modules)) { + $user_info = user_single(array('uid' => $uid)); + $extra_modules = table('users_extra_modules')->getExtraModulesByUid($uid); + + $users_extra_group_table = table('users_extra_group'); + $extra_groups = $users_extra_group_table->getUniGroupsByUid($uid); + + if (empty($uid) || user_is_founder($uid, true)) { + $module_list = table('modules')->getNonRecycleModules(); + $module_list = modules_support_all(array_keys($module_list)); + } elseif (!empty($user_info) && $user_info['type'] == ACCOUNT_OPERATE_CLERK && $user_info['founder_groupid'] != ACCOUNT_MANAGE_GROUP_VICE_FOUNDER) { + $clerk_module = pdo_fetch("SELECT p.type FROM " . tablename('users_permission') . " p LEFT JOIN " . tablename('uni_account_users') . " u ON p.uid = u.uid AND p.uniacid = u.uniacid WHERE u.role = :role AND p.uid = :uid", array(':role' => ACCOUNT_MANAGE_NAME_CLERK, ':uid' => $uid)); + if (empty($clerk_module)) { + return array(); + } + $module_list = array($clerk_module['type'] => $clerk_module['type']); + $module_list = modules_support_all(array_keys($module_list)); + } elseif (!empty($user_info) && empty($user_info['groupid']) && empty($extra_modules) && empty($extra_groups)) { + $module_list = pdo_getall('modules', array('issystem' => 1), array('name'), 'name'); + $module_list = modules_support_all(array_keys($module_list)); + } else { + if ($user_info['founder_groupid'] == ACCOUNT_MANAGE_GROUP_VICE_FOUNDER) { + $user_group_info = user_founder_group_detail_info($user_info['groupid']); + } else { + $user_group_info = user_group_detail_info($user_info['groupid']); + } + $packageids = $user_group_info['package']; + if (!empty($packageids) && in_array('-1', $packageids)) { + $module_list = table('modules')->getNonRecycleModules(); + $module_list = modules_support_all(array_keys($module_list)); + } else { + $module_list = array(); + $package_group = (array)pdo_getall('uni_group', array('id' => $packageids)); + $uni_group_add = pdo_get('uni_group', array('uid' => $uid)); + if (!empty($uni_group_add)) { + $package_group[] = $uni_group_add; + } + + $users_extra_group_table = table('users_extra_group'); + $extra_groups = $users_extra_group_table->getUniGroupsByUid($uid); + $extra_uni_groups = pdo_getall('uni_group', array('id' => array_keys($extra_groups))); + $package_group = array_merge($package_group, $extra_uni_groups); + if (!empty($package_group)) { + foreach ($package_group as $row) { + $row['modules'] = iunserializer($row['modules']); + if (empty($row) || empty($row['modules'])) { + continue; + } + foreach ($row['modules'] as $type => $modulenames) { + if (!is_array($modulenames) || empty($modulenames)) { + continue; + } + foreach ($modulenames as $name) { + switch ($type) { + case 'modules': + $module_list[$name][] = MODULE_SUPPORT_ACCOUNT_NAME; + break; + case 'account': + $module_list[$name][] = MODULE_SUPPORT_ACCOUNT_NAME; + break; + case 'wxapp': + $module_list[$name][] = MODULE_SUPPORT_WXAPP_NAME; + break; + case 'webapp': + $module_list[$name][] = MODULE_SUPPORT_WEBAPP_NAME; + break; + case 'phoneapp': + $module_list[$name][] = MODULE_SUPPORT_PHONEAPP_NAME; + break; + case 'aliapp': + $module_list[$name][] = MODULE_SUPPORT_ALIAPP_NAME; + break; + case 'baiduapp': + $module_list[$name][] = MODULE_SUPPORT_BAIDUAPP_NAME; + break; + case 'toutiaoapp': + $module_list[$name][] = MODULE_SUPPORT_TOUTIAOAPP_NAME; + break; + case 'welcome': + $module_list[$name][] = MODULE_SUPPORT_SYSTEMWELCOME_NAME; + break; + } + } + } + } + } + } + } + + if (!empty($extra_modules)) { + foreach ($extra_modules as $extra_module_key => $extra_module_val) { + if (!empty($module_list[$extra_module_val['module_name']]) && $module_list[$extra_module_val['module_name']] == 'all') { + continue; + } + $module_list[$extra_module_val['module_name']][] = $extra_module_val['support']; + } + } + + $modules = array(); + if (!empty($module_list)) { + $have_plugin_module = array(); + $plugin_list = pdo_getall('modules_plugin', array('name' => array_keys($module_list)), array()); + if (!empty($plugin_list)) { + foreach ($plugin_list as $plugin) { + $have_plugin_module[$plugin['main_module']][$plugin['name']] = $module_list[$plugin['name']]; + unset($module_list[$plugin['name']]); + } + } + if (!empty($module_list)) { + foreach ($module_list as $module => $support) { + $modules[$module] = $support; + if (!empty($have_plugin_module[$module])) { + foreach ($have_plugin_module[$module] as $plugin => $plugin_support) { + $modules[$plugin] = $plugin_support; + } + } + } + } + } + cache_write(cache_system_key('user_modules', array('uid' => $uid)), $modules); + } + + $module_list = array(); + if (!empty($modules)) { + $modulenames = array_keys($modules); + $all_modules = table('modules')->searchWithName($modulenames)->getAll('name'); + $plugin_data = table('modules_plugin')->getAllByNameOrMainModule($modulenames); + $all_recycle_info = table('modules_recycle')->searchWithNameType($modulenames, MODULE_RECYCLE_INSTALL_DISABLED)->getall('name'); + + foreach ($all_modules as $k => $value) { + $all_modules[$k]['logo'] = tomedia($all_modules[$k]['logo']); + $all_modules[$k]['subscribes'] = (array)iunserializer($all_modules[$k]['subscribes']); + $all_modules[$k]['handles'] = (array)iunserializer($all_modules[$k]['handles']); + $all_modules[$k]['isdisplay'] = 1; + $all_modules[$k]['main_module'] = ''; + $all_modules[$k]['plugin_list'] = array(); + } + foreach ($plugin_data as $value) { + $all_modules[$value['main_module']]['plugin_list'][] = $value['name']; + $all_modules[$value['name']]['main_module'] = $value['main_module']; + $all_modules[$value['name']]['main_module_logo'] = $all_modules[$value['main_module']]['logo']; + $all_modules[$value['name']]['main_module_title'] = $all_modules[$value['main_module']]['title']; + } + + foreach ($modules as $modulename => $support) { + if (empty($all_modules[$modulename]) || (!empty($_W['account']) && is_array($support) && !in_array($_W['account']->typeSign . '_support', $support))) { + continue; + } + $module_info = $all_modules[$modulename]; + foreach ($support_type as $support_name => $value) { + if (!empty($all_recycle_info[$modulename])) { + if ($all_recycle_info[$modulename][$support_name] > 0 && $module_info[$support_name] == $value['support']) { + $module_info[$support_name] = $value['not_support']; + } + } + if ($support !== 'all' && !empty($support)) { + if ($module_info[$support_name] == $value['support'] && !in_array($support_name, $support)) { + $module_info[$support_name] = $value['not_support']; + } + } + } + + $is_continue = true; + foreach ($support_type as $support_name => $value) { + if ($module_info[$support_name] == $value['support']) { + $is_continue = false; + } + } + if ($is_continue) { + continue; + } + $module_list[$modulename] = $module_info; + } + } + return $module_list; +} + +function modules_support_all($modulenames) +{ + if (empty($modulenames)) { + return array(); + } + $data = array(); + foreach ($modulenames as $name) { + $data[$name] = 'all'; + } + return $data; +} + + +function user_login_forward($forward = '') +{ + global $_W; + load()->model('module'); + $login_forward = trim($forward); + + if (!empty($forward)) { + return $login_forward; + } + + return $url = './home.php'; + + if ($_W['isadmin']) { + return url('home/welcome/system', array('page' => 'home')); + } else { + $user_end_time = user_end_time($_W['uid']); + if (!empty($user_end_time) && strtotime($user_end_time) < TIMESTAMP) { + return url('user/profile'); + } + } + + $login_forward = user_after_login_link(); + return $login_forward; +} + +function user_invite_register_url($uid = 0) +{ + global $_W; + if (empty($uid)) { + $uid = $_W['uid']; + } + return $_W['siteroot'] . 'web/index.php?c=user&a=register&owner_uid=' . $uid; +} + + +function user_save_create_group($account_group_info) +{ + global $_W; + $account_group_table = table('users_create_group'); + + $group_name = trim($account_group_info['group_name']); + $id = $account_group_info['id']; + + if (empty($group_name)) { + return error(-1, '账户权限组不能为空'); + } + + $account_group_table->searchWithGroupName($group_name); + + if (!empty($id)) { + $account_group_table->searchWithoutId($id); + } + + $account_group_exist = $account_group_table->getCreateGroupInfo(); + + if (!empty($account_group_exist)) { + return error(-1, '账户权限组已经存在!'); + } + + if (user_is_vice_founder()) { + $premission_check_result = permission_check_vice_founder_limit($account_group_info); + if (is_error($premission_check_result)) { + return $premission_check_result; + } + } + + if (empty($id)) { + pdo_insert('users_create_group', $account_group_info); + $create_group_id = pdo_insertid(); + if (user_is_vice_founder()) { + $own_create_group_table = table('users_founder_own_create_groups'); + $own_create_group_table->addOwnCreateGroup($_W['uid'], $create_group_id); + } + } else { + pdo_update('users_create_group', $account_group_info, array('id' => $account_group_info['id'])); + } + return error(0, '添加成功!'); +} + + +function user_save_group($group_info) +{ + global $_W; + $group_table = table('users_group'); + $name = trim($group_info['name']); + if (empty($name)) { + return error(-1, '用户权限组名不能为空'); + } + + $group_table->searchWithName($name); + if (!empty($group_info['id'])) { + $group_table->searchWithNoId($group_info['id']); + } + $name_exist = $group_table->getUsersGroupList(); + + if (!empty($name_exist)) { + return error(-1, '用户权限组名已存在!'); + } + if (user_is_vice_founder()) { + $permission_check_result = permission_check_vice_founder_limit($group_info); + if (is_error($permission_check_result)) { + return $permission_check_result; + } + } + + if (!empty($group_info['package'])) { + foreach ($group_info['package'] as $value) { + $package[] = intval($value); + } + } + $group_info['package'] = iserializer($package); + if (empty($group_info['id'])) { + pdo_insert('users_group', $group_info); + $users_group_id = pdo_insertid(); + if (user_is_vice_founder()) { + $table = table('users_founder_own_users_groups'); + $table->addOwnUsersGroup($_W['uid'], $users_group_id); + } + } else { + $old_group = $group_table->getById($group_info['id']); + if (empty($old_group)) { + return error(-1, '参数有误'); + } + $result = pdo_update('users_group', $group_info, array('id' => $group_info['id'])); + if (!empty($result) && $old_group['timelimit'] != $group_info['timelimit']) { + $all_group_users = table('users') + ->where('founder_groupid', ACCOUNT_MANAGE_GROUP_GENERAL) + ->where('groupid', $old_group['id']) + ->getall(); + if (!empty($all_group_users)) { + foreach ($all_group_users as $user) { + if ($group_info['timelimit'] > 0) { + $endtime = strtotime($group_info['timelimit'] . ' days', max($user['joindate'], $user['starttime'])); + if (user_is_vice_founder() && !empty($_W['user']['endtime'])) { + $endtime = min($endtime, $_W['user']['endtime']); + } + } else { + $endtime = 0; + } + $data['endtime'] = $endtime; + pdo_update('users', $data, array('uid' => $user['uid'])); + user_related_update($user['uid'], $data); + } + } + } + } + + return error(0, '添加成功'); +} + + +function user_save_founder_group($group_info) +{ + $name = trim($group_info['name']); + if (empty($name)) { + return error(-1, '用户权限组名不能为空'); + } + + if (!empty($group_info['id'])) { + $name_exist = pdo_get('users_founder_group', array('id <>' => $group_info['id'], 'name' => $name)); + } else { + $name_exist = pdo_get('users_founder_group', array('name' => $name)); + } + + if (!empty($name_exist)) { + return error(-1, '用户权限组名已存在!'); + } + + if (!empty($group_info['package'])) { + foreach ($group_info['package'] as $value) { + $package[] = intval($value); + } + } + $group_info['package'] = iserializer($package); + + if (empty($group_info['id'])) { + pdo_insert('users_founder_group', $group_info); + } else { + $old_group = table('users_founder_group')->getById($group_info['id']); + if (empty($old_group)) { + return error(-1, '参数有误'); + } + $result = pdo_update('users_founder_group', $group_info, array('id' => $group_info['id'])); + if (!empty($result) && $old_group['timelimit'] != $group_info['timelimit']) { + $all_group_users = table('users') + ->where('founder_groupid', ACCOUNT_MANAGE_GROUP_VICE_FOUNDER) + ->where('groupid', $old_group['id']) + ->getall(); + if (!empty($all_group_users)) { + foreach ($all_group_users as $user) { + if ($group_info['timelimit'] > 0) { + $endtime = strtotime($group_info['timelimit'] . ' days', max($user['joindate'], $user['starttime'])); + } else { + $endtime = 0; + } + $data['endtime'] = $endtime; + pdo_update('users', $data, array('uid' => $user['uid'])); + user_related_update($user['uid'], $data); + } + } + } + } + + return error(0, '添加成功'); +} + + +function user_group_format($lists) +{ + if (empty($lists)) { + return $lists; + } + $all_package = array(); + foreach ($lists as $key => $group) { + if (empty($group['package'])) { + continue; + } + $package = iunserializer($group['package']); + if (!is_array($package)) { + continue; + } + $all_package = array_merge($all_package, $package); + } + $group_package = uni_groups($all_package); + + foreach ($lists as $key => $group) { + $package = iunserializer($group['package']); + $lists[$key]['package'] = $package; + $group['package'] = array(); + if (is_array($package)) { + foreach ($package as $packageid) { + $group['package'][$packageid] = $group_package[$packageid]; + } + } + if (empty($package)) { + $lists[$key]['module_nums'] = 0; + $lists[$key]['wxapp_nums'] = 0; + $lists[$key]['webapp_nums'] = 0; + $lists[$key]['phoneapp_nums'] = 0; + continue; + } + if (is_array($package) && in_array(-1, $package)) { + $lists[$key]['module_nums'] = -1; + $lists[$key]['wxapp_nums'] = -1; + $lists[$key]['webapp_nums'] = -1; + $lists[$key]['phoneapp_nums'] = -1; + continue; + } + $names = array(); + $modules = array( + 'modules' => array(), + 'wxapp' => array(), + 'webapp' => array(), + 'phoneapp' => array(), + ); + if (!empty($group['package'])) { + foreach ($group['package'] as $package) { + $names[] = $package['name']; + $package['modules'] = !empty($package['modules']) && is_array($package['modules']) ? array_keys($package['modules']) : array(); + $package['wxapp'] = !empty($package['wxapp']) && is_array($package['wxapp']) ? array_keys($package['wxapp']) : array(); + $package['webapp'] = !empty($package['webapp']) && is_array($package['webapp']) ? array_keys($package['webapp']) : array(); + $package['phoneapp'] = !empty($package['phoneapp']) && is_array($package['phoneapp']) ? array_keys($package['phoneapp']) : array(); + $modules['modules'] = array_unique(array_merge($modules['modules'], $package['modules'])); + $modules['wxapp'] = array_unique(array_merge($modules['wxapp'], $package['wxapp'])); + $modules['webapp'] = array_unique(array_merge($modules['webapp'], $package['webapp'])); + $modules['phoneapp'] = array_unique(array_merge($modules['phoneapp'], $package['phoneapp'])); + } + $lists[$key]['module_nums'] = count($modules['modules']); + $lists[$key]['wxapp_nums'] = count($modules['wxapp']); + $lists[$key]['webapp_nums'] = count($modules['webapp']); + $lists[$key]['phoneapp_nums'] = count($modules['phoneapp']); + } + $lists[$key]['packages'] = implode(',', $names); + } + return $lists; +} + + +function user_end_time($uid) +{ + $user = table('users')->getById($uid); + if ($user['endtime'] == USER_ENDTIME_GROUP_EMPTY_TYPE || $user['endtime'] == USER_ENDTIME_GROUP_UNLIMIT_TYPE) { + $user['end'] = 0; + } elseif ($user['endtime'] == USER_ENDTIME_GROUP_DELETE_TYPE) { + $user['end'] = date('Y-m-d', $user['joindate']); + } else { + $user['end'] = date('Y-m-d', $user['endtime']); + } + return $user['end']; +} + + +function user_list_format($users, $founder_list = true) +{ + if (empty($users)) { + return array(); + } + foreach ($users as &$user) { + $user['avatar'] = !empty($user['avatar']) ? $user['avatar'] : './resource/images/nopic-user.png'; + $user['joindate'] = date('Y-m-d', $user['joindate']); + if ($user['endtime'] == USER_ENDTIME_GROUP_EMPTY_TYPE || $user['endtime'] == USER_ENDTIME_GROUP_UNLIMIT_TYPE) { + $user['endtime'] = '永久有效'; + } else { + $user['endtime'] = $user['endtime'] <= TIMESTAMP ? '服务已到期' : date('Y-m-d', intval($user['endtime'])); + } + + $user['module_num'] = array(); + if ($founder_list) { + $user['account_nums'] = permission_user_account_num($user['uid']); + } + $user['groupname'] = ''; + } + return $users; +} + +function user_info_check($user) +{ + if (!preg_match(REGULAR_USERNAME, $user['username'])) { + return error(-1, '必须输入用户名,格式为 3-30 位字符,可以包括汉字、字母(不区分大小写)、数字、下划线和句点。'); + } + if (user_check(array('username' => $user['username']))) { + return error(-2, '非常抱歉,此用户名已经被注册,你需要更换注册名称!'); + } + if (istrlen($user['password']) < 8) { + return error(-3, '必须输入密码,且密码长度不得低于8位。'); + } else { + $check_pass = safe_check_password(safe_gpc_string($user['password'])); + if (is_error($check_pass)) { + return $check_pass; + } + } + if (trim($user['password']) !== trim($user['repassword'])) { + return error(-4, '两次密码不一致!'); + } + return error(0, ''); +} + + +function user_info_save($user, $is_founder_group = false) +{ + global $_W; + $check_result = user_info_check($user); + if (is_error($check_result)) { + return $check_result; + } + + $timelimit = 0; + $timeadd = 0; + if ($timelimit > 0) { + $timeadd = strtotime($timelimit . ' days'); + } + if (user_is_vice_founder() && !empty($_W['user']['endtime'])) { + $timeadd = !empty($timeadd) ? min($timeadd, $_W['user']['endtime']) : $_W['user']['endtime']; + } + if (empty($timeadd)) { + $user['endtime'] = max(0, $user['endtime']); + } else { + $user['endtime'] = empty($user['endtime']) ? $timeadd : min($timeadd, $user['endtime']); + } + unset($user['vice_founder_name']); + unset($user['repassword']); + $user_add_id = user_register($user, 'admin'); + if (empty($user_add_id)) { + return error(-1, '增加失败,请稍候重试或联系网站管理员解决!'); + } + return array('uid' => $user_add_id); +} + + +function user_detail_formate($profile) +{ + if (!empty($profile)) { + $profile['reside'] = array( + 'province' => $profile['resideprovince'], + 'city' => $profile['residecity'], + 'district' => $profile['residedist'] + ); + $profile['birth'] = array( + 'year' => $profile['birthyear'], + 'month' => $profile['birthmonth'], + 'day' => $profile['birthday'], + ); + $profile['avatar'] = tomedia($profile['avatar']); + $profile['resides'] = $profile['resideprovince'] . $profile['residecity'] . $profile['residedist']; + $profile['births'] = ($profile['birthyear'] ? $profile['birthyear'] : '--') . '年' . ($profile['birthmonth'] ? $profile['birthmonth'] : '--') . '月' . ($profile['birthday'] ? $profile['birthday'] : '--') . '日'; + } + return $profile; +} + + +function user_support_urls() +{ + global $_W; + load()->classs('oauth2/oauth2client'); + $types = OAuth2Client::supportLoginType(); + $login_urls = array(); + foreach ($types as $type) { + if (!empty($_W['setting']['thirdlogin'][$type]['authstate'])) { + $login_urls[$type] = OAuth2Client::create($type, $_W['setting']['thirdlogin'][$type]['appid'], $_W['setting']['thirdlogin'][$type]['appsecret'])->showLoginUrl(); + } + } + if (empty($login_urls)) { + $login_urls['system'] = true; + } + return $login_urls; +} + + +function user_borrow_oauth_account_list() +{ + global $_W; + $user_have_accounts = uni_user_accounts($_W['uid']); + $oauth_accounts = array(); + $jsoauth_accounts = array(); + if (!empty($user_have_accounts)) { + foreach ($user_have_accounts as $account) { + if (!empty($account['key']) && (!empty($account['secret']) || $account['type'] == ACCOUNT_TYPE_OFFCIAL_AUTH)) { + if (in_array($account['level'], array(ACCOUNT_SERVICE_VERIFY))) { + $oauth_accounts[$account['acid']] = $account['name']; + } + if (in_array($account['level'], array(ACCOUNT_SUBSCRIPTION_VERIFY, ACCOUNT_SERVICE_VERIFY))) { + $jsoauth_accounts[$account['acid']] = $account['name']; + } + } + } + } + return array( + 'oauth_accounts' => $oauth_accounts, + 'jsoauth_accounts' => $jsoauth_accounts + ); +} + + +function user_founder_templates($founder_groupid) +{ + $group_detail_info = user_founder_group_detail_info($founder_groupid); + + if (empty($group_detail_info) || empty($group_detail_info['package'])) { + return array(); + } + + if (in_array(-1, $group_detail_info['package'])) { + $template_list = table('modules')->getAllTemplates(); + return $template_list; + } + + $template_list = array(); + foreach ($group_detail_info['package'] as $uni_group) { + if (!empty($group_detail_info['package_detail'][$uni_group]['templates'])) { + $template_list = array_merge($template_list, $group_detail_info['package_detail'][$uni_group]['templates']); + } + } + return $template_list; +} + + +function user_is_bind() +{ + global $_W; + if ($_W['isfounder']) { + return true; + } + $setting_bind = empty($_W['setting']['copyright']['bind']) ? '' : $_W['setting']['copyright']['bind']; + if (!empty($_W['user']['type']) && $_W['user']['type'] == USER_TYPE_CLERK) { + $setting_bind = empty($_W['setting']['copyright']['clerk']['bind']) ? '' : $_W['setting']['copyright']['clerk']['bind']; + } + if (empty($setting_bind)) { + return true; + } + + load()->classs('oauth2/oauth2client'); + $type_info = OAuth2Client::supportBindTypeInfo($setting_bind); + if (empty($type_info)) { + return true; + } + return OAuth2Client::create($setting_bind)->isbind(); +} + + +function user_check_mobile($mobile) +{ + if (empty($mobile)) { + return error(-1, '手机号不能为空'); + } + if (!preg_match(REGULAR_MOBILE, $mobile)) { + return error(-1, '手机号格式不正确'); + } + + $find_mobile = table('users_profile')->getByMobile($mobile); + if (empty($find_mobile)) { + return error(-1, '手机号不存在'); + } + return $find_mobile; +} + + +function user_change_welcome_status($uid, $welcome_status) +{ + if (empty($uid)) { + return true; + } + $user_table = table('users'); + $user_table->fillWelcomeStatus($welcome_status)->whereUid($uid)->save(); + return true; +} + + +function user_after_login_link() +{ + global $_W; + $url = ''; + $type = WELCOME_DISPLAY_TYPE; + if (!empty($_W['user']['welcome_link'])) { + $type = $_W['user']['welcome_link']; + } + + switch ($type) { + case WELCOME_DISPLAY_TYPE: + $url = './home.php'; + break; + case PLATFORM_DISPLAY_TYPE: + case MODULE_DISPLAY_TYPE: + default: + $last_operate = table('users_operate_history')->where('uid', $_W['uid'])->orderby('createtime', 'DESC')->get(); + if (USERS_OPERATE_TYPE_ACCOUNT == $last_operate['type']) { + $url = url('account/display/platform'); + } elseif (USERS_OPERATE_TYPE_MODULE == $last_operate['type']) { + $url = url('account/display/switch', array('module_name' => $last_operate['module_name'], 'uniacid' => $last_operate['uniacid'], 'switch_uniacid' => 1)); + } + break; + } + if (empty($url)) { + $url = './home.php'; + } + return $url; +} + +function user_available_extra_fields() +{ + $default_field = array('realname', 'births', 'qq', 'mobile', 'address', 'resides'); + $fields = table('core_profile_fields')->getall(); + $extra_fields = array(); + if (!empty($fields) && is_array($fields)) { + foreach ($fields as $field_info) { + if ($field_info['available'] == 1 && $field_info['showinregister'] == 1 && !in_array($field_info['field'], $default_field)) { + $extra_fields[] = $field_info; + } + } + } + return $extra_fields; +} + +function user_lastuse_module_default_account() +{ + return table('users_lastuse')->getDefaultModulesAccount(); +} + +function user_role_title($role = '') +{ + $data = array( + ACCOUNT_MANAGE_NAME_FOUNDER => '创始人', + ACCOUNT_MANAGE_NAME_VICE_FOUNDER => '副创始人', + ACCOUNT_MANAGE_NAME_OWNER => '主管理员', + ACCOUNT_MANAGE_NAME_MANAGER => '管理员', + ACCOUNT_MANAGE_NAME_OPERATOR => '操作员', + ACCOUNT_MANAGE_NAME_CLERK => '店员', + ); + if (!empty($role)) { + return empty($data[$role]) ? '' : $data[$role]; + } + return $data; +} + + +function user_save_operate_history($type, $value) +{ + global $_W; + $vaild_type = array(USERS_OPERATE_TYPE_ACCOUNT, USERS_OPERATE_TYPE_MODULE); + if (!in_array($type, $vaild_type)) { + return false; + } + $data = array('uid' => $_W['uid'], 'type' => $type); + if (USERS_OPERATE_TYPE_ACCOUNT == $type) { + $data['uniacid'] = $value; + } elseif (USERS_OPERATE_TYPE_MODULE == $type) { + $data['module_name'] = $value; + $data['uniacid'] = $_W['uniacid']; + } + table('users_operate_history')->deleteByUidTypeOperate($data); + $data['createtime'] = TIMESTAMP; + $result = table('users_operate_history')->fill($data)->save(); + if ($result) { + return true; + } else { + return false; + } +} + +function user_load_operate_history($limit_num = 40) +{ + global $_W; + $users_operate_history_table = table('users_operate_history'); + $users_operate_history_table->searchWithLimit($limit_num); + $result = $users_operate_history_table->getALlByUid($_W['uid']); + return $result; +} + +function user_save_operate_star($type, $uniacid, $module_name) +{ + global $_W; + if (!in_array($type, array(USERS_OPERATE_TYPE_ACCOUNT, USERS_OPERATE_TYPE_MODULE)) || empty($uniacid)) { + return error(-1, '参数不合法!'); + } + if (USERS_OPERATE_TYPE_MODULE == $type) { + if (!empty($module_name) && !module_exist_in_account($module_name, $uniacid)) { + return error(-1, '平台账号无该模块权限,请更新缓存后重试!'); + } + } + $data = array('uid' => $_W['uid'], 'uniacid' => $uniacid, 'module_name' => $module_name, 'type' => $type); + if (USERS_OPERATE_TYPE_ACCOUNT == $type) { + unset($data['module_name']); + } + $if_exists = table('users_operate_star')->where($data)->get(); + if ($if_exists) { + $result = table('users_operate_star')->where($data)->delete(); + } else { + $data['createtime'] = TIMESTAMP; + $maxrank = table('users_operate_star')->getMaxRank(); + $data['rank'] = intval($maxrank) + 1; + $result = table('users_operate_star')->fill($data)->save(); + } + if ($result) { + return error(0, ''); + } else { + return error(-1, '设置失败!'); + } +} + +function user_load_operate_star($limit_num = 100) +{ + global $_W; + $users_operate_star_table = table('users_operate_star'); + $users_operate_star_table->searchWithLimit($limit_num); + $result = $users_operate_star_table->getAllByUid($_W['uid']); + return $result; +} + +function user_account_delete($uniacid) +{ + if (empty($uniacid)) { + return false; + } + $mc_oauth_fans = pdo_getall('mc_oauth_fans', array('uniacid' => $uniacid), array('id', 'oauth_openid')); + if (!empty($mc_oauth_fans)) { + $ids = $openids = $uids = array(); + foreach ($mc_oauth_fans as $key => $oauth_openid) { + $ids[] = $oauth_openid['id']; + if (empty($oauth_openid['oauth_openid'])) { + continue; + } + $openids[] = $oauth_openid['oauth_openid']; + } + if (!empty($ids)) { + pdo_delete('mc_oauth_fans', array('id' => $ids, 'uniacid' => $uniacid)); + } + if (!empty($openids)) { + $mapping_fans = pdo_getall('mc_mapping_fans', array('uniacid' => $uniacid, 'openid' => $openids), array('uid')); + $uids = array_filter(array_column($mapping_fans, 'uid')); + pdo_delete('mc_mapping_fans', array('uniacid' => $uniacid, 'openid' => $openids)); + } + if (!empty($uids)) { + pdo_delete('mc_members', array('uniacid' => $uniacid, 'uid' => $uids)); + } + } + return true; +} \ No newline at end of file diff --git a/framework/model/utility.mod.php b/framework/model/utility.mod.php new file mode 100644 index 0000000..864d3b2 --- /dev/null +++ b/framework/model/utility.mod.php @@ -0,0 +1,64 @@ +where(array( + 'uniacid' => intval($uniacid), + 'receiver' => $receiver, + 'verifycode' => $code, + 'createtime >' => (TIMESTAMP - 1800) + ))->get(); + + return !empty($data); +} + + +function utility_image_rename($image_source_url, $image_destination_url) { + global $_W; + load()->func('file'); + $image_source_url = str_replace(array("\0","%00","\r"),'',$image_source_url); + if (empty($image_source_url) || !parse_path($image_source_url)) { + return false; + } + if (!strexists($image_source_url, $_W['siteroot']) || $_W['setting']['remote']['type'] > 0) { + $img_local_path = file_remote_attach_fetch($image_source_url); + if (is_error($img_local_path)) { + return false; + } + $img_source_path = ATTACHMENT_ROOT . $img_local_path; + } else { + $img_local_path = substr($image_source_url, strlen($_W['siteroot'])); + $img_path_params = explode('/', $img_local_path); + if ($img_path_params[0] != 'attachment') { + return false; + } + $img_source_path = IA_ROOT . '/' . $img_local_path; + } + if (!file_is_image($img_source_path)) { + return false; + } + $result = copy($img_source_path, $image_destination_url); + return $result; +} + + +function utility_smscode_verify($uniacid, $receiver, $verifycode = '') { + $table = table('uni_verifycode'); + $verify_info = $table->getByReceiverVerifycode($uniacid, $receiver, $verifycode); + + if (empty($verify_info)) { + $table->updateFailedCount($receiver); + return error(-1, '短信验证码不正确'); + } else if ($verify_info['createtime'] + 120 < TIMESTAMP) { + return error(-2, '短信验证码已过期,请重新获取'); + } else { + return error(0, '短信验证码正确'); + } + +} \ No newline at end of file diff --git a/framework/table/Account/Account.php b/framework/table/Account/Account.php new file mode 100644 index 0000000..fb491ff --- /dev/null +++ b/framework/table/Account/Account.php @@ -0,0 +1,295 @@ + '0', + 'hash' => '', + 'type' => '1', + 'isconnect' => '', + 'isdeleted' => '0', + 'endtime' => '0', + 'send_account_expire_status' => 0, + 'send_api_expire_status' => 0 + ); + + public function getByUniacid($uniacid) { + return $this->where('uniacid', $uniacid)->get(); + } + + public function getUniAccountByAcid($acid) { + return $this->query + ->from($this->tableName, 'a') + ->leftjoin('uni_account', 'u') + ->on('a.uniacid', 'u.uniacid') + ->where('a.acid' , intval($acid)) + ->get(); + } + + public function getUniAccountByUniacid($uniacid) { + return $this->query + ->from($this->tableName, 'a') + ->leftjoin('uni_account', 'u') + ->on('a.uniacid', 'u.uniacid') + ->where('a.uniacid' , intval($uniacid)) + ->get(); + } + + public function getUserAccountInfo($uid, $uniacid, $account_type) { + $type_info = uni_account_type($account_type); + return $this->query->from('uni_account', 'a') + ->leftjoin($type_info['table_name'], 'w') + ->on(array('w.uniacid' => 'a.uniacid')) + ->leftjoin('uni_account_users', 'au') + ->on(array('a.uniacid' => 'au.uniacid')) + ->where(array('a.uniacid' => $uniacid)) + ->where(array('au.uid' => $uid)) + ->orderby('a.uniacid', 'asc') + ->getall('uniacid'); + } + + + public function searchAccount($expire_type, $fields, $isdeleted = 1, $uid = 0) { + global $_W; + $uid = empty($uid) ? $_W['uid'] : $uid; + $this->query->from('uni_account', 'a') + ->select($fields) + ->leftjoin('account', 'b') + ->on(array('a.uniacid' => 'b.uniacid', 'a.default_acid' => 'b.acid')) + ->where('b.isdeleted !=', $isdeleted) + ->where('a.default_acid !=', '0') + ->where('b.type <>', array(9, 10)) + ->leftjoin('uni_account_users', 'c') + ->on(array('a.uniacid' => 'c.uniacid')) + ->leftjoin('users', 'u') + ->on(array('u.uid' => 'c.uid')); + + if (!user_is_founder($uid, true)) { + if (user_is_vice_founder($uid)) { + $users_uids = table('users_founder_own_users')->getFounderOwnUsersList($uid); + $users_uids = array_keys($users_uids); + $users_uids[] = $uid; + $this->query->where('c.uid', $users_uids)->where('c.role', array('clerk', 'operator', 'manager', 'owner', 'vice_founder')); + } else { + $this->query->where('c.uid', $uid)->where('c.role <>', 'clerk'); + } + } + if ($expire_type == 'expire') { + $this->searchWithExprie(); + } elseif ($expire_type == 'unexpire') { + $this->searchWithUnExprie(); + } + return $this; + } + + public function searchWithRole($role) { + global $_W; + return $this->query->where('c.role', $role)->where('c.uid', $_W['uid']); + } + public function searchWithExprie() { + $this->query->where(array( + 'b.endtime <' => TIMESTAMP, + 'b.endtime >' => USER_ENDTIME_GROUP_UNLIMIT_TYPE + )); + return $this; + } + + public function searchWithUnExprie() { + $this->query->where(function ($query) { + $query->where(array('b.endtime' => 0)) + ->whereor(array('b.endtime' => USER_ENDTIME_GROUP_UNLIMIT_TYPE)) + ->whereor(array('b.endtime >' => TIMESTAMP)); + }); + return $this; + } + + public function searchAccountList($expire = false, $isdeleted = 1, $fields = 'a.uniacid', $uid = 0) { + $this->searchAccount($expire, $fields, $isdeleted, $uid); + $this->query->groupby('a.uniacid'); + $list = $this->query->getall('uniacid'); + return $list; + } + + public function searchAccounTotal($expire = false) { + $this->searchAccount($expire, 'count(*) as total, b.type'); + $this->query->groupby('b.type'); + $list = $this->query->getall(); + return $list; + } + + public function searchWithKeyword($title) { + global $_W; + if (empty($title)) { + return $this; + } + if ($title == 'admin' && $_W['isadmin']) { + $this->query->where('ISNULL(c.uid)', true); + } else { + if ($_W['isfounder']){ + $user = table('uni_account_users') + ->searchWithUsers() + ->where('a.role', 'owner') + ->where('b.username', $title); + if (user_is_vice_founder($_W['uid'])) { + $uids = table('users_founder_own_users')->where('founder_uid', $_W['uid'])->getall('uid'); + if (!empty($uid)) { + $user->where('a.uid', array_keys($uids)); + } + } + $user = $user->get(); + } + !empty($user) && user_is_founder($user['uid'], true) ? $user = array() : $user; + !empty($user) ? $this->query->where('CONCAT(a.name,u.username) LIKE', "%{$title}%")->where('c.role', 'owner') : $this->query->where('a.name LIKE', "%{$title}%"); + } + return $this; + } + + public function searchWithTitle($title) { + $this->query->where('a.name', $title); + return $this; + } + + public function searchWithType($types = array()) { + $this->query->where(array('b.type' => $types)); + return $this; + } + + public function searchWithLetter($letter) { + if (!empty($letter) && strlen($letter) == 1) { + $this->query->where('a.title_initial', $letter); + } + return $this; + } + + public function accountRankOrder() { + global $_W; + if (!$_W['isadmin']) { + $this->query->orderby('c.rank', 'desc'); + } else { + $this->query->orderby('a.rank', 'desc'); + } + return $this; + } + + public function accountUniacidOrder($order = 'desc') { + $order = !empty($order) ? $order : 'desc'; + $this->query->orderby('a.uniacid', $order); + return $this; + } + + public function accountEndtimeOrder($order) { + $order = $order == 'endtime_asc' ? 'asc' : 'desc'; + return $this->query->orderby('b.endtime', $order) + ->where('b.endtime >', 2); + } + + public function accountInitialsOrder($order = 'asc') { + $order = !empty($order) ? $order : 'asc'; + $this->query->orderby('a.title_initial', $order); + return $this; + } + + public function searchWithViceFounder($vice_founder_id) { + $this->query + ->leftjoin('uni_account_users', 'c') + ->on(array('a.uniacid' => 'c.uniacid')) + ->where('c.role', 'vice_founder') + ->where('c.uid', $vice_founder_id); + return $this; + } + + + + public function accountGroupModules($uniacid, $type = '') { + $packageids = $this->query->from('uni_account_group')->where('uniacid', $uniacid)->select('groupid')->getall('groupid'); + $packageids = empty($packageids) ? array() : array_keys($packageids); + if (in_array('-1', $packageids)) { + $modules = $this->query->from('modules')->select('name')->getall('name'); + return array_keys($modules); + } + $uni_modules = array(); + + $uni_groups = $this->query->from('uni_group')->where('id', $packageids)->getall(); + $uni_account_extra_modules = table('uni_account_extra_modules')->where('uniacid', $uniacid)->getall(); + $acount_modules = array_merge($uni_groups, $uni_account_extra_modules); + if (!empty($acount_modules)) { + if (empty($type)) { + $account = table('account')->getByUniacid($uniacid); + $type = $account['type']; + } + foreach ($acount_modules as $group) { + $group_module = (array)iunserializer($group['modules']); + if (empty($group_module)) { + continue; + } + switch ($type) { + case ACCOUNT_TYPE_OFFCIAL_NORMAL: + case ACCOUNT_TYPE_OFFCIAL_AUTH: + $uni_modules = is_array($group_module['modules']) ? array_merge($group_module['modules'], $uni_modules) : $uni_modules; + break; + case ACCOUNT_TYPE_APP_NORMAL: + case ACCOUNT_TYPE_APP_AUTH: + case ACCOUNT_TYPE_WXAPP_WORK: + $uni_modules = is_array($group_module['wxapp']) ? array_merge($group_module['wxapp'], $uni_modules) : $uni_modules; + break; + case ACCOUNT_TYPE_WEBAPP_NORMAL: + $uni_modules = is_array($group_module['webapp']) ? array_merge($group_module['webapp'], $uni_modules) : $uni_modules; + break; + case ACCOUNT_TYPE_PHONEAPP_NORMAL: + $uni_modules = is_array($group_module['phoneapp']) ? array_merge($group_module['phoneapp'], $uni_modules) : $uni_modules; + break; + case ACCOUNT_TYPE_ALIAPP_NORMAL: + $uni_modules = is_array($group_module['aliapp']) ? array_merge($group_module['aliapp'], $uni_modules) : $uni_modules; + break; + } + } + $uni_modules = array_unique($uni_modules); + } + return $uni_modules; + } + + + public function userOwnedAccount($uid = 0) { + global $_W; + $uid = intval($uid) > 0 ? intval($uid) : $_W['uid']; + if (!user_is_founder($uid, true)) { + $uniacid_list = table('uni_account_users')->getUsableAccountsByUid($uid); + if (empty($uniacid_list)) { + return array(); + } + $this->query->where('u.uniacid', array_keys($uniacid_list)); + } + return $this->query->from('uni_account', 'u') + ->leftjoin('account', 'a') + ->on(array('u.default_acid' => 'a.acid')) + ->where('a.isdeleted', 0) + ->orderby('a.uniacid', 'DESC') + ->getall('uniacid'); + } + + public function searchWithuniAccountUsers() { + return $this->query->from('account', 'a') + ->leftjoin('uni_account_users', 'b') + ->on(array('b.uniacid' => 'a.uniacid')); + } + + public function searchWithUniAccount() { + return $this->query->from($this->tableName, 'a') + ->leftjoin('uni_account', 'b') + ->on('b.uniacid', 'a.uniacid'); + } + +} \ No newline at end of file diff --git a/framework/table/Account/Wechats.php b/framework/table/Account/Wechats.php new file mode 100644 index 0000000..dba26ff --- /dev/null +++ b/framework/table/Account/Wechats.php @@ -0,0 +1,68 @@ + '', + 'token' => '', + 'encodingaeskey' => '', + 'auth_refresh_token' => '', + 'level' => '0', + 'name' => '', + 'account' => '', + 'original' => '', + 'signature' => '', + 'country' => '', + 'province' => '', + 'city' => '', + 'username' => '', + 'password' => '', + 'lastupdate' => '0', + 'key' => '', + 'secret' => '', + 'styleid' => '1', + 'subscribeurl' => '', + 'createtime' => '', + ); + public function getAccount($uniacid) { + return $this->query->where('uniacid', $uniacid)->get(); + } + public function searchWithAccount() { + return $this->query->from($this->tableName, 't') + ->leftjoin('account', 'a') + ->on(array('t.uniacid' => 'a.uniacid')); + } + + public function searchWithsearchWithAccountAndUniAccountUsers() { + return $this->query->from($this->tableName, 't') + ->leftjoin('account', 'a') + ->on(array('t.uniacid' => 'a.uniacid')) + ->leftjoin('uni_account_users', 'u') + ->on(array('u.uniacid' => 't.uniacid')); + } +} \ No newline at end of file diff --git a/framework/table/Basic/Reply.php b/framework/table/Basic/Reply.php new file mode 100644 index 0000000..ea2dd51 --- /dev/null +++ b/framework/table/Basic/Reply.php @@ -0,0 +1,19 @@ + '', + 'content' => '' + ); +} \ No newline at end of file diff --git a/framework/table/Core/Attachment.php b/framework/table/Core/Attachment.php new file mode 100644 index 0000000..2796f6c --- /dev/null +++ b/framework/table/Core/Attachment.php @@ -0,0 +1,66 @@ + '', + 'uid' => '', + 'filename' => '', + 'attachment' => '', + 'type' => '', + 'createtime' => '', + 'module_upload_dir' => '', + 'group_id' => '0', + 'displayorder' => '', + ); + + public function deleteById($id) { + return $this->where('id', $id)->delete(); + } + + public function searchWithUniacid($uniacid) { + return $this->query->where('uniacid', $uniacid); + } + + public function searchWithUid($uid) { + return $this->query->where('uid', $uid); + } + + public function searchWithUploadDir($module_upload_dir) { + return $this->query->where(array('module_upload_dir' => $module_upload_dir)); + } + + public function searchWithType($type) { + return $this->query->where(array('type' => $type)); + } + + public function searchWithGroupId($groupid) { + return $this->query->where(array('group_id =' => $groupid)); + } + + public function searchWithTime($start_time, $end_time) { + return $this->query->where(array('createtime >=' => $start_time))->where(array('createtime <=' => $end_time)); + } + + public function SearchWithUserAndUniAccount() { + return $this->query->from($this->tableName, 'a') + ->leftjoin('users', 'b') + ->on('b.uid', 'a.uid') + ->leftjoin('uni_account', 'c') + ->on('a.uniacid','c.uniacid'); + } +} \ No newline at end of file diff --git a/framework/table/Core/AttachmentGroup.php b/framework/table/Core/AttachmentGroup.php new file mode 100644 index 0000000..1bb98a0 --- /dev/null +++ b/framework/table/Core/AttachmentGroup.php @@ -0,0 +1,32 @@ + '0', + 'name' => '', + 'uniacid' => '0', + 'uid' => '0', + 'type' => '0', + ); + + public function searchWithUniacidOrUid($uniacid, $uid) { + if (empty($uniacid)) { + $this->query->where('uniacid', 0)->where('uid', $uid); + } else { + $this->query->where('uniacid', $uniacid); + } + return $this; + } + +} \ No newline at end of file diff --git a/framework/table/Core/ProfileFields.php b/framework/table/Core/ProfileFields.php new file mode 100644 index 0000000..41c414f --- /dev/null +++ b/framework/table/Core/ProfileFields.php @@ -0,0 +1,43 @@ + '', + 'available' => 1, + 'title' => '', + 'description' => '', + 'displayorder' => 0, + 'required' => 0, + 'unchangeable' => 0, + 'showinregister' => 0, + 'field_length' => 0, + ); + + public function searchWithKeyword($keyword) { + $this->query->where('title LIKE', "%{$keyword}%"); + return $this; + } + + public function getFieldsList() { + return $this->query->orderby('displayorder', 'DESC')->getall(); + } + + public function getAvailableAndShowableFields() { + return $this->query->where('available', 1)->where('showinregister', 1)->orderby('displayorder', 'desc')->getall('field'); + } +} \ No newline at end of file diff --git a/framework/table/Core/Settings.php b/framework/table/Core/Settings.php new file mode 100644 index 0000000..43b7afd --- /dev/null +++ b/framework/table/Core/Settings.php @@ -0,0 +1,16 @@ + '', + 'value' => '', + ); +} \ No newline at end of file diff --git a/framework/table/Images/Reply.php b/framework/table/Images/Reply.php new file mode 100644 index 0000000..9699e94 --- /dev/null +++ b/framework/table/Images/Reply.php @@ -0,0 +1,25 @@ + '', + 'title' => '', + 'description' => '', + 'mediaid' => '', + 'createtime' => '' + ); +} \ No newline at end of file diff --git a/framework/table/Mc/CreditsRecord.php b/framework/table/Mc/CreditsRecord.php new file mode 100644 index 0000000..e87da96 --- /dev/null +++ b/framework/table/Mc/CreditsRecord.php @@ -0,0 +1,57 @@ + '0', + 'clerk_type' => '1', + 'createtime' => '', + 'credittype' => '', + 'module' => '', + 'num' => '0.00', + 'operator' => '', + 'real_uniacid' => '', + 'remark' => '', + 'store_id' => '0', + 'uid' => '', + 'uniacid' => '', + ); + + public function getCreditsRecordListByUidAndCredittype($uid, $credittype) { + return $this->query->from('mc_credits_record', 'r') + ->select('r.*, u.username as username') + ->leftjoin('users', 'u') + ->on(array('r.operator' => 'u.uid')) + ->where('r.uid', $uid) + ->where('r.credittype', $credittype) + ->orderby('r.id', 'desc') + ->getall(); + } + + public function searchWithUsers() { + return $this->query->from($this->tableName, 'r') + ->leftjoin('users', 'u') + ->on(array('r.operator' => 'u.uid')); + } + + public function searchWithUniacid($uniacid) { + return $this->query->where('uniacid', $uniacid); + } +} \ No newline at end of file diff --git a/framework/table/Mc/FansTag.php b/framework/table/Mc/FansTag.php new file mode 100644 index 0000000..040636e --- /dev/null +++ b/framework/table/Mc/FansTag.php @@ -0,0 +1,58 @@ + '', + 'fanid' => '', + 'openid' => '', + 'subscribe' => '0', + 'nickname' => '', + 'sex' => '0', + 'language' => '', + 'city' => '', + 'province' => '', + 'country' => '', + 'headimgurl' => '', + 'subscribe_time' => '', + 'unionid' => '', + 'remark' => '', + 'groupid' => '', + 'tagid_list' => '', + 'subscribe_scene' => '', + 'qr_scene' => '', + 'qr_scene_str' => '', + + ); + + public function getByOpenid($openid) { + $result = $this->query->where('openid', $openid)->get(); + return $result; + } + +} \ No newline at end of file diff --git a/framework/table/Mc/Groups.php b/framework/table/Mc/Groups.php new file mode 100644 index 0000000..b81bb89 --- /dev/null +++ b/framework/table/Mc/Groups.php @@ -0,0 +1,20 @@ + 0, + 'title' => '', + 'credit' => 0, + 'isdefault' => 0 + ); +} \ No newline at end of file diff --git a/framework/table/Mc/MappingFans.php b/framework/table/Mc/MappingFans.php new file mode 100644 index 0000000..4a6cfd1 --- /dev/null +++ b/framework/table/Mc/MappingFans.php @@ -0,0 +1,52 @@ + '', + 'uniacid' => '0', + 'uid' => '0', + 'openid' => '', + 'nickname' => '', + 'groupid' => '', + 'salt' => '', + 'follow' => '1', + 'followtime' => '', + 'unfollowtime' => '', + 'tag' => '', + 'updatetime' => '0', + 'unionid' => '', + 'user_from' => '', + ); + + public function searchWithUniacid($uniacid) { + return $this->query->where('uniacid', $uniacid); + } + + public function searchWithOpenid($openid) { + return $this->query->where('openid', $openid); + } + + public function searchWithUnionid($unionid) { + return $this->query->where('unionid', $unionid); + } +} \ No newline at end of file diff --git a/framework/table/Mc/Members.php b/framework/table/Mc/Members.php new file mode 100644 index 0000000..2453eb4 --- /dev/null +++ b/framework/table/Mc/Members.php @@ -0,0 +1,160 @@ + '', + 'affectivestatus' => '', + 'alipay' => '', + 'avatar' => '', + 'bio' => '', + 'birthday' => '0', + 'birthmonth' => '0', + 'birthyear' => '0', + 'bloodtype' => '', + 'company' => '', + 'constellation' => '', + 'createtime' => '', + 'credit1' => '0.00', + 'credit2' => '0.00', + 'credit3' => '', + 'credit4' => '0.00', + 'credit5' => '0.00', + 'credit6' => '0.00', + 'education' => '', + 'email' => '', + 'gender' => '0', + 'grade' => '', + 'graduateschool' => '', + 'groupid' => '0', + 'height' => '', + 'idcard' => '', + 'interest' => '', + 'lookingfor' => '', + 'mobile' => '', + 'msn' => '', + 'nationality' => '', + 'nickname' => '', + 'occupation' => '', + 'password' => '', + 'pay_password' => '', + 'position' => '', + 'qq' => '', + 'realname' => '', + 'residecity' => '', + 'residedist' => '', + 'resideprovince' => '', + 'revenue' => '', + 'salt' => '', + 'site' => '', + 'studentid' => '', + 'taobao' => '', + 'telephone' => '', + 'uniacid' => '', + 'user_from' => '', + 'vip' => '0', + 'weight' => '', + 'zipcode' => '', + 'zodiac' => '', + ); + + public function searchWithUniacid($uniacid) { + return $this->query->where('uniacid', $uniacid); + } + + public function searchWithEmail($email) { + return $this->query->where('email', $email); + } + + public function searchWithMobile($mobile) { + return $this->query->where('mobile', $mobile); + } + + public function searchWithoutUid($uid) { + return $this->query->where('uid <>', $uid); + } + + public function searchCreditsRecordUid($uid) { + $this->query->where('r.uid', $uid); + return $this; + } + + public function searchCreditsRecordType($type) { + $this->query->where('r.credittype', $type); + return $this; + } + + public function searchWithMobileOrEmail($mobile_or_email) { + $this->query->where('mobile', $mobile_or_email)->whereor('email', $mobile_or_email); + return $this; + } + public function searchWithMappingFans() { + return $this->query->from('mc_members', 'a') + ->leftjoin('mc_mapping_fans', 'b') + ->on(array('a.uid' => 'b.uid')); + } + + public function searchWithAccount() { + return $this->query->from('mc_members', 'm') + ->leftjoin('account', 'a') + ->on(array('m.uniacid' => 'a.uniacid')); + } +} \ No newline at end of file diff --git a/framework/table/Mc/OauthFans.php b/framework/table/Mc/OauthFans.php new file mode 100644 index 0000000..2f53bc8 --- /dev/null +++ b/framework/table/Mc/OauthFans.php @@ -0,0 +1,28 @@ + '', + 'uniacid' => '', + 'uid' => '', + 'openid' => '', + ); + + public function searchWithoAuthopenid($oauth_openid) { + return $this->query->where('oauth_openid', $oauth_openid); + } + + public function searchWithUniacid($uniacid) { + return $this->query->where('uniacid', $uniacid); + } +} \ No newline at end of file diff --git a/framework/table/Modules/Modules.php b/framework/table/Modules/Modules.php new file mode 100644 index 0000000..66b6768 --- /dev/null +++ b/framework/table/Modules/Modules.php @@ -0,0 +1,197 @@ + '', + 'type' => '', + 'title' => '', + 'title_initial' => '', + 'version' => '', + 'ability' => '', + 'description' => '', + 'author' => '', + 'url' => '', + 'settings' => '0', + 'subscribes' => '', + 'handles' => '', + 'isrulefields' => '0', + 'issystem' => '0', + 'target' => '0', + 'iscard' => '0', + 'permissions' => '', + 'wxapp_support' => '1', + 'account_support' => '1', + 'welcome_support' => '1', + 'webapp_support' => '1', + 'oauth_type' => '1', + 'phoneapp_support' => '1', + 'xzapp_support' => '1', + 'aliapp_support' => '1', + 'logo' => '', + 'baiduapp_support' => '1', + 'toutiaoapp_support' => '1', + 'cloud_record' => 0, + 'sectinos' => 0, + 'application_type' => 1, + ); + + public function bindings() { + return $this->hasMany('modules_bindings', 'module', 'name'); + } + + public function getByName($module_name) { + $result = $this->query->where('name', $module_name)->get(); + if (!empty($result['subscribes'])) { + $result['subscribes'] = iunserializer($result['subscribes']); + } + if (!empty($result['handles'])) { + $result['handles'] = iunserializer($result['handles']); + } + return $result; + } + protected function templatesMidToId($result) { + if (empty($result) || !is_array($result)) { + return array(); + } + foreach ($result as $key => $template) { + $result[$key] = $this->templateMidToId($template); + } + return $result; + } + protected function templateMidToId($result) { + global $_W; + if (empty($result) || !is_array($result)) { + return array(); + } + $result['id'] = $result['mid']; + if (file_exists('../app/themes/'.$result['name'].'/preview.jpg')) { + $result['logo'] = $_W['siteroot'].'app/themes/'.$result['name'].'/preview.jpg'; + } else { + $result['logo'] = $_W['siteroot'].'web/resource/images/nopic-203.png'; + } + return $result; + } + public function searchTemplateWithName($module_name) { + return $this->query->where('name', $module_name); + } + public function getAllTemplates($keyfields = '') { + $fields = array('mid', 'name', 'version', 'title', 'description', 'type', 'sections'); + $result = $this->query->select($fields)->where(array('application_type' => APPLICATION_TYPE_TEMPLATES, 'account_support' => MODULE_SUPPORT_ACCOUNT))->orderby('mid', 'DESC')->getall($keyfields); + return $this->templatesMidToId($result); + } + + public function getTemplateByName($module_name) { + $result = $this->query->select($this->templateFields)->where('name', $module_name)->where('application_type', APPLICATION_TYPE_TEMPLATES)->get(); + return $this->templateMidToId($result); + } + public function getTemplateByNames($module_names, $keyfields = '') { + $result = $this->query->select($this->templateFields)->where('name', $module_names)->where('application_type', APPLICATION_TYPE_TEMPLATES)->getall($keyfields); + return $this->templatesMidToId($result); + } + + public function getTemplateById($id) { + $result = $this->query->select($this->templateFields)->where('mid', $id)->where('application_type', APPLICATION_TYPE_TEMPLATES)->get(); + return $this->templateMidToId($result); + } + + public function getAllTemplateByIds($ids, $keyfields = '') { + $result = $this->query->select($this->templateFields)->where('mid', $ids)->where('application_type', APPLICATION_TYPE_TEMPLATES)->orderby('mid', 'DESC')->getall($keyfields); + return $this->templatesMidToId($result); + } + + public function getByNameList($modulename_list, $get_system = false) { + $this->query->whereor('name', $modulename_list)->orderby('mid', 'desc'); + if (!empty($get_system)) { + $this->whereor('issystem', 1); + } + return $this->query->getall('name'); + } + + public function deleteByName($module_name) { + return $this->query->where('name', $module_name)->delete(); + } + + public function getByHasSubscribes() { + return $this->query->select('name', 'subscribes')->where('subscribes !=', '')->getall(); + } + + public function getSupportWxappList() { + return $this->query->where('wxapp_support', MODULE_SUPPORT_WXAPP)->getall('mid'); + } + + public function searchWithType($type, $method = '=') { + if ($method == '=') { + $this->query->where('type', $type); + } else { + $this->query->where('type <>', $type); + } + return $this; + } + + public function getNonRecycleModules() { + load()->model('module'); + $modules = $this->where('issystem' , 0)->orderby('mid', 'DESC')->getall('name'); + if (empty($modules)) { + return array(); + } + foreach ($modules as &$module) { + $module_info = module_fetch($module['name']); + if (empty($module_info)) { + unset($module); + } + if (!empty($module_info['recycle_info'])) { + foreach (module_support_type() as $support => $value) { + if ($module_info['recycle_info'][$support] > 0 && $module_info[$support] == $value['support']) { + $module[$support] = $value['not_support']; + } + } + } + } + return $modules; + } + + public function getInstalled() { + load()->model('module'); + $fields = array_keys(module_support_type()); + $fields = array_merge(array('name', 'version', 'cloud_record'), $fields); + return $this->query->select($fields)->where(array('issystem' => '0'))->getall('name'); + } +} \ No newline at end of file diff --git a/framework/table/Uni/Account.php b/framework/table/Uni/Account.php new file mode 100644 index 0000000..e5e3737 --- /dev/null +++ b/framework/table/Uni/Account.php @@ -0,0 +1,37 @@ + '0', + 'default_acid' => '0', + 'name' => '', + 'description' => '', + 'rank' => '0', + 'createtime' => '', + 'title_initial' => '', + 'create_uid' => '0', + 'logo' => '', + 'qrcode' => '' + ); + public function searchWithAccount() { + return $this->query->from($this->tableName, 'a') + ->leftjoin('account', 'b') + ->on('a.uniacid', 'b.uniacid'); + } +} \ No newline at end of file diff --git a/framework/table/Uni/AccountMenus.php b/framework/table/Uni/AccountMenus.php new file mode 100644 index 0000000..1b3bbb2 --- /dev/null +++ b/framework/table/Uni/AccountMenus.php @@ -0,0 +1,59 @@ + '0', + 'menuid' => '0', + 'type' => '1', + 'title' => '', + 'sex' => '0', + 'group_id' => '-1', + 'client_platform_type' => '0', + 'area' => '', + 'data' => '', + 'status' => '0', + 'createtime' => '0', + 'isdeleted' => '0', + ); + + public function searchWithTypeAndUniacid($type = '', $uniacid = 0) { + if (!empty($type)) { + $this->where('type', $type); + } + if ($uniacid > 0) { + $this->where('uniacid', intval($uniacid)); + } + return $this; + } + + public function getByType($type = '') { + global $_W; + return $this->searchWithTypeAndUniacid($type, $_W['uniacid'])->get(); + } + + public function getAllByType($type = '') { + global $_W; + return $this->searchWithTypeAndUniacid($type, $_W['uniacid'])->getall('id'); + } +} \ No newline at end of file diff --git a/framework/table/Uni/AccountModules.php b/framework/table/Uni/AccountModules.php new file mode 100644 index 0000000..55cebbf --- /dev/null +++ b/framework/table/Uni/AccountModules.php @@ -0,0 +1,32 @@ + '', + 'module' => '', + 'enabled' => 0, + 'shortcut' => 0, + 'displayorder' => 0, + 'settings' => '', + ); + + public function getByUniacidAndModule($module_name, $uniacid) { + $result = $this->query->where('module', $module_name)->where('uniacid', $uniacid)->get(); + if (!empty($result)) { + $result['settings'] = iunserializer($result['settings']); + } + return $result; + } +} \ No newline at end of file diff --git a/framework/table/Uni/AccountUsers.php b/framework/table/Uni/AccountUsers.php new file mode 100644 index 0000000..40ba8de --- /dev/null +++ b/framework/table/Uni/AccountUsers.php @@ -0,0 +1,68 @@ + '', + 'uid' => '', + 'role' => '', + 'rank' => '0', + 'createtime' => '', + ); + + public function searchWithUserRole($role) { + return $this->query->where('role', $role); + } + + public function getUsableAccountsByUid($uid) { + return $this->query->where('uid', $uid)->where('role !=', ACCOUNT_MANAGE_NAME_CLERK)->getall('uniacid'); + } + + public function getOwnedAccountsByUid($uid) { + return $this->query->where('uid', $uid)->where('role', ACCOUNT_MANAGE_NAME_OWNER)->getall('uniacid'); + } + + public function searchWithRole($role) { + return $this->query->where('u.role', $role); + } + + public function getCommonUserOwnAccountUniacids($uid) { + return $this->query + ->from('uni_account_users', 'u') + ->select('u.uniacid, a.type') + ->innerjoin('account', 'a') + ->on(array('u.uniacid' => 'a.uniacid')) + ->where('u.uid', $uid) + ->getall('uniacid'); + } + + public function getAllUserRole($uid) { + return $this->query->where('uid', $uid)->getall('role'); + } + + public function getUserRoleByUniacid($uid, $uniacid) { + $info = $this->query->where(array('uid' => $uid, 'uniacid' => $uniacid))->get(); + return $info['role']; + } + + public function getUidByUniacidAndRole($uniacid, $role) { + $data = $this->where('uniacid', $uniacid)->where('role', $role)->get(); + return empty($data['uid']) ? 0 : $data['uid']; + } + + public function searchWithUsers() { + return $this->query->from($this->tableName, 'a') + ->leftjoin('users', 'b') + ->on('a.uid', 'b.uid'); + } +} \ No newline at end of file diff --git a/framework/table/Uni/Modules.php b/framework/table/Uni/Modules.php new file mode 100644 index 0000000..273f536 --- /dev/null +++ b/framework/table/Uni/Modules.php @@ -0,0 +1,85 @@ + '', + 'module_name' => '', + ); + + public function getAllByModuleName($module_name) { + return $this->query->select('uniacid')->where('module_name', $module_name)->getall('uniacid'); + } + public function getallByUniacid($uniacid) { + return $this->query->where('uniacid', $uniacid)->getall(); + } + + public function searchLikeModuleTitle($module_title) { + return $this->query->where('m.title LIKE', "%{$module_title}%"); + } + + public function searchWithModuleLetter($module_letter) { + return $this->query->where('m.title_initial', $module_letter); + } + + public function searchWithModuleName($module_name) { + $this->query->where('u.module_name', $module_name); + } + + public function searchGroupbyModuleName() { + return $this->query->groupby('u.module_name'); + } + + public function getModulesByUid($uid, $uniacid = 0) { + global $_W; + if (empty($uid)) { + $uid = $_W['uid']; + } + + if (!empty($uniacid)) { + $this->where('u.uniacid', $uniacid); + } else { + $this->where('u.uniacid <>', 0); + } + + $select_fields = " + u.uniacid, + u.module_name + "; + + if (!user_is_founder($uid) && $_W['highest_role'] != ACCOUNT_MANAGE_NAME_CLERK || user_is_vice_founder($uid)) { + $select_fields .= ", uau.role"; + $this->where('uau.uid', $uid); + $this->query->from('uni_account_users', 'uau') + ->leftjoin('uni_modules', 'u') + ->on(array('uau.uniacid' => 'u.uniacid')); + } elseif ($_W['highest_role'] == ACCOUNT_MANAGE_NAME_CLERK) { + $select_fields .= ", up.uniacid as permission_uniacid"; + $this->where('up.uid', $uid); + $this->query->from('users_permission', 'up') + ->leftjoin('uni_modules', 'u') + ->on(array('up.type' => 'u.module_name', 'up.uniacid' => 'u.uniacid')); + } else { + $this->query->from('uni_modules', 'u'); + } + + $modules = $this->query + ->select($select_fields) + ->getall(); + + $total = $this->getLastQueryTotal(); + return array('modules' => $modules, 'total' => $total); + } + + public function deleteUniModules($module_name, $uniacid) { + $this->query->where('module_name', $module_name)->where('uniacid', $uniacid)->delete(); + } + +} \ No newline at end of file diff --git a/framework/table/Uni/Settings.php b/framework/table/Uni/Settings.php new file mode 100644 index 0000000..0d85135 --- /dev/null +++ b/framework/table/Uni/Settings.php @@ -0,0 +1,80 @@ + 0, + 'passport' => '', + 'oauth' => '', + 'jsauth_acid' => 0, + 'notify' => '', + 'creditnames' => '', + 'creditbehaviors' => '', + 'welcome' => '', + 'default' => '', + 'default_message' => '', + 'shortcuts' => '', + 'payment' => '', + 'stat' => '', + 'default_site' => 0, + 'sync' => '', + 'recharge' => '', + 'tplnotice' => '', + 'grouplevel' => 1, + 'mcplugin' => '', + 'exchange_enable' => 0, + 'coupon_type' => 1, + 'statistics' => '', + 'bind_domain' => '', + 'comment_status' => 0, + 'reply_setting' => 0, + 'default_module' => '', + 'attachment_limit' => 0, + 'attachment_size' => '', + 'sync_member' => 0, + 'remote' => '' + ); + public function searchWirhUniAccountAndAccount(){ + return $this->query->from($this->tableName, 'a') + ->leftjoin('uni_account', 'b') + ->on('a.uniacid', 'b.uniacid') + ->leftjoin('account', 'c') + ->on('a.uniacid', 'c.uniacid'); + } + +} \ No newline at end of file diff --git a/framework/table/Users/Bind.php b/framework/table/Users/Bind.php new file mode 100644 index 0000000..98419a3 --- /dev/null +++ b/framework/table/Users/Bind.php @@ -0,0 +1,38 @@ + '', + 'bind_sign' => '', + 'third_type' => '0', + 'third_nickname' => '', + ); + + public function getByTypeAndUid($type, $uid) { + return $this->query->where('third_type', $type)->where('uid', $uid)->get(); + } + + public function getByTypeAndBindsign($type, $bind_sign) { + return $this->query->where('third_type', $type)->where('bind_sign', $bind_sign)->get(); + } + + public function getAllByUid($uid) { + return $this->query->where('uid', $uid)->getall('bind_sign'); + } + + public function searchWithUsers() { + return $this->query->from($this->tableName, 'b') + ->leftjoin('users', 'u') + ->on(array('b.uid' => 'u.uid')); + } +} \ No newline at end of file diff --git a/framework/table/Users/Permission.php b/framework/table/Users/Permission.php new file mode 100644 index 0000000..81fd91f --- /dev/null +++ b/framework/table/Users/Permission.php @@ -0,0 +1,98 @@ + '', + 'uid' => '', + 'type' => '', + 'permission' => '', + 'url' => '', + ); + + public $notModuleTypes = array( + PERMISSION_ACCOUNT, + PERMISSION_WXAPP, + PERMISSION_WEBAPP, + PERMISSION_PHONEAPP, + PERMISSION_ALIAPP, + PERMISSION_BAIDUAPP, + PERMISSION_TOUTIAOAPP, + PERMISSION_SYSTEM, + PERMISSION_MODULES + ); + + public function getUserPermissionByType($uid, $uniacid, $type = '') { + $this->query->where('uid', $uid)->where('uniacid', $uniacid); + if (!empty($type)) { + $this->query->where('type', $type); + } + $result = $this->query->get(); + if (!empty($result['permission'])) { + $result['permission'] = explode('|', $result['permission']); + } + return $result; + } + + public function getAllUserPermission($uid, $uniacid) { + return $this->query->where('uid', $uid) + ->where('uniacid', $uniacid)->getall('type'); + } + public function getAllUserModulePermission($uid, $uniacid = 0) { + if (!empty($uniacid)) { + $this->query->where('uniacid', $uniacid); + } + return $this->query->where('uid', $uid) + ->where('type !=', array(PERMISSION_ACCOUNT, PERMISSION_WXAPP, PERMISSION_WEBAPP, PERMISSION_PHONEAPP, PERMISSION_ALIAPP, PERMISSION_BAIDUAPP, PERMISSION_TOUTIAOAPP, PERMISSION_SYSTEM))->getall('type'); + } + + public function getClerkPermission($module) { + global $_W; + return $this->query->from('users_permission', 'p')->leftjoin('uni_account_users', 'u')->on(array('u.uid' => 'p.uid', 'u.uniacid' => 'p.uniacid'))->where('u.role', 'clerk')->where('p.type', $module)->where('u.uniacid', $_W['uniacid'])->getall('uid'); + } + + public function getClerkPermissionList($uniacid = 0, $uid = 0, $username = '') { + $this->query->from('users_permission', 'p') + ->select('p.*') + ->leftjoin('uni_account_users', 'u') + ->on(array('u.uid' => 'p.uid', 'u.uniacid' => 'p.uniacid')) + ->where('u.role', 'clerk'); + + if (!empty($uniacid)) { + $this->query->where('u.uniacid', $uniacid); + } + if (!empty($uid)) { + $this->query->where('u.uid', $uid); + } + if (!empty($username)) { + $this->query->leftjoin('users', 's') + ->on(array('s.uid' => 'p.uid')) + ->where('s.username like', "%$username%"); + } + if (empty($module)) { + $this->query->where('p.type !=', $this->notModuleTypes); + } else { + $this->query->where('p.type', $module); + } + return $this->query->getall(); + } + + public function searchWithUniAccountUsers() { + return $this->query->from($this->tableName, 'p') + ->leftjoin('uni_account_users', 'u') + ->on(array( + 'p.uid' => 'u.uid', + 'p.uniacid' => 'u.uniacid' + )); + } +} \ No newline at end of file diff --git a/framework/table/Users/Profile.php b/framework/table/Users/Profile.php new file mode 100644 index 0000000..810598c --- /dev/null +++ b/framework/table/Users/Profile.php @@ -0,0 +1,116 @@ + '', + 'createtime' => '', + 'edittime' => '', + 'realname' => '', + 'nickname' => '', + 'avatar' => '', + 'qq' => '', + 'mobile' => '', + 'fakeid' => '', + 'vip' => '0', + 'gender' => '0', + 'birthyear' => '0', + 'birthmonth' => '0', + 'birthday' => '0', + 'constellation' => '', + 'zodiac' => '', + 'telephone' => '', + 'idcard' => '', + 'studentid' => '', + 'grade' => '', + 'address' => '', + 'zipcode' => '', + 'nationality' => '', + 'resideprovince' => '', + 'residecity' => '', + 'residedist' => '', + 'graduateschool' => '', + 'company' => '', + 'education' => '', + 'occupation' => '', + 'position' => '', + 'revenue' => '', + 'affectivestatus' => '', + 'lookingfor' => '', + 'bloodtype' => '', + 'height' => '', + 'weight' => '', + 'alipay' => '', + 'msn' => '', + 'email' => '', + 'taobao' => '', + 'site' => '', + 'bio' => '', + 'interest' => '', + 'workerid' => '', + 'send_expire_status' => '0', + 'is_send_mobile_status' => '', + 'location' => '', + ); + + public function getByUid($uid) { + return $this->query->where('uid', $uid)->get(); + } + + public function getByMobile($mobile) { + return $this->query->where('mobile', $mobile)->get(); + } +} \ No newline at end of file diff --git a/framework/table/Users/Users.php b/framework/table/Users/Users.php new file mode 100644 index 0000000..2f25ef8 --- /dev/null +++ b/framework/table/Users/Users.php @@ -0,0 +1,174 @@ + '0', + 'groupid' => '0', + 'username' => '', + 'password' => '', + 'salt' => '', + 'type' => '1', + 'status' => '2', + 'joindate' => '0', + 'joinip' => '', + 'lastvisit' => '0', + 'lastip' => '', + 'remark' => '', + 'starttime' => '0', + 'endtime' => '0', + 'founder_groupid' => '0', + 'register_type' => '0', + 'openid' => '0', + 'welcome_link' => '', + 'notice_setting' => '', + ); + + public function getNoticeSettingByUid($uid) { + $notice_setting = iunserializer($this->where('uid', $uid)->getcolumn('notice_setting')); + if (!is_array($notice_setting)) { + $notice_setting = array(); + } + return $notice_setting; + } + + public function getUsersList($join_profile = true) { + $this->query->from('users', 'u'); + + $select = 'u.uid, u.owner_uid, u.groupid, u.username, u.type, u.status, u.joindate, u.joinip, u.lastvisit, + u.lastip, u.remark, u.starttime, u.endtime, u.founder_groupid,u.register_type, u.openid, u.welcome_link'; + + if ($join_profile) { + $select .= ',p.avatar as avatar, p.mobile as mobile, p.uid as puid, p.mobile as mobile'; + $this->query->leftjoin('users_profile', 'p')->on(array('u.uid' => 'p.uid')); + } + return $this->query->select($select)->orderby('u.uid', 'DESC')->getall('uid'); + } + + public function searchFounderOwnUsers($founder_uid) { + $this->query + ->innerjoin('users_founder_own_users', 'f') + ->on(array('u.uid' => 'f.uid')) + ->where('f.founder_uid', $founder_uid); + return $this; + } + + public function searchWithViceFounder() { + global $_W; + if (user_is_vice_founder()) { + $this->query->where('u.owner_uid', $_W['uid']); + } + return $this; + } + + public function searchWithStatus($status) { + $this->query->where('u.status', $status); + return $this; + } + + public function searchWithType($type) { + $this->query->where('u.type', $type); + return $this; + } + + public function searchWithFounder($founder_groupids) { + $this->query->where('u.founder_groupid', $founder_groupids); + return $this; + } + + public function searchWithoutFounder() + { + return $this->query->where('u.founder_groupid !=', ACCOUNT_MANAGE_GROUP_FOUNDER); + } + + public function searchWithTimelimitStatus($status) { + if ($status == 1) { + $this->where(function ($query) { + $query->where('u.endtime', 0) + ->whereor('u.endtime', USER_ENDTIME_GROUP_UNLIMIT_TYPE) + ->whereor('u.endtime >', TIMESTAMP); + }); + } elseif ($status == 2) { + $this->where(function ($query) { + $query->where('u.endtime >', USER_ENDTIME_GROUP_UNLIMIT_TYPE) + ->where('u.endtime <=', TIMESTAMP) + ->whereor('u.endtime', USER_ENDTIME_GROUP_DELETE_TYPE); + }); + + } + return $this; + } + + public function searchWithEndtime($day) { + $this->query->where('u.endtime >', USER_ENDTIME_GROUP_UNLIMIT_TYPE)->where('u.endtime <', TIMESTAMP + 86400 * $day); + return $this; + } + + public function searchWithMobile() { + $this->query->where('p.mobile !=', ''); + return $this; + } + + public function searchWithGroupId($group_id) { + $this->query->where('u.groupid', $group_id); + return $this; + } + + public function searchWithSendStatus() { + $this->query->where('p.send_expire_status', 0); + return $this; + } + + public function searchWithNameOrMobile($search, $join_profile = true, $uid_in = array()) { + if ($join_profile) { + $this->query->where(function ($query) use ($search) { + $query->where('u.username LIKE', "%{$search}%")->whereor('p.mobile LIKE', "%{$search}%"); + }); + } else { + $this->query->where('u.username LIKE', "%{$search}%")->whereor('u.uid', $uid_in); + } + return $this; + } + + public function searchWithOwnerUid($owner_uid) { + $this->query->where('u.owner_uid', $owner_uid); + return $this; + } + + public function userOrderBy($field = 'uid', $order = 'desc') { + $field = !empty($field) ? $field : 'joindate'; + $order = !empty($order) ? $order : 'desc'; + $this->query->orderby($field, $order); + return $this; + } + + public function searchWithUsersProfile() { + return $this->query->from($this->tableName, 'u') + ->leftjoin('users_profile', 'p') + ->on(array('u.uid' => 'p.uid')); + } +} \ No newline at end of file diff --git a/framework/version.inc.php b/framework/version.inc.php new file mode 100644 index 0000000..d6b7187 --- /dev/null +++ b/framework/version.inc.php @@ -0,0 +1,6 @@ +