文档地址:
网站应用的方式进行扫码登录:[https://developers.weixin.qq.com/doc/oplatform/Website_App/WeChat_Login/Wechat_Login.html](https://developers.weixin.qq.com/doc/oplatform/Website_App/WeChat_Login/Wechat_Login.html)
公众号的方式进行扫码登录:[https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Receiving_event_pushes.html](https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Receiving_event_pushes.html)
思路:
1:网站应用的方式直接参考微信文档即可明白登录流程,详细调用方法如下:
2:公众号方式的思路为:通过关注事件进行的推送,即用户扫描二维码后微信后台会向开发者推送关注或已关注的事件消息,开发者通过解析事件消息来对扫码的用户进行账号绑定或者获取账号信息,能获取到账号信息的即可以登录,获取不到则通知用户进行绑定。详细调用方法如下:
控制器层:
```
<?php
namespace Controllers;
use Controllers\BaseController;
use Util\SendSms;
use \Common\Tools;
class OauthController extends BaseController
{
public function getBindAction()
{
$auth = $this->request->get('auth');
if (empty($auth)) {
$this->outputJsonError('auth参数不允许为空');
}
$auth = Tools::authcode($auth, 'DECODE');
if (empty($auth)) {
$this->outputJsonError('非法的auth数据');
}
$oauthInfo = $this->local->call(array('service' => 'Services\Oauth', 'method' => 'getOauth', 'args' => array(['site' => 2, 'sid' => $auth], "itemid,nickname,userid")));
if (!$oauthInfo['data']) {
$this->outputJsonSuccess(['type' => 1]);
} elseif ($oauthInfo['data']['userid'] != $this->userinfo['userid']) {
$this->outputJsonSuccess(['type' => 2]);
} else {
$oauthInfo['data']['type'] = 3;
$this->outputJsonSuccess($oauthInfo['data']);
}
}
/**
* @Author zhp
* @DateTime 2020-04-22
* @desc [微信回调通知]
* @version [version]
* @return [type] [description]
*/
public function wxchatNotifyAction()
{
$checkSignature = $this->local->call(array('service' => 'Services\Oauth', 'method' => 'checkSignature', 'args' => array()));
if ($checkSignature['code'] != 200) {
exit('非法请求');
}
$HTTP_RAW_POST_DATA or $HTTP_RAW_POST_DATA = file_get_contents('php://input');
if (!$HTTP_RAW_POST_DATA) {
exit($_GET["echostr"]);
}
$this->local->call(array('service' => 'Services\Oauth', 'method' => 'wxchatNotify', 'args' => array($HTTP_RAW_POST_DATA)));
}
public function wxchatQrcodeBindAction()
{
$userid = $this->userinfo['userid'];
$sid = Tools::random(9, '123456789');
$auth = Tools::authcode($sid, '');
$scene_str = "wxbind_{$userid}_{$sid}";
$res = $this->local->call(array('service' => 'Services\Oauth', 'method' => 'wxchatQrcode', 'args' => array($scene_str)));
if ($res['code'] != 200) {
$this->outputJsonError($res['msg']);
} else {
$this->outputJsonSuccess(['auth' => $auth, 'url' => $res['data']['url']]);
}
}
/**
* @Author zhp
* @DateTime 2020-04-21
* @desc [公众号方式-生成二维码]
* @version [version]
* @return [type] [description]
*/
public function wxchatQrcodeAction()
{
$sid = Tools::random(9, '123456789');
$scene_str = "wxlogin_{$sid}";
$auth = Tools::authcode($sid, '');
$res = $this->local->call(array('service' => 'Services\Oauth', 'method' => 'wxchatQrcode', 'args' => array($scene_str)));
if ($res['code'] != 200) {
$this->outputJsonError($res['msg']);
} else {
$this->outputJsonSuccess(['auth' => $auth, 'url' => $res['data']['url']]);
}
}
/**
* @Author zhp
* @DateTime 2020-04-21
* @desc [公众号方式-扫码关注后登录]
* @version [version]
* @return [type] [description]
*/
public function wxchatLoginAction()
{
$header = [];
$auth = $this->request->get('auth');
if (empty($auth)) {
$this->outputJsonError('auth参数不允许为空');
}
$auth = Tools::authcode($auth, 'DECODE');
if (empty($auth)) {
$this->outputJsonError('非法的auth数据');
}
$header['HTTP_USER_AGENT'] = $this->request->getHeader("HTTP_USER_AGENT");
$result = $this->local->call(array('service' => 'Services\Oauth', 'method' => 'wxchatLogin', 'args' => array($auth, $header)));
$this->outputJsonSuccess($result['data']);
}
/**
* @Author zhp
* @DateTime 2020-04-21
* @desc [网站应用方式-扫码登录]
* @version [version]
* @return [type] [description]
*/
public function wxLoginAction()
{
$header = [];
$code = $this->request->getPost('code');
if (!$code) {
$this->outputJsonError('参数不允许为空');
}
$header['HTTP_USER_AGENT'] = $this->request->getHeader("HTTP_USER_AGENT");
$result = $this->local->call(array('service' => 'Services\Oauth', 'method' => 'wxLogin', 'args' => array($code, $header)));
if ($result['code'] != 200) {
$this->outputJsonError($result['msg'], 600, $result['data']);
} else {
$this->outputJsonSuccess($result['data']);
}
}
/**
* @Author zhp
* @DateTime 2020-04-21
* @desc [网站应用方式-微信绑定]
* @version [version]
* @return [type] [description]
*/
public function wxBindAction()
{
$code = $this->request->getPost('code');
if (!$code) {
$this->outputJsonError('参数不允许为空');
}
$wxUser = $this->local->call(array('service' => 'Services\Oauth', 'method' => 'getWx', 'args' => array($code)));
if ($wxUser['code'] != 200) {
$this->outputJsonError($wxUser['msg']);
}
$result = $this->local->call(array('service' => 'Services\Oauth', 'method' => 'wxBind', 'args' => array($wxUser['data'], $this->userinfo)));
if ($result['code'] != 200) {
$this->outputJsonError($result['msg']);
} else {
$this->outputJsonSuccess($result['data']);
}
}
/**
* @Author zhp
* @DateTime 2020-04-21
* @desc [微信解绑]
* @version [version]
* @return [type] [description]
*/
public function wxDelBingAction()
{
$this->local->call(array('service' => 'Services\Oauth', 'method' => 'wxDelBind', 'args' => array($this->userinfo)));
$this->outputJsonSuccess([]);
}
public function wxchatDelBindAction()
{
$data = $this->request->getPost();
if (empty($data['itemid'])) {
$this->outputJsonError('参数不允许为空');
}
$this->local->call(array('service' => 'Services\Oauth', 'method' => 'editOauth', 'args' => array(['itemid' => $data['itemid'], 'userid' => $this->userinfo['userid']], ['userid' => 0])));
$this->outputJsonSuccess([]);
}
/**
* @Author zhp
* @DateTime 2020-04-21
* @desc [网站应用方式or公众号方式扫码 后手机号绑定]
* @version [version]
* @return [type] [description]
*/
public function wxLoginMobileAction()
{
$data = $this->request->getPost();
if (empty($data['id']) || empty($data['site']) || empty($data['mobile']) || empty($data['mobilecode'])) {
$this->outputJsonError('参数不允许为空');
}
if (!Tools::isMobile($data['mobile'])) {
$this->outputJsonError('请输入正确的手机号');
}
if (!Tools::isCode($data['mobilecode'])) {
$this->outputJsonError('验证码格式错误');
}
if (!in_array($data['site'], [1, 2])) {
$this->outputJsonError('site参数错误');
}
//验证码
if ($data['mobilecode'] != $this->memcache->get('bind:mobile:code:' . $data['mobile'])) {
$this->outputJsonError('验证码错误');
}
$oauthInfo = $this->local->call(array('service' => 'Services\Oauth', 'method' => 'getOauth', 'args' => array(['itemid' => $data['id']], "itemid")));
if (empty($oauthInfo['data'])) {
$this->outputJsonError('不存在该微信用户信息');
}
$oauthInfo = $oauthInfo['data'];
$userInfo = $this->local->call(array('service' => 'Services\Member', 'method' => 'get', 'args' => array('mobile', ['mobile' => $data['mobile']])));
if ($userInfo['code'] != 200) {
//注册用户
$password = Tools::random(8);
$result = $this->local->call(array('service' => 'Services\Member', 'method' => 'add', 'args' => array('data' => ['mobile' => $data['mobile'], 'username' => $data['mobile'], 'password' => $password])));
if ($result['code'] != 200) {
$this->outputJsonError('注册失败');
}
$userInfo = $this->local->call(array('service' => 'Services\Member', 'method' => 'get', 'args' => array('id', ['userid' => $result['data']])));
//短信发送密码
$smsObj = new SendSms();
$smsObj->sendSms($data['mobile'], "您的登录密码为{$password},请牢记保存。【星空译站】");
} else {
//检测用户是否已绑定
$checkBind = $this->local->call(array('service' => 'Services\Oauth', 'method' => 'getOauth', 'args' => array(['userid' => $userInfo['data']['userid']], "itemid")));
if ($checkBind['data']) {
$this->outputJsonError('该手机号已绑定其它微信,请更换手机号');
}
}
$result = $this->local->call(array('service' => 'Services\Oauth', 'method' => 'wxBind', 'args' => array($oauthInfo, $userInfo['data'], $data['site'])));
if ($result['code'] != 200) {
$this->outputJsonError($result['msg']);
} else {
$header['HTTP_USER_AGENT'] = $this->request->getHeader("HTTP_USER_AGENT");
$jwt = $this->local->call(array('service' => 'Services\Oauth', 'method' => 'logAndJwt', 'args' => array($userInfo['data'], $header)));
$userInfo['data']['other'] = json_decode($userInfo['data']['other'], true);
$this->outputJsonSuccess(['userinfo' => $userInfo['data'], 'jwt' => $jwt['data']['jwt']]);
}
}
}
```
Service逻辑处理层
```
<?php
namespace Services;
use Firebase\JWT\JWT;
use \Common\ReqHelp;
use \Common\Tools;
use \Models\Member;
use \Models\Oauth;
use \Services\BaseService;
class OauthService extends BaseService
{
private $WX_TOKEN_URL = 'https://api.weixin.qq.com/sns/oauth2/access_token';
private $WX_USERINFO_URL = 'https://api.weixin.qq.com/sns/userinfo';
public function wxchatQrcode($scene_str = '')
{
$access_token = $this->getAccesstoken();
if ($access_token['code'] != 200) {
return $this->outputData([], 600, $access_token['msg']);
}
$url = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token={$access_token['data']}";
$param = '{"expire_seconds": 3600, "action_name": "QR_STR_SCENE", "action_info": {"scene": {"scene_str": "' . $scene_str . '"}}}';
$res = ReqHelp::postjson($url, $param);
if ($res['0'] != 200) {
return $this->outputData([], 600, '二维码获取失败');
}
$res = json_decode($res['1'], true);
return $this->outputData(['url' => $res['url']]);
}
public function wxchatNotify($HTTP_RAW_POST_DATA)
{
$nowtime = time();
if (function_exists('libxml_disable_entity_loader')) {
libxml_disable_entity_loader(true);
}
$x = (array) simplexml_load_string($HTTP_RAW_POST_DATA, 'SimpleXMLElement', LIBXML_NOCDATA);
if ($x['MsgType'] == 'event') {
//事件
switch ($x['Event']) {
case 'CLICK': //点击菜单拉取消息时的事件推送
switch ($x['EventKey']) {
}
break;
case 'subscribe': //订阅
$user = $this->getOauth(['openid' => $x['FromUserName']]);
$info = $this->wxchatGetWx($x['FromUserName'])['data'];
$param = [
'site' => 2,
'openid' => $x['FromUserName'],
'nickname' => $info['nickname'],
'avatar' => $info['headimgurl'],
'addtime' => $nowtime,
'unionid' => !empty($info['unionid']) ? $info['unionid'] : '',
'subscribe' => 1,
'sex' => $info['sex'],
'city' => $info['city'],
'province' => $info['province'],
'country' => $info['country'],
'language' => $info['language'],
];
if ($user['data']) {
$this->editOauth(['itemid' => $user['data']['itemid']], $param);
} else {
$this->addOauth($param);
}
if (strpos($x['EventKey'], 'qrscene_') !== false) {
$sid = substr($x['EventKey'], 8);
if (substr($sid, 0, 7) == 'wxlogin') {
$sid = substr($sid, 8);
$this->editOauth(['openid' => $x['FromUserName']], ['sid' => $sid]);
}
if (substr($sid, 0, 6) == 'wxbind') {
$sid = explode("_", substr($sid, 7));
$oauthInfo = $this->getOauth(['site' => 2, 'openid' => $x['FromUserName']], "itemid,userid");
if ($oauthInfo['data']['userid']) {
$this->editOauth(['openid' => $x['FromUserName']], ['sid' => $sid['1']]);
} else {
$this->editOauth(['openid' => $x['FromUserName']], ['userid' => $sid['0'], 'sid' => $sid['1']]);
}
}
}
break;
case 'unsubscribe': //取消订阅
break;
case 'SCAN':
//扫描二维码[已关注]
$user = $this->getOauth(['openid' => $x['FromUserName']]);
if ($user['data']) {
if (substr($x['EventKey'], 0, 7) == 'wxlogin') {
$sid = substr($x['EventKey'], 8);
$this->editOauth(['openid' => $x['FromUserName']], ['sid' => $sid]);
}
if (substr($x['EventKey'], 0, 6) == 'wxbind') {
$sid = explode("_", substr($x['EventKey'], 7));
$oauthInfo = $this->getOauth(['site' => 2, 'openid' => $x['FromUserName']], "itemid,userid");
if ($oauthInfo['data']['userid']) {
$this->editOauth(['openid' => $x['FromUserName']], ['sid' => $sid['1']]);
} else {
$this->editOauth(['openid' => $x['FromUserName']], ['userid' => $sid['0'], 'sid' => $sid['1']]);
}
}
}
break;
case 'LOCATION': //上报地理位置事件
break;
case 'VIEW': //点击菜单跳转链接时的事件推送
break;
case 'TEMPLATESENDJOBFINISH': //模板消息结果
break;
default:
break;
}
} else {
//消息
switch ($MsgType) {
case 'text': //文本消息
break;
case 'image': //图片消息
break;
case 'voice': //语音消息
break;
case 'video': //视频消息
break;
case 'location': //地理位置消息
break;
case 'link': //链接消息
break;
default:
break;
}
}
return $this->outputData([]);
}
/**
* @Author zhp
* @DateTime 2020-04-21
* @desc [解绑微信用户]
* @version [version]
* @param [type] $userInfo [description]
* @return [type] [description]
*/
public function wxDelBind($userInfo)
{
$oauthInfo = Oauth::findFirst(array(
'conditions' => "userid = {$userInfo['userid']}",
));
$oauthInfo->delete();
return $this->outputData([]);
}
public function addOauth($data)
{
$obj = new Oauth();
if ($obj->save($data)) {
return $this->outputData($obj->itemid);
} else {
return $this->outputData(false, 600, '添加失败!');
}
}
public function editOauth($search, $data)
{
$condition = '';
$bind = [];
if ($search) {
foreach ($search as $k => $v) {
$condition .= "{$k} = :{$k}: and ";
$bind[$k] = $v;
}
}
if (empty($condition)) {
return $this->outputData([]);
}
$condition = rtrim($condition, ' and ');
$oauthInfo = Oauth::findFirst(array(
'conditions' => $condition,
'bind' => $bind,
));
if (!$oauthInfo) {
return $this->outputData(false, 600, '不存在该信息');
}
$oauthInfo->save($data);
return $this->outputData([]);
}
/**
* @Author zhp
* @DateTime 2020-04-21
* @desc [获取绑定信息]
* @version [version]
* @param [type] $userid [description]
* @param string $fields [description]
* @return [type] [description]
*/
public function getOauth($search, $fields = "*")
{
$condition = '';
$bind = [];
if ($search) {
foreach ($search as $k => $v) {
$condition .= "{$k} = :{$k}: and ";
$bind[$k] = $v;
}
}
if (empty($condition)) {
return $this->outputData([]);
}
$condition = rtrim($condition, ' and ');
$oauthInfo = Oauth::findFirst(array(
'conditions' => $condition,
'bind' => $bind,
'columns' => "{$fields}",
));
if ($oauthInfo) {
return $this->outputData($oauthInfo->toArray());
} else {
return $this->outputData([]);
}
}
/**
* @Author zhp
* @DateTime 2020-04-21
* @desc [绑定微信用户]
* @version [version]
* @param [type] $wxUser [description]
* @param [type] $userInfo [description]
* @return [type] [description]
*/
public function wxBind($wxUser, $userInfo, $site)
{
//账户是否已绑定
$oauthInfo = Oauth::findFirst(array(
'conditions' => "userid = {$userInfo['userid']} and site = {$site}",
'columns' => 'itemid',
));
if ($oauthInfo) {
return $this->outputData([], 600, '该账户已绑定微信');
}
//微信是否绑定
$oauthInfo = Oauth::findFirst(array(
'conditions' => "itemid = {$wxUser['itemid']}",
));
if (!$oauthInfo) {
return $this->outputData([], 600, '不存在该微信信息');
}
if ($oauthInfo->userid) {
return $this->outputData([], 600, '该微信已绑定账户');
}
$oauthInfo->save(['userid' => $userInfo['userid']]);
return $this->outputData([]);
}
public function wxchatLogin($sid, $header = [])
{
$oauthInfo = Oauth::findFirst(array(
'conditions' => "site=2 and sid={$sid}",
'columns' => 'itemid,userid,openid',
));
if (!$oauthInfo) {
return $this->outputData(['type' => 1], 200, '未关注公众号');
}
$oauthInfo = $oauthInfo->toArray();
if ($oauthInfo['userid']) {
//登录
$userInfo = Member::findFirst(array(
"conditions" => "userid = {$oauthInfo['userid']}",
))->toArray();
$userInfo['other'] = json_decode($userInfo['other'], true);
$jwt = $this->logAndJwt($userInfo, $header);
return $this->outputData(['type' => 3, 'userinfo' => $userInfo, 'jwt' => $jwt['data']['jwt']]);
} else {
return $this->outputData(['type' => 2, 'id' => $oauthInfo['itemid'], 'site' => 2], 200, '请绑定账户');
}
}
/**
* @Author zhp
* @DateTime 2020-04-21
* @desc [网站应用方式-扫码登录]
* @version [version]
* @param [type] $code [description]
* @param array $header [description]
* @return [type] [description]
*/
public function wxLogin($code, $header = [])
{
$wxUser = $this->getWx($code);
if ($wxUser['code'] != 200) {
return $wxUser;
}
//该微信用户是否已绑定账号
$oauthInfo = Oauth::findFirst(array(
'conditions' => "openid = {$wxUser['openid']}",
'columns' => 'userid',
));
if ($oauthInfo) {
//登录
$userInfo = Member::findFirst(array(
"conditions" => "userid = {$oauthInfo->userid}",
))->toArray();
$jwt = $this->logAndJwt($userInfo, $header);
return $this->outputData(['userinfo' => $userInfo, 'jwt' => $jwt['data']['jwt']]);
} else {
//未登录手动绑定输入手机号
$this->di['memcache']->set("wx_login_{$wxUser['openid']}", json_encode($wxUser), 1800);
return $this->outputData(['id' => $res['openid'], 'site' => 1], 600, '请绑定账户');
}
}
/**
* @Author zhp
* @DateTime 2020-04-21
* @desc [网站应用的方式-扫码登录-获取用户信息]
* @version [version]
* @param [type] $code [description]
* @return [type] [description]
*/
public function getWx($code)
{
$appid = $this->di['config']->wx->appid;
$secret = $this->di['config']->wx->secret;
$url = $this->WX_TOKEN_URL . "?appid={$appid}&secret={$secret}&code=CODE&grant_type=authorization_code";
$res = ReqHelp::get($url);
$res = json_decode($res, true);
if (!empty($res['errcode'])) {
return $this->outputData([], 600, $res['errmsg']);
}
//获取微信用户信息
$url = $this->WX_USERINFO_URL . "?access_token={$res['access_token']}&openid={$res['openid']}";
$wxUser = ReqHelp::get($url);
$wxUser = json_decode($wxUser, true);
if (!empty($wxUser['errcode'])) {
return $this->outputData([], 600, $wxUser['errmsg']);
}
$wxUser['openid'] = $res['openid'];
return $this->outputData(['wxUser' => $wxUser]);
}
/**
* @Author zhp
* @DateTime 2020-04-21
* @desc 写登录日志和创建jwt
* @version [version]
* @param [type] $userInfo [description]
* @param array $header [description]
* @return [type] [description]
*/
public function logAndJwt($userInfo, $header = [])
{
$log['userid'] = $userInfo['userid'];
$log['username'] = $userInfo['username'];
$log['loginip'] = Tools::getip();
$log['agent'] = $header["HTTP_USER_AGENT"] ?? '';
// $result = Tools::getAddressByIp($log['loginip']);
// if ($result['status'] == 0) {
// $location = $result['data'][0]['location'];
// if (strstr($location, ' ')) {
// $loca = explode(' ', $location);
// $log['location'] = $loca[0] ?? '';
// $log['operator'] = $loca[1] ?? '';
// } else {
// $log['location'] = strstr($location, '本地局域网') ? '' : $location;
// $log['operator'] = '';
// }
// }
$this->di['local']->call(array('service' => 'Services\Login', 'method' => 'add', 'args' => array('data' => $log)));
//jwt token
$jwtdata = [
'userid' => $userInfo['userid'] ?? 0,
'expire' => strtotime(date('Ymd')) + 97200, //第二天凌晨3点
];
$jwt = JWT::encode($jwtdata, $this->di['config']->jwt->secret);
return $this->outputData(['jwt' => $jwt]);
}
/**
* @Author zhp
* @DateTime 2020-04-21
* @desc [公众号方式-验证签名]
* @version [version]
* @return [type] [description]
*/
public function checkSignature()
{
if (empty($_GET["signature"]) || empty($_GET["timestamp"]) || empty($_GET["nonce"])) {
return $this->outputData([], 600, '签名错误');
}
$signature = $_GET["signature"];
$timestamp = $_GET["timestamp"];
$nonce = $_GET["nonce"];
$token = $this->di['config']->wxPublicChat->token;
$tmpArr = array($token, $timestamp, $nonce);
sort($tmpArr, SORT_STRING);
$tmpStr = implode($tmpArr);
$tmpStr = sha1($tmpStr);
if ($tmpStr == $signature) {
return $this->outputData([]);
} else {
return $this->outputData([], 600, '签名错误');
}
}
/**
* @Author zhp
* @DateTime 2020-04-22
* @desc [公众号方式-获取微信用户信息]
* @version [version]
* @param [type] $openid [description]
* @return [type] [description]
*/
public function wxchatGetWx($openid)
{
$access_token = $this->getAccesstoken();
if (!$access_token['data']) {
return $this->outputData([], 600, $access_token['msg']);
}
$url = 'https://api.weixin.qq.com/cgi-bin/user/info?access_token=' . $access_token['data'] . '&openid=' . $openid;
$info = json_decode(ReqHelp::get($url), true);
return $this->outputData($info);
}
/**
* @Author zhp
* @DateTime 2020-04-21
* @desc [公众号方式]
* @version [version]
* @return [type] [description]
*/
public function getAccesstoken()
{
$appid = $this->di['config']->wxPublicChat->appid;
$secret = $this->di['config']->wxPublicChat->secret;
$url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={$appid}&secret={$secret}";
$memKey = "{$appid}_accesstoken";
$mem = $this->di['memcache']->get($memKey);
if ($mem) {
return $this->outputData($mem);
}
$res = ReqHelp::get($url);
$res = json_decode($res, true);
if (!empty($res['errcode'])) {
return $this->outputData([], 600, $res['errmsg']);
}
$this->di['memcache']->set($memKey, $res['access_token'], $res['expires_in'] - 1800);
return $this->outputData($res['access_token']);
}
}
```
- 技能知识点
- 对死锁问题的理解
- 文件系统原理:如何用1分钟遍历一个100TB的文件?
- 数据库原理:为什么PrepareStatement性能更好更安全?
- Java Web程序的运行时环境到底是怎样的?
- 你真的知道自己要解决的问题是什么吗?
- 如何解决问题
- 经验分享
- GIT的HTTP方式免密pull、push
- 使用xhprof对php7程序进行性能分析
- 微信扫码登录和使用公众号方式进行扫码登录
- 关于curl跳转抓取
- Linux 下配置 Git 操作免登录 ssh 公钥
- Linux Memcached 安装
- php7安装3.4版本的phalcon扩展
- centos7下php7.0.x安装phalcon框架
- 将字符串按照指定长度分割
- 搜索html源码中标签包的纯文本
- 更换composer镜像源为阿里云
- mac 隐藏文件显示/隐藏
- 谷歌(google)世界各国网址大全
- 实战文档
- PHP7安装intl扩展和linux安装icu
- linux编译安装时常见错误解决办法
- linux删除文件后不释放磁盘空间解决方法
- PHP开启异步多线程执行脚本
- file_exists(): open_basedir restriction in effect. File完美解决方案
- PHP 7.1 安装 ssh2 扩展,用于PHP进行ssh连接
- php命令行加载的php.ini
- linux文件实时同步
- linux下php的psr.so扩展源码安装
- php将字符串中的\n变成真正的换行符?
- PHP7 下安装 memcache 和 memcached 扩展
- PHP 高级面试题 - 如果没有 mb 系列函数,如何切割多字节字符串
- PHP设置脚本最大执行时间的三种方法
- 升级Php 7.4带来的两个大坑
- 不同域名的iframe下,fckeditor在chrome下的SecurityError,解决办法~~
- Linux find+rm -rf 执行组合删除
- 从零搭建Prometheus监控报警系统
- Bug之group_concat默认长度限制
- PHP生成的XML显示无效的Char值27消息(PHP generated XML shows invalid Char value 27 message)
- XML 解析中,如何排除控制字符
- PHP各种时间获取
- nginx配置移动自适应跳转
- 已安装nginx动态添加模块
- auto_prepend_file与auto_append_file使用方法
- 利用nginx实现web页面插入统计代码
- Nginx中的rewrite指令(break,last,redirect,permanent)
- nginx 中 index try_files location 这三个配置项的作用
- linux安装git服务器
- PHP 中运用 elasticsearch
- PHP解析Mysql Binlog
- 好用的PHP学习网(持续更新中)
- 一篇写给准备升级PHP7的小伙伴的文章
- linux 安装php7 -系统centos7
- Linux 下多php 版本共存安装
- PHP编译安装时常见错误解决办法,php编译常见错误
- nginx upstream模块--负载均衡
- 如何解决Tomcat服务器打开不了HOST Manager的问题
- PHP的内存泄露问题与垃圾回收
- Redis数据结构 - string字符串
- PHP开发api接口安全验证
- 服务接口API限流 Rate Limit
- php内核分析---内存管理(一)
- PHP内存泄漏问题解析
- 【代码片-1】 MongoDB与PHP -- 高级查询
- 【代码片-1】 php7 mongoDB 简单封装
- php与mysql系统中出现大量数据库sleep的空连接问题分析
- 解决crond引发大量sendmail、postdrop进程问题
- PHP操作MongoDB GridFS 存储文件,如图片文件
- 浅谈php安全
- linux上keepalived+nginx实现高可用web负载均衡
- 整理php防注入和XSS攻击通用过滤