首页
Search
1
解决 docker run 报错 oci runtime error
49,608 阅读
2
WebStorm2025最新激活码
28,204 阅读
3
互点群、互助群、微信互助群
23,060 阅读
4
常用正则表达式
21,664 阅读
5
罗技鼠标logic g102驱动程序lghub_installer百度云下载windows LIGHTSYNC
20,036 阅读
自习室
互通有无
搞钱日记
养生记
包罗万象
Search
标签搜索
职场副业
职业发展
副业赚钱
后端开发
内容创作
微服务
分布式系统
效率提升
DevOps
技能提升
流量变现
性能优化
云原生
高并发
编程学习
深度学习
人工智能
架构设计
机器学习
前端开发
loong
累计撰写
3,206
篇文章
累计收到
4
条评论
首页
栏目
自习室
互通有无
搞钱日记
养生记
包罗万象
页面
搜索到
78
篇与
的结果
2019-08-26
PHP身份证验证类
<?php /** *身份证号处理函数 */ /** * 功能:根据身份证号,自动返回生日 * @param stirng $IDCard 身份证号 * @return Ambigous <string, NULL> */ function getBrithday ($idCard) { if (strlen($idCard) == 18) { $birthday = substr($idCard, 6, 4) . '-' . substr($idCard, 10, 2) . '-' . substr($idCard, 12, 2); } elseif (strlen($idCard) == 15) { $birthday = "19" . substr($idCard, 6, 2) . '-' . substr($idCard, 8, 2) . '-' . substr($idCard, 10, 2); } else { $birthday = null; } return $birthday; } /** * 功能:根据身份证号,自动返回性别 * @param string $cid 身份证号 * @param number $comm 返回的性别类型 * @return string 男/女 1/0 */ function getSex ($cid, $comm = 0) { $cid = getIDCard($cid); $sexint = (int) substr($cid, 16, 1); if ($comm > 0) { return $sexint % 2 === 0 ? '女' : '男'; } else { return $sexint % 2 === 0 ? '0' : '1'; } } /** * 功能:把15位身份证转换成18位 * @param string $idCard * @return newid or id */ function getIDCard ($idCard) { // 若是15位,则转换成18位;否则直接返回ID if (15 == strlen($idCard)) { $w = array(7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2,1); $a = array("1","0","X","9","8","7","6","5","4","3","2"); $s = 0; $idCard18 = substr($idCard, 0, 6) . "19" . substr($idCard, 6); $idCard18_len = strlen($idCard18); for ($i = 0; $i < $idCard18_len; $i ++) { $s = $s + substr($idCard18, $i, 1) * $w[$i]; } return $idCard18.$a[$s % 11]; } else { return $idCard; } } /** * 根据身份证号返回年龄 * @param string $id 身份证号 * @return string|number */ function getAge($id){ //过了这年的生日才算多了1周岁 if(empty($id)) return ''; $date=strtotime(substr($id,6,8)); //获得出生年月日的时间戳 $today=strtotime('today'); //获得今日的时间戳 $diff=floor(($today-$date)/86400/365); //得到两个日期相差的大体年数 //strtotime加上这个年数后得到那日的时间戳后与今日的时间戳相比 $age=strtotime(substr($id,6,8).' +'.$diff.'years')>$today?($diff+1):$diff; return $age; }
2019年08月26日
5,638 阅读
0 评论
0 点赞
2019-08-26
百度地图两点坐标距离计算
百度地图两点坐标距离计算/** * * 根据两点的经纬度计算距离 * @author zhengshaozhuo * @version 2015-08-10 */ function calc_distance_by_pos($o_lat, $o_lng, $t_lat, $t_lng){ $pk = 180 / 3.14169; $_a1 = $o_lat / $pk; $_a2 = $o_lng / $pk; $_b1 = $t_lat / $pk; $_b2 = $t_lng / $pk; $t1 = cos($_a1) * cos($_a2) * cos($_b1) * cos($_b2); $t2 = cos($_a1) * sin($_a2) * cos($_b1) * sin($_b2); $t3 = sin($_a1) * sin($_b1); $tt = acos($t1 + $t2 + $t3); return (int)(6366000 * $tt); }
2019年08月26日
5,566 阅读
0 评论
4 点赞
2019-08-26
PHP地理位置计算
<?php // Geohash // @url: http://blog.jobbole.com/80633/ /** *求两个已知经纬度之间的距离,单位为米 *@param lng1,lng2 经度 *@param lat1,lat2 纬度 *@return float 距离,单位米 **/ function getdistance($lng1,$lat1,$lng2,$lat2){ //将角度转为狐度 $radLat1=deg2rad($lat1);//deg2rad()函数将角度转换为弧度 $radLat2=deg2rad($lat2); $radLng1=deg2rad($lng1); $radLng2=deg2rad($lng2); $a=$radLat1-$radLat2; $b=$radLng1-$radLng2; $s=2*asin(sqrt(pow(sin($a/2),2)+cos($radLat1)*cos($radLat2)*pow(sin($b/2),2)))*6378.137*1000; return intval($s); } function distanceConvert($s){ $s = intval($s); if($s <= 0){ return '附近'; }elseif($s > 0 && $s <= 1000){ return $s.'m'; }elseif($s > 1000 && $s <= 2000){ return '<2km'; }elseif($s > 2000 && $s <= 3000){ return '<3km'; }elseif($s > 3000 && $s <= 4000){ return '<4km'; }elseif($s > 4000 && $s <= 5000){ return '<5km'; }elseif($s > 5000){ return '>5km'; } } /** * 根据条件获取商户列表 * @param string $lng * @param string $lat * @param string $city_id * @param string $district_id * @param string $type_id * @param string $search * @return mixed */ //如果存在经纬度则考虑范围5公里内数据,如果不存在经纬度,则不考虑 public function GetShopList($navigationId = 0,$page = 1,$size =10 ,$lng = '', $lat ='', $city_id = '',$district_id = '',$type_id = '',$search = '') { $field = 'id,province_id,city_id,district_id,navigation_id,type_id,name,phone,address,logo,stime,etime,rule,activity,discount,latitude,longitude,status,token,sort,description,gmt_created'; $where = array( 'is_deleted' => 0, 'is_show' => 1, 'navigation_id'=>$navigationId, ); //判断城市,县区,分类是否存在 if(!empty($city_id)){ $where['city_id|province_id'] = $city_id; } if(!empty($district_id)){ $where['district_id'] = $district_id; } if(!empty($type_id)){ $where['type_id'] = $type_id; } if(!empty($search)){ $where['name'] = array('like',"%{$search}%"); } $offset = ($page * $size) - ($size - 1); //如果存在经纬度,就根据经纬度查询5公里范围内数据 if(!empty($lng) && !empty($lat)) { // //求出半径 // $radius = 5;//半径范围,单位km // $rangeLat = 180 / pi() * $radius / 6372.797;//纬度范围 // $rangeLng = $rangeLat / cos($lat * pi() / 180.0); //经度范围 // $maxLat = $lat + $rangeLat; //x1 // $minLat = $lat - $rangeLat; //x0 // $maxLng = $lng + $rangeLng; //y1 // $minLng = $lng - $rangeLng; //y0 // // $where['latitude'] = array(array('lt',$maxLat),array('gt',$minLat)); // $where['longitude'] = array(array('lt',$maxLng),array('gt',$minLng)); $list = $this->where($where)->field($field)->order("abs(longitude - {$lng}) + abs(latitude - {$lat})")->limit($offset,$size)->select(); }else{ $list = $this->where($where)->field($field)->order('sort asc')->limit($offset,$size)->select(); } //记录错误日志 if ($list === false) { wLog('GetShopList error! sql:' . $this->getLastSql(), $this->errorFile); wLog('GetShopList error! errorInfo:' . $this->error, $this->errorFile); } //wLog('GetShopList sql:' . $this->getLastSql(), $this->errorFile); return $list; }
2019年08月26日
4,455 阅读
0 评论
0 点赞
2019-08-26
PHP原生生成EXCEL
<?php /*** * 生成excle文件 ***/ $time = time(); $filename = date("Y年m月d日h点m分s秒", $time).'问卷数据'; $rows = Sp_Looks_Vote::downvote(); $file = $filename.".csv"; header('Content-Description: File Transfer'); header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename='.basename($file)); header('Content-Transfer-Encoding: binary'); header('Expires: 0'); header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); header('Pragma: public'); $tabletitle .= "购买地址,常常购买,喜欢模特,内容如何,印象如何,是否购买,感觉如何,购买方式,购买方式建议,吸引点,改进建议"; $conter = iconv('utf-8','gbk',$tabletitle)."\n"; echo $conter;die; /*** * 生成word文件 ***/ header("Content-Type: application/msword"); header("Content-Disposition: attachment; filename=doc.doc"); header("Pragma: no-cache"); header("Expires: 0"); $output = '<table border="1" cellspacing="2" cellpadding="2" width="90%" align="center">'; $output .= '<tr bgcolor="#cccccc"><td align="center">图片</td></tr>'; $output .= '<tr bgcolor="#f6f7fa"><td><span style="color:#FF0000;"><strong>下面是一张图片</strong></span& gt;</td></tr>'; $output .= '<tr><td align="center"><img src="http://zi.csdn.net/48260_2.gif"></td></tr>'; $output .= '</table>'; echo $output; ?>
2019年08月26日
3,473 阅读
0 评论
0 点赞
2019-08-26
PHP获取服务器状态
PHP获取服务器状态:<?php function get_server_status() { $fp = popen('top -b -n 2 | grep -E "^(Cpu|Mem|Tasks)"', "r");//获取某一时刻系统cpu和内存使用情况 $rs = ""; while (!feof($fp)) { $rs .= fread($fp, 1024); } pclose($fp); $sys_info = explode("\n", $rs); $tast_info = explode(",", $sys_info[3]);//进程 数组 $cpu_info = explode(",", $sys_info[4]); //CPU占有量 数组 $mem_info = explode(",", $sys_info[5]); //内存占有量 数组 //正在运行的进程数 $tast_running = trim(trim($tast_info[1], 'running')); //CPU占有量 $cpu_usage = trim(trim($cpu_info[0], 'Cpu(s): '), '%us'); //百分比 //内存占有量 $mem_total = trim(trim($mem_info[0], 'Mem: '), 'k total'); $mem_used = trim($mem_info[1], 'k used'); $mem_usage = round(100 * intval($mem_used) / intval($mem_total), 2); //百分比 /*硬盘使用率 begin*/ $fp = popen('df -lh | grep -E "^(/)"', "r"); $rs = fread($fp, 1024); pclose($fp); $rs = preg_replace("/\s{2,}/", ' ', $rs); //把多个空格换成 “_” $hd = explode(" ", $rs); $hd_avail = trim($hd[3], 'G'); //磁盘可用空间大小 单位G $hd_usage = trim($hd[4], '%'); //挂载点 百分比 /*硬盘使用率 end*/ //检测时间 $fp = popen("date +\"%Y-%m-%d %H:%M\"", "r"); $rs = fread($fp, 1024); pclose($fp); $detection_time = trim($rs); return array( 'cpu_usage' => $cpu_usage, 'mem_usage' => $mem_usage, 'hd_avail' => $hd_avail, 'hd_usage' => $hd_usage, 'tast_running' => $tast_running, 'detection_time' => $detection_time ); }
2019年08月26日
3,909 阅读
0 评论
2 点赞
2019-08-26
下单与支付流程的两种设计方案
两种方案两个分开事务过程 通常是创建订单,再支付,这适用于在线支付(第三方在线支付),可以先创建订单,可以此后再选择订单去支付。同一个事务内 另一种直接扣余额的订单(不支持第三方在线支付),其实可以创建订单和支付用一步就可以,订单生成就意味着支付了,只有成功支付才会生成订单,下单和支付放在一个事物内了。订单与支付 一般情况下,请求一次支付会创建一个订单,如果没支付的订单就不显示而已,这是为了,让创建订单和支付像是一步一样,简化了流程,其实实际情况不是用户感知到这样的,只不过没支付的订单,没必要显示给用户而已。 用户感知不到会创建订单,比如充值,购买会员等,用户感知不到这些操作会创建订单,但实际上是创建了订单的,这和商品订单有所不同。 但是有时创建订单和支付也可以一步完成,比如只规定使用余额支付的订单,就可以创建订单和支付为一步原子操作。
2019年08月26日
6,800 阅读
0 评论
78 点赞
2019-08-26
foreach使用引用时需要注意的问题
foreach ($car['cartList'] as &$shop) { } // 这里不释放会影响下面的$shop ,因为引用无法再正常使用 unset($shop); // 这里下面的循环$shop无法正常工作,因为上面$shop成为引用了 foreach ($car['cartList'] as $shop) { }&$item 要特别注意,遍历完必须马上 unset 否则就是一颗炸弹,对业务造成威胁,这种造成的业务错误往往很难排查! 所以不关紧要的变量需要提早释放,这是一个好的习惯,必须严格遵守,不是因为获得最大性能,而是因为可以减少这种难以预见,将来潜在的错误。
2019年08月26日
5,416 阅读
0 评论
16 点赞
2019-08-25
PHP数组与数据结构
数组是PHP中一个灰常、灰常、灰常重要的一个数据类型。因为他涉及到的知识点太多,太杂,我们的讲解是在数组类型部份告诉了大家一个大概,然后专门用一个章节来跟大家讲解。学习数组,大家主要学习两部分的知识:数组的定义,定义中的一些注意的坑数组的函数使用和(默写)又是默写级别的数组在之前我们让大家记住两个观点:数组可以存入多个不同类型的数据,是一个复合数据类型。数组的英文是array,学一下最简单的数组声明。那我们来进行简单的回顾:<?php $shu = array(1 , 1.5 , true ,'天王盖地虎,小鸡炖蘑菇'); echo '<pre>'; var_dump($shu); echo '</pre>'; ?>在上例中,我们发现我们存入了:整型浮点布尔字符串注:上例中echo pre这个标签的主要目的是为原样输出,格式展示的更好看,更清晰。我们用var_dump()打印出来显示看一下效果:我们仔细观察一下上面的这张图,你会发现以下几个特点:array(size = 4) 说明里面有4个元素0 => int 1 我们知道int是整型的意思,1是一个整型的数值。那前面的0,1,2,3和=>代表什么意思呢?最新前的0,1,2,3代表的是值的读取标识号,我们称之为下标或者键(英文:key)=> 是一个符号标准叫法叫作:键值对应符。因此,以后再看到 0=> int 1 可以这样来说。 下标访问符0对应整型的1。我们还称数组里面的键值对为元素,元素就是键值对的组合。哦耶! 数组好像还挺好学的,全是一些规律哟。我们通过上例,其实你一不小心的就完成了数组其中的一种声明方式:索引数组的声明哟。所谓索引数组:就是下标全为整型的数组。索引数组的下标必须要从0开始吗?答:这个问题其实不然,索引数组并不一定要从0开始。那如何能够不从0开始呢?答:需要用到大家在上面学的一小块知识哟。就是键值对应符。我们来动手写写。<?php $kele = array('只有不断努力才能博得未来',10 => 'NoAlike', 'PHP学院' , '去PHP学院去PHP', 19 => '凤姐和芙蓉我都爱' , '杨幂臭脚我最爱'); //打印显示$kele echo '<pre>'; var_dump($kele); echo '</pre>'; ?>上例中,我们一不小心就写了一个索引数组。不过索引数组的下标不是从0 开始的,而是从10开始的。不过上面的例子中,我们觉得写的不优美,我们可以将代码写的更加优美一些,格式更加清晰一些。<?php $kele = array( '只有不断努力才能博得未来', 10 => 'NoAlike', 'PHP学院' , '去PHP学院去PHP', 19 => '凤姐和芙蓉我都爱' , '杨幂臭脚我最爱' ); //打印显示$kele echo '<pre>'; var_dump($kele); echo '</pre>'; ?>这样是不是看得更清楚,一行对应一个数组的值。我们执行一下代码,看一下效果:通过上面的效果,我们来总结规律:索引数组若不强制声明他的下标,他的下标是从0开始的。(我们的第一个数组的值:只有不断努力才能博得未来。这个值的下标为0)。如果我指定过下标他的下标就为我指定的值。如下标为10和下标为19的,都是我指定过的值。若某个值(如NoAlike),强制指定了下标(下标为10)。在它后面加上的值(PHP学院),不指定下标的话。他们的下标增长规律为最大值+1。例如:凤姐和芙蓉我都爱的下标为19.我在后面加上了:杨幂臭脚我最爱。它的下标自动增长为了11。不知不觉,你已经学会了索引数组的创建,神奇吧?真为你感到高兴!###向索引数组中增加元素学习完了索引数组的创建,接下来我们学习索引数组的增加、修改和删除。<?php $minren = array( '杨幂', '王珞丹', '刘亦菲', '黄圣依' ); //如何向这$minren这个数组中增加元素呢 //猜猜范冰冰的下标是多少? $minren[] = '范冰冰'; $minren[100] = '范爷'; //它的下标又为几呢? $minren[] = '李晨'; ?>总结:向索引数组中增加元素用: 数组变量名[]、数组变量名[键值]这两种方式来增加元素键值的增长规则与之前的规则一样。都是最大值加1的原则。###向索引数组中删除元素我们还拿刚刚的数组来举例:<?php $minren = array( '杨幂', '王珞丹', '刘亦菲', '黄圣依', '范冰冰' ); //假设我不喜欢:黄圣依,如何将黄圣依给删掉掉呢? //如果删除掉后范冰冰的下标为多少呢? //如果在后面再追加一个元素,会填掉:“黄圣依”留下来的空吗? unset($minren[3]); $minren[] = '金星'; echo '<pre>'; var_dump($minren); echo '</pre>'; ?>看看效果:使用unset删除变量的方式来删除数组里面的值。删除了中间的值,并不会让后面的下标向前自动移动。而是原来的值为多少就为多少删除掉其中的某个值,新加入的值不会替换掉原来的位置,依然遵循最大值加1的原则。修改值我们学习最简单的创造、增加和删除。我相信大家一定能够推理出如何修改值了。<?php $minren = array( '杨幂', '王珞丹', '刘亦菲', '黄圣依', '范冰冰' ); $minren[5] = '范爷'; $minren[2] = '亦菲,不要架给韩国人好吗?'; echo '<pre>'; var_dump($minren); echo '</pre>'; ?>执行上面的代码,输出看看结果。1.用变量名[键] = 新值。就把数组中的值定的值修改了。索引数组的其他声明方式通过上面的例子,我们学习到了数组的声明。我们来学一下数组的其他声明方式。####一、直接用之前未声明的变量,用变量名后面接中括号的方式声明数组。<?php //直接写一个变量后面加上中括号,声明变量 $qi[] = '可口可乐'; $qi[10] ='百事'; echo '<pre>'; var_dump($qi); echo '</pre>'; ?>####二、每次用array()写的太麻烦了,还可以不用写array哟,更简单。<?php $minren = [ '杨幂', '王珞丹', 100 => '刘亦菲', '黄圣依', '范冰冰' ]; echo '<pre>'; var_dump($minren); echo '</pre>'; ?>上面是另外两种PHP学院的写法。当然,你自己喜欢使用哪一种就使用哪一种来声明。###关联数组索引数组适当的变一下形就出现了关联数组。只要数组里面有一个为字符串的数组,就为关联数组。通过上例中,我们发现数组的下标只能够为字符串,当然不能够满足我的需求。假设我想声明一个下标为帅对应李文凯这个值。肯定不能满足我的需求。那我们来声明一下关联数组。跟索引数组的声明方式完成一样。不过不同的是,必须要指定字符串的下标和必须要使用键值对应符。<?php //声明一下关联数组 $rela = array( '帅' => '李文凯', '很帅' => '黄晓明', '灰常灰常帅' => '宁泽涛', '有男人味的大叔' => '吴秀波', ); //再来玩玩简洁声明 $drink = [ '美' => '凤姐', '很美' => '芙蓉姐姐', 'verymei' => '杨幂', '心中滴女神呀' => '华妃', 100 => '孙俪', '娘娘', ]; // 输出 $rela echo '<pre>'; var_dump($rela); echo '</pre>'; // 输出$drink echo '<pre>'; var_dump($drink); echo '</pre>'; ?>我们来实验一下看看最终的结果是什么样的:我们通过实验知道:声明关联数组是 键名 => 值在关联数组可以有索引数组的元素关联数组中的索引数组的元素后再声明了无下标的元素,依然是最大值+1原则。(观察上图中的值为孙俪、娘娘的两个元素)。###关联数组的增、删、改<?php $drink = [ '美' => '凤姐', '很美' => '芙蓉姐姐', 'verymei' => '杨幂', '心中滴女神呀' => '华妃', 100 => '孙俪', '娘娘', ]; //追加方式与索引数组是一样的 $drink['kx'] = '康熙'; //输出试试 echo '<pre>'; var_dump($drink); echo '</pre>'; //删除一个试试 unset($drink['verymei']); echo '<pre>'; var_dump($drink); echo '</pre>'; //将芙蓉姐姐 改成:心里美才是真的美 $drink['很美'] = '心里美才是真的美'; echo '<pre>'; var_dump($drink); echo '</pre>'; ?>你动手做做刚刚的实验,你会发现操作方式与索引的操作方式一样。只不过下标在读取的时候读取的下标PHP学院了。####其他的关联数组声明方式<?php $drink['nf'] = '农夫山泉'; $cocacola = '可口可乐'; //当然可以是变量哟 $drink['kl'] = $cocacola; $data = array( 'kl' => $cocacola, ); ?>通过上例我们发现,在关联数组当中也是可以不用array,直接在变量后面接括号。括号里面插入字符串下标,一样也声明成功。后面插入变量的例子,只不过把字符串变成了变量,当然没有问题。###数组当中插入数组数组可以插入整型、浮点、字符串,那么数组当中可不可以插入数组呢?当然可以。在学习数组的时候,我们定义了这样一组名词。一维数组 数组里面没有其他数组,只有单纯的一些变量或者值。二维数组 数组里面插入了单层的一个数组,或者多个数组三维数组 在数组(A)里面插入了一个数组(B),在B数组里面又插入了一层级的数组(C),这种我们就称为三维数组超过三维的,统统都叫多维数组。注:索引数组和关联数组当中都可以再插入其他数组,让数组变为多维的。我们来声明一个一维数组,只有一个维度。索引、关联均可,这个操作大家都很熟。<?php //一维的索引数组 $data = [1 , 2 , 3 , 4 , 10 => 250]; //一维的关联数组 $rela = [ 'beijing' => '北京', 'shanghai' => '上海', 'tj' => '天津', ]; ?> echo '<pre>'; var_dump($rela); echo '</pre>'; echo '<pre>'; var_dump($data); echo '</pre>';一维数组大家很熟悉,也不难,就是声明数组嘛。二维也不难,只是在数组里面再插一个或多个数组。二维学好了,多维就学好了。<?php $person = array( 'office' => '办公室', //注意:插入第一个数组哟 'family' => array( '爸爸', '妈妈', 'yeye' => '爷爷', 'nn' => '奶奶', ), //注意:又插入了一个平级的数组 'jiaotong' => array( '自行车', '摩托车', '汽车', '飞机', ), ); echo '<pre>'; var_dump($person); echo '</pre>'; ?>我们执行一下看看效果:我们发现变量person 是一个数组类型。有三个元素(size=3)。第一个元素为 office 对应的是一个字符串“办公室”,第二个元素为family 里面是一个数组,这个数组又有4个元素,值分别为:爸爸、妈妈、爷爷、奶奶。第三个元素为jiaotong,里面也为一个数组有4个元素,值分别为:自行车、摩托车、汽车、飞机。好了,二维数组好声明,只要把格式写对了,确定是在一个数组里面再插入一个数组就好。那如何访问:爷爷和爸爸这两个值呢?<?php $person = [ 'office' => '办公室', //注意:插入第一个数组哟 'family' => [ '爸爸', '妈妈', 'yeye' => '爷爷', 'nn' => '奶奶', ], //注意:又插入了一个平级的数组 'jiaotong' => [ '自行车', '摩托车', '汽车', '飞机', ], ]; //访问“爸爸”这什值 echo $person['family'][0]; echo '<br />-----华丽丽的分割线------<br />'; //访问“爷爷”这什值 echo $person['family']['yeye']; echo '<br />-----华丽丽的分割线------<br />'; //访问“汽车”这什值 echo $person['jiaotong'][2]; ?>我们看看结果如下:上例大家会发现,访问二维数组不过是按照之前的下标读取方式依次向下读取即可。先写上变量,中括号写上family这个下标,再写上要访问元素的下标。三维数组我们说了概念,那我们直接上手实验看看效果:<?php $area = array( 'china' => array( '上海', '湖北', '天津', '北京' => array( 'hd' => '海淀', '朝阳', '房山', 'cp' => '昌平', ), '广东' => array( '深圳', '广州', '佛山', 'dg' => '东莞', ), ), 'usa' => array( '华盛顿', '旧金山', '纽约' => array( '曼哈顿区', '皇后区', '布鲁克林区', ), ), ); echo '<pre>'; var_dump($area); echo '</pre>'; ?>我们执行一下看看效果:说明:在变量$area下有二个数组,一个为china,一个为usa。在china这个数组里面插入了上海、湖北、天津,又插入了北京和广东。而北京和广东又是一个数组。在北京和广东这两个数组里面分别有不同的元素。在这usa 这个数组里面插美国的华盛顿、旧金山和纽约。而纽约下面又是一个数组,说明了纽约下面的几个区。所以说,三维数组就是在数组里面再插入一个数组(A),在A数组里面插入一个数组。我们接下来看看,如何来读取里面的值。<?php $area = array( 'china' => array( '上海', '湖北', '天津', '北京' => array( 'hd' => '海淀', '朝阳', '房山', 'cp' => '昌平', ), '广东' => array( '深圳', '广州', '佛山', 'dg' => '东莞', ), ), 'usa' => array( '华盛顿', '旧金山', '纽约' => array( '曼哈顿区', '皇后区', '布鲁克林区', ), ), ); //读取华盛顿 echo $area['usa']['0']; //读取:布鲁克林 echo $area['usa']['纽约'][2]; //读取:昌平 echo $area['china']['北京']['cp']; //修改cp下标的值改为:西城区 $area['china']['北京']['cp'] = '西城区'; //输出看看原来昌平的值是否发生了变化 echo $area['china']['北京']['cp']; ?>通过上面我们发现数组学习起来不难。学习多维数组的难点:注意格式,将每个维度的换行、缩进弄整齐。就不容易出错了。【切记】数组元素间的分割符为逗号,在数组中插入数组的时候,不要在结尾处写成了分号(;)下图是错误的载图展示:
2019年08月25日
3,908 阅读
0 评论
0 点赞
2019-08-12
大数据量搜索解决方案-ThinkPHP5+Elasticsearch搜索引擎
Elasticsearch 是一个分布式可扩展的实时搜索和分析引擎,一个建立在全文搜索引擎 Apache Lucene(TM) 基础上的搜索引擎。当然 Elasticsearch 并不仅仅是 Lucene 那么简单,它不仅包括了全文搜索功能,还可以进行以下工作:分布式实时文件存储,并将每一个字段都编入索引,使其可以被搜索。实时分析的分布式搜索引擎。可以扩展到上百台服务器,处理PB级别的结构化或非结构化数据。你往 ES 里写的数据,实际上都写到磁盘文件里去了,查询的时候,操作系统会将磁盘文件里的数据自动缓存到 Filesystem Cache 里面去。整个过程,如下图所示:ES 的搜索引擎严重依赖于底层的 Filesystem Cache,你如果给 Filesystem Cache 更多的内存,尽量让内存可以容纳所有的 IDX Segment File 索引数据文件,那么你搜索的时候就基本都是走内存的,性能会非常高。提升性能的小技巧:仅在 ES 中就存少量的数据,无关检索的数据使用HBase等数据库存储,让Filesystem Cache可以容纳更多的数据量。数据预热,经常会有人访问的数据,每隔一段时间,就提前访问一下,让数据进入 Filesystem Cache 里面去。1、安装Elastaic官网下载地址:https://www.elastic.co/downloads/elasticsearch# 解压到非root目录,运行时使用非root账号且必须安装java环境yum install javawget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-6.2.3.tar.gztar zxvf elasticsearch-6.2.3.tar.gzuseradd elasticsearchpassword elasticsearchchown elasticsearch:elasticsearch elasticsearch-6.2.3cd elasticsearch-6.2.3nohup ./bin/elasticsearch & #设置成常驻进程php扩展库引入 composer.json{ "require": { "elasticsearch/elasticsearch": "~6.0" } }Client使用示例:prepare($sql); $query->execute(); $lists = $query->fetchAll(); print_r($lists); } catch (Exception $e) { echo $e->getMessage(); } $client = ClientBuilder::create()->build(); foreach ($lists as $row) { $params = [ 'body' => [ 'id' => $row['id'], 'title' => $row['title'], 'content' => $row['content'] ], 'id' => 'article_' . $row['id'], 'index' => 'articles_index', 'type' => 'articles_type' ]; $client->index($params); } } /* * 功能:获取索引 * return */ public function getIndex(){ $client = ClientBuilder::create()->build(); $params = [ 'index' => 'articles_index', 'type' => 'articles_type', 'id' => 'article_1' ]; $res = $client->get($params); print_r($res); } /* * 功能:从索引中删除文档 * return */ public function delIndex(){ $client = ClientBuilder::create()->build(); $params = [ 'index' => 'articles_index', 'type' => 'articles_type', 'id' => 'article_1' ]; $res = $client->delete($params); print_r($res); } /* * 功能:设置索引 * return */ public function createIndex(){ $client = ClientBuilder::create()->build(); $params['index'] = 'articles_index'; $params['body']['settings']['number_of_shards'] = 2; $params['body']['settings']['number_of_replicas'] = 0; $client->indices()->create($params); } /* * 功能:查询条件 * return */ public function search(){ $client = ClientBuilder::create()->build(); $params = [ 'index' => 'articles_index', 'type' => 'articles_type', ]; //多字段匹配 // $params['body']['query']['multi_match']['query'] = '我的宝马发动机多少'; // $params['body']['query']['multi_match']['fields'] = ["title","content"]; // $params['body']['query']['multi_match']['type'] ="most_fields"; // most_fields 多字段匹配度更高 best_fields 完全匹配占比更高 // // //单个字段匹配 // $params['body']['query']['match']['content'] = '我的宝马多少马力'; //完全匹配 // $params['body']['query']['match_phrase']['content'] = '我的宝马多少马力'; //联合搜索 must,should,must_not $params['body']['query']["bool"]['must']["match"]['content'] = "宝马"; $params['body']['query']["bool"]['must_not']["match"]['title'] = "宝马"; $res = $client->search($params); print_r($res); } }
2019年08月12日
14,446 阅读
0 评论
9,924 点赞
2019-07-17
阿里巴巴开源镜像提供的 packagist 镜像服务 阿里云 Composer 全量镜像
全局配置(推荐)所有项目都会使用该镜像地址:composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/取消配置:composer config -g --unset repos.packagist项目配置仅修改当前工程配置,仅当前工程可使用该镜像地址:composer config repo.packagist composer https://mirrors.aliyun.com/composer/取消配置:composer config --unset repos.packagist调试composer 命令增加 -vvv 可输出详细的信息,命令如下:composer -vvv require alibabacloud/sdk
2019年07月17日
5,120 阅读
0 评论
10 点赞
2019-07-10
Windows下搭建虚拟机和Laravel开发环境配置VirtualBox+Vagrant+Homestead
方法一:前提条件:Windows 用户,你可能需要启用硬件虚拟化(VT-x)。这通常需要通过 BIOS 来启用它。如果你在一个 UEFI 系统上使用的是 Hyper-V,你需要关闭 Hyper-V 才能启用 VT-x下载安装最新版: VirtualBox 和 Vagrant1·首先将Homestead文件夹放入到当前用户目录之下2·然后 使用git命令工具3·cd 切换到Homestead目录下4·将virtualbox.box离线文件放入指定目录上5·执行 vagrant box add laravel/homestead 加上离线文件的路径virtualbox.box进行安装6·初始化:bash init.sh7·安装好之后打开Homestead文件夹打开Homestead.yaml文件进行修改配置:ip: “192.168.10.10”memory: 2048cpus: 3provider: virtualboxauthorize: ~/.ssh/id_rsa.pubkeys:– ~/.ssh/id_rsafolders:– map: F:/htdocs/Laravelto: /home/vagrant/Code/Laravelsites:– map: laravel.appto: /home/vagrant/Code/Laravel/publicdatabases:– homestead8·保存之后,加入hosts文件配置:192.168.10.10 laravel.app9·生成密钥:ssh-keygen10·vagrant up开启虚拟机11·vagrant ssh 进入到虚拟机系统上关闭虚拟机:vagrant halt查看vagrant常用命令:vagrant 方法二:1·你首先要确定你有个好的 terminal [ 终端:cmder 或 Git 的git bash ] . 注意windows的cmd不能用(个人推荐用Git bash)2·下载和安装 [ virtualbox ] 和 [ vagrant ]前者为系统装载用的,后者为系统控制用的3·如果你要使用 homestead 就必须要有个virtualbox.box的文件 ,官方 Laravel 下载这个文件的这个命令为vagrant box add laravel/homestead 但是因为中国的对外国网络资源的限制,你要下载这个文件可能会需要不少的时间,因此 , 在这我们拥有两个选择的余地选择一 : 当你使用官方下载命令时,你的终端会显示这个文件的源地址复制https://atlas.hashicorp.com/laravel/boxes/homestead/,然后按 ctrl +c 退出,然后用的喜欢的下载软件下载,最好是用最新版的,因为会有各种问题.选择二 : phphub上的 virtualbox.box好了 , 现在我假设你已经拥有这个文件,现在来用我们的方法添加 virtualbox.box . 打开你的ide(代码编译器) ,一般为 Sublime Text 和 Atom ,为何要提编译器呢 , 因为下面的步骤可能会需要其中一个的编译器 , 创建一个名为homestead.json的文件 , 输入以下内容{“name”: “laravel/homestead”,“versions”:[{“version”: “1.0.1”,“providers”: [{“name”: “virtualbox”,“url”: “D:/box/virtualbox.box” //你下载的virtualbox.box在电脑系统上的位置}]}]}打开的 IDE (编译器) 先不要保存,点击开始菜单或 win 快捷键 , 在搜索栏处输入你的terminal ( 终端 ) , 点击鼠标右键以管理员身份运行,一般会跳转到 : C:\Users\windows的账户名>然后回到 IDE (编译器) 保文件到C:\Users\windows的账户名这个目录下 , 并且命名为 homestead.json , 然后再回到terminal ( 终端 ) 输入一下代码 :C:\Users\windows的账户名> vagrant box add homestead.json C:\Users\windows的账户名> vagrant box add homestead.json==> box: Loading metadata for box 'homestead.json'box: URL: file://C:/Users/windows的账户名/homestead.json==> box: Adding box 'laravel/homestead' (v1.0.1) for provider: virtualboxbox: Downloading: "D:/box/virtualbox.box" //你下载的virtualbox.box在电脑上的位置box: Progress: 100% (Rate: 129M/s, Estimated time remaining: --:--:--)==> box: Successfully added box 'laravel/homestead' (v1.0.1) for 'virtualbox'!然后继续 在terminal ( 终端 ) 输入.C:\Users\windows的账户名> ssh-keygen -t rsa -C "
[email protected]
"说明 : 这个命令是创建 Homestead 连接秘匙 , 因为我们是在本机上运行的所以不需要密码之类的 , 一直按回车就行C:\Users\windows的账户名> ssh-keygen -t rsa -C "
[email protected]
"Generating public/private rsa key pair.Enter file in which to save the key (/c/Users/windows的账户名/.ssh/id_rsa):Created directory '/c/Users/windows的账户名/.ssh'.Enter passphrase (empty for no passphrase):Enter same passphrase again:Your identification has been saved in /c/Users/windows的账户名/.ssh/id_rsa.Your public key has been saved in /c/Users/windows的账户名/.ssh/id_rsa.pub.The key fingerprint is:SHA256:UTmPEezFQK0XUa5Km2lGnqOBgtCo5rwGGWCX8CaTN6g
[email protected]
key's randomart image is:+---[RSA 2048]----+| .. . o=*.o. ||..+o .= =. ||o=.= .. B .. ||oo= . .+ o. ||Eo. S o.. ||+. . . + * ||o.. . . . @ ||+. . = . ||.+. . |+----[SHA256]-----+5·现在继续 在terminal ( 终端 ) 输入.git clone https://github.com/laravel/homestead.git Homestead说明 : 这个命令是 下载 Homestead 目录,里面包含了Homestead 的配置文件C:\Users\windows的账户名> git clone https://github.com/laravel/homestead.git HomesteadCloning into 'Homestead'...remote: Counting objects: 1623, done.rRemote: Total 1623 (delta 0)eceiving objects: 99% (1, reused 0 (delt607/1623), 244a 0), pack-reuse.01 KiB | 13.00d 1623 KiB/sReceiving objects: 100% (1623/1623), 252.22 KiB | 13.00 KiB/s, done.Resolving deltas: 100% (958/958), done.Checking connectivity... done.现在让我们来看看文件是否现在成功了,在 在terminal ( 终端 ) 输入 : C:\Users\windows的账户名> lsHomestead/ //我其他文件夹就没写了,只要看到了这个文件夹你就算是把 Homestead 的配置文件下载下来了然后继续 在terminal ( 终端 ) 输入 C:\Users\windows的账户名 > cd HomesteadC:\Users\windows的账户名\Homestead >C:\Users\windows的账户名\Homestead > bash init.sh //初始化 .homestead 目录说明 : 这个bash init.sh 命令会创建一个 .homestead目录这个目录位于C:\Users\windows的账户名\ 这个目录下这个.homestead目录里有一个 Homestead.yaml 文件很多人windows启动Homestead失败都是因为这个配置文件的关系6·注意 !!!现在这个步骤很重要好了现在用 IDE(代码编译器) 打开目录地址 C:\Users\windows的账户名\ .homestead\Homestead.yaml , 你会看到如下代码|---| ip: "192.168.10.10"|memory: 2048|cpus: 1|provider: virtualbox||authorize: ~/.ssh/id_rsa.pub||keys:| - ~/.ssh/id_rsa||folders:| - map: ~/Code //这个是你的项目的地址,例如D:\随便\项目的目录 1| to: /home/vagrant/Code //这个是homestead系统的地址 2| //其实这就是windows和hometead两个系统共享一个文件夹,难懂一点的话叫||映射||sites: //__这个是你的项目| - map: homestead.app 这个是你项目要设定在你的浏览器上的地址 //需要设定C host文件| to: /home/vagrant/Code/Laravel/public //这里的Laravel其实就是D:\随便\项目的目录\Laravel||databases:| - homestead||# blackfire:|# - id: foo|# token: bar|# client-id: foo|# client-token: bar||# ports:|# - send: 50000|# to: 5000|# - send: 7777|# to: 777|# protocol: udp将以上的代码修改成以下的代码|—|ip: “192.168.10.10”|memory: 2048|cpus: 1|provider: virtualbox||authorize: ~/.ssh/id_rsa.pub||keys:| – ~/.ssh/id_rsa||folders:| – map: D:\随便\项目的目录 //当启动时会自动转换成D:/随便/项目的目录,这个是正确的| to: /home/vagrant/Code||sites: //看到这你可以看到为什么是sites,而不是site| – map: aimiliya.local 这个是你在hosts设定的网站地址| to: /home/vagrant/Code/king/public 这里的king是你设定的D:\随便\项目的目录\king|| – map: lamu.local| to: /home/vagrant/Code/lamu/public|| – map: leimu.local| to: /home/vagrant/Code/leimu/public|||databases:| – homestead||# blackfire:|# – id: foo|# token: bar|# client-id: foo|# client-token: bar||# ports:|# – send: 50000|# to: 5000|# – send: 7777|# to: 777|# protocol: udp|提醒 : IDE(代码编译器) 记得保存 .警告 : 以上代码为最基础的Homestead配置 ,你要进行开启其他功能最好阅读或参考 Laravel 和 vagrant官方文档举例 : 例如在 folders 下面填写 type:“nfs” , 这对于windows 来说是错误的 , 对于 mac 来说却是成功的 , 原因vagrant不支持对 windows 开启 nfs ,具体参考 synced-folders .7 .好了现在回到 terminal ( 终端 ) 启动吧,输入 vagrant up注意 : 在你以后重新启动Homestead .即 : vagrant up都必须在 Homestead 这个目录下启动C:\Users\windows的账户名\Homestead> vagrant upBringing machine 'default' up with 'virtualbox' provider...==> default: Checking if box 'laravel/homestead' is up to date...==> default: Clearing any previously set forwarded ports...==> default: Clearing any previously set network interfaces...==> default: Preparing network interfaces based on configuration...default: Adapter 1: natdefault: Adapter 2: hostonly==> default: Forwarding ports...default: 80 (guest) => 8000 (host) (adapter 1)default: 443 (guest) => 44300 (host) (adapter 1)default: 3306 (guest) => 33060 (host) (adapter 1)default: 5432 (guest) => 54320 (host) (adapter 1)default: 22 (guest) => 2222 (host) (adapter 1)==> default: Running 'pre-boot' VM customizations...==> default: Booting VM...==> default: Waiting for machine to boot. This may take a few minutes...default: SSH address: 127.0.0.1:2222default: SSH username: vagrantdefault: SSH auth method: private key==> default: Machine booted and ready!==> default: Checking for guest additions in VM...default: The guest additions on this VM do not match the installed version ofdefault: VirtualBox! In most cases this is fine, but in rare cases it candefault: prevent things such as shared folders from working properly. If you seedefault: shared folder errors, please make sure the guest additions within thedefault: virtual machine match the version of VirtualBox you have installed ondefault: your host and reload your VM.default:default: Guest Additions Version: 5.0.20default: VirtualBox Version: 5.1==> default: Setting hostname...==> default: Configuring and enabling network interfaces...==> default: Mounting shared folders...default: /vagrant =>C:/Users/windows的账户名/Homesteaddefault: /home/vagrant/Code => D:/随便/项目的目录 //当你没看到这条信息请返回你的Homestead.yaml设定==> default: Machine already provisioned. Run `vagrant provision` or use the `--provision`==> default: flag to force provisioning. Provisioners marked to run always will still run.好了,这算启动成功了,但是配置成功了吗?还不能确定的,输入 vagrant ssh 登入homesteadC:\Users\windows的账户名\Homestead> vagrant sshWelcome to Ubuntu 16.04 LTS (GNU/Linux 4.4.0-22-generic x86_64)*Documentation: https://help.ubuntu.com/vagrant@homestead:~$ //当看到这个说明登入成功了vagrant@homestead:~$ ls //查看下一级目录 ,有Code,可以安心Codevagrant@homestead:~$ cd Codevagrant@homestead:~/Code$ ls //当看到king了,你可以彻底放心了,配置成功了king提醒 :如果你启动了 Homestead , 你发觉你的配置文件 Homestead.yaml :想要修改 , 可以的使用命令:vagrant up –provision ,此命令必须在Homestead 启动后使用,此命令作用为更新Homestead.yaml的修改8·最后要在浏览器上显示你的网页你必须设定对应的hosts .hosts文件所在在目录:C:\Windows\System32\drivers\etc\hosts 先hosts拖到桌面,然后修改成:|# Copyright (c) 1993-2009 Microsoft Corp.|#|# This is a sample HOSTS file used by Microsoft TCP/IP for Windows.|#|# This file contains the mappings of IP addresses to host names. Each|# entry should be kept on an individual line. The IP address should|# be placed in the first column followed by the corresponding host name.|# The IP address and the host name should be separated by at least one|# space.|#|# Additionally, comments (such as these) may be inserted on individual|# lines or following the machine name denoted by a ‘#’ symbol.|#|# For example:|#|# 102.54.94.97 rhino.acme.com # source server|# 38.25.63.10 x.acme.com # x client host||# localhost name resolution is handled within DNS itself.|# 127.0.0.1 localhost|# ::1 localhost||192.168.10.10 aimiliya.local|192.168.10.10 lamu.local|192.168.10.10 leimu.local然后把刚复制到桌面而且修改好的hosts文件的拖回C:\Windows\System32\drivers\etc\hosts覆盖.注意:直接修改是不行的
2019年07月10日
4,550 阅读
0 评论
1 点赞
2019-07-10
PHP经典面试题汇总(六)
六十一·写出一个函数实现字符串翻转?方法一:strrev();方法二:$str = "abcdefg"; function show($str){ for ($i=strlen($str); $i>= 0; $i--) { $str2 .= $str{$i}; } return $str2; } echo @show($str);六十二.在hello.txt文件前面追加字符串,往前面写数据?$str = "h1\n"; $file = 'hello.txt'; $get = file_get_contents($file); file_put_contents($file,$str .=$get);六十三.判断用户ip地址是否在192.168.1.100~192.168.1.150范围内?方法一:$ip = "192.167.1.110"; $x = ip2long($ip); $ip1 = "192.168.1.100"; $min = ip2long($ip1); $ip2 = "192.168.1.150"; $max = ip2long($ip2); if($x > $max || $x < $min){ exit("ip不在范围内"); } echo "ip符合要求";方法二:$ip = "192.168.1.120"; echo $pos = strrpos($ip,'.')+1; $ipleft = substr($ip,0,$pos); $ipright = substr($ip,$pos); if($ipleft != "192.168.1."){ exit("ip不在范围内"); } if($ipright >150 || $ipright <100){ exit("ip不在范围内"); } echo "ip符合要求";六十四·请将2维数组按组 name的长度进行重新排序,按照顺序将id赋值(从1开始)?$arr = array( array('id' => 0,'name' => '323444'), array('id' => 0,"name" => 'sgegesssssg'), array('id' => 0,'name' => '这是字符串'), array('id' => 0,'name' => '101928ss323sssgee323'), array('id' => 0,'name' => 'slkgjeoge'), array('id' => 0,'name' => '32'), array('id' => 0,'name' => '1019283'), ); foreach ($arr as $val) { $long[] = strlen($val['name']); } array_multisort($long,$arr); foreach ($arr as $key => &$val) { $val['id'] = $key+1; } echo "
2019年07月10日
6,344 阅读
0 评论
3 点赞
2019-07-10
PHP经典面试题汇总(五)
五十一·用php写出显示客户端ip与服务器ip的代码?$_SERVER['SERVER_ADDR']; $_SERVER['REMOTE_ADDR']; gethostbyname("www.mobanw.com");五十二·include,require,include_once,require_once的区别 ?1·include一个文件存在错误的话,那么程序不会中端,而是继续执行,并显示一个警告错误,require一个文件存在错误的话,那么程序就会中断执行了,并显示致命错误。2·include有返回值,而require没有。3·include_once()会先检查要导入的档案是不是已经在该程序中的其它地方被导入过了,如果有的话就不会再次重复导入。4·include_once(),require_once()会先检查目标文件的内容是不是在之前就已经导入过了,如果是的话,便不会再次重复导入同样的内容五十三·如何修改session的生存时间?方法1:将php.ini中的session.gc_maxlifetime设置为9999重启apache方法2:session_start(); //保存一天,session的过期时间是有cookie决定的 $lifetime = 24*3600; setcookie(session_name(),session_id(),time()+$lifetime,'/');五十四·写出发帖数最多的十个人的名字的sql语句?,利用下表:members(id,username,posts,pass,email)select username,count(id) from members group by username order by count(id) desc limit 10;五十五·请说明php中传值和传引用的区别,什么时候传值什么时候传引用?按值传递:函数范围内对值的任何改变在函数外部都会被忽略,外部不会改变。按引用传递:函数范围内对值的任何改变在函数外部也能反应出这些修改,外部也可以改变。优缺点:按值传递时,php必须复制值。特别是对于大型的字符串和对象来说,这将会是一个代价很大的操作。按引用传递则不需要复制值,对于性能提高很有好处。五十六·在php中error_reporting这个函数的作用是什么?设置错误级别,错误信息回报。错误级别有以下五种:E_ALL,E_PARSE,E_ERROR,E_WARNING,E_NOTICE五十七·msyql_fetch_row(),mysql_fetch_assoc(),mysql_fetch_array()之间有什么区别?msyql_fetch_row()是从结果取出1行索引数组,作为枚举。mysql_fetch_assoc()获取的是关联数组msyql_fetch_array()获取的是关联和索引混合的数组mysql_num_rows($result)取得查询结果集总数五十八·$a=”abcdef”;请打印出$a中第一个字母?echo $a{0}或者echo substr($a,0,1);五十九·写出正则匹配js标签?$str = <<<scriptscript; preg_match_all('/
2019年07月10日
5,958 阅读
0 评论
0 点赞
2019-07-10
PHP经典面试题汇总(四)
三十九·请使用 php编写程序,读取出www.baidu.com的首页的网页内容,并存入字符串$str?方法一:$url ="http://www.baidu.com"; $str = file_get_contents($url); echo $str;方法二:$fp = fopen("http://www.baidu.com",'r'); $str = ''; while(!feof($fp)){ echo $str.=fread($fp,'1024'); }请用php将上题中读出来的网页内容的<title>标签的值解析出来?header("Content-type:text/html;charset=utf-8"); $url ="http://www.baidu.com"; $str = file_get_contents($url); preg_match('/<title>(.+)<\/title>/',$str,$ms); echo $ms[1];四十·通过php函数循环遍历出文件夹下的所有目录的文件,写出程序?$dir = "zt"; function dirList($dir){ $arr = scandir($dir); foreach($arr as $file){ if($file !='.' && $file !='..'){ $path = $dir."/".$file; if(is_dir($path)){ dirList($path); }else{ echo "<p>{$path}</p>"; } } } } dirList($dir);四十一·linux打印出一个文件夹下的所有目录和文件,编写shell脚本?vi tree.sh #! /bin/bash tree chomd 777 tree.sh四十二·什么是数据库索引,主键索引,唯一索引的区别,索引的缺点是什么?数据库索引就相当于一本书的目录,就是给数据库中的每张表建立索引,便于检索提高select 效率,加快搜索速度主键索引就是给每张表的主键设置索引,唯一索引就是给每张表的唯一值字段设置索引,主键索引本身就内置唯一索引,一旦在列里加唯一索引,列里的值就不能重复,主键索引在检索中比唯一索引快,一个表只能有一个主键索引,一个表可以有多个唯一索引,索引的缺点是建立索引需要增加存储空间,空间利用率低,并且数据发生变化时会改变索引资源消耗较大。四十三·数据库设计时,常遇到的性能瓶颈有哪些,常有的解决方案是?1·查询速度慢,避免全盘扫描,因为全盘扫描会导致大量的磁盘I/O操作,用sphinx来解决,和添加索引。2·读写过于频繁,使用读写分离操作。3·数据库压力大,采用分布式数据库负载均衡来解决。4·memcache缓存。5·链接数据库使用pdo,或者mysqli,预处理缓存字段。6·尽量使用MyISAM。7·建议表的列不要过多,要适当的多用些表。四十四·通过js实现页面的前进和后退操作?<a href="javascript:window.history.go(1)">前进</a> <a href="javascript:window.history.go(-1)">后退</a>四十五·浏览器ie和非ie浏览器的区分,区别是什么?<script> var val = navigator.userAgent; if(val.search('MSIE')>=0){ alert('ie浏览器'); }else{ alert('非ie浏览器'); } </script>四十六·设定网站的用户数量在千万级,但是活跃用户的数量只有1%,如何通过优化数据库提高活跃用户的访问速度?1·分区。(分活跃用户表和非活跃用户表)2·分表。(人为分表,需要在php写一段路由层,判断是活跃用户,或者非活跃用户)3·索引优化四十七·ajax技术利用了什么协议,简述一下ajax的工作机制?利用http协议工作原理:1·先通过浏览器内置的XMLHttpRequest类产生一个ajax对象,2·调用ajax对象open方法建立一个与某一个脚本发生通讯的链接3·设定好传输方式get/post,还要确定是异步还是同步,默认是异步4·调用ajax的send方法发送请求,发起对php文件的请求5·通过给ajax绑定状态检测事件,当状态码为4,并且服务器响应码为200时则获取php文件的响应数据。<script> function showHint(str) { var xmlhttp; if (str.length==0) { document.getElementById("txtHint").innerHTML=""; return; } if (window.XMLHttpRequest) { // IE7+, Firefox, Chrome, Opera, Safari 浏览器执行代码 xmlhttp=new XMLHttpRequest(); } else { // IE6, IE5 浏览器执行代码 xmlhttp=new ActiveXObject("Microsoft.XMLHTTP"); } xmlhttp.onreadystatechange=function() { if (xmlhttp.readyState==4 && xmlhttp.status==200) { document.getElementById("txtHint").innerHTML=xmlhttp.responseText; } } xmlhttp.open("GET","/try/ajax/gethint.php?q="+str,true); xmlhttp.send(); } </script>四十八·利用php打印出前一天的时间格式是2017-8-10 22:21:50?echo date('Y-n-d H:i:s',strtotime('-1 day'));四十九·echo ,print ,print_r的区别是什么?1·echo 和print是语言结构,print_r是函数2·echo 可以有多个参数,print,print_r只能有一个参数3·print()只能打印简单的数据类型变量的值(int ,string)print_r()可以打印出复杂类型变量的值(数组,对象)echo 可以输出一个或者多个字符串五十·能够使html和php分离开使用的模板引擎?Smarty,template,thinkphp,laravel,yii
2019年07月10日
6,059 阅读
0 评论
1 点赞
2019-07-10
PHP经典面试题汇总(三)
二十一·写出数据类型(int char varchar datetime text)的意思,varchar 和char的区别?int数字类型,char固定长度字符串,varchar实际(可变)长度字符串,datetime日期时间类型,text文本类型char长度是固定的,不管你存储的数据是多少他都会都固定的长度。而varchar则处可变长度但他要在总长度上加1字符,这个用来存储位置,由于某种原因char 固定长度,所以在处理速度上要比varchar快速很多,但是对费存储空间,所以对存储不大,但在速度上有要求的可以使用char类型,反之可以用varchar类型来实例二十二·MyISAM和InnoDB的基本区别?innoDB支持事务机制、存储过程、行级锁定,MyISAM不支持,MyISAM在增删改查中速度快于InnoDB,作为使用MySQL的用户角度出发,Innodb和MyISAM都是比较喜欢的,如果数据库平台要达到需求:99.9%的稳定性,方便的扩展性和高可用性来说的话,MyISAM绝对是首选,InnoDB不支持FULLTEXT类型的索引,InnoDB 中不保存表的具体行数,也就是说,执行select count(*) from table时,InnoDB要扫描一遍整个表来计算有多少行,但是MyISAM只要简单的读出保存好的行数即可二十三·客户端禁用了cookie,怎么实现session技术共享多个页面?方法一.通过session获取session_id进行传值:a.php页面(设置session) session_start(); header("Content-type:text/html;charset=utf-8"); $user = $_SESSION['name'] = 'zhangsan'; echo $sid = session_id(); $sname = session_name(); echo ""; print_r($user); echo ""; echo "cookie"; b.php页面(接收session) if(isset($_GET['PHPSESSID'])){ session_id($_GET['PHPSESSID']); } session_start(); echo session_id(); echo ""; print_r($_SESSION); echo "";方法二.或者php.ini 配置选项,里面有一个session.use_trans_sid=0设置为1(在herf action header会自动添加SID,但是js跳转不会自动增加); 重启apache可以生效二十四·isset()和empty()的区别,对不同数据的判断结果?isset()是判断变量是否存在,是否定义empty()是判断变量的值是否为空二十五·如何在页面之间传递变量?get,post,ajax,curl,cookie,session二十六·写出匹配url的正则表达式?$url = "https://www.baidu.com/index.php?id=1&name=user1"; $reg = "/(http|ftp|https):[\/]{2}[a-z]+[.]{1}[a-z\d\-]+[.]{1}[a-z\d]*[\/]*[A-Za-z\d]*[\/]*[A-Za-z\d]* /"; echo preg_match($reg,$url);二十七·请写出常见的排序算法,并用php实现冒泡排序,将数组$a=array()按照从小到大的方式进行排序?function mysort($arr){ for($i=0;$i<count($arr)-1;$i++){ for($j=0;$j
2019年07月10日
5,743 阅读
0 评论
0 点赞
2019-07-10
PHP经典面试题汇总(二)
十一·如何进行防止SQL注入?1·表单尽量用post提交,核心用户验证都用post,表单判断使用get,因为get比post快2·使用$_SERVER[HTTP_REFERER]判断提交表单的源头是否是本机域名$path = $_SERVER['HTTP_REFERER']; $arr = parse_url($path); $arr2= $arr['host']; echo "<pre>"; print_r($arr2);3·php.ini开启addslashes,防止用户输入信息有单引号或者双引号对sql语句带来的破坏性,开启之后会在单双引号之前加反斜杠\’\”4·密码需要设置md5或Sha1加密5·服务器本身的安全(web + mysql)十二·防止盗链?1·服务器上防止盗链:Apache 和Nginx做rewrite基于源来做判断阻止盗链Apache设置防盗链方法:(.htaccess文件)RewriteEngine on RewriteCond %{HTTP_REFERER} !^$ [NC] RewriteCond %{HTTP_REFERER} !linuxidc.cn [NC] RewriteCond %{HTTP_REFERER} !google.com [NC] RewriteCond %{HTTP_REFERER} !baidu.com [NC] RewriteRule .(jpg|gif|png|bmp|swf|jpeg) /image/replace.gif [R,NC,L] RewriteRule ^(.*)$ http://image.linuxidc.cn/image/$1 [L]不是以上网站访问来源就直接转向:RewriteRule .(jpg|gif|png|bmp|swf|jpeg) /image/replace.gif [R,NC,L]Nginx设置防盗链方法:(/usr/local/nginx/conf/nginx.conf文件)location ~ .*\.(jpg|gif|png|bmp|swf|jpeg)$ { expires 30d; valid_referers none blocked *.linuxidc.cn *.google.com *.baidu.com; if ($invalid_referer) { rewrite ^/ ; return 404; } }2·代码防止盗链:$_SERVER[‘HTTP_REFERER’]十三·用php写出一个安全的用户登录系统需要注意哪些方面?1·验证码2·U盾3·动态口令卡4·限制登录次数5·使用数字键盘6·密码不能粘贴7·网址使用ssl,服务器证书https8·注册验证必须要使用php验证9·以post提交给后端php程序十四·使用过哪些php框架,试着描述其优劣点?Thinkphp:ThinkPHP(FCS)是一个轻量级的中型框架,是从Java的Struts结构移植过来的中文PHP开发框架。它使用面向对象的开发结构和MVC模式,并且模拟实现了Struts的标签库,各方面都比较人性化,熟悉J2EE的开发人员相对比较容易上手,适合php框架初学者。 ThinkPHP的宗旨是简化开发、提高效率、易于扩展,其在对数据库的支持方面已经包括MySQL、MSSQL、Sqlite、PgSQL、 Oracle,以及PDO的支持。ThinkPHP有着丰富的文档和示例,框架的兼容性较强,但是其功能有限,因此更适合用于中小项目的开发。优点:1.易于上手,有丰富的中文文档;2.框架的兼容性较强,PHP4和PHP5完全兼容、完全支持UTF8等。3. 适合用于中小项目的开发缺点1.对Ajax的支持不是很好;2.目录结构混乱,需要花时间整理;3.上手容易,但是深入学习较难。Yii:Yii 是一个基于组件的高性能php框架,用于开发大型Web应用。Yii采用严格的OOP编写,并有着完善的库引用以及全面的教程。从 MVC,DAO/ActiveRecord,widgets,caching,等级式RBAC,Web服务,到主题化,I18N和L10N,Yii提供了 今日Web 2.0应用开发所需要的几乎一切功能。事实上,Yii是最有效率的PHP框架之一。优点1·纯OOP2·用于大规模Web应用3·模型使用方便4·开发速度快,运行速度也快。性能优异且功能丰富5·使用命令行工具。缺点:1·对Model层的指导和考虑较少2·文档实例较少3·英文太多4·要求PHP技术精通,OOP编程要熟练!5·View并不是理想view,理想中的view可能只是html代码,不会涉及PHP代码。Lavarel:优点Laravel 的设计思想是很先进的,非常适合应用各种开发模式TDD, DDD 和BDD,作为一个框架,它准备好了一切,composer 是个php 的未来,没有composer,PHP 肯定要走向没落。laravel 最大的特点和优秀之处就是集合了php 比较新的特性,以及各种各样的设计模式,Ioc 容器,依赖注入等。缺点基于组件式的框架,所以比较臃肿CodeIgniter:优点:推崇“简单就是美”这一原则。没有花哨的设计模式、没有华丽的对象结构,一切都是那么简单。几行代码就能开始运行,再加几行代码就可以进行输出。可谓是“大道至简”的典范。 配置简单,全部的配置使用PHP脚本来配置,执行效率高;具有基本的路由功能,能够进行一定程度的路 由;具有初步的Layout功能,能够制作一定程度的界面外观;数据库层封装的不错,具有基本的MVC功能. 快速简洁,代码不多,执行性能高,框架简单,容易上手,学习成本低,文档详细;自带了很多简单好用的library,框架适合小型应用.缺点:本身的实现不太理想。内部结构过于混乱,虽然简单易用,但缺乏扩展能力。 把Model层简单的理解为数据库操作. 框架略显简单,只能够满足小型应用,略微不太能够满足中型应用需要.评价:总体来说,拿CodeIgniter来完成简单快速的应用还是值得,同时能够构造一定程度的layout,便于模板的复用,数据操作层来说封装的不 错,并且CodeIgniter没有使用很多太复杂的设计模式,执行性能和代码可读性上都不错。至于附加的library 也还不错,简洁高效。十五·用过哪些版本控制工具?svn subversion 版本控制github 版本控制十六·进制转换?对照表:1 1 1 1 1 1 1 1(二进制)128 64 32 16 8 4 2 1(十进制)例如:(二进制转换为十进制) 101010111 = 1×2^8 + 1×2^6 + 1×2^4 + 1×2^2 + 1×2^1 + 1×2^0 = 256+64+16+4+2+1 = 343(十六进制转换为十进制) 3A5B=3×16^3 + Ax16^2 + 5×16^1 + Bx16^0 = 3×4096 + 10×256 + 80 + 11×1 = 12288+2560+80+11=14939(十六进制转换为二进制) 41=0100 000116进制的1位数代表2进制的4位数(二进制转换为十六进制) 11010110 = B6四个数为一组(1101)= 1×2^3 + 1×2^2 + 1×2^0 = 13=B,(0110)= 1×2^2 + 1×2^1 = B6(十进制转换为二进制) 13=1101余数=被除数-除数*商13/2(商6 余数1),6/2(商3 余数0),3/2(商1 余数1),1/2(商0 余数1)规律:不断除以2,保留余数,商为0时不再除以2,将所有余数倒序排列。(十进制转换为十六进制) 138=8A138/16(商8 余数10 A),8/16(商0 余数8)规律:不断除以16,保留余数,商为0时不再除以16,将所有余数倒序排列。$int = 1+2+"23+4" = 26; ascii码转换: chr(65) == A; ord(A) == 65; $a = array(1=>5,5=>8,22,2=>'8',81); $a[7] == 81 //前一个最大下标加2 $a[6] == 81 //前一个最大下标加1 $a[3] 不存在,空 $a[bar] = 'hello'; $a[bar] 和 $a['bar'] 结果一样hello;位运算:echo 1>>0; // 001 ==>1 echo 2>>1; // 010 ==> 001 => 1 二进制向右移动1位,结果转十进制 echo 3<<2; // 011 ==> 01100 => 1x2^3+1x2^2=12 二进制向左移动2位,结果转十进制echo 可以打印多个参数,print不可以十七·下面能正确输出yellow的结果有哪些:$fruits = array('apple' =>'red','banana' =>'yellow'); echo "A banana is {$fruits[banana]}"; echo "A banana is {$fruits['banana']}"; echo "A banana is $fruits[banana]"; heredoc: $str=<<<str this is string str; echo $str;以上等同于$str=”this is string”;十八·什么是面向对象,主要特征是什么?也就是我们常说的OOP,以对象为中心的程序设计思维或者方式,好处是有两个成员组成,成员属性和成员方法,提高代码重用性,避免代码冗余度三大特征:封装,继承,多态十九·session和cookie的区别是什么,请从协议,产生的原因与作用说明?cookie数据存放在客户端的浏览器上,session数据放在服务器上,cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗考虑到安全应当使用session,session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能考虑到减轻服务器性能方面,应当使用COOKIE,单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie,将登陆信息等重要信息存放为SESSION, 其他信息如果需要保留,可以放在COOKIE中二十·HTTP状态中的200,302,304,403,404,500代码含义?200:成功访问,并返回数据302:重定向304:缓存未过期403:服务器拒绝访问,Apache权限拒绝访问404:访问的页面不存在500:服务器内部错误linux压缩:tar czf text.tar.gz test.phplinux解压:tar xzf test.tar.gz
2019年07月10日
6,695 阅读
0 评论
2 点赞
2019-07-10
PHP经典面试题汇总(一)
一· 用php获取当前时间并打印,打印格式:2017-3-25 22:20:21?echo date('Y-n-d H:i:s'); //月份未满十不补零,二十四小时制 echo date('Y-m-d h:i:s'); //月份未满十补零,十二小时制二· 字符串转数组,数组转字符串,字符串截取,字符串替换,字符串查找的函数分别是什么?1)字符串转数组:$str = 'www.baidu.com'; print_r(str_split($str,3)); print_r(explode(".",$str));2)数组转字符串:$arr = array('aaa','bbb','ccc'); echo implode('',$arr); echo join(' ',$arr);3)字符串截取:$str = "这是一个字符串this is a string!"; echo substr($str,0,4); //截取英文字符串 echo mb_substr($str,0,4,'utf-8'); //按照字符个数截取字符串 echo mb_strcut($str,0,6); //按照字节数截取字符串(中文三个字节为一个中文字)4)字符串替换:$table_change = array('you'=>'her sister','Love' => 'hate'); echo strtr("I Love you",$table_change); //比str_replace快四倍,区分大小写,但是这个函数挺麻烦,不能替换为空,可以替换空白 $bodytag = str_replace("%body%", "black", ""); //区分大小写 echo $bodytag; $str = "linux is very good server for php"; echo preg_replace('/linux|php/','java',$str); //使用正则替换5)字符串查找:$str = "/web/b/c/index.html"; echo strpos($str,'/'); //查找第一个出现的位置,返回位置数 echo strrpos($str,'/'); //查找最后一个出现的位置,返回位置数 $pos = strrpos($str,'/'); echo substr($str,$pos+1); //截取路径里面的文件部分 echo substr($str,0,$pos); //截取路径里面的目录部分 echo basename($str); //获取路径中的文件名 echo dirname($str); //获取路径中的目录 $str = "pap is pbp and pcp or pdp"; preg_match_all('/p.p/',$str,$ms); //正则匹配,返回数组 echo "
2019年07月10日
6,683 阅读
0 评论
5 点赞
2019-07-09
高性能网站架构方案
高性能网站架构方案,用以优化网站响应时间,实现大型网站技术架构方案。无论是电子商务或者其他网站且可使用。一、优化网站响应时间的架构方案: 网站能不能留的住用户,一方面是看内容,另一方面是看响应时间。通常有以下几个方式来降低网站响应时间: 1、减少HTTP请求。包括合并css和javascript。减少图片数量,比如利用css的偏移技术来在一个图片中选择不同的位置内容。利用浏览器的Cache功能,我们可以在头中声明是否被浏览器缓存。 2、动态内容静态化。比如永久生成HTML文件。生成静态文件并设定生存时间,到期后查询新的动态内容进行替换。 3、优化数据库。数据库的性能对于项目整体性能中是重中之重。设计良好的Mysql比乱糟糟的Mysql性能高出N个数量级,更别论再引入NOSQL了,比如Redis,MongoDB。 4、使用负载均衡。将请求合理的分发到更多服务器。 5、使用缓存。把花费时间和资源成本高昂的计算结果取出缓存起来,避免重复计算。比如在Mysql前面挡一层Memcached。比如生成一个文件,使用的时候include进来。再比如PHP中的OPCACHE等。二、压力测试的架构方案: 吞吐率是指单位时间内处理的请求数,单位reqs/s。最大吞吐率是指单位时间内能够处理的最大请求出。模拟足够多的人数和并发请求来测试最大吞吐率的方法叫做压力测试。比如Apache自带的ab(Apache Bench)。ab的参数很多,常用的有请求数(-n),并发用户数(-c),超时时间(-t),长连接(-k),附件一个Cookie(-c name=value)$ab -c 10 -n 1000 http://localhost/三、长连接的架构方案: 每次请求都需要TCP的三次握手,握手完比表示连接正式联通,之后再发送数据。那么,把N个请求,就需要3N次握手,传递N次数据,得到N次响应,总共5N。如果把N个请求合成一个请求,就是3次握手,1次传递数据,1次返回响应,共5次。但是,有时候我们需要上一次响应的返回结果来发送新一轮的请求,在这个时候,合并请求并不好实现,这就需要长连接。使用起来很简单,在头中包含如下:Connection: Keep-Alive 客户端和服务器端都可以设置长连接的最大时间,当两者不统一时以小的一方为准。开启长连接后进行压力测试:$ab -c 10 -n 1000 http://localhost/ 发现提升不止三五倍。本机是提升了8倍的性能。四、提高Mysql的响应速度的架构方案: Handlerocker是日本的一位架构师开发。Mysql的一种插件。Handlerocker实现了绕过Mysql的SQL解析层。在Mysql5.1以上版本可以使用,详情可以查看Mysql手册。这里就不在阐述。五、Mysql主从复制的架构方案: 在分布式部署中,1台主库,N台从库。主库只写,从库只查。主库从库数据需要实现统一,这就是主从复制。优点是: 1、从库备份时,主库可以继续处理更新。 2、优化响应时间。 3、增加健壮性。主库挂了可以切换到从库作为备份。 主从复制的实现过程有三步,1个在主库,2个在从库: 1、主库服务器将用户对数据库更新的操作以二进制格式保存到Binary Log日志文件。然后Binlog Dump线程将Binary Log日志文件传输给从库服务器。 2、从库服务器通过一个I/O线程将主库服务器的Binary Log日志文件中的更新操作复制到一个叫做Relay Log中的中继日志文件中。 3、从库服务器通过另一个SQL线程Relay Log中继日志文件中的操作依次在本地执行,从而实现主从数据库之间数据的同步。 本篇只是简单的列出方案,详细的配置和实现步骤将在另一篇中写到。六、代理的架构方案: 读取内存的速度是读取硬盘的100000-1000000倍。把访问过的页面缓存在内存中,下次直接从内存中读取,可以有效加速。 1、传统代理。客户端发送请求给代理服务器,代理服务器向WEB服务器取到数据并返回给浏览器。代理服务器就是一个有大的存储空间的Cache。 2、反向代理。和传统代理原理类似,只是使用对象不同。传统代理的使用对象是客户端,反向代理的使用对象是服务器。用户通过反向代理访问Web服务器,Web服务器是隐藏起来的。不过用户不关心这些,权把代理服务器当作真实的Web服务器。反向代理有Vamish。七、异步计算的架构方案: 比较耗时的比如将用户上传的文件分发到多台机器,比如裁剪图片,视频转码等。可以使用异步方案。让用户无须等待计算结束而是先行返回结果。代表产品有和Me
2019年07月09日
10,115 阅读
0 评论
2 点赞
2019-07-02
libxml2 configure: error: xml2-config not found. Please check your libxml2 insta
在Linux下,编译安装PHP时报错:libxml2 configure: error: xml2-config not found. Please check your libxml2 installation.但是在Linux下已经安装了libxml2,我通过rpm -qa | grep libxml2就可以查到,那为什么还会提示那个错误呢?应该是libxml2-dev。ubuntu/debian:apt-get install libxml2-devcentos/redhat:yum install libxml2-devel
2019年07月02日
5,159 阅读
0 评论
2 点赞
2019-06-14
php使用unlink删除文件时失败的原因
在做网站的文件上传功能时,遇到了不能删除文件的问题。 我采用的方案是用户先上传到服务器,服务器再上传到阿里云的OSS,中间会有一个把图片临时存储到服务器的过程。使用php的@unlink(删除指定文件)方法时发现了删除失败的问题,很是疑惑。 开始以为是路径名写错了,后来确认路径没有错误并且是绝对路径。删除失败的原因是图片仍然被进程占用,以至于删除失败。 所以想要成功执行unlink操作,我们最好手动释放下文件对象,避免因为被其他线程或进程占用而导致删除失败,小呆萌如下:public function upload() { //获取上传文件 $file = $this->request->file('file'); if ($file) { // 移动文件到 uploads 目录下 $info = $file->rule('date')->move(ROOT_PATH . 'public' . DS . 'uploads'); if ($info) {//文件上传到服务器成功->接下来上传到OSS $filePath = ROOT_PATH . 'public' . DS . 'uploads/' . $info->getSaveName(); $oss = new Oss(); $result = $oss->putObject($filePath); if ($result) { //上传到OSS成功 unset($info);//解除图片的进程占用 @unlink($filePath); return success(['avatar' => $result['fileSrc']], '头像更新成功'); } } } }
2019年06月14日
6,864 阅读
0 评论
52 点赞
2019-05-17
通过酷Q实现qq机器人,实现qq客服、定时推送qq消息、群管理等功能
通过酷Q实现qq机器人,实现qq客服、定时推送qq消息、群管理等功能。方式:1.windows下载酷Q并安装http-api插件。 下载地址:https://pan.baidu.com/s/1qY55zp62.直接使用docker,通过wine运行在linux系统上。$ docker pull richardchien/cqhttp:latest $ mkdir coolq # 用于存储酷 Q 的程序文件 $ docker run -ti --rm --name cqhttp-test \ -v $(pwd)/coolq:/home/user/coolq \ # 将宿主目录挂载到容器内用于持久化酷 Q 的程序文件 -p 9000:9000 \ # noVNC 端口,用于从浏览器控制酷 Q -p 5700:5700 \ # HTTP API 插件开放的端口 -e COOLQ_ACCOUNT=123456 \ # 要登录的 QQ 账号,可选但建议填 -e CQHTTP_POST_URL=http://example.com:8080 \ # 事件上报地址 -e CQHTTP_SERVE_DATA_FILES=yes \ # 允许通过 HTTP 接口访问酷 Q 数据文件 richardchien/cqhttp:latest其中,CQHTTP_POST_URL、CQHTTP_SERVE_DATA_FILES 是用于配置插件运行的,格式为「CQHTTP_ + 插件配置项的大写」,具体的配置项,见 配置。然后访问 http://注意,默认情况下,容器启动时会检查是否已经存在 config 目录,如果不存在,则会将 CQHTTP_ 开头的环境变量写入到配置文件中;如果 config 目录存在,即不是首次启动,则不会做任何修改。因此,你可以在容器运行时手动修改配置文件,重启容器后仍然有效,这和旧版本的行为不一样!如果你要让容器每次启动时都使用环境变量重新创建配置文件,以保持插件行为和容器启动命令的一致性,可以设置环境变量 FORCE_ENV 的值为 true。完成上述配置后即可通过调用api完成qq的发送消息及qq群管理等功能,剩下的具体的业务逻辑使用自己熟悉的语言去实现即可。详细的接口文档:https://richardchien.gitee.io/coolq-http-api/附点餐小呆萌代码:/** * 接收事件上报 * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\ModelNotFoundException * @throws \think\exception\DbException */ public function receive(){ try{ $getData = input('post.') ? : file_get_contents('php://input'); if (!empty($getData['group_id']) && (int)$getData['group_id'] == $this->groupId) { if ($this->userId = $this->getGroupUserid()){ $content = $getData['raw_message'] ? : $getData['message']; //分离酷q的前置数据与内容文本 preg_match('/(.*[CQ:]{3}.*[]]{1})(.*)/u', $content, $arr); if (!empty($arr[1]) && !empty($arr[2])){ //提取前置数据中被@的qq号 preg_match('/(.*[CQ:at,qq=]{9})([0-9]{5,11})([]]{1})/u', $arr[1], $arr1); if (!empty($arr1[2]) && (int)$arr1[2] == 167114078){ //来到这里证明是被at了,取得纯文本内容进行下一步处理 $tasks = db("group_task") ->whereTime('create_time', 'today') ->select(); if (count($tasks)>=2){ preg_match_all("/([周]{1})([一二三四五六日]{1}).{0,3}([a-cA-C]{1}|[\u{4e0d}]{1}[\u{70b9}]{1})/u", $arr[2],$arr8); $dateArr = $this->getLastSevenDays(); if (!empty($arr8[2])) { //有选项 $data = []; //获取任务id与时间的对应数组,用于判断用户输入的时间有没有任务 $taskArr = array_column($tasks, 'id', 'time'); foreach ($arr8[2] as $key => $value) { $data[strtotime($dateArr[$this->changeDateType($value)])] = $arr8[3][$key]; if (!empty($taskArr[strtotime($dateArr[$this->changeDateType($value)])])){ $taskId = $taskArr[strtotime($dateArr[$this->changeDateType($value)])]; $this->order($taskId, $arr8[3][$key]); }else{ $this->sendGroup($this->groupId, "{$this->groupUserInfo['user_name']}周{$value},没有可点套餐。"); } } }else{ //无选项 preg_match('/([不]{1}[点]{1})/u', $arr[2],$arr2); preg_match('/([A-Ca-c])/u', $arr[2], $arr3); if (!empty($arr2[0]) && $arr2[0] == "不点" || !empty($arr3[0]) && in_array(ucfirst($arr3[0]), ['A', 'B', 'C'])){ $lists = []; $listsNote = []; foreach ($tasks as $v){ $lists[] = "周".$this->changeDateType((int)date("w", $v['time'])); $listsNote[] = "周".$this->changeDateType((int)date("w", $v['time'])) . "-A"; } $msg = "大佬,今天要点" . count($tasks) ."天的餐,你这样我不知道你想点哪一个呀。". PHP_EOL ."今日可点餐有" . implode('、', $lists) . ",点餐请按示例格式回复。". PHP_EOL ."如:" . implode(' ', $listsNote); $this->sendGroup($this->groupId, $msg); } } }else{ if (!empty($tasks[0]['id'])){ preg_match('/([不]{1}[点]{1})/u', $arr[2],$arr2); preg_match('/([A-Ca-c])/u', $arr[2], $arr3); if (!empty($arr2[0]) && $arr2[0] == "不点") { $this->order($tasks[0]['id'], $arr2[0]); exit; }else if (!empty($arr3[0]) && in_array(ucfirst($arr3[0]), ['A', 'B', 'C'])) { $this->order($tasks[0]['id'], ucfirst($arr3[0])); exit; }else { //$this->sendGroup($this->groupId, "不要@我,大佬不给我说话!"); exit; } } } } } } exit; } }catch (\Exception $e){ Log::write("Receive message:".$e->getMessage()); } } /** * 发送消息 * 多行内容部分记得urlencode * @param bool $toUserId * @param bool $content */ public function send($toUserId = false, $content = false){ if ($toUserId && $content){ $content = urlencode($content); $url = "http://127.0.0.1:5701/send_private_msg?user_id={$toUserId}&message={$content}"; file_get_contents($url); } } /** * 发送群消息 * @param bool $groupId * @param bool $message */ public function sendGroup($groupId = false, $message = false){ if ($groupId && $message){ $message = urlencode($message); $url = "http://127.0.0.1:5701/send_group_msg?group_id={$groupId}&message={$message}"; file_get_contents($url); } } /** * 获取群用户id * @return bool|mixed * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\ModelNotFoundException * @throws \think\exception\DbException */ private function getGroupUserid(){ $userModel = db('group_user'); $userInfo = $userModel->where(['qq'=>$this->params['user_id']])->find(); if (isset($userInfo['id'])){ if ((int)$userInfo['status']!=1) return false; $this->groupUserInfo = $userInfo; return $userInfo['id']; } $userParam = $this->params['sender']; $userInfo = [ 'qq' => $userParam['user_id'], 'user_name' => $userParam['nickname'], 'age' => $userParam['age'], 'sex' => $this->getSex($userParam['sex']), 'create_time' => time(), 'update_time' =>time() ]; $this->groupUserInfo = $userInfo; return $userModel->insertGetId($userInfo) ? : false; } private function order($taskId='', $type=''){ try { $type = ucfirst($type); $task = db("group_task") ->find($taskId); if ($task) { $dbModel = db('group_order'); $record = $dbModel ->where([ 'user_id' => $this->userId, 'task_id' => $task['id'] ]) ->find(); $msg = "{$this->groupUserInfo['user_name']},"; if ($record) { $result = $dbModel->update([ 'id' => $record['id'], 'task_id' => $task['id'], 'type' => $this->changeOrderType($type), 'update_time' => time() ]); $msg .= "更新点餐成功,"; } else { $result = $dbModel->insert([ 'user_id' => $this->userId, 'task_id' => $task['id'], 'type' => $this->changeOrderType($type), 'create_time' => time() ]); $msg .= "点餐成功,"; } if ((int)$this->changeOrderType($type) == 9) { $date = $this->changeDateType((int)date("w", $task['time'])); $msg = "{$this->groupUserInfo['user_name']},好的知道了,你周{$date}不点。"; }else if ($result) { $data = json_decode($task['data'], true); $msg .= "您点的是:{$type}餐,【{$data[$type]}】。"; }else{ $msg = "哦吼,点餐失败,系统出错了。"; } $this->sendGroup($this->groupId, $msg); }else{ $this->sendGroup($this->groupId, "{$this->groupUserInfo['user_name']},还没到点餐时间,到时间会通知你的,认真上班吧。"); } }catch (\Exception $e){ $this->sendGroup($this->groupId, "卡bug了,错误信息:".$e->getMessage().'line:'.$e->getLine()); } } /** * 添加点餐任务 * @return mixed */ public function add_task(){ if (request()->isPost()){ $content = input('post.content'); //提取文本中的日期 preg_match_all("'\d{1,2}月\d{1,2}'", $content,$arr1); $time = empty($arr1[0][0]) ? time() : strtotime(date('Y') . '/' . str_replace(['月'], '/', $arr1[0][0])); $dbModel = db("group_task"); $where = [ 'time' => $time ]; $check = $dbModel->where($where) ->find(); if ($check){ $date = date('Y年m月d日', $time); $this->error("{$date},该日期已存在订餐任务,不能重复添加!"); } preg_match_all('/([A-Za-z#].+)/u', $content,$arr); if (!empty($arr[1])) { $result = []; foreach ($arr[1] as $v){ $v = preg_replace("/(\s|\ \;| |\xc2\xa0)/","",$v); $data = explode('餐',$v); if (!empty($data[0]) && in_array($data[0], ['A', 'B', 'C']) && !empty($data[1])) { $result[$data[0]] = $data[1]; } } if (count($result)>=3) { $data = [ 'time' => $time, 'data' => json_encode($result, JSON_UNESCAPED_UNICODE), 'content' => $content, 'create_time' => time() ]; $dbModel->insert($data); $this->success('添加点餐任务成功!'); } } $this->error('添加任务失败!'); exit; } return $this->fetch(); } /** * 推送qq消息 */ public function push_message(){ if (request()->isPost()) { $content = input('post.content'); $this->sendGroup($this->groupId, $content); //$this->sendGroup($this->groupId, "来活了,老铁们,开始点餐啦,A、B、C随便选,不点的回复不点,点餐时需要先@小助手,否则不管用哦,点餐12点准时结束,过时不候。"); $this->success("推送成功!"); } return $this->fetch(); } /** * @return mixed * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\ModelNotFoundException * @throws \think\exception\DbException */ public function views(){ $userModel = db('group_user'); $day = input("param.day") ? : (date('d')); $startTime = strtotime(date("Y-m-{$day} 00:00:00")); $task = db("group_task") ->where(['time'=> $startTime]) ->find(); $data = empty($task['id'])? [] : $userModel->alias('u') ->field("u.id,u.user_name,o.type,o.create_time") ->join("group_order o", "o.task_id = {$task['id']} and o.user_id = u.id", 'LEFT') ->where(['u.status' => 1]) ->order("o.type asc") ->select(); $result = $this->array_group_by($data, 'type'); $notChoose = isset($result['']) ? implode(',', array_column($result[''], 'user_name')) : ''; $this->assign('not_choose', $notChoose); ksort($result); $record = []; $msg = []; foreach ($result as $k => $v){ if (!empty((int)$k) && in_array((int)$k, [1,2,3])){ $num = count($v); $msg[] = $this->changeOrderType($k) ." {$num}份"; $record[$k] = $num; } } $info = '云商项目开发部: '.implode(', ', $msg) . " 共计:".array_sum($record) . "份"; foreach ($data as $k => &$v){ if (!empty($v['type']) && in_array((int)$v['type'], [1, 2, 3])){ $v['status'] = 1; }else{ $v['status'] = ''; } $v['type'] = $this->changeOrderType($v['type']); if ($v['create_time']){ $v['create_time'] = date('Y-m-d H:i:s', $v['create_time']); } } krsort($msg); if (request()->isPost()){ $result = [ 'code' => 0, 'data' => $data ]; echo json_encode($result); exit; } if ($task){ $task = json_decode($task['data'], true); } $days = date('t', strtotime('Y-m')) + 1 ; $this->assign('days', $days); $this->assign('day', $day); $this->assign('task', $task); $this->assign('data', $data); $this->assign('info', $info); return $this->fetch(); } /** * @return mixed * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\ModelNotFoundException * @throws \think\exception\DbException */ public function view_month(){ $days = date('t', strtotime('2019-03')); $userModel = db('group_user'); $orderModel = db('group_order'); $month = input("param.month") ? : date('m'); if (request()->isPost()){ $startTime = strtotime(date("Y-{$month}-1")); $endTime = strtotime(date("Y-m-d", strtotime("last day of this month", strtotime(date("Y-{$month}-d"))))); $data = $userModel ->field("id,user_name") ->where(['status' => 1]) ->select(); foreach ($data as &$v){ $results = $orderModel->alias('o')->field("t.time") ->join('group_task t', "t.id = o.task_id", "LEFT") ->where([ 'o.user_id' => $v['id'], 't.time' => ['between', [$startTime, $endTime]], 'o.type' => ['IN', [1,2,3]] ])->select(); $v['type'] = "午餐"; $timeArr = array_column($results, 'time'); for ($i=1;$i 0, 'data' => $data ]; echo json_encode($result); exit; } $this->assign('months', [1,2,3,4,5,6,7,8,9,10,11,12]); $this->assign('month', $month); return $this->fetch(); } public static function array_group_by($arr, $key) { $grouped = []; foreach ($arr as $value) { $grouped[$value[$key]][] = $value; } if (func_num_args() > 2) { $args = func_get_args(); foreach ($grouped as $key => $value) { $parms = array_merge([$value], array_slice($args, 2, func_num_args())); $grouped[$key] = call_user_func_array('array_group_by', $parms); } } return $grouped; } /** * 点餐结束,推送点餐情况 * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\ModelNotFoundException * @throws \think\exception\DbException */ public function push_order_result(){ if (!empty($this->params['token']) && $this->params['token'] == $this->push_token) { $task = db("group_task") ->whereTime('create_time', 'today') ->select(); if ($task) { $userModel = db('group_user'); $msg = '今日点餐时间结束,点餐情况如下:'.PHP_EOL; foreach ($task as $v){ $orderDate = date('Y年m月d日', $v['time']); $msg .= "用餐时间:{$orderDate}".PHP_EOL; $data = $userModel->alias('u') ->field("u.id,u.user_name,o.type,o.create_time") ->join('group_order o', "o.user_id = u.id and task_id = {$v['id']}", 'LEFT') ->where(['u.status' => 1]) ->select(); $orderData = json_decode($v['data'], true); foreach ($data as $vo){ if (!empty($vo['type']) && in_array((int)$vo['type'], [1,2,3])){ $type = $this->changeOrderType($vo['type']); $msg .= "{$vo['user_name']} : {$type}餐 【{$orderData[$type]}】".PHP_EOL; }else{ $msg .= "{$vo['user_name']} : 不点".PHP_EOL; } } $result = $this->array_group_by($data, 'type'); $typeMsg = []; $record = []; foreach ($result as $k => $v){ if (!empty((int)$k) && in_array((int)$k, [1,2,3])){ $num = count($v); $typeMsg[$k] = $this->changeOrderType($k) ." {$num}份"; $record[$k] = $num; } } ksort($typeMsg); $msg .= PHP_EOL."{$orderDate} 云商项目开发部: ".implode(', ', $typeMsg) . " 共计:".array_sum($record) . "份".PHP_EOL; } $this->sendGroup($this->groupId, $msg); } } } /** * 开饭前推送今天的点餐情况 * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\ModelNotFoundException * @throws \think\exception\DbException */ public function push_today_order(){ if (!empty($this->params['token']) && $this->params['token'] == $this->push_token) { $task = db("group_task") ->whereTime('time', 'today') ->find(); if ($task){ $userModel = db('group_user'); $orderDate = date('m月d日', $task['time']); $msg = "下班开饭,{$orderDate}点餐情况如下,请对号入座:".PHP_EOL; $data = $userModel->alias('u') ->field("u.id,u.user_name,o.type,o.create_time") ->join('group_order o', "o.user_id = u.id and task_id = {$task['id']}", 'LEFT') ->where(['u.status' => 1]) ->select(); $orderData = json_decode($task['data'], true); foreach ($data as $vo){ if (!empty($vo['type']) && in_array((int)$vo['type'], [1,2,3])){ $type = $this->changeOrderType($vo['type']); $msg .= "{$vo['user_name']} : {$type}餐 【{$orderData[$type]}】".PHP_EOL; }else{ $msg .= "{$vo['user_name']} : 不点".PHP_EOL; } } //$msg .= PHP_EOL."你喜欢岁月静好,其实现实是大江奔流。"; $this->sendGroup($this->groupId, $msg); } } } /** * 获取未来7天分别是周几 * @param bool $time * @return array */ public function getLastSevenDays($time = false){ if (!$time) $time = time(); $data = []; for ($i=0;$i<7;$i++){ $data[date('w', $time)] = date('Y-m-d 00:00:00', $time); $time += 60*60*24; } return $data; } /** * 把中文的周几转换为数字并对应php date()方法 * @param string $date * @return bool|int */ public function changeDateType($date = ''){ $result = false; if (is_int($date)){ switch ($date){ case 1: $result = '一'; break; case 2: $result = '二'; break; case 3: $result = '三'; break; case 4: $result = '四'; break; case 5: $result = '五'; break; case 6: $result = '六'; break; case 0: $result = '日'; break; } }else{ if (empty($date)) return $result; switch ($date){ case '一': $result = 1; break; case '二': $result = 2; break; case '三': $result = 3; break; case '四': $result = 4; break; case '五': $result = 5; break; case '六': $result = 6; break; case '日': $result = 0; break; } } return $result; }
2019年05月17日
7,741 阅读
0 评论
46 点赞
2019-04-10
mysql优化之thread_cache_size
1、mysql服务器的线程数查看方法:show global status like 'Thread%';Threads_created:创建过的线程数,如果发现Threads_created值过大的话,表明MySQL服务器一直在创建线程,这也是比较耗资源,可以适当增加配置文件中thread_cache_size值2、优化参数thread_cache_sizethread_cache_size:当客户端断开之后,服务器处理此客户的线程将会缓存起来以响应下一个客户而不是销毁(前提是缓存数未达上限)即可以重新利用保存在缓存中线程的数量,当断开连接时如果缓存中还有空间,那么客户端的线程将被放到缓存中,如果线程重新被请求,那么请求将从缓存中读取,如果缓存中是空的或者是新的请求,那么这个线程将被重新创建,如果有很多新的线程,增加这个值可以改善系统性能。thread_cache_size大小的设置:如果是短连接,适当设置大一点,因为短连接往往需要不停创建,不停销毁,如果大一点,连接线程都处于取用状态,不需要重新创建和销毁,所以对性能肯定是比较大的提升。对于长连接,不能保证连接的稳定性,所以设置这参数还是有一定必要,可能连接池的问题,会导致连接数据库的不稳定性,也会出现频繁的创建和销毁,但这个情况比较少,如果是长连接,可以设置成小一点,一般在50-100左右。物理内存设置规则:通过比较Connections 和 Threads_created 状态的变量,可以看到这个变量的作用。(-->表示要调整的值) 根据物理内存设置规则如下: 1G ---> 8 2G ---> 16 3G ---> 32 >3G ---> 64查询thread_cache_size设置show global status like'thread_cache_size';优化方法:1、mysql> set global thread_cache_size=162、编辑/etc/my.cnf 更改/添加thread_concurrency = 163、mysql kill线程mysqladmin start slave stop slave kill某个连接到mysqlServer的线程
2019年04月10日
6,063 阅读
0 评论
49 点赞
2019-03-11
内部类-非静态内部类|静态内部类|匿名内部类
内部类-非静态内部类|静态内部类|匿名内部类package com.weitip.oop; /** * Created by IntelliJ IDEA. * User: loong * Date: 2019/3/11 * Time: 15:35 * Description: com.weitip.oop **/ public class InnerClass { public static void main(String[] args) { Outer.Inner inner = new Outer().new Inner(); inner.show(); Outer.Inner2 inner2 = new Outer.Inner2(); inner2.show(); } } class Outer{ private int age = 20; class Inner{ int age = 999; public void show(){ int age = 999999; System.out.println("外部类属性age:" + Outer.this.age); System.out.println("内部类属性age:" + this.age); System.out.println("局部变量age:" + age); } } static class Inner2{ public static void show() { System.out.println("内部静态类被调用"); } } }package com.weitip.oop; /** * Created by IntelliJ IDEA. * User: loong * Date: 2019/3/11 * Time: 16:01 * Description: com.weitip.oop **/ public class AnonymousInnerClass { public static void test(AA a){ a.aa(); } public static void main(String[] args) { AnonymousInnerClass.test(new AA(){ @Override public void aa() { System.out.println("匿名内部类被调用"); } }); } } interface AA{ void aa(); }
2019年03月11日
1,977 阅读
0 评论
0 点赞
2019-02-17
PHP7新特性
PHP7中也增加了一些新的语法,这些语法的使用也能对提高性能有帮助。1.标量参数类型声明 现在支持字符串(string)、整型(int)、浮点数(float)、及布尔型(bool)参数声明,以前只支持类名、接口、数组及Callable两种风格:强制转换模式(默认)与严格模式。<?php function sum(int ...$numbers){ var_dump($numbers); return array_sum($numbers); } echo sum("18","9984");运行结果如下: 以string类型传入的值会被强制转换为int类型,若类型转换失败会抛出错误。2.返回类型声明<?php function test():array { return [456,996]; } var_dump(test());运行结果:若返回值类型不为预设类型则报错:<?php function test():array { return 666; } var_dump(test());3.??运算符 ?? 用于替代需要isset的场合,这是一个语法糖。<?php $id = isset($_GET['id']) ? $_GET['id'] : null; $id = $_GET['id'] ?? null; 这两种写法是等效的。4.比较运算符 就是看两个表达式值的大小,三种关系: = 返回0、< 返回-1、 > 返回 1<?php echo 1 2; //-1 echo 1 1; //0 echo 2 1; //15.define支持定义数组类型的值 php 5.6已经支持CONST 语法定义数组类的常量,PHP7中支持define语法。"lili", "age"=>18]); var_dump(human);6.匿名类write();7.增加了整除函数 intdiv 对除法结果取整<?php echo intdiv(10,3); //输出3小结:性能提升:PHP 7要比PHP 5.6快两倍;全面一致的64位支持;新增了空接合操作符(??)。
2019年02月17日
5,785 阅读
0 评论
13 点赞
2019-02-17
PHP生成随机标识
用于微信小程序接口开发中生成3rd_session。/*** 生成随机标识*@param$len*@returnmixed|string*/public functionrandomFromDev($len) { $fp= @fopen('/dev/urandom','rb'); $result=''; if($fp!==FALSE) { $result.= @fread($fp,$len); @fclose($fp); }else{ trigger_error('Can not open /dev/urandom.'); } if(empty($result))$result= md5(mt_rand(111111111,999999999));//兼容 $result= base64_encode($result);// convert from binary to string $result= strtr($result,'+/','-_');// remove none url chars returnsubstr($result,0,$len);}
2019年02月17日
5,566 阅读
0 评论
4 点赞
2019-02-16
商品sku匹配及属性可选状态
最近在做商品sku的时候遇到了一些困惑,记录一下,以备日后会看。 先说一说需求: 1.根据选中的SKU,显示对应的SKU图片,没有选中的SKU时,默认展示SPU商品图,单击放大预览; 2.每个属性下属性值有多个时,默认不选,只有一个时,默认选中; 3.后台没有设置SKU时,则无属性值展示; 4.选中交互:选中某一个属性下属性值时,检查其他属性的属性值,哪些不能组合为一个SKU,不能组合的属性值只读,原选中的则取消选中。 已上就是给出的文字需求,在需求讨论的时候产品定了调调,通过既定的属性去确定一个sku,即所有未选择的属性假定一个初始值。一听心里乐了,所有选中的属性都已知,排序之后再匹配不就是轻松确定sku了嘛,美滋滋。/** * 获取商品sku属性(初始默认选中,已经被否了呀) */ public function goods_sku_version_1 (){ $goodsId = $this->post['goods_id'] or $this->response(201, 'goods_id不能为空'); $catId = mall_database_execute('goods') ->where(['goods_id' => $goodsId, 'is_on_sale'=> 1, 'is_delete' => 0]) ->getField('goods_type') or $this->response(208, '商品不存在'); //构建查询条件 $where = ['gs.goods_id'=> $goodsId]; $attrArr = []; if (!empty($this->post['attr_id'])){ $attrArr = explode(',', $this->post['attr_id']); sort($attrArr); //升序 $where['gs.attr_id_arr'] = implode(',', $attrArr); } //获取sku信息 $this->rows['info'] = mall_database_execute('goods_sku')->alias('AS gs') ->where($where) ->find() or $this->response(208, 'sku不存在'); if (empty($this->post['attr_id'])) $attrArr = explode(',', $this->rows['info']['attr_id_arr']); //获取顶级sku列表 $this->rows['attribute'] = mall_database_execute('goods_sku_list')->alias('AS gsl') ->field('ga.attr_id, ga.attr_type, ga.attr_name, gsl.attr_values_arr') ->join(mall_database_table('goods_attribute').' AS ga ON ga.attr_id = gsl.attr_id', 'LEFT') ->where([ 'gsl.goods_id' => $goodsId, 'gsl.status' => 1 ]) ->select() ? : ''; if (!empty($this->rows['attribute'])){ //通过二定一待,确定sku foreach ($this->rows['attribute'] as $k=>&$v){ $newAttrArr = $attrArr; $newAttrArr[$k] = '%'; $str = implode(',', $newAttrArr); $v['option'] = mall_database_execute('goods_sku') ->field('goods_sku_id,attr_id_arr,status' ) ->where([ 'goods_id' => $goodsId, 'attr_id_arr' => ['LIKE', $str] ]) ->select(); if (!empty($v['option'])){ foreach ($v['option'] as &$vo){ $newAttrArr = explode(',', $vo['attr_id_arr']); $attrInfo = mall_database_execute('goods_attribute') ->field('attr_id, attr_type, attr_name') ->where([ 'attr_id' => $newAttrArr[$k] ]) ->find(); unset($vo['attr_id_arr']); $vo = array_merge($attrInfo, $vo); } } } } $this->response(); } 本以为这样就完事了,结果没过多久需求就改了,不假定每个属性的初始值,根据用户当前选择动态匹配sku,GG。这个方案一开始没想明白的点在于,基于用户当前选择,推算所有属性的节点是否还有可选的可能(可用sku),之前想到过这一层面,想着偷懒完成需求即可,便没有深究。/** * 基于用户当前属性选择状态,获取sku,及推算每个属性的可选状态 */ public function goods_sku(){ $goodsId = $this->post['goods_id']; //检测商品是否存在 mall_database_execute('goods') ->where(['goods_id' => $goodsId, 'is_on_sale'=> 1, 'is_delete' => 0]) ->getField('goods_id') or $this->response(208, '商品不存在'); $where = [ 'goods_id' => $goodsId, 'status' => 1 ]; //获取所有可选sku的属性组合 $allSkuLists = array_column(mall_database_execute('goods_sku') ->field('attr_id_arr') ->where($where) ->select(), 'attr_id_arr'); $this->rows['sku_num'] = count($allSkuLists); if (!empty($this->post['attr_id'])){ $attrArr = explode(',', $this->post['attr_id']); foreach ($attrArr as &$vv){ if ($vv == '') $vv = '%'; } $where['old_id_arr'] = ['LIKE', implode(',', $attrArr)]; } //查询一个当前用户选择状态下满足条件的组合(先这样,等产品出了可能组合排序规则再完善) $this->rows['info'] = mall_database_execute('goods_sku') ->field('goods_sku_id,price,goods_number,attr_value,goods_thumb') ->where($where) ->find() ? : ''; if ($this->rows['info']['goods_thumb']) $this->rows['info']['goods_thumb'] = change_file_path($this->rows['info']['goods_thumb']); //获取规格 $attribute = mall_database_execute('goods_sku_list')->alias('AS gsl') ->field('ga.attr_id, ga.attr_type, ga.attr_name, gsl.attr_values_arr') ->join(mall_database_table('goods_attribute').' AS ga ON ga.attr_id = gsl.attr_id', 'LEFT') ->where([ 'gsl.goods_id' => $goodsId, 'gsl.status' => 1 ]) ->order('attr_type asc, attr_id asc') ->select(); if (!empty($attribute)){ //遍历获取所有规格的属性,并假定每种属性都不可选 foreach ($attribute as $k=>&$v){ $v['option'] = mall_database_execute('goods_attribute') ->field('attr_id,attr_type,attr_name,2 as status') ->where([ 'attr_id' => ['IN', $v['attr_values_arr']], 'status' => 1 ]) ->order('attr_id asc') ->select(); unset($v['attr_values_arr']); if (!empty($allSkuLists)){ //遍历所有属性判断基于用户选择状态下属性是否有可选方案 foreach ($v['option'] as &$vo){ //获取用户当前选择 $checkSku = explode(',', $this->post['attr_id']); //把当前属性与用户选择进行组合 $checkSku[$k] = $vo['attr_id']; //遍历所有可能的组合列表,查找是否有匹配当前的组合 foreach ($allSkuLists as $vov){ //判断条件:如果我有的你都有那就对了 $intersect = array_intersect($checkSku, explode(',', $vov)); asort($intersect); asort($checkSku); //序列化后做比较 if (implode(',', $intersect) == implode(',', array_filter($checkSku))) $vo['status'] = '1'; } } } } } $this->rows['attribute'] = $attribute ? : ''; $this->response(); }附上表结构:CREATE TABLE `fd_goods_sku` ( `goods_sku_id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id', `goods_id` int(11) NOT NULL, `old_id_arr` varchar(255) NOT NULL DEFAULT '' COMMENT '没排序之前的id组合', `attr_id_arr` varchar(255) NOT NULL DEFAULT '0' COMMENT '属性id', `status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '1正常,2失效', `price` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '售价,单位分', `goods_number` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '库存', `attr_value` varchar(255) NOT NULL DEFAULT '' COMMENT '商品自定义属性', `goods_thumb` varchar(255) NOT NULL DEFAULT '', `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`goods_sku_id`), KEY `goods_id` (`goods_id`,`goods_sku_id`) USING BTREE ) ENGINE=InnoDB AUTO_INCREMENT=2208 DEFAULT CHARSET=utf8mb4 COMMENT='商品sku表'; CREATE TABLE `fd_goods_sku_list` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `goods_id` int(10) unsigned NOT NULL, `attr_id` varchar(255) NOT NULL DEFAULT '' COMMENT '属性id', `attr_values_arr` varchar(255) NOT NULL DEFAULT '' COMMENT '属性值id', `status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '1正常,2失效', `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=599 DEFAULT CHARSET=utf8mb4 COMMENT='商品已选属性表'; 以上仅作记录,如大神们有更好方案请不吝赐教。
2019年02月16日
13,092 阅读
0 评论
35 点赞
2019-01-09
PHP Warning: file_get_contents failed to open stream解决办法
file_get_contents函数在获得远程文件时提示Warning: file_get_contents failed to open stream,希望例子能够帮助到各位,希望例子能够帮助到大家。在做项目时用 file_get_contents 来获取数据,php 报错 PHP Warning: file_get_contents failed to open stream: no suitable wrapper could be found.最后用了curl来获取数据!今天百度了一下!找到了解决办法!先拷贝过来!系统:centos 6.5在错误日志中,php报的错误是Warning: file_get_contents() [function.file-get-contents]: http:// wrapper is disabled in the server configuration by allow_url_fopen=0failed to open stream: no suitable wrapper could be found此警告说服务器阻止访问远程文件,修改php.ini把allow_url_fopen = Offallow_url_include = Off改成allow_url_fopen = Onallow_url_include = On重启php-fpm或者重启web服务。如果还是无法解决 的话windows下处理方法:c:\windows\php.iniextension=php_openssl.dll 把前的;去掉,重启iis服务。linux下处理方法:/etc/php.iniextension=php_openssl.dll 把前的;去掉,重启apache服务。 如果上面问题没能解决我的问题,我们可以如下测试。 $context = stream_context_create(array('http'=>array('ignore_errors'=>true)));$contents = file_get_contents($url, FALSE, $context);可以请求时,忽略错误。可以解决警告信息
2019年01月09日
6,514 阅读
0 评论
3 点赞
2018-09-18
PHP header()函数使用详细(301、404等错误设置)
header实现404无法找到页面 复制代码代码如下:Header("HTTP/1.1 404 Not Found"); 针对apache配置中的ErrorDocument 404 /404.php功能,把nginx配置中的 复制代码代码如下:error_page 404 /404.php; 改成 复制代码代码如下:error_page 404 = /404.php; php heager 301 复制代码代码如下: 不管页面有多少header,它会执行最后一个,不过是有条件的,例如: header('Location://www.jb51.net'); header('Location:http://www.g.cn'); header('Location:http://www.baidu.com'); 这个就会跳到百度 header('Location://www.jb51.net');echo '烈火网; header('Location:http://www.g.cn'); header('Location:http://www.baidu.com'); 这个就会跳到google 下面是关于header函数的详细使用说明 一、作用: ~~~~~~~~~ PHP只是以HTTP协议将HTML文档的标头送到浏览器,告诉浏览器具体怎么处理这个页面,至于传送的内容则需要熟悉一下HTTP协议了,与PHP无关了 传统的标头一定包含下面三种标头之一,并只能出现一次。 Location: xxxx:yyyy/zzzz Content-Type: xxxx/yyyy Status: nnn xxxxxx 二、先来了解一下HTTP协议的运作方式 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ HTTP协议是基于请求/响应范式的。一个客户机与服务器建立连接后,发送一个请求给服务器,请求方式的格式为,统一资源标识符、协议版本号,后边是 MIME信息包括请求修饰符、客户机信息和可能的内容。服务器接到请求后,给予相应的响应信息,其格式为一个状态行包括信息的协议版本号、一个成功或错误的代码,后边是MIME信息包括服务器信息、实体信息和可能的内容。 它分四个过程,在HTTP协议中,服务端是指提供HTTP服务的部分,客户端是指你使用的浏览器或者下载工具等等。在通讯时,由客户端发出请求连接,服务端建立连接;然后,客户端发出HTTP请求(Request),服务端返回响应信息(Respond),由此完成一个HTTP操作。 三、HTTP协议状态码表示的意思 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1×× 保留 2×× 表示请求成功地接收 3×× 为完成请求客户需进一步细化请求 4×× 客户错误 5×× 服务器错误 四、操作实例: ~~~~~~~~~~~~~ 重定向功能,这种最常见 强制用户每次访问这个页面时获取最新资料,而不是使用存在客户端的缓存。 代码 输出状态值到浏览器,主要用于访问权限控制 比如要限制一个用户不能访问该页,则可设置状态为404,如下所示,这样浏览器就显示为即该页不存在 注意: 传统的标头一定包含下面三种标头之一,并只能出现一次。 Content-Type: xxxx/yyyy Location: xxxx:yyyy/zzzz Status: nnn xxxxxx 在新的多型标头规格 (Multipart MIME) 方可以出现二次以上。 使用范例 范例一: 本例使浏览器重定向到 PHP 的官方网站。 Header("Location: //www.jb51.net/"); exit; 范例二: 要使用者每次都能得到最新的资料,而不是 Proxy 或 cache 中的资料,可以使用下列的标头 header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); header("Last-Modified: " . gmdate("D, d M Y H:i:s") . "GMT"); header("Cache-Control: no-cache, must-revalidate"); header("Pragma: no-cache"); 范例三: 让使用者的浏览器出现找不到档案的信息。 header("Status: 404 Not Found"); 范例四:让使用者下载档案。 header("Content-type: application/x-gzip"); header("Content-Disposition: attachment; filename=文件名"); header("Content-Description: PHP3 Generated Data"); header -- 发送一个原始 HTTP 标头说明 void header ( string string [, bool replace [, int http_response_code]] ) header() 函数用来发送一个原始 HTTP 标头。有关 HTTP 标头的更多内容见 HTTP/1.1 规范。 可选参数 replace 指明是替换掉前一条类似的标头还是增加一条相同类型的标头。默认为替换,但如果将其设为 FALSE 则可以强制发送多个同类标头。例如: 第二个可选参数 http_response_code 强制将 HTTP 响应代码设为指定值(此参数是 PHP 4.3.0 新加的)。 有两种特殊的 header 调用。第一种是标头以字符串“HTTP/”(大小写不重要)开头的,可以用来确定要发送的 HTTP 状态码。例如,如果配置了 Apache 用 PHP 来处理找不到文件的错误处理请求(使用 ErrorDocument 指令),需要确保脚本产生了正确的状态码。 注: HTTP 状态码标头行总是第一个被发送到客户端,而并不管实际的 header() 调用是否是第一个。除非 HTTP 标头已经发送出去,任何时候都可以通过用新的状态行调用 header() 函数来覆盖原先的。 HTTP状态检测(HTTP Header): 第二种特殊情况是以“Location:”标头。它不只是把这个标头发送回浏览器,它还将一个 REDIRECT(302)状态码返回给浏览器,除非之前已经发出了某个 3xx 状态码。 注: HTTP/1.1 标准需要一个绝对地址的 URI 做为 Location: 的参数, 但有一些客户端支持相对 URI。通常可以使用 $_SERVER['HTTP_HOST']、$_SERVER['PHP_SELF'] 及 dirname() 函数来自己从相对 URI 产生出绝对 URI:
2018年09月18日
5,913 阅读
0 评论
0 点赞
1
2