获取unionid

url https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect


/**
     * @Description: curl请求
     * @Author: Yang
     * @param $url
     * @param null $data
     * @param string $method
     * @param array $header
     * @param bool $https
     * @param int $timeout
     * @return mixed
     */
    function curl_request($url, $data = null, $method = 'GET', $header = array("content-type:application/json"), $https = true, $timeout = 50) {
        $method = strtoupper($method);
        $ch = curl_init(); //初始化
        curl_setopt($ch, CURLOPT_URL, $url); //访问的URL
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); //只获取页面内容,但不输出
        if ($https) {
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); //https请求 不验证证书
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); //https请求 不验证HOST
        }
        if ($method != "GET") {
            // if($method == 'POST'){
            //     curl_setopt($ch, CURLOPT_POST, true);//请求方式为post请求
            // }
            // if ($method == 'PUT' || strtoupper($method) == 'DELETE') {
            //     curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method); //设置请求方式
            // }
            curl_setopt($ch, CURLOPT_POSTFIELDS, $data); //请求数据
        }
        curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $header); //模拟的header头
        //curl_setopt($ch, CURLOPT_HEADER, false);//设置不需要头信息
        $result = curl_exec($ch); //执行请求
//        errlog("error: ".json_encode($result));die;
        curl_close($ch); //关闭curl,释放资源
        // echo "<pre>";var_dump( $header , $data , $result );

        return $result;
//        return json_decode($result,true);
    }

<?php
namespace app\api\controller\v1\publics;

use app\common\controller\ApiController;
use app\services\publics\LoginServices;
use app\services\publics\SmsServices;
use app\services\huawei\ObsServices;
use app\services\user\UserServices;
use app\api\service\Jssdk;


use EasyAdmin\tool\CommonTool;
use think\Cache;

class Publics extends ApiController {


    
    /**
     * 公众号根据code获取openid
     */
    public function wechatGetCode() {
        $params = $this->request->getMore([
            ['code',''],
            ['invite_code',''],
            ['redirect_url',''],
            ['type',''],
        ]);
        $code = $params['code'];
        $invite_code = 0;
        $redirect_uri = $params['redirect_url'];
        $snsapi_type = $params['type'];  //  空是静默授权  userinfo动态
        if( $snsapi_type ) {
            $snsapi_type = "snsapi_userinfo";
        }else{
            $snsapi_type = "snsapi_base";
        }
        
        //  发起授权
        if( !$code ){
            $wx_p_appid = sysconfig('wx_public','wx_p_appid');
//            $redirect_uri = urlencode( $url );//重定向地址
            $url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=$wx_p_appid&redirect_uri=$redirect_uri&response_type=code&scope=$snsapi_type&state=1#wechat_redirect";
            return app('json')->success( 'ok' , ['appid'=>$wx_p_appid,'url'=>$url] );
//            header("Location:" . $url);
        }
        
        $wx_p_appid = sysconfig('wx_public','wx_p_appid');
        $wx_p_secret_key = sysconfig('wx_public','wx_p_secret_key');
        
        $oauth2Url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=$wx_p_appid&secret=$wx_p_secret_key&code=$code&grant_type=authorization_code";
        $oauth2 = curl_request( $oauth2Url, $data=null, 'GET', array("content-type:application/json"), $https=true );
        $oauth2 = json_decode( $oauth2, true );
//        echo "<pre>";var_dump(  $oauth2  );die;
        if( !isset($oauth2["openid"]) )return app('json')->fail( '微信登陆错误' , [] , 402 );
        
        // 获得 access_token 和openid
        $openid = $oauth2['openid'];
        
        //  判断用户是否存在
        $loginServices = app()->make(LoginServices::class);
        $user_register = $loginServices->getOne(['wx_openid' => $openid ] , "wx_openid" );
        if( $user_register ) {
            $user_register['openid'] = $user_register['wx_openid'];
            $data = $loginServices->wechatLogin( $user_register );
            return app('json')->success( '登录成功' , $data );
        }
        
        
        //  用户头像昵称
        $get_user_info_url = "https://api.weixin.qq.com/sns/userinfo?access_token=" . $oauth2["access_token"] . "&openid=$openid&lang=zh_CN";
        $userinfo = curl_request( $get_user_info_url, $data=null, 'GET', array("content-type:application/json"), $https=true );
//        file_put_contents( "txt/1.txt" , $userinfo . PHP_EOL , FILE_APPEND );
        $userinfo = json_decode( $userinfo, true );
         
        //获取unionid 上级参数
        $wxpublic_access_token = $loginServices->get_access_token( $wx_p_appid , $wx_p_secret_key );
        $get_user_info_url2 = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=$wxpublic_access_token&openid=$openid&lang=zh_CN";
        $userinfo2 = curl_request( $get_user_info_url2 );
//        file_put_contents( "txt/2.txt" , $userinfo2 . PHP_EOL , FILE_APPEND );
        $userinfo2 = json_decode( $userinfo2, true );
        if(data_get($userinfo2,"errcode")) {
            $wxpublic_access_token = $loginServices->get_access_token( $wx_p_appid , $wx_p_secret_key , 1 );
            $get_user_info_url2 = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=$wxpublic_access_token&openid=$openid&lang=zh_CN";
            $userinfo2 = curl_request( $get_user_info_url2 );
            $userinfo2 = json_decode( $userinfo2, true );
        }

        $qrSceneStr = data_get($userinfo2,"qr_scene_str");
        if( $qrSceneStr ) {
            $invite_code = $qrSceneStr;
        }
        if( $invite_code==0 && data_get($userinfo2,"qr_scene") ) {
            $invite_code = $userinfo2['qr_scene'];
        }

//        echo "<pre>";var_dump( $code , $oauth2 , $userinfo );die;
        
        //  注册登录
        $data = $loginServices->wechatLogin( $userinfo , $invite_code );
        return app('json')->success( '登录成功' , $data );
    }
    

    /**
     * 获取微信jsddk配置
     */
    public function wx_sdk() {
        
        $params = $this->request->getMore([
            ['url',''],  
        ]);
        $url = $params['url'];
        $JssdkServices = app()->make(Jssdk::class);
        $data = $JssdkServices->getSignPackage( $url );
        return app('json')->success( 'ok' , $data ); 
    }

    /**
     * 获取微信access_token
     */
    public function get_access_token( $wx_p_appid , $wx_p_secret_key , $update_token=0 ) {
        $CacheServices = app()->make( Cache::class );

        if( $update_token == 1 ) {
            $access_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" . $wx_p_appid . "&secret=" . $wx_p_secret_key;
            $access_url_arr = curl_request( $access_url, $data=null, 'GET', array("content-type:application/json"), $https=true );
            $access_url_arr1 = json_decode( $access_url_arr, true );
//            echo "<pre>";var_dump(  $access_url_arr1  );die;
            $wxpublic_access_token = $access_url_arr1["access_token"];
            $CacheServices->set( "wxpublic_access_token" , $wxpublic_access_token , 6000 );
        }else{
            $wxpublic_access_token = $CacheServices->has( "wxpublic_access_token" );
            if( $wxpublic_access_token ) {
                $wxpublic_access_token = $CacheServices->get( "wxpublic_access_token" );
            }else{
                $access_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" . $wx_p_appid . "&secret=" . $wx_p_secret_key;
                $access_url_arr = curl_request( $access_url, $data=null, 'GET', array("content-type:application/json"), $https=true );
                $access_url_arr1 = json_decode( $access_url_arr, true );
//                echo "<pre>";var_dump(  $access_url_arr1  );die;
                $wxpublic_access_token = $access_url_arr1["access_token"];
                $CacheServices->set( "wxpublic_access_token" , $wxpublic_access_token , 6000 );
            }
        }
        return $wxpublic_access_token;
    }
}

frontend


<!DOCTYPE html>
<html lang="zh-CN">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>微信订阅通知</title>
	<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<!--	<script src="__PUBLIC__/index/js/jquery-2.2.3.min.js"></script>-->
	<style>
		* {
			margin: 0;
			padding: 0;
			box-sizing: border-box;
		}

		body {
			font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
			background-color: #f8f8f8;
			height: 100vh;
			display: flex;
			justify-content: center;
			align-items: center;
		}

		.settings-container {
			max-width: 400px;
			margin: 0 auto;
			padding: 20px;
			font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
		}

		.settings-header {
			text-align: center;
			margin-bottom: 30px;
			padding-bottom: 20px;
			border-bottom: 1px solid #f0f0f0;
		}

		.settings-title {
			font-size: 24px;
			color: #333;
			margin-bottom: 5px;
		}

		.settings-subtitle {
			font-size: 14px;
			color: #666;
		}

		.notification-toggle {
			display: flex;
			justify-content: space-between;
			align-items: center;
			padding: 15px 0;
			border-bottom: 1px solid #f0f0f0;
			margin-bottom: 20px;
		}

		.toggle-info {
			flex: 1;
		}

		.toggle-title {
			font-size: 16px;
			color: #333;
			margin-bottom: 3px;
		}

		.toggle-description {
			font-size: 12px;
			color: #999;
		}

		.toggle-switch {
			position: relative;
			display: inline-block;
			width: 50px;
			height: 26px;
		}

		.toggle-switch input {
			opacity: 0;
			width: 0;
			height: 0;
		}

		.toggle-slider {
			position: absolute;
			cursor: pointer;
			top: 0;
			left: 0;
			right: 0;
			bottom: 0;
			background-color: #ccc;
			transition: .3s;
			border-radius: 26px;
		}

		.toggle-slider:before {
			position: absolute;
			content: "";
			height: 18px;
			width: 18px;
			left: 4px;
			bottom: 4px;
			background-color: white;
			transition: .3s;
			border-radius: 50%;
		}

		input:checked + .toggle-slider {
			background-color: #007aff;
		}

		input:checked + .toggle-slider:before {
			transform: translateX(24px);
		}

		.user-info-section {
			margin-bottom: 30px;
		}

		.section-title {
			font-size: 16px;
			color: #333;
			margin-bottom: 15px;
			font-weight: 600;
		}

		.info-item {
			display: flex;
			margin-bottom: 10px;
			font-size: 14px;
		}

		.info-label {
			flex: 0 0 80px;
			color: #666;
		}

		.info-value {
			flex: 1;
			color: #333;
			word-break: break-all;
		}

		.refresh-button {
			width: 100%;
			padding: 12px;
			background-color: #007aff;
			color: white;
			border: none;
			border-radius: 5px;
			font-size: 16px;
			cursor: pointer;
			margin-bottom: 20px;
		}

		.refresh-button:active {
			background-color: #0066cc;
		}

		.settings-footer {
			text-align: center;
			font-size: 12px;
			color: #999;
			padding-top: 20px;
			border-top: 1px solid #f0f0f0;
		}

		.toast {
			position: fixed;
			top: 50%;
			left: 50%;
			transform: translate(-50%, -50%);
			background-color: rgba(0, 0, 0, 0.7);
			color: white;
			padding: 15px 20px;
			border-radius: 5px;
			z-index: 10000;
			display: none;
		}
	</style>
</head>
<body>
<div id="app">
	<div class="settings-container">
		<div class="settings-header">
			<h1 class="settings-title">消息订阅设置</h1>
			<p class="settings-subtitle">管理您的订阅偏好</p>
		</div>

		<div class="settings-content">
			<div class="notification-toggle">
				<div class="toggle-info">
					<div class="toggle-title">接收推送通知</div>
					<div class="toggle-description">开启后将接收重要消息推送</div>
				</div>
				<label class="toggle-switch">
					<input type="checkbox" v-model="notificationEnabled" @change="handleToggleChange">
					<span class="toggle-slider"></span>
				</label>
			</div>

<!--			<div class="user-info-section">-->
<!--				<h2 class="section-title">用户信息</h2>-->
<!--				<div class="info-item">-->
<!--					<span class="info-label">OpenID:</span>-->
<!--					<span class="info-value">{{ openid || '未获取' }}</span>-->
<!--				</div>-->
<!--				<div class="info-item">-->
<!--					<span class="info-label">UnionID:</span>-->
<!--					<span class="info-value">{{ unionid || '未获取' }}</span>-->
<!--				</div>-->
<!--			</div>-->

<!--			<button class="refresh-button" @click="refreshUserInfo">刷新信息</button>-->
		</div>

		<div class="settings-footer">
			此页面用于管理微信服务号的消息订阅设置
		</div>

		<div class="toast" id="toast">{{ toastMessage }}</div>
	</div>
</div>

<script>
	new Vue({
		el: '#app',
		data: {
			notificationEnabled: true,
			code: '',
			toastMessage: ''
		},
		mounted() {
			// 获取URL参数中的openid和unionid
			const urlParams = new URLSearchParams(window.location.search);
			this.code = urlParams.get('code') || '';

			if(this.code){
				this.wechatGetCode();
			}



			// 获取订阅状态
			this.notificationEnabled = true;


		},
		methods: {
			// 获取微信用户信息
			wechatGetCode() {
				// 调用后台接口,传递 code 参数
				fetch(`wechatGetCode.html?code=${this.code}`) // API_URL 已在 public/scripts.html 中定义为 "/Index"
					.then(response => response.json()) // 解析 JSON 响应
					.then(data => {
						console.log(data);
						// if (data.success) {
						// 	console.log(data)
						// 	// 假设后台返回格式:{success: true, data: {openid: 'xxx', unionid: 'xxx'}}
						//
						// 	this.showToast('用户信息获取成功');
						// } else {
						// 	this.showToast('获取失败: ' + (data.message || '未知错误'));
						// }
					})
					.catch(error => {
						this.showToast('网络错误,请稍后重试');
						console.error('请求失败:', error);
					});
			},


			// 处理开关状态变化
			handleToggleChange() {
				// 保存订阅状态到localStorage
				localStorage.setItem('notificationEnabled', this.notificationEnabled);

				// 显示提示
				this.showToast(this.notificationEnabled ? '已开启订阅通知' : '已关闭订阅通知');
			},



			// 显示提示消息
			showToast(message) {
				this.toastMessage = message;
				const toast = document.getElementById('toast');
				toast.textContent = message;
				toast.style.display = 'block';

				setTimeout(() => {
					toast.style.display = 'none';
				}, 2000);
			}
		}
	});
</script>
</body>
</html>

配置地址 在微信开发者工具中访问
微信网页开发 / 网页授权
https://developers.weixin.qq.com/doc/service/guide/h5/auth.html

微信公众平台
https://mp.weixin.qq.com/debug/cgi-bin/sandboxinfo?action=showinfo&t=sandbox/index

posted @ 2025-08-01 14:10  Bashuslovakia  阅读(6)  评论(0)    收藏  举报